/**
 * PRD §3 design tokens.
 *
 * VALUES COME FROM design/rapater-calculator.html, not from §3.1's table.
 * The two disagreed: §3.1 documented a light app surface with purple #7C3AED,
 * while every design file — and the deployed landing page — is dark with pink
 * #FF4D82. Resolved 2026-08-06 in favour of the design files, and §3.1/§3.2
 * were rewritten to match. Prompt 1.3 names the prototype as the visual truth,
 * and shape (§3.4) and type (§3.3) already agreed with it exactly.
 *
 * THE TOKEN NAMES ARE UNCHANGED, including `--purple`, which now holds a pink.
 * That reads oddly and is deliberate: the name is a role ("the one accent
 * colour"), not a hue, and renaming it would touch every rule in every design
 * file for no behavioural gain. If it is ever renamed, rename it everywhere at
 * once — a half-renamed accent is worse than a misnamed one.
 *
 * §3.5 forbids: black backgrounds, neon or acid accents, chart decoration,
 * rocket/fire/money-bag iconography, emoji, exclamation marks, animated
 * counters, grey drop shadows, and more than one accent beyond the semantic
 * three. Nothing below introduces any of them; nor should anything that
 * imports this file.
 */

:root {
  /* --- Surface and type colour ------------------------------------------ */
  --ink: #ffffff;        /* headings, primary text */
  --body: #b9aecb;       /* body copy */
  --muted: #877c99;      /* uppercase labels */
  --faint: #6e6483;      /* hints, empty states */
  --line: #33264a;       /* 1px borders and rules — never heavier (§3.4) */
  --card: #221831;
  --tint: rgba(255, 255, 255, 0.04); /* inset boxes inside cards */

  /* --- The one accent --------------------------------------------------- */
  --purple: #ff4d82;                        /* every neutral figure, primary buttons */
  --purple-soft: rgba(255, 77, 130, 0.14);  /* soft button fill, step numerals */
  --purple-deep: #ff7ba3;                   /* text on soft accent */

  /* --- The semantic three (§3.5 permits exactly these beyond the accent) - */
  --red: #ff5c7a;
  --red-soft: rgba(255, 92, 122, 0.1);
  --green: #2ed3a0;
  --green-soft: rgba(46, 211, 160, 0.11);
  --amber: #f5a524;
  --amber-soft: rgba(245, 165, 36, 0.1);

  /* --- Shape (§3.4) ------------------------------------------------------ */
  --r-pill: 999px;
  --r-card: 16px;
  --r-verdict: 20px;
  --r-inset: 14px;
  --r-panel: 26px;

  /* --- Depth (§3.4, restated for the dark surface) ----------------------- */
  /* §3.4's light-surface shadows were purple-tinted because a light card
     needs a coloured shadow to read as lifted. On #150F1E a tinted shadow is
     invisible, so the card uses a deep neutral and the accent glow is carried
     by the primary button instead. Same intent, inverted surface. */
  --shadow-card: none;
  --shadow-verdict: 0 30px 70px rgba(0, 0, 0, 0.45);
  --shadow-primary: 0 8px 26px rgba(255, 77, 130, 0.3);
  --shadow-primary-hover: 0 12px 32px rgba(255, 77, 130, 0.42);

  /* --- Type scale (§3.3) ------------------------------------------------- */
  --t-title: 38px;
  --t-section: 22px;
  --t-dir: 30px;      /* direction + symbol in the verdict header */
  /* Supporting figures INSIDE the verdict card — the dose row and the
     account-risk row. 20px, not the design file's 26px, and this is the one
     considered departure from it (2026-08-06).
     WHY: §6 item 3 requires the loss to be "the largest element on the page",
     and at 26px it was not reading that way. Four figures in a row are read as
     one block, and four at 26px collectively out-weigh a single 52px hero
     however large that hero is. Shrinking the supporting row was preferred to
     bumping the hero because it leaves the design file's 52px exactly as drawn.
     ONE TOKEN ON PURPOSE: the dose and account-risk figures are the same class
     of thing — detail that sits below the loss — so they move together. Two
     tokens would be two names for one concept, and the next person to change
     it would have to find both.
     SETTLED 2026-08-06. Chosen against the card in isolation, then re-checked
     in a browser against the full page — header, three 30px rules figures, the
     card below them. The loss still dominates. If a future page changes that
     composition, this is the number to re-check first. */
  --t-stat: 20px;
  --t-hero: 52px;     /* the loss — the largest element on the page */
  --t-lede: 17px;
  --t-body: 16px;
  --t-small: 14px;
  --t-label: 12px;    /* uppercase label */
}

/**
 * The page. Two radial washes over near-black, from the design file — the
 * gradient §3 describes as doing "the job marketing needs", carried into the
 * app surface now that both are dark.
 */
body {
  font-family: 'Poppins', system-ui, sans-serif;
  background:
    radial-gradient(900px 620px at 85% -8%, rgba(255, 77, 130, 0.18), transparent 60%),
    radial-gradient(760px 560px at -12% 55%, rgba(139, 92, 246, 0.14), transparent 60%),
    #150f1e;
  background-attachment: fixed;
  color: var(--ink);
  font-size: var(--t-body);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

/**
 * §3.3: "Every number carries font-variant-numeric: tabular-nums. No
 * exceptions — figures must not jitter when they update."
 *
 * Applied by element rather than by class, so a figure cannot be added without
 * it. The stop slider (§6 item 4) re-renders the whole card on every input
 * event, which is where a proportional digit would show as a twitch.
 */
.num,
input[inputmode='decimal'],
td,
th {
  font-variant-numeric: tabular-nums;
}

/** §3.3 "Small" — 14px/400/--body. */
.small {
  font-size: var(--t-small);
  color: var(--body);
}

/** §3.3: an uppercase label sits above every number. This is that label. */
.cap {
  font-size: var(--t-label);
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--purple);
}

/**
 * `hidden` MUST hide, whatever else a component says.
 *
 * The UA stylesheet's `[hidden] { display: none }` is beaten by any author rule
 * that sets `display` — and `.warn` sets `display: flex`. On 2026-08-06 that
 * put all eight §10.3 warnings on a live card at once, including two that
 * cannot fire in Phase 1 at all, so a reader was told their 1% risk was "above
 * 5%" and that a trade breached a cap no code had evaluated.
 *
 * Declared once, globally, with `!important`, because the failure is silent and
 * per-component: any future component that sets `display` re-opens it, and
 * nothing in a unit test can see it. This is the rule that makes `hidden`
 * mean hidden.
 */
[hidden] {
  display: none !important;
}

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation: none !important;
    transition: none !important;
  }
}

/**
 * THE FLOOR UNDER EVERY LINK.
 *
 * IN THIS FILE BECAUSE IT IS THE ONLY STYLESHEET EVERY PAGE LOADS. account.html
 * does not link verdict.css at all — it carries its own `.btn` — so a floor
 * placed there would have missed /account entirely, which is the page holding
 * §20.11's click-wrap.
 *
 * Nothing styled an anchor written into a page body by lib/ or public/*.js.
 * calculator.html and account.html style them under `.sitenav` and `.sitefoot`
 * only, so those anchors fell through to the browser's own link colour against
 * a dark background — and `<a href="/start">/start</a>` shipped reading as
 * prose, with the reader handed the URL instead.
 *
 * PRIMARY ACTIONS STILL TAKE `.btn`. This is the floor, not the pattern: it
 * means forgetting the class leaves a link merely unstyled instead of
 * invisible, turning a class of bug into a cosmetic one.
 *
 * `:not([class])` so it cannot reach `.btn` or any other styled anchor, and so
 * `.sitenav a` — which sets its own colour and drops the underline — keeps its
 * treatment. `.sitefoot a` ties on specificity and is declared later, in each
 * page's own <style>, so it wins there too.
 */
a:not([class]) {
  color: var(--purple);
  text-decoration: underline;
  text-underline-offset: 2px;
}

/**
 * THE TOP NAV ON A PHONE.
 *
 * index.html carried `nav ul{display:none}` at the 900px breakpoint, so on a
 * phone the landing page's whole link list was simply gone — which is why the
 * Account door was moved OUT of that list into the action group beside it
 * rather than fixed where it stood. The other navs never hid anything; they are
 * one non-wrapping flex row, so a 360px screen clips the tail off instead. Two
 * shapes, one outcome: links a phone cannot reach.
 *
 * NO JAVASCRIPT ANYWHERE IN IT. The disclosure is a checkbox and its <label>,
 * and the open state is `.navtoggle:checked ~ .navlinks`. Nothing here loads, so
 * nothing here can fail to load — a nav built on a script is a nav that
 * disappears when the script 404s, and a nav that vanishes is worse than a nav
 * that never collapsed. The checkbox is clipped rather than `display:none` so it
 * keeps its place in the tab order and Space still opens the list.
 *
 * ACCOUNT IS NOT IN THE ACCORDION. `.navpersist` sits outside the list and is
 * visible at every width in both the open and the closed state — the same
 * reasoning that put it in the landing page's action group, and the thing
 * lib/__tests__/signIn.test.ts is really protecting: the sign-in door has to be
 * on the first page a stranger sees, at every width, without a tap first.
 *
 * The rules below are on the new classes only. Each page keeps its own nav
 * colours and padding; this file owns the collapse and nothing else.
 */
nav .wrap {
  position: relative;
  flex-wrap: wrap;
}

.navlinks {
  display: flex;
  align-items: center;
  gap: 20px;
}

/* Clipped, not removed: still focusable, still toggled by Space. */
.navtoggle {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  border: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.navtoggle-label {
  display: none; /* the desktop row needs no disclosure */
  align-items: center;
  min-height: 40px;
  padding: 8px 14px;
  border: 1px solid var(--line);
  border-radius: 10px;
  font-size: 14px;
  line-height: 1;
  color: var(--body);
  cursor: pointer;
  user-select: none;
}

.navtoggle-label::after {
  content: ' \25BE';
}

.navtoggle:checked + .navtoggle-label::after {
  content: ' \25B4';
}

/* The checkbox is invisible, so the label has to show the focus. */
.navtoggle:focus-visible + .navtoggle-label {
  outline: 2px solid var(--purple);
  outline-offset: 2px;
}

@media (min-width: 901px) {
  /* Source order is brand, toggle, list, persistent — the visual order the
     desktop row already had is brand, list, persistent. */
  .navlinks {
    order: 1;
  }

  .navpersist {
    order: 2;
  }
}

@media (max-width: 900px) {
  nav .wrap {
    row-gap: 14px;
  }

  .navtoggle-label {
    display: inline-flex;
  }

  .navpersist {
    order: 2;
  }

  /* `flex-basis:100%` is what drops the list onto its own row instead of
     squeezing it into the one the brand is on. */
  .navlinks {
    order: 3;
    display: none;
    flex-basis: 100%;
    flex-direction: column;
    align-items: flex-start;
    gap: 16px;
    padding-bottom: 6px;
  }

  .navtoggle:checked ~ .navlinks {
    display: flex;
  }
}
