/* ============================================================
   Before I Tell — components: ladder, ask, terms, takeover,
   banner, adult briefing, forms, cards
   ============================================================ */

/* --- ladder (three levels) --- */
.ladder {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--s-5);
  margin-top: var(--s-7);
}
@media (max-width: 900px) { .ladder { grid-template-columns: 1fr; } }

.ladder__card {
  padding: var(--s-6);
  display: flex;
  flex-direction: column;
  gap: var(--s-3);
  text-align: left;
  min-height: 280px;
  /* sticker construction: full-strength color, ink outline, hard pop shadow */
  border: 2px solid var(--ink-line);
  box-shadow: var(--pop);
  /* hover uses the independent translate/rotate properties — the scroll
     reveal animation owns `transform`, so a transform hover would never fire */
  transition: translate 0.3s var(--ease-apple-spring), rotate 0.3s var(--ease-apple-spring),
              box-shadow 0.3s var(--ease-apple-spring);
}
@media (prefers-reduced-motion: no-preference) {
  .ladder__card:hover { translate: -3px -6px; rotate: -0.8deg; box-shadow: var(--pop-lg); }
}
/* each level wears its color at FULL strength; the badge goes paper-white.
   Rest tilts commit like stickers slapped on — the middle card stays square
   (sub-degree tilt reads as "crooked", committed tilt reads as "playful") */
.ladder__card--1 { background: var(--lv1); rotate: -1.2deg; }
.ladder__card--2 { background: var(--lv2); }
.ladder__card--3 { background: var(--lv3); rotate: 1.2deg; }
.ladder__badge {
  width: 52px; height: 52px;
  border-radius: 18px;
  display: grid;
  place-items: center;
  line-height: 1;
  margin-bottom: var(--s-2);
  background: var(--c-bg-page);
  color: var(--c-text);
  border: 2px solid var(--ink-line);
  box-shadow: var(--pop-sm);
}
.ladder__badge svg { width: 24px; height: 24px; }
@media (prefers-reduced-motion: no-preference) {
  .ladder__card:hover .ladder__badge { animation: badge-wiggle 0.5s var(--ease-apple-spring); }
}
@keyframes badge-wiggle {
  0% { transform: rotate(0); } 30% { transform: rotate(-8deg) scale(1.08); }
  70% { transform: rotate(6deg); } 100% { transform: rotate(0); }
}
.ladder__level {
  font-family: var(--font-mono);
  font-size: var(--t-caption);
  letter-spacing: 0.08em;
  color: var(--c-text);
  line-height: 1.5;
}
.ladder__card h3 { font-size: var(--t-head-sm); line-height: 1.25; }
/* full-strength color fills: every word steps up to full ink for AA */
.ladder__card p { color: var(--c-text); font-size: var(--t-body); margin: 0; flex: 1; }
.ladder__cost {
  font-size: var(--t-body-sm);
  font-weight: 600;
  color: var(--c-text);
  padding-top: var(--s-3);
  border-top: 2px dashed rgba(51, 38, 30, 0.3); /* fallback: color-mix absent on iOS 16.0-16.1 */
  border-top: 2px dashed color-mix(in srgb, var(--ink-line) 30%, transparent);
  line-height: 1.5;
}

/* --- refusals list --- */
.refusals {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--s-4) var(--s-6);
  margin-top: var(--s-6);
}
@media (max-width: 768px) { .refusals { grid-template-columns: 1fr; } }
.refusal {
  display: flex;
  gap: var(--s-3);
  align-items: flex-start;
}
.refusal__mark {
  flex: 0 0 auto;
  width: 26px; height: 26px;
  border-radius: 50%;
  background: var(--lv3);
  border: 2px solid var(--ink-line);
  display: grid;
  place-items: center;
  color: var(--c-text);
  font-size: 13px;
  font-weight: 700;
  line-height: 1;
  margin-top: 2px;
}
.refusal b { font-weight: 600; }
.refusal p { margin: 2px 0 0; color: var(--c-text-2); font-size: var(--t-body-sm); line-height: 1.5; }

/* --- evidence strip: three research stickers, slightly askew --- */
.evidence {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--s-5);
  margin-top: var(--s-6);
}
@media (max-width: 900px) { .evidence { grid-template-columns: 1fr; } }
.evidence__item {
  background: var(--c-bg-page);
  padding: var(--s-5);
  border: 2px solid var(--ink-line);
  border-radius: var(--r-card);
  box-shadow: var(--pop);
}
/* alternate tilt: rotate (independent property) never collides with the
   fly-in animations, which own `transform`. Committed angles, not sub-degree */
.evidence__item:nth-child(odd) { rotate: -1.6deg; }
.evidence__item:nth-child(even) { rotate: 1.2deg; }
.evidence__stat {
  font-family: var(--font-display);
  font-size: var(--t-display-md);
  font-weight: 800;
  letter-spacing: -0.02em;
  line-height: 1.15;
  color: var(--c-accent);
}
.evidence__item p { margin: var(--s-2) 0 0; font-size: var(--t-body-sm); color: var(--c-text-2); line-height: 1.55; }
.evidence__item cite {
  display: block;
  margin-top: var(--s-3);
  font-style: normal;
  font-family: var(--font-mono);
  font-size: var(--t-caption);
  color: var(--c-text-3);
  line-height: 1.5;
}

/* --- FAQ --- */
.faq { margin-top: var(--s-6); border-top: 1px solid var(--c-hairline); }
.faq details { border-bottom: 1px solid var(--c-hairline); }
.faq summary {
  padding: var(--s-4) 0;
  font-family: var(--font-display);
  font-size: var(--t-body-lg);
  font-weight: 700;
  line-height: 1.4;
  cursor: pointer;
  list-style: none;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: var(--s-4);
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after {
  content: "+";
  font-size: 22px;
  line-height: 1;
  color: var(--c-text-3);
  transition: transform 0.3s var(--ease-apple-out);
  flex: 0 0 auto;
}
.faq details[open] summary::after { transform: rotate(45deg); }
.faq details > div { padding: 0 0 var(--s-4); color: var(--c-text-2); max-width: var(--w-text); }

/* --- app shell --- */
.app-main { min-height: calc(100vh - 52px); display: flex; flex-direction: column; }
.app-view {
  flex: 1;
  width: 100%;
  max-width: var(--w-text);
  margin-inline: auto;
  padding: var(--s-7) var(--s-4) var(--s-9);
}
.app-view--wide { max-width: var(--w-content); }

/* step header */
.step-head { margin-bottom: var(--s-6); }
.app-view h1 { scroll-margin-top: var(--chrome-h, 80px); } /* focused heading clears the sticky nav (and the tier-2 banner when it's up) */
.step-head .eyebrow { margin-bottom: var(--s-2); }
.step-head h1 { font-size: var(--t-head-md); line-height: 1.15; letter-spacing: -0.01em; }
.step-head .lead { margin-top: var(--s-3); font-size: var(--t-body-lg); }

/* --- home level chooser --- */
.chooser { display: flex; flex-direction: column; gap: var(--s-4); margin-top: var(--s-6); }
.chooser__card {
  display: flex;
  align-items: center;
  gap: var(--s-4);
  padding: var(--s-5);
  border: none;
  border-radius: var(--r-card);
  background: var(--c-bg-page);
  color: var(--c-text);
  text-align: left;
  transition: border-color 0.25s var(--ease-apple-standard),
              transform 0.25s var(--ease-apple-spring),
              box-shadow 0.25s var(--ease-apple-standard);
}
.chooser__card { text-decoration: none; border: 2px solid var(--ink-line); box-shadow: var(--pop-sm); }
.chooser__card:hover {
  text-decoration: none;
  box-shadow: var(--pop);
}
@media (prefers-reduced-motion: no-preference) {
  .chooser__card { transition: translate 0.25s var(--ease-apple-spring), rotate 0.25s var(--ease-apple-spring), box-shadow 0.25s var(--ease-apple-spring); }
  .chooser__card:hover { translate: -2px -4px; rotate: -0.4deg; }
}
.chooser__num {
  font-family: var(--font-mono);
  font-size: var(--t-caption);
  font-weight: 700;
  color: var(--c-accent-deep);
  background: var(--c-accent-soft);
  border-radius: var(--r-pill);
  padding: 6px 0;
  text-align: center;
  line-height: 1.5;
  flex: 0 0 44px;
}
.chooser__body { flex: 1; }
.chooser__body b { font-size: var(--t-body-lg); font-weight: 600; display: block; line-height: 1.35; }
.chooser__body span { color: var(--c-text-2); font-size: var(--t-body-sm); line-height: 1.5; }
.chooser__arrow { color: var(--c-text-3); flex: 0 0 auto; }

/* resume card */
.resume-card {
  margin-top: var(--s-5);
  padding: var(--s-4) var(--s-5);
  border-radius: var(--r-input);
  background: var(--c-surface);
  display: flex;
  align-items: center;
  gap: var(--s-4);
  font-size: var(--t-body-sm);
  line-height: 1.5;
}
.resume-card b { font-weight: 600; }

/* --- ask --- */
.ask-form { display: flex; gap: var(--s-2); margin-bottom: var(--s-3); }
.ask-input {
  flex: 1;
  padding: 14px 18px;
  font: inherit;
  line-height: 1.4;
  color: var(--c-text);
  background: var(--c-bg-page);
  border: 1.5px solid var(--c-border-strong);
  border-radius: var(--r-input);
  transition: border-color 0.2s var(--ease-apple-standard);
}
.ask-input:focus { outline: none; border-color: var(--c-accent); box-shadow: 0 0 0 3px var(--c-accent-soft); }
.ask-input::placeholder { color: var(--c-text-3); }

.jurisdiction {
  font-size: var(--t-caption);
  color: var(--c-text-3);
  margin-bottom: var(--s-6);
  line-height: 1.5;
}

.answer-card {
  border: 2px solid var(--ink-line);
  border-radius: var(--r-card);
  padding: var(--s-5);
  background: var(--c-bg-page);
  box-shadow: var(--pop-sm);
  margin-bottom: var(--s-4);
}
.answer-card h2 { font-size: var(--t-head-sm); line-height: 1.3; margin-bottom: var(--s-3); }
.answer-card .answer-body { line-height: 1.6; }
.answer-card .answer-body p { margin-bottom: 0.8em; }
.cite-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-2);
  margin-top: var(--s-4);
  padding-top: var(--s-4);
  border-top: 1px solid var(--c-hairline);
}
.cite-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: var(--t-caption);
  line-height: 1.5;
  padding: 5px 12px;
  border-radius: var(--r-pill);
  background: var(--c-surface);
  color: var(--c-text-2);
  border: 1px solid var(--c-hairline);
}
.cite-chip { text-decoration: none; }
.cite-chip:hover { color: var(--c-text); text-decoration: none; border-color: var(--c-text); }

.alternates { margin-top: var(--s-4); font-size: var(--t-body-sm); color: var(--c-text-2); line-height: 1.5; }

/* --- terms builder --- */
.terms-form { border: none; margin: 0; padding: 0; }
.terms-form legend {
  font-size: var(--t-body-sm);
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--c-text-2);
  padding: 0;
  margin-bottom: var(--s-3);
  line-height: 1.5;
}
.terms-group { margin-bottom: var(--s-6); }

.term {
  display: flex;
  align-items: flex-start;
  gap: var(--s-3);
  padding: var(--s-4);
  border: 1px solid var(--c-divider);
  border-radius: var(--r-input);
  margin-bottom: var(--s-2);
  background: var(--c-bg-page);
  transition: border-color 0.2s var(--ease-apple-standard), background 0.2s var(--ease-apple-standard);
}
.term:has(input:checked) { border-color: var(--c-accent); background: var(--c-accent-soft); }
.term--locked { background: var(--c-surface); border-style: dashed; }

.term input[type="checkbox"] {
  appearance: none;
  -webkit-appearance: none;
  flex: 0 0 auto;
  width: 22px; height: 22px;
  margin: 1px 0 0;
  border: 1.5px solid var(--c-border-strong);
  border-radius: 7px;
  background: var(--c-bg-page);
  display: grid;
  place-items: center;
  cursor: pointer;
  transition: background 0.2s var(--ease-apple-standard), border-color 0.2s var(--ease-apple-standard);
}
.term input[type="checkbox"]:checked { background: var(--c-btn-bg); border-color: var(--c-btn-bg); }
.term input[type="checkbox"]:checked::after {
  content: "";
  width: 10px; height: 6px;
  border-left: 2px solid var(--c-btn-ink);
  border-bottom: 2px solid var(--c-btn-ink);
  transform: rotate(-45deg) translateY(-1px);
}
.term label { flex: 1; cursor: pointer; line-height: 1.5; }
.term--locked .lock-icon { flex: 0 0 auto; color: var(--c-locked); margin-top: 2px; }
.term__why { display: block; font-size: var(--t-body-sm); color: var(--c-text-2); margin-top: 3px; line-height: 1.5; }

.term select {
  font: inherit;
  font-size: var(--t-body-sm);
  padding: 6px 10px;
  margin-top: var(--s-2);
  border-radius: 8px;
  border: 1px solid var(--c-divider);
  background: var(--c-bg-page);
  color: var(--c-text);
}

/* --- scaffold --- */
.slot { margin-bottom: var(--s-5); }
.slot label {
  display: block;
  font-weight: 500;
  margin-bottom: var(--s-2);
  line-height: 1.4;
}
.slot .hint { font-size: var(--t-body-sm); color: var(--c-text-3); font-weight: 400; }
/* untyped `input`: the compose email and passphrase fields must get the same
   dress as text inputs (only text-like inputs ever sit directly in a .slot).
   font: inherit resolves to 16px — exactly iOS's no-zoom-on-focus threshold. */
.slot textarea, .slot input, .slot select {
  width: 100%;
  padding: 13px 16px;
  font: inherit;
  line-height: 1.5;
  color: var(--c-text);
  background: var(--c-bg-page);
  border: 1.5px solid var(--c-border-strong);
  border-radius: var(--r-input);
  resize: vertical;
  transition: border-color 0.2s var(--ease-apple-standard);
}
.slot textarea:focus, .slot input:focus, .slot select:focus {
  outline: none;
  border-color: var(--c-accent);
  box-shadow: 0 0 0 3px var(--c-accent-soft);
}
.slot textarea { min-height: 96px; }

/* --- review / words output --- */
.words-card {
  border: 2px solid var(--ink-line);
  border-radius: var(--r-card);
  padding: var(--s-6);
  background: var(--lv2-soft);
  box-shadow: var(--pop-sm);
  font-size: var(--t-body-lg);
  line-height: 1.6;
  margin-bottom: var(--s-4);
  white-space: pre-wrap; /* the scaffold card and sent messages keep their breaks */
  overflow-wrap: break-word; /* pasted URLs must wrap, not clip */
}
/* …but not when the card is a container of real elements rather than text */
.words-card:has(.link-box), .words-card:has(.term) { white-space: normal; }
.review-list { list-style: none; margin: 0 0 var(--s-5); padding: 0; }
.review-list li {
  display: flex;
  gap: var(--s-3);
  padding: var(--s-3) 0;
  border-bottom: 1px solid var(--c-hairline);
  line-height: 1.5;
}
.review-list li:last-child { border-bottom: none; }
.review-list .tick { color: var(--c-safe); flex: 0 0 auto; margin-top: 3px; }
.review-list .lock { color: var(--c-locked); flex: 0 0 auto; margin-top: 3px; }

/* link output */
.link-box {
  display: flex;
  gap: var(--s-2);
  margin: var(--s-4) 0;
}
.link-box input {
  flex: 1;
  padding: 12px 16px;
  font-family: var(--font-mono);
  font-size: var(--t-caption);
  line-height: 1.5;
  color: var(--c-text-2);
  background: var(--c-surface);
  border: 1px solid var(--c-divider);
  border-radius: var(--r-input);
  min-width: 0;
}
.copy-confirm {
  color: var(--c-safe);
  font-size: var(--t-body-sm);
  font-weight: 500;
  line-height: 1.5;
}

/* --- safety banner (tier 2) --- */
.safety-banner {
  position: sticky;
  top: 52px;
  z-index: 90;
  background: var(--c-crisis-bg);
  border-bottom: 1px solid var(--c-hairline);
  padding: var(--s-3) var(--s-4);
  font-size: var(--t-body-sm);
  line-height: 1.5;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--s-2) var(--s-3);
  justify-content: center;
  text-align: center;
}
.safety-banner a { font-weight: 600; color: var(--c-text); text-decoration: underline; text-underline-offset: 2px; }

/* --- tier 3 takeover --- */
.takeover {
  position: fixed;
  inset: 0;
  z-index: 300;
  display: grid;
  place-items: center;
  padding: var(--s-4);
  background: var(--takeover-dim);
}
.takeover__panel {
  width: 100%;
  max-width: 560px;
  max-height: min(86vh, 720px);
  /* svh: vh resolves to the LARGE viewport on phones, but the fixed overlay
     is sized to the small one while the URL bar shows — which it always does
     at the moment the takeover fires. Older browsers drop the invalid line. */
  max-height: min(86svh, 720px);
  overflow-y: auto;
  padding: var(--s-6);
  border-radius: var(--r-card);
  background: var(--c-bg-page);
  border: 1.5px solid var(--panel-border);
  box-shadow: var(--panel-shadow);
}
@media (prefers-reduced-motion: no-preference) {
  /* the dim eases in so the world softens rather than snaps — a crisis moment
     must feel grounding, never jarring. The panel settles gently with no
     playful overshoot; routes are instant (never stagger access to a helpline). */
  .takeover { animation: takeover-dim 0.35s var(--ease-apple-standard) both; }
  .takeover__panel { animation: takeover-in 0.55s var(--ease-out-expo) both; }
}
@keyframes takeover-dim {
  from { background: transparent; }
}
@keyframes takeover-in {
  from { opacity: 0; transform: translateY(16px); }
  to   { opacity: 1; transform: none; }
}
.takeover__panel h2 { font-size: var(--t-head-sm); line-height: 1.3; margin-bottom: var(--s-3); }
.takeover__panel p { color: var(--c-text-2); line-height: 1.6; }
.takeover__routes { display: flex; flex-direction: column; gap: var(--s-2); margin: var(--s-5) 0; }
.takeover__route {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-3);
  padding: var(--s-4);
  border: 1px solid var(--c-divider);
  border-radius: var(--r-input);
  color: var(--c-text);
  background: var(--c-bg-page);
  transition: border-color 0.2s var(--ease-apple-standard);
  line-height: 1.4;
}
.takeover__route { text-decoration: none; }
.takeover__route:hover { border-color: var(--c-text); text-decoration: none; }
.takeover__route b { display: block; font-weight: 600; }
.takeover__route span { font-size: var(--t-body-sm); color: var(--c-text-2); }
.takeover__route .num { font-family: var(--font-mono); font-weight: 700; color: var(--c-text); white-space: nowrap; }
.takeover__honest {
  font-size: var(--t-body-sm);
  color: var(--c-text-2);
  background: var(--c-surface);
  border-radius: var(--r-input);
  padding: var(--s-4);
  margin-bottom: var(--s-5);
  line-height: 1.55;
}
.takeover__exit { display: flex; justify-content: center; }

/* --- adult page --- */
.brief-section { margin-bottom: var(--s-7); }
.brief-section h2 { font-size: var(--t-head-sm); line-height: 1.3; margin-bottom: var(--s-4); }
.brief-steps { list-style: none; margin: 0; padding: 0; counter-reset: brief; }
.brief-steps li {
  counter-increment: brief;
  display: flex;
  gap: var(--s-4);
  padding: var(--s-4) 0;
  border-bottom: 1px solid var(--c-hairline);
  line-height: 1.55;
}
.brief-steps li:last-child { border-bottom: none; }
.brief-steps li::before {
  content: counter(brief, decimal-leading-zero);
  font-family: var(--font-mono);
  font-size: var(--t-caption);
  font-weight: 600;
  color: var(--c-text);
  flex: 0 0 32px;
  padding-top: 4px;
  line-height: 1.5;
}
.brief-steps b { font-weight: 600; }
.brief-steps p { margin: 3px 0 0; color: var(--c-text-2); font-size: var(--t-body-sm); line-height: 1.55; }

.request-cards { display: flex; flex-direction: column; gap: var(--s-3); }
.request-card {
  padding: var(--s-4) var(--s-5);
  /* pre-wrap: these also render relayed replies, and a counsellor's paragraphs
     and numbered lists must not collapse into one block */
  white-space: pre-wrap;
  overflow-wrap: break-word; /* long URLs in replies must wrap, not clip */
  border-left: 4px solid var(--c-accent);
  border-radius: var(--r-input);
  background: var(--c-accent-soft);
  font-size: var(--t-body-lg);
  font-weight: 500;
  line-height: 1.5;
  break-inside: avoid;
}
.hard-case {
  border: 1px solid var(--c-divider);
  border-radius: var(--r-card);
  padding: var(--s-5);
  background: var(--c-surface);
  line-height: 1.6;
}
.hard-case h3 { font-size: var(--t-body-lg); font-weight: 600; line-height: 1.4; margin-bottom: var(--s-3); }
.hard-case p { color: var(--c-text-2); }

.decode-note {
  padding: var(--s-3) var(--s-4);
  border-radius: var(--r-input);
  background: var(--c-surface);
  font-size: var(--t-body-sm);
  color: var(--c-text-2);
  margin-bottom: var(--s-5);
  line-height: 1.5;
}

/* --- utility rows --- */
.btn-row { display: flex; flex-wrap: wrap; gap: var(--s-3); margin-top: var(--s-6); align-items: center; }
.btn-row--between { justify-content: space-between; }
.spacer { flex: 1; }

/* --- two-column feature (landing) --- */
.grid-collapse { display: grid; grid-template-columns: 1fr 1fr; gap: var(--s-7); align-items: center; }
@media (max-width: 900px) {
  .grid-collapse { grid-template-columns: 1fr; gap: var(--s-5); }
}

/* --- noscript --- */
.noscript-box {
  max-width: var(--w-text);
  margin: var(--s-7) auto;
  padding: var(--s-5);
  border: 1px solid var(--c-divider);
  border-radius: var(--r-card);
  line-height: 1.6;
}

/* --- practice mode: full-screen rehearsal cue card ---
   Opaque page ground (not a dim) so the room feels private; sits BELOW the
   tier-3 takeover (300) which must always win. Closes on Escape — it's a
   rehearsal, not a lock. */
.practice {
  position: fixed;
  inset: 0;
  z-index: 250;
  overflow-y: auto;
  background: var(--c-bg);
  display: grid;
  justify-items: center;
  padding: var(--s-4);
}
.practice__panel {
  width: 100%;
  max-width: 720px;
  padding: var(--s-6) 0;
  /* auto margins center like place-items did, but keep the TOP of long text
     reachable through the container's scroll (place-items pushed it off) */
  margin-block: auto;
}
.practice__panel h2 {
  font-family: var(--font-display);
  font-size: var(--t-head-md);
  line-height: 1.25;
  margin: var(--s-2) 0 var(--s-3);
}
.practice__hint {
  color: var(--c-text-2);
  font-size: var(--t-body-sm);
  line-height: 1.55;
  max-width: 52ch;
}
.practice__words {
  font-family: var(--font-display);
  font-size: clamp(22px, 3.2vw, 34px);
  font-weight: 600;
  letter-spacing: -0.01em;
  line-height: 1.4;
  white-space: pre-wrap; /* the student's own line breaks survive */
  margin: var(--s-5) 0;
  padding: var(--s-5);
  border: 1.5px solid var(--ink-line);
  border-radius: var(--r-card);
  background: var(--lv3-soft);
  box-shadow: var(--pop);
  overflow-wrap: break-word;
}
@media (prefers-reduced-motion: no-preference) {
  html:not(.motion-off) .practice__panel { animation: takeover-in 0.4s var(--ease-apple-out) both; }
}

/* --- voice: optional pre-recorded "Listen" buttons (js/voice.js) --- */
.answer-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--s-3);
  flex-wrap: wrap;
}
.answer-head h2 { flex: 1 1 24ch; }
.voice-btn {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  flex: 0 0 auto;
}
.voice-icon { width: 18px; height: 18px; }
.voice-btn.playing {
  color: var(--c-accent-deep);
  border-color: currentColor;
}
/* gentle pulse while speaking; static under reduced motion / the pause toggle */
@media (prefers-reduced-motion: no-preference) {
  html:not(.motion-off) .voice-btn.playing .voice-icon { animation: voice-pulse 1.6s ease-in-out infinite; }
}
@keyframes voice-pulse {
  0%, 100% { opacity: 1; }
  50%      { opacity: 0.45; }
}

/* ---- small-phone fixes (audit-caught) ---- */
/* crisis takeover: the Kids Help Phone number overflowed its route row at
   <=420px. flex-basis 100% drops the number to its own line — guaranteed
   fit across mono-font metric differences between devices. Source order
   matters: this must sit after the base .takeover rules. */
@media (max-width: 420px) {
  .takeover__panel { padding: var(--s-4); }
  .takeover__route { flex-wrap: wrap; }
  .takeover__route .num { flex-basis: 100%; }
}
/* iOS zooms into any focused control under 16px — the link box and the
   check-in day select were 12/14px */
@media (max-width: 720px) {
  .link-box input { font-size: 16px; }
  .term select { font-size: 16px; }
}

/* ---- exact-email preview on the L2 compose screen ---- */
.mail-details { margin: var(--s-4) 0; }
.mail-details summary {
  cursor: pointer;
  font-weight: 600;
  padding: var(--s-3) var(--s-4);
  border: 1.5px solid var(--c-border-strong);
  border-radius: var(--r-input);
  background: var(--c-surface);
  line-height: 1.4;
  list-style: none;
}
.mail-details summary::-webkit-details-marker { display: none; }
.mail-details summary::before { content: "✉ "; }
.mail-details[open] summary { border-bottom-left-radius: 0; border-bottom-right-radius: 0; }
.mail-preview {
  margin: 0;
  padding: var(--s-4);
  border: 1.5px solid var(--c-border-strong);
  border-top: none;
  border-radius: 0 0 var(--r-input) var(--r-input);
  background: var(--c-bg-page);
  font-family: var(--font-mono);
  font-size: var(--t-body-sm);
  line-height: 1.55;
  white-space: pre-wrap;
  overflow-wrap: break-word;
  max-height: 340px;
  overflow-y: auto;
}

/* ============================================================
   v2 — patterns studied from shipped products (Mobbin research):
   · thin step progress + sticky action bar  (MyFitnessPal, Whatnot, Nibble)
   · option rows with the control on the RIGHT (Too Good To Go, MyFitnessPal)
   · answer sources + "ask next" rows (Perplexity/Comet, Opera, Mindvalley)
   · real chat bubbles + thread status (Binance, Coffee Meets Bagel)
   · success screen with copy AND native share (Wise, Commons)
   · crisis help grouped into labelled rows with call targets (How We Feel, Alan)
   ============================================================ */

/* --- step progress: a thin bar, not counting dots --- */
.wizard {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  margin-bottom: var(--s-5);
}
.wizard__track {
  flex: 1;
  height: 6px;
  border-radius: var(--r-pill);
  background: var(--c-surface-2);
  overflow: hidden;
}
.wizard__fill {
  height: 100%;
  border-radius: var(--r-pill);
  background: var(--c-accent);
  transition: width 0.45s var(--ease-apple-out);
}
.wizard__count {
  font-size: var(--t-caption);
  font-weight: 600;
  color: var(--c-text-2);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  white-space: nowrap;
  line-height: 1.4;
}

/* --- sticky action bar: the primary action is always in reach --- */
.action-bar {
  position: sticky;
  bottom: 0;
  z-index: 40;
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-3);
  align-items: center;
  margin: var(--s-7) calc(-1 * var(--s-4)) 0;
  padding: var(--s-4);
  background: var(--nav-bg-scrolled);
  border-top: 1px solid var(--c-hairline);
  backdrop-filter: saturate(180%) blur(16px);
  -webkit-backdrop-filter: saturate(180%) blur(16px);
}
.action-bar .btn { min-height: 48px; }
.action-bar__grow { flex: 1; }
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .action-bar { background: var(--c-bg); }
}

/* --- option rows: full-width, control on the right, whole row is the target --- */
.term {
  align-items: center;
  gap: var(--s-4);
  min-height: 60px;
  transition: border-color 0.18s var(--ease-apple-standard),
              background 0.18s var(--ease-apple-standard);
}
.term > div { order: 1; flex: 1; }
.term input[type="checkbox"] { order: 2; flex: 0 0 auto; margin: 0; }
.term:hover:not(.term--locked) { border-color: var(--c-border-strong); }
.term--locked { align-items: flex-start; }
.term--locked .lock-icon { order: 0; }

/* --- ask: suggestions as tappable rows, not loose chips --- */
.suggest-label {
  display: block;
  font-size: var(--t-body-sm);
  font-weight: 600;
  color: var(--c-text-2);
  margin: var(--s-5) 0 var(--s-2);
  line-height: 1.5;
}
.suggest-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-3);
  width: 100%;
  text-align: left;
  padding: var(--s-3) var(--s-4);
  margin-bottom: var(--s-2);
  min-height: 52px;
  border: 1px solid var(--c-divider);
  border-radius: var(--r-input);
  background: var(--c-bg-page);
  color: var(--c-text);
  font: inherit;
  font-size: var(--t-body);
  line-height: 1.45;
  cursor: pointer;
  transition: border-color 0.18s var(--ease-apple-standard),
              transform 0.18s var(--ease-apple-spring);
}
.suggest-row:hover { border-color: var(--c-text); transform: translateX(2px); }
.suggest-row::after {
  content: "\2192";
  flex: 0 0 auto;
  color: var(--c-text-3);
  font-size: var(--t-body-lg);
  line-height: 1.4;
}

/* --- chat thread (L2) --- */
.thread-head {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  padding-bottom: var(--s-4);
  margin-bottom: var(--s-4);
  border-bottom: 1px solid var(--c-hairline);
}
.thread-avatar {
  flex: 0 0 auto;
  width: 44px;
  height: 44px;
  display: grid;
  place-items: center;
  border-radius: var(--r-pill);
  background: var(--lv2);
  border: 1.5px solid var(--ink-line);
  font-weight: 700;
  font-size: var(--t-body-sm);
  color: var(--c-text);
  line-height: 1.4;
}
.thread-head__who { flex: 1; min-width: 0; }
.thread-head__who b { display: block; font-size: var(--t-body-lg); font-weight: 700; line-height: 1.3; }
.thread-status {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: var(--t-body-sm);
  color: var(--c-text-2);
  line-height: 1.45;
}
.thread-status::before {
  content: "";
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--c-text-3);
}
.thread-status--replied { color: var(--c-safe); }
.thread-status--replied::before { background: var(--c-safe); }

.msg-system {
  text-align: center;
  font-size: var(--t-body-sm);
  line-height: 1.55;
  color: var(--c-text-2);
  background: var(--c-surface);
  border-radius: var(--r-input);
  padding: var(--s-3) var(--s-4);
  margin-bottom: var(--s-5);
}
.msg-list { display: flex; flex-direction: column; gap: var(--s-3); margin-bottom: var(--s-5); }
.msg { display: flex; flex-direction: column; max-width: 82%; }
.msg--you { align-self: flex-end; align-items: flex-end; }
.msg--them { align-self: flex-start; align-items: flex-start; }
.msg__bubble {
  padding: var(--s-3) var(--s-4);
  border-radius: var(--r-card);
  line-height: 1.55;
  white-space: pre-wrap;
  overflow-wrap: break-word;
  border: 1.5px solid var(--ink-line);
}
.msg--you .msg__bubble {
  background: var(--lv3-soft);
  border-bottom-right-radius: var(--s-2);
}
.msg--them .msg__bubble {
  background: var(--c-bg-page);
  border-bottom-left-radius: var(--s-2);
  box-shadow: var(--pop-sm);
}
.msg__meta {
  font-size: var(--t-caption);
  color: var(--c-text-3);
  margin-top: 5px;
  line-height: 1.45;
}

/* --- success (L3 done) --- */
.success-mark {
  width: 72px;
  height: 72px;
  display: grid;
  place-items: center;
  margin-bottom: var(--s-4);
  border-radius: var(--r-pill);
  background: var(--c-safe-soft);
  border: 2px solid var(--c-safe);
  color: var(--c-safe);
}
.success-mark svg { width: 36px; height: 36px; }
@media (prefers-reduced-motion: no-preference) {
  html:not(.motion-off) .success-mark { animation: pop-in 0.5s var(--ease-apple-spring) both; }
}
@keyframes pop-in {
  from { opacity: 0; transform: scale(0.6); }
  to   { opacity: 1; transform: none; }
}

/* toast: confirms a copy without shifting the page.
   z-index and bottom are set once, below — the tier-3 crisis takeover (300)
   must always win, so this must never be raised above it. */
.toast {
  position: fixed;
  left: 50%;
  transform: translateX(-50%);
  max-width: min(92vw, 420px);
  padding: var(--s-3) var(--s-5);
  border-radius: var(--r-pill);
  background: var(--c-text);
  color: var(--c-bg);
  font-size: var(--t-body-sm);
  font-weight: 600;
  line-height: 1.5;
  box-shadow: var(--panel-shadow);
}
@media (prefers-reduced-motion: no-preference) {
  html:not(.motion-off) .toast { animation: toast-in 0.35s var(--ease-apple-out) both; }
}
@keyframes toast-in {
  from { opacity: 0; transform: translate(-50%, 12px); }
  to   { opacity: 1; transform: translate(-50%, 0); }
}

/* --- mobile: give the thumb room --- */
@media (max-width: 620px) {
  .action-bar { margin-left: calc(-1 * var(--s-3)); margin-right: calc(-1 * var(--s-3)); }
  .action-bar .btn { flex: 1; justify-content: center; }
  .msg { max-width: 90%; }
}

/* --- crisis strip: real tap targets ---
   The numbers were inline underlined text — a ~20px tall target for someone
   with shaking hands. Pills give a 44px row without changing the calm tone. */
.crisis__inner a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 6px 14px;
  border: 1px solid var(--c-divider);
  border-radius: var(--r-pill);
  background: var(--c-bg-page);
  text-decoration: none;
  font-weight: 600;
  line-height: 1.45;
}
.crisis__inner a:hover {
  border-color: var(--c-crisis-edge);
  text-decoration: none;
}
.crisis__inner { align-items: center; }

/* the starter list disappears once an answer lands, so give it breathing room */
.ask-starters { margin-top: var(--s-6); }

/* action-bar buttons must not wrap: "Send reply" broke onto two lines and the
   button grew into a square. Nowrap + tighter mobile padding keeps one line. */
.action-bar .btn { white-space: nowrap; }
@media (max-width: 420px) {
  .action-bar { gap: var(--s-2); padding: var(--s-3); }
  .action-bar .btn { padding-left: var(--s-3); padding-right: var(--s-3); font-size: var(--t-body-sm); }
}
/* the bar is the last thing on the page; the chrome row above it already
   carries the separation, so drop its own big top margin on small screens */
@media (max-width: 620px) {
  .action-bar { margin-top: var(--s-5); }
}

/* Tap targets on the terms list.
   The checkbox was 22px (under WCAG 2.5.8's 24px floor) and the label only
   covered its own text, so the empty half of a 60px row did nothing when
   tapped. Block label + 24px box makes the whole row the target. */
.term input[type="checkbox"] { width: 24px; height: 24px; }
.term label { display: block; padding: var(--s-2) 0; }
.term--locked > div > span:first-child { display: block; }

/* ---- review fixes ---- */

/* The toast sat at z-index 320, ABOVE the tier-3 crisis takeover (300), which
   must always win; and at bottom:24px it covered the sticky action bar on the
   one screen that has both. Below the takeover, above the bar it clears. */
.toast { z-index: 240; bottom: calc(96px + env(safe-area-inset-bottom, 0px)); }

/* CSS generated content joins the accessible name, so the row announced as
   "…parents? right arrow". The empty alt string keeps it decorative. */
.suggest-row::after { content: "\2192" / ""; }

/* Interactive boundaries were 1.26:1 against the page — nothing but the arrow
   said "this is a control". --c-border-strong is 3.38:1 (WCAG 1.4.11). */
.suggest-row { border-color: var(--c-border-strong); }

/* the progress fill carried 2.76:1 on its track; the deep rust is 4.11:1 and
   the same hue */
.wizard__fill { background: var(--c-accent-deep); }

/* Sticky bar hazards (WCAG 2.4.11 focus-not-obscured):
   · keyboard focus could scroll a row underneath the pinned bar
   · at 200% zoom / short viewports the wrapped bar ate half the screen */
html { scroll-padding-bottom: 120px; }
@media (max-height: 480px) {
  .action-bar { position: static; backdrop-filter: none; -webkit-backdrop-filter: none; }
}
/* honour the notch/home-indicator the viewport-fit=cover meta opts into */
.action-bar { padding-bottom: calc(var(--s-4) + env(safe-area-inset-bottom, 0px)); }

/* the bleed must match .app-view's padding exactly or an unblurred gutter
   shows at each edge — that padding stays --s-4 at every width */
@media (max-width: 620px) {
  .action-bar { margin-left: calc(-1 * var(--s-4)); margin-right: calc(-1 * var(--s-4)); }
}

/* the thread heading replaces the old <b>; keep its visual weight */
.thread-title {
  font-size: var(--t-body-lg);
  font-weight: 700;
  line-height: 1.3;
  margin: 0;
}
.thread-title:focus-visible { outline: 2px solid var(--c-accent); outline-offset: 3px; }

/* --chrome-h: how deep the fixed chrome is, so a scroll target lands below it
   instead of behind it.

   Chrome = the 53px sticky nav (52 + 1px border), plus the tier-2 safety
   banner when it is up, since that sticks directly underneath. Measured
   banner heights: 54px at >=879, then it wraps and keeps growing — 83px,
   112px at ~430, 133px at <=375. Hence two values, and 878px as the
   breakpoint because that is the real wrap point rather than a round number.
   The 80px floor (no banner) also absorbs the 18px .step-enter entrance
   transform, which a scroll can measure mid-animation.

   Declared in CSS rather than measured in JS on purpose: the student seeing
   the tier-2 banner is the one most likely to jump to the crisis numbers, and
   what protects them must not depend on a frame callback firing. Browsers
   without :has() keep the 80px floor, which still clears the nav.

   The crisis jump itself does NOT rely on these: ui.js measures the live
   nav + banner heights at click time, because that one target must be exact
   at every width. These values serve the other scroll targets. */
:root { --chrome-h: 80px; }
body:has(.safety-banner) { --chrome-h: 160px; }
@media (max-width: 878px) { body:has(.safety-banner) { --chrome-h: 200px; } }
/* .crisis[id], not .crisis: base.css's `[id] { scroll-margin-top: 64px }` has
   equal specificity, so a plain class would win only by stylesheet order —
   reordering the <link>s would silently drop the no-JS #crisis anchor back to
   64px and tuck the numbers under the nav. */
.crisis[id] { scroll-margin-top: var(--chrome-h); }
/* the Ask focus target is the answer's own heading */
.answer-card h2 { scroll-margin-top: var(--chrome-h); }

/* --- region picker: sits with the crisis numbers it governs --- */
.region-pick {
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  font-size: var(--t-body-sm);
  color: var(--c-text-2);
  line-height: 1.45;
}
.region-select {
  font: inherit;
  font-size: var(--t-body-sm);
  min-height: 44px;
  padding: 6px 10px;
  border: 1px solid var(--c-border-strong);
  border-radius: var(--r-input);
  background: var(--c-bg-page);
  color: var(--c-text);
  line-height: 1.45;
  max-width: 15rem;
}
.region-select:focus-visible { outline: 2px solid var(--c-accent); outline-offset: 2px; }
@media (max-width: 620px) {
  .region-pick { width: 100%; }
  .region-select { flex: 1; max-width: none; }
}

/* --- evidence strip: let the number carry the section ---
   Measured at 375px the stat sat at 30px — the floor of --t-display-md — so
   the research read as body copy. Every reference for this pattern (Zipline,
   Headspace, Collins) makes the numeral dominant and the citation quiet. Own
   clamp rather than a token change: --t-display-md is shared with headings. */
.evidence__stat {
  font-size: clamp(44px, 11vw, 60px);
  display: block;
  margin-bottom: var(--s-2);
}
/* the citation is provenance, not content — keep it legible but recessive */
.evidence__item cite { opacity: 0.85; }
