/* Astonik website. Colours and type are the app's own (docs/design/DESIGN-SYSTEM.md):
   night = Galactic Core, day = Ivory Court, the waitlist = Morning Clouds.
   Gold means "now" — the one primary action in view. */

@font-face { font-family: 'Fraunces'; src: url('/fonts/Fraunces-SemiBold.ttf') format('truetype'); font-weight: 600; font-display: swap; }
@font-face { font-family: 'Manrope'; src: url('/fonts/Manrope-Regular.ttf') format('truetype'); font-weight: 400; font-display: swap; }
@font-face { font-family: 'Manrope'; src: url('/fonts/Manrope-SemiBold.ttf') format('truetype'); font-weight: 600; font-display: swap; }
@font-face { font-family: 'Manrope'; src: url('/fonts/Manrope-Bold.ttf') format('truetype'); font-weight: 700; font-display: swap; }

:root {
  --night: #05070E;
  --night-2: #0B0F1A;
  --cream: #F6F1E6;
  --cream-dim: rgba(246, 241, 230, .74);
  --cream-faint: rgba(246, 241, 230, .56);
  --cream-line: rgba(246, 241, 230, .12);
  --gold: #EDC967;
  --gold-sky: #EFD394;
  --gold-a: #F0C86B;
  --gold-b: #D5A947;
  --gold-ink: #17120A;
  --pearl: #F3F6FA;
  --pearl-2: #EEF2F7;
  --pearl-3: #E2E8F0;
  --slate: #3A4F68;
  --ink: #1A1C24;
  --ink-dim: #343D4A;
  --ink-line: #D5DCE6;
  --deep-gold: #6E5213;
  --navy: #12243C;
  --violet: #825ABE;
  --serif: 'Fraunces', Georgia, 'Times New Roman', serif;
  --sans: 'Manrope', system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
  --r-card: 24px;
  --r-inner: 16px;
  --wrap: 72.5rem;
  --gutter: clamp(20px, 5vw, 40px);
  --ease: cubic-bezier(.2, .7, .2, 1);
  /* ONE vertical rhythm for every section. Eight sections with eight different
     paddings is a page without a beat, and it was one of the things reading as
     clumsy. Height-bounded like every other scaled size below. */
  --section-y: clamp(4.5rem, min(9vw, 11vh), 8.25rem);
}

/* 🚨 EVERY VIEWPORT-SCALED SIZE IS BOUNDED BY HEIGHT AS WELL AS WIDTH.
   A laptop is wide but SHORT — 1366×768, or 1920×1080 at Windows' 150% scaling,
   which is 1280×720 of CSS. Sizing display type and vertical rhythm on `vw`
   alone hands that screen the same 88px headline as a 27" monitor, and the hero
   then stands 909px tall in a 768px window: the proof list, the phones' feet and
   any hint of a next section all fall below the fold. So the preferred term of
   every clamp is `min(<vw>, <vh>)`, and paddings that only exist to breathe are
   `vh` outright. Widths stay on `vw` — a short screen is not a narrow one. */

*, *::before, *::after { box-sizing: border-box; }
html { scroll-behavior: smooth; scroll-padding-top: 5rem; -webkit-text-size-adjust: 100%; }
body {
  margin: 0;
  background: var(--night);
  color: var(--cream);
  font: 400 1rem/1.6 var(--sans);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}
/* `hidden` must beat any class that sets `display`: several controls are
   published hidden and shown by a script, and a `.btn { display: inline-flex }`
   would otherwise put them on screen, dead, when scripts are off. */
[hidden] { display: none !important; }
img { max-width: 100%; display: block; }
a { color: inherit; }
button { font: inherit; color: inherit; }
:focus-visible { outline: 2px solid var(--gold); outline-offset: 3px; border-radius: 6px; }
.day :focus-visible { outline-color: var(--deep-gold); }
.sr-only { position: absolute; width: 1px; height: 1px; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
.skip { position: absolute; left: 12px; top: -6rem; z-index: 100; background: var(--gold); color: var(--gold-ink); padding: 10px 16px; border-radius: 10px; font-weight: 700; text-decoration: none; }
.skip:focus { top: 12px; }

/* The gutter also clears a notch: the pages declare `viewport-fit=cover`, so in
   landscape on a phone the safe-area inset is the only thing keeping text off
   the cut-out. `max()` leaves every other screen on the plain gutter. */
.wrap {
  width: 100%; max-width: calc(var(--wrap) + 2 * var(--gutter)); margin: 0 auto;
  padding-left: max(var(--gutter), env(safe-area-inset-left));
  padding-right: max(var(--gutter), env(safe-area-inset-right));
}

/* ---------- type ---------- */
/* Every section's label is a small outlined tag with a dot (founder 2026-09-26:
   "remove the hyphens here and there, it looks odd, better design that"). The
   hairline that used to lead each label read as a stray hyphen in front of
   the words. Border, wash and dot are all mixed from the label's own colour, so
   the one rule holds on night, on pearl and paper, and on each Skies ground
   without naming any of them. A browser without color-mix() drops the border
   and the wash and keeps the dot and the words. */
.eyebrow {
  display: inline-flex; align-items: center; gap: 9px;
  padding: 7px 13px 7px 11px; border-radius: 999px;
  border: 1px solid color-mix(in srgb, currentColor 32%, transparent);
  background: color-mix(in srgb, currentColor 7%, transparent);
  font: 700 0.6875rem/1 var(--sans); letter-spacing: .18em; text-transform: uppercase;
  color: var(--gold-sky); margin: 0 0 clamp(14px, 2.2vh, 22px);
}
.eyebrow::before { content: ''; flex: none; width: 5px; height: 5px; border-radius: 50%; background: currentColor; box-shadow: 0 0 0 3px color-mix(in srgb, currentColor 18%, transparent); }
.day .eyebrow { color: var(--deep-gold); }
/* `balance` stops a two-line headline leaving one orphan word on line two —
   the cheapest single thing that separates a typeset page from a typed one.
   Browsers without it simply wrap as before. */
h1, h2, h3 { font-family: var(--serif); font-weight: 600; margin: 0; letter-spacing: -.02em; text-wrap: balance; }
h2 { font-size: clamp(2rem, min(4.6vw, 6.6vh), 3.375rem); line-height: 1.06; }
h2 em, h1 em { font-style: italic; color: var(--gold-sky); }
.day h2 em { color: var(--deep-gold); }
.lead { font-size: clamp(1.0625rem, min(1.5vw, 2.2vh), 1.15625rem); line-height: 1.65; color: var(--cream-dim); margin: clamp(14px, 2.6vh, 22px) 0 0; max-width: 40ch; }
.day .lead { color: var(--ink-dim); }
.center { text-align: center; }
.center .lead { margin-left: auto; margin-right: auto; }

/* ---------- buttons ---------- */
.btn {
  position: relative; overflow: hidden; isolation: isolate;
  display: inline-flex; align-items: center; justify-content: center; gap: 10px;
  min-height: 3.25rem; padding: 0 26px; border-radius: 999px;
  font: 700 0.96875rem/1.2 var(--sans); text-decoration: none; cursor: pointer;
  border: 1px solid transparent;
  transition: transform .25s var(--ease), box-shadow .25s var(--ease), background-color .25s, border-color .25s;
}
.btn:hover { transform: translateY(-1px); }
.btn:active { transform: translateY(0); }
/* The glow used to be a 34px gold halo, which reads as a template button and
   made the ghost button beside it look like a second primary. Gold is the one
   "now" on the page; it does not also need to be the brightest object. */
.btn-gold {
  background: linear-gradient(170deg, var(--gold-a), var(--gold-b));
  color: var(--gold-ink);
  border-color: rgba(23, 18, 10, .2);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .5), 0 8px 20px -14px rgba(23, 18, 10, .85);
}
.btn-gold:hover { box-shadow: inset 0 1px 0 rgba(255, 255, 255, .55), 0 14px 26px -14px rgba(23, 18, 10, .9); }
.btn-gold::after {
  content: ''; position: absolute; inset: 0; z-index: -1;
  background: linear-gradient(105deg, transparent 35%, rgba(255, 255, 255, .38) 50%, transparent 65%);
  transform: translateX(-120%);
}
.btn-gold:hover::after { transform: translateX(120%); transition: transform .9s var(--ease); }
.btn-ghost { border-color: rgba(246, 241, 230, .24); background: rgba(246, 241, 230, .04); color: var(--cream); }
.btn-ghost:hover { border-color: rgba(246, 241, 230, .5); background: rgba(246, 241, 230, .08); }
.day .btn-ghost { border-color: rgba(26, 28, 36, .2); background: rgba(255, 255, 255, .5); color: var(--ink); }
.btn-sm { min-height: 2.5rem; padding: 0 18px; font-size: 0.875rem; }
.btn svg { width: 1.125rem; height: 1.125rem; flex: none; }

/* ---------- nav ---------- */
/* Clear at the top of a page, so the sky every page opens on runs up behind the
   logo instead of stopping at a grey slab; glass once the page moves. Every
   page opens on a dark header, which is what makes clear safe there.
   🚨 CLEAR IS A SCRIPTED STATE. Only site.js knows the page has scrolled (and
   whether a light section is under the bar), so with scripts off the bar keeps
   its night glass everywhere — a clear bar would put cream text on the pearl
   and paper sections with nothing to turn it back. */
.nav {
  position: fixed; inset: 0 0 auto; z-index: 50;
  background: rgba(7, 8, 26, .76);
  -webkit-backdrop-filter: blur(18px) saturate(140%);
  backdrop-filter: blur(18px) saturate(140%);
  border-bottom: 1px solid var(--cream-line);
  transition: background-color .3s, border-color .3s;
}
.js .nav:not(.is-scrolled):not(.is-open) {
  background: transparent; border-color: transparent;
  -webkit-backdrop-filter: none; backdrop-filter: none;
}
.nav .wrap { display: flex; align-items: center; gap: 28px; min-height: 4.25rem; }
/* The logo: the tent under its star, then ASTONIK with the A's counter lit.
   Sized in rem so it grows with the reader's default text size, as the old
   typed wordmark did. The night lockup by default; the ink one over pearl. */
.wordmark { display: inline-flex; align-items: center; text-decoration: none; color: var(--cream); line-height: 0; }
.wordmark img { display: block; height: 2.375rem; width: auto; }
.wordmark .logo-day, .nav.is-day .wordmark .logo-night { display: none; }
.nav.is-day .wordmark .logo-day { display: block; }
.nav-links { display: flex; gap: 26px; margin-left: auto; list-style: none; padding: 0; }
.nav-links a { font: 600 0.875rem/1 var(--sans); color: var(--cream-dim); text-decoration: none; transition: color .2s; }
.nav-links a:hover { color: var(--cream); }
.nav-cta-row { display: none; }
.nav-toggle { display: none; margin-left: auto; width: 2.75rem; height: 2.75rem; border-radius: 12px; border: 1px solid var(--cream-line); background: transparent; cursor: pointer; }
.nav-toggle span { display: block; width: 18px; height: 1.5px; background: var(--cream); margin: 5px auto; transition: transform .3s var(--ease), opacity .2s; }
/* Over a light section the bar turns to pearl glass, so it never sits as a grey slab. */
.nav, .wordmark, .nav-links a, .nav-toggle span { transition: background-color .35s, border-color .35s, color .35s; }
.nav.is-day { background: rgba(243, 246, 250, .82); border-color: var(--ink-line); }
.nav.is-day .wordmark { color: var(--ink); }
.nav.is-day .nav-links a { color: var(--ink-dim); }
.nav.is-day .nav-links a:hover { color: var(--ink); }
.nav.is-day .nav-toggle { border-color: var(--ink-line); }
.nav.is-day .nav-toggle span { background: var(--ink); }
.nav.is-open .nav-toggle span:nth-child(1) { transform: translateY(6.5px) rotate(45deg); }
.nav.is-open .nav-toggle span:nth-child(2) { opacity: 0; }
.nav.is-open .nav-toggle span:nth-child(3) { transform: translateY(-6.5px) rotate(-45deg); }

@media (max-width: 53.75em) {
  .nav-toggle { display: block; }
  .nav .nav-cta { display: none; }
  .nav-links {
    position: absolute; top: 100%; left: 0; right: 0; flex-direction: column; gap: 0;
    margin: 0; padding: 8px var(--gutter) 20px;
    background: #07081A; border-bottom: 1px solid var(--cream-line);
    transform: translateY(-8px); opacity: 0; visibility: hidden;
    transition: opacity .25s, transform .25s var(--ease), visibility .25s;
  }
  .nav.is-open .nav-links { opacity: 1; transform: none; visibility: visible; }
  .nav-links a { display: block; padding: 16px 0; font-size: 1.0625rem; border-bottom: 1px solid var(--cream-line); }
  .nav-links li:last-child a { border: 0; }
  .nav.is-day .nav-links { background: rgba(243, 246, 250, .98); border-color: var(--ink-line); }
  .nav.is-day .nav-links a { border-color: var(--ink-line); }
  .nav-cta-row { display: block; padding-top: 14px; }
  /* `.nav-links a` is more specific than `.btn-gold`, so the label and the row
     rule below it have to be restated or the gold button draws dim cream ink
     on gold with a divider under it. */
  .nav-cta-row .btn { display: flex; width: 100%; min-height: 3rem; font-size: 0.96875rem; padding: 0 20px; border: 1px solid transparent; color: var(--gold-ink); }
}

/* ---------- sections ---------- */
.section { position: relative; padding: var(--section-y) 0; }
.day { background: var(--pearl); color: var(--ink); }
.section-head { max-width: 45rem; margin-bottom: clamp(36px, min(7vw, 7vh), 72px); }
.section-head.center { margin-left: auto; margin-right: auto; }

/* The honeypot field. The fit page's form carries one too, so it stays here. */
.hp { position: absolute; left: -10000px; width: 1px; height: 1px; overflow: hidden; }

/* ---------- footer ---------- */
.footer { padding: clamp(52px, 8vh, 72px) 0 calc(40px + env(safe-area-inset-bottom)); border-top: 1px solid var(--cream-line); background: var(--night); color: var(--cream-dim); font-size: 0.90625rem; }
.footer-top { display: flex; flex-wrap: wrap; justify-content: space-between; gap: 32px; }
.footer .wordmark img { height: 3rem; }
.footer-tag { margin: 12px 0 0; max-width: 32ch; }
.footer nav ul { list-style: none; padding: 0; margin: 0; display: grid; grid-template-columns: repeat(2, auto); gap: 12px 44px; }
.footer nav a { color: var(--cream); text-decoration: none; font-weight: 600; }
.footer nav a:hover { color: var(--gold-sky); }
.footer-fine { margin-top: 48px; padding-top: 26px; border-top: 1px solid var(--cream-line); display: grid; gap: 10px; font-size: 0.8125rem; color: var(--cream-faint); }
.footer-fine p { margin: 0; max-width: 80ch; }

/* ---------- document pages (legal, delete account) ---------- */
.doc-head { color: var(--cream); padding: clamp(104px, 15vh, 140px) 0 clamp(44px, 7vh, 64px); background: radial-gradient(ellipse 70% 120% at 70% 0%, rgba(213, 169, 71, .2), transparent 60%), var(--night); }
.doc-head h1 { font-size: clamp(2.125rem, min(5.5vw, 7vh), 3.5rem); line-height: 1.05; max-width: 18ch; }
.day .doc-head .eyebrow { color: var(--gold-sky); }
.doc-head .meta { margin: 18px 0 0; color: var(--cream-dim); font-size: 0.9375rem; }
.doc { padding: clamp(50px, 8vw, 90px) 0 clamp(80px, 10vw, 120px); }
.doc .wrap { max-width: calc(48.75rem + 2 * var(--gutter)); }
.prose { font-size: 1.03125rem; line-height: 1.75; color: var(--ink-dim); }
.prose h2 { font-size: clamp(1.625rem, 3vw, 2rem); line-height: 1.2; color: var(--ink); margin: 56px 0 16px; padding-top: 34px; border-top: 1px solid var(--ink-line); }
.prose h2:first-child { margin-top: 0; padding-top: 0; border-top: 0; }
.prose h3 { font-family: var(--sans); font-weight: 700; font-size: 1.125rem; letter-spacing: 0; color: var(--ink); margin: 34px 0 10px; }
.prose p { margin: 0 0 16px; }
.prose ul, .prose ol { margin: 0 0 18px; padding-left: 22px; }
.prose li { margin: 0 0 8px; }
.prose li::marker { color: var(--deep-gold); }
.prose strong { color: var(--ink); font-weight: 700; }
.prose a { color: var(--slate); text-underline-offset: 3px; }
.prose code { font: inherit; }
.prose hr { border: 0; border-top: 1px solid var(--ink-line); margin: 40px 0; }
.prose .table { overflow-x: auto; margin: 8px 0 24px; border: 1px solid var(--ink-line); border-radius: var(--r-inner); background: #fff; }
.prose table { width: 100%; border-collapse: collapse; font-size: 0.90625rem; line-height: 1.55; min-width: 35rem; }
.prose th, .prose td { text-align: left; vertical-align: top; padding: 12px 14px; border-bottom: 1px solid var(--ink-line); }
.prose th { background: var(--pearl-2); color: var(--ink); font-weight: 700; }
.prose tr:last-child td { border-bottom: 0; }
.prose .placeholder { background: #FDE8E4; color: #8A2A1E; border-radius: 4px; padding: 0 4px; }
.box { margin: 0 0 18px; padding: 24px 26px; border-radius: var(--r-card); background: #fff; border: 1px solid var(--ink-line); }
.box h2 { margin-top: 0; padding-top: 0; border-top: 0; }
.box ol { margin-bottom: 0; }
.draft-bar { position: fixed; z-index: 60; left: 0; right: 0; bottom: 0; padding: 10px 16px; text-align: center; background: #8A2A1E; color: #fff; font: 700 0.8125rem/1.4 var(--sans); }

/* ---------- 404 / 403 / 500 / 503 / offline ---------- */
.lost { min-height: 100vh; min-height: 100svh; display: grid; place-items: center; text-align: center; padding: clamp(96px, 14vh, 120px) 0; }
.lost h1 { font-size: clamp(2.375rem, min(7vw, 9vh), 4.875rem); line-height: 1; }
.lost p { color: var(--cream-dim); margin: 20px auto 34px; max-width: 34ch; font-size: 1.125rem; }

/* ---------- in the hand ----------
   Sizes are already bounded by width and height above; these are the things a
   thumb needs rather than a smaller number. One action per row at full width,
   so neither button is the narrow one; lists that stack instead of ragging
   across two lines; icon rails and card padding that give the words back the
   ~50px they were spending on chrome at 390px. */
@media (max-width: 38.75em) {
  .cta-row { gap: 10px; }
  .cta-row .btn { width: 100%; }
  .footer-top { gap: 26px; }
  .footer nav ul { gap: 4px 24px; }
  .footer nav a { display: inline-block; padding: 9px 0; }
  .prose h2 { margin-top: 42px; padding-top: 26px; }
}

/* A retention table is 2–3 columns of prose: squeezed into 350px it is
   unreadable, so it keeps its own sideways scroll. What it did not have was any
   sign that it scrolls — the second column simply ended mid-sentence at the
   screen edge. Below 600px the wrap is narrower than the table's own minimum,
   so the overflow is certain and the faded edge is never a lie. */
@media (max-width: 37.5em) {
  .prose table { min-width: 32.5rem; font-size: 0.875rem; }
  .prose th, .prose td { padding: 10px 12px; }
  .prose .table {
    -webkit-mask-image: linear-gradient(to right, #000 84%, rgba(0, 0, 0, .15));
    mask-image: linear-gradient(to right, #000 84%, rgba(0, 0, 0, .15));
  }
}

/* Quiet, first-party. Not a draft warning and not a cookie banner. */
.net-bar {
  position: fixed; z-index: 55; left: 0; right: 0; bottom: 0;
  padding: 10px 16px; text-align: center;
  background: #12243C; color: var(--cream);
  font: 700 0.8125rem/1.4 var(--sans);
  border-top: 1px solid rgba(237, 201, 103, .35);
}
body:has(.draft-bar) .net-bar { bottom: 44px; }

/* ---------- reveal on scroll (only when JS is running) ---------- */
.js [data-reveal] { opacity: 0; transform: translateY(22px); transition: opacity .9s var(--ease), transform .9s var(--ease); }
.js [data-reveal].is-in { opacity: 1; transform: none; }
.js [data-reveal='2'] { transition-delay: .1s; }
.js [data-reveal='3'] { transition-delay: .2s; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation: none !important; transition-duration: .01ms !important; }
  .js [data-reveal] { opacity: 1; transform: none; }
}

/* ---------- fit check (/fit/) ----------
   The ask stands on the night sky; the answer stands on pearl. Two grounds, so
   every colour below names which one it is for (§9: the ground follows the
   appearance, and ink measured against the wrong one is the bug that keeps
   coming back). `.fit-foot` sets its own night background on purpose — the page
   is `body.day`, so a section that set only cream TEXT would paint cream on
   pearl, which is that same bug in a new place. */
.fit-ask {
  position: relative; overflow: hidden; color: var(--cream);
  padding: clamp(104px, 15vh, 148px) 0 clamp(52px, 8vh, 84px);
  background: var(--night);
}
.fit-sky { position: absolute; inset: 0; }
.fit-sky img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; object-position: 50% 62%; opacity: .8; }
.fit-sky::after { content: ''; position: absolute; inset: 0; background: radial-gradient(ellipse 70% 90% at 50% 0%, rgba(213, 169, 71, .16), transparent 62%), linear-gradient(to bottom, rgba(5, 7, 14, .72), rgba(5, 7, 14, .42) 45%, var(--night)); }
.fit-ask .wrap { position: relative; }
.fit-ask h1 { font-size: clamp(2.125rem, min(5.6vw, 7vh), 3.625rem); line-height: 1.04; max-width: 15ch; }
.fit-ask .lead { max-width: 46ch; }

.fit-form { margin: clamp(26px, 4.4vh, 40px) 0 0; max-width: 40rem; }
.fit-field { display: flex; gap: 10px; }
.fit-field input {
  flex: 1 1 auto; min-width: 0; min-height: 3.75rem; padding: 0 20px; border-radius: var(--r-inner);
  border: 1px solid rgba(246, 241, 230, .22); background: rgba(246, 241, 230, .07); color: var(--cream);
  font: 400 1.03125rem/1 var(--sans); transition: border-color .2s, box-shadow .2s, background-color .2s;
}
.fit-field input::placeholder { color: var(--cream-faint); }
.fit-field input:focus { outline: none; border-color: var(--gold); background: rgba(246, 241, 230, .1); box-shadow: 0 0 0 4px rgba(237, 201, 103, .22); }
.fit-field .btn { flex: none; min-height: 3.75rem; }
.fit-hint { min-height: 1.5em; margin: 8px 0 0 4px; font-size: 0.875rem; font-weight: 600; color: var(--gold-sky); }

.fit-examples { display: flex; flex-wrap: wrap; align-items: center; gap: 9px; margin-top: 18px; font-size: 0.875rem; color: var(--cream-faint); }
.fit-examples button {
  border: 1px solid rgba(246, 241, 230, .2); background: rgba(246, 241, 230, .05); color: var(--cream-dim);
  border-radius: 999px; padding: 8px 15px; font: 600 0.84375rem/1 var(--sans); cursor: pointer;
  transition: border-color .2s, background-color .2s, color .2s, transform .2s var(--ease);
}
.fit-examples button:hover { color: var(--cream); border-color: rgba(246, 241, 230, .45); background: rgba(246, 241, 230, .09); transform: translateY(-1px); }
.fit-private { margin: clamp(22px, 3.4vh, 32px) 0 0; font-size: 0.84375rem; line-height: 1.55; color: var(--cream-faint); max-width: 54ch; }

/* ---- the answer, on pearl ---- */
.fit-answer { padding-top: clamp(48px, 7vh, 84px); }
.js .fit-nojs { display: none; }
.fit-nojs { margin: 34px 0 0; padding: 16px 18px; border-radius: var(--r-inner); border: 1px solid var(--ink-line); background: #fff; font-size: 0.90625rem; color: var(--ink-dim); }

.fit-result { opacity: 1; }
.js .fit-result { opacity: 0; transform: translateY(18px); transition: opacity .7s var(--ease), transform .7s var(--ease); }
.js .fit-result.is-in { opacity: 1; transform: none; }
.fit-result:focus { outline: none; }

.fit-head-row { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: clamp(24px, 4vw, 48px); align-items: center; }
.fit-head-words h2 { font-size: clamp(1.6875rem, min(3.8vw, 5.4vh), 2.625rem); }
.fit-head-words .lead { margin-top: 14px; max-width: 48ch; }

/* The gauge: a 270° arc starting bottom-left. Gold means "now" and belongs to a
   real fit, so a low score wears slate or red instead of the reward colour. The
   contrast that matters is the NUMBER's, not the ring's. */
.dial-wrap { position: relative; width: clamp(140px, 19vw, 178px); aspect-ratio: 1; flex: none; }
/* display:block — an inline SVG sits on a text baseline, which added 7px of
   descender below the circle and pushed the gauge off-centre in its own box. */
.dial { display: block; width: 100%; height: 100%; transform: rotate(135deg); overflow: visible; }
.dial circle { fill: none; stroke-width: 13; stroke-linecap: round; }
.dial-track { stroke: var(--pearl-3); }
.dial-value { stroke: var(--slate); transition: stroke-dashoffset 1.2s var(--ease); }
.tone-yes .dial-value { stroke: var(--gold-b); }
.tone-no .dial-value { stroke: #8A2A1E; }
.dial-num { position: absolute; inset: 0; display: grid; place-content: center; text-align: center; }
.dial-pct { font: 600 clamp(2.125rem, 4.6vw, 2.75rem)/1 var(--serif); letter-spacing: -.03em; color: var(--ink); font-variant-numeric: tabular-nums; }
.dial-cap { display: block; margin-top: 6px; font: 700 0.65625rem/1 var(--sans); letter-spacing: .2em; text-transform: uppercase; color: var(--ink-dim); }

.fit-rows { list-style: none; padding: 0; margin: clamp(34px, 5vh, 52px) 0 0; display: grid; gap: 2px; border-radius: var(--r-card); overflow: hidden; border: 1px solid var(--ink-line); background: var(--ink-line); }
.fit-rows li { display: grid; grid-template-columns: 2.375rem minmax(0, 1fr); gap: 16px; align-items: start; padding: 20px 24px; background: #fff; }
.fit-rows h3 { font-size: 1.09375rem; line-height: 1.3; font-family: var(--sans); font-weight: 700; letter-spacing: 0; color: var(--ink); }
.fit-rows p { margin: 5px 0 0; font-size: 0.9375rem; line-height: 1.55; color: var(--ink-dim); }
.fit-mark { width: 2.375rem; height: 2.375rem; border-radius: 12px; display: grid; place-items: center; font: 700 1rem/1 var(--sans); background: var(--pearl-3); color: var(--slate); }
.fit-rows .is-yes .fit-mark { background: rgba(31, 90, 58, .12); color: #1F5A3A; }
.fit-rows .is-no .fit-mark { background: rgba(138, 42, 30, .12); color: #8A2A1E; }
.fit-rows.is-preview .fit-mark { font-family: var(--serif); font-size: 1.0625rem; }

.fit-note { margin: 22px 0 0; padding: 22px 24px; border-radius: var(--r-card); border: 1px solid var(--ink-line); background: #fff; border-left: 3px solid var(--slate); }
.fit-note h3 { font: 700 0.75rem/1 var(--sans); letter-spacing: .16em; text-transform: uppercase; color: var(--slate); }
.fit-note p { margin: 12px 0 0; font-size: 0.96875rem; line-height: 1.6; color: var(--ink-dim); }
.fit-note.is-caveat { border-left-color: #8A2A1E; background: #FFFBFA; }
.fit-note.is-caveat h3 { color: #8A2A1E; }
.fit-note.is-good { border-left-color: var(--deep-gold); }
.fit-note.is-good h3 { color: var(--deep-gold); }

.fit-night { margin: 22px 0 0; padding: 24px 26px; border-radius: var(--r-card); border: 1px solid var(--ink-line); background: linear-gradient(160deg, #FFFDF7, #FBF6EA); }
.fit-night b { display: block; margin-bottom: 8px; font: 700 0.6875rem/1 var(--sans); letter-spacing: .16em; text-transform: uppercase; color: var(--deep-gold); }
.fit-night p { margin: 0; font: 600 clamp(1.1875rem, 2.4vw, 1.4375rem)/1.35 var(--serif); letter-spacing: -.01em; color: var(--ink); }
.fit-night-fine { display: block; margin-top: 14px; font-size: 0.84375rem; line-height: 1.5; color: var(--ink-dim); }

.fit-cta { display: flex; flex-wrap: wrap; align-items: center; gap: 12px; margin-top: 30px; }
.fit-again { border: 0; background: none; padding: 10px 4px; cursor: pointer; font: 700 0.9375rem/1 var(--sans); color: var(--slate); text-decoration: underline; text-underline-offset: 4px; }
.fit-again:hover { color: var(--ink); }
.fit-fine { margin: 26px 0 0; font-size: 0.84375rem; line-height: 1.6; color: var(--ink-dim); max-width: 72ch; }
.fit-fine a { color: var(--slate); }

/* ---------- the confidence, under the gauge ----------
   🚨 A SECOND NUMBER, NOT A SECOND SCORE. It answers "how sure are we of this
   read", so it is deliberately smaller, quieter and OUTSIDE the ring: inside
   it, a reader takes it for the match's margin of error. */
/* The clarify invitation, under the lead. Quieter than the lead so the
   verdict still leads, louder than fine print so the picker gets found. */
.fit-clarify { margin: 14px 0 0; padding-left: 14px; border-left: 2px solid var(--deep-gold); max-width: 50ch; font-size: 0.96875rem; line-height: 1.6; color: var(--ink-dim); }

.dial-conf { margin: 12px 0 0; text-align: center; font-size: 0.8125rem; line-height: 1.4; color: var(--ink-dim); }
.dial-conf b { display: block; font: 700 0.9375rem/1.2 var(--sans); color: var(--ink); font-variant-numeric: tabular-nums; }

/* ---------- the journey path (the doodle) ----------
   🚨 THIS IS THE ANSWER; THE SCORE IS ONLY ITS EXPLANATION. The stages a goal
   breaks into, and which of them Astonik can guide tonight.

   It is drawn as a sketch on purpose. A crisp infographic of a plan that is
   still being built would overclaim in a way a hand-drawn line does not — the
   rings are slightly off-round and the connectors wobble, which reads as
   "this is roughly how it would go", which is exactly the claim being made.

   Every colour here is measured against WHITE, which is this box's own ground
   (CLAUDE.md §9 — ink measured against the wrong ground is the bug that keeps
   coming back). The section around it is pearl; the box is #fff. */
.jpath {
  margin: clamp(30px, 4.6vh, 46px) 0 0; padding: clamp(20px, 2.6vw, 30px);
  border-radius: var(--r-card); border: 1px solid var(--ink-line); background: #fff;
  /* A column, not a full-width slab. Stage names are two or three words, so at
     1366 the card was 1160px of mostly white with the path hugging its left
     edge — which reads as a layout that ran out of content rather than one that
     was measured. */
  max-width: 48rem;
}
.jpath-head { margin: 0 0 clamp(18px, 2.4vh, 26px); }
.jpath-head b { display: block; font: 700 0.6875rem/1 var(--sans); letter-spacing: .16em; text-transform: uppercase; color: var(--deep-gold); }
.jpath-head span { display: block; margin-top: 8px; font-size: 0.9375rem; line-height: 1.5; color: var(--ink-dim); }
.jstages { list-style: none; margin: 0; padding: 0; }
.jstage {
  position: relative; display: grid; grid-template-columns: 2rem minmax(0, 1fr) auto;
  gap: 0 14px; align-items: start; padding-bottom: clamp(15px, 2.2vh, 22px);
}
.jstage:last-child { padding-bottom: 0; }

/* The connector, from under one ring to the top of the next. A repeating
   hand-drawn wave rather than a border: a straight 1px rule is a diagram, and
   this is a sketch. A data: URI is allowed by `img-src 'self' data:` — it is an
   image as far as the CSP is concerned, unlike an inline <style> block. */
.jstage:not(:last-child)::after {
  content: ''; position: absolute; left: 0; width: 2rem; top: 2.3rem; bottom: 2px;
  transform-origin: top;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='8' height='22'%3E%3Cpath d='M4 0c-2.6 3.6 2.6 7.4 0 11s2.6 7.4 0 11' fill='none' stroke='%23C09A46' stroke-width='1.7' stroke-linecap='round'/%3E%3C/svg%3E") repeat-y center top;
}
/* A link out of a stage Astonik does not cover is drawn as not-yet. The row's
   OWN level decides the line below it, so the path visibly thins where the
   coverage does. */
.jstage.is-prep:not(:last-child)::after,
.jstage.is-soon:not(:last-child)::after {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='8' height='22'%3E%3Cpath d='M4 0c-2.6 3.6 2.6 7.4 0 11s2.6 7.4 0 11' fill='none' stroke='%237E8BA0' stroke-width='1.6' stroke-linecap='round' stroke-dasharray='3 4.5'/%3E%3C/svg%3E");
}

.jmark { width: 2rem; height: 2rem; display: block; }
.jmark svg { width: 100%; height: 100%; display: block; overflow: visible; }
/* 66 is the ring path's own length, so the dash covers it exactly. The base
   state is DRAWN — the keyframe supplies the undrawn start — which is what
   makes "animations off" show a finished path instead of an empty one. */
.jring { fill: none; stroke: var(--deep-gold); stroke-width: 1.7; stroke-linecap: round; stroke-dasharray: 66; stroke-dashoffset: 0; }
.jtick { fill: none; stroke: var(--deep-gold); stroke-width: 2.1; stroke-linecap: round; stroke-linejoin: round; }
.jdot { fill: var(--slate); }
.jstage.is-prep .jring { stroke: var(--slate); }
.jstage.is-soon .jring { stroke: #7E8BA0; stroke-dasharray: 4 5; }

.jstage-body { min-width: 0; padding-top: 3px; }
.jstage-body h4 { margin: 0; font: 600 1.0625rem/1.35 var(--serif); letter-spacing: -.01em; color: var(--ink); }
.jstage-body p { margin: 3px 0 0; font: 700 0.6875rem/1.4 var(--sans); letter-spacing: .1em; text-transform: uppercase; color: var(--deep-gold); }
.jstage.is-prep .jstage-body p { color: var(--slate); }
/* #7E8BA0 is fine for a decorative ring and nowhere near the 4.5:1 a LABEL
   needs, so the not-yet row's words take the full ink-dim (§9's floor rule). */
.jstage.is-soon .jstage-body h4 { color: var(--ink-dim); }
.jstage.is-soon .jstage-body p { color: var(--ink-dim); }

/* "you start here" — the one row the person told us about. */
.jstage.is-here .jstage-body { position: relative; }
.jstage.is-here .jstage-body h4 { color: var(--ink); }
.jstage.is-here .jstage-body h4::after {
  content: ''; display: block; height: 6px; margin-top: 3px; max-width: 14rem;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='6'%3E%3Cpath d='M1 4.2C22 1.6 44 1.2 66 2.4c18 1 34 2 53 .6' fill='none' stroke='%23C09A46' stroke-width='2' stroke-linecap='round'/%3E%3C/svg%3E") repeat-x left center;
}

/* The picker. The stage list IS the clarification question, so the control
   lives on the row it names — a separate set of options would be this list
   written a second time, and the second copy is the one that goes stale. */
.jstage-pick {
  align-self: center; flex: none; border: 1px solid var(--ink-line); background: var(--pearl-2);
  color: var(--slate); border-radius: 999px; padding: 7px 14px; cursor: pointer;
  font: 700 0.8125rem/1 var(--sans); white-space: nowrap;
  transition: border-color .2s, background-color .2s, color .2s, transform .2s var(--ease);
}
.jstage-pick:hover { color: var(--ink); border-color: var(--slate); background: #fff; transform: translateY(-1px); }
.jpath-fine { margin: clamp(18px, 2.4vh, 24px) 0 0; padding-top: 16px; border-top: 1px solid var(--ink-line); font-size: 0.84375rem; line-height: 1.6; color: var(--ink-dim); }

/* The drawing itself. `animation-delay: inherit` is the whole trick: the row
   carries the stagger (one CSSOM write per row in js/fit.js) and every mark and
   connector inside it inherits that one value, so the path draws downward in
   order without a delay having to be written per element. */
.jstage { animation: jrise .5s var(--ease) both; }
.jstage .jring { animation: jdraw .95s var(--ease) both; animation-delay: inherit; }
.jstage .jtick, .jstage .jdot { animation: jpop .95s var(--ease) both; animation-delay: inherit; transform-box: fill-box; transform-origin: center; }
.jstage:not(:last-child)::after { animation: jgrow .6s var(--ease) both; animation-delay: inherit; }
@keyframes jrise { from { opacity: 0; transform: translateY(10px); } }
@keyframes jdraw { from { stroke-dashoffset: 66; } }
@keyframes jgrow { from { transform: scaleY(0); } }
@keyframes jpop { 0%, 58% { opacity: 0; transform: scale(.4); } 80% { opacity: 1; transform: scale(1.14); } 100% { opacity: 1; transform: scale(1); } }

@media (max-width: 38.75em) {
  /* The pick button drops to its own row rather than squeezing the stage name
     into a column two words wide. */
  .jstage { grid-template-columns: 1.75rem minmax(0, 1fr); }
  .jstage:not(:last-child)::after { width: 1.75rem; top: 2.05rem; }
  .jmark { width: 1.75rem; height: 1.75rem; }
  .jstage-pick { grid-column: 2; justify-self: start; margin-top: 10px; }
  .jstage-body h4 { font-size: 1rem; }
}

/* Support, not a score. Deliberately the one result that carries no dial. */
.fit-crisis { padding: clamp(28px, 4vw, 40px); border-radius: var(--r-card); background: #fff; border: 1px solid var(--ink-line); border-top: 4px solid #8A2A1E; max-width: 68ch; }
.fit-crisis h2 { font-size: clamp(1.625rem, 3.4vw, 2.125rem); color: var(--ink); }
.fit-crisis p { margin: 16px 0 0; font-size: 1.03125rem; line-height: 1.7; color: var(--ink-dim); }
.fit-crisis a { color: var(--slate); font-weight: 700; }
.fit-crisis-fine { font-size: 0.84375rem; color: var(--ink-dim); }

.fit-foot { background: var(--night); color: var(--cream); text-align: center; }
.fit-foot .lead { margin-left: auto; margin-right: auto; }
.fit-foot .fit-fine { margin: 32px auto 0; color: var(--cream-faint); }
.fit-foot .fit-fine a { color: var(--cream-dim); }

@media (max-width: 47.5em) {
  .fit-head-row { grid-template-columns: 1fr; justify-items: start; gap: 22px; }
  .dial-wrap { width: 132px; }
}
@media (max-width: 38.75em) {
  .fit-field { flex-direction: column; }
  .fit-field .btn { width: 100%; }
  .fit-rows li { padding: 18px; grid-template-columns: 2.125rem minmax(0, 1fr); gap: 13px; }
  .fit-mark { width: 2.125rem; height: 2.125rem; border-radius: 11px; }
  .fit-note { padding: 18px 20px; }
  .fit-night { padding: 20px; }
  .fit-cta .btn { width: 100%; }
  .fit-cta .fit-again { width: 100%; text-align: center; }
}
@media (prefers-reduced-motion: reduce) {
  .js .fit-result { opacity: 1; transform: none; }
}

/* The header gained a sixth link with `/fit/`, and at the tightest desktop
   width — 861px, one pixel above the hamburger breakpoint — the bar measured
   ZERO slack: wordmark + links + CTA exactly filled the wrap. It fits, but only
   exactly, and the failure is silent: `body { overflow-x: hidden }` would clip
   the "Join the waitlist" button rather than show anything wrong. A fallback
   font a few px wider during the swap, or the next label anyone adds, is enough.
   Tightening the two gaps only in the band where the bar is genuinely tight
   buys ~60px back and changes no other width and no other page. */
@media (min-width: 53.8125em) and (max-width: 60em) {
  .nav .wrap { gap: 18px; }
  .nav-links { gap: 18px; }
}

/* The wait, while the coach writes the answer. The app's own pattern
   (CLAUDE.md §10): a line that changes, with a sheen travelling across the
   letters — not a spinner and not three dots. `background-clip: text` is the
   whole effect, so the fallback when it is unsupported is simply flat text. */
.fit-wait { min-height: 11.25rem; display: grid; place-content: center; }
.fit-wait p {
  margin: 0; font: 600 clamp(1.1875rem, 2.4vw, 1.5rem)/1.4 var(--serif); letter-spacing: -.01em;
  color: var(--ink-dim);
  background: linear-gradient(100deg, var(--ink-dim) 30%, var(--deep-gold) 50%, var(--ink-dim) 70%);
  background-size: 300% 100%;
  -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent;
  animation: fit-sheen 2.4s linear infinite;
}
@keyframes fit-sheen { to { background-position: -200% 0; } }
@media (prefers-reduced-motion: reduce) {
  .fit-wait p { animation: none; -webkit-text-fill-color: var(--ink-dim); }
}

/* With scripts off the fit check cannot run, and `api/fit.php` answers JSON
   rather than a redirect — so a native submit would replace the page with a
   raw JSON blob. A dead control is worse than none (CLAUDE.md §9), so the form
   is not offered at all; `.fit-nojs` explains why and links onward, and the
   five questions above it still read as a page. */
html:not(.js) .fit-form,
html:not(.js) .fit-examples,
html:not(.js) .fit-private { display: none; }

/* The share control sits in the same row as the two buttons and is deliberately
   quiet: the point of the page is the answer, not the sharing. `.is-copied`
   only confirms; when the clipboard is refused the button shows the URL
   instead, which is long, so it wraps rather than pushing the row wide. */
.fit-share.is-copied { color: var(--deep-gold); text-decoration: none; }
.fit-share { max-width: 100%; overflow-wrap: anywhere; text-align: left; }

/* The report link sits in the same quiet row as "Try another goal". It is an
   <a href="mailto:">, not a button, so it keeps browser link behaviour
   (long-press, open in a mail client, copy address) — and it renders as the
   same quiet text as its neighbours rather than competing with the actions. */
.fit-report { text-decoration: underline; text-underline-offset: 4px; }
.fit-report:hover { color: var(--ink); }

/* The one interactive item in the header reads as one. */
.nav-links a.is-try { color: var(--gold-sky); }
.nav-links a.is-try:hover { color: var(--gold); }
.nav.is-day .nav-links a.is-try { color: var(--deep-gold); }

/* ---------- the acceptance dialog (/fit/) ----------
   A native <dialog>, so focus trapping, Escape and the backdrop come from the
   browser. ::backdrop cannot be styled through the element, hence the separate
   rule. Opaque, like every modal on this site (§9: faint glass is only for
   floating over empty sky). */
.fit-modal {
  max-width: 30rem; width: calc(100% - 2.5rem); padding: clamp(1.5rem, 4vw, 2rem);
  border: 1px solid var(--ink-line); border-radius: var(--r-card);
  background: #fff; color: var(--ink-dim);
  box-shadow: 0 2.5rem 5rem -1.5rem rgba(18, 36, 60, .5);
}
.fit-modal::backdrop { background: rgba(5, 7, 14, .62); }
.fit-modal h2 { font-size: clamp(1.35rem, 3vw, 1.7rem); line-height: 1.2; color: var(--ink); }
.fit-modal p { margin: 0.875rem 0 0; font-size: 0.97rem; line-height: 1.6; }
.fit-modal strong { color: var(--ink); }
.fit-modal a { color: var(--slate); text-underline-offset: 3px; }
.fit-modal-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 0.75rem; margin-top: 1.5rem; }
@media (max-width: 38.75em) {
  .fit-modal-actions .btn { width: 100%; }
  .fit-modal-actions .fit-again { width: 100%; text-align: center; }
}
