/* Kitchen Corkboard -- Impeccable direction round 35e5ab00 (Kevin's pick,
   from a roll assigned to a farmers-market chalkboard direction and raised
   by two dealt challengers). The app reads as the corkboard on the kitchen
   wall: warm paper, a cork-brown header band, hand-lettered section
   headers, and every card-level panel a pinned note with a soft lift and
   one small pushpin dot. Rows inside a panel stay flat and unrotated --
   Budget/Bills numbers must scan exactly as fast as before; the warmth
   lives in the frame, never the data. See PRODUCT.md and DESIGN.md. */
:root {
  color-scheme: light dark;
  --bg: #faf6ef;
  --surface: #fffefb;
  --surface-2: #f1e8d8;
  --cork: #8a5a34;
  --cork-deep: #6b4423;
  --on-cork: #fffdf9;
  --ink: #2b2013;
  --ink-dim: #6b5d48;
  /* On --surface (#fffefb), where every text use of this token actually
     sits, this is ~5.3:1 -- AA for normal text needs 4.5:1. The original
     #8f8266 only cleared 3.7:1; keep this at #766a52 or darker. */
  --ink-faint: #766a52;
  --ink-mute: #b0a488;

  --accent: #4c7a3a;
  --on-accent: #fffdf9;
  --accent-soft: #e4eedc;
  --alert: #c1442b;
  --alert-soft: #f5dfd6;
  --warn: #7d5710;
  --warn-soft: #f6e8c8;
  --info: #3e7c82;
  --info-soft: #dcedee;
  /* On-credit spend (ADR-0029) -- a muted violet, deliberately not --alert
     (over-budget red) or --ink-dim (normal actual): "owed, not overspent".
     ~5.4:1 on --surface. */
  --credit: #6f4d97;

  /* Categorical series for the Budget > Advice spend chart (ADR-0031) -- the
     one charting surface. Drawn from the named accents so it reads as the same
     palette; each theme redefines these alongside its own colours. */
  --chart-1: #4c7a3a; --chart-2: #3e7c82; --chart-3: #7d5710;
  --chart-4: #6f4d97; --chart-5: #c1442b; --chart-6: #5a6b52;

  --line: rgba(90, 62, 34, 0.16);
  --line-soft: rgba(90, 62, 34, 0.08);
  --line-firm: rgba(90, 62, 34, 0.28);

  /* Shift-pattern badges (ADR-0043): amber = a day shift, dark blue = a
     night shift. Exotic themes inherit these -- both read on any ground. */
  --shift-day-bg: #e0982c; --shift-day-ink: #3a2400;
  --shift-night-bg: #2f3f6d; --shift-night-ink: #eef1fb;

  --t-micro: 0.6875rem;
  --t-small: 0.75rem;
  --t-body: 0.875rem;
  --t-lead: 1rem;
  --t-head: 1.1875rem;

  --s1: 4px; --s2: 8px; --s3: 12px; --s4: 16px; --s5: 24px; --s6: 32px;

  --radius: 14px;
  --radius-sm: 8px;

  --ease: cubic-bezier(0.23, 1, 0.32, 1);
  --fast: 140ms;

  --font-body: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Arial, sans-serif;
  --font-display: "Caveat", "Segoe Script", cursive;

  /* Paper lifted slightly off the board -- card-level panels only. A row
     inside one never gets this: depth marks "this is a separate note,"
     never "this list is important." (The Pinned-Note Rule.) */
  --note-shadow: 0 2px 10px rgba(90, 62, 34, 0.14), 0 1px 2px rgba(90, 62, 34, 0.10);

  /* --- Theme knobs: shape/layout dials a generated theme (ADR-0030
     companion) overrides in one block without editing rule bodies. Geometry
     only -- colours live in the palette above, so these need no dark
     variants. --note-shadow / --font-* / --radius* are dials too. */
  --panel-radius: var(--radius);
  --panel-pad: var(--s4);
  --pin-size: 7px;
  --pin-radius: 50%;
  --pin-color: var(--ink-mute);
  --pin-top: var(--s2);
  --pin-right: var(--s3);
  --nav-tab-radius: 999px;
  --btn-radius: var(--radius-sm);
  --page-max: 960px;
  --page-pad: var(--s4);
  --layout-gap: var(--s4);

  /* Followed-kitchen card tints (spec #73): a small warm palette, one hashed
     hue per kitchen. Light, low-chroma so text stays legible. */
  --follow-hue-0: hsl(38 70% 94%);
  --follow-hue-1: hsl(18 68% 94%);
  --follow-hue-2: hsl(348 60% 95%);
  --follow-hue-3: hsl(52 72% 93%);
  --follow-hue-4: hsl(6 60% 95%);
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg: #1c140c; --surface: #2a1f14; --surface-2: #362819;
    --cork: #4a3018; --cork-deep: #2e1d0e; --on-cork: #f3e9d8;
    --ink: #f3e9d8; --ink-dim: #c7b89a; --ink-faint: #a3937a; --ink-mute: #7a6c55;
    --accent: #7fbf62; --on-accent: #1c140c; --accent-soft: #23361c;
    --alert: #e8836a; --alert-soft: #3a2018;
    --warn: #e0ac4a; --warn-soft: #3a2c12;
    --info: #6bb8be; --info-soft: #1c3436;
    --credit: #b99ae0;
    --chart-1: #7fbf62; --chart-2: #6bb8be; --chart-3: #e0ac4a;
    --chart-4: #b99ae0; --chart-5: #e8836a; --chart-6: #9aab90;
    --line: rgba(243, 233, 216, 0.12);
    --line-soft: rgba(243, 233, 216, 0.06);
    --line-firm: rgba(243, 233, 216, 0.22);
    --note-shadow: 0 2px 12px rgba(0, 0, 0, 0.35), 0 1px 2px rgba(0, 0, 0, 0.25);
    --shift-day-bg: #e2a648; --shift-day-ink: #2c1c00;
    --shift-night-bg: #4d5fa0; --shift-night-ink: #f0f3fd;
    --follow-hue-0: hsl(38 30% 20%);
    --follow-hue-1: hsl(18 32% 21%);
    --follow-hue-2: hsl(348 26% 22%);
    --follow-hue-3: hsl(52 30% 19%);
    --follow-hue-4: hsl(6 30% 22%);
  }
}

:root[data-theme="dark"] {
  --bg: #1c140c; --surface: #2a1f14; --surface-2: #362819;
  --cork: #4a3018; --cork-deep: #2e1d0e; --on-cork: #f3e9d8;
  --ink: #f3e9d8; --ink-dim: #c7b89a; --ink-faint: #a3937a; --ink-mute: #7a6c55;
  --accent: #7fbf62; --on-accent: #1c140c; --accent-soft: #23361c;
  --alert: #e8836a; --alert-soft: #3a2018;
  --warn: #e0ac4a; --warn-soft: #3a2c12;
  --info: #6bb8be; --info-soft: #1c3436;
  --credit: #b99ae0;
  --chart-1: #7fbf62; --chart-2: #6bb8be; --chart-3: #e0ac4a;
  --chart-4: #b99ae0; --chart-5: #e8836a; --chart-6: #9aab90;
  --line: rgba(243, 233, 216, 0.12);
  --line-soft: rgba(243, 233, 216, 0.06);
  --line-firm: rgba(243, 233, 216, 0.22);
  --note-shadow: 0 2px 12px rgba(0, 0, 0, 0.35), 0 1px 2px rgba(0, 0, 0, 0.25);
  --shift-day-bg: #e2a648; --shift-day-ink: #2c1c00;
  --shift-night-bg: #4d5fa0; --shift-night-ink: #f0f3fd;
  --follow-hue-0: hsl(38 30% 20%);
  --follow-hue-1: hsl(18 32% 21%);
  --follow-hue-2: hsl(348 26% 22%);
  --follow-hue-3: hsl(52 30% 19%);
  --follow-hue-4: hsl(6 30% 22%);
}

/* ===========================================================================
   Optional themes (header theme picker; see THEMES in app.ts). Each is a
   full palette override plus the shape/layout knobs from #106; a few add
   scoped chrome overrides for their signature look. Font stacks keep a real
   fallback -- the named faces aren't bundled, so e.g. atelier lands on
   Georgia, cyber on the platform monospace. The base corkboard is untouched.
   =========================================================================== */

/* -- Blueprint: flat technical, blue ink on cool paper -- */
:root[data-theme="blueprint"] {
  --bg: #f0f4f8; --surface: #ffffff; --surface-2: #e1e8ef;
  --cork: #1a365d; --cork-deep: #0f172a; --on-cork: #f8fafc;
  --ink: #0f172a; --ink-dim: #334155; --ink-faint: #475569; --ink-mute: #94a3b8;
  --accent: #2563eb; --on-accent: #ffffff; --accent-soft: #dbeafe;
  --alert: #dc2626; --alert-soft: #fee2e2;
  --warn: #b45309; --warn-soft: #fef3c7;
  --info: #0e7490; --info-soft: #cffafe;
  --credit: #7c3aed;
  --line: rgba(15, 23, 42, 0.12); --line-soft: rgba(15, 23, 42, 0.06); --line-firm: rgba(15, 23, 42, 0.22);
  --font-display: var(--font-body);
  --panel-radius: 6px; --nav-tab-radius: 6px; --btn-radius: 4px;
  --note-shadow: 0 1px 3px rgba(15, 23, 42, 0.1), 0 1px 2px rgba(15, 23, 42, 0.06);
  --pin-size: 0px;
}

/* -- Ledger: monospace headings, hard edges, accounting-red accent -- */
:root[data-theme="ledger"] {
  --bg: #f4f5f0; --surface: #ffffff; --surface-2: #e9eadf;
  --cork: #2c4c3b; --cork-deep: #1a2f24; --on-cork: #f4f5f0;
  --ink: #1a2f24; --ink-dim: #375344; --ink-faint: #4f6e5c; --ink-mute: #8eab9a;
  --accent: #9b2226; --on-accent: #ffffff; --accent-soft: #fad9d9;
  --alert: #b3540b; --alert-soft: #fcecd7;
  --warn: #8a4d0a; --warn-soft: #fadec9;
  --info: #005f73; --info-soft: #d6f2f8;
  --credit: #5a189a;
  --line: rgba(44, 76, 59, 0.15); --line-soft: rgba(44, 76, 59, 0.08); --line-firm: rgba(44, 76, 59, 0.3);
  --font-display: "Courier New", Courier, monospace;
  --panel-radius: 0px; --nav-tab-radius: 0px; --btn-radius: 0px;
  --note-shadow: none; --pin-size: 0px;
}

/* -- Minimal: black on white, no shadow, square -- */
:root[data-theme="minimal"] {
  --bg: #ffffff; --surface: #ffffff; --surface-2: #f3f4f6;
  --cork: #111827; --cork-deep: #000000; --on-cork: #ffffff;
  --ink: #111827; --ink-dim: #374151; --ink-faint: #4b5563; --ink-mute: #9ca3af;
  --accent: #111827; --on-accent: #ffffff; --accent-soft: #f3f4f6;
  --alert: #b91c1c; --alert-soft: #fee2e2;
  --warn: #b45309; --warn-soft: #fef3c7;
  --info: #0369a1; --info-soft: #e0f2fe;
  --credit: #4f46e5;
  --line: rgba(17, 24, 39, 0.12); --line-soft: rgba(17, 24, 39, 0.06); --line-firm: rgba(17, 24, 39, 0.22);
  --font-display: var(--font-body);
  --panel-radius: 0px; --nav-tab-radius: 0px; --btn-radius: 0px;
  --note-shadow: none; --pin-size: 0px;
}

/* -- Minimal Pink: the same flat / square / no-shadow mono treatment as
   Minimal Mono, with a plum ink ramp on a pale-pink ground, a deep-pink
   accent, and a soft baby-pink header band carrying dark-plum text. AA
   held: --accent ~8:1 on --surface; --on-cork (#4a1230) ~10:1 on the
   baby-pink --cork; --ink-faint (#6d3a55) ~8.8:1 on --surface. -- */
:root[data-theme="minimal-pink"] {
  --bg: #fdf5f8; --surface: #fffcfd; --surface-2: #f8e8f0;
  --cork: #f7cbdd; --cork-deep: #e7a8c4; --on-cork: #4a1230;
  --ink: #241019; --ink-dim: #4a2338; --ink-faint: #6d3a55; --ink-mute: #c98fb0;
  --accent: #9d174d; --on-accent: #ffffff; --accent-soft: #f9e6f0;
  --alert: #b91c1c; --alert-soft: #fde6e6;
  --warn: #b45309; --warn-soft: #fef3c7;
  --info: #0369a1; --info-soft: #e0f2fe;
  --credit: #6d28d9;
  --line: rgba(109, 31, 67, 0.14); --line-soft: rgba(109, 31, 67, 0.07); --line-firm: rgba(109, 31, 67, 0.26);
  --font-display: var(--font-body);
  --panel-radius: 0px; --nav-tab-radius: 0px; --btn-radius: 0px;
  --note-shadow: none; --pin-size: 0px;
}
/* Minimal Pink is the only theme with a light header band, so the header
   controls' translucent-black chips and near-white hairlines (tuned for a
   dark cork) get re-grounded in the plum ink here. */
[data-theme="minimal-pink"] header .icon-btn,
[data-theme="minimal-pink"] header button:not(.icon-btn),
[data-theme="minimal-pink"] .theme-select,
[data-theme="minimal-pink"] .name-chip-input {
  background: rgba(74, 18, 48, 0.07);
  border-color: rgba(74, 18, 48, 0.3);
}
[data-theme="minimal-pink"] header .icon-btn:hover,
[data-theme="minimal-pink"] header button:not(.icon-btn):hover:not(:disabled),
[data-theme="minimal-pink"] .theme-select:hover { border-color: rgba(74, 18, 48, 0.55); }
[data-theme="minimal-pink"] header .icon-btn:hover { color: var(--accent); }

/* -- Nordic Glass: frosted panels, floating pills, soft gradient ground -- */
:root[data-theme="nordic"] {
  --bg: #eef2f6;
  --surface: rgba(255, 255, 255, 0.75);
  --surface-2: rgba(230, 238, 248, 0.6);
  --cork: #1e293b; --cork-deep: #0f172a; --on-cork: #f8fafc;
  --ink: #0f172a; --ink-dim: #334155; --ink-faint: #64748b; --ink-mute: #94a3b8;
  --accent: #0369a1; --on-accent: #ffffff; --accent-soft: #e0f2fe;
  --alert: #be123c; --alert-soft: #ffe4e6;
  --warn: #b45309; --warn-soft: #fef3c7;
  --info: #0f766e; --info-soft: #ccfbf1;
  --credit: #7c3aed;
  --line: rgba(148, 163, 184, 0.25); --line-soft: rgba(148, 163, 184, 0.12); --line-firm: rgba(148, 163, 184, 0.4);
  --font-body: "Plus Jakarta Sans", "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  --font-display: var(--font-body);
  --panel-radius: 20px; --nav-tab-radius: 999px; --btn-radius: 999px;
  --note-shadow: 0 10px 30px -5px rgba(15, 23, 42, 0.08), 0 4px 12px -2px rgba(15, 23, 42, 0.04), inset 0 1px 1px rgba(255, 255, 255, 0.8);
  --pin-size: 0px;
}
[data-theme="nordic"] body {
  background-image:
    radial-gradient(at 0% 0%, rgba(224, 242, 254, 0.6) 0px, transparent 50%),
    radial-gradient(at 100% 100%, rgba(237, 233, 254, 0.6) 0px, transparent 50%);
  background-attachment: fixed;
}
[data-theme="nordic"] header {
  background: rgba(15, 23, 42, 0.88);
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
  border-bottom: 1px solid rgba(255, 255, 255, 0.12);
}
/* ponytail: backdrop blur on the panel classes only, not .calendar-day --
   a month grid of ~35 blurred layers is a real scroll cost. */
[data-theme="nordic"] .upcoming,
[data-theme="nordic"] .proposed,
[data-theme="nordic"] .connections,
[data-theme="nordic"] .csv-import,
[data-theme="nordic"] .budget-expenses,
[data-theme="nordic"] .income-card,
[data-theme="nordic"] .advice-card,
[data-theme="nordic"] .dashboard-widget,
[data-theme="nordic"] .household-member-row,
[data-theme="nordic"] .plant-saved-row {
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
  border: 1px solid rgba(255, 255, 255, 0.7);
}
[data-theme="nordic"] .nav-tab.active {
  background: var(--accent);
  border-color: transparent;
}

/* -- Bento Studio: dark modular grid, tinted-transparent state colours -- */
:root[data-theme="bento"] {
  --bg: #0d0f12; --surface: #16191e; --surface-2: #21262d;
  --cork: #16191e; --cork-deep: #0d0f12; --on-cork: #f0f6fc;
  --ink: #f0f6fc; --ink-dim: #8b949e; --ink-faint: #6e7681; --ink-mute: #484f58;
  --accent: #818cf8; --on-accent: #0d0f12; --accent-soft: rgba(129, 140, 248, 0.15);
  --alert: #fb7185; --alert-soft: rgba(251, 113, 133, 0.15);
  --warn: #fbbf24; --warn-soft: rgba(251, 191, 36, 0.15);
  --info: #38bdf8; --info-soft: rgba(56, 189, 248, 0.15);
  --credit: #c084fc;
  --line: rgba(240, 246, 252, 0.1); --line-soft: rgba(240, 246, 252, 0.05); --line-firm: rgba(240, 246, 252, 0.18);
  --panel-radius: 12px; --nav-tab-radius: 8px; --btn-radius: 8px;
  --note-shadow: 0 4px 20px rgba(0, 0, 0, 0.4), 0 0 0 1px rgba(255, 255, 255, 0.05);
  --pin-size: 0px;
}
[data-theme="bento"] .nav-tab { border-color: transparent; background: var(--surface-2); }
[data-theme="bento"] .nav-tab.active { background: var(--accent); color: var(--on-accent); }

/* -- Editorial Atelier: serif gazette, offset hard shadow, rule-underline tabs -- */
:root[data-theme="atelier"] {
  --bg: #f7f4ee; --surface: #fffdf9; --surface-2: #ede8dc;
  --cork: #2a2420; --cork-deep: #1a1614; --on-cork: #f7f4ee;
  --ink: #1c1815; --ink-dim: #544b43; --ink-faint: #786c62; --ink-mute: #a89c90;
  --accent: #9a3412; --on-accent: #ffffff; --accent-soft: #ffedd5;
  --alert: #b91c1c; --alert-soft: #fee2e2;
  --warn: #b45309; --warn-soft: #fef3c7;
  --info: #0f766e; --info-soft: #ccfbf1;
  --credit: #6b21a8;
  --line: rgba(42, 36, 32, 0.16); --line-soft: rgba(42, 36, 32, 0.08); --line-firm: rgba(42, 36, 32, 0.3);
  --font-body: Georgia, "Times New Roman", serif;
  --font-display: "Playfair Display", Georgia, "Times New Roman", serif;
  --panel-radius: 4px; --nav-tab-radius: 0px; --btn-radius: 2px;
  --note-shadow: 4px 4px 0 rgba(42, 36, 32, 0.06);
  --pin-size: 0px;
}
[data-theme="atelier"] header { border-bottom: 2px solid var(--accent); }
[data-theme="atelier"] .nav-tab.active {
  background: transparent;
  color: var(--accent);
  border-bottom: 2px solid var(--accent);
}
[data-theme="atelier"] button:not(.icon-btn):not(.nav-tab) {
  text-transform: uppercase;
  letter-spacing: 0.06em;
  font-size: var(--t-micro);
  font-weight: 700;
}

/* -- Cyber Terminal: obsidian HUD, mono type, glow accents, grid ground -- */
:root[data-theme="cyber"] {
  --bg: #090d16; --surface: #0f172a; --surface-2: #1e293b;
  --cork: #0f172a; --cork-deep: #020617; --on-cork: #38bdf8;
  --ink: #f1f5f9; --ink-dim: #94a3b8; --ink-faint: #64748b; --ink-mute: #475569;
  --accent: #34d399; --on-accent: #020617; --accent-soft: rgba(52, 211, 153, 0.18);
  --alert: #fb7185; --alert-soft: rgba(251, 113, 133, 0.18);
  --warn: #fbbf24; --warn-soft: rgba(251, 191, 36, 0.18);
  --info: #22d3ee; --info-soft: rgba(34, 211, 238, 0.18);
  --credit: #e879f9;
  --line: rgba(56, 189, 248, 0.2); --line-soft: rgba(56, 189, 248, 0.08); --line-firm: rgba(56, 189, 248, 0.4);
  --font-body: "JetBrains Mono", "Fira Code", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  --font-display: var(--font-body);
  --panel-radius: 4px; --nav-tab-radius: 4px; --btn-radius: 4px;
  --note-shadow: 0 0 15px rgba(52, 211, 153, 0.1);
  --pin-size: 0px;
}
[data-theme="cyber"] body {
  background-image:
    linear-gradient(rgba(56, 189, 248, 0.03) 1px, transparent 1px),
    linear-gradient(90deg, rgba(56, 189, 248, 0.03) 1px, transparent 1px);
  background-size: 24px 24px;
}
[data-theme="cyber"] header { border-bottom: 1px solid var(--accent); }
[data-theme="cyber"] .nav-tab { text-transform: uppercase; }
[data-theme="cyber"] .nav-tab.active { box-shadow: 0 0 12px rgba(52, 211, 153, 0.5); }
[data-theme="cyber"] .upcoming,
[data-theme="cyber"] .proposed,
[data-theme="cyber"] .connections,
[data-theme="cyber"] .csv-import,
[data-theme="cyber"] .budget-expenses,
[data-theme="cyber"] .income-card,
[data-theme="cyber"] .advice-card,
[data-theme="cyber"] .dashboard-widget,
[data-theme="cyber"] .household-member-row,
[data-theme="cyber"] .plant-saved-row,
[data-theme="cyber"] .calendar-day {
  border-top: 2px solid var(--accent);
}

* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
/* JS toggles `.hidden` to show/hide form sub-controls; a class that sets
   `display` (inline-flex groups, grids) otherwise wins over the UA rule
   and the "hidden" field keeps rendering. */
[hidden] { display: none !important; }
body {
  background: var(--bg);
  color: var(--ink);
  font: var(--t-body)/1.55 var(--font-body);
  font-variant-numeric: tabular-nums;
  -webkit-font-smoothing: antialiased;
  -webkit-text-size-adjust: 100%;
}
h1, h2, h3 { text-wrap: balance; font-family: var(--font-display); font-weight: 700; }
p, li { text-wrap: pretty; }

@media (prefers-reduced-motion: reduce) {
  * { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; }
}

/* The one authored motion moment: switching tabs settles the new page
   onto the board, like a fresh note being pinned up -- once per tab
   switch, never per card, never repeated per scroll or hover. */
@keyframes settle-onto-board {
  from { opacity: 0; transform: translateY(6px); }
  to { opacity: 1; transform: translateY(0); }
}
.board-page { animation: settle-onto-board 320ms cubic-bezier(0, 0.6, 0.2, 1); }

::selection { background: var(--accent-soft); color: var(--ink); }
::-webkit-scrollbar { width: 12px; height: 12px; }
::-webkit-scrollbar-track { background: var(--bg); }
::-webkit-scrollbar-thumb { background: var(--ink-mute); border: 3px solid var(--bg); border-radius: 999px; }
::-webkit-scrollbar-thumb:hover { background: var(--ink-faint); }
* { scrollbar-color: var(--ink-mute) var(--bg); scrollbar-width: thin; }

#root {
  max-width: var(--page-max);
  margin: 0 auto;
  padding: 0 var(--page-pad) var(--s6);
}

/* The cork band -- the one place color commits at full page width, the
   nameplate for the whole board. */
header {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--s2) var(--s3);
  margin: 0 calc(-1 * var(--page-pad));
  padding: var(--s3) var(--page-pad);
  background: var(--cork);
  border-bottom: 1px solid var(--cork-deep);
  position: sticky;
  top: 0;
  z-index: 10;
}
header h1 {
  font-size: 1.5rem;
  margin: 0;
  font-weight: 700;
  letter-spacing: 0;
  color: var(--on-cork);
}

/* The nameplate: mascot sticker + Caveat wordmark. The mark is a keyed-out
   transparent PNG -- no card, no border, it sits straight on the cork like a
   sticker on the board. */
.nameplate {
  display: flex;
  align-items: center;
  gap: var(--s2);
}
.nameplate-mark {
  height: 1.7em;
  width: auto;
  flex: 0 0 auto;
}
.signin .nameplate {
  flex-direction: column;
  align-items: center;
  gap: var(--s3);
}
.signin .nameplate-mark {
  height: 5rem;
}

header .icon-btn,
header button:not(.icon-btn) {
  margin-left: auto;
}
header .icon-btn + button:not(.icon-btn) { margin-left: 0; }

/* The theme picker sits where the old theme toggle did -- first control after
   the nameplate, pushed right; everything after it rides along without its
   own auto-margin. */
header .theme-picker { margin-left: auto; }
header .theme-picker ~ .icon-btn,
header .theme-picker ~ button:not(.icon-btn) { margin-left: 0; }
.theme-picker { display: inline-flex; align-items: center; gap: var(--s1); flex: 0 0 auto; }
.theme-picker-icon { display: flex; color: var(--on-cork); }
.theme-picker-icon svg { display: block; }
.theme-select {
  height: 38px;
  padding: 0 var(--s2);
  font: inherit;
  font-size: var(--t-small);
  color: var(--on-cork);
  background: rgba(0, 0, 0, 0.14);
  border: 1px solid rgba(255, 253, 249, 0.32);
  border-radius: var(--btn-radius);
  cursor: pointer;
}
.theme-select:hover { border-color: rgba(255, 253, 249, 0.5); }
/* The dropdown list itself renders in page context, not on the cork */
.theme-select option { color: var(--ink); background: var(--surface); }

header .icon-btn {
  color: var(--on-cork);
  border-color: rgba(255, 253, 249, 0.32);
  background: rgba(0, 0, 0, 0.14);
}
header .icon-btn:hover { color: var(--warn-soft); border-color: rgba(255, 253, 249, 0.5); }
header button:not(.icon-btn) {
  color: var(--on-cork);
  border-color: rgba(255, 253, 249, 0.32);
  background: rgba(0, 0, 0, 0.14);
}
header button:not(.icon-btn):hover:not(:disabled) { border-color: rgba(255, 253, 249, 0.5); }

.icon-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
  flex: 0 0 auto;
  padding: 0;
  color: var(--ink-faint);
  border: 1px solid var(--line);
  border-radius: var(--btn-radius);
  background: var(--surface-2);
  cursor: pointer;
  transition: color var(--fast) var(--ease), border-color var(--fast) var(--ease),
              transform var(--fast) var(--ease);
}
.icon-btn:hover { color: var(--accent); border-color: var(--accent); }
.icon-btn:active { transform: scale(0.97); }

/* Your own display name in the header -- a text chip, not a square icon
   button, so it sizes to the name and clips a long one. */
.name-chip {
  width: auto;
  min-width: 2.5rem;
  max-width: 7rem;
  padding: 0 var(--s2);
  font: inherit;
  font-size: var(--t-small);
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.name-chip-edit { display: flex; flex: 0 0 auto; }
.name-chip-input {
  width: 7rem;
  height: 38px;
  padding: 0 var(--s2);
  font-size: var(--t-small);
  color: var(--on-cork);
  background: rgba(0, 0, 0, 0.22);
  border: 1px solid rgba(255, 253, 249, 0.5);
  border-radius: var(--radius-sm);
}

/* --- Tabs -------------------------------------------------------------- */
.top-nav, .sub-nav {
  display: flex;
  gap: var(--s1);
  flex-wrap: wrap;
  margin-top: var(--s4);
  border-bottom: none;
}
.sub-nav { margin-top: var(--s3); margin-bottom: var(--s3); }

.nav-tab {
  flex: 0 0 auto;
  padding: var(--s2) var(--s3);
  font: inherit;
  font-size: var(--t-body);
  font-weight: 500;
  color: var(--ink-dim);
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: var(--nav-tab-radius);
  cursor: pointer;
  transition: color var(--fast) var(--ease), background var(--fast) var(--ease),
              border-color var(--fast) var(--ease), transform var(--fast) var(--ease);
}
.nav-tab:hover { color: var(--ink); border-color: var(--line-firm); }
.nav-tab:active { transform: scale(0.97); }
.nav-tab.active {
  color: var(--on-accent);
  background: var(--accent);
  border-color: var(--accent);
  font-weight: 600;
}
.nav-tab.active:hover { color: var(--on-accent); border-color: var(--accent); }

.sub-nav .nav-tab { font-size: var(--t-small); padding: var(--s1) var(--s3); }

section, .bills-tab, .budget-tab, .settings-tab { margin-top: var(--s5); }
section:first-child, .bills-tab:first-child { margin-top: var(--s4); }

/* --- Panels: every top-level content block is a note pinned to the board.
   A soft warm lift plus one small pushpin dot -- neutral by default, and
   colored only where the panel already carries a real state class (a
   proposal needs review, a calendar day has events). No new state is
   invented here; the pin only reads what the DOM already says. --- */
.upcoming, .proposed, .connections, .csv-import, .budget-expenses, .income-card,
.advice-card, .dashboard-widget, .household-member-row, .plant-saved-row, .calendar-day {
  position: relative;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--panel-radius);
  padding: var(--panel-pad);
  box-shadow: var(--note-shadow);
}
.income-card { padding: var(--panel-pad) var(--panel-pad) var(--s5); }

.upcoming::before, .proposed::before, .connections::before, .csv-import::before,
.budget-expenses::before, .income-card::before, .advice-card::before, .dashboard-widget::before,
.household-member-row::before, .calendar-day::before {
  content: "";
  position: absolute;
  top: var(--pin-top);
  right: var(--pin-right);
  width: var(--pin-size);
  height: var(--pin-size);
  border-radius: var(--pin-radius);
  background: var(--pin-color);
}
.proposed::before { background: var(--warn); }
.calendar-day.has-events::before { background: var(--accent); }

/* --- Rows: dense list lines inside a note, hairline dividers, a hover
   that says "this is where the pointer is" without a bordered chip per
   row. Flat, unrotated, no lift -- this is where numbers get read fast. --- */
.row {
  display: flex;
  gap: var(--s3);
  align-items: center;
  padding: var(--s2) 0;
  border-bottom: 1px solid var(--line-soft);
  transition: background var(--fast) var(--ease);
}
.row:last-child { border-bottom: none; }
.row:hover { background: var(--surface-2); margin: 0 calc(-1 * var(--s2)); padding-left: var(--s2); padding-right: var(--s2); }
/* min-width:0 lets a long name span shrink instead of pushing trailing
   buttons off a narrow phone screen (WCAG 1.4.10 Reflow). */
.row span { flex: 1; min-width: 0; }
.row-actions { flex-wrap: wrap; }

.status-overdue { color: var(--alert); font-weight: 600; }
.badges { flex: 0 0 auto; color: var(--warn); font-weight: 600; font-size: var(--t-small); text-align: right; }

/* A bill row carries a name, amount, date, optional badges, and up to two
   buttons -- more than fits one phone line. Without a wrap, every span
   above (flex:1, min-width:0) got squeezed onto the same line at once,
   so the amount and date shrank to near-zero width and wrapped their own
   text on top of each other instead of the row wrapping. */
.instance-row, .proposed-row { flex-wrap: wrap; row-gap: var(--s1); }
.instance-row > span:first-child, .proposed-row > span:first-child { flex: 1 1 8rem; min-width: 0; }
.instance-row > span:not(:first-child), .proposed-row > span:not(:first-child) { flex: 0 0 auto; }
.instance-row > button, .proposed-row > button { flex: 0 0 auto; }

/* Off-screen but read by assistive tech -- the live region for "Saved" and
   for state changes the app makes without a visible control. */
.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;
}
/* A save failure with its Retry -- alert-red, kept out of any label slot. */
.save-error { color: var(--alert); }
.save-error .save-retry {
  min-height: 0;
  margin-left: var(--s2);
  padding: 2px var(--s2);
  font-size: var(--t-small);
}
input[aria-invalid="true"], select[aria-invalid="true"] { border-color: var(--alert); }

/* A proposal is a claim, not a fact yet -- a warm marigold tint meaning
   "needs a look." */
.proposed-row { background: var(--warn-soft); border-radius: var(--radius-sm); padding-left: var(--s2); padding-right: var(--s2); }
.proposed-row:hover { background: var(--warn-soft); filter: brightness(0.97); }

/* --- Forms --------------------------------------------------------------
   36px controls, same radius-steps-in-from-the-panel rule as before,
   softened. */
input, select, textarea {
  font: inherit;
  font-size: var(--t-body);
  color: var(--ink);
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  padding: var(--s2) var(--s3);
  transition: border-color var(--fast) var(--ease);
}
textarea { resize: vertical; }
input:hover, select:hover, textarea:hover { border-color: var(--line-firm); }
input::placeholder, textarea::placeholder { color: var(--ink-faint); }
input:focus-visible, select:focus-visible, textarea:focus-visible, button:focus-visible, a:focus-visible,
[role="button"]:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

button {
  font: inherit;
  font-size: var(--t-body);
  font-weight: 500;
  padding: var(--s2) var(--s4);
  min-height: 36px;
  border-radius: var(--btn-radius);
  border: 1px solid var(--line);
  background: var(--surface-2);
  color: var(--ink);
  cursor: pointer;
  transition: background var(--fast) var(--ease), border-color var(--fast) var(--ease),
              transform var(--fast) var(--ease);
}
button:hover:not(:disabled) { border-color: var(--line-firm); }
button:active:not(:disabled) { transform: scale(0.97); }
button:disabled { opacity: 0.45; cursor: not-allowed; }

/* Phone widths: the default button is tuned for a mouse and reads as
   oversized on a phone, especially in a wrapped row. Trim height, padding
   and text -- kept at bare `button` specificity so every class-styled
   button (nav pills, icon buttons, the board segment control, the compact
   editbar buttons) keeps its own sizing untouched. The sign-in CTA is a
   deliberate exception restored just below. */
@media (max-width: 560px) {
  button {
    min-height: 32px;
    padding: var(--s1) var(--s3);
    font-size: var(--t-small);
  }
  .signin button {
    min-height: 44px;
    padding: var(--s3) var(--s5);
    font-size: var(--t-body);
  }
}

.add-bill-form, .simplefin-connect, .add-category-row, .delete-category-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s2);
  align-items: center;
  padding-bottom: var(--s3);
  margin-bottom: var(--s3);
  border-bottom: 1px solid var(--line-soft);
}
.add-bill-form input[type="text"] { flex: 1 1 10rem; }
.add-bill-form input[type="number"] { flex: 0 1 6rem; }
.add-bill-form input[type="date"] { flex: 0 1 9rem; }
.add-bill-form input[type="file"] { flex: 0 1 12rem; }
.add-bill-form .status, .simplefin-connect .status { flex-basis: 100%; color: var(--ink-dim); font-size: var(--t-small); }

/* Account-type prompt (ADR-0029): the session-dismissible banner, and the
   always-visible per-account picker on Settings. */
.account-type-banner {
  padding: var(--s3);
  margin-bottom: var(--s4);
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
}
.account-type-banner > p:first-child { margin: 0 0 var(--s2); font-weight: 600; }
.account-type-row { border-bottom: none; gap: var(--s2); flex-wrap: wrap; }
.account-type-row .row-actions { flex: 0 0 auto; }
.account-type-hint { margin: var(--s2) 0 0; }
.account-type-dismiss { margin-top: var(--s2); }
.account-type-list { flex-basis: 100%; display: flex; flex-direction: column; gap: var(--s2); }
.account-type-field { display: flex; align-items: center; gap: var(--s2); font-size: var(--t-small); color: var(--ink-dim); }
.account-type-field > span { flex: 1 1 auto; min-width: 0; }
.account-type-field select { flex: 0 1 10rem; }

/* --- Budget -------------------------------------------------------------- */
.month-nav { display: flex; align-items: center; gap: var(--s3); }
.month-nav h2 {
  margin: 0;
  font-size: 1.375rem;
  font-weight: 700;
  letter-spacing: 0;
  color: var(--ink);
}

.budget-layout { display: flex; align-items: flex-start; gap: var(--layout-gap); flex-wrap: wrap; }
.budget-expenses { flex: 1 1 24rem; min-width: 0; }
.income-card { flex: 0 1 18rem; }

/* Budget > Advice dashboard (ADR-0030 / ADR-0031). A stack of pinned-note
   sections; the spend donut is the one sanctioned chart. All colour comes
   from tokens so it tracks theme + dark mode. */
.advice-dashboard { display: flex; flex-direction: column; gap: var(--s4); }
.advice-section {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--panel-radius);
  padding: var(--s4);
  box-shadow: var(--note-shadow);
  display: flex;
  flex-direction: column;
  gap: var(--s3);
}
.advice-section h3 {
  margin: 0;
  font-family: var(--font-body);
  font-size: var(--t-micro);
  text-transform: uppercase;
  letter-spacing: 0.11em;
  font-weight: 600;
  color: var(--ink-faint);
}
.advice-intro { margin: 0; font-size: var(--t-small); line-height: 1.5; color: var(--ink-dim); }
.advice-caption { font-size: var(--t-micro); color: var(--ink-faint); }

.advice-kpi-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr)); gap: var(--s3); }
.advice-kpi {
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--panel-radius);
  padding: var(--s3); box-shadow: var(--note-shadow);
  display: flex; flex-direction: column; gap: var(--s1);
}
.advice-kpi h4 {
  margin: 0; font-family: var(--font-body); font-size: var(--t-micro);
  text-transform: uppercase; letter-spacing: 0.09em; font-weight: 600; color: var(--ink-faint);
}
.advice-kpi-value { margin: 0; font-size: var(--t-head); font-weight: 700; color: var(--ink); }

/* Spend donut */
.advice-donut-wrap { display: flex; flex-direction: column; align-items: center; gap: var(--s3); }
.advice-donut { width: 12rem; height: 12rem; max-width: 100%; }
.advice-donut-track { stroke: var(--line-soft); }
.advice-donut-slice { transition: opacity var(--fast) var(--ease); }
.advice-donut-slice:hover { opacity: 0.75; }
.slice-1 { stroke: var(--chart-1); background: var(--chart-1); }
.slice-2 { stroke: var(--chart-2); background: var(--chart-2); }
.slice-3 { stroke: var(--chart-3); background: var(--chart-3); }
.slice-4 { stroke: var(--chart-4); background: var(--chart-4); }
.slice-5 { stroke: var(--chart-5); background: var(--chart-5); }
.slice-6 { stroke: var(--chart-6); background: var(--chart-6); }
.advice-legend { display: grid; grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr)); gap: var(--s1) var(--s3); width: 100%; }
.advice-legend-item { display: flex; align-items: center; gap: var(--s2); font-size: var(--t-micro); min-width: 0; }
.advice-legend-dot { width: 9px; height: 9px; border-radius: 999px; flex: 0 0 auto; }
.advice-legend-name { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.advice-legend-val { color: var(--ink-dim); flex: 0 0 auto; }

.advice-list { margin: 0; padding-left: var(--s4); display: flex; flex-direction: column; gap: var(--s2); }
.advice-list li { font-size: var(--t-small); line-height: 1.45; }
.advice-foot { border-bottom: none; gap: var(--s3); flex-wrap: wrap; margin-top: var(--s2); align-items: flex-start; }
.advice-foot .advice-caption { flex: 1 1 12rem; }

/* Bills review */
.advice-bill-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr)); gap: var(--s3); }
.advice-bill {
  background: var(--surface-2); border: 1px solid var(--line-soft); border-radius: var(--radius-sm);
  padding: var(--s3); display: flex; flex-direction: column; gap: var(--s1);
}
.advice-bill-name { flex: 1; font-weight: 600; font-size: var(--t-small); }
.advice-badge {
  flex: 0 0 auto; font-size: var(--t-micro); font-weight: 600;
  padding: 0 var(--s2); border-radius: 999px; background: var(--warn-soft); color: var(--warn);
}

/* Category matrix */
.advice-table-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.advice-table { width: 100%; border-collapse: collapse; font-size: var(--t-small); min-width: 30rem; }
.advice-table th {
  text-align: left; padding: var(--s1) var(--s2); font-size: var(--t-micro);
  text-transform: uppercase; letter-spacing: 0.08em; color: var(--ink-faint);
  font-weight: 600; border-bottom: 1px solid var(--line); white-space: nowrap;
}
.advice-table td { padding: var(--s2); border-bottom: 1px solid var(--line-soft); vertical-align: middle; white-space: nowrap; }
.advice-table tr:last-child td { border-bottom: none; }
.advice-bar { display: inline-block; width: 5rem; height: 6px; border-radius: 999px; background: var(--line-soft); overflow: hidden; vertical-align: middle; margin-right: var(--s2); }
.advice-bar-fill { height: 100%; background: var(--accent); border-radius: 999px; }
.advice-bar-fill.over { background: var(--alert); }

.advice-badge.health-good { background: var(--accent-soft); color: var(--accent); }
.advice-badge.health-fair { background: var(--warn-soft); color: var(--warn); }

/* Goals (ADR-0032) */
.advice-goal {
  background: var(--surface-2); border: 1px solid var(--line-soft); border-radius: var(--radius-sm);
  padding: var(--s3); display: flex; flex-direction: column; gap: var(--s1);
}
.advice-goal .row { flex-wrap: wrap; }
.advice-goal-title { flex: 1; font-weight: 600; font-size: var(--t-small); }
.advice-bar.wide { display: block; width: 100%; height: 8px; margin: var(--s1) 0; }
.advice-goal-form { display: flex; flex-direction: column; gap: var(--s2); }
.advice-goal-field { display: flex; flex-direction: column; gap: var(--s1); font-size: var(--t-small); color: var(--ink-dim); }
.advice-goal-field input, .advice-goal-field select { max-width: 22rem; }

/* Action checklist */
.advice-checklist { display: flex; flex-direction: column; gap: var(--s2); }
.advice-check { display: flex; gap: var(--s2); align-items: flex-start; font-size: var(--t-small); line-height: 1.4; cursor: pointer; }
.advice-check.done span { color: var(--ink-faint); text-decoration: line-through; }

@media (max-width: 560px) {
  .advice-kpi-grid { grid-template-columns: repeat(2, 1fr); }
}
.income-card h2 {
  margin: 0 0 var(--s2);
  font-family: var(--font-body);
  font-size: var(--t-micro);
  text-transform: uppercase;
  letter-spacing: 0.11em;
  font-weight: 600;
  color: var(--ink-faint);
}
.income-card .budget-row { flex-wrap: wrap; }
/* The 4-field budget row (name/input/actual/Save) has no room to hold a
   straight line at phone width -- wraps instead of truncating the Save
   button off the edge. flex-wrap costs nothing at desktop widths, where
   there's room and it never triggers. */
.budget-row { flex-wrap: wrap; }
.budget-row input[type="number"] { flex: 0 1 6rem; }
.budget-row span:first-child { flex: 1 1 8rem; }
/* actual + suggested pack together onto the wrapped second line instead of
   each grabbing flex:1 and splitting it -- and "actual: $x · over" never
   breaks mid-phrase. */
.budget-row .budget-actual { flex: 0 1 auto; white-space: nowrap; font-size: var(--t-small); color: var(--ink-dim); }
.budget-row .suggested-tag { flex: 0 1 auto; }
/* Spending has run past what's budgeted for the category -- same --alert
   "in the red" cue as .status-overdue and the negative income-card value. */
.budget-actual.over-budget { color: var(--alert); font-weight: 600; }
/* On-credit reconciliation (ADR-0029): "$X charged · $Y assigned" on the
   category row, packed onto the wrapped line like .budget-actual. The
   >= $1-gap flag reuses the --alert "in the red" cue, plus the text suffix
   the span already carries so it survives greyscale / a screen reader. */
.budget-row .budget-on-credit { flex: 0 1 auto; white-space: nowrap; font-size: var(--t-small); color: var(--ink-dim); }
.budget-on-credit.on-credit-mismatch { color: var(--alert); font-weight: 600; white-space: normal; }
/* The plain "here's how much is on credit" annotation (ADR-0029, T8) --
   its own --credit violet, and it coexists with .budget-actual's own
   "· over" suffix rather than replacing it. */
.on-credit-annotation { color: var(--credit); font-weight: 600; font-size: var(--t-small); white-space: nowrap; }
.budget-row .on-credit-annotation { flex: 0 1 auto; }
.category-group-header .on-credit-annotation { flex: 0 0 auto; text-align: right; }
/* Income card's "On credit this month" line -- same size/weight as
   .income-card-note but --credit, not the --info hue. */
.income-card-line.on-credit-line { color: var(--credit); }
/* "suggested" (a running average, never saved) vs blank (an explicit,
   saved figure) -- text doubles as the error slot if an auto-save fails. */
.suggested-tag { color: var(--ink-faint); font-size: var(--t-small); font-style: italic; }

.income-card-summary {
  margin-top: var(--s3);
  padding-top: var(--s3);
  border-top: 1px solid var(--line);
}
.income-card-line {
  display: flex;
  justify-content: space-between;
  gap: var(--s2);
  padding: var(--s1) 0;
  font-weight: 600;
}
.income-card-value { color: var(--accent); }
.income-card-value.negative { color: var(--alert); }
/* Bills that show this month but are paid from another month's cheque --
   held out of "Budget Space Remaining", noted so the number reconciles. */
.income-card-note { font-weight: 500; color: var(--info); font-size: var(--t-small); }
.income-card-caption {
  margin: var(--s1) 0 0;
  font-size: var(--t-micro);
  font-style: italic;
  color: var(--ink-dim);
  font-weight: 400;
}

.income-source-breakdown { margin-top: var(--s3); padding-top: var(--s3); border-top: 1px solid var(--line); }
.income-source-breakdown h3 {
  margin: 0 0 var(--s2);
  font-family: var(--font-body);
  font-size: var(--t-micro);
  text-transform: uppercase;
  letter-spacing: 0.11em;
  font-weight: 600;
  color: var(--ink-faint);
}
.income-source-group { border-bottom: 1px solid var(--line-soft); }
.income-source-header { border-bottom: none; gap: var(--s2); }
.income-source-header .row-toggle:hover { background: var(--surface-2); }
.income-source-remove {
  flex: 0 0 auto;
  width: 1.75rem;
  height: 1.75rem;
  padding: 0;
  line-height: 1;
  color: var(--ink-dim);
  background: transparent;
  border-color: var(--line);
}
.income-source-remove:hover { color: var(--alert); border-color: var(--alert); }
.income-source-hidden-row { opacity: 0.65; }
.income-source-hidden-row:hover { opacity: 1; }

.income-source-breakdown select { margin-bottom: var(--s2); }
.budget-assign-row { padding-left: var(--s4); border-bottom: none; }
.budget-assign-row select { flex: 0 1 16rem; }

.income-assignment-row { padding-left: var(--s4); border-bottom: none; }
.income-assignment-row select { flex: 0 1 16rem; }

.budget-category-block { border-bottom: 1px solid var(--line-soft); }
.budget-category-block .budget-row { border-bottom: none; }
.budget-split-toggle { padding-left: var(--s4); font-size: var(--t-small); color: var(--ink-dim); }
.budget-split-toggle .row-toggle:hover { background: var(--surface-2); }
.budget-category-block .add-bill-form { padding-left: var(--s4); border-bottom: none; }

/* A category (part-)funded by another month's cheque: a left rule in the
   info accent, and a badge on its funding line saying which month its
   money reconciles against. */
.funded-prior-month { box-shadow: inset 3px 0 0 var(--info); }
.budget-split-toggle .carried-badge {
  flex: 0 0 auto;
  align-self: center;
  padding: 1px var(--s2);
  border-radius: var(--radius-sm);
  background: var(--info-soft);
  color: var(--info);
  font-size: var(--t-micro);
  font-weight: 600;
  white-space: nowrap;
}

/* The three-way funding choice inside a category's disclosure. A real
   fieldset -- the modes are mutually exclusive (ADR-0013), which is what
   radios are for. */
.funding-mode {
  padding: var(--s2) 0 var(--s2) var(--s4);
  margin: 0;
  border: none;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--s2) var(--s3);
}
.funding-mode legend {
  float: left;
  padding: 0;
  font-size: var(--t-micro);
  text-transform: uppercase;
  letter-spacing: 0.11em;
  font-weight: 600;
  color: var(--ink-faint);
}
.funding-mode-option {
  display: inline-flex;
  align-items: center;
  gap: var(--s1);
  font-size: var(--t-small);
  color: var(--ink-dim);
  cursor: pointer;
}
.funding-mode-option input { cursor: pointer; }

/* Admin's view of a category slice handed to a member. The badge is the
   only thing the Admin learns about the member's funding -- text says the
   state so it survives greyscale, colour reinforces it: muted "awaiting",
   --warn "partly assigned", --accent "assigned". */
.budget-share-heading {
  margin: var(--s2) 0 var(--s1) var(--s4);
  font-size: var(--t-micro);
  text-transform: uppercase;
  letter-spacing: 0.11em;
  font-weight: 600;
  color: var(--ink-faint);
}
.budget-share-row { padding-left: var(--s4); border-bottom: none; }
.budget-share-row input[type="number"] { flex: 0 1 6rem; }
.share-badge {
  flex: 0 0 auto;
  padding: 1px var(--s2);
  border-radius: var(--radius-sm);
  font-size: var(--t-micro);
  font-weight: 600;
  white-space: nowrap;
  background: var(--surface-2);
  color: var(--ink-dim);
}
.share-badge.share-partial { background: var(--warn-soft); color: var(--warn); }
.share-badge.share-assigned { background: var(--accent-soft); color: var(--accent); }

/* A member's own portion of a category, under it on their Budget page --
   assigned by the Admin, or one they took on themselves. */
.your-portion {
  padding: var(--s2) 0 var(--s2) var(--s4);
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--s1) var(--s2);
  font-size: var(--t-small);
  color: var(--ink-dim);
}
.your-portion-open { display: block; }
.your-portion-label {
  font-size: var(--t-micro);
  text-transform: uppercase;
  letter-spacing: 0.11em;
  font-weight: 600;
  color: var(--ink-faint);
}
.your-portion input[type="number"] { flex: 0 1 6rem; }
.your-portion-head { border-bottom: none; gap: var(--s2); }
.your-portion-progress { color: var(--ink-faint); font-size: var(--t-micro); }
.your-portion .add-bill-form { padding-left: 0; border-bottom: none; }
.your-portion .row { padding-left: 0; }

.budget-unfunded-nudge {
  display: block;
  width: 100%;
  margin-bottom: var(--s2);
  padding: var(--s2) var(--s3);
  text-align: left;
  font-size: var(--t-small);
  color: var(--ink-dim);
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
}
.budget-unfunded-nudge::before { content: "→ "; color: var(--accent); }
.budget-unfunded-nudge:hover { border-color: var(--accent); color: var(--ink); }

/* --- Dashboard ------------------------------------------------------------ */
.dashboard-tab { display: flex; flex-direction: column; gap: var(--layout-gap); }
.dashboard-widget h3 { margin: 0 0 var(--s3); font-size: 1.25rem; }

/* Per-member card customisation. The "Customise" control sits between the
   pinned notices and the reorderable content cards; edit mode adds a bar
   above each card and a list of hidden ones at the foot. */
.dashboard-customize-row { display: flex; justify-content: flex-end; align-items: center; margin-bottom: calc(-1 * var(--s2)); }
.dashboard-customize-row.editing { justify-content: space-between; }
.dashboard-customize-hint { font-size: var(--t-small); color: var(--ink-faint); }
/* Bar + card read as one pinned note: the wrapper carries the lift and the
   radius, the card inside gives up its own top edge. */
.dashboard-card-edit {
  display: flex;
  flex-direction: column;
  border-radius: var(--panel-radius);
  box-shadow: var(--note-shadow);
}
.dashboard-card-edit > .dashboard-widget {
  margin-top: 0; /* the bare `section` rule adds --s5; the bar is the top edge here */
  box-shadow: none;
  border-top: none;
  border-radius: 0 0 var(--panel-radius) var(--panel-radius);
}
.dashboard-card-editbar {
  gap: var(--s1);
  justify-content: flex-end;
  padding: var(--s1) var(--s2);
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: var(--panel-radius) var(--panel-radius) 0 0;
}
.dashboard-card-editbar button { flex: 0 0 auto; min-height: 0; padding: 2px var(--s2); font-size: var(--t-small); }
.dashboard-hidden-list .row:last-child { border-bottom: none; }
.dashboard-hidden-list .row button,
.dashboard-add-card .row button { flex: 0 0 auto; }
.dashboard-add-card .row:last-child { border-bottom: none; }

/* Stocks card (ADR-0034 / ADR-0035) -- a watchlist row is name + live
   price + a coloured day move; an owned holding adds a position line, and
   expands to its transaction log and price alerts. Crypto is grouped
   under its own subheading when both kinds are present. */
.stock-group-label {
  margin: var(--s3) 0 var(--s1);
  font-family: var(--font-body);
  font-size: var(--t-micro);
  text-transform: uppercase;
  letter-spacing: 0.11em;
  font-weight: 600;
  color: var(--ink-faint);
}
.stock-group-label:first-of-type { margin-top: var(--s2); }
.stock-holding { padding: var(--s2) 0; border-bottom: 1px solid var(--line-soft); }
.stock-holding:last-of-type { border-bottom: none; }
.stock-row-header { cursor: pointer; gap: var(--s2); border-bottom: none; padding: 0; user-select: none; flex-wrap: wrap; }
.stock-symbol { flex: 0 0 auto; font-weight: 700; }
.stock-name { flex: 1 1 6rem; min-width: 0; color: var(--ink-dim); font-size: var(--t-small); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.stock-price { flex: 0 0 auto; font-variant-numeric: tabular-nums; }
.stock-move { flex: 0 0 auto; font-size: var(--t-small); font-weight: 600; font-variant-numeric: tabular-nums; }
.stock-gain { color: var(--accent); }
.stock-loss { color: var(--alert); }
.stock-position-line { border-bottom: none; padding: var(--s1) 0 0; font-size: var(--t-small); color: var(--ink-dim); }
.stock-realized { margin: var(--s1) 0 0; font-size: var(--t-micro); color: var(--ink-faint); }
.stock-detail { margin-top: var(--s2); padding-left: var(--s3); border-left: 2px solid var(--line); }
.stock-alerts-label { margin: var(--s2) 0 var(--s1); font-size: var(--t-micro); font-weight: 600; text-transform: uppercase; letter-spacing: 0.1em; color: var(--ink-faint); }
.stock-detail > .stock-alerts-label:first-child { margin-top: 0; }
.stock-lot-row, .stock-alert-row { font-size: var(--t-small); padding: var(--s1) 0; border-bottom: none; }
.stock-lot-row .status { flex: 0 0 auto; }
.stock-lot-row button, .stock-alert-row button { min-height: 0; padding: 2px var(--s2); line-height: 1; flex: 0 0 auto; font-size: var(--t-small); }
.stock-lot-row button.income-source-remove, .stock-alert-row button.income-source-remove { width: 1.6rem; height: 1.6rem; padding: 0; }
.stock-alert-row.fired span { color: var(--ink-faint); text-decoration: line-through; }
.stock-alerts { margin-top: var(--s2); }
.stock-alert-hint { margin: var(--s2) 0 var(--s1); font-size: var(--t-small); color: var(--ink-dim); }
.stock-lot-form, .stock-alert-form { flex-wrap: wrap; gap: var(--s1); padding-top: 0; border-bottom: none; }
.stock-lot-form select, .stock-lot-form input, .stock-alert-form input { flex: 0 1 5rem; min-width: 0; }
.stock-alert-form select { flex: 0 1 5.5rem; min-width: 0; }
.stock-lot-form input[type="date"] { flex: 0 1 9rem; }
.stock-lot-form button, .stock-alert-form button { flex: 0 0 auto; }
.stock-remove { margin-top: var(--s2); color: var(--alert); }
.stock-result-row { font-size: var(--t-small); }
.stock-result-row span { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.stock-result-row button { flex: 0 0 auto; }
.weather-icon { display: inline-flex; color: var(--ink); }
.weather-icon svg { display: block; }
.weather-temps { font-size: 1.5rem; font-weight: 700; color: var(--ink); }
.weather-temps-small { font-size: var(--t-body); font-weight: 600; }
.weather-card-header { cursor: pointer; align-items: center; gap: var(--s2); border-bottom: none; padding: 0; user-select: none; }
.weather-card-primary { display: flex; align-items: center; gap: var(--s3); flex: 1 1 auto; }
.weather-city-name { font-weight: 600; color: var(--ink); }
.weather-city-row { align-items: center; gap: var(--s2); }
.bill-due-soon-item { border-bottom: 1px solid var(--line-soft); }
.bill-due-soon-item:last-child { border-bottom: none; }
.bill-due-soon-item .row { border-bottom: none; }
.bill-assignment-note { margin: 0 0 var(--s2); font-size: var(--t-small); color: var(--ink-faint); }
.bill-due-overdue { color: var(--alert); font-weight: 600; }
.bill-overdue-badge {
  margin-left: var(--s2); font-size: var(--t-micro); font-weight: 600;
  padding: 0 var(--s2); border-radius: 999px; background: var(--alert-soft); color: var(--alert);
  vertical-align: middle;
}

/* --- Household ---------------------------------------------------------- */
.household-member-row { margin-top: var(--s3); }
.household-member-header { display: flex; align-items: center; gap: var(--s3); }
.household-member-email, .household-member-role { color: var(--ink-dim); font-size: var(--t-small); }
.household-member-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s3);
  margin-top: var(--s3);
}
.tab-checkbox { display: flex; align-items: center; gap: var(--s1); font-size: var(--t-small); }

/* The invite form's tab checkboxes: a full-width wrapping block, so they
   don't crowd in beside the name input and clip on a phone. */
.invite-tab-choices {
  flex: 1 1 100%;
  display: flex;
  flex-wrap: wrap;
  gap: var(--s2) var(--s3);
}

/* A pending-invite row: name + Revoke share the top line; the long invite
   URL drops to its own full-width line (same wrap fix as .instance-row).
   The `.invite-row > *` selectors outrank `.row span { flex: 1 }`. */
.invite-row { flex-wrap: wrap; row-gap: var(--s1); }
.invite-row > span:first-child { flex: 1 1 12rem; }
.invite-row > button { flex: 0 0 auto; }
.invite-row > .invite-link-display { flex: 1 1 100%; }
.invite-link-display {
  font-family: ui-monospace, "SF Mono", Consolas, monospace;
  font-size: var(--t-small);
  color: var(--ink-dim);
  word-break: break-all;
}

/* A member's own accent, carried wherever their name appears -- see
   personAccent() in app.ts. Reuses the same named-role colors as status,
   deliberately: one small, closed palette for the whole board, not a
   second color system layered on top. */
.person-tag {
  display: inline-flex;
  align-items: center;
  gap: var(--s1);
}
.person-tag::before {
  content: "";
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--person-color, var(--ink-mute));
  flex: 0 0 auto;
}
/* --alert is deliberately excluded -- it means "overdue/problem"
   everywhere else on the board, and a person's name is neither. */
.person-accent-0 { --person-color: var(--accent); }
.person-accent-1 { --person-color: var(--warn); }
.person-accent-2 { --person-color: var(--info); }

/* Same three colors, same rotation logic, a separate hook for a
   different relationship (a bill assigned to an income source, not a
   person's name) -- see sourceAccentClass in app.ts. */
.source-accent-0 { --source-color: var(--accent); }
.source-accent-1 { --source-color: var(--warn); }
.source-accent-2 { --source-color: var(--info); }

.income-source-dot {
  display: inline-block;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--source-color, var(--ink-mute));
  flex: 0 0 auto;
}

/* --- Plants -------------------------------------------------------------- */
.plant-candidate-row { gap: var(--s3); }
.plant-thumbnail { width: 2.5rem; height: 2.5rem; object-fit: cover; border-radius: var(--radius); }
.plant-review-form {
  display: flex;
  flex-direction: column;
  gap: var(--s3);
  margin-top: var(--s4);
  max-width: 32rem;
}
.plant-review-form label { display: flex; flex-direction: column; gap: var(--s1); font-size: var(--t-small); }
.plant-review-form textarea {
  font: inherit;
  padding: var(--s2);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--ink);
  resize: vertical;
}
.plant-saved-row {
  margin-top: var(--s2);
  overflow: hidden;
}
.plant-row { border-bottom: none; padding: var(--s3) var(--s4); gap: var(--s2); }
/* The keyboard-activatable half of a disclosure row -- fills the width so
   the whole label area is the target; action buttons sit outside it. */
.row-toggle {
  flex: 1 1 auto;
  display: flex;
  align-items: center;
  gap: var(--s2);
  cursor: pointer;
  user-select: none;
  min-width: 0;
}
.row-toggle > .row-label { flex: 1 1 auto; min-width: 0; }
.row-chevron { flex: 0 0 auto; color: var(--ink-mute); font-size: var(--t-small); }
/* A recipe reads the same in its saved-list row and as a meal-queue tile:
   both lead with its photo. */
.recipe-row-thumb {
  flex: 0 0 auto;
  width: 2.5rem; height: 2.5rem;
  object-fit: cover;
  border-radius: var(--radius-sm);
}
.plant-details { padding: 0 var(--s4) var(--s4); border-top: 1px solid var(--line-soft); }
.plant-details p { margin: var(--s2) 0 0; font-size: var(--t-small); color: var(--ink-dim); }
.plant-care-guide { white-space: pre-wrap; color: var(--ink); }
.plant-search-flow {
  margin-top: var(--s5);
  padding-top: var(--s4);
  border-top: 1px solid var(--line);
}

/* --- Food ------------------------------------------------------------ */
.food-theme-group { border-bottom: 1px solid var(--line-soft); }
.food-theme-group:first-of-type { border-top: 1px solid var(--line-soft); margin-top: var(--s3); }
/* A suggestion row is a name plus up to two action buttons -- more than fits
   one phone line, so the buttons wrap under the name instead of crushing it
   to "kim" (same fix as .instance-row / .budget-row). */
.food-theme-group .row { flex-wrap: wrap; row-gap: var(--s1); }
.food-theme-group .row > span { flex: 1 1 8rem; }
.food-theme-group .row > button { flex: 0 0 auto; }
.today-group { margin-top: var(--s3); }
.today-group:first-of-type { margin-top: 0; }
.today-group h4 { margin: 0 0 var(--s1); font-family: var(--font-body); font-size: var(--t-small); font-weight: 600; color: var(--ink-dim); }
/* A collapsible nutrient-theme heading in By Cycle > Suggestions -- a real
   section header, not a list line: full ink, body size, 700, with a hover
   fill and a chevron so it reads as the thing you open (collapsed by
   default). */
.food-theme-header {
  margin: 0;
  display: flex;
  align-items: center;
  gap: var(--s2);
  padding: var(--s3) var(--s2);
  cursor: pointer;
  user-select: none;
  font-family: var(--font-body);
  font-size: var(--t-body);
  font-weight: 700;
  color: var(--ink);
}
.food-theme-header:hover { background: var(--surface-2); }
.food-theme-header:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.food-theme-header .row-chevron { color: var(--ink-dim); }
.food-theme-header .food-theme-name { flex: 1 1 auto; min-width: 0; }
.food-theme-header .food-theme-count {
  flex: 0 0 auto;
  font-size: var(--t-small);
  font-weight: 600;
  color: var(--ink-faint);
  font-variant-numeric: tabular-nums;
}
.recipe-preview-image { max-width: 12rem; border-radius: var(--radius); margin: var(--s2) 0; }
.recipe-instructions { white-space: pre-wrap; }

/* Recipe cost estimate (ADR-0028): a price or "In Pantry" badge pinned to
   the right of each ingredient line, then a subtotal row reusing the
   shopping list's .shopping-subtotal styling. */
.recipe-ingredients-cost li {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: var(--s2);
}
.recipe-cost-price { flex: 0 0 auto; color: var(--ink-dim); font-variant-numeric: tabular-nums; }
.recipe-cost-badge {
  flex: 0 0 auto;
  font-size: var(--t-micro);
  font-weight: 600;
  color: var(--accent);
  background: var(--accent-soft);
  border-radius: var(--radius-sm);
  padding: 0 var(--s1);
}
.recipe-cost-tail { flex: 0 0 auto; margin-left: auto; display: flex; flex-wrap: wrap; justify-content: flex-end; align-items: baseline; gap: var(--s2); }
.recipe-cost-tail .link-button { margin-left: 0; font-size: var(--t-small); }
.recipe-cost-info {
  flex: 0 0 auto;
  align-self: center;
  width: 1.1rem;
  height: 1.1rem;
  padding: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--ink-faint);
  border: none;
  background: none;
  cursor: pointer;
}
.recipe-cost-info:hover { color: var(--accent); }
.recipe-cost-src { flex-basis: 100%; font-size: var(--t-micro); color: var(--ink-faint); text-align: right; }
.recipe-cost-status { color: var(--ink-faint); font-size: var(--t-small); font-style: italic; }
.recipe-cost-note { color: var(--ink-faint); font-size: var(--t-micro); margin-top: var(--s1); }
.recipe-cost-subtotal { font-size: var(--t-small); }

/* --- Recipe Board (spec #63) ---------------------------------------------
   The board IS a corkboard, so the pinned-note metaphor goes all the way
   here: cards are notes on the grid, each with a pushpin dot. Rows inside a
   card still stay flat -- the Pinned-Note Rule holds. */
.board-filter-bar { margin-bottom: var(--s4); }
.board-filter-row { display: flex; flex-wrap: wrap; gap: var(--s2); align-items: center; }
.board-filter-row select, .board-filter-row input { min-height: 32px; }
.board-filter-spacer { flex: 1 1 auto; }
.board-followed { display: inline-flex; align-items: center; gap: var(--s1); font-size: var(--t-small); color: var(--ink-dim); }
.board-followed input:disabled + span { opacity: 0.55; }

.board-seg { display: inline-flex; border: 1px solid var(--line); border-radius: 999px; overflow: hidden; }
.board-seg button {
  border: none; border-radius: 0; min-height: 36px; padding: var(--s1) var(--s3);
  background: var(--surface); color: var(--ink-dim); font-size: var(--t-small); text-transform: capitalize;
}
.board-seg button.active { background: var(--accent); color: var(--on-accent); font-weight: 600; }

.board-more-toggle {
  margin-top: var(--s2); background: none; border: none; padding: var(--s1) 0;
  color: var(--ink-dim); font-size: var(--t-small); min-height: 0;
}
.board-more {
  margin-top: var(--s2); padding: var(--s3); background: var(--surface-2);
  border: 1px solid var(--line); border-radius: var(--radius-sm);
  display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: var(--s3);
}
.board-field, .board-form-field { display: flex; flex-direction: column; gap: 3px; }
/* Not an uppercase eyebrow -- matches .food-theme-group h4 (DESIGN.md). */
.board-field-label { font-family: var(--font-body); font-size: var(--t-small); font-weight: 600; color: var(--ink-dim); }
.board-tagset { display: flex; flex-wrap: wrap; gap: var(--s1); }
.board-tag, .board-load-more {
  font-size: var(--t-small); padding: var(--s1) var(--s3); border-radius: 999px;
  background: var(--surface-2); border: 1px solid var(--line); color: var(--ink-dim); min-height: 36px;
}
.board-tag.active { background: var(--accent-soft); border-color: var(--accent); color: var(--accent); font-weight: 600; }
.board-load-more { display: block; margin: var(--s4) auto 0; }

.board-grid {
  margin-top: var(--s4);
  display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: var(--s4);
}
/* A browse tile, NOT a pinned note: parchment ground, 8px radius, no lift,
   no pushpin -- the same call .meal-card makes, so a board recipe reads the
   same as a saved-recipe tile elsewhere (DESIGN.md, the Item-tile rule). */
.board-note {
  background: var(--surface-2); border: 1px solid var(--line); border-radius: var(--radius-sm);
  padding: var(--s4); cursor: pointer; text-align: left; transition: border-color var(--fast) var(--ease);
}
.board-note:hover { border-color: var(--line-firm); }
.board-note:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.board-note-name { font-size: 1.25rem; margin: 0 0 var(--s1); }
.board-note-line { display: flex; align-items: baseline; justify-content: space-between; gap: var(--s2); flex-wrap: wrap; }
.board-kitchen { font-weight: 600; font-size: var(--t-small); color: var(--ink-dim); }
.board-kitchen-anon { font-style: italic; font-weight: 500; color: var(--ink-faint); }
.board-rating { font-size: var(--t-small); color: var(--ink-faint); white-space: nowrap; }
.board-meta { font-size: var(--t-micro); color: var(--ink-faint); margin: var(--s1) 0 0; }
.board-desc { font-size: var(--t-small); color: var(--ink-dim); margin: var(--s2) 0 0; }
.board-chips { display: flex; flex-wrap: wrap; gap: var(--s1); margin-top: var(--s2); }
/* One neutral chip -- no per-facet colour (the closed palette carries meaning
   the app reserves for status, not "vegan"/"dinner"). */
.board-chip {
  font-size: var(--t-micro); letter-spacing: 0.02em;
  padding: 2px 8px; border-radius: 999px; background: var(--surface);
  color: var(--ink-dim); border: 1px solid var(--line);
}
.board-empty { text-align: center; padding: var(--s6) var(--s3); }

/* Followed-kitchen tint (spec #73) -- followed cards only; unfollowed + anonymous stay on --surface-2. */
.board-note[data-follow-hue="0"] { background: var(--follow-hue-0); }
.board-note[data-follow-hue="1"] { background: var(--follow-hue-1); }
.board-note[data-follow-hue="2"] { background: var(--follow-hue-2); }
.board-note[data-follow-hue="3"] { background: var(--follow-hue-3); }
.board-note[data-follow-hue="4"] { background: var(--follow-hue-4); }

.board-follow-star {
  font-size: var(--t-small); padding: var(--s1) var(--s3); min-height: 36px;
  border-radius: 999px; background: var(--surface); border: 1px solid var(--line); color: var(--ink-dim);
}
.board-follow-star.following { background: var(--accent-soft); border-color: var(--accent); color: var(--accent); font-weight: 600; }
.board-follow-prompt { font-style: italic; }

.board-bands { display: flex; flex-direction: column; gap: var(--s2); }
.board-band-h { margin: var(--s4) 0 0; font-family: var(--font-body); font-size: var(--t-small); font-weight: 600; color: var(--ink-dim); }
.board-tab-links { display: flex; gap: var(--s3); flex-wrap: wrap; }
.board-follow-row { display: flex; flex-direction: column; gap: var(--s2); }

.board-detail { display: flex; flex-direction: column; gap: var(--s2); }
.board-back { align-self: flex-start; background: none; border: none; padding: var(--s1) 0; color: var(--ink-dim); font-size: var(--t-small); }
.board-detail-actions { display: flex; flex-wrap: wrap; gap: var(--s2); }
.board-detail-name { font-size: 1.375rem; margin: var(--s1) 0; }
.board-detail-h {
  margin: var(--s4) 0 var(--s1); font-family: var(--font-body); font-size: var(--t-small);
  font-weight: 600; color: var(--ink-dim);
}
.board-ingredients { margin: 0; padding-left: var(--s4); font-size: var(--t-small); }
.board-instructions { white-space: pre-wrap; font-size: var(--t-small); color: var(--ink-dim); }

.board-your-rating { color: var(--accent); font-weight: 600; }
.board-rate { display: flex; flex-direction: column; gap: var(--s2); }
.board-rate-toggle { align-self: flex-start; font-size: var(--t-small); }
.board-rate-picker { display: flex; flex-wrap: wrap; gap: var(--s1); }
.board-star, .board-rate-clear { font-size: var(--t-small); padding: var(--s1) var(--s3); }
.board-star { min-width: 40px; }
.board-star.active { background: var(--accent); border-color: var(--accent); color: var(--on-accent); font-weight: 600; }
.board-rate-clear { color: var(--ink-dim); }
.board-rate-clear:hover { color: var(--alert); border-color: var(--alert); }

.board-report { display: flex; flex-direction: column; gap: var(--s2); }
.board-report-toggle { align-self: flex-start; font-size: var(--t-small); color: var(--ink-dim); }
.board-report-menu { display: flex; flex-direction: column; gap: var(--s2); }
.board-report-reasons { display: flex; flex-wrap: wrap; gap: var(--s1); }
.board-report-reason { font-size: var(--t-small); padding: var(--s1) var(--s3); }
.board-report-reason.active { background: var(--accent); border-color: var(--accent); color: var(--on-accent); font-weight: 600; }
.board-report-note { width: 100%; }

.board-mod-row, .board-mypost { display: flex; flex-direction: column; gap: var(--s2); }
.board-mod-reports { margin: 0; padding-left: var(--s4); font-size: var(--t-small); color: var(--ink-dim); }
.board-mod-text { white-space: pre-wrap; font-family: var(--font-body); font-size: var(--t-small); background: var(--surface-2); padding: var(--s2); overflow-x: auto; }
.board-banned-note { color: var(--alert); border: 1px solid var(--alert); padding: var(--s2); border-radius: var(--radius-sm); }

/* An accent-filled primary action -- the same treatment .signin button
   carries, promoted to a reusable modifier (cf. button.danger). */
button.primary { background: var(--accent); border-color: var(--accent); color: var(--on-accent); font-weight: 600; }
button.primary:hover:not(:disabled) { filter: brightness(1.06); border-color: var(--accent); }

.board-form { display: flex; flex-direction: column; gap: var(--s3); }
.board-form input, .board-form select, .board-form textarea { width: 100%; }
.board-form-triple { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--s2); }
.board-ing-row { display: flex; gap: var(--s2); margin-bottom: var(--s2); }
.board-ing-row input:first-child { flex: 2 1 0; }
.board-ing-row input:nth-child(2) { flex: 1 1 0; }
.board-form-actions { display: flex; gap: var(--s2); margin-top: var(--s2); }
.board-form-error { font-size: var(--t-micro); color: var(--alert); }

.board-kitchen-panel { margin-bottom: var(--s4); display: flex; flex-direction: column; gap: var(--s2); }
.board-kitchen-panel h4 { margin: 0; font-family: var(--font-body); font-size: var(--t-small); font-weight: 600; color: var(--ink-dim); }
.board-kitchen-form { display: flex; gap: var(--s2); }
.board-kitchen-form input { flex: 1 1 0; }

@media (max-width: 480px) {
  .board-grid { grid-template-columns: 1fr; }
  .board-form-triple { grid-template-columns: 1fr; }
}

/* --- Calendar --------------------------------------------------------- */
.calendar-grid {
  display: grid;
  /* A real 7-day week: every date sits under its weekday column. minmax(0,..)
     lets cells shrink below their content on a phone so the row never
     overflows -- event text truncates (the day panel shows it in full). */
  grid-template-columns: repeat(7, minmax(0, 1fr));
  gap: var(--s2);
  margin-top: var(--s4);
}
.calendar-dow {
  text-align: center;
  font-size: var(--t-micro);
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ink-dim);
  padding-bottom: var(--s1);
}
/* .calendar-day-blank needs no rule -- an empty div is the spacer; it
   deliberately doesn't match .calendar-day, so it gets no note styling. */
.calendar-day {
  min-height: 4.5rem;
}
/* Today: a firm accent edge and a bold accent day-number. No background
   tint -- it dropped the colored event text (--accent, --info) below AA. */
.calendar-day.is-today { border-color: var(--accent); box-shadow: inset 0 0 0 1px var(--accent); }
.calendar-day.is-today .calendar-day-number { color: var(--accent); font-weight: 700; }
.calendar-day-head { display: flex; align-items: center; justify-content: space-between; gap: var(--s1); }
.calendar-day-number { font-weight: 600; color: var(--ink-dim); font-size: var(--t-small); }
.calendar-day-weather { display: flex; align-items: center; gap: 2px; color: var(--ink-dim); }
.calendar-day-weather .weather-icon { width: 14px; height: 14px; }
.calendar-day-weather .weather-icon svg { width: 14px; height: 14px; }
.calendar-day-temp { font-size: var(--t-micro); }
.calendar-event {
  margin-top: var(--s1);
  font-size: var(--t-small);
  color: var(--ink);
  /* 7 columns leaves each cell narrow -- keep events to one line, the day
     panel below the grid shows the full text on tap. */
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Phones: seven columns across ~360px leaves each day near 45px -- a
   number and a shift badge already overflow it. Give every day a real
   width and let the week scroll sideways instead; the weekday header and
   the leading blanks are grid children, so they track the scroll, and the
   partial next column is the affordance. JS opens the grid on today (or
   the selected day) -- see centerScrolledCalendarCell. */
@media (max-width: 560px) {
  .calendar-grid {
    grid-template-columns: repeat(7, 5rem);
    overflow-x: auto;
    overscroll-behavior-x: contain;
    /* overflow clips the day-cells' note-lift shadow at the edges;
       a hair of padding gives the blur room, pulled back so the grid
       stays column-aligned. Extra bottom room is the scrollbar's lane. */
    padding: 3px 1px var(--s2);
    margin-inline: -1px;
    scrollbar-width: thin;
    scrollbar-color: var(--line-firm) transparent;
  }
  .calendar-grid::-webkit-scrollbar { height: 5px; }
  .calendar-grid::-webkit-scrollbar-thumb { background: var(--line-firm); border-radius: 999px; }
  .calendar-day { padding: var(--s1); min-height: 3.75rem; }
  /* A three-person day would crowd the number; let the badges drop to a
     second line in the cell head rather than clip. */
  .calendar-day-head { flex-wrap: wrap; }
  .calendar-event { font-size: var(--t-micro); }
  .calendar-dow { letter-spacing: 0; }
}
.calendar-event.calendar-bill { color: var(--accent); font-weight: 600; }
.calendar-event.calendar-paycheck { color: var(--info); font-weight: 600; }
.calendar-event.calendar-watering { color: var(--warn); font-weight: 600; }
.calendar-event.calendar-chore { color: var(--ink-dim); font-weight: 600; }
/* Daycare care-schedule feed (ADR-0038), read-only like collection days.
   The label text carries the meaning; colour is not load-bearing. */
.calendar-event.calendar-daycare { color: var(--info); font-weight: 600; font-style: italic; }

/* Authored calendar items. All one weight; the kind only shifts the hue
   a touch, and every label carries its own text (time / "turns N"), so
   colour is never load-bearing. */
.calendar-event.calendar-item { color: var(--ink); font-weight: 600; }
.calendar-event.calendar-item.kind-birthday { color: var(--info); }
.calendar-event.calendar-item.kind-reminder { color: var(--warn); }
.calendar-event.calendar-item-more { font-size: var(--t-micro); color: var(--ink-faint); font-style: italic; }

/* Shift patterns (ADR-0043): a coloured initial beside the date number, not
   a text row. margin-right:auto keeps the cluster next to the number and
   pushes the weather chip to the far edge. */
.calendar-shift-badges { display: flex; gap: 2px; margin-right: auto; }
.shift-badge {
  display: inline-flex; align-items: center; justify-content: center;
  width: 1.05rem; height: 1.05rem; border-radius: 50%;
  font-size: var(--t-micro); font-weight: 700; line-height: 1; flex: none;
}
.shift-badge-day { background: var(--shift-day-bg); color: var(--shift-day-ink); }
.shift-badge-night { background: var(--shift-night-bg); color: var(--shift-night-ink); }
.shift-badge-more { background: var(--surface-2); color: var(--ink-dim); font-weight: 600; }

.calendar-day-clickable { cursor: pointer; }
.calendar-day-clickable:hover { border-color: var(--accent); }
.calendar-day.is-selected { border-color: var(--accent); box-shadow: inset 0 0 0 2px var(--accent); }

.calendar-add-item { margin-top: var(--s3); }

/* Filter chips: a layer is shown while its chip is on; an off chip is
   muted and struck through so "hidden" reads at a glance. Only layers
   with content this month get a chip. */
.calendar-filters { display: flex; flex-wrap: wrap; gap: var(--s2); margin-top: var(--s3); }
.calendar-filter-chip {
  padding: var(--s1) var(--s3);
  border: 1px solid var(--line-firm);
  border-radius: var(--nav-tab-radius);
  background: transparent;
  color: var(--ink-faint);
  font-size: var(--t-small);
  cursor: pointer;
  transition: border-color var(--fast) var(--ease), color var(--fast) var(--ease);
}
.calendar-filter-chip:hover { border-color: var(--ink-mute); }
.calendar-filter-chip:not(.is-on) { text-decoration: line-through; opacity: 0.75; }
.calendar-filter-chip.is-on {
  border-color: var(--accent);
  background: var(--accent-soft);
  color: var(--accent);
  font-weight: 600;
}

/* Reorder card -- collapsed by default, above the collection-schedule card. */
.calendar-order-card, .waste-address-section {
  margin-top: var(--s4);
  padding: var(--s3);
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  background: var(--surface-2);
}
.calendar-order-card > summary, .waste-address-section > summary {
  cursor: pointer;
  font-weight: 600;
}
.calendar-order-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s2);
  padding: var(--s1) 0;
  border-bottom: 1px solid var(--line-soft);
}
.calendar-order-reorder { display: inline-flex; }
.calendar-order-reorder button { padding: 2px var(--s2); }
.calendar-order-reorder button:first-child { border-radius: var(--radius-sm) 0 0 var(--radius-sm); }
.calendar-order-reorder button:last-child { border-radius: 0 var(--radius-sm) var(--radius-sm) 0; margin-left: -1px; }
.calendar-order-reset { margin-top: var(--s2); font-size: var(--t-small); }

/* --- Day view: one blown-up day card. It IS a .calendar-day (same
   surface, note lift, pushpin, is-today edge) scaled up -- the layers
   grouped under quiet labels, the add/edit form attached below a divider,
   so opening a day reads as the grid cell magnified, not a new screen. */
.calendar-day-view-toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s2);
  flex-wrap: wrap;
  margin-top: var(--s3);
}
/* a "back" link leads here -- override .link-button's trailing drift */
.calendar-day-view-toolbar .calendar-day-view-back { margin-left: 0; }
.calendar-day-view-stepper { display: inline-flex; gap: var(--s2); }

.calendar-day-full {
  margin-top: var(--s3);
  min-height: 0;
  display: flex;
  flex-direction: column;
  gap: var(--s4);
}
/* is-today's inset accent ring replaces the panel note-lift; the blown-up
   card wants both -- the ring for "this is today", the lift for "this is a
   pinned note". */
.calendar-day-full.is-today { box-shadow: var(--note-shadow), inset 0 0 0 1px var(--accent); }
.calendar-day-full .calendar-day-head {
  align-items: center;
  gap: var(--s3);
  flex-wrap: wrap;
}
.calendar-day-view-date { margin: 0; font-size: 1.5rem; line-height: 1.15; color: var(--ink); letter-spacing: 0; }
.calendar-day-view-meta { display: inline-flex; align-items: center; gap: var(--s3); margin-left: auto; }
@media (max-width: 560px) {
  .calendar-day-full .calendar-day-head { flex-direction: column; align-items: flex-start; gap: var(--s1); }
  .calendar-day-view-meta { margin-left: 0; }
}
.calendar-day-full .calendar-day-weather { font-size: var(--t-body); }
.calendar-day-full .calendar-day-weather .weather-icon,
.calendar-day-full .calendar-day-weather .weather-icon svg { width: 18px; height: 18px; }
.calendar-day-full .calendar-day-temp { font-size: var(--t-small); }

.calendar-day-group { display: flex; flex-direction: column; }
.calendar-day-group-label {
  margin: 0 0 var(--s1);
  font-size: var(--t-label);
  font-weight: 600;
  letter-spacing: 0.11em;
  text-transform: uppercase;
  color: var(--ink-dim);        /* same quiet-column-label voice as .calendar-dow */
}
/* Rows inside a group: flat list lines with hairline dividers and real
   breathing room. The grid cell's colour classes (amber watering, dim
   chores, green bills) carry through untouched -- that's the continuity. */
.calendar-day-full .calendar-event,
.calendar-day-full .calendar-day-panel-item {
  margin: 0;
  border: 0;
  border-bottom: 1px solid var(--line-soft);
  border-radius: 0;
  padding: var(--s2) 0;
  background: transparent;
  font-size: var(--t-body);
  white-space: normal;
  overflow: visible;
  text-overflow: clip;
}
.calendar-day-group > :last-child { border-bottom: 0; }
.calendar-day-full .calendar-day-panel-item {
  display: flex;
  gap: var(--s2);
  align-items: baseline;
  width: 100%;
  text-align: left;
}
.calendar-day-full button.calendar-day-panel-item { cursor: pointer; }
.calendar-day-full button.calendar-day-panel-item:hover { border-bottom-color: var(--line-firm); }
.calendar-day-full button.calendar-day-panel-item:hover > span:first-child { text-decoration: underline; }
.calendar-day-full .calendar-day-panel-item.editing > span:first-child { text-decoration: underline; text-decoration-color: var(--accent); }
.calendar-day-full .calendar-day-panel-item.is-readonly { cursor: default; }
.calendar-day-full .calendar-day-panel-item .muted { margin-left: auto; color: var(--ink-faint); font-size: var(--t-small); }
.calendar-day-empty { margin: 0; }

.calendar-item-form {
  padding-top: var(--s4);
  border-top: 1px solid var(--line);
  display: flex;
  flex-direction: column;
  gap: var(--s3);
}
.calendar-item-form h3 { margin: 0; font-size: 1.25rem; }
.calendar-item-form input[type="text"],
.calendar-item-form input[type="date"],
.calendar-item-form textarea,
.calendar-item-form select { width: 100%; }
.calendar-form-row { display: flex; gap: var(--s2); }
.calendar-form-row > * { flex: 1 1 0; }
.calendar-form-label { display: flex; flex-direction: column; gap: var(--s1); font-size: var(--t-small); color: var(--ink-dim); }
.calendar-member-list { display: flex; flex-wrap: wrap; gap: var(--s1) var(--s3); }
.calendar-member-choice, .calendar-recur-check { display: inline-flex; align-items: center; gap: var(--s1); font-size: var(--t-small); cursor: pointer; }
.calendar-recur-row { display: flex; align-items: center; gap: var(--s2); padding-left: var(--s4); }
.calendar-recur-row input[type="text"] { flex: 0 0 4rem; }
.calendar-recur-row select { flex: 0 1 9rem; }
.calendar-recur-preview { margin: 0 0 0 var(--s4); font-size: var(--t-small); color: var(--ink-dim); font-style: italic; }
.calendar-form-actions { display: flex; gap: var(--s2); }
.calendar-item-form button.danger { color: var(--alert); border-color: var(--alert); }

/* Shift-pattern editor (Settings -> Preferences, ADR-0043). */
.shift-pattern-editor { display: flex; flex-direction: column; gap: var(--s3); max-width: 32rem; }
.shift-preset-gallery { display: grid; grid-template-columns: repeat(auto-fill, minmax(9.5rem, 1fr)); gap: var(--s2); }
.shift-preset {
  display: flex; flex-direction: column; gap: 2px;
  text-align: left; padding: var(--s2) var(--s3);
  border: 1px solid var(--line-firm); border-radius: var(--radius-sm);
  background: var(--surface); color: var(--ink); cursor: pointer;
}
.shift-preset[aria-pressed="true"] { border-color: var(--accent); box-shadow: inset 0 0 0 1px var(--accent); }
.shift-preset b { font-size: var(--t-body); }
.shift-preset small { color: var(--ink-dim); }
.shift-fine-tune > summary { cursor: pointer; font-size: var(--t-small); color: var(--ink-dim); }
.shift-block-list { display: flex; flex-direction: column; gap: var(--s2); margin-top: var(--s2); }
.shift-block-row { display: flex; align-items: center; gap: var(--s2); flex-wrap: wrap; }
.shift-block-row select { flex: 1 1 6rem; }
.shift-block-reorder { display: inline-flex; }
.shift-block-reorder button { padding: 2px var(--s1); font-size: var(--t-small); }
.shift-block-reorder button:first-child { border-radius: var(--radius-sm) 0 0 var(--radius-sm); }
.shift-block-reorder button:last-child { border-radius: 0 var(--radius-sm) var(--radius-sm) 0; margin-left: -1px; }
.shift-stepper { display: inline-flex; align-items: center; gap: var(--s1); }
.shift-stepper-value { min-width: 3.5rem; text-align: center; font-size: var(--t-small); font-variant-numeric: tabular-nums; }
.shift-block-remove { color: var(--alert); border-color: var(--line-firm); }
.shift-add-block { margin-top: var(--s2); font-size: var(--t-small); }
.shift-cycle-chip {
  align-self: flex-start; margin: 0;
  padding: 2px var(--s2); border-radius: 999px;
  background: var(--accent-soft); color: var(--accent);
  font-size: var(--t-small); font-weight: 600;
}
.shift-audience-people { display: flex; flex-wrap: wrap; gap: var(--s1) var(--s3); padding-left: var(--s4); }
.shift-editor-actions { display: flex; gap: var(--s2); flex-wrap: wrap; }
.shift-editor-actions button.danger { color: var(--alert); border-color: var(--alert); }
.paycheck-section {
  margin-top: var(--s5);
  padding-top: var(--s4);
  border-top: 1px solid var(--line);
}
/* Summary text on its own line; the payer-link select and Remove wrap below
   instead of overlapping the squeezed text (same fix as .instance-row). */
.paycheck-row { flex-wrap: wrap; row-gap: var(--s2); }
.paycheck-row > span:first-child { flex: 1 1 16rem; }
.paycheck-row > select { flex: 1 1 12rem; min-width: 0; }
.paycheck-row > button { flex: 0 0 auto; }
.notification-section {
  display: flex;
  flex-direction: column;
  gap: var(--s2);
  max-width: 32rem;
}
.notification-section .row { border-bottom: none; }
.notification-section .calendar-member-list { padding-left: var(--s4); }
.deals-postal-section {
  margin-top: var(--s5);
  padding-top: var(--s4);
  border-top: 1px solid var(--line);
}
.waste-address-section input[type="text"],
.deals-postal-section input[type="text"] { flex: 1 1 16rem; }

.collection-recollect, .collection-manual {
  margin-top: var(--s3);
  display: flex;
  flex-direction: column;
  gap: var(--s3);
}
.collection-recollect > p, .collection-manual > p {
  margin: 0;
  color: var(--ink-dim);
  font-size: var(--t-small);
}
.collection-rules, .collection-overrides { display: flex; flex-direction: column; gap: var(--s2); }
/* "+ Add rule" / "+ Add holiday move" -- natural width, not a full-bleed
   bar in the manual block's column flex. */
.collection-manual > button { align-self: flex-start; }

.collection-rule-row, .collection-override-row {
  flex-wrap: wrap;
  gap: var(--s2);
  align-items: center;
  border-bottom: none;
  padding: var(--s1) 0;
}
.collection-rule-row input[type="text"] { flex: 0 1 8rem; }
.collection-rule-row input[type="date"],
.collection-override-row input[type="date"] { flex: 0 1 9rem; }

/* "on <weekday>", "seasonal from <date> to <date>" -- a label and its
   control(s) that wrap as one unit instead of splitting mid-phrase. */
.collection-inline {
  display: inline-flex;
  align-items: center;
  gap: var(--s2);
  font-size: var(--t-small);
  color: var(--ink-dim);
}
/* Neutralise `.row span { flex: 1 }` for the little text labels inside
   these groups -- "on", "from", "to" should hug their control. */
.collection-rule-row .collection-inline > span,
.collection-override-row .collection-inline > span,
.collection-holiday .collection-inline > span { flex: 0 0 auto; }
/* When seasonal is on, the window sits on its own indented line under the
   rule rather than fighting for space on the wrapping control row. */
.collection-season { flex: 1 0 100%; flex-wrap: wrap; gap: var(--s2); padding-left: var(--s5); }
.collection-move-arrow { color: var(--ink-faint); }

/* The quiet "Remove" on a rule / override row: small, and commits to
   alert-red only on hover. */
.collection-remove {
  min-height: 0;
  padding: var(--s1) var(--s3);
  font-size: var(--t-small);
  color: var(--ink-dim);
}
.collection-remove:hover:not(:disabled) { color: var(--alert); border-color: var(--alert); }

/* Statutory-holiday shift -- its own line, with the day-count as an
   indented sub-control shown only when the toggle is on. */
.collection-holiday {
  display: flex;
  flex-direction: column;
  gap: var(--s2);
  padding-top: var(--s3);
  border-top: 1px solid var(--line-soft);
}
.collection-holiday-amount { padding-left: var(--s5); }
.collection-holiday-amount input[type="number"] { flex: 0 0 3rem; }

/* Prose lead-in over the holiday-moves list -- the block's own voice, not
   an uppercase kicker. */
.collection-group-lead { color: var(--ink-dim); font-size: var(--t-small); }

.collection-save { display: flex; align-items: center; gap: var(--s3); flex-wrap: wrap; }

/* This week's flyer price for a shopping-list item. */
.row .deal-badge {
  flex: 0 1 auto;
  align-self: center;
  padding: 1px var(--s2);
  border-radius: var(--radius-sm);
  background: var(--info-soft);
  color: var(--info);
  font-size: var(--t-micro);
  font-weight: 600;
  white-space: nowrap;
}
button.deal-badge-toggle {
  border: 1px solid transparent;
  cursor: pointer;
  min-height: 0;
}
button.deal-badge-toggle:hover { border-color: var(--info); }
.deal-badge-history { background: var(--surface-2); color: var(--ink-dim); }

/* The deal picker under an expanded list item -- one tappable block per
   deal, stacked, no cramped flex row. Choosing one collapses this. */
.deal-options {
  display: flex;
  flex-direction: column;
  gap: var(--s1);
  padding: var(--s2) 0 var(--s2) var(--s4);
  border-bottom: 1px solid var(--line-soft);
}
.deal-option {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 2px;
  width: 100%;
  text-align: left;
  padding: var(--s2);
  min-height: 0;
  background: var(--surface);
  border: 1px solid var(--line);
}
.deal-option:hover { border-color: var(--info); }
.deal-option.selected { border-color: var(--accent); background: var(--surface-2); }
.deal-option-sub { font-size: var(--t-micro); color: var(--ink-dim); font-weight: 400; }
.deal-option-clear { color: var(--ink-dim); }

/* A history option that also carries a "Fix" affordance (Receipts access)
   for correcting a mislabelled receipt price -- the option button grows,
   Fix stays a small fixed-width action beside it. */
.deal-option-row { display: flex; align-items: stretch; gap: var(--s2); }
.deal-option-row .deal-option { flex: 1 1 auto; }
.deal-option-fix {
  flex: 0 0 auto;
  align-self: center;
  min-height: 0;
  padding: var(--s1) var(--s3);
  font-size: var(--t-micro);
  color: var(--ink-dim);
}
.deal-option-edit { padding-bottom: 0; border-bottom: none; }

/* A shopping list row: name + price chip on the left as one wrapping
   unit, action(s) on the right. When the row is too narrow the left unit
   takes the full width and the actions drop to their own line, pushed
   right by margin-left:auto rather than orphaned under the name. */
.shopping-item { flex-wrap: wrap; row-gap: var(--s2); }
.shopping-item-main {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--s1) var(--s3);
}
.shopping-item-main > span { flex: 0 1 auto; min-width: 0; }
.shopping-item > button { flex: 0 0 auto; }
.shopping-item > button:first-of-type { margin-left: auto; }

/* The "why it's here" sub-line under a list item (phase suggestion,
   cheapest-seen price) -- tucked against its row, so the row itself reads
   fast. The item's hairline divider moves to the bottom of the meta line
   so the item still reads as one unit. */
.shopping-tab .row.has-meta { border-bottom: none; }
.shopping-tab .item-meta {
  padding-top: 0;
  margin-top: calc(-1 * var(--s1));
}
.shopping-tab .item-meta:hover { background: none; margin: 0; padding: 0 0 var(--s2); }
.shopping-tab .item-meta .status { font-size: var(--t-micro); }
.shopping-subtotal {
  font-weight: 700;
  border-bottom: none;
  border-top: 1px solid var(--line);
  margin-top: var(--s2);
}
.shopping-subtotal span:last-child { flex: 0 0 auto; font-variant-numeric: tabular-nums; }

/* Pantry item names come straight off a Walmart order-detail PDF and can
   run to a full product title -- long enough that squeezing "Move to
   shopping list" and "Remove" onto the same line shrinks the name into a
   single-word-per-line column and pushes the buttons past the edge of a
   phone screen instead. Give the name its own line and drop the actions
   underneath it. */
.pantry-row { flex-wrap: wrap; row-gap: var(--s2); }
.pantry-row > span:first-child { flex: 1 1 100%; min-width: 0; }
.pantry-row > button { flex: 0 0 auto; }
/* The recategorize control -- narrow, sits with the action buttons, drops
   to its own line on a phone like everything else in the wrapping row. */
.pantry-cat-select { flex: 0 1 10rem; }

/* Collapsible category groups (ADR-0041) -- the same disclosure shape the
   shopping list's store groups and By Cycle's nutrient themes use. */
.pantry-cat-group { border-bottom: 1px solid var(--line-soft); }
.pantry-cat-group:first-of-type { border-top: 1px solid var(--line-soft); margin-top: var(--s3); }
.pantry-cat-header { gap: var(--s2); }
.pantry-cat-header .row-toggle {
  padding: var(--s3) var(--s2);
  font-family: var(--font-body);
  font-size: var(--t-body);
  font-weight: 700;
  color: var(--ink);
}
.pantry-cat-header .row-toggle:hover { background: var(--surface-2); }
.pantry-cat-header .row-chevron { color: var(--ink-dim); }
.pantry-cat-name { flex: 1 1 auto; min-width: 0; }
.pantry-cat-count {
  flex: 0 0 auto;
  font-size: var(--t-small);
  font-weight: 600;
  color: var(--ink-faint);
  font-variant-numeric: tabular-nums;
}
/* Quiet destructive text button, same call as .collection-remove. */
.pantry-cat-remove {
  flex: 0 0 auto;
  border: none;
  background: none;
  padding: 0 var(--s2);
  min-height: 0;
  font-size: var(--t-small);
  color: var(--ink-dim);
}
.pantry-cat-remove:hover:not(:disabled) { color: var(--alert); border-color: transparent; }
.pantry-cat-empty { padding: var(--s2); margin: 0; }
.pantry-manage-row { margin-top: var(--s3); }
.pantry-add-category { margin-top: var(--s2); }

/* --- Receipts ----------------------------------------------------------- */
.receipts-tab .add-bill-form select { flex: 0 1 10rem; }

/* --- Cycle ---------------------------------------------------------------
   Member-private data (see PRODUCT.md) -- deliberately excluded from the
   board's decorative treatment rather than an oversight. Plain sans, no
   pinned-note lift, no pushpin: understated on purpose. */
.cycle-tab h2, .cycle-tab h3 {
  font-family: var(--font-body);
  font-weight: 600;
  color: var(--ink-dim);
}
.cycle-tab .dashboard-widget { box-shadow: none; }
.cycle-tab .dashboard-widget::before { display: none; }

/* --- CSV import ----------------------------------------------------------- */
.csv-import select { flex: 0 1 10rem; }
/* "last pulled / next pull" line above the transactions list -- a quiet
   annotation, not body copy, since the page never refreshes on its own. */
.sync-annotation { margin: 0 0 var(--s3); color: var(--ink-dim); font-size: var(--t-small); }

/* --- Chores: a read-only list on top, then the assigner-only rotation
   editor split into labelled blocks. --- */
.chores-tab h3 { margin: var(--s5) 0 var(--s2); font-size: 1.125rem; }
.chores-tab .add-bill-form select { flex: 0 1 12rem; }

/* --- Meal Planning: the week as a read view on top, a card per queued
   recipe below. Both are pinned notes -- the week is the primary one. --- */
.meal-planning { display: flex; flex-direction: column; gap: var(--s5); }
.meal-week-heading { display: flex; align-items: baseline; gap: var(--s3); flex-wrap: wrap; }
.meal-week-done { color: var(--accent); font-weight: 600; font-size: var(--t-small); }
.meal-status { margin: var(--s3) 0 0; }
.meal-day-row { gap: var(--s3); }
.meal-day-label { flex: 0 0 7rem; font-variant-numeric: tabular-nums; color: var(--ink-dim); }
.meal-day-name { flex: 1 1 auto; min-width: 0; }
.meal-day-empty { color: var(--ink-faint); font-style: italic; }
.meal-day-today .meal-day-label { color: var(--accent); font-weight: 600; }

.meal-card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(13rem, 1fr));
  gap: var(--s3);
  margin-top: var(--s3);
}
.meal-card {
  display: flex;
  flex-direction: column;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  overflow: hidden;
  /* --surface-2, not --surface: the panel behind is note-white, so a tile
     on the same white would read flat. --surface-2 is "one level in". */
  background: var(--surface-2);
}
.meal-card-img { width: 100%; height: 7rem; object-fit: cover; display: block; }
.meal-card-body { display: flex; flex-direction: column; gap: var(--s2); padding: var(--s3); }
.meal-card-name { font-weight: 600; }
.meal-card-actions { display: flex; flex-wrap: wrap; gap: var(--s2); align-items: center; }
.meal-card-actions select { flex: 1 1 8rem; min-width: 0; }

/* A .meal-card that is itself the tappable control -- tapping a day's
   "Plan"/"Change" button opens a grid of these instead of a per-card
   day-select, so picking a day is one action, not seven parallel forms. */
button.meal-pick-card { padding: 0; min-height: 0; width: 100%; text-align: left; }
button.meal-pick-card:hover:not(:disabled) { border-color: var(--accent); }
.meal-day-picker {
  padding: var(--s2) 0 var(--s3) var(--s4);
  border-bottom: 1px solid var(--line-soft);
}
.meal-day-picker-empty { margin-bottom: var(--s2); }
.meal-day-clear {
  margin-top: var(--s3);
  min-height: 0;
  padding: var(--s1) var(--s3);
  background: none;
  border-color: transparent;
  color: var(--ink-dim);
}
.meal-day-clear:hover:not(:disabled) { border-color: var(--line); }

.meal-queue-empty { display: flex; flex-direction: column; gap: var(--s2); align-items: flex-start; }
.meal-queue-more { margin-top: var(--s3); }

/* A plain flex row of buttons -- use instead of .add-bill-form, which
   carries a bottom hairline meant for a real form. */
.button-row { display: flex; flex-wrap: wrap; gap: var(--s2); align-items: center; margin-top: var(--s3); }

.meal-go-shopping { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--s2) var(--s3); padding-top: var(--s2); }

/* The whole "Dinner tonight" card is the tap target when nothing's planned
   (it navigates to Meal Planning); when a meal is set, only its row toggles. */
.dinner-card[role="button"] { cursor: pointer; }
.dinner-card[role="button"]:hover { border-color: var(--line-firm); }
.vendor-table { margin-top: var(--s4); }

/* Account / month pickers -- each a labelled column, wrapping side by side
   or stacking on a narrow phone instead of colliding with their labels. */
.txn-filters { flex-wrap: wrap; align-items: flex-end; gap: var(--s3); }
.txn-filter {
  flex: 1 1 9rem;
  max-width: 16rem;
  display: flex;
  flex-direction: column;
  gap: var(--s1);
  font-size: var(--t-micro);
  text-transform: uppercase;
  letter-spacing: 0.09em;
  color: var(--ink-faint);
}
.txn-filter select { flex: 0 0 auto; width: 100%; }

.category-group { border-bottom: 1px solid var(--line-soft); }
.category-group-header {
  cursor: pointer;
  font-weight: 600;
  border-bottom: none;
  user-select: none;
  flex-wrap: wrap;
}
.category-group-header:hover { background: var(--surface-2); }
.category-group-header span:first-child { flex: 1 1 8rem; min-width: 0; }
.category-group-header span:nth-child(2) { flex: 0 0 auto; text-align: right; font-variant-numeric: tabular-nums; }
.category-group-header .vendor-count { flex: 0 0 auto; text-align: right; font-weight: 400; color: var(--ink-faint); }
/* A category that gained a transaction on the latest bank pull -- reuses
   the same "needs a look" tint a proposed CSV row already carries, so the
   two never invent a second visual vocabulary for the same idea. Needs
   its own :hover to win over both .category-group-header's and
   .proposed-row's single-class ones. */
.category-group-header.proposed-row:hover { background: var(--warn-soft); filter: brightness(0.97); }
.category-new-amount { flex: 0 0 auto; text-align: right; font-weight: 600; color: var(--warn); }

/* A category expands to its vendors; each vendor expands to its individual
   transactions (ADR-0042). Vendor sub-header is a disclosure row one
   indent in from the category header. */
.vendor-subgroup { border-top: 1px solid var(--line-soft); }
.category-group > .vendor-subgroup:first-of-type { border-top: none; }
.vendor-subheader { padding-left: var(--s4); cursor: pointer; user-select: none; }
.vendor-subheader:hover { background: var(--surface-2); }
.vendor-subheader .vendor-subheader-name {
  flex: 1 1 8rem;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-weight: 600;
}
.vendor-subheader .vendor-subheader-amt { flex: 0 0 auto; font-variant-numeric: tabular-nums; }
.vendor-subheader .vendor-count { flex: 0 0 auto; }

/* One transaction: full description on its own line (recognising the
   charge is the whole point), then date / amount / category menu. Reused
   by the "new on latest pull" block and the per-vendor transaction lists.
   The two-class selector outranks the base `.row span { flex: 1 }`. */
.txn-row { flex-wrap: wrap; align-items: baseline; column-gap: var(--s3); row-gap: var(--s1); padding-left: var(--s5); }
.vendor-subgroup .txn-row:last-child { border-bottom: none; }
.txn-row .txn-row-desc { flex: 1 1 100%; min-width: 0; }
.txn-row .txn-row-date { flex: 0 0 auto; font-size: var(--t-small); color: var(--ink-dim); }
.txn-row .txn-row-amt { flex: 0 0 auto; font-variant-numeric: tabular-nums; font-weight: 600; }
.txn-row select { flex: 0 1 12rem; margin-left: auto; }

/* The transactions a category gained on the newest bank pull, lifted above
   the vendor list for a quick check. Same "needs a look" amber the
   category header's .proposed-row tint uses. */
.txn-new-batch {
  margin: var(--s2) 0 var(--s3);
  padding: var(--s1) var(--s3) var(--s2);
  background: var(--warn-soft);
  border-radius: var(--radius-sm);
}
.txn-new-batch-title { margin: var(--s2) 0 0; font-size: var(--t-small); font-weight: 600; color: var(--warn); }
.txn-new-batch .txn-row { padding-left: 0; border-bottom: 1px solid var(--line-soft); }
.txn-new-batch .txn-row:last-child { border-bottom: none; }

/* "This named row is really one of these unnamed ones -- which?" Shown
   above the category groups; amber, like everything else that means
   "needs your input" here. */
.txn-merge-prompt {
  margin: 0 0 var(--s3);
  padding: var(--s2) var(--s3) var(--s3);
  background: var(--warn-soft);
  border-radius: var(--radius-sm);
}
.txn-merge-prompt-title { margin: var(--s1) 0 var(--s2); font-size: var(--t-small); font-weight: 600; color: var(--warn); }
.txn-merge-candidate { column-gap: var(--s3); }
.txn-merge-candidate > span:first-child { flex: 1 1 8rem; min-width: 0; }
.txn-merge-candidate > button { flex: 0 0 auto; }

.totals-table { margin-top: var(--s5); }
.totals-table h2 {
  margin: 0 0 var(--s2);
  font-family: var(--font-body);
  font-size: var(--t-micro);
  text-transform: uppercase;
  letter-spacing: 0.11em;
  font-weight: 600;
  color: var(--ink-faint);
}
.totals-table .row span:last-child { flex: 0 1 6rem; text-align: right; }
.totals-grand { font-weight: 700; border-bottom: none; color: var(--ink); }

/* --- Sign-in --------------------------------------------------------------- */
.signin {
  text-align: center;
  margin-top: 20vh;
}
.signin h1 { font-size: 3rem; margin-bottom: var(--s4); }
.signin button {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--on-accent);
  font-weight: 600;
  padding: var(--s3) var(--s5);
}
.signin button:hover { filter: brightness(1.06); }

/* Request-access form: real content, so left-aligned and width-bounded
   rather than the centred one-button sign-in look. */
.signin.request-access {
  text-align: left;
  margin: 10vh auto 0;
  max-width: 420px;
}
.signin.request-access label,
.household-settings label {
  display: block;
  margin: var(--s3) 0 var(--s1);
  font-weight: 600;
  font-size: var(--t-small);
}
.signin.request-access input,
.signin.request-access textarea,
.household-settings input {
  width: 100%;
}
.signin.request-access button { margin-top: var(--s4); }

/* Manual link on the signed-out screens: its own line, not pushed to a flex
   edge like .link-button's default use inside a row. */
.signin .manual-link {
  display: inline-block;
  margin: var(--s4) 0 0;
}
.signin:not(.request-access) .manual-link { margin-top: var(--s5); }

/* Signed-out landing: the one-tap button stays above the fold for a
   returning member; the tagline, a static Budget taste, the two ways in,
   and the isolation promise sit below it for a first-time visitor. All
   built from existing parts (nameplate, .dashboard-widget note, .row,
   .advice-bar meter) so it needs no new asset and tracks every theme. */
.signin.signin-landing {
  margin: 8vh auto 0;
  /* Wide enough for the two-column feature grid below; the hero blocks
     keep their own tighter max-widths and stay centred within it. */
  max-width: 680px;
  padding-bottom: var(--s6);
}
.signin-tagline {
  font-family: var(--font-display);
  font-size: 1.5rem;
  line-height: 1.15;
  font-weight: 700;
  /* --ink-dim, not --cork: the dark theme repurposes --cork as a near-black
     header-band fill that vanishes as text on paper. */
  color: var(--ink-dim);
  margin: var(--s4) auto var(--s2);
}
.signin-sub {
  color: var(--ink-dim);
  font-size: var(--t-lead);
  max-width: 34ch;
  margin: 0 auto;
}
.signin-landing .signin-cta {
  margin-top: var(--s5);
  font-size: var(--t-lead);
}
.signin-doors {
  margin-top: var(--s4);
  display: grid;
  gap: var(--s2);
  max-width: 40ch;
  margin-inline: auto;
}
.signin-doors p {
  margin: 0;
  font-size: var(--t-small);
  color: var(--ink-faint);
  line-height: 1.4;
}
.signin-preview {
  text-align: left;
  margin: var(--s5) auto 0;
  max-width: 420px;
}
.signin-preview h2 { margin: 0; font-size: 1.25rem; }
.signin-preview-lead {
  margin: var(--s1) 0 var(--s3);
  font-size: var(--t-small);
  color: var(--ink-faint);
}
.signin-preview-row { gap: var(--s3); }
.signin-preview-row:hover { background: none; margin: 0; padding: var(--s2) 0; }
.signin-preview-name { flex: 1 1 auto; font-size: var(--t-body); }
.signin-preview .advice-bar { flex: 0 0 4.5rem; margin: 0; }
.signin-preview-amt {
  flex: 0 0 auto;
  font-size: var(--t-small);
  color: var(--ink-dim);
  font-variant-numeric: tabular-nums;
}
/* The isolation promise sits directly under the two doors, not at the
   foot of the scroll: for a first-time admin handing over financial data
   it is the objection to answer first. A touch more weight than the
   feature blurbs below it. */
.signin-privacy {
  margin: var(--s5) auto 0;
  max-width: 44ch;
  font-size: var(--t-body);
  color: var(--ink-dim);
  line-height: 1.5;
}

.signin-features-heading {
  font-family: var(--font-display);
  font-size: 1.375rem;
  font-weight: 700;
  color: var(--ink-dim);
  margin: var(--s6) 0 var(--s4);
}
.signin-features {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
  gap: var(--s3);
  text-align: left;
}
.signin-feature { padding: var(--s4); }
.signin-feature-icon {
  display: block;
  font-size: 1.5rem;
  line-height: 1;
  margin-bottom: var(--s2);
}
.signin-feature h3 { margin: 0 0 var(--s1); }
.signin-feature p {
  margin: 0;
  font-size: var(--t-small);
  color: var(--ink-faint);
  line-height: 1.45;
}

/* Operator console (spec #46) -- an Operate-mode surface, same corkboard
   framing as the household app, scanability first. */
.operator-console { max-width: 720px; margin: 0 auto; padding: 0 var(--s4) var(--s6); }
.operator-console > header {
  position: sticky; top: 0; z-index: 10;
  margin: 0 calc(-1 * var(--s4));
  padding: var(--s3) var(--s4);
  background: var(--cork);
  border-bottom: 1px solid var(--cork-deep);
}
.operator-console > header h1 { color: var(--on-cork); font-size: 1.5rem; margin: 0; }
.operator-console > header button {
  color: var(--on-cork);
  border-color: rgba(255, 253, 249, 0.32);
  background: rgba(0, 0, 0, 0.14);
}
.operator-console > header button:first-of-type { margin-left: auto; }
.operator-row {
  cursor: pointer;
  display: grid;
  grid-template-columns: minmax(7rem, 1.3fr) minmax(0, 1.6fr) auto minmax(7rem, auto);
  gap: var(--s1) var(--s3);
  align-items: baseline;
}
.operator-row:hover { background: var(--surface-2); }
.operator-row:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.operator-row-name { font-weight: 600; }
/* Pending queue marker -- a full-row accent-soft wash, the same shape as the
   .proposed row tint (DESIGN Colors), keyed off h.status. Not a side stripe. */
.operator-row--pending,
.operator-row--pending:hover { background: var(--accent-soft); }
.operator-row-state { display: flex; flex-direction: column; gap: 2px; }
.operator-row-status { font-size: var(--t-small); color: var(--ink-dim); text-transform: capitalize; }
.operator-row-status.is-pending { color: var(--accent); font-weight: 600; }
/* Below this width the 2-column grid can't hold the admin email and the
   date line without them shrinking past their text (.row span min-width:0)
   and overprinting the next cell -- so stack every field on its own line. */
@media (max-width: 560px) {
  .operator-row { grid-template-columns: 1fr; row-gap: 2px; }
}
.operator-detail .operator-actions { display: flex; flex-wrap: wrap; gap: var(--s2); margin-top: var(--s4); }
.operator-delete { flex-basis: 100%; margin-top: var(--s3); }
.operator-delete label { display: block; font-size: var(--t-small); font-weight: 600; margin-bottom: var(--s1); }

/* The Kitchen Name panel (spec #57) -- a section within the household detail
   note, not its own pinned note (Pinned-Note Rule). */
.operator-kitchen-panel { margin-top: var(--s4); padding-top: var(--s3); border-top: 1px solid var(--line-soft); }
.operator-kitchen-panel h4 { margin: 0 0 var(--s2); font-family: var(--font-body); font-size: var(--t-small); font-weight: 600; color: var(--ink-dim); }
.operator-kitchen-checklist { margin: var(--s1) 0 var(--s2); padding-left: var(--s4); font-size: var(--t-small); color: var(--ink-dim); }
.link-button.active { color: var(--accent); font-weight: 600; }

.get-started .get-started-item { align-items: center; }
.household-settings { margin-bottom: var(--s5); }
.setup-wizard .wizard-actions { flex-wrap: wrap; gap: var(--s2); }

/* Channel (spec #47): support threads + "what's new". Card-level panels are
   pinned notes; the rows inside stay flat (Pinned-Note Rule). */
/* Sits directly under the status-filter .sub-nav as a second nav row -- pull
   it up so the two read as one navigation block. */
.operator-console-links { margin-top: calc(-1 * var(--s2)); }
.whats-new-badge {
  background: var(--accent); color: var(--on-accent);
  border-radius: 999px; padding: 0 var(--s2); font-size: var(--t-small); font-weight: 700;
}
.whats-new-note { border-top: 1px solid var(--line-soft); padding-top: var(--s2); margin-top: var(--s2); }
.whats-new-note p:first-child { font-weight: 600; }
/* The operator composes the body in a textarea; keep its line breaks (same as
   .ticket-message) so a multi-line release note reads as written. */
.whats-new-note p:last-child { white-space: pre-wrap; }
.whats-new-header { cursor: pointer; user-select: none; }
.whats-new-header:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.whats-new .link-button { margin-top: var(--s2); }

.support-section .row { cursor: pointer; }
.support-section .row:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.ticket-thread { display: flex; flex-direction: column; gap: var(--s2); }
.ticket-message { border-radius: var(--radius-sm); padding: var(--s2) var(--s3); background: var(--surface-2); }
.ticket-message-operator { background: var(--accent-soft); }
.ticket-message p:last-child { white-space: pre-wrap; }
.ticket-reply { display: flex; flex-direction: column; gap: var(--s2); margin-top: var(--s3); }
.ticket-reply textarea { width: 100%; }

/* Dietary restrictions (member Settings + Admin per-member) ------------- */
.dietary-editor { display: flex; flex-direction: column; gap: var(--s2); margin-bottom: var(--s3); }
.diet-allergen-chips { display: flex; flex-wrap: wrap; gap: var(--s2); }
.diet-allergen-chip {
  display: inline-flex; align-items: center; gap: var(--s1);
  padding: 2px var(--s2); border-radius: 999px;
  background: var(--warn-soft); color: var(--warn);
  font-size: var(--t-small); text-transform: capitalize;
}
.diet-allergen-chip button {
  background: none; border: none; padding: 0; margin: 0;
  color: inherit; font: inherit; line-height: 1; cursor: pointer;
}
/* "contains nuts" flag on a pantry row / saved recipe / preview */
.diet-badge {
  flex: 0 0 auto;
  font-size: var(--t-micro); font-weight: 600;
  padding: 0 var(--s2); border-radius: 999px;
  background: var(--warn-soft); color: var(--warn);
  text-transform: capitalize;
}
.diet-badge-block { display: block; align-self: flex-start; margin: var(--s1) 0; }

.children-section { margin-top: var(--s5); }
.children-section .household-member-row { margin-bottom: var(--s3); }

/* --- Daycare parent portal (ADR-0038, #146) --------------------------- */
.daycare-enrollment { margin-top: var(--s5); }
.daycare-enrollment-head { align-items: baseline; gap: var(--s3); }
.daycare-enrollment-head h3 { margin: 0 0 var(--s2); }
.daycare-accepted { flex: 0 0 auto; font-size: var(--t-small); font-weight: 600; color: var(--accent); }
.daycare-share-preview { margin: var(--s2) 0; }
.daycare-field-row { align-items: baseline; gap: var(--s3); padding: var(--s1) 0; }
.daycare-field-label { flex: 0 0 9rem; color: var(--ink-dim); font-size: var(--t-small); }
.daycare-updates { margin-top: var(--s4); }
.daycare-updates h4 { margin: 0 0 var(--s2); }
.daycare-update { margin-top: var(--s3); }
.daycare-update h4 { margin: var(--s1) 0; }
.daycare-update p:last-child { white-space: pre-wrap; }

/* Caregiver (babysitter) view (ADR-0036) */
.caregiver-badge {
  flex: 0 0 auto; font-size: var(--t-small); font-weight: 600;
  padding: 2px var(--s2); border-radius: 999px;
  background: var(--accent-soft); color: var(--accent);
}
.caregiver-child-card p { margin: var(--s1) 0; }
.caregiver-notes { white-space: pre-wrap; }

/* Caregiver availability marks, on both the sitter's grid and the family's */
.calendar-event.cg-avail-available {
  background: var(--accent-soft);
  color: var(--accent);
  font-weight: 600;
}
.calendar-event.cg-avail-unavailable {
  background: var(--warn-soft);
  color: var(--warn);
  font-weight: 600;
}

.link-button {
  background: none;
  border: none;
  color: var(--accent);
  padding: 0;
  font: inherit;
  text-decoration: underline;
  cursor: pointer;
  margin-left: auto;
}

/* --- Nutrition (ADR-0049): recipe estimate panel + Product scan card ------ */
.nutrition-panel, .nutrition-card {
  margin-top: var(--s3);
  padding: var(--s3);
  background: var(--surface-2);
  border: 1px solid var(--line-soft);
  border-radius: var(--radius-sm);
}
.nutrition-panel-head, .nutrition-card-basis {
  display: flex; align-items: center; gap: var(--s2); flex-wrap: wrap;
}
.nutrition-panel-macros { font-weight: 600; }
.nutrition-grade {
  display: inline-flex; align-items: center; gap: var(--s2);
  font-weight: 700;
}
.nutrition-grade { padding: 2px var(--s2); border-radius: var(--radius-sm); color: #fff; }
.nutrition-grade.grade-a { background: #1a7f37; }
.nutrition-grade.grade-b { background: #4c9a2a; }
.nutrition-grade.grade-c { background: #b8860b; }
.nutrition-grade.grade-d { background: #c05621; }
.nutrition-grade.grade-e { background: #b42318; }
.nutrition-grade.grade-unknown { background: var(--line); color: var(--ink); }
.nutrition-grade-label { font-weight: 600; font-size: 0.9em; }

.nutrition-condition-badges, .nutrition-dietary-flags { display: flex; flex-wrap: wrap; gap: var(--s1); margin-top: var(--s2); }
.nutrition-condition-badge, .nutrition-dietary-flag {
  background: var(--warn-soft); color: var(--warn);
  padding: 2px var(--s2); border-radius: var(--radius-sm); font-size: 0.85em; font-weight: 600;
}

.nutrition-card-head { display: flex; gap: var(--s3); align-items: flex-start; }
.nutrition-card-img { width: 64px; height: 64px; object-fit: contain; border-radius: var(--radius-sm); background: #fff; }
.nutrition-card h4 { margin: 0; }
.nutrition-card h5 { margin: var(--s3) 0 var(--s1); }
.nutrition-verdict { display: flex; align-items: center; gap: var(--s2); padding: 2px 0; }
.nutrition-verdict-dot { width: 10px; height: 10px; border-radius: 50%; flex: none; }
.nutrition-verdict.rating-good .nutrition-verdict-dot { background: #1a7f37; }
.nutrition-verdict.rating-moderate .nutrition-verdict-dot { background: #b8860b; }
.nutrition-verdict.rating-bad .nutrition-verdict-dot { background: #b42318; }
.nutrition-verdict-value { margin-left: auto; font-variant-numeric: tabular-nums; color: var(--ink-faint); }
.nutrition-scan .receipt-scan-btn { display: inline-block; margin: var(--s2) 0; }
