/* Dev's stylesheet.

   Colour, radius, nav height, the card's geometry and the type tiers are the shared tokens in
   designTokens.css, generated from design/tokens.css. This file may not redeclare them (the
   design check fails if it does), so it contains no neutral colour literal and no card spacing
   number. Light and dark both come from those tokens; there is no second stylesheet.

   The rules this file implements: design/README.md, design/bottomNavBar.md, design/typography.md,
   design/mainPages.md, cardsAndInfographics.md and transactionCards.md. Where this
   file disagrees with them, this file is the bug. What is true of Dev alone is app-dev/DESIGN.md.

   The page was rebuilt on these rules on after Muscle: the document scrolls, the bar
   is the shared component, and every card is the three-box anatomy. Before that it was a 920px
   black page of its own with a bottom bar of its own copy. */

:root {
  --font: var(--font-ui);
  --font-mono: ui-monospace, SFMono-Regular, Menlo, monospace;
  /* Colour that carries meaning, one token per meaning (../DESIGN.md §1a; app-dev/DESIGN.md §2). The fills are Wad's own pastels
     (--asset, --spend-at, --liability); the -text variants are the same meanings where they are words, which the pastel is too pale
     to carry on a light surface. "Is this signal current" and "how full is this plan limit" are different meanings that happen to
     share hues, so they are different tokens and are not merged. */
  --status-ok: #69D3B0;
  --status-warn: #D3B669;
  --status-bad: #D37169;
  --status-unknown: var(--surface-3);
  --status-ok-text: #10B981;
  --status-bad-text: #E34234;
  --limit-ok: var(--ink);
  --limit-near: var(--status-warn);
  --limit-hit: var(--status-bad);
  /* "A tick changed here and is not saved yet": the catalog's own local-edit state, unrelated to health. */
  --pending: #D3B669;
  --pending-wash: rgba(211, 182, 105, .12);
  --page-gutter: 16px;       /* the column's side padding; the bar lines up with it */
  --card-width: 557px;       /* a card's widest, once the page is a grid (900px and up) */
}
:root[data-theme="light"] { --status-ok-text: #0E8F65; --status-bad-text: #C0392B; }

/* WHICH APP MADE A TASK (owner, 2026-11-03: "color code the tasks added by different apps"): one colour per app, the same wherever a task of that app is drawn (Today now; any page that shows tasks later). The names are
   the APPS of shared/tasks/taskModel.mjs. The hues are far from the status colours above (green, amber and red mean health, not an app) and from each other; the light set is darker so a thin glyph holds on a pale card.
   When a second app itself draws tasks these move into design/tokens.css (the standing rule: one unit). */
:root { --app-wad: #69A8D3; --app-muscle: #9BD369; --app-snap: #D38AC0; --app-dev: #A98AD3; }
:root[data-theme="light"] { --app-wad: #3F7FB0; --app-muscle: #5E9A2E; --app-snap: #B0529A; --app-dev: #7C55B8; }

*, *::before, *::after { box-sizing: border-box; }
body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font);
  font-size: var(--type-lead);
  -webkit-font-smoothing: antialiased;
  -webkit-tap-highlight-color: transparent;
}
button, input, select { font: inherit; }
button { cursor: pointer; color: inherit; }
button:disabled { opacity: .35; cursor: default; }
button:focus-visible, a:focus-visible, summary:focus-visible { outline: 2px solid var(--focus); outline-offset: 4px; }
button:active:not(:disabled) { transform: scale(.97); }
[hidden] { display: none !important; }
h1, h2, h3, p { margin: 0; }
a { color: inherit; text-decoration: none; }
svg { display: block; }
code, pre { font-family: var(--font-mono); }
code { font-size: var(--type-label); color: var(--ink); }

/* ----------------------------------------------------------------- the page
   The document scrolls. .app is a plain column: no height, no overflow, not fixed. The content
   column clears the bottom bar with the bar's own height token, never a number. */
.app { max-width: 440px; margin: 0 auto; padding: env(safe-area-inset-top) var(--page-gutter) 0; }          /* the top row's own margin (--top-lead, design/topBar/topBar.css) puts it below the status bar */
#content { padding: 0 0 calc(var(--bottom-nav-safe-h) + 8px); }
/* The strip under the status bar, so scrolled content does not show through the clock. */
body::before {
  content: "";
  position: fixed;
  top: 0; left: 0; right: 0;
  height: env(safe-area-inset-top);
  background: var(--bg);
  z-index: 3;
}
#shell, .slot { display: contents; }

/* One page at a time. Everything outside a card is separated by --card-gap; the only other
   vertical spacing out here is a heading's own margin (below). */
.page { display: flex; flex-direction: column; gap: var(--card-gap); animation: pageIn .25s ease; }
@keyframes pageIn { from { opacity: 0; } }

/* A section heading labels the cards under it: left-aligned and 6px in, 9px above (18 from
   the card before) and 3px below (12 to the card it labels). First on the page it takes no
   top margin: the page's own top padding owns that gap. */
.section-title {
  margin: 9px 0 3px;
  padding-left: 6px;
  font-size: var(--type-body);
  font-weight: 400;
  letter-spacing: .02em;
  color: var(--ink);
  opacity: .85;
}
.page > .section-title:first-child { margin-top: 0; }
/* A subpage's headings are centred and 2px in: the one visual tell that you are a level down. */
.page-sub > .section-title { padding: 0 2px; text-align: center; }

/* ------------------------------------------------------------------- the card
   Up to three boxes, always in this order: heading row, hero unit, graphic unit. Every
   distance is a token. A card is one of exactly two heights, 216 or 432, and sits on one
   type tier all the way down (main by default; class tier-quiet, defined in designTokens.css,
   moves all of it to 75%). A card whose content outgrows its height scrolls inside it. */
.card {
  display: flex;
  flex-direction: column;
  height: var(--card-height);
  padding: var(--card-title-inset);
  border: .5px solid var(--surface-border);
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: var(--card-shadow);
  overflow-x: hidden;
  overflow-y: auto;
  scrollbar-width: thin;
  scrollbar-color: var(--surface-3) transparent;
  text-align: left;
  color: inherit;
}
.card-double { height: var(--card-double-height); }
.card > :last-child { margin-bottom: 0; }
/* A card that is a button (the Overview cards take you to a page). */
button.card { width: 100%; font: inherit; cursor: pointer; }

/* Box 1: the heading row. One height, set by the title's own line and by nothing else: a taller
   thing in the row (the toggle, the action) is centred on the title line and overhangs it. */
.card-head {
  display: flex;
  flex: none;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  height: var(--card-head-h);
  margin-bottom: var(--card-box-gap);
}
.card-title { font-family: var(--card-title-font); font-size: var(--card-title-size); font-weight: var(--card-title-weight); line-height: var(--card-head-h); color: var(--ink); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* Box 1's corner control: code 1 (a readout), code 2 (an action), code 3 (a toggle of at most three). At most one, top right. */
.chip { display: inline-flex; align-items: center; gap: 7px; flex: none; font-size: var(--chip-size); font-weight: 300; letter-spacing: var(--chip-tracking); color: var(--muted); white-space: nowrap; }
.card-action {
  flex: none;
  padding: 5px 11px;
  border: 0;
  border-radius: 99px;
  background: var(--surface-2);
  font-size: var(--type-label);
  font-weight: 300;
  letter-spacing: .06em;
  color: var(--ink);
}
.card-icon { width: var(--card-head-h); height: var(--card-head-h); color: var(--muted); flex-shrink: 0; }

/* A status is a dot AND a word, so the colour is never alone. */
.dot { display: inline-block; width: 8px; height: 8px; flex: none; border-radius: 50%; background: var(--status-unknown); }
.dot.ok { background: var(--status-ok); }
.dot.warn { background: var(--status-warn); }
.dot.bad { background: var(--status-bad); }
.dot.unknown { background: var(--status-unknown); }

/* Box 2: the hero unit, the number and its caption as one pair. Money would be Kanit
   (design/typography.md rule 1); nothing here is money but the DadWad preview's amounts. */
.hero {
  flex: none;
  margin-bottom: var(--card-box-gap);
  font-size: var(--t-hero);
  font-family: var(--hero-font);
  font-weight: var(--hero-weight);
  font-variant-numeric: tabular-nums;
  line-height: 1;
  letter-spacing: var(--hero-tracking);
  text-align: center;
  color: var(--ink);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.hero:has(+ .hero-cap) { margin-bottom: var(--card-cap-gap); }
.hero-cap {
  flex: none;
  margin-bottom: var(--card-box-gap);
  font-size: var(--t-cap);
  font-weight: 300;
  line-height: 1;
  letter-spacing: .06em;
  text-align: center;
  color: var(--muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.hero-unit { margin-left: 2px; font-size: var(--t-hero-dec); font-weight: 400; color: var(--muted); }
/* A card that is an action and has no number: its one line of copy. */
.card-sub { margin-bottom: var(--card-box-gap); font-size: var(--card-sub-size); font-weight: var(--card-sub-weight); line-height: 1.5; color: var(--muted); }
.card-sub.small { font-size: var(--t-d2); font-weight: 300; }
.card-sub b { font-weight: 400; color: var(--ink); }
.card-sub a { color: var(--ink); text-decoration: underline; text-underline-offset: 3px; }

/* Box 3: Detail 1 is a label (uppercase, tracked, small), Detail 2 a figure or caption; both read the tier tokens, and the gap
   between lines of them is --card-detail-gap. text-box trims the line to the letters so the gap is the VISIBLE gap. */
.d1 {
  font-size: var(--t-d1);
  font-weight: 300;
  line-height: 1;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--muted);
  text-box: trim-both cap alphabetic;
}
.d2 { font-size: var(--t-d2); font-weight: 300; line-height: 1; color: var(--muted); text-box: trim-both cap alphabetic; }
.d2 b, .d2 code { font-weight: 400; color: var(--ink); }
.d2 code { font-size: inherit; }
.foot { margin-top: auto; padding-top: var(--card-foot-gap); font-size: var(--t-d2); font-weight: 300; line-height: 1.5; color: var(--muted); }
.foot b, .foot code { font-weight: 400; color: var(--ink); }
.foot code { font-size: inherit; }
.foot + .foot { margin-top: 0; padding-top: var(--card-detail-gap); }

/* Facts: a label left, a figure right, one line each, a hairline between rows when it is a list. */
.facts { display: flex; flex-direction: column; gap: var(--card-detail-gap); }
.fact { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; min-width: 0; }
.fact > :first-child { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fact > :last-child { flex: none; text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.fact .d2:last-child { color: var(--ink); }
.rows { display: flex; flex-direction: column; }
.rows .fact, .rows a.fact { padding: var(--card-detail-gap) 0; border-top: .5px solid var(--line); }
.rows > :first-child { border-top: 0; padding-top: 0; }
.rows a.fact:hover .d1 { color: var(--ink); }
.rows .fact .name { font-size: var(--stat-value-size); font-weight: 300; letter-spacing: 0; text-transform: none; color: var(--ink); line-height: 1.3; text-box: none; }
.row-state { display: inline-flex; align-items: center; gap: 7px; min-width: 0; }
.gap { flex: none; height: var(--card-box-gap); }
.d2.after { margin-top: var(--card-detail-gap); }
.rows.spaced { margin-top: var(--card-box-gap); }
.meta-list { margin-top: var(--card-detail-gap); line-height: 1.6; }
details summary { cursor: pointer; }
.spark-cap { margin-top: var(--card-detail-gap); }
.foot .card-action { display: block; margin-top: var(--card-detail-gap); }

/* A bar: the tier's thickness, a pill with a recessed track under it (Wad's Today bar). The fill's colour says how full, and the text
   beside it says the same in words. */
.bar { position: relative; flex: none; width: 100%; height: var(--t-bar); border-radius: 14px; background: var(--surface-2); overflow: hidden; }
.bar i { display: block; height: 100%; border-radius: 14px; background: var(--limit-ok); transition: width .4s cubic-bezier(.25, 1, .5, 1); }
.bar.near i { background: var(--limit-near); }
.bar.hit i { background: var(--limit-hit); }
.bar.reset i { width: 0 !important; }
.bar + .d2 { margin-top: var(--card-detail-gap); }
.hero.near { color: var(--limit-near); }
.hero.hit { color: var(--limit-hit); }

/* ------------------------------------------------------- the usage graphics
   Drawn to Wad's pixel rules: a bar is --t-bar, a reference line --mark-line, a chart's axis --axis-line. */
.spark { position: relative; flex: 1; min-height: 44px; }
.spark svg { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }
.spark .base { stroke: rgba(var(--ink-rgb), .75); stroke-width: var(--axis-line); vector-effect: non-scaling-stroke; }
.spark .line { fill: none; stroke: var(--ink); stroke-width: var(--series-line); stroke-linejoin: round; stroke-linecap: round; vector-effect: non-scaling-stroke; }
.spark .wash { fill: rgba(var(--ink-rgb), .08); stroke: none; }
.spark .end { position: absolute; width: 10px; height: 10px; margin: -5px 0 0 -5px; border-radius: 50%; background: var(--ink); box-shadow: 0 0 0 2px var(--surface); }
.spark-row { display: flex; flex-direction: column; gap: var(--card-detail-gap); min-width: 0; }
.spark-row + .spark-row { margin-top: var(--card-box-gap); }
.spark-cap { display: flex; justify-content: space-between; }
.spark-empty { font-size: var(--t-d2); font-weight: 300; line-height: 1.5; color: var(--muted); }

/* Columns: thin, 4px round at the data end and square on the baseline, 2px between neighbours. Today is the ink, the rest recede. */
.plot { position: relative; flex: 1; min-height: 120px; margin-left: 36px; }
.plot .gl { position: absolute; left: 0; right: 0; height: 0; border-top: var(--mark-line) solid var(--line); }
.plot .gl span { position: absolute; right: calc(100% + 8px); top: -5px; font-size: var(--t-d2); font-weight: 300; line-height: 1; color: var(--muted); font-variant-numeric: tabular-nums; white-space: nowrap; }
.plot .gl:first-child { border-top: var(--axis-line) solid rgba(var(--ink-rgb), .75); }
.cols { position: absolute; inset: 0; display: flex; align-items: flex-end; gap: 2px; }
.col { flex: 1; min-width: 0; height: 100%; display: flex; align-items: flex-end; justify-content: center; }
.col i { display: block; width: 100%; max-width: 24px; min-height: 2px; border-radius: 4px 4px 0 0; background: var(--surface-3); transition: background .12s; }
.col.zero i { opacity: .5; }
.col.latest i, .col:hover i { background: var(--ink); }
.xaxis { display: flex; justify-content: space-between; margin: var(--card-detail-gap) 0 0 36px; }
.xaxis.each span { flex: 1; text-align: center; }
.plot-wrap { display: flex; flex-direction: column; flex: 1; min-height: 0; }

/* A ranked list: a name, its share, one bar under it. The top one is full. */
.hrow { padding: var(--card-detail-gap) 0; border-top: .5px solid var(--line); }
.hrow:first-child { border-top: 0; padding-top: 0; }
.hl { display: flex; justify-content: space-between; gap: 12px; margin-bottom: var(--card-detail-gap); }
.hl span:first-child { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.hl .name { font-size: var(--stat-value-size); font-weight: 300; color: var(--ink); line-height: 1.2; }
.hv { color: var(--muted); font-variant-numeric: tabular-nums; white-space: nowrap; }
.hv em { font-style: normal; margin-left: 8px; }
.hb { height: calc(var(--t-bar) / 3); border-radius: 99px; background: var(--surface-2); overflow: hidden; }
.hb i { display: block; height: 100%; border-radius: 99px; background: var(--ink); opacity: .85; }

.why-block + .why-block { margin-top: var(--card-box-gap); }
.why-block .d1 { margin-bottom: var(--card-detail-gap); }
.why-row { display: flex; gap: 14px; align-items: baseline; padding: var(--card-detail-gap) 0; border-top: .5px solid var(--line); }
.why-row b { min-width: 48px; font-size: var(--stat-value-size); font-weight: 600; font-variant-numeric: tabular-nums; }
.why-row span { font-size: var(--t-d2); font-weight: 300; line-height: 1.5; color: var(--muted); }
.raw summary { cursor: pointer; font-size: var(--t-d2); font-weight: 300; color: var(--muted); }
.raw pre, .errlog { margin: var(--card-detail-gap) 0 0; padding: 12px 14px; border-radius: 14px; background: var(--surface-2); color: var(--muted); font-size: var(--type-caption); line-height: 1.5; white-space: pre-wrap; word-break: break-word; overflow: auto; max-height: 160px; }

.ctable-wrap { overflow: auto; flex: 1; min-height: 0; }
.ctable { width: 100%; border-collapse: collapse; font-size: var(--t-d2); font-weight: 300; font-variant-numeric: tabular-nums; }
.ctable th { position: sticky; top: 0; background: var(--surface); text-align: right; font-size: var(--t-d1); font-weight: 300; letter-spacing: .08em; text-transform: uppercase; color: var(--muted); padding: 0 8px var(--card-detail-gap); white-space: nowrap; }
.ctable td { padding: var(--card-detail-gap) 8px; text-align: right; border-top: .5px solid var(--line); color: var(--muted); }
.ctable th:first-child, .ctable td:first-child { text-align: left; padding-left: 0; }
.ctable td:first-child { color: var(--ink); white-space: nowrap; }

.chart-tip { position: fixed; z-index: 60; pointer-events: none; max-width: 250px; padding: 8px 11px; border: .5px solid var(--line); border-radius: 12px; background: var(--surface-3); box-shadow: var(--card-shadow); font-size: var(--type-label); font-weight: 300; line-height: 1.55; }
.chart-tip b { font-weight: 400; }
.chart-tip .m { color: var(--muted); }

/* ------------------------------------------------------- commands and forms */
.cmd-list { display: flex; flex-direction: column; }
.cmd-row { display: flex; align-items: center; gap: 10px; padding: 6px 0; border-top: .5px solid var(--line); }
.cmd-row:first-child { border-top: 0; padding-top: 0; }
.cmd-row code { flex: 1; min-width: 0; overflow-x: auto; white-space: pre; scrollbar-width: none; }
.cmd-row button { flex: none; padding: 4px 10px; border: 0; border-radius: 99px; background: var(--surface-2); font-size: var(--type-label); font-weight: 300; letter-spacing: .06em; color: var(--ink); }
.cmd-row button.copied { color: var(--status-ok-text); }

.field-row { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.field-row.spaced { margin-top: var(--card-box-gap); }
select, input[type=password], input[type=text], input[type=search] {
  min-width: 0;
  padding: 10px 15px;
  border: 0;
  border-radius: 99px;
  outline: none;
  background: var(--surface-2);
  color: var(--ink);
  font-size: var(--type-body);
}
input::placeholder { color: var(--muted); }
input:focus-visible, select:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
input[type=search] { flex: 1 1 190px; }
.field-row input[type=password], .field-row input[type=text] { flex: 1 1 160px; }
.btn { flex: none; padding: 10px 18px; border: 0; border-radius: 99px; background: var(--surface-2); font-size: var(--type-body); font-weight: 400; white-space: nowrap; color: var(--ink); }
.btn.primary { background: var(--ink); color: var(--on-accent); }
.btn:disabled { opacity: .35; }
.err { margin-top: var(--card-detail-gap); font-size: var(--t-d2); font-weight: 300; line-height: 1.5; color: var(--status-bad-text); }
.card > .field-row + .err { margin-top: var(--card-detail-gap); }
.live-out { margin-top: var(--card-detail-gap); font-size: var(--t-d2); font-weight: 300; line-height: 1.5; color: var(--muted); }
.live-out b { font-weight: 400; color: var(--ink); }
.live-out a { color: var(--ink); text-decoration: underline; text-underline-offset: 3px; }

/* The temporary statement-password portal (passwordPortal.mjs): one row per password the Mac asked for. */
.pw-row { padding: var(--card-detail-gap) 0; border-top: .5px solid var(--line); }
.pw-row:first-child { border-top: 0; padding-top: 0; }
.pw-row .fact { align-items: center; }
.pw-row .name { font-size: var(--stat-value-size); font-weight: 300; letter-spacing: 0; text-transform: none; color: var(--ink); line-height: 1.3; }
.pw-form { display: flex; flex-direction: column; gap: 8px; max-width: 460px; margin-top: var(--card-box-gap); }
.pw-form input { width: 100%; }
.pw-actions { display: flex; gap: 8px; justify-content: flex-end; }
.pw-row .pw-form[hidden], .pw-row .pw-err[hidden], .pw-row .pw-note[hidden] { display: none; }

/* ----------------------------------------------------------- DadWad's tabs */
.dadwad-rule { padding: 14px; border-radius: 18px; background: var(--surface-2); }
.dadwad-rule + .dadwad-rule { margin-top: var(--card-detail-gap); }
.dadwad-rule-top { display: flex; gap: 8px; align-items: center; margin-bottom: var(--card-detail-gap); flex-wrap: wrap; }
.dadwad-rule-top .dr-label { flex: 1 1 130px; background: var(--surface-3); }
.dadwad-rule-top select { background: var(--surface-3); }
.dadwad-rule-fields { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 8px; }
.dadwad-rule-fields label { display: flex; flex-direction: column; gap: 6px; }
.dadwad-rule-fields label .d1 { text-box: none; }
.dadwad-rule-fields input { width: 100%; background: var(--surface-3); }
.dadwad-tab-top { display: flex; gap: 8px; align-items: center; margin-bottom: var(--card-detail-gap); }
.dadwad-tab-top .dt-label { flex: 1; }
.dadwad-tab-rules { margin-bottom: var(--card-detail-gap); }
.dadwad-tab-preview { margin-top: var(--card-box-gap); padding-top: var(--card-detail-gap); border-top: .5px solid var(--line); }
.dadwad-preview-row { display: flex; justify-content: space-between; gap: 10px; padding: var(--card-detail-gap) 0; border-top: .5px solid var(--line); }
.dadwad-preview-row:first-of-type { border-top: 0; }
.dp-main { min-width: 0; display: flex; flex-direction: column; gap: var(--card-detail-gap); }
.dp-text { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: var(--stat-value-size); font-weight: 300; color: var(--ink); line-height: 1.2; }
.dp-amt { flex: none; font-size: var(--t-d2); font-weight: 300; font-variant-numeric: tabular-nums; white-space: nowrap; color: var(--ink); }
.dp-amt.credit { color: var(--status-ok-text); }

/* ---------------------------------------------------------- the sender catalog
   The senders are a LEDGER card (design/ledgerCard/, design/transactionCards.md): the shared sheet draws it. This app keeps the page it sits on, the tick, and the search card above it. */
.card.form-card { height: auto; flex: 0 0 auto; overflow: visible; }                 /* a content-sized FORM card (the tab editor, the search, the password portal): not a ledger, the owner has not ruled on these */
.log-tools { display: flex; flex: none; flex-wrap: wrap; gap: 8px; align-items: center; margin-bottom: var(--card-box-gap); }
}
.tick { display: flex; align-items: center; justify-content: center; cursor: pointer; position: relative; }
.tick input { position: absolute; opacity: 0; width: 0; height: 0; }
.tick i { display: block; width: 20px; height: 20px; border-radius: 7px; background: var(--surface-2); border: .5px solid var(--line); transition: background .12s; position: relative; }
.tick input:checked + i { background: var(--ink); border-color: transparent; }
.tick input:checked + i::after { content: ""; position: absolute; left: 7px; top: 3px; width: 5px; height: 10px; border: solid var(--on-accent); border-width: 0 2px 2px 0; transform: rotate(43deg); }
.tick input:focus-visible + i { outline: 2px solid var(--focus); outline-offset: 2px; }

/* The unsaved ticks: a floating action above the bar, never a second bar. It clears the bar by the bar's own height token
   (design/bottomNavBar.md rule 10: the FABs read --bottom-nav-safe-h). */
.saveBar {
  position: fixed;
  left: 50%;
  bottom: calc(var(--bottom-nav-safe-h) + 16px);
  transform: translateX(-50%);
  z-index: 25;
  display: flex;
  align-items: center;
  gap: 8px;
  width: min(408px, calc(100% - 2 * var(--page-gutter)));
  padding: 8px 8px 8px 20px;
  border: .5px solid var(--surface-border);
  border-radius: 99px;
  background: rgba(var(--bg-rgb), .8);
  -webkit-backdrop-filter: blur(20px) saturate(180%);
  backdrop-filter: blur(20px) saturate(180%);
  box-shadow: var(--card-shadow);
}
.saveMsg { flex: 1; min-width: 0; font-size: var(--type-label); font-weight: 300; line-height: 1.3; color: var(--muted); }
.saveMsg b { font-weight: 400; color: var(--ink); }
.saveBar .btn { padding: 9px 16px; font-size: var(--type-small); }

/* ---------------------------------------------------------------------- the dialog
   Native <dialog>: focus trapping, Esc and an inert background come with it. */
dialog {
  width: calc(100% - 32px);
  max-width: 408px;
  max-height: 85dvh;
  overflow: auto;
  padding: 22px;
  border: 1px solid var(--line);
  border-radius: 24px;
  background: var(--surface);
  color: var(--ink);
}
dialog::backdrop { background: rgba(0, 0, 0, .5); -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px); }
dialog h2 { font-size: var(--type-heading); font-weight: 400; }
dialog p { margin-top: 8px; font-size: var(--type-body); line-height: 1.6; color: var(--muted); }
.dialog-actions { display: flex; gap: 10px; margin-top: 12px; }
.full-button { width: 100%; min-height: 44px; margin-top: 10px; padding: 10px 15px; border: 0; border-radius: 14px; background: var(--surface-2); font-size: var(--type-body); }
.full-button.primary { background: var(--ink); color: var(--on-accent); }

/* ----------------------------------------------------------------- wider screens
   700px up the bar goes full width (track centred, button at the far right) and the page
   stops being a phone column; 900px up the cards form a grid, 4 columns from 1560px.
   Breakpoints are 700 / 900 / 1560 only (design/mainPages.md rule 6). */
@media (min-width: 700px) {
  .app { --page-gutter: 24px; max-width: none; width: 100%; padding-top: calc(env(safe-area-inset-top) + 24px); }
  #content { padding-top: 18px; }
  .card { padding-inline: 28px; width: 100%; max-width: var(--card-width); margin-inline: auto; }
}
@media (min-width: 900px) {
  .page:not(.page-sub) {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, var(--card-width)));
    grid-auto-rows: min-content;
    align-content: start;
    align-items: start;
  }
  /* A heading labels the cards under it, so it owns the whole row. */
  .section-title { grid-column: 1 / -1; }
  /* A double card is two rows tall here (441 = 2 x 216 + the gap), so the short cards fill in beside it. */
  .page:not(.page-sub) .card-double { grid-row: span 2; height: calc(2 * var(--card-height) + var(--card-gap)); }
  /* A content-sized log is two columns wide and takes the row to itself. A DadWad tab is an editor of entries: it is content-sized
     too, and two sit side by side. */
  .page:not(.page-sub) .card.ledger-card, .page:not(.page-sub) .card.form-card { grid-column: span 2; max-width: none; width: 100%; }
  .page:not(.page-sub) .card.form-card.dadwad-tab { grid-column: auto; max-width: var(--card-width); }
  /* A subpage is one column that centres under its centred headings, each part capped at --card-width. */
  .page-sub { align-items: center; }
  .page-sub > .section-title { align-self: stretch; }
}
@media (min-width: 1560px) {
  :root { --card-width: 476px; }
  .page:not(.page-sub) { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

/* The narrowest phones. */
@media (max-width: 360px) {
  .app { --page-gutter: 12px; }
  .card { padding: 18px; }
}

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

/* NO ZOOM ANYWHERE (owner: "double tap zoom ... is irritating ... restrict the zoom completely, we don't use it anymore"): pan only, so neither a double tap nor a pinch zooms the page. The viewport meta says the same (maximum-scale=1, user-scalable=no). Every app's stylesheet has this rule; design/test/noZoom.test.mjs fails if one lacks it. */
html { touch-action: pan-x pan-y; }


/* ---------------------------------------------------------------- Today: one day is one screen, in ONE huge card (dayTimeline.mjs, app.js)
   The card is an ordinary card in everything but its height: the same edges (the page gutter, and on a wide screen the grid's left edge and its full width), the same top (where a page's cards start),
   corner radius, border, surface, shadow and inset. Its height is the whole room from there to just above the bottom bar, given by the layout (below), and the page does not scroll. Inside, the day is 24
   EQUAL hours (the rail is a grid of 24 rows of 1fr, and an "Any" row, only when the day has such items, is one more share), one hairline row each: its number, then what stands in it on ONE line,
   so nothing wraps; an event is also a bar down the rail as long as the event. Kinds differ by SHAPE (a ring, a framed date, a bell, a spark), never by colour or weight alone
   (design/typography.md rule 7). Every size is a role token; the only numbers are the rail's own geometry. */
/* THE HEIGHT IS THE LAYOUT'S, as the width is (owner: "dynamically adjusted ... instead of a fixed height"): while Today is showing (`html.today-on`) the page is a column exactly one screen tall (100dvh follows the browser's
   toolbars), the top row takes its own height, and the card takes ALL THAT IS LEFT, down to the room the page column already keeps for the bottom bar. Nothing is measured or typed, so rotation, a toolbar
   appearing and any window size are right at once. A screen too short for 24 readable hours scrolls instead of squashing them (min-height). */
/* The one-screen column is the BODY (design/syncDesign.mjs: .app is never given a viewport height, and this does not pin it either: the document still scrolls natively, it is only never SHORTER than the screen).
   .app fills that column, so whatever padding it keeps above (the status-bar strip on a phone, the frost's 48px on a desktop) is simply inside the measure: no constant is subtracted anywhere. */
html.today-on body { display: flex; flex-direction: column; min-height: 100vh; min-height: 100dvh; }
html.today-on .app { flex: 1 1 auto; display: flex; flex-direction: column; width: 100%; }
html.today-on #main { flex: 1 1 auto; display: flex; flex-direction: column; min-height: 0; }
html.today-on #content, html.today-on #shell { flex: 1 1 auto; display: flex; flex-direction: column; min-height: 0; }
/* THE TWO GAPS ARE ONE (owner: "the gap between the card and the date row above it is exactly the gap between the card and the bottom bar"): the card starts --top-row-gap below the top row, and ends the SAME
   distance above the bottom bar's pill. The bar's band is --bottom-nav-safe-h (its height plus the home-indicator inset) and the pill stands 8px inside it (the band's own margin above the pill), so the room
   to keep under the card is the band less that 8px, plus the gap itself. */
html.today-on #content { padding-bottom: calc(var(--bottom-nav-safe-h) - 8px + var(--top-row-gap)); }
html.today-on #page-today.page:not(.page-sub) { flex: 1 1 auto; display: flex; flex-direction: column; min-height: 0; }
.card.day-card { flex: 1 1 0; height: auto; min-height: calc(24 * 18px + 2 * var(--card-title-inset)); overflow: hidden; }
/* Width, like every card: the column on a phone; on a wide screen the grid's left edge and the width of two columns (the whole page from 1560px, where there are four). */
@media (min-width: 900px) { .page:not(.page-sub) .card.day-card { width: 100%; max-width: calc(2 * var(--card-width) + var(--card-gap)); margin-inline: 0; } }
@media (min-width: 1560px) { .page:not(.page-sub) .card.day-card { max-width: none; } }
.day-sec { position: relative; flex: 1 1 0; min-height: 0; display: flex; flex-direction: column; }
.day-note { position: absolute; top: -2px; right: 0; font-size: var(--type-caption); font-weight: 300; letter-spacing: .04em; color: var(--status-bad-text); }
/* The all-day row is as tall as what is in it: its items WRAP (several apps' tasks have no time: every training session, every bill), and the 24 hours share what is left equally. */
.day-any { flex: 0 0 auto; display: grid; grid-template-columns: 44px 1fr; column-gap: 12px; align-items: start; padding: 9px 0; border-top: .5px solid var(--line); }
.day-any .day-lane { flex-wrap: wrap; gap: 9px 22px; overflow: visible; }
.day-any .day-time { line-height: 15px; }
.day-rail { flex: 24 1 0; min-height: 0; position: relative; list-style: none; margin: 0; padding: 0; display: grid; grid-template-rows: repeat(24, 1fr); }
.day-hour { position: relative; min-height: 0; display: grid; grid-template-columns: 44px 1fr; column-gap: 12px; align-items: center; border-top: .5px solid var(--line); }
.day-time { font-size: var(--type-caption); font-weight: 300; font-variant-numeric: tabular-nums; letter-spacing: .06em; line-height: 1; color: var(--muted); }
.day-hour.has .day-time, .day-hour.now .day-time { color: var(--ink); }
.day-hour.past .day-time { opacity: .6; }
.day-lane { display: flex; align-items: center; gap: 22px; min-width: 0; overflow: hidden; }
.day-item { display: flex; align-items: center; gap: 7px; min-width: 0; flex: 0 1 auto; max-width: 100%; white-space: nowrap; }
.day-item.past { opacity: .6; }
.day-glyph { flex: none; width: 15px; height: 15px; color: var(--app, var(--muted)); }       /* the app's colour; a done task is told by its check and its strike, not by losing the colour */
.day-item.done .day-title { text-decoration: line-through; text-decoration-color: var(--muted); }
.day-title { min-width: 0; overflow: hidden; text-overflow: ellipsis; font-size: var(--type-small); font-weight: 300; line-height: 1; color: var(--ink); }
.day-sub { flex: none; font-size: var(--type-caption); font-weight: 300; line-height: 1; letter-spacing: .04em; font-variant-numeric: tabular-nums; color: var(--muted); }
.day-evbar { position: absolute; left: 48px; width: 2px; border-radius: 1px; background: var(--app, var(--ink)); pointer-events: none; }
.day-evbar.past { opacity: .6; }
.day-hour.now .day-lane { padding-right: 52px; }     /* the "now" time stands at the row's right end: nothing under it */
.day-nowline { position: absolute; left: 52px; right: 0; height: 0; border-top: 1px solid var(--ink); pointer-events: none; }
.day-nowline::before { content: ""; position: absolute; left: -4px; top: -4.5px; width: 7px; height: 7px; border-radius: 50%; background: var(--ink); }
.day-nowtext { position: absolute; right: 0; top: -9px; padding: 0 6px; font-size: var(--type-tag); font-weight: 300; letter-spacing: .06em; font-variant-numeric: tabular-nums; color: var(--ink); background: var(--bg); }
