/* Hallkeeper base stylesheet and design system. SHARED CORE.
   Hand-written, no build step, no third-party requests. Aim: WCAG 2.2 AA (text >= 4.5:1, control
   borders, icons and the focus ring >= 3:1, visible focus, no color-only status) in light AND dark
   mode (tests/ux/test_design_v2.py checks the token pairs). Feature styles go in
   static/css/<area>.css, loaded via {% block head %}, and use these tokens.

   Design language v2 (ARCHITECTURE section 42; docs/design/DIRECTION-v2.md sections 2 and 4). It keeps
   every token name from v1 (sections 35 and 36) and changes the values, so pages restyle without
   template changes. One layer: the "calm" scale IS the base scale now.
   - Type: Inter (variable, self-hosted, OFL; static/fonts). --text-2xs 11 .. --text-4xl 44 px; admin
     and calm pages read at --text-md (14 px), other pages at --text-base (16 px). Numbers that line
     up (money, KPIs, tables) use tabular figures.
   - Color: never a raw hex outside :root. Surfaces --canvas < --paper < --surface-2 < --surface-3;
     text --ink / --ink-muted / --ink-subtle (the minimum for meta); lines --line (decorative) /
     --line-2 (secondary button edge) / --line-strong (input borders, 3:1+). --primary (+ --on-primary,
     --primary-hover, --primary-soft). Status pairs --{success,warning,danger,info,neutral}-{ink,bg};
     --error-* = --danger-* (v1 name). Red is reserved for destructive actions and true urgency.
     Charts: --chart-1 / --chart-2 and the --heat-0..5 ramp only (never status colors).
   - Dark mode: the same names re-picked, by the system setting, or forced with
     html[data-theme="light" | "dark"] (Account menu > Appearance; web/theme.py sets it before paint).
   - --accent / --on-accent: the main call to action. Admin: --primary. Public pages: the
     center's brand color (and the ink brand.py picked for it, so it always reads).
   - Elevation: cards are flat (1 px --line, no shadow). --shadow-1 hover raise, --shadow-2 menus and
     popovers, --shadow-3 dialogs, sheets and toasts. Radius --radius-xs 4 .. --radius-xl 20.
   - Motion: --dur-1..4 with --ease-out (entering) / --ease-in (leaving); all off under reduced motion.
   - Components: .btn (secondary) / .btn-primary (one per region) / .btn-quiet = .btn-ghost /
     .btn-danger / .btn-icon; inputs, select chevron, custom checks (admin); .badge (+ a shape:
     filled dot done, ring waiting, half in progress, diamond full, x stopped); .tag; .count-pill;
     .chip (filter); .card / .panel; tables; .empty-state (+ templates/_art.html); .skeleton;
     toasts (#toasts, success and notes only); details.menu; dialog.dialog (a bottom sheet on phones);
     .page-head (ui.page_head); .tabs; .breadcrumbs.
   - Links: no underline when they stand alone (titles, nav, "View all"); a quiet underline inside
     running text (.prose, plain paragraphs, hints, notices), because blue on near-black is under 3:1
     and color alone would fail WCAG 1.4.1. */

/* Inter variable (rsms/inter via @fontsource-variable/inter 5.1.0, SIL OFL 1.1: static/fonts/Inter-LICENSE.txt).
   Latin is preloaded by base.html; Latin Extended loads only when a page uses one of its characters. */
@font-face {
  font-family: "Inter"; font-style: normal; font-display: swap; font-weight: 100 900;
  src: url("/static/fonts/InterVariable.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329,
    U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Inter"; font-style: normal; font-display: swap; font-weight: 100 900;
  src: url("/static/fonts/InterVariable-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329,
    U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

:root {
  color-scheme: light dark;
  --brand: #2457c5;            /* overridden per org on public pages */
  --brand-ink: #fff;           /* text on --brand; dark when white fails 4.5:1 (hallkeeper/brand.py) */

  /* Light. Contrast noted against --paper (#fff); tests/ux/test_design_v2.py asserts the pairs. */
  --canvas: #f8f7f5;           /* page */
  --paper: #ffffff;            /* cards, inputs */
  --surface-2: #fafaf9;        /* row hover, quiet fills */
  --surface-3: #f2f1ee;        /* tags, table head band, skeleton base */
  --line: #ebe9e5;             /* card edges, dividers (decorative) */
  --line-2: #dedbd6;           /* secondary-button edge (the text names the control) */
  --line-strong: #8a837b;      /* input and control borders: 3.7:1 (WCAG 1.4.11) */
  --ink: #191817;              /* 17.7:1 */
  --ink-muted: #5f5a54;        /* 6.8:1; 6.0:1 on --surface-3 */
  --ink-subtle: #76706a;       /* 4.9:1: the minimum for meta text */
  --primary: #2457c5;          /* 6.5:1; white on it 6.5:1 */
  --primary-hover: #1d4fb8;
  --primary-soft: #eef3fd;     /* selected rows, current items; primary text on it 5.8:1 */
  --on-primary: #ffffff;
  --primary-fill: #2457c5;     /* a primary button's fill: white on it 6.5:1 (dark mode: a deeper blue, 5.2:1) */
  --primary-fill-hover: #1d4fb8;
  --on-primary-fill: #ffffff;
  --logo-chip: #ffffff;        /* behind an uploaded logo: none in light mode (paper), a light chip in dark mode */
  --success-ink: #1f7a4d; --success-bg: #eaf6ef;
  --warning-ink: #a3540b; --warning-bg: #fff6e8;
  --danger-ink: #b42318;  --danger-bg: #fdeceb;
  --neutral-ink: #4a4540; --neutral-bg: #f2f1ee;
  --warning-soft: #fffaf0;     /* adjusted price lines */
  --chart-1: #3a6fd8;          /* this period */
  --chart-2: #b07a1f;          /* comparison period */
  --heat-1: #cfdcf8; --heat-2: #b7cdf6; --heat-3: #86aaee; --heat-4: #4f80e0; --heat-5: #2457c5;
  /* Text on each heat step (insights prints the % in the cell): >= 4.5:1 in both themes (tested). */
  --heat-0-ink: #191817; --heat-1-ink: #191817; --heat-2-ink: #191817; --heat-3-ink: #191817; --heat-4-ink: #191817; --heat-5-ink: #ffffff;
  --shadow-1: 0 1px 2px rgb(20 18 16 / .05);
  --shadow-2: 0 4px 12px rgb(20 18 16 / .08), 0 1px 3px rgb(20 18 16 / .06);
  --shadow-3: 0 16px 40px rgb(20 18 16 / .14), 0 2px 8px rgb(20 18 16 / .06);
  --backdrop: rgb(20 18 16 / .32);
  /* Form-control glyphs (a select chevron, the tick in a checked box): images can't read a token. */
  --chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%235f5a54' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m7 10 5 5 5-5'/%3E%3C/svg%3E");
  --tick: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23ffffff' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m5 12.5 4.5 4.5L19 7.5'/%3E%3C/svg%3E");

  /* Derived (same in both themes) */
  --info-ink: var(--primary);  --info-bg: var(--primary-soft);
  --error-ink: var(--danger-ink); --error-bg: var(--danger-bg);   /* v1 names */
  --primary-dark: var(--primary-hover);                           /* v1 name */
  --heat-0: var(--surface-3);
  --accent: var(--primary);
  --on-accent: var(--on-primary);
  --accent-hover: var(--primary-hover);
  /* What a primary button fills with: the admin's primary fill; public pages map it to the brand (public.css). */
  --accent-fill: var(--primary-fill);
  --on-accent-fill: var(--on-primary-fill);
  --accent-fill-hover: var(--primary-fill-hover);
  --focus-ring: var(--primary);
  --focus: var(--focus-ring);  /* v1 name (the retired yellow halo) */
  --focus-halo: 0 0 0 4px color-mix(in srgb, var(--focus-ring) 22%, transparent);
  --chrome: var(--paper);      /* public header */
  --chrome-ink: var(--ink);
  --chrome-muted: var(--ink-muted);
  --side-bg: var(--canvas);    /* admin sidebar and phone top bar: the page itself, divided by a line */
  --side-ink: var(--ink);
  --side-muted: var(--ink-muted);
  --side-hover: var(--surface-3);
  --side-current: var(--paper);
  --nav-hover: var(--surface-3);
  --nav-current: var(--surface-3);
  --shadow-sm: var(--shadow-1); /* v1 names */
  --shadow: var(--shadow-1);
  --shadow-lg: var(--shadow-3);

  --radius-xs: 4px;
  --radius-sm: 6px;
  --radius: 10px;
  --radius-lg: 14px;
  --radius-xl: 20px;
  --radius-pill: 999px;
  --font: "Inter", ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --font-display: var(--font);
  --mono: ui-monospace, "Cascadia Mono", "SF Mono", Consolas, monospace;
  --text-2xs: .6875rem;        /* 11 / 16 */
  --text-xs: .75rem;           /* 12 / 16 */
  --text-sm: .8125rem;         /* 13 / 20 */
  --text-md: .875rem;          /* 14 / 20: admin body */
  --text-base: 1rem;           /* 16 / 24: public body, inputs on touch */
  --text-lg: 1.125rem;         /* 18 / 26 */
  --text-xl: 1.25rem;          /* 20 / 28 */
  --text-2xl: 1.5rem;          /* 24 / 30 */
  --text-3xl: 1.875rem;        /* 30 / 36 */
  --text-4xl: 2.75rem;         /* 44 / 48 */
  --sp-1: .25rem; --sp-2: .5rem; --sp-3: .75rem; --sp-4: 1rem; --sp-5: 1.5rem; --sp-6: 2rem;
  --sp-7: 3rem; --sp-8: 4rem; --sp-9: 6rem;
  --control-h: 2rem;           /* 32 px with a mouse; 44 px on touch screens and phones (below) */
  --label-w: 12.5rem;          /* side labels in .form-rows */
  --row-gap: 1.25rem;
  --dur-1: 120ms;              /* hover, press, colour */
  --dur-2: 180ms;              /* menus, popovers, toasts in */
  --dur-3: 260ms;              /* dialogs, sheets */
  --dur-4: 700ms;              /* the celebration tick (public confirmation) */
  --ease-out: cubic-bezier(.2, .8, .2, 1);
  --ease-in: cubic-bezier(.4, 0, 1, 1);
  --dur: var(--dur-1);         /* v1 names */
  --ease: var(--ease-out);
}
@media (pointer: coarse), (max-width: 40rem) {
  :root { --control-h: 2.75rem; }   /* WCAG 2.5.5 */
}

/* Dark. Twice, identically: by the system setting (unless the viewer forced light), and forced.
   tests/ux/test_design_v2.py checks both blocks match and pass the contrast table. */
@media screen and (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --canvas: #121110;
    --paper: #1b1a18;
    --surface-2: #201f1d;
    --surface-3: #282624;
    --line: #2e2c29;
    --line-2: #3d3a36;
    --line-strong: #8a847c;
    --ink: #ecebe8;
    --ink-muted: #a8a29a;
    --ink-subtle: #8f8981;
    --primary: #7aa5ff;
    --primary-hover: #9dbcff;
    --primary-soft: #1a2540;
    --on-primary: #11161f;
    --primary-fill: #3366d6;
    --primary-fill-hover: #3b6fd9;
    --on-primary-fill: #ffffff;
    --logo-chip: #f2f1ee;
    --success-ink: #6fcf97; --success-bg: #14271c;
    --warning-ink: #f2b866; --warning-bg: #2c2110;
    --danger-ink: #ff9b8f;  --danger-bg: #331816;
    --neutral-ink: #cfc9c1; --neutral-bg: #282624;
    --warning-soft: #2b2312;
    --chart-1: #5b8ef0;
    --chart-2: #b5832c;
    --heat-1: #22345a; --heat-2: #23407a; --heat-3: #2e5bb0; --heat-4: #4a7fe0; --heat-5: #8fb2ff;
    --heat-0-ink: #ecebe8; --heat-1-ink: #ecebe8; --heat-2-ink: #ecebe8; --heat-3-ink: #ecebe8; --heat-4-ink: #11161f; --heat-5-ink: #11161f;
    --shadow-1: 0 1px 2px rgb(0 0 0 / .5), 0 0 0 1px rgb(255 255 255 / .04);
    --shadow-2: 0 4px 12px rgb(0 0 0 / .5), 0 1px 3px rgb(0 0 0 / .5), 0 0 0 1px rgb(255 255 255 / .06);
    --shadow-3: 0 16px 40px rgb(0 0 0 / .6), 0 2px 8px rgb(0 0 0 / .5), 0 0 0 1px rgb(255 255 255 / .06);
    --backdrop: rgb(0 0 0 / .55);
    --chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23a8a29a' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m7 10 5 5 5-5'/%3E%3C/svg%3E");
    --tick: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2311161f' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m5 12.5 4.5 4.5L19 7.5'/%3E%3C/svg%3E");
  }
}
@media screen {
  :root[data-theme="dark"] {
    --canvas: #121110;
    --paper: #1b1a18;
    --surface-2: #201f1d;
    --surface-3: #282624;
    --line: #2e2c29;
    --line-2: #3d3a36;
    --line-strong: #8a847c;
    --ink: #ecebe8;
    --ink-muted: #a8a29a;
    --ink-subtle: #8f8981;
    --primary: #7aa5ff;
    --primary-hover: #9dbcff;
    --primary-soft: #1a2540;
    --on-primary: #11161f;
    --primary-fill: #3366d6;
    --primary-fill-hover: #3b6fd9;
    --on-primary-fill: #ffffff;
    --logo-chip: #f2f1ee;
    --success-ink: #6fcf97; --success-bg: #14271c;
    --warning-ink: #f2b866; --warning-bg: #2c2110;
    --danger-ink: #ff9b8f;  --danger-bg: #331816;
    --neutral-ink: #cfc9c1; --neutral-bg: #282624;
    --warning-soft: #2b2312;
    --chart-1: #5b8ef0;
    --chart-2: #b5832c;
    --heat-1: #22345a; --heat-2: #23407a; --heat-3: #2e5bb0; --heat-4: #4a7fe0; --heat-5: #8fb2ff;
    --heat-0-ink: #ecebe8; --heat-1-ink: #ecebe8; --heat-2-ink: #ecebe8; --heat-3-ink: #ecebe8; --heat-4-ink: #11161f; --heat-5-ink: #11161f;
    --shadow-1: 0 1px 2px rgb(0 0 0 / .5), 0 0 0 1px rgb(255 255 255 / .04);
    --shadow-2: 0 4px 12px rgb(0 0 0 / .5), 0 1px 3px rgb(0 0 0 / .5), 0 0 0 1px rgb(255 255 255 / .06);
    --shadow-3: 0 16px 40px rgb(0 0 0 / .6), 0 2px 8px rgb(0 0 0 / .5), 0 0 0 1px rgb(255 255 255 / .06);
    --backdrop: rgb(0 0 0 / .55);
    --chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23a8a29a' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m7 10 5 5 5-5'/%3E%3C/svg%3E");
    --tick: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2311161f' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m5 12.5 4.5 4.5L19 7.5'/%3E%3C/svg%3E");
  }
}
:root[data-theme="light"] { color-scheme: light; }
@media screen { :root[data-theme="dark"] { color-scheme: dark; } }  /* print stays light, forced theme or not */

*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; scroll-padding-top: 1rem; }
body {
  margin: 0; font-family: var(--font); font-size: var(--text-base); line-height: 1.5;
  color: var(--ink); background: var(--canvas);
  display: flex; flex-direction: column; min-height: 100vh;
  font-optical-sizing: auto; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale;
}
/* Admin and calm pages (every public page opts in): the 14 px working size. */
body:is(.area-admin, .calm) { font-size: var(--text-md); line-height: 1.43; letter-spacing: -.011em; }
main { flex: 1; padding-block: var(--sp-5) var(--sp-7); }
main:focus { outline: none; }
img { max-width: 100%; height: auto; }

h1, h2, h3, h4 { font-family: var(--font-display); line-height: 1.25; margin: 0 0 .5rem; color: var(--ink); }
h1 { font-size: var(--text-2xl); line-height: 1.25; font-weight: 650; letter-spacing: -.02em; }
h2 { font-size: var(--text-xl); font-weight: 600; letter-spacing: -.015em; margin-top: var(--sp-5); }
h3 { font-size: var(--text-base); font-weight: 600; letter-spacing: -.011em; }
.h4 { font-size: var(--text-md); font-weight: 600; margin: 1rem 0 .4rem; }
p { margin: 0 0 .75rem; }
code { font-family: var(--mono); font-size: .9em; background: var(--surface-3); padding: .1em .35em; border-radius: var(--radius-xs); overflow-wrap: anywhere; }
hr { border: 0; border-top: 1px solid var(--line); margin: var(--sp-5) 0; }
::selection { background: color-mix(in srgb, var(--primary) 22%, transparent); color: var(--ink); }
.muted { color: var(--ink-muted); }
.subtle { color: var(--ink-subtle); }
.lead { font-size: var(--text-base); color: var(--ink-muted); max-width: 52rem; }
.money, .num, .tabular, td.num, th.num { font-variant-numeric: tabular-nums; }

.container { width: min(1180px, 100% - 2rem); margin-inline: auto; }
.narrow { max-width: 30rem; margin-inline: auto; }

/* Links. Standalone (titles, nav, breadcrumbs, "View all"): no underline until hover or focus.
   Inside running text: a quiet underline (WCAG 1.4.1), full color on hover. A link with a class is a
   component (button, chip, card ...) and styles itself. */
a { color: var(--primary); text-decoration: none; text-underline-offset: .2em; text-decoration-thickness: from-font; }
a:hover { color: var(--primary-hover); text-decoration: underline; }
a:focus-visible { text-decoration: underline; }
:is(.prose, p:not([class]), p.small, p.muted, p.lead, p.hint, .hint, .notice, .note, .flash, .error-summary,
  .notice-line, blockquote, .field-check label, .help-more > p) a:not([class]) {
  text-decoration: underline; text-decoration-color: color-mix(in srgb, currentColor 35%, transparent);
}
:is(.prose, p:not([class]), p.small, p.muted, p.lead, p.hint, .hint, .notice, .note, .flash, .error-summary,
  .notice-line, blockquote, .field-check label, .help-more > p) a:not([class]):hover { text-decoration-color: currentColor; }
.prose { max-width: 46rem; }
.prose :is(h2, h3) { margin-top: var(--sp-5); }
.prose li + li { margin-top: .25rem; }

/* Focus: one ring everywhere (admin and public), never removed. Inputs show it instead of a border change. */
:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; box-shadow: var(--focus-halo); }
:is(input, select, textarea):focus-visible { outline-offset: 0; box-shadow: var(--focus-halo); }

.skip-link {
  position: absolute; left: .5rem; top: -3rem; z-index: 100; padding: .5rem 1rem;
  background: var(--primary); color: var(--on-primary); font-weight: 600; border-radius: 0 0 var(--radius-sm) var(--radius-sm);
}
.skip-link:focus { top: 0; color: var(--on-primary); }
.visually-hidden {
  position: absolute !important; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* Header & nav (shared skeleton; the admin shell is in admin.css, the public header in public.css) */
.site-header { background: var(--chrome); color: var(--chrome-ink); border-bottom: 1px solid var(--line); }
.header-inner {
  display: flex; flex-wrap: wrap; align-items: center; gap: .5rem 1rem; padding-block: .5rem; min-height: 3.5rem;
  padding-left: env(safe-area-inset-left); padding-right: env(safe-area-inset-right);
}
.brand { color: var(--chrome-ink); text-decoration: none; font-weight: 600; font-size: .9375rem; letter-spacing: -.01em; display: inline-flex; align-items: center; gap: .5rem; min-width: 0; }
.brand:hover { color: var(--chrome-ink); text-decoration: none; }
.brand-mark { display: inline-grid; place-items: center; flex: none; width: 1.75rem; height: 1.75rem; border-radius: 7px; background: var(--ink); color: var(--paper); font-weight: 700; font-size: .8125rem; }
.brand-org { font-weight: 450; color: var(--ink-muted); }
.brand-logo { max-height: 2rem; width: auto; border-radius: var(--radius-xs); }
/* An uploaded logo is usually drawn for a white page: dark mode puts it on a light chip so dark marks stay visible. */
:is(.brand-logo, .hero-logo, .board-logo, .org-logo, .logo-preview) { background: var(--logo-chip); }
@media screen and (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) :is(.brand-logo, .hero-logo, .board-logo, .org-logo, .logo-preview) { padding: 2px; border-radius: var(--radius-xs); }
}
@media screen { :root[data-theme="dark"] :is(.brand-logo, .hero-logo, .board-logo, .org-logo, .logo-preview) { padding: 2px; border-radius: var(--radius-xs); } }
.main-nav ul { list-style: none; display: flex; flex-wrap: wrap; gap: .125rem; margin: 0; padding: 0; }
.main-nav a { display: flex; align-items: center; gap: .5rem; min-height: 2rem; color: var(--chrome-ink); text-decoration: none; padding: .25rem .625rem; border-radius: var(--radius-sm); font-weight: 500; transition: background-color var(--dur-1) var(--ease-out), color var(--dur-1) var(--ease-out); }
.main-nav a:hover { background: var(--nav-hover); color: var(--chrome-ink); text-decoration: none; }
.main-nav a[aria-current="page"] { background: var(--nav-current); font-weight: 600; }
.nav-icon { width: 1rem; height: 1rem; flex: none; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
.account { margin-left: auto; display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; }
.account-name { font-size: var(--text-sm); }
.inline-form { display: inline-flex; gap: .35rem; align-items: center; margin: 0; }

.site-footer { border-top: 1px solid var(--line); background: transparent; padding-block: var(--sp-5); font-size: var(--text-sm); color: var(--ink-subtle); }
.site-footer p { margin: .2rem 0; }
.site-footer :is(p, li) a:not([class]), .site-footer a { color: var(--ink-muted); text-decoration: none; }
.site-footer a:hover { color: var(--ink); text-decoration: underline; }

/* The hidden attribute always wins (a .btn's display: inline-flex used to beat it, so a dialog's "×" and Cancel showed
   and did nothing without JavaScript). Scripts that reveal something clear the attribute. */
[hidden] { display: none !important; }

/* Buttons: 32 px (44 on touch), radius 6, weight 550. Secondary is the default; one primary per region. */
.btn {
  --btn-bg: var(--paper); --btn-ink: var(--ink); --btn-line: var(--line-2); --btn-shadow: var(--shadow-1);
  display: inline-flex; align-items: center; justify-content: center; gap: .375rem;
  min-height: var(--control-h); padding: .25rem .75rem; border-radius: var(--radius-sm);
  border: 1px solid var(--btn-line); background: var(--btn-bg); color: var(--btn-ink);
  font: inherit; font-size: var(--text-md); font-weight: 550; line-height: 1.25; letter-spacing: -.006em;
  text-align: center; text-decoration: none; cursor: pointer; box-shadow: var(--btn-shadow);
  transition: background-color var(--dur-1) var(--ease-out), border-color var(--dur-1) var(--ease-out),
    color var(--dur-1) var(--ease-out), box-shadow var(--dur-1) var(--ease-out), transform var(--dur-1) var(--ease-out);
  -webkit-tap-highlight-color: transparent; touch-action: manipulation;
}
.btn:hover { background: var(--surface-2); color: var(--btn-ink); text-decoration: none; }
.btn:active { transform: translateY(.5px); }
.btn .nav-icon, .btn > svg { width: 1rem; height: 1rem; }
.btn-primary {
  --btn-bg: var(--accent-fill); --btn-ink: var(--on-accent-fill); --btn-line: var(--accent-fill);
  --btn-shadow: inset 0 1px 0 rgb(255 255 255 / .12), var(--shadow-1);
}
.btn-primary:hover { background: var(--accent-fill-hover); border-color: var(--accent-fill-hover); color: var(--on-accent-fill); }
.btn-danger { --btn-ink: var(--danger-ink); }
.btn-danger:hover { background: var(--danger-bg); color: var(--danger-ink); border-color: color-mix(in srgb, var(--danger-ink) 40%, transparent); }
/* Ghost and quiet buttons: a faint resting surface, so a text button reads as a button, not as a stray word. An
   icon-only ghost (the ⋯ menu, a dialog's close) keeps no surface: its icon is the affordance. */
.btn-quiet, .btn-ghost {
  --btn-bg: color-mix(in srgb, var(--surface-3) 70%, transparent); --btn-line: transparent; --btn-ink: var(--ink-muted);
  --btn-shadow: none;
}
.btn-icon:is(.btn-quiet, .btn-ghost) { --btn-bg: transparent; }
.btn-quiet:hover, .btn-ghost:hover { background: var(--surface-3); color: var(--ink); }
/* A text button (a dialog's Cancel, an inline Remind): no surface at rest, the ink of a link. */
.btn-text { --btn-bg: transparent; --btn-line: transparent; --btn-ink: var(--primary); --btn-shadow: none; padding-inline: .5rem; }
.btn-text:hover { background: var(--primary-soft); color: var(--primary); }
.btn-icon { padding: 0; width: var(--control-h); }
.btn-small { min-height: 1.75rem; padding: .125rem .625rem; font-size: var(--text-sm); }
.btn-large { min-height: 2.75rem; padding: .5rem 1.25rem; font-size: var(--text-base); border-radius: var(--radius); }
.btn-block { width: 100%; margin-bottom: .5rem; }
@media (pointer: coarse), (max-width: 40rem) { .btn-small { min-height: 2.75rem; padding-inline: .8rem; } }
.btn[disabled], .btn[aria-disabled="true"] { opacity: .5; cursor: not-allowed; transform: none; }
.htmx-request.btn, .htmx-request .btn[type="submit"] { cursor: progress; }
/* Loading: the label stays; a 14 px spinner leads the button that was pressed (ui.js sets aria-busy on the submitting
   form and data-submitting on that one button, so a secondary or danger button beside it never spins). */
form[aria-busy="true"] [data-submitting]:not(:disabled)::before,
.htmx-request.btn::before {
  content: ""; flex: none; width: .875rem; height: .875rem; border-radius: 50%;
  border: 2px solid currentColor; border-right-color: transparent; animation: hk-spin .7s linear infinite;
}
@keyframes hk-spin { to { transform: rotate(360deg); } }
kbd {
  display: inline-block; font-family: var(--font); font-size: var(--text-2xs); font-weight: 550; line-height: 1.3;
  min-width: 1.25rem; padding: .0625rem .3125rem; text-align: center; border: 1px solid var(--line); border-radius: var(--radius-xs);
  background: var(--surface-3); color: var(--ink-muted);
}

/* Forms */
.field { margin-bottom: .875rem; }
.field label { display: block; font-weight: 550; margin-bottom: .25rem; }
.field-check label { font-weight: 400; }
.hint { margin: .25rem 0 0; color: var(--ink-muted); font-size: var(--text-sm); line-height: 1.4; }
.field .hint { margin: 0 0 .35rem; }
.field :is(.input-wrap, select, textarea, input) + .hint { margin: .25rem 0 0; }  /* hints under the control (admin/_forms.html) */
fieldset.checks > .hint { margin: 0 0 .35rem; }
.req { color: var(--danger-ink); }
input[type="text"], input[type="email"], input[type="password"], input[type="number"],
input[type="tel"], input[type="date"], input[type="time"], input[type="datetime-local"],
input[type="url"], input[type="search"], input[type="month"], input:not([type]), select, textarea {
  width: 100%; max-width: 36rem; font: inherit; font-size: var(--text-md); letter-spacing: normal; color: var(--ink); background-color: var(--paper);
  padding: .3125rem .625rem; border: 1px solid var(--line-strong); border-radius: var(--radius-sm); min-height: var(--control-h);
  box-shadow: none;
  transition: border-color var(--dur-1) var(--ease-out), box-shadow var(--dur-1) var(--ease-out);
}
body:not(.area-admin):not(.calm) :is(input, select, textarea) { font-size: var(--text-base); }
input:hover, select:hover, textarea:hover { border-color: var(--ink-muted); }
::placeholder { color: var(--ink-subtle); opacity: 1; }
select:not([multiple]):not([size]) {
  appearance: none; -webkit-appearance: none; padding-right: 2rem;
  background-image: var(--chevron); background-repeat: no-repeat; background-position: right .5rem center; background-size: 1rem;
}
input[type="checkbox"], input[type="radio"] { accent-color: var(--accent); }
textarea { min-height: 4.5rem; line-height: 1.5; }
input[type="file"] { font: inherit; font-size: var(--text-sm); max-width: 100%; }
input[type="file"]::file-selector-button {
  font: inherit; font-weight: 550; margin-right: .6rem; padding: .25rem .75rem; min-height: var(--control-h);
  border: 1px solid var(--line-2); border-radius: var(--radius-sm); background: var(--paper); color: var(--ink); cursor: pointer;
}
@media (max-width: 40rem) { :is(input, select, textarea) { font-size: var(--text-base) !important; } }  /* iOS doesn't zoom */
/* Custom checkbox and radio (admin; public pages keep the native control in the brand colour until slice D). */
.area-admin :is(input[type="checkbox"], input[type="radio"]) {
  appearance: none; -webkit-appearance: none; flex: none; width: 1rem; height: 1rem; margin: 0; vertical-align: -.2em;
  border: 1px solid var(--line-strong); border-radius: var(--radius-xs); background: var(--paper) no-repeat center / .75rem;
  cursor: pointer; transition: background-color var(--dur-1) var(--ease-out), border-color var(--dur-1) var(--ease-out);
}
.area-admin input[type="radio"] { border-radius: 50%; }
.area-admin :is(input[type="checkbox"], input[type="radio"]):hover { border-color: var(--ink-muted); }
.area-admin input[type="checkbox"]:checked { background-color: var(--accent); border-color: var(--accent); background-image: var(--tick); }
.area-admin input[type="checkbox"]:indeterminate { background: var(--accent) linear-gradient(var(--on-accent), var(--on-accent)) no-repeat center / .5rem 2px; border-color: var(--accent); }
.area-admin input[type="radio"]:checked { background-color: var(--accent); border-color: var(--accent); box-shadow: inset 0 0 0 3px var(--paper); }
.area-admin input[type="radio"]:checked:focus-visible { box-shadow: inset 0 0 0 3px var(--paper), var(--focus-halo); }
.area-admin :is(input[type="checkbox"], input[type="radio"]):disabled { opacity: .5; cursor: not-allowed; }
@media (forced-colors: active) {
  .area-admin :is(input[type="checkbox"], input[type="radio"]) { appearance: auto; -webkit-appearance: auto; background-image: none; box-shadow: none; }
}
.field-check { display: grid; grid-template-columns: auto minmax(0, 1fr); align-items: start; gap: .2rem .6rem; }
.field-check input { width: 1.125rem; height: 1.125rem; margin: .1rem 0 0; }
.area-admin .field-check input { width: 1rem; height: 1rem; margin-top: .125rem; }
.field-check label { margin: 0; }
.field-check .hint, .field-check .error-text { grid-column: 2; }
.has-error :is(input, select, textarea, .input-wrap), [aria-invalid="true"] { border-color: var(--danger-ink); box-shadow: 0 0 0 1px var(--danger-ink); }
.error-text { color: var(--danger-ink); font-weight: 550; font-size: var(--text-sm); margin: .25rem 0 0; }
.error-text::before { content: "\26A0\FE0E  "; }
fieldset { border: 1px solid var(--line); border-radius: var(--radius); padding: 1rem 1.25rem; margin: 0 0 1.25rem; min-width: 0; }
legend { font-weight: 600; padding: 0 .35rem; }
/* Prefix and suffix sit inside the field (no grey box); the field draws the border and the ring. */
.input-wrap {
  display: flex; align-items: center; max-width: 36rem; min-height: var(--control-h);
  border: 1px solid var(--line-strong); border-radius: var(--radius-sm); background: var(--paper);
  transition: border-color var(--dur-1) var(--ease-out), box-shadow var(--dur-1) var(--ease-out);
}
.input-wrap:hover { border-color: var(--ink-muted); }
.input-wrap:focus-within { outline: 2px solid var(--focus-ring); outline-offset: 0; box-shadow: var(--focus-halo); }
.input-wrap input { flex: 1 1 auto; min-width: 0; border: 0 !important; background: transparent; box-shadow: none !important; min-height: calc(var(--control-h) - 2px); }
.input-wrap input:focus-visible { outline: none; }
.input-affix { display: inline-flex; align-items: center; color: var(--ink-subtle); font-size: var(--text-sm); white-space: nowrap; padding: 0 0 0 .625rem; user-select: none; }
.input-wrap > input + .input-affix { padding: 0 .625rem 0 0; }
.has-prefix input { padding-left: .25rem; }
.has-suffix input { padding-right: .25rem; }

/* Messages: flashes (after a redirect), notices (in a page), notes (admin). One look: a tinted
   panel with the label or icon in text, never color alone. No red rails. */
.flashes { margin-bottom: var(--sp-4); display: grid; gap: .375rem; }
.flashes:empty { display: none; }
.flash, .notice, .note {
  padding: .5rem .75rem; border-radius: var(--radius-sm); border: 1px solid color-mix(in srgb, currentColor 18%, transparent);
  margin: 0 0 .75rem; background: var(--surface-2);
}
.flashes .flash { margin: 0; display: flex; align-items: flex-start; gap: .5rem; }
.notice > :last-child, .note > :last-child { margin-bottom: 0; }
.flash-success, .notice-success, .note-success { background: var(--success-bg); color: var(--success-ink); }
.flash-error, .notice-error, .note-error { background: var(--danger-bg); color: var(--danger-ink); }
.flash-warning, .notice-warning, .note-warning { background: var(--warning-bg); color: var(--warning-ink); }
.flash-info, .notice-info, .note-info { background: var(--info-bg); color: var(--info-ink); }
.note ul, .notice ul { margin: .3rem 0 0; padding-left: 1.2rem; }
.notice a, .note a, .flash a { color: inherit; }
.flash-text { flex: 1 1 auto; min-width: 0; }
.flash-close {
  flex: none; display: inline-grid; place-items: center; width: 1.75rem; height: 1.75rem; margin: -.25rem -.375rem -.25rem 0;
  border: 0; border-radius: var(--radius-xs); background: transparent; color: inherit; font: inherit; font-size: 1.125rem;
  line-height: 1; cursor: pointer; opacity: .75;
}
.flash-close[hidden] { display: none; }
.flash-close:hover { background: color-mix(in srgb, currentColor 12%, transparent); opacity: 1; }
@media (pointer: coarse) { .flash-close { width: 2.75rem; height: 2.75rem; margin-block: -.6rem; } }

/* Toasts (with JavaScript): success and notes float bottom-right (top-centre on phones), 5 s, at most 3.
   #toasts is the page's one polite live region; errors and warnings never become toasts. Without
   JavaScript the same messages stay in place at the top of the page (the rules above). */
.js .toasts {
  position: fixed; z-index: 90; right: 1.5rem; bottom: 1.5rem; left: auto; top: auto;
  width: min(23.75rem, calc(100vw - 2rem)); margin: 0; display: flex; flex-direction: column; gap: .5rem; pointer-events: none;
}
.js .toasts .flash {
  pointer-events: auto; align-items: center; gap: .625rem; padding: .625rem .5rem .625rem .75rem;
  background: var(--paper); color: var(--ink); border: 1px solid var(--line); border-radius: var(--radius);
  box-shadow: var(--shadow-3); font-size: var(--text-md); line-height: 1.4;
  animation: hk-toast-in var(--dur-2) var(--ease-out) both;
}
.js .toasts .flash::before {
  content: ""; flex: none; width: 1.125rem; height: 1.125rem; border-radius: 50%;
  background: var(--success-ink) var(--tick) no-repeat center / .75rem; align-self: flex-start; margin-top: .0625rem;
}
.js .toasts .flash-info::before { background: var(--primary) no-repeat center; box-shadow: inset 0 0 0 5px var(--primary), inset 0 0 0 9px var(--paper); }
.js .toasts .flash strong { font-weight: 600; }
.js .toasts .flash-label {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0);
  white-space: nowrap; border: 0;
}
.js .toasts .flash.is-leaving { animation: hk-toast-out calc(var(--dur-2) * .75) var(--ease-in) forwards; }
.toast-link { font-weight: 600; white-space: nowrap; }
.toast-action { display: inline-flex; margin: 0; }
button.toast-link {
  border: 0; padding: .125rem .375rem; margin: -.125rem 0; border-radius: var(--radius-xs); background: transparent;
  color: var(--primary); font: inherit; font-weight: 600; cursor: pointer;
}
button.toast-link:hover { background: var(--surface-3); }
@media (max-width: 47.99rem) {
  .js .toasts { right: 50%; bottom: auto; top: calc(3.25rem + .5rem); transform: translateX(50%); }
}
@keyframes hk-toast-in { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: none; } }
@keyframes hk-toast-out { to { opacity: 0; transform: translateY(4px); } }

/* The slim persistent line (verify your email): one line, its action at the end. */
.notice-line {
  display: flex; flex-wrap: wrap; align-items: center; gap: .25rem .75rem; margin: 0 0 var(--sp-4);
  padding: .375rem .5rem .375rem .75rem; border-radius: var(--radius-sm); font-size: var(--text-sm);
  background: var(--warning-bg); color: var(--warning-ink); border: 1px solid color-mix(in srgb, currentColor 18%, transparent);
}
.notice-line > p { margin: 0; flex: 1 1 18rem; }
.notice-line a { color: inherit; font-weight: 600; }
.notice-line form { margin: 0; }
.notice-line .btn { --btn-ink: var(--warning-ink); --btn-bg: transparent; --btn-line: color-mix(in srgb, currentColor 40%, transparent); --btn-shadow: none; }
.notice-line .btn:hover { background: color-mix(in srgb, currentColor 10%, transparent); color: var(--warning-ink); }

/* Empty states: a small drawing (templates/_art.html), one line, one muted line, one action. */
.empty-state {
  padding: var(--sp-6) var(--sp-5); border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--paper); margin-bottom: var(--sp-4); text-align: center;
}
.empty-state > p { max-width: 38rem; margin-inline: auto; }
.empty-state p:last-child { margin-bottom: 0; }
.empty-state > p:first-child > strong:first-child { display: block; font-size: var(--text-md); font-weight: 600; margin-bottom: .25rem; }
.empty-art { display: block; width: 6rem; height: 6rem; margin: 0 auto var(--sp-3); }
.empty-title { font-size: var(--text-md); font-weight: 600; color: var(--ink); margin: 0 0 .25rem; }
.empty-text { font-size: var(--text-sm); color: var(--ink-muted); }
.empty-state .empty-text { margin-bottom: var(--sp-4); }
.empty-actions { display: flex; flex-wrap: wrap; justify-content: center; gap: .5rem; }
.empty-inline { color: var(--ink-muted); margin: .25rem 0 .75rem; }
.art-line { fill: none; stroke: var(--ink-subtle); stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round; }
.art-fill { fill: var(--primary-soft); stroke: none; }
.art-accent { fill: none; stroke: var(--primary); stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round; }

.error-summary {
  padding: .75rem 1rem; margin-bottom: var(--sp-4); background: var(--danger-bg); color: var(--danger-ink);
  border: 1px solid color-mix(in srgb, var(--danger-ink) 30%, transparent); border-radius: var(--radius-sm);
}
.error-summary h2, .error-summary-title { margin: 0 0 .25rem; font-size: var(--text-md); font-weight: 600; color: var(--danger-ink); }
.error-summary ul { margin: 0; padding-left: 1.2rem; }
.error-summary a { color: var(--danger-ink); font-weight: 550; }
.error-summary:focus { outline: 2px solid var(--focus-ring); outline-offset: 2px; }

/* Cards, panels, stats: flat, one box deep. */
.card, .panel { background: var(--paper); border: 1px solid var(--line); border-radius: var(--radius); padding: 1.25rem; box-shadow: none; margin-bottom: var(--sp-4); }
.card h2:first-child, .card h3:first-child, .panel h2:first-child { margin-top: 0; }
:is(.card, .panel) > h2:first-child, .panel h2, .card-head h2, .card > h2 { font-size: var(--text-md); font-weight: 600; letter-spacing: -.006em; margin-bottom: .75rem; }
.card-head { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: .5rem; margin-bottom: .75rem; }
.card-head > * { margin-bottom: 0 !important; }
a.card, .card-link { color: inherit; text-decoration: none; transition: border-color var(--dur-1) var(--ease-out), box-shadow var(--dur-1) var(--ease-out); }
a.card:hover, .card-link:hover { border-color: var(--line-2); box-shadow: var(--shadow-1); color: inherit; text-decoration: none; }
.subcard { border: 1px solid var(--line); border-radius: var(--radius); padding: var(--sp-3) var(--sp-4); background: var(--surface-2); margin-bottom: 1rem; }
.subcard h3, .subcard h4 { margin-top: 0; }
:is(.card, .panel, .subcard) :is(.card, .panel, .subcard) {
  background: transparent; border: 0; border-top: 1px solid var(--line); border-radius: 0; box-shadow: none;
  padding: var(--sp-3) 0 0; margin: var(--sp-3) 0 0;
}
/* A fieldset inside a card (or a calm form) is a group: a divider and a small label, no box. */
:is(.card, .panel, .form-rows, .form-groups) fieldset:not(.checks):not(.day-pills):not(.pg-person) {
  border: 0; border-top: 1px solid var(--line); border-radius: 0; padding: var(--sp-4) 0 0; margin: var(--sp-4) 0 0;
}
:is(.card, .panel, .form-rows, .form-groups) fieldset:not(.checks):not(.day-pills):not(.pg-person) > legend {
  float: left; width: 100%; padding: 0; margin: 0 0 var(--sp-3);
  font-size: var(--text-sm); font-weight: 600; color: var(--ink);
}
:is(.card, .panel, .form-rows, .form-groups) fieldset:not(.checks):not(.day-pills):not(.pg-person) > legend + * { clear: both; }
:is(.card, .panel, .form-rows, .form-groups) > fieldset:not(.checks):not(.day-pills):not(.pg-person):first-child,
:is(.card, .panel, .form-rows, .form-groups) > input[type="hidden"]:first-child + fieldset:not(.checks):not(.day-pills):not(.pg-person) {
  border-top: 0; padding-top: 0; margin-top: 0;
}
fieldset.checks legend { font-weight: 550; }
.card-list, .card-grid { list-style: none; padding: 0; margin: 0 0 1.5rem; display: grid; gap: 1rem; }
.card-grid { grid-template-columns: repeat(auto-fill, minmax(16rem, 1fr)); }
.card-grid > .card { margin: 0; }
.hero { padding-block: .5rem 1rem; }
.stat-grid { list-style: none; padding: 0; margin: 0 0 2rem; display: grid; gap: 1rem; grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr)); }
.stat { background: var(--paper); border: 1px solid var(--line); border-radius: var(--radius); padding: 1rem 1.25rem; display: flex; flex-direction: column; }
.stat-value { font-size: var(--text-3xl); font-weight: 650; line-height: 1.15; letter-spacing: -.02em; font-variant-numeric: tabular-nums; }
.stat-label { color: var(--ink-muted); }

/* KPI card (ui.kpi): the whole card links to its report; value, then a delta line. */
.kpi { display: grid; gap: .25rem; padding: 1rem 1.25rem; background: var(--paper); border: 1px solid var(--line); border-radius: var(--radius); color: var(--ink); text-decoration: none; }
a.kpi:hover { border-color: var(--line-2); box-shadow: var(--shadow-1); color: var(--ink); text-decoration: none; }
.kpi .kpi-label { font-size: var(--text-sm); color: var(--ink-muted); }
.kpi .kpi-value { font-size: var(--text-3xl); font-weight: 650; letter-spacing: -.02em; line-height: 1.15; font-variant-numeric: tabular-nums; }
.kpi .kpi-delta { font-size: var(--text-sm); color: var(--ink-muted); font-variant-numeric: tabular-nums; }
.kpi .kpi-delta.is-good { color: var(--success-ink); }

/* "Show as table" under a chart (ui.chart_table): the same numbers, folded. */
.chart-table { margin-top: .75rem; font-size: var(--text-sm); }
.chart-table > summary { display: inline-flex; align-items: center; min-height: 2rem; cursor: pointer; color: var(--ink-muted); font-weight: 550; }
.chart-table > summary:hover { color: var(--ink); }
.chart-table[open] > summary { margin-bottom: .5rem; }

/* Tables: quiet head, 44 px rows (36 compact), row hover, titles in ink, numbers right-aligned. */
.table-wrap { position: relative; overflow: auto; background: var(--paper); border: 1px solid var(--line); border-radius: var(--radius); }
table { width: 100%; border-collapse: collapse; }
th, td { text-align: left; padding: .75rem; border-bottom: 1px solid var(--line); vertical-align: middle; }
thead th { background: var(--surface-2); padding-block: .5rem; font-size: var(--text-xs); font-weight: 550; color: var(--ink-muted); letter-spacing: 0; }
tbody th[scope="row"] { font-weight: 550; }
tbody tr { transition: background-color var(--dur-1) var(--ease-out); }
.table-wrap tbody tr:hover { background: var(--surface-2); }
tbody tr:last-child > * { border-bottom: 0; }
td.num, th.num { text-align: right; }
tbody :is(:is(td, th) > a:not([class]):first-child, .c-title > a:not([class]), a.c-title, a:has(> strong:only-child)) { color: var(--ink); font-weight: 550; }
tbody :is(:is(td, th) > a:not([class]):first-child, .c-title > a:not([class]), a.c-title, a:has(> strong:only-child)):hover { color: var(--primary); }
tbody a > strong:only-child { font-weight: inherit; }
:is(table.table-compact, table.compact) :is(th, td) { padding: .375rem .625rem; }
/* Long tables keep their header row in view: the wrapper scrolls (both ways) once taller than
   the screen, and the head sticks to its top. */
@media (min-width: 64rem) {
  .table-wrap:has(> table > tbody > tr:nth-child(15)) { max-height: min(78vh, 60rem); }
  .table-wrap > table > thead th { position: sticky; top: 0; z-index: 1; box-shadow: inset 0 -1px 0 var(--line); }
}

/* Chips (filters), tabs, page heads, breadcrumbs (admin and public) */
.chips { list-style: none; padding: 0; margin: 0 0 1rem; display: flex; flex-wrap: wrap; gap: .375rem; }
.chips li { border-radius: var(--radius-xs); padding: .125rem .5rem; font-size: var(--text-sm); background: var(--surface-3); color: var(--ink-muted); }
.chip {
  --chip-on-bg: var(--primary-soft); --chip-on-ink: var(--primary);
  display: inline-flex; align-items: center; gap: .375rem; min-height: 1.875rem; padding: .125rem .75rem;
  border: 1px solid var(--line-2); border-radius: var(--radius-pill); background: var(--paper); box-shadow: var(--shadow-1);
  text-decoration: none; font-size: var(--text-sm); font-weight: 550; color: var(--ink);
  transition: background-color var(--dur-1) var(--ease-out), border-color var(--dur-1) var(--ease-out);
}
.chip:hover { background: var(--surface-2); color: var(--ink); text-decoration: none; }
.chip[aria-current="page"], .chip[aria-pressed="true"], .chip.is-on { background: var(--chip-on-bg); border-color: transparent; color: var(--chip-on-ink); box-shadow: none; }
@media (pointer: coarse), (max-width: 40rem) { .chip { min-height: 2.75rem; } }
.tabs ul { list-style: none; padding: 0; margin: 0 0 1.25rem; display: flex; flex-wrap: wrap; gap: .25rem; border-bottom: 1px solid var(--line); }
.tabs a { display: flex; align-items: center; min-height: 2.25rem; padding: .3rem .75rem; text-decoration: none; color: var(--ink-muted); font-weight: 550; border-bottom: 2px solid transparent; margin-bottom: -1px; transition: color var(--dur-1) var(--ease-out), border-color var(--dur-1) var(--ease-out); }
.tabs a:hover { color: var(--ink); border-bottom-color: var(--line-2); text-decoration: none; }
.tabs a[aria-current="page"] { color: var(--ink); border-bottom-color: var(--accent); }
.page-head { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: flex-end; gap: .75rem 1rem; margin-bottom: var(--sp-5); }
.page-head h1 { margin-bottom: .125rem; }
.page-head p { margin-bottom: 0; }
.page-head-main { min-width: 0; flex: 1 1 20rem; }
.page-head-title { display: flex; flex-wrap: wrap; align-items: center; gap: .25rem .625rem; }
.page-head-title h1 { margin: 0; }
.page-head-meta { margin: .25rem 0 0; font-size: var(--text-sm); color: var(--ink-muted); }
.page-head-actions { display: flex; flex-wrap: wrap; gap: .5rem; align-items: center; }
.page-head-tabs { flex-basis: 100%; }
.page-head-tabs .tabs ul { margin-bottom: 0; }
.button-row { display: flex; flex-wrap: wrap; gap: .5rem; align-items: center; }
.breadcrumb, .breadcrumbs { margin-bottom: .375rem; font-size: var(--text-sm); color: var(--ink-subtle); }
.breadcrumb ol, .breadcrumbs ol { list-style: none; padding: 0; margin: 0; display: flex; flex-wrap: wrap; gap: .375rem; }
.breadcrumb li + li::before, .breadcrumbs li + li::before { content: "\203A"; margin-right: .375rem; color: var(--ink-subtle); }
:is(.breadcrumb, .breadcrumbs) a { color: var(--ink-muted); text-decoration: none; }
:is(.breadcrumb, .breadcrumbs) a:hover { color: var(--ink); text-decoration: underline; }
.breadcrumbs [aria-current="page"] { color: var(--ink); text-decoration: none; font-weight: 550; }

/* Status badges: 20 px, a tinted fill, no border, and a leading 6 px shape that differs per state, so
   the state never rests on color: filled dot = done/confirmed, ring = waiting, half = approved/in
   progress, diamond = full, x = cancelled/stopped. The text always names the state. */
.badge {
  display: inline-flex; align-items: center; gap: .375rem; min-height: 1.25rem; padding: 0 .5rem; border-radius: var(--radius-pill);
  font-size: var(--text-xs); font-weight: 550; line-height: 1.25rem; letter-spacing: 0; border: 0; white-space: nowrap;
  background: var(--neutral-bg); color: var(--neutral-ink); vertical-align: middle;
}
.badge-dot { flex: none; width: 6px; height: 6px; border-radius: 50%; border: 1.5px solid currentColor; }
.badge-confirmed .badge-dot, .badge-completed .badge-dot, .badge-closed .badge-dot, .badge-paid .badge-dot, .badge-succeeded .badge-dot,
.badge-won .badge-dot, .badge-approved_coi .badge-dot { background: currentColor; }
.badge-approved .badge-dot, .badge-quoted .badge-dot { background: linear-gradient(90deg, currentColor 50%, transparent 50%); }
.badge-full .badge-dot { border-radius: 1px; transform: rotate(45deg); background: currentColor; width: 6px; height: 6px; }
.badge-declined .badge-dot, .badge-cancelled .badge-dot, .badge-lost .badge-dot, .badge-failed .badge-dot, .badge-rejected .badge-dot {
  border: 0; border-radius: 0; width: 7px; height: 7px;
  background: linear-gradient(45deg, transparent 40%, currentColor 40% 60%, transparent 60%),
    linear-gradient(-45deg, transparent 40%, currentColor 40% 60%, transparent 60%);
}
.badge-approved, .badge-quoted { color: var(--info-ink); background: var(--info-bg); }
.badge-confirmed, .badge-won, .badge-paid, .badge-succeeded, .badge-approved_coi { color: var(--success-ink); background: var(--success-bg); }
.badge-pending_approval, .badge-quote_requested, .badge-new, .badge-pending { color: var(--warning-ink); background: var(--warning-bg); }
.badge-failed, .badge-rejected { color: var(--danger-ink); background: var(--danger-bg); }
.badge-declined, .badge-cancelled, .badge-lost, .badge-completed, .badge-closed { color: var(--neutral-ink); background: var(--neutral-bg); }

/* Tags (neutral labels) and count pills */
.tag {
  display: inline-flex; align-items: center; min-height: 1.125rem; padding: 0 .375rem; border-radius: var(--radius-xs);
  font-size: var(--text-xs); font-weight: 550; line-height: 1.125rem; background: var(--surface-3); color: var(--ink-muted);
  border: 0; vertical-align: middle; white-space: nowrap;
}
.count-pill {
  display: inline-block; min-width: 1.25rem; padding: 0 .375rem; border-radius: var(--radius-pill); background: var(--surface-3);
  color: var(--ink-muted); font-size: var(--text-xs); font-weight: 550; line-height: 1.25rem; text-align: center;
  font-variant-numeric: tabular-nums; vertical-align: middle;
}

/* Progress steps (booking lifecycle, renter checkout): text + shape per state. */
.progress-steps { position: relative; list-style: none; margin: 0 0 var(--sp-5); padding: 0; display: grid; grid-auto-flow: column; grid-auto-columns: minmax(5.5rem, 1fr); gap: var(--sp-2); overflow-x: auto; font-size: var(--text-xs); }
.progress-steps li { display: flex; align-items: center; gap: .4rem; padding-top: .5rem; border-top: 3px solid var(--line); color: var(--ink-muted); line-height: 1.25; }
.progress-steps .step-mark { flex: none; display: inline-grid; place-items: center; width: 1.25rem; height: 1.25rem; border-radius: 50%; border: 1.5px dotted var(--line-strong); font-size: .6875rem; font-weight: 650; }
.progress-steps .is-done { color: var(--success-ink); border-top-color: var(--success-ink); }
.progress-steps .is-done .step-mark { border: 1.5px solid var(--success-ink); background: var(--success-ink); color: var(--paper); }
.progress-steps .is-current { color: var(--ink); font-weight: 600; border-top-color: var(--accent); }
.progress-steps .is-current .step-mark { border: 1.5px solid var(--accent); background: var(--accent); color: var(--on-accent); }
.progress-steps .is-stopped { color: var(--danger-ink); font-weight: 600; border-top-color: var(--danger-ink); border-top-style: dashed; }
.progress-steps .is-stopped .step-mark { border: 1.5px solid var(--danger-ink); border-radius: 2px; transform: rotate(45deg) scale(.8); }

.placeholder { padding: 1rem 1.25rem; border: 1px dashed var(--line-2); border-radius: var(--radius); color: var(--ink-muted); background: var(--paper); }
.error-page { padding-block: 2rem; }
.error-code { font-family: var(--mono); color: var(--ink-muted); margin-bottom: .25rem; }

/* HTMX: a request indicator, and a soft fade-in for swapped content */
.htmx-indicator { opacity: 0; transition: opacity var(--dur-2); }
.htmx-request .htmx-indicator, .htmx-request.htmx-indicator { opacity: 1; }
.htmx-settling, .htmx-added { animation: hk-in var(--dur-2) var(--ease-out) both; }
[aria-busy="true"], .htmx-request:not(form):not(.btn):not(.htmx-indicator) { cursor: progress; }
@keyframes hk-in { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: none; } }

/* Skeletons: only for htmx swaps (the dashboard period switch, the command bar results). A
   .has-skeleton wrapper holds the content and a .skeleton-layer; the layer shows only when the
   wrapper is loading (.htmx-request through hx-indicator, or .is-loading), and only after 250 ms,
   so a fast swap never flashes. */
.skeleton {
  display: block; min-height: .75rem; border-radius: var(--radius-sm); color: transparent;
  background: linear-gradient(90deg, var(--surface-3) 0%, var(--surface-2) 50%, var(--surface-3) 100%) 0 0 / 200% 100%;
  animation: hk-shimmer 1.2s linear infinite;
}
@keyframes hk-shimmer { from { background-position: 100% 0; } to { background-position: -100% 0; } }
.has-skeleton { position: relative; }
.skeleton-layer {
  position: absolute; inset: 0; z-index: 2; display: grid; align-content: start; gap: .625rem; padding: inherit;
  background: var(--paper); opacity: 0; visibility: hidden; pointer-events: none;
  transition: opacity var(--dur-2) var(--ease-out) 0s, visibility 0s linear var(--dur-2);
}
:is(.has-skeleton.htmx-request, .has-skeleton.is-loading) > .skeleton-layer {
  opacity: 1; visibility: visible; transition: opacity var(--dur-2) var(--ease-out) 250ms, visibility 0s linear 250ms;
}

/* Menus and popovers: <details class="menu"><summary>...</summary><div class="menu-panel">...</div></details>.
   Works without JavaScript; ui.js adds Escape, a click outside, and arrow keys. */
.menu { position: relative; }
.menu > summary { list-style: none; cursor: pointer; }
.menu > summary::-webkit-details-marker { display: none; }
.menu-panel {
  position: absolute; z-index: 60; top: calc(100% + .25rem); left: 0; min-width: 13rem; max-width: min(20rem, calc(100vw - 1rem));
  padding: .25rem; background: var(--paper); color: var(--ink); border: 1px solid var(--line); border-radius: var(--radius);
  box-shadow: var(--shadow-2); font-size: var(--text-md); letter-spacing: -.006em;
}
.menu[open] > .menu-panel { animation: hk-pop var(--dur-2) var(--ease-out) both; }
.menu-end > .menu-panel { left: auto; right: 0; }
.menu-up > .menu-panel { top: auto; bottom: calc(100% + .25rem); }
@keyframes hk-pop { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: none; } }
.menu-item {
  display: flex; align-items: center; gap: .5rem; width: 100%; min-height: 2rem; padding: .25rem .5rem; margin: 0;
  border: 0; border-radius: var(--radius-sm); background: none; color: var(--ink); font: inherit; text-align: left;
  text-decoration: none; cursor: pointer; white-space: nowrap;
}
.menu-item:hover, .menu-item:focus-visible { background: var(--surface-3); color: var(--ink); text-decoration: none; }
.menu-item:focus-visible { outline-offset: -2px; box-shadow: none; }
.menu-item .nav-icon { color: var(--ink-subtle); }
.menu-item[aria-current="true"] { font-weight: 600; }
.menu-item .menu-end-mark { margin-left: auto; color: var(--ink-subtle); }
.menu-item kbd.menu-end-mark { color: var(--ink-muted); }
.menu-panel form { margin: 0; }
.menu-item.is-danger { color: var(--danger-ink); }
.menu-note { margin: 0; padding: .375rem .5rem; font-size: var(--text-xs); color: var(--ink-subtle); max-width: 16rem; white-space: normal; }
.menu-sep { height: 1px; background: var(--line); margin: .25rem -.25rem; border: 0; }
.menu-label { margin: 0; padding: .375rem .5rem .25rem; font-size: var(--text-xs); color: var(--ink-subtle); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
@media (pointer: coarse) { .menu-item { min-height: 2.75rem; } }
/* A segmented control (Appearance: System / Light / Dark; later the dashboard period). */
.seg { display: flex; padding: 2px; gap: 2px; background: var(--surface-3); border-radius: calc(var(--radius-sm) + 2px); }
.seg > * {
  flex: 1 1 0; display: inline-flex; align-items: center; justify-content: center; gap: .25rem; min-height: 1.75rem; padding: 0 .5rem;
  border: 0; border-radius: var(--radius-sm); background: transparent; color: var(--ink-muted); font: inherit; font-size: var(--text-sm);
  font-weight: 550; cursor: pointer; text-decoration: none;
}
.seg > :hover { color: var(--ink); text-decoration: none; }
.seg > :is([aria-pressed="true"], [aria-current="page"]) { background: var(--paper); color: var(--ink); box-shadow: var(--shadow-1); }
.seg .nav-icon { width: .875rem; height: .875rem; }
.menu-panel .seg { margin: .125rem .25rem .375rem; }

/* Dialogs and sheets: the native <dialog class="dialog">; a bottom sheet with a grab handle on phones. */
.dialog {
  width: min(32rem, calc(100vw - 2rem)); max-height: calc(100dvh - 4rem); padding: 0; margin: auto;
  border: 1px solid var(--line); border-radius: var(--radius-lg); background: var(--paper); color: var(--ink);
  box-shadow: var(--shadow-3); overflow: auto; overscroll-behavior: contain;
}
.dialog[open] { animation: hk-dialog-in var(--dur-3) var(--ease-out) both; }
.dialog::backdrop { background: var(--backdrop); -webkit-backdrop-filter: blur(2px); backdrop-filter: blur(2px); }
.dialog-head { display: flex; align-items: center; justify-content: space-between; gap: .75rem; padding: .875rem 1rem .875rem 1.25rem; border-bottom: 1px solid var(--line); }
.dialog-head h2 { margin: 0; font-size: var(--text-base); font-weight: 600; }
.dialog-body { padding: 1rem 1.25rem 1.25rem; }
.dialog-foot { display: flex; justify-content: flex-end; gap: .5rem; padding: .75rem 1.25rem; border-top: 1px solid var(--line); background: var(--surface-2); }
@keyframes hk-dialog-in { from { opacity: 0; transform: scale(.98); } to { opacity: 1; transform: none; } }
@keyframes hk-sheet-in { from { transform: translateY(100%); } to { transform: none; } }
@media (max-width: 40rem) {
  .dialog {
    width: 100%; max-width: 100%; max-height: 88dvh; margin: auto 0 0; border-width: 1px 0 0;
    border-radius: var(--radius-xl) var(--radius-xl) 0 0; padding-bottom: env(safe-area-inset-bottom);
  }
  .dialog[open] { animation-name: hk-sheet-in; }
  .dialog::before { content: ""; display: block; width: 2.25rem; height: 4px; margin: .5rem auto 0; border-radius: 2px; background: var(--line-2); }
}

/* Dialog forms (ui.dialog_form; design-v2-c). Without JavaScript, or without <dialog>, a dialog form is drawn in place as
   a plain section at the end of the page ("More forms"), so every opener (a link to its #id) still lands on its form. */
.dlg-forms-h { display: none; }
:is(html:not(.js), html.no-dialog) .dlg-forms-h { display: block; margin: var(--sp-6) 0 var(--sp-3); font-size: var(--text-xl); }
:is(html:not(.js), html.no-dialog) dialog.dialog-form {
  display: block; position: static; width: auto; max-width: 48rem; max-height: none; margin: 0 0 var(--sp-4); overflow: visible;
  box-shadow: none; border-radius: var(--radius); animation: none;
}
:is(html:not(.js), html.no-dialog) dialog.dialog-form::before { content: none; }
.dialog-form .dialog-head h2 { margin: 0; }

/* Meters without inline styles (design-v2-c): .bar-meter with one .pct-N class (0 to 100 in steps of 5) sets the fill.
   Decorative: the figures beside it say the same thing in words. */
.bar-meter { display: block; height: 6px; border-radius: var(--radius-pill); background: var(--surface-3); overflow: hidden; }
.bar-meter > span { display: block; height: 100%; width: var(--pct, 0%); border-radius: inherit; background: var(--chart-1); }
.pct-0 { --pct: 0%; } .pct-5 { --pct: 5%; } .pct-10 { --pct: 10%; } .pct-15 { --pct: 15%; } .pct-20 { --pct: 20%; } .pct-25 { --pct: 25%; } .pct-30 { --pct: 30%; } .pct-35 { --pct: 35%; } .pct-40 { --pct: 40%; } .pct-45 { --pct: 45%; } .pct-50 { --pct: 50%; } .pct-55 { --pct: 55%; } .pct-60 { --pct: 60%; } .pct-65 { --pct: 65%; } .pct-70 { --pct: 70%; } .pct-75 { --pct: 75%; } .pct-80 { --pct: 80%; } .pct-85 { --pct: 85%; } .pct-90 { --pct: 90%; } .pct-95 { --pct: 95%; } .pct-100 { --pct: 100%; }
@media (forced-colors: active) {
  .bar-meter { border: 1px solid CanvasText; background: Canvas; }
  .bar-meter > span { background: Highlight; forced-color-adjust: none; }
}

/* Keyboard shortcut list (the "?" dialog) */
.kbd-list { display: grid; grid-template-columns: max-content minmax(0, 1fr); gap: .5rem 1rem; margin: 0; align-items: baseline; }
.kbd-list dt { white-space: nowrap; }
.kbd-list dd { margin: 0; color: var(--ink-muted); }

/* Price breakdown: templates/partials/quote_lines.html, shared by admin, renter and
   commercial pages (integration). */
.quote-table caption { text-align: left; font-weight: 600; padding: .5rem .75rem; }
.quote-table th { font-weight: 400; }
.quote-table .line-label { display: block; font-weight: 550; }
.quote-table .line-why { display: block; color: var(--ink-muted); font-size: var(--text-sm); font-weight: 400; }
.quote-table .line-discount td, .quote-table .line-discount .line-label { color: var(--success-ink); }
.quote-table .line-adjust th, .quote-table .line-adjust td { background: var(--warning-soft); }
.quote-table .line-total th, .quote-table .line-total td { font-weight: 650; font-size: var(--text-base); border-top: 1px solid var(--ink); }
.quote-table .line-deposit th, .quote-table .line-deposit td { color: var(--ink-muted); }
.quote-table td { font-variant-numeric: tabular-nums; }
.quote-notes { font-size: var(--text-sm); color: var(--ink-muted); padding-left: 1.1rem; }
.notice.post-event { margin-top: .75rem; }

/* ---- More help, folded: a one-line summary that opens the full explanation (instead of a paragraph). */
.help-more { margin: -.25rem 0 var(--sp-4); font-size: var(--text-sm); color: var(--ink-muted); }
.help-more > summary { cursor: pointer; display: inline-flex; align-items: center; min-height: 2rem; color: var(--primary); font-weight: 550; }
.help-more > summary:hover { text-decoration: underline; }
.help-more[open] > summary { margin-bottom: .25rem; }
.help-more > p { max-width: 52rem; }
@media (pointer: coarse) { .help-more > summary { min-height: 2.75rem; } }

@media (max-width: 40rem) {
  h1 { font-size: var(--text-xl); }
  h2 { font-size: var(--text-lg); }
  .container { width: min(1180px, 100% - 2rem); }
  /* One scrollable row of nav links instead of three wrapped lines on a phone. */
  .main-nav { order: 10; flex-basis: 100%; overflow-x: auto; scrollbar-width: none; margin-inline: -.25rem; }
  .main-nav::-webkit-scrollbar { display: none; }
  .main-nav ul { flex-wrap: nowrap; }
  .main-nav a { white-space: nowrap; }
  .account-name { display: none; }
  .brand { flex: 1 1 0; }
  .brand-org { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .page-head { align-items: flex-start; }
  :is(.card, .panel) { padding: 1rem; }
}
/* Reduced motion: no movement, no shimmer; durations collapse so state changes still land. */
@media (prefers-reduced-motion: reduce) {
  :root { --dur-1: .01ms; --dur-2: .01ms; --dur-3: .01ms; --dur-4: .01ms; }
  *, *::before, *::after { transition-duration: .01ms !important; animation-duration: .01ms !important; animation-iteration-count: 1 !important; scroll-behavior: auto !important; }
  .skeleton { animation: none; }
  .btn:active { transform: none; }
}
@media print {
  :root { color-scheme: light; }
  .site-header, .site-footer, .skip-link, .btn, .flashes, .tabbar { display: none !important; }
  body { background: #fff; padding: 0 !important; }
  .card, .stat, .table-wrap, .panel { box-shadow: none; }
  .table-wrap { max-height: none !important; overflow: visible; }
  thead th { position: static !important; }
}

/* Shared utilities (admin and public pages). Last in this file so they win over the components above. */
.small { font-size: var(--text-sm); }
.nowrap { white-space: nowrap; }
.stack > * + * { margin-top: .5rem; }
.grid-2, .grid-3 { display: grid; gap: 0 1.25rem; }
@media (min-width: 48rem) {
  .grid-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .grid-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
.inline-fields { display: flex; flex-wrap: wrap; gap: .5rem 1rem; align-items: flex-end; }
.inline-fields .field { margin-bottom: 0; }
.inline-list { list-style: none; padding: 0; margin: 0 0 1rem; display: flex; flex-wrap: wrap; gap: .25rem 1.25rem; }
.plain-list { list-style: none; padding: 0; }
.optional { font-weight: 400; color: var(--ink-muted); }
.mono { font-family: var(--mono); letter-spacing: .02em; }

/* ---- Form rows (opt in with class="form-rows" on a form or a group) ----------------------------
   Labels beside fields where the form is wide enough (a container query, so it adapts to the
   sidebar and the setup menu), stacked otherwise. Hints and errors sit under the control. */
.form-rows { container-type: inline-size; }
@container (min-width: 38rem) {
  .form-rows .field:not(.field-check):not(:has(> label.visually-hidden)) {
    display: grid; grid-template-columns: var(--label-w, 12.5rem) minmax(0, 1fr); column-gap: var(--row-gap, 1.25rem); align-items: start;
  }
  .form-rows .field:not(.field-check):not(:has(> label.visually-hidden)) > label {
    grid-column: 1; grid-row: 1 / span 4; margin: 0; padding-top: calc((var(--control-h) - 1.5em) / 2);
  }
  .form-rows .field:not(.field-check):not(:has(> label.visually-hidden)) > :not(label) { grid-column: 2; }
  .form-rows .field.field-check { padding-left: calc(var(--label-w, 12.5rem) + var(--row-gap, 1.25rem)); }
  .form-rows fieldset.checks { padding-left: calc(var(--label-w, 12.5rem) + var(--row-gap, 1.25rem)); }
  .form-rows fieldset.checks > legend {
    float: left; width: var(--label-w, 12.5rem); margin-left: calc(-1 * (var(--label-w, 12.5rem) + var(--row-gap, 1.25rem))); padding: 0;
  }
  .form-rows :is(.grid-2, .grid-3) { grid-template-columns: minmax(0, 1fr); }
  .form-rows :is(.inline-fields, td, .filter-grid) .field { display: block; }
  .form-rows :is(.inline-fields, td, .filter-grid) .field > label { padding-top: 0; margin-bottom: .25rem; }
  .form-rows .form-indent { padding-left: calc(var(--label-w, 12.5rem) + var(--row-gap, 1.25rem)); }
  /* A note between rows lines up with the controls; a section's intro (right after its heading) doesn't. */
  :is(.form-rows, .form-rows :is(section, fieldset:not(.checks), .card, div:not(.field):not(.field-check))) > p.hint:not(h2 + *, h3 + *, legend + *) {
    padding-left: calc(var(--label-w, 12.5rem) + var(--row-gap, 1.25rem));
  }
}

/* ---- Form groups: the sections of one long form on one surface, divided, not a box each. ---- */
.form-groups { background: var(--paper); border: 1px solid var(--line); border-radius: var(--radius); padding: 0 var(--sp-5); margin-bottom: var(--sp-4); }
.form-groups > :is(section, .card, .form-group) {
  background: transparent; border: 0; border-top: 1px solid var(--line); border-radius: 0; box-shadow: none;
  margin: 0; padding: var(--sp-5) 0;
}
.form-groups > :is(section, .card, .form-group):first-of-type { border-top: 0; }
.form-groups > :is(section, .card, .form-group) > h2:first-child { margin: 0 0 var(--sp-3); font-size: var(--text-base); font-weight: 600; }
.form-groups > :is(.action-bar, .sticky-actions) { margin-inline: calc(-1 * var(--sp-5)); }
@media (max-width: 40rem) { .form-groups { padding: 0 var(--sp-4); } }

/* ---- The sticky action bar: the primary action of a long form stays in reach. ---------------- */
:root {
  --bar-bg: color-mix(in srgb, var(--paper) 88%, transparent);
  --bar-shadow: 0 -4px 16px rgb(20 18 16 / .06);
}
html:has(:is(.action-bar, .sticky-actions)) { scroll-padding-bottom: 6rem; }   /* WCAG 2.4.11 */
.action-bar, .sticky-actions {
  position: sticky; bottom: 0; z-index: 20; display: flex; flex-wrap: wrap; align-items: center;
  gap: var(--sp-2) var(--sp-3); margin: var(--sp-4) 0 0; padding: .625rem var(--sp-4);
  background: var(--bar-bg); border: 1px solid var(--line); border-bottom: 0; border-radius: var(--radius) var(--radius) 0 0;
  box-shadow: var(--bar-shadow); -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px);
}
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) { .action-bar, .sticky-actions { background: var(--paper); } }
.action-hint { color: var(--ink-muted); }
.card > :is(.action-bar, .sticky-actions) { margin-inline: -1.25rem; margin-bottom: -1.25rem; }
@media (max-width: 40rem) {
  .action-bar, .sticky-actions { margin-inline: calc(-1 * var(--sp-2)); padding: .6rem var(--sp-3); border-radius: 0; }
  :is(.card, .form-groups) > :is(.action-bar, .sticky-actions) { margin-inline: calc(-1 * var(--sp-4)); }
  .card > :is(.action-bar, .sticky-actions) { margin-bottom: -1rem; }
  :is(.action-bar, .sticky-actions) .btn-primary { flex: 1 1 auto; }
}

/* ---- Tables that become cards on a phone (class="table-cards" on the table) -------------------
   Each row is a card. Every cell carries its column name as <span class="tc-label">: hidden on wide
   screens (the table head says it), shown beside the value in a labelled card on a phone.
   Compact cards (add "tc-compact"): three or four short lines per row, laid out per table with
   grid-template-areas (admin.css); a cell's label stays for screen readers but is shown only when
   the cell has data-label-show (a bare number such as a balance); "c-sep" puts a "·" before a cell
   on the same line; "c-contents" lets a cell's own parts (title, meta line) take separate places.
   Screen readers: once a table is re-laid out as blocks, Safari/VoiceOver drops the table
   semantics (row and column headers aren't announced), which is why each cell names its column. */
.tc-label, .tc-unit { display: none; }
@media (max-width: 40rem) {
  .table-wrap:has(> table.table-cards) { background: transparent; border: 0; box-shadow: none; overflow: visible; max-height: none; }
  table.table-cards, table.table-cards tbody { display: block; }
  table.table-cards thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
  table.table-cards tr {
    display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: .3rem .75rem; margin: 0 0 .5rem; padding: .75rem .9rem;
    background: var(--paper); border: 1px solid var(--line); border-radius: var(--radius);
  }
  table.table-cards :is(th, td) { display: block; padding: 0; border: 0; text-align: left; }
  table.table-cards tbody tr:last-child > * { border-bottom: 0; }
  table.table-cards .tc-unit { display: inline; }

  /* Labelled cards: label on the left, value on the right, one line per cell. */
  table.table-cards:not(.tc-compact) :is(th, td) { grid-column: 1 / -1; }
  table.table-cards:not(.tc-compact) td:has(> .tc-label) { text-align: right; }
  table.table-cards:not(.tc-compact) .tc-label {
    display: block; float: left; margin-right: .75rem; text-align: left; color: var(--ink-muted); font-size: var(--text-xs); line-height: 1.9;
  }
  table.table-cards:not(.tc-compact) td:has(> .tc-label)::after { content: ""; display: block; clear: both; }

  /* Compact cards */
  table.tc-compact tr { column-gap: 0; row-gap: .15rem; padding: .6rem .8rem; margin-bottom: .4rem; align-items: baseline; }
  table.tc-compact .tc-label {
    display: inline; position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden;
    clip: rect(0 0 0 0); white-space: nowrap; border: 0;
  }
  table.tc-compact [data-label-show] .tc-label {
    position: static; width: auto; height: auto; margin: 0 .3rem 0 0; overflow: visible; clip: auto; white-space: normal;
    color: var(--ink-muted); font-size: var(--text-xs);
  }
  table.tc-compact .c-contents { display: contents; }
  table.tc-compact .c-contents > br, table.tc-compact .c-when > br { display: none; }
  table.tc-compact .c-sep::before { content: "\00B7"; content: "\00B7" / ""; margin: 0 .4rem; color: var(--ink-muted); }
  table.tc-compact .c-meta { color: var(--ink-muted); font-size: var(--text-xs); }
  table.tc-compact .c-none, table.tc-compact td.select-col:empty { display: none; }
  table.tc-compact :is(.c-end, .num) { text-align: right; justify-self: end; padding-left: .75rem; }
  table.tc-compact .c-title { font-weight: 600; min-width: 0; overflow-wrap: anywhere; }
}

/* A deployed test site taking pretend payments (base.html, CCR-D1): one quiet strip above everything. */
.site-test-strip { margin: 0; padding: .4rem 1rem; text-align: center; font-size: var(--text-sm); color: var(--warning-ink);
  background: var(--warning-bg); border-bottom: 1px dashed var(--warning-ink); }
@media print { .site-test-strip { display: none; } }
