/* One stylesheet. Mobile first; the ledger and sliders get room on a laptop. */
:root {
  /* retopt: navy ink and the mark's green. The brand green is 2.5:1 on white, so it is
     for fills, strokes and the primary button (with navy text, 7.2:1); anything that is
     TEXT on a light ground reads the darker --accent / --good instead. */
  --navy: #0B1526; --brand: #1DB97A; --brand-dim: #17a56c; --tint: #e6f7ef;
  --ink: var(--navy); --soft: #56657a; --line: #dde3e8; --bg: #f5f7f8; --card: #fff;
  --good: #0c6e4a; --warm: #b25b17; --stop: #9c2b1e; --accent: #0e7a52;
  --sans: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", sans-serif;
  /* one per account box, in the order `views.ACCOUNT_SERIES` lists them */
  --s0: #0e7a52; --s1: #2f6d9e; --s2: #b25b17; --s3: #6c5b8c;
  /* four more for the strategy comparison, which can draw eight lines where the
     account chart draws four. Same hue spacing, held to the same weight so no line
     reads as more important than another. */
  --s4: #8a7a1e; --s5: #1f6f6b; --s6: #9c3b6e; --s7: #4a5a7d;
  /* An entry box: its fill, and the dashed edge it wears until it is the one being typed
     in. --line is 1.3:1 on white, which is why a box drawn in it read as no box at all;
     --edge is 3.1:1, the WCAG floor for seeing that a control is there, and no darker,
     so a page of thirty fields still reads as light. */
  --field: #fff; --edge: #8494a7;
  --warm-bg: #fdf4ec; --stop-bg: #fdecea;
  --track: #d3dae2;   /* a slider's track past its handle */
  /* the tax curve's dots: the person who filled in the form, and their spouse. Checked
     as a pair for colour-blind separation and 3:1 on the card, in each mode. */
  --dot0: #b25b17; --dot1: #2f6d9e;
  /* the headline's bar: what the usual approach gets, and what optimizing adds */
  --gain-usual: #d4a20a; --gain-more: #1a9e68;
  --radius: 14px;
  color-scheme: light dark;
}
/* Dark, for a reader whose system asks for it. Screen only: paper stays white whatever
   the screen was, so a plan printed from a dark laptop is the same sheet. The brand green
   and the navy on the primary button are the same in both; the ink and the grounds turn
   over, and every text colour here is 4.5:1 or better on the card it sits on. */
@media screen and (prefers-color-scheme: dark) {
  :root {
    --bg: #0b1526; --card: #14213a; --field: #0e192c; --tint: #123a2e;
    --ink: #e8edf3; --soft: #a3b1c2; --line: #2b3b54; --edge: #6a7c94;
    --good: #4fd8a0; --accent: #45d395; --warm: #f0a46b; --stop: #f28b7e;
    --warm-bg: #3a2a17; --stop-bg: #3f1f1c; --track: #33445e;
    --dot0: #c97a42; --dot1: #4a8fc8;
    --gain-usual: #b08c10; --gain-more: #178f5f;
    --s0: #45d395; --s1: #6fb0e6; --s2: #f0a46b; --s3: #b19ee0;
    --s4: #d6c35a; --s5: #4cc6be; --s6: #ea85b8; --s7: #9fb2db;
  }
}
* { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body {
  margin: 0; background: var(--bg); color: var(--ink);
  font: 17px/1.55 var(--sans);
}
main { max-width: 720px; margin: 0 auto; padding: 0 18px 90px; }
body.results main { max-width: 860px; }
h1 { font-size: 1.6rem; line-height: 1.3; font-weight: 700; letter-spacing: -.01em; margin: .3em 0 .6em; }
h2 { font-size: 1.15rem; font-weight: 600; margin: 1.6em 0 .5em; }
h3 { font-size: 1rem; font-weight: 600; margin: 0 0 .6em; color: var(--soft); }
p { margin: .5em 0; }
a { color: var(--accent); }
[hidden] { display: none !important; }
.field em { font-style: normal; display: block; color: var(--soft); font-size: .82rem; margin-top: .25em; }

.top {
  display: flex; justify-content: space-between; align-items: center; gap: 12px;
  max-width: 860px; margin: 0 auto; padding: 18px;
}
.brand { display: inline-flex; align-items: center; gap: 12px; text-decoration: none; color: var(--ink); }
.brand img { display: block; height: 26px; width: auto; }
/* the wordmark's navy half is the page's ink, so a dark page shows the copy whose half
   is the dark page's ink (`views.BRAND`) */
.brand img.dark { display: none; }
@media screen and (prefers-color-scheme: dark) {
  .brand img.light { display: none; }
  .brand img.dark { display: block; }
}
.brand .tagline { font-size: .8rem; color: var(--soft); padding-left: 12px; border-left: 1px solid var(--line); }
@media (max-width: 480px) { .brand .tagline { display: none; } }
.where { color: var(--soft); font-size: .8rem; }
.steps { color: var(--soft); font-size: .8rem; letter-spacing: .08em; text-transform: uppercase; margin: 0; }
.sub { color: var(--soft); font-size: .92rem; }
.lede { font-size: 1.25rem; line-height: 1.4; }

.card { background: var(--card); border: 1px solid var(--line); border-radius: var(--radius); padding: 18px; margin: 14px 0; }
.card.big { text-align: center; }
.people { display: grid; gap: 14px; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); }
.two { display: grid; gap: 14px; grid-template-columns: 1fr 1fr; }

.field { display: block; margin: 0 0 18px; }
.field em.lead { margin: -1px 0 7px; }
.field > span { display: block; font-size: .92rem; margin-bottom: 5px; }
/* Every box waiting for an answer has a light dashed edge, so a reader can see at a
   glance what there is to fill in; the one they are in has a solid ink edge, its border
   and a 1px outline together, which needs no width change and so moves nothing. */
input[type=text], input[type=number], input[type=email], select {
  width: 100%; padding: 11px 12px; font: inherit; font-family: ui-sans-serif, system-ui, sans-serif;
  border: 1px dashed var(--edge); border-radius: 10px; background: var(--field); color: var(--ink);
}
input:focus, select:focus { outline: 2px solid var(--ink); outline-offset: 1px; }
input[type=text]:focus, input[type=number]:focus, input[type=email]:focus, select:focus {
  border-style: solid; border-color: var(--ink); outline-width: 1px; outline-offset: 0;
}

.chips { display: flex; flex-wrap: wrap; gap: 8px; margin: 4px 0 10px; }
.chip {
  display: inline-flex; align-items: center; gap: 6px; padding: 7px 13px; border-radius: 999px;
  border: 1px dashed var(--edge); background: var(--card); color: var(--ink); font-size: .88rem;
  cursor: pointer; font-family: ui-sans-serif, system-ui, sans-serif;
}
/* the radio stays in the accessibility tree and keyboard-reachable; only its box is hidden */
.chip input { position: absolute; opacity: 0; width: 1px; height: 1px; margin: 0; }
.chip:focus-within { outline: 2px solid var(--ink); outline-offset: 2px; }
/* a chip is an answer on offer, dashed like a box; the one chosen is solid, and a static
   chip only states an assumption, so it takes no dash. */
.chip.on { border-style: solid; border-color: var(--accent); background: var(--tint); color: var(--good); font-weight: 600; }
.chip.static { cursor: default; color: var(--soft); border: 1px solid var(--line); }

.actions { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; margin: 20px 0; }
/* a button and the note that explains it sit side by side, a gap between them */
.actions form, .actions .pdf, .actions .saved { display: inline-flex; flex-wrap: wrap; align-items: center; gap: 6px 12px; margin: 0; }
/* A button has a solid, darker edge and a slight lift, so it reads as something to press
   and never as one of the answer chips beside it, which are dashed until picked. Its edge
   was --line, 1.3:1, the same faint pill as a chip. */
button, .ghost {
  font: inherit; font-family: ui-sans-serif, system-ui, sans-serif; font-size: .95rem; font-weight: 500;
  padding: 11px 18px; border-radius: 999px; border: 1px solid var(--soft);
  background: var(--card); color: var(--ink); cursor: pointer; text-decoration: none; display: inline-block;
  box-shadow: 0 1px 2px rgba(11, 21, 38, .14);
}
button:focus-visible, .ghost:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }
button.primary, a.ghost.primary { background: var(--brand); border-color: var(--brand); color: var(--navy); font-weight: 600; }
button.primary:hover, a.ghost.primary:hover { background: var(--brand-dim); border-color: var(--brand-dim); }
/* The track page: the four ways to use it, in one row, so that they read as one choice
   of four rather than as a page of cards. In the 720px column they wrapped two to a row,
   and a reader could not tell how many there were. So this page alone is wide
   (`body.wide`), its prose kept to the column it reads in. Five across were cut off in a
   browser, so the advisor's tier is "(For Advisors)" beside the line above them. */
body.wide main, body.wide .top { max-width: 1200px; }
body.wide main > section > h1, body.wide main > section > p { max-width: 720px; }
.pick-row { position: relative; display: flex; flex-wrap: wrap; align-items: baseline;
  column-gap: 8px; margin: 26px 0 12px; }
h2.pick { font-size: 1.15rem; margin: 0; }
details.advisors > summary { cursor: pointer; list-style: none; color: var(--accent); font-weight: 600;
  font-size: 1.15rem; padding: 6px 0; }
details.advisors > summary::-webkit-details-marker { display: none; }
details.advisors > summary:hover { text-decoration: underline; }
/* Open, it lies over the cards under the line rather than pushing them down, and is
   anchored to the row, not the link, so that on a phone, where the link wraps under the
   heading, it still fits across the screen. */
details.advisors > .card { position: absolute; z-index: 5; top: 100%; left: 0; margin: 4px 0 0;
  width: min(480px, 100%); box-shadow: 0 8px 28px rgba(11, 21, 38, .35); }
details.advisors > .card > p { margin: 0 0 8px; font-weight: 600; }
details.advisors > .card > ul { padding-left: 1.2em; margin: 0 0 12px; font-size: .92rem; }
details.advisors > .card > .ghost { display: block; text-align: center; }
details.advisors > .card > p.sub { margin: 10px 0 0; text-align: center; }
.track-cards { display: grid; gap: 12px; }
.track-cards .card.track { margin: 0; display: flex; flex-direction: column; gap: 10px; }
.card.track > * { margin: 0; }
/* The card that is best value: edged in the brand's green, under a label drawn over its
   top edge, out of the flow so that the card keeps its neighbours' rows. */
.card.track.best { position: relative; border-color: var(--brand); box-shadow: 0 0 0 1px var(--brand); }
.card.track .badge { position: absolute; top: 0; left: 18px; transform: translateY(-50%);
  padding: 2px 10px; border-radius: 999px; background: var(--brand); color: var(--navy);
  font-size: .72rem; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; }
.card.track h2 { font-size: 1.1rem; }
.card.track .price p { margin: 0 0 4px; font-size: .88rem; color: var(--soft); }
.card.track .price .now { font-size: 1.05rem; font-weight: 600; color: var(--ink); }
.card.track .price .plans { color: var(--ink); font-weight: 600; }
.card.track .act .ghost { display: block; text-align: center; }
/* Where a button will be: the same pill, drawn as one that cannot be pressed. */
.card.track .soon, details.advisors .soon { display: block; text-align: center; padding: 10px 18px; border-radius: 999px;
  border: 1px dashed var(--edge); color: var(--soft); font-size: .92rem; }
.card.track ul { padding: 12px 0 0 1.2em; border-top: 1px solid var(--line); font-size: .92rem; }
.card.track li { margin: 0 0 6px; }
/* A tablet: one card to a row, what it costs and the button on the left, what it gives
   you on the right. */
@media (min-width: 640px) and (max-width: 1039px) {
  .track-cards .card.track { display: grid; column-gap: 24px; row-gap: 8px;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.3fr); grid-template-rows: auto auto 1fr auto; }
  .card.track > ul { grid-column: 2; grid-row: 1 / -1; border-top: 0; padding-top: 0;
    border-left: 1px solid var(--line); padding-left: calc(24px + 1.2em); margin-left: 0; }
  .card.track > :not(ul, .badge) { grid-column: 1; }
}
/* A laptop: all four across. Each card is the same five rows as its neighbours (a
   subgrid), so its name, its price, its button and what it gives you sit level with
   theirs and the row can be read across. */
@media (min-width: 1040px) {
  .track-cards { grid-template-columns: repeat(4, minmax(0, 1fr));
    grid-template-rows: auto auto auto auto 1fr; }
  .card.track ul { padding-left: 1.1em; }
  @supports (grid-template-rows: subgrid) {
    .track-cards .card.track { display: grid; grid-row: span 5; grid-template-rows: subgrid; row-gap: 10px; }
  }
}
/* On a phone or a tablet, with a script, the four fold to a name and a line each, so all
   four are on about one screen (`app.js`, UX.md decision 54). Folded, the whole card is
   the button that opens it; open, the button is the arrow in its corner. The "Best
   value" label stays on the folded card. */
.track-cards .fold { display: none; }
.fold-hint { margin: -6px 0 12px; }
@media (max-width: 1039px) {
  .track-cards.folding .card.track { position: relative; padding: 14px 64px 14px 18px; }
  .track-cards.folding .card.track:not(.open) { display: flex; gap: 4px; }
  .track-cards.folding .card.track:not(.open) > :not(h2, .sub, .fold, .badge) { display: none; }
  .track-cards.folding .fold {
    display: flex; align-items: center; justify-content: center; position: absolute;
    top: 8px; right: 8px; width: 48px; height: 48px; padding: 0; border: 0; border-radius: 50%;
    background: transparent; box-shadow: none; color: var(--accent); }
  .track-cards.folding .card.track:not(.open) .fold {
    inset: -1px; width: auto; height: auto; justify-content: flex-end; padding-right: 26px;
    border: 1px solid transparent; border-radius: var(--radius); }
  .track-cards.folding .fold:hover { border-color: var(--accent); box-shadow: none; }
  .track-cards.folding .fold::before {
    content: ""; width: 10px; height: 10px; border: solid currentColor; border-width: 0 2.5px 2.5px 0;
    transform: translateY(-3px) rotate(45deg); }
  .track-cards.folding .open .fold::before { transform: translateY(3px) rotate(-135deg); }
}
/* Signing in and the account page (docs/plans/ACCOUNTS.md §5), and the advisor's form
   for a price. */
form.narrow, section.narrow { max-width: 480px; }
fieldset.clients { border: 0; padding: 0; margin: 0; }
fieldset.clients legend { font-weight: 600; padding: 0; margin: 0 0 10px; }
/* The box only a script fills in (`app.custom_pricing_sent`): off the page, not hidden,
   since a script that skips hidden boxes is the one it is for. */
.trap { position: absolute; left: -10000px; width: 1px; height: 1px; overflow: hidden; }
ul.kept { padding-left: 1.2em; margin: 0; }
ul.kept li { margin: 0 0 6px; }
form.danger { margin-top: 18px; border-top: 1px solid var(--line); padding-top: 14px; }
button.small { padding: 6px 12px; font-size: .82rem; }
/* A child's age and the button that removes the child, on one line; the button that
   adds one sits under the last. */
.kid { display: flex; gap: 8px; align-items: center; margin: 0 0 8px; }
.kid select { flex: 1; min-width: 0; }
.kid button { flex: none; min-width: 44px; min-height: 44px; font-size: 1.1rem; }
button:hover, .ghost:hover { border-color: var(--accent); box-shadow: 0 2px 6px rgba(11, 21, 38, .18); }

.answer { border-top: 1px solid var(--line); padding-top: 14px; margin-top: 8px; }

/* --- step 1, a page at a time (UX.md decision 37) ------------------------------
   Each page is a fieldset so the script can switch an unticked one off whole; none of
   the browser's fieldset frame is wanted, and its default minimum width (as wide as its
   widest content) would push the two people's cards out of their grid on a phone. */
fieldset.page { border: 0; padding: 0; margin: 0; min-width: 0; }
fieldset.card { min-width: 0; }
/* The screen's questions that follow another answer (`views.screen_page`): a fieldset, so
   the script can switch one off whole and it posts nothing, with none of its frame. */
fieldset.ask { border: 0; padding: 0; margin: 0; min-width: 0; }
fieldset.page > h2 { margin-top: .5em; }
/* Focus is moved to a new page's heading so a screen reader starts reading there; it is
   not something to type in, so it draws no ring. */
h1[tabindex="-1"]:focus, h2[tabindex="-1"]:focus { outline: none; }
/* The checklist. A real checkbox, larger than the browser's, on a row the whole of which
   is the target; dashed like every answer on offer and solid once ticked, as a chip is. */
.ticks { display: grid; gap: 8px; margin-top: 4px; }
label.tick { display: flex; align-items: center; gap: 12px; padding: 12px 14px; cursor: pointer;
  border: 1px dashed var(--edge); border-radius: 10px; background: var(--card); font-size: .95rem; }
label.tick input { width: 1.25em; height: 1.25em; margin: 0; flex: none; accent-color: var(--accent); }
label.tick.on { border-style: solid; border-color: var(--accent); background: var(--tint); color: var(--good); font-weight: 600; }
label.tick:focus-within { outline: 2px solid var(--ink); outline-offset: 2px; }
/* With each explanation folded behind its "?" (decision 38) the questions sat close
   enough to read as one block, so on the questionnaire's pages each gets more room. The
   results page keeps its own density. */
body.step .field { margin-bottom: 30px; }
/* The "?" beside a question, and the explanation it opens beneath it (`app.js`). 24px
   across, the smallest target WCAG asks a tap to be given; the explanation opens as a
   bubble edged in the brand's green, so it reads as belonging to the question above. */
.tipbtn { display: inline-flex; align-items: center; justify-content: center; width: 24px; height: 24px;
  margin-left: 6px; vertical-align: middle; border: 1px solid var(--edge); border-radius: 50%;
  color: var(--soft); font: 600 .78rem var(--sans); cursor: pointer; user-select: none; }
.tipbtn:hover, .tipbtn[aria-expanded="true"] { border-color: var(--accent); color: var(--good); background: var(--tint); }
.tipbtn:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }
.field em.tip { margin: 2px 0 8px; padding: 8px 11px; background: var(--card); border: 1px solid var(--line);
  border-left: 3px solid var(--accent); border-radius: 8px; color: var(--ink); line-height: 1.45; }
/* Where you are: the pages your ticks made, the current one marked. Quieter than a
   button, because it is a map first and a way back second. */
.pagelist { list-style: none; display: flex; flex-wrap: wrap; gap: 6px; padding: 0; margin: 8px 0 2px; }
.pagelist button { padding: 4px 11px; font-size: .8rem; font-weight: 400; box-shadow: none;
  border-color: var(--line); color: var(--soft); }
.pagelist button[aria-current=step] { border-color: var(--accent); background: var(--tint);
  color: var(--good); font-weight: 600; }
.warnrow { background: var(--warm-bg); border-left: 3px solid var(--warm); padding: 10px 14px; border-radius: 0 8px 8px 0; }
.gate { border-radius: 10px; padding: 14px 16px; margin: 12px 0; }
.gate.block { background: var(--stop-bg); border-left: 4px solid var(--stop); }
.gate.warn { background: var(--warm-bg); border-left: 4px solid var(--warm); }
.gate p { margin: .3em 0 0; font-size: .92rem; }
.gate ol { margin: .5em 0 0; padding-left: 1.4em; font-size: .92rem; }
.gate li { margin: .45em 0; padding-left: .2em; }
.gate li::marker { font-weight: 600; color: var(--warm); }
/* The warnings and the caveats fold away until clicked (UX.md 51, 52); the heading is
   what is clicked, so it looks like it, with the browser's own triangle beside it. */
details.gate > summary, details.limits > summary { cursor: pointer; }
details.limits > summary h2 { display: inline; }
details.gate[open] > summary, details.limits[open] > summary { margin-bottom: .2em; }

/* the wait */
.baseline-num { font-size: 1.5rem; color: var(--soft); margin: 0; }
.baseline-num.small { font-size: 1.25rem; color: var(--ink); }
.best-num { font-size: 2.6rem; font-weight: 600; margin: 2px 0; letter-spacing: -.02em; }
.best-num.up { animation: pop .5s ease; }
@keyframes pop { 0% { transform: scale(1); color: var(--good); } 40% { transform: scale(1.06); color: var(--good); } 100% { transform: scale(1); } }
/* a figure the page is still working out (views.PENDING); app.js fills it in and drops the attribute */
[aria-busy="true"] { color: var(--soft); font-weight: 400; animation: breathe 1.6s ease-in-out infinite; }
@keyframes breathe { 50% { opacity: .35; } }
@media (prefers-reduced-motion: reduce) { [aria-busy="true"] { animation: none; } }
.delta { color: var(--good); min-height: 1.5em; margin: 0 0 12px; font-size: .95rem; }
.history { list-style: none; padding: 0; margin: 6px 0 10px; font-size: .9rem; color: var(--good);
  font-family: ui-sans-serif, system-ui, sans-serif; }
.history li { padding: 2px 0; animation: fade .5s ease; }
.narrate { list-style: none; padding: 0; margin: 18px 0; text-align: center; color: var(--soft); min-height: 3em; }
.narrate li { display: none; }
.narrate li.on { display: block; animation: fade .6s ease; }
@keyframes fade { from { opacity: 0; } to { opacity: 1; } }

/* results */
.rung { background: var(--card); border: 1px solid var(--line); border-radius: var(--radius); padding: 20px; margin: 16px 0; }
.rung.one h1 { font-size: 1.45rem; }
.decisions { list-style: none; padding: 0; margin: 14px 0; }
.decisions li { padding: 10px 0; border-top: 1px solid var(--line); }
/* The headline's comparison drawn (`views.gain_bar`): yellow as far as the usual approach
   reaches, green for what optimizing adds, a 2px gap between them, and both figures
   written beside it, so the pair is never told apart by colour alone. */
.gain { margin: 4px 0 14px; font-family: ui-sans-serif, system-ui, sans-serif; }
.gaintop { text-align: right; margin: 0 0 4px; font-size: .92rem; }
.gainbar { display: flex; gap: 2px; height: 18px; }
.gainbar span { display: block; height: 100%; }
.gainbar .usual { background: var(--gain-usual); border-radius: 4px 0 0 4px; }
.gainbar .more { background: var(--gain-more); border-radius: 0 4px 4px 0; }
.gainkey { list-style: none; padding: 0; margin: 8px 0 0; display: flex; flex-wrap: wrap;
  justify-content: space-between; gap: 4px 16px; font-size: .92rem; }
.gainkey li { display: inline-flex; align-items: center; gap: 7px; }
.gainkey i { width: 12px; height: 12px; border-radius: 3px; }
.gainkey .usual i { background: var(--gain-usual); }
.gainkey .more i { background: var(--gain-more); }
@media print { .gainbar span, .gainkey i { -webkit-print-color-adjust: exact; print-color-adjust: exact; } }
.saved code { font-family: ui-monospace, monospace; font-size: .78rem; word-break: break-all; }
/* inside "Change it, or keep it" now, which is a card of its own */
.rung.keep .assumptions { padding: 0; }
.rung.keep .actions { margin-bottom: 0; }
.replanrow { display: flex; gap: 10px; align-items: center; margin: 14px 0 4px; }
button.replan { font-size: 1rem; padding: 12px 22px; }
/* dormant until a chip changes: still drawn as a button, just plainly not pressable yet */
button.replan:disabled { background: transparent; color: var(--soft); border-color: var(--edge);
  font-weight: 400; cursor: default; box-shadow: none; }
.chip.changed { border-color: var(--warm); color: var(--warm); background: var(--warm-bg); }
@media (max-width: 600px) {
  .replanrow { flex-direction: column; align-items: stretch; }
  button.replan { width: 100%; }
}
.assumptions .lab { font-size: .8rem; color: var(--soft); text-transform: uppercase; letter-spacing: .08em; }
.cards { display: grid; gap: 12px; }
@media (min-width: 700px) { .cards { grid-template-columns: 1fr 1fr; } }
.dcard { border: 1px solid var(--line); border-radius: 10px; padding: 14px; }
.dcard h3 { color: var(--ink); }
.dcard .cost { font-size: 1.3rem; font-weight: 600; color: var(--good); }

.slider { margin: 18px 0; }
.slider label { display: block; font-size: .92rem; margin-bottom: 6px; }
/* A slider has to look like one. The browser's own read as a progress bar — Safari
   ignores `accent-color` on a range, so it was a grey bar with a small white knob — and
   people did not know they could drag it. So: a large handle in the brand green with
   arrows on it saying which way it moves, a track filled up to the handle (`--fill`, set
   by app.js as it draws), a hand cursor, and the two ends written under it. */
input[type=range] {
  -webkit-appearance: none; appearance: none; width: 100%; height: 30px; margin: 0;
  background: transparent; cursor: grab; --fill: 50%;
}
input[type=range]:active { cursor: grabbing; }
input[type=range]::-webkit-slider-runnable-track {
  height: 8px; border-radius: 999px;
  background: linear-gradient(to right, var(--accent) var(--fill), var(--track) var(--fill));
}
input[type=range]::-moz-range-track { height: 8px; border-radius: 999px; background: var(--track); }
input[type=range]::-moz-range-progress { height: 8px; border-radius: 999px; background: var(--accent); }
input[type=range]::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none; box-sizing: border-box;
  width: 30px; height: 30px; margin-top: -11px; border-radius: 50%;
  border: 3px solid var(--card); background: var(--brand) var(--grip) center / 16px no-repeat;
  box-shadow: 0 0 0 1px var(--accent), 0 2px 6px rgba(0, 0, 0, .3); transition: transform .12s ease;
}
input[type=range]::-moz-range-thumb {
  box-sizing: border-box; width: 30px; height: 30px; border-radius: 50%;
  border: 3px solid var(--card); background: var(--brand) var(--grip) center / 16px no-repeat;
  box-shadow: 0 0 0 1px var(--accent), 0 2px 6px rgba(0, 0, 0, .3); transition: transform .12s ease;
}
/* navy arrows on the green, 7.2:1, the pair the primary button already uses */
input[type=range] {
  --grip: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%230B1526' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 4 2 8l4 4M10 4l4 4-4 4'/%3E%3C/svg%3E");
}
input[type=range]:hover::-webkit-slider-thumb, input[type=range]:active::-webkit-slider-thumb { transform: scale(1.12); }
input[type=range]:hover::-moz-range-thumb, input[type=range]:active::-moz-range-thumb { transform: scale(1.12); }
/* the ring goes on the handle, which is the thing that moves, not round the whole row */
input[type=range]:focus { outline: none; }
input[type=range]:focus-visible::-webkit-slider-thumb { box-shadow: 0 0 0 2px var(--card), 0 0 0 4px var(--ink); }
input[type=range]:focus-visible::-moz-range-thumb { box-shadow: 0 0 0 2px var(--card), 0 0 0 4px var(--ink); }
/* High-contrast modes repaint backgrounds, which would leave a track and a handle drawn
   in nothing; the browser's own slider is the one those modes know how to draw. */
@media (forced-colors: active) { input[type=range] { -webkit-appearance: auto; appearance: auto; } }
.slider .ends { display: flex; justify-content: space-between; color: var(--soft);
  font: .8rem ui-sans-serif, system-ui, sans-serif; margin-top: 2px; }
.readout { font-size: 1.2rem; font-weight: 600; }
.band { color: var(--soft); font-size: .85rem; }

.ledgerbox { overflow-x: auto; }
table.ledger { width: 100%; border-collapse: collapse; font-size: .82rem;
  font-family: ui-sans-serif, system-ui, sans-serif; }
table.ledger th { text-align: right; color: var(--soft); font-weight: 500; padding: 6px 8px; white-space: nowrap; }
table.ledger td { text-align: right; padding: 6px 8px; border-top: 1px solid var(--line); white-space: nowrap; }
table.ledger th:first-child, table.ledger td:first-child { text-align: left; }
table.ledger tbody tr:not(.peek) { display: none; }
table.ledger.all tbody tr { display: table-row; }
/* Progressive disclosure by COLUMN. The simple table is totals — out of savings, tax,
   set aside — so a row still adds up on screen; `.detail` puts every part back. Header
   and cell carry the same class, so nothing can slide out of alignment. */
table.ledger th.det, table.ledger td.det { display: none; }
/* `.sub` is sized in rem, so inside a cell it ignored the table's own smaller type and
   an employer match printed larger than the contribution it annotates. */
table.ledger td .sub { font-size: .85em; }
table.ledger.detail th.det, table.ledger.detail td.det { display: table-cell; }
/* The one-pager is the copy a household saves, so on screen as well as on paper it shows
   every year and every column: what it shows is what the PDF holds (UX.md 46). */
body.print table.ledger tbody tr { display: table-row; }
body.print table.ledger th.det, body.print table.ledger td.det { display: table-cell; }
.ledgerctl { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 12px; }

/* the plan's whole life, in numbers a person can hold in their head */
/* 142px, not 150: a retired household has five of these and 150 fits four across the
   860px column, which leaves the fifth alone on a row of its own. */
.tiles { display: grid; gap: 10px; margin: 12px 0 18px;
  grid-template-columns: repeat(auto-fit, minmax(142px, 1fr)); }
.tile { background: var(--card); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 12px 14px; }
.tile .tv { display: block; font-size: 1.25rem; font-weight: 600; line-height: 1.2; }
.tile .tl { display: block; color: var(--soft); font-size: .84rem; margin-top: 3px;
  font-family: ui-sans-serif, system-ui, sans-serif; }

/* one line per account, and a legend that takes any of them off the chart */
.accts { margin: 6px 0 18px; }
.chart.accounts { background: var(--card); border: 1px solid var(--line);
  border-radius: var(--radius); }
.chart .acct { fill: none; stroke-width: 2; stroke-linejoin: round; }
.chart .acct.s0 { stroke: var(--s0); } .chart .acct.s1 { stroke: var(--s1); }
.chart .acct.s2 { stroke: var(--s2); } .chart .acct.s3 { stroke: var(--s3); }
.chart .acct.s4 { stroke: var(--s4); } .chart .acct.s5 { stroke: var(--s5); }
.chart .acct.s6 { stroke: var(--s6); } .chart .acct.s7 { stroke: var(--s7); }
/* The strategy the page is showing below is drawn heavier: the table says which row
   the ledger belongs to, and the chart should agree without a second legend. */
.chart .acct.pick { stroke-width: 3.5; }
.chart .acct.off { display: none; }
.keys { display: flex; flex-wrap: wrap; gap: 8px; margin: 6px 0 4px; }
.keys .key { display: inline-flex; align-items: center; gap: 7px; padding: 5px 11px;
  border-radius: 999px; border: 1px solid var(--line); background: var(--card); color: var(--ink);
  font-size: .84rem; cursor: pointer; }
.keys .key .swatch { width: 10px; height: 10px; border-radius: 2px; }
.keys .key.s0 .swatch { background: var(--s0); } .keys .key.s1 .swatch { background: var(--s1); }
.keys .key.s2 .swatch { background: var(--s2); } .keys .key.s3 .swatch { background: var(--s3); }
.keys .key.s4 .swatch { background: var(--s4); } .keys .key.s5 .swatch { background: var(--s5); }
.keys .key.s6 .swatch { background: var(--s6); } .keys .key.s7 .swatch { background: var(--s7); }
.keys .key .kv { color: var(--soft); }
.keys .key.off { opacity: .45; }
.keys .key.off .swatch { background: var(--line); }
/* The grid's legend names the lines and takes none of them off — the sliders read a
   fixed set of series and hiding one would leave a slider reading a line nobody can
   see. Flat, so it does not offer a click that does nothing. */
.keys.flat .key { cursor: default; }

svg.chart { width: 100%; height: auto; display: block; margin: 10px 0; }
.chart .curve { fill: none; stroke: var(--brand); stroke-width: 2.2; }
.chart .ax { fill: var(--soft); font: 11px ui-sans-serif, system-ui, sans-serif; }
.chart .mid { text-anchor: middle; }
.chart .end { text-anchor: end; }
/* Only the plan's own years take a pointer; everything else is decoration. */
.chart .zone, .chart .rule, .chart .curve, .chart .lead, .chart .pin,
.chart text, .chart .folk { pointer-events: none; }
.chart .dotg { pointer-events: all; cursor: pointer; }
.chart .hit { fill: transparent; }
/* a ring of the card's colour round each dot, so two that overlap stay two */
.chart .dot { fill: var(--dot0); stroke: var(--card); stroke-width: 1.5; }
.chart .dot.d1 { fill: var(--dot1); }
.chart .dotg:hover .dot { fill: var(--stop); r: 6.5; }
.chart .folk { fill: none; stroke: var(--soft); stroke-width: 1.4; stroke-dasharray: 2.5 2.5; opacity: .8; }
.foot .key { display: inline-block; width: 10px; height: 10px; border-radius: 50%; vertical-align: -1px; }
.foot .key.dot { background: var(--dot0); }
.foot .key.dot.d1 { background: var(--dot1); border-radius: 1px; transform: rotate(45deg) scale(.9); }
.foot .key.folk { border: 1.4px dashed var(--soft); }
#tip { position: absolute; z-index: 20; pointer-events: none; background: var(--ink); color: var(--card);
  font: 12px ui-sans-serif, system-ui, sans-serif; padding: 6px 10px; border-radius: 8px;
  transform: translate(-50%, -100%) translateY(-10px); width: max-content;
  max-width: calc(100vw - 16px); white-space: pre-line; }
.chart .rule { stroke: var(--line); stroke-width: 1; }
.chart .lead, .chart .markline { stroke: var(--soft); stroke-width: 1; stroke-dasharray: 3 3; opacity: .7; }
.chart .markline { stroke: var(--warm); opacity: .9; }
.chart .ax.strong { fill: var(--ink); font-weight: 600; }
.chart .ax.tiny { font-size: 9px; fill: var(--warm); }
/* A band's shading is on until its bar above the chart is clicked; pointing at the bar
   outlines the band, and shows it while the pointer stays if it was off. */
.chart .zone { display: none; }
.chart .zone.on, .chart .zone.peek { display: inline; }
.chart .zone.peek { stroke: var(--ink); stroke-width: 1.5; stroke-dasharray: 4 3; }
/* `views.svg_metr`: each band is told by its pattern, the flagged one by the warning
   colour; the patterns are drawn in the soft ink so they sit behind the curve */
.chart .hatch { stroke: var(--soft); stroke-width: 1.2; opacity: .42; }
.chart .hatchdot { fill: var(--soft); opacity: .55; }
.chart .zone.z0, .stripbar.z0 { fill: url(#metr-h0); }
.chart .zone.z1, .stripbar.z1 { fill: url(#metr-h1); }
.chart .zone.z2, .stripbar.z2 { fill: url(#metr-h2); }
.chart .zone.zf { fill: var(--warm); fill-opacity: .12; }
.stripbar { stroke: var(--soft); stroke-width: 1; }
.stripbar.zf { fill: var(--warm); fill-opacity: .4; stroke: var(--warm); }
.chart .bandlabel { font: 12px ui-sans-serif, system-ui, sans-serif; fill: var(--soft); }
/* each band is a line from the income where it starts to where it ends, with a tick at
   each end; it is a button, and the band it shades is the one in the plot below */
.chart .strip { cursor: pointer; pointer-events: all; outline: none; }
.chart .striphit { fill: transparent; }
/* a hidden band's bar stays, faded and dashed, so it can be brought back */
.chart .strip[aria-pressed="false"] .stripbar { opacity: .35; stroke-dasharray: 3 3; }
.chart .strip[aria-pressed="false"] .bandlabel { opacity: .6; }
.chart .strip:hover .stripbar, .chart .strip:focus-visible .stripbar { stroke: var(--ink); stroke-width: 1.5; }
.chart .strip:focus-visible .bandlabel { fill: var(--ink); }
.chart .callout { font: 600 12px ui-sans-serif, system-ui, sans-serif; fill: var(--ink); }
.chart .pin { fill: none; stroke: var(--ink); stroke-width: 1.6; }   /* not a plan dot */
.bandkey { display: none; list-style: none; padding: 0; margin: 4px 0 0;
  font: 12px ui-sans-serif, system-ui, sans-serif; color: var(--soft); }
.bandkey li { display: flex; align-items: center; gap: 8px; padding: 4px 0; cursor: pointer; }
.bandkey li[aria-pressed="false"] { opacity: .55; text-decoration: line-through; }
/* the key's swatch is the bar it names, in the same pattern */
.bandkey .sw { width: 18px; height: 10px; flex: none; }
.foot { font: 11px ui-sans-serif, system-ui, sans-serif; color: var(--soft); margin: 6px 0 0; }
@media (max-width: 600px) {
  .chart .bandlabel { display: none; }
  .bandkey { display: block; }
}
.lede.small { font-size: 1.05rem; margin-top: 4px; }
.chart .col { fill: var(--brand); opacity: .85; transform-origin: bottom; animation: grow .5s ease backwards; }
@keyframes grow { from { transform: scaleY(0); } to { transform: scaleY(1); } }
.chart .gapband { fill: var(--accent); opacity: .16; }
.chart .marker { stroke: var(--warm); stroke-width: 2; }

.limits { margin: 26px 0; color: var(--soft); font-size: .9rem; }
.limits h2 { font-size: .82rem; text-transform: uppercase; letter-spacing: .08em; }
.limits ul { padding-left: 1.1em; margin: 0; }
.limits li { margin: .35em 0; }

/* --- Ask about your plan (docs/plans/ASK.md §10, UX.md decision 55) -----------------
   A button fixed at the bottom right, and a panel above it that is not modal, so the
   ledger can be read beside an answer. The page gets room at its foot the height of the
   button, so the last line and "Change it, or keep it" are never under it. On a phone the
   panel is the whole screen, with a close button, rather than part of something. */
.sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0);
  white-space: nowrap; }
body.asking main { padding-bottom: 150px; }
.askbtn { position: fixed; right: 16px; bottom: 16px; z-index: 30;
  background: var(--brand); border-color: var(--navy); color: var(--navy); font-weight: 600;
  box-shadow: 0 2px 8px rgba(11, 21, 38, .28); }
.askbtn:hover { background: var(--brand-dim); }
.askbtn:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }
.askpanel { position: fixed; right: 16px; bottom: 76px; z-index: 31; width: 380px;
  max-height: 70vh; display: flex; flex-direction: column; background: var(--card);
  color: var(--ink); border: 1px solid var(--edge); border-radius: var(--radius);
  box-shadow: 0 6px 24px rgba(11, 21, 38, .25); }
.askpanel[hidden] { display: none; }
.askhead { display: flex; justify-content: space-between; align-items: center; gap: 8px;
  padding: 12px 14px 6px; }
.askhead h2 { margin: 0; font-size: 1.05rem; }
.askbody { padding: 0 14px; overflow-y: auto; flex: 1 1 auto; font-size: .92rem; }
.askbody p { margin: .45em 0; }
.askagree { font-weight: 600; font-size: .86rem; margin: 0 0 4px; width: 100%; }
.asklog { display: flex; flex-direction: column; gap: 10px; margin: 8px 0; }
.askturn { border-top: 1px solid var(--line); padding-top: 8px; }
.askq { font-weight: 600; white-space: pre-wrap; }
.aska { white-space: pre-wrap; }
.aska.waiting { color: var(--soft); font-style: italic; }
.asknote { color: var(--warm); font-size: .86rem; }
.asksuggest { display: flex; flex-direction: column; align-items: flex-start; gap: 6px; margin: 6px 0; }
.asksuggest button { text-align: left; white-space: normal; }
.askfoot { display: flex; flex-wrap: wrap; gap: 8px; padding: 10px 14px 14px; border-top: 1px solid var(--line); }
.askfoot textarea { width: 100%; font: inherit; font-size: .95rem; padding: 8px 10px;
  border: 1px solid var(--edge); border-radius: 10px; background: var(--field); color: var(--ink);
  resize: vertical; }
.askfoot textarea:focus-visible { outline: 2px solid var(--ink); outline-offset: 1px; }
.askrow { display: flex; width: 100%; justify-content: space-between; align-items: center; gap: 8px; }
@media (max-width: 600px) {
  .askpanel { inset: 0; width: auto; max-height: none; border-radius: 0; }
  body.askopen .askbtn { display: none; }
}
@media (prefers-reduced-motion: reduce) { .askpanel, .askbtn { transition: none; } }

/* A margin of our own rather than the browser's: with none, a PDF printer puts the
   logo against the edge of the sheet and a desktop printer cuts it off. */
@page { margin: 12mm; }
@page ledger { size: landscape; }
@media print {
  :root { color-scheme: light; }
  body { background: #fff; font-size: 10pt; }
  .actions, button, .slider, input[type=range], #sliders, .assumptions .replanrow,
  #tip, .ledgerctl, .rung.keep h2, .askbtn, .askpanel { display: none !important; }
  body.asking main { padding-bottom: 0; }
  /* one measure for the header and the plan, or the header prints wider than the page
     it heads: `body.results main` caps the plan at 860px and centres it, which on paper
     indents everything but the header. */
  main, body.results main { max-width: none; margin: 0; padding: 0; }
  /* the header stays on paper: a plan handed to an accountant should say whose it is */
  .top { max-width: none; margin: 0 0 14pt; padding: 0 0 8pt; border-bottom: 1px solid var(--line); }
  .brand img { height: 20pt; }
  .rung { border: none; padding: 0; margin: 0 0 14pt; break-inside: auto; }
  .pagebreak { break-before: page; }
  .ledgerbox { overflow: visible; }
  /* Every column on paper is up to twenty of them for a couple, and a portrait page
     clipped the right-hand ones: overflow that scrolls on screen is simply cut off in
     print. So the ledger and its heading get a landscape page of their own, the
     headings wrap instead of setting the width, and the figures stay on one line —
     a number broken across two lines is a number misread. */
  .ledgerwrap { page: ledger; }
  table.ledger { font-size: 7.5pt; width: 100%; }
  table.ledger th { white-space: normal; vertical-align: bottom; padding: .4em .35em; }
  table.ledger td { padding: .2em .35em; line-height: 1.25; }
  /* The type steps down with the column count, which runs from thirteen for a retired
     single to about twenty-eight for an American working couple with every account.
     Measured against landscape Letter: without these, Chrome shrinks the WHOLE plan to
     fit its widest table and Firefox and Safari clip the columns at the margin. */
  table.ledger:has(thead th:nth-child(16)) { font-size: 6.5pt; }
  table.ledger:has(thead th:nth-child(20)) { font-size: 6pt; }
  table.ledger:has(thead th:nth-child(23)) { font-size: 5.5pt; }
  table.ledger:has(thead th:nth-child(26)) { font-size: 5pt; }
  table.ledger:has(thead th:nth-child(28)) { font-size: 4.6pt; }
  table.ledger thead { display: table-header-group; }
  table.ledger tbody tr { display: table-row !important; break-inside: avoid; }
  /* paper is the record: every year AND every column, whatever the screen was showing */
  table.ledger th.det, table.ledger td.det { display: table-cell !important; }
  .tile { break-inside: avoid; }
  /* the account legend is a `button` because it toggles, and on paper it is the KEY —
   without it the chart is four unlabelled lines, so the blanket `button` rule above
   must not reach it. */
  .keys .key { display: inline-flex !important; }
  .accts, .tiles { break-inside: avoid; }
  .chart .col { animation: none; }
  .chart .dotg { pointer-events: none; }
}

/* --- "What you told us" on the printed plan: every input, so a reader can check them */
table.inputs { width: 100%; border-collapse: collapse; font-size: .88rem; margin: 10px 0 18px; }
table.inputs th, table.inputs td { text-align: left; padding: 5px 8px; border-top: 1px solid var(--line);
  vertical-align: top; }
table.inputs th[scope=row] { font-weight: 400; color: var(--soft); width: 55%; }
table.inputs td { font-weight: 600; }
table.inputs thead th { border-top: 0; font-weight: 600; color: var(--ink); }
table.inputs tr { break-inside: avoid; }

/* --- an advisor's clients and their upload (docs/plans/ACCOUNTS.md §5.7) */
table.inputs.clients td { font-weight: 400; }
table.inputs.clients td p { margin: 0 0 4px; }
.card textarea { width: 100%; box-sizing: border-box; font: .85rem/1.4 ui-monospace, monospace;
  padding: 10px; border: 1px solid var(--edge); border-radius: 8px; background: var(--card);
  color: var(--ink); }

/* --- the strategy comparison ------------------------------------------------
   It borrows `table.ledger`'s type and spacing and then undoes the one rule that
   does not belong to it: a ledger shows three preview rows and hides the rest
   behind a button, and a comparison of five strategies with four of them hidden
   is not a comparison. */
table.ledger.strategies tbody tr { display: table-row; }
table.ledger.strategies td, table.ledger.strategies th { vertical-align: top; }
table.ledger.strategies td.lab { text-align: left; white-space: normal; min-width: 15rem; }
table.ledger.strategies td.lab .foot { display: block; font-size: .78rem; line-height: 1.4;
  color: var(--soft); margin-top: 2px; white-space: normal; }
table.ledger.strategies th.act, table.ledger.strategies td.act { text-align: right; }
table.ledger.strategies td.act form { margin: 0; }
table.ledger.strategies td.act button { padding: 4px 10px; font-size: .78rem; }
table.ledger.strategies tr.sel { background: var(--tint); }
table.ledger.strategies tr.best td { font-weight: 600; }
table.ledger.strategies tr.short td { color: var(--soft); }
table.ledger.strategies tr.note td { text-align: left; white-space: normal; border-top: 0;
  padding-top: 0; font-size: .78rem; color: var(--warm); }
table.ledger.strategies .up { color: var(--good); }
table.ledger.strategies .down { color: var(--stop); }
section.compare .actions { margin-top: 14px; }

/* The footer of DEPLOY.md 5.4, on every page — except the one-pager, which already
   carries the sentence of its own and is a sheet somebody hands to someone else, where
   a second copy and two links to a website are noise. */
footer.site { max-width: 62rem; margin: 40px auto 24px; padding: 0 20px;
  font-size: .78rem; color: var(--warm); }
footer.site a { color: inherit; }
footer.site .muted { opacity: .7; }
body.print footer.site { display: none; }
