/* The Command Center: phone first, light and dark following the phone; the wide-screen layer (a PC) is at the end. */

:root {
  --bg: #f4f5f7;
  --surface: #ffffff;
  --surface-2: #eef0f3;
  --text: #16181d;
  --muted: #5d6573;
  --line: #dde1e7;
  --accent: #2f5bd3;
  --accent-text: #ffffff;
  --accent-soft: #e5ecfc;
  --advice: #1f7a4d;
  --advice-soft: #e2f4ea;
  --danger: #c23b33;
  --danger-soft: #fbe7e5;
  --warn: #9a6200;
  --warn-soft: #fff3d6;
  /* The kind of a report on Meldingen (COMMAND-101): Idee blue, Bug red, Feedback purple, Kaart green, Crash dark
     orange, Testerverzoek teal (COMMAND-869), Overig grey. */
  --type-idea: var(--accent);
  --type-bug: var(--danger);
  --type-feedback: #7c3aed;
  --type-map: var(--advice);
  --type-crash: #c2410c;
  --type-alert: var(--warn);
  --type-tester-request: #0f766e;
  --type-other: var(--muted);
  --radius: 14px;
  /* The page shell (COMMAND-486, COMMAND-884): the margin left and right of the tab bar and the page; the height of the
     sticky top block (public/topbar-height keeps it equal to the real one); the width of the utility bar along the left
     edge and of the Threads window's panel right beside it. */
  --gutter: 16px;
  --topbar-h: 52px; /* the tab bar alone since COMMAND-582 (no header row above it) */
  --utility-rail-w: 52px;
  --utility-panel-w: 400px;
  --shadow: 0 1px 2px rgb(0 0 0 / 6%);
  /* A chart row whose foreign key points into another ERD (COMMAND-542): its text, its band, its jump button. */
  --chart-xref: #6d28d9;
  --chart-xref-soft: #efe7ff;
  /* A table's id that descends from another table (COMMAND-703): its row, its line and its jump button, green. */
  --chart-descends: #15803d;
  --chart-descends-soft: #dcfce7;
  /* A base's table on the paper (COMMAND-762): a dashed grey outline, a grey body, a striped header and a dark chip with
     its ERD's name. A base table placed here: its own fields on a light-blue band with a blue bar and rule. The paper
     stays white in dark mode, so these are the same in both. */
  --chart-base-line: #8a94a3;
  --chart-base-fill: #f1f3f5;
  --chart-base-hatch: #cfd5dd;
  --chart-base-label: #5d6573;
  --chart-extend: #0369a1;
  --chart-extend-soft: #e0f2fe;
  --chart-base-fk: #2563eb;
  --chart-base-fk-soft: #dbeafe;
  color-scheme: light;
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg: #0f1115;
    --surface: #181b21;
    --surface-2: #22262e;
    --text: #e8eaee;
    --muted: #9aa2af;
    --line: #2c313a;
    --accent: #7c9cf5;
    --accent-text: #0f1115;
    --accent-soft: #1f2a45;
    --advice: #5cc98e;
    --advice-soft: #16301f;
    --danger: #f07b72;
    --danger-soft: #3a1b19;
    --warn: #f0b64a;
    --warn-soft: #34290f;
    --type-feedback: #b39afb;
    --type-crash: #fb923c;
    --type-tester-request: #2dd4bf;
    --shadow: none;
    /* The chart paper stays white in dark mode (.chart-stage), so the cross-ERD row keeps a light band with dark text;
       the jump button a shade brighter so it still stands out next to the dark page around the paper. */
    --chart-xref: #7c3aed;
    --chart-xref-soft: #ede4ff;
    /* The descends green on the white paper, as in light mode. */
    --chart-descends: #15803d;
    --chart-descends-soft: #dcfce7;
    /* A base's table on the paper (COMMAND-762): a dashed grey outline, a grey body, a striped header and a dark chip with
       its ERD's name. A base table placed here: its own fields on a light-blue band with a blue bar and rule. The paper
       stays white in dark mode, so these are the same in both. */
    --chart-base-line: #8a94a3;
    --chart-base-fill: #f1f3f5;
    --chart-base-hatch: #cfd5dd;
    --chart-base-label: #5d6573;
    --chart-extend: #0369a1;
    --chart-extend-soft: #e0f2fe;
    --chart-base-fk: #2563eb;
    --chart-base-fk-soft: #dbeafe;
    color-scheme: dark;
  }
}

* { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font: 16px/1.45 system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  overflow-wrap: anywhere;
}
a { color: var(--accent); }
/* Links inside free text from the floor (linkify.js): underlined so they read as
   links in both themes; a long URL wraps instead of widening the page. */
.auto-link { color: var(--accent); text-decoration: underline; text-underline-offset: 2px; overflow-wrap: anywhere; word-break: break-word; }
h1, h2, h3 { line-height: 1.25; margin: 0; }
.hidden { display: none !important; }
/* A file input the label opens: invisible but not display:none (older iOS ignores those). */
.file-input { position: absolute; width: 1px; height: 1px; opacity: 0; overflow: hidden; pointer-events: none; }
label.btn { position: relative; }
.muted { color: var(--muted); }
.small { font-size: 0.86rem; }
.error { color: var(--danger); }
.warn-text { color: var(--warn); }

/* ---------- shell ---------- */

/* The top of every screen: only the tab bar (COMMAND-582; PO, 2026-10-11: "wil
   alleen navigatie bar maar zien"), and under it the notice strip while a notice
   applies — ONE sticky block, in view however far the PO scrolls (PO, 2026-09-29:
   "de navigatie in de bodem is schijt irritant, dit moet naar boven.... en gewoon
   altijd zichtbaar"). Its own top padding keeps the notch and the clock clear. */
.topbar {
  position: sticky;
  top: 0;
  z-index: 5;
  padding-top: env(safe-area-inset-top);
  background: color-mix(in srgb, var(--bg) 92%, transparent);
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
  border-bottom: 1px solid var(--line);
}
/* The notice strip (public/sync-notice): thin, under the tab bar, only while
   "Nieuwe versie" or "Offline" applies. */
.sync-notice {
  padding: 4px calc(env(safe-area-inset-right) + 16px) 6px calc(env(safe-area-inset-left) + 16px);
  font-size: 0.8rem;
  text-align: center;
  border-top: 1px solid var(--line);
}
.sync-notice[hidden] { display: none; }
.icon-btn {
  width: 40px; height: 40px;
  border: 0; border-radius: 50%;
  background: var(--surface-2); color: var(--text);
  display: grid; place-items: center;
}
.icon-btn svg { width: 22px; height: 22px; }

/* The page uses the full width (COMMAND-486) next to the utility bar on the left (COMMAND-884): it starts right of the
   bar, and right of the Threads window's panel while that is open — the page shrinks, the panel never covers it (a
   phone: the panel covers the page, there is no room beside it). The id outranks a page's own margin (a chart page). */
.view {
  margin: 0 auto;
  padding: 12px 16px 0;
  padding-bottom: calc(env(safe-area-inset-bottom) + 24px);
}
#app:has(> .utility-bar) > main { margin-left: var(--utility-rail-w); }
#app:has(> .thread-window) > main { margin-left: calc(var(--utility-rail-w) + var(--utility-panel-w)); }
/* COMMAND-1661: a wide window (the shared browser) takes all the room right of the bar, so the page has none beside it. */
#app:has(> .thread-window.tw-wide) > main { margin-left: var(--utility-rail-w); }
@media (max-width: 720px) {
  #app:has(> .thread-window) > main { margin-left: var(--utility-rail-w); }
}

/* The tab bar: one row, never wrapped, the labels never cut or shrunk. When the
   tabs do not fit (a phone) the row scrolls sideways, the open tab is scrolled
   into view (app.js placeTabs) and a fade at an edge says there is more; when
   they fit, they share the width evenly, as wide as the page. */
.tabs {
  position: relative;
  display: flex;
  margin: 0 auto;
  padding: 0 calc(env(safe-area-inset-right) + 4px) 0 calc(env(safe-area-inset-left) + 4px);
  overflow-x: auto;
  overscroll-behavior-x: contain;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
}
.tabs::-webkit-scrollbar { display: none; }
.tabs.more-right { -webkit-mask-image: linear-gradient(to left, transparent, #000 28px); mask-image: linear-gradient(to left, transparent, #000 28px); }
.tabs.more-left { -webkit-mask-image: linear-gradient(to right, transparent, #000 28px); mask-image: linear-gradient(to right, transparent, #000 28px); }
.tabs.more-left.more-right {
  -webkit-mask-image: linear-gradient(to right, transparent, #000 28px, #000 calc(100% - 28px), transparent);
  mask-image: linear-gradient(to right, transparent, #000 28px, #000 calc(100% - 28px), transparent);
}
.tab {
  position: relative;
  flex: 1 0 auto;
  min-width: 56px;
  border: 0; border-bottom: 3px solid transparent;
  background: none; color: var(--muted);
  padding: 6px 8px 4px;
  display: flex; flex-direction: column; align-items: center; gap: 2px;
  font: inherit; font-size: 0.75rem; line-height: 1.25;
  white-space: nowrap; overflow-wrap: normal;
  cursor: pointer;
}
.tab svg { width: 20px; height: 20px; flex: none; }
.tab.active { color: var(--accent); font-weight: 600; border-bottom-color: var(--accent); }
.badge {
  position: absolute; top: 2px; left: calc(50% + 5px);
  min-width: 18px; height: 18px; padding: 0 5px;
  border-radius: 9px;
  background: var(--danger); color: #fff;
  font-size: 0.7rem; font-weight: 700; line-height: 18px; text-align: center;
}
/* The icons; never the ERD drawing, whose lines carry their own colour (COMMAND-1009). */
svg:not(.chart-svg) path { fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
/* Taken: the Work Dispatcher Agents' items that escalated to the PO (COMMAND-88), a red "X!" on the other side of the icon. */
.badge.badge-alert { left: auto; right: calc(50% + 5px); }

/* The utility bar (COMMAND-486; COMMAND-884, PO, 2026-10-13: "Utility Bar wordt nu een side bar aan de linker kant. De
   sidebar maakt gebruik van de hele hoogte"): a thin sidebar along the left edge, from under the top bar to the bottom
   of the screen, the top bar's look. Icons only, the full name on hover (the tooltip), never folded open (PO: "na design
   tekenen moet het niet collapsable zijn"). ONE group (COMMAND-766): Threads (a dot when a new loose thread was typed but
   not sent), Record Threads, New Idea (COMMAND-727; a dot when an idea was typed but not sent), Chores and up to three
   pinned threads, stacked from the bottom up (PO: "Items gaan van onder naar boven"): Threads lowest. Under the top bar
   (its menus open over the bar); the page starts right of it (.view above). */
.utility-bar {
  position: fixed;
  left: 0;
  top: var(--topbar-h);
  bottom: 0;
  z-index: 4;
  width: var(--utility-rail-w);
  display: flex; flex-direction: column;
  padding: 6px 0 calc(env(safe-area-inset-bottom) + 6px) env(safe-area-inset-left);
  box-sizing: content-box;
  background: color-mix(in srgb, var(--bg) 92%, transparent);
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
  border-right: 1px solid var(--line);
}
/* The group: its buttons one above the other from the bottom up; a screen too low for all of them scrolls the group. */
.utility-group { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column-reverse; align-items: center; justify-content: flex-start; gap: 4px; overflow-y: auto; scrollbar-width: none; }
.utility-group::-webkit-scrollbar { display: none; }
.utility-btn {
  position: relative;
  flex: none;
  width: 40px; height: 40px;
  display: inline-flex; align-items: center; justify-content: center;
  padding: 0;
  border: 0; border-radius: 8px;
  background: none; color: var(--text);
  font: inherit;
  cursor: pointer;
}
.utility-btn:hover { background: var(--surface-2); }
.utility-btn:disabled { opacity: 0.45; cursor: default; background: none; }
.utility-btn svg { width: 20px; height: 20px; flex: none; }
.utility-btn[aria-expanded="true"] { background: var(--accent-soft); color: var(--accent); }
.fab-dot { position: absolute; top: 4px; right: 4px; width: 12px; height: 12px; border-radius: 50%; background: var(--warn); border: 2px solid var(--bg); }
/* COMMAND-969: what waits behind Approvals and Questions for me, a small number on the button (the look of .tw-switch-count). */
.utility-count { position: absolute; top: 2px; right: 2px; min-width: 18px; height: 18px; padding: 0 5px; border-radius: 9px; background: var(--danger); color: #fff; font-size: 0.72rem; font-weight: 700; line-height: 18px; text-align: center; pointer-events: none; }
/* The panels' rows (public/answer-panels): the answer under what was asked. */
.ap-row-answer { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ap-details { display: flex; flex-direction: column; gap: 12px; }
.ap-details .ap-question { margin: 0; font-weight: 600; }
.ap-fact { display: flex; flex-direction: column; gap: 2px; }

/* The Threads window (COMMAND-766, public/thread-window): since COMMAND-884 a sidebar of its own, stuck to the utility
   bar's right side, from under the top bar to the bottom of the screen (PO: "het maakt gebruik van de volledige hoogte
   ook"). The page shrinks beside it, it never floats over the page (PO: "C wordt ingekrimpt, dus D zweeft niet over
   C"); on a phone, with no room beside it, it covers the page next to the bar. No backdrop, and nothing on the page, the
   top bar or another bar button closes it: only its own button again, or another button of the bar in its place. A
   header that stays (what the threads hang on, Open / Archived, New — or back, the thread's name, its actions), and only
   the list or the messages scroll. */
.thread-window {
  position: fixed;
  z-index: 4;
  left: calc(env(safe-area-inset-left) + var(--utility-rail-w) + 1px);
  top: var(--topbar-h);
  bottom: 0;
  width: var(--utility-panel-w);
  box-sizing: border-box;
  display: flex; flex-direction: column;
  padding: 12px 12px calc(env(safe-area-inset-bottom) + 12px);
  background: var(--surface);
  border-right: 1px solid var(--line);
}
.thread-window.enter { animation: panel-in .18s ease-out; }
@keyframes panel-in { from { transform: translateX(-24px); opacity: .6; } to { transform: none; opacity: 1; } }
@media (prefers-reduced-motion: reduce) { .thread-window.enter { animation: none; } }
@media (max-width: 720px) {
  .thread-window { right: 0; width: auto; border-right: 0; }
}
.thread-window.tw-wide { right: 0; width: auto; border-right: 0; }
/* View 1, Index: A (the record, Open / Archived) left, D (New) right; under it the list, the only part that scrolls. */
.tw-head { flex: none; display: flex; align-items: flex-start; justify-content: space-between; gap: 8px; margin-bottom: 10px; }
.tw-head-a { min-width: 0; display: flex; flex-direction: column; gap: 6px; }
.tw-home { display: block; max-width: 100%; font-weight: 700; font-size: 1rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
a.tw-home { color: var(--accent); text-decoration: none; }
a.tw-home:hover { text-decoration: underline; }
.tw-switch { display: inline-flex; width: fit-content; padding: 2px; border: 1px solid var(--line); border-radius: 8px; background: var(--surface-2); }
.tw-switch-btn { min-height: 28px; padding: 0 10px; border: 0; border-radius: 6px; background: none; color: var(--muted); font: inherit; font-size: 0.82rem; font-weight: 600; cursor: pointer; }
.tw-switch-btn.on { background: var(--surface); color: var(--text); box-shadow: 0 1px 3px rgb(0 0 0 / 18%); }
/* Escalated's count (COMMAND-809): how many open threads are escalated, a red number. */
.tw-switch-btn { display: inline-flex; align-items: center; gap: 5px; }
/* Unread (COMMAND-1084): an icon only, its name as tooltip. */
.tw-switch-btn.tw-switch-icon { padding: 0 8px; }
.tw-switch-btn.tw-switch-icon svg { width: 18px; height: 18px; flex: none; }
.tw-switch-count { min-width: 18px; height: 18px; padding: 0 5px; border-radius: 9px; background: var(--danger); color: #fff; font-size: 0.72rem; font-weight: 700; line-height: 18px; text-align: center; }
.tw-row-about { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tw-row-wait { color: var(--warn); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* COMMAND-1670: a card no PC starts (public/pin-waits): an orange line of its own. */
.pin-wait-line { display: block; flex-basis: 100%; color: var(--warn); font-size: 0.85em; line-height: 1.3; white-space: normal; }
.tw-new { flex: none; min-height: 36px; }
.tw-head-b { flex: none; display: flex; align-items: center; gap: 6px; }
.tw-next-ten { flex: none; min-height: 36px; }
.tw-body { flex: 1 1 auto; min-height: 0; overflow-y: auto; overscroll-behavior: contain; }
.tw-list { list-style: none; margin: 0; padding: 0; border: 1px solid var(--line); border-radius: 12px; overflow: hidden; }
.tw-list > li + li { border-top: 1px solid var(--line); }
.tw-row {
  display: flex; align-items: flex-start; gap: 8px; width: 100%; min-height: 48px; padding: 8px 10px;
  border: 0; background: transparent; color: var(--text); font: inherit; text-align: left; cursor: pointer;
}
.tw-row:hover { background: var(--surface-2); }
.tw-row-main { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.tw-row-title { display: flex; align-items: center; gap: 4px; min-width: 0; }
.tw-row-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* COMMAND-805: a favourite thread amber with a star (COMMAND-1257), an escalated one red with its badge;
   escalated after favourite, so red wins over amber alone; both is red into amber (BUG-833, below). */
/* COMMAND-1050: an archived row grey (Setup's colour); a favourite below it keeps its amber. */
.tw-row.archived, .tw-row.archived:hover { background: color-mix(in srgb, var(--color-thread-archived, var(--muted)) 14%, var(--surface)); box-shadow: inset 4px 0 0 var(--color-thread-archived, var(--muted)); }
.tw-row.favorite, .tw-row.favorite:hover { background: var(--warn-soft); box-shadow: inset 3px 0 0 var(--warn); }
.tw-row-star { flex: none; display: inline-flex; color: var(--warn); }
.tw-row-star svg { width: 16px; height: 16px; }
.tw-row-star svg path { fill: currentColor; }
/* COMMAND-1050: the colours of Setup's colour settings (public/colors), as the open conversation's border; an archived row
   grey (archived wins over escalated and favourite). */
.tw-row.escalated, .tw-row.escalated:hover { background: color-mix(in srgb, var(--color-thread-escalated, var(--danger)) 14%, var(--surface)); box-shadow: inset 4px 0 0 var(--color-thread-escalated, var(--danger)); }
/* BUG-833 (the PO, 2026-10-19: "het gradient ... als het zowel escalated als favorite is van links (rood) naar rechts (geel)"):
   escalated and a favourite — red on the left running into amber on the right, a red bar left and an amber bar right. */
.tw-row.escalated.favorite, .tw-row.escalated.favorite:hover { background: linear-gradient(to right, color-mix(in srgb, var(--color-thread-escalated, var(--danger)) 14%, var(--surface)), var(--warn-soft)); box-shadow: inset 4px 0 0 var(--color-thread-escalated, var(--danger)), inset -3px 0 0 var(--warn); }
/* COMMAND-1050: a kept-open conversation's chip, in Setup's colour (--color-thread-kept-open), beside the row's own state. */
.tw-row-kept-open {
  flex: none; margin-left: 4px; padding: 0 8px; border-radius: 9px;
  background: var(--color-thread-kept-open, var(--accent)); color: #fff;
  font-size: 0.72rem; font-weight: 700; line-height: 18px; white-space: nowrap;
}
/* COMMAND-811: the card a thread is on (an idea's), its number beside the name; it never shrinks away. */
.tw-row-card { flex: none; margin-left: 2px; font-size: 0.78rem; color: var(--muted); }
.tw-row.unread .tw-row-name { font-weight: 750; }
.tw-row-last { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tw-row-age { flex: none; }
.tw-note { margin: 4px 0; }
/* View 2, Chat (and New): the thread panel fills the window — F (back) | the name | G (its actions) on top, the
   messages in the middle (the only part that scrolls), the reply box at the bottom. */
.thread-window > .thread-panel { flex: 1 1 auto; height: auto; min-height: 0; resize: none; }
.thread-window > .thread-panel > .thread-history { flex: 1 1 auto; min-height: 0; }
.thread-window > .thread-panel > .thread-reply { padding-bottom: 0; }
/* BUG-933: a New screen's middle (public/thread newPanel) — no message area yet, so no border: it takes the free room
   (the message box stays at the bottom) and holds Instellingen at its top, the panel's full width. */
.thread-panel > .thread-new-body { flex: 1 1 auto; min-height: 0; margin-top: 12px; overflow-y: auto; overscroll-behavior: contain; }
/* CHORE-165, BUG-933: New ticket's type, a row of the box Instellingen (label above, the full width), as the Device picker. */
.tw-ticket-type { display: flex; flex-direction: column; gap: 4px; }
.tw-ticket-type-label { font-size: 0.85rem; color: var(--muted); }
.tw-ticket-type > select.input { width: 100%; }
.thread-panel-head .thread-back { flex: none; width: 40px; height: 40px; background: transparent; color: var(--muted); }
.thread-panel-head .thread-back:hover { background: var(--surface-2); color: var(--text); }
.thread-panel-head .thread-back svg { width: 20px; height: 20px; }
.tw-pin.on { color: var(--accent); }
/* COMMAND-936: an idea's details in the Ideas window — back | its name | its number | the toggle (Threads / Details) on
   top; under it its facts, description and a way to its page, or the card's Threads box in their place. */
.tw-card-head { flex: none; margin-bottom: 10px; }
.tw-card-head .tw-row-card { flex: none; }
/* CHORE-188: an opened ticket's number alone, a link; the menu stays top right. */
.tw-card-head .tw-chip-link { margin-right: auto; text-decoration: none; cursor: pointer; }
.tw-card-head .tw-chip-link:hover { text-decoration: underline; }
.tw-card-toggle { flex: none; display: inline-flex; align-items: center; gap: 5px; }
.tw-card-toggle svg { width: 16px; height: 16px; }
.tw-card-toggle.on { background: var(--surface-2); color: var(--accent); }
.tw-card-facts { display: grid; grid-template-columns: auto 1fr; gap: 6px 12px; margin-bottom: 14px; }
.tw-card-fact { display: contents; }
.tw-card-desc h4 { margin: 0 0 6px; font-size: 0.9rem; }
.tw-card-desc { margin-bottom: 14px; overflow-wrap: anywhere; }
/* COMMAND-1350: a chore's details — back | its title | its number | the thread head's ⋮ menu top right (its rules copied under
   .tw-card-head, beside the thread head's own), whose one row is Threads with a Settings-like switch at its right end. With the threads on, the
   card's Threads box takes the details' place over the whole height (BUG-792: as the old Ideas box; its list, or a
   tapped thread's chat, scrolls inside it). */
.tw-card-head .thread-more-btn { width: 40px; height: 40px; background: transparent; color: var(--muted); }
.tw-card-head .thread-more-btn:hover { background: var(--surface-2); color: var(--text); }
.tw-card-head .thread-more-btn svg { width: 20px; height: 20px; }
.tw-card-head .thread-more-menu .tw-chore-threads::after { order: 1; }
.tw-chore-threads .switch { order: 2; margin-left: auto; min-height: 0; pointer-events: none; }
.tw-chore-threads .switch-track { width: 36px; height: 22px; border-radius: 11px; }
.tw-chore-threads .switch-track::after { width: 16px; height: 16px; }
.tw-chore-threads .switch.on .switch-track::after { transform: translateX(14px); }
.tw-chore-body.threads-on { display: flex; flex-direction: column; overflow: hidden; }
.tw-chore-threads-box { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; }
/* BUG-792: the threads bare (no box, no Threads title), as the window's own views: the list scrolls under its tabs, a
   tapped thread's chat fills the whole height — never the page box's fixed height with its drag corner. */
.tw-card-threads { display: flex; flex-direction: column; overflow: hidden; }
.tw-threads { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; }
.tw-threads-list { flex: 1 1 auto; min-height: 0; overflow-y: auto; overscroll-behavior: contain; }
.tw-threads > .thread-panel { flex: 1 1 auto; height: auto; min-height: 0; resize: none; }
.tw-threads > .thread-panel > .thread-history { flex: 1 1 auto; min-height: 0; }
.tw-threads > .thread-panel > .thread-reply { padding-bottom: 0; }

.toast {
  position: fixed;
  left: 16px; right: 16px;
  bottom: calc(env(safe-area-inset-bottom) + 84px);
  /* Above the chat panel and the dialogs: an error while sending shows there too. */
  z-index: 30;
  max-width: 560px; margin: 0 auto;
  padding: 12px 14px;
  border-radius: 12px;
  background: var(--text); color: var(--bg);
  opacity: 0; transform: translateY(8px);
  transition: opacity .2s, transform .2s;
  pointer-events: none;
}
.toast.show { opacity: 1; transform: none; }
.toast.error { background: var(--danger); color: #fff; }
.toast.warn { background: var(--warn); color: #fff; }
/* A toast with one button (Ongedaan maken, COMMAND-266): the text and the button on one line; only the button takes a tap. */
.toast.has-action { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.toast-action { flex: none; min-height: 36px; padding: 6px 12px; border: 1px solid currentColor; border-radius: 8px; background: transparent; color: inherit; font: inherit; font-weight: 600; cursor: pointer; }
.toast.show .toast-action { pointer-events: auto; }

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

.card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 14px;
  margin: 0 0 12px;
}
.card h2 { font-size: 1.05rem; margin-bottom: 8px; }
.card-head { display: flex; justify-content: space-between; align-items: baseline; gap: 10px; }
.card-id { font-weight: 700; text-decoration: none; }
.asker { color: var(--muted); margin-top: 2px; }
.context { white-space: pre-wrap; margin: 10px 0 4px; }
.waiting {
  margin: 10px 0 0; padding: 8px 10px;
  border-radius: 10px;
  background: var(--surface-2);
  font-size: 0.9rem;
}
.tag {
  display: inline-block;
  margin-left: 6px; padding: 1px 7px;
  border-radius: 8px;
  background: var(--surface-2); color: var(--muted);
  font-size: 0.72rem;
}
.empty { text-align: center; color: var(--muted); padding: 40px 0; }

.group { margin-bottom: 18px; }
.group-title { font-size: 1rem; margin: 8px 2px; display: flex; align-items: center; gap: 8px; }
.project-title { font-size: 0.9rem; color: var(--muted); margin: 10px 2px 6px; display: flex; align-items: center; gap: 8px; font-weight: 600; }
.count {
  min-width: 22px; padding: 0 7px;
  border-radius: 11px;
  background: var(--surface-2); color: var(--muted);
  font-size: 0.75rem; line-height: 22px; text-align: center;
}

/* ---------- questions ---------- */

.question { border-top: 1px solid var(--line); margin-top: 14px; padding-top: 12px; }
.question h3 { font-size: 1.02rem; margin: 4px 0 10px; }
.chip {
  display: inline-block;
  padding: 1px 8px; border-radius: 8px;
  background: var(--accent-soft); color: var(--accent);
  font-size: 0.75rem; font-weight: 600;
}
.options { display: grid; gap: 8px; }
.option {
  text-align: left;
  width: 100%;
  padding: 11px 12px;
  border: 1.5px solid var(--line);
  border-radius: 12px;
  background: var(--surface);
  color: var(--text);
  font: inherit;
  display: grid; gap: 3px;
}
.option { cursor: pointer; -webkit-tap-highlight-color: transparent; }
.option:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.option.advised { border-color: color-mix(in srgb, var(--advice) 55%, var(--line)); }
.option.picked { border-color: var(--accent); background: var(--accent-soft); box-shadow: inset 0 0 0 1px var(--accent); }
/* IDEA-5669: an answered question is the same card, read only: the pick stays marked, the others quiet. */
.question.answered .option { cursor: default; }
.question.answered .option:not(.picked) { opacity: 0.55; }
.question-answer-note { margin: 8px 0 0; }
.option-label { font-weight: 650; display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.option-desc { color: var(--muted); font-size: 0.9rem; }
.advice {
  padding: 0 7px; border-radius: 8px;
  background: var(--advice-soft); color: var(--advice);
  font-size: 0.72rem; font-weight: 700; text-transform: uppercase; letter-spacing: .02em;
}
.why { color: var(--muted); margin: 8px 0 0; }

.input {
  width: 100%;
  margin-top: 10px;
  padding: 10px 12px;
  border: 1.5px solid var(--line);
  border-radius: 12px;
  background: var(--surface);
  color: var(--text);
  font: inherit;
}
.input:focus { outline: none; border-color: var(--accent); }
textarea.input { resize: vertical; }
/* Every box the PO writes in (COMMAND-48; PO, 2026-09-30: "Maak de reactie boxen groter bij
   default... dit is krapjes"): it opens about seven lines tall (a line is 1.45em; 23px is the
   padding and border of .input), grows with its text up to 60% of the screen and then scrolls,
   the same on phone and PC. app.js's h() gives every textarea the class grow; this is the one
   place its sizes live. A browser that sizes a box to its text itself does it here; elsewhere
   app.js (fitBox) follows the text. */
textarea.input.grow {
  min-height: calc(7 * 1.45em + 23px);
  max-height: 60vh;
  max-height: 60dvh;
  overflow-y: auto;
}
@supports (field-sizing: content) {
  textarea.input.grow { field-sizing: content; }
}
/* @project tags (COMMAND-106): after an @ the box offers the projects that fit, in a list right
   under it (public/tags). Big enough rows for a thumb; the marked one (Tab/Enter) stands out.
   A tag in a shown text is the project's pill (.proj-pill, below) in the flow of the text. */
.tag-suggest { margin: 4px 0 0; padding: 4px; list-style: none; background: var(--surface); border: 1px solid var(--line); border-radius: 10px; box-shadow: 0 4px 14px rgb(0 0 0 / 12%); }
.tag-option { display: flex; align-items: center; gap: 8px; min-height: 40px; padding: 4px 10px; border-radius: 8px; cursor: pointer; }
.tag-option.active, .tag-option:hover { background: var(--surface-2); }
.tag-option-skill .tag-skill-purpose { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tag-pill { vertical-align: 1px; }
/* @PC tags (COMMAND-134): a PC's name with a small PC icon — in the list, in a shown text, and on a
   work item that waits for that PC. Neutral (not a project colour); its kind word sits at the end. */
.device-pill { display: inline-flex; align-items: center; gap: 4px; padding: 0 8px; border-radius: 8px; background: var(--surface-2); color: var(--text); font-size: 0.75rem; font-weight: 700; white-space: nowrap; }
.device-pill svg { width: 13px; height: 13px; flex: none; }
.tag-kind { margin-left: auto; }
/* Record tags (COMMAND-483, public/tags): any record in the list, its name and, small and grey, its table; in a shown
   text a neutral pill with the record's live name that opens its page. One that is gone keeps its bracket name, struck
   through, and opens nothing. Old @project / @PC pills open their page too. */
.tag-option-record svg { width: 16px; height: 16px; flex: none; color: var(--muted); }
.tag-option-record .tag-name { font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.record-pill { display: inline-block; padding: 0 8px; border-radius: 8px; background: var(--surface-2); color: var(--text); font-size: 0.75rem; font-weight: 700; white-space: nowrap; }
.record-pill[role='link'], .proj-pill[role='link'], .device-pill[role='link'] { cursor: pointer; }
.record-pill[role='link']:hover, .proj-pill[role='link']:hover, .device-pill[role='link']:hover { text-decoration: underline; }
.record-pill.record-gone { color: var(--muted); text-decoration: line-through; }
/* COMMAND-604 (public/tag-card; it was COMMAND-547's tagged files below the text): every tagged record as the card of its
   kind — in a row under the text (each record once), or right there when the tag stands alone on its line. A card has
   a small toggle to its chip and a chip one back; the preview over a chip (hover, a long press on the phone) is the same
   card, compact. The cards stand under each other, each the width of the message (the PO, 2026-10-18: "waarom zijn
   Cards zo smal in de chat?? ze moeten onder elkaar komen, soms zie ik er 4 naast elkaar"). */
.tag-cards { display: flex; flex-direction: column; gap: 8px; margin-top: 8px; white-space: normal; }
.tag-display { position: relative; white-space: normal; }
.tag-display-card { display: flex; align-items: flex-start; gap: 4px; min-width: 0; max-width: 100%; }
p > .tag-display-card, .reply-text > .tag-display-card, .fmt > .tag-display-card, .rt > .tag-display-card { margin: 4px 0; }
.tag-display-chip { display: inline-flex; align-items: center; gap: 2px; }
.tag-card {
  display: flex; align-items: center; gap: 10px; flex: 1; min-width: 0;
  padding: 8px 10px; border: 1px solid var(--line); border-radius: 10px; background: var(--surface-2); color: var(--text);
}
.tag-card[role='link'] { cursor: pointer; }
.tag-card[role='link']:hover { border-color: var(--accent); }
.tag-card[role='link']:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.tag-card-icon { flex: none; display: inline-flex; align-items: center; justify-content: center; width: 28px; height: 28px; border-radius: 8px; background: var(--surface); color: var(--muted); }
.tag-card-icon svg { width: 16px; height: 16px; }
.tag-card-main { display: flex; flex-direction: column; min-width: 0; }
.tag-card-title { display: flex; align-items: baseline; gap: 6px; min-width: 0; font-weight: 600; font-size: 0.9rem; overflow-wrap: anywhere; }
.tag-card-meta { display: flex; align-items: center; gap: 5px; flex-wrap: wrap; }
.tag-card-key { flex: none; font-variant-numeric: tabular-nums; font-size: 0.75rem; font-weight: 700; color: var(--muted); }
.tag-card-swatch { display: block; width: 18px; height: 18px; border-radius: 50%; background: var(--proj, var(--accent)); }
.tag-card-lane, .tag-card-online { display: inline-block; flex: none; width: 8px; height: 8px; border-radius: 50%; background: var(--line); }
.tag-card-lane-refinement, .tag-card-lane-refined, .tag-card-lane-review, .tag-card-lane-merged { background: var(--accent); }
.tag-card-lane-in_progress { background: var(--warn); }
.tag-card-lane-testable, .tag-card-lane-accepted, .tag-card-lane-live, .tag-card-online.on { background: var(--advice); }
.tag-card-lane-rejected { background: var(--danger); }
/* CHORE-180: a ticket's status (a ticket's own: completed and done are finished) and its priority, on its card and its
   chip; the priority dot in the colours of the card page's priority (.work-prio). */
.tag-card-lane-completed, .tag-card-lane-done { background: var(--advice); }
.tag-card-prio { display: inline-block; flex: none; width: 8px; height: 8px; border-radius: 50%; background: var(--muted); }
.tag-card-prio-urgent { background: var(--danger); }
.tag-card-prio-high { background: var(--warn); }
.tag-card-prio-medium { background: var(--accent); }
.tag-card-prio-none { background: transparent; box-shadow: inset 0 0 0 1.5px var(--muted); }
.ticket-pill { display: inline-flex; align-items: center; gap: 5px; max-width: 100%; vertical-align: -3px; }
.ticket-pill .tag-card-key { font-size: inherit; }
.ticket-pill > :not(.ticket-pill-title) { flex: none; }
.ticket-pill > span:not(.tag-card-key):not(.ticket-pill-title):not(.tag-card-lane):not(.tag-card-prio) { font-weight: 600; color: var(--muted); }
.ticket-pill-title { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
/* A file's card is its FileCard: no second frame around it. */
.tag-card-file { padding: 0; border: 0; background: none; display: block; }
/* IDEA-5669: a question or an approval the PO can answer now — its block with the choices, right in the chat; answered,
   the small card with the question and the answer under it. */
.tag-card-live { display: block; padding: 10px 12px; }
.tag-card-live .ap-question { margin: 0 0 8px; font-weight: 600; }
.tag-card-live .question { margin: 0; padding-top: 0; border-top: 0; }
/* TP-614: QuestionGroupCard (public/question-group-card) — the bar with a number and a state icon per question, the
   current one marked, Vorige / Overslaan / Volgende, and the folded Klaar card. */
.question-group { display: flex; flex-direction: column; gap: 10px; }
.question-group .question { margin-top: 0; padding-top: 0; border-top: 0; }
.qg-head { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; }
.qg-bar { display: flex; flex-wrap: wrap; gap: 6px; list-style: none; margin: 0; padding: 0; }
.qg-step { display: inline-flex; align-items: center; gap: 4px; min-width: 44px; min-height: 32px; padding: 2px 8px; border: 1px solid var(--line); border-radius: 999px; background: var(--surface); color: var(--muted); font: inherit; cursor: pointer; }
.qg-step .lucide, .qg-step svg { width: 14px; height: 14px; }
.qg-step-answered { color: var(--advice); background: var(--advice-soft); border-color: transparent; }
.qg-step-skipped { color: var(--warn); background: var(--warn-soft); border-color: transparent; }
.qg-step.qg-current { color: var(--accent); border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent); font-weight: 600; }
.qg-nav { display: flex; justify-content: space-between; gap: 8px; }
.qg-nav .qg-skip { margin-left: auto; }
.qg-rule { margin: 0; border: 0; border-top: 1px solid var(--line); }
.qg-done-toggle { display: flex; align-items: center; gap: 8px; width: 100%; padding: 8px 10px; border: 1px solid var(--line); border-radius: 10px; background: var(--advice-soft); color: var(--text); font: inherit; text-align: left; cursor: pointer; }
.qg-done-toggle > .lucide, .qg-done-toggle > svg { color: var(--advice); }
.qg-done-toggle .qg-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.qg-done-list { display: flex; flex-direction: column; gap: 12px; }
.tag-card-live .ap-description { margin: 8px 0 10px; }
.tag-card-live-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.tag-card-answered .tag-card-icon { color: var(--advice); }
.tag-card-answered .tag-card-meta { color: var(--text); opacity: 0.85; }
/* IDEA-5669 (the PO, 2026-10-19): a question's and an approval's status icon left of its question (still open the yellow
   clock), the answer (an approval's outcome, and for rejected or other the explanation) in chips under the question; in
   its card, its live card and its chip. */
.asked-status { flex: none; display: inline-flex; align-items: center; justify-content: center; }
.asked-status svg { width: 16px; height: 16px; }
.asked-status-open, .asked-status-pending { color: #e0a800; }
.asked-status-answered, .asked-status-processed, .asked-status-approved { color: var(--advice); }
.asked-status-rejected { color: var(--danger); }
.asked-status-other { color: var(--accent); }
.asked-status-withdrawn { color: var(--muted); }
.asked-head { display: flex; align-items: flex-start; gap: 8px; }
.asked-head > .asked-status { height: 1.3em; }
.tag-card-headed > .asked-head { margin-bottom: 10px; }
.tag-card-headed .question > h3, .tag-card-headed .ap-question, .tag-card-headed .ap-details.answered .tag-card-live-actions { display: none; }
.asked-head-main { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.asked-chips { display: flex; flex-wrap: wrap; gap: 4px; }
.asked-chip { max-width: 100%; white-space: normal; overflow-wrap: anywhere; }
.asked-chip-answer, .asked-chip-approved, .asked-chip-answered, .asked-chip-processed { background: var(--advice-soft); color: var(--advice); }
.asked-chip-rejected { background: var(--danger-soft); color: var(--danger); }
.asked-chip-why { background: var(--surface-2); color: var(--text); font-weight: 500; }
.tag-pill .asked-head { display: inline-flex; gap: 6px; padding: 3px 0; vertical-align: top; white-space: normal; text-align: left; }
.tag-pill .asked-head .tag-card-title { font-size: inherit; }
.tag-pill .asked-status svg { width: 14px; height: 14px; }
/* TP-614: an answered question's or decided approval's chip is a button that unfolds its read-only card in place. */
.asked-pill { border: 0; font-family: inherit; cursor: pointer; }
.asked-pill:hover { background: var(--line); }
.tag-card-gone { background: var(--surface); color: var(--muted); border-style: dashed; }
.tag-card-gone .tag-card-title { text-decoration: line-through; font-weight: 500; }
.tag-card-pending .tag-card-meta { animation: tag-card-wait 1.2s ease-in-out infinite alternate; }
@keyframes tag-card-wait { from { opacity: 0.4; } to { opacity: 1; } }
@media (prefers-reduced-motion: reduce) { .tag-card-pending .tag-card-meta { animation: none; } }
.tag-card-toggle {
  flex: none; display: inline-flex; align-items: center; justify-content: center; width: 24px; height: 24px; padding: 0;
  border: 0; border-radius: 6px; background: none; color: var(--muted); cursor: pointer;
}
.tag-card-toggle:hover, .tag-card-toggle:focus-visible { background: var(--surface-2); color: var(--text); }
.tag-card-toggle svg { width: 16px; height: 16px; }
/* CHORE-202: every card's ⋮ beside its fold button (public/tag-card), the size of that button; its rows as a
   conversation's menu — the icon, its name (aria-label), the Threads switch at the end. Threads on: the record's Threads
   box in the card's place; Escaleren's reason box under the card, over the whole width. */
.tag-card-more { flex: none; display: inline-flex; }
.tag-card-more .thread-more > .thread-more-btn { display: inline-flex; align-items: center; justify-content: center; width: 24px; height: 24px; padding: 0; border: 0; border-radius: 6px; background: none; color: var(--muted); cursor: pointer; }
.tag-card-more .thread-more > .thread-more-btn:hover, .tag-card-more .thread-more[data-open] > .thread-more-btn { background: var(--surface-2); color: var(--text); }
.tag-card-more .thread-more-btn svg { width: 16px; height: 16px; }
.tag-card-more .thread-more-btn svg path { stroke-width: 3.2; }
.tag-card-more .thread-more-menu > button { display: flex; flex-direction: row; place-items: initial; align-items: center; width: 100%; height: auto; min-height: 40px; justify-content: flex-start; gap: 12px; padding: 0 12px; border: 0; border-radius: 6px; background: none; color: var(--muted); font: inherit; text-align: left; white-space: nowrap; cursor: pointer; }
.tag-card-more .thread-more-menu > button::after { content: attr(aria-label); color: var(--text); }
.tag-card-more .thread-more-menu > button:hover { background: var(--line); }
.tag-card-more .thread-more-menu > button svg { width: 18px; height: 18px; flex: none; }
.tag-card-more .thread-more-menu .fav-star.on { color: var(--warn); }
.tag-card-more .thread-more-menu .tag-card-threads-row::after { order: 1; }
.tag-card-more .thread-more-menu .tag-card-threads-row .switch { order: 2; margin-left: auto; min-height: 0; pointer-events: none; }
.tag-card-more .tag-card-threads-row .switch-track { width: 36px; height: 22px; border-radius: 11px; }
.tag-card-more .tag-card-threads-row .switch-track::after { width: 16px; height: 16px; }
.tag-display-threads > .tag-card-threads { flex: 1; min-width: 0; }
.tag-display-card:has(> .record-state-box) { flex-wrap: wrap; }
.tag-display-card > .record-state-box { order: 9; flex: 1 0 100%; margin: 4px 0 0; }
.tag-card-preview {
  position: fixed; z-index: 60; width: min(320px, calc(100vw - 16px));
  border-radius: 12px; background: var(--surface); box-shadow: 0 6px 24px rgb(0 0 0 / 18%);
}
.tag-card-preview .tag-card { background: var(--surface); }
/* The strip under a box that writes: what the draft tags, each with its toggle (a tap rewrites {card} / {chip}). */
.composer-box.has-tag-modes { flex-wrap: wrap; }
.tag-modes { order: 10; flex-basis: 100%; display: flex; flex-wrap: wrap; gap: 6px; padding: 0 6px; }
.tag-modes[hidden] { display: none; }
.tag-mode { display: inline-flex; align-items: center; gap: 2px; }
.tag-mode-chip .record-pill { opacity: 0.75; }
@media (min-width: 900px) {
  .tag-card-title { font-size: 0.95rem; }
}
/* The lookup page of a record without a page of its own (COMMAND-483, record-page recordCard): its name and kind. */
.card.record-card { max-width: 480px; }
.record-card-name { margin: 0; font-size: 1.1rem; overflow-wrap: anywhere; }
.record-card-kind { margin: 4px 0 0; }
select.input { appearance: auto; }

.gallery { display: flex; gap: 8px; overflow-x: auto; margin: 10px 0 2px; }
.gallery img { height: 120px; max-width: 220px; object-fit: cover; border-radius: 10px; border: 1px solid var(--line); display: block; }
.thumbs { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 10px; }
.thumb { position: relative; width: 72px; height: 72px; border-radius: 10px; overflow: hidden; background: var(--surface-2); display: grid; place-items: center; font-size: 0.7rem; color: var(--muted); }
.thumb img { width: 100%; height: 100%; object-fit: cover; }
.thumb-x {
  position: absolute; top: 3px; right: 3px;
  width: 24px; height: 24px; border: 0; border-radius: 50%;
  background: rgb(0 0 0 / 60%); color: #fff; font-size: 16px; line-height: 24px; padding: 0;
}

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

.actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 12px; justify-content: flex-end; }
.actions.tight { margin-top: 0; flex-wrap: nowrap; }
.btn {
  min-height: 44px;
  padding: 0 16px;
  border: 1.5px solid var(--line);
  border-radius: 12px;
  background: var(--surface-2);
  color: var(--text);
  font: inherit; font-weight: 600;
  display: inline-flex; align-items: center; justify-content: center;
  cursor: pointer;
  /* A label never breaks inside a word (COMMAND-137): the body's overflow-wrap: anywhere broke a label that came
     out a fraction of a pixel wider than its button (browser zoom, rounding) before its last letter ("Afwijze n"). */
  overflow-wrap: normal;
}
/* In a row of buttons that wraps (.actions), each label on one line: the row wraps as whole buttons instead
   (COMMAND-137; "Terugsturen met feedback" broke over two lines). The rows that squeeze their buttons into one
   line on purpose (.tight) still wrap a label between its words. */
.actions:not(.tight) > .btn { white-space: nowrap; }
.btn.primary { background: var(--accent); border-color: var(--accent); color: var(--accent-text); }
.btn.danger { background: var(--danger-soft); border-color: transparent; color: var(--danger); }
.btn.ghost { background: transparent; }
.btn.big { width: 100%; min-height: 52px; font-size: 1.05rem; margin-top: 12px; }
.btn:disabled { opacity: .45; cursor: default; }
.small-btn { min-height: 38px; padding: 0 12px; font-size: 0.88rem; }
.link { border: 0; background: none; color: var(--accent); padding: 4px 0; font: inherit; cursor: pointer; }

/* ---------- folds ---------- */

.fold { margin: 16px 0; }
.fold summary { cursor: pointer; color: var(--muted); font-weight: 600; padding: 8px 2px; }
.answered { background: var(--surface); border: 1px solid var(--line); border-radius: 12px; padding: 10px 12px; margin: 8px 0; }
.answered .q { margin: 4px 0; }
.answered .a { margin: 4px 0; font-weight: 650; white-space: pre-wrap; }
.todo-text { white-space: pre-wrap; margin: 8px 0; font-size: 1.02rem; }
/* A todo's and a request's decline box. */
.composer-title { font-weight: 600; color: var(--muted); }
.composer { margin-top: 12px; padding-top: 10px; border-top: 1px solid var(--line); }
.composer-title { margin-bottom: 6px; }

/* ---------- who does what ---------- */

.pc.stale { opacity: .7; }
.usage { display: grid; grid-template-columns: 56px 1fr 44px; align-items: center; gap: 8px; margin-top: 10px; }
.usage-reset { grid-column: 2 / 4; margin-top: -4px; font-variant-numeric: tabular-nums; }
.usage-label { font-size: 0.85rem; color: var(--muted); }
.usage-num { font-weight: 700; text-align: right; font-variant-numeric: tabular-nums; }
.bar { height: 10px; border-radius: 5px; background: var(--surface-2); overflow: hidden; }
/* A usage bar's fill gets its width and its blue-to-red colour from app.js (usageFill, COMMAND-77); width 0 until then. */
.fill { width: 0; height: 100%; border-radius: 5px; background: var(--accent); }
.warn { background: var(--warn-soft); color: var(--warn); padding: 8px 10px; border-radius: 10px; margin: 10px 0 0; font-size: 0.9rem; }
.roster { list-style: none; margin: 10px 0 0; padding: 0; }
.roster li { display: flex; gap: 10px; padding: 8px 0; border-top: 1px solid var(--line); }
.dot { flex: none; width: 10px; height: 10px; border-radius: 50%; margin-top: 7px; }
.dot.on { background: var(--advice); }
.dot.off { background: var(--line); }

/* ---------- controls ---------- */

.row { display: flex; justify-content: space-between; align-items: center; gap: 10px; padding: 10px 0; border-top: 1px solid var(--line); }
.row:first-of-type { border-top: 0; }
.field { display: block; margin-top: 10px; font-size: 0.9rem; color: var(--muted); }
.radios, .checks { display: grid; gap: 6px; margin-top: 10px; }
.check { display: flex; align-items: center; gap: 8px; min-height: 36px; }
.check input { width: 20px; height: 20px; accent-color: var(--accent); }
.commands { list-style: none; margin: 0; padding: 0; }
.commands li { padding: 8px 0; border-top: 1px solid var(--line); }

/* ---------- login ---------- */

.login { max-width: 420px; margin: 0 auto; padding: calc(env(safe-area-inset-top) + 48px) 16px 48px; }
.login h1 { font-size: 1.6rem; margin-bottom: 6px; }
.login h2 { font-size: 1.05rem; margin: 28px 0 4px; }
.first-time { border-top: 1px solid var(--line); margin-top: 24px; }
.code { text-transform: uppercase; letter-spacing: .12em; font-family: ui-monospace, "SF Mono", Menlo, monospace; text-align: center; font-size: 1.1rem; }
.login .error { margin-top: 14px; }

/* ---------- accounts: limits, the account page, messages ---------- */

/* An account's name anywhere: a tap opens its page. */
.acct-link { border: 0; background: none; padding: 0; font: inherit; color: var(--accent); cursor: pointer; text-align: left; text-decoration: underline; text-decoration-color: color-mix(in srgb, var(--accent) 35%, transparent); text-underline-offset: 3px; }
.acct-link.strong { font-weight: 700; }

.limits { margin-top: 2px; }
.usage.stale .fill { opacity: .4; }
.usage.stale .usage-num { color: var(--muted); }
.usage-updated { margin-top: 6px; }

/* The Accounts overview (COMMAND-74): one card per account in the Financiën list style — its head (e-mail, status and
   connector chips) a tap to its page, the PCs on it now and the bars. Old numbers are greyed with a short "verouderd".
   No pause per account (COMMAND-120): every PC's stop is the last row on the page for every PC (COMMAND-146,
   COMMAND-152: the bar on top of Devices opens it), in the one-row look below. */
.everybody-row { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 8px 12px; padding-top: 10px; padding-bottom: 10px; }
.everybody-row > .actions { margin-top: 0; }
.acct-open { border: 0; background: none; color: var(--text); font: inherit; padding: 0 0 6px; width: 100%; display: flex; justify-content: space-between; align-items: flex-start; gap: 10px; cursor: pointer; text-align: left; }
.acct-main { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.acct-name { font-size: 1.05rem; overflow-wrap: anywhere; }
.acct-chips { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
.chip.acct-status.working { background: var(--advice-soft); color: var(--advice); }
.chip.acct-status.no-work-dispatcher-agent { background: var(--surface-2); color: var(--muted); }
/* An account's connector (COMMAND-70, COMMAND-98): its own block under the PCs line, never in the head's row of chips
   (the amber pill there overlapped "Nu geen pc op dit account"). Connected: one tag. Not yet: its own address with
   Kopieer and one line where to add it. */
.acct-connector { margin: 8px 0 0; }
.acct-connector .tag.conn-state { margin: 0; }
/* The connector set of every account (COMMAND-363): a tick or a cross per connector, words and colour. */
.acct-cset { display: flex; flex-wrap: wrap; gap: 4px; margin: 8px 0 0; }
.tag.acct-cset-mark.connected { color: var(--advice); background: var(--advice-soft); }
.tag.acct-cset-mark.missing { color: var(--danger); background: var(--danger-soft); }
.acct-cset-list { list-style: none; padding: 0; margin: 0; display: grid; gap: 6px; }
.acct-cset-switches { display: grid; gap: 8px; }
.acct-cset-switch { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.acct-cset-switch .switch.busy { opacity: 0.6; pointer-events: none; }
.conn-add { padding: 8px 10px; border-radius: 10px; background: var(--warn-soft); }
.conn-add-title { display: block; font-size: 0.9rem; }
.conn-add-row { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-top: 6px; }
.conn-add-row .conn-url { flex: 1 1 220px; min-width: 0; margin: 0; padding: 6px 10px; font-size: 0.82rem; background: var(--surface); }
.acct-made .acct-head { padding: 0 0 6px; }
.conn-new-actions { justify-content: flex-start; margin-top: 8px; }
.acct-pcs { margin: 2px 0 0; }
.limits.stale .usage-label { color: var(--muted); }
.tag.stale-tag { margin-left: 0; font-weight: 700; }
/* An account's page: the PCs that came and went (COMMAND-73). */
.acct-moves { list-style: none; margin: 0; padding: 0; }
.acct-moves li { padding: 6px 0; border-top: 1px solid var(--line); }
.acct-moves li:first-child { border-top: 0; }
.acct-before { margin-top: 6px; }
.chev { color: var(--muted); font-size: 1.4rem; line-height: 1; }
.pill { display: inline-block; min-width: 18px; padding: 0 7px; border-radius: 9px; background: var(--danger); color: #fff; font-size: 0.72rem; font-weight: 700; line-height: 18px; text-align: center; }
.rare { display: flex; justify-content: flex-end; align-items: center; gap: 8px; margin-top: 8px; }

.acct-pc + .acct-pc { border-top: 1px solid var(--line); margin-top: 10px; padding-top: 10px; }
.section-title { font-size: 1rem; margin: 18px 2px 8px; }

.status { display: inline-block; padding: 1px 8px; border-radius: 8px; font-size: 0.75rem; font-weight: 650; white-space: nowrap; background: var(--surface-2); color: var(--muted); }
.status.waiting { background: var(--warn-soft); color: var(--warn); }
.status.picked-up { background: var(--accent-soft); color: var(--accent); }
.status.answered { background: var(--advice-soft); color: var(--advice); }

.reply { margin-top: 10px; padding: 10px 12px; border-radius: 12px; background: var(--surface-2); border-left: 3px solid var(--advice); }
.reply.interim { border-left-color: var(--line); }
/* The PO's own reply in a thread: indented, on the accent side. */
.reply.po { margin-left: 24px; background: var(--accent-soft); border-left: 3px solid var(--accent); }
/* A bubble's time, and the read ticks under the PO's own words, at its bottom right like WhatsApp (CHORE-241): a long
   message never needs a scroll up to see when it went out or whether it was picked up. */
.reply-stamp { display: flex; justify-content: flex-end; align-items: center; margin-top: 4px; }
/* The read receipt after the time of the PO's own words (COMMAND-1564): grey ticks, blue once read. */
.receipt { display: inline-flex; vertical-align: -2px; margin-left: 4px; color: var(--muted); }
.receipt svg { width: 15px; height: 15px; }
.receipt svg path { stroke-width: 2; }
.receipt-read { color: #34B7F1; }
/* Who sent a message as chips at the right end of its head (COMMAND-827, public/record-chips): its Claude account and its
   PC, a tap to their page, a hover (a long press on the phone) their Compact Layout. */
.reply-head.has-chips { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 8px; }
.reply-head-main { flex: 1 1 auto; min-width: 0; }
.reply-chips { display: inline-flex; flex-wrap: wrap; gap: 6px; margin-left: auto; }
.record-chip { display: inline-flex; align-items: center; gap: 4px; max-width: 100%; padding: 1px 8px; border-radius: 8px; background: var(--surface); color: var(--text); font-size: 0.75rem; font-weight: 700; text-decoration: none; white-space: nowrap; }
.record-chip svg { width: 13px; height: 13px; flex: none; }
.record-chip-name { overflow: hidden; text-overflow: ellipsis; }
a.record-chip { cursor: pointer; }
a.record-chip:hover { text-decoration: underline; }
a.record-chip:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.record-chip-compact {
  position: fixed; z-index: 60; width: min(320px, calc(100vw - 16px)); padding: 10px 12px;
  border: 1px solid var(--line); border-radius: 12px; background: var(--surface); color: var(--text); box-shadow: 0 6px 24px rgb(0 0 0 / 18%);
}
.record-chip-compact-head { display: flex; align-items: center; gap: 8px; }
.record-chip-compact-head svg { width: 18px; height: 18px; flex: none; }
.record-chip-compact-title { display: flex; flex-direction: column; min-width: 0; }
.record-chip-compact-title strong { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.record-chip-compact-body { margin-top: 8px; }
.record-chip-compact-body p { margin: 4px 0; }
/* The star of a conversation beside its Archiveren (COMMAND-244, COMMAND-578; COMMAND-1257: a favourite, public/favorites
   draws it and owns the rest of its look). */
/* Gesprekken (CHORE-233: the default index page again, a table row per conversation). Its first cell: a dot when an
   answer waits on the PO, the title on one line — bold then, like Gmail (COMMAND-236) — and under it only the last
   message ("Charlie: …", COMMAND-534) on one line, clipped with "…", or the typing dots while a session types there.
   A tap opens the conversation on its own page. */
.msg-cell { display: flex; align-items: flex-start; gap: 8px; min-width: 0; }
.msg-cell.unread { font-weight: 750; }
.msg-line-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.msg-line-head { display: flex; align-items: center; gap: 6px; min-width: 0; }
.msg-line-title { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 600; }
.msg-line-card { flex: none; }
.msg-line.unread .msg-line-title { font-weight: 750; }
.msg-line-last { display: block; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 400; }
/* A favourite row amber (COMMAND-1257), an escalated one red (COMMAND-553; after the favourite, so red wins), an archived
   one grey (a favourite keeps its amber) — escalated and archived in Setup's colours (COMMAND-1050), as the Threads rows. */
.lv-table tr.msg-line.archived, .lv-table tr.msg-line.archived:hover > td { background: color-mix(in srgb, var(--color-thread-archived, var(--muted)) 14%, var(--surface)); }
.lv-table tr.msg-line.archived > td:first-child { box-shadow: inset 4px 0 0 var(--color-thread-archived, var(--muted)); }
.lv-table tr.msg-line.favorite, .lv-table tr.msg-line.favorite:hover > td { background: var(--warn-soft); }
.lv-table tr.msg-line.favorite > td:first-child { box-shadow: inset 3px 0 0 var(--warn); }
.lv-table tr.msg-line.escalated, .lv-table tr.msg-line.escalated:hover > td { background: color-mix(in srgb, var(--color-thread-escalated, var(--danger)) 14%, var(--surface)); }
.lv-table tr.msg-line.escalated > td:first-child { box-shadow: inset 4px 0 0 var(--color-thread-escalated, var(--danger)); }
.msg-line.archived .msg-line-title { color: var(--muted); }
/* New's empty chat (COMMAND-979; the PO, 2026-10-14: "kan je het naar beneden volop trekken tot de onderkant van het
   scherm (met beetje margin ocourse, net als bovenin)"): as on a conversation's own page, the page is exactly as tall as
   the window under the top block and the chat fills it down to the bottom — the thread panel loses its fixed, draggable
   height, so its head and the reply box stay in place and only the messages scroll. A window too low for it lets the
   page scroll. */
.view:has(> .gs-new) {
  height: calc(100vh - var(--topbar-h, 52px));
  height: calc(100dvh - var(--topbar-h, 52px));
  min-height: 26rem;
  display: flex; flex-direction: column;
}
.view:has(> .gs-new) > * { flex: none; }
.view > .gs-new { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; margin-bottom: 0; padding: 12px; }
.gs-new > * { flex: none; }
.gs-new > .thread-panel[data-thread-new] { flex: 1 1 auto; height: auto; min-height: 0; resize: none; }
.gs-new > .thread-panel > .thread-history { flex: 1 1 auto; min-height: 4rem; }
.msg-dot { flex: none; align-self: flex-start; width: 9px; height: 9px; margin-top: 7px; border-radius: 50%; background: transparent; }
.msg-dot.on { background: var(--danger); }
.msg-line-typing .typing-dots { height: 1em; font-size: 1.2em; vertical-align: baseline; }
/* A conversation's state and tags in one row (the table's state column). */
.msg-page-state { display: inline-flex; flex-wrap: wrap; align-items: center; gap: 6px; }
.msg-page-state .tag { margin-left: 0; }
.reply-text { white-space: pre-wrap; margin: 4px 0 0; }
.tag.new { background: var(--danger-soft); color: var(--danger); font-weight: 700; }
/* Every thread the PO can answer (COMMAND-89): the opening message on top as it always read, a line under it, the
   buttons or the reply box, where it stands in one small line, then the replies as chat bubbles, newest first. */
.thread-divider { border: 0; border-top: 1px solid var(--line); margin: 12px 0 0; }
.thread-divider + .composer { padding-top: 0; border-top: 0; }
.thread-status { margin-top: 8px; color: var(--muted); }
.reply-foot { margin-top: 4px; }

/* ---------- Segment buttons (.seg-group, .seg) ---------- */

.seg-group { display: flex; flex-wrap: wrap; gap: 6px; }
/* A tab or segment button keeps its label, and the count beside it, on one line, never broken inside a word
   (COMMAND-159, as COMMAND-137 did for .btn): the body's overflow-wrap: anywhere broke a label that came out a
   fraction of a pixel wider than its button ("Goedkeuringe / n", "Vragen aan / mij" with its count under it). Its
   row wraps (.seg-group) or scrolls (Taken's, Nieuws's and Kosten's tabs on a phone, a board's lanes) as whole buttons. */
.seg { min-height: 38px; padding: 0 12px; border: 1.5px solid var(--line); border-radius: 10px; background: var(--surface); color: var(--text); font: inherit; font-size: 0.88rem; font-weight: 600; white-space: nowrap; overflow-wrap: normal; cursor: pointer; }
.seg.on { background: var(--accent); border-color: var(--accent); color: var(--accent-text); }
.seg:disabled { opacity: .45; }

/* ---------- Sub-tabs: Vragen's parts, and Vaults' (COMMAND-53) ---------- */

.sub-tabs { margin: 0 0 12px; }
.sub-tabs .seg { flex: 1 1 0; display: inline-flex; align-items: center; justify-content: center; gap: 6px; min-height: 42px; }
.seg-count { display: inline-block; min-width: 20px; padding: 0 6px; border-radius: 9px; background: var(--surface-2); color: var(--text); font-size: 0.75rem; line-height: 20px; }
.seg.on .seg-count { background: color-mix(in srgb, var(--accent-text) 25%, transparent); color: var(--accent-text); }

/* ---------- Projecten: one row per project (COMMAND-76), its own page (COMMAND-92) ---------- */

/* The list is the shared List view (COMMAND-394): the name, the status, the versions with their lights, who works on it,
   what needs attention. */
/* The bar on top of Devices for every PC (COMMAND-152): one row in this look — "Voor alle pc's" and the settings as
   chips — a tap to its page, as the row "Voor alle projecten" was on Projecten. */
.every-pc-bar { padding-top: 2px; padding-bottom: 2px; }
.project-row .fin-main { flex: 1 1 auto; gap: 4px; }
.project-envs { display: flex; flex-wrap: wrap; gap: 2px 14px; }
.project-env { display: inline-flex; align-items: center; gap: 6px; }
.project-env .dot { margin-top: 0; }
.project-chips { display: flex; flex-wrap: wrap; gap: 4px; }
.project-chips .tag { margin-left: 0; }
.tag.row-chip.is-warn { background: var(--warn-soft); color: var(--warn); font-weight: 700; }
.tag.row-chip.is-danger { background: var(--danger-soft); color: var(--danger); font-weight: 700; }
/* A number that is old (a PC's memory, COMMAND-135): greyed; its title says how old. */
.tag.row-chip.stale { opacity: .6; }
/* New projects (COMMAND-315): New in the list's search row (COMMAND-394, COMMAND-899), its form in a card under it, and each project's
   status as a tag. */
.project-new-form { padding: 4px 0; }
.project-new-form h2 { margin-bottom: 4px; }
.project-new-form .field .input { margin-top: 4px; width: 100%; }
.project-new-key { margin: 4px 0 0; min-height: 1em; }
/* New ERD on the Charts list (COMMAND-609): the same small form in a card under the search row (COMMAND-899). */
.chart-new-form h2 { margin-bottom: 4px; }
.chart-new-form .field .input { margin-top: 4px; width: 100%; }
.tag.project-status { margin-left: 0; }
.tag.project-status.is-warn { background: var(--warn-soft); color: var(--warn); font-weight: 700; }
.tag.project-status.is-danger { background: var(--danger-soft); color: var(--danger); font-weight: 700; }
/* A new project's setup (COMMAND-317): one line per step, its state as a small tag; a failed step's reason under it. */
.project-setup { list-style: none; margin: 0; padding: 0; display: grid; gap: 4px; }
.project-setup-step .tag { margin-left: 0; }
.project-setup-step.state-done .project-setup-name { color: var(--muted); }
.project-setup-step .tag.is-warn { background: var(--warn-soft); color: var(--warn); font-weight: 700; }
.project-setup-step .tag.is-danger { background: var(--danger-soft); color: var(--danger); font-weight: 700; }
.project-setup-why { font-size: 0.9em; color: var(--muted); margin-top: 2px; overflow-wrap: anywhere; }
.project-setup-step .tag.is-busy { background: var(--accent-soft); color: var(--accent); font-weight: 700; }
.project-setup-who { font-size: 0.9em; color: var(--muted); }
/* Its page (COMMAND-92): the project's settings and actions as its box had them, in its details card. */
.box-head { display: flex; justify-content: space-between; align-items: baseline; gap: 10px; }
.box-head h2 { margin-bottom: 4px; }
/* A PC that works on the project and is stopped (COMMAND-120): one line, a link to that PC. */
.project-box.is-stopped { border-color: color-mix(in srgb, var(--warn) 55%, var(--line)); }
.box-stopped { margin: 6px 0 2px; }
.box-stopped a { color: inherit; font-weight: 700; }
.set-row { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: center; gap: 8px 12px; padding: 10px 0; border-top: 1px solid var(--line); }
.box-head + .set-row, .card > h2 + .set-row { border-top: 0; }
.set-label { min-width: 0; flex: 1 1 160px; }
.set-control { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
/* Model and effort for every PC (COMMAND-312): a label and two selects per row, the rows as one small table that fills a
   phone and stays readable on a wide screen; Opslaan on the right under it. */
.run-settings-lines { flex: 1 1 100%; display: grid; grid-template-columns: max-content minmax(0, 1fr) minmax(0, 1fr); align-items: center; gap: 6px 8px; max-width: 560px; }
.run-setting-line { display: contents; }
.run-setting-label { font-size: 0.9rem; font-weight: 600; }
.run-settings-lines select.input { width: 100%; min-width: 0; margin: 0; padding: 4px 8px; }
.run-settings-row .set-control { margin-left: auto; }
.input.pct { width: 76px; margin: 0; padding: 6px 10px; text-align: right; font-variant-numeric: tabular-nums; }
.pct-sign { color: var(--muted); margin-left: -4px; }

/* A closed question's options in the Questions for me window (COMMAND-1118; the look of the old Eigen besluiten popup):
   the pick in the advice colour. */
.ap-options { margin: 0; padding-left: 18px; }
.ap-options li { margin: 4px 0; }
.ap-options li.picked { color: var(--advice); font-weight: 600; }

/* An on/off switch: a real checkbox under a drawn track. */
.switch { position: relative; display: inline-flex; align-items: center; gap: 8px; min-height: 38px; cursor: pointer; }
.switch input { position: absolute; inset: 0; width: 100%; height: 100%; margin: 0; opacity: 0; cursor: pointer; }
.switch-track { position: relative; width: 44px; height: 26px; border-radius: 13px; background: var(--line); transition: background .15s ease; flex: none; }
.switch-track::after { content: ''; position: absolute; top: 3px; left: 3px; width: 20px; height: 20px; border-radius: 50%; background: var(--surface); box-shadow: 0 1px 2px rgb(0 0 0 / 25%); transition: transform .15s ease; }
.switch.on .switch-track { background: var(--accent); }
.switch.on .switch-track::after { transform: translateX(18px); }
.switch.limit-switch.on .switch-track { background: var(--warn); }
.switch.own-switch.on .switch-track { background: var(--warn); }
.switch input:focus-visible + .switch-track { outline: 2px solid var(--accent); outline-offset: 2px; }
.switch-label { font-size: 0.88rem; font-weight: 600; }
/* In a box row the row says what the switch is: its own label is for screen readers only. */
.set-row .switch-label { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
.claimed { margin: 6px 0 0; }

/* ---------- Devices: one list, a row per PC (COMMAND-135); a PC's page ---------- */

/* The list is the shared List view (COMMAND-394): a PC's name — a tap to its page — when it was seen, its chips, its
   hardware in one line, its account card and its toggle, a row per PC (stacked on a phone). */
.device-row-name { display: inline-flex; flex-wrap: wrap; align-items: baseline; gap: 2px 10px; }
.lv-table td .acct-mini { margin: 0; }
.device-toggle { flex: none; }
.device-toggle .switch { min-height: 32px; }
.device-toggle.is-stopped .switch-label { color: var(--warn); }
/* Its page: the toggle on top beside its name; under it its settings (COMMAND-73, COMMAND-75: its one account on top;
   "Mag werken aan": a lookup, then a row per project). */
.record-actions .device-toggle { padding-top: 0; }
.device-current { margin: 2px 0 6px; }
/* Its account as a compact account card (COMMAND-103): the Accounts card in small — "Account: <e-mail>", its status
   and the bars with their countdowns, nothing to press in it; the whole card is a tap to the account's page. */
a.acct-mini { display: block; margin: 6px 0 8px; padding: 10px 12px; border: 1px solid var(--line); border-radius: 12px; background: var(--surface); color: var(--text); text-decoration: none; cursor: pointer; }
a.acct-mini:hover { border-color: color-mix(in srgb, var(--accent) 55%, var(--line)); }
a.acct-mini:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.acct-mini-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 10px; }
.acct-mini .acct-main { gap: 4px; }
.acct-mini .acct-name { font-size: 1rem; }
.acct-mini .usage { margin-top: 6px; }
.acct-mini .usage-updated { margin-top: 4px; }
/* Its memory (COMMAND-105): "RAM", the bar, "41 / 64 GB" on one compact row; the budget line at 90% on the bar (its
   place and the fill's width come from app.js, on the style object); calm, amber past 80%, red past 90%. An old number
   is greyed and says its age under the bar. */
.mem { display: grid; grid-template-columns: auto 1fr auto; align-items: center; gap: 8px; margin: 2px 0 6px; font-size: 0.86rem; }
.mem-label { color: var(--muted); font-weight: 600; }
.mem-num { font-weight: 600; font-variant-numeric: tabular-nums; white-space: nowrap; }
.mem-bar { position: relative; height: 8px; overflow: visible; }
.mem-fill.mem-ok { background: var(--accent); }
.mem-fill.mem-high { background: var(--warn); }
.mem-fill.mem-over { background: var(--danger); }
.mem-mark { position: absolute; top: -3px; bottom: -3px; width: 2px; margin-left: -1px; border-radius: 1px; background: var(--text); opacity: .55; }
.mem-age { grid-column: 2 / 4; margin-top: -4px; }
.mem.stale .fill { opacity: .4; }
.mem.stale .mem-num { color: var(--muted); }
/* A PC's hardware (COMMAND-111): its name on top of its box and one line under its memory, both links to its page. */
.box-head h2 a.device-name { color: inherit; text-decoration: none; }
.box-head h2 a.device-name:hover { text-decoration: underline; }
a.specs-line { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin: 0 0 8px; padding: 6px 10px; border: 1px solid var(--line); border-radius: 10px; background: var(--surface); color: var(--text); text-decoration: none; }
a.specs-line:hover { border-color: color-mix(in srgb, var(--accent) 55%, var(--line)); }
a.specs-line:focus-visible, .box-head h2 a.device-name:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.specs-text { min-width: 0; overflow-wrap: anywhere; font-variant-numeric: tabular-nums; }
a.specs-line .chev { flex: none; font-size: 1.1rem; }
/* The core release (COMMAND-117 step 5): one card on Devices (since COMMAND-652 the popup of its button in the search row), one
   line in each PC's box. */
.core-release-card .box-head { align-items: baseline; }
.core-release-n { font-variant-numeric: tabular-nums; }
.core-release-note { margin: 4px 0 2px; overflow-wrap: anywhere; }
.core-release-meta, .core-release-back { margin: 2px 0; }
.core-release-card .actions { margin-top: 8px; }
/* The Cloud row on Devices (COMMAND-636, public/cloud-runs): runs now, the last runs, the accounts — one line each.
   Since COMMAND-652 the popup of its button in Devices' search row: the first part starts at the top. */
.cloud-device h3 { margin: 12px 0 0; font-size: 0.95rem; }
.cloud-device h3:first-child { margin-top: 0; }
.cloud-device-list { list-style: none; margin: 6px 0 0; padding: 0; }
.cloud-device-list li { padding: 8px 0; border-top: 1px solid var(--line); overflow-wrap: anywhere; }
.cloud-device-run-head, .cloud-device-account-head { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
.cloud-device-account-head .switch { margin-left: auto; }
.chip.cloud-device-warn { background: var(--warn-soft); color: var(--warn); }
.core-line { margin: 0 0 8px; overflow-wrap: anywhere; font-variant-numeric: tabular-nums; }
.core-line .core-label { color: var(--muted, inherit); margin-right: 2px; }
/* The dry run of the named release (COMMAND-117 step 6): right under the core line, as one block with it. */
.core-line + .core-dry-line { margin-top: -6px; }
/* The full list on the PC's page: a label per part, its lines beside it (under it on a phone). */
.specs-list { display: grid; grid-template-columns: minmax(7rem, auto) 1fr; gap: 10px 16px; margin: 8px 0 0; }
.specs-row { display: contents; }
.specs-row dt { color: var(--muted); font-size: 0.86rem; }
.specs-row dd { margin: 0; min-width: 0; overflow-wrap: anywhere; }
.specs-main { font-weight: 600; font-variant-numeric: tabular-nums; }
.specs-sub { margin-top: 2px; font-variant-numeric: tabular-nums; }
.specs-read { margin: 14px 0 0; }
@media (max-width: 520px) {
  .specs-list { grid-template-columns: 1fr; gap: 2px; }
  .specs-row dd { margin-bottom: 10px; }
}
.allowed-title { font-size: 0.86rem; font-weight: 600; color: var(--muted); margin: 12px 0 0; }

/* A lookup with pills (public/pickers.js, COMMAND-75; any screen that picks projects may use it): one field, its
   options in a list under it, the chosen ones as pills in their project's colour (proj-c*), each with a ×. */
.picker { margin-top: 6px; }
.picker-field { position: relative; }
.picker-input { margin-top: 0; }
.picker-list {
  display: none; position: absolute; left: 0; right: 0; top: calc(100% + 4px); z-index: 10;
  margin: 0; padding: 4px; list-style: none;
  background: var(--surface); border: 1px solid var(--line); border-radius: 12px; box-shadow: 0 8px 24px rgb(0 0 0 / 16%);
  max-height: min(320px, 50vh); overflow-y: auto; overscroll-behavior: contain;
}
.picker-list.open { display: block; }
.picker-option { display: flex; align-items: center; gap: 10px; min-height: 42px; padding: 8px 10px; border-radius: 8px; cursor: pointer; }
.picker-option.active, .picker-option:hover { background: var(--accent-soft); }
.picker-option-label { min-width: 0; overflow-wrap: anywhere; }
.picker-swatch { flex: none; width: 10px; height: 10px; border-radius: 50%; background: var(--proj, var(--muted)); }
.picker-note { padding: 8px 10px; }
/* A section heading in a lookup's list (COMMAND-542: "This ERD", "Other ERDs"). */
.picker-section { padding: 8px 10px 2px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.04em; font-size: 0.72rem; }
.picker-empty { margin: 8px 0 0; }
.pill-list { display: flex; flex-wrap: wrap; gap: 6px; margin: 10px 0 0; padding: 0; list-style: none; }
.pick-pill {
  display: inline-flex; align-items: center; max-width: 100%; min-height: 34px;
  border: 1.5px solid transparent; border-radius: 999px; background: var(--proj-soft); color: var(--proj);
  font-size: 0.85rem; font-weight: 700;
}
.pick-pill .pill-name { display: inline-flex; align-items: center; gap: 6px; min-width: 0; padding: 4px 0 4px 12px; background: none; border: 0; color: inherit; font: inherit; }
.pick-pill button.pill-name { cursor: pointer; }
.pill-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pill-dot { flex: none; width: 9px; height: 9px; border-radius: 50%; background: var(--danger); }
.pill-x {
  flex: none; display: grid; place-items: center; width: 32px; height: 32px; margin-left: 2px; padding: 0;
  border: 0; border-radius: 50%; background: none; color: inherit; font: inherit; font-size: 1.15rem; line-height: 1; cursor: pointer;
}
.pill-x:hover, .pill-x:focus-visible { background: rgb(127 127 127 / 20%); }
/* Not checked out on this PC: drawn faded, a dashed edge. */
.pick-pill.pill-away { background: transparent; border-style: dashed; border-color: var(--proj); }
/* No ×: it cannot be taken away here (a project's vaults it always reads, COMMAND-100). */
.pick-pill.pill-locked .pill-name { padding-right: 12px; }
/* ONE value (pickers.js lookupOne, COMMAND-136): the field's own box with the chosen one as a pill inside it — the
   pill sits over the field — and its × opens the field again. An option may carry more beside its name. */
.picker-one-field { display: flex; align-items: center; min-height: 44px; padding: 4px 6px; border: 1.5px solid var(--line); border-radius: 12px; background: var(--surface); }
.picker-one-pill { background: var(--accent-soft); color: var(--accent); }
.picker-one .picker-swatch { display: none; }
.picker-one .picker-option { flex-wrap: wrap; row-gap: 4px; }
.picker-option-extra { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 10px; margin-left: auto; }
.mini-limits { display: inline-flex; flex-wrap: wrap; align-items: center; gap: 4px 10px; }
.mini-usage { display: inline-flex; align-items: center; gap: 4px; font-size: 0.78rem; color: var(--muted); }
.mini-bar { display: inline-block; width: 44px; height: 6px; }
.mini-usage-num { font-weight: 700; color: var(--text); font-variant-numeric: tabular-nums; }
.mini-limits.stale .fill { opacity: .4; }
.mini-limits.stale .mini-usage-num { color: var(--muted); }

.device-box { container-type: inline-size; }
/* A PC's Status (COMMAND-401): the PC itself — Uit (amber), Aan · aan het werk, Aan · niks te doen. Its toggle beside its
   name (COMMAND-135) is off only for the PO's Stop met alles; then its settings stand out. The two buttons are left for
   every PC at once (the page for every PC). */
.device-box.is-stopped { border-color: color-mix(in srgb, var(--warn) 55%, var(--line)); }
.device-status.is-working { color: var(--advice); }
.device-stop-actions { margin-top: 0; justify-content: flex-end; }
.allow-rows, .related-rows { margin: 10px 0 0; padding: 0; list-style: none; }
/* A PC's Work Dispatcher Agent as one field (COMMAND-503): "Work Dispatcher Agent: <state>". */
.floor-runs { margin: 10px 0 0; }
.floor-runs-label { margin-right: .35em; }
/* Each project on a PC is a card of its own (COMMAND-1448; the PO, 2026-10-16: "Projecten op een Device ziet er niet meer
   uit, kan je dit echt mooier maken zo een ProjectCard?"): its colour down the left side; the head is its on/off switch,
   its name and Verwijderen; under it every setting in a labelled cell — Bouwers, Analisten, Klussen and Bugs (each with
   its switch, COMMAND-1414), Custom Limit, Model en denkkracht — then what holds it back (COMMAND-344), only when there
   is something to say. One column on a phone; the limit and the model side by side once the list is wide enough. */
.related-rows-device-projects { container-type: inline-size; display: grid; gap: 10px; margin: 0; padding: 12px 14px 14px; }
.allow-row {
  display: grid; grid-template-columns: minmax(0, 1fr); align-items: stretch; gap: 8px; padding: 10px 12px;
  border: 1px solid var(--line); border-left: 4px solid var(--proj, var(--accent)); border-radius: 14px; background: var(--surface);
}
.allow-name, .allow-capacity, .allow-pickup, .allow-status { grid-column: 1 / -1; }
.allow-name { min-width: 0; display: flex; align-items: center; gap: 8px; }
/* The project on or off on this PC (COMMAND-387): its switch at the front of the head; an off card greyed, its numbers kept. */
.allow-name .project-on-switch { min-height: 32px; flex: none; }
.allow-name .project-on-switch .switch-label { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
.allow-row.is-off .pill-name, .allow-row.is-off .allow-capacity, .allow-row.is-off .allow-limit, .allow-row.is-off .allow-run { opacity: .45; }
.allow-row.is-off .allow-status { opacity: 1; }
.switch input:disabled { cursor: not-allowed; }
.allow-name .pill-name {
  display: inline-flex; align-items: center; gap: 6px; min-width: 0; max-width: 100%; min-height: 30px; padding: 2px 10px;
  border: 1.5px solid transparent; border-radius: 999px; background: var(--proj-soft); color: var(--proj);
  font: inherit; font-size: 0.9rem; font-weight: 700; overflow-wrap: anywhere;
}
.allow-name .allow-remove { margin-left: auto; flex: none; }
/* A cell: its word on the left, its switch and number on the right (Bouwers and Analisten: COMMAND-279). */
.allow-capacity { display: grid; grid-template-columns: minmax(0, 1fr); gap: 8px; }
.allow-capacity > .capacity-field, .capacity-switched, .allow-limit, .allow-run {
  display: flex; flex-wrap: wrap; align-items: center; gap: 6px 8px; min-width: 0; min-height: 44px; padding: 4px 6px 4px 10px;
  border-radius: 10px; background: var(--surface-2); font-size: 0.85rem;
}
.capacity-field { display: inline-flex; align-items: center; gap: 6px; font-size: 0.85rem; }
.allow-row .capacity-label, .allow-cell-label { margin-right: auto; font-weight: 600; }
.allow-capacity > .capacity-field, .capacity-switched, .allow-limit { flex-wrap: nowrap; }
.allow-row .capacity-field .capacity-input { width: 52px; }
.capacity-field .capacity-input { width: 64px; margin: 0; padding: 4px 8px; text-align: right; font-variant-numeric: tabular-nums; }
/* Klussen and Bugs (COMMAND-1414): the word, then the switch, then the number; the switch's long name only for a screen reader. */
.capacity-switched > .capacity-field { display: contents; }
.capacity-switched .capacity-label { order: -1; }
.capacity-switched .switch { min-height: 32px; }
.capacity-switched .switch-label { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
.allow-limit .switch { min-height: 32px; }
.allow-limit .switch-label { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
.allow-limit .input.pct { width: 60px; padding: 4px 8px; }
.allow-limit .input.pct:disabled { opacity: .55; }
/* Model and effort of the project on this PC (COMMAND-312): two compact selects in their cell. */
.allow-run select.input { width: auto; min-width: 0; margin: 0; padding: 4px 8px; font-size: 0.85rem; }
.allow-status { min-width: 0; padding-top: 8px; border-top: 1px dashed var(--line); }
/* Add and remove a project on a PC (COMMAND-738): the picker under the list's title, Verwijderen at the end of the head. */
.related-actions { padding: 10px 14px 0; }
.related-actions .device-project-add { width: auto; max-width: 100%; margin: 0; }
.allow-status-line { margin: 0; overflow-wrap: anywhere; }
@container (min-width: 600px) {
  .allow-row { grid-template-columns: minmax(0, 2fr) minmax(0, 3fr); }
}
/* The four numbers: one under the other on a phone, two by two, then all four on one line. */
@container (min-width: 440px) {
  .allow-capacity { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@container (min-width: 800px) {
  .allow-capacity { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}
.device-claims { margin: 0 0 4px; }
.claim-row .release-claim { white-space: nowrap; }
/* Versions and health per environment (COMMAND-11): a line per environment on the
   project's page, a light that always comes with a word. */
.dot.down { background: var(--danger); }
.env-line, .env-part { display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px 6px; margin-top: 4px; }
.env-line .dot, .env-part .dot { margin-top: 0; align-self: center; }
.env-part-list { list-style: none; margin: 4px 0 0; padding: 0; }
.btn.env-check { white-space: nowrap; }
/* A project's related lists with live rows (COMMAND-508): an environment's line and its fold under each other, a board's
   row with its Openen beside it; nothing to tap on the row itself. */
.related-rows > .related-row:first-child { border-top: 0; }
.related-row.env-row { display: block; cursor: default; }
.related-row.work-box-row { align-items: center; cursor: default; }
.inbox-box-row { display: inline-flex; flex-wrap: wrap; align-items: center; gap: 4px 8px; }
/* What a PC works on now (COMMAND-95): under a line, its account's pause and a line per work item it claimed (a
   related-list); a work item's line opens its card. */
.device-now { margin-top: 12px; padding-top: 10px; border-top: 1px solid var(--line); }
.device-now .device-now-title { margin: 0; }
.device-work-row .proj-pill { vertical-align: 1px; }
.device-work-meta { display: block; margin-top: 2px; }
.device-work-none { margin: 0; }

/* An environment's parts on Projecten: folded away, closed by default. */
.fold.earlier { margin: 6px 0 0; }
.fold.earlier summary { padding: 4px 2px; }

/* ---------- news (what the Work Dispatcher Agents told the PO in chat) ---------- */

/* Nieuws is the standard index page since COMMAND-655: ONE List view (a row per item), no Page Header (COMMAND-899). What it says
   stays three lines in the table; its page shows every word. Meer laden centred under the list, as Meldingen's. An account page keeps its card of the newest few (below). */
.lv-table td[data-field="text"] > .news-cell { display: -webkit-box; -webkit-line-clamp: 3; line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; white-space: normal; margin: 0; }
.news-cell.unread { font-weight: 600; }
.news-when { white-space: nowrap; }
.news-when .tag { margin-left: 4px; }
.news-detail .news-text { margin: 0; overflow-wrap: anywhere; }

.news-title { display: flex; align-items: center; gap: 8px; }
.news-list { list-style: none; margin: 0; padding: 0; }
.news-item { padding: 8px 0; border-top: 1px solid var(--line); }
.news-item:first-child { border-top: 0; padding-top: 2px; }
.news-item.unread .news-text { font-weight: 600; }
.news-head { display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px; }
.news-text { white-space: pre-wrap; margin: 3px 0 0; }
.kind { display: inline-block; padding: 0 7px; border-radius: 8px; font-size: 0.72rem; font-weight: 700; background: var(--surface-2); color: var(--muted); }
.kind.done { background: var(--advice-soft); color: var(--advice); }
.kind.instruction { background: var(--accent-soft); color: var(--accent); }
.news .link { margin-top: 4px; }
.news-head .proj-pill { margin-right: 4px; }

/* A project as a pill in its own colour (COMMAND-84): the same colour for a project wherever it
   shows — GROUPS.colorClass (groups.js) picks one of the twelve below from the project's id alone.
   Each sets --proj (the text) and --proj-soft (the background), again for the dark theme; proj-floor
   is for what is about no one project (the Work Dispatcher Agent's). Any screen may use these classes. */
.proj-pill { display: inline-block; padding: 0 8px; border-radius: 8px; background: var(--proj-soft); color: var(--proj); font-size: 0.75rem; font-weight: 700; white-space: nowrap; }
.proj-floor { --proj: var(--surface); --proj-soft: var(--muted); }
.proj-c0 { --proj: #b42318; --proj-soft: #fde8e6; }
.proj-c1 { --proj: #8a5a00; --proj-soft: #fdf0cf; }
.proj-c2 { --proj: #4b6b0a; --proj-soft: #eef5d8; }
.proj-c3 { --proj: #2451c7; --proj-soft: #e3ebfd; }
.proj-c4 { --proj: #b4480c; --proj-soft: #fdeadd; }
.proj-c5 { --proj: #19713f; --proj-soft: #dff3e7; }
.proj-c6 { --proj: #b3246b; --proj-soft: #fce4f0; }
.proj-c7 { --proj: #0b6d91; --proj-soft: #dcf1fa; }
.proj-c8 { --proj: #0d7065; --proj-soft: #d8f3ef; }
.proj-c9 { --proj: #4338ca; --proj-soft: #e7e5fc; }
.proj-c10 { --proj: #7e2fb5; --proj-soft: #f2e4fb; }
.proj-c11 { --proj: #7a4a26; --proj-soft: #f3e8de; }
@media (prefers-color-scheme: dark) {
  .proj-c0 { --proj: #ff9b91; --proj-soft: #42201d; }
  .proj-c1 { --proj: #f3c555; --proj-soft: #3a2e10; }
  .proj-c2 { --proj: #b8de6a; --proj-soft: #29331a; }
  .proj-c3 { --proj: #93b2ff; --proj-soft: #1d2a4d; }
  .proj-c4 { --proj: #ffad73; --proj-soft: #432a17; }
  .proj-c5 { --proj: #72d69c; --proj-soft: #173323; }
  .proj-c6 { --proj: #f59cc8; --proj-soft: #431c30; }
  .proj-c7 { --proj: #74cdef; --proj-soft: #14303d; }
  .proj-c8 { --proj: #63d6c7; --proj-soft: #123330; }
  .proj-c9 { --proj: #aaa4ff; --proj-soft: #26234f; }
  .proj-c10 { --proj: #d19df5; --proj-soft: #341f45; }
  .proj-c11 { --proj: #dcb08c; --proj-soft: #372a1f; }
}

/* A question part still in English (the Work Dispatcher Agent has not translated it yet). */
.tag.untranslated { background: var(--warn-soft); color: var(--warn); font-weight: 700; }
h3 .tag.untranslated { vertical-align: middle; }

/* The patch-note guard: games whose deploys have no note yet. */
.patch-behind { margin: 0 0 10px; padding: 6px 10px; border-radius: 10px; background: var(--danger-soft); color: var(--danger); font-size: 0.86rem; font-weight: 650; }

/* ---------- a question: its topic above it (the Questions for me window, COMMAND-1118) ---------- */

/* The topic above the question in the window: its card, project, conversation, asker and context. */
.q-topic { margin: 0 0 10px; }
.q-tags { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 6px; }
.q-tags .tag { margin-left: 0; }
/* An example question or approval (COMMAND-538): never taken for a real one. */
.tag.example-tag { background: var(--warn-soft); color: var(--warn); font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em; }
.prio { display: inline-block; padding: 1px 8px; border-radius: 8px; font-size: 0.75rem; font-weight: 700; }
.prio.child-safety { background: var(--danger); color: #fff; }
.prio.urgent { background: var(--warn-soft); color: var(--warn); }
/* Why it reached the PO although Eigen besluit may be on (COMMAND-172): Geld, Publiek, Live data, Jouw woord. */
.tag.po-only { margin-left: 0; font-weight: 700; background: var(--accent-soft); color: var(--accent); }
/* The explanation stands under the title, always open (COMMAND-342): body text, never a fold to click. */
.q-about { margin: 8px 0 0; }

/* A question that left the queue while the PO had it open: a popup over the
   screen (the next question is already drawn underneath). Phone first: a 16px
   gutter, scrolls inside itself when what the PO had typed is long. */
body.modal-open { overflow: hidden; }
.modal-backdrop {
  position: fixed; inset: 0;
  z-index: 20;
  display: grid; place-items: center;
  padding: calc(env(safe-area-inset-top) + 16px) 16px calc(env(safe-area-inset-bottom) + 16px);
  background: rgb(0 0 0 / 45%);
  animation: modal-in .15s ease-out;
}
.card.modal {
  margin: 0;
  text-align: center;
  box-shadow: 0 12px 40px rgb(0 0 0 / 25%);
}
.modal h2 { font-size: 1.15rem; margin: 0; }
.modal .modal-body > p { margin: 0 0 14px; }
.modal-mark { width: 48px; height: 48px; margin: 0 auto 10px; border-radius: 50%; display: grid; place-items: center; background: var(--warn-soft); color: var(--warn); font-size: 1.5rem; font-weight: 800; }
.vanished-q { text-align: left; margin: 0 0 12px; padding: 10px 12px; border-radius: 10px; background: var(--surface-2); }
.vanished-q p { margin: 2px 0 0; font-weight: 600; }
.kept { text-align: left; border-top: 1px solid var(--line); padding-top: 12px; }
.kept-intro { margin: 0 0 4px; color: var(--muted); }
.kept-h { font-size: 0.86rem; font-weight: 650; color: var(--muted); margin: 10px 0 6px; }
.kept-row { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin: 10px 0 6px; }
.kept-row .kept-h { margin: 0; }
.kept-picks { list-style: none; margin: 0; padding: 0; display: grid; gap: 6px; }
.kept-picks li { padding: 8px 12px; border: 1.5px solid var(--accent); border-radius: 10px; background: var(--accent-soft); }
.kept-note { margin: 0; padding: 8px 12px; border: 1px solid var(--line); border-radius: 10px; background: var(--surface); white-space: pre-wrap; max-height: 35vh; overflow-y: auto; }
.kept .thumbs { margin-top: 0; }
.modal .modal-foot .btn.big { margin-top: 0; }
@keyframes modal-in { from { opacity: 0; } to { opacity: 1; } }
@media (prefers-reduced-motion: reduce) { .modal-backdrop { animation: none; } }

/* The one popup shell (COMMAND-451, modal.js; PO, 2026-10-09: "We willen altijd de header en footer op een vaste
   locatie, en de content area krijgt een eigen scroll area als het heel veel content heeft"), like a Salesforce modal:
   the title bar and the button bar never move; only the middle scrolls, once the popup reaches about 85% of the screen.
   A short popup stays as small as its content. One steady width per size, never wider than the screen (a 16px gutter
   each side); the chat panel keeps its own width. Used by the chat panel, the question that left the queue, Opzeggen
   and the Bestand sheet. */
.modal-shell {
  display: flex; flex-direction: column;
  max-height: calc(85vh - env(safe-area-inset-top) - env(safe-area-inset-bottom));
  max-height: calc(85dvh - env(safe-area-inset-top) - env(safe-area-inset-bottom));
  overflow: hidden;
  padding: 0;
}
.modal-head { flex: none; padding: 16px 16px 10px; }
.modal-body { flex: 1 1 auto; min-height: 0; overflow-y: auto; overscroll-behavior: contain; padding: 2px 16px 12px; }
.modal-body:empty { display: none; }
.modal-foot { flex: none; padding: 12px 16px 16px; border-top: 1px solid var(--line); }
.modal-foot > .actions { margin-top: 0; }
/* The + menu of a message box in the foot opens above it (COMMAND-732): while it is open the shell lets it stick out,
   so a short popup (a title and the box) never cuts it off under its title. The body still scrolls
   on its own. */
.modal-shell:has(.composer-box .overlay-menu[data-open]) { overflow: visible; }
.modal-small { width: min(480px, 100vw - 32px); }
.modal-medium { width: min(640px, 100vw - 32px); }

/* A screenshot dragged over a text box: it lands as a photo. */
.input.dropping { border-color: var(--accent); background: var(--accent-soft); }

/* ---------- formatted text: steps, bullets, headings, copy chips ---------- */

.fmt { white-space: normal; }
.fmt > * { margin: 0 0 10px; }
.fmt > *:last-child { margin-bottom: 0; }
.fmt p { line-height: 1.5; }
.fmt-h { font-size: 1rem; margin: 14px 0 6px; }
.fmt-h:first-child { margin-top: 0; }
.todo-text.fmt, .context.fmt { margin: 10px 0; font-size: 1rem; }
.fmt-steps { list-style: none; margin: 0 0 10px; padding: 0; display: grid; gap: 12px; }
.fmt-steps li { display: grid; grid-template-columns: 28px 1fr; gap: 10px; align-items: start; }
.step-n {
  width: 28px; height: 28px; border-radius: 50%;
  display: grid; place-items: center;
  background: var(--accent); color: var(--accent-text);
  font-size: 0.85rem; font-weight: 800; font-variant-numeric: tabular-nums;
}
.step-body { padding-top: 3px; line-height: 1.5; min-width: 0; }
.fmt-list { margin: 0 0 10px; padding-left: 20px; display: grid; gap: 6px; }
/* A highlighted word or example in a todo, a question, a message (COMMAND-471; it was a code chip with a Kopieer button):
   the normal font, a little bolder, a faint accent background; it wraps like the words around it. */
.text-mark {
  font: inherit; font-weight: 600;
  padding: 0 4px; border-radius: 4px;
  background: var(--accent-soft);
  white-space: normal;
  -webkit-box-decoration-break: clone; box-decoration-break: clone;
}
/* A block to copy: its text as it is, the copy icon inside its top-right corner, visible without hovering (a phone has none). */
.copy-block {
  position: relative;
  margin: 6px 0 10px;
  border: 1px solid var(--line); border-radius: 10px;
  background: var(--surface-2);
}
.copy-block pre { margin: 0; padding: 10px 44px 10px 12px; overflow-x: auto; }
.copy-block code { font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace; font-size: 0.85rem; line-height: 1.5; white-space: pre; }
.copy-icon {
  position: absolute; top: 6px; right: 6px;
  width: 30px; height: 30px; padding: 0;
  display: grid; place-items: center;
  border: 0; border-radius: 6px;
  background: transparent; color: var(--muted);
  opacity: 1;
  cursor: pointer;
}
.copy-icon:hover, .copy-icon:focus-visible { background: var(--line); color: var(--text); }
.copy-icon.copied { color: var(--accent); }
.copy-icon svg { width: 18px; height: 18px; }
.copy-btn {
  flex: none;
  white-space: nowrap;
  min-height: 28px; padding: 0 10px;
  border: 0; border-radius: 6px;
  background: var(--accent); color: var(--accent-text);
  font: inherit; font-size: 0.78rem; font-weight: 700;
  cursor: pointer;
}
.lock-chip { display: inline-block; padding: 0 7px; border-radius: 8px; background: var(--warn-soft); color: var(--warn); font-size: 0.8rem; font-weight: 700; white-space: nowrap; }
.option .fmt.option-desc { color: var(--muted); font-size: 0.9rem; }
.option .fmt.option-desc > * { margin-bottom: 4px; }
.reply-text.fmt { margin: 4px 0 0; }

/* ---------- Taken: the shared List view (COMMAND-394; an index page like Accounts, no filter rows, COMMAND-643), the todo on its own page (COMMAND-92) ---------- */

/* Status (COMMAND-643): Open / Wacht op reactie / Afgehandeld, and under it where the task stands in its own words; a
   handled one quieter. Hoe dringend: the level's word in its colour (.urgency-now / -today / -whenever, below). */
.task-state { display: inline-flex; flex-direction: column; align-items: flex-start; gap: 2px; min-width: 0; }
.task-state-word { font-weight: 600; }
.task-state-closed .task-state-word { color: var(--muted); font-weight: 500; }
.task-urgency { font-weight: 600; white-space: nowrap; }
/* Taken (COMMAND-544): the PO's tasks and the agents' work in one List view; each row starts with whose it is (Jij, or the
   agent or PC). The Work Dispatcher Agents' work queue (COMMAND-88): a tap opens an item's page; escalated ones on top, red. */
.task-line { min-width: 0; display: flex; align-items: flex-start; gap: 8px; }
.task-line > .todo-line, .task-line > .agent-line-main { flex: 1; min-width: 0; }
.task-owner { flex: none; margin-left: 0; max-width: 9em; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.task-owner-po { background: var(--accent-soft); color: var(--accent); font-weight: 650; }
.agent-item.agent-escalated { border-color: var(--danger); box-shadow: inset 3px 0 0 var(--danger); }
.agent-item.agent-done, .agent-item.agent-dropped { opacity: 0.75; }
.agent-line-main { min-width: 0; display: inline-flex; flex-direction: column; gap: 2px; }
.agent-line-subject { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.agent-state-escalated { background: var(--danger-soft); color: var(--danger); font-weight: 700; }
.agent-state-held { background: var(--warn-soft); color: var(--warn); font-weight: 650; }
/* COMMAND-233: nobody who picks it up is live. */
/* The agents' tasks the PCs claim (COMMAND-452; built without a design: POC, the row's .poc-ui): rows of Taken's list. */
/* An agent task that failed 3 times (COMMAND-452): its last reason. */
.agent-task-reason { color: var(--danger); }
/* COMMAND-908: a Red tests task's runs under its line, one block per repository (POC, the row's .poc-ui). */
.red-tests-runs { display: flex; flex-direction: column; gap: 6px; margin-top: 4px; }
.red-tests-run { display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px 8px; padding-left: 8px; border-left: 2px solid var(--danger); }
.red-tests-end { color: var(--danger); font-weight: 650; }
.red-tests-test { flex-basis: 100%; overflow-wrap: anywhere; }
.agent-state.agent-state-stuck { background: var(--danger-soft); color: var(--danger); font-weight: 650; }
.agent-subject { margin: 6px 0; overflow-wrap: anywhere; }
.agent-actions .actions { flex-wrap: wrap; }
.agent-actions .btn.danger.on { outline: 2px solid var(--danger); }
/* A todo's (or a request's) line: its urgency icon, then its title and what it blocks. */
.todo-line {
  width: 100%; min-height: 44px;
  display: flex; align-items: baseline; gap: 10px;
  padding: 10px 4px;
  border: 0; border-radius: 8px;
  background: none; color: var(--text);
  font: inherit; text-align: left;
  cursor: pointer;
}
.todo-line:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
@media (hover: hover) { .todo-line:hover { background: var(--surface-2); } }
/* A todo's (or a request's) first cell in Taken's List view (COMMAND-394): its urgency icon, then its title and what
   it blocks — the row is the line, so no line box of its own. */
.list-view .todo-line { width: auto; min-height: 0; padding: 0; border-radius: 0; cursor: inherit; }
@media (hover: hover) { .list-view .todo-line:hover { background: none; } }
/* The title on one line: what does not fit ends in an ellipsis. */
.todo-line-title { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 600; }
/* The title, then under it what it blocks and where it is done. */
.todo-line-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.todo-line-main > .todo-line-title { flex: none; }

/* How urgent (COMMAND-72): an icon at the start of every line — a shape and a colour per level —
   what a todo that blocks work blocks under its title, and a filter row under the project tabs. */
.urgency-icon { flex: none; display: inline-flex; }
.urgency-icon svg { width: 20px; height: 20px; }
.urgency-now { color: var(--danger); }
.urgency-now svg path { stroke-width: 2.2; }
.urgency-today { color: var(--warn); }
.urgency-whenever { color: var(--muted); }
/* On the line the icon sits on the title's line, not on the baseline of the whole button. */
.todo-line > .urgency-icon { align-self: flex-start; margin-top: 1px; }
.todo-line-blocks { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--danger); font-weight: 600; }
.todo-line-meta { display: flex; align-items: center; gap: 6px; min-width: 0; }
.tag.urgency-unsorted { flex: none; padding: 0 6px; font-size: 0.72rem; }
.todo-urgency { margin: -4px 0 12px; }
.todo-urgency .seg { display: inline-flex; align-items: center; gap: 6px; }
.todo-urgency .urgency-icon svg { width: 18px; height: 18px; }
.todo-urgency .seg.on .urgency-icon { color: inherit; }
.todo-urgency-row { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin: 6px 0 2px; font-weight: 600; }
.todo-blocks { margin: 6px 0; padding: 8px 10px; border-radius: 10px; background: var(--danger-soft); color: var(--danger); font-weight: 600; }
/* A todo for one PC (COMMAND-136): the Device field on its page — the lookup, beside it (under it on a phone) the
   5-hour and week bars of the account that PC runs; the PC on the todo's line. */
.todo-device { margin: 8px 0 12px; }
.todo-device-label { color: var(--muted); font-weight: 600; }
.todo-device-label .req { color: var(--danger); }
.todo-device-row { display: flex; flex-wrap: wrap; align-items: flex-start; gap: 8px 20px; margin-top: 4px; }
.todo-device-pick { flex: 1 1 220px; min-width: 0; }
.todo-device-pick .picker { margin-top: 0; }
.todo-device-limits { flex: 1 1 240px; min-width: 0; }
.todo-device-limits .usage { margin-top: 4px; }
.todo-device-needed { margin: 6px 0 0; }
.todo-line-device { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* In the header of a todo's page (COMMAND-92): how urgent, on one line with its word. */
.record-field .todo-urgency-row { margin: 0; }
/* A request's level as a picker on its page (COMMAND-523, public/request-urgency). */
.request-urgency { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
.request-urgency .todo-urgency { margin: 0; }

/* Requests in Taken (COMMAND-133): a key or a camera beside the urgency icon on the line and on the page; the
   photos of a request in a grid, each with its caption; the delete-on row (Verwijderen na … dagen). */
.request-kind { flex: none; display: inline-flex; color: var(--muted); }
.request-kind svg { width: 18px; height: 18px; }
.todo-line > .request-kind { align-self: flex-start; margin-top: 2px; }
.request-kind-row { display: inline-flex; align-items: center; gap: 6px; }
.request-line-for { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.request-photo-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); gap: 10px; margin-top: 10px; }
.request-photo { position: relative; margin: 0; display: grid; gap: 6px; }
.request-photo img { width: 100%; aspect-ratio: 4 / 3; object-fit: cover; border-radius: 10px; border: 1px solid var(--line); background: var(--surface-2); display: block; }
.request-photo figcaption { overflow-wrap: anywhere; }
.request-photo .input.request-caption { min-height: 40px; margin: 0; }
.request-photo .thumb-x { top: 6px; right: 6px; }
.request-delete-after { margin-top: 12px; }
.request-delete-label { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
.request-delete-days { width: 5.5em; min-height: 36px; margin: 0; }
.request-delete-when { margin: 4px 0 0; }
/* A request for files (COMMAND-160): the files with a name under each, the ones on their way up with their progress. */
.request-files.dropping { outline: 2px dashed var(--accent); outline-offset: 2px; }
.request-files-count { margin: 10px 0 0; }
.request-file-list, .request-uploads { list-style: none; margin: 10px 0 0; padding: 0; display: grid; gap: 8px; }
.request-file { position: relative; display: flex; gap: 10px; align-items: flex-start; padding: 10px 40px 10px 10px; border: 1px solid var(--line); border-radius: 10px; background: var(--surface-2); }
.request-file-icon { flex: none; display: grid; place-items: center; width: 28px; height: 28px; color: var(--accent); }
.request-file-icon svg { width: 22px; height: 22px; }
.request-file-main { min-width: 0; flex: 1; display: grid; gap: 4px; }
.request-file-main .input.request-file-caption { min-height: 40px; margin: 0; }
.request-file-caption { overflow-wrap: anywhere; }
.request-file-meta { overflow-wrap: anywhere; }
.request-file .thumb-x { top: 8px; right: 8px; }
.request-upload { display: grid; gap: 6px; padding: 10px; border: 1px dashed var(--line); border-radius: 10px; }
.request-upload-failed { border-style: solid; border-color: var(--warn); background: var(--warn-soft); }
.request-upload-top, .request-upload-foot { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; justify-content: space-between; }
.request-upload-name { min-width: 0; overflow-wrap: anywhere; font-weight: 600; }
.request-upload-bar { width: 100%; height: 8px; accent-color: var(--accent); }
.request-upload-foot .btn { min-height: 36px; }
/* A file going up from any text box or the Docs editor (COMMAND-320): the same rows as a file request's. */
.box-uploads { margin: 8px 0; }
.box-uploads .request-uploads { margin-top: 0; }
.box-uploads-busy { margin: 6px 0 0; }

/* ---------- options: a checkbox for "one or more", a radio dot for "one" ---------- */

.pick-hint { margin: 2px 0 8px; font-size: 0.86rem; font-weight: 650; color: var(--muted); }
.option {
  grid-template-columns: 26px 1fr;
  column-gap: 12px; row-gap: 3px;
  align-items: start;
  min-height: 52px;
  padding: 12px 14px;
  background: var(--surface);
  border-color: var(--line);
}
.option > .option-label, .option > .option-desc { grid-column: 2; }
.opt-mark {
  grid-column: 1; grid-row: 1 / span 2;
  width: 24px; height: 24px; margin-top: 1px;
  display: grid; place-items: center;
  border: 2px solid var(--muted);
  background: var(--surface);
  transition: background .12s, border-color .12s;
}
.option.check .opt-mark { border-radius: 6px; }
.option.radio .opt-mark { border-radius: 50%; }
/* Not picked: plain, whatever it advises. Picked: unmistakable. */
.option.advised { border-color: var(--line); }
.option.picked { border-color: var(--accent); background: var(--accent-soft); box-shadow: inset 0 0 0 1px var(--accent); }
.option.check.picked .opt-mark { border-color: var(--accent); background: var(--accent); }
.option.check.picked .opt-mark::after { content: '✓'; color: var(--accent-text); font-size: 16px; font-weight: 900; line-height: 1; }
.option.radio.picked .opt-mark { border-color: var(--accent); }
.option.radio.picked .opt-mark::after { content: ''; width: 12px; height: 12px; border-radius: 50%; background: var(--accent); }

/* A clip per option (COMMAND-140): a round play button in the option's label line; the icon is drawn, never a glyph
   (an iPhone turns the play triangle into an emoji). Playing: two bars, in the accent colour. */
.clip-play {
  display: inline-flex; align-items: center; gap: 6px;
  min-width: 44px; min-height: 32px; padding: 4px 12px;
  border: 1px solid var(--line); border-radius: 999px;
  background: var(--surface-2); color: var(--text);
  font: inherit; font-size: 0.82rem; font-weight: 650; line-height: 1;
  cursor: pointer; -webkit-tap-highlight-color: transparent;
}
.clip-play:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.clip-play .clip-icon { width: 0; height: 0; border-style: solid; border-width: 6px 0 6px 10px; border-color: transparent transparent transparent currentColor; }
.clip-play.playing { border-color: var(--accent); color: var(--accent); background: var(--accent-soft); }
.clip-play.playing .clip-icon { width: 10px; height: 12px; border-width: 0 3px; border-color: currentColor; box-sizing: border-box; }
.clip-play .clip-time { font-variant-numeric: tabular-nums; color: inherit; }
.approval-clips { display: grid; gap: 6px; margin: 8px 0; }
.approval-clip { display: flex; align-items: center; gap: 10px; font-weight: 650; }

/* A command sent from the phone that a Work Dispatcher Agent has not carried out yet. */
.pending { color: var(--warn); font-weight: 650; }

/* ---------- credentials (the Credentials tab) ---------- */

.cred-target { margin-top: 4px; }
/* Why a key is needed (COMMAND-94): three short lines above a request's steps, or the amber line when missing. */
.cred-why { display: grid; gap: 6px; margin: 0 0 10px; padding: 10px 12px; border-radius: 10px; background: var(--surface-2); }
.cred-why-row { margin: 0; overflow-wrap: anywhere; }
.cred-why-label { display: block; font-size: 0.8rem; font-weight: 650; color: var(--muted); }
.warn.cred-why-missing { margin: 0 0 10px; }
.cred-field { display: flex; align-items: flex-start; gap: 8px; }
.cred-field .input { flex: 1; min-width: 0; }
.cred-eye { flex: none; width: 44px; height: 44px; margin-top: 10px; border-radius: 12px; color: var(--muted); }
.input.secret { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }
/* A multi-line value stays hidden until the eye is tapped (WebKit and Chromium). */
textarea.input.secret.masked { -webkit-text-security: disc; }
.cred-actions { align-items: center; justify-content: space-between; }
.cred-multi { display: inline-flex; align-items: center; gap: 6px; color: var(--muted); }
.cred-list { list-style: none; margin: 0; padding: 0; }
.cred-list li { padding: 8px 0; border-top: 1px solid var(--line); }
.cred-list li:first-child { border-top: 0; }
.cred-row { display: flex; justify-content: space-between; align-items: baseline; gap: 10px; }
.cred-ref { font-weight: 600; overflow-wrap: anywhere; }
.cred-left { flex: none; }
.cred-row .tag { flex: none; }
.tag.stored { background: var(--advice-soft); color: var(--advice); font-weight: 700; }
.tag.waiting { background: var(--warn-soft); color: var(--warn); font-weight: 700; }

/* ---------- vaults (COMMAND-4): a vault's keys on its own page (COMMAND-647: the list is the shared List view), the
   pills on a project's page on Projecten ---------- */

.vault-keys .vault-problem { margin: 0 0 10px; }
.vault-value { margin-top: 8px; white-space: pre-wrap; }
.vault-actions { justify-content: flex-start; margin-top: 8px; }
.vault-form { margin-top: 8px; }
.vault-add-names { display: flex; flex-wrap: wrap; gap: 8px; }
.vault-add-names .input { flex: 1 1 180px; min-width: 0; margin: 0; }
.vault-form-buttons { display: inline-flex; gap: 8px; }
.page-panel .vault-backup { margin: 0; }
/* A project's vaults on its page (COMMAND-100): the lookup with pills of Devices, beside the label on a wide screen,
   under it on a phone. */
.vault-picker { flex: 1 1 300px; max-width: 460px; min-width: 0; }
.vault-picker .picker { margin-top: 0; }

/* ---------- a new PC: the connector address (on top of Accounts, the only place; COMMAND-58) ---------- */

/* A value shown on screen (a vault key after Tonen): the look the new-PC key had. */
.newpc-key {
  min-height: 44px; padding: 11px 12px;
  border: 1px solid var(--line); border-radius: 10px;
  background: var(--surface-2);
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 0.9rem;
  overflow-wrap: anywhere; user-select: all;
}
.newpc-actions { justify-content: flex-start; margin-top: 10px; }

/* ---------- record pages (every detail page; after Salesforce record pages) ---------- */
/* Drawn in phone order: highlights, side panel (the messages), then the tab set.
   A wide screen gets two columns: the tabs left, the side panel right. */

.record-head { padding: 14px 16px; }
/* Every record page (COMMAND-92): a link back to the list it was opened from, on top of its header. */
.link.record-back { display: inline-flex; align-items: center; min-height: 32px; margin: -6px 0 6px; font-weight: 600; }
.record-missing .link.record-back { margin: 0; }
/* The rows that open a record page are links to its address: no underline, the row's own colour. */
a.fin-row { text-decoration: none; }
.record-title-row { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.record-icon { flex: none; width: 40px; height: 40px; border-radius: 10px; background: var(--accent); color: var(--accent-text); display: grid; place-items: center; }
.record-icon svg { width: 24px; height: 24px; }
.record-name { flex: 1; min-width: 0; }
.record-kicker { line-height: 1.2; }
.card h2.record-title { font-size: 1.2rem; margin: 0; overflow-wrap: anywhere; }
/* COMMAND-1468: a numbered record's title, under its number. */
.record-subtitle { margin-top: 2px; overflow-wrap: anywhere; }
.record-actions { display: flex; flex-wrap: wrap; gap: 8px; }
/* A record page's actions, Edit first (COMMAND-775): on a phone a line of their own under the title (the title keeps its
   width); from 600px right of it, as before (the min-width: 600px block below). An index page's header keeps its New
   beside the title. */
.record .record-head .record-title-row > .record-actions { flex-basis: 100%; }
.record-fields { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px 16px; margin: 14px 0 0; padding-top: 12px; border-top: 1px solid var(--line); }
.record-field dt { font-size: 0.78rem; color: var(--muted); }
.record-field dd { margin: 2px 0 0; font-weight: 650; overflow-wrap: anywhere; }
.level-text.mid { color: var(--warn); }
.level-text.high { color: var(--danger); }

.record-tabs { display: flex; flex-wrap: wrap; gap: 4px; margin: 4px 0 12px; border-bottom: 1px solid var(--line); }
.record-tab {
  border: 0; border-bottom: 3px solid transparent; margin-bottom: -1px;
  background: none; color: var(--muted);
  padding: 10px 14px; min-height: 44px;
  font: inherit; font-weight: 650;
  display: inline-flex; align-items: center; gap: 6px;
  /* One line, never broken inside a word, the count beside its label (COMMAND-159, like .seg). */
  white-space: nowrap; overflow-wrap: normal;
  cursor: pointer;
}
.record-tab.active { color: var(--accent); border-bottom-color: var(--accent); }

.record-dl { display: grid; grid-template-columns: max-content minmax(0, 1fr); gap: 6px 14px; margin: 0 0 4px; }
.record-dl dt { color: var(--muted); font-size: 0.86rem; }
.record-dl dd { margin: 0; overflow-wrap: anywhere; }
/* COMMAND-878, COMMAND-1344: the "Who works on it" box (public/record-handler) — one item per card: the kind of work with
   its icon beside a solid status badge (its colour setting, its ink black or white: public/colors), the card's key and
   title, the project chip, the repositories as tags, the PC, one time line. */
.handler-work { list-style: none; margin: 0; padding: 0; }
.handler-work > li { padding: 8px 0; }
.handler-work > li + li { border-top: 1px solid var(--line); }
.handler-item p { margin: 0 0 4px; overflow-wrap: anywhere; }
.handler-item-head { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.handler-kind { display: inline-flex; align-items: center; gap: 4px; font-size: 0.86rem; font-weight: 700; }
.handler-kind svg.lucide { width: 16px; height: 16px; flex: none; }
.handler-card-link { color: inherit; text-decoration: none; }
.handler-card-link:hover .handler-title { text-decoration: underline; }
.handler-meta { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
.handler-repo { display: inline-block; max-width: 100%; padding: 0 6px; border: 1px solid var(--line); border-radius: 6px; color: var(--muted); font-size: 0.72rem; line-height: 18px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.handler-where { color: var(--muted); font-size: 0.78rem; }
.pill.handler-status { padding: 0 8px; }
.handler-status-in_progress { background: var(--color-handler-in-progress, #eab308); color: var(--color-handler-in-progress-ink, #111827); }
.handler-status-waiting { background: var(--color-handler-waiting, #2563eb); color: var(--color-handler-waiting-ink, #ffffff); }
.handler-status-succeeded { background: var(--color-handler-succeeded, #16a34a); color: var(--color-handler-succeeded-ink, #111827); }
.handler-status-failed { background: var(--color-handler-failed, #dc2626); color: var(--color-handler-failed-ink, #ffffff); }
.handler-status-expired { background: var(--color-handler-expired, #8b929c); color: var(--color-handler-expired-ink, #111827); }
.handler-status-lapsed { background: var(--color-handler-expired, #8b929c); color: var(--color-handler-expired-ink, #111827); }
.mono { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }

.related-list { list-style: none; margin: 0; padding: 0; }
.related-row {
  width: 100%; min-height: 44px;
  display: flex; align-items: baseline; gap: 10px;
  padding: 10px 0; border: 0; border-top: 1px solid var(--line);
  background: none; color: var(--text); font: inherit; text-align: left;
  cursor: pointer;
}
.related-list li:first-child > .related-row { border-top: 0; }
.related-row .card-id { flex: none; color: var(--accent); }
.related-text { flex: 1; min-width: 0; }
.related-row .chev { flex: none; align-self: center; }

@media (min-width: 600px) {
  .record-fields { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  .record .record-head .record-title-row > .record-actions { flex-basis: auto; }
}

@media (min-width: 960px) {
  .record {
    display: grid;
    grid-template-columns: minmax(0, 1.7fr) minmax(340px, 1fr);
    grid-template-areas: "highlights highlights" "main side";
    column-gap: 16px;
    align-items: start;
  }
  .record-head { grid-area: highlights; }
  .record-main { grid-area: main; }
  .record-side { grid-area: side; }
  /* A page without a side panel (a card without its action panel open, COMMAND-7; a todo, a project, a work item,
     COMMAND-92): one column, no empty one beside it. */
  .record:not(:has(> .record-side)) { grid-template-columns: minmax(0, 1fr); grid-template-areas: "highlights" "main"; }
}

/* ---------- the one layout for every table (COMMAND-393, public/record-page) ---------- */
/* After Salesforce (PO, 2026-10-08): a Page Header on a record page (an index page and a
   View-all page have none since COMMAND-899: their views and actions sit in the search row); a List view (search,
   sort, a click opens the record) on an index page; on a record's Gerelateerd one related list per foreign key —
   its first 6 rows in a compact table and "Alles bekijken". Phone first: below 600px a table's rows stack (each cell
   with its column's name, nothing scrolls sideways) and the column names stay on top as a row of sort buttons. Every
   page keeps the one page box (COMMAND-43): a wide screen gives the List view the page's whole width. */
.page-crumbs ol { list-style: none; display: flex; flex-wrap: wrap; align-items: center; gap: 2px 6px; margin: -4px 0 8px; padding: 0; font-size: 0.86rem; }
.page-crumbs li { display: inline-flex; align-items: center; gap: 6px; min-width: 0; overflow-wrap: anywhere; }
.page-crumbs li + li::before { content: '›'; color: var(--muted); }
.page-crumb { color: var(--muted); }
a.page-crumb { color: var(--accent); font-weight: 600; text-decoration: none; }
.page-count { font-weight: 500; }
.page-notice { margin: 0 0 12px; }

/* clip, never hidden (COMMAND-485): hidden makes the box a scroll box of its own, and then its column names cannot stick
   under the index head. clip still keeps the rows inside the rounded corners. */
.list-view { padding: 0; overflow: clip; }
.lv-tools { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; padding: 12px 14px; border-bottom: 1px solid var(--line); }
.lv-search { flex: 1 1 220px; max-width: 420px; min-height: 40px; }
.lv-limited { flex: none; }
/* An index page's view tools (CHORE-235): on the right of the search row; on a phone they wrap under the search, still
   to the right. */
.lv-bar { display: flex; flex-wrap: wrap; align-items: center; justify-content: flex-end; gap: 8px; margin-left: auto; }
/* CHORE-235: the row above the search: the list view switcher on the left, the page's actions (New …) on the right. */
.lv-top { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; padding: 0 0 10px; }
.lv-top > .record-actions { margin-left: auto; }
.lv-note { flex: 1 1 auto; font-weight: 600; }
.lv-results > .lv-empty { margin: 14px; }
.lv-shown { margin: 0; padding: 8px 14px 12px; }
.lv-table { width: 100%; border-collapse: collapse; font-size: 0.92rem; }
.lv-table th { text-align: left; font-size: 0.8rem; font-weight: 650; color: var(--muted); padding: 8px 12px; border-bottom: 1px solid var(--line); white-space: nowrap; background: var(--surface-2); }
.lv-table td { padding: 10px 12px; border-bottom: 1px solid var(--line); vertical-align: top; overflow-wrap: anywhere; }
.lv-table tbody tr:last-child td { border-bottom: 0; }
.lv-table .lv-num { text-align: right; font-variant-numeric: tabular-nums; }
/* COMMAND-1223: a list's total row (Rollen: All roles). */
.lv-table tfoot td { border-top: 2px solid var(--line); border-bottom: 0; font-weight: 600; background: var(--surface-2); }
.lv-sort { border: 0; background: none; padding: 0; min-height: 28px; font: inherit; color: inherit; display: inline-flex; align-items: center; gap: 2px; cursor: pointer; white-space: nowrap; }
.lv-sort.on { color: var(--text); }
.lv-open { cursor: pointer; }
a.lv-link { color: var(--accent); font-weight: 650; text-decoration: none; }
a.lv-ref { color: var(--accent); text-decoration: none; }
/* A reference drawn as a card (COMMAND-1005): a role rule's rule, its name and its whole text. */
.ref-card { border: 1px solid var(--line); background: var(--surface-2); border-radius: 10px; padding: 10px 12px; max-width: 72ch; }
.ref-card-name { font-weight: 600; margin: 0 0 4px; }
.ref-card-text { margin: 0; white-space: pre-wrap; overflow-wrap: anywhere; line-height: 1.45; }
/* A text shown word for word in Details (COMMAND-1216: a block's refusal), its "for example" line above it. */
.record-pre { margin: 0; padding: 10px 12px; border-radius: 10px; background: var(--surface-2); white-space: pre-wrap; overflow-wrap: anywhere; font-size: 0.85em; line-height: 1.45; max-width: 100ch; }
.record-pre-example { margin: 0 0 4px; }
/* A Markdown field in Details (COMMAND-1654: a docs page's Description), formatted like its reading view; a wide table
   keeps its own sideways scroll (md-table-wrap). On a phone it spans the whole row under its label (the phone block). */
.record-md > :first-child { margin-top: 0; }
.record-md > :last-child { margin-bottom: 0; }
/* A role's page (COMMAND-1216): the marks on a rule the program blocks and on each block that stops the role. */
.role-rule-blocked-mark, .role-block-marks .pill { margin-left: 6px; }
.role-block-marks { margin: 4px 0 6px; }
@media (hover: hover) {
  .lv-open:hover td { background: var(--surface-2); }
  a.lv-link:hover, a.lv-ref:hover, a.page-crumb:hover { text-decoration: underline; }
}
/* The index head (COMMAND-485; PO, 2026-10-10: on a list page the title bar with the count and the add button, and the
   search, stay in place; only the list under them scrolls). An index page draws its crumbs, its own tools and the
   List view's search row (since COMMAND-899 with the views and actions on its right, no Page Header) in ONE head
   (record-page listView's pageHead) that sticks directly under the top bar (its real
   height: public/topbar-height, which also writes this head's height as --index-head-h). Opaque, so the rows slide under
   it; its own 12px on top (the page's padding pulled in) keeps a band of page between the top bar and the head. Above
   the rows, under the top bar and every popup. flow-root: a part's margin (a board's Page Header) stays inside the head.
   The boxes some pages show after the list come after it as before; the head stays while the PO scrolls on to them. */
.index-head {
  position: sticky;
  top: var(--topbar-h);
  z-index: 4;
  display: flow-root;
  margin-top: -12px;
  padding-top: 12px;
  background: var(--bg);
}
/* The search in the head and the rows under it read as one box: the search is its top, the list its bottom. */
.index-head > .lv-tools { background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius) var(--radius) 0 0; box-shadow: var(--shadow); }
.list-view.lv-joined { border-top: 0; border-top-left-radius: 0; border-top-right-radius: 0; }
/* The table's column names stick under the head (a wide screen and a tablet); they let go once the list has passed. A
   phone's stacked rows keep them in the flow, as a row of sort buttons above the rows (the layer at 599px). */
@media (min-width: 600px) {
  /* The line under them drawn inside: a collapsed table's own border stays behind while they stick. */
  .lv-index .lv-table th { position: sticky; top: calc(var(--topbar-h) + var(--index-head-h, 0px)); z-index: 1; box-shadow: inset 0 -1px 0 var(--line); }
}
/* COMMAND-1290 (PO, 2026-10-16: "alles een vaste breedte geven? afsnijden wat er uit de kolom valt met ..."; "een lijst
   met 5 kolommen is ieder 20%, een lijst van 2 is ieder 50%"): on a wide screen and a tablet a list's columns share its
   width equally (a column dragged wider or narrower keeps its own share, record-page's <col>), and a text that does not
   fit its column stays on one line and ends in "…" (the pointer resting on it shows it whole). The edge on the right of
   a column name is what the PO drags; a double click gives the column its equal share back. A phone keeps its stacked
   rows (the layer at 599px). */
@media (min-width: 600px) {
  .lv-table { table-layout: fixed; }
  .lv-table th, .lv-table td { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .lv-table td > *, .lv-table td :where(div, p) { max-width: 100%; overflow: hidden; text-overflow: ellipsis; }
  .lv-table th > .lv-sort { display: block; max-width: 100%; overflow: hidden; text-overflow: ellipsis; line-height: 28px; text-align: inherit; }
  .lv-table th { position: relative; }
  .lv-resize { position: absolute; top: 0; right: 0; bottom: 0; width: 9px; cursor: col-resize; touch-action: none; z-index: 1; }
  .lv-resize::after { content: ''; position: absolute; top: 25%; bottom: 25%; right: 3px; width: 2px; border-radius: 1px; background: var(--line); }
  .lv-resize:hover::after, .lv-resize:active::after { background: var(--accent); }
  .lv-resizing { cursor: col-resize; user-select: none; }
}
/* A long text (a description) stays a few lines in a list; its record page shows it whole. */
.lv-table td[data-field="description"] > * { display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; }

/* An open conversation on its own page, on a phone and a narrow window (COMMAND-562; PO, 2026-10-10: "only the messages
   content should be scrollable"; its own page since COMMAND-718): as on a wide screen (COMMAND-549, the layer at the
   end), the page is exactly as tall as the window under the top block and the conversation fills it — the thread panel
   loses its own fixed, draggable height, so its head on top and the reply box with its buttons at the bottom stay in
   place and only the messages between them scroll. The sub-tabs go: the conversation alone. The page keeps a little
   room at the bottom. A window too low for it lets the page scroll as before.
   The conversation stretches to the page, never to its content (COMMAND-479: several photos pushed Versturen off the
   right). COMMAND-717: the conversation is a record page (.record-message, at #message=<id> and at /threads/<uuid>);
   these rules hold while its tab Thread is open (data-tab="thread") — under the page header and the tab bar the tab's
   panel takes the rest and only the messages scroll; on Gerelateerd the page scrolls as every record page does. */
@media (max-width: 1099.98px) {
  .view:has(> .record-message[data-tab="thread"]) {
    height: calc(100vh - var(--topbar-h, 52px));
    height: calc(100dvh - var(--topbar-h, 52px));
    min-height: 26rem;
    display: flex; flex-direction: column;
  }
  .view:has(> .record-message[data-tab="thread"]) > * { flex: none; }
  .view.record-of-message > .sub-tabs { display: none; }
  .view > .record-message[data-tab="thread"] { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; align-items: stretch; }
  .record-message[data-tab="thread"] > * { flex: none; min-width: 0; }
  .record-message[data-tab="thread"] > .record-main { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; }
  .record-message[data-tab="thread"] > .record-main > * { flex: none; }
  .record-message[data-tab="thread"] > .record-main > .record-panel { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; }
  .record-message[data-tab="thread"] > .record-main > .record-panel > .msg-thread-card { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; margin-bottom: 0; }
  .record-message[data-tab="thread"] > .record-main > .record-panel > .msg-thread-card > * { flex: none; }
  .record-message[data-tab="thread"] > .record-main > .record-panel > .msg-thread-card > .thread-panel[data-thread] { flex: 1 1 auto; height: auto; min-height: 0; resize: none; }
  .record-message[data-tab="thread"] > .record-main > .record-panel > .msg-thread-card > .thread-panel > .thread-history { flex: 1 1 auto; min-height: 4rem; }
  /* COMMAND-804: with its side column (who works on it, its Threads box: the sub-threads) the conversation keeps the
     window's height and the side column follows under it — the page scrolls down to it, as every record page's does. */
  .view:has(> .record-message[data-tab="thread"]:has(> .record-side)) { height: auto; min-height: 0; }
  .record-message[data-tab="thread"]:has(> .record-side) > .record-main { flex: none; height: calc(100vh - var(--topbar-h, 52px) - 24px); height: calc(100dvh - var(--topbar-h, 52px) - 24px); min-height: 26rem; }
  .record-message[data-tab="thread"] > .record-side { order: 2; margin-top: 12px; }
}

/* A conversation's page header (COMMAND-717): its name on ONE line, cut off with "…"; its buttons (the thread's head
   parts, public/thread marks) on the right in one row. A phone puts them on a line of their own under the name. */
.record-message .card h2.record-title { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; overflow-wrap: normal; }
.record-message .record-actions { align-items: center; }
.record-message .record-actions > .thread-panel-marks { flex-wrap: wrap; justify-content: flex-end; }
@media (max-width: 599.98px) {
  .record-message .record-actions { flex: 1 1 100%; justify-content: flex-end; }
}
@media (min-width: 600px) {
  .record-message .record-title-row { flex-wrap: nowrap; }
  .record-message .record-actions { flex: none; flex-wrap: nowrap; }
  .record-message .record-actions > .thread-panel-marks { flex-wrap: nowrap; }
}

.related-card { padding: 0; overflow: hidden; }
.card h2.related-title { font-size: 1rem; margin: 0; padding: 12px 14px; border-bottom: 1px solid var(--line); }
.related-card > .related-empty { margin: 0; padding: 12px 14px; }
/* COMMAND-755: the New button of a related list, a View all page and a Threads box: on the right of the title row. A list only the
   system fills: the same button, greyed (aria-disabled — it still answers a tap with why). */
.related-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 8px 10px 8px 14px; border-bottom: 1px solid var(--line); }
.related-head h2.related-title { padding: 4px 0; border-bottom: 0; min-width: 0; }
.related-new { flex: none; min-height: 34px; }
.related-new[aria-disabled='true'] { opacity: 0.5; cursor: not-allowed; }
.thread-box-head .related-new { min-height: 34px; }
.lv-compact { font-size: 0.88rem; }
.lv-compact th { background: none; }
.lv-compact td { padding: 8px 12px; }
.related-foot { border-top: 1px solid var(--line); text-align: center; }
a.related-all { display: flex; align-items: center; justify-content: center; min-height: 44px; font-weight: 650; text-decoration: none; }
.record-system .record-dl dd { color: var(--muted); }
.acct-cell { display: inline-flex; flex-wrap: wrap; align-items: center; gap: 6px; }
/* A window's use in the AI Accounts list: a short bar and the percentage, its reset counting down under them. */
.usage-cell { display: inline-flex; flex-wrap: wrap; align-items: center; gap: 4px 6px; }
.usage-cell .usage-reset { flex-basis: 100%; margin: 0; }
.usage-cell.stale .fill { opacity: .4; }
.usage-cell.stale .usage-num { color: var(--muted); }
/* The accounts no PC reports yet, in their popup on AI Accounts (COMMAND-651): no room left under the last box. */
.page-panel .acct-waiting { margin: 0; }

@media (max-width: 599px) {
  .lv-table, .lv-table tbody, .lv-table tfoot, .lv-table tr, .lv-table td { display: block; }
  .lv-table thead { display: block; }
  .lv-table thead tr { display: flex; flex-wrap: wrap; gap: 0 14px; padding: 4px 12px; border-bottom: 1px solid var(--line); background: var(--surface-2); }
  .lv-table th { padding: 0; border: 0; background: none; }
  .lv-compact thead { display: none; }
  .lv-table tbody tr { padding: 10px 12px; border-bottom: 1px solid var(--line); }
  .lv-table tbody tr:last-child { border-bottom: 0; }
  .lv-table tfoot tr { padding: 10px 12px; border-top: 2px solid var(--line); background: var(--surface-2); }
  .lv-table tfoot td { border: 0; background: none; }
  .lv-table td { display: grid; grid-template-columns: minmax(84px, 38%) minmax(0, 1fr); gap: 10px; padding: 2px 0; border: 0; }
  .lv-table .lv-num { text-align: left; }
  .lv-table td::before { content: attr(data-label); color: var(--muted); font-size: 0.8rem; padding-top: 1px; }
  .lv-table td:first-child { display: block; padding-bottom: 4px; font-size: 0.98rem; }
  .lv-table td:first-child::before { content: none; }
  /* COMMAND-1290: no column widths and no edge to drag on a phone. */
  .lv-table colgroup, .lv-resize { display: none; }
  /* COMMAND-1654: a Markdown field in Details spans the whole row under its label. */
  .record-dl dd.record-md-field { grid-column: 1 / -1; }
}

/* The App Launcher (COMMAND-393): the nine dots at the left of the tab bar; a tap opens a dialog with a search over every
   table of the ERD. */
.tabs-bar { display: flex; align-items: stretch; margin: 0 auto; }
.tabs-bar > .tabs { flex: 1 1 auto; min-width: 0; margin: 0; padding-left: 0; }
.launcher-btn {
  flex: none; width: 44px; margin-left: calc(env(safe-area-inset-left) + 4px);
  border: 0; border-bottom: 3px solid transparent; background: none; color: var(--muted);
  display: grid; place-items: center; cursor: pointer;
}
.launcher-btn svg { width: 22px; height: 22px; }
.launcher-btn.on { color: var(--accent); }
@media (hover: hover) { .launcher-btn:hover { color: var(--accent); } }
/* Drawn by icon-button by its record (TP-596): the tab bar's look over icon-button's base for an icon-only button. */
.tabs-bar > .launcher-btn.icon-only:not(.btn) { display: grid; min-width: 44px; padding: 0; border-bottom: 3px solid transparent; border-radius: 0; color: var(--muted); }
.tabs-bar > .launcher-btn.icon-only.on:not(.btn) { color: var(--accent); }
@media (hover: hover) { .tabs-bar > .launcher-btn.icon-only:not(.btn):hover { color: var(--accent); } }
.launcher-btn.icon-only svg.lucide { width: 22px; height: 22px; }
/* The Instellingen person (COMMAND-818): the last thing in the tab bar, right after the Setup gear, and drawn like it
   (public/setup/index.css .setup-gear); it keeps the right edge clear, so the gear before it needs no margin there. */
.topbar-settings {
  flex: none; width: 44px; margin-right: calc(env(safe-area-inset-right) + 4px);
  border: 0; border-bottom: 3px solid transparent; background: none; color: var(--muted);
  display: grid; place-items: center; cursor: pointer;
}
.topbar-settings svg { width: 22px; height: 22px; }
.topbar-settings.on { color: var(--accent); border-bottom-color: var(--accent); }
@media (hover: hover) { .topbar-settings:hover { color: var(--accent); } }
.tabs-bar > .setup-gear:not(:last-child) { margin-right: 0; }
.launcher-backdrop { place-items: start center; padding-top: calc(env(safe-area-inset-top) + 16px); }
.launcher-panel { text-align: left; }
.launcher-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 10px; }
.launcher-search { width: 100%; min-height: 44px; }
.card .launcher-sub { margin: 4px 0 6px; font-size: 0.8rem; font-weight: 650; text-transform: uppercase; letter-spacing: 0.04em; }
.launcher-list { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: minmax(0, 1fr); }
a.launcher-item { display: flex; align-items: center; justify-content: space-between; gap: 10px; min-height: 44px; padding: 8px 10px; border-radius: 8px; color: var(--text); text-decoration: none; }
.launcher-name { min-width: 0; overflow-wrap: anywhere; font-weight: 600; }
.launcher-none { padding: 10px; }
@media (hover: hover) { a.launcher-item:hover { background: var(--surface-2); color: var(--accent); } }
a.launcher-item:focus-visible { background: var(--surface-2); }
@media (min-width: 600px) { .launcher-list { grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: 8px; } }
/* Apps like Salesforce (COMMAND-580): the App Launcher's Apps section above the tables, a tile per app with its icon. */
button.launcher-item.launcher-app { display: flex; align-items: center; gap: 10px; width: 100%; min-height: 44px; padding: 8px 10px; border: 0; border-radius: 8px; background: none; color: var(--text); font: inherit; text-align: left; text-decoration: none; cursor: pointer; }
.launcher-app .launcher-name { flex: 1 1 auto; }
.launcher-icon { display: inline-flex; flex: 0 0 auto; color: var(--accent); }
.launcher-icon svg { width: 20px; height: 20px; }
@media (hover: hover) { button.launcher-item.launcher-app:hover { background: var(--surface-2); color: var(--accent); } }
button.launcher-item.launcher-app:focus-visible { background: var(--surface-2); }
.launcher-apps + .launcher-sub { margin-top: 14px; }
/* What waits in an app (COMMAND-692): its tabs' counts added up on its tile, and a dot on the nine dots when something
   waits in another app than the open one. */
.badge.launcher-badge { position: static; flex: none; }
.launcher-btn { position: relative; }
.launcher-dot { position: absolute; top: 9px; right: 8px; width: 9px; height: 9px; border-radius: 50%; background: var(--danger); box-shadow: 0 0 0 2px var(--bg); }
/* The open app at the start of the tab bar (its icon and name; a tap opens the App Launcher), never scrolled away. */
.nav-app { flex: 0 1 auto; display: flex; align-items: center; gap: 6px; min-width: 0; max-width: 9.5em; padding: 0 10px 0 2px; border: 0; border-bottom: 3px solid transparent; background: none; color: var(--text); font: inherit; font-size: 0.8rem; font-weight: 650; line-height: 1.2; cursor: pointer; }
.nav-app-icon { display: inline-flex; flex: none; color: var(--accent); }
.nav-app-icon svg { width: 20px; height: 20px; }
.nav-app-name { min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
a.tab { text-decoration: none; }
/* An app's tabs (COMMAND-692: Mail has one tab, Meldingen two): each as wide as its name from the left on a phone too,
   never one tab stretched over the whole row next to the app's name. */
.tabs.app-tabs .tab { flex: 0 0 auto; min-width: 64px; padding-left: 10px; padding-right: 10px; }
/* A Lucide icon (public/icons): every element a 2px round stroke, no fill. */
svg.lucide :is(path, circle, rect, line, polyline, polygon, ellipse) { fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }

/* ---------- Goedkeuringen: approvals in Vragen (2026-09-29) ---------- */

/* Three parts in Vragen (and in Vaults): each as wide as its words, wrapping only on the smallest screens. */
.sub-tabs .seg { flex: 1 1 auto; padding: 0 10px; }
.approval-about > :first-child { margin-top: 0; }
.approval-about > :last-child { margin-bottom: 0; }
/* The work item's own name under its number (COMMAND-342). */
.card-title { margin: 2px 0 0; line-height: 1.35; }
.btn.on { border-color: var(--accent); background: var(--accent-soft); color: var(--accent); }
.btn.danger.on { border-color: var(--danger); background: var(--danger-soft); color: var(--danger); }
/* An approval's answer (COMMAND-828): Akkoord, Weigeren and Anders top right in its page's header; Akkoord answers at
   once (COMMAND-1185), Weigeren and Anders each open their popup — the question and the message box, its round send the
   one send (COMMAND-851: no Annuleren / Versturen). */
.approval-modal .modal-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.approval-modal .modal-head h2 { font-size: 1.15rem; margin: 0; }
.approval-dialog-q { margin: 0 0 12px; font-weight: 600; line-height: 1.4; }
.approval-pictures .gallery { margin-top: 0; }
/* An answered approval (COMMAND-169; in its Details since COMMAND-828): the answer as a chip (Akkoord green, Geweigerd
   red, Anders grey, Ingetrokken grey), the PO's words under it, then when and from where. */
.approval-answer { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin: 8px 0 4px; }
.answer-chip { display: inline-flex; align-items: center; min-height: 26px; padding: 2px 10px; border-radius: 999px; font-size: 0.86rem; font-weight: 700; background: var(--surface-2); color: var(--text); }
.answer-chip.yes { background: var(--advice-soft); color: var(--advice); }
.answer-chip.no { background: var(--danger-soft); color: var(--danger); }
.approval-done .approval-note { margin: 4px 0; }
.approval-done .answered-when { margin: 6px 0 2px; }
/* Goedkeuringen as one list (COMMAND-660): the state as a tag in its row (Open waits on the PO), Meer laden under the
   list while older answered ones wait on the server. */
.tag.approval-state { margin-left: 0; font-weight: 700; }
.tag.approval-state.open { background: var(--warn-soft); color: var(--warn); }
.tag.approval-state.yes { background: var(--advice-soft); color: var(--advice); }
.tag.approval-state.no { background: var(--danger-soft); color: var(--danger); }

/* ---------- Financiën: the full cost picture (COMMAND-10) ---------- */

.fin-total { font-size: 2rem; font-weight: 750; line-height: 1.15; margin: 2px 0; font-variant-numeric: tabular-nums; }
.fin-split { margin: 8px 0 0; font-weight: 600; font-variant-numeric: tabular-nums; }
.fin-refresh { margin: 8px 0 0; }
/* Totalen (COMMAND-662, a popup behind Kosten's button in its search row): the VAT switch under the totals card. */
.fin-vat { margin: 12px 0 0; }
/* A row of chips with how many each (COMMAND-394): Taken's. Kosten's kinds and Facturen's chips (Alle, Te controleren,
   Geen factuur) are columns of their lists since COMMAND-662 and COMMAND-663. */
.fin-kinds { margin: 0 0 12px; }
.fin-kinds .seg { display: inline-flex; align-items: center; gap: 6px; }
/* A line in the List view: when it is paid under one another (its renewal or its day, its next payment). */
.fin-when { display: inline-flex; flex-direction: column; gap: 2px; }
/* A line's next payment (COMMAND-81): a short line under its amount ("volgende betaling 12 okt"), on its page a
   whole one; not known is said too, with a pointer to the Startdatum field. */
.fin-details .fin-next-full { margin: 6px 0 0; }
.fin-next-full .fin-next-fill { padding: 0; font-size: inherit; text-align: left; }
.fin-lines { list-style: none; margin: 0; padding: 0; }
.fin-line + .fin-line { border-top: 1px solid var(--line); }
.fin-row {
  display: flex; justify-content: space-between; align-items: flex-start; gap: 10px;
  width: 100%; padding: 10px 0;
  border: 0; background: none; color: inherit; font: inherit; text-align: left; cursor: pointer;
}
.fin-main { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.fin-main strong { overflow-wrap: anywhere; }
.fin-badges .tag:first-child { margin-left: 0; }
.fin-amt { display: flex; flex-direction: column; align-items: flex-end; gap: 2px; text-align: right; white-space: nowrap; font-variant-numeric: tabular-nums; }
.tag.fin-check { background: var(--warn-soft); color: var(--warn); font-weight: 700; }
/* Inkomsten (COMMAND-424): a company's income next to its costs, this month and per month — since COMMAND-662 one card
   per company in the Inkomsten popup, a line between them. */
.fin-income h3 { margin: 0 0 4px; font-size: 1rem; }
.page-panel .modal-body > .fin-income + .fin-income { margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--line); }
.fin-income-row { display: flex; justify-content: space-between; gap: 12px; padding: 2px 0; }
.fin-income-row.net, .fin-income-row.result { font-weight: 700; }
.fin-income-amount { font-variant-numeric: tabular-nums; white-space: nowrap; }
.fin-income-months { width: 100%; border-collapse: collapse; font-variant-numeric: tabular-nums; }
.fin-income-months th, .fin-income-months td { padding: 3px 4px; text-align: right; }
.fin-income-months th:first-child, .fin-income-months td:first-child { text-align: left; }
/* A new line's form opens on the list; a cost line's is on its own
   page (COMMAND-92, below), and so is an invoice's (COMMAND-394). */
.fin-form { border-color: var(--accent); }
.fin-fields { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 0 10px; }
.fin-field { display: flex; flex-direction: column; margin-top: 8px; min-width: 0; }
.fin-field .input { margin-top: 4px; }
.fin-f-vendor, .fin-f-name, .fin-f-note { grid-column: 1 / -1; }
.fin-check-row { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.fin-end-row { align-items: center; }
.fin-end { display: flex; align-items: center; gap: 6px; margin-right: auto; }
.fin-end .input { margin-top: 0; width: auto; }
/* A cost's page (COMMAND-92): what it costs on top (its own amount beside it); its details card holds where it stands
   with a cancellation, its next payment in full and its form — no card in a card. */
.fin-pop-amt { display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px 10px; font-variant-numeric: tabular-nums; }
.record-field .fin-badges .tag { margin: 0 4px 2px 0; }
.fin-form.on-page { margin: 12px 0 0; padding: 12px 0 0; border-top: 1px solid var(--line); border-color: var(--line); }
.fin-cancel-state p { margin: 0; }
.fin-cancel-state .actions { justify-content: flex-start; margin-top: 8px; }
/* The Opzeggen question, in a small dialog over the list or the cost's page: the cost and what it costs, the day it
   stops (today, or the end of the paid period), who cancels it, the yes. */
.card.modal.fin-cancel-modal { text-align: left; }
.fin-cancel-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin: -8px -8px 4px 0; }
.fin-cancel-close { flex: none; }
.fin-cancel-modal h2 { overflow-wrap: anywhere; }
.fin-cancel-step .fin-pop-amt { margin-bottom: 12px; }
.fin-cancel-step h3 { margin: 0 0 4px; font-size: 1rem; }
.fin-cancel-day .input { width: auto; }
.fin-cancel-days { flex-wrap: wrap; margin-top: 8px; }
.fin-cancel-how { margin: 10px 0 0; }
/* COMMAND-180: what removing a Hetzner thing loses (the data on it; an address for good), a warning of its own; and the
   sites that point at an address — both wrap on a phone, however long a name or an address. */
.fin-cancel-lost { margin: 10px 0 0; overflow-wrap: anywhere; }
.fin-cancel-runs { margin: 6px 0 0; padding-left: 18px; }
.fin-cancel-runs li { overflow-wrap: anywhere; }
/* Opzeggen on a row: its own small button in its own column, beside the row's tap (never inside it). */
.lv-table td .fin-cancel { min-height: 32px; }
/* Exporteren per kwartaal (COMMAND-394): a quarter and company, how many and their sum, then the ZIP and the CSV. */
.inv-quarter { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 6px 12px; padding: 10px 0; }
.inv-quarter .inv-export { margin: 0; }
.tag.fin-cancelled { background: var(--surface-2); font-weight: 700; }

/* ---------- the Claude connector (COMMAND-8): the consent page, the box on Vaults ---------- */

.consent .card { margin-top: 16px; }
.consent-card p, .consent-may p { margin: 6px 0 0; }
.consent-who { font-size: 1.05rem; }
.consent-host { font-size: 1.15rem; color: var(--accent); }
.consent-list { margin: 6px 0 12px; padding-left: 20px; display: grid; gap: 6px; }
.consent-never { color: var(--muted); }
.consent-done { margin-top: 18px; color: var(--advice); font-weight: 600; }
/* Whose connection (COMMAND-156 step 9): the PO's own Claude, or an employee's. */
.consent-whose .consent-role { display: grid; gap: 2px; width: 100%; margin-top: 8px; padding: 10px 12px; text-align: left; font: inherit; color: var(--text); background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); cursor: pointer; }
.consent-whose .consent-role.on { border-color: var(--accent); background: var(--accent-soft); }
.consent-pick { margin: 12px 0 0; }

.conn-url {
  margin-top: 8px; padding: 10px 12px;
  border: 1px solid var(--line); border-radius: 10px; background: var(--surface-2);
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 0.88rem;
  overflow-wrap: anywhere; user-select: all;
}
.conn-row { border-top: 1px solid var(--line); margin-top: 10px; padding-top: 10px; }
.conn-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.conn-name { font-weight: 600; overflow-wrap: anywhere; }
.conn-row.ended .conn-name { color: var(--muted); text-decoration: line-through; }
.conn-calls { margin: 6px 0 0; padding: 0; list-style: none; display: grid; gap: 3px; }
.conn-call.failed { color: var(--danger); }
.conn-actions { justify-content: flex-start; margin-top: 8px; }
/* The connector on the Accounts tab (COMMAND-68): its switch as one small row on top, each connection in its
   account's box, the ones without an account in a box at the bottom. */
.card.conn-master-row { padding-top: 8px; padding-bottom: 8px; }
/* Whether an account is connected (COMMAND-70): a chip of its own on the account's card. */
.tag.conn-state { margin: 6px 0 0; font-weight: 650; }
.tag.conn-state.connected { background: var(--advice-soft); color: var(--advice); }
.tag.conn-state.not-connected { background: var(--warn-soft); color: var(--warn); }
.todo-recheck { margin-top: 6px; font-weight: 600; }
.conn-master-row .box-head { align-items: center; }
.conn-master-row > p.muted { margin: 4px 0 2px; }
.tag.via-claude { background: var(--accent-soft); color: var(--accent); font-weight: 700; }
.tag.fresh { background: var(--warn-soft); color: var(--warn); font-weight: 700; }

/* ---------- Meldingen: player reports and crashes (COMMAND-12) ---------- */

/* How each project's reading goes, in the popup behind the search row's Bronnen button (COMMAND-644), and how many cannot
   be read now on the button itself. */
.inbox-sources p { margin: 4px 0; }
.inbox-sources-failing { margin-left: 6px; }
/* The list is the shared List view (COMMAND-394): a report's title with its kind's icon (and a dot while it is new), a
   tap to its page. */
.inbox-icon { flex: none; display: inline-flex; margin-top: 1px; color: var(--muted); }
.inbox-icon svg { width: 20px; height: 20px; }
/* The kind (COMMAND-101): the icon at the start of the line and the word in its column. */
.type-idea { color: var(--type-idea); }
.type-bug { color: var(--type-bug); }
.type-feedback { color: var(--type-feedback); }
.type-map { color: var(--type-map); }
.type-crash { color: var(--type-crash); }
.type-alert { color: var(--type-alert); }
.type-tester-request { color: var(--type-tester-request); }
.type-other { color: var(--type-other); }
.inbox-type { font-weight: 600; }
.inbox-type-icon { flex: none; display: inline-flex; }
.inbox-type-icon svg { width: 18px; height: 18px; }
.inbox-title, .crash-title { display: inline-flex; align-items: baseline; gap: 7px; overflow-wrap: anywhere; }
.inbox-title.is-new { font-weight: 750; }
.inbox-dot { flex: none; width: 8px; height: 8px; border-radius: 50%; background: var(--accent); transform: translateY(-1px); }
.tag.env-live { background: var(--danger-soft); color: var(--danger); font-weight: 700; }
.tag.env-test { background: var(--accent-soft); color: var(--accent); }
.tag.picked { background: var(--advice-soft); color: var(--advice); font-weight: 700; }
.inbox-card { font-size: 0.85rem; white-space: nowrap; padding-top: 2px; }
.inbox-detail p { margin: 6px 0; }
.inbox-text { margin-top: 2px; overflow-wrap: anywhere; }
.inbox-actions { margin: 0; }
/* A tester request (COMMAND-869): Toelaten and Weigeren in its row while it is open, beside where it stands. */
.inbox-row-actions { display: inline-flex; flex-wrap: wrap; gap: 6px; margin: 4px 0 0 8px; vertical-align: middle; }
.inbox-row-actions .small-btn { min-height: 32px; }
.inbox-behaviour .tag { margin-left: 6px; }

/* ---------- Crashes (COMMAND-197): the Crashes page (/crash-issues, COMMAND-644/645) and a crash's page ---------- */

/* The status column of the Crashes list (COMMAND-645): a fixed crash in the advice colour, as on its own page. */
.crash-state.state-resolved { color: var(--advice); }
.crash-status.resolved { color: var(--advice); }
.crash-culprit { margin: 0 0 8px; font-weight: 600; overflow-wrap: anywhere; }
/* The stack: one line per frame, wrapped inside its card (never a page that scrolls sideways on a phone). */
.crash-frames { margin: 0; padding-left: 22px; font-size: 0.86rem; }
.crash-frame { margin: 3px 0; overflow-wrap: anywhere; }
.crash-frame code { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 0.84rem; overflow-wrap: anywhere; word-break: break-word; }
.crash-text { white-space: pre-wrap; overflow-wrap: anywhere; }
.crash-url { overflow-wrap: anywhere; }
.crash-grouping code { overflow-wrap: anywhere; }
.crash-event { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 6px; }
.crash-link { font-weight: 600; }

/* ---------- Integraties (COMMAND-166): the outside services, the key each uses, Hetzner's servers — Integraties and Servers
   (a page of its own since COMMAND-649), each the shared List view, an integration's page with its key and facts
   (COMMAND-394) ---------- */

.int-account-name { font-weight: 600; overflow-wrap: anywhere; }
.tag.int-state { margin-left: 0; font-weight: 700; }
.tag.int-ok { background: var(--advice-soft); color: var(--advice); }
.tag.int-bad { background: var(--danger-soft); color: var(--danger); }
.tag.int-warn { background: var(--warn-soft); color: var(--warn); }
.int-key-row { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 6px; margin: 6px 0; }
.int-key-name { font-weight: 600; overflow-wrap: anywhere; }
.int-key-row .int-link { margin-left: auto; }
.int-picker { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 10px; margin: 6px 0 8px; }
.int-picker .picker { flex: 1 1 260px; min-width: 0; }
.int-error { margin: 4px 0; overflow-wrap: anywhere; }
/* A server's name in the Servers list (and a project's related list): Beschermd and its conversation's mark beside it. */
.int-server-name { font-weight: 600; overflow-wrap: anywhere; }
.int-price { font-variant-numeric: tabular-nums; white-space: nowrap; }
.tag.int-protected { background: var(--accent-soft); color: var(--accent); font-weight: 700; }
.tag.int-server-state { margin-left: 0; background: var(--warn-soft); color: var(--warn); }
.int-total { margin: 8px 4px 4px; font-weight: 600; }
/* An integration's facts on its page (COMMAND-176): one line per fact (its box, its last backup, what still uses it). */
.int-checking { font-style: italic; }
.int-key-env { font-weight: 600; }
.int-fact { margin: 4px 0; overflow-wrap: anywhere; }
.int-box-link { font-weight: 600; color: var(--accent); text-decoration: none; }
.int-box-link:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 4px; }
@media (hover: hover) { .int-box-link:hover { text-decoration: underline; } }
.tag.int-backup-state { margin-left: 0; font-weight: 700; }
/* The Gmail card (COMMAND-178): who holds the daily task, a sentence in its tone; it wraps on a phone. */
.tag.int-daily-state { margin-left: 0; font-weight: 700; white-space: normal; max-width: 100%; }
/* A server's page. */
.int-role { margin: 6px 0 2px; font-weight: 600; }
.int-note { margin: 2px 0 6px; overflow-wrap: anywhere; }
.int-run-list { list-style: none; margin: 0 0 8px; padding: 0; }
.int-run { padding: 6px 0; overflow-wrap: anywhere; }
.int-run + .int-run { border-top: 1px solid var(--line); }
/* Open in Hetzner beside a server's name (COMMAND-195): a whole button that wraps under a long name on a phone, its
   label on one line. */
.int-open-hetzner { white-space: nowrap; }
/* What runs on a server (COMMAND-193): what stands out on top, the disks and memory as bars as wide as the card, then
   one group per project under each other on a phone (side by side on a wide screen, below). Long names wrap. */
.int-inv-source { margin: 2px 0 8px; }
.int-inv-advice { margin: 8px 0 12px; padding: 8px 12px; border-radius: 8px; background: var(--warn-soft); }
.int-inv-advice h3 { margin: 0 0 4px; font-size: 1em; }
.int-inv-advice-list { margin: 0; padding-left: 18px; }
.int-inv-advice-item { margin: 3px 0; overflow-wrap: anywhere; }
.int-inv-advice-item.int-bad { color: var(--danger); font-weight: 600; }
.int-inv-machine { display: grid; grid-template-columns: 1fr; gap: 8px 24px; margin: 8px 0 12px; }
.int-inv-disk, .int-inv-memory { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.int-inv-bar { display: block; height: 8px; border-radius: 4px; background: var(--surface-2); overflow: hidden; }
.int-inv-bar-fill { display: block; height: 100%; border-radius: 4px; background: var(--accent); }
.int-inv-bar-fill.int-ok { background: var(--ok, var(--accent)); }
.int-inv-bar-fill.int-warn { background: var(--warn); }
.int-inv-bar-fill.int-bad { background: var(--danger); }
/* What runs on a server: the related list server-inventory--server-id (COMMAND-509), one thing under the other. */
.related-rows-server-inventory { display: grid; grid-template-columns: 1fr; gap: 0 24px; }
.int-inv-project { overflow-wrap: anywhere; }
.int-inv-item { display: flex; flex-direction: column; gap: 2px; padding: 6px 0; min-width: 0; }
.int-inv-item + .int-inv-item { border-top: 1px solid var(--line); }
.int-inv-item-main { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 6px; }
.int-inv-name { overflow-wrap: anywhere; }
.tag.int-inv-kind { margin-left: 0; }
.tag.int-inv-untracked { margin-left: 0; background: var(--warn-soft); color: var(--warn); font-weight: 700; }
.int-inv-facts, .int-inv-origin { overflow-wrap: anywhere; }

/* ---------- Skills (COMMAND-143): every skill the PCs run, marked Hardcoded or Company made ---------- */

.skills-tools { margin: 0 0 10px; }
.skills-tools .input { width: 100%; }
/* A skill in the List view (COMMAND-394): its name, the first paragraph of its description (one line, an ellipsis when
   it does not fit), its marks. */
.skill-name { font-weight: 600; overflow-wrap: anywhere; }
.skill-desc { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* A skill's rules in order (COMMAND-1076). */
.skill-rule-list { margin: 0 0 8px; padding-left: 22px; }
.skill-rule { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; padding: 4px 0; }
.skill-rule-actions { margin-left: auto; display: inline-flex; gap: 4px; }
.skill-rule-add { max-width: 100%; }
/* In a list (Skills, Regels) the description wraps and stays a few lines, and a name breaks only between words: a
   description kept on one line took the whole width and squeezed the name column to one letter (COMMAND-1003). */
.lv-table .skill-desc { display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; white-space: normal; }
.lv-table .skill-name { overflow-wrap: break-word; }
.lv-table td:first-child { min-width: 10rem; }
.tag.skill-kind { flex: none; margin-left: 0; font-weight: 700; white-space: nowrap; }
.tag.skill-kind-hardcoded { background: var(--accent-soft); color: var(--accent); }
.tag.skill-kind-company { background: var(--advice-soft); color: var(--advice); }
.skills-note { margin: 10px 2px 0; }
/* Which core release and which PCs the list is of, in the popup behind its button in the search row (COMMAND-657). */
.skills-source { margin: 0; overflow-wrap: anywhere; }
/* A skill's page: its description as written, the PCs it is on. */
.skill-description { white-space: pre-wrap; overflow-wrap: anywhere; margin: 6px 0; }
.skill-pc { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 8px; padding: 6px 0; }
.skill-pc + .skill-pc { border-top: 1px solid var(--line); }
.tag.skill-other { margin-left: 0; background: var(--warn-soft); color: var(--warn); font-weight: 700; }
/* COMMAND-156: the marks beside the kind (switched off, may be switched off, changed lately), the company's switch, and
   a skill's changes with the old and the new lines side by side. */
.skill-line-tags { flex: none; display: flex; flex-direction: column; align-items: flex-end; gap: 4px; }
.tag.skill-mark { margin-left: 0; white-space: nowrap; }
.tag.skill-off { background: var(--warn-soft); color: var(--warn); font-weight: 700; }
.tag.skill-optional { background: var(--surface-2); color: var(--muted); }
.tag.skill-recent, .tag.skill-asked { background: var(--accent-soft); color: var(--accent); }
.tag.skill-current { background: var(--surface-2); color: var(--text); }
.tag.skill-undone { background: var(--warn-soft); color: var(--warn); }
/* TP-598: switched off but still on a PC (Niet meer in gebruik), and a folder the Command Center does not know (Onbekend). */
.tag.skill-unused { background: var(--warn-soft); color: var(--warn); }
.tag.skill-kind-unknown { background: var(--surface-2); color: var(--muted); }
.skill-change-list { list-style: none; margin: 0; padding: 0; }
.skill-change { padding: 10px 0; }
.skill-change + .skill-change { border-top: 1px solid var(--line); }
.skill-change-head { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 8px; }
.skill-change-why { margin: 6px 0 2px; overflow-wrap: anywhere; }
.skill-change-asked { margin: 0 0 6px; }
.skill-diff {
  display: flex; flex-direction: column;
  margin: 6px 0; border: 1px solid var(--line); border-radius: 8px; overflow: hidden;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 12px; line-height: 1.4;
}
.diff-row { display: grid; grid-template-columns: 1fr 1fr; }
.diff-row + .diff-row, .diff-gap { border-top: 1px solid var(--line); }
.diff-head { font-family: inherit; font-weight: 700; background: var(--surface-2); }
.diff-cell { display: flex; gap: 6px; min-width: 0; padding: 3px 6px; }
.diff-cell + .diff-cell { border-left: 1px solid var(--line); }
.diff-n { flex: none; min-width: 2.2em; text-align: right; color: var(--muted); user-select: none; }
.diff-text { flex: 1; min-width: 0; white-space: pre-wrap; overflow-wrap: anywhere; }
.diff-out { background: var(--warn-soft); }
.diff-in { background: var(--accent-soft); }
.diff-gap { padding: 3px 6px; text-align: center; background: var(--surface-2); }
/* COMMAND-171: the evaluation of a skill — its advice as a tag in the list and on the page, the box Evaluatie with the
   earlier ones folded away, and the thread under it (oldest first) with the reply box. */
.tag.skill-advice { margin-left: 0; white-space: nowrap; font-weight: 700; }
.tag.skill-advice-keep { background: var(--advice-soft); color: var(--advice); }
.tag.skill-advice-remove { background: var(--danger-soft); color: var(--danger); }
.tag.skill-advice-archived { background: var(--surface-2); color: var(--muted); }
.skill-eval-fields dd { overflow-wrap: anywhere; }
.skill-eval-fields p { margin: 0; }
.skill-eval-advice { display: flex; flex-direction: column; align-items: flex-start; gap: 4px; }
.skill-eval-why, .skill-eval-used-for { white-space: pre-wrap; overflow-wrap: anywhere; }
.skill-eval-outcome { margin: 8px 0 0; font-weight: 650; }
.skill-eval-outcome-archived { color: var(--muted); }
.skill-eval-outcome-kept { color: var(--advice); }
/* A skill's evaluations as the rows of its related list Evaluaties (COMMAND-510): the newest first, an earlier one marked. */
.skill-eval-row { padding: 10px 0; }
.skill-eval-row + .skill-eval-row { border-top: 1px solid var(--line); }
.skill-eval-row.is-earlier { color: var(--muted); }
.tag.skill-eval-earlier-tag { margin: 0 0 6px; background: var(--surface-2); color: var(--muted); }
/* One Threads box everywhere (COMMAND-395; COMMAND-806: the Threads window's component, public/thread-window box): a
   record's page (the right column on a wide screen, under the title on a phone), a docs page, a cost, a work card. On
   top its title, Open / Archived and New; under it the list of the record's threads (an unread dot, the name, the last
   message, how long ago), only the list scrolls. A tapped thread's chat (with a back arrow) or New's empty chat takes
   the list's place. COMMAND-501 (the PO, 2026-10-10: "Header & Footer(Chat Input) moeten allebij vaste lengte hebben en
   altijd zichtbaar … nieuwste onderaan"): a thread is a chat panel like a Salesforce modal — the header on top, the
   messages oldest first in the middle, the reply box at the bottom. Header and reply box keep their height and stay in
   view; the panel can be dragged taller, and only the messages area grows and scrolls. */
.thread-box { container-type: inline-size; }
.thread-box-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-bottom: 8px; }
.thread-box-head h2 { margin: 0; font-size: 1rem; }
.thread-box-head.tw-head { align-items: flex-start; margin-bottom: 10px; }
.thread-new { min-height: 40px; }
/* The box's list scrolls on its own, as the window's does; a tall page never grows a long box. */
.thread-box .tw-body { max-height: min(28rem, 60vh); max-height: min(28rem, 60dvh); }
.thread-panel {
  display: flex; flex-direction: column;
  height: min(40rem, 70vh);
  height: min(40rem, 70dvh);
  min-height: min(20rem, 70dvh);
  resize: vertical; overflow: hidden;
}
/* Still loading, gone or failed: a line of text, no chat panel yet. */
.thread-panel:not([data-thread]) { height: auto; min-height: 0; resize: none; }
.thread-panel > *, .thread-panel > .thread-panel-head, .thread-panel > .thread-reply { flex: none; }
/* COMMAND-578: the head is ONE line — the title left (cut off with "…"), the icons right; nothing wraps under it. */
.thread-panel-head { display: flex; flex-wrap: nowrap; align-items: center; justify-content: space-between; gap: 8px; min-width: 0; }
.thread-subject { flex: 1 1 0; min-width: 0; margin: 0; font-size: 0.98rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* COMMAND-1046: the marks may shrink, but only the record pill gives way — the icon buttons never leave the head. */
.thread-panel-marks { flex: 0 1 auto; min-width: 0; display: flex; flex-wrap: nowrap; align-items: center; gap: 4px; }
.thread-panel-marks > * { flex: none; }
/* COMMAND-861: the record a thread hangs on, as its record pill — cut off with "…" so the head stays one line. */
.thread-panel-marks .thread-record { flex: 0 1 auto; min-width: 2.5rem; max-width: min(16rem, 40vw); display: inline-flex; }
.thread-panel-marks .thread-record .record-pill { overflow: hidden; text-overflow: ellipsis; max-width: 100%; line-height: 1.6; }
/* COMMAND-1065: a thread's card link gives way the same, and icons that still do not fit scroll inside the head (no
   scrollbar) — Archiveren, the last one, stays pinned at the right end, so it is never cut off past the edge of a narrow
   head (the Threads window). The title (flex-basis 0) gives way before any of them. */
.thread-panel-marks .card-id { flex: 0 1 auto; min-width: 2.5rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* COMMAND-1134, COMMAND-1136: every button of the head sits in one vertical "⋮" menu, so only the card link and "⋮" share the line;
   COMMAND-1631: the menu is icon-button's overlay menu (a toggle that grows from the button's corner; its panel's shape is
   in icon-button/index.css), each action a row with its icon and its own label (aria-label). */
.thread-panel-marks .thread-more > .thread-more-btn { display: inline-flex; align-items: center; justify-content: center; cursor: pointer; border-radius: 999px; }
.thread-panel-marks .thread-more[data-open] > .thread-more-btn { color: var(--text); }
/* COMMAND-1140: a row is a flex line — the icon left, its name right of it (the .icon-btn grid stacked them on top of each other). */
.thread-panel-marks .thread-more-menu .icon-btn { display: flex; flex-direction: row; place-items: initial; align-items: center; width: 100%; height: auto; min-height: 40px; justify-content: flex-start; gap: 12px; padding: 0 12px; border-radius: 6px; font: inherit; text-align: left; white-space: nowrap; }
.thread-panel-marks .thread-more-menu .icon-btn::after { content: attr(aria-label); color: var(--text); }
.thread-panel-marks .thread-more-menu .icon-btn:hover { background: var(--line); }
/* COMMAND-1136: every button of the head is a row here, the open-questions button (a text button) too; dots bolder. */
.thread-panel-marks .thread-more-menu > :not(.icon-btn) { display: flex; align-items: center; width: 100%; min-height: 40px; justify-content: flex-start; text-align: left; padding: 0 10px; border: 0; border-radius: 6px; background: none; color: var(--text); font: inherit; }
.thread-panel-marks .thread-more-menu > :not(.icon-btn):hover { background: var(--line); }
.thread-panel-marks .thread-more-btn svg path { stroke-width: 3.2; }
/* COMMAND-1350: the same ⋮ menu in a chore's details head (public/thread-window). */
.tw-card-head .thread-more > .thread-more-btn { display: inline-flex; align-items: center; justify-content: center; cursor: pointer; border-radius: 999px; }
.tw-card-head .thread-more[data-open] > .thread-more-btn { color: var(--text); }
.tw-card-head .thread-more-menu .icon-btn { display: flex; flex-direction: row; place-items: initial; align-items: center; width: 100%; height: auto; min-height: 40px; justify-content: flex-start; gap: 12px; padding: 0 12px; border-radius: 6px; font: inherit; text-align: left; white-space: nowrap; }
.tw-card-head .thread-more-menu .icon-btn::after { content: attr(aria-label); color: var(--text); }
.tw-card-head .thread-more-menu .icon-btn:hover { background: var(--line); }
.tw-card-head .thread-more-menu > :not(.icon-btn) { display: flex; align-items: center; width: 100%; min-height: 40px; justify-content: flex-start; text-align: left; padding: 0 10px; border: 0; border-radius: 6px; background: none; color: var(--text); font: inherit; }
.tw-card-head .thread-more-menu > :not(.icon-btn):hover { background: var(--line); }
.tw-card-head .thread-more-btn svg path { stroke-width: 3.2; }
/* Its icon buttons: a 44px tap, a quiet circle until hovered; a favourite is a filled amber star. */
.thread-panel-marks .icon-btn { width: 44px; height: 44px; background: transparent; color: var(--muted); }
.thread-panel-marks .icon-btn:hover { background: var(--surface-2); color: var(--text); }
.thread-panel-marks .icon-btn svg { width: 20px; height: 20px; flex: none; }
.thread-panel-marks .fav-star.on { color: var(--warn); }
/* COMMAND-816: the escalation toggle — a grey triangle, red while the conversation is escalated. */
.thread-panel-marks .thread-escalate.on, .thread-panel-marks .thread-escalate.on:hover { color: var(--danger); }
.thread-panel-marks .thread-escalate:disabled { opacity: 1; cursor: default; }
.thread-archive { min-height: 44px; }
/* COMMAND-445: a line of the Command Center itself ("🤖 Roxy has left the chat"): centred and grey, no bubble. */
.thread-panel .thread-system { text-align: center; color: var(--muted); margin: 10px 0; }
/* IDEA-5669: under the newest questions line, its open questions and approvals as their tags (chip, unfolding to the card). */
.thread-panel .thread-q-cards { display: flex; flex-direction: column; gap: 6px; margin: 0 0 10px; text-align: left; }
.thread-reply { margin-top: 10px; }
.thread-reply textarea { width: 100%; }
/* The reply box's size is the message box's own (.composer-pill > textarea.input.grow, COMMAND-664, COMMAND-672). */
.thread-panel > .thread-reply { padding-bottom: 12px; }
/* COMMAND-1050 (the PO, 2026-10-15): an archived thread a border of its own colour and a layer over the reply box
   ("Thread is archived"; a tap lifts it). COMMAND-1165 (the PO, 2026-10-15: "weg met de border... ik zeg de hele component
   achtergrond rood. de message & input box blijven gewoon zoals ze zijn"): an escalated thread has no border, the whole
   panel's background is red; the messages and the reply box keep their own. The colours are Setup's colour settings
   (public/colors: --color-thread-escalated, --color-thread-archived), the theme's beside them. */
.thread-panel.thread-escalated, .thread-panel.thread-closed { border-radius: 12px; padding: 8px 10px 0; }
.thread-panel.thread-closed { border: 2px solid; }
.thread-panel.thread-escalated { background: color-mix(in srgb, var(--color-thread-escalated, var(--danger)) 35%, var(--surface)); }
/* COMMAND-1201 (the PO, 2026-10-15: "alleen de achterground van de component rood.... NIET DE CHAT"): the message list keeps
   the theme's own background; only the panel around it is red. */
.thread-panel.thread-escalated > .thread-history { background: var(--surface); }
.thread-panel.thread-closed { border-color: var(--color-thread-archived, var(--muted)); }
.thread-reply.thread-reply-covered { position: relative; }
.thread-archived-cover {
  position: absolute; inset: 0 0 12px; z-index: 2;
  display: flex; align-items: center; justify-content: center;
  border: 0; border-radius: 12px; cursor: pointer;
  background: color-mix(in srgb, var(--color-thread-archived, var(--muted)) 88%, transparent);
  color: #fff; font-weight: 700; font-size: 0.95rem;
}
.thread-window > .thread-panel > .thread-reply > .thread-archived-cover { bottom: 0; }
.thread-reply .actions { justify-content: flex-end; }
/* COMMAND-223, reopened: under a conversation's reply box, with an accent bar like the chat panel's line, the way to a new
   conversation for a new question typed there. */
.reply-elsewhere { margin: 8px 0 0; padding: 2px 0 2px 8px; border-left: 3px solid var(--accent); }
.reply-to-chat { padding: 0; font-size: inherit; font-weight: 600; }
.reply.pending { opacity: .7; }
.thread-none, .thread-box-loading, .thread-loading { margin: 0 0 8px; }
.thread-history {
  flex: 1 1 auto; min-height: 0;
  margin-top: 12px; padding: 0 10px 10px;
  border: 1px solid var(--line); border-radius: 12px;
  overflow-y: auto; overscroll-behavior: contain;
}
/* COMMAND-444: a Thread Agent at work — one bubble under the newest message (COMMAND-501), its name and three dots that rise in turn. It
   keeps to its own width (a chat bubble, not a full-width bar) on a phone and on a wide screen alike. */
.thread-typing { margin-top: 12px; width: fit-content; max-width: 100%; }
.thread-typing .reply-head { margin-bottom: 2px; }
.typing-dots { display: inline-flex; gap: 4px; align-items: flex-end; height: 1.2em; font-size: 1.4em; line-height: 1; font-weight: 700; color: var(--muted); }
.typing-dots > span { display: inline-block; animation: typing-dot 1.2s ease-in-out infinite; }
.typing-dots > span:nth-child(2) { animation-delay: .2s; }
.typing-dots > span:nth-child(3) { animation-delay: .4s; }
@keyframes typing-dot { 0%, 60%, 100% { transform: translateY(0); opacity: .45; } 30% { transform: translateY(-.25em); opacity: 1; } }
@media (prefers-reduced-motion: reduce) { .typing-dots > span { animation: none; opacity: .8; } }
/* A box that scrolls inside the page (COMMAND-220: "ook scrollbar stijlen!!"): a thin scrollbar in the app's own
   colours, light and dark — Firefox and today's Chrome read the first rule, older Chrome and Safari the others. */
.scroll-box { scrollbar-width: thin; scrollbar-color: color-mix(in srgb, var(--muted) 45%, transparent) transparent; }
.scroll-box::-webkit-scrollbar { width: 8px; height: 8px; }
.scroll-box::-webkit-scrollbar-track { background: transparent; }
.scroll-box::-webkit-scrollbar-thumb { background: color-mix(in srgb, var(--muted) 45%, transparent); background-clip: padding-box; border: 2px solid transparent; border-radius: 8px; }
.scroll-box::-webkit-scrollbar-thumb:hover { background-color: var(--muted); }
.skill-ask-evaluation { margin-top: 4px; }

/* ---------- Regels (COMMAND-170): the rulebook's sections and the roles, each part marked shared or own ---------- */
.rules-results .card + .card { margin-top: 12px; }
.rules-results h2 { margin: 0 0 6px; font-size: 1rem; }
.tag.rule-layer { margin-left: 0; font-weight: 700; white-space: nowrap; }
.tag.rule-layer-core { background: var(--accent-soft); color: var(--accent); }
.tag.rule-layer-own { background: var(--advice-soft); color: var(--advice); }
.tag.rule-layer-builtin { background: var(--surface-2); color: var(--muted); }
/* COMMAND-192: a project's own rules, a third soft colour (purple), readable in light and dark. */
.tag.rule-layer-project { background: color-mix(in srgb, var(--type-feedback) 14%, var(--surface)); color: var(--type-feedback); }
.rules-project { border-top: 1px solid var(--line); padding: 6px 0; }
.rules-project:first-of-type { border-top: 0; }
.rules-project > summary { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 10px; cursor: pointer; padding: 6px 0; }
/* Zoek in tekst and Over deze lijst (COMMAND-658): popups from the header, the search box over its hits. */
.page-panel .rules-search { width: 100%; margin: 0 0 10px; }
.rules-notes p { margin: 0 0 8px; }
.rule-counts { white-space: nowrap; }
.rule-snippet { overflow-wrap: anywhere; }
.rule-part-head { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 8px; margin: 0 0 4px; font-size: 1rem; }
.rule-behind { margin: 0 0 12px; }
.rule-items { list-style: none; margin: 0; padding: 0; }
.rule-item { padding: 8px 0; }
.rule-item + .rule-item { border-top: 1px solid var(--line); }
.rule-item-head { display: flex; align-items: baseline; gap: 6px; margin: 0 0 2px; }
.rule-item .md > :first-child { margin-top: 0; }
.rule-item .md > :last-child { margin-bottom: 0; }
.rule-layers { display: inline-flex; flex-wrap: wrap; gap: 4px; }
/* COMMAND-187: the PO's conversation on a page, in the page's side panel (a phone: right under the title; a wide
   screen: the column on the right, beside the rule text), and its mark in the list: Antwoord where an answer waits. */
.rule-thread h2 { margin: 0 0 6px; font-size: 1rem; }
.tag.rule-thread-mark { margin-left: 0; font-weight: 700; white-space: nowrap; }
.tag.rule-thread-answer { background: var(--warn-soft); color: var(--warn); }
.tag.rule-thread-open { background: var(--surface-2); color: var(--muted); }
.rule-gone p { margin: 0; }
/* COMMAND-194: the PO's conversation on a record — a server, a project, a PC, an account (under its limits), a docs
   page — in the record page's side panel (a phone: right under the title; a wide screen: the column on the right); a
   docs page's under the page, and beside it on a wide screen. Its mark in the lists. */
.record-thread h2 { margin: 0 0 6px; font-size: 1rem; }
.record-thread-gone p { margin: 0 0 6px; }
.tag.thread-mark { margin-left: 6px; font-weight: 700; white-space: nowrap; }
.tag.thread-mark-answer { background: var(--warn-soft); color: var(--warn); }
.tag.thread-mark-open { background: var(--surface-2); color: var(--muted); }
/* COMMAND-807: a docs page is the shared record page in Documentatie's content column, beside the page tree: one column
   (its text, then the Threads box) until the screen holds both columns next to the tree (1500px, as before). */
@media (min-width: 960px) and (max-width: 1499px) {
  .docs-content .record { grid-template-columns: minmax(0, 1fr); grid-template-areas: "highlights" "main" "side"; }
}
@media (min-width: 1500px) {
  .docs-page-split { display: grid; grid-template-columns: minmax(0, 1fr) 340px; column-gap: var(--gutter); align-items: start; }
  .docs-page-split > .record-thread { position: sticky; top: calc(var(--topbar-h) + 12px); }
  /* COMMAND-220: the column stays within the screen; the open thread's messages take what is left of it (then they
     scroll), the reply box stays at its bottom (COMMAND-501); only a very low screen lets the column itself scroll. */
  .docs-page-split > .record-thread {
    display: flex; flex-direction: column;
    max-height: calc(100vh - var(--topbar-h) - 32px);
    max-height: calc(100dvh - var(--topbar-h) - 32px);
    overflow-y: auto; overscroll-behavior: contain;
  }
  .docs-page-split > .record-thread > * { flex: none; }
  /* The open thread's history takes what is left of the column (COMMAND-395: the box, its open thread, its history). */
  .docs-page-split > .record-thread > .thread-box-body,
  .docs-page-split > .record-thread > .thread-box-body > .thread-panel { flex: 0 1 auto; min-height: 0; display: flex; flex-direction: column; }
  .docs-page-split > .record-thread > .thread-box-body > *,
  .docs-page-split > .record-thread > .thread-box-body > .thread-panel > * { flex: none; }
  .docs-page-split > .record-thread > .thread-box-body > .thread-panel > .thread-history { flex: 1 1 auto; min-height: 0; }
}

/* ---------- Bestanden (COMMAND-142): every file, where it is used, and Bestand in every text box ---------- */

/* Zoek in alle bestanden (COMMAND-656): the server's search in a popup, its box over its results. */
.page-panel .files-search { width: 100%; margin: 0 0 10px; }
/* A file in the List view (COMMAND-394): a small picture (or its kind's icon) before its name, a lock after it (its
   "delete on" day in a column of its own since COMMAND-656); its projects as chips. A picture loads only as it comes into view; nothing plays from the list. */
.file-row-name { display: inline-flex; flex-wrap: wrap; align-items: center; gap: 4px 10px; }
.file-thumb { flex: none; width: 48px; height: 48px; border-radius: 8px; object-fit: cover; border: 1px solid var(--line); background: var(--surface-2); }
.file-thumb-icon { display: grid; place-items: center; color: var(--accent); }
.file-thumb-icon svg { width: 24px; height: 24px; }
.file-row-name .file-thumb { width: 36px; height: 36px; }
.file-row-name .file-thumb-icon svg { width: 20px; height: 20px; }
.file-name { font-weight: 600; overflow-wrap: anywhere; }
.file-row-tags { display: inline-flex; flex-wrap: wrap; gap: 4px; }
.tag.file-project { margin-left: 0; white-space: nowrap; }
.tag.file-lock { margin-left: 0; background: var(--warn-soft); color: var(--warn); font-weight: 700; }
.file-lock-text { color: var(--warn); font-weight: 650; }
/* A file's page: the file itself, then where it is used (a gone place greyed and marked). */
.file-preview .file-media { margin: 0; }
.file-preview img { display: block; max-width: 100%; height: auto; border-radius: 10px; border: 1px solid var(--line); }
.file-use-list { list-style: none; margin: 0; padding: 0; }
.file-use { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 8px; padding: 8px 0; }
.file-use + .file-use { border-top: 1px solid var(--line); }
.file-use.gone .file-use-link { color: var(--muted); }
.file-use-link { overflow-wrap: anywhere; text-align: left; }
.tag.file-use-deleted, .tag.file-use-archived { margin-left: 0; background: var(--surface-2); color: var(--muted); font-weight: 700; }
/* The files that came with a text: photos as before (.gallery), any other file below them as its media. */
.media-list { display: flex; flex-direction: column; gap: 8px; margin: 10px 0 2px; }
.file-media { margin: 0; min-width: 0; }
.file-media-photo img { display: block; max-width: 220px; max-height: 160px; object-fit: cover; border-radius: 10px; border: 1px solid var(--line); }
/* COMMAND-601: the file card's picture (ImageDisplay): a small one with a message, the width of the text on a Docs
   page or in a card's text; a tap shows it over the whole screen. */
.file-image { display: inline-block; max-width: 100%; cursor: zoom-in; }
.file-image img { display: block; border-radius: 10px; border: 1px solid var(--line); }
.file-image-thumb img { max-width: 220px; max-height: 160px; object-fit: cover; }
.gallery .file-image-thumb img { height: 120px; max-height: none; }
.file-image-full img, .file-media-photo .file-image-full img { max-width: 100%; max-height: 70vh; height: auto; object-fit: contain; }
.file-video { display: block; width: 100%; max-height: 60vh; border-radius: 10px; border: 1px solid var(--line); background: #000; }
.file-media-bar { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 10px; margin-top: 6px; font-size: 0.85rem; }
.file-media-name { font-weight: 600; overflow-wrap: anywhere; }
.file-media-audio { display: flex; align-items: center; gap: 12px; padding: 10px 12px; border: 1px solid var(--line); border-radius: 10px; background: var(--surface-2); }
.file-media-file { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 12px; }
.file-media-file .md-file-link { flex: 1; min-width: 0; }
.file-details { flex: none; font-size: 0.85rem; }
.md-media .file-details { margin-top: 6px; }
/* A file that went (COMMAND-138): where it was shown, its name and "Verwijderd op <datum>" in a quiet box. */
.file-gone { display: inline-flex; flex-wrap: wrap; align-items: baseline; gap: 2px 8px; padding: 8px 10px; border: 1px dashed var(--line); border-radius: 10px; background: var(--surface-2); color: var(--muted); font-size: 0.9rem; max-width: 100%; }
.file-gone-name { font-weight: 600; color: var(--text); overflow-wrap: anywhere; }
.gallery .file-gone { align-self: center; }
.md-link-gone { color: var(--muted); }
.md-link-gone .file-gone { padding: 2px 8px; font-size: 0.8rem; }
/* A file's Instellingen (COMMAND-138): its day, the checkbox with days or a day, Opslaan and Verwijder nu. */
.file-settings h2 { display: flex; align-items: center; gap: 6px; }
.file-settings-icon { display: inline-grid; place-items: center; width: 20px; height: 20px; color: var(--accent); }
.file-settings-icon svg { width: 20px; height: 20px; }
.file-delete-state { margin: 0 0 8px; font-weight: 600; }
.file-delete-rule { font-weight: 400; }
.file-delete-label, .file-delete-on { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin: 8px 0 0; }
.file-delete-days { width: 5.5em; min-height: 36px; margin: 0; }
.file-delete-date { width: auto; min-height: 36px; margin: 0; }
.file-settings-actions { margin-top: 12px; }
.file-in-use { margin-top: 12px; }
.file-in-use .file-use-list { margin: 6px 0; }
.tag.file-row-delete { margin-left: 0; background: var(--danger-soft); color: var(--danger); white-space: nowrap; }
/* Regels (a popup since COMMAND-656): one row per kind of file. */
.file-rule-list { list-style: none; margin: 0; padding: 0; }
.file-rule { display: flex; flex-direction: column; gap: 4px; padding: 10px 0; }
.file-rule + .file-rule { border-top: 1px solid var(--line); }
.file-rule-edit { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
.file-rule-days { width: 5.5em; min-height: 36px; margin: 0; }
.file-rule-ask { margin-top: 6px; }
/* A file waiting in a text box: its icon and name, with × (a photo keeps its thumbnail). */
.thumb.thumb-file { width: auto; max-width: 220px; height: 44px; padding: 0 34px 0 10px; display: flex; align-items: center; gap: 6px; place-items: initial; }
.thumb-file-icon { flex: none; display: grid; place-items: center; width: 20px; height: 20px; color: var(--accent); }
.thumb-file-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 0.8rem; color: var(--text); }
/* The sheet Bestand opens: Nieuw uploaden or Uit Bestanden (a pick from the shared files). Over the page, outside it. */
.file-sheet-back {
  position: fixed; inset: 0; z-index: 20;
  display: flex; align-items: flex-end; justify-content: center;
  padding: 16px; background: rgba(0, 0, 0, 0.45);
}
.file-sheet {
  border-radius: 14px;
  background: var(--surface); color: var(--text); box-shadow: 0 8px 28px rgb(0 0 0 / 25%);
}
.file-sheet h2 { margin: 0; font-size: 1.05rem; }
.file-sheet-actions { flex-wrap: wrap; }
.file-pick-search { width: 100%; margin: 4px 0 8px; }
.file-pick-list { list-style: none; margin: 0; padding: 0; }
.file-pick-list li + li { border-top: 1px solid var(--line); }
.file-pick {
  display: flex; align-items: center; gap: 12px; width: 100%;
  min-height: 52px; padding: 6px 4px; border: 0; border-radius: 8px;
  background: none; color: var(--text); font: inherit; text-align: left; cursor: pointer;
}
@media (hover: hover) { .file-pick:hover { background: var(--surface-2); } }
.file-pick-text { min-width: 0; display: flex; flex-direction: column; gap: 2px; }
@media (min-width: 900px) { .file-sheet-back { align-items: center; } }

/* ---------- A skill call (COMMAND-482): the popup of the Skill button, a call as a pill in a box and in a message ---------- */
.skill-call-back {
  position: fixed; inset: 0; z-index: 21;
  display: flex; align-items: flex-end; justify-content: center;
  padding: 16px; background: rgba(0, 0, 0, 0.45);
}
@media (min-width: 900px) { .skill-call-back { align-items: center; } }
.skill-call { border-radius: 14px; background: var(--surface); color: var(--text); box-shadow: 0 8px 28px rgb(0 0 0 / 25%); }
.skill-call h2 { margin: 0; font-size: 1.05rem; }
.skill-call-purpose { margin: 4px 0 0; }
.skill-call-search { width: 100%; margin: 4px 0 8px; }
.skill-call-list { list-style: none; margin: 0; padding: 0; }
.skill-call-list li + li { border-top: 1px solid var(--line); }
.skill-call-pick {
  display: flex; flex-direction: column; align-items: flex-start; gap: 2px; width: 100%;
  min-height: 48px; padding: 8px 4px; border: 0; border-radius: 8px;
  background: none; color: var(--text); font: inherit; text-align: left; cursor: pointer;
}
@media (hover: hover) { .skill-call-pick:hover { background: var(--surface-2); } }
.skill-call-field { display: flex; flex-direction: column; gap: 4px; margin: 0 0 14px; }
.skill-call-label { font-weight: 600; font-size: 0.9rem; }
.skill-call-star { color: var(--warn); }
.skill-call-help { margin: 0; }
.skill-call-hint { margin: 0; }
.skill-call-hint:empty { display: none; }
.skill-call-field select.input, .skill-call-field input.input { width: 100%; }
.skill-call-value { padding: 6px 0; white-space: pre-wrap; overflow-wrap: anywhere; }
/* A call as a pill: in a box above its text (with ×), and in a sent message (a tap shows its values). */
.skill-call-pills { list-style: none; display: flex; flex-wrap: wrap; gap: 6px; margin: 0 0 8px; padding: 0; }
.skill-call-chip { display: inline-flex; align-items: center; max-width: 100%; border-radius: 999px; background: var(--accent-soft); }
.skill-call-chip .pill-x { border: 0; background: none; color: var(--muted); padding: 0 10px 0 2px; font: inherit; cursor: pointer; }
.skill-pill {
  display: inline-block; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  padding: 3px 10px; border: 0; border-radius: 999px; vertical-align: baseline;
  background: var(--accent-soft); color: var(--text); font: inherit; font-size: 0.9em; cursor: pointer;
}
@media (hover: hover) { .skill-pill:hover { filter: brightness(0.95); } }

/* ---------- Questions on a conversation (COMMAND-619, public/thread-questions; built without a design: POC) ---------- */
/* The button in the conversation's head, the lines about its questions, and the popup that walks them. */
.thread-questions-btn { white-space: nowrap; }
.thread-panel .thread-q-line.done { opacity: 0.75; }
.thread-panel details.thread-q-line summary { cursor: pointer; }
.thread-q-answers { margin: 6px auto 0; max-width: 60ch; text-align: left; white-space: pre-wrap; overflow-wrap: anywhere; }
.thread-q-show { margin-left: 4px; }
.thread-questions-back {
  position: fixed; inset: 0; z-index: 21;
  display: flex; align-items: flex-end; justify-content: center;
  padding: 16px; background: rgba(0, 0, 0, 0.45);
}
@media (min-width: 900px) { .thread-questions-back { align-items: center; } }
/* The Bestand sheet the popup's + menu opens (COMMAND-747) comes after it in <body>: it shows above the popup. */
.thread-questions-back ~ .file-sheet-back { z-index: 22; }
.thread-questions { border-radius: 14px; background: var(--surface); color: var(--text); box-shadow: 0 8px 28px rgb(0 0 0 / 25%); }
.thread-questions .modal-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.thread-questions h2 { margin: 0; font-size: 1.05rem; }
.thread-q-meta { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin: 0 0 6px; }
.thread-q-question { margin: 4px 0 10px; font-size: 1.05rem; }
.thread-q-context { margin: 0 0 10px; }
.thread-q-options { list-style: none; display: flex; flex-direction: column; gap: 8px; margin: 0 0 12px; padding: 0; }
.thread-q-option {
  display: flex; flex-direction: column; align-items: flex-start; gap: 2px; width: 100%;
  min-height: 48px; padding: 10px 12px; border: 1px solid var(--line); border-radius: 10px;
  background: var(--surface); color: var(--text); font: inherit; text-align: left; cursor: pointer;
}
.thread-q-option.on { border-color: var(--accent); background: var(--accent-soft); }
@media (hover: hover) { .thread-q-option:hover { background: var(--surface-2); } .thread-q-option.on:hover { background: var(--accent-soft); } }
/* COMMAND-600: an option with a sound clip — the play button beside the pick, the pick taking the rest of the row. */
.thread-q-option-row { display: flex; align-items: center; gap: 8px; }
.thread-q-option-row > .thread-q-option { flex: 1 1 auto; min-width: 0; }
.thread-q-option-row > :not(.thread-q-option) { flex: 0 0 auto; }
.thread-questions .gallery { margin: 0 0 10px; }
.thread-q-done { margin: 8px 0; }
.thread-questions .actions { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 8px; }

/* ---------- Documentatie: the spaces (COMMAND-9), laid out like Confluence (COMMAND-85) ---------- */
/* On a phone, stacked: the search over every space, the space switcher (the space on screen;
   a tap lists every space per company), the page tree in a panel that folds away above a
   page, then the content — a space's home, or a page with its breadcrumbs. What a search
   found takes the content's place (a line each, with its space's coloured pill). A page's
   Markdown (markdown.js). The two columns of a wide screen are in the layer at the end.
   Nothing is fixed to the bottom. */
.docs-side { margin: 0 0 12px; }
.docs-search { margin: 0 0 10px; }
.docs-search .input { width: 100%; }
.docs-results[hidden],
.docs-content[hidden] { display: none; }
.docs-switch { margin: 0 0 10px; }
.docs-switch-btn {
  width: 100%; min-height: 56px;
  display: flex; align-items: center; gap: 10px;
  padding: 8px 12px;
  border: 1px solid var(--line); border-radius: 12px;
  background: var(--surface); color: var(--text);
  font: inherit; text-align: left; cursor: pointer;
}
.docs-switch-btn:focus-visible, .docs-tree-toggle:focus-visible, .docs-switch-item:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.docs-switch-btn > svg, .docs-tree-toggle > svg { flex: none; width: 18px; height: 18px; fill: none; stroke: currentColor; stroke-width: 2.2; color: var(--muted); transition: transform .15s; }
.docs-switch-btn.open > svg, .docs-tree-toggle.open > svg { transform: rotate(180deg); }
.docs-mark {
  flex: none; width: 34px; height: 34px; border-radius: 9px;
  display: grid; place-items: center;
  background: var(--proj-soft, var(--surface-2)); color: var(--proj, var(--text));
  font-weight: 800; font-size: 1rem;
}
.docs-switch-text { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.docs-switch-name { font-weight: 700; overflow-wrap: anywhere; }
.docs-switch-sub { overflow-wrap: anywhere; }
.docs-switch-list { margin-top: 6px; padding: 4px 6px 6px; border: 1px solid var(--line); border-radius: 12px; background: var(--surface); }
.docs-switch-company-name { margin: 8px 6px 2px; font-size: 0.72rem; font-weight: 700; letter-spacing: .04em; text-transform: uppercase; }
.docs-switch-list ul { list-style: none; margin: 0; padding: 0; }
.docs-switch-item {
  display: flex; align-items: center; gap: 10px;
  min-height: 48px; padding: 6px 8px; border-radius: 8px;
  color: var(--text); text-decoration: none;
}
.docs-switch-item.on { background: var(--accent-soft); }
@media (hover: hover) { .docs-switch-item:not(.on):hover { background: var(--surface-2); } }
.docs-tree-toggle {
  width: 100%; min-height: 44px;
  display: flex; align-items: center; gap: 8px;
  padding: 0 12px;
  border: 1px solid var(--line); border-radius: 12px;
  background: var(--surface); color: var(--text);
  font: inherit; font-weight: 650; text-align: left; cursor: pointer;
}
.docs-tree-title { flex: 1; min-width: 0; overflow-wrap: anywhere; }
.docs-tree { margin-top: 6px; }
.docs-tree[hidden] { display: none; }
.docs-lines { list-style: none; margin: 0; padding: 0; }
.docs-lines li + li { border-top: 1px solid var(--line); }
.docs-line {
  display: flex; flex-direction: column; gap: 4px;
  min-height: 44px; padding: 10px 4px;
  border-radius: 8px;
  color: var(--text); text-decoration: none;
}
.docs-line:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
@media (hover: hover) { .docs-line:hover { background: var(--surface-2); } }
.docs-line-title { font-weight: 600; overflow-wrap: anywhere; }
.docs-line-meta { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 8px; min-width: 0; }
.docs-line-when { min-width: 0; overflow-wrap: anywhere; }
.docs-line-meta .proj-pill { max-width: 100%; overflow: hidden; text-overflow: ellipsis; }
.docs-result-snippet { color: var(--muted); overflow-wrap: anywhere; }
.docs-result-snippet b { color: var(--text); font-weight: 700; }
.space-sub { margin-top: -2px; }
.crumbs { display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px; margin: 0 2px 10px; color: var(--muted); }
.crumb { color: var(--accent); text-decoration: none; }
.crumb.here { color: var(--text); font-weight: 600; overflow-wrap: anywhere; }
.crumb-sep { color: var(--muted); }
.space-head h2 { margin-bottom: 2px; }
.space-kicker { margin: 0 0 2px; font-size: 0.72rem; font-weight: 700; letter-spacing: .04em; text-transform: uppercase; }
.space-count { margin: 8px 0 0; }
.space-desc { margin: 8px 0 0; }
.tree-card { padding: 8px 10px; }
.tree { list-style: none; margin: 0; padding: 0 0 0 18px; }
.tree.tree-top { padding-left: 0; }
.tree-row { display: flex; align-items: center; gap: 4px; min-height: 40px; border-top: 1px solid var(--line); }
.tree-top > .tree-item:first-child > .tree-row { border-top: 0; }
.tree-fold {
  flex: none; width: 32px; height: 32px;
  display: grid; place-items: center;
  border: 0; background: none; color: var(--muted); cursor: pointer; border-radius: 8px;
}
.tree-fold svg { width: 16px; height: 16px; fill: none; stroke: currentColor; stroke-width: 2.4; transition: transform .15s; }
/* Drawn by icon-button by its record (TP-596): docs.fold_open/close give the chevron, so it no longer turns. */
.tree-row > .tree-fold.icon-only:not(.btn) { border-radius: 8px; color: var(--muted); }
.tree-fold.icon-only svg.lucide { width: 16px; height: 16px; }
/* TP-618: a ticket's Jira-story line (record-page/pages/tickets.js). */
.ticket-story { margin: 0 0 12px; }
.ticket-story-link { display: inline-flex; align-items: center; gap: 4px; }
.ticket-story-link svg.lucide { width: 14px; height: 14px; }
.tree-fold.none { visibility: hidden; }
.tree-link { flex: 1; min-width: 0; padding: 6px 0; color: var(--text); text-decoration: none; overflow-wrap: anywhere; }
/* The page on screen, in the tree. */
.tree-row.on { background: var(--accent-soft); border-radius: 8px; }
.tree-link.on { color: var(--accent); font-weight: 700; }
.code-tag { flex: none; }
.md-page { padding: 16px; }
.page-title { font-size: 1.3rem; margin: 0 0 4px; overflow-wrap: anywhere; }
.page-meta { margin: 0 0 12px; }
.md-toc { margin: 4px 0 12px; }
.md-toc ul { margin: 4px 0 0; padding-left: 18px; }
.md { line-height: 1.55; overflow-wrap: anywhere; }
.md > * { margin: 0 0 12px; }
.md > *:last-child { margin-bottom: 0; }
.md p { margin: 0 0 10px; }
.md li > p { margin: 0 0 4px; }
.md-h { line-height: 1.3; margin: 20px 0 8px; scroll-margin-top: 120px; }
.md-h1 { font-size: 1.2rem; }
.md-h2 { font-size: 1.1rem; padding-bottom: 4px; border-bottom: 1px solid var(--line); }
.md-h3 { font-size: 1rem; }
.md-h4 { font-size: 0.95rem; color: var(--muted); }
.md > .md-h:first-child { margin-top: 0; }
.md-link { color: var(--accent); text-decoration: underline; text-underline-offset: 2px; }
.md-code { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 0.86em; background: var(--surface-2); border-radius: 6px; padding: 1px 5px; }
.md-list { padding-left: 22px; }
.md-list > li { margin: 2px 0; }
.md-task { list-style: none; position: relative; }
.md-tick {
  position: absolute; left: -22px; top: 4px;
  width: 16px; height: 16px; border-radius: 4px;
  border: 1.5px solid var(--muted);
  display: grid; place-items: center; font-size: 11px; line-height: 1;
}
.md-tick.done { background: var(--advice); border-color: var(--advice); color: #fff; }
.md-quote { margin: 0 0 12px; padding: 4px 0 4px 12px; border-left: 3px solid var(--line); color: var(--muted); }
/* A warning block (COMMAND-1170: a quote that starts with [!WARNING]): amber, the page's own text size and colour. */
.md-alert.warn { margin: 0 0 12px; padding: 8px 10px; border-radius: 10px; border-left: 3px solid var(--warn); background: var(--warn-soft); color: var(--text); font-size: inherit; }
.md-alert.warn > :last-child { margin-bottom: 0; }
.md-hr { border: 0; border-top: 1px solid var(--line); margin: 16px 0; }
.md-img-off { display: inline-block; padding: 2px 8px; border-radius: 8px; background: var(--surface-2); color: var(--muted); font-size: 0.85rem; }
/* Files inside a page (COMMAND-141): in the place they are written, never wider than the text. A picture enlarges on
   a tap; a video plays in place; a sound has the clip button (COMMAND-140); any other file is a download row. */
.md-media { margin: 12px 0; min-width: 0; }
.md-caption { margin-top: 6px; font-size: 0.85rem; color: var(--muted); overflow-wrap: anywhere; }
.md-audio, .md-file-link { display: flex; align-items: center; gap: 12px; padding: 10px 12px; border: 1px solid var(--line); border-radius: 10px; background: var(--surface-2); }
.md-file-link { color: var(--text); text-decoration: none; }
.md-file-link:hover strong, .md-file-link:focus-visible strong { text-decoration: underline; }
.md-file-icon { flex: none; display: grid; place-items: center; width: 28px; height: 28px; color: var(--accent); }
.md-media-text { display: flex; flex-direction: column; gap: 2px; min-width: 0; overflow-wrap: anywhere; }
.md-lightbox {
  position: fixed; inset: 0; z-index: 100;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 12px;
  padding: 16px; background: rgba(0, 0, 0, 0.9);
}
.md-lightbox-img { max-width: 100%; max-height: calc(100% - 64px); object-fit: contain; border-radius: 8px; touch-action: pinch-zoom; }
.md-lightbox-bar { display: flex; flex-wrap: wrap; justify-content: center; gap: 10px; }
/* The PO's page editor (COMMAND-141): the title, the text, Bestand toevoegen, and the page as it will look under it. */
.docs-edit-field { display: flex; flex-direction: column; gap: 4px; }
.docs-edit-tools { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; margin: 12px 0 8px; }
.docs-edit-text { width: 100%; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 0.85rem; line-height: 1.5; }
.docs-edit-error { margin: 8px 0 0; }
.docs-preview { margin-top: 18px; padding-top: 12px; border-top: 1px dashed var(--line); }
.docs-preview > h3 { margin: 0 0 8px; font-weight: 600; }
.md-pre { border: 1px solid var(--line); border-radius: 10px; background: var(--surface-2); overflow: hidden; }
.md-pre-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 6px 12px; border-bottom: 1px solid var(--line); }
.md-pre .copy-block.md-pre-body { margin: 0; border: 0; border-radius: 0; background: transparent; }
.md-pre pre { margin: 0; padding: 10px 44px 10px 12px; overflow-x: auto; }
.md-pre code, .md-plain { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 0.8rem; line-height: 1.5; }
.md-plain { white-space: pre-wrap; overflow-wrap: anywhere; }
/* A wide table scrolls sideways inside its own box: the page itself never does. */
.md-table-wrap { max-width: 100%; overflow-x: auto; -webkit-overflow-scrolling: touch; border: 1px solid var(--line); border-radius: 10px; }
.md-table { border-collapse: collapse; min-width: 100%; font-size: 0.88rem; }
.md-table th, .md-table td { padding: 6px 10px; border-top: 1px solid var(--line); text-align: left; vertical-align: top; overflow-wrap: normal; }
.md-table thead th { border-top: 0; background: var(--surface-2); font-weight: 650; white-space: nowrap; }
.md-table .al-right { text-align: right; }
.md-table .al-center { text-align: center; }
.page-children { margin-top: 18px; padding-top: 10px; border-top: 1px solid var(--line); }
.page-children h3 { font-size: 0.95rem; margin: 0 0 6px; }
.page-children ul { margin: 0; padding-left: 20px; }
.page-actions { margin-top: 18px; }
.version-list { list-style: none; margin: 0; padding: 0; }
.version-row { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 10px; padding: 10px 2px; border-top: 1px solid var(--line); color: var(--text); text-decoration: none; }
.version-list li:first-child .version-row { border-top: 0; }
.version-note { flex-basis: 100%; }
.old-note { margin: 0 0 12px; }

/* ---------- Borden: every project's board (COMMAND-7) ---------- */
/* Phone first: every board as a row of the List view (COMMAND-394); a board and a card as a record page
   (COMMAND-1091: no Kanban). */


/* Every board: its name in a row of the List view. */
.work-board-name { overflow-wrap: anywhere; }
.work-board-name .tag { margin-left: 6px; }

/* A board's record page: what an old or moving board says, and the new card's form. */
.work-archived { margin: 0 2px 10px; }
.work-new-card h2, .work-panel h2 { margin-bottom: 4px; }
.work-new-card .field .input { margin-top: 4px; }

/* A card's title in a List view row. */
.work-row-title { font-weight: 600; line-height: 1.35; overflow-wrap: anywhere; }
.label-tags { display: inline-flex; flex-wrap: wrap; gap: 4px; }
.label-tag { display: inline-block; padding: 1px 7px; border-radius: 8px; background: var(--accent-soft); color: var(--accent); font-size: 0.72rem; font-weight: 600; line-height: 1.5; }
.label-tag.more { background: var(--surface-2); color: var(--muted); }

/* COMMAND-760: a card's priority in its page header (a tap opens the picker) and in the picker: a colour dot per level. */
.work-prio { display: inline-flex; align-items: center; gap: 6px; padding: 2px 10px; border: 1px solid var(--line); border-radius: 8px; background: var(--surface-2); color: var(--text); font: inherit; font-size: 0.85rem; font-weight: 600; line-height: 1.6; }
button.work-prio { cursor: pointer; min-height: 30px; }
button.work-prio:hover, button.work-prio[aria-expanded='true'] { border-color: var(--accent); }
.work-prio-dot { display: inline-block; width: 8px; height: 8px; border-radius: 50%; flex: none; background: var(--muted); }
.work-prio-urgent .work-prio-dot { background: var(--danger); }
.work-prio-high .work-prio-dot { background: var(--warn); }
.work-prio-medium .work-prio-dot { background: var(--accent); }
.work-prio-low .work-prio-dot { background: var(--muted); }
.work-prio-none .work-prio-dot { background: transparent; box-shadow: inset 0 0 0 1.5px var(--muted); }
.work-priority-pick .seg { display: inline-flex; align-items: center; gap: 6px; }
.work-priority-pick .seg.on .work-prio-dot { box-shadow: 0 0 0 1.5px var(--accent-text); }
.work-epic-pick { flex-wrap: wrap; }
/* A "not before" date (COMMAND-260): the chip on a card that waits for its day, and the date picker in its panel. */
.tag.work-not-before-tag { margin-left: 0; background: var(--surface-2); color: var(--text); font-weight: 600; }
.work-not-before-pick { margin: 0 0 12px; }
.work-not-before-pick .input { width: 100%; max-width: 280px; }
/* TP-583: why a sleeping card waits, under Niet voor. */
.work-wait-why { color: var(--muted); font-size: 0.9em; }
/* A parked card (COMMAND-296): its chip, and the Park sheet's two choices and card number field. */
.tag.work-parked-tag { margin-left: 0; background: var(--surface-2); color: var(--text); font-weight: 600; }
.work-park-modes { display: flex; flex-wrap: wrap; gap: 8px; margin: 0 0 12px; }
.work-park-on { margin: 0 0 12px; }
.work-park-on .input { width: 100%; max-width: 280px; }
/* Omzetten (COMMAND-737, COMMAND-1017, POC): the kind it becomes, then the panel's text above Omzetten and Annuleren, as
   the Park sheet lays out. */
.work-convert-pick { margin: 0 0 12px; }
.work-convert-hint { margin: 0 0 12px; max-width: 60ch; }

/* A card (a record page): the card alone (COMMAND-535). */
.work-kicker { color: inherit; }
.work-panel .input { margin-top: 6px; }
/* A card's archive (COMMAND-196): on an archived card, the note with Terugzetten on top; Archiveren's reasons and the
   other card's number. */
.work-archive-note { margin: 0 0 10px; }
.work-archive-note p { margin: 0 0 6px; }
.work-archive-note .actions { margin: 0; }
.work-archive-reasons { margin: 4px 0 0; }
.work-archive-by { display: block; margin-top: 10px; }
.work-archive-by .input { width: 100%; }
.tag.work-archived-tag { color: var(--muted); }
a.related-row, a.btn { text-decoration: none; }

/* Stored text drawn by richtext.js (a card's description, its comments): our own elements only. */
.rt { overflow-wrap: anywhere; }
.rt > :first-child { margin-top: 0; }
.rt > :last-child { margin-bottom: 0; }
.rt p { margin: 0 0 10px; line-height: 1.5; }
.rt h1, .rt h2, .rt h3, .rt h4 { font-size: 1rem; margin: 16px 0 6px; }
.rt h1 { font-size: 1.15rem; }
.rt h2 { font-size: 1.08rem; }
.rt ul, .rt ol { margin: 0 0 10px; padding-left: 22px; }
.rt li { margin: 3px 0; }
.rt li > p { margin: 0; }
.rt blockquote { margin: 0 0 10px; padding: 2px 12px; border-left: 3px solid var(--line); color: var(--muted); }
.rt code, .rt kbd { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 0.88em; padding: 1px 5px; border-radius: 6px; background: var(--surface-2); }
.rt pre { margin: 0 0 10px; padding: 10px 12px; border-radius: 10px; background: var(--surface-2); overflow-x: auto; white-space: pre; overflow-wrap: normal; }
.rt pre code { padding: 0; background: none; }
.rt hr { border: 0; border-top: 1px solid var(--line); margin: 14px 0; }
.rt-table { overflow-x: auto; margin: 0 0 10px; }
.rt table { border-collapse: collapse; font-size: 0.9rem; }
.rt th, .rt td { border: 1px solid var(--line); padding: 6px 8px; text-align: left; vertical-align: top; overflow-wrap: normal; }
.rt th { background: var(--surface-2); }
.rt td > p:last-child, .rt th > p:last-child { margin: 0; }
.rt-picture { font-weight: 600; }
.rt-no-picture { display: inline-block; padding: 2px 8px; border-radius: 8px; background: var(--surface-2); color: var(--muted); font-size: 0.85rem; }
.rt-task { list-style: none; margin-left: -20px; display: flex; gap: 6px; }
.rt-task.done { color: var(--muted); }
.rt-tick { flex: none; }
.rt-task > div { flex: 1; min-width: 0; }

/* Project verwijderen (COMMAND-336): the red button at the bottom of a project's page, the two choices, the confirm screen. */
.project-remove .project-remove-mode { display: flex; align-items: baseline; gap: 12px; margin: 8px 0; flex-wrap: wrap; }
.project-remove .project-remove-mode .btn { min-width: 9em; }
.project-remove .project-remove-mode p { margin: 0; flex: 1 1 14em; }
.project-remove-list { margin: 8px 0; }
.project-remove-list ul { margin: 4px 0 0; padding-left: 1.2em; }
.project-remove-confirm h2 { color: var(--danger); }

/* ---------- a wide screen: a PC, a laptop (COMMAND-28) ---------- */
/* ---------- Financiën → Facturen: every invoice per platform (COMMAND-30) ---------- */

.fin-inv { display: inline-flex; align-items: center; gap: 6px; }
.inv-dot { display: inline-block; width: 8px; height: 8px; border-radius: 50%; background: var(--warn); flex: none; }
/* COMMAND-663: the daily Gmail run stopped — a red dot on Facturen's Totalen button, the red line itself in its popup. */
.inv-stale-dot { margin-left: 6px; vertical-align: middle; background: var(--danger); }
.inv-counts { margin: 8px 0 0; font-weight: 700; }
/* COMMAND-175: the daily Gmail run stopped (48 hours): red in Facturen's Totalen (on top of Facturen until COMMAND-663). */
.inv-import-stale { margin: 8px 0 0; padding: 6px 10px; border-radius: 10px; background: var(--danger-soft); color: var(--danger); font-size: 0.86rem; font-weight: 650; }
.inv-add.disabled { opacity: .6; pointer-events: none; }
.inv-missing-line { padding: 10px 0; }
.inv-missing-text { margin: 0 0 6px; }
.inv-export { margin-top: 10px; }
.inv-mailbox { display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 8px 0; overflow-wrap: anywhere; }
.inv-imports li { padding: 6px 0; }
.inv-platform { display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 8px 0; }
.inv-platform.off .fin-main { opacity: .55; }
.inv-platform-form { margin-top: 8px; border-top: 1px solid var(--line); padding-top: 4px; }
.fin-f-inote { grid-column: 1 / -1; }
/* The file: a photo inline; a PDF behind "Bestand openen" (a phone's browser shows a PDF best on its own). */
.inv-file { display: flex; flex-direction: column; align-items: flex-start; gap: 8px; margin: 10px 0 4px; }
.inv-img { max-width: 100%; max-height: 60vh; border-radius: 10px; border: 1px solid var(--line); }
.inv-preview { display: none; }

/* What a PC may reach (COMMAND-157 step 3): its kind and its companies or projects as segment buttons, a little air
   between the rows. */
.pc-access .seg-group { margin: 8px 0; }
.pc-access .pc-access-list .seg { min-height: 34px; font-size: 0.84rem; }

/* Everything above is the phone layout and stays exactly as it is. From 1100px wide
   this layer, and only this layer, lays the same cards out side by side, up to a
   comfortable maximum width (PO, 2026-09-29: "op een PC voelt het zo smal aan...
   maak gebruik van de ruimte die je hebt ... Dus allebei ondersteunen aub!").
   The navigation stays on top; nothing the phone shows is hidden here.
   app.js gives the page a class per tab (view-todos, ...; on Vragen q-part-approvals,
   q-part-mine) and draws the few wrappers this needs (.box-grid); on
   a phone those wrappers change nothing. */

/* ---------- the token meter (COMMAND-186 step 5): a card at the bottom of Accounts ---------- */

.tok-card .seg-group { margin-top: 10px; }
.tok-stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 10px; margin-top: 12px; }
.tok-stat { display: flex; flex-direction: column; gap: 2px; min-width: 0; padding: 10px 12px; border: 1px solid var(--line); border-radius: 10px; background: var(--surface); }
.tok-stat-label { font-size: 0.8rem; color: var(--muted); }
.tok-stat-value { font-size: 1.4rem; font-variant-numeric: tabular-nums; }
/* A change says itself in words with an arrow; the colour only repeats it (less is the aim). */
.tok-change { font-size: 0.85rem; font-weight: 600; }
.tok-change.down { color: var(--advice); }
.tok-change.up { color: var(--danger); }
.tok-change.same { color: var(--muted); }
.tok-sub { margin: 16px 0 6px; font-size: 0.95rem; }
.tok-days, .tok-group-list { list-style: none; margin: 0; padding: 0; }
.tok-day { display: grid; grid-template-columns: 7.5em minmax(0, 1fr) 4.5em; grid-template-areas: 'name bar num' '. comp comp'; align-items: center; gap: 0 10px; padding: 4px 0; }
.tok-day-name { grid-area: name; font-size: 0.85rem; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.tok-day.today .tok-day-name { color: var(--text); font-weight: 600; }
.tok-bar { grid-area: bar; height: 8px; border-radius: 4px; }
.tok-fill { width: 0; height: 100%; border-radius: 4px; background: var(--accent); }
.tok-day.today .tok-fill { opacity: .55; }
.tok-day-num { grid-area: num; text-align: right; font-size: 0.9rem; font-weight: 600; font-variant-numeric: tabular-nums; }
.tok-day-comp { grid-area: comp; }
.tok-day-comp:empty { display: none; }
.tok-day { cursor: pointer; border-radius: 6px; }
.tok-day.open { background: var(--surface-2); }
.tok-day-detail { grid-column: 1 / -1; margin: 2px 0 4px; overflow-wrap: anywhere; }
.tok-group { padding: 10px 0; border-top: 1px solid var(--line); }
.tok-group-head { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 10px; }
.tok-group-name { flex: 1 1 12em; min-width: 0; overflow-wrap: anywhere; }
.tok-group-num { font-weight: 700; font-variant-numeric: tabular-nums; }
.tok-group-parts { display: flex; flex-wrap: wrap; gap: 4px 16px; margin: 4px 0 0; }
.tok-group-kinds { margin: 2px 0 0; overflow-wrap: anywhere; }
.tok-reported { margin-top: 10px; }

/* What the PO sent escalated (COMMAND-339: an escalated word ignores every usage limit and is picked up at once) carries
   a red "Escalated" badge. Escalating is holding the send button of the message box (COMMAND-576, below). */
.escalated-badge {
  display: inline-block; margin-left: 6px; padding: 0 8px;
  border-radius: 9px; background: var(--danger); color: #fff;
  font-size: 0.72rem; font-weight: 700; line-height: 18px; vertical-align: middle; white-space: nowrap;
}
.reply.escalated { box-shadow: inset 3px 0 0 var(--danger); }

/* UI built without a design (the house rule) carries the class poc-ui, so it stays grep-able. It draws nothing: the PO
   had the red dashed outline and the "POC" badge taken away in the Command Center (COMMAND-817). Its position:
   relative has no weight (:where), so a marked element's own position wins: a fixed popup such as the Threads window
   stays fixed (COMMAND-799); children placed against a marked element keep their anchor. */
:where(.poc-ui) { position: relative; }
/* The mail compose popup (COMMAND-411, public/mail-compose): built without a design (poc-ui). Its pictures and files
   (COMMAND-747, app.js thumbs) sit between the label and the text box. */
.mail-compose-field > .thumbs { margin: 4px 0 8px; }
.mail-compose-bcc { margin-top: 8px; }
.mail-compose-recipients { margin: 8px 0 0; padding-left: 18px; }

/* Request Custom Connector, the built-in connectors and Cases (COMMAND-627; built without a design: POC). A case's status
   and a built-in connector's state as coloured pills; a refused field's line under it; a built-in connector's actions. */
.tag.case-status.info { background: var(--accent-soft); color: var(--accent); }
.tag.case-status.warn, .tag.hub-action-kind.warn { background: var(--warn-soft); color: var(--warn); }
.tag.case-status.ok, .tag.hub-builtin.hub-builtin-ok { background: var(--advice-soft); color: var(--advice); }
.tag.case-status.bad, .tag.hub-builtin.hub-builtin-bad { background: var(--danger-soft); color: var(--danger); }
/* Builds (COMMAND-726, public/builds; built without a design: POC). A build's status as a coloured chip; its log as a
   list that takes the page's width (a phone and a wide screen alike), a handover note marked with a coloured edge; a
   build approval's builds one per line that wraps, a long repository or link breaking rather than widening the page. */
.tag.build-status { margin-left: 0; }
.tag.build-status.info { background: var(--accent-soft); color: var(--accent); }
.tag.build-status.warn, .tag.build-handover { background: var(--warn-soft); color: var(--warn); }
.tag.build-status.ok { background: var(--advice-soft); color: var(--advice); }
.tag.build-status.bad { background: var(--danger-soft); color: var(--danger); }
/* COMMAND-1435, COMMAND-1592: under a build's repository its part, how many changes are done, and the changes in order. */
.build-repo .build-part, .build-repo .build-changes-done { display: block; }
.build-repo .build-changes { margin: 2px 0 0; padding-left: 18px; }
.build-repo .build-change.done .build-change-title { text-decoration: line-through; }
.build-repo .build-change-added { color: var(--warn); }
/* A PC's Berichten tab (COMMAND-909, public/device-messages; built without a design: POC). A delivery's status as a
   coloured tag: answered and delivered green, on its way blue, waiting for a PC that is off amber, expired grey. */
.device-messages-head { display: flex; justify-content: flex-end; margin-bottom: 10px; }
.tag.device-message-status { margin-left: 0; }
.tag.device-message-status.ok { background: var(--advice-soft); color: var(--advice); }
.tag.device-message-status.info { background: var(--accent-soft); color: var(--accent); }
.tag.device-message-status.warn { background: var(--warn-soft); color: var(--warn); padding: 1px 7px; margin: 0; font-size: 0.72rem; border-radius: 8px; }
.tag.device-message-status.grey { background: var(--surface-2); color: var(--muted); }
.build-log { min-width: 0; }
.build-notes { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 10px; }
.build-note { padding: 8px 10px; border-left: 3px solid var(--line); border-radius: 6px; background: var(--surface-2); overflow-wrap: anywhere; }
.build-note-handover { border-left-color: var(--warn); }
.build-note-head { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin-bottom: 4px; }
.build-note-head .tag { margin-left: 0; }
.build-pr-link, .build-approval-link, .build-approval-pr { overflow-wrap: anywhere; }
.build-approval-where { margin: 8px 0; }
.build-approval-builds { list-style: none; margin: 8px 0 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }
.build-approval-build { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 10px; min-width: 0; overflow-wrap: anywhere; }
.build-approval-repo { font-weight: 600; }
.case-request-form .case-field-error, .case-request-form .case-exists { margin: -4px 0 10px; }
.hub-action-list { list-style: none; margin: 0; padding: 0; }
.hub-action { padding: 8px 0; border-top: 1px solid var(--line); }
.hub-action-description { margin: 4px 0 0; }

/* The ERD row of a project's page (COMMAND-413): the Lucid link and who draws in it now; wraps on a phone. */
.erd-row { display: inline-flex; flex-wrap: wrap; align-items: baseline; gap: 4px 12px; padding-right: 28px; }
.erd-turn.is-busy { font-weight: 600; }

/* The message box (COMMAND-576, public/composer; the PO, 2026-10-11: like WhatsApp). ONE rounded field holding the +
   (its menu: Photo, File, Skill, Screenshot) and the text; the round, filled send button right of it. Held, the field
   fills red from left to right over --composer-hold (COMPOSER.HOLD_MS, set on the box); full red is an escalated
   message. The same on a phone and a wide screen: the field takes the room, the buttons keep a thumb's size. The text
   (the box's own textarea, COMMAND-672: every message box is this box) is never stretched by hand: it opens one line
   tall and grows with its text up to six lines, then scrolls inside itself (it overrides textarea.input.grow;
   COMMAND-664). 20px is the padding of the text inside .composer-pill, which has no border. The + and send sit at its
   bottom, level with the first line while it is one line tall. */
.composer-box { position: relative; display: flex; align-items: flex-end; gap: 8px; margin-top: 10px; }
.composer-pill {
  position: relative; flex: 1; min-width: 0;
  display: flex; align-items: flex-end; gap: 2px;
  padding: 3px 4px;
  border: 1.5px solid var(--line); border-radius: 24px;
  background: var(--surface);
}
.composer-pill:focus-within { border-color: var(--accent); }
.composer-pill > textarea.input,
.composer-pill > textarea.input.grow {
  position: relative; z-index: 1;
  flex: 1; min-width: 0; width: auto;
  margin: 0; padding: 10px 8px;
  border: 0; border-radius: 0;
  background: transparent;
  resize: none;
  min-height: calc(1.45em + 20px);
  max-height: calc(6 * 1.45em + 20px);
}
.composer-pill > textarea.input:focus { border: 0; }
/* The + is icon-button's overlay menu (CHORE-212): its panel's shape is in icon-button/index.css; the field no longer
   clips, so the menu grows out of it from the +'s corner. */
.composer-attach { margin-bottom: 2px; }
.composer-plus {
  position: relative; flex: none;
  width: 40px; height: 40px;
  border: 0; border-radius: 50%;
  background: transparent; color: var(--muted);
  display: grid; place-items: center; cursor: pointer;
}
.composer-plus:hover, .composer-attach[data-open] > .composer-plus { background: var(--surface-2); color: var(--text); }
.composer-plus svg { width: 24px; height: 24px; }
/* The red fill behind the text while send is held; it resets at once when the press ends early. */
.composer-fill {
  position: absolute; inset: 0 auto 0 0; width: 0;
  border-radius: 22.5px; /* the field's round corners inside its border: the field itself no longer clips (CHORE-212) */
  background: var(--danger); opacity: 0.35;
  pointer-events: none; transition: none;
}
.composer-box[data-hold="on"] .composer-fill { width: 100%; transition: width var(--composer-hold, 2000ms) linear; }
.composer-send {
  flex: none; width: 48px; height: 48px;
  border: 0; border-radius: 50%;
  background: var(--accent); color: var(--accent-text);
  display: grid; place-items: center; cursor: pointer;
  /* A hold is a hold: no scrolling, no text selection, no long-press menu of the phone. */
  touch-action: none; user-select: none; -webkit-user-select: none; -webkit-touch-callout: none;
  -webkit-tap-highlight-color: transparent;
}
.composer-send svg { width: 24px; height: 24px; }
.composer-send.composer-send-danger { background: var(--danger); color: #fff; }
.composer-send:disabled { opacity: 0.45; cursor: default; }
.composer-send.sending { opacity: 0.6; }
.composer-box[data-hold="on"] .composer-send { background: var(--danger); color: #fff; transform: scale(1.08); transition: transform 0.15s; }
/* The mic in the send slot (COMMAND-577, public/speech-input): while the field is empty the round button is a mic
   (the box's data-mic="on"); one typed character turns it into send. The send button stays in the box, hidden. A tap
   records: red, pulsing, a stop square (data-rec="recording"); on the paid route a small spinner while the recording
   turns into text (data-rec="transcribing"). */
.composer-mic {
  display: none; position: relative;
  flex: none; width: 48px; height: 48px;
  border: 0; border-radius: 50%;
  background: var(--accent); color: var(--accent-text);
  place-items: center; cursor: pointer;
  user-select: none; -webkit-user-select: none; -webkit-touch-callout: none;
  -webkit-tap-highlight-color: transparent;
}
.composer-box[data-mic="on"] .composer-mic { display: grid; }
.composer-box[data-mic="on"] .composer-send { display: none; }
.composer-mic > span { grid-area: 1 / 1; }
.composer-mic-icon { display: grid; place-items: center; }
.composer-mic svg { width: 24px; height: 24px; }
.composer-mic-stop svg path, .composer-mic-stop svg rect { fill: currentColor; }
.composer-mic-stop, .composer-mic-spinner { display: none; }
.composer-mic:disabled { cursor: default; }
.composer-box[data-rec="recording"] .composer-mic { background: var(--danger); color: #fff; animation: composer-mic-pulse 1.4s ease-out infinite; }
.composer-box[data-rec="recording"] .composer-mic-idle,
.composer-box[data-rec="transcribing"] .composer-mic-idle { display: none; }
.composer-box[data-rec="recording"] .composer-mic-stop { display: grid; }
.composer-box[data-rec="transcribing"] .composer-mic-spinner {
  display: block; width: 22px; height: 22px;
  border: 2.5px solid currentColor; border-right-color: transparent; border-radius: 50%;
  animation: composer-mic-spin 0.8s linear infinite;
}
@keyframes composer-mic-pulse { 0% { box-shadow: 0 0 0 0 var(--danger); } 100% { box-shadow: 0 0 0 12px transparent; } }
@keyframes composer-mic-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  .composer-box[data-rec="recording"] .composer-mic { animation: none; box-shadow: 0 0 0 4px var(--danger-soft); }
  .composer-box[data-rec="transcribing"] .composer-mic-spinner { animation-duration: 2.4s; }
}
.composer-item {
  display: flex; align-items: center; gap: 12px;
  min-height: 44px; padding: 0 12px;
  border: 0; border-radius: 8px;
  background: transparent; color: var(--text);
  font: inherit; text-align: left; cursor: pointer;
}
.composer-item:hover, .composer-item:focus-visible { background: var(--surface-2); }
.composer-item:disabled { opacity: 0.5; cursor: default; }
.composer-item-icon { display: grid; place-items: center; color: var(--accent); }
.composer-item-icon svg { width: 20px; height: 20px; }
/* Later / Cancel under a box: plain buttons outside the field. */
.actions.composer-after { margin-top: 8px; }

/* Bespreek (COMMAND-536): the thread beside a question, an approval or a todo. The button carries a small dot while
   its Thread Agent has a reply the PO has not seen; the thread opens in the page-panel popup, a little lower than on a
   page so the popup's head stays in view. No design yet: POC (poc-ui). */
.discuss-thread > .thread-panel[data-thread] { height: min(36rem, 62vh); height: min(36rem, 62dvh); }

/* ----- The chart page (COMMAND-477, public/chart-page): /charts/<id> as a full-screen editor like Lucidchart ----- */
/* Under the app's top navigation the page fills the rest of the screen, edge to edge: a slim bar on top, the tools on
   the left, the drawing, the inspector on the right for a selected table, line or group. On a phone the tools are a row
   at the bottom and the inspector a sheet that slides over the lower part. The drawing stays white like the PO's Lucid
   ERDs, in dark mode too. No design yet: the tools and the inspector carry the POC marker (poc-ui). */
.view.page-record:has(.chart-page) { max-width: none; padding: 0; margin: 0; }
.chart-page { display: flex; flex-direction: column; height: calc(100dvh - var(--topbar-h, 52px) - 16px); min-height: 420px; }
.chart-page-bar { display: flex; align-items: center; gap: 6px 14px; flex-wrap: wrap; padding: 6px 12px; border-bottom: 1px solid var(--line); background: var(--surface); }
.chart-back { white-space: nowrap; }
.chart-name { margin: 0; font-size: 1.05rem; overflow-wrap: anywhere; }
.chart-name-input { font-size: 1rem; font-weight: 600; min-width: 0; width: min(420px, 50vw); }
.chart-bar-gap { flex: 1; }
/* Releases (COMMAND-441): a base chart's release next to its name, what a chart is built on, and an amber marker when
   its base has a newer release. */
.chart-releases { display: inline-flex; align-items: baseline; gap: 4px 10px; flex-wrap: wrap; }
.chart-release { font-weight: 600; }
.chart-release-new { padding: 1px 8px; border-radius: 999px; background: var(--warn-soft); color: var(--warn); font-size: 0.8rem; font-weight: 600; white-space: nowrap; }
.chart-page-note { padding: 16px; }
/* Which version each environment's database is equal to (COMMAND-1054): a chip per environment in the bar, a tap opens
   what differs. No design yet: POC. */
.chart-db { display: inline-flex; align-items: center; gap: 4px 6px; flex-wrap: wrap; }
.chart-db-chip { padding: 1px 8px; border: 0; border-radius: 999px; font: inherit; font-size: 0.8rem; font-weight: 600; white-space: nowrap; cursor: pointer; }
.chart-db-chip:disabled { cursor: default; }
.chart-db-equal { background: var(--advice-soft); color: var(--advice); }
.chart-db-differs { background: var(--warn-soft); color: var(--warn); }
.chart-db-unread { background: var(--bg); color: var(--muted); }
.chart-db-popup { width: min(720px, 94vw); max-height: 80vh; display: flex; flex-direction: column; padding: 16px 18px; }
.chart-db-popup-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 12px; }
.chart-db-popup-head h2 { margin: 0; font-size: 1.05rem; }
.chart-db-diffs { margin: 10px 0 0; padding-left: 18px; overflow: auto; font-size: 0.9rem; line-height: 1.5; }
.chart-db-diff { overflow-wrap: anywhere; }
/* The version switch (COMMAND-1087): the button in the bar and the line while an older version is shown; its list of
   milestones is public/chart-milestones (TP-569). */
.chart-versions-btn { padding: 1px 8px; border: 1px solid var(--line); border-radius: 999px; background: var(--surface); color: inherit; font: inherit; font-size: 0.8rem; font-weight: 600; white-space: nowrap; cursor: pointer; }
.chart-versions-btn.old { background: var(--warn-soft); color: var(--warn); }
.chart-version-old { color: var(--warn); }
/* COMMAND-1430: a locked version: a lock in the version button. */
.chart-versions-btn.locked { display: inline-flex; align-items: center; gap: 4px; }
.chart-version-lock svg { width: 12px; height: 12px; fill: none; stroke: currentColor; stroke-width: 2.4; vertical-align: -1px; }

.chart-icon-btn { width: 40px; height: 40px; display: inline-flex; align-items: center; justify-content: center; border: 1px solid var(--line); border-radius: 10px; background: var(--surface); color: var(--text); cursor: pointer; }
.chart-icon-btn svg { width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-width: 2; }
.chart-icon-btn:disabled { opacity: 0.4; cursor: default; }
.chart-page-body { flex: 1; min-height: 0; display: grid; grid-template-columns: 64px minmax(0, 1fr); }
.chart-page.with-inspector .chart-page-body { grid-template-columns: 64px minmax(0, 1fr) 360px; }
/* The tool bar: one column of tools, its label under each icon (Lucid's left bar). */
.chart-tools { display: flex; flex-direction: column; gap: 2px; padding: 8px 4px; border-right: 1px solid var(--line); background: var(--surface); overflow-y: auto; }
.chart-tool { display: flex; flex-direction: column; align-items: center; gap: 2px; min-height: 52px; padding: 6px 2px; border: 0; border-radius: 8px; background: none; color: var(--text); cursor: pointer; font: inherit; }
.chart-tool svg { width: 22px; height: 22px; fill: none; stroke: currentColor; stroke-width: 1.8; }
.chart-tool-label { font-size: 0.68rem; line-height: 1.1; text-align: center; }
.chart-tool.on { background: var(--accent-soft, #e3ebff); color: var(--accent, #2f5bd3); }
.chart-tool:disabled { opacity: 0.35; cursor: default; }
@media (hover: hover) { .chart-tool:not(:disabled):not(.on):hover { background: var(--surface-2); } }
/* The drawing: everything that is left, with the zoom at its bottom right and a search box at its top. */
.chart-stage { position: relative; min-width: 0; min-height: 0; overflow: hidden; background: #ffffff; touch-action: none; }
.chart-svg { display: block; width: 100%; height: 100%; cursor: grab; user-select: none; -webkit-user-select: none; }
.chart-svg:active { cursor: grabbing; }
.chart-table { cursor: pointer; }
.chart-table:focus { outline: none; }
.chart-table.on .chart-table-box, .chart-table:focus-visible .chart-table-box { stroke: #2f5bd3; stroke-width: 3; }
.chart-line.on { stroke: #2f5bd3; stroke-width: 2.5; }
.chart-line-hit { cursor: pointer; }
/* A row whose target is in another ERD (COMMAND-542): its own colour and a small jump button at its right end. */
.chart-row-xref .chart-row-xref-bg { fill: var(--chart-xref-soft); }
.chart-row-xref .chart-key, .chart-row-xref .chart-field { fill: var(--chart-xref); font-weight: bold; }
.chart-jump { cursor: pointer; }
.chart-jump-box { fill: var(--chart-xref); }
.chart-jump:hover .chart-jump-box, .chart-jump:focus-visible .chart-jump-box { stroke: #2f5bd3; stroke-width: 2; }
.chart-jump:focus { outline: none; }
/* An id that descends from another table (COMMAND-703): its row and its line in the descends green. */
.chart-row-descends .chart-row-descends-bg { fill: var(--chart-descends-soft); }
.chart-row-descends .chart-key, .chart-row-descends .chart-field { fill: var(--chart-descends); font-weight: bold; }
.chart-row-descends .chart-jump-box { fill: var(--chart-descends); }
.chart-line-descends { stroke: var(--chart-descends); }
.chart-group.on .chart-group-box { stroke: #2f5bd3; stroke-width: 3; }
.chart-note.on rect { stroke: #2f5bd3; stroke-width: 3; }
/* Find (COMMAND-540): every hit yellow, the current one a stronger yellow with an orange outline. The paper stays white
   in dark mode too (.chart-stage), so these fills and the dark text on them read the same in both. A note is yellow
   already: a hit there is a deeper yellow with an amber outline. */
.chart-row.chart-hit .chart-row-mark { fill: #fff176; }
.chart-row.chart-hit-current .chart-row-mark { fill: #ffd54a; stroke: #f97316; stroke-width: 2; }
.chart-row.chart-hit .chart-key, .chart-row.chart-hit .chart-field, .chart-row.chart-hit .chart-type { fill: #1f2328; }
.chart-table-head.chart-hit .chart-head { fill: #fff176; }
.chart-table-head.chart-hit .chart-head-text { fill: #1f2328; }
.chart-table-head.chart-hit-current .chart-head { fill: #ffd54a; stroke: #f97316; stroke-width: 3; }
.chart-table.chart-hit > .chart-table-box { fill: #fffbd1; stroke: #e0b400; stroke-width: 2; }
.chart-table.chart-hit-current > .chart-table-box { fill: #fff3a0; stroke: #f97316; stroke-width: 3; }
.chart-note.chart-hit rect { fill: #ffe14d; stroke: #e0b400; stroke-width: 2; }
.chart-note.chart-hit-current rect { fill: #ffd54a; stroke: #f97316; stroke-width: 3; }
/* The right-click menu (COMMAND-541): a small list where the PO clicked; the layer under it closes it. */
.chart-menu-layer { position: fixed; inset: 0; z-index: 20; }
.chart-menu { position: fixed; min-width: 190px; display: flex; flex-direction: column; padding: 4px; border: 1px solid var(--line); border-radius: 8px; background: var(--surface); box-shadow: 0 6px 20px rgb(0 0 0 / 25%); }
.chart-menu-item { text-align: left; padding: 7px 10px; border: 0; border-radius: 6px; background: none; color: var(--text); font: inherit; cursor: pointer; }
.chart-menu-item:hover, .chart-menu-item:focus-visible { background: var(--line); }
.chart-menu-item.danger { color: #e5534b; }
.chart-svg[data-edit='tables'][data-tool='select'] .chart-table, .chart-svg[data-edit='tables'][data-tool='select'] .chart-group-handle, .chart-svg[data-edit][data-tool='select'] .chart-note { cursor: move; }
.chart-svg[data-tool='table'], .chart-svg[data-tool='note'], .chart-svg[data-tool='group'] { cursor: crosshair; }
.chart-svg[data-tool='line'] .chart-row { cursor: crosshair; }
/* COMMAND-440: a base's tables, groups and notes are read-only on the paper: never a move cursor, never a line's start. */
.chart-svg[data-edit][data-tool='select'] .chart-table.chart-inherited, .chart-svg[data-edit][data-tool='select'] .chart-inherited .chart-group-handle, .chart-svg[data-edit][data-tool='select'] .chart-note.chart-inherited { cursor: pointer; }
.chart-svg[data-tool='line'] .chart-inherited .chart-row { cursor: default; }
.chart-base-label { pointer-events: none; user-select: none; }
/* COMMAND-823: the chip is the base table's jump button (to the table in its own ERD). */
.chart-base-label.chart-base-jump { pointer-events: auto; cursor: pointer; }
.chart-base-jump:hover .chart-base-label-box, .chart-base-jump:focus-visible .chart-base-label-box { stroke: #2f5bd3; stroke-width: 2; }
.chart-base-jump:focus { outline: none; }
/* COMMAND-762: a base's table (not placed here) on the base look; a selected or found one keeps its blue or yellow. */
.chart-inherited > .chart-table-box { stroke: var(--chart-base-line); stroke-dasharray: 5 3; fill: var(--chart-base-fill); }
.chart-base-hatch-bg { fill: #e3e6ea; }
.chart-base-hatch-line { stroke: var(--chart-base-hatch); }
.chart-base-label-box { fill: var(--chart-base-label); }
.chart-base-label-text { fill: #ffffff; }
/* COMMAND-823: a base's table is shown only when this ERD stands on it: green when a table here descends from it, blue
   when only a plain FK points at it — its outline and chip, the FK line toward it and the field. Own FKs stay grey. */
.chart-inherited.chart-base-descends > .chart-table-box { stroke: var(--chart-descends); }
.chart-inherited.chart-base-descends .chart-base-label-box { fill: var(--chart-descends); }
.chart-inherited.chart-base-fk > .chart-table-box { stroke: var(--chart-base-fk); }
.chart-inherited.chart-base-fk .chart-base-label-box { fill: var(--chart-base-fk); }
.chart-line-base-fk { stroke: var(--chart-base-fk); }
.chart-row-base-fk .chart-row-base-fk-bg { fill: var(--chart-base-fk-soft); }
.chart-row-base-fk .chart-key, .chart-row-base-fk .chart-field { fill: var(--chart-base-fk); font-weight: bold; }
/* A base table placed here: the base rows muted (the drawing's opacity), its own fields on the extension band. */
.chart-row-extension .chart-row-extension-bg { fill: var(--chart-extend-soft); }
.chart-extension-bar { fill: var(--chart-extend); }
.chart-extension-rule { stroke: var(--chart-extend); }
.chart-svg[data-tool='line'] .chart-row-inherited { cursor: default; }
.chart-hint { position: absolute; top: 10px; left: 50%; transform: translateX(-50%); margin: 0; padding: 6px 12px; border-radius: 999px; background: rgb(31 35 40 / 85%); color: #ffffff; pointer-events: none; max-width: calc(100% - 24px); text-align: center; }
.chart-zoom-bar { position: absolute; right: 12px; bottom: 12px; display: flex; align-items: center; gap: 6px; padding: 4px; border: 1px solid var(--line); border-radius: 12px; background: var(--surface); color: var(--text); box-shadow: 0 2px 8px rgb(0 0 0 / 12%); }
.chart-zoom-level { min-width: 52px; text-align: center; font-variant-numeric: tabular-nums; font-weight: 600; }
/* The Find box (COMMAND-540, like Lucid's): its title and ×, the input with "1 van N" at its right, two checkboxes and
   the previous / next arrows; at the top right of the drawing, over it. */
.chart-find { position: absolute; top: 12px; right: 12px; width: min(300px, calc(100% - 24px)); padding: 10px 12px 8px; z-index: 2; box-shadow: 0 6px 20px rgb(0 0 0 / 18%); }
.chart-find-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.chart-find-title { margin: 0; font-size: 1rem; }
.chart-find-close { width: 36px; height: 36px; border: 0; background: none; color: var(--muted); font-size: 1.4rem; cursor: pointer; }
.chart-find-field { position: relative; margin-top: 6px; }
.chart-find-input { width: 100%; box-sizing: border-box; padding-right: 72px; }
.chart-find-count { position: absolute; right: 10px; top: 50%; transform: translateY(-50%); color: var(--muted); font-size: 0.85rem; font-variant-numeric: tabular-nums; pointer-events: none; }
.chart-find-option { display: flex; align-items: center; gap: 8px; margin-top: 6px; cursor: pointer; }
.chart-find-nav { display: flex; gap: 4px; margin-top: 6px; }
/* The inspector (Lucid's Properties panel). */
.chart-inspector { min-width: 0; overflow-y: auto; padding: 10px 14px 24px; border-left: 1px solid var(--line); background: var(--surface); }
.chart-inspector h4 { margin: 14px 0 4px; }
.chart-panel-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.chart-panel-name { margin: 0; font-size: 1rem; overflow-wrap: anywhere; }
.chart-panel-close { width: 44px; height: 44px; border: 0; background: none; color: var(--muted); font-size: 1.5rem; cursor: pointer; }
.chart-in-row { display: grid; grid-template-columns: 96px minmax(0, 1fr); align-items: center; gap: 8px; margin-top: 8px; }
.chart-in-row .input { width: 100%; box-sizing: border-box; }
.chart-color { display: inline-flex; align-items: center; gap: 10px; }
.chart-in-color { width: 44px; height: 32px; padding: 0; border: 1px solid var(--line); border-radius: 6px; background: none; }
.chart-fields { list-style: none; margin: 0; padding: 0; }
.chart-field-row { display: grid; grid-template-columns: 70px minmax(0, 1fr) minmax(0, 1fr); gap: 4px 6px; align-items: center; padding: 4px 0; border-bottom: 1px solid var(--line); font-size: 0.85rem; overflow-wrap: anywhere; }
.chart-fields.editable .chart-field-row { grid-template-columns: 16px 56px minmax(0, 1fr) minmax(0, 1fr) 28px; }
.chart-field-row .input { width: 100%; box-sizing: border-box; padding: 4px 6px; font-size: 0.85rem; }
.chart-field-row.dragging { opacity: 0.5; }
.chart-field-head { display: grid; grid-template-columns: 70px minmax(0, 1fr) minmax(0, 1fr); gap: 6px; }
.chart-drag-handle { cursor: grab; color: var(--muted); user-select: none; }
.chart-field-remove { width: 28px; height: 28px; border: 0; background: none; color: var(--muted); font-size: 1.2rem; cursor: pointer; }
.chart-col-key { color: var(--muted); white-space: nowrap; }
/* COMMAND-762: a placed table's fields per ERD — a small heading per layer, the base fields fixed and faded. */
.chart-field-layer { padding: 8px 0 2px; border-bottom: 1px solid var(--line); font-weight: 600; }
.chart-field-row.chart-field-inherited { opacity: 0.6; }
.chart-place { margin-top: 8px; }
.chart-place-hint { margin: 6px 0 0; }
.chart-notes-from { margin: 6px 0 2px; font-weight: 600; }
.chart-table-note-base { background: var(--surface-2); }
/* "Points to" under a foreign-key field (COMMAND-542): the lookup of its target table. */
.chart-field-ref { padding: 2px 0 8px 22px; border-bottom: 1px solid var(--line); }
.chart-field-ref .picker { margin-top: 2px; }
.chart-ref-label { display: block; }
.chart-ref-clear { margin-top: 4px; }
.chart-col-field { font-weight: 600; }
.chart-add-field { margin-top: 8px; }
.chart-refs { margin: 4px 0 8px; padding-left: 18px; font-size: 0.85rem; }
.chart-inspector-notes { margin-top: 6px; }
/* A table's own notes (COMMAND-480): the list under its fields, the add box, the inline edit box. */
.chart-table-notes { list-style: none; margin: 4px 0 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.chart-table-note { padding: 8px 10px; border: 1px solid var(--line); border-radius: 8px; background: var(--surface); }
.chart-table-note-text { margin: 0; white-space: pre-wrap; overflow-wrap: anywhere; }
.chart-table-note-meta { margin: 4px 0 0; }
.chart-table-note-actions { display: flex; gap: 12px; margin-top: 4px; }
/* The add box and the edit box are the message box (public/composer, COMMAND-672). */
.chart-table-note .composer-box { margin-top: 0; }
.chart-remove-table, .chart-remove-line, .chart-remove-group { margin-top: 18px; }
.chart-note-actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 8px; }
/* A phone: the tools a row at the bottom (the page ends at the bottom of the screen), the inspector a sheet. */
@media (max-width: 720px) {
  .chart-page-body, .chart-page.with-inspector .chart-page-body { grid-template-columns: minmax(0, 1fr); grid-template-rows: minmax(0, 1fr) auto; }
  .chart-stage { grid-row: 1; }
  .chart-tools { grid-row: 2; flex-direction: row; overflow-x: auto; overflow-y: hidden; padding: 4px 8px; border-right: 0; border-top: 1px solid var(--line); }
  .chart-tool { min-width: 56px; }
  .chart-zoom-bar { bottom: 8px; right: 8px; }
  .chart-zoom-bar .chart-fit-btn { display: none; }
  .chart-inspector { position: fixed; left: var(--utility-rail-w); right: 0; bottom: 0; z-index: 9; max-height: 60dvh; border-left: 0; border-top: 1px solid var(--line); border-radius: 16px 16px 0 0; box-shadow: 0 -6px 20px rgb(0 0 0 / 20%); }
}
/* The Mail screen (COMMAND-410, public/mail.js; the shared index page since COMMAND-646): a table, an unread subject
   bold and its text at most two lines; a mail opens on its own page. The HTML of a mail sits in a locked frame. A mail's own block has no
   design yet: marked POC (poc-ui). */
.mail-subject-cell { display: inline-flex; align-items: center; gap: 6px; }
.mail-subject-cell.mail-unread { font-weight: 700; }
.list-view[data-list='mail-messages'] td[data-field='preview'] > * { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.mail-linked-item.mail-unread { font-weight: 700; }
.mail-clip svg, .mail-file svg { width: 14px; height: 14px; fill: none; stroke: currentColor; stroke-width: 1.8; vertical-align: -2px; }
.mail-open { display: flex; flex-direction: column; gap: 10px; }
.mail-head { display: grid; grid-template-columns: max-content minmax(0, 1fr); gap: 2px 12px; margin: 0; font-size: 0.9rem; }
.mail-head dt { color: var(--muted); }
.mail-head dd { margin: 0; overflow-wrap: anywhere; }
.mail-actions { display: flex; flex-wrap: wrap; gap: 6px; }
.mail-files { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: 6px 14px; }
.mail-body { min-width: 0; }
.mail-html { display: block; width: 100%; height: 65vh; min-height: 360px; border: 1px solid var(--line); border-radius: 8px; background: #fff; resize: vertical; }
.mail-text { white-space: pre-wrap; overflow-wrap: anywhere; font-size: 0.95rem; }
.mail-pictures { margin-bottom: 8px; font-size: 0.9rem; }
.mail-plain { margin-top: 8px; }
.mail-links h3, .mail-linked h2 { margin: 0 0 6px; }
.mail-link-list, .mail-linked-list, .mail-picker-list { list-style: none; margin: 0 0 8px; padding: 0; display: flex; flex-direction: column; gap: 4px; }
.mail-unlink { font-size: 1.1rem; line-height: 1; padding: 0 4px; }
.mail-kind { font-size: 0.75rem; }
.mail-picker { display: flex; flex-direction: column; gap: 6px; }
.mail-picker-item { width: 100%; text-align: left; display: flex; align-items: baseline; gap: 6px; flex-wrap: wrap; padding: 6px 8px; border: 1px solid var(--line); border-radius: 8px; background: none; font: inherit; color: inherit; cursor: pointer; }
.mail-picker-item[disabled] { opacity: 0.55; cursor: default; }
.mail-linked { margin-top: 10px; }
.mail-linked-item { text-align: left; }
/* A Claude account linked once to the Command Center (COMMAND-618, claude-logins/index.js): built without a design (poc-ui). */
.acct-login-cell { display: inline-flex; flex-wrap: wrap; align-items: center; gap: 6px; }
.chip.acct-login { background: var(--surface-2); color: var(--muted); }
.chip.acct-login.linked { background: var(--advice-soft); color: var(--advice); }
.chip.acct-login.signing-in { background: var(--warn-soft); color: var(--warn); }
.chip.acct-login.broken { background: var(--danger-soft); color: var(--danger); }
.acct-proof.works { color: var(--advice); }
.acct-proof-detail { word-break: break-word; }
.todo-code-field { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin: 10px 0; }
.todo-code-field label { flex-basis: 100%; }
.todo-code-field input { flex: 1 1 220px; min-width: 0; }
/* Run tests now and a project's test state (COMMAND-633, project-tests/index.js): built without a design (poc-ui). Each
   repository's run on its own line that wraps on a phone; a long reason breaks rather than widening the page. */
.project-tests { display: flex; flex-direction: column; align-items: flex-start; gap: 4px; min-width: 0; }
.tag.tests-state, .tag.tests-mark { margin-left: 0; }
.tag.tests-mark { margin-left: 6px; }
.tag.tests-state.is-running, .tag.tests-mark.is-running { background: var(--accent-soft); color: var(--accent); font-weight: 700; }
.tag.tests-state.is-green, .tag.tests-mark.is-green { background: var(--advice-soft); color: var(--advice); font-weight: 700; }
.tag.tests-state.is-red, .tag.tests-mark.is-red { background: var(--danger-soft); color: var(--danger); font-weight: 700; }
.tag.tests-state.is-cancelled, .tag.tests-mark.is-cancelled { background: var(--warn-soft); color: var(--warn); font-weight: 700; }
.tests-runs { margin: 0; padding: 0; list-style: none; display: flex; flex-direction: column; gap: 2px; min-width: 0; max-width: 100%; }
.tests-run { overflow-wrap: anywhere; }
.tests-run.is-green .tests-run-state { color: var(--advice); }
.tests-run.is-red .tests-run-state, .tests-run.is-refused .tests-run-state { color: var(--danger); }
.tests-run.is-running .tests-run-state { color: var(--accent); }
.tests-run-problem { color: var(--danger); }
/* COMMAND-906: a project's deploys (public/project-deploys). No class starting "deploy-" here (test/projects.test.mjs). */
.project-deploys { display: flex; flex-direction: column; align-items: flex-start; gap: 6px; min-width: 0; }
.deploys-stage { display: flex; flex-direction: column; align-items: flex-start; gap: 2px; min-width: 0; max-width: 100%; }
.tag.deploys-state { margin-left: 0; }
.tag.deploys-mark { margin-left: 6px; }
.tag.deploys-state.is-running, .tag.deploys-mark.is-running { background: var(--accent-soft); color: var(--accent); font-weight: 700; }
.tag.deploys-state.is-green, .tag.deploys-mark.is-green { color: var(--advice); }
.tag.deploys-state.is-red, .tag.deploys-mark.is-red { background: var(--danger-soft); color: var(--danger); font-weight: 700; }
.tag.deploys-state.is-held, .tag.deploys-mark.is-held { background: var(--warn-soft); color: var(--warn); font-weight: 700; }
.deploys-parts { margin: 0; padding: 0; list-style: none; display: flex; flex-direction: column; gap: 2px; min-width: 0; max-width: 100%; }
.deploys-part { overflow-wrap: anywhere; }
.deploys-part.is-green .deploys-part-state { color: var(--advice); }
.deploys-part.is-red, .deploys-part.is-red .deploys-part-state { color: var(--danger); }
.deploys-part.is-held .deploys-part-state { color: var(--warn); font-weight: 700; }
.deploys-part.is-running .deploys-now { color: var(--accent); font-weight: 700; }
.deploys-run { white-space: nowrap; }
/* COMMAND-1428: a project's addresses (public/project-addresses). */
.project-addresses .addresses-domain + .addresses-domain { margin-top: 10px; }
.project-addresses .addresses-domain p { margin: 0 0 4px; }
.addresses-hosts { margin: 0; padding: 0; list-style: none; display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.addresses-host { overflow-wrap: anywhere; }
.addresses-link { white-space: nowrap; }
/* The table inspector (COMMAND-1007): Stamt af van in the descends colour; Verwijst naar as Veld | Tabel. */
.chart-in-descends { margin: 0 0 8px; color: var(--chart-descends, #2e9d5b); }
.chart-refs-head, .chart-ref-line { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.4fr); gap: 8px; }
.chart-refs-head { padding: 0 0 2px; }
.chart-refs .chart-ref-line { list-style: none; padding: 2px 0; }
.chart-refs:has(> .chart-ref-line) { padding-left: 0; margin: 0 0 8px; }
/* COMMAND-969: the card chip of an opened approval or question opens its card. */
.tw-chip-open { border: 0; cursor: pointer; font: inherit; }

/* A connector's own values on its integration page (COMMAND-1082): one block for the company, one per project. */
.int-settings-block { display: grid; gap: 8px; padding: 10px 0; border-top: 1px solid var(--line, rgba(127, 127, 127, 0.2)); }
.int-settings-block:first-of-type { border-top: 0; }
.int-settings-block h3 { margin: 0; font-size: 0.95em; }
.int-setting { display: grid; gap: 4px; }
.int-setting-input { width: 100%; max-width: 520px; }
.int-settings-save { justify-self: start; }
.int-settings-add { margin-top: 8px; max-width: 320px; }

@media (min-width: 1100px) {
  :root {
    --gutter: 24px;
    --topbar-h: 52px; /* the sticky tab bar, for what sticks below it (its real height: public/topbar-height) */
  }
  /* A page that scrolls and one that does not keep the same width. */
  html { scrollbar-gutter: stable; }

  /* ----- the top: the tab bar as wide as the page ----- */
  .tabs {
    padding-left: calc(env(safe-area-inset-left) + var(--gutter) - 8px);
    padding-right: calc(env(safe-area-inset-right) + var(--gutter) - 8px);
  }
  .tab:hover:not(.active) { color: var(--text); }
  /* The tab bar with the App Launcher's dots (COMMAND-393): the row as wide as the page, the tabs the rest of it. */
  .tabs-bar { padding-left: calc(env(safe-area-inset-left) + var(--gutter) - 8px); }
  .tabs-bar > .tabs { padding-left: 0; }
  .launcher-btn { margin-left: 0; }
  /* An app's tabs (COMMAND-580): each as wide as its name from the left, as Salesforce does, never two tabs stretched
     over the whole width; the app's name has room. */
  .tabs.app-tabs .tab { flex: 0 0 auto; min-width: 88px; padding-left: 14px; padding-right: 14px; }
  .nav-app { max-width: 16em; font-size: 0.9rem; padding-right: 14px; }

  /* ----- the page ----- */
  /* Every page, every tab and every part of a tab gets the same box as the header
     and the tab bar: one width, one left edge, so nothing moves when the PO
     switches (COMMAND-43, PO, 2026-09-30: "Foto 1 is juist, maar waarom springt
     foto 2 naar het midden?????" — Gesprekken was a narrower page in the middle).
     The full width of the screen since COMMAND-486 (PO, 2026-10-10: no empty bands
     left and right): the gutter on both sides, no page narrowed to a column. */
  .view {
    padding-left: calc(env(safe-area-inset-left) + var(--gutter));
    padding-right: calc(env(safe-area-inset-right) + var(--gutter));
  }
  /* What runs on a server (COMMAND-193; its related list since COMMAND-509): the things side by side, as many as fit;
     the disks and memory side by side. */
  .related-rows-server-inventory { grid-template-columns: repeat(auto-fill, minmax(340px, 1fr)); }
  .int-inv-machine { grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); }

  /* ----- Vragen ----- */
  /* The three parts (of Vaults too): each as wide as its words, on the left. */
  .sub-tabs .seg { flex: 0 0 auto; padding: 0 18px; }

  /* An open conversation on its own page (COMMAND-549; PO, 2026-10-10: "3 fucking scrollbars"; its own page since
     COMMAND-718): ONE scroll box, its messages. The page is exactly as tall as the window under the top block (its real
     height: public/topbar-height); the sub-tabs above it keep their height; the conversation, its thread card and the
     thread panel fill the rest (the panel no longer has its own fixed, draggable height here), so the panel's head on
     top and the reply box with its buttons at the bottom stay in place and only the messages between them scroll. The
     page ends at the bottom of the screen (the utility bar is on the left since COMMAND-884). A window too low for it
     still lets the page scroll. COMMAND-717: the
     conversation is a record page (.record-message, at #message=<id> and at /threads/<uuid>): while its tab Thread is open
     (data-tab="thread") the tab's panel takes the room under the page header and the tab bar, the side column beside it
     since COMMAND-804; on Gerelateerd the page scrolls as every record page does. */
  .view:has(> .record-message[data-tab="thread"]) {
    height: calc(100vh - var(--topbar-h));
    height: calc(100dvh - var(--topbar-h));
    display: flex; flex-direction: column;
    padding-bottom: calc(env(safe-area-inset-bottom) + 20px);
  }
  .view:has(> .record-message[data-tab="thread"]) > * { flex: none; }
  .view.record-of-message > .sub-tabs { display: flex; }
  .view > .record-message[data-tab="thread"] { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; align-items: stretch; }
  .record-message[data-tab="thread"] > * { flex: none; min-width: 0; }
  .record-message[data-tab="thread"] > .record-main { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; }
  .record-message[data-tab="thread"] > .record-main > * { flex: none; }
  .record-message[data-tab="thread"] > .record-main > .record-panel { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; }
  .record-message[data-tab="thread"] > .record-main > .record-panel > .msg-thread-card { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; margin-bottom: 0; }
  .record-message[data-tab="thread"] > .record-main > .record-panel > .msg-thread-card > * { flex: none; }
  .record-message[data-tab="thread"] > .record-main > .record-panel > .msg-thread-card > .thread-panel[data-thread] { flex: 1 1 auto; height: auto; min-height: 16rem; resize: none; }
  .record-message[data-tab="thread"] > .record-main > .record-panel > .msg-thread-card > .thread-panel > .thread-history { flex: 1 1 auto; min-height: 6rem; }
  /* COMMAND-804: the side column on the right as on every record page (who works on it, its Threads box: the
     sub-threads), as tall as the conversation beside it; a long side column scrolls on its own. */
  .view > .record-message[data-tab="thread"]:has(> .record-side) {
    display: grid;
    grid-template-columns: minmax(0, 1.7fr) minmax(340px, 1fr);
    grid-template-rows: auto minmax(0, 1fr);
    grid-template-areas: "highlights highlights" "main side";
    column-gap: 16px;
  }
  .record-message[data-tab="thread"] > .record-side { order: 0; margin-top: 0; min-height: 0; overflow-y: auto; }

  /* ----- Borden, Docs and Facturen: the boxes in a grid ----- */
  .box-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(400px, 1fr));
    gap: 16px;
    align-items: start;
    margin-bottom: 12px;
  }
  .box-grid > .card { margin: 0; min-width: 0; }
  /* Projecten (COMMAND-76): a row reads across — the name, its versions and its chips on one line where they fit. */
  .project-row .fin-main { flex-direction: row; flex-wrap: wrap; align-items: center; gap: 4px 18px; }
  .project-row .fin-main > strong { flex: 0 0 220px; }

  /* ----- lists: wider rows, the buttons on the same line ----- */
  /* Credentials: the field with Opslaan beside it. Accounts: the new-PC connector address with Kopieer. */
  .view-credentials .card.cred,
  .view-ai-accounts .card.newpc {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    column-gap: 16px;
    align-items: center;
  }
  .view-credentials .card.cred > *,
  .view-ai-accounts .card.newpc > * { grid-column: 1 / -1; }
  .view-credentials .card.cred > .tag { justify-self: start; }
  /* The field and its buttons are the top of the request's thread (COMMAND-89): that part lays out the same way. */
  .view-credentials .card.cred > .thread { display: grid; grid-template-columns: minmax(0, 1fr) auto; column-gap: 16px; align-items: center; }
  .view-credentials .card.cred > .thread > * { grid-column: 1 / -1; }
  .view-credentials .card.cred > .thread > .cred-field { grid-column: 1; align-self: start; }
  .view-credentials .card.cred > .thread > .cred-actions { grid-column: 2; align-self: start; margin-top: 10px; flex-wrap: nowrap; gap: 16px; }
  .view-ai-accounts .card.newpc > .conn-url { grid-column: 1; }
  .view-ai-accounts .card.newpc > .newpc-actions { grid-column: 2; margin-top: 8px; flex-wrap: nowrap; }

  /* Accounts (COMMAND-74): the account cards side by side in the .box-grid above. Every PC's stop (the last row on the
     page for every PC, COMMAND-146, COMMAND-152) keeps its buttons on its one row. */
  .every-pc-row > .actions { flex-wrap: nowrap; }

  /* Documentatie (COMMAND-9): a page as wide as the text column; the one list (COMMAND-85) as wide too. */
  .md-page { padding: 22px 26px; }
  .version-row:hover, .tree-link:hover { border-color: var(--accent); color: var(--accent); }

  /* Facturen: the PDF itself beside the form on a wide screen (a phone opens it on its own). */
  .inv-preview { display: block; width: 100%; height: 70vh; border: 1px solid var(--line); border-radius: 10px; background: var(--surface-2); }
  /* ----- Documentatie (COMMAND-85): Confluence's two columns ----- */
  /* The search, the space switcher and the page tree a column on the left that stays in view
     (it scrolls on its own when the tree is long); the content on the right, its text at a
     reading width. The tree is always there: the bar that folds it away on a phone goes. */
  .docs-layout { display: grid; grid-template-columns: 320px minmax(0, 1fr); gap: var(--gutter); align-items: start; }
  .docs-side {
    position: sticky; top: calc(var(--topbar-h) + 12px);
    max-height: calc(100vh - var(--topbar-h) - 32px);
    overflow-y: auto; overscroll-behavior: contain;
    margin: 0; padding: 2px 4px 12px 2px;
  }
  .docs-tree-toggle { display: none; }
  .docs-tree, .docs-tree[hidden] { display: block; margin-top: 0; }
  /* The token meter (COMMAND-186 step 5): each day on one line, its summaries in a column of their own. */
  .tok-day { grid-template-columns: 9em minmax(0, 1fr) 5em 9em; grid-template-areas: 'name bar num comp'; }
  .tok-day-comp:empty { display: block; }
  .tok-stat-value { font-size: 1.6rem; }
  .escalated-badge { font-size: 0.8rem; line-height: 20px; }
}
