/**
 * css/components/onboarding-thread.css
 * 02 Oct 2026 v10
 *
 * v10 - W4-19. Consent text at body size and colour: the list, the ticks'
 *      labels, the notes and the links were 15px, and the list and notes
 *      the secondary grey, on the screen people agree on. The typed year
 *      (.age-q__year).
 *
 * v9 - W4-6. .ob-consent__restore: Restore from a file on the consent
 *      screen. The file input is visually hidden but focusable; its label is
 *      the button, and shows the focus ring when the input has focus.
 *
 * v8 - AGE-CHECK. The age question (.age-q*, shared by onboarding and the
 *      age-check screen) and the under-18 screen (.u18-*).
 *
 * 01 Oct 2026 v7
 *
 * v7 - PT-2 HEALTH-CONSENT. .ob-consent__note under the second tick, and
 *      the health-consent screen (.hc-*), which reuses the drawn checkbox.
 *
 * v6 - Six text uses and one hardcoded #E8F4F4 repointed to --color-text.
 *      SURFACE-TOKEN, 05 Sep 2026. `color: var(--color-surface, #E8F4F4)`
 *      was a BACKGROUND token doing a text job, and it was already
 *      broken: in the light scheme #E8F4F4 on #F8FAFC measures 1.07:1,
 *      so anyone on SCHEME-1 had invisible text. A live WCAG 1.4.3
 *      failure found while fixing something else. --color-text adapts
 *      per scheme: 11.87:1 dark, 17.06:1 light, 21.00:1 high-contrast.
 *
 * v5 — WOW-0. Styles for the new consent gate (.ob-consent*), which runs
 *   before Step 1. Every token below confirmed against css/base/
 *   variables.css before use, not assumed. Accessibility notes:
 *   - The Continue button uses aria-disabled + .is-inactive, never the
 *     HTML disabled attribute, so it stays focusable and announced. Its
 *     inactive state is 0.55 opacity, matching tier-gating.css's chosen
 *     value rather than inventing a third one (see PT-7).
 *   - Checkbox target is 24px with a 44px minimum row height, meeting
 *     WCAG 2.2 AA SC 2.5.8 Target Size (Minimum).
 *   - Links are underlined, not colour-only, for SC 1.4.1 Use of Colour.
 *   - :focus-visible outlines use --color-border-focus throughout.
 *
 * v4 — Gemini QA reported the past-step fade was not visible at all
 *   (C1/C2 FAIL). Investigated with full DevTools verification rather
 *   than guessing: confirmed via getComputedStyle on a live faded
 *   bubble that the JS, class application, and CSS rule were ALL
 *   working exactly as intended (#142525/#9FB8B8, matching source
 *   precisely). The actual issue was a design judgement, not a bug —
 *   the background colour difference between active and faded states
 *   was only 12/765, invisible at a glance even though technically
 *   correct. Widened to #0A1414 (56/765 difference) while reconfirming
 *   text contrast stays comfortably above WCAG AA (7.42:1).
 *
 * v3 — WCAG contrast fix for the past-step fade. The original
 *   opacity: 0.45 approach measured ~3.9:1 contrast (fails AA 4.5:1
 *   minimum) because dimming the whole bubble shrinks the gap between
 *   its already-dark background and its light text. Replaced with a
 *   solid colour swap (#9FB8B8 on #142525, measures 7.59:1) that reads
 *   as visually muted without ever dropping below AA. See thread.js v3
 *   for the matching JS timing fix.
 *
 * v2 — Post-QA revision: added .ob-header (sticky wordmark), .ob-gate
 *   (reflection consent buttons), .ob-continue-wrap/.ob-continue-btn
 *   (active-pace Continue tap), and .ob-bubble--coach.is-past (the
 *   past-step fade — Option A from the visual-overwhelm review).
 *
 * OB-THREAD conversational UI.
 * Coach bubbles (left-aligned), user bubbles (right-aligned),
 * typing indicator, inline chip trays, inline text input bar,
 * and the Step 0 splash screen.
 *
 * Imported by css/main.css.
 * No layout rules here — thread.js mounts inside the app shell.
 * WCAG 2.2 AA throughout: min 44px tap targets, focus-visible rings,
 * prefers-reduced-motion respected.
 */

/* ─────────────────────────────────────────────────────────────────────────────
   STEP 0 — WORDMARK SPLASH
   Full-screen. Deep navy. Alongside wordmark centred.
   thread.js handles the 1500ms fade-in / fade-out sequence.
───────────────────────────────────────────────────────────────────────────── */

.ob-splash {
  position: fixed;
  inset: 0;
  background: var(--color-dark, #0D1F1F);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 200;
  opacity: 0;
  transition: opacity 400ms ease;
}

.ob-splash.is-visible {
  opacity: 1;
}

.ob-splash__wordmark {
  font-size: calc(2rem * var(--user-text-scale, 1));
  font-weight: 700;
  color: #ffffff;
  letter-spacing: 0.04em;
  /* The wordmark is decorative at this moment — aria-hidden on the element */
}

/* ─────────────────────────────────────────────────────────────────────────────
   THREAD WRAPPER
   Scrollable column. Occupies full viewport minus bottom input bar.
   nav is hidden during onboarding (router handles this).
───────────────────────────────────────────────────────────────────────────── */

.ob-thread {
  display: flex;
  flex-direction: column;
  min-height: 100dvh;
  background: var(--color-dark, #0D1F1F);
  padding-bottom: 80px; /* space for the input bar fixed at bottom */
}

.ob-thread__scroll {
  flex: 1;
  overflow-y: auto;
  padding: 24px 16px 16px;
  display: flex;
  flex-direction: column;
  gap: 0; /* gaps handled per-bubble via margin */
  -webkit-overflow-scrolling: touch;
  scroll-behavior: smooth;
}

/* ─────────────────────────────────────────────────────────────────────────────
   BUBBLES — SHARED BASE
───────────────────────────────────────────────────────────────────────────── */

.ob-bubble {
  max-width: 88%;
  padding: 14px 16px;
  border-radius: 18px;
  font-size: calc(1rem * var(--user-text-scale, 1));
  line-height: 1.55;
  word-break: break-word;
  opacity: 0;
  transition: opacity 300ms ease;
}

.ob-bubble.is-visible {
  opacity: 1;
}

@media (prefers-reduced-motion: reduce) {
  .ob-bubble {
    transition: none;
    opacity: 1;
  }
}

/* ─────────────────────────────────────────────────────────────────────────────
   COACH BUBBLE — left-aligned
   Deep teal-tinted surface. Near-white text.
───────────────────────────────────────────────────────────────────────────── */

.ob-bubble--coach {
  align-self: flex-start;
  background: #162A2A; /* slightly lighter than --color-dark, coach surface */
  color: var(--color-text);   /* v6: was #E8F4F4, invisible in light scheme */
  border-bottom-left-radius: 4px;
  margin-top: 16px;
  margin-bottom: 4px;
}

/* Coach bubble that directly follows another coach bubble (no extra gap) */
.ob-bubble--coach + .ob-bubble--coach {
  margin-top: 4px;
}

/* Sequential-reveal parts: each part is a separate coach bubble */
.ob-bubble--coach.ob-bubble--part {
  margin-top: 0;
  border-radius: 12px;
}

.ob-bubble--coach.ob-bubble--part:first-of-type {
  border-top-left-radius: 18px;
}

.ob-bubble--coach.ob-bubble--part:last-of-type {
  border-bottom-left-radius: 4px;
  margin-bottom: 4px;
}

/* ─────────────────────────────────────────────────────────────────────────────
   USER BUBBLE — right-aligned
   Brand teal. White text.
───────────────────────────────────────────────────────────────────────────── */

.ob-bubble--user {
  align-self: flex-end;
  background: var(--color-primary, #1B6B6B);
  color: #ffffff;
  border-bottom-right-radius: 4px;
  margin-top: 4px;
  margin-bottom: 16px;
  white-space: pre-line; /* preserves \n line breaks in summary bubbles */
}

/* ─────────────────────────────────────────────────────────────────────────────
   TYPING INDICATOR
   Three dots. Coach surface. Animates while coach "thinks".
   thread.js shows this before each coach message, then replaces it.
───────────────────────────────────────────────────────────────────────────── */

.ob-typing {
  align-self: flex-start;
  background: #162A2A;
  border-radius: 18px;
  border-bottom-left-radius: 4px;
  padding: 14px 18px;
  margin-top: 16px;
  display: flex;
  align-items: center;
  gap: 5px;
  opacity: 0;
  transition: opacity 200ms ease;
}

.ob-typing.is-visible {
  opacity: 1;
}

@media (prefers-reduced-motion: reduce) {
  .ob-typing {
    transition: none;
    opacity: 1;
  }
}

.ob-typing__dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--color-muted, #6B8585);
  animation: ob-dot-pulse 1.2s ease-in-out infinite;
}

.ob-typing__dot:nth-child(2) { animation-delay: 0.2s; }
.ob-typing__dot:nth-child(3) { animation-delay: 0.4s; }

@keyframes ob-dot-pulse {
  0%, 80%, 100% { opacity: 0.3; transform: scale(0.85); }
  40%            { opacity: 1;   transform: scale(1);    }
}

@media (prefers-reduced-motion: reduce) {
  .ob-typing__dot {
    animation: none;
    opacity: 0.6;
  }
}

/* ─────────────────────────────────────────────────────────────────────────────
   CHIP TRAY — inline multi-select and single-select
   Appears in the thread below a coach bubble.
   Chips wrap naturally. Confirm button below chips (multi-select only).
───────────────────────────────────────────────────────────────────────────── */

.ob-chips {
  align-self: stretch;
  margin: 8px 0 4px;
  opacity: 0;
  transition: opacity 300ms ease;
}

.ob-chips.is-visible {
  opacity: 1;
}

@media (prefers-reduced-motion: reduce) {
  .ob-chips { transition: none; opacity: 1; }
}

.ob-chips__wrap {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  padding: 4px 0;
}

/* Individual chip */
.ob-chip {
  display: inline-flex;
  align-items: center;
  padding: 10px 16px;
  min-height: 44px; /* WCAG 2.2 AA tap target */
  border-radius: 22px;
  border: 1.5px solid var(--color-mid, #2C3E3E);
  background: transparent;
  color: var(--color-text);
  font-size: calc(0.9rem * var(--user-text-scale, 1));
  line-height: 1.3;
  cursor: pointer;
  transition: background 150ms ease, border-color 150ms ease, color 150ms ease;
  text-align: left;
  -webkit-tap-highlight-color: transparent;
}

.ob-chip:hover {
  border-color: var(--color-primary, #1B6B6B);
  background: rgba(27, 107, 107, 0.15);
}

.ob-chip:focus-visible {
  outline: 3px solid var(--color-primary, #1B6B6B);
  outline-offset: 2px;
}

/* Selected state */
.ob-chip.is-selected {
  background: var(--color-primary, #1B6B6B);
  border-color: var(--color-primary, #1B6B6B);
  color: #ffffff;
}

/* Skip chip — muted styling */
.ob-chip--skip {
  border-color: transparent;
  color: var(--color-muted, #6B8585);
  font-size: calc(0.85rem * var(--user-text-scale, 1));
  padding: 10px 12px;
}

.ob-chip--skip:hover {
  color: var(--color-text);
  background: transparent;
  border-color: transparent;
}

/* Disabled state — after confirmation */
.ob-chip:disabled,
.ob-chips.is-locked .ob-chip {
  pointer-events: none;
  opacity: 0.5;
}

@media (prefers-reduced-motion: reduce) {
  .ob-chip { transition: none; }
}

/* Confirm button — multi-select only. Below chip wrap. */
.ob-chips__confirm {
  display: block;
  width: 100%;
  margin-top: 12px;
  padding: 14px 24px;
  min-height: 52px;
  border-radius: 12px;
  border: none;
  background: var(--color-primary, #1B6B6B);
  color: #ffffff;
  font-size: calc(1rem * var(--user-text-scale, 1));
  font-weight: 600;
  cursor: pointer;
  transition: background 100ms ease, opacity 150ms ease;
  -webkit-tap-highlight-color: transparent;
}

.ob-chips__confirm:hover {
  background: #155858;
}

.ob-chips__confirm:focus-visible {
  outline: 3px solid var(--color-primary, #1B6B6B);
  outline-offset: 3px;
}

.ob-chips__confirm:disabled {
  opacity: 0.4;
  cursor: default;
}

@media (prefers-reduced-motion: reduce) {
  .ob-chips__confirm { transition: none; }
}

/* ─────────────────────────────────────────────────────────────────────────────
   INLINE TEXT INPUT BAR
   Fixed to bottom of screen during Step 2 (name entry).
   Replaced by the sheet trigger bar or chip tray for other steps.
───────────────────────────────────────────────────────────────────────────── */

.ob-input-bar {
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 12px 16px;
  padding-bottom: calc(12px + env(safe-area-inset-bottom));
  background: #0D1F1F;
  border-top: 1px solid var(--color-mid, #2C3E3E);
  z-index: 50;
  opacity: 0;
  transform: translateY(8px);
  transition: opacity 250ms ease, transform 250ms ease;
}

.ob-input-bar.is-visible {
  opacity: 1;
  transform: translateY(0);
}

@media (prefers-reduced-motion: reduce) {
  .ob-input-bar { transition: none; opacity: 1; transform: none; }
}

.ob-input-bar__field {
  flex: 1;
  padding: 12px 16px;
  min-height: 48px;
  border-radius: 24px;
  border: 1.5px solid var(--color-mid, #2C3E3E);
  background: #162A2A;
  color: var(--color-text);
  font-size: calc(1rem * var(--user-text-scale, 1));
  outline: none;
  transition: border-color 150ms ease;
}

.ob-input-bar__field::placeholder {
  color: var(--color-muted, #6B8585);
}

.ob-input-bar__field:focus {
  border-color: var(--color-primary, #1B6B6B);
}

@media (prefers-reduced-motion: reduce) {
  .ob-input-bar__field { transition: none; }
}

.ob-input-bar__send {
  flex-shrink: 0;
  width: 48px;
  height: 48px;
  border-radius: 50%;
  border: none;
  background: var(--color-primary, #1B6B6B);
  color: #ffffff;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: background 100ms ease, opacity 150ms ease;
  -webkit-tap-highlight-color: transparent;
}

.ob-input-bar__send:hover { background: #155858; }
.ob-input-bar__send:disabled { opacity: 0.4; cursor: default; }

.ob-input-bar__send:focus-visible {
  outline: 3px solid var(--color-primary, #1B6B6B);
  outline-offset: 2px;
}

/* Send icon — inline SVG arrow */
.ob-input-bar__send svg {
  width: 20px;
  height: 20px;
  fill: #ffffff;
}

/* ─────────────────────────────────────────────────────────────────────────────
   SHEET TRIGGER BAR
   Shown instead of the text input bar for sheet steps.
   Two buttons: open label and skip label.
───────────────────────────────────────────────────────────────────────────── */

.ob-sheet-bar {
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 12px 16px;
  padding-bottom: calc(12px + env(safe-area-inset-bottom));
  background: #0D1F1F;
  border-top: 1px solid var(--color-mid, #2C3E3E);
  z-index: 50;
  opacity: 0;
  transform: translateY(8px);
  transition: opacity 250ms ease, transform 250ms ease;
}

.ob-sheet-bar.is-visible {
  opacity: 1;
  transform: translateY(0);
}

@media (prefers-reduced-motion: reduce) {
  .ob-sheet-bar { transition: none; opacity: 1; transform: none; }
}

.ob-sheet-bar__open {
  width: 100%;
  padding: 14px 24px;
  min-height: 52px;
  border-radius: 12px;
  border: none;
  background: var(--color-primary, #1B6B6B);
  color: #ffffff;
  font-size: calc(1rem * var(--user-text-scale, 1));
  font-weight: 600;
  cursor: pointer;
  transition: background 100ms ease;
  -webkit-tap-highlight-color: transparent;
}

.ob-sheet-bar__open:hover { background: #155858; }

.ob-sheet-bar__open:focus-visible {
  outline: 3px solid var(--color-primary, #1B6B6B);
  outline-offset: 3px;
}

.ob-sheet-bar__skip {
  width: 100%;
  padding: 10px 24px;
  min-height: 44px;
  border-radius: 12px;
  border: none;
  background: transparent;
  color: var(--color-muted, #6B8585);
  font-size: calc(0.9rem * var(--user-text-scale, 1));
  cursor: pointer;
  transition: color 100ms ease;
  -webkit-tap-highlight-color: transparent;
}

.ob-sheet-bar__skip:hover { color: var(--color-text); }

.ob-sheet-bar__skip:focus-visible {
  outline: 3px solid var(--color-primary, #1B6B6B);
  outline-offset: 2px;
}

@media (prefers-reduced-motion: reduce) {
  .ob-sheet-bar__open,
  .ob-sheet-bar__skip { transition: none; }
}

/* ─────────────────────────────────────────────────────────────────────────────
   BEGIN BUTTON — Step 14 closing moment
   Full-width. Fades in 600ms after closing coach message completes.
   Routes to today.js.
───────────────────────────────────────────────────────────────────────────── */

.ob-begin-wrap {
  padding: 24px 16px;
  padding-bottom: calc(24px + env(safe-area-inset-bottom));
}

.ob-begin {
  display: block;
  width: 100%;
  padding: 16px 24px;
  min-height: 56px;
  border-radius: 12px;
  border: none;
  background: var(--color-primary, #1B6B6B);
  color: #ffffff;
  font-size: calc(1.05rem * var(--user-text-scale, 1));
  font-weight: 700;
  cursor: pointer;
  opacity: 0;
  transition: opacity 400ms ease, background 100ms ease;
  -webkit-tap-highlight-color: transparent;
}

.ob-begin.is-visible { opacity: 1; }
.ob-begin:hover { background: #155858; }

.ob-begin:focus-visible {
  outline: 3px solid var(--color-primary, #1B6B6B);
  outline-offset: 3px;
}

@media (prefers-reduced-motion: reduce) {
  .ob-begin { transition: none; opacity: 1; }
}

/* ─────────────────────────────────────────────────────────────────────────────
   THREAD HEADER
   "Alongside: Move" wordmark fixed at top of the thread screen.
   Stays visible as the conversation scrolls below it.
───────────────────────────────────────────────────────────────────────────── */

.ob-header {
  position: sticky;
  top: 0;
  z-index: 10;
  background: var(--color-dark, #0D1F1F);
  padding: 16px 20px 12px;
  border-bottom: 1px solid #1A2E2E;
}

.ob-header__wordmark {
  display: block;
  font-size: calc(1rem * var(--user-text-scale, 1));
  font-weight: 700;
  color: var(--color-primary, #1B6B6B);
  letter-spacing: 0.02em;
}

/* Adjust thread scroll top padding to account for sticky header */
.ob-thread__scroll {
  padding-top: 16px;
}

/* ─────────────────────────────────────────────────────────────────────────────
   REFLECTION GATE — Step 4 consent question
   Two-button Y/N choice, same visual language as chips but styled as a
   deliberate pair rather than a tray (only ever two options here).
───────────────────────────────────────────────────────────────────────────── */

.ob-gate {
  align-self: stretch;
  margin: 8px 0 4px;
  opacity: 0;
  transition: opacity 300ms ease;
}

.ob-gate.is-visible { opacity: 1; }

@media (prefers-reduced-motion: reduce) {
  .ob-gate { transition: none; opacity: 1; }
}

.ob-gate__wrap {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.ob-gate__btn {
  width: 100%;
  padding: 14px 20px;
  min-height: 52px;
  border-radius: 12px;
  border: 1.5px solid var(--color-mid, #2C3E3E);
  background: transparent;
  color: var(--color-text);
  font-size: calc(1rem * var(--user-text-scale, 1));
  font-weight: 600;
  cursor: pointer;
  transition: background 150ms ease, border-color 150ms ease;
  -webkit-tap-highlight-color: transparent;
}

.ob-gate__btn:hover {
  border-color: var(--color-primary, #1B6B6B);
  background: rgba(27, 107, 107, 0.15);
}

.ob-gate__btn:focus-visible {
  outline: 3px solid var(--color-primary, #1B6B6B);
  outline-offset: 2px;
}

.ob-gate__btn--primary {
  background: var(--color-primary, #1B6B6B);
  border-color: var(--color-primary, #1B6B6B);
  color: #ffffff;
}

.ob-gate__btn--primary:hover { background: #155858; }

.ob-gate__btn:disabled {
  pointer-events: none;
  opacity: 0.5;
}

@media (prefers-reduced-motion: reduce) {
  .ob-gate__btn { transition: none; }
}

/* ─────────────────────────────────────────────────────────────────────────────
   SEQUENTIAL REVEAL — Continue tap
   Quiet, low-emphasis control under each reflection part. Deliberately
   understated — this is a pause for breath, not a decision point.
───────────────────────────────────────────────────────────────────────────── */

.ob-continue-wrap {
  display: flex;
  justify-content: center;
  margin: 12px 0 20px;
  opacity: 0;
  transition: opacity 400ms ease;
}

.ob-continue-wrap.is-visible { opacity: 1; }

@media (prefers-reduced-motion: reduce) {
  .ob-continue-wrap { transition: none; opacity: 1; }
}

.ob-continue-btn {
  padding: 10px 24px;
  min-height: 44px;
  border-radius: 22px;
  border: 1.5px solid var(--color-mid, #2C3E3E);
  background: transparent;
  color: var(--color-muted, #6B8585);
  font-size: calc(0.9rem * var(--user-text-scale, 1));
  font-weight: 500;
  cursor: pointer;
  transition: background 150ms ease, border-color 150ms ease, color 150ms ease;
  -webkit-tap-highlight-color: transparent;
}

.ob-continue-btn:hover {
  border-color: var(--color-primary, #1B6B6B);
  color: var(--color-text);
  background: rgba(27, 107, 107, 0.15);
}

.ob-continue-btn:focus-visible {
  outline: 3px solid var(--color-primary, #1B6B6B);
  outline-offset: 2px;
}

/* ─────────────────────────────────────────────────────────────────────────────
   PAST-STEP FADE (Option A — agreed, WCAG-corrected)
   Once a step is complete, its coach bubbles recede to signal "done" while
   the active step stays at full brightness. User bubbles remain full
   opacity always — they are the permanent record of what was said.

   IMPORTANT: this does NOT use opacity. Applying opacity to the bubble
   element dims foreground and background together, and because the
   background here is already dark, opacity actually shrinks the contrast
   gap rather than preserving it — at 45% opacity the original version
   measured ~3.9:1, below the 4.5:1 AA minimum for normal text. Fixed by
   setting solid, pre-calculated colours instead: #9FB8B8 on #142525
   measures 6.9:1, comfortably above AA, while still reading as visually
   muted against the full-brightness #E8F4F4 on #162A2A active bubble.
───────────────────────────────────────────────────────────────────────────── */

.ob-bubble--coach.is-past {
  /* v4: confirmed via direct DevTools inspection (computed styles
     matched the intended #142525/#9FB8B8 exactly) that the fade logic
     was working perfectly end to end — JS, class application, and CSS
     all correct. The actual problem: the background colour difference
     between active (#162A2A) and past (#142525) was only 12/765 —
     essentially invisible at a glance, which is exactly how Gemini's
     screenshot-based QA evaluated it (correctly reporting no visible
     fade, since there practically wasn't one). Widened to #0A1414,
     a 56/765 difference — meaningfully darker and visually distinct —
     while keeping text contrast at 7.42:1, comfortably above the 4.5:1
     WCAG AA minimum verified for the previous version. */
  background: #0A1414;
  color: #8FA8A8;
  transition: background 500ms ease, color 500ms ease;
}

@media (prefers-reduced-motion: reduce) {
  .ob-bubble--coach.is-past { transition: none; }
}


/* ─── Consent gate (11 Aug 2026 v5, WOW-0) ─────────────────────────────── */

.ob-consent {
  padding: var(--space-6) var(--space-5) var(--space-8);
  max-width: 34rem;
  margin: 0 auto;
}

.ob-consent__heading {
  font-size: var(--text-xl);
  font-weight: var(--font-semibold);
  color: var(--color-text);
  margin-bottom: var(--space-5);
}

.ob-consent__subheading {
  font-size: var(--text-base);
  font-weight: var(--font-semibold);
  color: var(--color-text);
  margin-bottom: var(--space-3);
}

.ob-consent__summary {
  background: var(--color-bg-elevated);
  border: 1px solid var(--color-border-light);
  border-radius: var(--radius-lg);
  padding: var(--space-4);
  margin-bottom: var(--space-5);
}

.ob-consent__list {
  margin: 0 0 var(--space-4);
  padding-left: var(--space-5);
}

.ob-consent__list li {
  font-size: var(--text-base);
  color: var(--color-text);
  margin-bottom: var(--space-2);
  line-height: 1.5;
}

.ob-consent__links {
  font-size: var(--text-base);
  color: var(--color-text);
  line-height: 1.6;
  margin: 0;
}

/* Underlined, not colour-only — WCAG 2.2 AA SC 1.4.1 */
.ob-consent__link {
  color: var(--color-primary);
  text-decoration: underline;
}

.ob-consent__link:focus-visible,
.ob-consent .btn-inline-link:focus-visible {
  outline: 3px solid var(--color-border-focus);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}

/* 44px minimum row — WCAG 2.2 AA SC 2.5.8 Target Size */
.ob-consent__tick {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  min-height: 44px;
  margin-bottom: var(--space-3);
}

/* CONSENT-1, 12 Aug 2026. Graeme, device pass: "I consented because of
   the colour change on continue, but the box should show a tick or be
   fully teal."

   He was right, and this is the worst place in the product for it. The
   only styling was accent-color, which on a dark background renders the
   native box as a hollow teal outline that looks near-identical checked
   and unchecked. The ONLY reliable signal that consent had registered was
   the Continue button brightening -- a different element, further down
   the screen, communicating by colour alone.

   That is a WCAG 1.4.1 failure (colour as the sole indicator) on the one
   control in the app with legal weight. Somebody could tap Continue
   believing they had not agreed, or agree without registering that they
   had.

   Now drawn explicitly: empty box with a visible border unchecked, filled
   with a tick when checked. Three signals rather than one -- fill, tick,
   and border weight -- so it survives greyscale and low vision.

   appearance:none is safe here because every state below is drawn by
   hand; the input keeps its native semantics and keyboard behaviour. */
.ob-consent__checkbox {
  appearance: none;
  -webkit-appearance: none;
  width: 24px;
  height: 24px;
  flex-shrink: 0;
  margin-top: 2px;
  background: var(--color-bg);
  border: 2px solid var(--color-text-secondary);
  border-radius: var(--radius-sm);
  cursor: pointer;
  display: grid;
  place-content: center;
  transition: background var(--transition-fast), border-color var(--transition-fast);
}

.ob-consent__checkbox::before {
  content: "";
  width: 13px;
  height: 13px;
  transform: scale(0);
  /* A tick drawn as a clip-path, so it needs no font, no icon file and no
     network request -- this screen must work on a first, offline-capable
     load before anything else has cached. */
  clip-path: polygon(14% 44%, 0 65%, 40% 100%, 100% 16%, 82% 0%, 37% 62%);
  background: var(--color-text-inverse);
}

.ob-consent__checkbox:checked {
  background: var(--color-primary);
  border-color: var(--color-primary);
}

.ob-consent__checkbox:checked::before { transform: scale(1); }

.ob-consent__checkbox:hover:not(:checked) { border-color: var(--color-primary); }

@media (prefers-reduced-motion: reduce) {
  .ob-consent__checkbox { transition: none; }
}

.ob-consent__checkbox:focus-visible {
  outline: 3px solid var(--color-border-focus);
  outline-offset: 2px;
}

.ob-consent__label {
  font-size: var(--text-base);
  color: var(--color-text);
  line-height: 1.5;
  cursor: pointer;
}

.ob-consent__error {
  font-size: var(--text-sm);
  color: var(--color-danger);
  margin-bottom: var(--space-3);
  font-weight: var(--font-medium);
}

/* Inactive, NOT disabled — stays focusable and announced. 0.55 matches
   tier-gating.css rather than introducing a third opacity value. */
.ob-consent__tick + .ob-consent__error + .btn.is-inactive,
.ob-consent .btn.is-inactive {
  opacity: 0.55;
  transition: opacity 150ms ease;
}

@media (prefers-reduced-motion: reduce) {
  .ob-consent .btn.is-inactive { transition: none; }
}

/* PT-2 HEALTH-CONSENT, 01 Oct 2026. The line under the health tick, and
   the screen that asks before the next health question. The checkbox is
   the same hand-drawn .ob-consent__checkbox (CONSENT-1: never colour
   alone). */
.ob-consent__note {
  font-size: var(--text-base);
  color: var(--color-text);
  margin: calc(-1 * var(--space-2)) 0 var(--space-3) calc(24px + var(--space-3));
}

.ob-consent__restore {
  display: grid;
  gap: var(--space-2);
  margin-top: var(--space-5);
  padding-top: var(--space-4);
  border-top: 1px solid var(--color-border);
}
.ob-consent__restore .ob-consent__note { margin: 0; }
.ob-consent__file {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}
.ob-consent__file:focus-visible + .ob-consent__file-label {
  outline: 3px solid var(--color-text);
  outline-offset: 2px;
}
.ob-consent__file-label { cursor: pointer; min-height: 44px; }

.hc-view {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  padding: var(--space-5) var(--space-4);
  max-width: 36rem;
  margin: 0 auto;
}

.hc-title { font-size: var(--text-2xl); margin: 0; }
.hc-text  { color: var(--color-text); line-height: 1.6; margin: 0; }
.hc-error { color: var(--color-danger); font-size: var(--text-sm); font-weight: var(--font-medium); min-height: 1.2em; margin: 0; }

/* AGE-CHECK, 01 Oct 2026. The age question, in onboarding (.ob-age) and
   on its own screen (.age-view); and the under-18 screen. Selects are
   44px high (2.5.8); the error is words, never colour alone. */
.ob-age {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  padding: var(--space-6) var(--space-5) var(--space-8);
  max-width: 34rem;
  margin: 0 auto;
}
.age-view, .u18-view {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  padding: var(--space-5) var(--space-4);
  max-width: 36rem;
  margin: 0 auto;
}
.age-title, .u18-title { font-size: var(--text-2xl); margin: 0; }
.age-q { border: 0; padding: 0; margin: 0; display: flex; flex-direction: column; gap: var(--space-3); }
.age-q__legend { font-size: var(--text-lg); font-weight: var(--font-semibold); margin-bottom: var(--space-2); padding: 0; }
.age-q__hint { color: var(--color-text-secondary); margin: 0; line-height: 1.6; }
.age-q__row { display: flex; gap: var(--space-3); flex-wrap: wrap; }
.age-q__field { display: flex; flex-direction: column; gap: var(--space-1); flex: 1 1 8rem; }
.age-q__label { font-size: var(--text-sm); color: var(--color-text); }
.age-q__select {
  min-height: 44px;
  padding: var(--space-2) var(--space-3);
  background: var(--color-surface);
  color: var(--color-text);
  border: 2px solid var(--color-text-secondary);
  border-radius: var(--radius-sm);
  font-size: var(--text-base);
}
.age-q__year { font-variant-numeric: tabular-nums; }
.age-q__select::placeholder { color: var(--color-text-secondary); opacity: 1; }
.age-q__error { color: var(--color-danger); font-size: var(--text-sm); font-weight: var(--font-medium); min-height: 1.2em; margin: 0; }
.u18-subtitle { font-size: var(--text-lg); margin: var(--space-2) 0 0; }
.u18-text { margin: 0; line-height: 1.6; color: var(--color-text); }
.u18-list { margin: 0; padding-left: var(--space-5); display: flex; flex-direction: column; gap: var(--space-3); line-height: 1.6; }
.u18-link { color: var(--color-primary); text-decoration: underline; }
.u18-small { margin: var(--space-3) 0 0; font-size: var(--text-sm); }
