@import url('https://fonts.googleapis.com/css2?family=Nunito:ital,wght@0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,400;1,600&family=JetBrains+Mono:wght@400;500;700&display=swap');

/* ── Design tokens ───────────────────────────────────────────────────────── */

:root {
  /* ====================================================================
     COLOR — PEACH / CORAL PRIMARY
     A peach primary feels warmer and less clinical than medical blue.
     ==================================================================== */

  /* Primary scale — peach → coral */
  --peach-50:  #FFF6F1;
  --peach-100: #FFE8DC;
  --peach-200: #FFD2BB;
  --peach-300: #FFB591;
  --peach-400: #FF9A76;   /* brand light */
  --peach-500: #F57E58;   /* brand primary */
  --peach-600: #F26A4B;   /* brand deep */
  --peach-700: #D4512F;
  --peach-800: #A83D23;
  --peach-900: #7A2C18;

  /* Accent — sage (secondary, for "approved / calm" surfaces) */
  --sage-50:  #F2F7F3;
  --sage-100: #E0ECE3;
  --sage-200: #C2D9C8;
  --sage-300: #9BC0A4;
  --sage-400: #74A780;
  --sage-500: #558E63;
  --sage-600: #42724E;
  --sage-700: #33583C;

  /* Accent — butter (soft highlight, for tags/cards) */
  --butter-50:  #FFFBEF;
  --butter-100: #FFF3CE;
  --butter-200: #FFE69A;
  --butter-300: #FFD66A;
  --butter-400: #F5C043;
  --butter-500: #D9A327;

  /* Warm neutrals — brown-tinted grey, never cold */
  --ink-0:   #FFFFFF;
  --ink-50:  #FBF8F5;      /* page background */
  --ink-100: #F3EDE6;      /* subtle surface */
  --ink-150: #EAE1D7;      /* divider */
  --ink-200: #DBCFC1;      /* hairline */
  --ink-300: #B9AA99;      /* disabled text */
  --ink-400: #8C7D6D;      /* caption */
  --ink-500: #6B5D50;      /* secondary body */
  --ink-700: #3E3128;      /* body */
  --ink-900: #2A1D18;      /* display / headings */

  /* Semantic */
  --success-500: #558E63;
  --success-100: #E0ECE3;
  --warning-500: #D9A327;
  --warning-100: #FFF3CE;
  --danger-500:  #D4512F;
  --danger-100:  #FFE8DC;
  --info-500:    #5B8AA6;
  --info-100:    #E2ECF2;

  /* ====================================================================
     SEMANTIC ROLES
     Use these in components; swap underlying palette without breaking.
     ==================================================================== */
  --brand:          var(--peach-500);
  --brand-hover:    var(--peach-600);
  --brand-press:    var(--peach-700);
  --brand-soft:     var(--peach-100);
  --brand-softer:   var(--peach-50);

  --bg:             var(--ink-50);
  --bg-elevated:    var(--ink-0);
  --bg-sunken:      var(--ink-100);

  --fg-1:           var(--ink-900);   /* headings, emphatic */
  --fg-2:           var(--ink-700);   /* body */
  --fg-3:           var(--ink-500);   /* secondary */
  --fg-4:           var(--ink-400);   /* caption */
  --fg-disabled:    var(--ink-300);
  --fg-on-brand:    #FFFFFF;

  --border:         var(--ink-150);
  --border-strong:  var(--ink-200);
  --border-brand:   var(--peach-300);

  /* ====================================================================
     TYPE
     One family, many weights. Rounded geometric → friendly + credible.
     ==================================================================== */
  --font-sans:    'Nunito', 'Nunito Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
  --font-display: 'Nunito', 'Nunito Sans', -apple-system, system-ui, sans-serif;
  --font-mono:    'JetBrains Mono', ui-monospace, 'SF Mono', Menlo, monospace;

  /* Scale — modular, 1.2 ratio, anchored at 16px */
  --text-xs:   0.75rem;     /* 12 */
  --text-sm:   0.875rem;    /* 14 */
  --text-base: 1rem;        /* 16 */
  --text-md:   1.125rem;    /* 18 */
  --text-lg:   1.25rem;     /* 20 */
  --text-xl:   1.5rem;      /* 24 */
  --text-2xl:  1.875rem;    /* 30 */
  --text-3xl:  2.25rem;     /* 36 */
  --text-4xl:  3rem;        /* 48 */
  --text-5xl:  3.75rem;     /* 60 */
  --text-6xl:  4.5rem;      /* 72 */

  /* Weights — we mostly use 400/600/700/800 */
  --w-regular: 400;
  --w-medium:  500;
  --w-semibold:600;
  --w-bold:    700;
  --w-black:   800;

  /* Leading + tracking */
  --leading-tight:   1.15;
  --leading-snug:    1.3;
  --leading-normal:  1.5;
  --leading-relaxed: 1.65;

  --tracking-tight:  -0.02em;
  --tracking-snug:   -0.01em;
  --tracking-normal: 0;
  --tracking-wide:   0.04em;

  /* ====================================================================
     SPACING — 4pt grid
     ==================================================================== */
  --s-0:  0;
  --s-1:  0.25rem;   /* 4  */
  --s-2:  0.5rem;    /* 8  */
  --s-3:  0.75rem;   /* 12 */
  --s-4:  1rem;      /* 16 */
  --s-5:  1.25rem;   /* 20 */
  --s-6:  1.5rem;    /* 24 */
  --s-7:  1.75rem;   /* 28 */
  --s-8:  2rem;      /* 32 */
  --s-10: 2.5rem;    /* 40 */
  --s-12: 3rem;      /* 48 */
  --s-16: 4rem;      /* 64 */
  --s-20: 5rem;      /* 80 */
  --s-24: 6rem;      /* 96 */

  /* ====================================================================
     RADII — generously rounded (but not childish)
     Core rule: pills for actions, soft-rounded for containers.
     ==================================================================== */
  --radius-xs:   6px;
  --radius-sm:   10px;
  --radius-md:   14px;      /* inputs, cards */
  --radius-lg:   20px;      /* panels, modals */
  --radius-xl:   28px;      /* hero cards */
  --radius-2xl:  36px;
  --radius-pill: 999px;     /* buttons, chips */

  /* ====================================================================
     SHADOW — soft, warm-tinted
     Never pure black — always peach-ink brown.
     ==================================================================== */
  --shadow-xs:  0 1px 2px rgba(62, 49, 40, 0.06);
  --shadow-sm:  0 2px 6px rgba(62, 49, 40, 0.06), 0 1px 2px rgba(62, 49, 40, 0.04);
  --shadow-md:  0 8px 20px rgba(62, 49, 40, 0.08), 0 2px 6px rgba(62, 49, 40, 0.05);
  --shadow-lg:  0 20px 40px rgba(62, 49, 40, 0.10), 0 6px 14px rgba(62, 49, 40, 0.06);
  --shadow-xl:  0 32px 64px rgba(62, 49, 40, 0.14), 0 10px 24px rgba(62, 49, 40, 0.08);
  --shadow-brand: 0 12px 28px rgba(242, 106, 75, 0.28);
  --shadow-inset: inset 0 1px 0 rgba(255, 255, 255, 0.7);

  /* Focus ring — accessible + on-brand */
  --focus-ring: 0 0 0 3px rgba(245, 126, 88, 0.35);

  /* ====================================================================
     MOTION
     Soft, short, no bounce-overshoot except on playful accents.
     ==================================================================== */
  --ease-out:     cubic-bezier(0.22, 1, 0.36, 1);
  --ease-in-out:  cubic-bezier(0.65, 0, 0.35, 1);
  --ease-spring:  cubic-bezier(0.34, 1.56, 0.64, 1);
  --dur-fast:     120ms;
  --dur-base:     220ms;
  --dur-slow:     380ms;

  /* ====================================================================
     CHART TOKENS — retinted to warm palette
     These names are read at runtime by trend_detail.html via
     getComputedStyle, so the names must not change.
     ==================================================================== */
  --chart-line:         var(--peach-500);
  --chart-line-bg:      rgba(245, 126, 88, 0.12);
  --chart-hover:        var(--peach-600);
  --chart-range-bg:     rgba(155, 192, 164, 0.18);
  --chart-range-border: var(--sage-300);
  /* Grid lines and axis text use warm-neutral tokens so the chart interior
     matches the rest of the UI. Canvas 2D cannot resolve CSS custom properties
     directly, so the JS reads these via getComputedStyle at runtime. */
  --chart-grid:         rgba(234, 225, 215, 0.8);   /* --ink-150 at 80% opacity */
  --chart-axis-text:    var(--ink-500);              /* --fg-3 equivalent */

}

*, *::before, *::after {
    box-sizing: border-box;
    margin: 0;
    padding: 0;
}

html, body {
    font-family: var(--font-sans);
    font-size: var(--text-base);
    line-height: var(--leading-normal);
    color: var(--fg-2);
    background: var(--bg);
    -webkit-font-smoothing: antialiased;
    text-rendering: optimizeLegibility;
}

body {
    min-height: 100vh;
    display: flex;
    flex-direction: column;
}

/* ── Nav ─────────────────────────────────────────────────────────────────── */

.nav {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0 var(--s-8);
    height: 3.5rem;
    background-color: var(--ink-900);
    color: var(--peach-100);
    flex-shrink: 0;
    /* Positioned so absolute children (dropdowns) anchor to the nav bar. */
    position: relative;
}

.nav__site-name {
    display: flex;
    align-items: center;
    gap: var(--s-2);
    font-weight: 700;
    font-size: 1.3rem;
    letter-spacing: -0.02em;
    color: var(--peach-100);
    text-decoration: none;
}

.nav__logo {
    height: 2rem;
    width: auto;
}

.nav__site-name:hover {
    color: var(--peach-100);
}

.nav__links {
    display: flex;
    align-items: center;
    gap: var(--s-5);
}

.nav__links a {
    color: var(--peach-200);
    text-decoration: none;
    font-size: 0.9rem;
    font-weight: 500;
    padding: var(--s-1) var(--s-2);
    border-radius: var(--radius-xs);
    transition: color var(--dur-fast) var(--ease-out),
                background-color var(--dur-fast) var(--ease-out);
}

.nav__links a:hover {
    color: var(--peach-50);
    background-color: rgba(255, 255, 255, 0.06);
}

/* Active link gets a warm underline to mark the current route. */
.nav__links a.nav__link--active {
    color: var(--fg-on-brand);
    text-decoration: underline;
    text-underline-offset: 3px;
}

.nav__links a:focus-visible {
    outline: none;
    box-shadow: var(--focus-ring);
    border-radius: var(--radius-xs);
}

.nav__username {
    font-size: 0.9rem;
    color: var(--ink-200);
}

/* The logout button sits inline with nav links, so it inherits the nav's
   visual language rather than the general form button style. */
.nav__logout-form {
    display: inline;
}

/* The nav logout button overrides the general submit style since it lives in
   the dark nav bar and needs its own visual treatment. */
.nav__logout-form button[type="submit"] {
    display: inline;
    margin-top: 0;
    padding: var(--s-1) var(--s-3);
    font-size: 0.9rem;
    font-weight: 500;
    color: var(--peach-200);
    background: none;
    border: 1px solid var(--peach-700);
    border-radius: 4px;
    box-shadow: none;
}

.nav__logout-form button[type="submit"]:hover {
    background-color: transparent;
    border-color: var(--peach-500);
    color: var(--peach-50);
    transform: none;
}

/* The focus ring uses a lighter opacity here because the nav background is
   dark — the standard ring reads clearly against it. */
.nav__logout-form button[type="submit"]:focus-visible {
    box-shadow: var(--focus-ring);
}

/* ── Hamburger menu (mobile nav toggle) ───────────────────────────────────── */

/* Hidden on desktop; shown on mobile via the media query below. */
.nav__hamburger {
    display: none;
}

@media (max-width: 639px) {
    .nav__hamburger {
        display: flex;
        align-items: center;
        justify-content: center;
        background: none;
        border: none;
        color: var(--peach-200);
        cursor: pointer;
        padding: var(--s-2);
        margin: 0;
        border-radius: var(--radius-xs);
    }

    .nav__hamburger:hover {
        color: var(--peach-50);
        background-color: rgba(255, 255, 255, 0.06);
    }

    .nav__hamburger:focus-visible {
        outline: none;
        box-shadow: var(--focus-ring);
    }

    .nav__hamburger svg {
        width: var(--text-xl);
        height: var(--text-xl);
    }

    /* Dropdown panel — hidden by default, shown when toggled open. */
    #nav-panel.nav__links {
        display: none;
        position: absolute;
        top: 100%;
        left: 0;
        right: 0;
        flex-direction: column;
        align-items: stretch;
        gap: 0;
        background-color: var(--ink-900);
        padding: var(--s-2) 0;
        border-top: 1px solid var(--ink-200);
        z-index: 100;
    }

    #nav-panel.nav__links--open {
        display: flex;
    }

    /* Menu items in the mobile dropdown get full-width tap targets. */
    #nav-panel.nav__links a,
    #nav-panel.nav__links .nav__username,
    #nav-panel.nav__links .nav__logout-form {
        padding: var(--s-3) var(--s-8);
    }

    #nav-panel.nav__links .nav__logout-form {
        display: block;
    }

    /* The logout button expands to fill the row for an easier tap target.
       Explicitly clears the orange pill styling from the generic
       button[type="submit"] rule so it matches the other dropdown rows. */
    #nav-panel.nav__links .nav__logout-form button[type="submit"] {
        display: block;
        width: 100%;
        text-align: left;
        padding: 0;
        border: none;
        background: none;
        box-shadow: none;
        color: var(--peach-200);
        font-size: 0.9rem;
        font-weight: 500;
    }

    #nav-panel.nav__links .nav__logout-form button[type="submit"]:hover {
        background-color: transparent;
        color: var(--peach-50);
    }
}

/* ── Account dropdown (desktop nav) ────────────────────────────────────── */

/* The trigger button sits outside #nav-panel so the hamburger JS does not
   interfere. Hidden on mobile; the hamburger shows the items flat instead. */
.nav__account-trigger {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: none;
    border: none;
    color: var(--peach-200);
    cursor: pointer;
    padding: var(--s-2);
    border-radius: var(--radius-xs);
}

.nav__account-trigger:hover {
    color: var(--peach-50);
    background-color: rgba(255, 255, 255, 0.06);
}

.nav__account-trigger:focus-visible {
    outline: none;
    box-shadow: var(--focus-ring);
}

.nav__account-trigger svg {
    width: var(--text-xl);
    height: var(--text-xl);
}

/* The dropdown panel lives inside #nav-panel (single source of truth — no
   duplication). On desktop it is an absolutely-positioned popover; on mobile
   the media query below strips the popover styles so the items render as
   flat rows inside the hamburger dropdown. */
#nav-account-menu {
    display: none;
    position: absolute;
    /* Anchored below the nav bar, at the right edge (near the trigger). */
    top: 100%;
    right: 0;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    background-color: var(--ink-900);
    padding: var(--s-2) 0;
    border: 1px solid var(--ink-700);
    border-radius: var(--radius-sm);
    box-shadow: var(--shadow-md);
    z-index: 100;
    min-width: 220px;
}

#nav-account-menu.nav__account-menu--open {
    display: flex;
}

/* Email label — non-interactive, visually separated from the links below.
   Scoped to desktop only because the ID-prefixed selector would otherwise
   beat the .hide-on-mobile utility on mobile and render the email twice
   (once here, once via the dedicated mobile email row in #nav-panel). */
@media (min-width: 640px) {
    #nav-account-menu .nav__username {
        display: block;
        padding: var(--s-2) var(--s-4);
        padding-bottom: calc(var(--s-2) + var(--s-1));
        font-size: 0.85rem;
        color: var(--ink-300);
        border-bottom: 1px solid var(--ink-700);
        margin-bottom: var(--s-1);
    }
}

/* Links inside the dropdown get full-width tap targets. */
#nav-account-menu a {
    display: block;
    padding: var(--s-2) var(--s-4);
    color: var(--peach-200);
    text-decoration: none;
    font-size: 0.9rem;
    font-weight: 500;
}

#nav-account-menu a:hover {
    color: var(--peach-50);
    background-color: rgba(255, 255, 255, 0.06);
}

#nav-account-menu a:focus-visible {
    outline: none;
    box-shadow: inset var(--focus-ring);
}

/* Logout form inside the account dropdown. */
#nav-account-menu .nav__logout-form {
    display: block;
}

/* The logout button overrides the generic orange pill styling so it visually
   matches the Settings row. Uses #nav-account-menu (ID selector) to beat the
   specificity of the generic button[type="submit"]:not(...) rule. On mobile
   the #nav-panel rule takes over — see the media query below. */
#nav-account-menu .nav__logout-form button[type="submit"] {
    display: block;
    width: 100%;
    text-align: left;
    padding: var(--s-2) var(--s-4);
    margin-top: 0;
    border: none;
    background: none;
    box-shadow: none;
    color: var(--peach-200);
    font-size: 0.9rem;
    font-weight: 500;
    border-radius: 0;
}

#nav-account-menu .nav__logout-form button[type="submit"]:hover {
    background-color: rgba(255, 255, 255, 0.06);
    color: var(--peach-50);
    transform: none;
}

#nav-account-menu .nav__logout-form button[type="submit"]:active {
    background-color: rgba(255, 255, 255, 0.06);
    transform: none;
}

#nav-account-menu .nav__logout-form button[type="submit"]:focus-visible {
    outline: none;
    box-shadow: inset var(--focus-ring);
}

/* ── Desktop nav layout (>= 640px) ───────────────────────────────────── */

/* On desktop the trigger sits to the right of the nav links group. Push the
   links group to the right so brand is on the left and { links + trigger } are
   grouped on the right, matching the original space-between look. */
@media (min-width: 640px) {
    .nav {
        justify-content: flex-start;
    }
    .nav__links {
        margin-left: auto;
    }
    /* Visual separation between the last nav link and the account icon. */
    .nav__account-trigger {
        margin-left: var(--s-3);
    }
}

/* ── Mobile: flatten account dropdown into hamburger rows ─────────────── */

/* On mobile the account trigger is hidden and the menu contents render as
   static rows at the top of the hamburger dropdown — no popover chrome. */
@media (max-width: 639px) {
    /* Strip popover styles; render the menu as flat column rows.
       The email span inside the menu has .hide-on-mobile so it does not
       render on mobile — a dedicated .show-on-mobile email row earlier in
       #nav-panel handles the mobile email position (before Biomarkers). */
    #nav-account-menu {
        display: flex;
        position: static;
        flex-direction: column;
        border: none;
        border-radius: 0;
        box-shadow: none;
        padding: 0;
        min-width: 0;
        background: none;
    }
}

/* ── Page content wrapper ────────────────────────────────────────────────── */

/* Grows to fill remaining vertical space so the landing page can center
   itself within it using flex, while other pages simply flow from the top. */
.page-content {
    flex: 1;
    display: flex;
    flex-direction: column;
}

/* ── Landing page ────────────────────────────────────────────────────────── */

/* The landing page overrides the nav block to empty, so .page-content fills
   the full viewport height. The .landing element then centers itself within
   that space. */
.landing {
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    text-align: center;
    padding: var(--s-8);
    /* Opt out of the global `main` constraints (max-width: 480px; margin: 3rem
       auto) so the gradient is full-bleed and flex: 1 can actually stretch the
       element to fill .page-content. */
    max-width: none;
    margin: 0;
    /* min-height: 0 lets the flex child shrink below its content size so the
       100dvh body constraint actually takes effect on small viewports. */
    min-height: 0;
    overflow: auto;
}

.landing__title {
    font-size: clamp(var(--text-4xl), 10vw, var(--text-6xl));
    font-weight: var(--w-black);
    letter-spacing: -0.03em;
    line-height: 1;
    color: var(--fg-1);
    margin-bottom: var(--s-4);
}

.landing__subtitle {
    font-size: clamp(var(--text-base), 3vw, var(--text-xl));
    font-weight: 400;
    color: var(--fg-3);
    letter-spacing: 0.08em;
}

/* ── Typography ──────────────────────────────────────────────────────────── */

h1, .h1 {
    font-family: var(--font-display);
    font-weight: var(--w-black);
    font-size: clamp(2.25rem, 4.5vw, var(--text-5xl));
    line-height: var(--leading-tight);
    letter-spacing: var(--tracking-tight);
    color: var(--fg-1);
    text-wrap: balance;
    margin-bottom: var(--s-6);
}

h2, .h2 {
    font-family: var(--font-display);
    font-weight: var(--w-bold);
    font-size: clamp(1.75rem, 3vw, var(--text-3xl));
    line-height: var(--leading-tight);
    letter-spacing: var(--tracking-snug);
    color: var(--fg-1);
    text-wrap: balance;
    margin-top: var(--s-8);
    margin-bottom: var(--s-5);
}

h3, .h3 {
    font-family: var(--font-display);
    font-weight: var(--w-bold);
    font-size: var(--text-xl);
    line-height: var(--leading-snug);
    letter-spacing: var(--tracking-snug);
    color: var(--fg-1);
    margin-bottom: var(--s-4);
}

h4, .h4 {
    font-family: var(--font-sans);
    font-weight: var(--w-semibold);
    font-size: var(--text-lg);
    line-height: var(--leading-snug);
    color: var(--fg-1);
}

p, .body {
    font-size: var(--text-base);
    line-height: var(--leading-relaxed);
    color: var(--fg-2);
    text-wrap: pretty;
    margin-bottom: var(--s-4);
}

p:last-child {
    margin-bottom: 0;
}

.body-lg {
    font-size: var(--text-md);
    line-height: var(--leading-relaxed);
    color: var(--fg-2);
}

.body-sm {
    font-size: var(--text-sm);
    line-height: var(--leading-normal);
    color: var(--fg-3);
}

.caption, small {
    font-size: var(--text-xs);
    line-height: var(--leading-normal);
    color: var(--fg-4);
}

.eyebrow {
    font-family: var(--font-sans);
    font-size: var(--text-xs);
    font-weight: var(--w-bold);
    letter-spacing: var(--tracking-wide);
    text-transform: uppercase;
    color: var(--brand);
}

code, kbd, .code {
    font-family: var(--font-mono);
    font-size: 0.92em;
    background: var(--ink-100);
    padding: 0.1em 0.35em;
    border-radius: var(--radius-xs);
    color: var(--fg-1);
}

a {
    color: var(--brand);
    text-decoration-line: underline;
    text-decoration-color: transparent;
    text-underline-offset: 3px;
    text-decoration-thickness: 1px;
    transition: text-decoration-color var(--dur-fast) var(--ease-out),
                color var(--dur-fast) var(--ease-out);
}

a:hover { color: var(--brand-hover); text-decoration-color: currentColor; }
a:focus-visible { outline: none; box-shadow: var(--focus-ring); border-radius: 2px; }

/* Utility color classes */
.fg-1 { color: var(--fg-1); }
.fg-2 { color: var(--fg-2); }
.fg-3 { color: var(--fg-3); }
.fg-4 { color: var(--fg-4); }
.fg-brand { color: var(--brand); }

/* ── Page main content area ──────────────────────────────────────────────── */

main {
    width: 100%;
    max-width: 480px;
    margin: 3rem auto;
    padding: 0 var(--s-6);
}

.main--wide {
    max-width: 960px;
}

/* The page-header sits above table content and needs its own bottom margin
   because the h1 inside it would otherwise push against the action button
   rather than the content below. */
.page-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: var(--s-6);
}

.page-header h1 {
    margin-bottom: 0;
}

.back-link {
    margin-bottom: var(--s-3);
    font-size: var(--text-sm);
}

.back-link a {
    color: var(--fg-3);
}

.back-link a:hover {
    color: var(--fg-1);
}

/* ── Forms ───────────────────────────────────────────────────────────────── */

/* Django's as_p wraps each field in a <p>, so we target those directly.
   The margin-bottom on <p> above already provides spacing between fields. */
form p {
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
}

/* .form-field is the component wrapper used by components/form_field.html.
   form p handles the legacy as_p layout; both share the same child styles. */
.form-field {
    display: flex;
    flex-direction: column;
    gap: var(--s-1);
    margin-bottom: var(--s-4);
}

label {
    font-size: var(--text-sm);
    font-weight: var(--w-semibold);
    color: var(--fg-1);
}

input[type="text"],
input[type="password"],
input[type="email"],
input[type="date"],
select,
textarea {
    width: 100%;
    padding: var(--s-3) var(--s-4);
    font-family: inherit;
    font-size: var(--text-base);
    color: var(--fg-1);
    background-color: var(--bg-elevated);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-md);
    outline: none;
    transition: border-color var(--dur-fast) var(--ease-out),
                box-shadow var(--dur-fast) var(--ease-out);
}

input[type="text"]:focus,
input[type="password"]:focus,
input[type="email"]:focus,
input[type="date"]:focus,
select:focus,
textarea:focus {
    border-color: var(--brand);
    box-shadow: var(--focus-ring);
}

input[type="text"]::placeholder,
input[type="password"]::placeholder,
input[type="email"]::placeholder,
input[type="date"]::placeholder,
textarea::placeholder {
    color: var(--fg-4);
}

input[type="text"]:disabled,
input[type="password"]:disabled,
input[type="email"]:disabled,
input[type="date"]:disabled,
select:disabled,
textarea:disabled {
    background-color: var(--bg-sunken);
    color: var(--fg-disabled);
    cursor: not-allowed;
}

textarea {
    resize: vertical;
    min-height: 6rem;
}

/* Help text rendered by the form_field component. */
.form-field__help-text {
    font-size: var(--text-sm);
    color: var(--fg-3);
    margin-bottom: 0;
}

/* Error list rendered by the form_field component. */
.form-field__errors {
    list-style: none;
    margin: 0;
    padding: 0;
}

.form-field__errors li {
    font-size: var(--text-sm);
    color: var(--danger-500);
}

/* WARNING: Any bare <button type="submit"> will pick up the orange pill styling
   below. Opt out by adding a .button or .toolbar__button class, or use explicit
   overrides (see .nav__logout-form button and #nav-account-menu button rules).

   button[type="submit"] without an explicit .button class (login/register use
   form.as_p which emits a bare <button type="submit">). These pages get the
   same primary pill styling without requiring template changes. The :not()
   guards prevent this rule from leaking pill styles into dismiss buttons
   (.button) and icon-only toolbar buttons (.toolbar__button). */
button[type="submit"]:not(.button):not(.toolbar__button) {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    margin-top: var(--s-2);
    padding: 0.625rem 1.25rem;
    font-family: inherit;
    font-size: var(--text-base);
    font-weight: var(--w-semibold);
    color: var(--fg-on-brand);
    background-color: var(--brand);
    border: none;
    border-radius: var(--radius-pill);
    box-shadow: var(--shadow-brand);
    cursor: pointer;
    transition: background-color var(--dur-fast) var(--ease-out),
                color var(--dur-fast) var(--ease-out),
                transform var(--dur-fast) var(--ease-out),
                box-shadow var(--dur-base) var(--ease-out);
}

button[type="submit"]:not(.button):not(.toolbar__button):hover {
    background-color: var(--brand-hover);
}

button[type="submit"]:not(.button):not(.toolbar__button):active {
    background-color: var(--brand-press);
    transform: scale(0.98);
}

button[type="submit"]:not(.button):not(.toolbar__button):focus-visible {
    outline: none;
    box-shadow: var(--focus-ring), var(--shadow-brand);
}

button[type="submit"]:not(.button):not(.toolbar__button) + a {
    margin-left: var(--s-4);
}

/* ── Buttons ─────────────────────────────────────────────────────────────── */

.button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0.625rem 1.25rem;
    font-family: inherit;
    font-size: var(--text-base);
    font-weight: var(--w-semibold);
    border-radius: var(--radius-pill);
    cursor: pointer;
    transition: background-color var(--dur-fast) var(--ease-out),
                color var(--dur-fast) var(--ease-out),
                transform var(--dur-fast) var(--ease-out),
                box-shadow var(--dur-base) var(--ease-out);
    text-decoration: none;
    border: none;
}

.button:focus-visible {
    outline: none;
}

.button--sm {
    padding: 0.5rem 1rem;
    font-size: var(--text-sm);
}

.button--primary {
    color: var(--fg-on-brand);
    background-color: var(--brand);
    box-shadow: var(--shadow-brand);
}

.button--primary:hover {
    background-color: var(--brand-hover);
    color: var(--fg-on-brand);
}

.button--primary:active {
    background-color: var(--brand-press);
    transform: scale(0.98);
}

.button--primary:focus-visible {
    box-shadow: var(--focus-ring), var(--shadow-brand);
}

/* The secondary button uses a transparent fill so it reads as a lower-emphasis
   action alongside a primary button. The border provides enough affordance that
   it still reads as interactive without competing visually. */
.button--secondary {
    color: var(--fg-1);
    background-color: transparent;
    border: 1.5px solid var(--border-strong);
}

.button--secondary:hover {
    background-color: var(--ink-100);
    color: var(--fg-1);
}

.button--secondary:active {
    background-color: var(--ink-150);
    transform: scale(0.98);
}

.button--secondary:focus-visible {
    box-shadow: var(--focus-ring);
}

/* ── Table ───────────────────────────────────────────────────────────────── */

.table {
    width: 100%;
    border-collapse: collapse;
    background-color: var(--bg-elevated);
}

.table th,
.table td {
    padding: var(--s-3) var(--s-4);
    text-align: left;
    border-bottom: 1px solid var(--border);
}

/* Header cells use a smaller, slightly muted style to visually separate them
   from data rows without adding a background or outer border. */
.table th {
    font-size: var(--text-sm);
    font-weight: var(--w-semibold);
    color: var(--fg-1);
}

.table td {
    color: var(--fg-2);
}

/* Category header rows span all columns and use a light tint to visually
   group the rows beneath them. */
.table__category-header {
    background-color: var(--bg-sunken);
}

/* ── Card ────────────────────────────────────────────────────────────────── */

.card {
    background-color: var(--bg-elevated);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    padding: var(--s-5);
    box-shadow: var(--shadow-sm);
}

@media (min-width: 640px) {
    .card {
        padding: var(--s-6);
    }
}

/* Interactive cards (e.g. clickable list items) get a hover shadow to signal
   they are actionable. Non-interactive cards stay flat to avoid false affordance. */
.card--interactive:hover {
    box-shadow: var(--shadow-md);
}

.card__header {
    padding-bottom: var(--s-4);
    border-bottom: 1px solid var(--border);
    margin-bottom: var(--s-4);
}

.card__title {
    font-size: var(--text-lg);
    font-weight: 700;
}

.card__content {
    color: var(--fg-2);
}

/* The global reset strips padding/margin from all elements, which causes list
   markers to render outside the card boundary. Restore standard indentation
   for prose content rendered inside cards (e.g. the assessment HTML). */
.card__content ul,
.card__content ol {
    padding-left: 1.5em;
    margin-bottom: var(--s-4);
}

.card__content li + li {
    margin-top: var(--s-1);
}

.card__content table {
    width: 100%;
    border-collapse: collapse;
}

.card__content th,
.card__content td {
    padding: var(--s-3) var(--s-4);
    text-align: left;
    border-bottom: 1px solid var(--border);
}

.card__content th {
    font-size: var(--text-sm);
    font-weight: 600;
    color: var(--fg-3);
}

/* ── Flash messages ──────────────────────────────────────────────────────── */

/* Django messages framework renders one message per item. We display them
   as a stacked list just below the nav, before the page content. */
.messages {
    list-style: none;
    margin: 0;
    padding: 0;
}

.message {
    padding: var(--s-3) var(--s-6);
    font-size: var(--text-sm);
    font-weight: 500;
    border-left: 4px solid transparent;
}

.message--success {
    background-color: var(--success-100);
    color: var(--success-500);
    border-left-color: var(--success-500);
}

.message--error {
    background-color: var(--danger-100);
    color: var(--danger-500);
    border-left-color: var(--danger-500);
}

.message--warning {
    background-color: var(--warning-100);
    color: var(--warning-500);
    border-left-color: var(--warning-500);
}

.message--info {
    background-color: var(--info-100);
    color: var(--info-500);
    border-left-color: var(--info-500);
}

/* ── Error and help text ─────────────────────────────────────────────────── */

/* Django renders field errors as a <ul class="errorlist"> immediately before
   the input. */
.errorlist {
    list-style: none;
    margin: 0;
    padding: 0;
}

.errorlist li {
    font-size: var(--text-sm);
    color: var(--danger-500);
    margin-top: var(--s-1);
}

/* Django renders help text as a <span class="helptext"> after the input. */
.helptext {
    font-size: var(--text-sm);
    color: var(--fg-3);
    margin-top: 0.2rem;
}

/* ── Important biomarker cards ───────────────────────────────────────────── */

.biomarker-cards {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
    gap: var(--s-4);
}

.biomarker-cards__empty {
    color: var(--fg-3);
}

.biomarker-card {
    display: flex;
    flex-direction: column;
    gap: var(--s-2);
    background-color: var(--bg-elevated);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    padding: var(--s-4);
    color: var(--fg-2);
    box-shadow: var(--shadow-sm);
    transition: border-color var(--dur-fast) var(--ease-out),
                box-shadow var(--dur-fast) var(--ease-out);
    position: relative;
}

.biomarker-card:hover {
    border-color: var(--border-brand);
    box-shadow: var(--shadow-md);
    color: var(--fg-2);
}

/* Card background encodes trend: is this biomarker getting better or worse?
   Value text color (in-range/out-of-range) separately encodes current status. */
.biomarker-card--improving {
    background-color: var(--sage-100);
    border-color: var(--sage-200);
    border-left: 4px solid var(--sage-500);
}

.biomarker-card--worsening {
    background-color: var(--peach-100);
    border-color: var(--peach-200);
    border-left: 4px solid var(--danger-500);
}

.biomarker-card__name {
    font-size: var(--text-sm);
    font-weight: var(--w-semibold);
    color: var(--fg-3);
}

.biomarker-card__body {
    display: flex;
    align-items: baseline;
    gap: var(--s-2);
}

.biomarker-card__value {
    font-size: var(--text-lg);
    font-weight: var(--w-bold);
}

.biomarker-card__value--in-range {
    color: var(--success-500);
}

.biomarker-card__value--out-of-range {
    color: var(--danger-500);
}

.biomarker-card__previous {
    font-size: var(--text-sm);
}

.biomarker-card__previous--in-range {
    color: var(--success-500);
}

.biomarker-card__previous--out-of-range {
    color: var(--danger-500);
}

.biomarker-card__footer {
    margin-top: auto;
    display: flex;
    justify-content: space-between;
    align-items: flex-end;
}

.biomarker-card__range {
    font-size: var(--text-sm);
    color: var(--fg-3);
    margin-left: auto;
}

/* Transparent overlay makes the entire card clickable for owners
   without wrapping interactive popover elements in an <a>. */
.biomarker-card__overlay-link {
    position: absolute;
    inset: 0;
    z-index: 1;
}

/* ── Trend list ──────────────────────────────────────────────────────────── */

.trend-list {
    display: flex;
    flex-wrap: wrap;
    gap: var(--s-2);
    margin-bottom: var(--s-6);
}

.trend-list__item {
    display: inline-block;
    padding: var(--s-2) var(--s-4);
    background-color: var(--bg-elevated);
    border: 1px solid var(--border);
    border-radius: 6px;
    font-size: var(--text-sm);
    font-weight: 500;
    color: var(--fg-2);
    text-decoration: none;
    transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

.trend-list__item:hover {
    border-color: var(--brand);
    box-shadow: 0 0 0 3px rgba(245, 126, 88, 0.15);
    color: var(--fg-2);
}

.trend-list__empty {
    color: var(--fg-3);
}

/* ── Drop zone upload UI ─────────────────────────────────────────────────── */

.drop-zone {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: var(--s-2);
    padding: var(--s-8) var(--s-6);
    background-color: var(--bg-elevated);
    border: 2px dashed var(--border);
    border-radius: 6px;
    cursor: pointer;
    text-align: center;
    transition: border-color 0.15s ease, background-color 0.15s ease;
}

.drop-zone:hover,
.drop-zone:focus-visible {
    border-color: var(--brand);
    background-color: rgba(245, 126, 88, 0.04);
    outline: none;
}

/* Highlighted state while a drag is in progress over the zone. */
.drop-zone--active {
    border-color: var(--brand);
    background-color: rgba(245, 126, 88, 0.08);
}

/* Inert state once uploading has started — no pointer interaction allowed. */
.drop-zone--disabled {
    pointer-events: none;
    opacity: 0.4;
    cursor: default;
}

.drop-zone__prompt {
    font-size: var(--text-base);
    font-weight: 500;
    color: var(--fg-2);
    margin-bottom: 0;
}

.drop-zone__browse-link {
    color: var(--brand-hover);
    text-decoration: underline;
}

.drop-zone__hint {
    font-size: var(--text-sm);
    color: var(--fg-3);
    margin-bottom: 0;
}

/* The real file input is visually hidden; the drop zone acts as its proxy. */
.drop-zone__input {
    display: none;
}

/* ── File list ───────────────────────────────────────────────────────────── */

.file-list {
    list-style: none;
    margin-top: var(--s-4);
    display: flex;
    flex-direction: column;
    gap: var(--s-3);
}

.file-list__item {
    display: grid;
    /* name takes remaining space; size and status are fixed-width enough to
       not need explicit sizing — auto handles them. */
    grid-template-columns: 1fr auto auto;
    grid-template-rows: auto auto;
    align-items: center;
    column-gap: var(--s-3);
    row-gap: var(--s-1);
    padding: var(--s-3) var(--s-4);
    background-color: var(--bg-elevated);
    border: 1px solid var(--border);
    border-radius: 6px;
}

.file-list__item--success {
    border-color: var(--sage-200);
    background-color: var(--success-100);
}

.file-list__item--error {
    border-color: var(--peach-200);
    background-color: var(--danger-100);
}

.file-list__name {
    font-size: var(--text-sm);
    font-weight: 500;
    /* Prevent very long filenames from breaking the layout. */
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.file-list__size {
    font-size: var(--text-sm);
    color: var(--fg-3);
    white-space: nowrap;
}

.file-list__status {
    font-size: var(--text-sm);
    white-space: nowrap;
}

.file-list__item--success .file-list__status {
    color: var(--success-500);
}

.file-list__item--error .file-list__status {
    color: var(--danger-500);
}

/* Progress bar spans the full width below the filename row. */
.file-list__progress-wrap {
    grid-column: 1 / -1;
    height: 4px;
    background-color: var(--border);
    border-radius: 2px;
    overflow: hidden;
}

.file-list__progress-bar {
    height: 100%;
    background-color: var(--brand);
    border-radius: 2px;
    transition: width 0.1s linear;
}

/* ── Upload actions / done links ──────────────────────────────────────────── */

.upload-actions {
    margin-top: var(--s-6);
}

.upload-done {
    margin-top: var(--s-6);
}

/* ── Trend chart ─────────────────────────────────────────────────────────── */

.trend-chart-container {
    background-color: var(--bg-elevated);
    border: 1px solid var(--border);
    border-radius: 6px;
    padding: var(--s-6);
    margin-top: var(--s-4);
}

.trend-chart {
    /* cursor: grab signals that the chart is pannable. */
    cursor: grab;
}

.trend-chart:active {
    cursor: grabbing;
}

/* ── Toolbar ─────────────────────────────────────────────────────────────── */

.toolbar {
    display: flex;
    align-items: center;
    gap: var(--s-1);
}

button.toolbar__button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2rem;
    height: 2rem;
    padding: 0;
    margin: 0;
    margin-top: 0;
    font-size: inherit;
    background: none;
    border: 1px solid transparent;
    border-radius: 4px;
    cursor: pointer;
    color: var(--fg-3);
    transition: color 0.15s ease, border-color 0.15s ease;
}

button.toolbar__button:hover {
    color: var(--fg-2);
    border-color: var(--border);
}

button.toolbar__button:focus-visible {
    outline: none;
    box-shadow: var(--focus-ring);
}

/* ── Pill badges ─────────────────────────────────────────────────────────── */

.pill {
    display: inline-block;
    padding: 0.1rem 0.5rem;
    font-size: var(--text-sm);
    font-weight: 600;
    line-height: 1.4;
    border-radius: 999px;
    vertical-align: middle;
    margin-left: var(--s-2);
}

.pill--public {
    background-color: var(--danger-100);
    color: var(--danger-500);
}

/* ── Range bar (blood test detail table) ─────────────────────────────────── */

/* The range bar column is narrower than the other columns because the bar
   itself is a compact visual; it does not need the same padding. */
.table__range-cell {
    width: 160px;
    min-width: 120px;
    padding-top: var(--s-2);
    padding-bottom: var(--s-2);
}

/* Container track. Rounded ends are applied selectively via modifier classes
   so that only sides with a definite reference bound get a pill shape — sides
   where the bound was defaulted (not present in the data) stay square to
   signal that the axis extends beyond the data. */
.range-bar {
    position: relative;
    height: 8px;
    background-color: var(--ink-100);
    border: 1px solid var(--border);
    border-radius: 0;
    overflow: visible;
}

.range-bar--round-left {
    border-top-left-radius: 999px;
    border-bottom-left-radius: 999px;
}

.range-bar--round-right {
    border-top-right-radius: 999px;
    border-bottom-right-radius: 999px;
}

/* Inner track clips the green bar to the container's rounded corners. The
   marker sits outside this element so it can overflow the track boundary. */
.range-bar__track {
    position: absolute;
    inset: 0;
    overflow: hidden;
    border-radius: inherit;
}

/* Sage in-range section. Straight edges on both sides — rounding is handled
   by the parent .range-bar__track clipping to the container shape. */
.range-bar__green {
    position: absolute;
    top: 0;
    height: 100%;
    background-color: var(--sage-300);
    border-radius: 0;
}

/* Marker: downward-pointing triangle sitting above a vertical line. The
   triangle is rendered via a CSS border trick on a zero-width element. The
   vertical line extends downward from the triangle tip to the bar track. */
.range-bar__marker {
    position: absolute;
    top: -6px;
    /* Center the marker on its position by shifting left half the triangle width. */
    transform: translateX(-50%);
    width: 0;
    height: 0;
    /* Downward-pointing triangle: 5px wide, 6px tall. */
    border-left: 5px solid transparent;
    border-right: 5px solid transparent;
    border-top: 6px solid var(--fg-1);
}

/* Vertical stem below the triangle tip, drawn as an ::after pseudo-element. */
.range-bar__marker::after {
    content: "";
    position: absolute;
    /* Align the stem with the triangle tip (top of the border-top). */
    top: -6px;
    left: -1px;
    width: 2px;
    /* Stem height: triangle height (6px) + bar track height (8px). */
    height: 14px;
    background-color: var(--fg-1);
}

/* ── Info-icon popover ───────────────────────────────────────────────────── */

/*
 * Markup contract (see static/js/popover.js for full documentation):
 *
 *   <span class="info-icon-wrap">
 *     <button class="info-icon" data-popover-id="…" aria-label="About …"
 *             aria-expanded="false" aria-controls="…" type="button">
 *       <!-- SVG -->
 *     </button>
 *     <div id="…" class="info-popover" aria-label="…" hidden>
 *       <button class="info-popover__close" aria-label="Close" type="button">…</button>
 *       <!-- pre-rendered explainer HTML -->
 *     </div>
 *   </span>
 */

/* Wrapper keeps the icon inline with the biomarker name link. */
.info-icon-wrap {
    display: inline-flex;
    align-items: center;
    vertical-align: middle;
    margin-left: var(--s-1);
}

/* The icon button itself: no chrome, comfortable tap target (~24px).
   position+z-index elevate the button above .biomarker-card__overlay-link.
   The elevation is on the button (not the wrapper) so the wrapper does NOT
   create a stacking context — otherwise the descendant .info-popover would
   be trapped inside it and stack below sibling wrappers' icons. */
.info-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.5rem;   /* 24px tap target */
    height: 1.5rem;
    padding: 0;
    background: none;
    border: none;
    border-radius: var(--radius-pill);
    cursor: pointer;
    color: var(--info-500);
    opacity: 0.7;
    transition: opacity var(--dur-fast) var(--ease-out),
                color var(--dur-fast) var(--ease-out);
    flex-shrink: 0;
    position: relative;
    z-index: 2;
}

.info-icon:hover,
.info-icon[aria-expanded="true"] {
    opacity: 1;
    color: var(--info-500);
}

.info-icon:focus-visible {
    outline: none;
    box-shadow: var(--focus-ring);
}

.info-icon svg {
    width: 1rem;
    height: 1rem;
    pointer-events: none;
}

/* The popover panel: fixed-positioned so it escapes any overflow:hidden
   ancestors and is positioned relative to the viewport. JS sets top/left. */
.info-popover {
    position: fixed;
    z-index: 200;
    max-width: min(480px, calc(100vw - 1rem));
    max-height: min(480px, calc(100vh - 2rem));
    overflow-y: auto;
    background-color: var(--bg-elevated);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-lg);
    padding: var(--s-4);
}

/* Close button in the top-right corner of the popover. */
.info-popover__close {
    position: absolute;
    top: var(--s-2);
    right: var(--s-2);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.5rem;
    height: 1.5rem;
    padding: 0;
    background: none;
    border: none;
    border-radius: var(--radius-pill);
    cursor: pointer;
    color: var(--fg-3);
    font-size: var(--text-base);
    line-height: 1;
    transition: color var(--dur-fast) var(--ease-out);
}

.info-popover__close:hover {
    color: var(--fg-1);
}

.info-popover__close:focus-visible {
    outline: none;
    box-shadow: var(--focus-ring);
}

/* Prose content inside the popover (rendered Markdown). */
.info-popover__content {
    padding-top: var(--s-1);
    font-size: var(--text-sm);
    color: var(--fg-2);
    line-height: var(--leading-relaxed);
}

.info-popover__content h3 {
    font-size: var(--text-sm);
    font-weight: var(--w-semibold);
    color: var(--fg-1);
    margin-top: var(--s-4);
    margin-bottom: var(--s-1);
}

.info-popover__content h3:first-child {
    margin-top: 0;
}

.info-popover__content p {
    margin-bottom: var(--s-2);
}

.info-popover__content p:last-child {
    margin-bottom: 0;
}

.info-popover__content ul,
.info-popover__content ol {
    padding-left: 1.25em;
    margin-bottom: var(--s-2);
}

/* Visibility utilities. Use the 640px breakpoint established for .card. */
@media (max-width: 639px) {
    .hide-on-mobile {
        display: none;
    }
}
@media (min-width: 640px) {
    .show-on-mobile {
        display: none;
    }
}
