:root{
  --paper:#EEF2EF; --surface:#FFFFFF; --ink:#1C2A2B; --soft:#56666A;
  --moss:#2F5D50; --moss-2:#DCE8E2; --dusk:#4E5292; --dusk-2:#E3E4F3;
  --glow:#F2C38B; --glow-2:#FBEBD6; --alert:#A3362B; --alert-2:#F8E1DD;
  --line:#CFDAD5;
  --serif:"Newsreader", Georgia, "Times New Roman", serif;
  --sans:"Hanken Grotesk", system-ui, -apple-system, "Segoe UI", sans-serif;
  color-scheme: light;
}
@media (prefers-color-scheme: dark){
  :root{
    --paper:#131C1D; --surface:#1B2728; --ink:#E6EEEB; --soft:#9EB0AD;
    --moss:#7FB9A6; --moss-2:#223A35; --dusk:#A4A8E6; --dusk-2:#262A48;
    --glow:#F2C38B; --glow-2:#3A2E20; --alert:#F08C80; --alert-2:#3D2220;
    --line:#2D3C3D; color-scheme: dark;
  }
}
*{box-sizing:border-box}
html,body{margin:0}
/* The page does not scroll. Only the middle does.
 *
 * A sticky header and a fixed tab bar look right until iOS rubber-bands the
 * document, and then it drags both of them — the header dips, the bar lifts.
 * No amount of overscroll-behavior fixes that, because the thing being dragged
 * IS the document.
 *
 * So the document is pinned to the viewport and the app becomes three rows:
 * header, a scrolling middle, tab bar. The bars are not inside the scrolling
 * element, so scrolling cannot move them. This is how a native app is built. */
/* The canvas behind the app is the page's own colour.
 *
 * If anything ever leaves a strip at the bottom — a native wrapper that sizes
 * the web view short, a keyboard resize that doesn't fully restore — that strip
 * should simply continue the page. Build 15 painted it white to blend into a
 * full-width tab bar; the bar floats now and no longer touches the bottom, so
 * the page colour is the one that disappears. */
html{height:100%;background:var(--paper)}
body{background:var(--paper);color:var(--ink);font:15px/1.5 var(--sans);-webkit-font-smoothing:antialiased;height:100%;overflow:hidden;overscroll-behavior:none;display:flex;flex-direction:column}
h1,h2,h3{font-family:var(--serif);font-weight:500;line-height:1.25;margin:0 0 .4rem}
h1{font-size:1.5rem;letter-spacing:-.012em}
h2{font-size:1.12rem}
h3{font-size:1rem}
p{margin:0 0 .7rem;max-width:62ch}
a{color:var(--moss)}
button,input,textarea,select{font:inherit;color:inherit}
/* The focus ring was 3px of the orange accent, which read as a warning. It
   stays — a keyboard user has no other way to see where they are — but in the
   app's own green, thinner, and never on `main`.

   `main` is the thing that was drawing a full-width yellow line across the
   screen: it carries tabindex="-1" and is focused on every navigation so the
   screen reader announces the new page. That focus should be silent. */
:focus-visible{outline:2px solid color-mix(in srgb,var(--moss) 60%,transparent);outline-offset:2px;border-radius:8px}
main:focus,main:focus-visible{outline:none}
.composer textarea:focus,.composer textarea:focus-visible{outline:none;border-color:var(--moss)}
.search input:focus,.search input:focus-visible{outline:none}
.skip{position:absolute;left:-999px}
.skip:focus{left:12px;top:12px;background:var(--surface);padding:8px 12px;z-index:50}

/* Three columns, not space-between: the outer two share the leftover width
   equally, so the middle one lands on the centre of the screen and stays there
   whatever the sides contain. No rule under it — the bar is the same colour as
   the page, so it simply stops being a thing you notice. Opaque rather than
   blurred, because a translucent bar with no border shows scrolled text
   ghosting through it. */
.topbar{position:static;flex:0 0 auto;z-index:20;display:grid;grid-template-columns:1fr auto 1fr;align-items:center;gap:12px;padding:9px 16px;padding-top:max(9px,env(safe-area-inset-top));background:var(--paper)}
.top-left{justify-self:start;display:flex;align-items:center}
.top-right{justify-self:end;display:flex;align-items:center}
.brand{justify-self:center;display:flex;align-items:center;text-decoration:none;color:var(--ink)}
/* Present, never shouting. A solid red block on every screen of an anxiety app
   is its own small stressor; this reads as calm and still lands where the eye
   goes first: the top-left corner. */
.sos-btn{background:var(--alert-2);color:var(--alert);border:1px solid color-mix(in srgb,var(--alert) 18%,transparent);text-decoration:none;font-weight:600;font-size:.76rem;padding:5px 11px;border-radius:999px;white-space:nowrap}
.icon-btn{display:grid;place-items:center;width:32px;height:32px;border-radius:999px;color:var(--soft);text-decoration:none;flex:0 0 auto}
.icon-btn svg{width:19px;height:19px;fill:none;stroke:currentColor;stroke-width:1.7;stroke-linecap:round;stroke-linejoin:round}
.icon-btn[aria-current="page"]{background:var(--moss-2);color:var(--moss)}

/* min-height:0 is the one everyone forgets: without it a flex child refuses to
   shrink below its content and the scroll falls back to the document. */
main{flex:1 1 auto;min-height:0;overflow-y:auto;overscroll-behavior:contain;-webkit-overflow-scrolling:touch;outline:none;padding:18px 16px 28px}
main>*{max-width:680px;margin-left:auto;margin-right:auto}
/* A floating bar, the way Instagram does it.
 *
 * Three things make that look what it is, and all three matter:
 *  1. A true pill — radius half the height, not a rounded rectangle.
 *  2. Glass — translucent, with the page blurred behind it. Which only works
 *     if there IS something behind it, so the bar hangs in a zero-height slot
 *     and the scrolling middle runs underneath.
 *  3. Icons alone. The words are still in the DOM for screen readers.
 *
 * --bar is the single source of truth for its height: the middle's bottom
 * padding, the composer's clearance and the add button's offset are all
 * derived from it, and a test asserts the rendered height still matches. Get
 * that wrong and the bar quietly covers the last line of every screen. */
:root{--bar:48px;--bar-gap:12px}
.bar-slot{position:relative;height:0;flex:0 0 auto;z-index:20}
.tabbar{position:absolute;left:12px;right:12px;bottom:calc(var(--bar-gap) + env(safe-area-inset-bottom));
  height:var(--bar);display:grid;grid-template-columns:repeat(5,1fr);align-items:center;
  border:0;border-radius:999px;
  background:color-mix(in srgb,var(--surface) 72%,transparent);
  backdrop-filter:blur(22px) saturate(1.7);-webkit-backdrop-filter:blur(22px) saturate(1.7);
  box-shadow:0 6px 24px color-mix(in srgb,var(--ink) 14%,transparent)}
/* Safari and iOS do support backdrop-filter, but if it is ever unavailable a
   72%-opaque bar over scrolling text is unreadable. Go solid instead. */
@supports not ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px))){
  .tabbar{background:var(--surface)}
}
.tabbar a{display:grid;place-items:center;height:100%;text-decoration:none;color:var(--soft)}
.tabbar svg{width:23px;height:23px;fill:none;stroke:currentColor;stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round}
.tabbar a[aria-current="page"]{color:var(--ink)}
.tabbar a[aria-current="page"] svg{stroke-width:2.4}
/* Room to scroll the last line clear of the bar it now passes under. */
main{padding-bottom:calc(var(--bar) + var(--bar-gap) + 16px + env(safe-area-inset-bottom))}
/* The composer gets the same clearance, in the block where it is defined —
   putting it here would lose to that shorthand. */

.lede{color:var(--soft);font-size:.95rem}
.block{background:var(--surface);border:1px solid color-mix(in srgb,var(--line) 55%,transparent);border-radius:14px;padding:14px 15px;margin:0 0 11px}
.block.flat{background:transparent;border-style:dashed}
.row{display:flex;gap:10px;align-items:center;flex-wrap:wrap}
.spread{display:flex;justify-content:space-between;align-items:center;gap:10px}
.muted{color:var(--soft);font-size:.88rem}
.small{font-size:.8rem}
.stack>*+*{margin-top:10px}

.btn{display:inline-flex;align-items:center;justify-content:center;gap:6px;border:0;border-radius:11px;padding:9px 15px;font-weight:600;font-size:.92rem;cursor:pointer;text-decoration:none;background:var(--moss);color:#fff;min-height:44px}
@media (prefers-color-scheme: dark){.btn{color:#0F1A17}}
.btn.ghost{background:transparent;color:var(--moss);border:1.5px solid var(--moss)}
.btn.quiet{background:var(--moss-2);color:var(--ink)}
.btn.dusk{background:var(--dusk)}
.btn.danger{background:var(--alert)}
.btn.wide{width:100%}
.btn:disabled{opacity:.45;cursor:not-allowed}

label{display:block;font-weight:600;margin:14px 0 6px}
input[type=text],input[type=number],textarea,select{width:100%;padding:11px 12px;border:1.5px solid var(--line);border-radius:10px;background:var(--paper)}
textarea{min-height:84px;resize:vertical}
input[type=range]{width:100%;accent-color:var(--moss)}
.rangeval{font-variant-numeric:tabular-nums;font-weight:700}

/* program chooser: three distinct paths */
.paths{display:grid;gap:12px}
.path{display:block;text-decoration:none;color:var(--ink);border-radius:18px;padding:18px 18px 16px;border-left:6px solid var(--c)}
.path.mood{--c:var(--glow);background:var(--glow-2)}
.path.worry{--c:var(--moss);background:var(--moss-2)}
.path.ocd{--c:var(--dusk);background:var(--dusk-2)}
.path h3{margin-bottom:4px}
.path p{margin:0;color:var(--soft);font-size:.95rem}

/* ---- the course ---- */
.course-bar{height:8px;border-radius:999px;background:color-mix(in srgb,var(--line) 60%,transparent);overflow:hidden}
.course-bar i{display:block;height:100%;border-radius:999px;background:var(--moss);transition:width .35s ease}
.weeks{display:grid;gap:10px;margin-top:16px}
.week{display:block;text-decoration:none;color:var(--ink);background:var(--surface);border:1px solid color-mix(in srgb,var(--line) 55%,transparent);
  border-radius:16px;padding:14px 16px}
.week h3{margin:0;font-size:1rem}
.week p{margin:6px 0 0}
/* Finished weeks keep their colour. Greying out completed work reads as
   "spent" rather than "done", and the point of a course is that the part
   behind you is the part you earned. */
.week.done{border-color:color-mix(in srgb,var(--moss) 40%,transparent);background:var(--moss-2)}
.week.locked{opacity:.72}
.week.locked h3::after{content:" 🔒";font-size:.8em}
/* A completed step stays fully readable — someone re-reading week two in week
   five is the behaviour this course wants, not an edge case. */
.step.done{border-color:color-mix(in srgb,var(--moss) 40%,transparent)}

/* The week is a list of titles until someone opens one. */
.step{padding:0}
.step>summary{display:flex;align-items:center;gap:11px;padding:14px 15px;cursor:pointer;list-style:none}
/* Safari draws its own triangle via ::-webkit-details-marker and ignores
   list-style on its own, so both rules are needed. */
.step>summary::-webkit-details-marker{display:none}
.step-n{flex:0 0 auto;display:grid;place-items:center;width:24px;height:24px;border-radius:999px;
  background:var(--moss-2);color:var(--moss);font-size:.8rem;font-weight:700}
.step.done .step-n{background:var(--moss);color:var(--surface)}
.step-t{flex:1 1 auto;font-family:var(--serif);font-size:1.05rem;line-height:1.3}
/* A chevron that turns, so a closed row reads as openable rather than as a
   heading someone is expected to stare at. */
.step>summary::after{content:"";flex:0 0 auto;width:8px;height:8px;margin-left:2px;
  border-right:2px solid var(--soft);border-bottom:2px solid var(--soft);
  transform:rotate(45deg) translate(-2px,-2px);transition:transform .18s ease}
.step[open]>summary::after{transform:rotate(-135deg) translate(-2px,-2px)}
.step[open]>summary{padding-bottom:4px}
/* The body is indented to match the title, so an open step still reads as one
   item in a list rather than as the page starting again. */
.step>:not(summary){margin-left:15px;margin-right:15px}
.step>:last-child{margin-bottom:15px}

/* check-in choices */
.opts{display:grid;gap:8px;margin-top:8px}
.opt{display:flex;gap:10px;align-items:center;padding:10px 12px;border:1.5px solid var(--line);border-radius:10px;cursor:pointer}
.opt:has(input:checked){border-color:var(--moss);background:var(--moss-2)}
.opt input{accent-color:var(--moss);width:18px;height:18px}
.q{padding:14px 0;border-bottom:1px solid var(--line)}
.q:last-child{border-bottom:0}
.q p{margin:0;font-weight:500}

.mood-scale{display:grid;grid-template-columns:repeat(5,1fr);gap:6px}
.mood-scale button{border:1px solid color-mix(in srgb,var(--line) 70%,transparent);background:var(--paper);border-radius:12px;padding:10px 0;cursor:pointer;font-size:.8rem;line-height:1.2}
.mood-scale button b{display:block;font-size:1.05rem;font-family:var(--serif);font-weight:500}
.mood-scale button[aria-pressed="true"]{border-color:var(--moss);background:var(--moss-2)}

/* The fear ladder — the app's signature visual */
.ladder{position:relative;margin:18px 0 8px;padding-left:28px}
.ladder::before,.ladder::after{content:"";position:absolute;top:0;bottom:0;width:4px;border-radius:2px;background:var(--dusk);opacity:.35}
.ladder::before{left:6px}.ladder::after{right:6px}
.rung{position:relative;display:grid;grid-template-columns:1fr auto;gap:8px;align-items:center;margin:0 22px 10px 0;padding:12px 14px;background:var(--surface);border:1.5px solid var(--line);border-radius:12px}
.rung::before{content:"";position:absolute;left:-26px;right:-26px;top:50%;height:3px;background:var(--dusk);opacity:.35;z-index:-1}
.rung.done{border-color:var(--dusk);background:var(--dusk-2)}
.suds{font-variant-numeric:tabular-nums;font-weight:700;color:var(--dusk);min-width:3ch;text-align:right}
.rung .meta{font-size:.82rem;color:var(--soft)}

/* exposure timer */
.timer{font-family:var(--serif);font-size:2.8rem;text-align:center;font-variant-numeric:tabular-nums;margin:6px 0}
.curve{width:100%;height:140px;display:block}

/* breathing orb — SOS */
.orb-wrap{display:grid;place-items:center;height:260px;margin:8px 0}
.orb{width:120px;height:120px;border-radius:50%;background:radial-gradient(circle at 40% 35%,#FBE3C3,var(--glow) 60%,#E7A866);box-shadow:0 0 0 18px color-mix(in srgb,var(--glow) 22%,transparent);transition:transform 4s ease-in-out}
.orb.in{transform:scale(1.8)}
.orb.hold{transform:scale(1.8)}
.orb.out{transform:scale(1);transition-duration:6s}
.orb-label{font-family:var(--serif);font-size:1.15rem;text-align:center;min-height:2rem}
@media (prefers-reduced-motion: reduce){.orb,.orb.out{transition:none}}

.crisis{background:var(--alert-2);border:1.5px solid var(--alert);border-radius:18px;padding:18px;margin:0 0 16px}
.crisis h2,.crisis h3{color:var(--alert)}
.lines{list-style:none;padding:0;margin:10px 0 0;display:grid;gap:8px}
.lines a{display:flex;justify-content:space-between;gap:10px;padding:12px 14px;border-radius:12px;background:var(--surface);text-decoration:none;color:var(--ink);font-weight:600}
.lines a span{color:var(--alert);font-variant-numeric:tabular-nums;white-space:nowrap}

/* coach */
.chat{display:flex;flex-direction:column;gap:10px;margin-bottom:12px}
.msg{max-width:86%;padding:11px 14px;border-radius:16px;white-space:pre-wrap}
.msg.me{align-self:flex-end;background:var(--moss);color:#fff;border-bottom-right-radius:4px}
@media (prefers-color-scheme: dark){.msg.me{color:#0F1A17}}
.msg.bot{align-self:flex-start;background:var(--surface);border:1px solid var(--line);border-bottom-left-radius:4px}
/* Paragraphs inside a bubble. pre-wrap stays on .msg for the single-paragraph
   case; when there are several, real <p> elements set the spacing so it does
   not depend on how many newlines the model happened to send. */
.msg p{margin:0}
.msg p+p{margin-top:.72em}
.msg.flag{border-color:var(--dusk);background:var(--dusk-2)}
.composer{display:flex;gap:8px;align-items:flex-end}
.composer textarea{min-height:44px;height:44px;max-height:140px;resize:none;border-radius:22px;padding:10px 16px;background:var(--surface);line-height:1.4;border:1px solid color-mix(in srgb,var(--line) 70%,transparent)}
.composer .btn{border-radius:22px}
/* A row of the page column, not an overlay. */
/* A flow row, so it would sit under the floating bar without this clearance.
   While typing the bar is gone and the composer takes the space back — see
   body.typing below. */
.dock{flex:0 0 auto;z-index:15;background:var(--paper);border-top:1px solid color-mix(in srgb,var(--line) 55%,transparent);
  padding:8px 18px calc(var(--bar) + var(--bar-gap) + 6px + env(safe-area-inset-bottom))}
.dock[hidden]{display:none}
.dock-in{max-width:680px;margin:0 auto}
.dock .chips{margin:0 0 8px;flex-wrap:nowrap;overflow-x:auto;scrollbar-width:none;-webkit-overflow-scrolling:touch}
.dock .chips::-webkit-scrollbar{display:none}
.dock .chips:empty{display:none}
.dock .chip{white-space:nowrap;flex-shrink:0}
body.typing{padding-bottom:0}
body.typing .tabbar{display:none}
body.typing .dock{padding-bottom:max(10px,env(safe-area-inset-bottom))}
.chips{display:flex;gap:6px;flex-wrap:wrap;margin:6px 0 12px}
.chip{border:1px solid color-mix(in srgb,var(--line) 70%,transparent);background:var(--surface);border-radius:999px;padding:6px 12px;font-size:.8rem;cursor:pointer}

/* progress */
.chart{width:100%;height:170px;display:block}
.stat{display:flex;flex-direction:column}
.stat b{font-family:var(--serif);font-size:1.5rem;font-weight:500;line-height:1}
.stats{display:grid;grid-template-columns:repeat(3,1fr);gap:10px}
.band{display:inline-block;padding:2px 10px;border-radius:999px;background:var(--moss-2);font-size:.85rem;font-weight:600}

.list{list-style:none;padding:0;margin:0}
.list li{padding:10px 0;border-bottom:1px solid var(--line)}
.list li:last-child{border-bottom:0}

#toast{position:fixed;left:50%;bottom:100px;transform:translateX(-50%) translateY(20px);background:var(--ink);color:var(--paper);padding:10px 16px;border-radius:10px;opacity:0;pointer-events:none;transition:.25s;z-index:40}
#toast.show{opacity:1;transform:translateX(-50%)}

.disclaimer{font-size:.78rem;color:var(--soft);border-top:1px solid var(--line);padding-top:14px;margin-top:24px}

@media print{
  .topbar,.tabbar,.noprint{display:none!important}
  body{background:#fff;color:#000;padding:0}
  .block{border-color:#bbb}
}
.chip[aria-pressed="true"]{background:var(--moss-2);border-color:var(--moss)}

/* calming sounds */
.sounds{display:grid;grid-template-columns:repeat(2,1fr);gap:8px}
.sound{display:flex;align-items:center;gap:10px;padding:12px;border:1.5px solid var(--line);border-radius:12px;background:var(--paper);cursor:pointer;font-weight:600;text-align:left}
.sound[aria-pressed="true"]{border-color:var(--moss);background:var(--moss-2)}
.wave{display:inline-flex;align-items:flex-end;gap:2px;height:16px;width:16px}
.wave i{display:block;width:3px;height:5px;border-radius:2px;background:var(--moss);opacity:.5}
.sound[aria-pressed="true"] .wave i{opacity:1;animation:bar 1.2s ease-in-out infinite}
.sound[aria-pressed="true"] .wave i:nth-child(2){animation-delay:.2s}
.sound[aria-pressed="true"] .wave i:nth-child(3){animation-delay:.4s}
@keyframes bar{0%,100%{height:4px}50%{height:15px}}
@media (prefers-reduced-motion: reduce){.sound .wave i{animation:none!important}}
.guide-line{margin:12px 0 0;padding:12px 13px;border-radius:11px;background:var(--glow-2);font-family:var(--serif);font-size:1rem;line-height:1.45}

/* header: find a therapist */
.top-actions{display:flex;flex-direction:row;align-items:center;gap:8px}
.find-btn{border:1.5px solid var(--moss);color:var(--moss);background:var(--surface);text-decoration:none;font-weight:600;font-size:.85rem;padding:6px 14px;border-radius:999px}
.find-btn[aria-current="page"]{background:var(--moss);color:#fff}
@media (prefers-color-scheme: dark){.find-btn[aria-current="page"]{color:#0F1A17}}
.dirs{display:grid;gap:10px}
.dir{display:block;text-decoration:none;color:var(--ink);padding:14px 16px;border:1.5px solid var(--line);border-radius:14px;background:var(--surface)}
.dir b{display:block;color:var(--moss)}
.dir span{color:var(--soft);font-size:.9rem}
.summary-box{white-space:pre-wrap;background:var(--paper);border:1.5px dashed var(--line);border-radius:12px;padding:14px;font-size:.95rem}

/* Science check: the one-line conclusion, set apart from the explanation. */
.takeaway { margin-top: 14px; padding: 12px 14px; border-left: 3px solid var(--moss); background: rgba(47,93,80,.06); border-radius: 0 10px 10px 0; }

/* Account */
.field{display:block;margin:0 0 12px}
.field span{display:block;font-size:.88rem;font-weight:600;margin:0 0 5px}
.field input{width:100%;box-sizing:border-box;font:inherit;font-size:16px;padding:11px 13px;border:1px solid var(--line);border-radius:12px;background:var(--surface);color:inherit}
.field input:focus{outline:2px solid var(--moss);outline-offset:1px}
.note{margin-top:10px;padding:10px 12px;border-radius:12px;font-size:.9rem}
.note.bad{background:rgba(155,58,50,.09);color:var(--alarm,#9B3A32)}
.note.good{background:rgba(47,93,80,.09);color:var(--moss)}

/* The limit heads-up. Deliberately the quietest thing on the screen. */
.msg.quiet{opacity:.75;font-size:.9rem;border:1px dashed var(--line);background:transparent}

/* The mark. Two files rather than one recoloured in CSS, because it is a
   raster of the original artwork — the shape is hers, not a redrawing of it.
   Sized to the cap height of the wordmark so the two read as one lockup. */
.brand .mark{width:27px;height:auto;display:block;flex:0 0 auto}
.brand .mark.dark{display:none}
@media (prefers-color-scheme: dark){
  .brand .mark.light{display:none}
  .brand .mark.dark{display:block}
}

/* Navigation links inside a card: no underline, a little weight instead.
   Prose links elsewhere keep theirs — those genuinely need to look like links. */
.nav-list a{display:block;padding:7px 0;text-decoration:none;font-weight:500;color:var(--ink)}
.nav-list a:hover{color:var(--moss)}
.nav-list a+a{border-top:1px solid color-mix(in srgb,var(--line) 45%,transparent)}

/* Search */
.search{display:flex;align-items:center;gap:8px;background:var(--surface);border:1px solid color-mix(in srgb,var(--line) 55%,transparent);border-radius:11px;padding:0 12px;margin:0 0 12px}
.search svg{width:17px;height:17px;flex:0 0 auto;fill:none;stroke:var(--soft);stroke-width:1.9;stroke-linecap:round}
/* font-family and weight set outright: a search input takes its own bold
   default from the browser otherwise, which is why the placeholder was
   shouting. 16px because anything smaller makes iOS zoom the page on focus. */
.search input{flex:1;border:0;background:transparent;outline:none;font-family:var(--sans);font-weight:400;font-size:16px;line-height:1.4;padding:11px 0;min-height:44px;color:var(--ink);-webkit-appearance:none;appearance:none}
.search input::placeholder{color:var(--soft);font-weight:400;opacity:1}
.search input::-webkit-search-cancel-button{-webkit-appearance:none}
.search:focus-within{border-color:var(--moss)}
.sr-only{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}

/* iOS zooms the page whenever a focused field is under 16px, and the app's base
   size is 15 — which is how the zoom got introduced in the first place.
   Unconditional rather than behind an @supports touch check: that check cannot
   be exercised in a desktop browser, so it would be a rule nobody could test.
   16px in a form field is unremarkable everywhere else anyway. */
input,textarea,select{font-size:16px}

/* The app is sized to the VISIBLE viewport, not the layout one, so the keyboard
   opening shrinks the app instead of hiding the bottom of it behind the keys.
   The transform also makes body the containing block for the composer, which is
   why that no longer needs any arithmetic to find the bottom of the screen. */
/* Height only. An earlier version also translated the body by
   visualViewport.offsetTop to keep it inside the visible region — but that
   offset is non-zero in ordinary situations (an in-progress phone call raises
   it), and the result was the whole app sitting a hundred-odd pixels down the
   screen. Sizing to the visible height is the part that was actually needed. */
body{height:var(--vvh,100%)}

/* Membership card */
.plan{background:var(--surface);border:1px solid color-mix(in srgb,var(--moss) 22%,transparent);border-radius:18px;padding:20px 18px;margin:0 0 14px;box-shadow:0 1px 2px rgba(28,42,43,.04)}
.plan-on{border-color:color-mix(in srgb,var(--moss) 45%,transparent);background:linear-gradient(180deg,var(--moss-2),var(--surface) 60%)}
.plan-tag{margin:0;font-size:.7rem;font-weight:700;letter-spacing:.09em;text-transform:uppercase;color:var(--moss)}
.plan-name{margin:6px 0 0;font-size:1.3rem}
.plan-price{margin:12px 0 0;font-family:var(--serif);font-size:2.1rem;line-height:1;color:var(--ink)}
.plan-price span{font-family:var(--sans);font-size:.85rem;color:var(--soft);font-weight:500}
/* Holds the line's height while the App Store is answering, so the card does
   not jump when the real figure lands. */
.plan-price:empty::before{content:"";display:inline-block;width:5.2ch;height:1em;border-radius:6px;background:color-mix(in srgb,var(--line) 45%,transparent)}
.price-none{font-family:var(--sans);font-size:.95rem;color:var(--soft);font-weight:500}
.plan-list{list-style:none;margin:18px 0 0;padding:0}
.plan-list li{position:relative;padding:0 0 0 26px;margin:0 0 9px;color:var(--ink);font-size:.94rem}
.plan-list li::before{content:"";position:absolute;left:4px;top:.42em;width:9px;height:5px;border-left:2px solid var(--moss);border-bottom:2px solid var(--moss);transform:rotate(-45deg)}

/* ---------- today's list, and the button that fills it ---------- */

/* The slot has no height of its own, so the button hangs off the top edge of
   whatever row follows it — the tab bar, or the composer. Nothing measures
   anything, which is the only way this survives the keyboard. */
.fab-slot{position:relative;height:0;flex:0 0 auto;z-index:25}
.fab{position:absolute;right:16px;bottom:calc(var(--bar) + var(--bar-gap) + 12px + env(safe-area-inset-bottom));display:inline-flex;align-items:center;gap:7px;
  border:0;border-radius:999px;padding:11px 16px;font-weight:600;font-size:.86rem;cursor:pointer;
  background:var(--moss);color:#fff;box-shadow:0 8px 22px color-mix(in srgb,var(--ink) 22%,transparent)}
@media (prefers-color-scheme: dark){.fab{color:#0F1A17}}
.fab svg{width:16px;height:16px;fill:none;stroke:currentColor;stroke-width:2.2;stroke-linecap:round}
.fab[hidden]{display:none}
/* Room to scroll the last card clear of the button, only on the screen that
   has one. A floating button that permanently covers the final line of the
   page is a floating button that ate the page. */
body.has-fab main{padding-bottom:calc(var(--bar) + var(--bar-gap) + 74px + env(safe-area-inset-bottom))}

/* Signed out, or still deciding.
 *
 * The tab bar is hidden rather than disabled: five tabs that all lead back to
 * the same sign-in form is a worse experience than not drawing them, and it is
 * also the honest picture — there is nothing behind them yet. The composer and
 * the task button go for the same reason.
 *
 * The "Need help" button in the header is deliberately NOT hidden. It is the
 * one thing that has to survive every state this app can be in. */
body.gated .bar-slot,
body.gated .fab-slot,
body.gated .dock{display:none}
body.gated main{padding-bottom:28px}

.tasks{list-style:none;margin:6px 0 0;padding:0}
.tasks li{display:flex;gap:11px;align-items:flex-start;padding:9px 0;border-top:1px solid color-mix(in srgb,var(--line) 45%,transparent)}
.tasks li:first-child{border-top:0}
.tasks li>div{flex:1 1 auto;min-width:0}
.tasks .meta{font-size:.8rem;color:var(--soft);margin-top:2px}
.tasks .is-done,.tasks li.is-done>div>div{color:var(--soft)}
.tasks li.is-done>div>div:first-child{text-decoration:line-through}
.tick{flex:0 0 auto;width:22px;height:22px;margin-top:1px;border-radius:999px;cursor:pointer;
  border:1.8px solid color-mix(in srgb,var(--moss) 45%,transparent);background:transparent}
.tick.on{background:var(--moss);border-color:var(--moss);
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='3.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 12.5 9.5 18 20 6.5'/%3E%3C/svg%3E");
  background-size:14px;background-position:center;background-repeat:no-repeat}
.x{flex:0 0 auto;border:0;background:transparent;color:var(--soft);font-size:1.2rem;line-height:1;cursor:pointer;padding:0 2px}

/* ---------- the suggestion sheet ---------- */
.sheet{position:fixed;inset:0;z-index:60;display:flex;flex-direction:column;justify-content:flex-end;
  background:color-mix(in srgb,var(--ink) 40%,transparent)}
.sheet-in{background:var(--surface);border-radius:22px 22px 0 0;padding:16px 16px calc(18px + env(safe-area-inset-bottom));
  max-height:82%;overflow-y:auto;overscroll-behavior:contain}
.sheet-in h2{margin:0}
.sug{border:1px solid color-mix(in srgb,var(--line) 55%,transparent);border-radius:14px;padding:13px 14px;margin:11px 0 0}
.sug-text{margin:0 0 5px;font-weight:600}
.sug .btn{min-height:40px;padding:7px 13px;font-size:.86rem}

/* The confirmation on the therapist form. Green enough to read as "done",
   quiet enough not to look like a celebration — someone on this screen is
   looking for a therapist, not collecting a badge. */
.block.sent{background:var(--moss-2);border-color:color-mix(in srgb,var(--moss) 28%,transparent)}
.block.sent h2{margin-bottom:6px}

/* The science groups are labels, not prose headings — they name a shelf. Bold
   sans reads as a label; the serif at weight 500 read as more body text, which
   is why the sections ran together. */
.sci-h{font-family:var(--sans);font-weight:700;font-size:.98rem;letter-spacing:.005em;margin-bottom:2px}

/* The reminder time sits beside its button rather than under a label of its
   own — one row, because the whole setting is one decision. */
.rem-time{display:flex;align-items:center;gap:7px;margin:0}
.rem-time input{padding:8px 10px;border:1px solid color-mix(in srgb,var(--line) 70%,transparent);border-radius:10px;background:var(--surface);min-height:44px}

/* While the keyboard is up the app is already sized to sit above it, so the
   home-indicator inset underneath is space nobody can see. */
body.kb .dock{padding-bottom:10px}

/* A personalised line, visibly theirs rather than more of the course talking.
   Tinted rather than boxed — a hard border would make their own words look
   like a callout bolted on, which is the opposite of the intended effect. */
.yours{margin:12px 0 0;padding:10px 12px;border-left:3px solid var(--moss);
  background:color-mix(in srgb,var(--moss-2) 70%,transparent);border-radius:0 10px 10px 0}
.yours p{margin:0}

/* ---- Your Four Weeks ---- */
.plan-how{margin:0;padding-left:20px}
.plan-how li{margin:0 0 8px}
.plan-how li::marker{color:var(--moss);font-weight:700}
.task-head{display:flex;align-items:center;gap:10px;margin-bottom:6px}
/* Difficulty as dots rather than a number. "Level 4" invites someone to feel
   they are behind; four dots is just how far up the ladder this rung is. */
.lv{letter-spacing:2px;font-size:.7rem;color:var(--moss)}
.task-text{font-family:var(--serif);font-size:1.08rem;line-height:1.35;margin:0 0 6px}
/* A checked task keeps its colour and its text. Fading it out would say the
   work is spent; it is the opposite — it is the evidence. */
.task.checked{border-color:color-mix(in srgb,var(--moss) 45%,transparent)}
.task.checked.skipped{border-color:color-mix(in srgb,var(--line) 80%,transparent)}
.task.done{background:color-mix(in srgb,var(--moss-2) 45%,var(--surface))}
.note-wrap{display:block;margin-top:10px}
.note{width:100%;box-sizing:border-box;font:inherit;font-size:16px;line-height:1.45;resize:none;overflow:hidden;
  padding:9px 11px;border:1px solid color-mix(in srgb,var(--line) 70%,transparent);border-radius:10px;
  background:color-mix(in srgb,var(--paper) 55%,var(--surface));color:inherit}
.note:focus{outline:none;border-color:var(--moss);background:var(--surface)}
.note::placeholder{color:var(--soft)}

/* Web-only download strip above the header. A row of the column, so the
   no-scroll layout is untouched; hidden in the native app and in print. */
.get-app{display:flex;align-items:center;gap:12px;flex:0 0 auto;padding:10px 16px;padding-top:max(10px,env(safe-area-inset-top));
  background:var(--moss);color:#fff;text-decoration:none;font-size:.95rem;line-height:1.2}
.get-app img{width:28px;height:28px;border-radius:7px;flex:0 0 auto}
.get-app-text{flex:1;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.get-app-btn{background:#fff;color:var(--moss);font-weight:700;padding:7px 14px;border-radius:999px;flex:0 0 auto}
.get-app + .topbar{padding-top:9px}
body.native .get-app{display:none}
body.native .get-app + .topbar{padding-top:max(9px,env(safe-area-inset-top))}
