/* Shopkeep, Core's staff operations app (formerly Steward, before that Guildhall).
   Plain CSS, no external fonts or scripts (CSP); the one face, for the wordmark, is served
   from this server beside the lobby TV's. The design language is written
   down in web/DESIGN.md; the short version:

     one question per page, one primary action;
     a row is two lines: a title with at most one pill, then one line of facts;
     colour means "needs attention", everything else is neutral;
     blank fields are not drawn, empty sections fold to a line;
     figures only when the number changes what you do next;
     explanations fold under "How this works";
     the rail lists what you use, badges count only what is yours to do.

   Every class names the thing it styles. */

@font-face { font-family: "Big Shoulders Display"; src: url("/tv/fonts/BigShouldersDisplay-VF.ttf") format("truetype"); font-weight: 100 900; font-display: swap; }

:root {
  color-scheme: light;

  --bg: #f4f5f7;
  --surface: #ffffff;
  --surface-2: #f7f8fa;
  --surface-3: #eef0f3;
  --raised: #ffffff;      /* popovers, menus and search results: one step above the page, with a 1px --line */
  --raised-hover: #eef0f3;
  --ink: #15181c;
  --ink-2: #454c56;
  --ink-3: #5f6670;      /* 5.3:1 on --bg */
  --line: #e5e7eb;
  --line-2: #d2d7dd;
  --control: #8a919b;    /* the edge of a text field or select: 3:1 on --surface */
  --control-edge: var(--control); /* a field's edge against whatever it sits on; the dark top bar sets its own */

  /* Core green, darkened only as far as white text on it needs (4.9:1). */
  --accent: #437e1b;
  --accent-2: #376a15;
  --accent-soft: #e8f2df;
  --today: color-mix(in srgb, var(--accent-soft) 60%, transparent);
  --accent-ink: #24470d;
  --accent-contrast: #ffffff;
  --primary: #437e1b;     /* filled buttons; dark mode uses a calmer green than its links */
  --primary-2: #376a15;
  --primary-ink: #ffffff;

  --ok: #0b7472;         /* done is teal, apart from the accent green of links and buttons */
  --ok-soft: #e0f3f1;
  --warn: #9a5208;
  --warn-soft: #fcf1e2;
  --danger: #c0202f;
  --danger-soft: #fce9eb;
  --neutral-soft: #eef0f3;
  /* Counts: neutral unless what they count is overdue, then the badge colour. */
  --count-bg: #e2e5ea;
  --count-ink: #15181c;
  --badge-bg: #c0202f;
  --badge-ink: #ffffff;
  --store-soft: #efe7fb;
  --store-ink: #5b2ea6;
  --mine-soft: #dff3f3;
  --mine-ink: #0e6b6b;
  /* Game dots: at least 3:1 on the surface and on a segmented control, in both themes. */
  --g-magic: #9333ea; --g-pokemon: #a16207; --g-riftbound: #0284c7; --g-cyberpunk: #db2777; --g-one-piece: #ea580c;
  --g-sports: #0d9488; --g-show: #8d6e63; --g-other: #6b7280; --g-prerelease: #334155;

  --side-bg: #f4f5f7;
  --bar-bg: #ffffff;

  /* Core's house colours, shared with the Guildhall player app: the app bar and the wordmark. */
  --core-black: #161a13;
  --core-green: #7ac142;
  --display: "Big Shoulders Display", "Arial Narrow", var(--sans);

  /* Radii: 4 for chips and keys, 8 for controls, 12 for cards and sheets, a pill for pills. */
  --r-sm: 4px;
  --radius: 8px;
  --radius-lg: 12px;
  --r-pill: 999px;
  --shadow: 0 1px 2px rgba(16, 24, 40, 0.04);
  --shadow-lg: 0 12px 32px rgba(16, 24, 40, 0.16);
  --scrim: rgba(16, 24, 40, 0.42);   /* behind a dialog, a sheet or the open drawer */
  --scrim-strong: rgba(16, 24, 40, 0.55);
  --sans: ui-sans-serif, -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
  --mono: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  --bar-h: 56px;
  --side-w: 228px;
  --tab-h: 60px;

  /* Type scale: seven sizes, nothing readable under 12px. (Phone text fields stay 16px so iOS
     does not zoom; the wordmark has its own sizes.) */
  --t-xs: 12px; --t-sm: 13px; --t-md: 15px; --t-lg: 17px; --t-xl: 20px; --t-2xl: 24px; --t-3xl: 28px;

  /* spacing scale */
  --s1: 4px; --s2: 8px; --s3: 12px; --s4: 16px; --s5: 20px; --s6: 24px; --s8: 32px;
  --row-x: 18px;      /* the horizontal inset of a row inside a card */
}
:root[data-theme="dark"] {
  color-scheme: dark;
  --bg: #0f120d;
  --surface: #171b14;
  --surface-2: #1d2219;
  --surface-3: #262c21;
  --raised: #252c20;
  --raised-hover: #323b2b;
  --ink: #eef1ea;
  --ink-2: #c8cdc4;
  --ink-3: #959c8f;
  --line: #303828;      /* cards separate from the page */
  --line-2: #3c4534;
  --control: #657058;
  --accent: #9ccc78;
  --accent-2: #b0d993;
  --accent-soft: #1f2c16;
  --today: color-mix(in srgb, var(--accent) 14%, transparent);
  --accent-ink: #c5e8a6;
  --accent-contrast: #0c0f0a;
  --primary: #5ea532;     /* 6.3:1 with --primary-ink; deep enough not to be the brightest thing on a dark screen */
  --primary-2: #6aaf3d;
  --primary-ink: #0c0f0a;
  --ok: #4fd1c5;
  --ok-soft: #11302d;
  --warn: #f2b25b;
  --warn-soft: #362710;
  --danger: #ff7a86;
  --danger-soft: #3a191e;
  --neutral-soft: #2a3024;
  --count-bg: #343b2d;
  --count-ink: #eef1ea;
  --badge-bg: #d33a48;
  --badge-ink: #ffffff;
  --store-soft: #2c2140;
  --store-ink: #c9adff;
  --mine-soft: #143333;
  --mine-ink: #7fd8d8;
  --g-magic: #c084fc; --g-pokemon: #eab308; --g-riftbound: #38bdf8; --g-cyberpunk: #f472b6; --g-one-piece: #fb923c;
  --g-sports: #2dd4bf; --g-show: #bcaaa4; --g-other: #9ca3af; --g-prerelease: #94a3b8;
  --side-bg: #0f120d;
  --bar-bg: #161a13;
  --shadow: none;
  --shadow-lg: 0 12px 32px rgba(0, 0, 0, 0.6);
  --scrim: rgba(0, 0, 0, 0.55);
  --scrim-strong: rgba(0, 0, 0, 0.7);
}

/* ---------- Base ---------- */

* { box-sizing: border-box; }
html, body { margin: 0; height: 100%; }
body {
  font-family: var(--sans);
  font-size: var(--t-md);
  line-height: 1.5;
  color: var(--ink);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
}
/* hidden always hides, whatever display a class gives (folded strip chips are .btn). */
[hidden] { display: none !important; }
h1, h2, h3, h4 { margin: 0; font-weight: 600; letter-spacing: -0.01em; }
h1 { font-size: var(--t-2xl); line-height: 1.25; letter-spacing: -0.015em; text-wrap: balance; }
h2 { font-size: var(--t-lg); }
h3 { font-size: var(--t-md); }
h4 { font-size: var(--t-md); }
p { margin: 0; }
a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }
button { font: inherit; color: inherit; }
input, select, textarea { font: inherit; color: var(--ink); }
strong { font-weight: 600; }
kbd { font-family: var(--mono); font-size: var(--t-xs); }
svg.i { width: 18px; height: 18px; flex: none; fill: none; stroke: currentColor; stroke-width: 1.75; stroke-linecap: round; stroke-linejoin: round; vertical-align: -3px; }
svg.i.sm { width: 14px; height: 14px; vertical-align: -2px; }
svg.i.left { transform: rotate(90deg); }
svg.i.right { transform: rotate(-90deg); }
summary { list-style: none; }
summary::-webkit-details-marker { display: none; }

.skip { position: absolute; left: -999px; }
.skip:focus { left: 12px; top: 12px; background: var(--surface); padding: 8px; z-index: 99; }
/* Before the app answers: the dark bar and the wordmark, then a quiet line. */
.boot { min-height: 100vh; display: flex; flex-direction: column; background: var(--bg); }
.boot .boot-main { flex: 1; display: grid; place-items: center; color: var(--ink-3); }

.muted { color: var(--ink-3); }
.small { font-size: var(--t-sm); }
.mono { font-family: var(--mono); font-size: var(--t-sm); white-space: nowrap; }
/* An ID keeps its real hyphen and never wraps; a short fact never splits; a fact line breaks evenly. */
.ticket-num, .mono, .doc-no, .id { white-space: nowrap; }
.fact { white-space: nowrap; }
.list .meta, .todo .meta, .mini .meta, td .sub, .page-head .sub, .tab-sub { text-wrap: pretty; }
/* Home's to-do lines wrap pretty: the full width, and a tail ("was due.") never sits alone. */
.todo .meta { text-wrap: pretty; }
td.m-cell, th.m-cell { display: none; }
.nowrap { white-space: nowrap; }
.problem { color: var(--danger); }
.link { color: var(--accent); text-decoration: underline; }
.footnote { font-size: var(--t-sm); color: var(--ink-3); margin-top: 14px; max-width: 80ch; }
.form input[readonly], .form textarea[readonly], .form select[disabled] { background: var(--neutral-soft); color: var(--ink-2); cursor: not-allowed; }

:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* ---------- Wordmark ---------- */

/* SHOPKEEP in Core's display face over a short green rule. Type only: no emblem. */
.wordmark { font-family: var(--display); font-weight: 800; font-size: 24px; line-height: 1; letter-spacing: 0.06em; text-transform: uppercase; padding-bottom: 3px; border-bottom: 3px solid var(--core-green); }

/* ---------- Sign-in ---------- */

.signin { min-height: 100vh; position: relative; display: grid; place-items: center; padding: 48px 24px; background: var(--bg); }
.signin .theme-btn { position: absolute; top: 12px; right: 16px; }
.signin-main { width: min(420px, 100%); display: grid; gap: 24px; }
.signin-brand { display: grid; justify-items: start; gap: 12px; }
.signin-brand .wordmark { font-size: 32px; color: var(--ink); }
.signin-greet { color: var(--ink-2); font-size: var(--t-md); }
.signin-card { width: min(420px, 100%); background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius-lg); box-shadow: var(--shadow); padding: 28px; display: grid; gap: 18px; }
.signin-card h1 { font-size: var(--t-xl); }
.google-btn {
  display: flex; align-items: center; justify-content: center; gap: 10px;
  width: 100%; padding: 10px 16px; border: 1px solid var(--line-2); border-radius: var(--radius); background: var(--surface); cursor: pointer; font-weight: 600; text-decoration: none;
}
.google-btn:hover { background: var(--surface-2); }
.google-btn svg { width: 18px; height: 18px; }
.divider { display: flex; align-items: center; gap: 12px; color: var(--ink-3); font-size: var(--t-xs); }
.divider::before, .divider::after { content: ""; flex: 1; height: 1px; background: var(--line); }
.preview-roles { display: grid; gap: 6px; }
.preview-role {
  display: grid; grid-template-columns: 36px 1fr auto; gap: 12px; align-items: center; text-align: left;
  padding: 8px 10px; border: 1px solid transparent; border-radius: var(--radius); background: transparent; cursor: pointer;
}
.preview-role:hover { background: var(--surface-2); border-color: var(--line); }
.preview-role .who { font-weight: 600; }
.preview-role .blurb { color: var(--ink-3); font-size: var(--t-sm); display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.signin-card .form .actions { justify-content: stretch; }
.signin-card .form .actions .btn { flex: 1; justify-content: center; }
.signin-error { padding: 10px 12px; border-radius: var(--radius); background: var(--danger-soft); color: var(--danger); font-size: var(--t-sm); }
.signin-note { padding: 10px 12px; border-radius: var(--radius); background: var(--surface-2); border: 1px solid var(--line); font-size: var(--t-sm); }
.signin-note code { font-family: var(--mono); font-size: var(--t-xs); overflow-wrap: anywhere; }

/* ---------- Shell ---------- */

.shell { display: grid; grid-template-columns: var(--side-w) minmax(0, 1fr); grid-template-rows: var(--bar-h) 1fr; min-height: 100vh; }

.topbar {
  grid-column: 1 / -1; position: sticky; top: 0; z-index: 30; height: var(--bar-h);
  display: flex; align-items: center; gap: 8px; padding: 0 16px 0 18px;
  background: var(--bar-bg); border-bottom: 1px solid var(--line); color: var(--ink);
  color-scheme: dark; --bar-bg: var(--core-black); --ink: #eef1ea; --ink-2: #c8cdc4; --ink-3: #9aa294; --line: #2a3124; --line-2: #3a4233;
  --surface: #1e241a; --surface-2: #1e241a; --surface-3: #2a3124; --control-edge: #6b7562; --accent: #8fd653; --accent-soft: #2a3a1d; --accent-ink: #c5e8a6; --accent-contrast: #0c0f0a;
}
.topbar .brand { display: flex; align-items: center; text-decoration: none; color: inherit; width: calc(var(--side-w) - 34px); flex: none; }
.topbar .brand:hover { text-decoration: none; }
.topbar .brand .wordmark { font-size: 22px; }
.search { position: relative; flex: 0 1 400px; margin-right: auto; }
.search input {
  width: 100%; height: 36px; padding: 0 36px 0 36px; border: 1px solid var(--control-edge); border-radius: var(--radius); background: var(--surface-2);
}
.search input::-webkit-search-cancel-button { display: none; }
.search input:focus { background: var(--surface); border-color: var(--accent); outline: none; box-shadow: 0 0 0 3px var(--accent-soft); }
.search > svg { position: absolute; left: 11px; top: 50%; transform: translateY(-50%); color: var(--ink-3); pointer-events: none; }
.search kbd { position: absolute; right: 9px; top: 50%; transform: translateY(-50%); color: var(--ink-3); border: 1px solid var(--line-2); border-radius: var(--r-sm); padding: 0 5px; line-height: 16px; pointer-events: none; }
.search input:focus ~ kbd { display: none; }
.search-results { position: absolute; top: calc(100% + 6px); left: 0; right: 0; background: var(--raised); border: 1px solid var(--line); border-radius: var(--radius-lg); box-shadow: var(--shadow-lg); padding: 6px; z-index: 40; }
/* The bar is always dark; the results drop onto the page, so they take the page's own colours. */
:root:not([data-theme="dark"]) .topbar .search-results { color-scheme: light; --surface: #ffffff; --surface-3: #eef0f3; --line: #e5e7eb; --ink: #15181c; --ink-3: #5f6670; --accent-soft: #e8f2df; --accent-ink: #24470d; --raised: #ffffff; --raised-hover: #eef0f3; color: var(--ink); }
/* Search dims the page under its results at every width, so results never read as part of the page under them.
   The bar is its own stacking context (sticky, z 30): it is lifted over the scrim so its results are not dimmed. */
.shell:is(.search-open, :has(.topbar .search-results:not([hidden])))::after { content: ""; position: fixed; inset: var(--bar-h) 0 0; background: var(--scrim); z-index: 40; }
.shell:is(.search-open, :has(.topbar .search-results:not([hidden]))) .topbar { z-index: 41; }
.topbar .search-results { max-height: min(60vh, 520px); overflow: auto; }
.iconbtn.search-btn { display: none; }
.search-results a { display: flex; align-items: flex-start; gap: 10px; padding: 8px 10px; border-radius: var(--r-sm); color: inherit; }
.search-results a > svg { margin-top: 2px; color: var(--ink-3); }
.search-results a:hover, .search-results a.sel { background: var(--raised-hover); text-decoration: none; }
.search-results .name { display: block; font-weight: 600; }
.search-results .blurb { display: block; color: var(--ink-3); font-size: var(--t-sm); }
.search-results .none { padding: 8px 10px; color: var(--ink-3); }
.search-results mark { background: none; color: inherit; text-decoration: underline 2px var(--accent); text-underline-offset: 3px; }

.iconbtn { position: relative; width: 36px; height: 36px; border: 0; border-radius: var(--radius); background: transparent; cursor: pointer; display: grid; place-items: center; color: var(--ink-2); flex: none; padding: 0; }
.iconbtn:hover { background: var(--surface-3); text-decoration: none; }
.iconbtn.sm { width: 32px; height: 32px; border-radius: var(--r-sm); }
/* A small ⋯ looks 32px but takes a 44px press: the hit area reaches past it, invisibly. */
.iconbtn.sm::after { content: ""; position: absolute; inset: -6px; }
.iconbtn .badge { position: absolute; top: -2px; left: 21px; box-sizing: border-box; min-width: 18px; height: 18px; padding: 0 4px; border-radius: var(--r-pill); background: var(--count-bg); color: var(--count-ink); font-size: var(--t-xs); font-weight: 700; display: grid; place-items: center; line-height: 1; border: 1.5px solid var(--bar-bg); }
/* The count sits clear of the glyph. It is neutral (everything waiting); a red ring on it says some of it is overdue: two shapes, not three. */
.iconbtn .badge.due { border-color: var(--danger); box-shadow: 0 0 0 1px var(--bar-bg); }
.menu-btn { display: none; }

.userbtn { display: flex; align-items: center; gap: 8px; padding: 3px 8px 3px 3px; border: 0; border-radius: var(--r-pill); background: transparent; cursor: pointer; color: var(--ink-2); }
.userbtn:hover { background: var(--surface-3); }
.userbtn .uname { font-weight: 600; color: var(--ink); }

/* Fixed, like the sticky bar it drops from, so it opens in view however far the page is scrolled. */
.popover { position: fixed; top: calc(var(--bar-h) - 6px); right: 16px; width: 360px; background: var(--raised); border: 1px solid var(--line); border-radius: var(--radius-lg); box-shadow: var(--shadow-lg); z-index: 40; overflow: hidden; }
.popover .pop-head { padding: 12px 16px; border-bottom: 1px solid var(--line); display: flex; align-items: center; justify-content: space-between; }
.popover .pop-head h3 { font-size: var(--t-md); }
.popover .pop-body { max-height: min(440px, calc(100vh - var(--bar-h) - 80px)); overflow: auto; padding-bottom: 6px; }
.popover .pop-body.more { -webkit-mask-image: linear-gradient(to bottom, #000 calc(100% - 28px), transparent); mask-image: linear-gradient(to bottom, #000 calc(100% - 28px), transparent); }
.pop-scrim { position: fixed; inset: 0; background: var(--scrim); z-index: 45; }
.popover .pop-sec { font-size: var(--t-xs); font-weight: 600; color: var(--ink-3); padding: 12px 16px 2px; }
.popover .pop-list { list-style: none; margin: 0; padding: 2px 6px; }
.popover .pop-list a { display: flex; gap: 10px; align-items: flex-start; padding: 8px 10px; border-radius: var(--r-sm); color: inherit; }
.popover .pop-list a > svg { margin-top: 1px; color: var(--ink-3); }
.popover .pop-list a.danger > svg { color: var(--danger); }
.popover .pop-list a.warn > svg { color: var(--warn); }
.popover .pop-list a:hover { background: var(--surface-3); text-decoration: none; }
.popover .pop-list .t { font-weight: 600; }
/* Short lines balance, so a sentence's tail ("was due.") never sits alone. */
.popover .pop-list .t, .popover .pop-list .m { text-wrap: balance; }
.popover .pop-list .m { color: var(--ink-3); font-size: var(--t-sm); display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.popover .pop-empty { padding: 24px 16px; color: var(--ink-3); text-align: center; }
.popover .pop-user { padding: 14px 16px; display: flex; gap: 12px; align-items: center; border-bottom: 1px solid var(--line); }
.popover .pop-menu { padding: 6px; display: grid; }
.popover .pop-menu + .pop-menu, .pop-theme + .pop-menu { border-top: 1px solid var(--line); }
.popover .pop-menu a, .popover .pop-menu button { display: flex; align-items: center; gap: 10px; padding: 8px 10px; border: 0; border-radius: var(--r-sm); background: transparent; cursor: pointer; text-align: left; color: inherit; width: 100%; }
.popover .pop-menu a:hover, .popover .pop-menu button:hover { background: var(--raised-hover); text-decoration: none; }
.popover.user { width: 272px; }
.pop-theme { padding: 10px 16px; border-top: 1px solid var(--line); display: flex; align-items: center; justify-content: space-between; gap: 10px; font-size: var(--t-sm); color: var(--ink-3); }
.pop-theme .seg .btn { padding: 3px 8px; font-size: var(--t-xs); }

.rail {
  background: var(--side-bg); border-right: 1px solid var(--line); padding: 12px 10px 0;
  display: flex; flex-direction: column; position: sticky; top: var(--bar-h); height: calc(100vh - var(--bar-h)); overflow-y: auto;
}
.rail .sec { font-size: var(--t-xs); color: var(--ink-3); font-weight: 600; letter-spacing: 0.02em; padding: 22px 10px 4px; }
.nav-item {
  display: flex; align-items: center; gap: 11px; padding: 6px 10px; margin: 1px 0; color: var(--ink-2); border-radius: var(--radius);
  text-decoration: none; border: 0; background: transparent; width: 100%; text-align: left; cursor: pointer; font-weight: 500;
}
.nav-item:hover { background: var(--surface-3); color: var(--ink); text-decoration: none; }
.nav-item.active { background: var(--surface); color: var(--ink); font-weight: 600; box-shadow: inset 0 0 0 1px var(--line); }
.nav-item .i { color: var(--ink-3); }
.nav-item.active .i { color: var(--accent); }
/* One count style everywhere it appears: the rail, a page's tabs, and the phone's tab bar. */
.nav-item .count, .tabs .count, .tabbar i, .tally { min-width: 20px; padding: 0 6px; line-height: 20px; border-radius: var(--r-pill); text-align: center; font-size: var(--t-xs); font-weight: 700; font-style: normal; background: var(--count-bg); color: var(--count-ink); font-variant-numeric: tabular-nums; }
.nav-item .count.due, .tabs .count.due, .tabbar i.due, .tally.due { background: var(--badge-bg); color: var(--badge-ink); }
.nav-item .count { margin-left: auto; }
.nav-item .count.wait { height: 20px; }
.nav-item .count.wait, .iconbtn .badge.wait { opacity: 0.35; }
/* More stays reachable: it sits at the foot of the rail and pins there when the list scrolls. */
.rail .more { margin-top: auto; border-top: 1px solid var(--line); padding: 8px 0 12px; position: sticky; bottom: 0; background: var(--side-bg); }
.rail > :nth-last-child(2):has(+ .more) { margin-bottom: 12px; }
.rail .more > summary { color: var(--ink-3); }
.rail .more > summary .i { transition: transform 0.15s; transform: rotate(-90deg); }
.rail .more[open] > summary .i { transform: none; }
.scrim { display: none; }
.tabbar { display: none; }

.avatar {
  width: 32px; height: 32px; border-radius: 50%; display: grid; place-items: center; font-size: var(--t-xs); font-weight: 600;
  background: var(--accent-soft); color: var(--accent-ink); flex: none;
}
.avatar.sm { width: 26px; height: 26px; font-size: var(--t-xs); }
.avatar.large { width: 48px; height: 48px; font-size: var(--t-lg); }
.avatar.bot { background: var(--neutral-soft); color: var(--ink-2); }

/* ---------- Page ---------- */

.main { padding: 28px 40px 72px; max-width: 1180px; width: 100%; min-width: 0; }
.page-head { display: flex; align-items: flex-end; justify-content: space-between; gap: 16px; margin-bottom: 20px; flex-wrap: wrap; }
.page-head .sub { color: var(--ink-3); margin-top: 3px; }
.page-head .actions { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }
/* A head above tabs keeps one height on every tab (title, a sub-line's room, the actions), so the tabs never move. */
.page-head:has(+ .tabs) { min-height: 56px; align-items: flex-start; align-content: flex-start; }
/* On a phone the reserve is only for a page whose heads have a sub-line (.subs marks a page where only some tabs do);
   a title alone sits on the tabs with no empty band. */
@media (max-width: 860px) { .page-head:has(+ .tabs) { min-height: 36px; } .page-head:is(:has(.sub), .subs):has(+ .tabs) { min-height: 72px; } }
.back-link { display: inline-flex; align-items: center; gap: 2px; font-size: var(--t-sm); color: var(--ink-3); margin: 0 0 4px -4px; padding: 4px 6px 4px 0; min-height: 32px; }
.back-link .i { width: 16px; height: 16px; }
.back-link:hover { color: var(--ink); }
.ticket-subject > .meta { color: var(--ink-3); font-size: var(--t-sm); font-weight: 400; }

/* Tabs move between the views of one page. */
.tabs { display: flex; gap: 2px; border-bottom: 1px solid var(--line); margin: -8px 0 20px; overflow-x: auto; scrollbar-width: none; }
.tabs::-webkit-scrollbar { display: none; }
/* A tab strip wider than the screen fades at the edge it continues past (app.js sets the classes); a chip strip folds the rest under "+N" instead (foldStrip). */
.tabs.fade-r { -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 40px), transparent); mask-image: linear-gradient(to right, #000 calc(100% - 40px), transparent); }
.tabs.fade-l { -webkit-mask-image: linear-gradient(to left, #000 calc(100% - 40px), transparent); mask-image: linear-gradient(to left, #000 calc(100% - 40px), transparent); }
.tabs.fade-l.fade-r { -webkit-mask-image: linear-gradient(to right, transparent, #000 40px, #000 calc(100% - 40px), transparent); mask-image: linear-gradient(to right, transparent, #000 40px, #000 calc(100% - 40px), transparent); }
.tabs a { display: inline-flex; align-items: center; gap: 6px; padding: 9px 12px; color: var(--ink-3); font-weight: 500; border-bottom: 2px solid transparent; margin-bottom: -1px; white-space: nowrap; }
.tabs a:hover { color: var(--ink); text-decoration: none; }
.tabs a.on { color: var(--ink); border-bottom-color: var(--accent); font-weight: 600; }
.tabs .tabs-more { flex: none; margin-left: auto; }
.tabs .tabs-more > summary { display: inline-flex; align-items: center; gap: 4px; padding: 9px 12px; min-height: 44px; color: var(--ink-3); font-weight: 500; list-style: none; white-space: nowrap; }
.tabs .tabs-more > summary::-webkit-details-marker { display: none; }
.tabs .tabs-more.on > summary { color: var(--ink); font-weight: 600; box-shadow: inset 0 -2px 0 var(--accent); }
.tabs .tabs-more .menu-item .count { margin-left: auto; }
.tabs .tabs-more .menu-item.on { font-weight: 600; color: var(--ink); box-shadow: inset 3px 0 0 var(--accent); }
/* A phone tab strip whose open tab is under More names that section in a small heading below it. */
.tab-here { font-size: var(--t-md); font-weight: 600; color: var(--ink); margin: -4px 0 12px; }

/* The row of controls above a view: where you are in time, and how you are looking at it. */
.viewbar { display: flex; align-items: center; gap: 10px 14px; flex-wrap: wrap; margin-bottom: 14px; }
.viewbar .spacer { flex: 1; }
.pager { display: inline-flex; align-items: center; gap: 2px; }
.pager .iconbtn { width: 32px; height: 32px; }
.pager-label { font-weight: 600; font-size: var(--t-lg); min-width: 0; padding: 0 6px; white-space: nowrap; }
.pager .btn { margin-left: 8px; }
.hint { font-size: var(--t-sm); color: var(--ink-3); margin: 0 2px 18px; max-width: 90ch; }
.hint .off { color: var(--ink-3); }

.about { margin-top: 22px; font-size: var(--t-sm); color: var(--ink-3); max-width: 80ch; }
.about > summary { cursor: pointer; width: max-content; display: flex; align-items: center; gap: 4px; list-style: none; min-height: 32px; }
.about > summary::-webkit-details-marker { display: none; }
.about > summary .i { transform: rotate(-90deg); transition: transform 0.15s; }
.about[open] > summary .i { transform: none; }
.about > summary:hover { color: var(--ink-2); }
.about > div { margin-top: 8px; display: grid; gap: 8px; line-height: 1.55; }

/* ---------- Cards and sections ---------- */

.card { background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius-lg); box-shadow: var(--shadow); min-width: 0; }
.card + .card, .card + .grid, .grid + .card, .grid + .grid, .summary + .card, .summary + .grid { margin-top: 18px; }
/* A card head has no rule under it; its padding and weight set it apart. */
.card-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 14px var(--row-x) 6px; }
.card-head h2 { font-size: var(--t-lg); display: flex; align-items: center; gap: 8px; text-wrap: balance; }
.card-head h2 .n { font-weight: 500; color: var(--ink-3); font-variant-numeric: tabular-nums; }
/* A "See all" link in a card head is small; a linked title inside the head keeps its own size. */
.card-head > a, .card-head .head-tools > a { font-size: var(--t-sm); }
.card-head .head-tools { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; justify-content: flex-end; }
.card-body { padding: 16px var(--row-x); }
.card-body.flush { padding: 0; }
.card-action { margin-top: 12px; }

/* A card that folds: its head is the summary. Used for things worth having but not worth reading every visit. */
details.card > summary.card-head { cursor: pointer; border-bottom: 0; justify-content: flex-start; gap: 8px; }
details.card > summary.card-head:hover { background: var(--surface-2); border-radius: var(--radius-lg); }
details.card[open] > summary.card-head:hover { border-radius: var(--radius-lg) var(--radius-lg) 0 0; }
details.card > summary.card-head { padding-bottom: 13px; }
details.card[open] > summary.card-head { padding-bottom: 6px; }
/* Single-line folds that sit together are one card with ruled rows, not a card each. */
/* Adjacent folds share one card (groupFolds): the group draws the border, radius and shadow; inside, one 1px rule. */
.fold-group { overflow: hidden; }
.fold-group > details.card { border: 0; border-radius: 0; box-shadow: none; margin: 0; background: transparent; }
.fold-group > details.card + details.card, .ticket-layout .fold-group > details.card + details.card { border-top: 1px solid var(--line); margin-top: 0; }
.fold-group > details.card > summary.card-head:hover, .fold-group > details.card[open] > summary.card-head:hover { border-radius: 0; }
/* A page whose only content is one list: the rows sit on the surface with no frame. */
.card.solo { border-color: transparent; box-shadow: none; }
/* An empty list keeps its card; its one sentence sits where the rows would. */
/* An empty record section is one line: its name, then what would go there. */
.empty-line { display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px 12px; padding: 12px var(--row-x); }
.empty-line + .empty-line { border-top: 1px solid var(--line); }
.empty-line strong { font-weight: 600; }
.empty-line > .btn { margin-left: auto; align-self: center; }
/* A list nothing in can be clicked (On shift today, Coming up) is grouped by space, not rules. */
.list.calm > li { border-bottom: 0; padding-top: 7px; padding-bottom: 7px; }
details.card > summary.card-head .i { color: var(--ink-3); transform: rotate(-90deg); transition: transform 0.15s; }
details.card[open] > summary.card-head .i { transform: none; }
/* A folded section's head is quieter than a content card's, so it never outranks the content. */
details.card > summary.card-head h2 { font-size: var(--t-md); font-weight: 600; color: var(--ink-2); }

.grid { display: grid; gap: 18px; align-items: start; }
.grid > .card + .card { margin-top: 0; }
.grid.cols-1 { grid-template-columns: minmax(0, 1fr); }
.grid.cols-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.grid.cols-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.grid.cols-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.grid.even { align-items: stretch; }
.span-2 { grid-column: span 2; }
.span-3 { grid-column: span 3; }

/* Figures: one light strip, only where the number decides what happens next. */
.summary { display: flex; flex-wrap: wrap; margin: 0 0 18px; padding: 0; background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius-lg); overflow: hidden; }
.summary.grid { gap: 0; }
.summary .figure { flex: 1 1 150px; display: flex; flex-direction: column-reverse; justify-content: flex-end; gap: 1px; padding: 12px var(--row-x); box-shadow: -1px 0 0 var(--line); }
.summary dt { color: var(--ink-3); font-size: var(--t-sm); }
.summary dd { margin: 0; font-weight: 600; font-size: var(--t-xl); line-height: 1.2; font-variant-numeric: tabular-nums; }
.summary .figure.danger dd { color: var(--danger); }
.summary .figure.amber dd { color: var(--warn); }

/* Status pills: one per row, for the state that decides what happens next.
   gem = in hand, gold = waiting on someone, moss = done, sash = needs attention, grey = just a label. */
.status { display: inline-block; font-size: var(--t-xs); font-weight: 600; white-space: nowrap; padding: 1px 8px; border-radius: var(--r-pill); line-height: 1.55; vertical-align: 1px; }
.status::first-letter { text-transform: uppercase; }
.status.gem { background: var(--accent-soft); color: var(--accent-ink); }
.status.sash { background: var(--danger-soft); color: var(--danger); }
.status.gold { background: var(--warn-soft); color: var(--warn); }
.status.moss { background: var(--ok-soft); color: var(--ok); }
.status.grey { background: var(--neutral-soft); color: var(--ink-2); font-weight: 500; }
/* Mandatory is important, not late: ink, outlined, never red. */
.status.strong { background: transparent; color: var(--ink); font-weight: 700; box-shadow: inset 0 0 0 1px var(--ink-3); }
.status.release { margin-top: 4px; }
tr.released td { opacity: .6; }
.role-chip { display: inline-block; font-size: var(--t-xs); font-weight: 500; padding: 1px 8px; border-radius: var(--r-pill); background: var(--neutral-soft); color: var(--ink-2); white-space: nowrap; }
.tag-text { font-size: var(--t-sm); color: var(--ink-3); font-weight: 500; }
.tag-text.warn { color: var(--warn); font-weight: 600; }

.dot { display: inline-block; width: 8px; height: 8px; border-radius: 50%; margin-right: 6px; vertical-align: middle; }
.dot.ok { background: var(--ok); }
.dot.warn { background: var(--warn); }
.dot.error { background: var(--danger); }
/* Off is a ring in --ink-3, so it reads in both themes. A row with a status pill draws no dot. */
.dot.off { background: transparent; box-shadow: inset 0 0 0 1.5px var(--ink-3); }

/* ---------- Buttons ---------- */

.btn {
  display: inline-flex; align-items: center; gap: 6px; padding: 7px 14px;
  border: 1px solid var(--line-2); border-radius: var(--radius); background: var(--surface); cursor: pointer; font-weight: 500; font-size: var(--t-md); white-space: nowrap; text-decoration: none; color: var(--ink); line-height: 1.3;
}
.btn:hover { background: var(--surface-2); text-decoration: none; }
.btn.primary, .btn.gem { background: var(--primary); border-color: var(--primary); color: var(--primary-ink); font-weight: 600; }
.btn.primary:hover, .btn.gem:hover { background: var(--primary-2); border-color: var(--primary-2); }
/* A primary that cannot be pressed looks plain, not like a faded green. */
.btn.primary[disabled] { background: var(--surface-3); border-color: var(--line-2); color: var(--ink-3); opacity: 1; }
.btn.sm { padding: 5px 11px; font-size: var(--t-sm); min-height: 32px; }
.btn.ghost { background: transparent; border-color: transparent; color: var(--accent); }
.btn.ghost:hover { background: var(--accent-soft); }
.btn[disabled] { opacity: 0.5; cursor: not-allowed; }
.btn.ghost.danger { color: var(--danger); }
.linkbtn { border: 0; background: none; padding: 0; color: var(--accent); cursor: pointer; font-size: inherit; }
.linkbtn:hover { text-decoration: underline; }

.seg { display: inline-flex; padding: 3px; background: var(--surface-3); border-radius: var(--radius); gap: 2px; }
.seg .btn { border: 0; background: transparent; color: var(--ink-2); padding: 4px 12px; border-radius: calc(var(--radius) - 3px); min-height: 36px; }  /* concentric inside the 3px padding */
.seg .btn:hover { background: var(--surface); }
.seg .btn.on { background: var(--surface); color: var(--ink); font-weight: 600; box-shadow: 0 1px 2px rgba(16, 24, 40, 0.1); }
.seg.wrap-row { flex-wrap: wrap; margin: 0 0 14px; }

/* The overflow menu: everything a row can do that is not its one visible action.
   The list is positioned by app.js when it opens, so a scrolling table cannot clip it. */
.menu { position: relative; display: inline-block; }
.menu > summary { cursor: pointer; color: var(--ink-3); }
.menu[open] > summary { background: var(--surface-3); color: var(--ink); }
.menu-pop { position: fixed; z-index: 45; min-width: 180px; padding: 6px; background: var(--raised); border: 1px solid var(--line); border-radius: var(--radius); box-shadow: var(--shadow-lg); display: grid; }
.menu-item { display: flex; align-items: center; gap: 10px; width: 100%; padding: 8px 10px; border: 0; border-radius: var(--r-sm); background: transparent; cursor: pointer; text-align: left; color: var(--ink); font-size: var(--t-md); white-space: nowrap; text-decoration: none; }
.menu-item:hover { background: var(--raised-hover); text-decoration: none; }
.menu-item.danger { color: var(--danger); }
/* A destructive choice inside a dialog (a review's Deny): a plain button in red text. */
.btn.danger-text { color: var(--danger); }
/* The sheet behind a strip's "+N": one 44px row per hidden chip. */
.strip-sheet { display: grid; gap: 2px; margin: -4px -6px; }
.strip-sheet .menu-item .unread { margin-left: auto; }
.menu-item[disabled] { opacity: 0.5; cursor: not-allowed; }
.menu-sep { height: 1px; background: var(--line); margin: 5px 4px; }

/* ---------- Lists and tables ----------
   A row is two lines: .title (with at most one .status) and .meta. */

.list { list-style: none; margin: 0; padding: 0; }
.list > li { display: flex; gap: 14px; align-items: center; padding: 12px var(--row-x); border-bottom: 1px solid var(--line); }
.list > li:last-child { border-bottom: 0; }
.list .grow { flex: 1; min-width: 0; }
/* A card head (16px, 600) outranks a row title (15px, 500, ink). */
.list .title { font-weight: 500; color: var(--ink); display: flex; flex-wrap: wrap; align-items: baseline; column-gap: 6px; row-gap: 2px; }
.list li.row-click { cursor: pointer; }
.list li.row-click:hover { background: var(--surface-2); }
.linkbtn.row-open { color: inherit; font-weight: inherit; text-align: left; min-height: 0; }
.linkbtn.row-open:hover { text-decoration: underline; }
/* A row that opens: the whole row is the target, the title link is there for the keyboard. */
.list li[data-href], tr[data-href] { cursor: pointer; }
.list li[data-href]:hover { background: var(--surface-2); }
.list .title a { color: inherit; }
.list .meta { color: var(--ink-3); font-size: var(--t-sm); margin-top: 2px; }
.list .meta.problem { color: var(--danger); }
.list .right { text-align: right; flex: none; display: flex; align-items: center; justify-content: flex-end; gap: 8px; }
.list .right .when { font-size: var(--t-sm); color: var(--ink-3); white-space: nowrap; font-variant-numeric: tabular-nums; }
.row-actions { display: inline-flex; gap: 4px; flex-wrap: wrap; justify-content: flex-end; align-items: center; }
.list li.mandatory { box-shadow: inset 3px 0 0 var(--danger); }
/* A dense list: one line per row, still a 44px target. */
.list.dense > li { padding-block: 6px; min-height: 44px; flex-wrap: wrap; row-gap: 0; }
.list li.open { cursor: pointer; }
.list li.open:hover { background: var(--surface-2); }
.list.flush { border: 0; }
.card-head + .card-body > .list > li:first-child, .card-head + .list > li:first-child { padding-top: 10px; }
/* One empty state everywhere: a centred grey line, and at most one action under it. */
.empty { padding: 28px var(--row-x); color: var(--ink-3); text-align: center; font-size: var(--t-md); }
.list .empty, .list > li.empty { display: block; padding: 20px var(--row-x); }
.empty .btn, .empty .linkbtn { margin-top: 10px; }
/* A money field: "$" inside the left edge, two decimals (fieldHelpers). */
.money { position: relative; display: block; }
.money > .money-sign { position: absolute; left: 11px; top: 50%; transform: translateY(-50%); font-size: var(--t-md); color: var(--ink-3); pointer-events: none; }
@media (max-width: 860px) { .money > .money-sign { font-size: 16px; } }
.form .money > input { padding-left: 22px; font-variant-numeric: tabular-nums; }
/* A native date picker shows its chosen date in the house format under it. */
.date-box { position: relative; display: block; }
.date-echo { position: absolute; left: 11px; right: 40px; top: 50%; transform: translateY(-50%); font-size: var(--t-md); font-weight: 400; color: var(--ink); pointer-events: none; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.date-echo:empty, .date-box:has(input:focus) .date-echo { display: none; }
.date-box input.filled:not(:focus)::-webkit-datetime-edit { color: transparent; }
.date-box input[readonly] + .date-echo { color: var(--ink-2); }
@media (max-width: 860px) { .date-echo { font-size: 16px; } }
/* A page with nothing on it: the empty line sits on the page background, left-aligned with the head, not in an empty box. */
.card.bare { background: transparent; border-color: transparent; box-shadow: none; }
.card.bare .empty { padding: 8px 0; text-align: left; color: var(--ink-2); }

.datebox { width: 50px; text-align: center; flex: none; padding: 5px 0; border-radius: var(--radius); background: var(--surface-3); align-self: flex-start; }
.datebox-month { font-size: var(--t-xs); color: var(--ink-3); text-transform: uppercase; font-weight: 700; letter-spacing: 0.04em; }
.datebox-day { font-weight: 600; font-size: var(--t-xl); line-height: 1.1; }
.event-note, .post-body { font-size: var(--t-sm); margin-top: 4px; color: var(--ink-2); display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.results { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 6px; }
.results .status { cursor: help; }
.results a.status { text-decoration: none; }
.results a.status:hover { filter: brightness(1.08); }
.post-thumb { width: 44px; height: 44px; object-fit: cover; flex: none; border-radius: var(--r-sm); }

table { width: 100%; border-collapse: collapse; font-size: var(--t-md); }
th { text-align: left; font-size: var(--t-xs); color: var(--ink-3); font-weight: 600; padding: 10px 14px; border-bottom: 1px solid var(--line); background: var(--surface-2); white-space: nowrap; }
td { padding: 10px 14px; border-bottom: 1px solid var(--line); vertical-align: middle; }
tr:last-child td { border-bottom: 0; }
tbody tr:hover td { background: var(--surface-2); }
td.num, th.num { text-align: right; font-variant-numeric: tabular-nums; }
td .sub { display: block; font-size: var(--t-sm); color: var(--ink-3); font-weight: 400; }
/* A table's first column names the row in ink; the row itself opens it. */
td:first-child > a, td:first-child .person-name a { color: var(--ink); }
/* A table row's title is the same as a list row's: 15px, weight 500, ink. */
td:first-child strong { font-weight: 500; color: var(--ink); }
.list .title, .todo .title, .mini .title, .agenda .title, td:first-child strong { text-wrap: pretty; }
.m-only, td .m-only { display: none; }
.it-detail + .kv { margin-top: 12px; }
/* In tables a grey status is plain words; only attention states are pills. */
td .status.grey { background: none; padding: 0; font-weight: 500; font-size: var(--t-sm); color: var(--ink-2); vertical-align: baseline; }
td.actions { text-align: right; white-space: nowrap; vertical-align: middle; }
td.actions > .btn, td.actions > .menu { vertical-align: middle; }
td.actions .btn + .menu, td.actions .btn + .btn { margin-left: 4px; }
tr.low td:first-child { box-shadow: inset 3px 0 0 var(--danger); }
.table-wrap { overflow-x: auto; border-radius: 0 0 var(--radius-lg) var(--radius-lg); }
.table-wrap table { min-width: 720px; }
td.mono, td.nowrap, th { white-space: nowrap; }
.card > .table-wrap:first-child { border-radius: var(--radius-lg); }
.person-cell { display: flex; gap: 10px; align-items: center; }
.muted-row td { opacity: 0.55; }

.toolbar { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; padding: 12px var(--row-x); border-bottom: 1px solid var(--line); }
.toolbar input[type="search"], .toolbar select { padding: 6px 10px; border: 1px solid var(--control); border-radius: var(--radius); background: var(--surface); }
.toolbar input[type="search"] { min-width: 240px; flex: 1 1 240px; max-width: 360px; }
.toolbar-check { display: flex; gap: 6px; align-items: center; font-size: var(--t-sm); }
.toolbar .spacer { flex: 1; }

/* Facts: label / value pairs, drawn only for values that exist. */
.kv { display: grid; grid-template-columns: max-content 1fr; gap: 6px 16px; font-size: var(--t-md); margin: 0; align-items: baseline; }
.kv dt { color: var(--ink-3); }
.kv dd { margin: 0; min-width: 0; overflow-wrap: anywhere; }
.kv.wide { grid-template-columns: 220px 1fr; }
.kv .status { vertical-align: 0; }
.code-big { font-size: var(--t-lg); font-weight: 700; }

.checklist { list-style: none; margin: 0; padding: 0; }
.checklist li { display: flex; gap: 10px; padding: 6px 0; align-items: flex-start; }
.checklist .tick { width: 18px; height: 18px; border-radius: 50%; border: 1.5px solid var(--line-2); display: grid; place-items: center; flex: none; margin-top: 1px; color: transparent; }
.checklist .tick.done { background: var(--ok); border-color: var(--ok); color: #fff; }
.checklist label { display: flex; gap: 10px; align-items: center; cursor: pointer; }
/* The track is --control so an empty bar still reads at 3:1 in both themes. */
/* An empty track is an outline at 3:1 (--control), so 0 still reads as a bar with nothing in it. */
.bar { height: 6px; background: transparent; box-shadow: inset 0 0 0 1px var(--control); margin-bottom: 14px; border-radius: var(--r-sm); overflow: hidden; }
.bar > i { display: block; height: 100%; background: var(--accent); border-radius: var(--r-sm); }
.bar.sm { height: 4px; margin: 6px 0 0; max-width: 260px; }

.person { display: flex; gap: 14px; padding: 16px; }
.person-name { font-weight: 600; }
.person-tags { margin: 6px 0 8px; display: flex; gap: 6px; flex-wrap: wrap; }
.grid.even > .card:has(> .person) { display: flex; }
.person { flex: 1; }
.person > .grow { display: flex; flex-direction: column; min-width: 0; }
.person-contact { margin-top: 8px; overflow-wrap: anywhere; }
.person-act { margin-top: auto; padding-top: 12px; display: flex; align-items: center; min-height: 48px; }
/* Your own card ends at the same height as the others: the note sits where their Message button does. */
.person-you { font-size: var(--t-sm); color: var(--ink-3); }
.person-cell { min-width: 0; }
.person-cell > div { min-width: 0; }
.person-cell .sub { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.form-error { margin: 12px 0 0; color: var(--danger); font-size: var(--t-sm); font-weight: 600; }

/* ---------- Notices ---------- */

.notice { padding: 12px 14px; border: 1px solid var(--line); border-radius: var(--radius-lg); background: var(--surface); display: flex; gap: 12px; align-items: flex-start; margin-bottom: 16px; }
.n-ico { width: 28px; height: 28px; border-radius: var(--radius); display: grid; place-items: center; flex: none; background: var(--accent-soft); color: var(--accent-ink); }
.notice.sash { border-color: color-mix(in srgb, var(--danger) 30%, var(--line)); }
.notice.sash .n-ico { background: var(--danger-soft); color: var(--danger); }
.notice.gold .n-ico { background: var(--warn-soft); color: var(--warn); }
.notice.moss .n-ico { background: var(--ok-soft); color: var(--ok); }
.notice > div { padding-top: 3px; }
.grid > .notice { margin: 0; }
.notice.quiet { display: block; border: 0; background: none; padding: 0; margin: -6px 0 16px; color: var(--ink-3); font-size: var(--t-sm); }
.notice.quiet .n-ico { display: none; }
.notice.quiet > div { padding-top: 0; }
/* Technical detail for IT, folded under a plain sentence (itDetail in app.js). */
.it-detail { margin-top: 6px; font-size: var(--t-sm); color: var(--ink-3); }
.it-detail > summary { cursor: pointer; width: max-content; display: flex; align-items: center; gap: 6px; }
.it-detail > summary .i { transform: rotate(-90deg); transition: transform 0.15s; }
.it-detail[open] > summary .i { transform: none; }
.card-lead { margin-bottom: 14px; }
.list.inline-rows > li { padding-left: 0; padding-right: 0; }
.it-detail > div { margin-top: 4px; overflow-wrap: anywhere; }

/* ---------- Forms ---------- */

.form { display: grid; gap: 14px; }
.form label { display: grid; gap: 5px; align-content: start; font-size: var(--t-sm); font-weight: 500; color: var(--ink-2); }
/* "(optional)" and similar sit on the label's own line, not under it. */
.form .hint-in, .opt { font-weight: 400; color: var(--ink-3); }
.form .label-line { display: block; }
.form input, .form select, .form textarea { padding: 8px 10px; border: 1px solid var(--control); border-radius: var(--radius); background: var(--surface); width: 100%; font-size: var(--t-md); font-weight: 400; color: var(--ink); }
.form .form-help { font-size: var(--t-sm); color: var(--ink-3); }
/* Every field shows where the caret is: a 2px accent ring. */
.form input:focus-visible, .form select:focus-visible, .form textarea:focus-visible, .form input:focus, .form select:focus, .form textarea:focus,
.toolbar input:focus, .toolbar select:focus, .chat .compose input:focus, .checklist-add input:focus, .compose-box textarea:focus, .detail-kv select:focus, .detail-kv input[type="date"]:focus,
.card-head select:focus, .card-head input:focus, .tags-table select:focus, .tags-table .tag-qty:focus, .list select:focus, .search input:focus, .help-q:focus-within {
  outline: 2px solid var(--accent); outline-offset: 1px; border-color: var(--accent); box-shadow: none; }
.form textarea { min-height: 96px; resize: vertical; }
.form .row { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.form .row[hidden], .form label[hidden] { display: none; }
/* A field left alone on a row's last line takes the full width, never a half column beside nothing. */
.form .row > :last-child:nth-child(odd) { grid-column: 1 / -1; }
/* A text-only button that starts a line (Remove this item) lines its words up with the field edge above. */
.form .footnote > .btn.ghost:first-child { margin-left: -11px; }
.form .actions, .doc-actions, .modal .card-body > .actions { display: flex; gap: 8px; justify-content: flex-end; flex-wrap: wrap; }
.doc-actions { margin-top: 16px; }
.doc-body { margin-top: 12px; }
.field-label { font-size: var(--t-sm); font-weight: 500; color: var(--ink-2); margin-bottom: 6px; }
.checks { display: grid; gap: 4px; }
.checks label { display: flex; align-items: center; gap: 10px; font-weight: 400; padding: 6px 0; cursor: pointer; }
.checks .avail { color: var(--ink-2); }
/* Destinations: one line each, the name never wraps; "not connected" sits at the end in body-contrast text. */
.checks.dest label { white-space: nowrap; }
.checks.dest .d-name { flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.dest-note { margin: 4px 0 0; color: var(--ink-2); }
/* A focused field never hides under a dialog's pinned buttons. */
/* Focus is never hidden: a field scrolled to by Tab clears the sticky dialog head and footer, the app bar and (on a phone) the tab bar. */
.modal { scroll-padding-top: 64px; scroll-padding-bottom: 80px; }
html { scroll-padding-top: calc(var(--bar-h) + 8px); }
@media (max-width: 860px) { html { scroll-padding-bottom: calc(var(--tab-h) + env(safe-area-inset-bottom) + 12px); } }
.checks.inline { display: flex; flex-wrap: wrap; gap: 0 14px; }
/* Every native checkbox is 20px in the accent colour. */
input[type="checkbox"], .form input[type="checkbox"] { width: 20px; height: 20px; padding: 0; accent-color: var(--accent); }
.checks input { width: 20px; flex: none; }
.checks.tight { display: flex; flex-wrap: wrap; gap: 6px 14px; }
.checks.tight label { display: inline-flex; align-items: center; gap: 5px; }
.checks.pkgs { max-height: 50vh; overflow: auto; padding-right: 6px; }
.checks.pkgs .ver { color: var(--ink-3); font-size: var(--t-xs); font-family: var(--mono); }
.pick-person { display: flex; gap: 10px; align-items: center; text-decoration: none; color: inherit; }
/* A tick box sits beside its words, not stretched across the form like a text field. */
.form .check-line { display: flex; flex-wrap: wrap; align-items: flex-start; gap: 8px; }
.form .check-line input[type="checkbox"] { width: 20px; margin: 1px 0 0; flex: none; }
.fold { border: 1px solid var(--line); border-radius: var(--radius); background: var(--surface-2); }
.fold > summary { padding: 10px 12px; cursor: pointer; font-weight: 600; }
.fold[open] > summary { border-bottom: 1px solid var(--line); }
.fold .fold-body { padding: 12px; display: flex; flex-direction: column; gap: 14px; }
.invite-url { padding: 10px 12px; border: 1px dashed var(--line-2); border-radius: var(--radius); background: var(--surface-2); font-family: var(--mono); font-size: var(--t-xs); overflow-wrap: anywhere; user-select: all; }

/* ---------- Home ---------- */

.home { max-width: none; }
.home-head { margin-bottom: 22px; }
.home-head .date { font-size: var(--t-sm); color: var(--ink-3); margin-bottom: 2px; }
.home-head h1 { font-size: var(--t-3xl); }
.home-grid { display: grid; grid-template-columns: minmax(0, 1.6fr) minmax(0, 1fr); gap: 20px; align-items: start; }
.home-col { display: grid; gap: 20px; min-width: 0; }
.home-col > .card + .card { margin-top: 0; }

.shift-card { padding: 20px 22px 0; }
.shift-card.on { box-shadow: inset 3px 0 0 var(--ok); }
.shift-top { display: flex; align-items: center; gap: 20px; }
.shift-top .grow { flex: 1; min-width: 0; }
.eyebrow { font-size: var(--t-sm); font-weight: 600; color: var(--ink-3); display: flex; align-items: center; gap: 7px; }
.shift-card.on .eyebrow { color: var(--ok); }
.live { width: 8px; height: 8px; border-radius: 50%; background: var(--ok); box-shadow: 0 0 0 3px var(--ok-soft); }
.shift-card .when { font-size: var(--t-3xl); font-weight: 600; letter-spacing: -0.02em; line-height: 1.2; margin-top: 4px; font-variant-numeric: tabular-nums; }
.shift-card .where { color: var(--ink-2); margin-top: 2px; }
/* No shift today: one line, and Clock in is a small button. */
/* With no shift today it is one quiet line above Needs you, not a card. */
.shift-card.idle { padding: 12px 16px; display: flex; flex-wrap: wrap; align-items: center; gap: 6px 16px; }
.shift-card.idle .eyebrow { display: none; }
.shift-card.idle .shift-top { gap: 10px; }
/* The line takes the free space and wraps; Clock in ends the top row, the same place for every role. */
.shift-card.idle .shift-top { flex: 1 1 100%; }
.shift-card.idle .shift-top .grow { display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px 8px; flex: 1 1 0; min-width: 0; }
.shift-card.idle .when { font-size: var(--t-md); font-weight: 600; letter-spacing: 0; margin: 0; }
.shift-card.idle .where { font-size: var(--t-sm); color: var(--ink-3); margin: 0; }
.shift-card.idle .shift-foot { margin: 0; padding: 0; border-top: 0; flex: 1 1 auto; gap: 6px 16px; }
.shift-card.idle .shift-foot > span { margin-right: 0; }
.shift-card.idle .punches { flex: 1 0 100%; margin: 0; border-top: 0; }
.shift-card.idle .punches > summary { padding: 4px 0; }
.clock-btn { min-width: 128px; justify-content: center; padding: 11px 20px; font-size: var(--t-md); border-radius: var(--radius); }
.clock-btn { flex: none; }
.shift-card.idle .clock-btn { min-width: 0; padding: 5px 11px; font-size: var(--t-sm); }
.shift-foot { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 18px; margin-top: 18px; padding: 12px 0 14px; border-top: 1px solid var(--line); font-size: var(--t-sm); color: var(--ink-3); }
.shift-foot > span { margin-right: auto; }
.shift-foot strong { color: var(--ink); font-variant-numeric: tabular-nums; }
.punches { margin: 0 -22px; border-top: 1px solid var(--line); }
.punches > summary { padding: 11px 22px; cursor: pointer; font-size: var(--t-sm); color: var(--ink-2); display: flex; align-items: center; gap: 8px; }
.punches > summary:hover { color: var(--ink); }
.punches > summary .i { color: var(--ink-3); transform: rotate(-90deg); transition: transform 0.15s; }
.punches[open] > summary .i { transform: none; }
.punches .clock-recent, .punches .clock-sub { margin: 0 22px; }
.punches .clock-recent:last-child { margin-bottom: 8px; }
.clock-recent > li { padding: 9px 0; }
.clock-recent .title { font-size: var(--t-sm); }
.clock-sub { margin-top: 10px; }

.needs .card-head { border-bottom: 0; padding-bottom: 4px; }
.todo { list-style: none; margin: 0; padding: 0 0 4px; }
.todo > li { display: flex; align-items: center; gap: 12px; padding: 10px var(--row-x); }
.todo > li + li { border-top: 1px solid var(--line); }
.todo .title { font-weight: 500; color: var(--ink); }
.todo .meta { color: var(--ink-3); font-size: var(--t-sm); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.todo .grow { flex: 1; min-width: 0; }
.t-ico { width: 32px; height: 32px; border-radius: var(--radius); display: grid; place-items: center; flex: none; background: var(--accent-soft); color: var(--accent-ink); }
.todo li.danger .t-ico { background: var(--danger-soft); color: var(--danger); }
/* Overdue: a red stripe and a red fact line; the title stays ink. */
.todo li.danger { box-shadow: inset 3px 0 0 var(--danger); }
.todo li.danger .meta { color: var(--danger); }
/* No shift today: the first overdue item leads Home at the size the shift clock has on a working day, and the greeting steps down. */
.todo.lead > li:first-child { padding-top: 14px; padding-bottom: 14px; }
.todo.lead > li:first-child .title { font-size: var(--t-3xl); font-weight: 650; letter-spacing: -0.01em; line-height: 1.25; text-wrap: balance; }
.todo.lead > li:first-child .meta { font-size: var(--t-md); }
.home.idle .home-head h1 { font-size: var(--t-xl); }
.todo li.warn .meta { color: var(--warn); }
.todo .go, .list .go { color: var(--ink-3); display: grid; place-items: center; width: 28px; height: 28px; border-radius: var(--r-sm); }
.todo .go:hover, .list .go:hover { background: var(--surface-3); color: var(--ink); }
.todo-sec { font-size: var(--t-xs); font-weight: 600; color: var(--ink-3); padding: 12px var(--row-x) 2px; border-top: 1px solid var(--line); }
.card-head + .todo-sec, .needs.rest > .todo-sec:first-child { border-top: 0; padding-top: 0; }
.needs.rest > .todo-sec:first-child { padding-top: 14px; }
.todo-more > summary { padding: 8px var(--row-x) 12px; font-size: var(--t-sm); color: var(--accent); cursor: pointer; }
.todo-more[open] > summary { display: none; }
.needs.clear { display: flex; align-items: center; gap: 14px; padding: 16px var(--row-x); }
.needs.clear .t-ico { background: var(--ok-soft); color: var(--ok); }

.announce { display: flex; gap: 14px; align-items: flex-start; padding: 14px var(--row-x); color: inherit; }
.announce:hover { text-decoration: none; border-color: var(--line-2); }
/* A short note shows whole: the clamp only stops a long one, and the card opens the thread. */
.announce .a-text { display: -webkit-box; -webkit-line-clamp: 6; -webkit-box-orient: vertical; overflow: hidden; text-wrap: pretty; }
.announce .a-meta { color: var(--ink-3); font-size: var(--t-sm); margin-top: 3px; }

/* Home has one lead card (Needs you); the store's day (On shift, Deliveries, Releasing soon, Coming up) is open
   sections on the page, set apart by space, not boxes or rules. */
.card.side { background: none; border-color: transparent; box-shadow: none; --row-x: 0px; }
.card.side .side-sec:first-child h3 { padding-top: 0; }
.side-sec { padding-bottom: 8px; }
.side-sec + .side-sec h3 { padding-top: 18px; }
/* Every Home card head is one style: the h2 size and weight, with its link on the right at --t-sm. */
.side-sec h3 { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; font-size: var(--t-lg); padding: 14px var(--row-x) 6px; }
.side-sec h3 a { font-size: var(--t-sm); font-weight: 500; }
.side-empty, .side-note { font-size: var(--t-sm); color: var(--ink-3); padding: 2px var(--row-x) 8px; }
.people, .mini, .agenda { list-style: none; margin: 0; padding: 0; }
.people li { display: flex; align-items: center; gap: 10px; padding: 5px var(--row-x); font-size: var(--t-sm); }
.people .grow { flex: 1; min-width: 0; }
.people .muted { font-variant-numeric: tabular-nums; font-size: var(--t-sm); }
.mini li { display: flex; align-items: center; gap: 10px; padding: 7px var(--row-x); }
.mini .grow, .agenda .grow { flex: 1; min-width: 0; }
.mini .title, .agenda .title { font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mini .meta, .agenda .meta { font-size: var(--t-sm); color: var(--ink-3); }
.mini .meta.problem { color: var(--danger); }
.agenda li { display: grid; grid-template-columns: 92px minmax(0, 1fr); gap: 10px; padding: 7px var(--row-x); align-items: baseline; }
.agenda .day { font-size: var(--t-sm); font-weight: 600; color: var(--ink-3); white-space: nowrap; }
.agenda li.mand .meta { color: var(--ink); font-weight: 600; }

/* ---------- Schedule ---------- */

.week { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); }
/* The day column and chip padding are tight so an event's name keeps whole words on two lines; type stays 15px. */
.week .day { border-right: 1px solid var(--line); padding: 12px 6px; min-height: 180px; }
.week .day:last-child { border-right: 0; }
.week .day.today { background: var(--today); }
.week .dh { font-size: var(--t-xs); color: var(--ink-3); font-weight: 600; }
.week .dn { font-weight: 600; font-size: var(--t-xl); margin-bottom: 10px; }
.week .day.today .dn { color: var(--accent); }
/* A week chip grows down, never sideways: the title breaks between words only (keepHyphens holds "all-hands"
   together), and the time and Mandatory take their own line. */
.shift { position: relative; min-width: 0; font-size: var(--t-md); line-height: 1.35; padding: 5px 8px; margin-bottom: 4px; border-radius: var(--r-sm); background: var(--surface-3); color: var(--ink); overflow-wrap: break-word; }
.shift .when { display: block; color: var(--ink); font-variant-numeric: tabular-nums; }
/* Your own shift: a tint and an accent edge. Time off: a dashed outline, grey once approved. */
.shift.me { background: var(--accent-soft); color: var(--ink); font-weight: 600; box-shadow: inset 3px 0 0 var(--accent); }
.shift.off { background: transparent; color: var(--ink-2); border: 1px dashed var(--control); }
/* Events are outlined and neutral, so a colour on the schedule only ever means a game, your shift, or attention. */
.shift.ev { background: var(--surface); color: var(--ink); box-shadow: inset 0 0 0 1px var(--line-2); }
/* A mandatory event is an event chip like any other (the 1px outline, a medium title, the time smaller), with the
   house Mandatory label under it, as in every list: no heavier outline, no capitals. */
.shift.ev { padding-inline: 6px; }
.shift.ev .ev-t { font-weight: 500; overflow-wrap: normal; hyphens: manual; text-wrap: balance; }
.shift.ev .when { font-size: var(--t-sm); }
.shift.ev > .status.strong { display: inline-block; margin-top: 4px; }
.shift.grab { cursor: grab; }
.shift.grab:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.shift.dragging { opacity: 0.4; }
.shift.cancelled { text-decoration: line-through; opacity: 0.6; }
.shift .loc { font-size: var(--t-xs); text-transform: uppercase; letter-spacing: 0.05em; color: var(--ink-3); margin-left: 4px; }
.shift .del { position: absolute; top: 2px; right: 4px; border: 0; background: transparent; color: inherit; opacity: 0; cursor: pointer; font-size: var(--t-sm); line-height: 1; padding: 2px 3px; }
.shift:hover .del, .shift:focus-within .del { opacity: 0.8; }
.week .day.over { background: var(--accent-soft); box-shadow: inset 0 0 0 2px var(--accent); }

/* ---------- Calendar ---------- */

.month { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); }
.month .dow { font-size: var(--t-xs); color: var(--ink-3); font-weight: 600; padding: 8px 10px; border-bottom: 1px solid var(--line); }
.month .cell { display: flex; flex-direction: column; justify-content: flex-start; align-items: stretch; width: 100%; text-align: left; font: inherit; color: inherit; background: transparent; border: 0; border-right: 1px solid var(--line); border-bottom: 1px solid var(--line); padding: 6px 8px; min-height: 104px; cursor: pointer; min-width: 0; }
.month .cell:nth-child(7n) { border-right: 0; }
.month .cell:nth-last-child(-n+7) { border-bottom: 0; }
.month .cell:hover { background: var(--surface-2); }
.month .cell.out { color: var(--ink-3); background: var(--surface-2); }
.month .cell.today { background: var(--today); }
.month .cell .dn { font-weight: 600; font-size: var(--t-sm); margin-bottom: 4px; display: flex; justify-content: space-between; align-items: baseline; }
.month .cell.today .dn { color: var(--accent); }
.month .cell .dn .n { font-size: var(--t-xs); color: var(--ink-3); font-weight: 500; }
.month .more { font-size: var(--t-xs); color: var(--ink-3); }
.month .dots { display: none; gap: 3px; align-items: center; flex-wrap: wrap; }
.month .dots .gdot, .month .dots .cdot { width: 7px; height: 7px; margin: 0; }
.cal-key-shift { display: none !important; }
.cal-key-shift .i { width: 12px; height: 12px; }
/* A month chip: the whole name (broken between words), then the time on a line of its own. The cell and its week grow to fit. */
.chip { display: block; min-width: 0; font-size: var(--t-sm); line-height: 1.3; padding: 3px 6px; margin-bottom: 3px; border-radius: var(--r-sm); background: var(--surface-3); color: var(--ink-2); }
.chip .c-name { display: block; overflow-wrap: break-word; }
.chip .c-time { display: block; font-weight: 500; color: var(--ink-2); font-variant-numeric: tabular-nums; }
.chip .i { width: 12px; height: 12px; margin-right: 3px; vertical-align: -2px; color: var(--ink-3); }
.chip.me { background: var(--accent-soft); color: var(--ink); font-weight: 600; box-shadow: inset 3px 0 0 var(--accent); }
.chip.ev { background: var(--surface); color: var(--ink); box-shadow: inset 0 0 0 1px var(--control); }
.chip.mand { background: var(--surface); color: var(--ink); font-weight: 500; box-shadow: inset 0 0 0 1.5px var(--ink-2); }
.chip.off { background: transparent; color: var(--ink-2); border: 1px dashed var(--control); }
.chip.store { background: var(--surface-3); color: var(--ink); box-shadow: inset 3px 0 0 var(--ink-3); }
.chip.mine { background: var(--mine-soft); color: var(--mine-ink); }
.chip.pkg { background: transparent; color: var(--ink-2); padding-left: 2px; }
.chip.gone { text-decoration: line-through; opacity: 0.6; }
.cdot { width: 7px; height: 7px; border-radius: 50%; background: var(--ink-3); }
.cdot.me { background: var(--accent); } .cdot.ev { background: transparent; box-shadow: inset 0 0 0 1.5px var(--ink); } .cdot.mand { background: transparent; box-shadow: inset 0 0 0 2px var(--ink); } .cdot.off { background: transparent; border: 1.5px dashed var(--ink-3); }
.cdot.store { background: var(--ink-3); } .cdot.mine { background: var(--mine-ink); } .cdot.pkg { background: transparent; box-shadow: inset 0 0 0 1.5px var(--ink-2); }
.cal-legend { display: flex; flex-wrap: wrap; gap: 6px 14px; padding: 10px var(--row-x); font-size: var(--t-xs); color: var(--ink-3); }
.cal-legend > span { display: inline-flex; align-items: center; gap: 6px; }
.cal-legend .i { width: 12px; height: 12px; }
/* The legend draws each key the way the grid does: chips on a wide screen, dots on a phone. */
.ckey { display: inline-block; width: 18px; height: 11px; border-radius: var(--r-sm); background: var(--surface-3); }
.ckey.me { background: var(--accent-soft); box-shadow: inset 3px 0 0 var(--accent); }
.ckey.ev { background: var(--surface); box-shadow: inset 0 0 0 1px var(--control); }
.ckey.mand { background: var(--surface); box-shadow: inset 0 0 0 1.5px var(--ink-2); }
.ckey.off { background: transparent; border: 1px dashed var(--control); }
.ckey.store { box-shadow: inset 3px 0 0 var(--ink-3); }
.ckey.mine { background: var(--mine-soft); }
.cal-legend .cdot, .cal-legend .k-phone { display: none; }
.agenda-day { padding: 12px var(--row-x) 4px; font-size: var(--t-sm); display: flex; justify-content: space-between; gap: 12px; font-weight: 600; color: var(--ink-3); border-top: 1px solid var(--line); }
.agenda-day.today { color: var(--accent-ink); }
.agenda-day .on-shift { font-weight: 500; color: var(--ink-3); }
.agenda-day:first-child { border-top: 0; }
.agenda-day + .list > li:first-child { border-top: 0; }
.cal-when { font-size: var(--t-sm); color: var(--ink-2); min-width: 118px; padding-top: 1px; font-variant-numeric: tabular-nums; }
.cal-preview { white-space: pre-wrap; font-size: var(--t-sm); line-height: 1.5; background: var(--surface-2); border: 1px solid var(--line); border-radius: var(--radius); padding: 12px 14px; margin: 0; font-family: var(--sans); }
.cal-recent .meta { overflow-wrap: anywhere; }
.cal-seg { margin-bottom: 12px; }
.form .cal-allday { align-self: end; }
.cal-actions { margin-top: 14px; }
.cal-note { margin-top: 10px; }

/* ---------- Time clock and timesheets ---------- */

/* The pager's day name is the date picker: the native field lies invisibly over it. */
.pager-label.pick { position: relative; display: inline-flex; align-items: center; gap: 4px; cursor: pointer; border-radius: var(--radius); }
.pager-label.pick:hover { background: var(--surface-3); }
.pager-label.pick:focus-within { outline: 2px solid var(--accent); outline-offset: 2px; }
.pager-label.pick .i { color: var(--ink-3); }
.pager-label.pick input { position: absolute; inset: 0; width: 100%; height: 100%; opacity: 0; cursor: pointer; border: 0; padding: 0; }
.day-line { margin: -4px 0 16px; color: var(--ink-2); font-size: var(--t-md); }
.warn-word, .ts-flag { color: var(--warn); font-weight: 600; }
.ts-flag.late { color: var(--danger); }
.table-wrap .ts-table { min-width: 720px; }
.ts-table .num { text-align: right; white-space: nowrap; font-variant-numeric: tabular-nums; }
.ts-entry { white-space: nowrap; }
.ts-entry + .ts-entry { margin-top: 4px; }

/* ---------- Messaging ---------- */

/* Messages, one rule (DESIGN): a short thread sizes to its messages and the composer follows the last one; once the thread
   is long enough to scroll, the composer docks at the foot of the screen (above the tab bar on a phone). No blank pane. */
.chat { display: grid; grid-template-columns: 230px 1fr; align-items: start; }
.chat .threads { align-self: stretch; }
.chat .threads { border-right: 1px solid var(--line); padding: 8px; background: var(--surface-2); border-radius: var(--radius-lg) 0 0 var(--radius-lg); }
.chat .threads button { display: flex; align-items: center; gap: 8px; width: 100%; border: 0; background: transparent; padding: 7px 10px; border-radius: var(--r-sm); cursor: pointer; text-align: left; color: var(--ink-2); }
.chat .threads button:hover { background: var(--surface-3); }
.chat .threads button.on { background: var(--surface); color: var(--ink); font-weight: 600; box-shadow: inset 0 0 0 1px var(--line); }
.chat .threads .unread { margin-left: auto; background: var(--count-bg); color: var(--count-ink); font-size: var(--t-xs); font-weight: 700; padding: 0 6px; border-radius: var(--radius); }
.thread-group { font-size: var(--t-xs); color: var(--ink-3); font-weight: 600; padding: 8px 10px 4px; }
.thread-group.later { padding-top: 16px; }
/* New message is the Direct list's last row: + then the words, left-aligned like a conversation. */
.chat .threads .thread-new { color: var(--ink-2); font-weight: 500; }
.chat .threads .thread-new .i { width: 16px; height: 16px; margin: 0 4px 0 2px; color: var(--ink-3); }
.new-rule { display: flex; align-items: center; gap: 10px; color: var(--accent-ink); font-size: var(--t-xs); font-weight: 700; }
.new-rule::before, .new-rule::after { content: ""; flex: 1; border-top: 1px solid var(--accent); }
.chat .pane { display: flex; flex-direction: column; min-width: 0; }
.chat .pane > .card-head { justify-content: flex-start; }
.chat .pane > .card-head h2 { white-space: nowrap; flex: none; }
.chat .pane > .card-head .small { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
@media (max-width: 860px) {
  /* The pane head names the open conversation in full (a chip in the strip may be cut), then its description, wrapped. */
  .chat .pane > .chat-head { flex-wrap: wrap; row-gap: 2px; }
  .chat .pane > .chat-head h2 { white-space: normal; flex: 1 1 100%; }
  .chat .pane > .chat-head .small { white-space: normal; overflow: visible; }
}
.chat .msgs { padding: 18px; display: grid; gap: 16px; align-content: start; }
.msg { display: grid; grid-template-columns: 32px 1fr; gap: 10px; }
.msg .who { font-weight: 600; }
.msg .when { color: var(--ink-3); font-size: var(--t-xs); margin-left: 8px; }
.chat .compose { display: flex; flex-wrap: wrap; gap: 8px; padding: 12px 16px; border-top: 1px solid var(--line); position: sticky; bottom: 0; z-index: 2; background: var(--surface); border-radius: 0 0 var(--radius-lg) 0; }
/* A message that did not go: its text stays in the box, with this line under it. */
.chat .compose .send-note { flex: 1 0 100%; margin: 0; font-size: var(--t-sm); color: var(--danger); }
.chat .compose .send-note .linkbtn { font-size: inherit; }
.chat .compose-note { padding: 12px 16px; border-top: 1px solid var(--line); color: var(--ink-3); font-size: var(--t-sm); }
.chat .compose input { flex: 1; padding: 8px 12px; border: 1px solid var(--control); border-radius: var(--radius); background: var(--surface); }

/* ---------- Marketing composer ---------- */

.composer { display: grid; grid-template-columns: 1.2fr 1fr; gap: 18px; }
.preview-label { font-size: var(--t-sm); color: var(--ink-3); margin-bottom: 8px; }
.preview { border: 1px solid var(--line); border-radius: var(--radius); padding: 14px; background: var(--surface-2); }
.preview .ph { display: flex; align-items: center; gap: 8px; font-size: var(--t-sm); color: var(--ink-3); margin-bottom: 10px; }
.preview .pt { font-weight: 600; margin-bottom: 4px; }
.preview-img { width: 100%; max-height: 220px; object-fit: cover; margin-bottom: 10px; display: block; border-radius: var(--r-sm); }
.upload { position: relative; border: 1px dashed var(--line-2); border-radius: var(--radius); padding: 14px; background: var(--surface-2); }
.upload.over { border-color: var(--accent); background: var(--accent-soft); }
.upload.has { border-style: solid; }
.upload.busy { border-style: solid; border-color: var(--accent); }
.upload.busy .upload-empty { color: var(--ink-2); }
/* The composer's last field clears the pinned buttons with room to spare. */
.modal .composer > .form { padding-bottom: 16px; }
/* A disabled choice still reads (well over 3:1); the box says it can't be picked. */
.checks.dest label.off:has(input:disabled) { color: var(--ink-2); cursor: not-allowed; }
.upload input[type="file"] { position: absolute; inset: 0; opacity: 0; cursor: pointer; width: 100%; height: 100%; }
.upload.has input[type="file"] { display: none; }
.upload-empty { font-size: var(--t-sm); color: var(--ink-2); text-align: center; text-wrap: pretty; }
.upload-has { display: flex; gap: 12px; align-items: center; }
.upload-has[hidden], .upload-empty[hidden] { display: none; }
.upload-has img { width: 56px; height: 56px; object-fit: cover; border-radius: var(--r-sm); }
.upload-has iframe { width: 160px; height: 90px; border: 0; border-radius: var(--r-sm); background: #000; pointer-events: none; flex: none; }
.upload-name { font-weight: 600; }
.quick-btns { display: flex; gap: 6px; flex-wrap: wrap; }
ol.steps { margin: 0 0 14px 18px; padding: 0; display: grid; gap: 6px; }

/* ---------- Modal and toast ---------- */

.modal-bg { position: fixed; inset: 0; background: var(--scrim); display: grid; place-items: center; z-index: 50; padding: 20px; }
.modal { background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius-lg); box-shadow: var(--shadow-lg); width: min(620px, 100%); max-height: 90vh; overflow: auto; }
.modal.wide, .modal:has(.composer) { width: min(880px, 100%); }
.modal .card-head { position: sticky; top: 0; background: var(--surface); z-index: 1; }
.modal .card-head h2 { font-size: var(--t-lg); }
/* A dialog that opens on its title shows the ring when the keyboard opened it. */
.modal .card-head h2:focus:not(:focus-visible) { outline: none; }
.modal .card-head h2:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: var(--r-sm); }
.modal .card-body { padding: 18px; }
/* The buttons that finish a dialog stay on screen while its body scrolls. */
.modal .card-body > .form > .actions:last-child, .modal .card-body > .doc-actions:last-child, .modal .card-body > .actions:last-child {
  position: sticky; bottom: 0; z-index: 1; margin: 4px -18px -18px; padding: 12px 18px; background: var(--surface); border-top: 1px solid var(--line); }
.modal .detail-flag { margin-bottom: 14px; }
/* A state shown where a button would be is drawn the button's height, so the row lines up. */
.doc-actions { align-items: center; }
.doc-actions > .status { display: inline-flex; align-items: center; gap: 6px; padding: 7px 14px; font-size: var(--t-md); line-height: 1.3; border-radius: var(--radius); }
.modal .close { width: 44px; height: 44px; margin: -6px -10px -6px 0; display: grid; place-items: center; border: 0; background: transparent; border-radius: var(--r-sm); cursor: pointer; color: var(--ink-3); }
.modal .close:hover { background: var(--surface-3); color: var(--ink); }
.modal .kv + .doc-body, .modal .kv + .doc-actions { margin-top: 16px; }
.detail-para { margin-top: 14px; white-space: pre-wrap; line-height: 1.55; }
.detail-para + .detail-para { margin-top: 10px; }

#toast { position: fixed; bottom: 20px; left: 50%; transform: translateX(-50%) translateY(6px); background: var(--ink); color: var(--bg); border-radius: var(--radius); padding: 10px 16px; font-size: var(--t-sm); opacity: 0; transition: opacity 0.2s, transform 0.2s; pointer-events: none; z-index: 60; box-shadow: var(--shadow-lg); }
#toast.on { opacity: 1; transform: translateX(-50%) translateY(0); }
#toast.on.has-undo { pointer-events: auto; }
#toast .toast-undo { border: 0; background: none; color: var(--core-green); font: inherit; font-weight: 700; margin-left: 10px; padding: 4px 2px; cursor: pointer; }
.popover .pop-foot { display: block; padding: 10px 16px; border-top: 1px solid var(--line); font-size: var(--t-sm); font-weight: 600; }
.popover .pop-close { display: none; }

/* ---------- IT tickets ---------- */

.ticket-layout { display: grid; grid-template-columns: minmax(0, 1fr) 320px; gap: 18px; align-items: start; }
.ticket-layout .card + .card { margin-top: 18px; }
.ticket-num { font-family: var(--mono); font-size: var(--t-sm); color: var(--ink-3); }
.title .ticket-num, a > .ticket-num { margin-right: 6px; }
.ticket-subject { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.source-chip { display: inline-flex; align-items: center; gap: 4px; font-size: var(--t-xs); color: var(--ink-3); white-space: nowrap; }
.thread-list .msg { padding: 14px var(--row-x); border-bottom: 1px solid var(--line); }
.thread-list .msg:last-child { border-bottom: 0; }
/* An empty conversation is one quiet line under its head, so the composer sits right below. */
.thread-list > .empty { padding: 0 var(--row-x) 12px; text-align: left; font-size: var(--t-sm); }
.msg .body { white-space: pre-wrap; margin-top: 2px; overflow-wrap: anywhere; }
.msg.internal { background: var(--warn-soft); }
.msg .tag { font-size: var(--t-xs); font-weight: 600; text-transform: uppercase; letter-spacing: 0.06em; color: var(--warn); margin-left: 8px; }
.compose-box { display: grid; gap: 10px; padding: 14px var(--row-x); border-top: 1px solid var(--line); }
/* A task's checklist: one step per row, the box is the action. A ticked step greys out but stays. */
.checklist { list-style: none; margin: 0; padding: 0; }
.checklist > li { display: flex; align-items: flex-start; gap: 12px; padding: 10px var(--row-x); border-bottom: 1px solid var(--line); }
.checklist > li:last-child { border-bottom: 0; }
.checklist label { display: flex; align-items: flex-start; gap: 12px; flex: 1; min-width: 0; cursor: pointer; }
.checklist input[type="checkbox"] { width: 20px; height: 20px; margin: 1px 0 0; flex: none; accent-color: var(--accent); cursor: pointer; }
.checklist input[type="checkbox"]:disabled { cursor: default; }
.checklist .step { overflow-wrap: anywhere; }
.checklist li.done .step { color: var(--ink-3); text-decoration: line-through; }
.checklist .meta { color: var(--ink-3); font-size: var(--t-xs); margin-top: 2px; text-decoration: none; }
.checklist .right { flex: none; }
.checklist-add { display: flex; gap: 8px; padding: 10px var(--row-x); border-top: 1px solid var(--line); }
.checklist-add input { flex: 1; min-width: 0; padding: 7px 10px; border: 1px solid var(--control); border-radius: var(--radius); background: var(--surface); }
.task-progress { display: flex; align-items: center; gap: 10px; font-size: var(--t-xs); color: var(--ink-3); white-space: nowrap; }
.task-progress .bar { margin: 0; width: 90px; }
.task-progress .bar > i.full { background: var(--ok); }
.list .meta.overdue, .sub .overdue, .overdue { color: var(--danger); }
.form textarea.steps { min-height: 120px; font-family: inherit; }
/* A task is one panel: its note, its steps and the add-a-step field read as one list, set apart by space, not rules. */
.task-body { white-space: pre-wrap; overflow-wrap: anywhere; padding-bottom: 6px; }
.task-body + .checklist > li, .ticket-layout .checklist > li { border-bottom: 0; padding-block: 7px; }
.ticket-layout .checklist-add { border-top: 0; padding-top: 6px; padding-bottom: 14px; }
.compose-box textarea { min-height: 84px; resize: vertical; padding: 8px 10px; border: 1px solid var(--control); border-radius: var(--radius); background: var(--surface); }
.compose-box .row { display: flex; align-items: center; gap: 12px; justify-content: space-between; flex-wrap: wrap; }
.detail-kv { display: grid; grid-template-columns: 92px minmax(0, 1fr); gap: 10px 12px; font-size: var(--t-md); margin: 0; align-items: center; }
.detail-kv dt { color: var(--ink-3); }
.detail-kv dd { margin: 0; min-width: 0; }
.detail-kv .saved-note { display: block; font-size: var(--t-xs); color: var(--ok); font-weight: 600; }
.detail-kv select, .detail-kv input[type="date"] { width: 100%; padding: 6px 8px; border: 1px solid var(--control); border-radius: var(--radius); background: var(--surface); color: inherit; font: inherit; }
/* A date the viewer can change reads in the house format; the native picker sits on top of it, invisible, and opens on a press. */
.date-field { position: relative; display: block; padding: 6px 8px; border: 1px solid var(--control); border-radius: var(--radius); background: var(--surface); cursor: pointer; }
.date-field:focus-within { outline: 2px solid var(--accent); outline-offset: 1px; }
.detail-kv .date-field input[type="date"] { position: absolute; inset: 0; width: 100%; height: 100%; opacity: 0; cursor: pointer; border: 0; padding: 0; }
.timeline { list-style: none; margin: 0; padding: 0; font-size: var(--t-sm); }
.timeline li { display: grid; grid-template-columns: 8px 1fr; gap: 10px; padding: 6px 0; align-items: start; }
.timeline li::before { content: ""; width: 8px; height: 8px; border-radius: 50%; background: var(--line-2); margin-top: 5px; }
.timeline .when { color: var(--ink-3); }
tr.urgent td:first-child { box-shadow: inset 3px 0 0 var(--danger); }

/* ---------- Lobby TV ---------- */

.slide-list li.off { opacity: 0.55; }
.slide-thumb { width: 64px; height: 40px; flex: none; border-radius: var(--r-sm); border: 1px solid var(--line); object-fit: cover; background: var(--surface-3); }
.reorder { display: inline-flex; gap: 2px; }
.reorder .btn { min-width: 26px; padding: 2px 6px; line-height: 1.3; }
.reorder .btn[disabled] { opacity: 0.35; }

.pair-url { margin: 12px 0; padding: 12px 14px; background: var(--surface-3); border-radius: var(--radius); overflow-wrap: anywhere; }
.pair-url code { font-family: var(--mono); font-size: var(--t-sm); }
.devlog { max-height: 55vh; overflow: auto; margin: 0 0 12px; padding: 12px 14px; background: var(--surface-3); border-radius: var(--radius); font-family: var(--mono); font-size: var(--t-xs); line-height: 1.45; white-space: pre-wrap; overflow-wrap: anywhere; }

/* The preview runs the real player page in an iframe at panel proportions. */
.tv-preview { width: 100%; background: #0d1017; border-radius: var(--radius-lg); overflow: hidden; border: 1px solid var(--line-2); }
.tv-preview.landscape { aspect-ratio: 16 / 9; }
.tv-preview.portrait { aspect-ratio: 9 / 16; max-width: 420px; margin: 0 auto; }
.tv-preview iframe { width: 100%; height: 100%; border: 0; display: block; }

.slide-form .kind-only[hidden] { display: none; }   /* a class with display beats the UA rule for [hidden] */
.slide-form .kind-seg { margin: 4px 0 6px; }
.slide-form .block-head { font-weight: 600; margin-top: 4px; padding-top: 12px; border-top: 1px solid var(--line); }
.slide-form .event-block { display: flex; flex-direction: column; gap: 14px; }
.slide-form .check-line { display: flex; flex-wrap: wrap; align-items: baseline; gap: 8px; }
.slide-form .check-line input { margin: 0; }

/* ---------- Integrations ---------- */

.int-detail { color: var(--ink-3); font-size: var(--t-sm); margin-top: 2px; }
/* A select in a list row (Square locations): drawn like every other field. */
.list select { padding: 6px 8px; border: 1px solid var(--control); border-radius: var(--radius); background: var(--surface); color: var(--ink); max-width: 220px; }

/* Game colours: the website calendar's keys and hues, except that nothing is pure red or green
   (those mean "attention" and "done" here): prereleases are indigo, sports cards teal, shows brown. */
.gdot { display: inline-block; width: 9px; height: 9px; border-radius: 50%; margin-right: 5px; vertical-align: middle; background: var(--g-other); }
.gdot.magic { background: var(--g-magic); }
.gdot.pokemon { background: var(--g-pokemon); }
.gdot.riftbound { background: var(--g-riftbound); }
.gdot.cyberpunk { background: var(--g-cyberpunk); }
.gdot.one_piece { background: var(--g-one-piece); }
.gdot.sports_cards { background: var(--g-sports); }
.gdot.show { background: var(--g-show); }
.gdot.other { background: var(--g-other); }
.gdot.prerelease { background: var(--g-prerelease); }

/* ---------- Personnel records: the on-screen record and the paper copy for signatures ---------- */

.record-h { margin: 16px 0 4px; font-size: var(--t-md); }
/* A heading inside a flush list card, grouping the rows under it (HR acknowledgements by document). */
.list-h { display: flex; align-items: baseline; gap: 8px; margin: 0; padding: 16px var(--row-x) 2px; font-size: var(--t-md); font-weight: 600; text-wrap: balance; }
.list-h .n { font-size: var(--t-sm); font-weight: 500; color: var(--ink-3); font-variant-numeric: tabular-nums; }
.list + .list-h { border-top: 1px solid var(--line); }
.list-h .list-h-meta { margin-left: auto; font-size: var(--t-sm); font-weight: 500; color: var(--ink-2); }
h4.record-h { font-size: var(--t-sm); color: var(--ink-2); }
.print-sig { display: none; }
@media print {
  body > *:not(.modal-bg) { display: none !important; }
  .modal-bg { position: static; background: none; padding: 0; display: block; }
  .modal { box-shadow: none; border: 0; max-height: none; width: 100%; overflow: visible; }
  .modal .close, .modal .actions, .modal form, .modal .doc-actions { display: none !important; }
  .print-sig { display: grid; gap: 28px; margin-top: 40px; font-size: var(--t-sm); }
}

/* ---------- Documents ----------
   Found by number or title, opened as a PDF, printed. The number is the handle: it is on the
   printout's file name, so it gets its own quiet chip everywhere it appears. */

/* One ID style: bare mono in --ink-3, first in the facts (tickets, tasks, documents). */
.doc-no { font-family: var(--mono); font-size: var(--t-sm); color: var(--ink-3); white-space: nowrap; }
.doc-search { flex: none; width: 280px; margin: 0; }
/* The app bar's search is a sheet on a phone; this one stays inline, since it is how a phone finds a document. */
.search.doc-search, .search.hr-search { display: block; }
.doc-summary { margin: -8px 0 16px; color: var(--ink-2); max-width: 80ch; }
.doc-summary p { margin: 0; }
/* Tags are their own row of chips under the summary, so no chip is stranded at the end of a sentence. */
.doc-tags { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 6px; }
.doc-preview { overflow: hidden; padding: 0; }
/* The inline PDF is a page: letter-shaped, fit to its width, with the browser's own toolbar hidden (Print is in the head). */
.doc-preview { background: var(--surface); }
.doc-preview.doc-text { background: none; overflow: visible; }
.doc-preview iframe { display: block; width: 100%; aspect-ratio: 8.5 / 11; height: auto; max-height: min(80vh, 1100px); border: 0; background: var(--surface); }
/* A text or Markdown document is shown as its text: body size, as tall as it is, no page frame. */
.doc-text .doc-body { margin: 0 0 24px; padding: 0; font-size: var(--t-md); line-height: 1.6; white-space: pre-wrap; overflow-wrap: anywhere; max-width: 80ch; color: var(--ink); }
.doc-text .doc-h { font-size: var(--t-lg); font-weight: 600; }
.doc-text .doc-body[aria-busy] { display: grid; gap: 10px; }
/* Print on a text document loads its PDF out of sight and prints that. */
.print-frame { position: fixed; right: 0; bottom: 0; width: 1px; height: 1px; border: 0; opacity: 0; pointer-events: none; }
/* A pinned document carries a filled pin; pinning is in the row's ⋯. */
.pinned-mark { display: grid; place-items: center; width: 32px; height: 32px; color: var(--accent); }
.pinned-mark svg path:first-child { fill: currentColor; }
.card-head select, .card-head input[type="search"] { padding: 5px 8px; border: 1px solid var(--control); border-radius: var(--radius); background: var(--surface); font-size: var(--t-sm); max-width: 55%; }
.form fieldset { border: 0; padding: 0; margin: 0; display: grid; gap: 8px; min-width: 0; }
.form .check-line input[type="radio"] { width: auto; margin: 2px 0 0; flex: none; accent-color: var(--accent); }
.form fieldset legend { font-size: var(--t-sm); font-weight: 500; color: var(--ink-2); margin-bottom: 6px; padding: 0; }
.acl { display: grid; gap: 8px; }
.acl:empty { display: none; }
.acl-row { display: grid; grid-template-columns: minmax(0, 1fr) 180px auto; gap: 8px; align-items: center; }
.acl-add { justify-self: start; }
@media (max-width: 600px) {
  /* Filters fold into a sheet (app.js foldFilters): the search and one button share a row. */
  .card > .toolbar.folded { display: flex; flex-wrap: nowrap; }
  .card > .toolbar.folded > select { display: none; }
  .card > .toolbar.folded > .search.fsearch { flex: 1 1 auto; width: auto; }
  .card > .toolbar.folded > .f-btn { flex: none; }
  .doc-search { width: 100%; }
  .acl-row { grid-template-columns: minmax(0, 1fr) auto; }
  .acl-row .acl-level { grid-column: 1; grid-row: 2; }
  /* On a phone a PDF is a short look at its first page; Open PDF beside Print shows it whole. */
  .doc-preview iframe { aspect-ratio: auto; height: 320px; max-height: none; }
}

/* ---------- HR ----------
   Two audiences on the same components: an employee on a phone reading a policy and
   signing it, and an owner at the counter working through who has not. */

.card.hr-clear .card-head h2 { color: var(--ok); }
.hr-timeline > li { position: relative; padding-left: 30px; }
.hr-timeline .hr-dot { position: absolute; left: 16px; top: 18px; width: 8px; height: 8px; border-radius: 50%; background: var(--accent); flex: none; }
.hr-timeline > li::before { content: ""; position: absolute; left: 19.5px; top: 26px; bottom: -12px; width: 1px; background: var(--line); }
.hr-timeline > li:last-child::before { display: none; }
.hr-history .meta { text-transform: none; }

/* The document being read before it is signed. Scrolls on its own so the signature
   controls stay reachable on a phone without scrolling the whole modal. */
.hr-doc-body { max-height: 46vh; overflow-y: auto; padding: 14px 16px; background: var(--surface-2); border: 1px solid var(--line); border-radius: var(--radius); line-height: 1.65; }
.hr-sign { margin-top: 16px; }
.hr-receipt .mono { font-family: var(--mono); font-size: var(--t-xs); word-break: break-all; white-space: normal; }
.hr-sig-img { max-width: 320px; border: 1px solid var(--line); border-radius: var(--radius); background: #fff; }
.hr-manage .summary { margin-bottom: 18px; }
.hr-manage .list { border: 1px solid var(--line); border-radius: var(--radius); margin-bottom: 16px; }
/* The app bar's search styling, reused in the HR page header rather than centred in it. */
.hr-search { flex: none; width: 240px; margin: 0; }
tr.hr-row { cursor: pointer; }
tr.hr-row:hover td { background: var(--surface-2); }
/* A person's file: facts in two columns, then what is on record. */
.profile { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px 32px; }
.profile .kv { align-content: start; }
.profile-missing { margin-top: 14px; font-size: var(--t-sm); color: var(--ink-3); }

/* Price tags: two lines of fields per item (what it is, then how it is priced), more on a phone.
   A custom band's wording takes a third line when it is asked for. */
.tag-size { max-width: 320px; }
.tag-rows { display: grid; gap: 14px; }
.tag-row {
  display: grid; gap: 8px; align-items: end;
  grid-template-columns: minmax(0, 1.5fr) minmax(0, 1fr) minmax(0, 1fr) minmax(0, 0.8fr) 32px;
  grid-template-areas: "name name detail detail remove" "band was price copies .";
}
.tag-row + .tag-row { border-top: 1px solid var(--line); padding-top: 14px; }
.tag-row .t-name { grid-area: name; }
.tag-row .t-detail { grid-area: detail; }
.tag-row .t-remove { grid-area: remove; }
.tag-row .t-band { grid-area: band; }
.tag-row .t-text { grid-column: 1 / 3; }
.tag-row .t-was { grid-area: was; }
.tag-row .t-price { grid-area: price; }
.tag-row .t-copies { grid-area: copies; }
.tag-row [data-remove-tag] { width: 32px; height: 36px; padding: 0; justify-content: center; color: var(--ink-3); }
.tag-row [data-remove-tag][hidden] { display: inline-flex; visibility: hidden; }  /* keeps the columns lined up */
.tag-more { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
@media (max-width: 600px) {
  .tag-row {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    grid-template-areas: "name name" "detail detail" "band text" "was price" "copies remove";
  }
  .tag-row .t-text { grid-area: text; }
  .tag-row .t-remove { justify-self: end; }
}

/* ---------- Geneva: a slice of Discord in Guildhall's own colours ----------
   The channel list, the conversation, the composer: shaped like Discord so what you
   write reads the way it will land, drawn with the same tokens as every other page. */

.dc { display: grid; grid-template-columns: 240px minmax(0, 1fr); min-height: 620px; overflow: hidden; }
.dc-side { display: flex; flex-direction: column; background: var(--surface-2); border-right: 1px solid var(--line); min-width: 0; }
.dc-server { display: flex; align-items: center; gap: 10px; padding: 12px 14px; border-bottom: 1px solid var(--line); font-weight: 700; }
.dc-server-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dc-pic { width: 32px; height: 32px; border-radius: 50%; object-fit: cover; flex: none; }
.dc-pic.dc-server-pic { width: 28px; height: 28px; border-radius: var(--radius); }
.dc-pic.dc-avatar { width: 40px; height: 40px; }
.dc-pic.dc-avatar.sm { width: 32px; height: 32px; }
.dc-initial { display: grid; place-items: center; background: var(--accent); color: var(--accent-contrast); font-weight: 700; font-size: var(--t-md); }
.dc-channels { flex: 1; overflow: auto; padding: 8px; }
.dc-cat { font-size: var(--t-xs); font-weight: 700; letter-spacing: 0.04em; text-transform: uppercase; color: var(--ink-3); padding: 14px 8px 4px; }
.dc-cat:first-child { padding-top: 6px; }
.dc-ch { display: flex; align-items: center; gap: 6px; width: 100%; border: 0; background: transparent; padding: 6px 8px; border-radius: var(--r-sm); cursor: pointer; text-align: left; color: var(--ink-3); font: inherit; font-size: var(--t-md); font-weight: 500; }
.dc-ch:hover { background: var(--surface-3); color: var(--ink-2); }
.dc-ch.on { background: var(--surface); color: var(--ink); font-weight: 600; box-shadow: inset 0 0 0 1px var(--line); }
.dc-ch.locked { opacity: 0.7; }
.dc-ch-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; flex: 1; }
.dc-hash { color: var(--ink-3); font-weight: 500; font-size: var(--t-lg); line-height: 1; width: 18px; flex: none; display: inline-flex; justify-content: center; }
.dc-hash .i { width: 16px; height: 16px; }
.dc-lock .i { width: 13px; height: 13px; }
.dc-badge { margin-left: auto; background: var(--count-bg); color: var(--count-ink); font-size: var(--t-xs); font-weight: 700; padding: 0 6px; border-radius: var(--radius); min-width: 16px; text-align: center; }
.dc-empty { color: var(--ink-3); font-size: var(--t-sm); padding: 12px 10px; }
.dc-me { display: flex; align-items: center; gap: 8px; padding: 8px 10px; border-top: 1px solid var(--line); background: var(--surface-3); }
.dc-me .dc-name { font-size: var(--t-sm); font-weight: 600; }
.dc-me-sub { font-size: var(--t-xs); color: var(--ink-3); }
.dc-bot { display: inline-block; background: var(--accent); color: var(--accent-contrast); font-size: var(--t-xs); font-weight: 700; padding: 1px 5px; border-radius: var(--r-sm); vertical-align: 2px; margin-left: 4px; letter-spacing: 0.02em; }
.dc-main { display: flex; flex-direction: column; min-width: 0; }
.dc-head { display: flex; align-items: center; gap: 8px; padding: 12px 16px; border-bottom: 1px solid var(--line); min-height: 48px; }
.dc-head .dc-hash { font-size: var(--t-xl); width: 22px; }
.dc-head .dc-hash .i { width: 20px; height: 20px; }
.dc-topic { color: var(--ink-3); font-size: var(--t-sm); border-left: 1px solid var(--line-2); padding-left: 10px; margin-left: 4px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dc-msgs { flex: 1; overflow: auto; padding: 8px 0 12px; display: flex; flex-direction: column; max-height: 62vh; }
.dc-welcome { margin: auto 16px 8px; padding: 8px 0 16px; border-bottom: 1px solid var(--line); }
.dc-welcome-hash { width: 56px; height: 56px; border-radius: 50%; background: var(--surface-3); display: grid; place-items: center; font-size: var(--t-3xl); color: var(--ink-2); margin-bottom: 8px; }
.dc-welcome-hash .i { width: 30px; height: 30px; }
.dc-welcome h3 { margin: 0 0 4px; font-size: var(--t-xl); }
.dc-welcome p { margin: 0; color: var(--ink-3); font-size: var(--t-md); }
.dc-msg { display: grid; grid-template-columns: 40px minmax(0, 1fr); gap: 12px; padding: 8px 16px; }
.dc-msg:hover { background: var(--surface-2); }
.dc-msg-head { display: flex; align-items: baseline; gap: 2px; }
.dc-name { font-weight: 600; }
.dc-when { color: var(--ink-3); font-size: var(--t-xs); margin-left: 8px; }
.dc-text { white-space: pre-wrap; overflow-wrap: anywhere; line-height: 1.4; margin-top: 2px; }
.dc-mention { background: var(--accent-soft); color: var(--accent-ink); border-radius: var(--r-sm); padding: 0 2px; font-weight: 500; }
.dc-foot { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; font-size: var(--t-xs); color: var(--ink-3); margin-top: 4px; }
.dc-state { display: inline-flex; align-items: center; gap: 4px; }
.dc-state .i { width: 13px; height: 13px; }
.dc-state.ok { color: var(--ok); }
.dc-state.bad { color: var(--danger); }
.dc-state.wait { color: var(--warn); }
.dc-msg.queued .dc-text { opacity: 0.6; }
.dc-msg.failed .dc-msg-body { border-left: 2px solid var(--danger); padding-left: 8px; margin-left: -10px; }
.dc-compose { padding: 0 16px 14px; }
.dc-input { display: flex; align-items: flex-end; gap: 6px; background: var(--surface-3); border: 1px solid var(--line); border-radius: var(--radius); padding: 6px 6px 6px 14px; }
.dc-input:focus-within { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
.dc-input textarea { flex: 1; border: 0; background: transparent; resize: none; font: inherit; font-size: var(--t-md); line-height: 1.4; padding: 6px 0; max-height: 220px; color: var(--ink); outline: none; min-width: 0; }
.dc-send { width: 34px; height: 34px; border: 0; border-radius: var(--r-sm); background: var(--accent); color: var(--accent-contrast); display: grid; place-items: center; cursor: pointer; flex: none; }
.dc-send:hover { background: var(--accent-2); }
.dc-send[disabled] { opacity: 0.5; cursor: default; }
.dc-compose-foot { display: flex; justify-content: space-between; align-items: center; gap: 12px; flex-wrap: wrap; margin-top: 6px; font-size: var(--t-xs); }
.dc-closed { color: var(--ink-3); font-size: var(--t-sm); padding: 12px 16px 16px; border-top: 1px solid var(--line); }
@media (max-width: 860px) {
  .dc { grid-template-columns: 1fr; min-height: 0; }
  .dc-side { border-right: 0; border-bottom: 1px solid var(--line); }
  .dc-channels { display: flex; gap: 4px; overflow-x: auto; padding: 8px; }
  .dc-cat { padding: 6px 4px; align-self: center; white-space: nowrap; }
  .dc-ch { width: auto; white-space: nowrap; }
  .dc-me { display: none; }
  .dc-msgs { max-height: 50vh; min-height: 260px; }
}

/* ---------- Responsive ---------- */

@media (max-width: 1100px) {
  .grid.cols-3, .grid.cols-4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .span-3 { grid-column: span 2; }
  .composer { grid-template-columns: 1fr; }
  .ticket-layout { grid-template-columns: 1fr; }
  .home-grid { grid-template-columns: minmax(0, 1fr) minmax(0, 300px); }
  .main { padding: 24px 28px 64px; }
}
@media (max-width: 860px) {
  .shell { grid-template-columns: minmax(0, 1fr); }
  .topbar { padding: 0 8px 0 6px; gap: 4px; }
  .topbar .brand { width: auto; margin-right: auto; }
  .topbar .brand { padding-left: 8px; }
  /* Search is a button in the bar that opens the same box as a sheet under it. */
  .search { display: none; }
  .iconbtn.search-btn { display: grid; }
  .shell.search-open #search { display: block; position: fixed; top: var(--bar-h); left: 0; right: 0; margin: 0; padding: 10px 12px 12px; background: var(--bar-bg); border-bottom: 1px solid var(--line); z-index: 41; }
  .shell.search-open #search > svg { left: 23px; top: 32px; transform: translateY(-50%); }
  .shell.search-open #search input { height: 44px; font-size: 16px; }
  .shell.search-open #search kbd { display: none; }
  .shell.search-open .search-results { position: static; margin-top: 8px; max-height: calc(100vh - var(--bar-h) - 90px); overflow: auto; }
  .userbtn .uname, .userbtn > .i { display: none; }
  /* In the drawer More scrolls with the list, so the last Manage pages are never hidden under it. */
  .rail .more { position: static; }
  .rail {
    position: fixed; top: var(--bar-h); left: 0; bottom: calc(var(--tab-h) + env(safe-area-inset-bottom)); width: min(280px, 85vw); z-index: 40; height: auto;
    transform: translateX(-100%); transition: transform 0.2s ease; background: var(--surface);
  }
  .shell.menu-open .rail { transform: none; box-shadow: var(--shadow-lg); }
  /* The drawer's last entries clear the tab bar, and the list fades at its foot while there is more. */
  .rail { padding-bottom: 8px; }
  .rail::after { content: ""; position: sticky; bottom: -8px; display: block; flex: none; height: 32px; margin-top: -24px; background: linear-gradient(to bottom, transparent, var(--surface)); pointer-events: none; }
  .shell.menu-open .tabbar a.on { color: var(--ink-3); font-weight: 500; }
  .shell.menu-open #tab-menu { color: var(--accent); font-weight: 600; }
  .scrim:not([hidden]) { display: block; position: fixed; inset: var(--bar-h) 0 calc(var(--tab-h) + env(safe-area-inset-bottom)) 0; background: var(--scrim); z-index: 35; }
  .main { padding: 18px 14px calc(var(--tab-h) + 32px); }
  .tabbar {
    display: grid; grid-template-columns: repeat(5, 1fr); position: fixed; left: 0; right: 0; bottom: 0; z-index: 30;
    height: calc(var(--tab-h) + env(safe-area-inset-bottom)); padding-bottom: env(safe-area-inset-bottom);
    background: var(--bar-bg); border-top: 1px solid var(--line);
  }
  .tabbar a, .tabbar button { position: relative; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 3px; border: 0; background: none; color: var(--ink-3); font-size: var(--t-xs); font-weight: 500; cursor: pointer; text-decoration: none; }
  .tabbar .i { width: 22px; height: 22px; }
  .tabbar a.on { color: var(--accent); font-weight: 600; }
  .tabbar a, .tabbar button { font-size: var(--t-xs); }
  .tabbar i { position: absolute; top: 4px; left: calc(50% + 6px); min-width: 18px; padding: 0 5px; line-height: 18px; border: 2px solid var(--bar-bg); }
  /* Thumbs: every control a finger presses is at least 44px tall. */
  .iconbtn, .iconbtn.sm, .menu > summary.iconbtn { width: 44px; height: 44px; }
  /* The phone bell count: 20px tall, up and right of the glyph. */
  .iconbtn .badge { top: 2px; left: 25px; min-width: 20px; height: 20px; }
  .btn { min-height: 44px; }
  /* A small button is drawn 34px; its tap area reaches 44px (::after), so a row action can sit beside the title. */
  .btn.sm { min-height: 34px; padding: 6px 12px; position: relative; }
  .btn.sm::after { content: ""; position: absolute; inset: -5px -2px; }
  .seg .btn { min-height: 38px; padding: 8px 12px; }
  .pager .iconbtn { width: 44px; height: 44px; }
  .linkbtn { min-height: 44px; }
  .popover .pop-menu a, .popover .pop-menu button { min-height: 44px; }
  .menu-item { min-height: 44px; }
  /* One head on every page: title, the one primary, and ⋯ on a line (app.js phoneHead); a filter or search gets its own row. */
  .page-head { margin-bottom: 14px; flex-wrap: wrap; align-items: center; gap: 4px 10px; }
  .page-head > .sub { order: 3; flex: 1 0 100%; margin: 0; }
  /* A detail page: the title takes the whole first row, the actions the row under it. */
  .page-head.detail .ph-title { flex: 1 0 100%; }
  /* Every detail head (ticket, task, document) spaces the same: title, sub-line, then its buttons 10px down, 20px above the page. */
  .page-head.detail { margin-bottom: 20px; }
  .page-head.detail > .actions { order: 4; margin-top: 6px; }
  .page-head.detail.menu-only .ph-title { flex: 1 1 0; }
  /* ⋯ (44px) centres on the title's last line (30px): it hangs 7px below the line's foot. */
  .page-head.detail.menu-only > .actions { order: 0; align-self: flex-end; margin-top: 0; margin-bottom: -7px; }
  .page-head .ph-title { flex: 1; min-width: 0; }
  .page-head .actions { flex: none; flex-wrap: nowrap; gap: 4px; }
  /* The phone primary is lighter than the title: 36px to the eye, a 44px press. */
  .page-head .actions .btn.primary { position: relative; min-height: 36px; padding: 6px 14px; }
  .page-head .actions .btn.primary::after { content: ""; position: absolute; inset: -4px 0; }
  .head-row { margin: -4px 0 14px; }
  /* Small text links people press often (a card head's link, links in a row's facts, a notice, an empty state) keep
     their quiet look but press as 44px tall; a row's chevron presses as 44px around its 28px mark. */
  :is(.card-head > a, .meta a, .sub a, .notice a, .empty a, .list-h a, dd a, .shift-foot a) { position: relative; }
  :is(.card-head > a, .meta a, .sub a, .notice a, .empty a, .list-h a, dd a, .shift-foot a)::after { content: ""; position: absolute; inset: -13px -4px; }
  .todo .go, .list .go { width: 44px; height: 44px; margin: -8px; }
  /* An open head ⋯ sits in the room the head makes under its title (bindMenus), the head's full width. */
  .page-head.menu-open { position: relative; }
  .page-head.menu-open .menu { position: static; }
  .page-head.menu-open .menu-pop { position: absolute; top: auto; bottom: 0; left: 0; right: 0; }
  /* The calendar's month and Store/Mine share one row. */
  .viewbar.cal-bar { justify-content: space-between; gap: 8px; }
  .viewbar.cal-bar:not(:has(.pager .btn)) { flex-wrap: nowrap; }
  .cal-bar .pager-label { font-size: var(--t-md); padding: 0 2px; }
  .cal-bar .seg .btn { padding: 8px 10px; }
  .tabs + .head-row { margin-top: -8px; }
  .head-row .search { display: block; width: 100%; max-width: none; }
  .toolbar.with-seg { flex-wrap: nowrap; }
  .toolbar.with-seg input[type="search"] { min-width: 120px; flex: 1 1 0; }
  .toolbar.with-seg .seg { flex: none; }
  .seg.strip { display: flex; width: fit-content; flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none; max-width: 100%; }
  .seg.strip::-webkit-scrollbar { display: none; }
  .seg.strip .btn { flex: none; white-space: nowrap; }
  /* Filters in a table's toolbar: search across, then the selects two to a row. */
  .card > .toolbar:has(select) { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
  .card > .toolbar:has(select) input[type="search"], .card > .toolbar:has(select) > .search.fsearch { grid-column: 1 / -1; min-width: 0; max-width: none; }
  .card > .toolbar:has(select) select { min-width: 0; width: 100%; }
  .card > .toolbar:has(select) .spacer { display: none; }
  .home-grid { grid-template-columns: minmax(0, 1fr); }
  .home-head h1 { font-size: var(--t-2xl); }
  .shift-card { padding: 16px 16px 0; }
  .shift-top { flex-wrap: wrap; gap: 14px; }
  .shift-card .when, .todo.lead > li:first-child .title { font-size: var(--t-2xl); }
  .clock-btn { width: 100%; padding: 13px 20px; }
  .shift-card.idle .shift-top { flex-wrap: nowrap; align-items: center; }
  .shift-card.idle .clock-btn { width: auto; padding: 6px 12px; }
  .punches { margin: 0 -16px; }
  .punches > summary { padding: 11px 16px; }
  .punches .clock-recent, .punches .clock-sub { margin: 0 16px; }
  /* Figures sit three across (two when there are two or four), never two and an orphan. */
  .summary { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .summary:has(> .figure:nth-child(2):last-child), .summary:has(> .figure:nth-child(4):last-child) { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .summary .figure { padding: 10px 12px; box-shadow: -1px 0 0 var(--line), 0 -1px 0 var(--line); }
  .summary dt { font-size: var(--t-xs); line-height: 1.3; }
  .signin { place-items: start center; padding: 56px 16px 32px; }
  .signin .theme-btn { top: 6px; right: 6px; }
  .signin-brand .wordmark { font-size: 28px; }
  .grid.cols-2, .grid.cols-3, .grid.cols-4 { grid-template-columns: 1fr; }
  .span-2, .span-3 { grid-column: auto; }
  .profile { grid-template-columns: 1fr; }
  .week { grid-template-columns: 1fr; }
  /* A day is a line: "Mon 7", then its shifts underneath. */
  .week .day { border-right: 0; border-bottom: 1px solid var(--line); min-height: 0; display: flex; flex-wrap: wrap; align-items: baseline; column-gap: 6px; }
  .week .day:last-child { border-bottom: 0; }
  .week .dh { font-size: var(--t-sm); }
  .week .dn { font-size: var(--t-md); flex: 1; margin: 0 0 6px; }
  .week .day > .shift { flex: 1 1 100%; }
  .month .cell { min-height: 58px; padding: 4px 5px; }
  .month .cell .dn { font-size: var(--t-xs); }
  .month .cell .dn .n, .month .chip, .month .more { display: none; }
  .month .dots { display: flex; }
  .cal-key-shift { display: inline-flex !important; }
  .cal-legend .k-wide, .cal-legend .ckey { display: none; }
  /* Each key sits tight to its dot and well apart from the next, so a dot reads with its own name. */
  .cal-legend { column-gap: 18px; }
  .cal-legend .k-phone { display: inline-flex; align-items: center; gap: 5px; }
  .cal-legend .gdot { margin: 0; }
  .cal-legend .cdot { display: inline-block; }
  /* A game's phone mark: its letter in ink over a bar in the game's colour. A mandatory event: an outlined square. */
  .gk { display: inline-block; min-width: 9px; padding: 0 1px 1px; font-size: 10px; font-weight: 700; line-height: 1; text-align: center; color: var(--ink); border-bottom: 3px solid var(--g-other); }
  .gk.magic { border-color: var(--g-magic); } .gk.pokemon { border-color: var(--g-pokemon); } .gk.riftbound { border-color: var(--g-riftbound); }
  .gk.cyberpunk { border-color: var(--g-cyberpunk); } .gk.one_piece { border-color: var(--g-one-piece); } .gk.sports_cards { border-color: var(--g-sports); }
  .gk.show { border-color: var(--g-show); } .gk.prerelease { border-color: var(--g-prerelease); }
  .month .dots .cdot.mand, .cal-legend .cdot.mand { width: 9px; height: 9px; border-radius: 1px; box-shadow: inset 0 0 0 2px var(--ink); }
  .cal-when { min-width: 0; }
  /* Channels become one scrolling strip of chips above the conversation. */
  .chat { grid-template-columns: minmax(0, 1fr); grid-template-rows: auto auto; min-height: 0; }
  .chat .threads { border-right: 0; border-bottom: 1px solid var(--line); display: flex; align-items: center; gap: 6px; padding: 6px 8px 6px 0; border-radius: var(--radius-lg) var(--radius-lg) 0 0; }
  .chat .thread-chips { display: flex; align-items: center; gap: 4px; flex: 1; min-width: 0; padding: 0 8px; overflow-x: auto; scrollbar-width: none; scroll-snap-type: x proximity; scroll-padding-inline: 8px; }
  .chat .thread-chips::-webkit-scrollbar { display: none; }
  .chat .thread-chips button { scroll-snap-align: start; }
  .chat .threads button { width: auto; flex: none; white-space: nowrap; min-height: 40px; }
  .thread-group { display: none; }
  .form .row { grid-template-columns: 1fr; }
  /* A popover is a sheet from the bottom over a dimmed page (app.js adds .pop-scrim). */
  .popover, .popover.user { top: auto; bottom: 0; left: 0; right: 0; width: auto; z-index: 46; border-radius: var(--radius-lg) var(--radius-lg) 0 0; border-bottom: 0; padding-bottom: env(safe-area-inset-bottom); }
  .popover .pop-body { max-height: 60vh; }
  .popover::before { content: ""; display: block; width: 36px; height: 4px; border-radius: var(--r-sm); background: var(--line-2); margin: 8px auto 0; }
  /* Dialogs rise from the bottom as a sheet; the body scrolls and the buttons stay put. */
  .modal-bg { padding: 0; place-items: end stretch; }
  .modal, .modal.wide { width: 100%; max-height: 92vh; border-radius: var(--radius-lg) var(--radius-lg) 0 0; border-bottom: 0; }
  .modal .card-body > .form > .actions:last-child, .modal .card-body > .doc-actions:last-child, .modal .card-body > .actions:last-child { padding-bottom: calc(12px + env(safe-area-inset-bottom)); }
  /* Tables that are lists of things (tasks, tickets, stock) become two-line rows. */
  .table-wrap table.stack { min-width: 0; }
  table.stack thead { display: none; }
  table.stack, table.stack tbody { display: block; }
  table.stack tr { display: flex; align-items: center; gap: 12px; padding: 12px var(--row-x); border-bottom: 1px solid var(--line); }
  table.stack tr:last-child { border-bottom: 0; }
  table.stack td { display: none; padding: 0; border: 0; background: none !important; }
  table.stack td:first-child { display: block; flex: 1; min-width: 0; }
  table.stack td.actions { display: flex; flex: none; align-items: center; gap: 4px; }
  /* The row action rule (DESIGN.md rule 2): beside the title unless fitRows() marks the row .stack. */
  table.stack tr.stack { flex-wrap: wrap; row-gap: 8px; }
  table.stack tr.stack td.actions { flex: 1 0 100%; justify-content: flex-start; }
  table.stack td.empty { display: block; flex: 1; }
  table.stack tr.urgent, table.stack tr.low { box-shadow: inset 3px 0 0 var(--danger); }
  table.stack tr.urgent td:first-child, table.stack tr.low td:first-child { box-shadow: none; }
  table.stack .d-only { display: none; }
  table.stack .sub.m-only { display: block; }
  table.stack span.m-only:not(.sub) { display: inline; }
  table.stack tbody tr:hover td { background: none; }
  .popover.user { width: auto; }
  .hr-search { max-width: none; width: 100%; }
  .hr-doc-body { max-height: 40vh; }
  .kv { grid-template-columns: 1fr; gap: 2px 0; }
  .kv dt { margin-top: 8px; font-size: var(--t-xs); }
  .kv dt:first-child { margin-top: 0; }
  .kv.wide { grid-template-columns: 1fr; }
  /* A short action and ⋯ stay on the row, right-aligned beside the title; when the title would
     get under 60% of the row (a long label, two controls) fitRows() adds .stack and they take
     their own line under the facts, lined up with the title. */
  .list > li { gap: 12px; }
  .list .right { flex-wrap: nowrap; gap: 4px; }
  .list > li.stack { flex-wrap: wrap; row-gap: 8px; }
  .list > li.stack > .right { flex: 1 0 100%; justify-content: flex-start; }
  .list > li.stack:has(> .avatar) > .right { padding-left: 48px; }
  /* .span: the action shares the title's line and the facts run full width beneath both. */
  .list > li.span { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 2px 12px; align-items: center; }
  .list > li.span > .grow { display: contents; }
  .list > li.span > .grow > * { grid-column: 1 / -1; }
  .list > li.span > .grow > .title { grid-column: 1; grid-row: 1; }
  .list > li.span > .right { grid-column: 2; grid-row: 1; margin-block: -6px; }
  .list > li.span > .right:not(:has(.btn)), table.stack tr.span > td.actions:not(:has(.btn)) { margin-block: -11px; }
  /* An event's date is one line above its title ("NOV 11 Wed"), so the title has the row's width. */
  .list > li:has(> .datebox) { flex-wrap: wrap; row-gap: 2px; }
  .list > li > .datebox { flex: 1 0 100%; width: auto; display: flex; align-items: baseline; gap: 5px; padding: 0; border: 0; background: none; text-align: left; }
  .list > li > .datebox .sk { margin: 0; }
  .list > li > .datebox .datebox-month, .list > li > .datebox .datebox-day { font-size: var(--t-xs); font-weight: 700; line-height: 1.5; color: var(--ink-2); letter-spacing: 0.04em; text-transform: uppercase; }
  .list > li > .datebox .small { display: inline; font-size: var(--t-xs); color: var(--ink-3); }
  .list > li.span:has(> .datebox) > .datebox { grid-column: 1 / -1; grid-row: 1; }
  .list > li.span:has(> .datebox) > .grow > .title, .list > li.span:has(> .datebox) > .right { grid-row: 2; }
  /* A phone-only piece of a list row (a Going pill on the facts line) shows; its desktop twin hides. */
  .list .m-only { display: inline-block; }
  .list div.m-only { display: block; }
  .list .d-only { display: none; }
  /* A table row keeps the same shapes: .span puts the action on the title's line and the facts under both. */
  table.stack tr.span { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 2px 12px; align-items: center; }
  table.stack tr.span > td:first-child { display: contents; }
  table.stack tr.span > td:first-child > * { grid-column: 1 / -1; }
  table.stack tr.span > td:first-child > :is(strong, .tline) { grid-column: 1; grid-row: 1; }
  table.stack tr.span > td.actions { grid-column: 2; grid-row: 1; margin-block: -6px; }
  /* Home: a to-do's time or due date wraps to a second line rather than being cut. */
  .todo .meta { white-space: normal; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; }
  /* Home lists follow the same row rule, with no icon tile. */
  .todo .t-ico { display: none; }
  .todo > li > .btn, .mini li > .btn { flex: none; }
  .todo > li.stack, .mini li.stack { flex-wrap: wrap; row-gap: 8px; }
  .todo > li.stack > .btn, .mini li.stack > .btn { order: 3; }
  .todo > li.stack > .grow, .mini li.stack > .grow { flex: 1 0 100%; }
  .mini .title { white-space: normal; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; }
  /* A sheet's last line clears its pinned buttons. */
  .modal .card-body { padding-bottom: calc(18px + env(safe-area-inset-bottom)); }
  /* Lobby TV rows keep two lines: no thumbnail; order and the rest are in ⋯. */
  .slide-list .slide-thumb { display: none; }

  #toast { bottom: calc(var(--tab-h) + 16px); }
}

/* Price tags: the Needs tags queue. The checkbox column is narrow, the count and size sit in
   the row so a sheet can be set up without opening anything, and the bulk bar appears above
   the table once something is ticked. */
th.check, td.check { width: 32px; padding-right: 0; }
.tag-list > li > .row-check { flex: none; width: 20px; height: 20px; margin: 0; accent-color: var(--accent); }
.tags-table .tag-qty { width: 64px; padding: 5px 8px; border: 1px solid var(--control); border-radius: var(--radius); background: var(--surface); text-align: right; }
.tags-table select { max-width: 200px; padding: 5px 8px; border: 1px solid var(--control); border-radius: var(--radius); background: var(--surface); }
.tags-table select.unset { color: var(--ink-2); }
.tags-table .sub { white-space: normal; }
.toolbar.bulkbar { background: var(--accent-soft); }
.toolbar.bulkbar select { padding: 4px 8px; }

/* ---------- Guided tour: a spotlight on one thing and a card that says what it is ---------- */
.tour-bg { position: fixed; inset: 0; z-index: 60; }
.tour-spot { position: fixed; z-index: 61; border-radius: var(--radius); pointer-events: none; box-shadow: 0 0 0 9999px var(--scrim-strong), 0 0 0 2px var(--accent); transition: top 0.18s, left 0.18s, width 0.18s, height 0.18s; }
.tour-spot[hidden] { display: none; }
.tour-bg:has(+ .tour-spot[hidden]) { background: var(--scrim-strong); }
.tour-card { position: fixed; z-index: 62; width: min(380px, calc(100vw - 24px)); background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius-lg); box-shadow: var(--shadow-lg); padding: 16px 18px 14px; }
.tour-card.center { top: 50% !important; left: 50% !important; transform: translate(-50%, -50%); width: min(440px, calc(100vw - 24px)); }
.tour-card h2 { font-size: var(--t-lg); margin-bottom: 6px; }
.tour-card p { font-size: var(--t-sm); line-height: 1.5; color: var(--ink-2); }
.tour-card p + p { margin-top: 8px; }
.tour-card kbd { padding: 1px 5px; border: 1px solid var(--line-2); border-radius: var(--r-sm); background: var(--surface-2); }
.tour-count { font-size: var(--t-xs); font-weight: 600; color: var(--ink-3); letter-spacing: 0.02em; min-height: 14px; margin-bottom: 4px; }
.tour-actions { display: flex; gap: 8px; align-items: center; margin-top: 14px; flex-wrap: wrap; }
.tour-actions .spacer { flex: 1; }
.tour-actions .linkbtn { color: var(--ink-3); }
.tour-actions .linkbtn:hover { color: var(--ink); }
@media (max-width: 860px) {
  .tour-card:not(.center) { top: auto !important; left: 12px !important; right: 12px; bottom: calc(var(--tab-h) + 12px); width: auto; }
  .tour-card:not(.center).up { top: calc(var(--bar-h) + 12px) !important; bottom: auto; }
}
/* Reduced motion: nothing slides, fades, or spins. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { transition-duration: 0.01ms !important; animation-duration: 0.01ms !important; animation-iteration-count: 1 !important; scroll-behavior: auto !important; }
  .tour-spot { transition: none; }
}

/* ---------- Help: the written tour ---------- */
.help-search { display: flex; align-items: center; gap: 12px; margin-bottom: 16px; flex-wrap: wrap; }
.help-secs { display: grid; gap: 24px; min-width: 0; }
.help-sec, .help-row { scroll-margin-top: calc(var(--bar-h) + 12px); }
/* Each Help row is its own disclosure: the fold chevron, then the name and what it is for. It opens in place. */
.help-list > li.help-row { display: block; padding: 0; }
.help-list .help-more > summary { display: flex; align-items: flex-start; gap: 10px; padding: 10px var(--row-x); cursor: pointer; border-radius: var(--radius); }
/* Help groups are set apart by space, so the rows inside carry no rules. */
.help-group .help-list > li.help-row { border-bottom: 0; }
.help-group > .card-head { border-bottom: 0; padding-bottom: 4px; }
/* Help groups sit on the page: no panel, no edge; the heading, the space between groups and the 70ch measure group them. */
.card.help-group, .help-others > .card { background: transparent; border-color: transparent; box-shadow: none; }
.help-others > .card > .card-head { border-bottom: 0; }
/* With no panel, a group's heading and rows line up with the search box and the page title. */
.card.help-group > .card-head, .help-others > .card > .card-head { padding-left: 0; padding-right: 0; }
.card.help-group .help-more > summary, .help-others .help-more > summary { padding-left: 0; padding-right: 0; }
.card.help-group .help-body, .help-others .help-body { padding-left: 26px; padding-right: 0; }
.help-list .help-more > summary:hover { background: var(--surface-2); }
.help-list .help-more > summary .grow { flex: 1; min-width: 0; }
.help-list .help-more > summary > .i { flex: none; margin-top: 3px; color: var(--ink-3); transform: rotate(-90deg); transition: transform 0.15s; }
.help-list .help-more[open] > summary > .i { transform: none; }
.help-list .title { font-size: var(--t-md); font-weight: 600; color: var(--ink); }
.help-list .help-summary { font-size: var(--t-md); color: var(--ink-2); margin-top: 1px; max-width: 70ch; }
.help-list .help-who { color: var(--ink-3); }
.help-list .help-body { padding: 0 var(--row-x) 16px calc(var(--row-x) + 26px); }
.help-open { margin-bottom: 8px; font-weight: 600; }
.help-search .search.fsearch { flex: 1 1 280px; max-width: 480px; }
.help-body { max-width: 70ch; line-height: 1.55; font-size: var(--t-md); }
.help-body .help-who { color: var(--ink-3); font-size: var(--t-sm); margin-bottom: 10px; display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.help-body .help-who .field-label { margin: 0; }
.help-body .help-summary { font-size: var(--t-lg); color: var(--ink); margin-bottom: 12px; }
.help-body h3 { font-size: var(--t-md); color: var(--ink-2); font-weight: 600; margin: 16px 0 6px; }
.help-sec .card-head h2 a { color: inherit; }
.help-body p + p { margin-top: 8px; }
.help-body ul, .help-body ol { margin: 6px 0 6px 20px; padding: 0; display: grid; gap: 5px; }
.help-body dl { margin: 6px 0 0; display: grid; grid-template-columns: max-content minmax(0, 1fr); gap: 6px 14px; }
.help-body dt { font-weight: 600; white-space: nowrap; }
.help-body dd { margin: 0; color: var(--ink-2); }
.help-body kbd { padding: 1px 5px; border: 1px solid var(--line-2); border-radius: var(--r-sm); background: var(--surface-2); }
.help-body .tip { padding: 10px 12px; border-left: 3px solid var(--accent); background: var(--accent-soft); border-radius: 0 var(--radius) var(--radius) 0; margin-top: 10px; font-size: var(--t-sm); }
@media (max-width: 860px) {
  /* On a phone the section list is one Jump to… select instead of forty links. */
  .help-body dl { grid-template-columns: minmax(0, 1fr); gap: 2px; }
  .help-body dd { margin-bottom: 6px; }
}

/* ---------- Player Passport ---------- */
.list > li.dim .title, .list > li.dim .meta { opacity: 0.55; }
.pp-trends { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 18px; }
.pp-bars { display: flex; align-items: flex-end; gap: 3px; height: 64px; margin: 6px 0; }
.pp-bars span { flex: 1; background: var(--accent); border-radius: var(--r-sm) var(--r-sm) 0 0; min-width: 4px; }
.pp-swatch { display: inline-flex; gap: 2px; flex: none; }
.pp-swatch i { width: 14px; height: 28px; border-radius: var(--r-sm); border: 1px solid var(--line); }
.form select[multiple] { min-height: 120px; }

/* Vendor Reports (web/vendor-reports.js) */
.card-head:has(> .seg) { flex-wrap: wrap; }
.card-head > .seg { flex-wrap: wrap; }
.vr-rows td { vertical-align: top; }
.list li.muted-row { opacity: 0.6; }
#vr-cands { display: grid; gap: 10px; max-height: 320px; overflow: auto; }
.vr-cand label { display: block; font-weight: 400; }
.vr-cand .sub { display: block; font-size: var(--t-xs); color: var(--ink-3); }

/* One search field: the toolbar search, the Documents search, the HR search, and Help.
   An icon, the control border, 36px tall (44 on a phone), the same radius. */
.search.fsearch { display: block; position: relative; flex: none; margin: 0; }
.search.fsearch input[type="search"] { width: 100%; min-width: 0; max-width: none; height: 36px; padding: 0 12px 0 34px; border: 1px solid var(--control); border-radius: var(--radius); background: var(--surface); color: var(--ink); font-size: var(--t-md); }
.search.fsearch > svg { left: 10px; }
.toolbar > .search.fsearch, .card-head .search.fsearch { flex: 1 1 240px; min-width: 200px; max-width: 360px; }
.search.fsearch.doc-search { width: 280px; flex: none; }
.search.fsearch.hr-search { width: 240px; flex: none; }
.tab-sub { margin: -12px 0 16px; color: var(--ink-3); font-size: var(--t-sm); }
/* A sheet whose body runs past its pinned buttons shows a shadow above them. */
.modal.overflows .card-body > .form > .actions:last-child, .modal.overflows .card-body > .doc-actions:last-child, .modal.overflows .card-body > .actions:last-child { box-shadow: 0 -8px 14px -8px rgba(16, 24, 40, 0.22); }
@media (max-width: 860px) {
  .search.fsearch, .search.fsearch.doc-search, .search.fsearch.hr-search, .toolbar > .search.fsearch, .card-head .search.fsearch, .help-search .search.fsearch { flex: 1 1 100%; width: 100%; max-width: none; min-width: 0; }
  .search.fsearch input[type="search"] { height: 44px; font-size: 16px; }
  /* A toolbar with a search and one switch (Inventory) keeps them on one row. */
  .card > .toolbar:not(:has(select)):has(> .seg) { flex-wrap: nowrap; }
  .card > .toolbar:not(:has(select)):has(> .seg) > .search.fsearch { flex: 1 1 auto; width: auto; }
  .card > .toolbar:not(:has(select)):has(> .seg) > .spacer { display: none; }
  .card > .toolbar > .seg { flex: none; }
}
/* Keyboard focus shows on every control; inside the rail, tabs, and menus the ring sits just inside, so a scrolling edge never cuts it. */
.rail :focus-visible, .tabs a:focus-visible, .menu > summary:focus-visible, .tabbar :focus-visible { outline-offset: -2px; }

/* Loading: grey bars in the real card and row shapes, so nothing jumps when the data lands. */
.sk { display: block; height: 12px; border-radius: var(--r-sm); background: var(--surface-3); }
.sk-head { width: 140px; height: 16px; }
.sk-title { height: 14px; margin: 3px 0 8px; }
.sk-a { width: 62%; } .sk-b { width: 48%; } .sk-c { width: 56%; }
.sk-meta { width: 34%; height: 10px; }
.sk-chip { display: inline-block; width: 120px; height: 10px; vertical-align: middle; }
.sk-btn { width: 96px; height: 30px; border-radius: var(--radius); }
.sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }

/* A counter touchscreen or tablet: the desktop's small controls grow to 36px. */
@media (pointer: coarse) and (min-width: 861px) {
  .btn.sm { min-height: 36px; }
  .iconbtn.sm, .menu > summary.iconbtn { width: 36px; height: 36px; }
}

@media (max-width: 860px) {
  /* The drawer starts after the four pages the tab bar already shows. */
  .rail > a.nav-item[href="#/today"], .rail > a.nav-item[href="#/schedule"], .rail > a.nav-item[href="#/events"], .rail > a.nav-item[href="#/messages"] { display: none; }
  /* Every phone sheet has the same top: a handle, and a close button at the right. */
  .modal::before { content: ""; display: block; width: 36px; height: 4px; border-radius: var(--r-sm); background: var(--line-2); margin: 8px auto 0; }
  .popover .pop-close { display: grid; position: absolute; top: 8px; right: 8px; }
  .popover .pop-head { padding-right: 56px; }
  .popover.user .pop-user { padding-right: 56px; }
  .popover { position: fixed; }
  .back-link { min-height: 44px; }
  /* Phone week: one line a shift, name left and time right; your own keeps its tint. */
  .week .day > .shift { display: flex; align-items: baseline; gap: 8px; padding: 6px 8px; margin-bottom: 2px; }
  .week .day > .shift:not(.me):not(.ev):not(.off) { background: none; padding-left: 0; padding-right: 0; }
  .week .day > .shift .when { display: inline; margin-left: auto; font-variant-numeric: tabular-nums; color: var(--ink); opacity: 1; }
  .week .day > .shift .loc { margin-left: 0; }
  /* An event's title keeps its line; its time and Mandatory go under it. */
  .week .day > .shift.ev { flex-direction: column; align-items: flex-start; gap: 0; }
  .week .day > .shift.ev .when { margin-left: 0; }
  /* Messages: the chips that fit, then "+N" for the rest (foldStrip); "+ New" sits outside, always whole. */
  .chat .threads .thread-new { width: auto; margin: 0; flex: none; color: var(--ink); box-shadow: inset 0 0 0 1px var(--line-2); }
  .wide-only { display: none; }
}
@media (max-width: 600px) {
  .signin-card { padding: 20px 16px; }
  .signin { padding-left: 12px; padding-right: 12px; }
}
/* On a phone the calendar's time sits on its own line above the title, so titles keep the row's width. */
@media (max-width: 860px) {
  .list > li:has(> .cal-when) { flex-wrap: wrap; row-gap: 2px; }
  .list > li > .cal-when { flex: 1 1 100%; padding-top: 0; }
}
/* Phase H, phone chrome. */
@media (max-width: 860px) {
  /* The page ends above the tab bar and the home indicator. */
  .main { padding-bottom: calc(var(--tab-h) + env(safe-area-inset-bottom) + 32px); }
  /* Phone-only pills that lead a facts line carry their own separator. */
  .list .m-only.m-lead { display: inline; }
  /* Home's own to-dos: an action always takes its own line under the text, one placement for the list. */
  .todo > li:has(> .btn) { flex-wrap: wrap; row-gap: 8px; }
  .todo > li:has(> .btn) > .grow { flex: 1 0 100%; }
  .todo > li:has(> .btn) > .btn { order: 3; }
  /* Messages: the composer follows a short thread; a long one scrolls with the page and the composer docks above the tab bar. */
  .chat { display: flex; flex-direction: column; }
  .chat .compose, .chat .compose-note { position: sticky; bottom: calc(var(--tab-h) + env(safe-area-inset-bottom)); z-index: 2; background: var(--surface); border-radius: 0 0 var(--radius-lg) var(--radius-lg); }
  /* The sign-in preview list stays short enough to reach the first card. */
  .preview-role .blurb { -webkit-line-clamp: 1; }
}

/* Phone fields: everything you type in is 16px (readable, and iOS does not zoom), and a detail view's selects are 44px tall. */
@media (max-width: 860px) {
  input:not([type="checkbox"]):not([type="radio"]):not([type="file"]):not([type="range"]):not([type="color"]), select, textarea { font-size: 16px; }
  .detail-kv select, .detail-kv input[type="date"], .detail-kv .date-field { min-height: 44px; }
}

/* A 320px calendar keeps month and Store/Mine on one row: narrower arrows, still 44px tall. */
@media (max-width: 359px) { .cal-bar .pager .iconbtn { width: 34px; } .cal-bar .seg .btn { padding: 8px 8px; } }
