/*
 * WageRouter's look, on top of Pico CSS 2.1.1 (book: "Brand and styles with Pico CSS", "The
 * redesign"). The approved final draft of 2026-10-31 and docs/brand.md are the source.
 *
 * Pico styles plain semantic HTML and exposes its colors as CSS custom properties. This file only
 * (1) loads our fonts, (2) sets Pico's variables to the tokens below, and (3) adds what Pico
 * doesn't have: the wordmark, money figures, icons, the shell (top bar, tab bar, sidebar), cards,
 * the segmented control, stacked tables, and single-card pages.
 *
 * **Dark only** (the owner, 2026-11-05): one palette, "Soft charcoal", on `:root`. Every page is
 * <html data-theme="dark"> so Pico's own dark defaults apply underneath.
 *
 * **Colour roles** (docs/brand.md): cyan acts (main buttons, links, the current tab), indigo
 * supports (second buttons, badges), teal confirms (saved, done, the glow, money in ▲), red is
 * money out ▼ and problems. The only gradient left is the logo's cyan → indigo.
 *
 * No inline styles anywhere: the Content Security Policy is `style-src 'self'`, so all styling
 * lives in files like this one. web/tests/views/contrast.rs checks the token pairs are readable.
 */

/* ---------------------------------------------------------------- fonts (OFL, self-hosted) */

/* ANCHOR: fonts */
/* Nunito for words (rounded and friendly; four weights), Geist Mono for figures. */
@font-face {
  font-family: "Nunito";
  src: url("/static/fonts/nunito-latin-400-v5.3.0.woff2") format("woff2");
  font-weight: 400;
  font-display: swap;
}
@font-face {
  font-family: "Nunito";
  src: url("/static/fonts/nunito-latin-600-v5.3.0.woff2") format("woff2");
  font-weight: 600;
  font-display: swap;
}
@font-face {
  font-family: "Nunito";
  src: url("/static/fonts/nunito-latin-700-v5.3.0.woff2") format("woff2");
  font-weight: 700;
  font-display: swap;
}
@font-face {
  font-family: "Nunito";
  src: url("/static/fonts/nunito-latin-800-v5.3.0.woff2") format("woff2");
  font-weight: 800;
  font-display: swap;
}
/* ANCHOR_END: fonts */
@font-face {
  font-family: "Geist Mono";
  src: url("/static/fonts/geist-mono-latin-400-v5.3.0.woff2") format("woff2");
  font-weight: 400;
  font-display: swap;
}
@font-face {
  font-family: "Geist Mono";
  src: url("/static/fonts/geist-mono-latin-500-v5.3.0.woff2") format("woff2");
  font-weight: 500;
  font-display: swap;
}

/* ---------------------------------------------------------------- the tokens */

/* ANCHOR: tokens */
:root {
  color-scheme: dark;
  --wr-font: "Nunito", ui-rounded, system-ui, -apple-system, "Segoe UI", sans-serif;
  --wr-font-mono: "Geist Mono", ui-monospace, "SF Mono", Menlo, monospace;

  /* Soft charcoal: four greys, each a step lighter, so cards sit on the page and menus on cards. */
  --wr-bg: #121212;
  --wr-card: #1c1c1c;
  --wr-raised: #262626;
  --wr-hover: #2e2e2e;
  /* Hairlines: dividers inside a card, then card borders. Fields get a stronger edge, so their
     outline passes WCAG's 3:1 for controls (a card's border is decoration and needn't). */
  --wr-line: #262626;
  --wr-border: #333333;
  --wr-border-strong: #444444;
  --wr-field-border: #6b6b6b;

  --wr-text: #ededed;
  --wr-body: #bdbdbd;
  --wr-muted: #a3a3a3;
  --wr-dim: #8a8a8a;
  --wr-placeholder: #8a8a8a;
  --wr-input: #121212;

  /* The roles. Each has its colour for fills and borders, and a lighter one for text. */
  --wr-cyan: #22d3ee;
  --wr-cyan-hover: #67e8f9;
  --wr-on-cyan: #121212;
  --wr-indigo: #818cf8;
  --wr-indigo-text: #a5b4fc;
  --wr-teal: #2dd4bf;
  --wr-teal-text: #5eead4;
  --wr-red: #ff5c77;
  --wr-red-text: #ff8fa1;
  /* The same four as RGB triples, for tints and rings: `rgba(var(--wr-teal-rgb), 0.22)`. */
  --wr-cyan-rgb: 34, 211, 238;
  --wr-indigo-rgb: 129, 140, 248;
  --wr-teal-rgb: 45, 212, 191;
  --wr-red-rgb: 255, 92, 119;
  --wr-in: var(--wr-teal);   /* money in, always with ▲ */
  --wr-out: var(--wr-red);   /* money out, always with ▼ */

  /* The logo's gradient: the wordmark's "ROUTER" and nothing else. */
  --wr-logo-grad: linear-gradient(100deg, #22d3ee, #818cf8);

  /* Crisp: 12px corners on cards, 10px on buttons and fields. */
  --wr-radius: 12px;
  --wr-radius-sm: 10px;
  /* The glowing ring: a field being typed in, a saved line (the owner liked it in the drafts). */
  --wr-ring: 0 0 0 3px rgba(var(--wr-teal-rgb), 0.22);
  --wr-ring-saved: 0 0 0 5px rgba(var(--wr-teal-rgb), 0.16);

  --wr-glass: rgba(18, 18, 18, 0.86);
  --wr-scrim: rgba(0, 0, 0, 0.6);
  --wr-ease: cubic-bezier(0.2, 0.8, 0.2, 1);

  --pico-font-family-sans-serif: var(--wr-font);
  --pico-font-family-monospace: var(--wr-font-mono);
  --pico-font-family: var(--wr-font);
  --pico-border-radius: var(--wr-radius-sm);
}
/* ANCHOR_END: tokens */

/* ---------------------------------------------------------------- the tokens, mapped onto Pico */

/* ANCHOR: pico_mapping */
/* `:root[data-theme]` has the same specificity as Pico's own theme selectors (one pseudo-class,
   one attribute), and this file loads after Pico's, so these values win. */
:root[data-theme] {
  --pico-background-color: var(--wr-bg);
  --pico-color: var(--wr-text);
  --pico-h1-color: var(--wr-text);
  --pico-h2-color: var(--wr-text);
  --pico-h3-color: var(--wr-text);
  --pico-h4-color: var(--wr-text);
  --pico-h5-color: var(--wr-text);
  --pico-h6-color: var(--wr-text);
  --pico-muted-color: var(--wr-muted);
  --pico-muted-border-color: var(--wr-line);
  --pico-card-background-color: var(--wr-card);
  --pico-card-sectioning-background-color: var(--wr-raised);
  --pico-card-border-color: var(--wr-border);
  --pico-card-box-shadow: 0 0 0 1px var(--wr-border);
  --pico-table-border-color: var(--wr-line);
  --pico-text-selection-color: rgba(var(--wr-cyan-rgb), 0.3);
  --pico-ins-color: var(--wr-in);
  --pico-del-color: var(--wr-out);

  /* Links and main buttons: cyan. Its text on a cyan button is near-black (11:1). */
  --pico-primary: var(--wr-cyan);
  --pico-primary-hover: var(--wr-cyan-hover);
  --pico-primary-underline: rgba(var(--wr-cyan-rgb), 0.45);
  --pico-primary-hover-underline: var(--wr-cyan-hover);
  --pico-primary-focus: rgba(var(--wr-teal-rgb), 0.35);
  --pico-primary-background: var(--wr-cyan);
  --pico-primary-hover-background: var(--wr-cyan-hover);
  --pico-primary-border: var(--wr-cyan);
  --pico-primary-hover-border: var(--wr-cyan-hover);
  --pico-primary-inverse: var(--wr-on-cyan);

  /* Second buttons: indigo outline. */
  --pico-secondary: var(--wr-indigo-text);
  --pico-secondary-background: transparent;
  --pico-secondary-hover-background: rgba(var(--wr-indigo-rgb), 0.12);
  --pico-secondary-border: var(--wr-indigo);
  --pico-secondary-hover-border: var(--wr-indigo-text);
  --pico-secondary-inverse: var(--wr-indigo-text);
  --pico-secondary-focus: rgba(var(--wr-teal-rgb), 0.35);

  --pico-form-element-background-color: var(--wr-input);
  --pico-form-element-selected-background-color: var(--wr-raised);
  --pico-form-element-border-color: var(--wr-field-border);
  --pico-form-element-color: var(--wr-text);
  --pico-form-element-placeholder-color: var(--wr-placeholder);
  --pico-form-element-active-background-color: var(--wr-input);
  --pico-form-element-active-border-color: var(--wr-teal);
  --pico-form-element-focus-color: rgba(var(--wr-teal-rgb), 0.22);
  /* Pico draws the checkbox's tick white; on a cyan box it needs to be dark (11:1, not 1.6:1). */
  --pico-icon-checkbox: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23121212' stroke-width='4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'%3E%3C/polyline%3E%3C/svg%3E");
  --pico-switch-color: var(--wr-on-cyan);
  --pico-switch-background-color: var(--wr-raised);
  --pico-switch-checked-background-color: var(--wr-cyan);
}
/* ANCHOR_END: pico_mapping */

body { background: var(--wr-bg); -webkit-font-smoothing: antialiased; }

/* Cards: Pico's <article>, with the 12px corners and a hairline. */
article {
  border: 1px solid var(--wr-border);
  border-radius: var(--wr-radius);
  box-shadow: none;
}

/* The glowing focus ring, on everything you can tab to (Pico gives fields and buttons their own,
   from the variables above). */
:focus-visible { outline: 2px solid var(--wr-teal); outline-offset: 2px; }
input:not([type="checkbox"], [type="radio"], [type="range"], [type="file"]):focus,
select:focus,
textarea:focus {
  border-color: var(--wr-teal);
  box-shadow: var(--wr-ring);
}

/* ---------------------------------------------------------------- type */

/* ANCHOR: headings */
/* Nunito's heaviest weight for titles, as in the draft, with a hair of negative tracking. */
h1,
h2,
h3 {
  font-family: var(--wr-font);
  font-weight: 800;
  letter-spacing: -0.01em;
  line-height: 1.25;
  text-wrap: balance;
}
h1 { font-size: 1.65rem; }
h2 { font-size: 1.2rem; }
h3 { font-size: 1.05rem; font-weight: 700; }
@media (min-width: 768px) {
  h1 { font-size: 1.85rem; }
  h2 { font-size: 1.3rem; }
}
/* ANCHOR_END: headings */
strong, b { font-weight: 700; }
/* Small capitals labels above a value ("INCOMING", "LEFT THIS MONTH"). */
.wr-label {
  color: var(--wr-muted);
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

/* Figures: Geist Mono with tabular digits, so money columns line up. */
.num,
.money {
  font-family: var(--wr-font-mono);
  font-variant-numeric: tabular-nums;
}
.money-in { color: var(--wr-in); }
.money-out { color: var(--wr-out); }

/* ---------------------------------------------------------------- brand */

/* ANCHOR: wordmark */
/* The wordmark (brand/wordmark.html): "Wage" in the text colour, "Router" in the logo's gradient,
   set in spaced capitals. The HTML keeps "WageRouter" in mixed case, so a screen reader says the
   word rather than spelling ten letters; the capitals are CSS. */
.wr-wordmark {
  font-family: var(--wr-font);
  font-weight: 800;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  white-space: nowrap;
  /* Our own token, not --pico-color: Pico redefines --pico-color inside links. */
  color: var(--wr-text);
  line-height: 1;
}
.wr-wordmark .router {
  background: var(--wr-logo-grad);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}
/* ANCHOR_END: wordmark */
.wr-brand {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  text-decoration: none;
}
.wr-brand img { display: block; }

/* ---------------------------------------------------------------- buttons */

/* ANCHOR: buttons */
/* Main buttons: solid cyan, near-black text. Second buttons (`.secondary`): an indigo outline.
   Both 10px corners, bold, and they press in when tapped. Hover lifts the cyan and adds a ring. */
button,
[type="submit"],
[type="button"],
[role="button"] {
  font-weight: 700;
  border-radius: var(--wr-radius-sm);
  transition: transform 0.08s, box-shadow 0.2s, background-color 0.2s, border-color 0.2s, color 0.2s;
}
/* Pressed: a little smaller for a moment (off with Animations off: see "motion"). */
button:active,
[type="submit"]:active,
[role="button"]:active { transform: scale(0.97); }
button:not(.secondary):not(.outline):not(.contrast):hover,
[type="submit"]:not(.secondary):not(.outline):hover,
[role="button"]:not(.secondary):not(.outline):not(.contrast):hover {
  box-shadow: 0 0 0 4px rgba(var(--wr-cyan-rgb), 0.18);
}
button.secondary,
[role="button"].secondary,
[type="submit"].secondary {
  background: transparent;
  border-color: var(--wr-indigo);
  color: var(--wr-indigo-text);
}
button.secondary:hover,
[role="button"].secondary:hover,
[type="submit"].secondary:hover {
  background: rgba(var(--wr-indigo-rgb), 0.12);
  border-color: var(--wr-indigo-text);
  color: var(--wr-indigo-text);
}
/* An icon on a button takes the button's text colour. */
button .wr-icon,
[role="button"] .wr-icon { background: currentColor; }
/* ANCHOR_END: buttons */

/* ---------------------------------------------------------------- icons */

/* ANCHOR: accent */
/* Icons: Lucide SVG files used as a mask, painted with the text colour around them, so an icon
   is grey in a grey label, cyan on the current tab, dark on a cyan button. No inline SVG or
   styles. Each icon name maps to its file here (web/tests/views/icons.rs checks every icon the
   app uses has a rule and a file). */
.wr-icon {
  display: inline-block;
  flex: none;
  width: 1.4rem;
  height: 1.4rem;
  vertical-align: middle;
  background: currentColor;
  -webkit-mask: var(--wr-icon) center / contain no-repeat;
  mask: var(--wr-icon) center / contain no-repeat;
}
/* ANCHOR_END: accent */
.wr-i-house { --wr-icon: url("/static/icons/house.svg"); }
.wr-i-notebook-pen { --wr-icon: url("/static/icons/notebook-pen.svg"); }
.wr-i-menu { --wr-icon: url("/static/icons/menu.svg"); }
.wr-i-x { --wr-icon: url("/static/icons/x.svg"); }
.wr-i-circle-user { --wr-icon: url("/static/icons/circle-user.svg"); }
.wr-i-log-out { --wr-icon: url("/static/icons/log-out.svg"); }
.wr-i-shield { --wr-icon: url("/static/icons/shield.svg"); }
.wr-i-key-round { --wr-icon: url("/static/icons/key-round.svg"); }
.wr-i-clock { --wr-icon: url("/static/icons/clock.svg"); }
.wr-i-settings { --wr-icon: url("/static/icons/settings.svg"); }
.wr-i-moon { --wr-icon: url("/static/icons/moon.svg"); }
.wr-i-sun { --wr-icon: url("/static/icons/sun.svg"); }
.wr-i-monitor { --wr-icon: url("/static/icons/monitor.svg"); }
.wr-i-bell { --wr-icon: url("/static/icons/bell.svg"); }
.wr-i-bell-ring { --wr-icon: url("/static/icons/bell-ring.svg"); }
.wr-i-sparkles { --wr-icon: url("/static/icons/sparkles.svg"); }
.wr-i-mail { --wr-icon: url("/static/icons/mail.svg"); }
.wr-i-copy { --wr-icon: url("/static/icons/copy.svg"); }
.wr-i-qr-code { --wr-icon: url("/static/icons/qr-code.svg"); }
.wr-i-check-check { --wr-icon: url("/static/icons/check-check.svg"); }
.wr-i-inbox { --wr-icon: url("/static/icons/inbox.svg"); }
.wr-i-trash-2 { --wr-icon: url("/static/icons/trash-2.svg"); }
.wr-i-circle-help { --wr-icon: url("/static/icons/circle-help.svg"); }
.wr-i-users { --wr-icon: url("/static/icons/users.svg"); }
.wr-i-user-plus { --wr-icon: url("/static/icons/user-plus.svg"); }
.wr-i-ban { --wr-icon: url("/static/icons/ban.svg"); }
.wr-i-circle-check { --wr-icon: url("/static/icons/circle-check.svg"); }
.wr-i-activity { --wr-icon: url("/static/icons/activity.svg"); }
.wr-i-megaphone { --wr-icon: url("/static/icons/megaphone.svg"); }
.wr-i-blocks { --wr-icon: url("/static/icons/blocks.svg"); }
.wr-i-triangle-alert { --wr-icon: url("/static/icons/triangle-alert.svg"); }
.wr-i-send { --wr-icon: url("/static/icons/send.svg"); }
.wr-i-life-buoy { --wr-icon: url("/static/icons/life-buoy.svg"); }
.wr-i-eye { --wr-icon: url("/static/icons/eye.svg"); }
.wr-i-smartphone { --wr-icon: url("/static/icons/smartphone.svg"); }
.wr-i-id-card { --wr-icon: url("/static/icons/id-card.svg"); }
.wr-i-briefcase { --wr-icon: url("/static/icons/briefcase.svg"); }
.wr-i-arrow-left { --wr-icon: url("/static/icons/arrow-left.svg"); }
.wr-i-arrow-up { --wr-icon: url("/static/icons/arrow-up.svg"); }
.wr-i-arrow-down { --wr-icon: url("/static/icons/arrow-down.svg"); }
.wr-i-graduation-cap { --wr-icon: url("/static/icons/graduation-cap.svg"); }
.wr-i-hand-coins { --wr-icon: url("/static/icons/hand-coins.svg"); }
.wr-i-banknote { --wr-icon: url("/static/icons/banknote.svg"); }
.wr-i-split { --wr-icon: url("/static/icons/split.svg"); }
.wr-i-landmark { --wr-icon: url("/static/icons/landmark.svg"); }
.wr-i-panel-left { --wr-icon: url("/static/icons/panel-left.svg"); }
.wr-i-piggy-bank { --wr-icon: url("/static/icons/piggy-bank.svg"); }
.wr-i-receipt { --wr-icon: url("/static/icons/receipt.svg"); }
.wr-i-award { --wr-icon: url("/static/icons/award.svg"); }
.wr-i-file-text { --wr-icon: url("/static/icons/file-text.svg"); }
.wr-i-layers { --wr-icon: url("/static/icons/layers.svg"); }
.wr-i-download { --wr-icon: url("/static/icons/download.svg"); }
.wr-i-search { --wr-icon: url("/static/icons/search.svg"); }
.wr-i-clipboard-list { --wr-icon: url("/static/icons/clipboard-list.svg"); }

/* An icon inside a button sits before its label. */
button .wr-icon,
[role="button"] .wr-icon { margin-right: 0.5rem; width: 1.15rem; height: 1.15rem; }
[role="button"].secondary { display: inline-flex; align-items: center; }

.wr-muted { color: var(--wr-muted); }

/* Text for screen readers only (e.g. "Unread:" before a bold title). */
.wr-sr {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* ANCHOR: badge */
/* A count badge: the unread number on the bell and next to "Notifications". */
.wr-badge {
  display: inline-grid;
  place-items: center;
  min-width: 1.25rem;
  height: 1.25rem;
  padding: 0 0.35rem;
  margin-left: auto;
  border-radius: 999px;
  background: var(--wr-indigo);
  color: var(--wr-on-cyan);
  font-size: 0.72rem;
  font-weight: 600;
  line-height: 1;
}
/* On the bell button: a small dot pinned to the top-right corner. */
.wr-iconbtn { position: relative; }
.wr-badge-dot {
  position: absolute;
  top: -0.3rem;
  right: -0.3rem;
  margin: 0;
  box-shadow: 0 0 0 2px var(--wr-bg);
}
/* ANCHOR_END: badge */

/* "Sample" on a record from a sample set (book: "Sample data"). Outlined, so it reads as a label
   and not as a count like .wr-badge. */
.wr-sample {
  display: inline-block;
  margin-left: 0.4rem;
  padding: 0.05rem 0.5rem;
  border: 1px solid var(--wr-indigo);
  border-radius: 6px;
  color: var(--wr-indigo-text);
  font-family: var(--pico-font-family);
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  line-height: 1.4;
  text-transform: uppercase;
  vertical-align: middle;
}

/* ANCHOR: shell */
/* ---------------------------------------------------------------- the shell: phones first */

/* Phones: a sticky top bar (the brand and the bell) and a tab bar fixed to the bottom, with Menu
   as its last tab. The
   `env(safe-area-inset-*)` values keep both clear of the iPhone notch and home indicator. */
.wr-topbar {
  position: sticky;
  top: 0;
  z-index: 10;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: max(0.6rem, env(safe-area-inset-top)) 1rem 0.6rem;
  background: var(--wr-glass);
  -webkit-backdrop-filter: blur(14px);
  backdrop-filter: blur(14px);
  border-bottom: 1px solid var(--wr-line);
}
.wr-topbar .wr-wordmark { font-size: 0.95rem; }
.wr-topbar-actions { display: flex; gap: 0.6rem; }
.wr-iconbtn[aria-current="page"] { border-color: var(--wr-cyan); color: var(--wr-cyan); }
.wr-iconbtn {
  display: grid;
  place-items: center;
  width: 2.75rem;   /* 44px: the minimum comfortable touch target */
  height: 2.75rem;
  border-radius: var(--wr-radius-sm);
  border: 1px solid var(--wr-border);
  background: transparent;
  /* A link, but its icon is grey like the draft's, not link-cyan; cyan only when current. */
  color: var(--wr-body);
}
.wr-iconbtn:hover { border-color: var(--wr-border-strong); color: var(--wr-text); }

.wr-sidebar { display: none; }
.wr-main {
  width: 100%;
  max-width: 64rem;
  margin: 0 auto;
  padding: 1.5rem 1rem 2rem;
  /* Clear of the notch when a phone is turned sideways (`viewport-fit=cover` in the layout). */
  padding-left: max(1rem, env(safe-area-inset-left));
  padding-right: max(1rem, env(safe-area-inset-right));
}
/* Room for the fixed tab bar, so it never covers the end of the page. */
.wr-main.wr-has-tabs { padding-bottom: calc(6.5rem + env(safe-area-inset-bottom)); }

.wr-tabbar {
  position: fixed;
  inset: auto 0 0 0;
  z-index: 10;
  display: flex;
  justify-content: space-around;
  align-items: flex-end;
  /* On iPhones the home indicator needs `safe-area-inset-bottom` (34px) of clear space; that's
     the bar's bottom padding by itself, not added to ours, as in Apple's own tab bars. */
  padding: 0.35rem 0.5rem max(0.35rem, env(safe-area-inset-bottom));
  background: var(--wr-glass);
  -webkit-backdrop-filter: blur(14px);
  backdrop-filter: blur(14px);
  border-top: 1px solid var(--wr-line);
}
.wr-tab {
  position: relative;
  flex: 1 1 0;
  max-width: 6rem;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.2rem;
  padding: 0.4rem 0 0.2rem;
  color: var(--wr-dim);
  font-size: 0.72rem;
  font-weight: 600;
  text-decoration: none;
}
/* ANCHOR: tab_label */
/* One line, always: a label that wrapped would lift its icon above the others and make the bar
   taller (the Phase 6 phone check, when Home was a raised circle that the bar's edge touched). Tab names are one
   word (`NavEntry::tab_label`); this is the safety net if one is still too wide. */
.wr-tab-label {
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* ANCHOR_END: tab_label */
.wr-tab[aria-current="page"] { color: var(--wr-text); }
/* ANCHOR: current_tab */
/* The current tab (the owner's choice, 2026-11-05: no raised Home circle): its icon turns cyan,
   and a short cyan line with a soft glow marks it along the bar's top edge (shell/tabbar.html). */
.wr-tab[aria-current="page"] { font-weight: 800; }
.wr-tab[aria-current="page"] .wr-icon { color: var(--wr-cyan); }
.wr-tab-line {
  position: absolute;
  top: -0.36rem;
  width: 1.75rem;
  height: 2px;
  border-radius: 2px;
  background: var(--wr-cyan);
  box-shadow: 0 0 10px rgba(var(--wr-cyan-rgb), 0.7);
}
/* A tapped tab looks current straight away, while the next page loads (motion.js, "tab_going"). */
.wr-tab.wr-tab-going { color: var(--wr-text); }
.wr-tab.wr-tab-going .wr-icon,
.wr-tab:active .wr-icon { color: var(--wr-cyan); }
/* ANCHOR_END: current_tab */

/* The navigation list: the desktop sidebar and the phone menu page. Pico lays out <nav> and its
   lists as a horizontal bar; these rules turn that into a vertical list. */
.wr-nav { display: flex; flex-direction: column; align-items: stretch; }
.wr-nav ul { display: flex; flex-direction: column; align-items: stretch; gap: 0.15rem; margin: 0; padding: 0; }
.wr-nav li { display: block; list-style: none; margin: 0; padding: 0; }
/* Pico pulls a nav's first and last lists outwards with negative margins, using selectors
   (`nav ul:first-of-type`) more specific than `.wr-nav ul`; this matches them. */
.wr-nav ul:is(:first-of-type, :last-of-type) { margin-inline: 0; }
.wr-nav li a,
.wr-nav li button.wr-navbtn {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  width: 100%;
  margin: 0;
  padding: 0.6rem 0.75rem;
  border: 0;
  border-radius: 0.6rem;
  background: transparent;
  box-shadow: none;
  color: var(--wr-muted);
  font-size: 0.95rem;
  text-align: left;
  text-decoration: none;
}
.wr-nav li button.wr-navbtn .wr-icon { margin: 0; width: 1.4rem; height: 1.4rem; }
/* Sign out is a button (it posts), but reads like the links around it. */
.wr-nav li button.wr-navbtn { font-weight: 400; }
.wr-nav li a:hover,
.wr-nav li button.wr-navbtn:hover { background: var(--wr-raised); color: var(--wr-text); }
.wr-nav li a[aria-current="page"] { background: var(--wr-raised); color: var(--wr-text); font-weight: 700; box-shadow: inset 2px 0 0 var(--wr-cyan); }
.wr-nav li a[aria-current="page"] .wr-icon { color: var(--wr-cyan); }
.wr-nav form { margin: 0; }
.wr-nav-heading {
  margin: 1.1rem 0 0.35rem;
  padding: 0 0.75rem;
  color: var(--wr-muted);
  font-size: 0.72rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}
/* `ul.` raises the specificity above `.wr-nav ul`, which resets every list's margin and padding. */
.wr-nav ul.wr-nav-foot { margin-top: 1.1rem; padding-top: 0.9rem; border-top: 1px solid var(--wr-border); }
.wr-who { margin: 0.75rem 0 0; padding: 0 0.75rem; color: var(--wr-muted); font-size: 0.85rem; }
/* The phone menu page: bigger rows, easy to hit with a thumb. */
.wr-menu li a,
.wr-menu li button.wr-navbtn { padding: 0.85rem 0.75rem; font-size: 1.05rem; }

/* ---------------------------------------------------------------- the shell: desktop */

@media (min-width: 768px) {
  .wr-topbar,
  .wr-tabbar { display: none; }
  .wr-layout {
    display: grid;
    grid-template-columns: 15.5rem minmax(0, 1fr);
    min-height: 100vh;
  }
  .wr-sidebar {
    display: flex;
    flex-direction: column;
    gap: 1.5rem;
    position: sticky;
    top: 0;
    height: 100vh;
    overflow-y: auto;
    padding: 1.4rem 0.9rem;
    border-right: 1px solid var(--wr-line);
  }
  .wr-sidebar .wr-brand { padding: 0 0.5rem; }
  .wr-sidebar .wr-wordmark { font-size: 1.05rem; }
  /* Account and sign-out sit at the bottom of the sidebar. */
  .wr-sidebar .wr-nav { flex: 1; }
  .wr-sidebar .wr-nav ul.wr-nav-foot { margin-top: auto; }
  .wr-main,
  .wr-main.wr-has-tabs { padding: 2.25rem 2.5rem 3rem; }
  /* The brand and the fold button share the top row. */
  .wr-sidebar-top { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; }
  .wr-side-toggle { display: inline-flex; align-items: center; justify-content: center; width: 2.25rem; height: 2.25rem; margin: 0; padding: 0; flex: none; border-color: var(--wr-border); color: var(--wr-muted); }
  .wr-side-toggle[hidden] { display: none; }
  .wr-side-toggle .wr-icon { margin: 0; }
  /* Folded (static/js/sidebar.js; the owner, 2026-11-08): a strip of icons, so a phone turned
     sideways shows more of the page. The names stay for screen readers; counts stay on the icon. */
  html[data-nav="collapsed"] .wr-layout { grid-template-columns: 4.5rem minmax(0, 1fr); }
  html[data-nav="collapsed"] .wr-sidebar { padding: 1.2rem 0.5rem; align-items: center; }
  html[data-nav="collapsed"] .wr-sidebar-top { flex-direction: column; }
  html[data-nav="collapsed"] .wr-sidebar .wr-brand { padding: 0; }
  html[data-nav="collapsed"] .wr-sidebar .wr-wordmark,
  html[data-nav="collapsed"] .wr-sidebar .wr-nav-heading { display: none; }
  html[data-nav="collapsed"] .wr-sidebar .wr-nav a,
  html[data-nav="collapsed"] .wr-sidebar .wr-nav button.wr-navbtn { position: relative; justify-content: center; padding-left: 0.5rem; padding-right: 0.5rem; }
  /* The name is the link's one span without a class (the icon and the count have theirs). */
  html[data-nav="collapsed"] .wr-sidebar .wr-nav a > span:not([class]),
  html[data-nav="collapsed"] .wr-sidebar .wr-nav button.wr-navbtn > span:not([class]) {
    position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap;
  }
  html[data-nav="collapsed"] .wr-sidebar .wr-nav .wr-badge { position: absolute; top: 0; left: calc(50% + 0.3rem); right: auto; margin: 0; font-size: 0.6rem; }
  html[data-nav="collapsed"] .wr-sidebar .wr-nav ul { padding: 0; }
}
/* ANCHOR_END: shell */

/* ---------------------------------------------------------------- dashboard cards */

/* ANCHOR: ticker_css */
/* Home's greeting and ticker cards (the final draft): Incoming and Outgoing side by side, even
   on a phone, then "Left this month" across the full width. */
.wr-greeting { margin-bottom: 1.25rem; }
.wr-greeting h1 { margin-bottom: 0.25rem; }
.wr-greeting p { margin: 0; color: var(--wr-muted); }
.wr-ticker {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0.65rem;
  max-width: 44rem;
  margin-bottom: 0.5rem;
}
.wr-ticker-note { margin: 0 0 1.5rem; }
.wr-tick {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  min-width: 0;
  padding: 1rem;
  border: 1px solid var(--wr-border);
  border-radius: var(--wr-radius);
  background: var(--wr-card);
  color: var(--wr-text);
  text-decoration: none;
  transition: border-color 0.15s, background-color 0.15s;
}
a.wr-tick:hover { border-color: var(--wr-border-strong); background: var(--wr-raised); }
/* One line, arrow and all: the size follows the phone's width so "▲ $12,345.67" still fits in
   half a 360px screen (a wrapped arrow sat alone above the figure). */
.wr-tick-figure { font-size: clamp(0.95rem, 4.6vw, 1.35rem); font-weight: 500; letter-spacing: -0.02em; white-space: nowrap; }
.wr-tick-line { color: var(--wr-muted); font-family: var(--wr-font-mono); font-size: clamp(0.68rem, 3vw, 0.78rem); }
.wr-tick-left {
  grid-column: 1 / -1;
  flex-direction: row;
  align-items: center;
  justify-content: space-between;
}
.wr-tick-left > span:first-child { display: grid; gap: 0.15rem; }
.wr-tick-left .wr-tick-line { font-family: var(--wr-font); font-size: 0.8rem; }
.wr-tick-left .wr-tick-figure { font-size: 1.2rem; }
@media (min-width: 768px) {
  .wr-tick-figure { font-size: 1.6rem; }
}
/* ANCHOR_END: ticker_css */

.wr-cards {
  display: grid;
  gap: 1rem;
  grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
}
.wr-card {
  display: flex;
  flex-direction: column;
  gap: 0.45rem;
  padding: 1.15rem 1.25rem;
  border: 1px solid var(--wr-border);
  border-radius: var(--pico-border-radius);
  background: var(--wr-card);
  color: var(--wr-text);
  text-decoration: none;
  transition: border-color 0.15s, box-shadow 0.15s;
}
.wr-card:hover {
  border-color: var(--wr-border-strong);
  background: var(--wr-raised);
}
.wr-card-head { display: flex; align-items: center; gap: 0.55rem; color: var(--wr-muted); font-size: 0.9rem; }
.wr-card-headline { font-size: 1.2rem; font-weight: 800; }
.wr-card-detail { color: var(--wr-muted); font-size: 0.9rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Settings → Animations and sounds: one row per switch, its name and a line about it on the left
   and the switch on the right, divided by a hairline. */
.wr-setting {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  margin: 0;
  padding: 0.75rem 0;
  cursor: pointer;
}
.wr-setting + .wr-setting { border-top: 1px solid var(--wr-line); }
.wr-setting > span { display: grid; gap: 0.15rem; }
.wr-setting small { color: var(--wr-muted); font-size: 0.85rem; }
.wr-setting input[role="switch"] { flex: none; margin: 0; }
#motion-sounds-saved:not(:empty) { margin-top: 0.75rem; }

/* Radio choices drawn as tappable rows (Settings → Appearance). */
.wr-choices { display: grid; gap: 0.5rem; margin-bottom: 1rem; }
.wr-choice {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin: 0;
  padding: 0.75rem 0.9rem;
  border: 1px solid var(--wr-border);
  border-radius: var(--pico-border-radius);
  background: var(--wr-raised);
  cursor: pointer;
}
/* `flex: none`: when a label wraps onto two lines, a flex row shrinks its items to fit, and the
   radio was squeezed into an upright oval (phone review, 2026-10-16). It keeps its size now. */
.wr-choice input { margin: 0; flex: none; }
/* Tick boxes are squares with soft corners. Pico rounds them with the theme's corner radius
   (0.65rem), which on a 20px box is nearly a circle: every checkbox looked like a radio button,
   which means "pick one" (seen on Settings → Dashboard, 2026-10-17). Switches keep their pill. */
input[type="checkbox"]:not([role="switch"]) { border-radius: 0.3rem; }

/* ANCHOR: card_order */
/* Settings → Dashboard: one row per tool, the tick box filling the row and the arrows at its
   end. Each arrow is a 44px square, the comfortable minimum for a thumb. */
.wr-card-order { margin: 0 0 1rem; padding: 0; }
.wr-card-order li {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin: 0 0 0.5rem;
  list-style: none;
}
.wr-card-order .wr-choice { flex: 1; min-width: 0; }
.wr-card-moves { display: flex; flex: none; gap: 0.4rem; }
.wr-card-moves button {
  display: grid;
  place-items: center;
  width: 2.75rem;
  height: 2.75rem;
  margin: 0;
  padding: 0;
}
.wr-card-moves .wr-icon { width: 1.2rem; height: 1.2rem; }
/* Pages land on a section after a save without JavaScript (#dashboard-cards, #support-access);
   keep its heading clear of the sticky top bar. */
.wr-main article[id] { scroll-margin-top: 5rem; }
/* ANCHOR_END: card_order */
/* Every option as wide as the list, whatever its text (Pico's labels otherwise fit their content). */
.wr-choices .wr-choice { width: 100%; }
/* Pico draws a checked radio with the primary *border* colour, which is transparent here (the
   buttons use a gradient instead), so every selected radio needs its own ring. One rule for all of
   them: a per-component rule missed the fit questions, whose answers vanished when chosen (AI2;
   web/tests/views/radios.rs keeps it). */
input[type="radio"]:checked { border-color: var(--wr-cyan); background-color: var(--wr-bg); }
.wr-choice:has(input:checked) { border-color: var(--wr-cyan); background: rgba(var(--wr-cyan-rgb), 0.08); }

/* Forms and record cards stay a readable width on wide screens. */
.wr-main > article { max-width: 44rem; }

/* A page title with an action beside it (e.g. "Mark all as read"). */
.wr-title-row { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 0.75rem; margin-bottom: 1rem; }
.wr-title-row h1 { margin: 0; }
.wr-title-row form { margin: 0; }
.wr-title-actions { display: flex; flex-wrap: wrap; gap: 0.5rem; }
button.wr-small { width: auto; margin: 0; padding: 0.4rem 0.8rem; font-size: 0.85rem; display: inline-flex; align-items: center; }

/* ---------------------------------------------------------------- notifications */

.wr-notices { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.5rem; }
.wr-notices li { list-style: none; margin: 0; }
.wr-notices form { margin: 0; }
/* The notification (it opens it) and a delete button beside it. */
.wr-notice-row { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 0.4rem; align-items: stretch; }
.wr-notice-row form { display: flex; }
button.secondary.wr-notice-delete {
  display: grid;
  place-items: center;
  width: 2.75rem;   /* 44px touch target */
  margin: 0;
  padding: 0;
  background: var(--wr-card);
  border: 1px solid var(--wr-border);
  color: var(--wr-muted);
}
button.secondary.wr-notice-delete:hover { background: var(--wr-raised); }
button.wr-notice-delete .wr-icon { margin: 0; width: 1.15rem; height: 1.15rem; }
/* Each notification is a full-width button (it opens it); laid out as icon | text | time. */
/* `.secondary.` matches the second-button rules' specificity (`[type="submit"].secondary`),
   which would otherwise paint the notice indigo. */
button.secondary.wr-notice {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: start;
  gap: 0.85rem;
  width: 100%;
  margin: 0;
  padding: 0.9rem 1rem;
  text-align: left;
  color: var(--wr-text);
  background: var(--wr-card);
  border: 1px solid var(--wr-border);
  font-weight: 400;
}
button.secondary.wr-notice:hover { background: var(--wr-raised); }
.wr-notice-text { display: grid; gap: 0.2rem; }
.wr-notice-title { font-weight: 500; }
.wr-notice-body { color: var(--wr-muted); font-size: 0.9rem; white-space: pre-line; }
.wr-notice-when { color: var(--wr-muted); font-size: 0.8rem; white-space: nowrap; }
/* Unread: bold title, a gradient edge, and the gradient on the time. */
button.secondary.wr-notice-unread { border-color: var(--wr-indigo); box-shadow: inset 3px 0 0 var(--wr-indigo); }
button.wr-notice-unread .wr-notice-title { font-weight: 600; }

/* Empty states: a large icon and a short line. */
.wr-empty { display: grid; justify-items: center; gap: 0.25rem; padding: 3rem 1rem; text-align: center; }
.wr-empty .wr-icon { width: 2.5rem; height: 2.5rem; margin-bottom: 0.75rem; }
.wr-empty p { margin: 0; }

/* ---------------------------------------------------------------- help, privacy, terms */

/* Public pages (not signed in): a slim brand bar instead of the shell. */
.wr-public-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding-bottom: 1rem;
  margin-bottom: 1.5rem;
  border-bottom: 1px solid var(--wr-border);
}
.wr-public-head .wr-wordmark { font-size: 1.05rem; }
.wr-legal-links { margin: 1rem 0 0; text-align: center; font-size: 0.85rem; color: var(--wr-muted); }
.wr-legal-links a { color: var(--wr-muted); }
.wr-who.wr-legal-links { text-align: left; margin-top: 0.35rem; }
.wr-version { font-size: 0.85rem; }
/* The ownership line at the bottom of every page. */
.wr-footer {
  margin-top: 3rem;
  padding-top: 1rem;
  border-top: 1px solid var(--wr-border);
  font-size: 0.8rem;
  color: var(--wr-muted);
  text-align: center;
}
.wr-footer p { margin: 0; color: inherit; }
/* Headings with an icon in front. */
article h2 .wr-icon { margin-right: 0.35rem; vertical-align: -0.2em; }
/* FAQ: one row per question, divided by hairlines. Pico floats the chevron (`summary::after`),
   which drifts when a question wraps; as a flex item it stays at the right edge. */
.wr-faq details { margin: 0; padding: 0.8rem 0; border-bottom: 1px solid var(--wr-border); }
.wr-faq details:last-of-type { border-bottom: 0; padding-bottom: 0; }
.wr-faq summary { display: flex; align-items: center; justify-content: space-between; gap: 0.75rem; font-weight: 500; }
.wr-faq summary::after { flex: none; float: none; margin-left: auto; }
.wr-faq details p { margin: 0.6rem 0 0; color: var(--wr-muted); }
/* Long-form text: a readable line length. */
.wr-prose { max-width: 44rem; }
.wr-prose h2 { margin-top: 1.75rem; }
/* "This is a draft" banner on the legal pages. */
.wr-draft {
  border-left: 3px solid var(--wr-indigo);
  background: rgba(var(--wr-indigo-rgb), 0.08);
  padding: 0.75rem 1rem;
  border-radius: var(--pico-border-radius);
  max-width: 44rem;
}

/* Settings → Sample data (book: "Sample data"): one block per set, its story folded away. */
.wr-sample-set { margin: 1rem 0; padding-top: 1rem; border-top: 1px solid var(--wr-border); }
.wr-sample-set details { margin-bottom: 0.75rem; }
.wr-sample-set details p { max-width: 44rem; color: var(--wr-muted); }
.wr-sample-story { margin-bottom: 1rem; }
.wr-sample-story p { max-width: 44rem; }
.wr-facts.wr-sample-counts { margin-bottom: 1rem; }
/* The first-visit offer on Home. */
.wr-offer { border: 1px solid var(--wr-indigo); }
.wr-offer-actions { display: flex; flex-wrap: wrap; gap: 0.75rem; }
.wr-offer-actions form,
.wr-offer-actions button { margin: 0; }

/* ---------------------------------------------------------------- admin panel */

/* A label/value list (client details). */
.wr-facts { display: grid; grid-template-columns: max-content 1fr; gap: 0.4rem 1.25rem; margin: 0; }
.wr-facts dt { color: var(--wr-muted); font-weight: 400; }
.wr-facts dd { margin: 0; overflow-wrap: anywhere; }
/* Rows with something on the left and an action or time on the right. */
.wr-switches,
.wr-log { list-style: none; margin: 0; padding: 0; }
.wr-switches li,
.wr-log li {
  list-style: none;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.55rem 0;
  border-bottom: 1px solid var(--wr-border);
}
.wr-switches li:last-child,
.wr-log li:last-child { border-bottom: 0; }
.wr-switches span { display: inline-flex; align-items: center; gap: 0.6rem; }
.wr-switches form { margin: 0; }
.wr-log small { white-space: nowrap; }
.wr-feed .wr-feed-what { display: block; margin-top: 0.15rem; }
.wr-actions { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-bottom: 0.75rem; }
.wr-actions form { margin: 0; }
/* The support view's banner: unmistakable, so the admin always knows whose data this is. */
.wr-support-banner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  margin-bottom: 1.25rem;
  padding: 0.7rem 0.9rem;
  border: 1px solid var(--wr-indigo);
  border-radius: var(--wr-radius-sm);
  background: rgba(var(--wr-indigo-rgb), 0.1);
}
.wr-support-banner > span { display: inline-flex; align-items: center; gap: 0.5rem; }
.wr-support-banner form { margin: 0; }
/* Messages: the client checklist only with "Chosen clients", the group list only with "A group". */
.wr-message-form:not(:has(input[name="audience"][value="chosen"]:checked)) .wr-audience-chosen,
.wr-message-form:not(:has(input[name="audience"][value="group"]:checked)) .wr-audience-group {
  display: none;
}
/* Two buttons side by side: the support banner's, and each row of the admin's Support page. */
.wr-support-actions { display: inline-flex; flex-wrap: wrap; gap: 0.5rem; }
.wr-support-actions form { margin: 0; }
/* The support access switch (Help & support): a little air before the text that explains it. */
.wr-switch-form { margin-bottom: 1rem; }
/* Admin → a client → AI: room between "Save allowance" and the test button below it (D4). */
.wr-ai-cap { margin-bottom: 1rem; }

/* A one-time secret (the temporary password): large, monospace, easy to copy. */
.wr-secret code {
  display: inline-block;
  padding: 0.6rem 0.9rem;
  font-family: var(--wr-font-mono);
  font-size: 1.15rem;
  letter-spacing: 0.04em;
  user-select: all;
}
[role="button"].wr-small { display: inline-flex; align-items: center; width: auto; margin: 0; padding: 0.4rem 0.8rem; font-size: 0.85rem; }

/* ---------------------------------------------------------------- PWA: the update banner */

/* ANCHOR: update_banner */
.wr-update {
  position: fixed;
  left: max(1rem, env(safe-area-inset-left));
  right: max(1rem, env(safe-area-inset-right));
  bottom: calc(1rem + env(safe-area-inset-bottom));
  z-index: 20;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  padding: 0.7rem 0.8rem 0.7rem 1rem;
  border: 1px solid rgba(var(--wr-cyan-rgb), 0.45);
  border-radius: var(--wr-radius);
  background: var(--wr-raised);
  box-shadow: 0 10px 30px -12px rgba(0, 0, 0, 0.6);
  font-size: 0.9rem;
}
.wr-update[hidden] { display: none; }
.wr-update button { flex: none; }
/* Phones: sit above the tab bar. Desktop: a small card in the bottom-right corner. */
@media (max-width: 767px) {
  body:has(.wr-tabbar) .wr-update { bottom: calc(5.75rem + env(safe-area-inset-bottom)); }
}
@media (min-width: 768px) {
  .wr-update { left: auto; max-width: 26rem; }
}
/* ANCHOR_END: update_banner */

/* Notes and other record lists. */
.wr-note header { display: flex; justify-content: space-between; align-items: baseline; gap: 1rem; }
.wr-note p { white-space: pre-line; }

/* ANCHOR: records */
/* Tool pages ported from v1 (ADR-0011): the forms fold away like v1's collapsible form cards
   (open when there's something to do in them), and each saved record is a card. */
.wr-lead { max-width: 44rem; }
/* Back, above a page's title (layouts/base.html). A 44px-tall tap target, kept quiet. */
.wr-back { display: inline-flex; align-items: center; gap: 0.35rem; min-height: 2.75rem; margin: -0.5rem 0 0.25rem; color: var(--wr-muted); text-decoration: none; }
.wr-back:hover { color: var(--wr-text); }
.wr-back .wr-icon { width: 1.15rem; height: 1.15rem; }
/* Under a tool's intro: how its data is protected, and the planned AI writer (wr.tool_notes). */
.wr-tool-notes { max-width: 44rem; margin: -0.25rem 0 1.5rem; padding: 0; }
.wr-tool-notes li { display: flex; gap: 0.6rem; align-items: flex-start; margin: 0 0 0.4rem; list-style: none; font-size: 0.875rem; color: var(--wr-muted); }
.wr-tool-notes .wr-icon { width: 1.1rem; height: 1.1rem; margin-top: 0.1rem; }
details.wr-form-card {
  max-width: 44rem;
  margin-bottom: 1.25rem;
  padding: 0.9rem 1.1rem;
  border: 1px solid var(--wr-border);
  border-radius: var(--pico-border-radius);
  background: var(--wr-card);
}
/* The title (and its one-line summary) on the left, Pico's open/close arrow top-right. */
details.wr-form-card > summary { display: flex; align-items: flex-start; gap: 0.75rem; font-weight: 600; }
details.wr-form-card > summary::after { flex: none; float: none; margin-left: auto; }
details.wr-form-card[open] > summary { margin-bottom: 0.75rem; }
.wr-summary-line { display: block; margin-top: 0.2rem; font-weight: 400; font-size: 0.85rem; color: var(--wr-muted); }
.wr-form-card-note { color: var(--wr-muted); font-size: 0.9rem; }
.wr-records { display: grid; gap: 0.75rem; max-width: 44rem; }
.wr-records > h2 { margin-bottom: 0; }
.wr-records > p { margin: 0; }
.wr-record { margin: 0; padding: 1rem 1.1rem; scroll-margin-top: 5rem; }
/* Job Tracker (v1's cards): the title with its status badge, and notes that keep their lines. */
.wr-track-head { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: 0.25rem 0.75rem; }
.wr-track-head h3 { margin-bottom: 0.25rem; }
/* Status badges (the draft): indigo while it's still to do (Saved), teal once applied and
   moving (Applied to Offer), grey when it's over (Rejected, Withdrawn). 6px corners, bold. */
.wr-track-badge {
  padding: 0.05rem 0.5rem;
  border: 1px solid var(--wr-indigo);
  border-radius: 6px;
  color: var(--wr-indigo-text);
  font-size: 0.78rem;
  font-weight: 700;
  white-space: nowrap;
}
.wr-track-badge:is(.is-applied, .is-screening, .is-interview, .is-offer) { border-color: var(--wr-teal); color: var(--wr-teal-text); }
.wr-track-badge:is(.is-rejected, .is-withdrawn) { border-color: var(--wr-border-strong); color: var(--wr-muted); }
/* ANCHOR: tracker_filter */
/* The Job Tracker's filter (the draft's segmented control): All, Preparing or Applied. Plain
   radio buttons and `:has()`, so it needs no script and sends nothing. */
.wr-tracker-filter { margin: 0 0 1rem; padding: 0; border: 0; }
main:has(.wr-tracker-filter input[value="preparing"]:checked) .wr-track-apps,
main:has(.wr-tracker-filter input[value="applied"]:checked) .wr-track-prep { display: none; }
/* ANCHOR_END: tracker_filter */
.wr-track-notes { white-space: pre-line; }
/* Fetch details: the button and "Reading the posting…" under the posting link, then the notice. */
.wr-fetch { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem 0.75rem; margin-bottom: var(--pico-spacing); }
.wr-fetch button { margin: 0; }
.wr-fetch-notice { padding: 0.6rem 0.8rem; border-left: 3px solid var(--wr-cyan); }
/* A Job Search card's tracker row: the Save to tracker button, or v1's "In your Job Tracker" line,
   with room before View description. */
.wr-jobs-card-track { margin-bottom: 0.9rem; }
.wr-jobs-card-track form { margin: 0; }
.wr-jobs-card-tracked { margin: 0; color: var(--wr-muted); font-size: 0.9rem; }
/* The Apply kit (RL3, tools/job-tracker/apply.html): "Did you apply?" when the client comes back
   from the posting, then the copy rows: label, the value (all of it in the page; long ones show
   three lines) and Copy. On a phone the label sits above the value. */
.wr-kit-section { margin-top: 2rem; }
.wr-apply-prompt { margin: 1rem 0; padding: 0.75rem 1rem; border-left: 3px solid var(--wr-cyan); }
.wr-apply-prompt p { margin-bottom: 0.25rem; }
/* Each copy group folds (RL4): a `<details>` that starts closed, its name and field count in the
   summary, so the page is a short list until the client opens the one they need. */
/* Rows with a line between them and room to tap (at least 44px tall on a phone). */
.wr-kit-group { margin: 0; border-bottom: 1px solid var(--wr-border); }
.wr-kit-group:first-of-type { border-top: 1px solid var(--wr-border); }
.wr-kit-group > summary { padding: 0.7rem 0; font-weight: 600; line-height: 1.35; }
.wr-kit-count { color: var(--wr-muted); font-weight: 400; font-size: 0.9rem; white-space: nowrap; }
.wr-kit-group[open] { padding-bottom: 0.75rem; }
.wr-kit-row {
  display: grid;
  grid-template-columns: 9rem 1fr auto;
  gap: 0.25rem 0.75rem;
  align-items: start;
  padding: 0.45rem 0;
  border-top: 1px solid var(--wr-border);
}
.wr-kit-row button { margin: 0; }
.wr-kit-label { color: var(--wr-muted); font-size: 0.875rem; }
.wr-kit-value {
  white-space: pre-line;
  overflow-wrap: anywhere;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 3;
  line-clamp: 3;
  overflow: hidden;
}
@media (max-width: 576px) {
  .wr-kit-row { grid-template-columns: 1fr auto; }
  .wr-kit-label { grid-column: 1 / -1; }
}
/* The AI Assistant's page (AI1, tools/ai/index.html): its sections spaced like the Apply kit's. */
.wr-ai-section { margin-top: 2rem; }
.wr-ai-section ul { padding-left: 1.25rem; }
/* Guided AI tailoring (AI2, tools/job-tracker/_tailor.html): the wait (a spinner above the words),
   the requirements, one fieldset per question, and the truthfulness reminder. */
/* The section is scrolled to after the answers are saved (htmx's show:top, or #tailor without
   JavaScript): keep its saved line clear of the sticky top bar. */
#tailor { scroll-margin-top: 5rem; }
.wr-tailor-wait {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.75rem;
  padding: 2rem 1rem;
  color: var(--wr-muted);
  font-weight: 500;
  text-align: center;
}
.wr-tailor-list { list-style: none; padding: 0; }
.wr-tailor-list li { display: flex; gap: 0.5rem; align-items: flex-start; margin-bottom: 0.5rem; }
.wr-tailor-question { margin-bottom: 1rem; }
.wr-tailor-replies { display: flex; flex-wrap: wrap; gap: 0.25rem 1.25rem; margin-bottom: 0.5rem; }
.wr-review-badge { display: flex; gap: 0.4rem; align-items: center; color: var(--wr-muted); font-size: 0.9rem; }
.wr-tailor-reminder { display: flex; gap: 0.5rem; align-items: flex-start; font-weight: 500; }
/* ANCHOR: pdf_viewer */
/* The in-app PDF viewer (RL4, tools/resumes-letters/view.html): each page drawn on white paper,
   one under another, as wide as the column allows. Until the first page is drawn, a page-shaped
   placeholder shimmers, with a spinner above the words near its top, so it's in view on a phone. */
.wr-pdf { max-width: 50rem; margin: 1rem 0; }
.wr-pdf-page {
  display: block;
  width: 100%;
  height: auto;
  margin: 0 0 1rem;
  background: #fff; /* paper stays white in the dark theme */
  border-radius: 0.25rem;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.25);
}
.wr-pdf-loading {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.75rem;
  aspect-ratio: 8.5 / 11;
  padding-top: 4rem;
  border-radius: 0.25rem;
  color: var(--wr-muted);
  font-weight: 500;
  text-align: center;
  background: linear-gradient(90deg, var(--wr-hover) 30%, var(--wr-border-strong) 50%, var(--wr-hover) 70%);
  background-size: 300% 100%;
  animation: wr-shimmer 1.4s ease-in-out infinite;
}
.wr-pdf-loading.wr-pdf-failed { animation: none; background: var(--wr-hover); }
.wr-pdf-fallback { color: var(--wr-muted); font-size: 0.9rem; }
@media (prefers-reduced-motion: reduce) {
  .wr-pdf-loading { animation: wr-pulse 1.6s ease-in-out infinite !important; }
  .wr-pdf-loading.wr-pdf-failed { animation: none !important; }
}
/* ANCHOR_END: pdf_viewer */
.wr-record h3 { margin: 0 0 0.4rem; font-size: 1.05rem; }
.wr-record p { margin-bottom: 0.5rem; white-space: pre-line; overflow-wrap: anywhere; }
.wr-record-actions { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-top: 0.75rem; }
.wr-record-actions form { margin: 0; }
/* After a save the page jumps to the saved card (`#pip-12`); outline it so it's easy to spot. */
.wr-record:target { outline: 2px solid var(--wr-teal); outline-offset: 2px; }
/* Suggestions (nothing saved yet): dashed and flat, so they read as "not yours yet". */
.wr-suggest { border: 1px dashed var(--wr-border); background: transparent; box-shadow: none; }
.wr-suggest-tag { margin-bottom: 0.25rem; font-size: 0.75rem; letter-spacing: 0.06em; text-transform: uppercase; color: var(--wr-muted); }
a[role="button"].wr-small { width: auto; margin: 0; padding: 0.4rem 0.8rem; font-size: 0.85rem; display: inline-flex; align-items: center; }
/* ANCHOR_END: records */

/* ANCHOR: employment */
/* Employment's form: v1 switched between a job's and a career gap's fields, and between
   calendar dates and a season, with a script. Here CSS does it: `:has()` asks the form whether
   the "Career gap" radio or the "Is seasonal" box is checked. Without `:has()` (old browsers)
   every field shows, and the server still reads only the ones that apply. */
.wr-gap-only,
.wr-seasonal-only { display: none; }
form:has(input[name="kind"][value="gap"]:checked) .wr-job-only { display: none; }
form:has(input[name="kind"][value="gap"]:checked) .wr-gap-only { display: inline; }
form:has(#f-is_seasonal:checked):not(:has(input[name="kind"][value="gap"]:checked)) .wr-seasonal-only { display: block; }
form:has(#f-is_seasonal:checked):not(:has(input[name="kind"][value="gap"]:checked)) .wr-calendar-dates { display: none; }
/* ANCHOR: segmented */
/* The segmented control (the Crisp draft): a row of choices in one hairline frame, the chosen one
   lifted onto the raised grey. Each choice is a real radio button inside its label, kept for
   keyboards and screen readers but drawn by its label; the focus ring goes on the label. */
.wr-seg {
  display: flex;
  flex-wrap: wrap;
  gap: 3px;
  width: fit-content;
  max-width: 100%;
  margin-bottom: 0.4rem;
  padding: 3px;
  border: 1px solid var(--wr-border);
  border-radius: var(--wr-radius-sm);
}
.wr-seg label {
  position: relative;
  display: inline-flex;
  align-items: center;
  margin: 0;
  padding: 0.45rem 0.9rem;
  border-radius: 7px;
  color: var(--wr-muted);
  font-size: 0.92rem;
  cursor: pointer;
  transition: background-color 0.2s, color 0.2s;
}
.wr-seg input {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  opacity: 0;
  cursor: pointer;
}
.wr-seg label:has(input:checked) { background: var(--wr-raised); color: var(--wr-text); font-weight: 700; }
.wr-seg label:has(input:focus-visible) { outline: 2px solid var(--wr-teal); outline-offset: 1px; }
/* ANCHOR_END: segmented */
.wr-kind small { display: block; margin-top: 0.25rem; }
.wr-check { display: flex; align-items: center; gap: 0.5rem; margin-bottom: 0.25rem; }
.wr-check input { margin: 0; flex: none; }
.wr-employment-form fieldset:not(:first-child) { margin-top: 1rem; }
.wr-employment-form fieldset > legend { font-weight: 600; margin-bottom: 0.5rem; }
.wr-employment-form small { color: var(--wr-muted); }
/* ANCHOR_END: employment */

/* ANCHOR: education */
/* Education's form: each kind's fields (v1 switched them with a script). School / degree is the
   default, so its parts show unless another kind is checked. `display: revert` gives an element
   back its normal display (block for a div, inline for a span). */
.wr-edu-hs,
.wr-edu-online { display: none; }
form:has(input[name="kind"][value="high_school"]:checked) .wr-edu-hs { display: revert; }
form:has(input[name="kind"][value="online"]:checked) .wr-edu-online { display: revert; }
form:has(input[name="kind"][value="high_school"]:checked) .wr-edu-school,
form:has(input[name="kind"][value="online"]:checked) :is(.wr-edu-school, .wr-edu-not-online) { display: none; }
.wr-education-form small { color: var(--wr-muted); }
/* ANCHOR_END: education */

/* Skillset Profiles: suggested skills as tappable chips (v1's), each a real checkbox or radio
   button inside a pill, wrapping onto as many lines as they need. A ticked chip is tinted. */
.wr-chips-field { margin: 1.25rem 0 0.5rem; }
.wr-chips-field legend { font-weight: 600; margin-bottom: 0.25rem; }
.wr-chips-help { display: block; color: var(--wr-muted); margin-bottom: 0.5rem; }
.wr-chips { display: flex; flex-wrap: wrap; gap: 0.45rem; margin: 0 0 0.6rem; }
.wr-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  margin: 0;
  padding: 0.45rem 0.8rem;
  border: 1px solid var(--wr-border);
  border-radius: 999px;
  background: var(--wr-raised);
  font-size: 0.92rem;
  cursor: pointer;
}
.wr-chip input { margin: 0; flex: none; }
.wr-chip:has(input:checked) { border-color: var(--wr-cyan); background: rgba(var(--wr-cyan-rgb), 0.12); }
.wr-chips-more summary { color: var(--wr-muted); font-size: 0.9rem; margin-bottom: 0.5rem; }
.wr-chips-field small { display: block; color: var(--wr-muted); }
/* The guided form's numbered steps, and the O*NET credit under the search. */
.wr-step { margin-bottom: 1.5rem; }
.wr-step h2 { display: flex; align-items: center; gap: 0.6rem; font-size: 1.15rem; }
.wr-step-num {
  display: inline-grid;
  place-items: center;
  width: 1.8rem;
  height: 1.8rem;
  border-radius: 50%;
  background: var(--wr-cyan);
  color: var(--wr-on-cyan);
  font-size: 0.95rem;
  font-weight: 800;
  flex: none;
}
.wr-results { margin: 0.5rem 0 1rem; padding: 0; }
.wr-results li { list-style: none; margin: 0 0 0.4rem; }
.wr-credit { color: var(--wr-muted); font-size: 0.78rem; }

/* Application Profiles' pickers: the box, the skillset's Primary radio beside it, and a note
   when the record already comes along with another pick. */
.wr-ap-pick { margin-bottom: 0.45rem; }
.wr-ap-pick .wr-check { display: inline-flex; margin-right: 1rem; }
.wr-ap-primary { color: var(--wr-muted); font-size: 0.9rem; }
.wr-ap-note { display: block; margin: -0.1rem 0 0 1.9rem; color: var(--wr-muted); }

/* References' link pickers: one checkbox per job or education record. */
.wr-picker { margin-top: 1rem; }
.wr-picker legend { font-weight: 600; margin-bottom: 0.5rem; }
.wr-picker .wr-check { margin-bottom: 0.4rem; }
.wr-reference-form small { display: block; color: var(--wr-muted); }

/* ANCHOR: incoming */
/* Incoming Wages: the form's sections, projects per month only for per-project pay, and v1's
   two summary tiles. */
.wr-section { margin-top: 1rem; }
.wr-section > legend { font-weight: 600; margin-bottom: 0.5rem; }
.wr-incoming-form small,
.wr-from-job small { display: block; color: var(--wr-muted); }
.wr-per-project { display: none; }
form:has(select[name="pay_basis"] option[value="per_project"]:checked) .wr-per-project { display: block; }
.wr-from-job { margin-bottom: 1.25rem; padding-bottom: 1rem; border-bottom: 1px solid var(--wr-border); }
.wr-inline { display: flex; gap: 0.5rem; align-items: center; }
.wr-inline select { margin: 0; }
.wr-inline button { width: auto; margin: 0; flex: none; }
.wr-tiles { display: grid; gap: 0.75rem; grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr)); max-width: 44rem; margin-bottom: 0.5rem; }
.wr-tile { margin: 0; padding: 1rem 1.1rem; }
.wr-tile p { margin: 0; }
.wr-tile-label { font-size: 0.85rem; color: var(--wr-muted); }
.wr-tile-value { font-size: 1.35rem; font-weight: 600; margin: 0.15rem 0 0.35rem; }
.wr-tile-line { font-size: 0.85rem; color: var(--wr-muted); }
.wr-fineprint { max-width: 44rem; font-size: 0.8rem; }
.wr-pay-line { font-weight: 500; }
/* "Not counted yet" and the pay-rate check: a quiet note, not an error. */
.wr-check-note { border-left: 3px solid var(--wr-border); padding-left: 0.6rem; font-size: 0.9rem; }
/* ANCHOR_END: incoming */

/* ANCHOR: paychecks */
/* Paychecks: the form's groups of lines. On a phone a line is its category over its name and
   amount; wider, all three sit in one row. */
.wr-paycheck-form small { display: block; color: var(--wr-muted); }
.wr-more { margin: 0.5rem 0 1.25rem; }
.wr-more > summary { font-weight: 600; }
.wr-lines { margin: 1.25rem 0 0; padding-top: 1rem; border-top: 1px solid var(--wr-line); }
.wr-lines > legend { font-weight: 700; }
.wr-lines-note { margin: -0.25rem 0 0.75rem; }
.wr-line {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 7.5rem;
  gap: 0 0.5rem;
  margin-bottom: 0.5rem;
}
.wr-line select { grid-column: 1 / -1; }
.wr-line select,
.wr-line input { margin-bottom: 0.4rem; }
.wr-line .wr-line-error { grid-column: 1 / -1; margin: -0.2rem 0 0.4rem; color: var(--wr-red-text); }
@media (min-width: 768px) {
  .wr-line { grid-template-columns: minmax(0, 14rem) minmax(0, 1fr) 8rem; }
  .wr-line select { grid-column: auto; }
}
.wr-lines > button { margin-top: 0.25rem; }
.wr-form-buttons { display: flex; flex-wrap: wrap; gap: 0.75rem; margin-top: 1.5rem; }
.wr-form-buttons > * { width: auto; margin: 0; }

/* "Your paycheck": one stacked bar of where the gross pay went, its legend, then each group's
   lines. The bar's fills are chart colours, darker steps of the brand's roles (teal take-home,
   red taxes, indigo before-tax) plus amber for after-tax, checked as a set with the chart
   palette validator on the card's #1c1c1c (lightness band, colour-blind separation, 3:1 contrast;
   book: "Paychecks"). "Not listed" is a plain grey on purpose: it's the part no line explains. The
   legend says every part in words, so colour is never the only clue. */
.wr-paycheck-lead { font-size: 1.1rem; }
.wr-bar {
  display: block;
  width: 100%;
  height: 1.25rem;
  margin: 0.75rem 0;
  border-radius: 4px;
}
/* A 2px gap between parts: each part's 1px edge in the card's colour. */
.wr-bar rect { stroke: var(--wr-card); stroke-width: 1px; vector-effect: non-scaling-stroke; }
.wr-bar-take_home { fill: #0d9488; background: #0d9488; }
.wr-bar-taxes { fill: #e11d48; background: #e11d48; }
.wr-bar-before_tax { fill: #6366f1; background: #6366f1; }
.wr-bar-after_tax { fill: #d97706; background: #d97706; }
.wr-bar-not_listed { fill: #737373; background: #737373; }
.wr-bar-legend { list-style: none; margin: 0; padding: 0; }
.wr-bar-legend li {
  list-style: none;
  display: grid;
  grid-template-columns: 0.75rem minmax(0, 1fr) auto 3rem;
  gap: 0.6rem;
  align-items: center;
  margin: 0 0 0.35rem;
}
.wr-bar-legend li > :last-child { text-align: right; }
.wr-bar-key { width: 0.75rem; height: 0.75rem; border-radius: 3px; }
.wr-paycheck-group { margin-top: 1.75rem; }
.wr-paycheck-group-head { display: flex; justify-content: space-between; align-items: baseline; gap: 1rem; }
.wr-paycheck-group-head h2 { margin: 0; font-size: 1.15rem; }
.wr-paycheck-group > p { margin: 0.25rem 0 0.75rem; }
/* The lines sit a little in from their group's heading and total, so each group reads as one
   (the owner's testing, 2026-11-07). */
.wr-paycheck-lines { list-style: none; margin: 0; padding: 0 0 0 1rem; }
.wr-paycheck-lines li { list-style: none; margin: 0 0 0.75rem; padding-bottom: 0.6rem; border-bottom: 1px solid var(--wr-line); }
.wr-paycheck-line { display: flex; justify-content: space-between; gap: 1rem; }
.wr-paycheck-lines small { display: block; margin-top: 0.15rem; }
.wr-paycheck-card h3 a { color: inherit; text-decoration: none; }

/* Read a photo: the photo to cover, the full width of the card. `touch-action: none` lets a
   finger draw a box instead of scrolling the page. */
.wr-cover { margin-top: 1rem; }
.wr-cover canvas {
  display: block;
  width: 100%;
  height: auto;
  margin: 0.5rem 0 0.75rem;
  border: 1px solid var(--wr-border);
  border-radius: 8px;
  touch-action: none;
  cursor: crosshair;
}
.wr-cover [data-cover-send] { margin-top: 0.75rem; }
.wr-cover-sample { margin-bottom: 1.5rem; }
.wr-cover-pages { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; }
/* A stored photo, shown inside the app's file viewer (files/view.html). */
.wr-file-image { display: block; max-width: 100%; height: auto; border: 1px solid var(--wr-border); border-radius: 10px; margin: 1rem 0; }
/* A job's paychecks, folded until opened (the owner, 2026-11-07). */
.wr-paychecks-fold { margin: 0.25rem 0 0.75rem; }
.wr-paychecks-fold > summary { font-weight: 600; }
.wr-paychecks-fold[open] > summary { margin-bottom: 0.75rem; }
.wr-paychecks-fold .wr-paycheck-card { margin-bottom: 0.75rem; }
/* Each job's paychecks in a card of their own on the list, its paycheck cards a step raised
   inside it, so one job's paychecks never run into the next job's. */
.wr-source-card { background: var(--wr-card); border: 1px solid var(--wr-border); border-radius: 12px; padding: 1rem 1.1rem; margin-bottom: 1.25rem; }
.wr-source-card > h2 { margin-top: 0; }
.wr-source-card .wr-record { background: var(--wr-raised); }

/* Bring In More (book: "Bring In More Wages"): the figures, the Now / What if bar, each job's
   what-ifs and the pretend jobs. A pretend job is dashed and tagged, so it never reads as real
   pay; the what-ifs are striped in the bar; the bills are a dashed line in money-out red; money
   coming in is teal with ▲ (docs/brand.md). */
.wr-bim-figures { margin-bottom: 1.25rem; scroll-margin-top: 5rem; }
.wr-bim-up { color: var(--wr-teal-text); font-weight: 700; }
.wr-bim-bar { margin: 0.5rem 0 0; max-width: 44rem; }
.wr-bim-bar figcaption { font-size: 0.85rem; margin-bottom: 0.35rem; }
.wr-bim-rows { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; gap: 0.4rem 0.6rem; align-items: center; font-size: 0.9rem; }
.wr-bim-rows svg { width: 100%; height: 1.1rem; display: block; }
.wr-bim-track { fill: var(--wr-raised); }
.wr-bim-now { fill: #0d9488; }
.wr-bim-stripe { fill: #2dd4bf; }
.wr-bim-extra { stroke: #2dd4bf; stroke-width: 1px; vector-effect: non-scaling-stroke; }
.wr-bim-bills { stroke: var(--wr-red); stroke-width: 2px; stroke-dasharray: 3 2; vector-effect: non-scaling-stroke; }
.wr-bim-legend { list-style: none; display: flex; flex-wrap: wrap; gap: 0.25rem 1rem; margin: 0.5rem 0 0; padding: 0; font-size: 0.85rem; color: var(--wr-muted); }
.wr-bim-legend li { list-style: none; display: inline-flex; align-items: center; gap: 0.4rem; }
.wr-bim-key { display: inline-block; width: 0.8rem; height: 0.8rem; border-radius: 3px; }
.wr-bim-key-now { background: #0d9488; }
.wr-bim-key-extra { background: repeating-linear-gradient(90deg, #2dd4bf 0 3px, transparent 3px 6px); outline: 1px solid #2dd4bf; }
.wr-bim-key-bills { width: 0; height: 0.9rem; border-radius: 0; border-left: 2px dashed var(--wr-red); }
.wr-bim-job, .wr-bim-pretend { margin-bottom: 0.75rem; }
.wr-bim-pretend { border: 1.5px dashed var(--wr-border-strong); background: transparent; }
.wr-bim-tag { margin: 0 0 0.25rem; font-size: 0.75rem; font-weight: 700; letter-spacing: 0.12em; text-transform: uppercase; color: var(--wr-indigo-text); }
.wr-bim-inputs { display: grid; gap: 0 0.75rem; grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr)); }
.wr-bim-inputs input { margin-bottom: 0.5rem; }
.wr-bim-error { display: block; min-height: 0; color: var(--wr-red-text); }
.wr-bim-error:empty { display: none; }
.wr-bim-more { margin: 0.25rem 0 0.6rem; }
.wr-bim-clear { margin: 0.5rem 0 1rem; }
/* What would it take? (BM3): the question, then every path as a row with its Try it. */
.wr-bim-take, .wr-bim-answer { scroll-margin-top: 5rem; }
.wr-bim-ask { max-width: 32rem; }
.wr-bim-rates { margin: 0 0 0.75rem; }
.wr-bim-rates summary { font-size: 0.9rem; color: var(--wr-muted); }
.wr-bim-ask-buttons { display: flex; flex-wrap: wrap; gap: 0.5rem; }
.wr-bim-ask-buttons button { width: auto; margin: 0; }
.wr-bim-answer { margin-top: 1rem; }
.wr-bim-answer-lead { font-weight: 700; margin-bottom: 0.25rem; }
.wr-bim-paths { list-style: none; margin: 0.75rem 0; padding: 0; }
.wr-bim-paths li.wr-bim-path { list-style: none; display: flex; align-items: center; justify-content: space-between; gap: 0.75rem; padding: 0.6rem 0; border-bottom: 1px solid var(--wr-border); }
.wr-bim-path p { margin: 0; }
.wr-bim-path-title { font-weight: 600; }
.wr-bim-path form { margin: 0; flex: none; }
.wr-bim-path form button { margin: 0; }
.wr-bim-path-none .wr-bim-path-title { color: var(--wr-muted); }
.wr-bim-entry { margin: 1.5rem 0 1rem; border: 1px solid var(--wr-cyan); }
.wr-bim-entry h2 { font-size: 1.15rem; margin-bottom: 0.4rem; }
.wr-bim-entry h2 .wr-icon { color: var(--wr-teal); }
/* Keep More (ADR-0022): the job's benefits line on the list, the guide's facts and "Also
   offered". */
.wr-guide-line { display: flex; gap: 0.5rem; align-items: flex-start; margin-bottom: 0.75rem; }
.wr-guide-line .wr-icon { color: var(--wr-teal); flex: none; margin-top: 0.2rem; }
.wr-guide-facts { margin-bottom: 0.75rem; }
.wr-guide-facts dd { margin: 0; }
.wr-guide-also { padding-left: 1.1rem; margin-bottom: 0; }
.wr-guide-also li { margin-bottom: 0.5rem; }
@media (max-width: 34em) {
  /* On a phone, each fact's label above its value. */
  .wr-guide-facts { grid-template-columns: 1fr; gap: 0.1rem; }
  .wr-guide-facts dd { margin-bottom: 0.6rem; }
}
/* Keep More's notes on a paycheck (ADR-0022): under the line they're about, a note worth doing
   with a teal edge, its benefit muted and "Learn more" a disabled placeholder; the summary at the
   top links down to them. */
.wr-keep-note { margin: 0.5rem 0 0.25rem; padding: 0.6rem 0.75rem; border-radius: 10px; background: var(--wr-raised); }
.wr-keep-note p { display: flex; gap: 0.5rem; align-items: flex-start; margin-bottom: 0.4rem; }
.wr-keep-note p:last-child { margin-bottom: 0; }
.wr-keep-note .wr-icon { color: var(--wr-teal); flex: none; margin-top: 0.2rem; }
.wr-keep-worth { border-left: 3px solid var(--wr-teal); scroll-margin-top: 5rem; }
.wr-keep-tag { display: inline-flex; gap: 0.3rem; align-items: center; flex: none; font-weight: 700; color: var(--wr-teal); }
.wr-keep-learn { display: flex; flex-wrap: wrap; align-items: center; gap: 0.6rem; }
.wr-keep-learn button { width: auto; margin: 0; }
.wr-keep-missing { list-style: none; }
.wr-keep-summary { margin: 1rem 0; }
.wr-keep-summary h2 { display: flex; gap: 0.5rem; align-items: center; font-size: 1.1rem; margin-bottom: 0.5rem; }
.wr-keep-summary h2 .wr-icon { color: var(--wr-teal); }
.wr-keep-summary ul { margin-bottom: 0.5rem; padding-left: 1.25rem; }
/* Bulleted even with one item (the owner, 2026-11-07): each is a way to keep more or protect.
   The summary is an <aside>, and Pico makes `aside li` a plain block, which drops the bullet: it
   has to be a list item again. */
.wr-keep-summary li { display: list-item; list-style: disc; padding: 0.15rem 0; }
.wr-keep-monthly { font-weight: 700; color: var(--wr-teal); }
.wr-keep-older { display: flex; gap: 0.5rem; align-items: flex-start; }
/* ANCHOR_END: paychecks */

/* ANCHOR: outgoing */
/* Outgoing Wages: the picker (v1's grouped checkboxes), the fill-in rows, and the custom bill's
   "new category" box, shown only when "A new category…" is chosen. */
.wr-step { font-weight: 600; margin-bottom: 0.5rem; }
.wr-pick-group { margin-bottom: 0.75rem; }
.wr-pick-group > legend { font-weight: 600; margin-bottom: 0.35rem; }
.wr-pick-group .wr-check,
.wr-add-custom { margin-bottom: 0.3rem; }
.wr-add-custom { margin: 0.5rem 0 1rem; font-weight: 500; }
.wr-tag { display: inline-block; margin-left: 0.35rem; padding: 0 0.4rem; border: 1px solid var(--wr-border); border-radius: 1rem; font-size: 0.7rem; color: var(--wr-muted); vertical-align: middle; }
.wr-tag-added { border-color: rgba(var(--wr-teal-rgb), 0.5); }
/* In a card's heading (Education's "In person" / "Online"), the tag keeps the body font. */
.wr-record h3 .wr-tag { font-family: var(--pico-font-family); font-weight: 400; }
.wr-fill-row { max-width: 44rem; margin-bottom: 1rem; padding: 0.9rem 1.1rem; border: 1px solid var(--wr-border); border-radius: var(--pico-border-radius); background: var(--wr-card); }
.wr-fill-row > legend { font-weight: 600; padding: 0 0.3rem; }
.wr-fill-help { display: block; max-width: 44rem; margin-bottom: 1rem; color: var(--wr-muted); }
.wr-new-group,
.wr-custom-only { display: none; }
.wr-fill-row:has(select[name="group"] option[value="__new"]:checked) .wr-new-group,
.wr-bill-form:has(select[name="group"] option[value="__new"]:checked) .wr-new-group,
.wr-bill-form:has(select[name="category"] option[value="other"]:checked) .wr-custom-only { display: block; }
.wr-round-up { margin: -0.5rem 0 1rem; }
.wr-bill-form small { display: block; color: var(--wr-muted); }
/* ANCHOR_END: outgoing */

/* ---------------------------------------------------------------- stacked tables */

/* ANCHOR: stacked */
/* `wr.table` (views/components/ui.html): a normal table on wide screens; below 640px each row
   becomes a card, and each cell shows its column name (from `data-label`) in front of the value. */
table.wr-stack caption { text-align: left; color: var(--wr-muted); padding-bottom: 0.5rem; }
td.num, th.num { text-align: right; font-family: var(--wr-font-mono); font-variant-numeric: tabular-nums; }
@media (max-width: 640px) {
  table.wr-stack thead {
    /* Hidden on screen but still read by screen readers. */
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
  }
  table.wr-stack tr {
    display: block;
    margin-bottom: 0.75rem;
    padding: 0.4rem 0.9rem;
    border: 1px solid var(--wr-border);
    border-radius: var(--pico-border-radius);
    background: var(--wr-card);
  }
  table.wr-stack td {
    display: flex;
    justify-content: space-between;
    gap: 1rem;
    padding: 0.4rem 0;
    border: 0;
    background: transparent;
  }
  table.wr-stack td::before {
    content: attr(data-label);
    color: var(--wr-muted);
    font-family: var(--pico-font-family-sans-serif);
    font-size: 0.85rem;
  }
}
/* ANCHOR_END: stacked */

/* Messages from the server, e.g. "That email and password don't match". */
/* ANCHOR: status_lines */
/* Both are a row: an icon drawn by CSS (a mask, like .wr-icon), then the words. */
[role="alert"],
.wr-saved {
  display: flex;
  align-items: flex-start;
  gap: 0.6rem;
  padding: 0.7rem 1rem;
  border-radius: var(--wr-radius-sm);
}
[role="alert"]::before,
.wr-saved::before {
  content: "";
  flex: none;
  width: 1.15rem;
  height: 1.15rem;
  margin-top: 0.15rem;
  background: currentColor;
  -webkit-mask: var(--wr-line-icon) center / contain no-repeat;
  mask: var(--wr-line-icon) center / contain no-repeat;
}
[role="alert"] {
  --wr-line-icon: url("/static/icons/triangle-alert.svg");
  border: 1px solid var(--wr-red);
  background: rgba(var(--wr-red-rgb), 0.08);
  color: var(--wr-text);
}
[role="alert"]::before { background: var(--wr-red-text); }
/* Confirmations, e.g. "Time zone saved.": a teal line with its glowing ring (the draft), and a
   tick. arrive.js scrolls it into view and makes it glow when it arrives. */
.wr-saved {
  --wr-line-icon: url("/static/icons/circle-check.svg");
  border: 1px solid var(--wr-teal);
  color: var(--wr-teal-text);
  box-shadow: var(--wr-ring-saved);
}
/* ANCHOR_END: status_lines */

/* The client page's "Delete account": set apart, with a red button, because it can't be undone. */
.wr-danger-zone {
  border: 1px solid var(--wr-out);
}
/* The same `:not()` chain as the primary-button hover rule, plus `.wr-danger`, so this rule is the
   more specific one and wins over the cyan. */
button.wr-danger:not(.secondary):not(.outline):not(.contrast),
button.wr-danger:not(.secondary):not(.outline):not(.contrast):hover {
  /* A deeper red than --wr-red for the fill: white on #ff5c77 is about 2.9:1, below WCAG AA;
     on #c41e44 it's about 5.9:1. */
  background: #c41e44;
  border-color: #c41e44;
  color: #fff;
  box-shadow: none;
}
button.wr-danger .wr-icon { background: currentColor; }


/* ---------------------------------------------------------------- sign-in and other single-card pages */

/* ANCHOR: auth_centre */
/* Centred in the *visible* screen. `100vh` on Android Chrome is the height with the address bar
   hidden, so on first load the card sat below the middle; `100dvh` ("dynamic viewport height")
   is the height actually showing. The `100vh` line stays as a fallback for older browsers. */
.wr-auth {
  min-height: 100vh;
  min-height: 100dvh;
  display: grid;
  place-items: center;
  padding: 2rem 1rem;
}
.wr-auth article {
  width: min(100%, 26rem);
  margin: 0;
}
/* Pico pads <main>; around a full-height card that padding would make the page taller than the
   screen, pushing the card down and making it scroll. */
main:has(> .wr-auth) { padding-block: 0; }
/* ANCHOR_END: auth_centre */
/* The footer shares the screen with the card instead of sitting below a full-height block (which
   would make the sign-in page scroll again): <main> becomes a screen-tall column, the card's
   block takes the space the footer leaves, and the card is centred in that. */
main:has(> .wr-auth) {
  min-height: 100vh;
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
}
main:has(> .wr-auth) > .wr-auth { flex: 1; min-height: 0; }
main:has(> .wr-auth) > .wr-footer { margin-top: 0; padding-block: 0.75rem; }
.wr-narrow { max-width: 30rem; }
/* Two-factor setup (account/two_factor/*.html). The QR code stays black on white in both themes:
   scanners need the contrast, and a light quiet zone around it. */
.wr-qr {
  width: min(100%, 15rem);
  margin: 0 auto 1rem;
  padding: 0.5rem;
  background: #ffffff;
  border-radius: var(--pico-border-radius);
}
.wr-qr svg { display: block; width: 100%; height: auto; }
.wr-key code { font-size: 1rem; letter-spacing: 0.05em; word-spacing: 0.4em; }
/* Recovery codes: two columns of monospace, easy to copy one by one. */
.wr-codes {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(11rem, 1fr));
  gap: 0.5rem;
  padding: 0;
  margin-bottom: 1.5rem;
}
.wr-codes li { list-style: none; }
.wr-codes code { font-size: 1rem; }
/* The guided app setup: four bars, filled up to the current step. */
.wr-stepper { display: flex; gap: 0.35rem; padding: 0; margin: 0 0 0.4rem; }
.wr-stepper li { flex: 1; height: 0.3rem; border-radius: 1rem; background: var(--wr-border); list-style: none; }
.wr-stepper li.wr-done { background: var(--wr-cyan); }
.wr-step-label { margin-bottom: 0.75rem; font-size: 0.85rem; color: var(--wr-muted); }
/* Step 2's two ways to add the entry: the phone way first on a phone, where a QR code on the same
   screen can't be scanned; the QR code first on a wide screen, where it's the easy way. */
.wr-setup-ways { display: flex; flex-direction: column; gap: 1.25rem; margin-bottom: 1.25rem; }
.wr-setup-ways section { padding: 1rem; border: 1px solid var(--wr-border); border-radius: var(--pico-border-radius); }
.wr-setup-ways h2 { font-size: 1.05rem; margin-bottom: 0.75rem; }
.wr-setup-ways h2 .wr-icon { margin-right: 0.4rem; vertical-align: -0.15em; }
.wr-setup-ways [role="button"] { width: 100%; text-align: center; }
.wr-setup-ways .wr-key { display: block; margin: 0.35rem 0; }
/* Back/Cancel links under a step's Next button. */
.wr-narrow article > [role="button"] + p { margin-top: 1rem; }
@media (min-width: 64rem) {
  .wr-way-computer { order: -1; }
}
.wr-lockup {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.9rem;
  text-align: center;
  margin-bottom: 1.75rem;
}
.wr-lockup .wr-wordmark { font-size: 1.6rem; }
.wr-tagline { color: var(--wr-muted); margin: 0; }
.wr-auth article > a[role="button"] { display: block; width: 100%; text-align: center; }

/* ---------------------------------------------------------------- the hero card (a two-tone tint) */

.wr-hero {
  background: var(--wr-card);
  border: 1px solid var(--wr-indigo);
}

/* Read by screen readers, not shown: the sign-in page's heading, under its visible wordmark. */
.wr-sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* Job Search (book: "Job Search"): v1's cards. The description opens on the card ("View
   description" becomes "Hide description"), and the excerpt steps aside while it's open. */
.wr-jobs-form small { display: block; margin-top: 0.25rem; }
.wr-jobs-status { padding: 0.75rem 1rem; border-left: 3px solid var(--pico-primary); background: var(--pico-card-sectioning-background-color); }
.wr-jobs-card h3 { margin-bottom: 0.25rem; }
.wr-jobs-card p { margin-bottom: 0.35rem; }
.wr-jobs-card-employer { font-weight: 500; }
.wr-jobs-card-apply { color: var(--pico-ins-color); }
.wr-jobs-card:has(.wr-jobs-details[open]) .wr-jobs-card-excerpt { display: none; }
/* "View description" in the theme's link blue, open or closed: Pico colours a <details> summary
   with its own accordion variables (and its own blue when open), so those are set here. */
.wr-jobs-details {
  --pico-accordion-close-summary-color: var(--wr-cyan);
  --pico-accordion-open-summary-color: var(--wr-cyan);
  --pico-accordion-active-summary-color: var(--wr-cyan-hover);
}
.wr-jobs-details summary { font-weight: 500; }
.wr-jobs-details:not([open]) .wr-when-open, .wr-jobs-details[open] .wr-when-closed { display: none; }
.wr-jobs-text { white-space: pre-line; overflow-wrap: anywhere; }
.wr-jobs-empty { color: var(--pico-muted-color); }
/* htmx's loading indicators. Its own injected styles are off (they'd break the CSP), so these are
   the rules it would add: hidden until the element, or the one that made the request, is busy. */
.htmx-indicator { display: none; }
.htmx-request .htmx-indicator, .htmx-request.htmx-indicator { display: block; }

/* ---------------------------------------------------------------- The busy message */

/* ANCHOR: busy */
/* What a slow outside call is doing, in the middle of the screen while it runs (static/js/busy.js;
   the owner's rule, 2026-10-29). It sits over everything, tab bar and update banner included,
   and the dimmed page behind it takes no taps, so nothing is sent twice. */
.wr-busy {
  position: fixed;
  inset: 0;
  z-index: 30;
  display: grid;
  place-items: center;
  padding: 1rem;
  background: var(--wr-scrim);
  /* A slight blur, so the page's text doesn't compete with the message. */
  -webkit-backdrop-filter: blur(2px);
  backdrop-filter: blur(2px);
}
.wr-busy[hidden] { display: none; }
.wr-busy-card {
  /* The spinner above the words, both centred: side by side, the spinner read as a bullet and
     pushed the words off centre (the owner's phone check, 2026-10-29). */
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.85rem;
  min-width: 12rem;
  max-width: 22rem;
  padding: 1.4rem 1.75rem;
  border: 1px solid rgba(var(--wr-cyan-rgb), 0.45);
  border-radius: var(--wr-radius);
  background: var(--wr-raised);
  box-shadow: 0 10px 30px -12px rgba(0, 0, 0, 0.6);
  font-weight: 700;
  text-align: center;
}
/* ANCHOR_END: busy */

/* ---------------------------------------------------------------- Spinner and live results */

/* ANCHOR: spinner */
/* Our own spinner: a ring in the brand gradient that this sheet turns. (Pico's icon turned inside
   an image, small and grey, and on a phone it read as a still dot.) `wr-spinner-lg` in the busy
   message. */
.wr-spinner {
  --wr-spinner-size: 1.25rem;
  display: inline-block;
  flex: none;
  width: var(--wr-spinner-size);
  height: var(--wr-spinner-size);
  border-radius: 50%;
  background: conic-gradient(from 90deg, rgba(var(--wr-cyan-rgb), 0), var(--wr-cyan));
  /* Only the ring shows: the middle is masked out. */
  -webkit-mask: radial-gradient(farthest-side, transparent calc(100% - 3px), #000 calc(100% - 2.5px));
  mask: radial-gradient(farthest-side, transparent calc(100% - 3px), #000 calc(100% - 2.5px));
  animation: wr-spin 0.8s linear infinite;
}
.wr-spinner-lg { --wr-spinner-size: 2.25rem; }
@keyframes wr-spin { to { transform: rotate(360deg); } }
/* ANCHOR_END: spinner */

/* ANCHOR: live_results */
/* Live results (book: "Jobs as they arrive"): placeholder cards that shimmer where the jobs will
   be, a status line, and new cards that fade in as each step's jobs arrive. */
#wr-jobs-results { scroll-margin-top: 5.5rem; } /* clear of the top bar when htmx scrolls to it */
/* The spinner above the words, centred, not beside them like a bullet (the owner's rule; code
   review 2026-10-30, R-09). */
.wr-jobs-finding {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  margin: 0.25rem 0 1rem;
  color: var(--wr-muted);
  font-weight: 500;
}
.wr-skeleton { pointer-events: none; }
.wr-bone {
  display: block;
  width: 75%;
  height: 0.85rem;
  margin: 0 0 0.7rem;
  border-radius: 0.4rem;
  background: linear-gradient(90deg, var(--wr-hover) 30%, var(--wr-border-strong) 50%, var(--wr-hover) 70%);
  background-size: 300% 100%;
  animation: wr-shimmer 1.4s ease-in-out infinite;
}
.wr-bone-title { width: 60%; height: 1.2rem; margin-bottom: 0.9rem; }
.wr-bone-short { width: 40%; }
.wr-bone-long { width: 90%; margin-bottom: 0; }
@keyframes wr-shimmer { from { background-position: 100% 0; } to { background-position: 0 0; } }
/* htmx marks new content `htmx-added` for a moment: new cards start faded and slightly low. */
.wr-jobs-card { transition: opacity 0.3s ease-out, transform 0.3s ease-out; }
.wr-jobs-card.htmx-added { opacity: 0; transform: translateY(6px); }
/* The moment a search or More results is being sent: a small spinner in its button. */
.wr-jobs-form.htmx-request #wr-jobs-submit::before,
.wr-jobs-form:has(#f-profile.htmx-request) #wr-jobs-submit::before,
.wr-jobs-more.htmx-request button::before {
  content: "";
  display: inline-block;
  width: 1em;
  height: 1em;
  margin-right: 0.5em;
  vertical-align: -0.15em;
  border: 2px solid currentColor;
  border-right-color: transparent;
  border-radius: 50%;
  animation: wr-spin 0.7s linear infinite;
}
/* Reduce Motion on: Pico stops every animation; ours pulse gently instead of turning or sweeping,
   so a wait still shows it's alive. */
@media (prefers-reduced-motion: reduce) {
  .wr-spinner,
  .wr-bone,
  .wr-jobs-form.htmx-request #wr-jobs-submit::before,
  .wr-jobs-form:has(#f-profile.htmx-request) #wr-jobs-submit::before,
  .wr-jobs-more.htmx-request button::before {
    animation: wr-pulse 1.6s ease-in-out infinite !important;
  }
  .wr-bone { background: var(--wr-border-strong); }
  .wr-jobs-card { transition: none; }
}
@keyframes wr-pulse { 50% { opacity: 0.4; } }
/* ANCHOR_END: live_results */

/* The viewer's Ask for changes (2026-10-31): a button among the others; open, its box takes the
   whole row under them. */
.wr-viewer-ask { margin: 0; }
.wr-viewer-ask[open] { flex-basis: 100%; }
.wr-viewer-ask > summary { list-style: none; margin: 0; }
.wr-viewer-ask > summary::-webkit-details-marker { display: none; }
.wr-viewer-ask form { margin-top: 0.75rem; }

/* ANCHOR: arrive */
/* Results come into view, and glow (static/js/arrive.js; the owner's rule, 2026-10-31): a ring in
   the brand's accent that swells and fades twice, so the eye finds what it waited for. With
   Reduce Motion, a still outline for the same time instead. */
.wr-arrived {
  --wr-arrive-glow: rgba(var(--wr-teal-rgb), 0.55);
  border-radius: var(--pico-border-radius, 0.5rem);
  animation: wr-arrive 1.3s ease-out 2;
}
@keyframes wr-arrive {
  0% { box-shadow: 0 0 0 0 var(--wr-arrive-glow); background-color: rgba(var(--wr-teal-rgb), 0.1); }
  45% { box-shadow: 0 0 0 7px var(--wr-arrive-glow); }
  100% { box-shadow: 0 0 0 14px transparent; background-color: transparent; }
}
@media (prefers-reduced-motion: reduce) {
  .wr-arrived {
    animation: none !important;
    outline: 3px solid var(--wr-teal);
    outline-offset: 3px;
  }
}
/* ANCHOR_END: arrive */

/* ---------------------------------------------------------------- motion */

/* ANCHOR: motion */
/* Animations (Settings → Animations and sounds, on by default; book: "The redesign"). Every
   moving thing in the app is listed here or marked "motion" where it lives, so turning them off
   is one place: `<html data-motion="off">` (the setting) or the device's Reduce Motion. */

/* Page to page: the new page rises in while the old one fades, and the top bar, sidebar and tab
   bar stay put, except the tab's cyan line, which slides to the new tab. A cross-document view
   transition: the browser does it between two ordinary page loads, no script needed (Chrome,
   Edge, Safari 18.2 and up; other browsers just change page). static/js/motion.js skips it when
   Animations are off. */
@media (prefers-reduced-motion: no-preference) {
  @view-transition { navigation: auto; }
}
.wr-topbar { view-transition-name: wr-topbar; }
.wr-tabbar { view-transition-name: wr-tabbar; }
.wr-tab-line { view-transition-name: wr-tab-line; }
@media (min-width: 768px) {
  .wr-sidebar { view-transition-name: wr-sidebar; }
}
::view-transition-old(root) { animation: wr-page-out 0.14s ease-in both; }
::view-transition-new(root) { animation: wr-page-in 0.28s var(--wr-ease) both; }
::view-transition-group(wr-tab-line) { animation-duration: 0.34s; animation-timing-function: var(--wr-ease); }
@keyframes wr-page-out { to { opacity: 0; } }
@keyframes wr-page-in { from { opacity: 0; transform: translateY(10px); } }

/* A tab's icon presses in under the finger. */
.wr-tab .wr-icon { transition: transform 0.12s var(--wr-ease); }
.wr-tab:active .wr-icon { transform: scale(0.86); }

/* Cards rise in, one after another, when a page of cards opens (Home). */
.wr-rise > * { animation: wr-rise 0.45s var(--wr-ease) both; }
.wr-rise > :nth-child(2) { animation-delay: 0.05s; }
.wr-rise > :nth-child(3) { animation-delay: 0.1s; }
.wr-rise > :nth-child(4) { animation-delay: 0.15s; }
.wr-rise > :nth-child(5) { animation-delay: 0.2s; }
.wr-rise > :nth-child(n + 6) { animation-delay: 0.25s; }
@keyframes wr-rise { from { opacity: 0; transform: translateY(8px); } }

/* Animations off: nothing slides, rises, presses or glows; a wait still shows it's alive (the
   spinners and placeholders pulse, as with Reduce Motion), and an arrival gets a still outline. */
:root[data-motion="off"] *,
:root[data-motion="off"] *::before,
:root[data-motion="off"] *::after {
  animation: none !important;
  transition: none !important;
  scroll-behavior: auto !important;
}
:root[data-motion="off"] :is(button, [type="submit"], [role="button"]):active,
:root[data-motion="off"] .wr-tab:active .wr-icon { transform: none; }
:root[data-motion="off"] :is(.wr-spinner, .wr-bone, .wr-pdf-loading:not(.wr-pdf-failed), .wr-launch-loading),
:root[data-motion="off"] :is(.wr-jobs-form.htmx-request #wr-jobs-submit, .wr-jobs-more.htmx-request button)::before {
  animation: wr-pulse 1.6s ease-in-out infinite !important;
}
:root[data-motion="off"] .wr-bone { background: var(--wr-border-strong); }
:root[data-motion="off"] .wr-arrived {
  outline: 3px solid var(--wr-teal);
  outline-offset: 3px;
}
@media (prefers-reduced-motion: reduce) {
  .wr-rise > * { animation: none !important; }
  button:active, [type="submit"]:active, [role="button"]:active,
  .wr-tab:active .wr-icon { transform: none; }
}
/* ANCHOR_END: motion */

/* ANCHOR: wage-router */
/* The Wage Router (book: "The Wage Router"): the flow's colours by what the money does (the
   brand's roles), the three drawings (one shown per screen), and the key under the upright one. */
:root {
  --wr-f-in: #2dd4bf;     /* money in: jobs, the employer, take-home */
  --wr-f-tax: #ff5c77;    /* taxes */
  --wr-f-keep: #8a8a8a;   /* insurance and other deductions */
  --wr-f-save: #818cf8;   /* still yours, saved */
  --wr-f-bills: #ff5c77;  /* bills you must pay */
  --wr-f-flex: #ffa3b2;   /* bills you could cut back: the same red, lighter (the owner) */
  --wr-f-card: #a5b4fc;   /* card payoff */
  --wr-f-spend: #bdbdbd;  /* spending money, giving, other */
  --wr-f-open: #22d3ee;   /* not routed yet: the money to give a job */
}
.wr-wr-flow { margin-bottom: 1.5rem; scroll-margin-top: 5rem; }
.wr-wr-tiles { max-width: none; grid-template-columns: repeat(auto-fit, minmax(8rem, 1fr)); }
.wr-wr-in .num { color: var(--wr-teal); }
.wr-wr-open { border: 1px solid rgba(var(--wr-cyan-rgb), 0.55); }
.wr-wr-open .wr-tile-value .num { color: var(--wr-cyan); }
.wr-wr-over { border: 1px solid var(--wr-red); }
.wr-wr-over .wr-tile-value .num { color: var(--wr-red-text); }
.wr-wr-figure { margin: 0.75rem 0 0; padding: 0.9rem 0.85rem 0.75rem; border: 1px solid var(--wr-border); border-radius: var(--wr-radius); background: var(--wr-card); }
.wr-wr-caption { display: none; justify-content: space-between; gap: 0.75rem; margin-bottom: 0.6rem; font-size: 0.68rem; font-weight: 700; letter-spacing: 0.04em; text-transform: uppercase; white-space: nowrap; color: var(--wr-muted); }
.wr-wr-svg { display: block; width: 100%; height: auto; overflow: visible; }
.wr-wr-mid, .wr-wr-wide { display: none; }
.wr-wr-band { opacity: 0.34; }
.wr-wr-box.wr-wr-open { fill: rgba(var(--wr-cyan-rgb), 0.14); stroke: var(--wr-f-open); stroke-width: 1.5; stroke-dasharray: 4 3; }
.wr-wr-band.wr-wr-open { fill: var(--wr-f-open); }
.wr-wr-in { fill: var(--wr-f-in); } .wr-wr-tax { fill: var(--wr-f-tax); } .wr-wr-keep { fill: var(--wr-f-keep); }
.wr-wr-save { fill: var(--wr-f-save); } .wr-wr-bills { fill: var(--wr-f-bills); } .wr-wr-flex { fill: var(--wr-f-flex); }
.wr-wr-card { fill: var(--wr-f-card); } .wr-wr-spend { fill: var(--wr-f-spend); }
.wr-wr-stripe-bg { fill: var(--wr-card); } .wr-wr-stripe { fill: var(--wr-f-in); }
.wr-wr-label { font: 700 12px var(--wr-font); fill: var(--wr-text); paint-order: stroke; stroke: var(--wr-card); stroke-width: 4px; stroke-linejoin: round; }
.wr-wr-amount { font: 500 11.5px var(--wr-font-mono); fill: var(--wr-muted); }
.wr-wr-inside { font: 800 11.5px var(--wr-font); fill: #121212; }
.wr-wr-lead { stroke: var(--wr-dim); stroke-width: 1; }
/* The key: each stage's entries indented under its heading (the owner, 2026-11-08). */
.wr-wr-key { display: flex; flex-direction: column; gap: 0.6rem; margin-top: 0.75rem; }
.wr-wr-key-h { margin: 0; font-size: 0.72rem; font-weight: 800; letter-spacing: 0.08em; text-transform: uppercase; color: var(--wr-dim); }
.wr-wr-chips { display: flex; flex-wrap: wrap; gap: 0.2rem 0.85rem; margin: 0.3rem 0 0 0.75rem; padding: 0; list-style: none; }
.wr-wr-chips li { list-style: none; display: inline-flex; align-items: center; gap: 0.4rem; margin: 0; font-size: 0.85rem; color: var(--wr-body); }
.wr-flow-chip { display: inline-block; flex: none; width: 0.7rem; height: 0.7rem; margin-right: 0.45rem; border-radius: 3px; vertical-align: baseline; }
.wr-wr-chips .wr-flow-chip { margin-right: 0; }
.wr-flow-chip-in { background: var(--wr-f-in); } .wr-flow-chip-tax { background: var(--wr-f-tax); } .wr-flow-chip-keep { background: var(--wr-f-keep); }
.wr-flow-chip-save { background: var(--wr-f-save); } .wr-flow-chip-bills { background: linear-gradient(90deg, var(--wr-f-bills) 0 60%, var(--wr-f-flex) 60%); }
.wr-wr-chips .wr-flow-chip-bills { background: var(--wr-f-bills); } .wr-flow-chip-flex { background: var(--wr-f-flex); }
.wr-flow-chip-card { background: var(--wr-f-card); } .wr-flow-chip-spend { background: var(--wr-f-spend); }
.wr-flow-chip-open { background: transparent; border: 1.5px dashed var(--wr-f-open); }
.wr-flow-chip-striped { background: repeating-linear-gradient(135deg, var(--wr-f-in) 0 3px, transparent 3px 6px); outline: 1px solid var(--wr-f-in); }
/* The routes. */
.wr-route { margin-bottom: 0.75rem; scroll-margin-top: 5rem; }
.wr-route-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 0.75rem; }
.wr-route-head h3 { margin: 0 0 0.15rem; display: flex; align-items: center; }
.wr-route-head p { margin: 0; }
/* The client's note on a route (the owner, 2026-11-08). */
.wr-route-note { margin-top: 0.25rem !important; font-size: 0.9rem; color: var(--wr-body); }
.wr-route-amount { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem 0.75rem; margin: 0.6rem 0 0; }
.wr-route-amount label { margin: 0; font-size: 0.9rem; color: var(--wr-muted); }
.wr-route-amount input { flex: 1 1 8rem; max-width: 11rem; margin: 0; font-family: var(--wr-font-mono); }
.wr-route-amount button { margin: 0; width: auto; }
.wr-route-error { display: block; color: var(--wr-red-text); }
.wr-route-error:empty { display: none; }
.wr-wr-start { border: 1px solid var(--wr-cyan); }
/* Tap to light up a path (static/js/wage-router.js): the rest dims. */
.wr-wr-box, .wr-wr-band, .wr-wr-chips li, .wr-route[data-key] { cursor: pointer; }
.wr-wr-box, .wr-wr-band { transition: opacity 0.25s var(--wr-ease); }
.wr-wr-focus .wr-wr-band { opacity: 0.08; }
.wr-wr-focus .wr-wr-box { opacity: 0.25; }
.wr-wr-focus .wr-wr-band.wr-on { opacity: 0.62; }
.wr-wr-focus .wr-wr-box.wr-on { opacity: 1; }
/* The labels and lead lines dim with their boxes (the owner, 2026-11-08: sideways, the words of
   dimmed boxes stayed bright). */
.wr-wr-svg text, .wr-wr-lead { transition: opacity 0.25s var(--wr-ease); }
.wr-wr-svg text[data-key] { cursor: pointer; }
.wr-wr-focus text, .wr-wr-focus .wr-wr-lead { opacity: 0.3; }
.wr-wr-focus text.wr-on, .wr-wr-focus .wr-wr-lead.wr-on { opacity: 1; }
/* The key's lit entry, clear on an upright phone (the owner, 2026-11-08: it was barely visible):
   a cyan outline and tint, and the other entries dimmed. Every entry keeps the same padding and
   border, so lighting one doesn't move the others. */
.wr-wr-chips li { padding: 0.1rem 0.45rem; border: 1px solid transparent; border-radius: 6px; transition: opacity 0.25s var(--wr-ease); }
.wr-wr-key.wr-wr-focus .wr-wr-chips li { opacity: 0.45; }
.wr-wr-key.wr-wr-focus .wr-wr-chips li.wr-on { opacity: 1; }
.wr-wr-chips li.wr-on { background: rgba(var(--wr-cyan-rgb), 0.14); border-color: var(--wr-cyan); color: var(--wr-text); font-weight: 700; }
.wr-route.wr-on { border-color: var(--wr-cyan); box-shadow: 0 0 0 3px rgba(var(--wr-cyan-rgb), 0.15); }
/* "With your what-if": a link drawn as a switch (it works without JavaScript). */
.wr-wr-switchrow { display: flex; justify-content: space-between; align-items: center; gap: 1rem; margin: 0 0 1rem; padding: 0.7rem 1rem; border: 1px solid var(--wr-border); border-radius: var(--wr-radius); background: var(--wr-card); }
.wr-wr-switchrow p { margin: 0; }
.wr-wr-switch { position: relative; flex: none; width: 48px; height: 28px; border-radius: 999px; background: var(--wr-raised); border: 1px solid var(--wr-border); }
.wr-wr-switch::after { content: ""; position: absolute; top: 3px; left: 3px; width: 20px; height: 20px; border-radius: 50%; background: var(--wr-muted); transition: transform 0.25s var(--wr-ease); }
.wr-wr-switch[aria-checked="true"] { background: rgba(var(--wr-cyan-rgb), 0.22); border-color: var(--wr-cyan); }
.wr-wr-switch[aria-checked="true"]::after { transform: translateX(20px); background: var(--wr-cyan); }
/* An emergency savings goal. */
.wr-route-goal { margin-top: 0.6rem; padding-top: 0.6rem; border-top: 1px solid var(--wr-line); }
.wr-route-goal p { margin: 0 0 0.3rem; }
.wr-route-goal progress { --pico-progress-color: var(--wr-f-save); --pico-progress-background-color: var(--wr-raised); margin: 0.2rem 0 0.5rem; height: 0.5rem; }
.wr-route-what-if { color: var(--wr-teal-text); }
@media (prefers-reduced-motion: reduce) {
  .wr-wr-box, .wr-wr-band, .wr-wr-switch::after { transition: none; }
}
/* A phone turned sideways, or a computer: the side menu shows, and the flow runs left to right. */
@media (min-width: 768px) {
  .wr-wr-down, .wr-wr-key { display: none; }
  .wr-wr-mid { display: block; }
  .wr-wr-caption { display: flex; }
}
@media (min-width: 1200px) {
  .wr-wr-mid { display: none; }
  .wr-wr-wide { display: block; }
}
@media (max-width: 34em) {
  .wr-wr-hide-small { display: none; }
}
/* ANCHOR_END: wage-router */

/* ANCHOR: launch */
/* The splash screen (pwa/launch.html): the emblem in the middle of the screen, where the iPhone's
   launch picture puts it, with the name, the tagline and "Loading…" below. Motion A (the owner,
   2026-11-08): the routes at half white, light running in along two and out along three, the
   junction swelling as it passes; "Loading…" fades in and out. With Reduce Motion: still, and the
   word pulses (the app's rule for waits). */
.wr-launch { position: fixed; inset: 0; z-index: 50; background: var(--wr-bg); }
.wr-launch-mark { position: absolute; top: 50%; left: 50%; width: 96px; height: 96px; margin: -48px 0 0 -48px; }
.wr-launch-route { stroke: rgba(255, 255, 255, 0.5); }
.wr-launch-light { stroke: #fff; stroke-dasharray: 26 100; stroke-dashoffset: 26; }
.wr-launch-in { animation: wr-launch-in 1.6s linear infinite; }
.wr-launch-out { animation: wr-launch-out 1.6s linear infinite; }
@keyframes wr-launch-in { 0% { stroke-dashoffset: 26; } 45%, 100% { stroke-dashoffset: -100; } }
@keyframes wr-launch-out { 0%, 40% { stroke-dashoffset: 26; } 90%, 100% { stroke-dashoffset: -100; } }
.wr-launch-hub { transform-origin: 27px 32px; animation: wr-launch-hub 1.6s var(--wr-ease) infinite; }
@keyframes wr-launch-hub { 0%, 35% { transform: scale(1); } 45% { transform: scale(1.18); } 60%, 100% { transform: scale(1); } }
.wr-launch-words { position: absolute; top: calc(50% + 66px); left: max(16px, env(safe-area-inset-left)); right: max(16px, env(safe-area-inset-right)); text-align: center; }
.wr-launch-words p { margin: 0; }
.wr-launch-name { font-weight: 800; font-size: 1.15rem; letter-spacing: 0.14em; color: var(--wr-text); }
.wr-launch-name span { background: var(--wr-logo-grad); -webkit-background-clip: text; background-clip: text; color: transparent; }
.wr-launch-tagline { margin-top: 0.35rem !important; font-size: 0.95rem; color: var(--wr-body); text-wrap: balance; }
.wr-launch-loading { margin-top: 1.4rem !important; font-size: 0.85rem; font-weight: 700; color: var(--wr-muted); animation: wr-pulse 1.6s ease-in-out infinite; }
/* Still, with Reduce Motion or Animations off: the routes all white, no light; "Loading…" still
   pulses (it's in the Animations-off list above). */
@media (prefers-reduced-motion: reduce) {
  .wr-launch-light { display: none; }
  .wr-launch-route { stroke: #fff; }
  .wr-launch-hub { animation: none; }
  .wr-launch-loading { animation: wr-pulse 1.6s ease-in-out infinite !important; }
}
:root[data-motion="off"] .wr-launch-light { display: none; }
:root[data-motion="off"] .wr-launch-route { stroke: #fff; }
/* ANCHOR_END: launch */

/* ANCHOR: tax-guide */
/* The Tax Guide (ADR-0025): a reading page. One column on a phone; from 1200px the chapter's
   other sections sit beside it. Figures in the mono face, words ("Not announced yet") in the
   body face. */
.wr-guide { display: grid; gap: 2rem; }
.wr-guide-section { max-width: 44rem; min-width: 0; }
.wr-guide-section h2 { font-size: 1.05rem; margin: 1.6rem 0 0.5rem; }
.wr-guide-section ul { padding-left: 1.2rem; }
.wr-guide-section li { list-style: disc; margin-bottom: 0.35rem; }
.wr-guide-crumb { font-size: 0.85rem; margin-bottom: 0.3rem; }
.wr-guide-back { font-size: 0.9rem; margin-bottom: 0.5rem; }
.wr-guide-notice { padding: 0.6rem 0.8rem; border: 1px solid var(--wr-indigo); border-radius: 10px; color: var(--wr-indigo-text); background: rgba(var(--wr-indigo-rgb), 0.08); font-size: 0.9rem; }
.wr-guide-notice a { color: var(--wr-indigo-text); }
.wr-guide-law { font-weight: 700; }
.wr-guide-short { font-size: 1.1rem; color: var(--wr-text); }
.wr-guide-figs { overflow-x: auto; }
.wr-guide-figs table { margin: 0; min-width: 18rem; }
.wr-guide-figs th small { display: block; font-weight: 600; color: var(--wr-dim); font-size: 0.72rem; }
.wr-guide-figs tbody th { font-weight: 400; color: var(--wr-body); }
.wr-guide-figs td { font-family: var(--wr-font-mono); font-variant-numeric: tabular-nums; white-space: nowrap; }
.wr-guide-figs td.wr-guide-quiet { font-family: var(--pico-font-family); font-style: italic; color: var(--wr-muted); white-space: normal; }
.wr-guide-new { margin-top: 1.4rem; padding-left: 0.9rem; border-left: 3px solid var(--wr-teal); }
.wr-guide-new h2 { margin-top: 0; color: var(--wr-teal-text); }
.wr-guide-new p { margin-bottom: 0.4rem; }
.wr-guide-sources { font-size: 0.85rem; }
.wr-guide-sources a { color: var(--wr-muted); }
.wr-guide-section h1 { margin-top: 0.75rem; }
/* The chapter's sections beside the page, from 1200px only. Pico lays every nav out as a row,
   so the list is set back to a column. */
.wr-guide-side { display: none; font-size: 0.9rem; }
.wr-guide-side h2 { font-size: 0.8rem; letter-spacing: 0.1em; text-transform: uppercase; color: var(--wr-dim); margin-bottom: 0.75rem; }
.wr-guide-side ul { display: block; padding-left: 0; margin: 0 0 1rem; }
.wr-guide-side li { display: block; list-style: none; padding: 0; margin-bottom: 0.5rem; }
.wr-guide-side p { padding: 0; margin: 0; }
.wr-guide-side a { color: var(--wr-muted); text-decoration: none; }
.wr-guide-side a[aria-current="page"] { color: var(--pico-primary); font-weight: 700; }
.wr-guide-contents { display: grid; gap: 1rem; }
.wr-guide-contents li { list-style: none; margin-bottom: 0.35rem; }
.wr-guide-contents ul { padding-left: 0; margin-bottom: 0; }
@media (min-width: 1200px) {
  .wr-guide { grid-template-columns: minmax(0, 44rem) 15rem; align-items: start; }
  .wr-guide-side { display: block; position: sticky; top: 1rem; }
  .wr-guide-contents { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
/* ANCHOR_END: tax-guide */

