/* MemoryProof — calm, accessible design system.
   Accessible by construction (large type, high contrast, big targets) WITHOUT being
   marketed as a medical/elderly product (guardrail G1). */

:root {
  /* iPhone status bar / home indicator. Named so layout can be tested with a forced value. */
  --sat: env(safe-area-inset-top, 0px);
  --sab: env(safe-area-inset-bottom, 0px);

  /* ── the brand, exactly as in the founder's vector file (assets/brand/memoryproof-logo.svg; research/brand-2026-09-28/
     dark-theme-brief.md): navy #12242E, gold = a top-to-bottom gradient #F1E1BF → #B6A172, wordmark #FFFFFF. The solid
     points are for things too thin to carry the gradient. ── */
  --navy: #12242e;
  --gold-grad: linear-gradient(180deg, #f1e1bf 0%, #b6a172 100%);
  --gold-top: #f1e1bf; --gold-25: #e1d0aa; --gold-mid: #d2bf97; --gold-75: #c2af82; --gold-bottom: #b6a172;

  /* ── dark theme (default) — the logo's world: everything structural in navies of the logo's own hue (201°), lifted a
     little for surfaces and separated by gold-tinted hairlines instead of shadows; the gold itself only on a few chosen
     elements (brand mark, primary button, Today ring, active tab, chosen option, main chart line, eyebrow labels).
     Every text colour reaches 4.5:1 on the surfaces it sits on (measured in the running app). ── */
  --bg: #12242e;
  --bg-2: #1c3441;       /* fields, tag buttons, tracks */
  --card: #162b36;
  --card-2: #1a313d;
  --lift: #213b49;       /* a chosen option's surface (with the gold outline) */
  --line: rgba(241,225,191,.10);
  --ink-head: #ffffff;   /* headings — the wordmark's white */
  --ink: #f2ede4;        /* body — a warm off-white */
  --ink-2: #afc1ca;      /* secondary — a cool grey-blue from the navy */
  --ink-3: #96abb6;      /* tertiary — ≥ 4.5:1 on every surface, incl. --lift */
  --eyebrow: var(--gold-mid);   /* the small uppercase labels */
  --accent: #a6c3d3;     /* a quiet light steel of the navy's hue: icons, dots, week strip, test highlights — NOT gold */
  --accent-2: #83a6b9;
  --accent-3: #a4b2ea;   /* secondary data line (sleep) — periwinkle, clear of the gold score line */
  --accent-soft: #c7dbe6;
  --warn: #e9b48b;       /* disclaimers — a soft apricot, clear of the gold */
  /* TEXT and FILL variants of the accents. --accent/--accent-2 stay the colour of lines, rings, dots and icons;
     text drawn in an accent colour uses the *-ink variant, and a surface that carries --on-accent text uses the
     *-fill variant, so both reach 4.5:1 (WCAG AA). In the dark theme they are the accents themselves. */
  --accent-ink: var(--accent);
  --accent-2-ink: #a8cde1;   /* links */
  --accent-fill: var(--accent);
  --accent-2-fill: var(--accent-2);
  --warn-ink: var(--warn);
  --cap-neg: #9eabb3;    /* "below your usual range" caption: calm, distinct from the accent, never alarming */
  --neg-ink: #df9690;    /* a study row marked "negative" in the library */
  --danger: #e69994;
  --tap-bg: var(--ink-2);   /* the weekly picture test's neutral "tapped" flash (says nothing about right or wrong) */
  --tap-ink: var(--card);
  --chart-b: #7dc5c0;   /* memory 2nd line (mean trials) — a sea green, clear of the gold score line */
  --baseline-trailing: #d59ad0;   /* trailing 30-day average reference line — mauve, distinct from the grey initial baseline */
  --chart-main: var(--gold-mid);  /* legend swatches of the main line and its band */
  --chev: #7f949f;       /* chevrons (non-text, ≥ 3:1) */
  /* the primary action: the gold gradient with navy text (12.3:1 at the top, 6.3:1 at the bottom) */
  --primary-grad: var(--gold-grad);
  --on-primary: var(--navy);
  --primary-shadow: 0 8px 22px -14px rgba(241,225,191,.45);   /* the one, barely-there lift */
  /* evidence-grade colours (library) — four DISTINCT hues, theme-aware, visible on dark & pale */
  --ev-none: #9aa7b0; --ev-weak: #e28d83; --ev-mixed: #e7a46a; --ev-strong: #77c59e;
  /* the same grades as TEXT (the grade word on a badge) */
  --ev-none-ink: var(--ev-none); --ev-weak-ink: var(--ev-weak); --ev-mixed-ink: var(--ev-mixed); --ev-strong-ink: var(--ev-strong);
  --radius: 20px;
  --maxw: 720px;
  --font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  /* themeable surfaces (overridden wholesale in [data-theme="light"]) */
  --bg-grad: linear-gradient(180deg, #152a35 0px, var(--bg) 460px);   /* a hint of depth at the top, nothing more */
  --card-grad: linear-gradient(180deg, rgba(241,225,191,.018), rgba(241,225,191,0));
  --hairline: rgba(241,225,191,.18);
  --elev: 0 0 0 0 transparent;
  --elev-hero: 0 0 0 0 transparent;
  --inset-hi: inset 0 1px 0 rgba(255,255,255,.025);
  --glass: #12242e;   /* the fixed bars' surface — OPAQUE so their text keeps ClearType (see .nav) */
  --surf-hi: rgba(241,225,191,.035);
  --surf-hi-2: rgba(241,225,191,.06);
  --track-center: rgba(175,193,202,.34);
  --on-accent: var(--navy);
  --accent-glow: transparent;   /* no glows */
  --hero-grad: linear-gradient(180deg, var(--card-2), var(--card));
  --hero-border: rgba(241,225,191,.12);
  --hero-glow: rgba(166,195,211,.16);   /* the soft ring around today's dot in the week strip */
  --chart-panel: rgba(241,225,191,.012);
  --chart-panel-stroke: rgba(241,225,191,.06);
  --chart-grid: rgba(241,225,191,.05);
  --gl-stroke: #afc1ca;
  --warn-bg: rgba(233,180,139,.06);
  --warn-bd: rgba(233,180,139,.26);
  /* the icon badge used app-wide: a faint lift of the navy, a hairline instead of a shadow */
  --badge: radial-gradient(135% 135% at 32% 22%, rgba(166,195,211,.15), rgba(166,195,211,.05) 55%, rgba(255,255,255,.01) 100%);
  --badge-shadow: inset 0 1px 0 rgba(241,225,191,.10), inset 0 0 0 1px rgba(241,225,191,.06);
}

/* The light theme's tokens live at the end of this file (after the gold rules they restyle). */

* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; overflow-x: hidden; max-width: 100%; }
/* The canvas behind the page in the theme's own colour, so a short tab (e.g. Experiments) and the iOS
   overscroll bounce never show bare white under the bottom tab bar. */
html { background-color: var(--bg); }
body {
  background: var(--bg-grad);
  background-attachment: fixed;
  /* Every tab fills the screen, short ones included, so the bottom tab bar always sits on a full page
     (100dvh where supported tracks the phone's real viewport as browser bars collapse). */
  min-height: 100vh;
  min-height: 100dvh;
  color: var(--ink);
  font-family: var(--font);
  font-size: 1.0625rem;   /* 17px at the default root size; relative so the text-size setting scales it */
  line-height: 1.5;
  padding-bottom: calc(var(--navh, 92px) + 8px);
  transition: background-color .25s ease, color .25s ease;
}

/* The page runs under the status bar (viewport-fit=cover), so the top row must clear the clock and
   the notch when Baseline is installed to the Home Screen. env() is 0 in a normal browser tab. */
#app { max-width: var(--maxw); margin: 0 auto; padding: max(22px, calc(var(--sat) + 8px)) 18px 8px; }

h1, h2, h3 { line-height: 1.2; margin: 0 0 .28em; color: var(--ink-head); }
h1 { font-size: 1.9rem; letter-spacing: -0.02em; }
h2 { font-size: 1.3rem; }
h3 { font-size: 1.05rem; }
p { margin: 0 0 1em; color: var(--ink-2); }
a { color: var(--accent-2-ink); }
/* The two privacy-notice links carry an inline accent colour inside their (frozen, pending review) texts;
   their text colour must still reach 4.5:1. */
a.privlink, a.privlink2 { color: var(--accent-ink) !important; }
small { color: var(--ink-3); }

/* The brand line: the logo's gold brain (dark theme: on the page itself; light theme: on a small navy tile, the app
   icon), then the real wordmark — the vector letters of assets/brand/wordmark.svg used as a mask, so they take the
   text colour (white on navy, the ink on the light theme). The name is also there as text for screen readers and
   copy/paste (.brand-word, visually hidden). */
.brand { display: flex; align-items: center; gap: 10px; margin-bottom: 10px; }
.brand .mark {
  width: 32px; height: 32px; flex: 0 0 auto; display: inline-block;
  background: url(assets/brand/mark.svg) center / contain no-repeat;
}
[data-theme="light"] .brand .mark { width: 30px; height: 30px; border-radius: 8px; background-image: url(assets/brand/icon.svg); }
.brand .name { font-weight: 700; letter-spacing: -0.01em; font-size: 1.15rem; display: inline-flex; align-items: center; gap: 7px; min-width: 0; }
.brand .wordmark {
  flex: 0 0 auto; display: inline-block; width: 7.2em; height: 1.22em; color: var(--ink-head); background: currentColor;
  -webkit-mask: url(assets/brand/wordmark.svg) left center / contain no-repeat; mask: url(assets/brand/wordmark.svg) left center / contain no-repeat;
}
.brand .brand-tag { color: var(--ink-3); font-weight: 500; font-size: .8em; letter-spacing: .01em; }
/* The logo line: beside the wordmark when all of it fits on this screen at this text size, otherwise on its own line
   directly under the logo, left-aligned — never cut. CSS alone decides, so it is right from the first paint and after
   every resize, rotation, text-size or language change: the brand row wraps, and the line is one flex item that stays
   on the first row only when it fits whole (a line too long even for its own row wraps inside it). Its "·" sits in
   the item's own left padding, which the same negative margin pulls back: beside the wordmark it shows; at the start
   of the second row it lies outside the brand's box and is clipped. */
.brand:not(.brand-hero) { flex-wrap: wrap; row-gap: 2px; overflow: hidden; }
.brand:not(.brand-hero) .name { display: contents; }
.brand:not(.brand-hero) .wordmark { margin-right: calc(.44em - 3px); }  /* + the 10px gap: 7px to the "·" (.55em of the line = .44em here) */
.brand:not(.brand-hero) .brand-tag { position: relative; padding-left: .55em; margin-left: -.55em; }
.brand:not(.brand-hero) .brand-sep { position: absolute; left: 0; top: 0; }
.brand-word, .sr-only, .brand-hero .brand-sep {
  position: absolute !important; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden;
  clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; border: 0;
}
/* the account screen: the full logo, mark above wordmark — the first impression */
.brand.brand-hero { flex-direction: column; gap: 14px; margin: 4px 0 26px; text-align: center; }
.brand.brand-hero .mark { width: 76px; height: 76px; }
[data-theme="light"] .brand.brand-hero .mark { width: 72px; height: 72px; border-radius: 18px; }
.brand.brand-hero .name { flex-direction: column; gap: 8px; }
.brand.brand-hero .wordmark { width: 13.5em; height: 2.3em; -webkit-mask-position: center; mask-position: center; }
/* never wider than the screen: at 320 px with extra-large text the wordmark shrinks to fit (its letters scale, the mask
   is "contain"); every other size keeps 13.5em (v91b) */
.brand.brand-hero .name, .brand.brand-hero .wordmark { max-width: 100%; }
.brand.brand-hero .brand-tag { font-size: .9rem; letter-spacing: .02em; text-wrap: balance; }  /* a line too long for the screen wraps */

.card {
  position: relative;
  background: var(--card-grad), var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 22px;
  margin-bottom: 16px;
  box-shadow: var(--elev), var(--inset-hi);
  color: var(--ink);            /* <button class="card"> must not fall back to black ButtonText */
}
/* a tappable card uses the app font at the body size (a <button> otherwise falls back to the browser's
   13px system font, which also ignored the text-size setting) */
button.card { font: inherit; }
.card.tight { padding: 13px; }
/* subtle hairline highlight along the top edge for a crafted, premium feel */
.card::after {
  content: ""; position: absolute; left: 14px; right: 14px; top: 0; height: 1px; border-radius: 1px;
  background: linear-gradient(90deg, transparent, var(--hairline), transparent); pointer-events: none;
}
.card-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; }

.muted { color: var(--ink-3); }
.eyebrow { text-transform: uppercase; letter-spacing: .12em; font-size: .72rem; color: var(--eyebrow); margin-bottom: 4px;
  overflow-wrap: break-word; hyphens: auto; }   /* a long German word at 320 px breaks (e1b) */

/* buttons */
/* A tap is a tap: `manipulation` drops the browser's double-tap-to-zoom wait, which otherwise
   swallows the second of two fast taps (the speed test's whole interaction). Pinch-zoom and
   scrolling are unaffected, so nothing about accessibility is lost. */
button, a, input, select, textarea, label, [role="button"] {
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
}
.btn {
  appearance: none; border: 1px solid var(--line); background: var(--card-2);
  color: var(--ink); font: inherit; font-weight: 600;
  padding: 13px 18px; border-radius: 12px; cursor: pointer;
  transition: box-shadow .05s ease, border-color .2s ease, background .2s ease;
  min-height: 48px;
}
.btn:hover { border-color: var(--accent); }
/* Press feedback must never MOVE the element. A `transform: scale()` shrinks the button out from
   under the finger, the tap then lands on whatever is behind it and the click is silently lost.
   A translucent inset overlay reads as a press on both themes and leaves the hit box untouched. */
.btn:active:not(:disabled) { box-shadow: inset 0 0 0 999px rgba(128,128,128,.16); }
.btn.primary:active:not(:disabled) { filter: brightness(1.05); box-shadow: none; }
/* the primary action: the logo's gold gradient with navy text, in both themes */
.btn.primary { background: var(--primary-grad); color: var(--on-primary); border: none; box-shadow: var(--primary-shadow); }
.btn.ghost { background: transparent; }
.btn.block { width: 100%; }
.btn.sm { padding: 9px 13px; min-height: 44px; font-size: .9rem; }
.btn-row { display: flex; gap: 10px; flex-wrap: wrap; }
.btn.danger { color: var(--danger); border-color: rgba(230,153,148,.34); }
[data-theme="light"] .btn.danger { border-color: rgba(176,46,60,.35); }
/* profile avatar */
.avatar {
  width: 54px; height: 54px; border-radius: 50%; flex: 0 0 auto;
  display: flex; align-items: center; justify-content: center;
  font-weight: 700; font-size: 1.35rem; color: var(--on-accent);
  background: linear-gradient(135deg, var(--accent-fill), var(--accent-2-fill)); box-shadow: var(--badge-shadow);
}
/* consent checkboxes + inline error text */
.check { display: flex; gap: 10px; align-items: flex-start; margin: 11px 0 0; font-size: .85rem; color: var(--ink-2); cursor: pointer; line-height: 1.42; }
.check input[type="checkbox"] { width: 18px; height: 18px; margin: 1px 0 0; flex: 0 0 auto; accent-color: var(--accent); cursor: pointer; }
.danger { color: var(--danger); }

/* dashboard task tiles */
.tiles { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.tile {
  text-align: left; display: flex; flex-direction: column; gap: 6px;
  padding: 16px; border-radius: 14px; border: 1px solid var(--line);
  background: var(--card-2); cursor: pointer; color: var(--ink); font: inherit;
}
.tile:hover { border-color: var(--accent); }
.tile .t-ico { font-size: 1.4rem; }
.tile .t-name { font-weight: 700; }
.tile .t-sub { color: var(--ink-3); font-size: .82rem; }
.tile .t-last { color: var(--accent-ink); font-size: .82rem; font-weight: 600; }
.tile.feature { background: var(--card-2); border-color: var(--line); }
@media (max-width: 480px) { .tiles { grid-template-columns: 1fr; } }

/* form controls */
label.field { display: block; margin-bottom: 14px; }
label.field .lab { display: block; font-weight: 600; margin-bottom: 6px; }
input[type="text"], input[type="password"], input[type="email"], input[type="tel"],
input[type="search"], input[type="url"], input[type="number"], textarea, select {
  width: 100%; background: var(--bg-2); border: 1px solid var(--line);
  color: var(--ink); border-radius: 10px; padding: 12px; font: inherit;
}
textarea { min-height: 70px; resize: vertical; }
/* the 6-digit email code: one big, evenly spaced numeric field (easy to read, type and paste into) */
input.code-input {
  font-size: 1.9rem; font-weight: 700; letter-spacing: .4em; text-align: center; min-height: 64px;
  font-variant-numeric: tabular-nums; padding: 12px 12px 12px calc(12px + .4em);
}
.seg { display: flex; gap: 8px; flex-wrap: wrap; }
.seg button {
  flex: 1 1 auto; min-width: 56px; padding: 11px 10px; border-radius: 10px;
  border: 1px solid var(--line); background: var(--bg-2); color: var(--ink-2);
  font: inherit; cursor: pointer;
}
.seg button.on { background: var(--accent-fill); color: var(--on-accent); border-color: transparent; font-weight: 700; }
/* e1d: the sign-up's 18+ box (js/app.js ageQuestion; one box since 2026-10-03, 18+ everywhere) — at least a finger tall */
.age-q { margin: 0 0 14px; min-height: 44px; align-items: center; }

.chips { display: flex; flex-wrap: wrap; gap: 8px; }
/* a tag button: the app font, and at least 44px tall at every text size (a finger-sized target) */
.chip {
  display: inline-flex; align-items: center; min-height: 44px;
  padding: 9px 13px; border-radius: 999px; border: 1px solid var(--line);
  background: var(--bg-2); color: var(--ink-2); cursor: pointer;
  font-family: var(--font); font-size: .92rem; line-height: 1.25;
}
.chip.on { background: var(--accent-2-fill); color: var(--on-accent); border-color: transparent; font-weight: 600; }
.chip-i { display: inline-flex; vertical-align: -2px; margin-left: 6px; opacity: .5; }
.chip-i:hover { opacity: 1; }
.chip.on .chip-i { opacity: .8; }
/* the small group headings inside the tag picker (Supplements / Activities / Your routines) */
.tag-group-head { color: var(--ink-3); font-size: .7rem; text-transform: uppercase; letter-spacing: .1em; }
/* routines (js/routines.js): one tap logs a named set of tags; a second tap takes them off again */
.routines-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin: 0 0 6px; }
.routines { display: flex; flex-wrap: wrap; gap: 8px; }
.routine {
  display: flex; flex-direction: column; justify-content: center; align-items: flex-start; gap: 1px;
  min-height: 44px; max-width: 100%; padding: 7px 14px; border-radius: 14px; text-align: left;
  border: 1px solid var(--line); background: var(--bg-2); color: var(--ink); font: inherit; cursor: pointer;
}
.routine:hover { border-color: var(--accent); }
.routine.on { background: var(--accent-2-fill); color: var(--on-accent); border-color: transparent; }
.routine .r-name { font-weight: 700; font-size: .92rem; }
.routine .r-tags { font-size: .76rem; opacity: .8; overflow-wrap: anywhere; }
.routine-edit-row { padding: 10px 0; border-bottom: 1px solid var(--line); }
/* Today: tag the day (js/log.js App.todayTagCard). One tap saves a tag, a second tap takes it off; a small
   Today | Yesterday switch picks the day; "Day complete" records that nothing is missing. */
.tagday-head { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 10px; margin: 0 0 10px; }
.tagday-head .eyebrow { margin: 0; }
.dayswitch { display: inline-flex; flex: 0 0 auto; padding: 2px; border: 1px solid var(--line); border-radius: 999px; background: var(--bg-2); }
.dayswitch button {
  min-height: 44px; min-width: 44px; padding: 0 14px; border: none; border-radius: 999px;
  background: none; color: var(--ink-2); font: inherit; font-size: .86rem; cursor: pointer;
}
.dayswitch button.on { background: var(--accent-fill); color: var(--on-accent); font-weight: 700; }
.tagday .routines { margin-top: 8px; }
.tagday-actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 10px; }
.tagday-note { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-top: 8px; font-size: .86rem; color: var(--ink-2); }
.daydone { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--line); }
.daydone-label { font-weight: 700; color: var(--accent-ink); }

/* check-in: 1–10 sleep rating row + result popup. Five per row at any width, so the numbers never
   wrap into a stretched half-width leftover. */
.rate-row { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 6px; }
.rate-btn {
  padding: 12px 0; border-radius: 12px;
  border: 1px solid var(--line); background: var(--bg-2); color: var(--ink);
  cursor: pointer; font-size: 1rem; font-weight: 600; font-family: var(--font);
}
.rate-btn:hover { border-color: var(--accent); color: var(--accent-ink); }
.rate-btn.on { background: var(--accent-fill); color: var(--on-accent); border-color: transparent; }
.result-score { font-size: 2.2rem; font-weight: 800; color: var(--ink); margin: 6px 0 0; line-height: 1.1; }
/* what a score means on its OWN scale (e.g. the weekly test's chance level) — sits right under the number */
.score-cap { font-size: .82rem; margin-top: -6px; }

/* task runner */
.runner {
  position: fixed; inset: 0; z-index: 50; overflow: hidden;
  background: var(--bg-grad);
  display: flex; flex-direction: column; text-align: center;
  padding: 14px 16px 24px;   /* literal first so the shorthand always applies (env enhancement below) */
}
@supports (padding: max(0px)) {
  .runner { padding-top: max(14px, var(--sat)); padding-bottom: max(24px, var(--sab)); }
}
.runner-top { display: flex; align-items: center; justify-content: flex-end; min-height: 38px; flex: 0 0 auto; width: 100%; }
.runner-prog { position: absolute; top: 0; left: 0; right: 0; height: 3px; background: var(--surf-hi-2); z-index: 1; }
.runner-prog-fill { height: 100%; background: linear-gradient(90deg, var(--accent), var(--accent-2)); border-radius: 0 3px 3px 0; transition: width .4s cubic-bezier(.4,0,.2,1); box-shadow: 0 0 8px var(--accent-glow); }
/* full-screen focused stage (no floating card / dead space); the runner backdrop IS the surface */
.runner .stage {
  flex: 1 1 auto; width: min(520px, 100%); margin: 0 auto; min-height: 0;
  display: flex; align-items: center; justify-content: center; flex-direction: column;
  gap: 16px; padding: 4px 2px 0; user-select: none;
}
.runner .stage.tap { cursor: pointer; }
/* a test's instructions: centred when they fit, scrolling from the top when they don't (a small phone at a large
   text size) — the runner itself never scrolls, so without this the Start button could end up off the screen */
.runner .stage.intro { justify-content: flex-start; overflow-y: auto; padding-bottom: 8px; }
.runner .stage.intro > :first-child { margin-top: auto; }
.runner .stage.intro > :last-child { margin-bottom: auto; flex: 0 0 auto; }
.runner .stage.intro > .btn { flex: 0 0 auto; }   /* Start keeps its full height with the one-line "About this test" under it (v92-sci) */
/* completion (saved / practice) screen: scrollable body + pinned primary action, so the Done button
   is always in view on a small phone without pulling the screen down. The body is centred when it fits and scrolls
   from its top when it doesn't (auto margins, as .stage.intro — plain centring would cut its top off, out of reach). */
.runner .stage.result { justify-content: stretch; gap: 10px; }
.runner .stage.result .result-scroll {
  flex: 1 1 auto; min-height: 0; width: 100%; overflow-y: auto;
  display: flex; flex-direction: column; align-items: center; justify-content: flex-start; gap: 12px;
}
.runner .stage.result .result-scroll > :first-child { margin-top: auto; }
.runner .stage.result .result-scroll > :last-child { margin-bottom: auto; }
.runner .stage.result .result-foot {
  flex: 0 0 auto; width: 100%; display: flex; justify-content: center; padding-top: 6px;
}
.target {
  width: 130px; height: 130px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center; font-size: 2rem; font-weight: 700;
}
.target.wait { background: #3a2630; color: #c98; }
.target.go { background: #1f6e63; color: #d9fff8; }
.bignum { font-size: 3rem; font-weight: 800; letter-spacing: -.02em; }
.bigsym { font-size: 3.4rem; }
.grid-sym { display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px; width: min(420px, 90vw); }
.grid-sym button {
  font-size: 1.9rem; padding: 14px 0; border-radius: 12px;
  border: 1px solid var(--line); background: var(--bg-2); cursor: pointer;
}
.grid-sym button.picked { background: var(--accent-2); border-color: transparent; }
/* multiple-choice option grid (speed + associative tasks) — thumb-friendly, tactile.
   The surface (background, border, press squeeze) is painted on an inset ::before layer, never on
   the button itself: scaling the button shrank it out from under the finger mid-tap, the click then
   retargeted to the container, the delegated handlers' closest('button[data-…]') returned null and
   the answer was dropped. The ::before moves; the hit box never does. */
.opts { display: grid; grid-template-columns: repeat(2, 1fr); gap: 12px; width: min(360px, 86vw); margin: 10px auto 0; }
.opt {
  position: relative; isolation: isolate;
  font-size: 1.9rem; padding: 22px 0; border-radius: 16px; min-height: 78px;
  border: none; background: none; color: var(--ink); cursor: pointer; font-family: var(--font);
  /* opacity-only entrance: the old translateY(6px) meant a fast tap could land while the button was
     still sliding into place (the speed test renders the next item after 120ms). */
  animation: optin .22s ease backwards;   /* backwards, not both: see .fadein (ClearType) */
}
.opt::before {
  content: ""; position: absolute; inset: 0; z-index: -1; border-radius: inherit;
  border: 1px solid var(--line); background: var(--card-2); box-shadow: var(--inset-hi);
  transition: transform .09s ease, background .15s ease, border-color .15s ease, box-shadow .2s ease;
}
.opt:active:not(:disabled)::before { transform: scale(.955); border-color: var(--accent); }
.opt:disabled { cursor: default; opacity: .92; }
.opt.ok::before { background: #1f6e63; border-color: transparent; transform: scale(1.02); }
.opt.bad::before { background: #6e2f3a; border-color: transparent; }
/* weekly picture test: a NEUTRAL confirmation of the tap. No green/red — the test never says whether an
   answer was right. Text and surface reach 4.5:1 in both themes. */
.opt.tapped { color: var(--tap-ink); }
.opt.tapped::before { background: var(--tap-bg); border-color: transparent; transition: none; }   /* at once, with its text colour */
@keyframes optin { from { opacity: 0; } to { opacity: 1; } }
@media (prefers-reduced-motion: reduce) { .opt { animation: none; } }
/* weekly oMST object frame: a fixed square so the layout doesn't jump when the image hides; plain
   neutral backing reads in both themes (the images already ship on a plain background per the guide) */
.mst-frame {
  /* sized from BOTH axes so the picture + the three answers always fit a short window (the runner
     clips overflow rather than scrolling) */
  width: min(300px, 72vw, max(180px, calc(100vh - 260px - var(--size-chrome)))); aspect-ratio: 1; margin: 4px auto 0;
  display: flex; align-items: center; justify-content: center;
  border-radius: 16px;
  /* Images ship on a clean solid white background, framed as a white "photo card". */
  background: #ffffff; border: 1px solid rgba(0,0,0,.06); overflow: hidden;
  box-shadow: 0 8px 26px rgba(0,0,0,.30);
}
.mst-img { max-width: 100%; max-height: 100%; object-fit: contain; display: block; }
/* weekly-test loading skeleton: a softly pulsing placeholder inside the normal frame while the
   session's pictures preload (same footprint as a trial, so nothing jumps when it starts) */
.mst-skeleton {
  width: 84%; height: 84%; border-radius: 12px;
  background: var(--ink-3);
  animation: mstpulse 1.8s ease-in-out infinite;
}
@keyframes mstpulse { 0%, 100% { opacity: .14; } 50% { opacity: .3; } }
.runner .hint { color: var(--ink-3); max-width: 460px; }
/* the working-memory test's "↶ Undo last tap" (e1b, js/tasks.js runGrid): under the board, a 44 px target; greyed while
   there is nothing to undo */
.runner .grid-undo { flex: 0 0 auto; display: inline-flex; align-items: center; justify-content: center; gap: 7px; max-width: 100%; }
.runner .grid-undo:disabled { opacity: .4; cursor: default; }
.runner .grid-undo .undo-ico { font-size: 1.25em; line-height: 1; }
.runner .close { position: static; }
.progress { color: var(--ink-3); font-size: .8rem; letter-spacing: .14em; text-transform: uppercase; font-weight: 600; }

/* library */
.lib-item { }
.lib-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; cursor: pointer; }
.lib-name { font-weight: 700; }
.badge {
  font-size: .72rem; padding: 4px 9px; border-radius: 999px; white-space: nowrap;
  border: 1px solid var(--line); color: var(--ink-2);
}
.badge.none, .badge.weak, .badge.minimal { color: var(--ev-weak-ink); border-color: var(--line); }
.badge.mixed, .badge.limited, .badge.acute { color: var(--ev-mixed-ink); border-color: var(--line); }
.badge.conditional, .badge.emerging { color: var(--ev-strong-ink); border-color: var(--line); }
.lib-body { margin-top: 12px; display: none; }
.lib-item.open .lib-body { display: block; }
.lib-layer { margin-bottom: 12px; }
.lib-layer .k { font-size: .72rem; text-transform: uppercase; letter-spacing: .1em; color: var(--ink-3); }
.lib-src { font-size: .82rem; color: var(--ink-3); }
/* library dot columns — header labels align over each supplement's three axis dots */
.dotcols { display: flex; flex: 0 0 auto; align-items: center; }
.dotcol { width: 38px; display: flex; align-items: center; justify-content: center; }
/* the column labels are abbreviations (their full names in the title): at the larger text sizes they stay within their
   38 px column rather than running into the next one (e1b) */
.lib-colhead { font-size: min(.68rem, 11.5px); text-transform: uppercase; letter-spacing: .02em; color: var(--ink-3); }
.lib-colhead-row { cursor: default; }
.lib-colhead-row:hover, .lib-colhead-row:active { background: none; }
.lib-src li { margin-bottom: 3px; }
/* "One new supplement every week" (js/libvote.js): the vote choices (a tick on a chosen one, not colour alone) and the
   suggestion field with its Send button on one row */
.lib-vote { margin-bottom: 14px; }
.lib-vote-sub { margin: 2px 0 12px; font-size: .88rem; color: var(--ink-2); }
.lib-vote-chip svg { margin-right: 6px; }
.lib-suggest .lab { display: block; font-weight: 600; margin: 16px 0 6px; }
.lib-suggest-row { display: flex; gap: 8px; align-items: stretch; }
.lib-suggest-row input { flex: 1 1 auto; min-width: 0; min-height: 44px; }
.lib-suggest-row .btn { flex: 0 0 auto; }

/* disclaimers */
.disclaimer {
  border: 1px solid var(--warn-bd); background: var(--warn-bg);
  color: var(--ink-2); border-radius: 12px; padding: 11px 13px; font-size: .86rem;
}
.disclaimer strong { color: var(--warn-ink); }
.disclaimer a { display: inline-block; padding: 13px 2px; margin: -13px -2px; }

/* onboarding */
.ob { max-width: 560px; margin: 6vh auto; }
.ob ol { color: var(--ink-2); padding-left: 1.1em; }
.ob li { margin-bottom: 8px; }

/* nav — an OPAQUE bar, no backdrop blur: a blurred translucent bar is a composited layer, and Windows then
   draws its labels with grayscale antialiasing instead of ClearType (soft text). Same for .sheet-head below. */
.statusbar-scrim {
  position: fixed; top: 0; left: 0; right: 0; height: var(--sat); z-index: 60;
  background: var(--glass); pointer-events: none;
}

.nav {
  position: fixed; bottom: 0; left: 0; right: 0; z-index: 40;
  display: flex; justify-content: space-around; gap: 2px;
  background: var(--glass);
  border-top: 1px solid var(--line); padding: 8px 6px max(8px, var(--sab));
}
.nav-btn {
  position: relative; flex: 1; min-width: 0; background: none; border: none; color: var(--ink-3);
  display: flex; flex-direction: column; align-items: center; gap: 2px;
  font: inherit; font-size: .68rem; padding: 6px 2px; cursor: pointer; border-radius: 10px;
  transition: color .18s ease, opacity .1s ease;
}
.nav-btn .nav-ico { font-size: 1.15rem; line-height: 1; transition: transform .18s ease; }
/* a long tab name (e.g. Russian "Эксперименты" at extra large on a 320 px phone) is shortened with "…" rather
   than pushing the last tab off the screen */
.nav-btn > span:last-child { max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.nav-btn:active { opacity: .55; }
.nav-btn.on { color: var(--accent-ink); }
.nav-btn.on .nav-ico { transform: translateY(-1px); }

.chart { width: 100%; height: auto; display: block; }
.chart-panel { fill: var(--chart-panel); stroke: var(--chart-panel-stroke); stroke-width: 1; }
.chart-line { stroke: var(--accent); stroke-width: 2.6; stroke-linecap: round; stroke-linejoin: round; }
.chart-dot { fill: var(--accent); }
.chart-dot.sub { fill: var(--accent); opacity: .45; }
.chart-last-halo { fill: var(--accent); opacity: .16; }
.chart-last { fill: var(--accent); stroke: var(--bg); stroke-width: 2.2; }
/* Chart text sizes are set by js/charts.js (at least 11 px on screen, growing with the text-size setting), so
   these classes carry no font-size: a CSS font-size would override the one the chart sets. */
/* trailing 30-day average reference line — a distinct mauve/purple dashed line + label (your own recent average, G2) */
.chart-trailing { stroke: var(--baseline-trailing); stroke-width: 1.4; opacity: .92; }
.chart-trailing-label { fill: var(--baseline-trailing); letter-spacing: .03em; font-family: var(--font); }
/* the long-term line (js/longterm.js): one neutral dashed line, the same whichever way it slopes */
.chart-longterm { stroke: var(--ink-2); stroke-width: 2; stroke-dasharray: 8 4; stroke-linecap: round; fill: none; }
.chart-axis { fill: var(--ink-3); font-family: var(--font); }
.chart-grid { stroke: var(--chart-grid); stroke-width: 1; }
.chart-yaxis { fill: var(--ink-3); font-family: var(--font); }
.chart-empty { fill: var(--ink-3); font-family: var(--font); }

.row-list { list-style: none; padding: 0; margin: 0; }
.row-list li { display: flex; justify-content: space-between; padding: 10px 0; border-bottom: 1px solid var(--line); color: var(--ink-2); }
.row-list li:last-child { border-bottom: none; }

.pattern-stat { display: flex; align-items: baseline; gap: 8px; margin: 6px 0; }
.pattern-stat .v { font-size: 1.5rem; font-weight: 800; color: var(--ink); }
.center { text-align: center; }
.spacer { height: 8px; }

/* Phones have no room for a desktop gutter: 18px of page padding plus 22px of card padding
   spent 40px a side. Tightening both gives the content ~24px more width on a 393px screen. */
@media (max-width: 480px) {
  #app { padding-left: 12px; padding-right: 12px; }
  .sheet-body { padding-left: 12px; padding-right: 12px; }
  .card { padding: 16px; }
  .card.tight { padding: 12px; }
}
/* fill-mode `backwards`, never `both`/`forwards`: a finished filling transform/opacity animation keeps the whole
   view composited, and Windows then draws ALL its text with grayscale antialiasing instead of ClearType (soft text). */
.fadein { animation: fade .3s cubic-bezier(.32,.72,0,1) backwards; }
@keyframes fade { from { opacity: 0; transform: translateY(9px); } to { opacity: 1; transform: none; } }
/* home progress ring — smooth sweep on load (no glow filter: --accent-glow is transparent in both themes,
   and a non-none filter still forces an extra composited layer) */
.hero-arc { transition: stroke-dashoffset 1.05s cubic-bezier(.34,.8,.25,1); }

/* ── premium icon badges + duotone glyphs (used app-wide) ── */
.ico-badge {
  width: 44px; height: 44px; border-radius: 50%; flex: 0 0 auto;
  display: flex; align-items: center; justify-content: center;
  background: var(--badge); box-shadow: var(--badge-shadow);
}
.ico-badge.sm { width: 34px; height: 34px; }
.ico-badge.lg { width: 56px; height: 56px; }
.ico-badge svg { width: 23px; height: 23px; display: block; }
.ico-badge.sm svg { width: 19px; height: 19px; }
.ico-badge.lg svg { width: 28px; height: 28px; }
.gl { stroke: var(--gl-stroke); stroke-width: 1.85; fill: none; stroke-linecap: round; stroke-linejoin: round; }
.accs { stroke: var(--accent); stroke-width: 1.85; fill: none; stroke-linecap: round; stroke-linejoin: round; }
.acc { fill: var(--accent); stroke: none; }
.dim { fill: rgba(220,236,234,.20); stroke: none; }

/* ── metric rows ("Your results" dashboard) ── */
.metric {
  display: flex; align-items: center; gap: 13px; width: 100%;
  padding: 14px 2px; border: none; border-bottom: 1px solid var(--line);
  background: none; color: var(--ink); cursor: pointer; font: inherit; text-align: left;
}
.metric:last-of-type { border-bottom: none; }
.metric { border-radius: 10px; transition: background .12s ease; }
.metric:hover { background: var(--surf-hi); }
/* press states are paint-only (see .btn above) — nothing here may move under a finger */
.metric:active { background: var(--surf-hi-2); }
button.card { transition: box-shadow .15s ease; }
button.card:active { box-shadow: inset 0 0 0 999px rgba(128,128,128,.10), var(--elev), var(--inset-hi); }
.metric .m-mid { flex: 1 1 58%; min-width: 0; }
/* a word too long for its row breaks rather than running into what stands beside it (e1b) */
.metric .m-name { font-size: .95rem; font-weight: 550; overflow-wrap: break-word; }
.metric .m-mid > .muted { overflow-wrap: break-word; }
.metric .m-name .m-sub { color: var(--ink-3); font-size: .8rem; font-weight: 400; }
.track { position: relative; height: 8px; margin-top: 9px; background: var(--surf-hi-2); border-radius: 5px; }
/* A5 (2026-10-03): the sentence at the top of a chart — the last 7 days; quiet: when the usual range appears, or too few
   tests in the 7 days (js/trends.js weekReading) */
.week-line { margin: 2px 0 12px; font-size: 1.02rem; font-weight: 650; line-height: 1.35; color: var(--ink); }
.week-line.quiet { font-weight: 500; font-size: .92rem; color: var(--ink-2); }
/* A8 (2026-10-03): the result pop-up's ending during a test's first tests, and the 10 steps to the usual range */
.result-delta { font-size: 1.02rem; font-weight: 650; line-height: 1.35; color: var(--ink); margin: 8px 0 0; }
.result-prog { margin: 14px 0 2px; }
.result-prog-label { font-size: .9rem; color: var(--ink-2); margin-bottom: 7px; }
.result-segs { display: flex; gap: 4px; }
.result-segs i { flex: 1; height: 6px; border-radius: 3px; background: var(--surf-hi-2); box-shadow: inset 0 0 0 1px var(--line); }
.result-segs i.on { background: var(--gold-grad); box-shadow: none; }
/* v103: the same bar until a usual range exists — a row on Trends (where its position bar comes later), the overall
   score's cards, under the top line of a chart (js/trends.js rangeSegs) */
.result-segs.row-segs { margin-top: 9px; }
.hero-card .result-segs { margin-top: 12px; }
.result-segs.card-segs { margin: 0 0 8px; }
.result-segs.sheet-segs { margin: -4px 0 14px; }
.track .center { position: absolute; left: 50%; top: -3px; bottom: -3px; width: 1px; background: var(--track-center); }
.track .fillpos { position: absolute; left: 50%; top: 0; bottom: 0; background: linear-gradient(90deg, var(--accent-2), var(--accent-soft)); border-radius: 0 5px 5px 0; }
.track .fillneg { position: absolute; right: 50%; top: 0; bottom: 0; background: rgba(150,176,180,.5); border-radius: 5px 0 0 5px; }
.metric .m-rt { text-align: right; flex: 0 1 auto; min-width: 0; max-width: 42%; }
.metric .m-val { font-size: 1rem; font-weight: 700; }
.metric .m-val small { font-size: .72rem; color: var(--ink-2); font-weight: 500; }
.metric .m-cap { font-size: .72rem; margin-top: 2px; }
.m-cap.pos { color: var(--accent-ink); } .m-cap.neg { color: var(--cap-neg); } .m-cap.mid { color: var(--ink-2); }
.metric .m-chev { color: var(--chev); flex: 0 0 auto; display: flex; }
/* e1b: text never collides, in any language, at 320 px with extra-large text — the rows with a number on the right
   (num-row: Today's tests, Trends' tests and sleep, the lab values' list). The name and the number share the line while
   their longest words fit side by side (the name gets 3 parts of the room left, the number 1 — as before); when they
   don't (German "Arbeitsgedächtnis" at extra large), the number moves below the name, to the right (flex-wrap: the name is
   never narrower than its longest word, the number never narrower than itself). The chevron stays at the right, in the
   middle of the row. */
.metric.num-row { flex-wrap: wrap; row-gap: 6px; position: relative; padding-right: 32px; }
.metric.num-row .m-mid { flex: 3 1 0; min-width: auto; }
.metric.num-row .m-rt { flex: 1 1 auto; flex-basis: min-content; min-width: auto; max-width: none; margin-left: auto; }
.metric.num-row .m-val { white-space: nowrap; }
.metric.num-row .m-chev { position: absolute; right: 4px; top: 50%; transform: translateY(-50%); }
.ends { display: flex; justify-content: space-between; font-size: .7rem; letter-spacing: .07em; text-transform: uppercase; color: var(--ink-3); margin-top: 10px; }

/* ── hero card (overall index) ── */
.hero-card {
  position: relative; overflow: hidden; cursor: pointer;
  background: var(--hero-grad);
  border: 1px solid var(--hero-border); border-radius: var(--radius);
  padding: 18px 19px;
  box-shadow: var(--elev-hero), var(--inset-hi);
}
/* ambient corner glow — premium depth without a heavy graphic */
.hero-card::before {
  content: ""; position: absolute; right: -36px; top: -52px; width: 190px; height: 190px; border-radius: 50%;
  background: radial-gradient(circle, var(--hero-glow), transparent 68%); pointer-events: none;
}
.hero-card .hero-row { display: flex; align-items: center; gap: 9px; }
.hero-card .state { font-size: 1.25rem; font-weight: 650; margin: 9px 0 4px; max-width: 220px; line-height: 1.25; }
.hero-card .hint { font-size: .8rem; color: var(--accent-ink); display: flex; align-items: center; gap: 3px; }
.hero-spark { position: absolute; right: 13px; top: 22px; width: min(148px, calc(100% - 220px)); height: 60px; }
.legend { display: flex; gap: 6px 14px; font-size: .72rem; color: var(--ink-2); margin: 11px 2px 2px; }
.legend span { display: inline-flex; align-items: center; gap: 5px; min-width: 0; }
.legend i { width: 13px; height: 3px; border-radius: 2px; display: inline-block; flex: none; }

/* screen header used across views */
.screen-head { display: flex; align-items: center; gap: 11px; margin-bottom: 16px; }

/* ── detail sheet overlays (drill-downs) ── */
.sheet { position: fixed; inset: 0; z-index: 45; overflow-y: auto; background: var(--bg-grad); }
.sheet-head { position: sticky; top: 0; z-index: 1; display: flex; align-items: center; gap: 11px;
  padding: max(13px, calc(var(--sat) + 8px)) 18px 13px;
  background: var(--glass); border-bottom: 1px solid var(--line); }   /* opaque, no blur — see .nav (ClearType) */
.sheet-back { width: 44px; height: 44px; border-radius: 50%; border: 1px solid var(--line); background: var(--card-2);
  color: var(--ink); display: flex; align-items: center; justify-content: center; cursor: pointer; flex: 0 0 auto; }
/* a long German test name ("Arbeitsgedächtnis") fits a 320 px screen at extra-large text: the title never grows past 5.4%
   of the screen's width (e1b); a word longer still breaks rather than running out */
.sheet-title { font-size: min(1.05rem, 5.4vw); font-weight: 650; min-width: 0; overflow-wrap: anywhere; }
.sheet-body { max-width: var(--maxw); margin: 0 auto; padding: 18px 18px 50px; }

/* ── library: two-population grade badges + colour key ── */
.lib-grades { display: flex; flex-direction: column; gap: 5px; align-items: flex-end; flex: 0 0 auto; }
.lib-grade { display: flex; align-items: center; gap: 6px; }
.lib-grade .gl { font-size: .56rem; text-transform: uppercase; letter-spacing: .05em; color: var(--ink-3); }
.grade-key { display: flex; flex-wrap: wrap; gap: 6px; margin: 8px 0 2px; }

/* ── week dots + quiet streak (home, all three layouts) ──
   Filled dot = a day with a check-in; outline dot = none (neutral, never guilt-styled);
   today gets a soft accent ring. Streak caption is small and calm. */
.week-strip { display: flex; align-items: center; justify-content: center; gap: 20px; margin: 16px 0 6px; }
.week-dots { display: flex; gap: 11px; }
.wd { display: flex; flex-direction: column; align-items: center; gap: 5px; }
.wd-dot { width: 9px; height: 9px; border-radius: 50%; border: 1.5px solid var(--track-center); }
.wd-dot.on { background: var(--accent); border-color: var(--accent); }
.wd-dot.today { box-shadow: 0 0 0 2.5px var(--hero-glow); border-color: var(--accent-soft); }
.wd-day { font-size: .66rem; letter-spacing: .05em; text-transform: uppercase; color: var(--ink-3); line-height: 1; }
.week-streak { text-align: center; }
.week-streak b { display: block; font-size: .95rem; font-weight: 700; color: var(--ink); line-height: 1.2; }
.week-streak span { font-size: .66rem; letter-spacing: .12em; text-transform: uppercase; color: var(--ink-3); }

/* ── Monday recap card ("Your week") — descriptive counts only, dismissible ── */
.recap-card { padding-right: 52px; }
/* v124 — "No email after a minute? Look in your spam folder.": a line of its own wherever an email was sent (the code
   screen, after "Resend code", after "Forgot my password"), in the body colour so it is read, not skipped. */
.mail-spam { margin: 6px 0 12px; font-size: .92rem; line-height: 1.4; font-weight: 600; color: var(--ink); }
/* v124 — You ▸ About, at the app's earlier address only: the one line that names the new address, with its × (.recap-x) */
.addr-note { position: relative; margin: 8px 0 12px; padding: 11px 52px 11px 14px; border: 1px solid var(--hairline); border-radius: 12px;
  background: var(--lift); font-size: .88rem; line-height: 1.45; color: var(--ink); }
.addr-note p { margin: 0; }
.addr-note a { color: var(--accent-ink); overflow-wrap: anywhere; }
.recap-x {
  position: absolute; top: 4px; right: 4px; width: 44px; height: 44px; border-radius: 50%;
  border: none; background: none; color: var(--ink-3); font: inherit; font-size: 1.15rem;
  display: flex; align-items: center; justify-content: center; cursor: pointer;
  transition: background .15s ease, color .15s ease;
}
.recap-x:hover { background: var(--surf-hi); color: var(--ink-2); }

/* ── The end of the day's check-in on Today (js/dayend.js): the reward card (Q8) and the free-month card (A4, js/offer.js),
   in the recap card's look ── */
.reward-card .reward-line { margin: 2px 0 0; }
.reward-link { display: flex; align-items: center; gap: 10px; width: 100%; min-height: 48px; margin-top: 12px; padding: 10px 12px;
  border: 1px solid var(--line); border-radius: 12px; background: var(--bg-2); color: var(--ink); font: inherit; font-weight: 600;
  text-align: left; cursor: pointer; }
.reward-link span { flex: 1; min-width: 0; overflow-wrap: break-word; }
.reward-link svg { flex: none; }
.reward-link:hover { border-color: var(--accent); }
.offer-card .offer-interest { margin: 0 0 8px; font-size: .95rem; }
.offer-list { margin: 4px 0 14px; padding-left: 20px; line-height: 1.45; }
.offer-list > li { margin: 6px 0; }
.offer-tags .tag-top { padding: 5px 0; align-items: center; }
.offer-price { margin: 0 0 6px; }
.offer-keep { font-size: .86rem; margin: 0 0 14px; }
/* the question before the tour (js/interest.js): a page over Today; its answers in the experiment options' look */
.runner.interest-screen { overflow-y: auto; text-align: left; }
.interest-page { width: 100%; margin: 4vh auto; }
.interest-page h1 { outline: none; }
.exp-opt.interest-opt { min-height: 56px; padding: 14px 18px; margin-top: 12px; font-weight: 650; font-size: 1.05rem; }

/* ── Trial-enrollment prompt on the final check-in result popup (js/app.js maybeTrialPrompt) ── */
.trial-prompt {
  margin-top: 16px; padding-top: 14px; border-top: 1px solid var(--line);
}
.trial-prompt.done {
  text-align: center; padding-top: 12px;
}

/* ── v90: Today header with the text-size button, practice invite, time-span switch, feedback ── */
.today-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.today-head h1 { margin: 0; }
/* "Aa": opens Normal / Large / Extra large (js/app.js openTextSize) — a 44 px target, grows with the setting */
.aa-btn {
  flex: 0 0 auto; min-width: 48px; min-height: 48px; padding: 0 12px; border-radius: 999px;
  border: 1px solid var(--line); background: var(--card-2); color: var(--ink); cursor: pointer;
  font: inherit; font-weight: 700; font-size: 1.05rem; letter-spacing: .01em;
}
.aa-btn:hover { border-color: var(--accent); }
.aa-btn small { font-size: .78em; color: inherit; }
/* the end of a practice round: the invite to the real test and its two buttons */
.practice-invite { margin: 4px 0 0; font-weight: 600; color: var(--ink); max-width: 460px; }
.practice-foot { flex-wrap: wrap; gap: 10px; }
/* Week / Month / All above a test's chart */
.range-seg { margin: 2px 0 10px; }
.range-seg button { min-height: 44px; }
/* the feedback entry (Today + You) and its sheet */
.fb-entry { display: flex; align-items: center; gap: 12px; width: 100%; text-align: left; cursor: pointer; }
.fb-entry .fb-text { flex: 1; min-width: 0; }
.fb-count { font-size: .78rem; color: var(--ink-3); text-align: right; margin-top: 4px; }
.fb-sheet textarea { min-height: 150px; }
.fb-status { font-size: .9rem; margin: 10px 0 0; min-height: 1px; }
.fb-status.ok { color: var(--accent-ink); font-weight: 600; }
/* the public pages (values.html, roadmap.html) */
.page-list { margin: 0; padding-left: 1.2em; color: var(--ink-2); }
.page-list li { margin-bottom: 8px; }
.page-list li:last-child { margin-bottom: 0; }

/* ── Text & button size (Normal / Large / Extra large) ───────────────────────────────────────────
   A device-local display preference set on <html data-size> (js/app.js applyUiSize). rem-based type
   scales straight from the root font-size; the px-based tap targets are bumped explicitly so the
   buttons grow with the text. --size-chrome is the extra vertical space the larger headings and
   buttons eat inside the task runner (which clips rather than scrolls) — the JS-sized play areas
   add the same allowance via App.uiSizeChrome(). */
:root { --size-chrome: 0px; }
html[data-size="large"]  { font-size: 115%; --size-chrome: 28px; }
html[data-size="xlarge"] { font-size: 132%; --size-chrome: 56px; }

[data-size="large"]  .btn { min-height: 56px; padding: 15px 20px; }
[data-size="xlarge"] .btn { min-height: 64px; padding: 18px 22px; }
[data-size="large"]  .btn.sm { min-height: 0; padding: 11px 15px; }
[data-size="xlarge"] .btn.sm { min-height: 0; padding: 13px 17px; }
[data-size="large"]  .opt { min-height: 92px; padding: 26px 0; }
[data-size="xlarge"] .opt { min-height: 104px; padding: 30px 0; }
/* Speed-test number pad: the runner clips instead of scrolling, and everything above the pad (key,
   prompt, symbol) also grows. So the pad goes WIDER (bigger target for a finger) and its button
   height is capped by the space the window actually has left - on a short phone it never runs off the
   bottom of the screen; on a normal phone it reaches the full larger size. */
[data-size] #digits { max-width: min(340px, 94vw) !important; }
[data-size="large"]  #digits .opt { min-height: 0; padding: 0; height: clamp(56px, calc((100vh - 440px) / 3), 92px); }
[data-size="xlarge"] #digits .opt { min-height: 0; padding: 0; height: clamp(56px, calc((100vh - 480px) / 3), 104px); }
/* Speed test on a short screen (iPhone SE size and similar; founder 2026-10-03): the bottom row of the number pad ran off
   the screen. Here the stage's gaps, the shown symbol and the pad's buttons shrink to the space there is, so the whole pad
   stays on the screen at every text size. The key keeps its 5 + 4 layout and size; the test's timing and scoring don't
   change. Taller screens are untouched. */
@media (max-height: 740px) {
  .runner .stage.speed-stage { gap: 8px; }
  .runner .stage.speed-stage .bigsym { margin: 2px 0 !important; }
  .runner .stage.speed-stage .bigsym svg { width: 64px; height: 64px; }
  .runner .stage.speed-stage #digits { gap: 8px; }
  .runner .stage.speed-stage #digits .opt { min-height: 0; padding: 0; height: clamp(48px, calc((100vh - 420px - var(--size-chrome)) / 3), 78px); }
}
[data-size="large"]  .seg button { padding: 14px 12px; }
[data-size="xlarge"] .seg button { padding: 17px 14px; }
[data-size="large"]  .chip { padding: 11px 15px; }
[data-size="xlarge"] .chip { padding: 13px 17px; }
[data-size="large"]  .routine { min-height: 52px; padding: 9px 16px; }
[data-size="xlarge"] .routine { min-height: 58px; padding: 11px 18px; }
[data-size="large"]  .dayswitch button { min-height: 52px; padding: 0 16px; }
[data-size="xlarge"] .dayswitch button { min-height: 58px; padding: 0 18px; }
/* the bottom nav grows with its labels — keep the same clearance under the page content */
[data-size="large"]  body { padding-bottom: 104px; }
[data-size="xlarge"] body { padding-bottom: 116px; }

/* ── v90: tags compared — rows, label pills, range bars, day strip (js/trends.js) — and the experiment views (js/app.js) ── */
.tag-row { display: block; width: 100%; text-align: left; font: inherit; color: var(--ink); background: none; border: none;
  border-bottom: 1px solid var(--line); padding: 13px 0; }
button.tag-row { cursor: pointer; }
.tag-row:last-child { border-bottom: none; }
/* name and label pill share a line while they fit; on a narrow screen or with large text the pill wraps under the
   name, and a pill wider than the whole row wraps its words ("… · still refining") rather than sticking out */
.tag-top { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: baseline; gap: 4px 10px; }
.tag-top > b, .tag-top > .lib-name { min-width: 0; overflow-wrap: anywhere; }
.tag-pill { font-size: .72rem; font-weight: 700; padding: 3px 9px; border-radius: 10px; flex: 0 1 auto;
  max-width: 100%; min-width: 0; overflow-wrap: anywhere; }
.tag-pill.tp-consistent { background: var(--accent-fill); color: var(--on-accent); }
.tag-pill.tp-early { border: 1.5px solid var(--accent); color: var(--accent-ink); }
.tag-pill.tp-none { background: var(--bg-2); color: var(--ink-2); }
.tag-pill.tp-wait { border: 1.5px dashed var(--ink-3); color: var(--ink-2); }
/* the refining phase: a first estimate, or an early sign that is still refining — dashed, like something not yet settled */
.tag-pill.tp-first { border: 1.5px dashed var(--accent); color: var(--ink-2); }
.tag-pill.tp-early.tp-refining { border-style: dashed; }
.tag-sent { margin: 6px 0 8px; font-size: .95rem; line-height: 1.35; color: var(--ink); }
.tag-days { font-size: .8rem; color: var(--ink-2); margin-top: 6px; line-height: 1.4; }
.tag-track { position: relative; height: 14px; background: var(--bg-2); border-radius: 7px; }
.tag-track .zero { position: absolute; left: 50%; top: -3px; bottom: -3px; width: 2px; margin-left: -1px; background: var(--ink-3); }
.tag-track .rng { position: absolute; top: 3px; height: 8px; border-radius: 4px; background: var(--accent); opacity: .45; }
.tag-track .dot { position: absolute; top: 1px; width: 12px; height: 12px; margin-left: -6px; border-radius: 50%; background: var(--accent); }
.tag-axis { display: flex; justify-content: space-between; font-size: .72rem; color: var(--ink-2); margin-top: 3px; }
/* e1b: the overview — the tag's name, then one line per test (its name and label; the label moves under the name when
   both don't fit); under a bar on a detail page, the range named in words */
.tag-name b { overflow-wrap: anywhere; }
.tag-top.tag-test { margin-top: 6px; font-size: .9rem; color: var(--ink-2); align-items: center; }
.tag-top.tag-test > span:first-child { min-width: 0; overflow-wrap: break-word; }
.tag-top.tag-test > .tag-pill { margin-left: auto; }   /* moved under the name, it stays on the right like the others */
.tag-ci { font-size: .8rem; color: var(--ink-2); margin-top: 6px; line-height: 1.4; }
.tag-strip { display: grid; grid-template-columns: repeat(21, 1fr); gap: 3px; margin: 10px 0 4px; }
.tag-strip i { display: block; height: 12px; border-radius: 3px; background: var(--bg-2); }
.tag-strip i.on { background: var(--accent-ink); }
.tag-note, .exp-better { background: var(--bg-2); border-radius: 12px; padding: 10px 12px; font-size: .88rem; line-height: 1.4; margin-top: 12px; color: var(--ink); }
/* a tag's page: the first-estimate message once, with its label; those rows then have no sentence between pill and bar (v91b) */
.tag-first-note .tag-pill { display: inline-block; }
.tag-top + .tag-bar { margin-top: 10px; }
.exp-step { font-size: .72rem; letter-spacing: .08em; text-transform: uppercase; color: var(--ink-2); margin: 16px 0 6px; }
.exp-opt { display: block; width: 100%; text-align: left; font: inherit; color: var(--ink); cursor: pointer;
  border: 1px solid var(--line); background: var(--bg-2); border-radius: 12px; padding: 10px 12px; margin-top: 8px; }
.exp-opt.on { border: 2px solid var(--accent-fill); padding: 9px 11px; }
.exp-opt .muted { display: block; font-size: .84rem; margin-top: 2px; line-height: 1.4; }
.exp-bar { height: 10px; background: var(--bg-2); border-radius: 5px; overflow: hidden; margin: 8px 0; }
.exp-bar b { display: block; height: 100%; background: var(--accent-fill); border-radius: 5px; }
/* the long-term line's sentence under a chart (js/trends.js longTermEl), and on the Trends overall card */
.lt-row { margin-top: 10px; }
.lt-top { margin-bottom: 5px; }
.lt-top .tag-pill { display: inline-block; }
.lt-sent { font-size: .86rem; line-height: 1.4; color: var(--ink); }
.lt-sent.muted { color: var(--ink-2); }
.hero-card .lt-row { margin-top: 12px; position: relative; }
.hero-card .lt-sent { font-size: .8rem; color: var(--ink-2); }

/* ── v90: lab values (js/labs.js · js/labsphoto.js · js/labsoverlay.js) ──
   The person's own results, shown as entered. NOTHING here colours a value by what it is: the lab's range is a neutral
   grey band and its flag plain text. --lab-1 is the colour of the one lab line drawn over a test chart (no red, no
   green), kept clear of what a test chart already draws — the test line (--accent) and the recent-average line
   (--baseline-trailing); it reaches 4.5:1 as text on the card in its theme. */
:root { --lab-1: #f2a65a; }   /* the light theme's value lives in its token block at the end of this file */
.chart-labband { fill: var(--ink-3); fill-opacity: .14; }
/* a form field switched off by the `hidden` attribute stays off (label.field sets display:block) */
label.field[hidden] { display: none; }
/* the date of a lab result: the same field look as the text inputs, a finger-sized target */
input[type="date"] { width: 100%; min-height: 48px; background: var(--bg-2); border: 1px solid var(--line); color: var(--ink);
  border-radius: 10px; padding: 10px 12px; font: inherit; color-scheme: dark; }
[data-theme="light"] input[type="date"] { color-scheme: light; }
.lab-entry { display: flex; align-items: center; gap: 12px; width: 100%; text-align: left; cursor: pointer; }
.lab-entry .lab-entry-text { flex: 1; min-width: 0; }
.lab-actions { margin: 0 0 16px; }
.lab-actions .btn { flex: 1 1 160px; }
.lab-ref { padding: 12px 0; border-bottom: 1px solid var(--line); }
.lab-ref:last-of-type { border-bottom: none; }
.lab-ref-top { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.lab-ref-desc { font-size: .86rem; margin-top: 3px; line-height: 1.4; }
.lab-link { display: inline-flex; align-items: center; gap: 4px; min-height: 44px; padding: 0; border: none; background: none;
  color: var(--accent-2-ink); font: inherit; font-size: .86rem; cursor: pointer; text-align: left; }
.lab-row { display: block; width: 100%; text-align: left; font: inherit; color: var(--ink); background: none; border: none;
  border-bottom: 1px solid var(--line); padding: 12px 0; cursor: pointer; }
.lab-row:last-child { border-bottom: none; }
.lab-row-top { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: baseline; gap: 4px 10px; }
.lab-row-sub { font-size: .84rem; color: var(--ink-2); margin-top: 3px; line-height: 1.4; overflow-wrap: anywhere; }
.lab-two { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.lab-two label.field { margin-bottom: 0; }
.lab-flag { margin-bottom: 14px; }
.lab-err { font-size: .9rem; margin: 10px 0 0; min-height: 1px; }
.lab-key { flex: none; display: block; }
.lab-band-swatch { flex: none; width: 14px !important; height: 10px !important; border-radius: 2px; background: var(--ink-3) !important; opacity: .3; }
.lab-overlay-btn { margin-top: 10px; }
/* v91 "Add sleep trends" (js/sleepoverlay.js): e1b — one thin solid line (a chart shows one extra line, sleep or lab), in
   a hue clear of everything a test chart already draws (the test line, the recent-average line, the lab colour); it
   reaches 4.5:1 as text on the card. */
:root { --sleep-1: #9fd98a; }   /* soft green; the light theme's value lives in its token block at the end of this file */
.sleep-overlay-btn { margin-top: 8px; }
.sleep-key { flex: none; display: block; }
.lab-review { border: 1px solid var(--line); border-radius: 14px; padding: 12px; margin-bottom: 12px; background: var(--card); }
.lab-review.ok { border-color: var(--accent); }
.lab-review .lab-read { font-size: .8rem; color: var(--ink-2); margin-bottom: 8px; overflow-wrap: anywhere; }
.lab-review-foot { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 8px; margin-top: 10px; }
.lab-review-foot .btn { flex: 1 1 120px; }
.lab-done { font-weight: 700; color: var(--accent-ink); }

/* ── v90: MemoryProof Plus (js/paywall.js) and reminders (js/reminders.js) ──
   Calm on purpose: the locked card and the free-month card use the ordinary card look — no countdown colour, no
   warning red; prices are plain text. */
.plus-lock-row { display: flex; align-items: center; gap: 12px; }
.card.plus-lock { margin-top: 6px; }
.plus-group { font-size: .78rem; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; color: var(--ink-3); margin: 16px 0 6px; }
.plus-list { margin: 0; padding: 0 0 0 20px; color: var(--ink-2); font-size: .92rem; line-height: 1.5; }
.plus-list li { margin: 2px 0; }
.plus-list.on { color: var(--ink); }
.plus-yours { margin: 16px 0 14px; font-weight: 600; color: var(--accent-ink); }
.btn.plus-price { display: flex; flex-direction: column; align-items: center; gap: 2px; }
.btn.plus-price span { font-size: .8rem; font-weight: 500; }   /* full strength: ≥ 4.5:1 on the light theme's gold button too */
/* the website's plan sheet: "I'm 18 or older" above the plans, which stay faded and inactive until it is ticked (js/paywall.js) */
.btn.plus-price:disabled { opacity: .45; cursor: default; }
.check.plus-adult { margin: 0 0 12px; font-size: .95rem; color: var(--ink); }
/* 2026-10-06, the website's plan sheet only (js/paywall.js — never the store apps): the 30-day money-back guarantee,
   first under "With a membership" and again at the plan buttons, and the payment sentence under them. The guarantee is
   prominent on purpose (founder decision): a gold outline on the lifted surface, its lead in the gold of the eyebrow
   labels (≥ 4.5:1 in both themes). No display is set on .plus-guarantee, so its `hidden` attribute hides it. */
.plus-guarantee { margin: 2px 0 10px; padding: 11px 14px; border: 1.5px solid var(--eyebrow); border-radius: 12px; background: var(--lift);
  color: var(--ink); font-size: .95rem; line-height: 1.45; }
.plus-guarantee b { color: var(--eyebrow); font-weight: 700; }
.plus-guarantee.at-buy { margin: 0 0 14px; }
.plus-guarantee.at-buy b { display: block; margin-bottom: 3px; font-size: 1.06rem; line-height: 1.3; }
.plus-pay { display: flex; align-items: flex-start; gap: 9px; margin: 14px 0 0; color: var(--ink); font-size: .95rem; font-weight: 600; line-height: 1.45; }
.plus-pay svg { flex: 0 0 auto; margin-top: 2px; }
.plus-paylink { margin: 4px 0 0 27px; font-size: .8rem; }
.plus-history-list { max-height: 320px; overflow-y: auto; margin-bottom: 12px; }
.plus-history-list li { font-size: .9rem; }
.rem-sep { border-top: 1px solid var(--line); margin: 18px 0 14px; }
/* the status line under a reminder / payment action (the same look as the feedback box's) */
.rem-status, .plus-status { font-size: .9rem; margin: 10px 0 0; min-height: 1px; }
.rem-steps { margin: 6px 0 0; padding-left: 22px; line-height: 1.5; }
.rem-steps li { margin: 6px 0; }
/* the reminder time: the same field look as the text inputs, a finger-sized target */
input[type="time"] { width: 100%; min-height: 48px; background: var(--bg-2); border: 1px solid var(--line); color: var(--ink);
  border-radius: 10px; padding: 10px 12px; font: inherit; color-scheme: dark; }
[data-theme="light"] input[type="time"] { color-scheme: light; }

/* ── "Connect a wearable" (js/wearables.js): one big button per source — its name, and "✓ connected ›" once it is. A
   source that can't be connected here (Apple Health outside the iPhone app) is a dashed, flat button with a readable
   note. Its sheet also opens over the onboarding's sleep popup (a .runner, 50). ── */
.wear-btns { display: flex; flex-direction: column; gap: 10px; margin-top: 14px; }
.wear-btn { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 2px 12px; text-align: left; }
.wear-btn .wear-name { min-width: 0; overflow-wrap: anywhere; }
.wear-btn .wear-state { display: inline-flex; align-items: center; gap: 4px; margin-left: auto; font-size: .88rem; color: var(--accent-ink); }
.wear-btn .wear-state svg { color: var(--chev); }
.wear-btn:disabled { cursor: default; background: transparent; border-style: dashed; color: var(--ink-3); }
.wear-btn:disabled:hover { border-color: var(--line); }
.wear-btn:disabled .wear-state { color: var(--ink-3); font-weight: 500; }
.wear-msg { font-size: .82rem; color: var(--ink-3); }
.wear-msg:not(:empty) { margin-top: 10px; }
.sheet.wear-sheet { z-index: 55; }

/* ── v92-sci: "The science behind the tests" (js/science.js) — the app's own type, cards and colours, in both themes.
   The sheet also opens over a test's start screen, so it sits above the test runner (50); the status-bar scrim (60)
   stays on top. A source's long address breaks anywhere rather than running past a 320 px screen. ── */
.sheet.sci-sheet { z-index: 55; }
.sheet.privacy-sheet { z-index: 55; }   /* the Privacy notice also opens from the Plus sheet (a .runner, z 50) */
.sci-card h2 { margin-bottom: .45em; }
.sci-card h3 { margin: 1.15em 0 .3em; }
.sci-card > :last-child { margin-bottom: 0; }
.sci-lead { font-weight: 600; color: var(--ink); }
.sci-src { margin: 0; padding-left: 1.7em; color: var(--ink-2); font-size: .9rem; line-height: 1.45; }
.sci-src li { margin-bottom: 10px; overflow-wrap: anywhere; }
.sci-src li:last-child { margin-bottom: 0; }
.sci-foot { font-size: .86rem; margin: 0 4px 10px; }
/* "About this test ›": a link-look button — on its own line under a test's chart (.row, a 44 px target), or at the end
   of the start screen's one quiet line (a 44 px target made of padding, so the line keeps its height) */
.sci-link { font: inherit; color: var(--accent-2-ink); background: none; border: none; padding: 0; cursor: pointer; }
.sci-link.row { display: flex; align-items: center; justify-content: center; width: fit-content; max-width: 100%; min-height: 44px;
  margin: 10px auto 0; padding: 0 8px; }
.sci-oneliner .sci-link { display: inline-block; padding: 12px 4px; margin: -12px -4px; font-weight: 600; }

/* ── e1e (behind js/config.js BASELINE_FEATURES): the guided tour (js/tour.js), the first-time explainers and their "?"
   (js/explain.js). The tour dims the whole screen except one or two spotlights (an SVG with holes) and sits above
   everything else, the status-bar scrim included; an explainer sits above a detail sheet. Nothing slides for someone who
   asked their device for reduced motion. ── */
.tour { position: fixed; inset: 0; z-index: 70; }
.tour-dim { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }
.tour-dim path { fill: rgba(6,14,19,.74); }
[data-theme="light"] .tour-dim path { fill: rgba(18,36,46,.58); }
.tour-ring { position: absolute; border: 2px solid var(--gold-mid); border-radius: 16px; pointer-events: none;
  transition: top .28s ease, left .28s ease, width .28s ease, height .28s ease; }
[data-theme="light"] .tour-ring { border-color: var(--gold-top); }
.card.tour-card { position: absolute; width: min(420px, calc(100vw - 24px)); max-height: calc(100vh - 24px); overflow-y: auto;
  margin: 0; padding: 14px 18px 16px; transition: top .28s ease, left .28s ease; }
.tour-card h2 { font-size: 1.2rem; margin: 4px 0 6px; outline: none; }
.tour-card p { margin: 0; color: var(--ink-2); font-size: .95rem; line-height: 1.45; }
.tour-top { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.tour-count { font-size: .8rem; color: var(--ink-2); letter-spacing: .04em; font-weight: 600; }
.tour-skip, .help-q { font: inherit; background: none; border: none; cursor: pointer; }
.tour-skip { min-height: 44px; padding: 0 16px; color: var(--ink); font-size: .9rem; font-weight: 600; border-radius: 999px;
  border: 1px solid var(--ink-3); background: var(--card-2); }
.tour-prog { height: 4px; margin: 8px 0 2px; border-radius: 2px; background: var(--surf-hi-2); overflow: hidden; }
.tour-prog b { display: block; height: 100%; border-radius: 2px; background: var(--accent); }
.tour-btns { display: flex; gap: 10px; margin-top: 16px; }
.tour-btns .btn { flex: 1 1 0; min-width: 0; }
.tour-btns .btn.primary { flex: 2 1 0; }
/* the small key under a card's text: the chart's marks (a picture beside each line) or the tag labels (the label above
   its line) */
.tour-keys { margin-top: 8px; }
.tour-key { display: flex; gap: 12px; align-items: flex-start; padding: 8px 0 0; margin-top: 8px; border-top: 1px solid var(--line); }
.tour-key p { margin: 0; color: var(--ink); font-size: .9rem; line-height: 1.38; }
.tour-key-ico { flex: 0 0 40px; padding-top: 2px; }
.tour-key-ico svg { display: block; }
.tour-key.pill { display: block; }
.tour-key.pill .tag-pill { display: inline-block; margin-bottom: 4px; }
.tour-card button:focus-visible, .explain-card button:focus-visible, .help-q:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
@media (prefers-reduced-motion: reduce) { .tour-ring, .card.tour-card { transition: none; } }
/* the tour's example results (js/tourdemo.js): the "Example" label on the top edge of every example card, and the examples
   drawn inside the tour over the tab (a test's result, a test's chart) — under its dim, as the real screens would be */
.tour-ex-card { position: relative; }
.hero-card.tour-ex-card { overflow: visible; }
.tour-ex { position: absolute; top: -9px; left: 16px; z-index: 2; padding: 4px 9px; border-radius: 7px; line-height: 1;
  font-size: .7rem; font-weight: 700; letter-spacing: .1em; text-transform: uppercase;
  background: var(--accent-fill); color: var(--on-accent); pointer-events: none; }
.tour-stage { position: absolute; inset: 0; overflow: hidden; background: var(--bg-grad); text-align: left; }
.tour-stage.pop { padding: max(3vh, var(--sat)) 16px 0; }
/* the "?" that opens an explainer again: a 44 px target around a small ring */
.help-q { flex: 0 0 auto; width: 44px; height: 44px; padding: 0; display: inline-flex; align-items: center; justify-content: center; border-radius: 50%; }
.help-q span { width: 26px; height: 26px; border-radius: 50%; border: 1.5px solid var(--accent); color: var(--accent-ink);
  font-size: .85rem; font-weight: 700; line-height: 1; display: flex; align-items: center; justify-content: center; }
.help-q:hover span { background: var(--surf-hi-2); }
.sheet-head .help-q { margin-left: auto; }
.help-row { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin: -10px -8px -8px 0; }
.help-row .eyebrow { margin-bottom: 0; }
.explain-ov { position: fixed; inset: 0; z-index: 57; display: flex; align-items: flex-end; justify-content: center; overflow-y: auto;
  background: rgba(6,14,19,.62); padding: 16px 12px max(16px, var(--sab)); }
[data-theme="light"] .explain-ov { background: rgba(18,36,46,.45); }
@media (min-width: 600px) { .explain-ov { align-items: center; } }
.card.explain-card { width: min(480px, 100%); margin: 0; max-height: calc(100vh - 32px); overflow-y: auto; }
.explain-card h2 { font-size: 1.2rem; margin: 2px 0 8px; outline: none; }
.explain-card .explain-intro { color: var(--ink); font-size: .95rem; line-height: 1.45; margin: 0 0 4px; }
.explain-row { display: flex; gap: 12px; align-items: flex-start; padding: 10px 0; border-top: 1px solid var(--line); }
.explain-row p { margin: 0; color: var(--ink); font-size: .93rem; line-height: 1.42; }
.explain-key { flex: 0 0 40px; padding-top: 2px; }
.explain-key svg { display: block; }
.explain-row.pill-row { display: block; }
.explain-row.pill-row .tag-pill { display: inline-block; margin-bottom: 5px; }

/* ── The dark theme's gold (research/brand-2026-09-28/dark-theme-brief.md) ─────────────────────────────────────────
   The logo's gold, always its exact top-to-bottom gradient (or a solid point of it on something too thin), on a
   few chosen elements only — the brand mark, the primary button (above), the Today ring, the active tab, a chosen
   option, the main score line of a chart with its band, and the eyebrow labels (--eyebrow). Nothing else is gold.
   These rules are the base for BOTH themes; the light theme's block at the end of this file restyles what they
   draw for its pale paper (deeper golds for lines and text). ── */
:root {
  /* a chosen option: its surface lifted, the gold as a fine outline — the same everywhere */
  --sel-fill: linear-gradient(var(--lift), var(--lift)) padding-box, var(--gold-grad) border-box;
}
:root .chip.on,
:root .seg button.on,
:root .dayswitch button.on,
:root .routine.on,
:root .rate-btn.on,
:root .exp-opt.on {
  background: var(--sel-fill); border: 1px solid transparent; color: var(--ink-head); font-weight: 700;
}
:root .exp-opt.on { padding: 10px 12px; }
:root .exp-opt.on .muted { color: var(--ink-2); }
/* the active tab: a short gold bar on the tab bar's top edge; its icon and name in the body colour */
:root .nav-btn.on { color: var(--ink); }
:root .nav-btn.on::before {
  content: ""; position: absolute; top: -9px; left: 50%; width: 26px; height: 3px; margin-left: -13px;
  border-radius: 0 0 3px 3px; background: var(--gold-grad);
}
/* the Today ring: the gold gradient (js/app.js draws both gradients) */
:root .hero-arc { stroke: url(#hgGold); }
/* charts: the main score line in the gold gradient (each chart defines its own, js/charts.js), its dots, band and area
   in the gold's middle tone; tag markers and the tooltip button stay in the quiet steel. No glow pass. */
:root svg.chart,
:root svg.hero-spark { --accent: var(--gold-mid); }
:root svg.chart .chart-line { stroke: var(--chart-gold, var(--gold-mid)); }
:root svg.chart .chart-line[filter] { display: none; }
:root svg.chart rect[fill-opacity="0.13"] { fill-opacity: .11; }   /* the usual range (tests and overall score) */
:root svg.chart #areaGrad stop:first-child,
:root svg.chart #idxGrad stop:first-child { stop-opacity: .08; }
:root svg.chart .chart-tagdot { fill: #a6c3d3; }
:root svg.chart .chart-details rect { fill: #a6c3d3; stroke: #a6c3d3; }
:root svg.hero-spark .spark-line { stroke: url(#hsGold); }
:root svg.hero-spark #hsg stop:first-child { stop-opacity: .14; }
/* no ambient glow in the overall card */
:root .hero-card::before { display: none; }
/* the working-memory board: a firm edge on the blocks (they are a near-invisible navy-on-navy without it; ≥ 3:1 —
   the same fix the light theme carries in its block below) */
:root #grid { --line: rgba(241,225,191,.5); }

/* ── THE light theme (the founder's pick, 30 Sep 2026 — the former "Light B") ─────────────────────────────────────────
   The logo on a very light tint of its own navy (a cool blue-grey paper). Built only
   from the logo: navy #12242E for text and structure; the gold gradient #F1E1BF → #B6A172 for the primary button, a
   chosen option and the frames (the gold edge along the top of a card, the overall card, the icon badges); where the
   gold has to work as a thin line or as text on the pale paper, a deeper gold of the same hue: --gold-line → --gold-ink
   for the score lines (charts and the Trends preview, ≥ 3:1 all the way), --gold-light → --gold-ink for the Today ring
   (it repeats the count written inside it), --gold-line for the active tab and a chosen option's edge, --gold-ink
   (≥ 4.5:1 on every surface) for gold text. Icons, dots, the week strip, the test squares and the tag labels use a
   steel of the navy, as the dark theme does. Every text colour reaches 4.5:1 on the surfaces it sits on. The gold
   rules above (:root …) also match this theme; the rules at the end of this block restyle what they draw for the
   pale paper. Set with <html data-theme="light"> (js/app.js applyTheme, index.html). ── */
[data-theme="light"] {
  --ink-head: #12242e;       /* headings — the logo's navy */
  --ink: #1b2e39;            /* body */
  --ink-2: #3a4f5b;          /* secondary */
  --ink-3: #516b79;          /* tertiary */
  --gold-light: #c6a254;     /* the top of the Today ring's gradient */
  --gold-line: #9e7d35;      /* the gold as a thin line: ≥ 3:1 on every surface */
  --gold-ink: #7f642a;       /* the gold as text (eyebrow labels, disclaimer titles): ≥ 4.5:1 on every surface */
  --eyebrow: var(--gold-ink);
  --steel: #3d6c85;          /* the navy's steel: icons, dots, week strip, test squares, tag markers — NOT gold */
  --accent: var(--steel);
  --accent-2: #5d8aa3;
  --accent-3: #7982c3;       /* the sleep line on the overall chart — a soft periwinkle, under the score line */
  --accent-soft: #a9c3d1;
  --accent-ink: #35657e;
  --accent-2-ink: #245f80;   /* links */
  --accent-fill: #35657e;
  --accent-2-fill: #3f7089;
  --on-accent: #ffffff;
  --lift: #fcf8ef;
  --warn: var(--gold-bottom);
  --warn-ink: var(--gold-ink);
  --cap-neg: #5f696f;
  --neg-ink: #b02e3c;
  --danger: #b02e3c;
  --tap-bg: var(--ink-2);
  --tap-ink: #ffffff;
  --chart-b: #1d7373;
  --baseline-trailing: #8e4e9b;
  --chart-main: var(--gold-line);
  --chev: #70848f;
  --primary-grad: var(--gold-grad);   /* the logo's own gradient with navy text (12.3:1 at the top, 6.3:1 at the bottom) */
  --on-primary: var(--navy);
  --primary-shadow: inset 0 0 0 1px rgba(158,125,53,.45), 0 6px 16px -10px rgba(127,100,42,.5);
  --ev-none: #89949b; --ev-weak: #d0574c; --ev-mixed: #c78420; --ev-strong: #2f9168;   /* dots: ≥ 3:1 on white */
  --ev-none-ink: #5f696f; --ev-weak-ink: #b8343f; --ev-mixed-ink: #8c5e10; --ev-strong-ink: #1d7550;
  --card: #ffffff;
  --card-grad: linear-gradient(transparent, transparent);
  --hairline: rgba(182,161,114,.85);   /* the gold edge along the top of every card */
  --inset-hi: inset 0 0 0 0 transparent;
  --surf-hi: rgba(18,36,46,.035);
  --surf-hi-2: rgba(18,36,46,.07);
  --track-center: rgba(18,36,46,.3);
  --accent-glow: transparent;
  --hero-grad: #ffffff;
  --hero-border: rgba(182,161,114,.65);   /* the overall card: a gold frame */
  --hero-glow: rgba(61,108,133,.2);
  --chart-panel: rgba(18,36,46,.018);
  --chart-panel-stroke: rgba(18,36,46,.07);
  --chart-grid: rgba(18,36,46,.08);
  --gl-stroke: var(--ink-2);
  --warn-bg: rgba(241,225,191,.28);
  --warn-bd: rgba(182,161,114,.6);
  --badge: radial-gradient(135% 135% at 32% 22%, rgba(18,36,46,.07), rgba(18,36,46,.03) 55%, rgba(255,255,255,.8) 100%);
  --badge-shadow: inset 0 0 0 1px rgba(182,161,114,.6);   /* a gold ring round the icon badges and the avatar */
  --lab-1: #1e6baa;
  --sleep-1: #2c7630;
  /* a chosen option: the logo's gradient with navy text, edged in the deeper gold */
  --sel-fill: var(--gold-grad) padding-box, linear-gradient(var(--gold-line), var(--gold-line)) border-box;
  --bg: #ebf1f4;             /* the paper: the logo's navy hue (201°), very light */
  --bg-2: #e4ebef;
  --card-2: #f4f7f9;
  --line: rgba(18,36,46,.11);
  --bg-grad: linear-gradient(180deg, #f0f4f7 0px, var(--bg) 460px);
  --glass: #ebf1f4;   /* opaque — see the dark theme's note */
  --elev: 0 1px 2px rgba(18,36,46,.04), 0 10px 26px -20px rgba(18,36,46,.22);
  --elev-hero: 0 1px 2px rgba(18,36,46,.04), 0 14px 30px -22px rgba(18,36,46,.26);
}
/* What the tokens can't reach. The gold gradients js/app.js (#hgGold), js/trends.js (#hsGold) and js/charts.js
   (mpGold…) write in with the logo's colours, restyled into the deeper gold (CSS outranks an SVG's own stop colours);
   the chart's dots, band and tooltip ring in the gold line colour, its usual range in the logo's light gold; tag
   markers and the tooltip button in the steel. The working-memory squares with a firm edge (and white on the paper).
   The second line of a chosen option, and the speed test's right/wrong flash, readable on their colours. Light
   date/time pickers. (The brand mark as the app icon, the danger button's edge and the light pickers are set next to
   their components above.) */
[data-theme="light"] .nav-btn.on::before { background: var(--gold-line); }
[data-theme="light"] #hgGold stop:first-child { stop-color: var(--gold-light); }
[data-theme="light"] :is(#hsGold, [id^="mpGold"]) stop:first-child { stop-color: var(--gold-line); }
[data-theme="light"] :is(#hgGold, #hsGold, [id^="mpGold"]) stop:last-child { stop-color: var(--gold-ink); }
[data-theme="light"] svg.chart,
[data-theme="light"] svg.hero-spark { --accent: var(--gold-line); }
[data-theme="light"] svg.chart rect[fill-opacity="0.13"] { fill: var(--gold-top); fill-opacity: .5; }
[data-theme="light"] svg.chart .chart-tagdot { fill: var(--steel); }
[data-theme="light"] svg.chart .chart-details rect { fill: var(--steel); stroke: var(--steel); }
[data-theme="light"] #grid { --line: rgba(18,36,46,.5); --bg-2: var(--card); }   /* the squares' edge ≥ 3:1, white on the paper */
[data-theme="light"] .opt.ok,
[data-theme="light"] .opt.bad { color: #ffffff; }
[data-theme="light"] .routine.on .r-tags { opacity: .9; }   /* 5.3:1 on the gold (at .8: 4.45) */
[data-theme="light"] .exp-opt.on .muted { color: var(--ink); }   /* 5.6:1 on the gold (--ink-2: 3.4) */
[data-theme="light"] .dim { fill: rgba(18,36,46,.16); }
