/* Spectrum CrossCheck · components, v2.1 "Kochi, calm" (u3-foundation, 16 Oct 2026).
   Master's class contract (every class a template uses and every class JS builds or reads) wearing the v2.1 look, plus
   v2.1's shared pieces (glass, drawer, sheet, seg, tip, prog, fig, av, mtab, tabbar, chips, kv rows, dbig, cross).
   Status colour only through .is-<family> / the marks. No glow: no text-shadow (the map labels' halo lives in map.css),
   no blurred coloured box-shadow. The chart kit is in charts.css, the map in map.css. */

@layer components {

/* ============ 1. The money-status language: word + mark + colour, never colour alone ============
   <span class="status is-hold"><svg class="mark" aria-hidden="true"><use href="#m-hold"/></svg>Hold</span>
   Marks (sprite.svg): hold = red octagon, two bars · less = red octagon, a minus · check = amber diamond, a dark ? ·
   wait = blue clock · ok = green tick · paid = violet ₹ stamp · refused = graphite slashed disc · none = a small dot.
   --mf fill, --ms edge, --mg glyph; --tone word colour, --tone-bg tint, --tone-line tint edge, --tone-edge, --tone-ring. */
.mark { width: 16px; height: 16px; flex: none; overflow: visible; }
.mark--lg { width: 22px; height: 22px; }
.mark--xl { width: 30px; height: 30px; }
.is-hold, .is-less { --mf: var(--hold-fill); --ms: var(--hold-fill); --mg: var(--hold-on); --tone: var(--hold); --tone-bg: var(--hold-tint);
  --tone-line: var(--hold-line); --tone-edge: var(--hold-edge); --tone-fill: var(--hold-fill); --tone-ring: var(--hold-ring); }
.is-check   { --mf: var(--check-fill); --ms: var(--check-mark); --mg: var(--check-glyph); --tone: var(--check); --tone-bg: var(--check-tint);
  --tone-line: var(--check-line); --tone-edge: var(--check-edge); --tone-fill: var(--check-fill); --tone-ring: var(--check-ring); }
.is-wait    { --mf: none; --ms: var(--wait-fill); --mg: var(--wait-fill); --tone: var(--wait); --tone-bg: var(--wait-tint);
  --tone-line: var(--wait-line); --tone-edge: var(--wait-edge); --tone-fill: var(--wait-fill); --tone-ring: transparent; }
.is-ok      { --mf: none; --ms: var(--ok-mark); --mg: var(--ok-mark); --tone: var(--ok); --tone-bg: var(--ok-tint);
  --tone-line: var(--ok-line); --tone-edge: var(--ok-edge); --tone-fill: var(--lit); --tone-ring: transparent; }
.is-paid    { --mf: var(--paid-tint); --ms: var(--paid-fill); --mg: var(--paid); --tone: var(--paid); --tone-bg: var(--paid-tint);
  --tone-line: var(--paid-line); --tone-edge: var(--paid-edge); --tone-fill: var(--paid-fill); --tone-ring: transparent; }
.is-refused { --mf: var(--refused-fill); --ms: var(--refused-fill); --mg: var(--refused-on); --tone: var(--refused); --tone-bg: var(--refused-tint);
  --tone-line: var(--refused-line); --tone-edge: var(--refused-edge); --tone-fill: var(--refused-fill); --tone-ring: transparent; }
.is-none    { --mf: var(--ink-4); --ms: var(--ink-4); --mg: var(--ink-4); --tone: var(--ink-3); --tone-bg: var(--paper-2);
  --tone-line: var(--line-2); --tone-edge: var(--line-strong); --tone-fill: var(--ink-4); --tone-ring: transparent; }

/* the inline mark + word (v2.1 .st) */
.status, .st { display: inline-flex; align-items: center; gap: 6px; font-size: var(--t-meta); font-weight: 600; color: var(--tone, var(--ink));
  white-space: nowrap; line-height: 1.25; }
/* OK is the quietest: the green tick carries it, the word stays ink so a page of OKs stays calm */
.status.is-ok { color: var(--ink-2); }
.status.is-none { color: var(--ink-3); font-weight: 560; }
/* the chip (v2.1 .tag): a tinted 28 px rounded rectangle, for a word that must read across a room */
.status--chip, .tag { display: inline-flex; align-items: center; gap: 6px; min-height: 28px; padding: 0 10px 0 7px; border-radius: 9px;
  background: var(--tone-bg, var(--paper-3)); color: var(--tone, var(--ink)); font-size: 13.5px; font-weight: 640; white-space: nowrap; }
.status--chip.is-ok { color: var(--ok); }
.status--chip .mark, .tag .mark { width: 15px; height: 15px; }

/* the stamp (v2.1): a bordered, turned word with a small signature line. Paid in violet; "Not paying" in red ink. */
.stamp { display: inline-flex; align-items: center; gap: 6px; padding: 4px 10px 3px; border: 2.5px solid var(--paid-fill); border-radius: 10px;
  color: var(--paid); font-weight: 760; letter-spacing: .07em; text-transform: uppercase; font-size: 13px; line-height: 1.15;
  transform: rotate(-6deg); background: color-mix(in srgb, var(--paper) 86%, transparent); }
.stamp:has(small) { flex-direction: column; gap: 0; }
.stamp small { display: block; font-size: 10.5px; letter-spacing: .04em; font-weight: 640; text-transform: none; }
.stamp.is-hold, .stamp.is-less { border-color: var(--hold-fill); color: var(--hold); }
.stamp.is-ok { border-color: var(--ink-2); color: var(--ink); }
.stamp .mark { width: 15px; height: 15px; }
.stamp.is-landing { animation: stamp-land var(--dur-3) var(--ease-stamp) both; }
@keyframes stamp-land { 0% { opacity: 0; transform: rotate(-16deg) scale(1.8); } 100% { opacity: 1; transform: rotate(-6deg) scale(1); } }

/* ============ 2. Money: Mona Sans set wide, a small raised ₹ ============ */
.money, .amt { font-variant-numeric: var(--num); white-space: nowrap; font-weight: 600; font-stretch: 104%; letter-spacing: -.004em; }
.money--lg { font-size: var(--t-figure); font-weight: 620; font-stretch: 112%; letter-spacing: -.022em; line-height: 1.05; }
.money--xl { font-size: var(--t-figure-xl); font-weight: 620; font-stretch: 112%; letter-spacing: -.03em; line-height: 1; }
.money .rs { font-weight: 560; margin-right: .04em; }
.money--lg .rs, .money--xl .rs { font-size: .74em; vertical-align: .22em; opacity: .85; letter-spacing: 0; }
.money .p { font-size: .78em; color: var(--ink-3); }                /* paisa, only when not zero */
.money.is-tone { color: var(--tone); }
/* the hero figure (v2.1 .fig, {% fig %}) */
.fig { font-weight: 620; font-stretch: 112%; letter-spacing: -.03em; line-height: 1; font-variant-numeric: proportional-nums lining-nums; white-space: nowrap; }
.fig .rs { font-size: .74em; font-weight: 560; vertical-align: .22em; margin-right: .04em; letter-spacing: 0; opacity: .85; }
.fig .p { font-size: .5em; letter-spacing: 0; color: var(--ink-3); }
.fig s { font-size: .42em; color: var(--ink-3); font-weight: 500; letter-spacing: 0; margin-left: 8px; vertical-align: .55em; }
.fig-xl { font-size: 54px; } .fig-l { font-size: 40px; } .fig-m { font-size: 26px; letter-spacing: -.022em; } .fig-s { font-size: 19px; letter-spacing: -.012em; }

/* v2.1's type classes (a lane's page may use them; sentence case always) */
.head-xl { font-size: var(--t-head-xl); line-height: 1.12; font-weight: 610; font-stretch: 104%; letter-spacing: -.026em; text-wrap: balance; }
.head-l { font-size: 30px; line-height: 1.15; font-weight: 610; font-stretch: 104%; letter-spacing: -.022em; text-wrap: balance; }
.head-xl .mute, .head-l .mute { color: var(--ink-3); font-weight: 560; }
.title { font-size: 17px; line-height: 1.3; font-weight: 620; letter-spacing: -.008em; }
.meta { font-size: 13px; color: var(--ink-3); }
.micro { font-size: 12px; color: var(--ink-3); }

/* ============ 3. Buttons (ink primary, white secondary, quiet text; never status-coloured; no pills) ============ */
.btn { display: inline-flex; align-items: center; justify-content: center; gap: var(--sp-2); min-height: var(--h-button); padding: 0 18px;
  border: 0; border-radius: var(--r-2); background: var(--paper); color: var(--ink); box-shadow: var(--sh-1), var(--hi);
  font-weight: 580; font-size: 14.5px; line-height: 1.2; letter-spacing: -.003em; text-decoration: none; white-space: nowrap; user-select: none;
  transition: transform var(--dur-1) var(--ease-out), box-shadow var(--dur-2) var(--ease-out), background-color var(--dur-2) linear, color var(--dur-2) linear; }
.btn:hover { box-shadow: var(--sh-2), var(--hi); }
.btn:active { transform: scale(.975); box-shadow: var(--sh-press); }
.btn--primary, .btn-primary { background: var(--ink); color: var(--on-ink); box-shadow: var(--sh-btn); }
.btn--primary:hover, .btn-primary:hover { background: var(--ink); box-shadow: var(--sh-btn-hover); }
.btn--primary .icon:last-child, .btn-primary .icon:last-child, .btn .arr { transition: transform var(--dur-2) var(--ease-out); }
.btn--primary:hover .icon:last-child:not(:first-child), .btn-primary:hover .icon:last-child:not(:first-child), .btn:hover .arr { transform: translateX(3px); }
.btn--quiet { background: transparent; box-shadow: none; color: var(--ink-2); padding: 0 10px; min-height: 36px;
  text-decoration: underline; text-underline-offset: .2em; text-decoration-color: var(--line-3); }
.btn--quiet:hover { background: var(--paper-3); color: var(--ink); box-shadow: none; text-decoration-color: currentColor; }
.btn--sm { min-height: 32px; padding: 0 12px; font-size: var(--t-meta); border-radius: 9px; }
.btn--lg, .btn-l { min-height: 50px; padding: 0 22px; font-size: 16px; border-radius: 14px; }
.btn-xl { min-height: 54px; border-radius: 16px; font-size: 16px; }
.btn--block { display: flex; width: 100%; }
/* a disabled primary is a quiet paper-3 button, with its reason beside it */
.btn[disabled], .btn[aria-disabled="true"] { cursor: not-allowed; transform: none; background: var(--paper-3); color: var(--ink-3);
  box-shadow: inset 0 0 0 1px var(--line-2); }
.btn .kbd-hint { margin-left: var(--sp-1); }
.btn .icon { width: 18px; height: 18px; }
/* a staff button (.btn--bi, the name kept for the hooks): one line of English (UI v2.1 wave 4), wrapping when it must */
.btn--bi { flex-direction: column; gap: 0; padding: var(--sp-2) var(--sp-4); line-height: 1.25; white-space: normal; text-align: center; }
.btn--bi .en { font: inherit; }
/* an icon-only button, and v2.1's quiet text link with an arrow */
.iconbtn { width: 38px; height: 38px; border-radius: 12px; display: inline-grid; place-items: center; color: var(--ink-2); background: none; border: 0;
  transition: background-color var(--dur-1) linear, color var(--dur-1) linear, transform var(--dur-1) var(--ease-out); }
.iconbtn:hover { background: var(--paper-3); color: var(--ink); }
.iconbtn:active { transform: scale(.94); }
.iconbtn .icon { width: 20px; height: 20px; }
.link { color: var(--ink-2); font-weight: 560; font-size: 14px; display: inline-flex; align-items: center; gap: 6px; text-decoration: none; }
.link:hover { color: var(--ink); }
.link .icon { width: 15px; height: 15px; transition: transform var(--dur-2) var(--ease-out); }
.link:hover .icon:last-child { transform: translateX(3px); }

/* ============ 4. The desk shell: the glass top bar, the sections, the find box, the account ============ */
/* glass: the top bar, the map's controls and legend, Daniel's tab bar. The blur sits on a layer behind the content, so a
   fixed child (the find palette) still measures from the window. */
.glass { position: relative; background: var(--glass); box-shadow: var(--sh-2), var(--hi); }
.glass::before { content: ""; position: absolute; inset: 0; z-index: -1; border-radius: inherit; pointer-events: none;
  -webkit-backdrop-filter: blur(18px) saturate(1.35); backdrop-filter: blur(18px) saturate(1.35); }
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) { .glass { background: var(--glass-strong); } }

.bar, .topbar { position: sticky; top: 14px; z-index: var(--z-bar); display: flex; align-items: center; gap: 18px; height: 58px;
  margin: 14px 16px 0; padding: 0 10px 0 16px; border-radius: 18px; isolation: isolate; }
.logo, .brand { display: inline-flex; align-items: center; gap: 10px; color: var(--ink); text-decoration: none; flex: none; white-space: nowrap; min-height: 40px; }
.logo svg, .brand svg { width: 22px; height: 22px; }
.logo b, .brand b, .logo { font-size: 16.5px; font-weight: 660; letter-spacing: -.012em; }
.logo small, .brand small { font-size: 14px; font-weight: 460; color: var(--ink-3); letter-spacing: 0; }
.nav { display: flex; align-items: center; gap: 2px; margin-left: 8px; }
.nav a { position: relative; height: 38px; display: inline-flex; align-items: center; gap: 7px; padding: 0 13px; border-radius: 11px;
  color: var(--ink-2); text-decoration: none; font-size: 14.5px; font-weight: 540; white-space: nowrap;
  transition: background-color var(--dur-1) linear, color var(--dur-1) linear; }
.nav a:hover { background: var(--hover-ink); color: var(--ink); }
.nav a[aria-current="page"], .nav a[aria-current="true"] { color: var(--ink); background: var(--paper); box-shadow: var(--sh-1); }
/* the section dot: something in that section is the viewer's next step (7 px amber; no number badge) */
.nav .dot, .mtab .dot { width: 7px; height: 7px; border-radius: 50%; background: var(--check-fill); box-shadow: 0 0 0 2px var(--paper); flex: none; }
/* the dot sits beside the section's link (the link's own markup stays exactly <a href aria-current>Label</a>) */
.nav > .dot { position: relative; z-index: 1; margin: 0 15px 0 -24px; pointer-events: none; }   /* net -2 px, its own flex gap: the next link keeps its usual place */
.nav a:has(+ .dot) { padding-right: 27px; }
.nav .count { min-width: 20px; height: 18px; padding: 0 6px; border-radius: 9px; background: var(--ink); color: var(--on-ink); font-size: 11.5px; font-weight: 700;
  display: inline-grid; place-items: center; }
.bar-gap { flex: 1 1 auto; }
/* the date and time from the server (ui.js moves it each minute) */
.bar-when { font-size: 14px; font-weight: 520; color: var(--ink-2); padding: 0 10px; white-space: nowrap; font-variant-numeric: proportional-nums; }

/* the find box as v2.1's search pill ("/" keycap); focused, it becomes the centred palette with a scrim (below, §19) */
.search { display: flex; align-items: center; gap: 9px; flex: 0 1 272px; width: 272px; min-width: 0; height: 40px; padding: 0 8px 0 13px; border-radius: 12px;
  color: var(--ink-3); font-size: 14px; background: var(--hover-ink); box-shadow: inset 0 0 0 1px var(--line);
  transition: background-color var(--dur-1) linear, box-shadow var(--dur-1) linear; text-align: left; }
.search:hover { background: var(--hover-ink-2); }
.search svg { width: 17px; height: 17px; flex: none; }
.search kbd { margin-left: auto; }

/* the account: the avatar opens the menu (v2.1 .av, soft tints) */
.me { display: inline-flex; align-items: center; gap: 8px; font-size: var(--t-small); font-weight: 600; color: var(--ink-2); flex: none; }
.me .avatar, .av { --av-b: var(--av-bg); --av-i: var(--av-ink); width: 36px; height: 36px; border-radius: 50%; display: inline-grid; place-items: center; flex: none;
  font-size: 14px; font-weight: 650; background: var(--av-b); color: var(--av-i); box-shadow: inset 0 0 0 1px var(--line); }
.av { width: 28px; height: 28px; font-size: 12.5px; }
.av.s { --av-b: var(--av-s-bg); --av-i: var(--av-s-ink); } .av.a { --av-b: var(--av-a-bg); --av-i: var(--av-a-ink); } .av.d { --av-b: var(--av-bg); --av-i: var(--av-ink); }
.av-l { width: 36px; height: 36px; font-size: 14px; }

/* the page column */
.page { max-width: 1376px; margin: 0 auto; padding: 28px 32px var(--sp-9); }
.page-head { display: flex; align-items: flex-end; justify-content: space-between; gap: var(--sp-5); margin-bottom: var(--sp-5); }
.page-head .sub { margin-top: 6px; color: var(--ink-2); font-size: var(--t-body); }
.crumbs, .eyebrow { font-size: 13px; font-weight: 520; color: var(--ink-3); margin-bottom: 10px; letter-spacing: .005em; }
.crumbs a { color: inherit; display: inline-flex; align-items: center; min-height: var(--target); text-decoration: none; }
.crumbs a:hover { color: var(--ink); text-decoration: underline; }
/* the section's tabs: a quiet row under the bar (the current one = paper + a hairline shadow) */
.tabs { display: flex; gap: 2px; margin-bottom: var(--sp-4); }
.tabs a { display: inline-flex; align-items: center; min-height: 34px; padding: 0 12px; border-radius: 10px; color: var(--ink-3); text-decoration: none;
  font-weight: 540; font-size: 14px; white-space: nowrap; transition: background-color var(--dur-1) linear, color var(--dur-1) linear; }
.tabs a:hover { color: var(--ink); background: var(--hover-ink); }
.tabs a[aria-current="page"] { color: var(--ink); background: var(--paper); box-shadow: var(--sh-1); }

/* ============ 5. Cards and panels: paper, radius 20, the layered shadow; a status shows as a mark in the head ============ */
.panel { background: var(--paper); border-radius: var(--r-4); box-shadow: var(--sh-2); }
.panel-head { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3); padding: 16px 20px 12px; border-bottom: 1px solid var(--line); }
.panel-head h2, .panel-head h3 { font-size: 15.5px; font-weight: 640; }
.panel-body { padding: 16px 20px 20px; }
.label { font-size: 13px; font-weight: 560; color: var(--ink-3); }      /* sentence case; never all caps, never monospace */
.card { position: relative; background: var(--paper); border-radius: var(--r-4); padding: 20px 22px; box-shadow: var(--sh-2); }
/* a card that needs a person wears a crisp ring in its family's colour (no tinted slab, no edge bar) */
.card.is-hold, .card.is-less, .card.is-check { box-shadow: 0 0 0 1.5px var(--tone-ring), var(--sh-2); }

/* ============ 6. The worklist rows (v2.1's list rows: mark · title and one small line · amount · chevron or action) ============ */
.work { background: var(--paper); border-radius: var(--r-4); box-shadow: var(--sh-2); overflow: hidden; container: work / inline-size; }
.work-group { display: flex; align-items: baseline; gap: 10px; padding: 18px 20px 8px; border-top: 1px solid var(--line); }
.work-group:first-child { border-top: 0; }
.work-group h2 { font-size: 15.5px; font-weight: 640; color: var(--ink); letter-spacing: -.006em; }
.work-group .when { font-size: 13.5px; color: var(--ink-3); font-weight: 520; padding: 0; }
.work-group .due { margin-left: auto; }
.work-item { display: grid; grid-template-columns: 92px minmax(0, 1fr) 120px 184px; align-items: center; gap: 14px; min-height: 64px;
  padding: 13px 18px 13px 20px; border-top: 1px solid var(--line); position: relative; transition: background-color var(--dur-1) linear; }
.work-item:hover { background: var(--paper-2); }
.work-item[aria-current="true"] { background: var(--paper-2); }
.work-item[aria-current="true"]::before { content: ""; position: absolute; left: 0; top: 10px; bottom: 10px; width: 3px; border-radius: 0 3px 3px 0; background: var(--ink); }
.work-item .margin { align-self: start; padding-top: 2px; }
.work-item .margin .status { white-space: normal; align-items: flex-start; }   /* a long word wraps inside the margin, never into the title */
.work-item .what { min-width: 0; }
.work-item .what h3 { font-size: 15px; font-weight: 600; line-height: 1.3; letter-spacing: -.004em; font-stretch: 100%; }
.work-item .what p { margin-top: 2px; font-size: 13.5px; color: var(--ink-3); line-height: 1.4; }
.work-item .what p .sep { color: var(--ink-4); padding: 0 .3em; }
.work-item .amt { text-align: right; font-size: 15.5px; }
.work-item .amt small { display: block; color: var(--ink-3); font-size: var(--t-micro); font-weight: 500; margin-top: 1px; }
.work-item .act { display: flex; justify-content: flex-end; gap: var(--sp-2); flex-wrap: wrap; }
.work-item .act .why-not { display: block; margin-top: 4px; font-size: var(--t-micro); color: var(--ink-3); text-align: right; }
.work-item.is-leaving { animation: leave var(--dur-3) var(--ease-in) forwards; }
@keyframes leave { 0% { opacity: 1; transform: none; } 40% { opacity: 0; transform: translateX(24px); } 100% { opacity: 0; transform: translateX(24px); max-height: 0; min-height: 0; padding-block: 0; border-width: 0; } }
@container work (max-width: 760px) {
  .work-item { grid-template-columns: 84px minmax(0, 1fr) auto; grid-template-areas: "m w w" "m a b"; row-gap: var(--sp-2); }
  .work-item .margin { grid-area: m; } .work-item .what { grid-area: w; } .work-item .amt { grid-area: a; text-align: left; } .work-item .act { grid-area: b; }
}
@container work (max-width: 480px) {
  .work-item { grid-template-columns: minmax(0, 1fr) auto; grid-template-areas: "m m" "w w" "a b"; }
}
.work-foot { display: flex; align-items: center; gap: var(--sp-4); padding: 12px 20px; border-top: 1px solid var(--line); color: var(--ink-3); font-size: var(--t-meta); }

/* a due line: time is neutral ink; the urgency comes from the item's own status (v2.1: amber words with the clock) */
.due { display: inline-flex; align-items: center; gap: 6px; font-size: 13px; font-weight: 560; color: var(--ink-2); white-space: nowrap; }
.due svg { width: 14px; height: 14px; }
.due--soon { color: var(--check); }

/* the drop zone: paper-2 with a quiet edge, the upload icon, one line */
.drop { display: flex; align-items: center; gap: var(--sp-3); padding: 14px 16px; border: 1.5px dashed var(--line-strong); border-radius: var(--r-3);
  color: var(--ink-2); font-size: var(--t-small); background: var(--paper-2); transition: background-color var(--dur-1) linear, border-color var(--dur-1) linear; }
.drop svg { width: 20px; height: 20px; color: var(--ink-3); flex: none; }
.drop.is-over, .drop.active { border-color: var(--ink); background: var(--paper); color: var(--ink); }

/* ============ 7. The one progress component (v2.1 .prog): 4 px bars, done = ink-2, now = half lit with a dot,
   labels and small subs under. {% prog %} draws it; .run (ui/c/run.html), .steps (ui/c/steps.html) and the staff
   .progress (ui/c/_progress.html) keep their markup and wear the same look. ============ */
.prog { display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); gap: 6px; margin: 0; padding: 0; list-style: none; }
.prog li { position: relative; min-width: 0; font-size: 12.5px; font-weight: 540; color: var(--ink-3); }
.prog .pb { position: relative; display: block; height: 4px; border-radius: 2px; background: var(--line-2); margin-bottom: 9px; }
.prog li.done .pb { background: var(--ink-2); }
.prog li.now .pb { background: linear-gradient(90deg, var(--lit) 0 50%, var(--line-2) 50%); }
.prog li.now .pb::after { content: ""; position: absolute; left: calc(50% - 5px); top: -3px; width: 10px; height: 10px; border-radius: 50%; background: var(--lit);
  box-shadow: 0 0 0 3px var(--paper); }
.prog li.now { color: var(--ink); font-weight: 650; }
.prog .pl { display: block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.prog small { display: block; font-size: 11.5px; font-weight: 470; color: var(--ink-3); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* the run (ol.run > li.run-step: .run-dot, .t, .d): the same bars; the dot's ✓ / number is for the eye only, so it rests */
.run { display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); gap: 6px; margin: 0; padding: 0; list-style: none; }
.run-step { position: relative; min-width: 0; padding-top: 13px; font-size: 12.5px; font-weight: 540; color: var(--ink-3); }
.run-step::before { content: ""; position: absolute; left: 0; right: 0; top: 0; height: 4px; border-radius: 2px; background: var(--line-2); }
.run-step.is-done::before { background: var(--ink-2); }
.run-step.is-now::before { background: linear-gradient(90deg, var(--lit) 0 50%, var(--line-2) 50%); }
.run-step.is-now::after { content: ""; position: absolute; left: calc(50% - 5px); top: -3px; width: 10px; height: 10px; border-radius: 50%; background: var(--lit);
  box-shadow: 0 0 0 3px var(--paper); }
.run-dot { display: none; }
.run-step .t { display: block; font-weight: inherit; font-size: inherit; line-height: 1.3; color: inherit; }
.run-step.is-now .t { color: var(--ink); font-weight: 650; }
.run-step .d { display: block; color: var(--ink-3); font-size: 11.5px; font-weight: 470; margin-top: 1px; line-height: 1.3; }
@media (max-width: 700px) { .run-step, .prog li { font-size: 11px; } .run-step .d { font-size: 11px; } }

/* Daniel's steps (ol.steps > li "1 · Decide"): three bars */
.steps { display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); gap: 6px; margin: 0; padding: 0; list-style: none; }
.steps li { position: relative; display: flex; flex-direction: column; gap: 9px; font-size: 12.5px; font-weight: 540; color: var(--ink-3); }
.steps li::before { content: ""; height: 4px; border-radius: 2px; background: var(--line-2); transition: background-color var(--dur-3) var(--ease-out); }
.steps li.is-done { color: var(--ink-2); } .steps li.is-done::before { background: var(--ink-2); }
.steps li.is-now { color: var(--ink); font-weight: 650; } .steps li.is-now::before { background: linear-gradient(90deg, var(--lit) 0 50%, var(--line-2) 50%); }
.steps li.is-now::after { content: ""; position: absolute; left: calc(50% - 5px); top: -3px; width: 10px; height: 10px; border-radius: 50%; background: var(--lit);
  box-shadow: 0 0 0 3px var(--paper); }

/* ============ 8. Tables (v2.1 .otab): quiet heads, hairlines, hover paper-2; the totals as statement figures ============
   Child combinators only: a proof table inside a cell keeps its own look. Rows align to their first line. */
.ledger { width: 100%; background: var(--paper); font-size: 14.5px; border-collapse: separate; border-spacing: 0; }
.ledger > thead > tr > th { position: sticky; top: 76px; z-index: 1; background: var(--paper); color: var(--ink-2); font-size: 12.5px; font-weight: 600;
  padding: 14px 14px 10px; border-bottom: 1px solid var(--line-2); white-space: nowrap; text-align: left; vertical-align: bottom; }
.ledger > thead > tr > th.n { text-align: right; }
.ledger > tbody > tr > td { padding: 11px 14px; border-top: 1px solid var(--line); vertical-align: top; line-height: 20px; }
.ledger > tbody > tr:first-child > td { border-top: 0; }
.ledger > tbody > tr > td.n { text-align: right; }
.ledger > tbody > tr > td.mk { width: 104px; }
.ledger > tbody > tr > td.act { white-space: nowrap; }
.ledger .sub { display: block; color: var(--ink-3); font-size: var(--t-micro); line-height: 1.35; }
.ledger > tbody > tr:hover > td { background: var(--paper-2); }
.ledger > tbody > tr.group > td { padding-block: 16px 6px; background: var(--paper); font-weight: 640; font-size: 13.5px; color: var(--ink-2); vertical-align: bottom; }
.ledger > tbody > tr.group .muted { font-weight: 500; }
.ledger > tbody > tr[aria-current="true"] > td { background: var(--paper-2); }
.ledger > tbody > tr[aria-current="true"] > td:first-child { box-shadow: inset var(--edge) 0 0 var(--ink); }
.ledger > tfoot > tr > td { padding: 11px 14px; font-weight: 620; border-top: 1px solid var(--line-2); }

/* the totals strip: the head of a check or a board, as statement figures (one figure per family, its mark beside the word) */
.totals { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)) auto; background: var(--paper); border-radius: var(--r-4); box-shadow: var(--sh-2);
  margin-bottom: var(--sp-5); overflow: hidden; }
.total { padding: 18px 20px 16px; border-left: 1px solid var(--line); min-width: 0; }
.total:first-child { border-left: 0; }
.total .k { display: flex; align-items: center; gap: 6px; font-size: 13px; font-weight: 560; color: var(--ink-2); }
.total .money { display: block; margin-top: 8px; font-size: 26px; font-weight: 620; font-stretch: 112%; letter-spacing: -.022em; line-height: 1.05; }
.total small { display: block; margin-top: 6px; color: var(--ink-3); font-size: 12.5px; }
.total.is-hold .k, .total.is-less .k { color: var(--hold); }
.total.is-check .k { color: var(--check); }
.total-act { display: flex; flex-direction: column; justify-content: center; align-items: flex-end; gap: 6px; padding: 16px 20px; border-left: 1px solid var(--line); }
.total-act small { color: var(--ink-3); font-size: var(--t-micro); }
@media (max-width: 700px) {
  .totals { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .total { border-left: 0; border-top: 1px solid var(--line); }
  .total:nth-child(-n+2) { border-top: 0; }
  .total:nth-child(even) { border-left: 1px solid var(--line); }
  .total-act { grid-column: 1 / -1; border-left: 0; border-top: 1px solid var(--line); align-items: stretch; }
}
/* a ledger in its panel */
.table-panel { background: var(--paper); border-radius: var(--r-4); box-shadow: var(--sh-2); overflow: clip; }
.ledger td .ev { margin-top: 2px; color: var(--ink-2); font-size: var(--t-meta); }
/* proof: folded under the reason, opened in place */
.proof-toggle { display: inline; }
.proof-toggle[open] { display: block; }
.proof-toggle summary { display: inline; cursor: pointer; font-size: var(--t-meta); font-weight: 600; color: var(--ink-2); text-decoration: underline;
  text-decoration-color: var(--line-3); text-underline-offset: .2em; margin-left: 6px; }
.proof-toggle[open] summary { margin-bottom: 4px; }
.proof-toggle p { margin-top: 4px; font-size: var(--t-meta); color: var(--ink-2); }
table.mini { width: auto; margin: 6px 0 2px; font-size: var(--t-meta); background: var(--paper); border-radius: 12px; box-shadow: var(--sh-1);
  border-collapse: separate; border-spacing: 0; overflow: hidden; }
table.mini th, table.mini td { padding: 6px 12px; border-bottom: 1px solid var(--line); white-space: nowrap; line-height: 1.4; }
table.mini td.n, table.mini th.n { text-align: right; }
table.mini th { color: var(--ink-3); font-weight: 600; background: var(--paper-2); }
table.mini tr:last-child td { border-bottom: 0; }
table.mini tr.is-hold td { color: var(--hold); font-weight: 600; }
table.mini tr.is-total td { font-weight: 640; }
table.mini .status { font-size: var(--t-meta); }
/* options: pick one of the ways the app found (a radio card each) */
.opts { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin-top: var(--sp-2); }
.opt { display: grid; grid-template-columns: auto 1fr auto; gap: 2px var(--sp-2); align-items: center; padding: 10px 14px; border-radius: 14px;
  background: var(--paper-2); box-shadow: inset 0 0 0 1px var(--line-strong); font-size: var(--t-meta); min-width: 300px; white-space: nowrap; cursor: pointer;
  transition: box-shadow var(--dur-1) linear, background-color var(--dur-1) linear; }
.opt:has(input:checked) { background: var(--paper); box-shadow: inset 0 0 0 2px var(--ink); }
.opt .money { font-weight: 640; }
.opt .tag { grid-column: 2 / 4; color: var(--ink-3); font-size: var(--t-micro); background: none; min-height: 0; padding: 0; font-weight: 500; }
/* an inline form inside a row: one select or input and its button */
.inline-form { display: flex; gap: var(--sp-2); align-items: center; margin-top: var(--sp-2); max-width: 640px; }
.inline-form select, .inline-form input { min-height: 36px; font-size: var(--t-small); }

/* ============ 9. The decision card (Daniel's deck card, v2.1 .dcard): one decision per card ============ */
.decision { padding: 18px; border-radius: var(--r-5); box-shadow: var(--sh-3); }
.decision.is-hold, .decision.is-less, .decision.is-check { box-shadow: var(--sh-3); }
.decision .top { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3); flex-wrap: wrap; }
.decision .top .money--lg { font-size: 46px; font-weight: 620; font-stretch: 112%; letter-spacing: -.03em; }
.decision h3 { font-size: 17px; font-weight: 620; margin-top: 14px; line-height: 1.3; letter-spacing: -.008em; }
.decision .why { margin-top: 10px; color: var(--ink-2); font-size: 15.5px; line-height: 1.45; }
.decision details { margin-top: 14px; }
.decision summary { display: flex; align-items: center; gap: 10px; min-height: 44px; padding: 10px 14px; border-radius: 15px; background: var(--paper-2);
  box-shadow: inset 0 0 0 1px var(--line); font-size: 14px; font-weight: 560; color: var(--ink-2); cursor: pointer; list-style: none; }
.decision summary::-webkit-details-marker { display: none; }
.decision summary:hover { background: var(--paper-3); }
.decision .choices { display: grid; grid-template-columns: 1.1fr 1fr; gap: 10px; margin-top: 16px; }
.decision .choices.three { grid-template-columns: 1fr 1fr 1fr; }
.decision .choices .btn { min-height: 54px; border-radius: 16px; font-size: 16px; white-space: normal; text-align: center; line-height: 1.2; padding-inline: 12px; }
.decision .choices.three .btn { font-size: var(--t-small); min-height: 48px; }
.decision.is-decided { padding-block: 14px; box-shadow: var(--sh-1); }
.decision .signed { margin-top: var(--sp-2); font-size: var(--t-meta); color: var(--ink-2); }

/* ============ 10. The owner shell (Daniel's phone, centred on a laptop) ============ */
.ph { max-width: 560px; margin: 0 auto; min-height: 100dvh; display: flex; flex-direction: column; }
.ph-head { display: flex; align-items: center; gap: 4px; min-height: 64px; padding: 14px var(--gutter) 6px; }
.ph-back { text-decoration: none; padding-left: 6px; margin-left: -8px; gap: 2px; }
.ph-head .when, .ph-head .ph-heading { flex: 1 1 auto; min-width: 0; font-size: 16px; font-weight: 640; letter-spacing: -.008em; color: var(--ink);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; padding: 0 8px; }
.ph-body { flex: 1 0 auto; padding: var(--sp-3) var(--gutter) var(--sp-7); display: flex; flex-direction: column; gap: var(--sp-4); }
.ph-lead { font-size: var(--t-h1); font-weight: 660; letter-spacing: -.026em; line-height: 1.1; font-stretch: 104%; }
.ph-lead .muted { font-weight: 560; }
.section-title { display: flex; align-items: baseline; justify-content: space-between; gap: var(--sp-3); font-size: 15.5px; font-weight: 640; color: var(--ink);
  margin: var(--sp-3) 4px calc(-1 * var(--sp-1)); letter-spacing: -.006em; }
.section-title a { font-weight: 560; font-size: var(--t-meta); color: var(--ink-2); }
.figs { display: grid; grid-template-columns: 1fr auto; align-items: end; gap: var(--sp-1) var(--sp-3); }
.figs .k { color: var(--ink-3); font-size: var(--t-meta); font-weight: 560; }
/* the outlets board: one row per outlet, the mark in the margin */
.board { background: var(--paper); border-radius: var(--r-4); box-shadow: var(--sh-2); overflow: hidden; }
.board-row { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: var(--sp-3); min-height: 52px; padding: 12px 16px;
  border-top: 1px solid var(--line); text-decoration: none; color: var(--ink); transition: background-color var(--dur-1) linear; }
.board-row:first-child { border-top: 0; }
a.board-row:hover { background: var(--paper-2); }
.board-row .name { font-weight: 600; font-size: 15px; }
.board-row .name small { display: block; font-weight: 450; color: var(--ink-3); font-size: 13px; margin-top: 1px; }
.board-row .right { display: flex; align-items: center; gap: var(--sp-3); }

/* Daniel's floating tab bar (links only): glass, at the bottom of his column */
.tabbar { position: sticky; bottom: 0; z-index: var(--z-tabbar); padding: 18px 12px calc(10px + env(safe-area-inset-bottom));
  background: linear-gradient(180deg, rgba(var(--wash), 0) 0, var(--canvas) 22px); }
.tabbar nav { display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); height: 64px; border-radius: 22px; padding: 6px; background: var(--glass-strong); }
.tabbar a, .mtab a { position: relative; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 3px; border-radius: 16px;
  font-size: 11.5px; font-weight: 580; color: var(--ink-3); text-decoration: none; transition: background-color var(--dur-1) linear, color var(--dur-1) linear; }
.tabbar a .icon, .mtab a .icon { width: 21px; height: 21px; }
.tabbar a:hover, .mtab a:hover { color: var(--ink); }
.tabbar a[aria-current="page"], .tabbar a[aria-current="true"], .mtab a[aria-current="page"], .mtab a[aria-current="true"] { color: var(--ink); background: var(--paper); box-shadow: var(--sh-1); }
.tabbar .bdg { position: absolute; top: 5px; left: calc(50% + 6px); min-width: 18px; height: 18px; padding: 0 5px; border-radius: 9px; background: var(--ink); color: var(--on-ink);
  font-size: 11px; font-weight: 700; display: grid; place-items: center; box-shadow: 0 0 0 2px var(--paper); }
/* the desk's bottom tab bar under 760 px (Overview · Payments · Cash · Outlets; the account menu lists the rest) */
.mtab { display: none; }

/* ============ 11. Fields: 40 px desk / 48 px phone, an edge that reads (3:1), the ring in ink ============ */
.field { display: flex; flex-direction: column; gap: 6px; }
.field-h { display: flex; align-items: center; gap: 4px; }   /* a field label with its "i" hint beside it */
.field > label, .field > .field-h > label, .field > .label-text { font-size: 13px; font-weight: 560; color: var(--ink-2); }
.field .hint { font-size: var(--t-meta); color: var(--ink-3); }
.field .hint > span { display: block; }
.field .error { display: flex; gap: 6px; align-items: flex-start; font-size: var(--t-meta); font-weight: 600; color: var(--hold); }
.field.has-error input, .field.has-error textarea, .field.has-error select { border-color: var(--hold-fill); box-shadow: 0 0 0 1px var(--hold-fill); }

/* ============ 12. Notes, empty, waiting, refusal, toast ============ */
.note { display: flex; gap: 12px; align-items: flex-start; padding: 14px 16px; border-radius: 14px; background: var(--paper-2); font-size: 14px; color: var(--ink-2);
  box-shadow: inset 0 0 0 1px var(--line); }
.note[class*="is-"] { color: var(--ink); }
.note.is-hold, .note.is-less { background: var(--hold-tint); box-shadow: none; }
.note.is-check { background: var(--check-tint); box-shadow: none; }
.note .mark { margin-top: 2px; }
.empty { padding: var(--sp-8) var(--sp-5); text-align: center; color: var(--ink-2); font-size: var(--t-body); }
.empty .mark { margin: 0 auto var(--sp-3); width: 28px; height: 28px; }
.empty p + p { margin-top: 6px; color: var(--ink-3); font-size: var(--t-small); }
.spin { animation: spin 1.4s linear infinite; transform-origin: 50% 50%; }
@keyframes spin { to { transform: rotate(360deg); } }
/* a toast confirms (never Undo on money): ui.js shows new notes from #messages here; app.js builds its own .toast */
.toasts { position: fixed; z-index: var(--z-toast); left: 50%; bottom: 24px; transform: translateX(-50%); display: grid; gap: 8px; width: max-content;
  max-width: calc(100vw - 32px); }
.toast { position: fixed; left: 50%; bottom: var(--sp-6); z-index: var(--z-toast); transform: translateX(-50%); display: flex; align-items: center; gap: 14px;
  padding: 11px 14px 11px 16px; border-radius: 14px; background: var(--toast-bg); color: var(--toast-ink); font-size: 14px; font-weight: 520;
  box-shadow: var(--sh-toast); animation: toast-in var(--dur-3) var(--ease-spring) both; }
.toasts > .toast { position: static; transform: none; }
.toast .mark { width: 18px; height: 18px; --ms: var(--toast-link); --mg: var(--toast-link); }
.toast a, .toast button { color: var(--toast-link); font-weight: 640; padding: 6px 8px; border-radius: 8px; text-decoration: none; background: none; border: 0;
  display: inline-flex; align-items: center; justify-content: center; min-height: 44px; min-width: 44px; margin-block: -8px; }   /* a thumb's width (WCAG 2.5.5) */
.toast a:hover, .toast button:hover { background: var(--toast-hover); }
.toast.is-out { animation: toast-out 260ms var(--ease-in-out) both; }
@keyframes toast-in { from { opacity: 0; transform: translate(-50%, 14px) scale(.96); } }
.toasts > .toast { animation-name: toast-in-static; }
@keyframes toast-in-static { from { opacity: 0; transform: translateY(14px) scale(.96); } }
@keyframes toast-out { to { opacity: 0; transform: translateY(8px) scale(.98); } }

/* ============ 13. Staff (phone; the look only in wave 1): solid surfaces, 48 px controls, big type ============ */
/* the staff header (v2.1): back, where in large type and who small under it, the "Saved" tick at the right. Solid canvas
   (no blur: cheap phones); the shell's own .ph-top (closes/phone/base.html, staff.css) wears the same look */
.close-head { position: sticky; top: 0; z-index: var(--z-bar); background: var(--canvas); padding: 10px var(--gutter) 12px;
  box-shadow: 0 1px 0 var(--line); }
.close-head .who { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: 2px var(--sp-3); min-height: 48px; }
.close-head.has-back .who { grid-template-columns: auto minmax(0, 1fr) auto; margin-left: -10px; }
.ch-back.iconbtn { width: 44px; height: 44px; color: var(--ink); }
.ch-back .icon { width: 24px; height: 24px; }
.ch-where { display: flex; flex-direction: column; min-width: 0; line-height: 1.25; }
.close-head .who .outlet { color: var(--ink); font-size: 18px; font-weight: 600; letter-spacing: -.01em; overflow-wrap: anywhere; }
.ch-who { font-size: 13px; font-weight: 500; color: var(--ink-3); overflow-wrap: anywhere; }
/* "Saved": the draft is on this phone. A tick and a word in green; never a button (no edge, no fill, not a target) */
.draft.is-chip { grid-column: -2; margin: 0; padding: 0 2px; gap: 5px; font-size: 13.5px; font-weight: 560; color: var(--ok); white-space: nowrap; }
.draft.is-chip .icon { width: 17px; height: 17px; }
/* v2.1's step names under the segments: done quiet, the current one in ink */
.stepnames { display: grid; grid-template-columns: repeat(var(--steps, 4), minmax(0, 1fr)); gap: 6px; margin: 8px 0 0; padding: 0; list-style: none;
  font-size: 12.5px; font-weight: 520; color: var(--ink-2); text-align: center; }
.stepnames li { min-width: 0; overflow-wrap: anywhere; line-height: 1.25; }
.stepnames li.is-done { color: var(--ink-3); }
.stepnames li.is-now { color: var(--ink); font-weight: 640; }
.progress { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 6px; margin-top: 12px; }
.progress i { position: relative; height: 4px; border-radius: 2px; background: var(--line-2); }
.progress i.is-done { background: var(--ink-2); }
.progress i.is-now { background: linear-gradient(90deg, var(--lit) 0 50%, var(--line-2) 50%); }
.progress i.is-now::after { content: ""; position: absolute; left: calc(50% - 5px); top: -3px; width: 10px; height: 10px; border-radius: 50%; background: var(--lit);
  box-shadow: 0 0 0 3px var(--canvas); animation: dot-in var(--dur-3) var(--ease-spring) both; }
@keyframes dot-in { from { transform: scale(0); } }
.stepline { display: flex; justify-content: space-between; align-items: baseline; margin-top: 9px; font-size: 13px; font-weight: 600; color: var(--ink-2); }
.close-body { padding: var(--sp-4) var(--gutter) calc(var(--sp-9) + 84px); }
/* the staff words are English only: the .en span (from {% say %}, |said and app.js) carries its parent's type */
.step-title { font-size: 27px; font-weight: 640; line-height: 1.2; letter-spacing: -.02em; font-stretch: 102%; color: var(--ink); text-wrap: balance; }
.step-title .en { display: block; font: inherit; letter-spacing: inherit; }
.say { margin-top: var(--sp-3); font-size: var(--t-body); line-height: 1.55; color: var(--ink-2); }
.say .en { display: block; }
.bi-label { display: flex; flex-direction: column; gap: 0; }
.bi-label .en { font: inherit; color: inherit; }
/* a title with its "i" hint: the words stay inline so the hint sits at the end of the line, not on a line of its own */
.step-title:has(> .ihint) > .en, .bi-label:has(> .ihint) > .en { display: inline; }
.bi-label:has(> .ihint) { display: block; }
.amount-field { position: relative; margin-top: var(--sp-2); }
.amount-field .rs { position: absolute; left: 18px; top: 50%; transform: translateY(-50%); font-size: 28px; font-weight: 560; color: var(--ink-3); pointer-events: none; }
.amount-field input { min-height: 76px; padding-left: 48px; font-size: 36px; font-weight: 660; font-stretch: 108%; letter-spacing: -.02em; border-width: 2px;
  border-color: var(--ink); border-radius: 18px; background: var(--paper); font-variant-numeric: var(--num); }
.amount-field input:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
.draft { display: flex; align-items: center; gap: var(--sp-2); margin-top: var(--sp-3); font-size: 13px; color: var(--ok); font-weight: 540; }
.draft .mark { width: 16px; height: 16px; }
/* the thumb bar: Back, then the one next step (solid canvas, no blur on cheap phones) */
.close-actions { position: fixed; left: 0; right: 0; bottom: 0; z-index: var(--z-bar); display: grid; grid-template-columns: minmax(min-content, 1fr) 1.7fr; gap: 12px;
  padding: 12px var(--gutter) calc(14px + env(safe-area-inset-bottom)); background: var(--canvas); box-shadow: 0 -1px 0 var(--line); }
.close-actions .btn { min-height: 64px; border-radius: 18px; font-size: 16px; padding-inline: var(--sp-3); }
.btn--bi.has-icon { display: grid; grid-template-columns: auto auto; column-gap: 6px; align-content: center; justify-content: center; }
.btn--bi.has-icon svg { width: 20px; height: 20px; align-self: center; }
.btn--bi.has-icon .en { text-align: left; }
.close-actions .btn--primary { font-size: 18px; font-weight: 640; }
.reckon { margin-top: var(--sp-5); background: var(--paper); border-radius: 22px; box-shadow: var(--sh-2); overflow: hidden; }
.reckon-row { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: var(--sp-3); padding: 14px 16px; border-top: 1px solid var(--line); }
.reckon-row:first-child { border-top: 0; }
.reckon-row .money { font-size: 21px; font-weight: 620; }
.reckon-row.is-result { background: var(--tone-bg, transparent); border-top: 1px solid var(--tone-line, var(--line)); }
.reckon-row.is-result .money { font-size: 30px; font-stretch: 112%; letter-spacing: -.02em; color: var(--tone, var(--ink)); }
.reckon-row.is-result .bi-label { font-size: var(--t-body); font-weight: 620; color: var(--tone, var(--ink)); }
.pinsheet { position: fixed; left: 0; right: 0; bottom: 0; z-index: var(--z-sheet); background: var(--paper); border-radius: 28px 28px 0 0; box-shadow: var(--sh-3);
  padding: 26px var(--gutter) calc(var(--sp-4) + env(safe-area-inset-bottom)); animation: sheet-up var(--dur-3) var(--ease-out) both; }
@keyframes sheet-up { from { transform: translateY(100%); } }
.pinsheet .grab { width: 40px; height: 5px; border-radius: 3px; background: var(--line-3); margin: -14px auto var(--sp-3); }
.scrim { position: fixed; inset: 0; z-index: calc(var(--z-sheet) - 1); background: var(--scrim); animation: fade var(--dur-2) linear both; }
@keyframes fade { from { opacity: 0; } }
.pin-dots { display: flex; justify-content: center; gap: 18px; margin: var(--sp-3) 0 var(--sp-4); }
.pin-dots i { width: 16px; height: 16px; border-radius: 50%; box-shadow: inset 0 0 0 2px var(--ink); transition: background-color var(--dur-1) linear; }
.pin-dots i.on { background: var(--ink); }
.keys { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--sp-2); }
.keys button { min-height: 60px; border: 0; border-radius: 16px; background: var(--paper-2); box-shadow: inset 0 0 0 1.5px var(--line-2); font-size: 26px; font-weight: 640;
  font-variant-numeric: var(--num); color: var(--ink); touch-action: manipulation; transition: transform var(--dur-1) var(--ease-out), background-color var(--dur-1) linear; }
.keys button:active { transform: scale(.94); background: var(--paper-3); }
.keys button svg { width: 28px; height: 28px; margin: auto; }
.keys button.k-sm { font-size: var(--t-small); font-weight: 600; color: var(--ink-2); }
.offline { position: sticky; top: 0; z-index: calc(var(--z-bar) + 1); display: flex; align-items: center; gap: var(--sp-3); padding: 10px var(--gutter);
  background: var(--wait-tint); color: var(--ink); box-shadow: 0 1px 0 var(--wait-line); animation: drop-in var(--dur-2) var(--ease-out) both; }
.offline .mark { width: 22px; height: 22px; }
.offline { font-size: var(--t-meta); font-weight: 560; line-height: 1.4; }
.offline .en { display: block; }
.offline .count { margin-left: auto; font-weight: 700; color: var(--wait); font-size: var(--t-meta); white-space: nowrap; }
@keyframes drop-in { from { transform: translateY(-100%); } }
.queue { margin-top: var(--sp-4); border-radius: 18px; background: var(--paper); box-shadow: inset 0 0 0 1.5px var(--wait-line); }
.queue-row { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; gap: var(--sp-3); align-items: center; padding: 12px 16px; border-top: 1px dashed var(--wait-line); }
.queue-row:first-child { border-top: 0; }
.done-state { display: grid; justify-items: center; text-align: center; gap: var(--sp-2); padding: var(--sp-6) 0 var(--sp-4); }
.done-state .big-mark { width: 64px; height: 64px; }
}

/* ============ 14. Motion: state changes and arrivals ============ */
@layer components {
  .is-changed { animation: changed 900ms linear; border-radius: 6px; }
  @keyframes changed { from { background-color: var(--wait-tint); box-shadow: 0 0 0 4px var(--wait-tint); } to { background-color: transparent; box-shadow: 0 0 0 4px transparent; } }
  /* View Transitions (HTMX: hx-swap="... transition:true"). Things that move keep a view-transition-name only while moving. */
  ::view-transition-group(*) { animation-duration: var(--dur-3); animation-timing-function: var(--ease-out); }
  ::view-transition-old(*), ::view-transition-new(*) { animation-duration: var(--dur-2); }
  ::view-transition-old(root), ::view-transition-new(root) { animation-duration: 520ms; animation-timing-function: var(--ease-in-out); }
  /* HTMX swap classes, opt-in per element (data-motion), so a 3-second status poll never animates:
     data-motion="leave" steps aside while hx-swap waits (swap:200ms); data-motion="enter" settles in when added. */
  [data-motion~="leave"].htmx-swapping { opacity: 0; transform: translateX(16px); transition: opacity var(--dur-2) var(--ease-in), transform var(--dur-2) var(--ease-in); }
  [data-motion~="enter"].htmx-added { animation: settle-in var(--dur-3) var(--ease-out) both; }
  @keyframes settle-in { from { opacity: 0; transform: translateY(6px); } }
  /* page arrival: a parent marked .arrive lifts its children in, 70 ms apart (v2.1) */
  .arrive > * { animation: rise var(--dur-4) var(--ease-out) both; }
  .arrive > :nth-child(2) { animation-delay: 70ms; } .arrive > :nth-child(3) { animation-delay: 140ms; } .arrive > :nth-child(4) { animation-delay: 210ms; }
  .arrive > :nth-child(5) { animation-delay: 280ms; } .arrive > :nth-child(n+6) { animation-delay: 340ms; }
  @keyframes rise { from { opacity: 0; transform: translateY(12px); } }
}
@media (prefers-reduced-motion: reduce) {
  @layer components {
    ::view-transition-group(*) { animation: none; }
    [data-motion~="leave"].htmx-swapping { transform: none; }
    [data-motion~="enter"].htmx-added { animation-name: fade; }
  }
}

/* the staff app is English only (the client asked): <html lang="en-IN" data-density="phone">; the words' spans are
   <span class="en" lang="en"> ({% say %}, app.js). */
@layer components {
  [lang="en"] { font-family: var(--font); line-height: var(--lh-body); }
}

/* reduced motion: the same changes, without travel (fades of 150-360 ms); nothing loops, everything final within ~0.7 s */
@media (prefers-reduced-motion: reduce) {
  @layer components {
    .work-item.is-leaving { animation: leave-calm var(--dur-2) linear forwards; }
    @keyframes leave-calm { to { opacity: 0; } }
    .stamp.is-landing { animation: fade var(--dur-2) linear both; }
    .pinsheet, .offline, .toast, .toasts > .toast { animation: fade var(--dur-2) linear both; }
    .progress i.is-now::after { animation: none; }
    .arrive > * { animation: fade var(--dur-4) ease both !important; }
    .spin { animation-duration: 4s; }
    .btn:active, .iconbtn:active, .keys button:active { transform: none; }
  }
}

/* ============ 15. Print: paper, black ink, the marks still carry the meaning ============ */
@media print {
  @layer components {
    @page { size: A4; margin: 12mm 12mm 16mm;
      @bottom-left { content: "Spectrum · printed " attr(data-printed); font: 8pt "Mona Sans", sans-serif; color: #444; }
      @bottom-right { content: "Page " counter(page) " of " counter(pages); font: 8pt "Mona Sans", sans-serif; color: #444; } }
    body { background: #fff; }
    body::before { display: none; }
    .bar, .nav, .search, .no-print, .close-actions, .offline, .toast, .toasts, .skip, .desk-messages, .mtab, .tabbar, .drawer, .scrim, .sheet[role="dialog"], .tip { display: none !important; }
    .page { max-width: none; padding: 0; }
    .card, .panel, .work, .board, .table-panel, .totals, .tablewrap { box-shadow: none !important; border: 1px solid #777; }
    .status, .money.is-tone, .fig { color: #000 !important; }
    /* status edges and rings print in black, never in colour */
    .card[class*="is-"], .board-row[class*="is-"], .ledger > tbody > tr[class*="is-"] { --tone-edge: #000; --tone-line: #777; --tone-ring: #000; }
    /* marks print as shapes in black: outline for the light ones, solid for the loud ones */
    .is-hold, .is-less, .is-refused { --mf: #000; --ms: #000; --mg: #fff; }
    .is-check, .is-wait, .is-paid, .is-ok, .is-none { --mf: #fff; --ms: #000; --mg: #000; }
    a { color: #000; text-decoration: none; }
    table { font-size: 10pt; }
    thead { display: table-header-group; }
    .ledger > thead > tr > th { position: static; }
    tr, .keep-together { break-inside: avoid; }
    h1, h2, h3 { break-after: avoid; }
  }
}

/* ============ 16. Shells: the bar's menus, the tabs strip, the owner header, the bare .icon, Pay less, the decision
   card's forms, phone-density 44 px rules ============ */
@layer components {
  .icon { display: inline-block; width: 1.15em; height: 1.15em; flex: none; vertical-align: -.2em; }
  .work-item.is-less .amt .money, .total.is-less .money { color: var(--hold); }

  /* decision card (ui/c/decision_card.html): each choice is its own form on an existing POST; the reason box opens full width */
  .decision .choices > form { display: grid; margin: 0; min-width: 0; }
  .decision .choices > form > .btn { width: 100%; }
  .decision .choices > .reason-box { margin: 0; min-width: 0; }
  .decision .choices > .reason-box[open] { grid-column: 1 / -1; }
  .decision .choices > .reason-box > summary.btn { display: flex; width: 100%; min-height: 54px; justify-content: center; font-size: 16px; text-decoration: none;
    background: var(--paper); box-shadow: var(--sh-1), var(--hi); border-radius: 16px; padding: 0 12px; color: var(--ink); font-weight: 580; }
  .decision .choices > .reason-box > form { display: flex; flex-direction: column; gap: var(--sp-2); margin-top: var(--sp-3); }
  .decision .choices > .reason-box > form > .btn { min-height: 54px; }
  .decision .amount { text-align: right; }
  .decision .amount .was { display: block; font-size: var(--t-meta); color: var(--ink-3); text-decoration: line-through; font-weight: 500; }

  /* a focused or landed element stops clear of the floating bar (and of the bottom tab bars on a phone) */
  html:has(> body.desk) { scroll-padding-top: 88px; }
  html:has(> body.owner) { scroll-padding-bottom: 104px; }
  body.owner .toasts { bottom: calc(100px + env(safe-area-inset-bottom)); }   /* the toast clears his tab bar */
  @media (max-width: 760px) { html:has(> body.desk) { scroll-padding-top: 76px; scroll-padding-bottom: 96px; } }
  /* the floating bar's band (guide v2, 21 Oct 2026: scrolled lines showed in the gap above and beside the bar): the
     page's own ground and glaze (body::before's, to the pixel) fill the top of the window behind the bar, so a line
     scrolls away under it, never around it. Under the skip link, the drawers, menus, tips and the tours. */
  body.desk::after { content: ""; position: fixed; inset: 0 0 auto 0; height: 72px; z-index: calc(var(--z-bar) - 1); pointer-events: none;
    background: var(--glaze), var(--canvas); background-attachment: fixed; background-size: 100% 520px; background-repeat: no-repeat; }
  @media (max-width: 760px) { body.desk::after { height: 64px; } }

  /* ---- desk shell: the account menu, the section's tabs, messages ---- */
  .menu { position: relative; flex: none; margin: 0; }
  .menu > summary { list-style: none; display: inline-flex; align-items: center; gap: var(--sp-2); min-height: 40px; padding: 0 2px;
    border: 0; border-radius: 12px; background: none; cursor: pointer; font-weight: 600; font-size: var(--t-small); color: var(--ink-2); user-select: none; }
  .menu > summary::-webkit-details-marker { display: none; }
  .menu > summary:hover, .menu[open] > summary { color: var(--ink); }
  .menu > summary .count { min-width: 20px; height: 18px; padding: 0 6px; border-radius: 9px; background: var(--ink); color: var(--on-ink);
    font-size: var(--t-micro); font-weight: 700; display: inline-grid; place-items: center; }
  .menu-panel { position: absolute; right: 0; top: calc(100% + 10px); z-index: var(--z-sheet); min-width: 248px; display: flex; flex-direction: column;
    padding: 8px; background: var(--paper); border-radius: 18px; box-shadow: var(--sh-3); animation: menu-in var(--dur-2) var(--ease-out) both; transform-origin: top right; }
  @keyframes menu-in { from { opacity: 0; transform: translateY(-4px) scale(.98); } }
  .menu-panel a, .menu-panel button { display: flex; align-items: center; gap: 12px; width: 100%; min-height: 40px; margin: 0; padding: 0 12px;
    border: 0; border-radius: 11px; background: none; color: var(--ink); text-decoration: none; text-align: left; justify-content: flex-start;
    font: inherit; font-weight: 560; font-size: 14.5px; box-shadow: none; cursor: pointer; }
  .menu-panel a:hover, .menu-panel button:hover { background: var(--paper-2); color: var(--ink); }
  .menu-panel a[aria-current] { background: var(--paper-3); }
  .menu-panel .icon { width: 18px; height: 18px; color: var(--ink-3); }
  .menu-panel form { display: block; margin: 6px 0 0; padding: 6px 0 0; border-top: 1px solid var(--line); }
  .menu-who { margin: 0 0 6px; padding: 8px 12px 12px; border-bottom: 1px solid var(--line); font-size: var(--t-meta); color: var(--ink-3); }
  .menu-who b { color: var(--ink); font-weight: 640; }
  .menu-who + form { border-top: 0; margin-top: 0; }
  .menu-sections { display: none; flex-direction: column; margin-bottom: 6px; padding-bottom: 6px; border-bottom: 1px solid var(--line); }
  .me > summary { color: var(--ink-2); }
  .bar-menu { display: none; }
  .bar-menu .menu-panel { left: auto; right: 0; }
  .desk-sub { max-width: 1376px; margin: 0 auto; padding: 14px 32px 0; }
  .desk-sub .tabs { margin-bottom: 0; overflow-x: auto; scrollbar-width: none; }
  .desk-sub .tabs a { flex: none; }
  .desk-messages { max-width: 1376px; margin: 0 auto; padding: var(--sp-4) 32px 0; display: flex; flex-direction: column; gap: var(--sp-2); }
  .desk-messages:empty { display: none; }
  .desk-messages .note { margin: 0; }
  .page:focus { outline: none; }
  .page:has(> .page-aside) { display: grid; grid-template-columns: minmax(0, 1fr) 360px; gap: var(--sp-6); align-items: start; }
  .page-main { min-width: 0; }
  @media (max-width: 1100px) { .page:has(> .page-aside) { grid-template-columns: minmax(0, 1fr); } }
  /* 761-1180 px: the find box folds to its icon and the clock steps aside (v2.1) */
  @media (max-width: 1180px) and (min-width: 761px) {
    .bar .search { flex: none; width: 44px; padding: 0; justify-content: center; position: relative; }
    .bar .search > svg { pointer-events: none; }
    .bar .search input { position: absolute; inset: 0; opacity: 0; cursor: pointer; }
    .bar .search kbd, .bar-when { display: none; }
    .bar { gap: 10px; }
    .nav { margin-left: 0; } .nav a { padding: 0 10px; }
  }
  /* under 760 px: brand + search icon + avatar; the bottom tab bar; the menu lists the sections */
  @media (max-width: 760px) {
    .bar, .topbar { top: 10px; margin: 10px 10px 0; height: 54px; padding: 0 6px 0 12px; border-radius: 16px; gap: 6px; }
    .bar > .nav, .bar-when { display: none; }
    .logo small { display: none; }
    .me .me-name { display: none; }
    .menu > summary { min-height: 44px; min-width: 44px; justify-content: center; }
    .menu-panel a, .menu-panel button { min-height: 44px; }
    .menu-sections { display: flex; }
    .desk-sub { padding: 10px 16px 0; }
    .desk-sub .tabs { flex-wrap: wrap; overflow: visible; }
    .desk-sub .tabs a { min-height: 44px; }
    .desk-messages { padding: var(--sp-3) 16px 0; }
    .page { padding: 20px 16px var(--sp-7); }
    .bar .logo, .skip { min-height: 44px; display: inline-flex; align-items: center; }
    body.desk { padding-bottom: calc(86px + env(safe-area-inset-bottom)); }
    body.desk .toasts { bottom: calc(96px + env(safe-area-inset-bottom)); }   /* clear of the tab bar (polish-1: her answers come as toasts) */
    .mtab { display: block; position: fixed; left: 0; right: 0; bottom: 0; z-index: var(--z-tabbar); padding: 14px 10px calc(10px + env(safe-area-inset-bottom));
      background: linear-gradient(180deg, rgba(var(--wash), 0), var(--canvas) 18px); pointer-events: none; }
    .mtab nav { pointer-events: auto; }
    .mtab nav { display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); height: 62px; border-radius: 22px; padding: 6px; background: var(--glass-strong); }
    .mtab .dot { position: absolute; top: 8px; left: calc(50% + 9px); width: 8px; height: 8px; }
  }

  /* a desk page opened on a phone (Daniel follows "See the close" from Tonight): phone-sized buttons and tabs */
  @media (max-width: 900px) { body.desk .btn { min-height: 44px; } body.desk .btn--sm { min-height: 44px; } .desk-sub .tabs a { min-height: 44px; } }

  /* phone density: every control at least 44 px tall (WCAG 2.5.8 asks 24; the phones' rule is 44) */
  [data-density="phone"] .skip { min-height: 44px; display: inline-flex; align-items: center; }
  [data-density="phone"] .section-title a { display: inline-flex; align-items: center; min-height: 44px; margin-block: -12px; }
  [data-density="phone"] .decision summary { min-height: 44px; }
  [data-density="phone"] .btn { min-height: max(44px, var(--h-button)); }
  [data-density="phone"] .btn--sm { min-height: 44px; }

  /* ---- owner shell (Daniel's phone pages): his initial opens the menu ---- */
  .ph-head .me { margin-left: auto; }
  .ph-head .menu > summary { min-height: 44px; min-width: 44px; justify-content: center; padding: 0; }
  .ph-head .ph-back { min-height: 44px; }
  .ph-messages { padding: var(--sp-3) var(--gutter) 0; display: flex; flex-direction: column; gap: var(--sp-2); }
  .ph-messages:empty { display: none; }
  .ph-body:focus { outline: none; }
}
@media print { @layer components { .menu, .desk-sub, .ph-head .ph-back, .ph-head .menu, body.desk::after { display: none !important; } } }

/* ============ 17. Pager: Previous · Page N of M · Next (core/pagination.html) ============ */
@layer components {
  .pager { display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: var(--sp-2) var(--sp-4); margin-top: var(--sp-5); }
  .pager .btn .icon { width: 16px; height: 16px; }
  .pager .btn[aria-disabled="true"] { cursor: default; }
  .pager-at { font-size: var(--t-small); font-weight: 560; color: var(--ink-2); white-space: nowrap; }
}
@media print { @layer components { .pager { display: none !important; } } }

/* ============ 18. Staff pieces the frame and flows share ============ */
@layer components {
  /* the progress bar has one segment per step (close_head.html sets --steps), not always four */
  .progress { grid-template-columns: repeat(var(--steps, 4), minmax(0, 1fr)); }
  /* a sticky staff header stays under the offline bar while that shows (app.js sets --offline-h to the bar's height) */
  .close-head { top: var(--offline-h, 0px); }
  /* on a wide screen the staff header lines up with the page's one 520 px column (as .close-actions does) */
  .close-head { padding-inline: max(var(--gutter), calc((100% - 520px) / 2 + var(--gutter))); }
  /* the thumb bar: one column in the middle on a wide screen; a lone primary spans it */
  .close-actions { padding-inline: max(var(--gutter), calc((100% - 520px) / 2 + var(--gutter))); }
  .close-actions > :only-child { grid-column: 1 / -1; }
  .close-actions .btn--bi .en { max-width: 100%; overflow-wrap: break-word; }
  /* a staff choice: one radio per row, the whole row is the target */
  .choices { display: flex; flex-direction: column; gap: var(--sp-2); margin: 0; padding: 0; border: 0; min-width: 0; }
  .choices > legend { padding: 0; margin-bottom: var(--sp-2); }
  .choice { display: flex; align-items: center; gap: var(--sp-3); min-height: var(--h-row); padding: 12px 16px; border: 0; border-radius: 15px;
    background: var(--paper-2); box-shadow: inset 0 0 0 1.5px var(--line-strong); color: var(--ink); font-weight: 560; cursor: pointer; overflow-wrap: anywhere;
    transition: box-shadow var(--dur-1) linear, background-color var(--dur-1) linear; }
  .choice:has(input:checked) { background: var(--paper); box-shadow: inset 0 0 0 2px var(--ink); }
  .choice input[type=radio], .choice input[type=checkbox] { width: 22px; height: 22px; flex: none; margin: 0; }
  /* a queue row holds its own buttons on a second line when an entry could not be sent */
  .queue-row.is-refused { border-top-style: solid; }
  .queue-row > .mark { margin-top: 2px; align-self: start; }
  .queue-row { row-gap: var(--sp-1); }
  /* a staff button's icon keeps its size whatever squeezes the button */
  .btn--bi.has-icon svg { max-width: none; }
  /* a toast's label takes the toast's own ink */
  .toast .bi-label .en { color: inherit; }
  .toast .mark.is-ok { --ms: currentColor; }
}

/* ============ 19. Find and the keyboard: the bar's find box and its panel (v2.1's palette), search results, J/K's
   current item, the shortcuts sheet. The markup is ui/c/_search_panel.html, _results.html, _keys_sheet.html. ============ */
@layer components {
  .search > svg { flex: none; }
  .search input { flex: 1 1 auto; min-width: 0; width: auto; min-height: 0; height: 100%; padding: 0; border: 0; border-radius: 0;
    background: none; color: var(--ink); font-size: 14px; box-shadow: none; }
  .search input::placeholder { color: var(--ink-3); }
  .search input:focus-visible { outline: none; }
  /* a find box's clear button: ink, not the browser's blue (colour means money) */
  input[type="search"]::-webkit-search-cancel-button { -webkit-appearance: none; appearance: none; width: 14px; height: 14px; cursor: pointer;
    background: var(--ink-2);
    -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M3.5 3.5l9 9m0-9l-9 9' stroke='black' stroke-width='2.2' stroke-linecap='round'/%3E%3C/svg%3E") center / contain no-repeat;
    mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M3.5 3.5l9 9m0-9l-9 9' stroke='black' stroke-width='2.2' stroke-linecap='round'/%3E%3C/svg%3E") center / contain no-repeat; }
  .search-link { display: none; }

  /* focused, the bar's find box becomes v2.1's centred palette over a scrim (/, Ctrl K and ⌘ K focus it: keys.js) */
  .bar .search:focus-within { position: fixed; z-index: 2; top: 14vh; left: 0; right: 0; margin: 0 auto; width: min(620px, calc(100vw - 32px)); height: 58px;
    padding: 0 18px; gap: 12px; border-radius: 20px; background: var(--paper); color: var(--ink-3); box-shadow: var(--sh-3); }
  /* (no transform or opacity on the box itself: a transform would make it the containing block of its own fixed scrim,
     an opacity animation the root its scrim's blur samples; its contents fade in instead) */
  .bar .search:focus-within > * { animation: fade 200ms linear both; }
  .bar .search:focus-within::before { content: ""; position: fixed; inset: 0; z-index: -1; background: var(--scrim); animation: fade 200ms linear both;
    -webkit-backdrop-filter: blur(3px); backdrop-filter: blur(3px); }
  .bar .search:focus-within::after { content: ""; position: absolute; inset: 0; z-index: -1; border-radius: inherit; background: var(--paper); }
  .bar .search:focus-within > svg { width: 19px; height: 19px; }
  @media (min-width: 761px) { .bar .search input::-webkit-search-cancel-button { display: none; } }
  .bar .search:focus-within input { position: static; opacity: 1; font-size: 16.5px; cursor: text; }
  .bar .search:focus-within > kbd { display: inline-grid; }
  .bar .search:focus-within > kbd::before { content: "esc"; }
  .bar .search:focus-within > kbd { font-size: 0; }
  .bar .search:focus-within > kbd::before { font-size: 11.5px; }
  .bar .search:focus-within:has(.search-panel:not([hidden])) { border-radius: 20px 20px 0 0; box-shadow: var(--sh-1); }
  /* the open palette and its scrim sit over everything the bar's own layer is under (a phone's bottom tab bar) */
  .bar:has(.search:focus-within) { z-index: var(--z-sheet); }

  /* the panel under the box: the HTMX answer (ui/c/_search_panel.html); in the palette, its body */
  .search-panel { position: absolute; top: calc(100% + 8px); right: 0; z-index: var(--z-sheet); width: min(480px, calc(100vw - 2 * var(--gutter)));
    max-height: min(72vh, 560px); overflow: auto; overscroll-behavior: contain; background: var(--paper); border-radius: 18px; box-shadow: var(--sh-3);
    color: var(--ink); text-align: left; }
  .bar .search:focus-within .search-panel { top: 100%; left: 0; right: 0; width: auto; max-height: min(62vh, 440px); border-radius: 0 0 20px 20px;
    border-top: 1px solid var(--line); box-shadow: var(--sh-3); padding: 0 8px 4px; }
  .search-panel-say { padding: 12px 10px 4px; font-size: 12px; color: var(--ink-3); font-weight: 600; }
  .search-panel .results { gap: 0; }
  .search-panel .results-group { border: 0; border-radius: 0; box-shadow: none; background: none; }
  .search-panel .results-head { padding: 10px 10px 4px; background: none; border: 0; font-size: 12px; color: var(--ink-3); font-weight: 600; }
  .search-panel .result { padding: 8px 10px; border-top: 0; border-radius: 11px; }
  .search-panel .result:hover, .search-panel .result[aria-current="true"] { background: var(--paper-3); box-shadow: none; }
  .search-panel .result-title { font-size: 14.5px; }
  .search-panel-foot { position: sticky; bottom: 0; display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-1) var(--sp-3);
    padding: 10px; margin: 4px -8px -4px; border-top: 1px solid var(--line); background: var(--paper); font-size: var(--t-meta); }
  .search-panel-foot a { display: inline-flex; align-items: center; min-height: var(--target); font-weight: 600; }

  /* the palette's rows (ui/c/_results.html compact): an icon, the name, one small line and the amount at the right; the
     whole row one link; the current one (J/K, ↑/↓) on paper-3, as v2.1's palette (no ink edge here) */
  .search-panel .results.is-compact .result { display: block; padding: 0; }
  .result-row { display: flex; align-items: center; gap: 12px; min-height: 42px; padding: 9px 10px; border-radius: 11px; color: var(--ink);
    text-decoration: none; font-size: 14.5px; }
  .result-row > .icon { width: 17px; height: 17px; flex: none; color: var(--ink-3); }
  .result-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 520; }
  .result-brief { flex: 0 1 auto; min-width: 0; max-width: 60%; margin-left: auto; padding-left: 12px; overflow: hidden; text-overflow: ellipsis;
    white-space: nowrap; color: var(--ink-3); font-size: 13px; }
  .result-brief .money { font-weight: inherit; }
  @media (max-width: 560px) {
    .result-row { display: grid; grid-template-columns: 17px minmax(0, 1fr); column-gap: 12px; row-gap: 1px; }
    .result-brief { grid-column: 2; max-width: none; margin: 0; padding: 0; white-space: normal; }
  }
  .bar .search-panel .result[data-item][aria-current="true"] { background: var(--paper-3); box-shadow: none; }
  .search-panel .result-row:hover { background: var(--paper-3); }
  .result-title > .icon { width: 17px; height: 17px; flex: none; margin-right: 10px; color: var(--ink-3); }

  /* search results (ui/c/_results.html): a group per kind, one line per result, the link first */
  .results { display: flex; flex-direction: column; gap: var(--sp-5); }
  .results-group { background: var(--paper); border-radius: var(--r-4); box-shadow: var(--sh-2); overflow: hidden; container-type: inline-size; }
  .results-head { display: flex; align-items: baseline; gap: var(--sp-2); padding: 16px 20px 8px; font-size: 15.5px; font-weight: 640; line-height: var(--lh-tight); }
  .results-count { color: var(--ink-3); font-weight: 520; font-size: 13.5px; }
  .results-list { list-style: none; margin: 0; padding: 0; }
  .result { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: start; gap: var(--sp-1) var(--sp-4); padding: 12px 20px; border-top: 1px solid var(--line); }
  .result:first-child { border-top: 0; }
  .result-title { display: inline-flex; align-items: center; min-height: var(--target); font-weight: 600; font-size: 15px; color: var(--ink); text-decoration: none; overflow-wrap: anywhere; }
  .result-title:hover { text-decoration: underline; }
  /* what matched: heavier, on a grey ground (not a colour: colour means money) */
  .result b { font-weight: 720; background: var(--paper-3); border-radius: 3px; box-shadow: 0 0 0 1px var(--paper-3); }
  .result-sub { display: flex; flex-wrap: wrap; gap: 0 var(--sp-2); font-size: 13px; color: var(--ink-3); line-height: 1.4; }
  .result-sub > span + span::before { content: "·"; margin-right: var(--sp-2); color: var(--ink-4); }
  .result-also { display: flex; flex-wrap: wrap; gap: 0 var(--sp-4); font-size: var(--t-meta); }
  .result-also a { display: inline-flex; align-items: center; min-height: var(--target); font-weight: 560; }
  .result-side { display: flex; flex-direction: column; align-items: flex-end; gap: var(--sp-1); padding-top: 2px; text-align: right; }
  .result-side .money { font-weight: 620; white-space: nowrap; }
  @container (max-width: 420px) { .result { padding-inline: 16px; gap: var(--sp-1) var(--sp-3); } .result-side .status { font-size: 12.5px; } }

  /* J/K's current item (core/ui/keys.js): an ink edge and aria-current="true" on any list's items; the focus ring sits
     inside the item, so a list that clips its corners never cuts it */
  [data-item] { scroll-margin-top: 104px; scroll-margin-bottom: var(--sp-4); }
  [data-item]:focus-visible { outline-offset: -3px; }
  [data-item][aria-current="true"]:not(tr):not(.work-item):not(.card) { background: var(--paper-2); box-shadow: inset 3px 0 0 var(--ink); }
  table > tbody > tr[data-item][aria-current="true"] > :is(td, th):first-child { box-shadow: inset var(--edge) 0 0 var(--ink); }
  /* a table row draws no outline of its own: its focus ring is drawn on its cells (top, bottom, and the row's two ends).
     !important: a page's own row edge (its tr:focus / tone edge, in the later pages layer) must never hide the focus */
  tr[data-item]:focus-visible { outline: none; }
  table > tbody > tr[data-item]:focus-visible > :is(td, th) { box-shadow: inset 0 2px 0 var(--focus), inset 0 -2px 0 var(--focus) !important; }
  table > tbody > tr[data-item]:focus-visible > :is(td, th):first-child { box-shadow: inset 0 2px 0 var(--focus), inset 0 -2px 0 var(--focus), inset var(--edge) 0 0 var(--focus) !important; }
  table > tbody > tr[data-item]:focus-visible > :is(td, th):last-child { box-shadow: inset 0 2px 0 var(--focus), inset 0 -2px 0 var(--focus), inset -2px 0 0 var(--focus) !important; }
  .card[data-item][aria-current="true"] { outline: 2px solid var(--ink); outline-offset: 2px; }

  /* the account menu's "Keyboard shortcuts" */
  .menu-panel .menu-keys { justify-content: space-between; gap: var(--sp-3); }
  .menu-keys kbd { margin-left: auto; }

  /* the shortcuts sheet: a native <dialog> (ui/c/_keys_sheet.html) */
  .keys-sheet { width: min(520px, calc(100vw - 2 * var(--gutter))); max-height: calc(100vh - 2 * var(--sp-6)); padding: 0; border: 0;
    border-radius: var(--r-5); background: var(--paper); color: var(--ink); box-shadow: var(--sh-3); }
  .keys-sheet::backdrop { background: var(--scrim); }
  .keys-sheet[open] { animation: keys-in var(--dur-3) var(--ease-out) both; }
  @keyframes keys-in { from { opacity: 0; transform: translateY(8px); } }
  .keys-sheet-body { padding: 24px 28px 28px; }
  .keys-sheet-head { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3); margin-bottom: var(--sp-3); }
  .keys-sheet-head h2 { font-size: 22px; }
  .shortcuts { margin: 0; }
  .shortcuts > div { display: grid; grid-template-columns: minmax(150px, auto) minmax(0, 1fr); gap: var(--sp-3); align-items: baseline;
    padding: 10px 0; border-top: 1px solid var(--line); }
  .shortcuts > div:first-child { border-top: 0; }
  .shortcuts dt { font-weight: 600; white-space: nowrap; }
  .shortcuts dt .muted { font-size: var(--t-meta); padding: 0 2px; }
  .shortcuts dd { margin: 0; color: var(--ink-2); font-size: var(--t-small); }
  .shortcuts kbd { min-width: 1.9em; }
  .shortcuts-note { margin-top: var(--sp-3); padding: 14px 16px; border-radius: 14px; background: var(--paper-2); font-size: var(--t-small); color: var(--ink-2); }
  .shortcuts-note i { font-style: normal; font-weight: 640; color: var(--ink); }

  /* under 760 px the find box is the bar's search icon (the box itself, transparent over it: a tap focuses it, with or
     without JS); focused, the palette opens at the top of the screen, above where a phone's keyboard comes up. The
     a.search-link stays in the markup for keys.js and pages with no box. */
  @media (max-width: 760px) {
    .bar .search { flex: none; width: 44px; height: 44px; padding: 0; justify-content: center; position: relative; margin-left: auto;
      background: none; box-shadow: none; color: var(--ink-2); }
    .bar .search > svg { pointer-events: none; width: 20px; height: 20px; }
    .bar .search input { position: absolute; inset: 0; opacity: 0; cursor: pointer; }
    .bar .search > kbd, .search-panel-foot .muted { display: none; }
    .bar .search:focus-within { top: 10px; width: calc(100vw - 20px); height: 56px; padding: 0 14px; }
    .bar .search:focus-within > kbd { display: none; }
    .bar .search:focus-within .search-panel { max-height: min(56vh, 440px); }
    .search-link { display: none; }
    .shortcuts > div { grid-template-columns: minmax(0, 1fr); gap: var(--sp-1); }
  }
}
@media (prefers-reduced-motion: reduce) { @layer components { .keys-sheet[open], .menu-panel { animation-name: fade; } } }
@media print { @layer components { .search-link, .search-panel, .keys-sheet { display: none !important; } } }

/* ============ 20. v2.1's shared pieces (one partial or tag each; shown in the gallery at /ops/ui/) ============ */
@layer components {
  /* ---- the drawer (desk: a right sheet, 540 px; phone: a bottom sheet, 88 vh) + its scrim. ui.js opens it on a[data-drawer]
     and loads the a's data-part into #drawer-body (ui/c/drawer.html) ---- */
  .drawer-scrim { position: fixed; inset: 0; z-index: var(--z-sheet); background: var(--scrim); opacity: 0; transition: opacity var(--dur-3) var(--ease-out); }
  .drawer-scrim.is-on { opacity: 1; }
  .drawer { position: fixed; z-index: var(--z-drawer); top: 12px; right: 12px; max-height: calc(100vh - 24px); width: min(540px, calc(100vw - 24px));
    background: var(--paper); border-radius: var(--r-5); box-shadow: var(--sh-3); display: flex; flex-direction: column; overflow: hidden;
    transform: translateX(calc(100% + 24px)); transition: transform 520ms var(--ease-out); }
  .drawer.is-on { transform: none; }
  .drawer:focus { outline: none; }
  .drawer-h { display: flex; align-items: flex-start; gap: 14px; padding: 24px 24px 16px 28px; }
  .drawer-h .grow { flex: 1; min-width: 0; }
  .drawer-h h2 { font-size: 22px; line-height: 1.2; font-weight: 630; letter-spacing: -.016em; }
  .drawer-h p { margin-top: 4px; font-size: 13px; color: var(--ink-3); }
  .drawer-b { flex: 1 1 auto; min-height: 0; overflow: auto; padding: 4px 28px 28px; overscroll-behavior: contain; }
  .drawer-b > * + * { margin-top: 22px; }
  .drawer-b.htmx-request { opacity: .55; transition: opacity var(--dur-2) linear; }
  .drawer .stag > * { animation: rise 520ms var(--ease-out) both; }
  .drawer .stag > :nth-child(2) { animation-delay: 50ms; } .drawer .stag > :nth-child(3) { animation-delay: 100ms; }
  .drawer .stag > :nth-child(4) { animation-delay: 150ms; } .drawer .stag > :nth-child(5) { animation-delay: 200ms; } .drawer .stag > :nth-child(n+6) { animation-delay: 240ms; }
  .drawer-foot { padding: 14px 28px 20px; border-top: 1px solid var(--line); }
  @media (max-width: 640px) {
    .drawer { top: auto; left: 0; right: 0; bottom: 0; width: 100%; max-height: 88vh; border-radius: 26px 26px 0 0; transform: translateY(105%); }
    .drawer::before { content: ""; position: absolute; top: 8px; left: 50%; width: 40px; height: 5px; margin-left: -20px; border-radius: 3px; background: var(--line-3); }
    .drawer-h { padding: 26px 20px 12px 22px; } .drawer-b { padding: 4px 22px 28px; }
  }
  /* ---- Daniel's bottom sheet ([data-sheet] → a server-rendered <section class="sheet" hidden>; without JS it is a <details>) ---- */
  .sheet[role="dialog"] { position: fixed; left: 0; right: 0; bottom: 0; z-index: var(--z-drawer); max-width: 560px; margin: 0 auto; max-height: 88vh; overflow: auto;
    background: var(--paper); border-radius: 28px 28px 0 0; padding: 26px 20px calc(20px + env(safe-area-inset-bottom)); box-shadow: var(--sh-3);
    transform: translateY(105%); transition: transform 460ms var(--ease-out); }
  .sheet[role="dialog"].is-on { transform: none; }
  .sheet[role="dialog"]::before { content: ""; position: absolute; top: 9px; left: 50%; width: 40px; height: 5px; margin-left: -20px; border-radius: 3px; background: var(--line-3); }
  .sheet[role="dialog"] h2 { font-size: 21px; font-weight: 640; letter-spacing: -.016em; }
  .sheet[role="dialog"] .meta, .sheet[role="dialog"] > p { margin-top: 4px; font-size: 14.5px; color: var(--ink-3); }
  .sheet[role="dialog"] .acts { margin-top: 18px; display: grid; grid-template-columns: 1fr 1.4fr; gap: 10px; }
  .sheet[role="dialog"] .acts .btn { width: 100%; }
  details.sheet-fallback > summary { cursor: pointer; }
  /* ---- radio chips for a reason (the "Pay anyway" sheet) ---- */
  .chips { margin-top: 18px; display: grid; gap: 8px; border: 0; padding: 0; }
  .chip { display: flex; align-items: center; gap: 12px; width: 100%; min-height: 48px; padding: 12px 16px; border-radius: 15px; background: var(--paper-2);
    box-shadow: inset 0 0 0 1px var(--line-strong); font-size: 15px; font-weight: 540; text-align: left; cursor: pointer;
    transition: box-shadow var(--dur-1) linear, background-color var(--dur-1) linear; }
  .chip input { width: 20px; height: 20px; margin: 0; flex: none; }
  .chip:has(input:checked), .chip[aria-checked="true"] { background: var(--paper); box-shadow: inset 0 0 0 2px var(--ink); }
  /* ---- the segmented control (Map / Table): links with ?view=, a spring thumb (ui.js) ---- */
  .seg { position: relative; display: inline-flex; padding: 4px; border-radius: 13px; isolation: isolate; }
  .seg a, .seg button { position: relative; z-index: 1; height: 34px; padding: 0 16px; border-radius: 10px; font-size: 14px; font-weight: 560; color: var(--ink-3);
    display: inline-flex; align-items: center; gap: 7px; text-decoration: none; transition: color var(--dur-2) linear; }
  .seg a[aria-current="true"], .seg a[aria-current="page"], .seg button[aria-pressed="true"] { color: var(--ink); }
  .seg:not(.has-thumb) a[aria-current="true"], .seg:not(.has-thumb) a[aria-current="page"] { background: var(--paper); box-shadow: var(--sh-1); }
  .seg .thumb { position: absolute; z-index: 0; top: 4px; bottom: 4px; left: 0; width: 0; border-radius: 10px; background: var(--paper); box-shadow: var(--sh-1);
    transition: transform var(--dur-3) var(--ease-spring), width var(--dur-3) var(--ease-spring); }
  .seg .icon { width: 17px; height: 17px; }
  /* ---- the tooltip ([data-tip] JSON {t, s, v}; hover and focus; ui.js) ---- */
  .tip { position: fixed; z-index: var(--z-tip); pointer-events: none; padding: 9px 11px; border-radius: 11px; background: var(--paper); box-shadow: var(--sh-3);
    font-size: 13px; line-height: 1.35; max-width: 260px; opacity: 0; transform: translateY(4px); transition: opacity 120ms linear, transform 160ms var(--ease-out); }
  .tip.is-on { opacity: 1; transform: none; }
  .tip b { display: block; font-weight: 620; } .tip .s { display: block; color: var(--ink-3); } .tip .v { display: block; font-weight: 640; margin-top: 2px; }
  [data-tip] { cursor: default; }
  /* ---- drawer rows: key, value, right (v2.1 .kv/.kvr/.kvh), and the drawer's hero figure ---- */
  .kv { display: grid; gap: 2px; margin: 0; padding: 0; list-style: none; }
  .kvr { display: grid; grid-template-columns: 28px 1fr auto; gap: 12px; align-items: start; padding: 11px 0; border-top: 1px solid var(--line); text-decoration: none; color: inherit; }
  .kvh + .kvr, .kvr:first-child { border-top: 0; }
  a.kvr:hover { background: var(--paper-2); border-radius: 10px; }
  .kvr .k { font-size: 12.5px; color: var(--ink-3); font-weight: 560; }
  .kvr .v { font-size: 15px; font-weight: 560; min-width: 0; }
  .kvr .v small { display: block; font-size: 13px; font-weight: 440; color: var(--ink-3); margin-top: 1px; }
  .kvr .r { font-variant-numeric: proportional-nums; font-weight: 600; white-space: nowrap; text-align: right; }
  .kvr .r small { display: block; font-size: 12px; font-weight: 500; color: var(--ink-3); }
  .kvh { margin: 16px 0 2px 40px; font-size: 12px; font-weight: 600; color: var(--ink-3); }
  .kvh:first-child { margin-top: 0; }
  .dbig { padding: 20px 22px; border-radius: 18px; background: var(--paper-2); }
  .dbig .fig { font-size: 40px; }
  .dbig .label, .dbig .lab { display: block; margin-bottom: 8px; }
  .dbig small, .dbig .sub { display: block; margin-top: 8px; font-size: 13.5px; color: var(--ink-2); }
  /* ---- the crosses: lit (nothing to do), unlit with its dot (a problem), closed (past). Never a red cross. ---- */
  .cross { position: relative; display: inline-grid; place-items: center; flex: none; width: 22px; height: 22px; }
  .cross svg { width: 100%; height: 100%; }
  .cross-dot { position: absolute; top: -1px; right: -1px; width: 38%; height: 38%; border-radius: 50%; box-shadow: 0 0 0 2px var(--paper); }
  .cross-dot.is-hold, .cross-dot.is-less { background: var(--hold-fill); } .cross-dot.is-check { background: var(--check-fill); } .cross-dot.is-wait { background: var(--wait-fill); }
}
@media (prefers-reduced-motion: reduce) {
  @layer components {
    .drawer { transition: transform 1ms, opacity 260ms; }
    .drawer .stag > * { animation: fade 360ms ease both !important; }
    .sheet[role="dialog"] { transition-duration: 1ms; }
    .seg .thumb { transition-duration: 120ms; transition-timing-function: ease-out; }
  }
}

/* "Get latest" (feed/_pull.html): the button and its live words on one line, wrapping under it when narrow. */
.pull { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 10px; margin: 8px 0; }
.pull form { margin: 0; }
.pull-words { font-size: var(--t-meta); color: var(--ink-2); }
.pull--done .pull-words, .pull--nothing_new .pull-words { color: var(--ok, var(--ink)); }
.pull--offline .pull-words, .pull--failed .pull-words, .pull--lapsed .pull-words, .pull--stalled .pull-words { color: var(--check, var(--ink)); }

/* ---- the "i" hint ({% hint %}, core/hints.py; DecentraLabs' Hint): a real button with the letter i in a small circle and
   its role=tooltip bubble, shown by CSS on hover and on focus (a tap focuses it, so phones get it too; ui.js also focuses
   it on a tap where the browser would not). ui.js moves the bubble to fixed coordinates inside the screen, so no table,
   card or narrow phone cuts it off; without JS it opens above, centred (ihint--end: towards the left). The hit area is the
   desk's 24 px (44 px on the phone shells) while the circle stays small, with negative margins so the line keeps its height. ---- */
@layer components {
  .ihint { position: relative; display: inline-flex; vertical-align: middle; margin-left: 2px; font-weight: 400; letter-spacing: 0;
    text-transform: none; white-space: normal; }
  .hint-btn { display: inline-grid; place-items: center; width: 24px; height: 24px; margin: -4px -2px; padding: 0; border: 0;
    border-radius: 50%; background: transparent; color: var(--ink-3); cursor: help; font: inherit; line-height: 1; }
  .hint-btn > span { display: grid; place-items: center; width: 16px; height: 16px; border: 1.4px solid currentColor;
    border-radius: 50%; font-family: Georgia, "Times New Roman", serif; font-size: 11px; font-weight: 700; font-style: italic;
    line-height: 1; transition: background-color 120ms linear, color 120ms linear; }
  .hint-btn:hover > span, .hint-btn:focus-visible > span, .ihint:focus-within .hint-btn > span { background: var(--ink); border-color: var(--ink); color: var(--on-ink); }
  .hint-btn:focus-visible { outline: 2px solid var(--focus); outline-offset: 1px; }
  [data-density="phone"] .hint-btn { width: 44px; height: 44px; margin: -14px -12px; }
  [data-density="phone"] .hint-btn > span { width: 18px; height: 18px; font-size: 12px; }
  /* shut, the bubble is fixed (off the top of the screen), so a hidden bubble never widens a narrow page; open without JS it
     sits above its button */
  .hint-bubble { position: fixed; bottom: calc(100% + 8px); left: 50%; z-index: var(--z-tip); width: max-content;
    max-width: min(280px, calc(100vw - 24px)); padding: 9px 11px; border-radius: 11px; background: var(--ink); color: var(--on-ink);
    box-shadow: var(--sh-3); font-family: var(--font); font-size: 13px; font-weight: 440; font-style: normal; line-height: 1.4;
    letter-spacing: 0; text-align: left; text-transform: none; white-space: normal; overflow-wrap: break-word;
    transform: translateX(-50%) translateY(3px); opacity: 0; visibility: hidden; pointer-events: none;
    transition: opacity 120ms linear, transform 120ms var(--ease-out), visibility 0s 120ms; }
  .ihint--end .hint-bubble { left: auto; right: -6px; transform: translateY(3px); }
  .ihint:hover .hint-bubble, .ihint:focus-within .hint-bubble { position: absolute; opacity: 1; visibility: visible; transform: translateX(-50%);
    transition: opacity 120ms linear, transform 120ms var(--ease-out), visibility 0s; }
  .ihint--end:hover .hint-bubble, .ihint--end:focus-within .hint-bubble { transform: none; }
  /* placed by ui.js: fixed, inside the screen, above the button (below when there is no room) */
  .ihint.is-placed .hint-bubble, .ihint.is-placed:hover .hint-bubble, .ihint.is-placed:focus-within .hint-bubble { position: fixed;
    bottom: auto; right: auto; transform: none; transition: opacity 120ms linear, visibility 0s 120ms; }
  .ihint.is-placed:hover .hint-bubble, .ihint.is-placed:focus-within .hint-bubble { transition: opacity 120ms linear, visibility 0s; }
  .ihint.is-shut .hint-bubble { opacity: 0; visibility: hidden; }
  @media print { .ihint { display: none; } }
}

/* ---- loading (core/ui/busy.js): the thin route bar at the top while a page, a form or an htmx answer is on its way (after
   150 ms, so a fast page never flickers), a busy button (disabled, aria-busy, a small spinner, its label kept), and the
   short line for a file being prepared or uploaded. ---- */
@layer components {
  .route-bar { position: fixed; inset: 0 0 auto 0; z-index: calc(var(--z-tip) + 1); height: 3px; pointer-events: none;
    transform-origin: 0 50%; transform: scaleX(0); opacity: 0; background: var(--lit); }
  .route-bar.is-on { opacity: 1; animation: route-trickle 12s cubic-bezier(.1, .7, .2, 1) forwards; }
  .route-bar.is-done { opacity: 0; transform: scaleX(1); animation: none; transition: transform 160ms ease-out, opacity 260ms linear 160ms; }
  @keyframes route-trickle { 0% { transform: scaleX(0); } 10% { transform: scaleX(.35); } 40% { transform: scaleX(.7); } 100% { transform: scaleX(.92); } }
  button[aria-busy="true"], .button[aria-busy="true"], input[type="submit"][aria-busy="true"] { cursor: progress; position: relative; }
  .btn[aria-busy="true"] { cursor: progress; transform: none; }
  .btn--primary[aria-busy="true"], .btn-primary[aria-busy="true"] { background: var(--ink); color: var(--on-ink); box-shadow: var(--sh-btn); opacity: .88; }
  button[aria-busy="true"]::after, .button[aria-busy="true"]::after { content: ""; display: inline-block; flex: none; width: .9em; height: .9em;
    margin-left: .5em; vertical-align: -.12em; border: 2px solid currentColor; border-right-color: transparent; border-radius: 50%;
    animation: spin .7s linear infinite; }
  .busy-note { position: fixed; left: 50%; bottom: 20px; z-index: var(--z-toast); max-width: calc(100vw - 32px); padding: 10px 16px;
    border-radius: 12px; background: var(--ink); color: var(--on-ink); box-shadow: var(--sh-toast); font-size: var(--t-small);
    font-weight: 520; transform: translateX(-50%); display: flex; align-items: center; gap: 10px; }
  .busy-note::before { content: ""; flex: none; width: 14px; height: 14px; border: 2px solid currentColor; border-right-color: transparent;
    border-radius: 50%; animation: spin .7s linear infinite; }
  .busy-note[hidden] { display: none; }
  body.staff .busy-note, [data-density="phone"] .busy-note { bottom: 96px; }
  @media (max-width: 760px) { body.desk .busy-note { bottom: calc(96px + env(safe-area-inset-bottom)); } }
}
@media (prefers-reduced-motion: reduce) {
  @layer components {
    .route-bar.is-on { animation-duration: 30s; }
    button[aria-busy="true"]::after, .button[aria-busy="true"]::after, .busy-note::before { animation-duration: 2s; }
  }
}

/* ============ The Monday's bank files card (banksheet/_monday_card.html, sp-owner-monday) ============
   On Daniel's home column, the Overview's left side and Bank files: how many shops' files are in, Download all, I sent
   these to the bank, then each shop's state in one wrapped row. Download all and I sent these share .mall. */
@layer components {
  .mcard { display: grid; gap: 10px; margin: 0 0 18px; }
  .mcard .eyebrow { display: flex; align-items: center; gap: 6px; margin: 0; }
  .mcard-h { display: flex; align-items: center; gap: 8px; font-size: 21px; line-height: 1.2; font-weight: 680; letter-spacing: -.012em; margin: 0; }
  .mcard-sub { display: flex; gap: 8px; align-items: flex-start; margin: 0; font-size: 14px; color: var(--ink-2); }
  .mcard-sub .mark { flex: none; margin-top: 2px; }
  .mcard-act { display: grid; gap: 6px; margin-top: 4px; }
  .mcard-act form { margin: 0; }
  .mcard-why { display: block; font-size: 13px; color: var(--ink-3); }          /* its "i" follows the words, never a line alone */
  .mcard-shops { display: flex; flex-wrap: wrap; gap: 6px 14px; margin: 4px 0 0; padding: 10px 0 0; list-style: none; border-top: 1px solid var(--line); }
  .mcard-shops li { display: inline-flex; align-items: center; gap: 6px; font-size: 13px; color: var(--ink-2); }
  .mcard-shops li .status { font-size: 12px; }
  .mcard-shops li span:last-child { white-space: nowrap; }
  .mcard-foot { margin: 0; font-size: 13px; }
  .mcard.is-sent .mcard-h { font-size: 18px; }
  .mall-lede { margin: 6px 0 0; max-width: 62ch; font-size: 14.5px; color: var(--ink-2); }
  .mall-form { display: grid; gap: 18px; }
  .mall-list { list-style: none; margin: 0; padding: 0; }
  .mall-list .dl-line { display: flex; align-items: center; gap: 10px; }
  .mall-list .dl-tx { display: grid; gap: 2px; min-width: 0; }
  .mall-list .dl-tx small { font-size: 12.5px; color: var(--ink-3); }
  .mall-list .dl-amt { margin-left: auto; white-space: nowrap; }
  .mall-tick { flex: 1; min-width: 0; margin: 0 !important; align-items: center !important; }
  .mall-go { display: grid; gap: 10px; margin: 6px 0 18px; justify-items: start; }
  .mall-go .btn--lg { min-width: min(100%, 320px); }
  .mall-more, .mall-foot { margin: 8px 0 0; font-size: 13px; }
  .mcard-foot .link, .mall-foot .link { display: inline-flex; align-items: center; min-height: 44px; margin-block: -12px; }  /* a 44 px target, same line */
  .mall-shop > .dl-body { display: grid; gap: 10px; padding: 14px 20px 16px; }  /* a shop's warnings: off the card's edges */
  .mall-shop > .dl-body > * { margin: 0; }
  @media (max-width: 520px) {
    .mcard-h { font-size: 19px; }
    .mall-go { justify-items: stretch; }
  }
}

/* Undo Paid (core/_undo_paid.html, 1 Nov 2026): a quiet button that opens its confirm and reason box in place; and a
   refused decision said on its own line (core.templatetags.ui line_refused, monday.js). */
@layer components {
  .undo-paid { margin-top: var(--sp-2); min-width: 0; }
  .undo-paid > summary { list-style: none; display: inline-flex; width: auto; }
  .undo-paid > summary::-webkit-details-marker { display: none; }
  .undo-paid .mc-confirm-body { display: flex; flex-direction: column; align-items: stretch; gap: var(--sp-2); margin-top: var(--sp-2);
    padding: var(--sp-3) var(--sp-4); background: var(--paper-2); border-radius: var(--r-2); max-width: 520px; text-align: left; }
  .undo-paid .mc-confirm-body p { overflow-wrap: anywhere; }
  .undo-paid .field input { width: 100%; }
  .undo-paid .mc-confirm-body > .btn { align-self: flex-start; }
  .board-row > .undo-paid { grid-column: 1 / -1; }
  .dl-line.undo-line { flex-wrap: wrap; }
  .dl-line.undo-line > .undo-paid { flex-basis: 100%; }
  .line-refused { margin: var(--sp-2) 0; }
}
@layer components {
  .om-typed { margin-top: var(--sp-4); }
  .om-typed .mc-confirm-body { display: flex; flex-direction: column; align-items: stretch; gap: var(--sp-2); margin-top: var(--sp-2);
    padding: var(--sp-3) var(--sp-4); background: var(--paper-2); border-radius: var(--r-2); }
  .om-typed .field input { width: 100%; }
}
@layer components {
  .om-grand { margin-top: var(--sp-4); }
  .om-grand-sums { display: grid; grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr)); gap: var(--sp-2); margin: var(--sp-2) 0; }
  .om-grand-sums > div { display: flex; flex-direction: column; padding: var(--sp-2) var(--sp-3); background: var(--paper-2); border-radius: var(--r-2); }
  .om-grand-sums dt { font-size: var(--fs-sm, .875rem); color: var(--ink-2); }
  .om-grand-sums dd { margin: 0; font-size: 1.25rem; font-weight: 700; font-variant-numeric: tabular-nums; }
  .om-grand-parts, .om-grand-shops ul { list-style: none; margin: 0; padding: 0; }
  .om-grand-parts li { display: flex; justify-content: space-between; gap: var(--sp-3); padding: var(--sp-1) 0; border-bottom: 1px solid var(--line); }
  .om-grand-parts b { font-variant-numeric: tabular-nums; white-space: nowrap; }
  .om-grand-shops { margin-top: var(--sp-3); }
  .om-grand-shops summary { cursor: pointer; font-weight: 600; min-height: 44px; display: flex; align-items: center; }
  .om-grand-shops li { display: flex; flex-direction: column; padding: var(--sp-2) 0; border-bottom: 1px solid var(--line); }
  .om-grand-shops li span { color: var(--ink-2); overflow-wrap: anywhere; }
}
@layer components {
  /* the desk week page: Undo Paid spans the file's row (its list box grows: pages/monday.css) */
  .mc-file > .undo-paid { grid-column: 1 / -1; justify-self: end; max-width: 32rem; width: 100%; }
  .mc-file > .undo-paid > summary { margin-left: auto; }
}
/* S20 (help-words, 7 Nov): a desk page on a phone (Sreepriya at 390, a desk link Daniel opens) has 44 px targets, as the phone
   pages do (tests/e2e/a11y.mjs min 44 there). Every rule only raises: the desk sizes under 44 go up, and anything a page already
   made bigger keeps its size (a min-height in a later layer would replace it, never floor it). Every selector names body.desk:
   the staff phone shell loads this file too. */
@layer components {
  @media screen and (max-width: 900px) {
    :root:not([data-density="phone"]) body.desk { --target: 44px; --h-control: 44px; }
    body.desk .hint-btn { width: 44px; height: 44px; margin: -14px -12px; }
    body.desk .inline-form select, body.desk .inline-form input, body.desk .btn--quiet { min-height: 44px; }
    :where(body.desk) :where(summary, .link) { min-height: 44px; }            /* no weight: any page rule for its height wins */
  }
}
@layer utilities {
  @media screen and (max-width: 900px) {
    /* the busy screens' own sizes under 44 (today.css, flags.css, overview.css, bank.css), raised */
    body.desk .td-row .act .btn, body.desk .td-result-act .btn, body.desk .td-row .act .inline-form input[name="note"],
    body.desk .td-in-head .link, body.desk .td-line .link, body.desk .td-week > summary, body.desk .fl-filter select,
    body.desk .fl-filter > .btn, body.desk .fl-act .btn--sm, body.desk .fl-group-go, body.desk .fl-more a, body.desk .seeall,
    body.desk .bk-h2-link, body.desk .td-others > summary { min-height: 44px; }
    body.desk a.t, body.desk .pm-mid small > a { display: inline-flex; align-items: center; min-height: 44px; margin-block: -12px; }
    body.desk .bk-tl-run a.t { display: flex; min-height: 44px; }      /* a step's whole row, as wide as before (.run-step .t) */
  }
}
