/* ============================================================================
   TEMAN — prototype design system
   Light, warm and gentle: soft paper, fresh green, generous roundness.
   Product feel borrowed from everyday messaging apps (WhatsApp / WeChat):
   the conversation is the centre, and everything around it stays quiet.
   Fewer sentences, clearer pictures — charts carry the argument.

   Every class used by app.js is defined here — the JS generates markup
   against these names, so nothing may be renamed without changing both.
   ========================================================================== */

/* ------------------------------------------------------------- tokens --- */
:root {
  /* surfaces */
  --paper:      #fbfaf6;
  --surface:    #ffffff;
  --surface-2:  #f1f7f2;

  /* ink */
  --ink:        #24312c;
  --muted:      #5f6f68;
  --faint:      #8b9a92;

  /* greens */
  --pine:       #1f9d63;
  --pine-deep:  #157a4a;
  --pine-soft:  #e4f5ea;
  --wa:         #d9fdd3;   /* outgoing chat bubble — messaging-app green */

  /* warm accent */
  --clay:       #e0764a;
  --clay-soft:  #fdeee4;

  /* pastel door tints — the mindline.sg card language, softened */
  --tint-mint:   #e8f6ee;
  --tint-butter: #fdf4dc;
  --tint-sky:    #e8f2fb;
  --tint-lav:    #eef0fb;
  --tint-blush:  #fdeee6;

  /* the one strong call to action — an ink pill, calm against the pastels */
  --ink-cta:     #1b2a23;

  /* structure */
  --line:       #e9e6dd;
  --sand:       #f4f1e8;
  --focus:      #1f9d63;

  /* states */
  --ok:         #2f9d6b;
  --mild:       #c08a2e;
  --mid:        #d2762f;
  --high:       #c25a4a;

  /* type — Proza Libre throughout, the face mindline.sg sets its body in */
  --sans:  "Proza Libre", "Segoe UI", system-ui, -apple-system, sans-serif;
  --serif: "Proza Libre", "Segoe UI", system-ui, -apple-system, sans-serif;   /* display face */

  /* shape */
  --radius: 20px;
  --radius-sm: 13px;
  --wrap:   1120px;
  /* The landing page runs wider than the reading pages — its doors are a grid,
     not prose. Reading pages keep --wrap; only index.html opts into --wrap-wide. */
  --wrap-wide: 1440px;
  --shadow-sm: 0 1px 2px rgba(36, 49, 44, .05), 0 2px 8px rgba(36, 49, 44, .05);
  --shadow-md: 0 8px 28px rgba(36, 49, 44, .10);
}

/* -------------------------------------------------------------- base --- */
* { box-sizing: border-box; }
html { scroll-behavior: smooth; }
body {
  margin: 0;
  font-family: var(--sans);
  font-size: 16px;
  line-height: 1.6;
  color: var(--ink);
  background: var(--paper);
  -webkit-font-smoothing: antialiased;
}
h1, h2, h3, h4 { font-family: var(--serif); font-weight: 800; line-height: 1.22; letter-spacing: -0.02em; margin: 0 0 0.45em; }
h1 { font-size: clamp(2rem, 4.6vw, 3.1rem); }
h2 { font-size: clamp(1.5rem, 2.9vw, 2.1rem); }
h3 { font-size: 1.16rem; }
h4 { font-size: 1.02rem; }
p { margin: 0 0 1em; }
a { color: var(--pine-deep); text-decoration: none; }
a:hover { text-decoration: underline; }
img { max-width: 100%; }
hr { border: 0; border-top: 1px solid var(--line); margin: 2.5rem 0; }
::selection { background: var(--pine-soft); }
:focus-visible { outline: 3px solid rgba(31, 157, 99, .4); outline-offset: 2px; border-radius: 6px; }

.wrap { max-width: var(--wrap); margin: 0 auto; padding: 0 24px; }
.wrap--wide { max-width: var(--wrap-wide); }
.muted { color: var(--muted); }
.small { font-size: 0.875rem; }
.tiny { font-size: 0.8rem; }
.center { text-align: center; }
.mt0 { margin-top: 0; } .mb0 { margin-bottom: 0; }
.mt1 { margin-top: 0.75rem; } .mt2 { margin-top: 1.5rem; } .mt3 { margin-top: 2.5rem; }
.mb1 { margin-bottom: 0.75rem; } .mb2 { margin-bottom: 1.5rem; } .mb3 { margin-bottom: 2.5rem; }
.big { font-weight: 700; }

/* ------------------------------------------------------------ ribbon --- */
/* The prototype notice: a warm note, not a dark bar. */
/* ------------------------------------------------------------ header --- */
.site-head {
  position: sticky; top: 0; z-index: 60;
  background: rgba(255, 255, 255, .9);
  backdrop-filter: blur(12px);
  border-bottom: 1px solid var(--line);
}
.site-head__in { display: flex; align-items: center; gap: 22px; height: 66px; }
.logo {
  display: inline-flex; align-items: center; gap: 9px; flex-shrink: 0;
  font-family: var(--serif); font-size: 1.4rem; font-weight: 800; color: var(--pine-deep);
}
.logo:hover { text-decoration: none; }
/* The favicon mark, promoted to the logo — two circles, one conversation. */
.logo__mark { width: 30px; height: 30px; flex-shrink: 0; }
.logo__word { display: inline-flex; align-items: baseline; gap: 7px; }
.logo .sub { font-family: var(--sans); font-size: .66rem; font-weight: 500; color: var(--faint); letter-spacing: .04em; white-space: nowrap; }
.ico { width: 16px; height: 16px; flex-shrink: 0; }
.head-cta { margin-left: auto; display: flex; align-items: center; gap: 10px; white-space: nowrap; }

/* The menu button. Everything that is not the chat lives behind it: the
   tools, the references, the 24/7 lines and sign-in. */
.menu-btn {
  display: inline-flex; align-items: center; gap: 10px;
  font-family: var(--sans); font-size: 0.9rem; font-weight: 600;
  color: var(--ink); background: var(--surface);
  border: 1px solid var(--line); border-radius: 999px;
  padding: 9px 18px 9px 16px; cursor: pointer;
  transition: border-color 0.12s, background 0.12s, color 0.12s;
}
.menu-btn:hover { border-color: #cfe8da; background: #f6fdf9; color: var(--pine-deep); }
.menu-btn__bars { display: inline-flex; flex-direction: column; gap: 3px; width: 16px; }
.menu-btn__bars i { display: block; height: 2px; border-radius: 2px; background: currentColor; }
.menu-btn__bars i:nth-child(2) { width: 74%; }
.menu-btn__bars i:nth-child(3) { width: 88%; }

.menu-panel { position: fixed; inset: 0; z-index: 90; }
.menu-panel__backdrop {
  position: absolute; inset: 0; background: rgba(20, 32, 27, .34);
  animation: menuFade .18s ease both;
}
.menu-panel__in {
  position: absolute; top: 0; right: 0; height: 100%; width: min(390px, 92vw);
  background: var(--surface); border-left: 1px solid var(--line);
  box-shadow: -18px 0 46px rgba(27, 42, 35, .16);
  padding: 22px 24px 30px; overflow-y: auto;
  animation: menuSlide .22s cubic-bezier(.2, .7, .2, 1) both;
}
@keyframes menuFade { from { opacity: 0; } to { opacity: 1; } }
@keyframes menuSlide { from { transform: translateX(18px); opacity: .4; } to { transform: none; opacity: 1; } }
.menu-panel__head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 16px; }
.menu-panel__title { font-family: var(--serif); font-weight: 800; font-size: 1.15rem; color: var(--pine-deep); }
.menu-close {
  border: 0; background: transparent; font-size: 1.6rem; line-height: 1;
  color: var(--faint); cursor: pointer; padding: 0 4px; border-radius: 8px;
}
.menu-close:hover { color: var(--ink); }
.menu-list { display: grid; gap: 2px; }
.menu-list a { display: block; padding: 11px 12px; border-radius: var(--radius-sm); color: var(--ink); font-size: 0.98rem; font-weight: 500; }
.menu-list a:hover { background: var(--pine-soft); color: var(--pine-deep); text-decoration: none; }
.menu-list a.active { background: var(--pine-soft); color: var(--pine-deep); font-weight: 600; }
.menu-block { margin-top: 18px; padding-top: 18px; border-top: 1px solid var(--line); }
.menu-help {
  display: flex; align-items: center; gap: 9px; width: 100%;
  font-family: var(--sans); font-size: 0.95rem; font-weight: 600;
  color: #b3542b; background: var(--clay-soft);
  border: 1px solid transparent; border-radius: var(--radius-sm);
  padding: 12px 14px; cursor: pointer;
}
.menu-help:hover { background: #fbe0cf; }
.menu-help .ico { width: 17px; height: 17px; }
.menu-crisis { margin-top: 12px; background: var(--surface-2); border: 1px solid var(--line); border-radius: var(--radius-sm); padding: 14px 16px; }
.menu-crisis__lead { font-size: 0.85rem; margin: 0 0 12px; }
.menu-crisis__row { margin-bottom: 10px; font-size: 0.85rem; }
.menu-crisis__row:last-child { margin-bottom: 0; }
.menu-crisis__row .cn { display: block; font-weight: 700; color: var(--ink); }
.menu-crisis__row .cd { display: block; color: var(--muted); }
.menu-crisis__row .cn-note { display: block; font-size: 0.74rem; color: var(--faint); }
/* Crisis numbers are safety-critical. Underlined at rest, not on hover: on a
   phone there is no hover, and these must read as tappable, not as body text. */
.menu-crisis__row .cd a,
.crisis-card li a { color: var(--pine-deep); text-decoration: underline; text-underline-offset: 2px; font-weight: 600; }
/* The door from the menu's numbers to the page that explains them. Smaller
   than the numbers on purpose — the menu is for the number, the page is for
   the reading. */
.menu-crisis__more { display: inline-block; margin-top: 12px; font-size: 0.8rem; color: var(--pine-deep); text-decoration: underline; text-underline-offset: 2px; }
.menu-account { display: flex; align-items: center; gap: 9px; padding: 11px 12px; border-radius: var(--radius-sm); color: var(--ink); font-weight: 500; }
.menu-account:hover { background: var(--pine-soft); color: var(--pine-deep); text-decoration: none; }

/* Phones: the bar keeps the logo and the menu button. */
@media (max-width: 620px) {
  .logo .sub { display: none; }
  .menu-btn__label { display: none; }
  .menu-btn { padding: 9px 14px; }
  .site-head__in { gap: 12px; }
}

/* ----------------------------------------------------------- buttons --- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  font-family: var(--sans); font-size: 0.95rem; font-weight: 600;
  padding: 12px 22px; border-radius: 999px; border: 1px solid transparent;
  cursor: pointer; transition: transform 0.12s ease, box-shadow 0.15s ease, background 0.15s ease;
  text-decoration: none; line-height: 1;
}
.btn:hover { text-decoration: none; transform: translateY(-1px); }
.btn:active { transform: translateY(0); }
/* The primary action is an ink pill — mindline's calm contrast against the pastels.
   Pine stays the brand: logo, links, active states, the chat itself. */
.btn--primary { background: var(--ink-cta); color: #fff; box-shadow: 0 6px 16px rgba(27, 42, 35, .18); }
.btn--primary:hover { background: #2a3d33; box-shadow: var(--shadow-md); }
.btn--ghost { background: var(--surface); color: var(--ink); border-color: var(--line); }
.btn--ghost:hover { border-color: #cfe8da; background: #f6fdf9; color: var(--pine-deep); }
.btn--clay { background: var(--clay); color: #fff; }
.btn--clay:hover { background: #cf6539; }
.btn--small { padding: 8px 16px; font-size: 0.85rem; }
.btn--block { width: 100%; }
.btn[disabled] { opacity: 0.5; cursor: not-allowed; transform: none; }

.chip {
  display: inline-flex; align-items: center; gap: 6px;
  border: 1px solid var(--line); background: var(--surface);
  color: var(--ink); border-radius: 999px; padding: 9px 15px;
  font: inherit; font-size: 0.875rem; font-weight: 500; cursor: pointer;
  text-decoration: none;
  transition: border-color 0.12s, background 0.12s;
}
.chip:hover { border-color: #cfe8da; background: #f2fbf6; text-decoration: none; }
.chip--on { border-color: var(--pine); background: var(--pine); color: #fff; }
.chip--on:hover { border-color: var(--pine-deep); background: var(--pine-deep); color: #fff; }

/* ------------------------------------------------------- application form --- */
/* A chip that wraps a checkbox. Without the checked rule the only sign a focus
   area had been picked was the native tick, which is easy to miss in a row of
   twelve. */
.chip-row { display: flex; flex-wrap: wrap; gap: 8px; }
.chip--pick input { margin: 0; accent-color: var(--pine); }
.chip--pick:has(input:checked) {
  border-color: var(--pine); background: var(--pine-soft); color: var(--pine-deep); font-weight: 600;
}
.consent-row {
  display: flex; align-items: flex-start; gap: 10px; cursor: pointer;
  border: 1px solid var(--line); border-radius: var(--radius-sm);
  background: var(--surface); padding: 14px 16px; margin-top: 18px;
}
.consent-row input { margin: 3px 0 0; flex: none; accent-color: var(--pine); }

/* ---------------------------------------------------------- booking ------- */
/* The counsellor picker. Two columns rather than three: these are not shop
   cards, they are people, and the credential and the fee are the two things
   anyone actually compares. */
.bk-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
button.bk-pick {
  font: inherit; color: inherit; text-align: left; cursor: pointer; padding: 16px;
  border: 1px solid var(--line); background: var(--surface); border-radius: var(--radius);
  transition: transform 0.15s ease, box-shadow 0.2s ease, border-color 0.2s ease;
}
button.bk-pick:hover { transform: translateY(-3px); box-shadow: var(--shadow-md); border-color: #d5ecdd; }
button.bk-pick.on { border-color: var(--pine); box-shadow: 0 0 0 2px var(--pine-soft); }

/* The day strip scrolls sideways on a phone instead of wrapping into six rows —
   a week is a horizontal thing, and a wrapped grid of dates is read wrong. */
.bk-days { display: flex; gap: 8px; overflow-x: auto; padding: 2px 2px 8px; }
.bk-day {
  font: inherit; cursor: pointer; flex: none; width: 74px; padding: 10px 6px;
  display: flex; flex-direction: column; align-items: center; gap: 1px;
  border: 1px solid var(--line); border-radius: var(--radius-sm);
  background: var(--surface); color: var(--ink); line-height: 1.15;
}
.bk-day:hover { border-color: #cfe8da; background: #f2fbf6; }
.bk-day.on { border-color: var(--pine); background: var(--pine); color: #fff; }
.bk-day__dow { font-size: 0.68rem; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; opacity: 0.75; }
.bk-day__num { font-size: 1.25rem; font-weight: 700; }
.bk-day__mon { font-size: 0.7rem; opacity: 0.75; }
/* How many hours that day has left. The one number that stops somebody opening
   six days to find the seventh. */
.bk-day__n { font-size: 0.62rem; opacity: 0.6; margin-top: 2px; }
.bk-times { display: flex; flex-wrap: wrap; gap: 8px; }
button.chip { font: inherit; cursor: pointer; }

@media (max-width: 640px) {
  .bk-grid { grid-template-columns: 1fr; }
}

.tag {
  display: inline-block; font-size: 0.72rem; font-weight: 600; letter-spacing: 0.03em;
  color: var(--pine-deep); background: var(--pine-soft);
  border-radius: 999px; padding: 4px 11px;
}
.tag--clay { color: #b3542b; background: var(--clay-soft); }
.tag--muted { color: var(--muted); background: var(--sand); }
.tag--ok { color: #1c7a4b; background: var(--pine-soft); }
.tag--warn { color: #8a6414; background: #fdf3d8; }
.tag--stop { color: #a03e30; background: #fbe9e5; }

/* -------------------------------------------------------------- hero --- */
.hero {
  padding: 72px 0 60px;
  background:
    radial-gradient(880px 400px at 10% -10%, #e2f6ea 0%, rgba(226, 246, 234, 0) 62%),
    radial-gradient(700px 340px at 96% 4%, #fdf0e6 0%, rgba(253, 240, 230, 0) 60%);
}
.hero__grid { display: grid; grid-template-columns: 1.15fr 0.85fr; gap: 52px; align-items: center; }
.hero h1 { margin-bottom: 0.35em; }
.hero .lede { font-size: 1.1rem; color: var(--muted); max-width: 34em; }

/* The landing page's first section is the chat's own furniture — the mark on
   the right, the box under it — so the page reads as the thing it is selling.
   The section already spans the viewport; .wrap--wide is what keeps the copy
   readable inside it, and the entry row takes that full width on purpose. */
.hero--entry .hero__grid { align-items: center; margin-bottom: 40px; }
.hero__bot { position: relative; width: min(100%, 300px); aspect-ratio: 1; justify-self: center; }
/* The chat rail sizes the mark off its column; here it fills this box instead.
   The halos are deliberately not in this rule: they are positioned by `inset:
   5%` off their own edges, and giving them a width as well anchors them at
   left: 5% and oversizes them, which reads as a ring sliding off the mark.
   Everything else about the beat — the halos' inset, the timings, the
   reduced-motion override — is the rail's, unchanged. */
.hero__bot .bot__mark { width: 100%; height: 100%; }

.entry { max-width: 720px; margin: 0 auto; }
.entry__row {
  display: flex; align-items: center; gap: 10px;
  padding: 7px 7px 7px 20px; border-radius: 999px;
  background: var(--card); border: 1.5px solid var(--line);
  box-shadow: var(--shadow-sm);
  transition: border-color .18s ease, box-shadow .18s ease;
}
.entry__row:focus-within { border-color: var(--pine); box-shadow: 0 0 0 4px var(--pine-soft); }
/* 16px, and it stays 16px at every width: below that iOS Safari zooms the whole
   page the moment the box takes focus, which on a phone looks like the layout
   breaking. The chat composer is pinned for the same reason. */
.entry__input {
  flex: 1; min-width: 0; font: inherit; font-size: 16px; color: var(--ink);
  background: none; border: 0; outline: none; padding: 12px 0;
}
.entry__input::placeholder { color: var(--faint); }
.entry__go {
  flex: none; display: grid; place-items: center; width: 46px; height: 46px;
  border: 0; border-radius: 50%; cursor: pointer;
  background: var(--pine); color: #fff; transition: background .18s ease, transform .18s ease;
}
.entry__go:hover { background: var(--pine-deep); }
.entry__go:active { transform: scale(.94); }
.entry__go .ico { width: 21px; height: 21px; }
.entry__note { margin: 12px 0 0; text-align: center; color: var(--faint); font-size: 0.82rem; }
.entry__chips { display: flex; flex-wrap: wrap; justify-content: center; gap: 8px; margin-top: 14px; }

@media (max-width: 880px) {
  .hero { padding: 40px 0 34px; }
  .hero__grid { grid-template-columns: 1fr; gap: 34px; }
  /* Stacked, the copy leads and the mark follows it — the mark is the hook on
     a wide screen, but on a phone the sentence is what has to be read first. */
  .hero--entry .hero__grid { margin-bottom: 26px; }
  .hero__bot { width: 132px; }
  .entry__row { padding: 5px 5px 5px 16px; }
  .entry__go { width: 42px; height: 42px; }
}


/* ----------------------------------------------------------- sections --- */
.section { padding: 62px 0; }
.section--tint { background: var(--surface-2); }
/* Was the dark green banner — now a soft mint band with dark ink. */
.section--deep {
  background: linear-gradient(165deg, #e6f6ec 0%, #f4fbf6 100%);
  border-top: 1px solid #ddefe4;
  border-bottom: 1px solid #ddefe4;
}
.section--deep .card { border-color: #ddefe4; }
.section_head { max-width: 44rem; margin-bottom: 32px; }
.section_head p { color: var(--muted); font-size: 1.02rem; }

.grid { display: grid; gap: 22px; }
.grid--2 { grid-template-columns: repeat(2, 1fr); }
.grid--3 { grid-template-columns: repeat(3, 1fr); }
.grid--4 { grid-template-columns: repeat(4, 1fr); }
/* A pair, capped at the width three used to fill and centred in it. The home
   page shows what the pricing page shows minus the free tier, and with the
   audio session gone that is two cards — which under `grid--3` left a ~470px
   hole where the third column had been. Capped rather than stretched: two equal
   columns across the 1392px wrap are 684px each, and a plan card that wide
   stops reading as a card. 940px puts each one back at ~459px, within a couple
   of pixels of the width the free tier and Care used to have. */
.grid--pair { grid-template-columns: repeat(2, 1fr); max-width: 940px; margin: 0 auto; }
@media (max-width: 980px) { .grid--4 { grid-template-columns: repeat(2, 1fr); } .grid--3 { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 700px) { .grid--2, .grid--3, .grid--4, .grid--pair { grid-template-columns: 1fr; } }

/* -------------------------------------------------------------- cards --- */
.card {
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 26px; box-shadow: var(--shadow-sm);
}
.card h3 { margin-bottom: 0.35em; }
.card p:last-child { margin-bottom: 0; }
.card--lift { transition: transform 0.15s ease, box-shadow 0.2s ease, border-color 0.2s ease; }
.card--lift:hover { transform: translateY(-3px); box-shadow: var(--shadow-md); border-color: #d5ecdd; }

/* ----------------------------------------------------------------- doors --- */
/* The mindline.sg card language: a tinted door with no border, a one-line
   promise, a small mark, and an arrow. Whole-card links; arrows at the foot. */
.doors { display: grid; grid-template-columns: repeat(3, 1fr); gap: 18px; }
@media (max-width: 980px) { .doors { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 700px) { .doors { grid-template-columns: 1fr; } }

.door {
  display: flex; flex-direction: column; gap: 7px;
  background: var(--surface-2); border-radius: 22px; padding: 24px 26px;
  color: var(--ink); min-height: 172px;
  transition: transform .15s ease, box-shadow .2s ease;
}
.door:hover { text-decoration: none; transform: translateY(-3px); box-shadow: var(--shadow-md); }
.door__title { font-family: var(--serif); font-weight: 800; font-size: 1.15rem; line-height: 1.3; letter-spacing: -0.01em; }
.door__sub { color: var(--muted); font-size: .92rem; max-width: 30em; }
.door__arrow { margin-top: auto; padding-top: 14px; font-weight: 600; font-size: .92rem; color: var(--pine-deep); }
/* the small doors' affordance: one round arrow, bottom right */
.door__go {
  margin-top: auto; align-self: flex-end;
  width: 34px; height: 34px; border-radius: 50%;
  background: rgba(255, 255, 255, .75); color: var(--ink);
  display: grid; place-items: center; font-size: .95rem;
  transition: background .15s ease, transform .15s ease;
}
.door:hover .door__go { background: #fff; transform: translateX(2px); }
.door__art { margin-bottom: 8px; }
.door__top { display: flex; align-items: flex-start; justify-content: space-between; gap: 14px; margin-bottom: 6px; }
.door__top .door__art { margin-bottom: 0; }
.door--mint   { background: var(--tint-mint); }
.door--butter { background: var(--tint-butter); }
.door--sky    { background: var(--tint-sky); }
.door--lav    { background: var(--tint-lav); }
.door--blush  { background: var(--tint-blush); }
.door--sand   { background: var(--sand); }

/* the crisis door's own CTA: the numbers, big enough to read at a glance.
   minmax(0, max-content): identical on desktop, but the columns can give way
   on a narrow phone instead of pushing the whole page sideways. */
.door__lines { display: grid; grid-template-columns: repeat(2, minmax(0, max-content)); gap: 10px 30px; margin-top: 8px; }
.door__lines a { display: flex; flex-direction: column; line-height: 1.15; color: var(--ink); font-size: .78rem; }
.door__lines b { font-family: var(--serif); font-size: 1.55rem; color: #b3542b; letter-spacing: -0.01em; }
.door__lines a:hover { text-decoration: none; }
.door__lines a:hover b { text-decoration: underline; }

/* illustration slot — a generated line drawing drops straight in here;
   the module's mini-graph sits beside it, so the mark is sized for a pair */
.door__art img { display: block; width: 62px; height: 62px; object-fit: contain; }
.door__viz { padding-top: 4px; }
.door__viz svg { display: block; width: 88px; height: auto; }

.card__num {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 42px; height: 42px; padding: 0 11px; margin-bottom: 12px;
  font-family: var(--serif); font-weight: 800; font-size: 0.95rem;
  background: var(--pine-soft); color: var(--pine-deep); border-radius: var(--radius-sm);
}
.kb-points { margin: 14px 0 0; padding: 0; list-style: none; }
.kb-points li { padding: 5px 0 5px 26px; position: relative; color: var(--muted); font-size: 0.92rem; }
.kb-points li::before {
  content: "✓"; position: absolute; left: 0; top: 5px; width: 18px; height: 18px;
  border-radius: 50%; background: var(--pine-soft); color: var(--pine-deep);
  font-size: 0.66rem; font-weight: 700; line-height: 18px; text-align: center;
}

/* quote / callout */
.callout {
  border-left: 4px solid var(--pine); background: var(--pine-soft);
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0; padding: 16px 20px; margin: 20px 0;
}
.callout--clay { border-color: var(--clay); background: var(--clay-soft); }
.callout--warn { border-color: var(--high); background: #fff6e6; }
.callout p:last-child { margin-bottom: 0; }

/* steps */
.steps { display: grid; gap: 20px; grid-template-columns: repeat(3, 1fr); }
@media (max-width: 800px) { .steps { grid-template-columns: 1fr; } }
.step__n {
  width: 36px; height: 36px; border-radius: 50%; background: var(--pine); color: #fff;
  display: inline-flex; align-items: center; justify-content: center;
  font-family: var(--serif); font-weight: 800; font-size: 0.95rem; margin-bottom: 12px;
}

/* stat blocks (audit numbers) */
.stat { text-align: left; }
.stat__big { font-family: var(--serif); font-weight: 800; font-size: 2.1rem; color: var(--pine-deep); line-height: 1.05; display: block; margin-bottom: 6px; }

/* ------------------------------------------------------------- pricing --- */
.plan-card { position: relative; display: flex; flex-direction: column; }
.plan-card--popular { border: 2px solid var(--pine); box-shadow: 0 10px 30px rgba(31, 157, 99, .13); }
.plan-card__flag {
  position: absolute; top: -13px; left: 24px; background: var(--pine); color: #fff;
  font-size: 0.72rem; font-weight: 700; letter-spacing: 0.03em;
  padding: 4px 12px; border-radius: 999px;
}
.plan-card__price { font-family: var(--serif); font-weight: 800; font-size: 2.05rem; margin: 10px 0 2px; }
.plan-card__unit { color: var(--faint); font-size: 0.85rem; }
.plan-card__for { color: var(--muted); font-size: 0.92rem; margin: 10px 0 14px; }
.plan-feats { list-style: none; padding: 0; margin: 0 0 22px; flex: 1; }
.plan-feats li { padding: 7px 0 7px 26px; position: relative; font-size: 0.92rem; color: var(--muted); }
.plan-feats li::before { content: "✓"; position: absolute; left: 0; top: 7px; color: var(--pine); font-weight: 700; }

/* ---------------------------------------------------------- counsellors --- */
.counsellor { display: flex; flex-direction: column; }
.counsellor__head { display: flex; gap: 14px; align-items: center; margin-bottom: 12px; }
.avatar {
  width: 52px; height: 52px; border-radius: 50%; flex: none;
  background: linear-gradient(140deg, #d9fdd3, #a7e8c4);
  display: flex; align-items: center; justify-content: center;
  font-family: var(--serif); font-size: 1.15rem; color: var(--pine-deep); font-weight: 800;
}
.counsellor__name { font-weight: 700; line-height: 1.25; }
.counsellor__cred { color: var(--muted); font-size: 0.8rem; line-height: 1.4; }
/* A real photo when the profile carries one; the initials tile stays the
   default for every mock profile. */
.avatar--photo { background: none; padding: 0; overflow: hidden; }
.avatar--photo img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* The Head Counsellor sits above the grid in a wider card. */
.counsellor--head { margin-bottom: 26px; }
.counsellor--head > .tag { align-self: flex-start; margin-bottom: 14px; }
.counsellor--head .counsellor__name { font-size: 1.35rem; }
.counsellor--head .counsellor__cred { font-size: 0.86rem; }
.focus-tags { display: flex; flex-wrap: wrap; gap: 6px; margin: 10px 0 14px; }
.focus-tags span { background: var(--surface-2); border-radius: 999px; padding: 4px 11px; font-size: 0.78rem; color: var(--muted); }
.counsellor__foot { display: flex; flex-wrap: wrap; gap: 8px 12px; justify-content: space-between; align-items: center; margin-top: auto; padding-top: 12px; border-top: 1px solid var(--line); }

/* ---------------------------------------------------------------- chat --- */
/* The centrepiece — bubbles read like an everyday messaging app.

   The shell is the page now rather than a card on it: Teman has a rail on the
   left and the conversation has the rest, at every width, from the moment the
   page loads. The column that used to open only when voice was switched on is
   simply the layout, which is what consolidating the two surfaces means. */
.chat-wrap { max-width: 1152px; margin: 0 auto; padding: 0 24px; }
/* One line up top, not three. The paragraph that used to sit beside the lede —
   the flash tier, the system prompt, the crisis screen — moved under the shell
   as #chat-mode-note for a while, and is now off the page entirely: the
   disclosure that matters is the one the conversation itself opens with, and
   the rest belongs to the docs. Above the chat it was pushing the chat itself
   off the first screen. */
/* Sized to be passed, not read. This heading is furniture beside a conversation
   that already has a name in the header below it, and at 32px on a desktop it
   was the largest thing on a screen whose subject is the transcript. */
.chat-main .page-head { padding: 20px 0 8px; }
.chat-main .page-head h1 { font-size: clamp(1.3rem, 2.2vw, 1.45rem); }
.chat-main .page-head .lede { font-size: 0.88rem; max-width: none; }
.chat-shell {
  margin: 0 auto;
  display: flex; flex-direction: column; height: min(86vh, 880px);
  background: var(--surface); border: 1px solid var(--line); border-radius: 26px;
  overflow: hidden; box-shadow: var(--shadow-md);
}
/* One row: who, then what you can do. It holds no topic and no tier — those are
   in the transcript now — so the two groups are short enough to stay on one
   line at every width, and the name block is the one thing that gives.
   `min-width: 0` on the block is what lets it: a flex child will not shrink
   below its content without it, so the supervision line would push the buttons
   off the edge instead of truncating. */
.chat-head {
  display: flex; align-items: center; gap: 10px; padding: 9px 14px;
  border-bottom: 1px solid var(--line); background: var(--surface);
}
.chat-head__who { min-width: 0; }
.chat-head__avatar { width: 36px; height: 36px; font-size: 0.95rem; }
.chat-head .who { font-family: var(--serif); font-weight: 800; font-size: 0.92rem; line-height: 1.2; display: flex; align-items: center; gap: 7px; }
.chat-head .who .tag { font-size: 0.6rem; padding: 2px 7px; }
/* Not a flex row, deliberately: the ellipsis needs a block box around the text,
   and in a flex container the text becomes an anonymous item that
   `text-overflow` cannot reach. The dot is an inline-block instead — it aligns
   the same way and the truncation actually happens. */
.chat-head .status {
  color: var(--ok); font-size: 0.72rem;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.chat-head .status::before {
  content: ""; width: 6px; height: 6px; border-radius: 50%; background: var(--ok);
  display: inline-block; vertical-align: middle; margin-right: 5px;
}
.chat-head__right { margin-left: auto; display: flex; gap: 8px; align-items: center; flex: none; }
/* Everything the conversation is made of, in one column: the transcript that
   scrolls, then the typing row and the composer, which do not. Only the
   transcript is allowed to shrink — `min-height: 0` is what lets it, and
   without it a flex child refuses to go below its content and pushes the
   composer off the bottom of the shell. */
.chat-col { grid-area: 1 / 2; display: flex; flex-direction: column; min-height: 0; }
.chat-col > :not(.chat-body) { flex: none; }
.chat-body {
  flex: 1; min-height: 0; overflow-y: auto; padding: 22px 18px 24px;
  border-left: 1px solid var(--line);
  background-color: #f6f3ec;
  background-image: radial-gradient(rgba(31, 157, 99, .05) 1px, transparent 1px);
  background-size: 18px 18px;
}
/* What the conversation is about, at the top of the transcript. It reads as a
   subject line because that is what it is — the thing the header used to carry
   and no longer does, where it competed with the name for the same row. */
.chat-topic {
  margin: 0 0 14px; font-size: 0.76rem; font-weight: 600; letter-spacing: 0.04em;
  text-transform: uppercase; color: var(--faint);
}
.chat-topic .live-flag { text-transform: none; letter-spacing: 0; }

/* The intro had no rule of its own, so the question inherited the global h3 —
   18.6px over a paragraph over eight buttons, all of it between the top of the
   transcript and the first starting point. It is a prompt, not a page title. */
#chat-intro h3 { font-size: 1.05rem; margin: 0 0 6px; line-height: 1.3; }
#chat-intro p { line-height: 1.5; }

.msg { display: flex; margin-bottom: 10px; }
.msg--ai { justify-content: flex-start; }
.msg--user { justify-content: flex-end; }
.bubble {
  max-width: 78%; padding: 10px 14px; border-radius: 18px 18px 18px 6px;
  font-size: 0.9rem; line-height: 1.55;
  background: var(--surface); border: 1px solid #eae7de; color: var(--ink);
  box-shadow: 0 1px 2px rgba(36, 49, 44, .05);
  animation: rise 0.22s ease both;
}
@keyframes rise { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }
.msg--ai .bubble { background: var(--surface); }
.msg--user .bubble { background: var(--wa); border-color: transparent; color: #1d2b24; border-radius: 18px 18px 6px 18px; }
/* The replay button on one of Teman's replies. A sibling of the bubble rather
   than a child, so the bubble next to it never reflows when the audio lands and
   the words stay exactly where they were read. Sized to a thumb rather than to
   the icon: at 375px this is a tap target first and a control second. */
.msg-say {
  flex: 0 0 auto; align-self: flex-end;
  min-width: 32px; min-height: 32px; margin: 0 0 2px 7px; padding: 0;
  display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid #eae7de; border-radius: 999px; background: var(--surface);
  color: var(--muted); cursor: pointer;
  box-shadow: 0 1px 2px rgba(36, 49, 44, .05);
}
.msg-say .ico { width: 16px; height: 16px; }
.msg-say:hover { color: var(--ink); border-color: #dcd8cc; }
.msg__meta { font-size: 0.72rem; color: var(--faint); margin: 4px 6px 0; }
.typing {
  display: inline-flex; align-self: flex-start; gap: 4px; padding: 14px 18px;
  background: var(--surface); border: 1px solid #eae7de; border-radius: 18px 18px 18px 6px;
  box-shadow: 0 1px 2px rgba(36, 49, 44, .05);
}
.typing i { width: 6px; height: 6px; border-radius: 50%; background: var(--faint); animation: blink 1.2s infinite; }
.typing i:nth-child(2) { animation-delay: 0.15s; } .typing i:nth-child(3) { animation-delay: 0.3s; }
@keyframes blink { 0%, 100% { opacity: 0.25; } 50% { opacity: 1; } }

/* The typing row sits between the transcript and the composer, where the reply
   it is standing in for will actually land. The margin is the breathing room
   that stops it reading as the last line of the conversation. */
#chat-typing { margin: 0 18px 12px; }

/* The typing bar is a keyboard target, not the end of the transcript. The
   transcript above it is a tinted, dotted plane; this is a solid white bar with
   a real top edge and a shadow that only falls upward (a non-inset box-shadow
   is clipped to outside the border box, so the safety row below is untouched).
   That edge is the whole difference between the two. */
.composer {
  position: relative; z-index: 1;
  display: flex; gap: 10px; padding: 13px 14px; border-top: 1px solid var(--line);
  background: var(--surface); box-shadow: 0 -6px 16px rgba(36, 49, 44, .06);
}
.composer input {
  flex: 1; border: 1.5px solid var(--line); border-radius: 999px; padding: 13px 18px;
  font-family: var(--sans); font-size: 0.95rem; background: var(--surface-2); color: var(--ink);
}
.composer input:focus { outline: none; border-color: var(--pine); background: var(--surface); box-shadow: 0 0 0 3px rgba(31, 157, 99, .15); }
.send-btn {
  width: 46px; height: 46px; border-radius: 50%; border: 0; background: var(--pine); color: #fff;
  font-size: 1.15rem; cursor: pointer; display: flex; align-items: center; justify-content: center; flex: none;
  box-shadow: 0 6px 16px rgba(31, 157, 99, .28); transition: background .15s ease, transform .15s ease;
}
.send-btn:hover { background: var(--pine-deep); transform: translateY(-1px); }
.send-btn:disabled, .composer input:disabled { opacity: 0.5; }

/* The 24/7 lines sit inside the chat, one tap from anywhere in the conversation
   — and the tap is in the header now rather than on a row of its own under the
   composer. That row cost the transcript a line at every width and two on a
   phone, and it was furniture around the one control that has to be findable at
   a glance. It is not quieter up here: it keeps the warm colour and the icon,
   and the header is where a person looks for what they can do. */
.chat-help {
  display: inline-flex; align-items: center; gap: 6px;
  font-family: var(--sans); font-size: 0.78rem; font-weight: 600;
  color: #b3542b; background: var(--clay-soft);
  border: 1px solid transparent; border-radius: 999px; padding: 7px 12px; cursor: pointer;
  transition: background 0.12s;
}
.chat-help:hover { background: #fbe0cf; }
.chat-help .ico { width: 14px; height: 14px; flex: none; }
#chat-crisis-card { margin-top: 0; }

.crisis-card {
  border: 1px solid #f6d9c9; border-radius: var(--radius); background: #fff7f3;
  padding: 18px 20px; margin: 6px 0 14px; max-width: 92%;
}
.crisis-card h4 { color: #b3542b; margin-bottom: 8px; font-family: var(--sans); font-size: 0.95rem; letter-spacing: 0.02em; }
.crisis-card ul { margin: 0; padding-left: 18px; }
.crisis-card li { margin-bottom: 6px; font-size: 0.92rem; }
.crisis-card .big { font-weight: 700; }
.crisis-card p a { color: var(--pine-deep); text-decoration: underline; text-underline-offset: 2px; font-weight: 600; }

/* ------------------------------------------------------------ help pages -- */
/* /help-now and /how-the-crisis-screen-works: static markup on purpose — the
   numbers are the content here, not a script's output, so these pages carry
   their own small layout rather than the chat's JS-rendered card. */
.help-lines { display: grid; gap: 14px; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); margin: 18px 0 6px; }
.help-line { background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); padding: 20px 22px; }
.help-line--urgent { background: #fff7f3; border-color: #f6d9c9; }
.help-line h3 { margin: 0 0 4px; font-size: 1.05rem; }
.help-line__num { font-size: 1.55rem; font-weight: 700; line-height: 1.25; margin: 2px 0 8px; color: var(--pine-deep); }
.help-line--urgent .help-line__num { color: #b3542b; }
.help-line__num a { color: inherit; text-decoration: underline; text-underline-offset: 3px; }
.help-line__num .wa { font-size: 0.95rem; font-weight: 600; }
.help-line .btn { margin: 2px 6px 0 0; }
/* A verbatim quote of machine output — the crisis reply, word for word. */
.reply-quote { border-left: 3px solid var(--pine); background: var(--surface-2); border-radius: 0 var(--radius-sm) var(--radius-sm) 0; padding: 14px 18px; margin: 14px 0; }
.reply-quote p { margin: 0; }

/* -- the inline account form --------------------------------------------- */
/* It lives in the transcript on purpose. Navigating to login.html would take
   the conversation with it, and the conversation is the thing the person has
   just spent an hour building — so the form comes to them instead. */
.auth-inline { margin-top: 14px; padding-top: 14px; border-top: 1px solid var(--line); max-width: 400px; }
.auth-inline__tabs { display: flex; gap: 8px; margin-bottom: 13px; }
.auth-inline .field { margin-bottom: 10px; }
.auth-inline .field label { display: block; font-size: 0.78rem; color: var(--muted); margin-bottom: 4px; }
.auth-inline input {
  width: 100%; border: 1px solid var(--line); border-radius: 10px; padding: 10px 13px;
  font-family: var(--sans); font-size: 0.92rem; background: var(--surface-2); color: var(--ink);
}
.auth-inline input:focus { outline: none; border-color: var(--pine); background: var(--surface); box-shadow: 0 0 0 3px rgba(31, 157, 99, .15); }
.auth-inline__msg { margin: 0 0 9px; min-height: 1.2em; color: var(--muted); }
.auth-inline__msg--bad { color: #b3542b; }

/* -- the stage: Teman on the left, the conversation on the right ---------- */
/* One layout for both surfaces. Text and voice are the same conversation in the
   same box — the rail says what Teman is doing, the transcript says what was
   said, and switching voice on changes the rail rather than the arrangement.
   Two modes meant two layouts to keep honest, and the one that drifts is the
   one nobody is reading.

   The transcript never leaves the screen. That is the property the safety case
   rests on, not a layout preference. Everything spoken is written into it before
   it is said out loud, and everything heard is written into it as it is
   recognised — including when Teman has run out of voice and is answering in
   text only. */
/* 340px of rail was a sixth of a laptop screen given to a logo and two buttons,
   and every pixel of it came off the transcript — which is the thing the
   request wanted more of. 250px still fits the orb, the state line and the
   controls without wrapping. */
.chat-stage {
  display: grid; flex: 1; min-height: 0;
  grid-template-columns: minmax(210px, 250px) minmax(0, 1fr);
  align-items: stretch;
}
/* The rail is a column, not the room: Teman on the left at a fixed width, the
   conversation taking everything else. The reverse — a wide bot and a 340px
   transcript — is what the old voice mode did, and it is the arrangement the
   request was to change: the chat box is the thing that needs the width. */
/* The padding came in with the width. At 340px the rail could afford 24px of
   air on each side; at 250px that same air was a fifth of the column, and the
   state line — the one thing on the rail that has to be read — was wrapping to
   three lines inside 202px. */
.voice-stage {
  grid-area: 1 / 1;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 15px; padding: 24px 16px; text-align: center;
  background: linear-gradient(170deg, #e9f7ef 0%, #fbfdfb 72%);
}

/* ---- the bot ----------------------------------------------------------- --
   The logo itself, promoted from the favicon the same way the wordmark was:
   the green circle and the smaller orange one, beating.

   The beat answers the state, so it carries information instead of
   decorating. It quickens when Teman speaks, slows while it thinks, and stops
   when the microphone is off. A bot that beats the same way whether it can
   hear you or not is the one thing on this screen that could mislead. */
.bot {
  position: relative; flex: none; width: min(72%, 165px); aspect-ratio: 1;
  padding: 0; border: 0; background: none; cursor: pointer; border-radius: 50%;
  animation: botIn .5s cubic-bezier(.2, .9, .3, 1.2) both;
}
@keyframes botIn { from { opacity: 0; transform: scale(.7); } to { opacity: 1; transform: none; } }
.bot:focus-visible { outline: 3px solid var(--pine); outline-offset: 8px; }

.bot__mark {
  display: block; width: 100%; height: 100%; overflow: visible;
  filter: drop-shadow(0 18px 34px rgba(31, 157, 99, .3));
}
/* The beat belongs to the green circle, not to the pair.
 *
 * It used to be a transform on the whole svg, anchored at the big circle's
 * centre — so both circles grew together and the mark beat as one object. The
 * green one is the one that means "Teman is here"; the orange one is a smaller
 * satellite, and dragging it along made the logo swell rather than pulse.
 *
 * `transform-box: fill-box` is what makes this possible at all: without it a
 * percentage `transform-origin` on an SVG child resolves against the nearest
 * viewport, so the circle would scale away from its own centre and drift across
 * the mark. With it, `center` means the centre of this circle. */
.bot__mark .mark__green {
  transform-box: fill-box;
  transform-origin: center;
  animation: heartbeat 3.6s ease-in-out infinite;
}
/* The orange satellite does not beat, and this is where that is written down
   rather than left as an absence to be verified. `!important` because the thing
   it guards against is somebody later animating `.bot__mark` itself — the whole
   svg — which is the version of this that was here before, and which would
   quietly swallow the small circle again without a single test noticing. */
.bot__mark .mark__brown { animation: none !important; }
@keyframes heartbeat {
  0%, 100% { transform: scale(1); }
  12%      { transform: scale(1.09); }
  24%      { transform: scale(1); }
  36%      { transform: scale(1.055); }
  52%      { transform: scale(1); }
}
.bot__halo {
  position: absolute; inset: 5%; border-radius: 50%; pointer-events: none;
  border: 1.5px solid rgba(31, 157, 99, .32);
  animation: halo 3.6s ease-out infinite;
}
.bot__halo--2 { animation-delay: 1.8s; }
@keyframes halo {
  0%        { transform: scale(.66); opacity: .65; }
  80%, 100% { transform: scale(1.32); opacity: 0; }
}

.voice-state { color: var(--muted); font-size: 0.85rem; line-height: 1.45; min-height: 2.6em; max-width: 26ch; }
.voice-controls { display: flex; gap: 10px; }
/* Smaller than the 52px .call-btn it inherits: these sit under the orb on a
   rail that is now a third narrower, and at 52px the row read as the subject of
   the column rather than as controls beside Teman. */
.voice-controls .call-btn { width: 38px; height: 38px; font-size: 0.95rem; }
/* Both glyphs are drawn now. The mic used to be an emoji character sitting
   beside a drawing, which is why this rule exists at all — at 16px the drawing
   read as smaller than the emoji it sat next to. The size stays because both
   drawings are detailed enough that below 19px they smudge. */
.voice-controls .call-btn .ico { width: 19px; height: 19px; }
/* The smallest type on the page. It answers the question the two controls above
   it raise — is this thing recording me, and does it write before it speaks —
   and an answer read twice becomes furniture, so it is set like a footnote
   rather than like copy. */
.voice-note { margin: 0; font-size: 0.68rem; line-height: 1.45; color: var(--muted); max-width: 34ch; }
.voice-stage .call-super { margin-top: 2px; font-size: 0.68rem; line-height: 1.4; padding: 5px 11px; max-width: 100%; }

/* Every state override names the green circle and the halo, never the svg.
   The beat is a property of the circle now (see .bot__mark .mark__green), so a
   rule pointing at .bot__mark would set a duration on an element with no
   animation on it and the state would silently stop changing the pace. The
   rules that are about how the mark *looks* — opacity, greyscale — still name
   the svg, because those apply to both circles. */
.voice-stage[data-voice="listening"] .mark__green,
.voice-stage[data-voice="listening"] .bot__halo { animation-duration: 4.6s; }
/* `idle` is the page at rest, before voice is switched on. It needs no rule:
   the base heartbeat below is the slowest beat in the set, which is exactly
   what resting looks like. */
/* `quiet` is the one state that has to be legible the other way round: the
   microphone is live and Teman is not speaking, because the spoken allowance is
   spent. It keeps the listening pace on purpose — slowing or stopping the beat
   would say the microphone is off, and it is not. The state line and the card
   in the transcript are what carry the difference. */
.voice-stage[data-voice="quiet"] .mark__green,
.voice-stage[data-voice="quiet"] .bot__halo { animation-duration: 4.6s; }
.voice-stage[data-voice="speaking"] .mark__green,
.voice-stage[data-voice="speaking"] .bot__halo  { animation-duration: 1.9s; }
.voice-stage[data-voice="thinking"] .mark__green { animation-duration: 2.8s; }
.voice-stage[data-voice="thinking"] .bot__mark   { opacity: .88; }
.voice-stage[data-voice="paused"] .bot__mark,
.voice-stage[data-voice="noMic"]  .bot__mark    { filter: grayscale(.45); }
.voice-stage[data-voice="paused"] .mark__green,
.voice-stage[data-voice="noMic"]  .mark__green  { animation-play-state: paused; }
.voice-stage[data-voice="paused"] .bot__halo,
.voice-stage[data-voice="noMic"]  .bot__halo    { animation-play-state: paused; opacity: .25; }

/* What the microphone is hearing, written into the transcript as it is
   recognised and replaced by the real message the moment the sentence is
   sent. It is the voice-to-text step shown rather than asserted — the person
   watches their own words land in the chat box. */
.bubble--heard {
  background: var(--wa); border-color: transparent; color: #1d2b24;
  border-radius: 18px 18px 6px 18px; opacity: .62; font-style: italic;
}
.bubble--heard::after { content: "▍"; margin-left: 2px; animation: caret 1s steps(2) infinite; }
@keyframes caret { 0%, 50% { opacity: 1; } 51%, 100% { opacity: 0; } }

@media (max-width: 880px) {
  /* The phone. The chat stops being a card floating in a marketing scroll and
     becomes the screen: full width, one visible viewport tall, with the typing
     bar pinned to the bottom edge of it.

     `dvh` rather than `vh` because the URL bar collapses as you scroll and a
     `vh`-sized box is taller than the phone whenever that bar is showing.
     `--kb` is what watchKeyboard() publishes when the soft keyboard takes a bite
     out of the visual viewport: without it the shell keeps its full height and
     the composer ends up behind the keys, which is the "keyboard squeezes
     everything away" complaint. Subtracting it puts the composer back on top.
     66px is the sticky site header, whose height is fixed at styles.css:115. */
  body[data-page="chat"] main {
    height: calc(100dvh - 66px - var(--kb, 0px));
    display: flex; flex-direction: column; overflow: hidden;
  }
  /* The footer comes off, AND the document stops scrolling behind the shell.
     Both, because `--kb` alone was not enough and the live report says why:
     "the keyboard pops up and the whole page is pushed up with the footer over
     the keyboard and the typing bar far away". With the footer still below
     main, the document has exactly the footer's height of scrollable room —
     and when an input takes focus, the browser scrolls the layout viewport to
     "reveal" it. That scroll lifts the shell by the footer's height, drops the
     footer onto the keyboard, and leaves the composer riding up out of reach.
     The calc() was right; there was simply somewhere for the page to scroll.
     With nothing below `main` the document is header + shell = precisely the
     visual viewport (100dvh - 66px - kb + the 66px header), there is no scroll
     to make, and the composer stays where `--kb` put it — glued to the top of
     the keyboard. `overflow: hidden` is the belt to that braces: even a
     rubber-band pan cannot drag the shell now.
     Nothing is lost with the footer: its two doors are on screen already —
     "Get help now" in the chat head carries the crisis numbers, and the menu
     (the header's ☰) carries both them and the counsellor panel. */
  body[data-page="chat"] .site-foot { display: none; }
  body[data-page="chat"] { overflow: hidden; overscroll-behavior: none; }
  /* `margin: 0`, not the desktop `margin: 0 auto`. An auto margin in the cross
     axis cancels `align-items: stretch`, so with `max-width: none` the wrap
     stops filling and shrink-to-fits instead — and its content floor was 389px
     on a 375px phone, which put the right-hand end of the chat header (and the
     End button with it) off the edge of the screen. The auto margin is there to
     centre a capped column; there is no cap any more, so it has no job. */
  .chat-main .chat-wrap { flex: 1; min-height: 0; max-width: none; padding: 0; margin: 0; }
  /* The heading and its paragraph come off entirely, which is what a chat app
     has: no page title above the conversation. "Talk to Teman" is the name in
     the header a few pixels below, and the lede under it was describing the
     screen you are already looking at. On a 746px phone the pair cost about
     60px, and 60px here is two messages. The same words are on the page above
     the shell only on a desktop, where they are not in anything's way. */
  .chat-main .page-head { display: none; }

  /* The shell fills the screen exactly: the stage takes every pixel that is
     left, and the composer at the bottom of the column is the bottom of the
     page. Nothing else has a strip down there any more — the DeepSeek and
     crisis note that used to sit under the shell is off the page entirely,
     and the disclosure it carried lives in the transcript's opening, above
     the first reply. */
  #chat-root { display: flex; flex-direction: column; height: 100%; }
  /* Same auto-margin trap as .chat-wrap above, and the same fix. */
  .chat-shell { flex: 1; min-height: 0; margin: 0; }
  /* The two cards under the shell come off. On a phone the chat is the page,
     and a card stack below a composer pinned to the bottom is pixels nobody
     asked to scroll past — the same reasoning the footnote strip above just
     lost to. Both doors they hold (the crisis numbers, the counsellor panel)
     are still on screen: "Get help now" is in the head, and the footer is one
     scroll below the shell. */
  .chat-aside { display: none; }
  /* The eight starting points go too. They sit at the top of the transcript —
     the first thing anyone sees — and on a phone a starting point is a
     desktop luxury: the input is under a thumb already, and the mic is on the
     strip above it. What remains is the disclosure and one line pointing at
     both, which is the part that had to stay. */
  #chat-intro .grid { display: none; }
  /* Full bleed: on a phone the shell is the screen, so its own frame would be a
     border drawn around the thing you are already inside. */
  .chat-shell { border-radius: 0; border-left: 0; border-right: 0; max-width: none; }

  /* The rail stops being a column and becomes a strip: a small orb, the state
     line, the mic, on one row above the transcript. It keeps the two things that
     matter — that Teman is on screen, and what Teman is doing.
     The supervision chip and the microphone note come off here; the head above
     already says "Supervised by human counsellors", so nothing is lost that is
     not still on screen, and the strip gets its height back. */
  .chat-stage { grid-template-columns: 1fr; grid-template-rows: auto minmax(0, 1fr); }
  .voice-stage {
    grid-area: 1 / 1;
    flex-direction: row; flex-wrap: wrap; row-gap: 8px;
    align-items: center; justify-content: flex-start;
    gap: 12px; padding: 9px 14px; text-align: left;
    border-bottom: 1px solid var(--line);
  }
  .chat-col { grid-area: 2 / 1; }
  .bot { width: 44px; }
  /* The state line is the reason the strip exists, so it gets the row to
     itself and the count waits its turn. Four things on one 375px row — orb,
     state, count, controls — left the state line 56px wide and wrapping to
     four lines, which is the strip failing at its one job.
     A real flex-basis, not `flex: 1` with a zero basis: at basis 0 the line
     never overflows on paper, so `flex-wrap` never fires and the count still
     wins the argument on the screen. With 140px stated, the row is honestly
     too wide, the count wraps to its own line, and the state line keeps 195px.
     The budget tag is back at five left — the point at which it is worth a
     line — and until then the wall is what carries it. `order: 1` keeps the
     mic and End on the first row: left in source order the tag wraps first and
     drags the controls down with it, so the one button a person is reaching
     for moves 50px the moment their allowance gets low. */
  .voice-state { flex: 1 1 140px; min-width: 0; font-size: 0.8rem; max-width: none; }
  .voice-controls { flex: none; gap: 8px; }
  #voice-budget { flex: none; order: 1; }
  #voice-budget:not(.tag--warn) { display: none; }
  .voice-stage .call-super, .voice-stage .voice-note { display: none; }
  /* 44px, not 32px. These are the two switches on the strip and they were the
     smallest tap targets on the page — smaller than the thing they control
     (the orb) and smaller than the send button beside them. 32px is what a
     mouse needs; a thumb needs the 44px every platform's own guidance names,
     and the row has the width for it: orb, then two buttons, is 152px of 375. */
  .voice-stage .call-btn { width: 44px; height: 44px; font-size: 0.85rem; }
  .voice-stage .call-btn .ico { width: 20px; height: 20px; }
  .chat-body { border-left: 0; padding: 14px 14px 12px; }

  /* The soft keyboard. Under 16px iOS Safari zooms the whole page when an input
     takes focus, and a page zoomed to 1.3x is one the person then has to pinch
     back out of — which is most of what "pinch should not move it" is about. */
  .composer input { font-size: 16px; padding: 10px 15px; }

  .chat-body { overscroll-behavior: contain; -webkit-overflow-scrolling: touch; }
  /* The composer is now the bottom of the shell, so the safe-area inset that
     used to sit under the help row belongs to it. Without this the send button
     lands on the home indicator on a notched phone — the one control nothing
     else can substitute for.
     Smaller than the desktop bar on purpose: 13px of padding around a 46px
     send button is 72px, a fifth of a 746px screen spent on one text input,
     every second of the conversation. 8px around a 40px button is 56px and
     still past the tap-target floor. The bar itself does not move — the
     column pins it to the bottom of the shell at every size. */
  .composer { gap: 8px; padding: 8px 12px calc(8px + env(safe-area-inset-bottom, 0px)); }
  .send-btn { width: 40px; height: 40px; font-size: 1rem; }
  #chat-typing { margin: 0 14px 10px; }

  /* Two rows, and the split between them is the point. The first is who this
     is — the avatar, the name, and, beside the name rather than under it, the
     supervision line. It used to wrap under the name, which cost two lines on
     every phone and left "Supervised by human counsell…" reading as a layout
     bug rather than as the claim the product rests on. Beside the name at
     0.7rem it is about 160px of a 351px row and finishes its own sentence.
     The second row is what you can do about it: what you have left, pushed to
     the far left, then the two buttons. */
  .chat-head { flex-wrap: wrap; padding: 8px 12px; gap: 6px 8px; }
  .chat-head__avatar { width: 32px; height: 32px; font-size: 0.85rem; }
  /* A row of its own inside the flex row above, so the name and the claim sit
     on one baseline. `min-width: 0` on both this and the status is what lets
     the claim truncate rather than widen the row; the name itself never gives
     (`flex: none`) because "Teman A…" is worse than a clipped sentence, and
     the sentence is on the safety page in full. */
  .chat-head__who { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: row; align-items: center; gap: 7px; }
  .chat-head .who { flex: none; font-size: 0.88rem; white-space: nowrap; }
  .chat-head .status { min-width: 0; font-size: 0.7rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  /* Full width, forced onto its own line, so the count has a row to start on.
     `margin-left: auto` is the desktop centring and has no job here. */
  .chat-head__right { flex: 1 1 100%; margin-left: 0; }
  #chat-count { margin-right: auto; }
  .chat-help { padding: 6px 10px; font-size: 0.74rem; }
  .chat-head__right .btn--small { padding: 6px 11px; font-size: 0.74rem; }
  .chat-topic { font-size: 0.72rem; margin-bottom: 12px; }
}

/* ----------------------------------------------------------------- call --- */
/* What is left of the standalone call page's styles. The shell, timer, state
   line and scripted transcript went with the page; these three are the
   controls the live voice rail on the chat page actually renders. */
.call-btn {
  position: relative;
  width: 52px; height: 52px; border-radius: 50%; border: 1px solid var(--line);
  background: var(--surface); color: var(--ink); font-size: 1.1rem; cursor: pointer;
  box-shadow: var(--shadow-sm); transition: transform .15s ease;
  display: inline-flex; align-items: center; justify-content: center;
}
.call-btn:hover { transform: translateY(-2px); }
.call-btn--end { background: #ffe9e4; border-color: #f6d0c7; color: #b04a40; }
.call-btn--end:hover { background: #ffdcd4; }
/* Muted reads as muted at a glance: the same speaker with a stroke through it.
   Drawn here rather than as a second icon, because two drawings of one control
   are two drawings that can stop agreeing. The outline is inset from the button
   edge so the strike crosses the glyph, not the circle. */
.call-btn--off { color: var(--muted); background: transparent; box-shadow: none; }
.call-btn--off::after {
  content: ""; position: absolute; left: 50%; top: 50%;
  width: 21px; height: 2px; border-radius: 2px; background: currentColor;
  transform: translate(-50%, -50%) rotate(-45deg);
}
.call-btn--off .ico { opacity: .75; }
/* The microphone is live, and this is the only button on the rail that says so.
   Teman speaking is the default and needs no badge; a microphone that is
   hearing is the state a person has to be able to check at a glance. Colour
   only — the strike above owns the off state, and filling the circle would
   read as a primary action rather than as a state. */
.call-btn--live { color: var(--pine-deep); background: var(--pine-soft); border-color: rgba(31, 157, 99, .5); }
.call-super {
  margin-top: 20px; font-size: 0.8rem; color: var(--pine-deep); display: inline-flex; gap: 8px; align-items: center;
  background: var(--pine-soft); border-radius: 999px; padding: 7px 15px;
}

/* ------------------------------------------------------------ check-in --- */
.instrument { max-width: 780px; margin: 0 auto; }
.q-item { border-bottom: 1px solid var(--line); padding: 20px 0; }
.q-item:last-of-type { border-bottom: 0; }
.q-text { font-weight: 500; margin-bottom: 14px; }
/* The answer is a position on a line, so the control is a range and not a row
   of buttons. The row reads [Rough] ————o———— [Good] 7, and the grid keeps the
   readout column a fixed width so the track does not shift as the number
   changes width from 0 to 10. */
.q-slide-row { display: grid; grid-template-columns: auto minmax(0, 1fr) auto 2.2rem; align-items: center; gap: 12px; }
.q-slide { width: 100%; margin: 0; accent-color: var(--pine); cursor: pointer; }
.q-slide:focus-visible { outline: 2px solid var(--pine); outline-offset: 4px; border-radius: 999px; }
.q-val { text-align: right; font-weight: 600; font-variant-numeric: tabular-nums; }
@media (max-width: 640px) {
  /* The anchors are the first thing to go on a phone: the slider is the
     control, and 0 and 10 are discoverable by dragging it. The readout stays,
     because it is the only exact number on the row. */
  .q-slide-row { grid-template-columns: minmax(0, 1fr) 2.2rem; }
  .q-slide-row > .tiny { display: none; }
}
.score-bar { height: 10px; border-radius: 999px; background: var(--sand); overflow: hidden; margin: 18px 0 6px; }
.score-bar i { display: block; height: 100%; border-radius: 999px; transition: width 0.6s ease; }
/* The four areas of the outcome measure, read side by side rather than as one
   number — a total hides which part of life moved. */
.subscale { margin-top: 14px; }
.subscale .score-bar { margin: 8px 0 0; height: 8px; }
/* The list owns the spacing between scales, so the children stop adding their
   own on top of it — otherwise the gap is 26px between items and 14px before
   the first, which reads as a mistake. */
.subscale-list { display: grid; gap: 14px; margin-top: 12px; }
.subscale-list .subscale { margin-top: 0; }
.result-card { border-radius: var(--radius); padding: 26px 28px; border: 1px solid var(--line); background: var(--surface); }
.result-card.tone-ok { border-color: #cdeada; background: #f2fbf6; } .result-card.tone-ok .score-bar i { background: var(--ok); }
.result-card.tone-mild { border-color: #f0e3c2; background: #fdf9ec; } .result-card.tone-mild .score-bar i { background: var(--mild); }
.result-card.tone-mid { border-color: #f3ddc8; background: #fdf4eb; } .result-card.tone-mid .score-bar i { background: var(--mid); }
.result-card.tone-high { border-color: #f5d3cb; background: #fdefec; } .result-card.tone-high .score-bar i { background: var(--high); }

/* ------------------------------------------------------------- account --- */
.stat-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 16px; }
@media (max-width: 900px) { .stat-grid { grid-template-columns: repeat(2, 1fr); } }
/* One column on a phone. Two 1fr tracks at 390px give each card about 160px,
   and the sparkline is drawn 260px wide — so the tracks grow to fit it, the
   grid overflows the page, and the whole account page scrolls sideways. The
   card's own min-width: 0 is the other half of the fix: a grid item's
   automatic minimum is its min-content width, which is exactly what let a
   260px drawing push a 160px column out of the viewport. */
@media (max-width: 560px) { .stat-grid { grid-template-columns: 1fr; } }
.stat-card { background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); padding: 18px; box-shadow: var(--shadow-sm); min-width: 0; }
.stat-card .k { color: var(--faint); font-size: 0.78rem; text-transform: uppercase; letter-spacing: 0.06em; }
.stat-card .v { font-family: var(--serif); font-weight: 800; font-size: 1.35rem; margin-top: 6px; }
.list-rows { display: grid; gap: 8px; }
.row {
  display: flex; align-items: center; gap: 16px; padding: 13px 18px; font-size: 0.93rem;
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius-sm);
}
.row .grow { flex: 1; }
.row .k { color: var(--faint); font-size: 0.8rem; }
.badge { font-size: 0.75rem; font-weight: 600; border-radius: 999px; padding: 3px 10px; }
.badge--ok { background: var(--pine-soft); color: var(--pine-deep); }
.badge--plain { background: var(--sand); color: var(--muted); }
/* A check-in that flagged — a positive safety item, or a band that opens a
   case. Same token the high bands use, so the colour means one thing. */
.badge--warn { background: #fdefec; color: var(--high); }
/* The trend line. This selector used to read `.spark svg`, which matches
   nothing — sparkline() puts `class="spark"` on the svg itself, so the rule
   never applied and the drawing kept its hard-coded 260px width at every
   viewport. `svg.spark` is the element that actually exists, and max-width
   lets it shrink inside a narrow card instead of pushing the page sideways. */
svg.spark { display: block; max-width: 100%; height: auto; }

/* ------------------------------------------------------------ checkout --- */
.steps-nav { display: flex; gap: 10px; margin-bottom: 30px; flex-wrap: wrap; }
.step-pill {
  display: flex; align-items: center; gap: 9px; font-size: 0.85rem; color: var(--muted);
  border: 1px solid var(--line); border-radius: 999px; padding: 8px 16px; background: var(--surface);
}
.step-pill .n { width: 20px; height: 20px; border-radius: 50%; background: var(--sand); color: var(--muted); display: flex; align-items: center; justify-content: center; font-size: 0.74rem; font-weight: 700; }
.step-pill.on { color: var(--pine-deep); border-color: var(--pine); background: var(--pine-soft); font-weight: 600; }
.step-pill.on .n { background: var(--pine); color: #fff; }
/* The same pill as a button, because the application form's steps are clickable
   and the checkout's are not. Buttons do not inherit the page font on their own. */
button.step-pill { font: inherit; font-size: 0.85rem; cursor: pointer; }
button.step-pill[aria-selected="true"] { cursor: default; }
.pay-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
@media (max-width: 640px) { .pay-grid { grid-template-columns: 1fr; } }
.pay-opt {
  border: 2px solid var(--line); border-radius: var(--radius-sm); background: var(--surface); padding: 16px;
  cursor: pointer; display: flex; align-items: center; gap: 12px; font: inherit; font-weight: 500;
}
.pay-opt.on { border-color: var(--pine); background: #f2fbf6; }
.qr-box { text-align: center; padding: 22px; background: var(--surface-2); border-radius: var(--radius); }
.qr-box .fakeqr { width: 168px; height: 168px; margin: 0 auto 12px; background:
  repeating-conic-gradient(#24312c 0% 25%, #fff 0% 50%) 0 0/16px 16px; border-radius: 12px; border: 6px solid #fff; box-shadow: var(--shadow-sm); }
.field { margin-bottom: 16px; }
.field label { display: block; font-size: 0.85rem; font-weight: 600; margin-bottom: 6px; }
.field input, .field select {
  width: 100%; border: 1px solid var(--line); border-radius: var(--radius-sm);
  padding: 12px 14px; font-family: var(--sans); font-size: 0.95rem; background: var(--surface);
}
.field input:focus, .field select:focus { outline: none; border-color: var(--pine); box-shadow: 0 0 0 3px rgba(31, 157, 99, .15); }

/* -------------------------------------------------------------- footer --- */
.site-foot { background: #eef7f1; border-top: 1px solid #ddefe4; color: var(--ink); margin-top: 40px; padding: 36px 0 26px; }
.site-foot a { color: var(--muted); }
.site-foot a:hover { color: var(--pine-deep); }
.site-foot .logo { color: var(--pine-deep) !important; font-size: 1.2rem; }
.site-foot .logo__mark { width: 24px; height: 24px; }
/* Five links and the mark — every other destination lives behind the menu. */
.foot-row { display: flex; align-items: center; justify-content: space-between; gap: 16px 28px; flex-wrap: wrap; }
.foot-links { display: flex; flex-wrap: wrap; gap: 4px 24px; font-size: 0.88rem; }
.foot-base { border-top: 1px solid #ddefe4; margin-top: 24px; padding-top: 16px; font-size: 0.78rem; color: var(--faint); display: flex; justify-content: space-between; gap: 14px; flex-wrap: wrap; }

/* -------------------------------------------------------------- charts --- */
/* The visual language: fewer sentences, clearer pictures. */
.chart-card {
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 26px; box-shadow: var(--shadow-sm);
}
.chart-card h3 { margin-bottom: 0.25em; }
.chart-card .sub { font-size: 0.85rem; color: var(--faint); margin-bottom: 20px; }

.bars { display: grid; gap: 16px; }
.bar-row { display: grid; grid-template-columns: 10.5rem 1fr auto; align-items: center; gap: 14px; }
.bar-row .lbl { font-size: 0.88rem; color: var(--muted); }
.bar-track { height: 14px; background: var(--sand); border-radius: 999px; overflow: hidden; }
.bar-fill {
  height: 100%; border-radius: 999px; min-width: 12px;
  background: linear-gradient(90deg, #5fce9b, var(--pine));
  transform-origin: left center; animation: growIn 0.9s cubic-bezier(.2, .7, .2, 1) both;
}
.bar-fill--wa    { background: linear-gradient(90deg, #9fe8c1, #3fbc82); }
.bar-fill--clay  { background: linear-gradient(90deg, #f0a173, var(--clay)); }
.bar-fill--muted { background: linear-gradient(90deg, #dfe5e1, #c2ccc6); }
.bar-row .val { font-family: var(--serif); font-weight: 800; font-size: 0.98rem; }
.bar-note { font-size: 0.78rem; color: var(--faint); margin-top: 2px; }
@keyframes growIn { from { transform: scaleX(0.03); } to { transform: scaleX(1); } }

.donut-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 18px; text-align: center; }
/* The landing page shows two and the consoles three, which used to be done with
   an inline style on the element — and an inline style cannot be overridden by
   a media query, so the pair never collapsed and overflowed a phone. A modifier
   class can. */
.donut-grid--2 { grid-template-columns: repeat(2, 1fr); }
@media (max-width: 620px) { .donut-grid, .donut-grid--2 { grid-template-columns: 1fr; } }
.donut svg { display: block; margin: 0 auto 10px; }
.donut .dv { font-family: var(--serif); font-weight: 800; font-size: 1.1rem; }
.donut .dl { font-size: 0.82rem; color: var(--muted); }
.donut circle { fill: none; stroke-width: 9; stroke-linecap: round; }
.donut .track { stroke: var(--sand); }
.donut .arc { stroke: var(--pine); }

.legend { display: flex; flex-wrap: wrap; gap: 16px; font-size: 0.8rem; color: var(--muted); margin-top: 16px; }
.legend i { display: inline-block; width: 11px; height: 11px; border-radius: 4px; margin-right: 7px; vertical-align: -1px; }

.flow { display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px; }
.flow-step { background: var(--surface); border: 1px solid var(--line); border-radius: 18px; padding: 20px; text-align: center; box-shadow: var(--shadow-sm); }
.flow-step .ic {
  width: 46px; height: 46px; margin: 0 auto 10px; border-radius: 15px;
  background: var(--pine-soft); color: var(--pine-deep);
  display: flex; align-items: center; justify-content: center; font-size: 1.3rem;
}
.flow-step .t { font-family: var(--serif); font-weight: 800; font-size: 0.98rem; margin-bottom: 4px; }
.flow-step .d { font-size: 0.84rem; color: var(--muted); }

.mini-stats { display: flex; flex-wrap: wrap; gap: 10px; }
.mini-stat {
  display: inline-flex; align-items: baseline; gap: 7px;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: 999px; padding: 8px 16px; font-size: 0.85rem; color: var(--muted);
}
.mini-stat strong { font-family: var(--serif); font-size: 1rem; color: var(--pine-deep); }

.live-flag { font-size: 0.72rem; font-weight: 600; color: var(--pine-deep); background: var(--pine-soft); border-radius: 999px; padding: 3px 10px; }

/* --------------------------------------------------------- utilities  --- */
.stack { display: flex; flex-direction: column; gap: 14px; }
.inline { display: flex; gap: 12px; align-items: center; flex-wrap: wrap; }
.right { margin-left: auto; }
.hide { display: none !important; }
.page-head { padding: 46px 0 8px; }
.page-head .lede { color: var(--muted); font-size: 1.06rem; max-width: 46rem; }

/* ------------------------------------------------------------ accounts --- */
/* Sign-in / sign-up: one quiet card, Google first, email second. */
.auth-shell { max-width: 480px; margin: 0 auto; }
.auth-card { padding: 32px 34px; }
.auth-card h1 { font-size: 1.75rem; margin: 10px 0 6px; }
.auth-divider { display: flex; align-items: center; gap: 12px; margin: 20px 0 18px; color: var(--faint); font-size: 0.8rem; }
.auth-divider::before, .auth-divider::after { content: ""; flex: 1; height: 1px; background: var(--line); }
.btn--google { background: var(--surface); color: var(--ink); border-color: var(--line); font-weight: 600; }
.btn--google:hover { background: #f8f8f6; border-color: #d8d5cb; }
.g-logo { width: 18px; height: 18px; flex: none; }
.auth-error { color: var(--high); font-size: 0.85rem; background: #fdefec; border: 1px solid #f5d3cb; border-radius: var(--radius-sm); padding: 10px 14px; margin: 4px 0 14px; }
/* Reserves its own line so the change-password card does not jump the moment a
   refusal appears under it. */
.pw-msg { min-height: 1.1em; margin: 4px 0 10px; }
/* The sign-in page's email door. Google is the default, so the form behind
   this control is a disclosure: the control reads as a quiet line of text,
   not a second button competing with the one above it. */
.auth-toggle {
  display: block; width: 100%; margin: 12px 0 0; padding: 8px 0;
  background: none; border: 0; cursor: pointer; font: inherit;
  font-size: 0.875rem; color: var(--pine-deep); text-align: center;
  text-decoration: underline; text-underline-offset: 3px;
}
.auth-toggle:hover { color: var(--pine); }
.auth-toggle:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; border-radius: 6px; }
#email-form-wrap { margin-top: 14px; }
/* Google Identity Services renders its own iframe at a fixed width; centre it
   in the card rather than letting it sit left. */
#gsi-button { display: flex; justify-content: center; }
.auth-strip { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; background: var(--surface-2); border: 1px solid var(--line); border-radius: var(--radius); padding: 14px 18px; }

/* --------------------------------------------------------- admin console --- */
/* ------------------------------------------------------------ app shell --- */
/* The signed-in pages — my account, the counsellor console, the admin console
   — share one frame: a rail on the left carrying who you are and where you can
   go, and the working area beside it. The rail is the same object on all three
   so moving between them does not move the furniture, and a person who is both
   a member and a counsellor does not have to relearn the page.

   It is a rail and not a tab strip because the admin console now has nine
   destinations with counts on them. A strip of nine chips wraps onto two lines
   at this width and stops reading as navigation. */
.app { display: grid; grid-template-columns: 244px minmax(0, 1fr); gap: 26px; align-items: start; }

.app-side {
  position: sticky; top: 16px;
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 14px 12px; box-shadow: var(--shadow-sm);
}
.app-side__brand { display: flex; align-items: center; gap: 9px; padding: 2px 6px 12px; text-decoration: none; color: var(--ink); }
.app-side__brand span { font-weight: 600; font-size: 0.98rem; letter-spacing: -0.01em; }
.app-side__brand em { display: block; font-style: normal; font-weight: 400; font-size: 0.68rem; text-transform: uppercase; letter-spacing: 0.09em; color: var(--faint); }
.app-side__logo { width: 24px; height: 24px; flex: none; }
.app-side__me { display: flex; gap: 11px; align-items: center; padding: 12px 6px 13px; border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); }
.app-side__me .tiny { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 160px; }
.app-side__me strong { display: block; font-size: 0.92rem; line-height: 1.25; }
.app-side__me .avatar { flex: none; }

.app-nav { display: grid; gap: 2px; margin: 10px 0; }
.app-nav__group { font-size: 0.68rem; text-transform: uppercase; letter-spacing: 0.09em; color: var(--faint); padding: 13px 11px 5px; }
.app-nav__item {
  display: flex; align-items: center; gap: 10px; width: 100%; text-align: left;
  padding: 9px 11px; border: 0; border-left: 3px solid transparent; border-radius: 4px 10px 10px 4px;
  background: none; cursor: pointer; font: inherit; font-size: 0.9rem; color: var(--ink);
  transition: background .12s ease, border-color .12s ease;
}
.app-nav__item:hover { background: var(--surface-2); }
.app-nav__item.is-on { background: var(--pine-soft); color: var(--pine-deep); font-weight: 600; border-left-color: var(--pine); }
.app-nav__item .ico { width: 17px; height: 17px; flex: none; opacity: .85; }
.app-nav__n { margin-left: auto; font-size: 0.72rem; color: var(--faint); font-variant-numeric: tabular-nums; }
.app-nav__item.is-on .app-nav__n { color: var(--pine-deep); }
.app-nav__n--alert { background: var(--tag-warn-bg, #fdf3d8); color: #8a6414; border-radius: 999px; padding: 1px 7px; font-weight: 700; }
.app-side__foot { border-top: 1px solid var(--line); padding-top: 11px; display: grid; gap: 7px; }

.app-main { min-width: 0; }
.app-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 16px; flex-wrap: wrap; margin-bottom: 18px; }
.app-head h1 { font-size: 1.85rem; margin: 6px 0 2px; }

@media (max-width: 900px) {
  .app { grid-template-columns: 1fr; gap: 16px; }
  /* min-width: 0 on the rail is what makes the scrolling nav below work at all.
     A grid item's automatic minimum size is its min-content width, so without
     this the 1fr track grows to fit the whole nav strip — the strip never
     scrolls, the page does, and the account page is 1348px wide on a 390px
     phone. The overflow-x on .app-nav cannot help until something lets the
     column be narrower than its contents. */
  .app-side { position: static; min-width: 0; }
  .app-nav { grid-auto-flow: column; grid-auto-columns: max-content; overflow-x: auto; gap: 6px; padding-bottom: 4px; margin: 8px 0; }
  .app-nav__group { display: none; }
  .app-nav__item { white-space: nowrap; }
  /* Same trap on the footer: it becomes a row too, and it carries the sign-out
     and settings links. */
  .app-side__foot { grid-auto-flow: column; overflow-x: auto; }
}

/* ---- management tables -------------------------------------------------- --
   A list you can work rather than read: a filter bar, columns that line up
   down the page, a selectable row with its own actions, and a footer that says
   what is being shown of what. The console is a tool, and tools get used in
   bulk — one row at a time is a demo, not a management screen. */
.mg-bar { display: flex; gap: 9px; align-items: center; flex-wrap: wrap; margin-bottom: 16px; }
.mg-bar .a-search { flex: 1 1 260px; }
.mg-count { font-size: 0.78rem; color: var(--faint); font-variant-numeric: tabular-nums; }

.mg { border: 1px solid var(--line); border-radius: var(--radius); background: var(--surface); overflow: hidden; box-shadow: var(--shadow-sm); }
.mg__head, .mg__row { display: grid; align-items: center; gap: 12px; padding: 11px 16px; }
.mg__head {
  background: var(--surface-2); border-bottom: 1px solid var(--line);
  font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.06em; color: var(--faint); font-weight: 700;
}
.mg__row { border-bottom: 1px solid var(--line); cursor: pointer; transition: background .12s ease; }
.mg__row:last-child { border-bottom: 0; }
.mg__row:hover { background: #fbfdfb; }
.mg__row.is-sel { background: var(--pine-soft); }
.mg__row.is-off { opacity: .58; }
.mg__cell { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mg__who { display: flex; gap: 10px; align-items: center; min-width: 0; }
.mg__who strong { display: block; overflow: hidden; text-overflow: ellipsis; }
.mg__empty { padding: 30px 16px; text-align: center; color: var(--muted); font-size: 0.9rem; }
.mg__foot { display: flex; justify-content: space-between; align-items: center; gap: 12px; flex-wrap: wrap; padding: 12px 16px; border-top: 1px solid var(--line); background: var(--surface-2); font-size: 0.8rem; color: var(--muted); }

.mg__check { width: 16px; height: 16px; accent-color: var(--pine); cursor: pointer; margin: 0; }
.mg__acts { display: flex; gap: 4px; justify-content: flex-end; }
.mg__act {
  border: 1px solid transparent; background: none; cursor: pointer; border-radius: 8px;
  padding: 4px 8px; font: inherit; font-size: 0.76rem; color: var(--muted);
}
.mg__act:hover { background: var(--surface); border-color: var(--line); color: var(--ink); }
.mg__act--go:hover { color: var(--pine-deep); border-color: #cfe8da; background: #f2fbf6; }
.mg__act--stop:hover { color: #a03e30; border-color: #f6d0c7; background: #fdefec; }

/* The bulk bar replaces the filter bar's right side once rows are selected —
   an action that needs a selection must not be clickable without one, so it is
   not on screen without one. */
.mg-bulk {
  display: flex; gap: 10px; align-items: center; flex-wrap: wrap;
  background: var(--pine-soft); border: 1px solid #cfe8da; border-radius: var(--radius-sm);
  padding: 9px 14px; margin-bottom: 14px; font-size: 0.85rem; color: var(--pine-deep);
}
.mg-pager { display: flex; gap: 6px; align-items: center; }

/* ---- record sheet ------------------------------------------------------- --
   The detail panel for one account or one counsellor. Sub-tabs rather than one
   long scroll: "who they are", "what they have done here" and "what can be
   done to them" are three different jobs and get three panes. */
.sheet { border: 1px solid var(--line); border-radius: var(--radius); background: var(--surface); box-shadow: var(--shadow-md); overflow: hidden; }
.sheet__top { display: flex; gap: 14px; align-items: flex-start; padding: 18px 20px; border-bottom: 1px solid var(--line); background: linear-gradient(160deg, #f3faf6 0%, var(--surface) 70%); }
.sheet__top h3 { margin: 0 0 2px; }
.sheet__tabs { display: flex; gap: 4px; padding: 0 20px; border-bottom: 1px solid var(--line); background: var(--surface); flex-wrap: wrap; }
.sheet__tab {
  border: 0; border-bottom: 2px solid transparent; background: none; cursor: pointer;
  padding: 11px 12px; font: inherit; font-size: 0.86rem; color: var(--muted);
}
.sheet__tab:hover { color: var(--ink); }
.sheet__tab.is-on { color: var(--pine-deep); border-bottom-color: var(--pine); font-weight: 600; }
.sheet__body { padding: 20px; }
.sheet__kv { display: grid; grid-template-columns: 150px minmax(0, 1fr); gap: 9px 16px; font-size: 0.88rem; align-items: baseline; }
.sheet__kv dt { color: var(--faint); font-size: 0.8rem; }
.sheet__kv dd { margin: 0; word-break: break-word; }
.sheet__grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); gap: 14px; }

.admin-tabs { display: flex; gap: 8px; flex-wrap: wrap; margin: 20px 0 22px; }
.drawer { background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); padding: 22px 24px; box-shadow: var(--shadow-sm); }
.a-input {
  width: 100%; border: 1px solid var(--line); border-radius: var(--radius-sm);
  padding: 9px 12px; font-family: var(--sans); font-size: 0.9rem; background: var(--surface); color: var(--ink);
}
.a-input:focus { outline: none; border-color: var(--pine); box-shadow: 0 0 0 3px rgba(31, 157, 99, .15); }
textarea.a-input { resize: vertical; }
.a-search {
  flex: 1; min-width: 220px; border: 1px solid var(--line); border-radius: 999px;
  padding: 10px 16px; font-family: var(--sans); font-size: 0.9rem; background: var(--surface); color: var(--ink);
}
.a-search:focus { outline: none; border-color: var(--pine); box-shadow: 0 0 0 3px rgba(31, 157, 99, .15); }
.row[data-user], .row[data-case], .row[data-counsellor] { border-left: 3px solid transparent; }
.row[data-user]:hover, .row[data-case]:hover, .row[data-counsellor]:hover { border-left-color: var(--pine); background: #fbfdfb; }

@media (prefers-reduced-motion: reduce) {
  /* The mark and its halo were missing from this list, which made the one
     animation the product leads with — the mark beating on the landing page and
     on the chat rail — the one piece of motion that ignored the setting. With
     the animation off the halo rests at its own inset rather than mid-pulse, so
     it reads as a still ring around the mark instead of a shrunken one.

     `.mark__green`, not `.bot__mark`: the beat is on the green circle now, and
     a list naming the svg would leave the part that actually moves running. */
  .bubble, .bar-fill, .mark__green, .bot__halo { animation: none !important; transform: none !important; }
  html { scroll-behavior: auto; }
}
