/* ═══════════════════════════════════════════════════════════════
   Your hospital's AI programme. Windows classic, as it looked in 2000.

   What changed and why: the previous "calm desk" stylesheet was the
   default look a language model produces (paper tones, one teal, serif
   headings, pills, soft shadows). DESIGN.md lists the tells. This file
   replaces all of it. The desk is a desktop: the programme is a tabbed
   window, the quarter's figures run as their own small program, the
   diary is a text file open in a notepad, and a taskbar with a Start
   menu sits along the bottom. Proposals are cards drawn as small
   windows, events are message boxes, decisions are dialog icons.
   Grey chrome, one-pixel-plus-one-pixel bevels, navy title bars,
   Tahoma. Nothing rounded, nothing soft.

   Content this look needed: once events became email messages, the
   third-person card text read as narration, so every event body in
   content/ was rewritten in the sender's own words, dated notices got
   an automated "Regulatory calendar" sender, and a reply may carry its
   own article chip (one line in js/engine.js). DESIGN.md allows this.

   The render code in js/ui.js and js/screens.js is untouched: every
   class it emits is restyled under its old name. index.html adds the
   title bars, client areas, the two side programs and the taskbar.
   ═══════════════════════════════════════════════════════════════ */

:root {
  --face: #c0c0c0;
  --face-light: #dfdfdf;
  --chart-bg: #000000; --chart-grid: #008040; --chart-line: #00ff00; --chart-mark: #ffff00; /* the performance-monitor graph on the review */
  --hilight: #ffffff;
  --on-fill: #ffffff; /* words on a stamp fill (badges, discs, counters): white on a light theme, black on the dark one */
  --shadow: #808080;
  --dark: #000000;
  --title-a: #0a246a;
  --title-b: #a6caf0;
  --title-text: #ffffff;
  --window: #ffffff;
  --window-text: #000000;
  --desktop: #3a6ea5;
  --select: #0a246a;
  --select-text: #ffffff;
  --gray-text: #303030;
  --disabled-text: #5a5a5a;
  --link: #0000ff;
  --info: #ffffe1;
  --stamp-green: #008000;
  --stamp-red: #c00000;
  --band-watchful: #f0c000; /* the watchful band as a fill (the review's year blocks); amber is its text colour */
  --stamp-blue: #000080;
  --stamp-amber: #b08000;
  /* The four figures' icon colours (js/ui.js RES_LABEL, C.ICONS.res): 3:1 on the window, the face and the modern surface. */
  --res-budget: #8a5a00;
  --res-capacity: #1a5fb4;
  --res-benefit: #b0125e;
  --res-trust: #6b3fb5;
  --font: Tahoma, "MS Sans Serif", Arial, "Segoe UI", sans-serif;
  --font-mono: "Courier New", Courier, monospace;
  /* Department colours: the same hex as content/meta.json departments (tests/css.test.js holds them level). Each gives
     3:1 as a dot or stripe on the light and dark surfaces and 4.5:1 under white text on the kicker bar. */
  --dept-emergency-department: #d0662f;
  --dept-acute-medicine: #cd5263;
  --dept-radiology: #677baa;
  --dept-pharmacy: #288a7c;
  --dept-nursing: #c8553d;
  --dept-outpatients: #b8860b;
  --dept-operations: #a47229;
  --dept-human-resources: #6f8a3d;
  --dept-education-and-training: #768326;
  --dept-it: #26879a;
  --dept-data-and-analytics: #3780bf;
  --dept-research: #8a6cc0;
  --dept-communications: #b9567e;
  --dept-finance: #358b60;
  --dept-governance: #8f7760;
  --dept-executive: #9d65b5;
  --dept-outside: #7b7b7b;
  --dept-staff-representatives: #bd51b4;
  --dept-patients: #7373ca;
  --action: #5b3cf5; /* programmes and one-offs: things you can do, in a colour no department has (tests/css.test.js) */
  /* The action icons' colours (js/ui.js actionIcon; .ic-action.ic-<key> below) say what pressing the button does or
     spends, from the colours that already mean it: switching on is green, stopping red, spending budget the budget's
     colour, spending your team's time capacity's, and nothing spent now ink (a trust cost shows in the dots). Each holds
     3:1 on the window, the classic face and the modern surface (tests/css.test.js). */
  --act-money: var(--res-budget); --act-staff: var(--res-capacity); --act-stop: var(--stamp-red);
  --act-wait: var(--window-text); --act-on: #0a6b0a; --act-wait-edge: var(--shadow); /* the edge of a button that spends nothing now: grey, since ink reads as chosen */
  /* The symbol language: the duty groups' tints (on duty tiles only; tests/icons.test.js keeps them apart from every
     other colour, for colour-blind eyes too) and the sizes that keep a symbol on its line. Telling and training share
     the navy that means telling; the provider's duties the amber of the provider role; paperwork is ink on white. */
  --duty-watch: #0e8fa6; --duty-watch-fill: #e3f4f7; --duty-tell: var(--stamp-blue); --duty-tell-fill: #e6e6f5;
  --duty-paper: var(--window-text); --duty-paper-fill: var(--window); --duty-provider: var(--stamp-amber); --duty-provider-fill: #f8efd6;
  --ic-inline: 16px; --sym-tile: 22px; --sym-line: 18px; /* an icon's size (.ic reads --ic, which a context sets), a duty tile's square and its picture (--sym-ic), the line a chip keeps to */
  --dept: var(--shadow);
  --target: 23px;
  --titlebar: 18px;
}
[data-dept="emergency-department"] { --dept: var(--dept-emergency-department); }
[data-dept="acute-medicine"] { --dept: var(--dept-acute-medicine); }
[data-dept="radiology"] { --dept: var(--dept-radiology); }
[data-dept="pharmacy"] { --dept: var(--dept-pharmacy); }
[data-dept="nursing"] { --dept: var(--dept-nursing); }
[data-dept="outpatients"] { --dept: var(--dept-outpatients); }
[data-dept="operations"] { --dept: var(--dept-operations); }
[data-dept="human-resources"] { --dept: var(--dept-human-resources); }
[data-dept="education-and-training"] { --dept: var(--dept-education-and-training); }
[data-dept="it"] { --dept: var(--dept-it); }
[data-dept="data-and-analytics"] { --dept: var(--dept-data-and-analytics); }
[data-dept="research"] { --dept: var(--dept-research); }
[data-dept="communications"] { --dept: var(--dept-communications); }
[data-dept="finance"] { --dept: var(--dept-finance); }
[data-dept="governance"] { --dept: var(--dept-governance); }
[data-dept="executive"] { --dept: var(--dept-executive); }
[data-dept="outside"] { --dept: var(--dept-outside); }
[data-dept="staff-representatives"] { --dept: var(--dept-staff-representatives); }
[data-dept="patients"] { --dept: var(--dept-patients); }

/* Dark is the "High Contrast Black" scheme: black face, white text, purple title bars, green selection. */
:root[data-theme="dark"] {
  --on-fill: #000000;
  --face: #000000; --face-light: #404040; --hilight: #ffffff; --shadow: #808080; --dark: #c0c0c0;
  --title-a: #800080; --title-b: #000000; --title-text: #ffffff;
  --window: #000000; --window-text: #ffffff; --desktop: #000000; --select: #008000; --select-text: #ffffff;
  --gray-text: #c0c0c0; --disabled-text: #a0a0a0; --link: #80ff80; --info: #000000;
  --stamp-green: #40ff40; --stamp-red: #ff6060; --stamp-blue: #80c0ff; --stamp-amber: #ffd040;
  --res-budget: #f0b940; --res-capacity: #78b8ff; --res-benefit: #ff7ab8; --res-trust: #c3a6ff;
  --action: #a896ff;
  --act-on: #58d058;
  --duty-watch: #3fd0e8; --duty-watch-fill: #000000; --duty-tell-fill: #000000; --duty-provider-fill: #000000;
}
@media (pointer: coarse) { :root { --target: 44px; --titlebar: 30px; } }

/* ── Base ── */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
html { font-size: 13px; }
/* The three faces beside the system font: the documents' face (a mail's body, the ledgers, the Calendar, a pitch), the
   glyph of the blue 'i' badges, and the serif of the § and quote marks. The first two are the new desktop's own face there
   (css/modern.css remaps them); the marks keep their serif on both desktops. --row-rule is the rule between the rows of a list (the AI systems, a system's duties, its story,
   the Timeline, the review's table), a hairline in the new look. On body, not :root, so the themes compose. */
/* The raised panel (a button, a tab, a card, the Start menu), the window frame, the sunken field (a list box, a text field, a
   pressed button), the bar that folds something (a sheet's fold bar, a branch bar), the box it opens into (a group box, a fold's
   body) and the pressed bar as components: their face, their four-colour
   edge, their inset bevel and their corner, named once here and set once more by the new look (css/modern.css: a flat layer, a
   hairline, no bevel, a rounded corner). On body, not :root, so higher contrast (which sets --shadow on body) and the dark theme
   (from :root) compose. */
body { --raised-bg: var(--face); --raised-edge: var(--hilight) var(--dark) var(--dark) var(--hilight); --raised-shadow: inset -1px -1px var(--shadow), inset 1px 1px var(--face-light); --raised-radius: 0;
  --frame-bg: var(--face); --frame-edge: var(--face-light) var(--dark) var(--dark) var(--face-light); --frame-shadow: inset -1px -1px var(--shadow), inset 1px 1px var(--hilight); --frame-radius: 0;
  --field-edge: var(--shadow) var(--hilight) var(--hilight) var(--shadow); --field-shadow: inset 1px 1px var(--dark), inset -1px -1px var(--face-light); --field-radius: 0;
  --bar-bg: var(--raised-bg); --bar-edge: var(--raised-edge); --bar-shadow: var(--raised-shadow); --bar-radius: var(--raised-radius);
  --box-bg: var(--face); --box-edge: var(--shadow); --box-shadow: inset 1px 1px var(--hilight), 1px 1px var(--hilight); --box-radius: 0;
  --pressed-edge: var(--dark) var(--hilight) var(--hilight) var(--dark); --pressed-shadow: inset 1px 1px var(--shadow);
  --row-rule: 1px dotted var(--face); --font-doc: Arial, Helvetica, sans-serif; --font-glyph: Georgia, serif; --font-serif: Georgia, "Times New Roman", serif; font-family: var(--font); font-size: 1rem; line-height: 1.4; background: var(--desktop); color: var(--window-text); min-height: 100dvh; overflow-x: hidden; }
html:has(body.ui-large-text) { font-size: 15px; } /* Larger text grows the root, so everything sized in rem grows with it, paragraphs included */
body.high-contrast { --gray-text: var(--window-text); --shadow: var(--dark); --face-light: var(--hilight); --res-budget: var(--window-text); --res-capacity: var(--window-text); --res-benefit: var(--window-text); --res-trust: var(--window-text); }
h1, h2, h3, .sheet-title { font-family: var(--font); font-weight: 700; line-height: 1.25; }
h1 { font-size: 1.5rem; } h2 { font-size: 1.15rem; } h3 { font-size: 1rem; margin: 10px 0 4px; }
p { margin-bottom: 0.7em; }
button { font: inherit; color: inherit; background: none; border: none; cursor: default; }
a { color: var(--link); }
.hidden { display: none !important; }
.hint { color: var(--gray-text); font-size: 0.92rem; }
.small { font-size: 0.9rem; }
.badge { color: var(--gray-text); font-size: 0.85rem; margin-top: 12px; }
.build-line { font-size: 0.8rem; color: var(--window-text); opacity: 0.7; margin: 4px 0 0; overflow-wrap: anywhere; }
.prose p { color: var(--window-text); }
.scene { font-size: 1rem; color: var(--window-text); }
.mono { font-family: var(--font-mono); }
*:focus-visible { outline: 1px dotted var(--window-text); outline-offset: -4px; }
input, select { font: inherit; color: var(--window-text); background: var(--window); padding: 2px 4px; min-height: var(--target); }
input[type="checkbox"], input[type="radio"] { min-height: 0; width: 13px; height: 13px; margin-right: 6px; }
/* An option button (New game's list): on the old desktop a round sunken well, with a dot once chosen */
input[type="radio"] { -webkit-appearance: none; appearance: none; padding: 0; border: 0; border-radius: 50%; background: var(--window); box-shadow: inset 1px 1px var(--shadow), inset -1px -1px var(--hilight), inset 2px 2px var(--dark), inset -2px -2px var(--face-light); }
input[type="radio"]:checked { background: radial-gradient(circle closest-side, var(--window-text) 0 32%, transparent 38%) var(--window); }

/* ── Bevels: one pixel outside, one pixel inside, the way Win95 drew them ── */
.btn, .choice, .folder-tab, .drawer-tab, .task-btn, .start-btn, .folder-panel, .turn-banner, .air-pill, .more-menu, .menu-sub, .doc, .btn-small,
.close-btn, .caption-btn, .status .air, .prog-tile, .pitch-from button.person, .ending-splash.ending-classic .splash {
  border: 1px solid; border-color: var(--raised-edge); box-shadow: var(--raised-shadow); background: var(--raised-bg); border-radius: var(--raised-radius);
}
.win, .sheet, .drawer-panel, .taskbar, .prog-node {
  border: 1px solid; border-color: var(--frame-edge); box-shadow: var(--frame-shadow); background: var(--frame-bg); border-radius: var(--frame-radius);
}
.mg-field, .mg-readout, .mg-meter, .mg-art, .mg-install, .mg-pip, .mg-score-bar, .pane, .register, .timeline, .story, .log-peek, .drawer-body, .num, .trust, .leaf, .trust-bar-wrap, .controls, .file, .ledger-wrap, .notice, .surcharge, .review-cell, .ledger-q, .metric-chip, .cast-list, .cast-folders, .choice.chosen, .choice:active, .btn:active, .task-btn[aria-pressed="true"], .task-btn:active, .start-btn[aria-expanded="true"],
input, select, .new-game-list, .msg-body, #event-result.outcome, .calendar, .sheet-pitch, .file dd, .about-body, .handbook-nav, .soon-parts li::before {
  border: 1px solid; border-color: var(--field-edge); box-shadow: var(--field-shadow); border-radius: var(--field-radius);
}
/* A pressed button is sunken but keeps the shape it had raised */
.choice.chosen, .choice:active, .btn:active, .task-btn[aria-pressed="true"], .task-btn:active, .start-btn[aria-expanded="true"] { border-radius: var(--raised-radius); }
.pane, .register, .timeline, .story, .log-peek, .drawer-body, .controls, .ledger-wrap, .review-cell, .metric-chip, .cast-list, .cast-folders { background: var(--window); color: var(--window-text); }

/* ── Screens (prototype pattern kept: stacked fixed layers, cross-fade) ── */
.screen { position: fixed; inset: 0; display: flex; flex-direction: column; min-height: 100dvh; transition: opacity 0.2s; overflow: auto; scroll-padding-top: 12px; }
.screen.hidden { display: flex !important; opacity: 0; pointer-events: none; }
.screen.hidden * { pointer-events: none !important; }
.screen:focus-visible { outline: none; } /* focused with tabindex -1 only to seat the next Tab in it (focusScreen) */
.transition-overlay { position: fixed; inset: 0; background: var(--desktop); opacity: 0; pointer-events: none; transition: opacity 0.2s; z-index: 90; }
.transition-overlay.active { opacity: 1; pointer-events: auto; }

/* ── Windows ── */
.win, .sheet { position: relative; padding: 2px; }
.titlebar { display: flex; align-items: center; gap: 5px; height: var(--titlebar); padding: 0 2px 0 5px; background: linear-gradient(90deg, var(--title-a), var(--title-b)); color: var(--title-text); font-weight: 700; font-size: 0.95rem; user-select: none; }
.titlebar-icon { font-size: 0.9rem; line-height: 1; width: 14px; text-align: center; }
.titlebar-text { flex: 1; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.titlebar-text h2 { display: inline; font: inherit; }
.close-btn { position: static; width: 16px; height: 14px; min-width: 0; min-height: 0; line-height: 1; font-size: 12px; font-weight: 700; color: var(--dark); padding: 0 0 1px; margin-left: 2px; flex: none; }
.close-btn:active { border-color: var(--dark) var(--hilight) var(--hilight) var(--dark); box-shadow: none; }
@media (pointer: coarse) { .close-btn { width: 32px; height: 26px; font-size: 16px; } }
/* A window's own caption button beside its close button (the mini game window's sound): the close button's bevel.
   On a touch screen it keeps a gap from the close button (Skip), so a slip never throws the game away. */
.caption-btn { position: static; display: inline-flex; align-items: center; justify-content: center; width: 16px; height: 14px; min-width: 0; min-height: 0; padding: 0; margin-left: 2px; color: var(--dark); flex: none; cursor: pointer; }
.caption-btn:active { border-color: var(--dark) var(--hilight) var(--hilight) var(--dark); box-shadow: none; }
.caption-btn .audio-glyph { width: 10px; height: 9px; }
@media (pointer: coarse) { .caption-btn { width: 32px; height: 26px; margin-right: 8px; } .caption-btn .audio-glyph { width: 14px; height: 12px; } }
.client { padding: 10px 10px 10px; }
.sheet-meta { display: flex; justify-content: space-between; gap: 12px; font-size: 0.9rem; color: var(--gray-text); margin-bottom: 6px; flex-wrap: wrap; }
.sheet-meta > span:first-child { color: var(--window-text); }
.sheet-meta > span:first-child:not(:empty)::before { content: ''; display: inline-block; width: 9px; height: 9px; background: var(--dept); border: 1px solid var(--dark); margin-right: 6px; vertical-align: -1px; }
.sheet-title { font-size: 1.15rem; margin: 2px 0 8px; }

/* ── Buttons: 23px, one line, centred, the default one ringed in black ── */
.btn { min-height: var(--target); min-width: 75px; padding: 1px 12px; font-size: 1rem; color: var(--window-text); text-align: center; line-height: 1.3; white-space: nowrap; }
.btn:active { padding: 2px 11px 0 13px; }
.btn-primary { font-weight: 700; outline: 1px solid var(--dark); outline-offset: 0; position: relative; }
.btn-primary:focus-visible { outline: 1px solid var(--dark); }
/* The old desktop's ornaments (the dotted focus frame, the Start menu's rule and caret, the address book's folder tree and legend, the Reference
   tree's line, the tip's tail, the Options colon, About's band) are drawn under body:not([data-os="modern"]), so the new desktop has nothing to cancel */
body:not([data-os="modern"]) .btn-primary:focus-visible::before { content: ''; position: absolute; inset: 3px; border: 1px dotted var(--window-text); pointer-events: none; }
.btn-danger { color: var(--stamp-red); }
.btn[disabled] { color: var(--disabled-text); cursor: not-allowed; }
.btn[disabled]:active { padding: 1px 12px; border-color: var(--hilight) var(--dark) var(--dark) var(--hilight); box-shadow: inset -1px -1px var(--shadow), inset 1px 1px var(--face-light); }
.btn small { display: inline; font-weight: 400; font-size: 0.85rem; color: var(--gray-text); margin-left: 8px; }
.btn[disabled] small { color: inherit; }
.btn-small { min-height: 21px; min-width: 0; padding: 0 9px; font-size: 0.92rem; }
.link-btn { background: none; border: 0; padding: 0; font: inherit; color: var(--link); text-decoration: underline; cursor: pointer; min-height: var(--target); } /* reads as one of the links beside it (Copy details on the review) */
.actions { display: flex; flex-wrap: wrap; gap: 6px; justify-content: flex-end; margin: 12px 0 4px; }
.actions .btn { white-space: normal; }
.actions .btn-primary { order: -1; }
#sys-actions, #prog-actions, #iv-actions { display: grid; grid-template-columns: 1fr; gap: 4px; }
#sys-actions .btn, #prog-actions .btn, #iv-actions .btn { display: grid; grid-template-columns: 110px 1fr; gap: 8px; align-items: baseline; text-align: left; padding: 4px 10px; min-width: 0; }
#sys-actions .btn small, #prog-actions .btn small, #iv-actions .btn small { margin-left: 0; }
/* The proposal sheet's buttons carry only their title; the dots beneath say which resources move (hover lights them). */
#sys-actions { grid-template-columns: repeat(auto-fit, minmax(82px, 1fr)); }
#sys-actions .btn { display: flex; flex-direction: column; align-items: center; justify-content: flex-start; text-align: center; gap: 2px; padding: 6px 6px; }
#sys-actions .btn .res-dots { margin-top: 0; justify-content: center; gap: 6px; }
#sys-actions .btn .btn-label { line-height: 1.2; }
/* The proposal's buttons are tiles: the action's picture on top, big enough to find at a glance. */
#sys-actions .btn .lead-ic .ic { display: block; --ic: 22px; margin: 0 auto 3px; }

/* Action buttons (the proposal's tiles, a programme's sizes and stop, a one-off's Do it, a control's Fund) keep the
   desktop's own button face. What tells them apart is the period's disabled look: on the old desktop, etched text (grey
   with a white shadow below right) and a grey icon; on the new one, the pale fill, text and border of its disabled
   buttons (css/modern.css), and the AI systems rows' own buttons (.reg-act) follow them. A button that can be pressed shows its action's icon in its family's colour (--act, set
   per key under Icons below; the action colour where a button has no key). */
/* An action button is .act-btn wherever it is built (actionButton in js/views.js, a programme's size, the Staff handbook's key); :not(#_)
   gives the class an id's weight, the weight the lists of sites had, so a disabled button's picture and dot stay grey under the rules below */
.act-btn:not(#_):not([disabled]):not(.btn-primary) .ic-action { color: var(--act); }
body:not([data-os="modern"]) .act-btn:not(#_).btn-primary:not([disabled]) .ic-action { color: var(--act); }
body:not([data-os="modern"]) .act-btn:not(#_):not(.chosen)[disabled],
body:not([data-os="modern"]) .act-btn:not(#_):not(.chosen)[disabled] :is(small, span, strong) { color: var(--shadow); text-shadow: 1px 1px var(--hilight); opacity: 1; }
:root[data-theme="dark"] body:not([data-os="modern"]) .act-btn:not(#_):not(.chosen)[disabled],
:root[data-theme="dark"] body:not([data-os="modern"]) .act-btn:not(#_):not(.chosen)[disabled] :is(small, span, strong) { color: var(--disabled-text); text-shadow: none; }
.act-btn:not(#_)[disabled] .ic,
.act-btn:not(#_)[disabled] .res-dot::after { color: var(--disabled-text); }
#sys-actions .btn:active, #prog-actions .btn:active, #iv-actions .btn:active { padding: 5px 9px 3px 11px; }
/* A sheet's action buttons (the .actions row of the proposal, programme and one-off sheets) carry their family's colour
   as an edge along the top (the owner's call of 2026-10-25), kept while pressed; a locked or disabled one lies flat and
   dotted, as a locked programme does (its rule, with .prog-node.is-locked) */
.actions > .act-btn:not(#_):not([disabled]) { box-shadow: inset 0 3px var(--act-edge), var(--raised-shadow); }
.actions > .act-btn:not(#_):not([disabled]):active { box-shadow: inset 0 3px var(--act-edge), var(--field-shadow); }
.report-wrap .actions { justify-content: flex-start; }

/* ── Menu ── */
#screen-menu { align-items: center; justify-content: flex-start; padding: 24px 12px; }
.menu-wrap { position: relative; z-index: 1; max-width: 640px; width: 100%; margin: auto 0; } /* above the logon's asset tag */
.menu-title { font-size: 1.5rem; margin-bottom: 4px; }
.menu-intro { margin-bottom: 4px; }
.menu-buttons { display: flex; flex-wrap: wrap; gap: 6px; margin: 6px 0 12px; }
/* The logon's buttons sit at the bottom right, as a dialog's do, the main one first. The first-launch balloon is the
   row under them, pointing up at the main button (.logon-main lets it into the grid; inline-size containment keeps
   its words from widening the buttons' columns). On a phone the row is a column and the balloon follows its button. */
.logon-buttons { display: grid; grid-template-columns: repeat(4, auto); justify-content: end; gap: 6px; margin: 12px 0 8px; }
.logon-main { display: contents; }
.logon-balloon { grid-row: 2; grid-column: 1 / -1; contain: inline-size; position: relative; margin-top: 10px; padding: 7px 30px 8px 32px; text-align: left; font-size: 0.92rem; background: var(--info); color: var(--window-text); border: 1px solid var(--window-text); border-radius: 6px; box-shadow: 2px 2px 0 rgba(0, 0, 0, 0.25); } /* the replies' balloon (.word-body) */
.logon-balloon > strong { display: block; }
.logon-balloon-i { position: absolute; left: 8px; top: 8px; width: 16px; height: 16px; border-radius: 50%; background: var(--select); color: var(--select-text); font: 700 0.8rem/16px var(--font-serif); text-align: center; }
.logon-balloon-x { position: absolute; top: 1px; right: 1px; width: 24px; height: 24px; line-height: 1; font-size: 1rem; }
.logon-balloon-x:hover { color: var(--select); }
body:not([data-os="modern"]) .logon-balloon::after { content: ''; position: absolute; left: 22px; top: -11px; border: 11px solid transparent; border-top: 0; border-bottom-color: var(--window-text); }
body:not([data-os="modern"]) .logon-balloon::before { content: ''; position: absolute; left: 23px; top: -9px; z-index: 1; border: 10px solid transparent; border-top: 0; border-bottom-color: var(--info); }
.logon-saved { margin: 0 0 8px; text-align: right; }
/* New game: the kinds of game in a sunken list, a choice per row, the practice copy's line under it when it is not one */
.new-game-list { margin: 8px 0 6px; background: var(--window); color: var(--window-text); }
.new-game-item { display: flex; align-items: flex-start; gap: 4px; padding: 7px 10px; }
.new-game-item + .new-game-item { border-top: var(--row-rule); }
.new-game-item > input { flex: none; margin-top: 4px; }
.new-game-text { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.new-game-when { color: var(--select); font-weight: 700; font-size: 0.92rem; }
:root[data-theme="dark"] .new-game-when { color: var(--link); }
.new-game-line { color: var(--gray-text); font-size: 0.9rem; line-height: 1.35; }
.new-game-refresher { margin: 2px 0 6px; }
.new-game-refresher .link-btn { min-height: 0; font-size: inherit; }
.menu-seed { margin: 6px 0 12px; font-size: 0.92rem; color: var(--gray-text); }
.menu-seed summary { cursor: default; color: var(--window-text); }
.menu-seed label { display: block; margin-top: 6px; }
.menu-seed input { width: 100%; }

/* ── Desktop: two columns of windows ── */
.desk { position: relative; z-index: 1; max-width: 1280px; width: 100%; margin: 0 auto; padding: 14px 14px 60px; display: grid; grid-template-columns: 240px minmax(0, 1fr) 260px; gap: 14px; align-items: start; }
.desk-col { display: flex; flex-direction: column; gap: 14px; min-width: 0; }
.desk-left, .desk-side { position: sticky; top: 14px; }
.desk-left { z-index: 2; } /* a sticky column is a stacking context: the course's notice, fixed inside this one, must sit above the folder column drawn after it */
/* The middle column fits the screen above the taskbar: Status stays put and the folder's
   cards scroll inside it, under the tabs. Phones (one column) and very short screens scroll the page. */
@media (min-width: 861px) and (min-height: 521px) {
  .desk-main { position: sticky; top: 14px; max-height: calc(100dvh - 74px); }
  .folder, .folder > .client { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; } /* the folder and its client both fill the column and stack what they hold */
  /* The tab's toolbar stays put at the top of the panel; only the body under it scrolls. */
  .folder .folder-panel { flex: 1 1 auto; min-height: 0; overflow: hidden; }
  .folder .folder-body { flex: 1 1 auto; min-height: 0; overflow: auto; }
}
/* The left column fits the screen too, where it is a column of its own (three columns): the diary takes its usual
   height when it has the room and gives way to the planner above it, so opening a window never makes the desk scroll
   (a desk that can scroll jumps when a window opens or the AI programme button is pressed). */
@media (min-width: 1001px) and (min-height: 521px) {
  .desk-left { max-height: calc(100dvh - 74px); }
  .desk-left .notepad { flex: 0 1 auto; min-height: 0; display: flex; flex-direction: column; }
  .desk-left .notepad > .client { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; }
  .desk-left .log-peek { height: auto; min-height: 80px; flex: 0 1 60vh; }
}
/* A drawn scroll bar in the old desktop's style wherever the game scrolls inside a window (the folder, a sheet, the
 lower boxes of a proposal, a long card), so the player can see there is more: bevelled arrow buttons and thumb (the window bevel), on the dotted track. The modern look has its own. */
/* The classic scroll bar, wherever the game scrolls inside a window; the list is written once and nested (CSS nesting,
   Chrome 120, Safari 17.2, Firefox 117 and later; older browsers show their own bars). The dark theme swaps the arrows. */
body:not([data-os="modern"]) :is(.folder .folder-body, #modal-system > .sheet > .client, #modal-programme > .sheet > .client, #modal-intervention > .sheet > .client, #event-sheet .msg-body, .cast-list, .drawer-body, #modal-qmail .qmail-body, #timeline-list) {
  --sb-up: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='7' height='4'%3E%3Cpath d='M3 0h1v1h1v1h1v1h1v1H0V3h1V2h1V1h1z' fill='black'/%3E%3C/svg%3E"); --sb-down: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='7' height='4'%3E%3Cpath d='M0 0h7v1H6v1H5v1H4v1H3V3H2V2H1V1H0z' fill='black'/%3E%3C/svg%3E");
  &::-webkit-scrollbar { width: 16px; }
  &::-webkit-scrollbar-track { background-image: repeating-conic-gradient(var(--hilight) 0 25%, var(--face) 0 50%); background-size: 2px 2px; }
  &::-webkit-scrollbar-thumb,
  &::-webkit-scrollbar-button:vertical:start:decrement,
  &::-webkit-scrollbar-button:vertical:end:increment { background-color: var(--face); box-shadow: inset -1px -1px var(--dark), inset 1px 1px var(--face-light), inset -2px -2px var(--shadow), inset 2px 2px var(--hilight); }
  &::-webkit-scrollbar-button:vertical:start:decrement,
  &::-webkit-scrollbar-button:vertical:end:increment { display: block; height: 16px; background-repeat: no-repeat; background-position: 4px 6px; }
  &::-webkit-scrollbar-button:vertical:start:decrement { background-image: var(--sb-up); }
  &::-webkit-scrollbar-button:vertical:end:increment { background-image: var(--sb-down); }
  &::-webkit-scrollbar-button:vertical:start:decrement:active,
  &::-webkit-scrollbar-button:vertical:end:increment:active { box-shadow: inset 1px 1px var(--shadow), inset -1px -1px var(--shadow); background-position: 5px 7px; }
  &::-webkit-scrollbar-button:vertical:start:increment,
  &::-webkit-scrollbar-button:vertical:end:decrement { display: none; }
}
:root[data-theme="dark"] body:not([data-os="modern"]) :is(.folder .folder-body, #modal-system > .sheet > .client, #modal-programme > .sheet > .client, #modal-intervention > .sheet > .client, #event-sheet .msg-body, .cast-list, .drawer-body, #modal-qmail .qmail-body, #timeline-list) { --sb-up: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='7' height='4'%3E%3Cpath d='M3 0h1v1h1v1h1v1h1v1H0V3h1V2h1V1h1z' fill='white'/%3E%3C/svg%3E"); --sb-down: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='7' height='4'%3E%3Cpath d='M0 0h7v1H6v1H5v1H4v1H3V3H2V2H1V1H0z' fill='white'/%3E%3C/svg%3E"); }
.desk-section > .client { padding: 8px 8px 8px; }
.count-soft { font-weight: 400; color: var(--gray-text); }
.empty-note { color: var(--gray-text); padding: 10px 8px; }

/* The Calendar: the quarter, the date and the month */
.quarter .client, .folder-body, .mg .client { display: flex; flex-direction: column; gap: 8px; } /* the Calendar's client, a tab's body (folder-body, below) and a mini game's client stack their parts the same way */
.leaf { display: flex; flex-direction: column; padding: 6px 10px; line-height: 1.2; background: var(--window); }
.leaf-period { font-weight: 700; font-size: 1.3rem; }
.leaf-turn { font-size: 0.9rem; color: var(--gray-text); }
.leaf-turn #turn-date { color: var(--window-text); }
/* Status: the figures, trust and End quarter in one row, always on the desk (it cannot be minimised); In the air on a
   row of its own under them while something is in the air, and what was said along the bottom (the owner's calls of
   2026-10-14) */
.status > .client { display: flex; flex-direction: column; gap: 8px; --say-col: 18px; } /* the column the speakers' pictures stand in (.portrait.sm), which every balloon starts after */
.status-row { display: flex; flex-wrap: wrap; gap: 6px; align-items: stretch; } /* one row on a wide desk; trust and End quarter wrap under the figures when narrow */
.status-row .numbers { flex: 3 1 260px; }
.status-row .trust { flex: 2 1 190px; justify-content: center; }
.numbers { display: grid; grid-template-columns: repeat(3, 1fr); gap: 6px; }
.num { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 1px; padding: 5px 4px; line-height: 1.1; background: var(--window); text-align: center; }
.num strong { font-size: 1.25rem; font-weight: 700; font-variant-numeric: tabular-nums; }
.num strong small { font-size: 0.85rem; color: var(--gray-text); font-weight: 400; }
.num > span { font-size: 0.85rem; color: var(--gray-text); } /* the labels; the number's own span (capacity) keeps the number's size */
.trust { position: relative; display: flex; flex-direction: column; gap: 4px; padding: 6px 10px; background: var(--window); }
.trust-label { display: flex; gap: 5px; align-items: baseline; font-size: 0.85rem; color: var(--gray-text); line-height: 1.1; }
.trust-label strong { color: var(--window-text); font-size: 1.1rem; }
.trust-label em { font-style: normal; }
.trust-bar-wrap { height: 12px; background: var(--window); overflow: hidden; }
#trust-bar { height: 100%; background: var(--stamp-green); transition: width 0.3s, background 0.3s; background-image: repeating-linear-gradient(90deg, transparent 0 8px, var(--window) 8px 10px); }
#trust-bar.band-watchful { background-color: var(--stamp-amber); }
#trust-bar.band-shaken { background-color: var(--stamp-red); animation: trustPulse 1.2s steps(2, end) infinite; }
.trust.band-steady .trust-label strong { color: var(--stamp-green); }
.trust.band-watchful .trust-label strong { color: var(--stamp-amber); }
.trust.band-shaken .trust-label strong { color: var(--stamp-red); }
@keyframes trustPulse { 0%,100% { opacity: 1; } 50% { opacity: 0.4; } }
.end-btn { width: 100%; min-height: calc(var(--target) + 4px); margin-top: 2px; }
/* End quarter ends the figures row, as tall as the figures and as wide as its words; a narrow Status wraps it, with
   trust, under the figures */
.status-row .end-btn { flex: 0 0 auto; width: auto; min-width: 0; margin: 0; padding: 4px 12px; white-space: nowrap; align-self: stretch; }
.news-tag { display: inline-flex; align-items: center; gap: 3px; margin-left: 3px; padding: 0 5px; border: 1px solid var(--shadow); font-size: 0.78rem; white-space: nowrap; }
.news-tag .ic { --ic: 12px; }
/* What just happened (tell in js/screens.js): the last three consequences of the player's actions, newest on top.
   Each is a speech balloon from whoever spoke, its tail at their picture, in the tooltip's yellow; a consequence with
   no one speaking has the balloon without the tail. Inside, two lines: who or what, with a tag and a mood chip, then
   the reply or the consequence. */
.status-news { list-style: none; display: flex; flex-direction: column; gap: 6px; margin: 0; padding: 0; line-height: 1.3; }
.news-item { display: flex; gap: 8px; align-items: flex-start; }
.news-item.older { font-size: 0.86em; opacity: 0.7; }
.news-mark { flex: none; width: var(--say-col); text-align: center; padding-top: 6px; color: var(--action); }
.news-item.refused .news-mark { color: var(--stamp-red); font-weight: 700; }
.news-more { margin-left: auto; font-size: 0.8rem; min-height: 0; padding: 0 2px; line-height: 1.3; }
.word-portrait { flex: none; width: var(--say-col); padding-top: 6px; }
.word-body { position: relative; flex: 1 1 auto; min-width: 0; padding: 4px 10px 5px; background: var(--info); color: var(--window-text); border: 1px solid var(--window-text); border-radius: 6px; box-shadow: 2px 2px 0 rgba(0, 0, 0, 0.25); margin-left: 6px; } /* the left margin is room for the tail, so every balloon starts at the same place, tail or none */
.word-portrait + .word-body::before { content: ''; position: absolute; left: -7px; top: 12px; width: 10px; height: 10px; background: inherit; border-left: 1px solid var(--window-text); border-bottom: 1px solid var(--window-text); transform: rotate(45deg); }
.word-head { display: flex; flex-wrap: wrap; align-items: baseline; column-gap: 5px; font-size: 0.82rem; color: var(--gray-text); }
.word-head strong { color: var(--window-text); }
.news-item.refused .news-tag { color: var(--stamp-red); border-color: var(--stamp-red); }
.word-head .mood-chip { margin: 0; }
.word-text { margin: 0; font-size: 0.95rem; }
.word-text.quote { font-style: italic; }
.word-sub { margin: 2px 0 0; font-size: 0.85rem; color: var(--gray-text); } /* the law under the reply (noteLine in js/screens.js) */
.num.lit, .trust.lit, .res-chip.lit { outline: 2px dotted var(--stamp-green); outline-offset: 1px; }
.num.lit-down, .trust.lit-down, .res-chip.lit-down { outline-color: var(--stamp-red); }
.res-chip.lit-mixed { outline: 2px dotted var(--stamp-amber); outline-offset: 1px; }
.res-chip.lit-kept { outline: 2px dotted var(--gray-text); outline-offset: 1px; }
.res-chip.lit-unknown { outline: 2px dashed var(--gray-text); outline-offset: 1px; }
#turn-date.ticked { animation: dateFlash 0.9s steps(2, end); }
@keyframes dateFlash { 0% { color: var(--stamp-blue); font-weight: 700; } 100% { color: inherit; } }

/* The diary: a text file in a notepad */
.menubar { display: flex; flex-wrap: wrap; gap: 2px; padding: 1px 2px; font-size: 0.95rem; border-bottom: 1px solid var(--shadow); box-shadow: 0 1px var(--hilight); margin-bottom: 2px; }
.menubar span { padding: 1px 6px; color: var(--disabled-text); }
.menubar-btn { padding: 1px 6px; color: var(--window-text); text-decoration: none; min-height: var(--target); white-space: nowrap; }
.menubar-btn:hover, .menubar-btn:focus-visible, .more-menu button:hover, .more-menu button:focus-visible { background: var(--select); color: var(--select-text); outline: none; } /* the menu bar's and the Start menu's highlight */
.notepad .client { padding: 2px; }
.log-peek { list-style: none; color: var(--window-text); font-family: var(--font-mono); font-size: 0.9rem; padding: 4px 6px; height: 60vh; min-height: 200px; overflow: auto; line-height: 1.35; }
.log-peek li { padding: 1px 0; }

/* ── The Year planner and the run strip: a year as four of the old desktop's progress bars ── */
/* Engine.runProgress through the run strip of js/views.js. The planner on the desk shows the year; the same strip
   over the ledger and the timeline shows every year of the run (run-all). A bar fills in blocks as the quarter runs;
   a pennant over a bar says a date of the Act applies from that quarter (grey once that quarter is behind). */
.planner .client, .options-body .opt-rows { display: flex; flex-direction: column; gap: 2px; } /* the planner's client and an Options group's rows: a tight stack */
.planner .link-btn { align-self: flex-start; }
#planner-body { cursor: pointer; }
.run-strip { display: flex; flex-direction: column; gap: 6px; }
.run-years { display: flex; flex-wrap: wrap; gap: 6px 10px; }
.run-yr { flex: 1 1 100%; min-width: 0; }
.run-all .run-yr { flex: 1 1 70px; max-width: 150px; } /* seven years fit one row of the timeline's sheet; a phone wraps them */
.run-cells { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 3px; }
.run-all .run-cells { gap: 2px; }
.run-cell { position: relative; display: flex; flex-direction: column; gap: 1px; padding-top: 11px; min-width: 0; }
.run-bar { position: relative; display: block; height: 16px; background: var(--window); border: 1px solid; border-color: var(--shadow) var(--hilight) var(--hilight) var(--shadow); box-shadow: inset 1px 1px var(--dark); }
.run-all .run-bar { height: 12px; }
.run-fill { position: absolute; left: 2px; top: 2px; bottom: 1px; width: calc((100% - 3px) * var(--run-fill, 0)); background: repeating-linear-gradient(90deg, var(--select) 0 6px, transparent 6px 8px); }
.run-all .run-fill { background: var(--select); }
.run-cell.is-before .run-bar { background-image: repeating-conic-gradient(var(--hilight) 0 25%, var(--face) 0 50%); background-size: 2px 2px; box-shadow: none; }
.run-cell.is-now .run-bar { outline: 1px dotted var(--window-text); outline-offset: 1px; }
.run-flag { position: absolute; top: -3px; left: calc(50% - 4px); font: 700 11px/1 var(--font-serif); color: var(--stamp-blue); } /* a quarter with a date of the Act: the § of the symbol language (amber stays for risk) */
.run-cell.is-past .run-flag { color: var(--shadow); }
.run-q { font-size: 0.8rem; line-height: 1.2; text-align: center; color: var(--gray-text); }
.run-cell.is-now .run-q { color: var(--window-text); font-weight: 700; }
.run-all .run-q { display: none; }
.run-yr-label { font-size: 0.85rem; line-height: 1.3; text-align: center; color: var(--gray-text); }
.run-yr.is-current .run-yr-label { color: var(--window-text); font-weight: 700; }
.run-lines { display: flex; flex-direction: column; gap: 1px; font-size: 0.92rem; line-height: 1.3; }
.run-position { font-weight: 700; }
.run-next-head, .run-january { color: var(--gray-text); }
.run-next-list { list-style: none; }
.run-next-list li { padding-left: 10px; text-indent: -10px; }
.run-next-list li::before { content: '\00a7\00a0'; color: var(--stamp-blue); font-family: var(--font-serif); font-weight: 700; } /* a date in the Act: § */
#timeline-run { margin-bottom: 8px; }
/* The timeline keeps to the screen: its note, the run strip and the foot line stay put and the list of dates scrolls inside */
#modal-timeline > .sheet > .client { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; }
#modal-timeline > .sheet > .client > * { flex: none; }
#modal-timeline #timeline-list, #modal-system > .sheet > .client, #modal-programme > .sheet > .client, #modal-intervention > .sheet > .client { flex: 1 1 auto; min-height: 0; overflow: auto; } /* the part that scrolls inside a window that fits the screen: the Timeline's list, the proposal's, programme's and one-off's client (their sheets, below) */
/* The whole run in a window of its own under the yearly ledger (renderEvent in js/screens.js): the two are centred
   together as a lone message is, and the ledger gives up some height so both are in view. Years only: no lines. */
#event-planner { width: 100%; max-width: 760px; margin: 10px 0 auto; flex: none; }
.ledger-planner > .client { padding: 6px 10px 8px; }
#event-sheet.is-ledger { margin-bottom: 0; max-height: calc(100dvh - var(--event-pad-y, 40px) - 110px); }
#event-sheet.is-ledger:has(+ #event-planner.tutorial-hidden) { margin-bottom: auto; max-height: calc(100dvh - var(--event-pad-y, 40px)); } /* the course hides the planner until its step: the ledger is a lone card then, centred as one (the owner, 2026-10-26) */

/* Taskbar: Start, then the running programs */
.taskbar { position: fixed; left: 0; right: 0; bottom: 0; z-index: 5; display: flex; align-items: center; gap: 3px; padding: 3px 2px max(2px, env(safe-area-inset-bottom)); border-left: none; border-right: none; border-bottom: none; box-shadow: inset 0 1px var(--hilight); min-height: 30px; }
.start-btn { font-weight: 700; padding: 1px 8px 1px 6px; min-width: 0; min-height: var(--target); display: inline-flex; align-items: center; gap: 5px; }
.start-btn:active { padding: 2px 7px 0 7px; } /* the same width as at rest (.btn:active is wider), so the taskbar does not shift */
.start-btn::before { content: ''; display: inline-block; width: 14px; height: 12px; background: linear-gradient(90deg, #ff0000 50%, #00a000 50%) top / 100% 50% no-repeat, linear-gradient(90deg, #0000ff 50%, #ffff00 50%) bottom / 100% 50% no-repeat; border: 1px solid var(--dark); }
.task-btn { display: inline-flex; align-items: center; gap: 5px; min-height: var(--target); min-width: 120px; padding: 1px 8px; color: var(--window-text); text-decoration: none; font-size: 1rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* A program on the desk has its button pressed: a window that is open (aria-pressed), and the AI programme, which is
   always open and is a link to its window, not a toggle ([href]). */
.task-btn[aria-pressed="true"] { font-weight: 700; background-image: repeating-conic-gradient(var(--hilight) 0 25%, var(--face) 0 50%); background-size: 2px 2px; }
body:not([data-os="modern"]) .taskbar::after { content: ''; margin-left: auto; }
/* A minimised program: its window leaves the desk, the column stays */
.desk-section.minimised { display: none; }
.taskbar .more-wrap { position: relative; }

/* Start menu */
.more-menu { position: absolute; left: 0; bottom: calc(100% + 2px); min-width: 210px; padding: 3px 3px 3px 26px; z-index: 20; display: flex; flex-direction: column; }
.more-menu::before { content: 'AI programme'; position: absolute; left: 3px; top: 3px; bottom: 3px; width: 22px; background: linear-gradient(0deg, var(--title-a), var(--shadow)); color: var(--title-text); font-weight: 700; font-size: 1.05rem; writing-mode: vertical-rl; transform: rotate(180deg); text-align: left; padding: 6px 0; letter-spacing: 0.04em; }
.more-menu button { position: relative; text-align: left; padding: 6px 24px 6px 30px; font-size: 1rem; min-height: 32px; color: var(--window-text); white-space: nowrap; }
.more-menu button > .ic { position: absolute; left: 7px; top: 50%; transform: translateY(-50%); --ic: 16px; }
/* The program group (toggleActGroup in js/screens.js): a folder item with an arrow, its programs in a cascading menu */
.menu-group { position: relative; display: flex; flex-direction: column; }
body:not([data-os="modern"]) .menu-group-btn::after { content: '\25B8'; position: absolute; right: 8px; top: 50%; transform: translateY(-50%); }
.menu-group-btn[aria-expanded="true"] { background: var(--select); color: var(--select-text); }
.menu-sub { position: absolute; left: 100%; top: -3px; min-width: 180px; padding: 3px; z-index: 21; display: flex; flex-direction: column; }
.menu-sub-title { display: none; }
.more-menu .menu-shutdown { margin-top: 4px; }
body:not([data-os="modern"]) .more-menu .menu-shutdown::after { content: ''; position: absolute; left: 2px; right: 2px; top: -3px; border-top: 1px solid var(--shadow); border-bottom: 1px solid var(--hilight); }
.more-menu .count { display: inline-block; min-width: 18px; padding: 0 4px; background: var(--window); color: var(--window-text); border: 1px solid var(--shadow); font-size: 0.85rem; text-align: center; margin-left: 6px; }
.more-menu button:hover .count { background: var(--select-text); color: var(--select); }

/* In the air: the conditions still running, on a row of their own in Status under the figures. The row is one note as
   wide as the window, raised as a pill is, with what it says and the arrows inside it (the owner's calls of 2026-10-14). */
.status .air { display: flex; align-items: stretch; gap: 0; }
.air-row { flex: 1; min-width: 0; display: flex; flex-wrap: wrap; gap: 6px; }
/* Several things in the air: one at a time. The row scrolls sideways and snaps to each entry, which is what makes it
   swipeable; its scrollbar is hidden, and the arrows, as tall as the line, page through (the owner's calls of
   2026-10-14). On a touch screen the line grows to the arrows' full target instead. */
.air-nav { display: none; }
.air.many .air-nav { display: inline-flex; align-items: center; justify-content: center; flex: none; min-width: var(--target); min-height: 0; padding: 0 6px; }
@media (pointer: coarse) { .air.many .air-nav { min-height: var(--target); } }
.air.many .air-nav > .ic:first-child { margin-right: 0; }
/* Pressed, the row opens to show everything in the air, a line each, and the arrows go; pressed again it folds (toggleAir) */
.air-row[role="button"] { cursor: pointer; }
.air-row[role="button"]:focus-visible { outline: 1px dotted var(--window-text); outline-offset: -2px; }
.air.open .air-row { flex-direction: column; flex-wrap: nowrap; gap: 0; }
.air.open .air-pill + .air-pill { border-top: 1px dotted var(--shadow); }
.air.many .air-row { flex-wrap: nowrap; gap: 0; overflow-x: auto; scroll-snap-type: x mandatory; scrollbar-width: none; overscroll-behavior-x: contain; }
.air.many .air-row::-webkit-scrollbar { display: none; }
.air.many .air-pill { flex: 0 0 100%; min-width: 0; scroll-snap-align: start; }
/* Each thing in the air reads as one sentence that wraps where it must: its mark, picture, what it is, the figure it
   moves and how long it has left */
.air-pill { display: block; padding: 3px 10px; font-size: 0.92rem; }
.air-pill::before, .air-pill > span { margin-right: 6px; }
.air-pill::before { content: 'i'; display: inline-flex; align-items: center; justify-content: center; width: 14px; height: 14px; border-radius: 50%; background: var(--stamp-blue); color: var(--on-fill); font-weight: 700; font-family: var(--font-glyph); font-size: 0.85rem; vertical-align: 1px; } /* centred on the line's words, in both looks */
.air-pill .air-note { color: var(--stamp-blue); font-weight: 700; }
.air-pill .air-left { color: var(--gray-text); }
/* Inside the note, what it says and the arrows are flat: the note is the one raised thing */
.status .air .air-pill { border: none; box-shadow: none; background: transparent; }
.status .air .air-nav { border-color: transparent; box-shadow: none; background: transparent; }
.status .air .air-nav:hover:not(:disabled), .status .air .air-nav:focus-visible { background: var(--face-light); }

/* Tabbed dialog */
.folder-tabs { display: flex; gap: 0; align-items: flex-end; padding: 0 2px; position: relative; z-index: 1; }
.folder-tab { border-bottom: none; padding: 3px 10px 4px; margin-right: -1px; font-size: 1rem; color: var(--window-text); min-height: calc(var(--target) - 2px); box-shadow: inset 1px 1px var(--face-light), inset -1px 0 var(--shadow); position: relative; top: 1px; }
.folder-tab.active { font-weight: 700; padding: 4px 12px 6px; margin-bottom: -1px; z-index: 2; background: var(--face); box-shadow: inset 1px 1px var(--face-light), inset -1px 0 var(--shadow), 0 1px var(--face); }
.folder-panel { padding: 12px 10px 10px; display: flex; flex-direction: column; gap: 8px; }
/* The order of a tab's list (deskListsModel in js/views.js): a small box at the top right of the panel */
/* A tab's toolbar: the In tray's filter and each tab's order, at the right, above the body that scrolls (folder-body). */
.desk-tools { display: flex; flex-wrap: wrap; justify-content: flex-end; align-items: center; gap: 4px 12px; } /* a readiness strip too wide for the row takes its own line above the selects */
.desk-tools > label { min-width: 0; flex-shrink: 0; } /* the selects keep their width; the readiness strip beside them wraps instead */
.desk-note { flex: 1 1 auto; min-width: 0; margin: 0; font-size: 0.82rem; } /* the AI systems tab's readiness strip: on a line of its own below Systems in place and the filter and sort (the owner's call of 2026-10-13) */
.desk-tools > label select { min-width: 0; max-width: 100%; }
.desk-filter select { width: 9em; } /* its longest choice would otherwise squeeze the order beside it */
.desk-sort, .desk-filter { display: inline-flex; align-items: center; gap: 5px; font-size: 0.82rem; color: var(--gray-text); }
.desk-sort select, .desk-filter select { min-height: 22px; padding: 0 3px; font-size: 0.82rem; }
@media (pointer: coarse) { .desk-sort select, .desk-filter select { min-height: 30px; } } /* smaller than the usual touch target: the owner's call for this toolbar */

/* Cards: each proposal is a small window. Title bar, white document area, status bar. */
.card-row { display: grid; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); gap: 10px; }
.card-row .empty-note { grid-column: 1 / -1; }
.doc { position: relative; display: grid; grid-template-columns: 1fr auto; grid-template-rows: auto auto 1fr auto; gap: 0; padding: 2px; text-align: left; color: var(--window-text); min-height: 150px; align-items: stretch; }
.doc:hover, .doc:focus-visible { outline: 1px dotted var(--window-text); outline-offset: 2px; }
.doc-kicker { grid-column: 1 / -1; display: flex; align-items: center; justify-content: space-between; gap: 6px; height: 18px; padding: 0 5px; --bar: color-mix(in srgb, var(--dept) 55%, #000); background: linear-gradient(90deg, var(--bar), color-mix(in srgb, var(--dept) 80%, #000)); color: #fff; font-weight: 700; font-size: 0.85rem; white-space: nowrap; overflow: hidden; }
.doc-kicker > span:first-child { flex: 1; overflow: hidden; text-overflow: ellipsis; }
.doc .doc-kicker .kind-tag { background: transparent; border: none; color: #fff; padding: 0; font-size: 0.85rem; font-weight: 700; align-self: center; }
.doc .doc-kicker .date-stamp { color: #fff; background: transparent; border: none; padding: 0; font-weight: 400; font-size: 0.85rem; }
.doc.is-new .doc-kicker::after { content: 'new'; font-size: 0.8rem; background: var(--info); color: #000; padding: 0 5px; font-weight: 700; border: 1px solid var(--dark); line-height: 1.2; }
.doc-title { grid-column: 1 / -1; display: flex; align-items: flex-start; gap: 8px; font-weight: 700; font-size: 1.05rem; padding: 6px 8px 2px; line-height: 1.25; background: var(--window); border: 1px solid var(--shadow); border-bottom: none; }
.doc-hook { grid-column: 1 / -1; padding: 0 8px 8px; font-size: 0.95rem; color: var(--window-text); font-style: italic; background: var(--window); border: 1px solid var(--shadow); border-top: none; }
/* The two footer rows stack: people and claim, then the answer-by date on its own row at the right.
   Side by side, a wrapped first row ran under the date. */
.doc-foot { grid-column: 1 / -1; display: flex; flex-wrap: wrap; align-items: center; gap: 3px; margin-top: 3px; font-size: 0.85rem; min-height: 22px; min-width: 0; }
.doc-foot + .doc-foot { justify-self: end; }
.doc-foot:empty { display: none; }
.doc-foot > * { border: 1px solid; border-color: var(--shadow) var(--hilight) var(--hilight) var(--shadow); padding: 1px 5px; background: var(--face); color: var(--window-text); display: inline-flex; align-items: center; gap: 4px; min-height: 20px; white-space: nowrap; }
.doc-foot .people { margin-bottom: 0; color: var(--window-text); }
.doc-foot .claim, .doc-foot .date-stamp { border-style: solid; background: var(--face); }
.doc .stamp { font-size: 0.9rem; flex: none; margin-top: 1px; } /* on the title's line, at its end */
.doc-title-text { flex: 1; min-width: 0; }
.sheet.is-action { --dept: var(--action); }
.doc-foot > :empty { display: none; }
.date-stamp { font-size: 0.85rem; color: var(--window-text); border: 1px solid var(--shadow); padding: 0 5px; white-space: nowrap; display: inline-block; background: var(--window); }
.date-stamp.soon { color: var(--stamp-red); font-weight: 700; }
.claim { font-size: 0.85rem; color: var(--gray-text); border: 1px dashed var(--shadow); padding: 0 5px; white-space: nowrap; background: var(--window); }
.claim.real { border-style: solid; color: var(--stamp-green); border-color: var(--stamp-green); }
.claim .ic { --ic: 13px; margin-right: 3px; vertical-align: -0.15em; } /* centred on the chip's line (the alignment rule) */
.reg-row:hover .claim .ic, .reg-row:focus-visible .claim .ic { color: inherit; } /* on the selection colour the picture takes the row's own, or it would vanish */
.waiting { list-style: none; display: flex; flex-direction: column; gap: 4px; }
.waiting li { display: flex; align-items: center; gap: 8px; font-size: 0.92rem; padding: 4px 8px; border: 1px dotted var(--shadow); background: var(--window); }
.waiting li .ic { --ic: var(--ic-inline); flex: none; } /* the hourglass of a proposal coming back (C.ICONS.time.back) */
.waiting li .w-title { font-weight: 700; }
.waiting li .link-btn { margin-left: auto; min-height: 0; }

/* Register and programme lists: ListView rows */
/* A list keeps its whole height in the folder's body, which scrolls (the body is a flex column): a list that could
   shrink would clip its rows and hide them with no way to reach them, as a fold opening under a row once did. */
.register, .programmes-list { list-style: none; overflow: hidden; flex-shrink: 0; } /* the tree has no box of its own: it sits on the folder's face, where buttons live */
.register-org { margin-top: 8px; }
.reg-row { display: grid; grid-template-columns: auto minmax(0, 1fr) minmax(7.5em, auto); gap: 10px; align-items: center; padding: 4px 8px; width: 100%; text-align: left; border-bottom: var(--row-rule); border-left: 4px solid var(--dept); min-height: var(--target); color: var(--window-text); }
.reg-row:last-child { border-bottom: none; }
/* An AI systems row is three things in one li: the row button, a tail of its own buttons beside it, a fold under both
   (js/ui.js registerRow). The dotted rule between rows is the li's; the two-tap note lands under the row. */
.reg-item { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: start; border-bottom: 1px dotted var(--face); } /* its own rule, not --row-rule: on the new desktop the face colour on the layer is all but invisible, and the token's hairline there would be a change */
.reg-item:last-child { border-bottom: none; }
.reg-item > .reg-row { border-bottom: none; }
.reg-item > .tap-note { order: 1; }
/* The status and the due count sit in columns of one width (the row's grid above: the status cell holds the status mark
   and, under it, what is due; a long title wraps rather than push it out of line), and the tail (at most three buttons
   and the chevron) is one width whatever it holds, so the dots and the words line up from row to row. */
.register.blind .reg-row { grid-template-columns: auto minmax(0, 1fr) minmax(9.5em, auto); } /* without a register the status is in the typewriter face, so the column is wider: Research pilot fits */
/* A list too narrow for a row and its buttons side by side (the new look's desk on a screen 1024 wide, a tablet on its
   side) puts the buttons under the row, as a phone does */
.register { container: register / inline-size; }
@container register (max-width: 460px) { .reg-item { grid-template-columns: 1fr; } .reg-tail { width: auto; padding: 2px 8px 4px; } .reg-fold { padding-left: 8px; } }
.reg-tail { display: flex; align-items: center; justify-content: flex-end; gap: 4px; align-self: center; box-sizing: border-box; width: calc(4 * var(--target) + 24px); padding: 2px 6px; }
.reg-act { min-width: var(--target); min-height: var(--target); padding: 0 6px; display: inline-flex; align-items: center; justify-content: center; gap: 4px; }
.reg-chevron { min-width: var(--target); min-height: var(--target); padding: 0 6px; background: transparent; border: 1px solid transparent; color: var(--window-text); font-size: 1rem; }
/* The carets of everything that folds: ▸ closed and ▾ open, from the button's aria-expanded (the register's chevron, the handbook's
   books, the pitch's person button; the branch bars and the sheet's fold bars keep a space after theirs) */
.reg-chevron::before, .hb-book::before, .lead-caret::before { content: '\25B8'; }
.reg-chevron[aria-expanded="true"]::before, .hb-book[aria-expanded="true"]::before, button.person[aria-expanded="true"] .lead-caret::before { content: '\25BE'; }
.branch-toggle::before, .foldbox > h3 .box-toggle::before { content: '\25BE\00a0'; }
.branch-toggle[aria-expanded="false"]::before, .foldbox > h3 .box-toggle[aria-expanded="false"]::before { content: '\25B8\00a0'; }
/* The selection colour on anything a pointer rests on or the keyboard reaches: the register's chevron and rows, the readiness strip's
   button, the tree's node and tile faces, the address book's row (selected, or focused) */
.reg-chevron:hover, .reg-chevron:focus-visible, .ready-open:hover, .ready-open:focus-visible, .reg-row:hover, .reg-row:focus-visible, .node-face:hover, .node-face:focus-visible, .tile-face:hover, .tile-face:focus-visible, .cast-row.selected, .cast-row:focus-visible { background: var(--select); color: var(--select-text); outline: 1px dotted var(--select-text); outline-offset: -2px; }
/* The file under the row: who brought it, its figures, what it needs (the sheet's control rows) */
.reg-fold { grid-column: 1 / -1; padding: 2px 8px 8px 38px; }
.reg-fold[hidden] { display: none; }
.reg-ledger { margin: 0 0 4px; }
.reg-fold-head { font-size: 0.85rem; font-weight: 700; color: var(--gray-text); margin: 6px 0 2px; }
.reg-fold .controls { padding: 0; }
/* The readiness strip above the rows: a line per date of the Act that reaches a known high-risk system, a bar for how
   many have nothing due (readinessStripModel); the line opens the Timeline. A note when blind or nothing is reached. */
.register-ready { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; align-items: center; gap: 6px 10px; }
.ready-note { font-size: 0.82rem; color: var(--gray-text); }
.ready-open { display: inline-flex; align-items: center; gap: 6px; text-align: left; padding: 1px 6px; border: 1px dotted var(--shadow); background: var(--window); color: var(--window-text); font-size: 0.82rem; }
.ready-bar { width: 56px; height: 8px; border: 1px solid var(--dark); background: var(--face); }
.ready-bar i { display: block; height: 100%; background: var(--stamp-green); }
.ready-count, .mg-steps-item { white-space: nowrap; display: inline-flex; align-items: center; gap: 4px; } /* a count and its chip; a step and its picture on the mini game's map */
.ready-label { display: inline-flex; align-items: center; gap: 2px; white-space: nowrap; }
/* What needs the player, as chips under the facts (registerRowModel attention) */
.reg-attn { display: block; margin-top: 2px; }
.attn { display: inline-block; font-size: 0.82rem; line-height: 1.3; padding: 0 5px; margin: 1px 4px 0 0; border: 1px solid var(--stamp-red); color: var(--stamp-red); }
.reg-row:hover .attn, .reg-row:focus-visible .attn { color: inherit; border-color: var(--select-text); }
.reg-row:hover .figure-word .ic, .reg-row:focus-visible .figure-word .ic { color: inherit; } /* on the selection colour the picture takes the row's own */
.reg-sub .figure-word, .reg-ledger .figure-word { font-weight: 400; } /* a row's and a fold's figures read as a line, not as a tip's bold names */
.reg-row:hover :is(.reg-icon, .reg-title, .reg-sub, .reg-status, .reg-due, .kind-tag, .date-stamp, .claim), .reg-row:focus-visible :is(.reg-icon, .reg-title, .reg-sub, .reg-status, .reg-due, .kind-tag, .date-stamp, .claim),
.reg-row:hover .kind-tag, .reg-row:focus-visible .kind-tag, .reg-row:hover .date-stamp, .reg-row:hover .claim { background: transparent; border-color: var(--select-text); }
.reg-icon { font-size: 1.1rem; line-height: 1; width: 20px; text-align: center; }
.reg-title { font-weight: 700; }
.reg-sub { font-size: 0.9rem; color: var(--gray-text); }
.reg-status { font-size: 0.9rem; color: var(--window-text); display: flex; flex-direction: column; align-items: flex-start; gap: 3px; white-space: nowrap; }
.dot, .res-dot i { width: 8px; height: 8px; background: var(--gray-text); display: inline-block; border: 1px solid var(--dark); } /* a system's status dot and a resource hint's dot (.res-dot, below) */
.dot.live { background: var(--stamp-green); } .dot.suspended, .dot.due { background: var(--stamp-red); } .dot.research, .dot.building { background: var(--stamp-blue); } .dot.proposed, .dot.deferred { background: var(--gray-text); } /* waiting is not a risk: amber means risk only */ .dot.rejected, .dot.stopped { background: var(--shadow); }
.reg-due { font-size: 0.9rem; color: var(--stamp-red); font-weight: 700; white-space: nowrap; }
.reg-row.just-changed { animation: rowFlash 1.6s steps(4, end); }
@keyframes rowFlash { 0% { background: var(--select); color: var(--select-text); } 100% { background: transparent; } }
.register.blind { background: var(--face); }
.register.blind .reg-due, .register.blind .reg-status { font-family: var(--font-mono); color: var(--gray-text); }
/* On the selection colour a row's grey lines (its sub line, and the status and due in the typewriter face when blind) and
   the status mark's picture take the row's own text colour, or they vanish into the navy (the owner's reports of
   2026-10-25); weighted past the blind rule above and the status mark's own colours */
.register .reg-row:hover :is(.reg-sub, .reg-status, .reg-due, .reg-status .ic), .register .reg-row:focus-visible :is(.reg-sub, .reg-status, .reg-due, .reg-status .ic) { color: inherit; }
.reg-org-head { font-size: 0.92rem; font-weight: 700; margin: 8px 0 2px; color: var(--window-text); } /* the AI systems tab's hospital-wide duties, in bold (the owner's call of 2026-10-10) */
/* A tab's header (Systems in place, Programme tree) heads its list in the toolbar row, beside the filter and sort that
   work on it, and the tab's note takes its own line below the row, above the list (the owner's calls of 2026-10-13) */
.desk-tools > .desk-head { margin: 0 auto 0 0; }
#panel-register .desk-tools > .register-ready { flex-basis: 100%; order: 1; }
.desk-tools > .desk-head ~ .desk-note { flex-basis: 100%; } /* the In tray's and the Programmes tab's line, under the header and sort */
#panel-register .desk-tools > .register-ready:empty { display: none; }
.kind-tag { display: inline-block; font-size: 0.85rem; padding: 0 5px; background: var(--face); color: var(--window-text); border: 1px solid var(--shadow); align-self: flex-start; }
.kind-tag.law { background: var(--select); color: var(--select-text); border-color: var(--select); }
.kind-tag.law .src-mark { color: inherit; } /* the § takes the tag's light text, or it would vanish into the fill */

/* ── The Programmes tab: a tech tree (fillProgrammesTree in js/views.js) ──
   A raised bar heads each branch (its root's name and how much is in place; pressing it folds the branch). Under it a
   row per programme, nested under what it needs by depth with a dotted elbow: its node on the left, a dotted link, what
   stays on as flat white tiles, then the one-offs it opens as square tiles. A programme in place is a raised panel; one
   open to set up is raised too, with its Set up button and a grey picture; a locked one is flat, a dotted edge and a
   lock, saying what it needs. The node is
   a bevelled panel in the folder's face, and its face button is the whole node but the corner buttons, so hovering
   anywhere lights it all. A tile's face opens the one-off's sheet; a tile that can be done is a raised button like
   any other on this desktop, its figures in colour, the word Ready and a small Do button in its corner; one that
   cannot (cooling, waiting for the programme, done for good) is flat, a dotted outline on the face, its words
   embossed grey as a disabled button's are, with a lock while the programme is still going in. The tree sits on
   the folder's own grey, not in a white list box, so those three looks stay apart. Words stay in tooltips and on the sheets. */
.prog-tree { display: flex; flex-direction: column; gap: 8px; padding: 4px 2px; background: transparent; border: none; box-shadow: none; }
.prog-row { position: relative; display: flex; align-items: flex-start; gap: 0; min-height: 0; }
.prog-row[data-depth="1"] { margin-left: 34px; } .prog-row[data-depth="2"] { margin-left: 68px; } .prog-row[data-depth="3"] { margin-left: 102px; }
.prog-row[data-depth]::before { content: ''; position: absolute; left: -22px; top: -9px; width: 18px; height: 70px; border-left: 1px dotted var(--dark); border-bottom: 1px dotted var(--dark); } /* the elbow up to what it needs */
/* A branch's bar: raised, since pressing it folds the branch (the sheet's fold bars' material) */
.prog-branch { list-style: none; margin-top: 4px; }
.prog-branch:first-child { margin-top: 0; }
.branch-toggle { box-sizing: border-box; display: flex; align-items: center; gap: 8px; width: 100%; min-height: var(--target); padding: 2px 8px; font: inherit; font-weight: 700; text-align: left; color: var(--window-text); cursor: pointer; background: var(--bar-bg); border: 1px solid; border-color: var(--bar-edge); box-shadow: var(--bar-shadow); border-radius: var(--bar-radius); }
.branch-toggle:active, .foldbox > h3 .box-toggle:active, .pitch-from button.person[aria-expanded="true"] { border-color: var(--pressed-edge); box-shadow: var(--pressed-shadow); } /* pressed, or held open */
.branch-toggle:focus-visible { outline: 1px dotted var(--window-text); outline-offset: -4px; }
.branch-sum { margin-left: auto; font-weight: 400; font-size: 0.85rem; color: var(--gray-text); white-space: nowrap; }
/* The bar tells, even folded: the root's picture, a pip per programme (green in place, blue going in) and how many
   one-offs and add-ons inside are ready, in the ready green */
.branch-icon { flex: none; font-size: 1.05rem; line-height: 1; }
.branch-pips { display: inline-flex; flex: none; gap: 3px; }
.branch-pips i { display: block; width: 10px; height: 10px; box-sizing: border-box; border: 1px solid var(--shadow); background: var(--window); }
.branch-pips i.pip-in { background: var(--stamp-green); border-color: var(--stamp-green); }
.branch-pips i.pip-building { background: var(--stamp-blue); border-color: var(--stamp-blue); }
.branch-ready { margin-left: auto; font-size: 0.75rem; font-weight: 700; line-height: 16px; padding: 0 6px; color: var(--stamp-green); border: 1px solid currentColor; background: var(--window); white-space: nowrap; }
.branch-ready + .branch-sum { margin-left: 0; }
.prog-node { position: relative; flex: 0 0 auto; width: 150px; min-height: 124px; box-sizing: border-box; padding: 0; color: var(--window-text); display: flex; flex-direction: column; }
.node-face { flex: 1 1 auto; width: 100%; box-sizing: border-box; padding: 8px 8px 6px; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 4px; background: transparent; border: 1px solid transparent; color: inherit; font: inherit; text-align: center; cursor: pointer; }
.node-face:hover .node-size-label, .node-face:hover .node-status, .node-face:hover .node-covers, .node-face:focus-visible .node-size-label, .node-face:focus-visible .node-status, .node-face:focus-visible .node-covers { color: inherit; }
.node-icon { font-size: 1.5rem; line-height: 1; }
.node-title { font-weight: 700; font-size: 0.9rem; line-height: 1.2; }
/* What the programme covers: the tiles of the duties it makes cheaper or meets (programmeNodeModel covers) */
.node-covers { display: flex; flex-wrap: wrap; justify-content: center; align-items: center; gap: 3px; font-size: 0.78rem; color: var(--gray-text); }
.node-covers .duty-tile { --sym-tile: 18px; --sym-ic: 12px; }
/* A programme's sheet: what it gives once set up, in words (the node's tooltip facts), then the duties it covers */
/* The programme and one-off sheets as ability cards (no person): the line of dry humour, what it is, then its facts as
   rows (fillFactRows): a label, then figures, items with their pictures, or words and pips */
.sheet .sheet-what { margin: 0 0 8px; }
.ability-facts { display: grid; grid-template-columns: max-content minmax(0, 1fr); gap: 6px 10px; margin: 0 0 10px; padding: 8px 10px; font-size: 0.92rem; align-items: baseline; background: var(--face); border: 1px solid var(--shadow); box-shadow: inset 1px 1px var(--hilight); }
.ability-facts dt { color: var(--gray-text); }
.ability-facts dd { margin: 0; display: flex; flex-wrap: wrap; align-items: center; gap: 4px 10px; min-width: 0; }
.ability-facts ul, .fact-list { list-style: none; margin: 0; padding: 0; width: 100%; }
:is(.ability-facts, .fact-list) li { display: flex; align-items: center; gap: 6px; }
:is(.ability-facts, .fact-list) li + li { margin-top: 3px; }
:is(.ability-facts, .fact-list) li > .ic, .ability-facts .figure-word .ic { --ic: var(--ic-inline); flex: none; }
.ability-facts .duty-tile { --sym-tile: 18px; --sym-ic: 12px; flex: none; }
.ability-facts .fact-ok > .ic { color: var(--stamp-green); }
.ability-facts .fact-missing { color: var(--gray-text); }
.fact-glyph { width: var(--ic-inline); text-align: center; flex: none; }
.ability-facts .cd-pips { margin-right: 4px; }
.kind-tag .src-act, .kind-tag .ic { margin-right: 3px; }
.doc-kicker .kind-tag .src-act { color: inherit; } /* on a card's coloured header the mark takes the header's own text colour */
.kind-tag .ic { --ic: 12px; vertical-align: -0.15em; }
/* The size the programme is at: a pip per size it could be (on up to the one in place, the next one dotted) and the
   size's name; only where there is more than one size. */
.node-size, .tile-foot { display: flex; flex-direction: column; align-items: center; gap: 2px; } /* a node's size pips and a tile's foot: a centred stack */
.node-size-label { font-size: 0.78rem; color: var(--gray-text); line-height: 1.2; text-align: center; }
.node-pips, .cd-pips { display: inline-flex; gap: 3px; }
.pip { display: inline-block; width: 9px; height: 9px; box-sizing: border-box; background: var(--window); border: 1px solid var(--dark); }
.pip.on { background: var(--stamp-green); }
.pip.next { border-style: dotted; }
.node-status { font-size: 0.82rem; color: var(--gray-text); display: flex; align-items: center; gap: 5px; white-space: nowrap; }
.node-mini { display: flex; gap: 2px; position: absolute; top: 2px; right: 2px; }
.node-act, .tile-act { min-width: 26px; min-height: 26px; padding: 0 4px; display: inline-flex; align-items: center; justify-content: center; }
.node-act .ic, .tile-act .ic { --ic: 15px; }
/* Open to set up: the picture grey until it is in place. Locked: flat, a dotted edge, embossed grey words, a lock. */
.prog-node.is-open .node-icon { filter: grayscale(1); opacity: 0.6; }
.prog-node.is-locked, .actions > .act-btn[disabled] { background: transparent; border: 1px dotted var(--shadow); box-shadow: none; color: var(--disabled-text); text-shadow: 1px 1px var(--hilight); }
.prog-node.is-locked .node-icon { filter: grayscale(1); opacity: 0.45; }
.prog-node.is-locked .node-status { white-space: normal; text-align: center; color: inherit; }
/* Where a programme stands, at a glance (the owner's call of 2026-10-13): a chip in the state tones the systems use,
   green in place, blue going in, plain not set up; in place, a green edge along its top */
.node-chip { display: inline-flex; align-items: center; gap: 4px; font-size: 0.72rem; font-weight: 700; line-height: 16px; padding: 0 6px; border: 1px solid currentColor; background: var(--window); white-space: nowrap; }
.node-chip::before { content: ''; flex: none; width: 7px; height: 7px; border-radius: 50%; background: currentColor; }
.node-chip.tone-in { color: var(--stamp-green); }
.node-chip.tone-building { color: var(--stamp-blue); }
.node-chip.tone-open { color: var(--gray-text); font-weight: 400; }
.node-chip.tone-locked { color: var(--gray-text); font-weight: 400; border-style: dotted; } /* on a card: what a locked programme waits for */
.node-chip.tone-locked::before { display: none; }
.node-face:hover .node-chip.tone-open, .node-face:focus-visible .node-chip.tone-open { color: var(--window-text); }
.prog-node.is-in { box-shadow: inset 0 3px var(--stamp-green), inset 1px 1px var(--hilight), inset -1px -1px var(--shadow); }
.node-lock { position: absolute; top: 5px; left: 5px; width: 14px; height: 14px; color: var(--disabled-text); }
/* The link from a node to its tiles: a dotted line at the node's middle, the branch of the tree. Every node and every
   tile is one size (150 by 124, 108 by 124), so the rows line up whatever each holds (the owner's call of 2026-10-11). */
.prog-link { flex: 0 0 22px; height: 0; border-top: 2px dotted var(--dark); margin-top: 61px; }
.prog-link.faint { border-top-color: var(--shadow); }
/* Lit paths: a programme in place lights the elbow up to what it needs and the line to its tiles */
.prog-row.lit > .prog-link { border-top: 2px solid var(--stamp-green); }
.prog-row.lit[data-depth]::before { border-left: 2px solid var(--stamp-green); border-bottom: 2px solid var(--stamp-green); }
.prog-tiles { display: flex; flex-wrap: wrap; gap: 6px; min-width: 0; } /* every tile one height, and each row's the same (the owner's call of 2026-10-13) */
.prog-tile { position: relative; width: 108px; min-height: 104px; box-sizing: border-box; display: flex; flex-direction: column; color: var(--window-text); text-align: center; } /* the .btn bevel: a button that can be pressed */
.tile-face { flex: 1 1 auto; width: 100%; box-sizing: border-box; padding: 6px 4px 4px; display: flex; flex-direction: column; align-items: center; justify-content: space-between; gap: 2px; background: transparent; border: 1px solid transparent; color: inherit; font: inherit; text-shadow: inherit; text-align: center; cursor: pointer; }
.tile-face:hover, .tile-face:focus-visible { text-shadow: none; }
.tile-face:hover .ic, .tile-face:focus-visible .ic, .tile-face:hover .tile-state, .tile-face:focus-visible .tile-state { color: inherit; }
.tile-mini { position: absolute; top: 2px; right: 2px; }
.prog-tile > .tap-note { order: 1; } /* the Do button's two-tap note grows the tile downwards */
.tile-icon { font-size: 1.4rem; line-height: 1; }
.tile-title { font-size: 0.78rem; line-height: 1.15; font-weight: 700; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden; }
.tile-figs { display: flex; flex-wrap: wrap; justify-content: center; gap: 1px 6px; font-size: 0.78rem; }
.tile-figs .figure-word .ic { --ic: 12px; margin-right: 2px; }
.cd-pips .pip { width: 7px; height: 7px; }
.cd-pips .pip.on { background: var(--gray-text); } /* a one-off cooling down is not a risk */
.tile-state { font-size: 0.72rem; line-height: 1.2; white-space: nowrap; }
.prog-tile.st-ready .tile-state { color: var(--stamp-green); font-weight: 700; }
/* What stays on: a flat tile that tells (passiveTilesModel), white and sunken while it works, dotted until then */
.pass-tile { align-items: center; justify-content: center; gap: 6px; padding: 10px 5px 8px; font-size: 0.78rem; background: var(--window); border: 1px solid; border-color: var(--shadow) var(--hilight) var(--hilight) var(--shadow); box-shadow: none; }
/* Quieter: what works now shows a tick in its corner, its words kept for a screen reader; Once set up stays written */
.pass-tile.on::after { content: '\2713'; position: absolute; top: 3px; right: 6px; color: var(--stamp-green); font-weight: 700; font-size: 0.85rem; }
.pass-pic .ic { --ic: 20px; }
.pass-pic .duty-tile { --sym-tile: 22px; }
.pass-text { font-weight: 700; line-height: 1.2; }
.pass-word { font-size: 0.72rem; color: var(--stamp-green); font-weight: 700; }
.pass-tile.off { background: transparent; border: 1px dotted var(--shadow); color: var(--disabled-text); text-shadow: 1px 1px var(--hilight); }
.pass-tile.off .pass-word { color: inherit; font-weight: 400; }
.pass-tile.off .pass-pic { opacity: 0.5; filter: grayscale(1); }
.tile-gap { align-self: stretch; width: 0; border-left: 1px dotted var(--shadow); margin: 0 2px; } /* between what stays on and what you do */
/* Not now: flat on the face, a dotted edge, the words embossed grey the way a disabled button's are (it still opens the sheet) */
.prog-tile.st-cooling, .prog-tile.st-locked, .prog-tile.st-later, .prog-tile.st-unmet, .prog-tile.st-spent, .prog-tile.st-off {
  background: transparent; border: 1px dotted var(--shadow); box-shadow: none; color: var(--disabled-text); text-shadow: 1px 1px var(--hilight);
  & .ic { color: var(--disabled-text); }
  & .tile-icon { opacity: 0.45; filter: grayscale(1); }
}
.tile-lock { position: absolute; top: 4px; left: 4px; width: 14px; height: 14px; color: var(--disabled-text); }
/* A bought add-on: flat, white, sunk like what stays on (it tells, it does not act); it says Bought */
.prog-tile.st-bought { background: var(--window); border: 1px solid; border-color: var(--shadow) var(--hilight) var(--hilight) var(--shadow); box-shadow: none; }
.prog-tile.st-bought .tile-face { cursor: default; }
.prog-tile.st-bought .tile-state { color: var(--stamp-green); font-weight: 700; }
.tile-now { position: absolute; top: 2px; left: 2px; font-size: 0.7rem; font-weight: 700; line-height: 1.3; padding: 0 4px; background: var(--stamp-red); color: var(--on-fill); border: 1px solid var(--dark); text-shadow: none; }
.tile-face:hover .tile-now, .tile-face:focus-visible .tile-now { border-color: var(--select-text); } /* top left, across from the Do button at the top right; a locked tile, whose lock sits there, never shows it */
.prog-node.just-changed, .prog-tile.just-changed { animation: rowFlash 1.6s steps(4, end); }
/* Unlocking: a new node grows in from its centre, its link draws out to the right, and each tile switches on in turn,
   grey to lit (the index is the tile's place on the branch). A tile that comes back ready switches on alone. Nothing
   under reduced motion (the global rule). */
.prog-node.prog-unlock { animation: nodeUnlock 0.36s steps(4, end) both; }
.prog-link.draw { animation: linkDraw 0.3s steps(3, end) 0.3s both; }
.prog-tile.tile-unlock { animation: tileOn 0.3s steps(3, end) both; animation-delay: calc(0.5s + var(--i, 0) * 0.14s); }
/* A narrow tree (a phone, or the modern desk's middle column at 1024): each row stacks, the node across the row with its
   corner buttons inline, the link a short drop, the tiles under it. By the tree's own width, so it holds wherever the
   folder is narrow. */
.programmes-list { container-type: inline-size; container-name: tree; }
@keyframes linkDrop { 0% { clip-path: inset(0 0 100% 0); } 100% { clip-path: inset(0 0 0 0); } }
@container tree (max-width: 380px) {
  .prog-row { flex-wrap: wrap; }
  .prog-node { width: 100%; min-height: 0; flex-direction: row; align-items: center; }
  .prog-node .node-face { flex-direction: row; flex-wrap: wrap; justify-content: flex-start; gap: 10px; padding: 6px 8px; width: auto; min-width: 0; } /* beside the corner buttons, not under them */
  .prog-row[data-depth="1"] { margin-left: 18px; } .prog-row[data-depth="2"] { margin-left: 36px; } .prog-row[data-depth="3"] { margin-left: 54px; }
  .prog-row[data-depth]::before { left: -12px; width: 9px; height: 30px; } /* the elbow meets the short row's middle */
  .prog-node.is-locked .node-status { text-align: left; }
  .prog-node.is-locked .node-face { padding-left: 24px; } /* room for the lock in the corner, so it never sits on the picture */
  .prog-node .node-mini { position: static; margin: 0 6px 0 auto; }
  .prog-link { flex-basis: calc(100% - 16px); height: 10px; border-top: none; border-left: 2px dotted var(--dark); margin: 0 0 0 16px; } /* its own line, under the node, within the row */
  .prog-link.draw { animation-name: linkDrop; }
  .prog-row.lit > .prog-link { border-top: none; border-left: 2px solid var(--stamp-green); }
  .prog-tile { width: calc(50% - 3px); } /* two to a row, sharing the width a phone has, so a tile's words keep to two lines */
  .branch-sum { display: none; } /* the pips say how much is in place; the bar's spoken name still says it in words */
  .prog-tiles { width: 100%; padding-left: 8px; }
}
@keyframes nodeUnlock { 0% { transform: scale(0.6); opacity: 0; } 100% { transform: none; opacity: 1; } }
@keyframes linkDraw { 0% { clip-path: inset(0 100% 0 0); } 100% { clip-path: inset(0 0 0 0); } }
@keyframes tileOn { 0% { opacity: 0; filter: grayscale(1) contrast(0.6); } 60% { opacity: 1; filter: grayscale(1) contrast(0.6); } 100% { opacity: 1; filter: none; } }

/* ── Turn banner: a splash ── */
/* Closing the quarter is a progress dialog: time passes as the blocks march */
.turn-banner { position: fixed; top: 40%; left: 50%; transform: translate(-50%,-50%); width: 320px; max-width: calc(100% - 24px); padding: 28px 14px 12px; font-weight: 700; font-size: 1.1rem; z-index: 60; pointer-events: none; text-align: center; color: var(--window-text); opacity: 0; visibility: hidden; }
.turn-banner.show { opacity: 1; visibility: visible; }
.turn-banner::before { content: 'Closing the quarter'; position: absolute; top: 2px; left: 2px; right: 2px; height: 18px; line-height: 18px; padding: 0 6px; text-align: left; font-size: 0.95rem; background: linear-gradient(90deg, var(--title-a), var(--title-b)); color: var(--title-text); }
.turn-banner small { display: block; font-weight: 400; font-size: 0.92rem; color: var(--gray-text); margin-top: 2px; }
.turn-banner::after { content: ''; display: block; height: 16px; margin-top: 10px; border: 1px solid; border-color: var(--shadow) var(--hilight) var(--hilight) var(--shadow); box-shadow: inset 1px 1px var(--dark); background: repeating-linear-gradient(90deg, var(--select) 0 10px, transparent 10px 12px) 0 0 / 0% 100% no-repeat, var(--window); }
.turn-banner.show::after { animation: progress 1.3s steps(12, end) forwards; }
@keyframes progress { from { background-size: 0% 100%, auto; } to { background-size: 100% 100%, auto; } }

/* ── Sheets: dialogs over the desktop ── */
.overlay { position: fixed; inset: 0; background: rgba(0,0,0,0.25); display: flex; align-items: flex-start; justify-content: center; padding: 28px 12px 60px; z-index: 40; overflow: auto; }
/* Tall content scrolls instead of clipping: start at the top and let auto margins centre what fits */
#screen-event, #screen-tutorial-complete { align-items: center; justify-content: flex-start; padding: 20px 12px; } /* the message screen and the course's closing message (below): a card, centred the same way */
#event-sheet { margin: auto 0; display: flex; flex-direction: column; max-height: calc(100dvh - var(--event-pad-y, 40px)); }
/* A card taller than the screen keeps its head and its answers in view; the body scrolls inside the card */
#event-sheet > .client { flex: 1 1 auto; min-height: 0; }
#event-sheet > .client > * { flex-shrink: 0; }
#event-sheet > .client > .msg-body, #modal-qmail .qmail-body { flex: 1 1 auto; min-height: 80px; overflow: auto; } /* the body of a card or a mail (#modal-qmail, below) scrolls inside its window */
#modal-variant, #confirm-modal, #modal-options, #modal-new-game, #modal-share { align-items: flex-start; padding: 28px 12px; }
#modal-variant .sheet, #confirm-modal .sheet, #modal-options .sheet, #modal-new-game .sheet, #modal-share .sheet { margin: auto 0; }
.sheet { width: 100%; max-width: 620px; color: var(--window-text); }
/* The width modifiers come after the default so they win (until 2026-10-17 they sat before it and never applied):
   tall for the proposal sheet, the Timeline and the diary; narrow for Options, the variant box and the message boxes
   (confirm, copy, tips), a small box, not the width of the window behind it. */
.msgbox { max-width: 640px; }
.sheet-tall { max-width: 720px; }
.sheet-narrow { max-width: 420px; }
.sheet-narrow.msgbox { max-width: 420px; } /* a weight the phone block's .msgbox { max-width: none } cannot beat: a tip or confirm box stays a small box on a phone in landscape */
.copy-text { width: 100%; box-sizing: border-box; font-family: var(--font-mono); font-size: 0.85rem; color: var(--window-text); background: var(--window); border: 1px solid; border-color: var(--shadow) var(--hilight) var(--hilight) var(--shadow); resize: vertical; margin-top: 6px; }
.msgbox.is-ledger { max-width: 760px; }
.msgbox.is-report { max-width: 700px; }
/* The message is an Outlook Express window: menu bar, labelled header, white body, reply toolbar, status bar */
.msgbox .client { display: flex; flex-direction: column; padding-top: 6px; }
.msg-head { position: relative; display: flex; flex-direction: column; gap: 2px; padding: 2px 48px 8px 0; border-bottom: 1px solid var(--shadow); box-shadow: 0 1px var(--hilight); margin-bottom: 8px; }
.msg-head .msg-row { display: grid; grid-template-columns: 64px 1fr; gap: 6px; align-items: baseline; font-size: 0.95rem; margin: 0; }
.msg-label { font-weight: 700; }
.msg-head .sheet-title { margin: 0; font-size: 1.05rem; }
.msg-head .people { margin: 0; color: var(--window-text); }
.msg-head .people > span:not(.person) { font-size: 0; }
.msg-cc:has(.people:empty) { display: none; }
.speaker-name { font-weight: 700; }
.speaker-does { color: var(--gray-text); }
.speaker-does:not(:empty)::before { content: '('; } .speaker-does:not(:empty)::after { content: ')'; }
.speaker-mood { color: var(--gray-text); font-size: 0.88rem; }
.speaker-mood:empty { display: none; }
.speaker-mood:not(:empty)::before { content: '· '; }
/* How a person stands with you: a small label beside their name (Who's who, the proposal sheet) */
.mood-chip { display: inline-block; font-size: 0.78rem; font-weight: 400; color: var(--gray-text); border: 1px solid var(--shadow); background: var(--window); padding: 0 5px; margin: 0 6px 0 0; vertical-align: middle; white-space: nowrap; }
.cast-name .mood-chip { margin: 0 0 0 6px; }
.msg-portrait { position: absolute; right: 0; top: 0; }
.msg-portrait:empty { display: none; }
.msg-body { padding: 10px; min-height: 120px; background: var(--window); color: var(--window-text); font-family: var(--font-doc); }
.msg-body .scene { margin: 0; }
.msg-body .surcharge { margin: 8px 0 0; }
.msg-body .ledger-wrap { margin-bottom: 0; }
#event-result.outcome { margin-top: 6px; padding: 8px 10px; background: var(--window); font-family: var(--font-doc); }
#event-result .actions { margin-bottom: 0; }
.msg-status { display: flex; flex-wrap: wrap; gap: 3px; margin: 6px -10px -10px; padding: 3px 3px 3px; border-top: 1px solid var(--hilight); }
.msg-status .event-res { display: contents; }
.msg-cell, .msg-status .res-chip { display: inline-flex; align-items: center; gap: 5px; min-height: 20px; padding: 1px 6px; font-size: 0.85rem; color: var(--window-text); background: var(--face); border: 1px solid; border-color: var(--shadow) var(--hilight) var(--hilight) var(--shadow); box-shadow: none; }
.msg-cell:empty { display: none; }
#event-system { flex: 1 1 auto; }
#event-system:not(:empty)::before { content: ''; width: 9px; height: 9px; background: var(--dept); border: 1px solid var(--dark); flex: none; }
.sheet.is-world #event-system::before { background: var(--gray-text); } /* from outside: grey, the colour of outside */
#event-options.choices { display: flex; flex-direction: row; align-items: stretch; gap: 0; margin: 6px -10px 0; padding: 4px 6px 4px; border-top: 1px solid var(--shadow); box-shadow: inset 0 1px var(--hilight); }
#event-options .choice { flex: 1 1 0; min-width: 0; display: flex; flex-direction: column; align-items: center; text-align: center; gap: 2px; padding: 5px 6px; min-height: 64px; border-color: transparent; box-shadow: none; background: transparent; }
#event-options .choice + .choice { border-left-color: var(--shadow); box-shadow: inset 1px 0 var(--hilight); }
/* The icon is the stamp the choice will earn: do, refuse, note or risk */
#event-options .choice::before { content: '✔'; display: inline-flex; align-items: center; justify-content: center; width: 20px; height: 20px; border-radius: 50%; background: var(--stamp-green); color: var(--on-fill); font-size: 0.9rem; font-weight: 700; line-height: 1; margin-bottom: 2px; }
#event-options .choice[data-tone="refuse"]::before { content: '✖'; background: var(--stamp-red); }
#event-options .choice[data-tone="note"]::before { content: 'i'; background: var(--stamp-blue); font-family: var(--font-glyph); }
#event-options .choice[data-tone="risk"]::before { content: '!'; background: var(--stamp-amber); border-radius: 0; clip-path: polygon(50% 0, 100% 100%, 0 100%); width: 22px; padding-top: 5px; }
/* An answer with its own icon: the picture sits in a badge whose colour and shape give the tone (do and note round,
   refuse square, risk a diamond), so the tone does not rest on colour alone. */
#event-options .choice.has-badge::before { content: none; display: none; }
.choice .choice-badge { display: inline-flex; align-items: center; justify-content: center; width: 24px; height: 24px; flex: none; border-radius: 50%; background: var(--stamp-green); color: var(--on-fill); margin-bottom: 2px; }
.choice-badge .ic { --ic: 14px; }
.choice[data-tone="note"] .choice-badge { background: var(--stamp-blue); }
.choice[data-tone="refuse"] .choice-badge { background: var(--stamp-red); border-radius: 3px; }
.choice[data-tone="risk"] .choice-badge { background: var(--stamp-amber); border-radius: 0; width: 28px; height: 28px; margin: -2px 0 0; clip-path: polygon(50% 0, 100% 50%, 50% 100%, 0 50%); }
.choice[data-tone="risk"] .choice-badge .ic { --ic: 12px; }
#event-options .choice:hover, #event-options .choice:focus-visible { border-color: var(--hilight) var(--dark) var(--dark) var(--hilight); box-shadow: inset -1px -1px var(--shadow), inset 1px 1px var(--face-light); background: var(--face); }
#event-options .choice:active, #event-options .choice.chosen { border-color: var(--shadow) var(--hilight) var(--hilight) var(--shadow); box-shadow: inset 1px 1px var(--dark), inset -1px -1px var(--face-light); background: var(--face); padding: 6px 5px 4px 7px; }
#event-options .choice strong { font-weight: 700; }
#event-options .choice .key { margin-right: 4px; }
#event-options .choice > span { font-size: 0.85rem; }
#event-options .res-dots { justify-content: center; margin-top: auto; padding-top: 3px; }
#event-options .choice .stamp { position: static; transform: none; margin-top: 2px; }
.people { display: flex; flex-wrap: wrap; gap: 4px 10px; align-items: center; font-size: 0.9rem; color: var(--gray-text); margin-bottom: 6px; }
.people .person { display: inline-flex; align-items: center; gap: 4px; }
.event-res { display: flex; gap: 4px; flex-wrap: wrap; margin: 0 0 10px; }
.res-chip { display: inline-flex; align-items: center; gap: 5px; padding: 2px 8px; font-size: 0.85rem; color: var(--gray-text); border: 1px solid; border-color: var(--shadow) var(--hilight) var(--hilight) var(--shadow); background: var(--window); }
.res-chip strong { font-size: 1rem; color: var(--window-text); }
.res-chip.band-steady strong { color: var(--stamp-green); } .res-chip.band-watchful strong { color: var(--stamp-amber); } .res-chip.band-shaken strong { color: var(--stamp-red); }
.surcharge { font-size: 0.92rem; color: var(--stamp-red); padding: 5px 8px; margin-bottom: 10px; background: var(--window); }
.later { list-style: none; display: flex; flex-direction: column; gap: 2px; margin: 0 0 10px; }
.later li { font-size: 0.92rem; color: var(--gray-text); padding-left: 16px; position: relative; }
.later li::before { content: '└'; position: absolute; left: 2px; color: var(--shadow); font-family: var(--font-mono); }
/* the symbol a line is about (laterSymbol in js/views.js), before its words */
.later li .later-sym, .later li .duty-tile { display: inline-flex; vertical-align: -0.3em; margin-right: 5px; }
.later li .duty-tile { --sym-tile: 18px; --sym-ic: 12px; }
.later-sym .ic { --ic: var(--ic-inline); }
.later-sym.tone-red { color: var(--stamp-red); } .later-sym.tone-amber { color: var(--stamp-amber); } .later-sym.tone-blue { color: var(--stamp-blue); } .later-sym.tone-green { color: var(--stamp-green); }
.later-sym.due { width: var(--ic-inline); height: var(--ic-inline); align-items: center; justify-content: center; border-radius: 50%; background: var(--stamp-red); color: var(--window); font-size: 0.8rem; font-weight: 700; }
.file { display: grid; grid-template-columns: max-content 1fr; gap: 6px 10px; font-size: 0.95rem; margin: 6px 0 12px; padding: 8px 10px; background: var(--window); }
.file dt { display: inline-flex; align-items: center; gap: 5px; color: var(--window-text); align-self: start; padding-top: 3px; }
.file dt::after { content: ':'; margin-left: -5px; } /* a form's label: "Built by:" */
.file dt .ic { --ic: 14px; color: var(--gray-text); }
/* The tier badge (tierBadge in js/ui.js): the tier's icon and short name, coloured by C.TIER_TONE. */
.tier-badge { display: inline-flex; align-items: center; gap: 4px; padding: 0 6px; font-size: 0.85rem; font-weight: 700; white-space: nowrap; color: var(--on-fill); background: var(--stamp-blue); border: 1px solid var(--dark); }
.tier-badge .ic { --ic: 12px; }
.tier-badge.tone-red { background: var(--stamp-red); } .tier-badge.tone-amber { background: var(--stamp-amber); color: #000; }
.tier-badge.tone-green { background: var(--stamp-green); } .tier-badge.tone-ink { background: var(--gray-text); color: var(--window); }
.doc-foot > .tier-badge { background: var(--stamp-blue); } .doc-foot > .tier-badge.tone-red { background: var(--stamp-red); } .doc-foot > .tier-badge.tone-amber { background: var(--stamp-amber); } .doc-foot > .tier-badge.tone-green { background: var(--stamp-green); } .doc-foot > .tier-badge.tone-ink { background: var(--gray-text); } /* on a card the new look's .doc-foot > * outranks .tier-badge: this weight keeps the tone's colour (its border and text were restated for nothing) */
.legal-line .tier-badge { margin-right: 6px; }
.reg-row .tier-badge { margin: 2px 6px 0 0; }

/* ── The symbol language (js/ui.js: dutyTile, stateChip, timeChip, statusMark, sourceMark) ──
   One shape per kind of thing, one meaning per colour. A duty tile is a flat square, tinted by the duty's group (the
   group colours are on duty tiles only); a state chip is flat, rounded and outlined, coloured by the meaning scale
   (red now, green done, ink to come, grey not applicable), with its own glyph or picture for every state; a status
   mark is a bare picture and word; a source mark is § before the Act's own references. Icons sit centred in a box one
   line tall, so they keep to their line at any text size (no pixel nudges). */
.duty-tile { --sym-ic: var(--ic-inline); display: inline-flex; align-items: center; justify-content: center; flex: none; width: var(--sym-tile); height: var(--sym-tile);
  background: var(--duty-fill, var(--window)); border: 1px solid var(--duty-edge, var(--window-text)); color: var(--window-text); }
.duty-tile .ic { --ic: var(--sym-ic); vertical-align: 0; }
.duty-tile[data-group="watch"] { --duty-edge: var(--duty-watch); --duty-fill: var(--duty-watch-fill); }
.duty-tile[data-group="tell"] { --duty-edge: var(--duty-tell); --duty-fill: var(--duty-tell-fill); }
.duty-tile[data-group="paperwork"] { --duty-edge: var(--duty-paper); --duty-fill: var(--duty-paper-fill); }
.duty-tile[data-group="provider"] { --duty-edge: var(--duty-provider); --duty-fill: var(--duty-provider-fill); }
.state-chip { display: inline-flex; align-items: center; gap: 4px; padding: 0 7px 0 4px; min-height: var(--sym-line); white-space: nowrap; vertical-align: top;
  font-size: 0.9rem; line-height: 1.2; border: 1px solid var(--chip, var(--gray-text)); border-radius: 8px; color: var(--chip, var(--gray-text)); background: var(--window); }
.state-chip .ic { --ic: var(--ic-inline); vertical-align: 0; }
.state-chip.st-due, .state-chip.urgent { --chip: var(--stamp-red); font-weight: 700; }
.state-chip.st-funded { --chip: var(--stamp-green); }
.state-chip.st-coming, .state-chip.time-chip { --chip: var(--window-text); }
.state-chip.st-legacy, .state-chip.st-open, .state-chip.st-preview { --chip: var(--gray-text); }
.state-chip.st-ended { --chip: var(--stamp-red); } /* the shield lost: the grace period ended */
.state-chip.time-chip.urgent { --chip: var(--stamp-red); }
.sym-glyph { display: inline-flex; align-items: center; justify-content: center; flex: none; font-weight: 700; line-height: 1; }
.state-chip.st-due .sym-glyph, .state-chip.urgent .sym-glyph:not(.src-act) { width: var(--ic-inline); height: var(--ic-inline); border-radius: 50%; background: var(--stamp-red); color: var(--window); font-size: 0.8rem; }
.state-chip.st-open .sym-glyph { width: var(--ic-inline); height: var(--ic-inline); border: 1px solid currentColor; border-radius: 50%; font-size: 0.75rem; }
.src-act { font-family: var(--font-serif); font-size: 1.1em; color: var(--stamp-blue); }
.src-mark { margin-right: 3px; }
.src-mark.ic { --ic: var(--ic-inline); vertical-align: -0.2em; }
.status-mark { display: inline-flex; align-items: center; gap: 4px; white-space: nowrap; vertical-align: top; min-height: var(--sym-line); }
.status-mark .ic { --ic: var(--ic-inline); vertical-align: 0; color: var(--window-text); }
.status-mark.st-live .ic { color: var(--act-on); }
.status-mark.st-unassessed { color: var(--stamp-red); } .status-mark.st-unassessed .ic { color: var(--stamp-red); }
/* The key in How to play (fillSymbolKey): one symbol and its word to a line */
.key-head { font-size: 0.9rem; margin: 10px 0 4px; }
.symbol-key { list-style: none; margin: 0; padding: 0; display: grid; gap: 4px; }
.symbol-key li { display: grid; grid-template-columns: minmax(2.5em, auto) 1fr; gap: 8px; align-items: center; font-size: 0.92rem; }
.symbol-key .key-sym { display: inline-flex; align-items: center; }
.symbol-key .state-chip .sym-word:empty, .symbol-key .status-mark .sym-word:empty { display: none; }
body.high-contrast .duty-tile { --duty-fill: var(--window); border-width: 2px; }
body.high-contrast .state-chip { border-width: 2px; }
/* A word picked out in the text (richText in js/ui.js, meta.glossary): its category's icon, a tint and an underline, so it
   stands out without colour alone. One that names an article is a button that opens it in the Reference drawer. */
.term { display: inline; padding: 0 2px; font: inherit; font-weight: 700; color: inherit; line-height: inherit; text-align: inherit;
  background: color-mix(in srgb, var(--term) 16%, transparent); border: none; border-bottom: 1px dotted var(--term); --term: var(--stamp-blue); }
.term .ic { --ic: 12px; margin-right: 2px; vertical-align: -0.1em; color: var(--term); }
/* A figure named in a tip, with its picture from Status before it (figureText in js/ui.js) */
.figure-word { font-weight: 700; white-space: nowrap; }
.figure-word .ic, .num span[data-ic] .ic, .trust-label span[data-ic] .ic { --ic: 14px; margin-right: 3px; vertical-align: -0.15em; } /* a figure's picture before its word, in a tip and in Status (the label stays inline text, so its baseline is the word's and the icon sits on the line) */
.term-status { --term: var(--stamp-amber); } .term-role { --term: var(--stamp-blue); } .term-term { --term: var(--stamp-green); }
button.term { cursor: pointer; min-height: 0; box-shadow: none; }
button.term:hover, button.term:focus-visible { border-bottom-style: solid; background: color-mix(in srgb, var(--term) 28%, transparent); outline: 1px dotted var(--window-text); outline-offset: 0; }
body.high-contrast .term { background: none; border-bottom: 2px solid var(--window-text); }
body.high-contrast .term .ic { color: var(--window-text); }
.file dd { margin: 0; min-width: 0; overflow-wrap: anywhere; } /* the value sits in a filled-in field, drawn with the logon's (below) */
.legal-line { font-size: 1rem; margin-bottom: 10px; }
.legal-line .muted { color: var(--gray-text); }
.notice { padding: 6px 8px 6px 30px; margin-bottom: 10px; font-size: 0.95rem; background: var(--info); color: var(--window-text); position: relative; }
:root[data-theme="dark"] .notice { border-color: var(--stamp-amber); }
.notice::before { content: 'i'; position: absolute; left: 8px; top: 7px; width: 15px; height: 15px; border-radius: 50%; background: var(--stamp-blue); color: var(--on-fill); font-weight: 700; font-family: var(--font-glyph); font-size: 0.85rem; text-align: center; line-height: 15px; }

/* Controls: a ListView with a Fund button */
.controls, .timeline { list-style: none; display: flex; flex-direction: column; padding: 2px 0; } /* the controls' list and the Timeline (below): a ListView */
.controls:empty { display: none; } /* the hint says why there is nothing; no empty bar under it */
/* The row grammar (the symbol language): tile, words, state chip, button. Everything keeps to the label's first line:
   the row aligns to its top, and the label is padded so its first line is centred on the tile, as the chip is. */
.control { display: grid; grid-template-columns: var(--sym-tile) 1fr auto auto; gap: 4px 10px; align-items: start; padding: 4px 8px; border-bottom: var(--row-rule); font-size: 0.95rem; min-height: var(--target); }
.control .c-tile { display: flex; align-items: center; height: var(--sym-tile); }
.control .c-label { display: flex; flex-wrap: wrap; gap: 5px; align-items: baseline; padding-top: calc((var(--sym-tile) - var(--sym-line)) / 2); line-height: var(--sym-line); }
.control .c-status { white-space: nowrap; display: flex; align-items: center; min-height: var(--sym-tile); }
.control > .btn-small, .control > .c-cost { align-self: start; min-height: var(--sym-tile); }
.control:last-child { border-bottom: none; }
.control .c-cost { font-size: 0.9rem; color: var(--gray-text); }
.story { list-style: none; color: var(--window-text); font-size: 0.95rem; padding: 4px 8px; }
.story li { padding: 3px 0; border-bottom: var(--row-rule); }
.story li:last-child { border-bottom: none; }
.story li.hint { color: var(--gray-text); }
/* A diary line anywhere (diaryLineEl in js/views.js): the date in bold, a colon, the words */
.diary-date::after { content: ': '; }

/* Choices: the buttons along the bottom of a message box */
.choices { display: flex; flex-direction: column; gap: 6px; margin-top: 8px; }
.choices.two { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.choice { position: relative; display: flex; flex-direction: column; gap: 1px; text-align: left; padding: 5px 10px; font-size: 1rem; color: var(--window-text); min-height: var(--target); }
.choice:hover { background: var(--face-light); }
.choice:active, .choice.chosen { padding: 6px 9px 4px 11px; }
.choice strong { font-weight: 700; }
.choice span { font-size: 0.92rem; color: var(--gray-text); }
.choice .choice-warn { color: var(--stamp-red); font-weight: 700; } /* a version the player knows the Act bans (the version picker) */
.choice .key { color: var(--gray-text); font-size: 0.9rem; margin-right: 6px; font-family: var(--font-mono); }
.choice .means { display: block; font-size: 0.9rem; color: var(--gray-text); margin-top: 2px; }
.choice[disabled] { cursor: default; }
.choice[disabled]:not(.chosen) { color: var(--window-text); opacity: 0.7; }
.res-dots { display: flex; gap: 8px; margin-top: 4px; flex-wrap: wrap; }
.res-dot { display: inline-flex; align-items: center; gap: 3px; font-size: 0.85rem; color: var(--gray-text); }
.res-dot.up i { background: var(--stamp-green); } .res-dot.down i { background: var(--stamp-red); } .res-dot.mixed i { background: linear-gradient(90deg, var(--stamp-green) 50%, var(--stamp-red) 50%); } .res-dot.kept i { background: transparent; }
.res-dot.unknown i { background: transparent; border-style: dashed; }
/* Duties in a button's dots: the duty tile in small, with no arrow (more duties is not "up"); its edge says whether
   the choice helps with duties (green), adds to them (red) or both (amber). */
.res-dot .duty-tile.mini { --sym-tile: 10px; border-width: 2px; background: var(--window); }
.res-dot.up .duty-tile.mini { border-color: var(--stamp-green); } .res-dot.down .duty-tile.mini { border-color: var(--stamp-red); }
.res-dot.mixed .duty-tile.mini { border-color: var(--stamp-amber); } .res-dot.kept .duty-tile.mini { border-color: var(--gray-text); }
/* A dot with a resource icon: the icon takes the direction's colour, and an arrow says it without colour. */
.res-dot .ic { --ic: 14px; }
/* Dots inside the other action buttons: under the label and cost on the programme and one-off sheets, beside the word
   on a control's Fund button, on a programme size's last row; and on a desk card's foot, without the box its neighbours get. */
/* A one-off's Do it and a programme's Stop: the action's icon in a column of its own, centred down the button (the owner's
   call of 2026-10-08), the word beside it (with why it cannot be done, or what stopping costs), and the dots with how long
   it takes centred under both. */
#prog-actions .btn, #iv-actions .btn { grid-template-columns: 26px auto minmax(0, 1fr); column-gap: 10px; row-gap: 2px; align-content: center; }
#prog-actions .btn > .lead-ic, #iv-actions .btn > .lead-ic { grid-column: 1; grid-row: 1 / span 2; align-self: center; display: flex; justify-content: center; }
#prog-actions .btn > .lead-ic .ic, #iv-actions .btn > .lead-ic .ic { --ic: 22px; }
/* The dots span the whole button so they centre on it, not on the words beside the icon; padding as wide as the icon's
   column and gap (26px + 10px) on both sides keeps them clear of the icon and balanced. */
#prog-actions .btn .res-dots, #iv-actions .btn .res-dots { grid-column: 1 / -1; grid-row: 2; padding: 0 36px; margin-top: 2px; justify-content: center; align-items: center; gap: 4px 12px; }
/* How long an action takes, the last item of its row of dots (dotsRow in js/views.js), so it wraps with them. */
.res-dots .takes { font-size: 0.85rem; color: var(--gray-text); }
/* A programme size's last row: the dots, then how long it takes, one row that wraps as one and is centred on the button
   (the owner's calls of 2026-10-08 and 09, as on a proposal's tiles). */
#prog-levels .choice .level-foot { display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 4px 12px; margin-top: 3px; }
/* A programme size is a button row in the desktop's own button look: the action's icon large at the left, centred down the
   button, and its three rows beside it (name, what it does, the dots and the days); no highlight on hover (the old desktop's
   buttons had none). */
#prog-levels .choice { display: grid; grid-template-columns: 26px minmax(0, 1fr); column-gap: 10px; align-items: start; }
#prog-levels .choice > :not(.lead-ic) { grid-column: 2; }
#prog-levels .choice > .lead-ic { grid-column: 1; grid-row: 1 / span 3; align-self: center; display: flex; justify-content: center; }
#prog-levels .choice > .lead-ic .ic { --ic: 22px; }
/* The last row spans the whole button so it centres on it, the icon's column and gap (26px + 10px) as padding on both
   sides so it stays clear of the icon. Its row is named: an auto-placed item would skip the row the icon reaches into. */
#prog-levels .choice > .level-foot { grid-column: 1 / -1; grid-row: 3; padding: 0 36px; }
body:not([data-os="modern"]) #prog-levels .choice:not(.chosen):hover { background: var(--face); }
.control .btn-small, .hb-colour { display: inline-flex; align-items: center; gap: 6px; } /* a control's small button and a Colours entry of Help: a picture beside words */
.control .btn-small .res-dots { margin-top: 0; gap: 4px; }
.control .btn-small .res-dot { font-size: 0; gap: 1px; } /* icon and arrow only: the button is small, the tooltip gives the cost */
.control .btn-small .res-dot.has-ic::after { font-size: 0.6rem; }
.control .btn-small .res-dot:not(.has-ic) i { width: 7px; height: 7px; }
.doc-foot > .res-dots { border: none; background: none; padding: 0; margin-top: 0; gap: 6px; min-height: 0; }
.res-dot.has-ic::after { font-size: 0.75em; line-height: 1; }
.res-dot.has-ic.up::after { content: '▲'; color: var(--stamp-green); } .res-dot.has-ic.down::after { content: '▼'; color: var(--stamp-red); }
.res-dot.has-ic.mixed::after { content: '▲▼'; color: var(--stamp-amber); } .res-dot.has-ic.kept::after { content: '='; }

/* ── Icons (js/icons.js; icon() in js/ui.js) ── */
/* Decorative pictures in the text colour, drawn from the current look's set. The classic set is pixel art on a 24 grid:
   at 12px or 24px its pixels land whole. */
/* An icon in a line of text sits centred on it, in em so it keeps to the line at any text size (the alignment rule;
   tests/css.test.js refuses a pixel nudge on an icon). In a flex row (buttons, chips) the row centres it instead. */
.ic { --ic: var(--ic-inline); display: inline-block; width: var(--ic); height: var(--ic); flex: none; vertical-align: -0.22em; overflow: visible; }
.icon-sprite { position: absolute; width: 0; height: 0; overflow: hidden; }
.btn > .ic:first-child, .folder-tab > .ic:first-child { margin-right: 5px; }
.btn-label .ic { margin-right: 5px; }
/* The four figures keep their own colour wherever they appear */
.ic-res.ic-budget { color: var(--res-budget); } .ic-res.ic-capacity { color: var(--res-capacity); }
.ic-res.ic-benefit { color: var(--res-benefit); } .ic-res.ic-trust { color: var(--res-trust); }
.res-dot .ic-res { color: var(--gray-text); }
/* Action icons: each key's family colour, keyed by data-act, which the icon (js/ui.js actionIcon) and its button
   (js/views.js actionButton) both carry, so the picture and the button's edge read one table (the keys are
   C.ICONS.actions; tests/css.test.js holds every key to a family). --act-edge is the button's edge, the family's colour
   but for waiting, which takes the grey edge (--act-wait-edge). */
.ic-action { --act: var(--action); }
.act-btn { --act-edge: var(--act); }
[data-act="buy"], [data-act="fund"] { --act: var(--act-money); }
[data-act="assess"], [data-act="build"], [data-act="research"], [data-act="do_intervention"] { --act: var(--act-staff); }
[data-act="defer"], [data-act="pause"] { --act: var(--act-wait); --act-edge: var(--act-wait-edge); }
[data-act="reject"], [data-act="stop"], [data-act="stop_pilot"], [data-act="stop_programme"] { --act: var(--act-stop); }
[data-act="go_live"], [data-act="resume"] { --act: var(--act-on); }
.res-dot.up .ic-res { color: var(--stamp-green); } .res-dot.down .ic-res { color: var(--stamp-red); } .res-dot.mixed .ic-res { color: var(--stamp-amber); }
.res-chip .ic { --ic: 14px; align-self: center; }
.delta { display: inline-flex; align-items: center; gap: 4px; font-size: 0.9rem; font-weight: 700; padding: 1px 8px; border: 1px solid var(--stamp-green); color: var(--stamp-green); background: var(--window); }
.delta .ic { --ic: 14px; color: inherit; }
.outcome { margin-top: 12px; padding-top: 10px; border-top: 1px solid var(--shadow); box-shadow: 0 -1px var(--hilight) inset; }
.score { font-size: 0.92rem; color: var(--gray-text); margin-bottom: 6px; font-weight: 700; }
.score.full { color: var(--stamp-green); } .score.partial { color: var(--stamp-amber); } .score.none { color: var(--gray-text); }
.verdict { margin: 8px 0 12px; font-size: 0.95rem; }
/* Once answered, the other answers fold away behind the link under them (fillAssessAnswer, showOthers); the chosen one stays. */
#assess-options.answered .choice:not(.chosen) { display: none; }
#assess-options.answered.show-others .choice:not(.chosen) { display: flex; }
.assess-others { margin: 4px 0 0; font-size: 0.9rem; }
.deltas { display: flex; gap: 6px; flex-wrap: wrap; margin: 2px 0 10px; }
.delta.down { border-color: var(--stamp-red); color: var(--stamp-red); }
.why { margin: 4px 0 12px; font-size: 0.95rem; }
.why summary { cursor: default; color: var(--link); text-decoration: underline; }
.why p { margin: 6px 0 4px; }
.tags { display: inline; }
.tag { display: inline-block; white-space: nowrap; background: var(--window); color: var(--link); border: 1px solid var(--shadow); padding: 0 5px; font-size: 0.85rem; margin: 1px 4px 1px 0; text-decoration: underline; cursor: default; }
.tag.other { color: var(--window-text); } /* other law: its own mark (the landmark), not the amber of risk */

/* Stamps: dialog icons */
.stamp { display: inline-flex; align-items: center; gap: 6px; font-weight: 700; font-size: 0.95rem; color: var(--window-text); white-space: nowrap; pointer-events: none; }
.stamp::before { content: ''; display: inline-flex; align-items: center; justify-content: center; width: 18px; height: 18px; border-radius: 50%; background: var(--stamp-blue); color: var(--on-fill); font-size: 0.85rem; font-weight: 700; line-height: 1; flex: none; font-family: var(--font-glyph); }
.stamp.tone-blue::before { content: 'i'; background: var(--stamp-blue); }
.stamp.tone-green::before { content: '✔'; background: var(--stamp-green); font-family: var(--font); }
.stamp.tone-red::before { content: '✖'; background: var(--stamp-red); font-family: var(--font); }
.stamp.tone-amber::before { content: '!'; background: var(--stamp-amber); border-radius: 0; clip-path: polygon(50% 0, 100% 100%, 0 100%); width: 20px; height: 18px; padding-top: 4px; font-family: var(--font); }
.stamp.tone-ink::before { content: '■'; background: transparent; color: var(--window-text); border: 1px solid var(--window-text); border-radius: 0; font-size: 0.6rem; }
.stamp.tone-green { color: var(--stamp-green); } .stamp.tone-red { color: var(--stamp-red); } .stamp.tone-amber { color: var(--stamp-amber); } .stamp.tone-blue { color: var(--stamp-blue); }
.stamp.landed { animation: stampIn 0.25s steps(3, end) both; }
@keyframes stampIn { 0% { transform: scale(1.3); opacity: 0; } 100% { transform: none; opacity: 1; } }
.stamp-row { min-height: 26px; margin: 2px 0 8px; display: flex; align-items: center; }
.sheet .stamp-corner { position: static; display: inline-flex; margin: 0 0 6px; }
/* The system sheet's stamp (Live, Pilot, Suspended…) sits in the meta row, just after the department and status; the date stays right. */
.sheet-meta .meta-stamp { margin-right: auto; display: inline-flex; align-items: center; }
.sheet-meta .meta-stamp .stamp-corner { margin: 0; font-size: 0.85rem; }
.choice .stamp { position: absolute; right: 10px; top: 50%; transform: translateY(-50%); }

/* Portraits: initials in a square, or a drawn face (img/portraits), which brings its own ground in the person's hue.
   The insides are 16, 32 and 64 pixels (sm, lg, the People card) so the classic pictures, drawn on a 16-pixel grid,
   scale by whole pixels. */
.portrait { display: inline-flex; align-items: center; justify-content: center; font-weight: 700; letter-spacing: 0.02em; background: hsl(var(--hue) 45% 80%); color: hsl(var(--hue) 50% 20%); border: 1px solid var(--dark); box-shadow: 1px 1px var(--dark); flex: none; font-family: var(--font); }
.portrait.lg { width: 34px; height: 34px; font-size: 1rem; }
.portrait.sm { width: 18px; height: 18px; font-size: 0.7rem; box-shadow: none; }
.portrait.doc-icon { background: var(--window); border: 1px dashed var(--shadow); color: var(--gray-text); box-shadow: none; }
:root[data-theme="dark"] .portrait { background: hsl(var(--hue) 35% 30%); color: hsl(var(--hue) 50% 90%); border-color: var(--hilight); box-shadow: none; }
.portrait.drawn { overflow: hidden; }
.portrait.drawn img { display: block; width: 100%; height: 100%; }
.portrait.drawn .pic-modern { display: none; }

/* World events: a system message from outside */
.sheet.is-world .titlebar { background: linear-gradient(90deg, #404040, #808080); }
/* A proposal's sheet takes its department's colour and a programme's or one-off's the action colour, as their cards'
   header bars do (the same mix under white text, held at 4.5:1 by tests/css.test.js). */
.sheet.is-proposal > .titlebar, .sheet.is-action > .titlebar { background: linear-gradient(90deg, color-mix(in srgb, var(--dept) 55%, #000), color-mix(in srgb, var(--dept) 80%, #000)); color: #fff; }
/* The system sheet's letterhead (the owner's call of 2026-10-25): its title bar holds the tested mix under its words and
   runs out to the department's own colour, and under it the kicker and the title sit on the department's tint with the
   system's picture drawn large (js/views.js, the system skeleton: .sheet-head stays while the client scrolls). */
.sheet.is-proposal > .titlebar { background: linear-gradient(90deg, color-mix(in srgb, var(--dept) 80%, #000) 0 50%, var(--dept)); }
.sheet-head { display: grid; grid-template-columns: 44px minmax(0, 1fr); column-gap: 8px; align-items: center; padding: 8px 10px; background: color-mix(in srgb, var(--dept) 14%, var(--window)); border-bottom: 1px solid var(--shadow); box-shadow: 0 1px var(--hilight); }
.sheet-head .sheet-ic { grid-row: 1 / span 2; font-size: 30px; line-height: 1; text-align: center; }
.sheet-head .sheet-meta { margin-bottom: 2px; }
.sheet-head .sheet-title { margin: 0; }
.sheet.is-world .titlebar-text::after { content: ' from outside'; font-weight: 400; }
.sheet.is-world .sheet-meta > span:first-child::before { background: var(--gray-text); }

/* Board meeting minutes and the ledger */
.sheet.is-review .sheet-title::before { content: 'Minutes'; display: block; font-size: 0.85rem; font-weight: 400; color: var(--gray-text); margin-bottom: 2px; }
.review-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(110px, 1fr)); gap: 6px; margin: 4px 0 12px; }
.review-cell { display: flex; flex-direction: column; gap: 1px; padding: 5px 8px; }
.review-label { font-size: 0.85rem; color: var(--gray-text); display: inline-flex; align-items: center; gap: 4px; }
.review-label .ic { --ic: 14px; }
.cell-glyph.due { display: inline-flex; align-items: center; justify-content: center; width: 14px; height: 14px; border-radius: 50%; background: var(--stamp-red); color: var(--window); font-size: 0.75rem; }
.review-value { font-size: 1.2rem; font-weight: 700; }
.review-cell.bad .review-value { color: var(--stamp-red); }
.review-cell.blind .review-value { color: var(--gray-text); font-family: var(--font-mono); }
/* The ledger is a year-end workbook: formula bar, row numbers, gridlines, a double rule under totals */
.sheet.is-ledger .titlebar-text::after { content: ' · ledger.xls'; font-weight: 400; }
.ledger-wrap { padding: 0; margin-bottom: 10px; border: none; box-shadow: none; background: transparent; counter-reset: row; --grid: #d4d4d4; }
.ledger-wrap .hint { padding: 0 0 4px; }
.ledger-quarters { display: grid; grid-template-columns: repeat(4, 1fr); gap: 0; margin: 0 0 6px; }
.ledger-q { padding: 2px 6px; font-family: var(--font-doc); font-size: 11px; color: var(--gray-text); background: var(--window); border: 1px solid var(--grid); box-shadow: none; }
.ledger-q strong { display: block; font-size: 13px; color: var(--window-text); }
.ledger { width: 100%; border-collapse: collapse; font-family: var(--font-doc); font-size: 12px; color: var(--window-text); font-variant-numeric: tabular-nums; background: var(--window); }
.ledger th, .ledger td { border: 1px solid var(--grid); padding: 2px 6px; vertical-align: top; }
.ledger tr { counter-increment: row; }
.ledger th:first-child, .ledger td:first-child { padding-left: 34px; position: relative; }
.ledger th:first-child::before, .ledger td:first-child::before { content: counter(row); position: absolute; left: 0; top: 0; bottom: 0; width: 27px; background: var(--face); color: var(--window-text); font-weight: 400; font-size: 11px; text-align: center; line-height: 20px; border-right: 1px solid #a0a0a0; }
.ledger th { text-align: left; font-weight: 700; background: var(--face); border-bottom: 1px solid var(--dark); }
.ledger td.l > .ic, .ledger td.l > .cell-glyph { margin-right: 4px; vertical-align: -0.2em; width: 14px; height: 14px; } /* a line's symbol (cellSymbol) */
.ledger td:first-child { width: 34%; min-width: 150px; }
.ledger td.n { text-align: right; white-space: nowrap; width: 1%; }
.ledger td.note { color: var(--gray-text); font-size: 11px; white-space: normal; }
.ledger tr.total td { font-weight: 700; border-top: 1px solid var(--dark); border-bottom: 3px double var(--dark); }
.ledger .up { color: var(--stamp-green); } .ledger .down { color: var(--stamp-red); }
:root[data-theme="dark"] .ledger-wrap { --grid: #404040; }
/* ── The quarter report: a mail from the hospital's own reporting. Where a message from outside has prose and replies,
   this has objects pasted in from the office programs of the day: two workbook sheets (the ledger's grid) and a
   chart, each in the hatched frame of an embedded object, and one Close. ── */
.sheet.is-report > .titlebar { background: linear-gradient(90deg, #0f4a25, #2a7a47); color: #fff; }
.sheet.is-report .titlebar-text::after { content: ' · quarter report.xls'; font-weight: 400; }
.qmail-body, .review .client { display: flex; flex-direction: column; gap: 10px; } /* a mail's body and the programme review's client stack their parts the same way */
/* It arrives the way a message from someone does, growing up from the taskbar, once the desk has been back a moment.
   Until then the desk is held (holdDesk in js/screens.js): shown, with the busy cursor, taking no input. */
#modal-qmail .sheet { transform-origin: 50% 100%; animation: windowOut 0.24s steps(4, end); }
#screen-play.desk-held { cursor: progress; }
#screen-play.desk-held * { pointer-events: none; }
/* The report fits the screen as the proposal sheet does, and only its sheets and chart scroll: the title bar, the
   From and Subject rows and Close stay where they are. */
#modal-qmail > .sheet > .client { flex: 1 1 auto; min-height: 0; }
#modal-qmail .msg-head, #modal-qmail .qmail-end, #modal-qmail .qmail-body > .embed { flex: none; }
.embed { padding: 3px; background: repeating-linear-gradient(45deg, var(--shadow) 0 1px, var(--window) 1px 4px); }
.embed-cap { padding: 1px 6px; font-family: var(--font-doc); font-size: 11px; color: var(--window-text); background: var(--face); border: 1px solid var(--shadow); border-bottom: none; }
.embed-body { background: var(--window); border: 1px solid var(--shadow); overflow-x: auto; counter-reset: row; --grid: #d4d4d4; }
.embed-body .hint { margin: 0; padding: 6px 8px; }
:root[data-theme="dark"] .embed-body { --grid: #404040; }
.xl th.n { text-align: right; }
.xl td { vertical-align: middle; }
.xl td.n.up, .xl td.n.down { font-weight: 700; }
.xl td.up, .xl td.down { white-space: nowrap; }
.xl td .ic-res { vertical-align: -0.15em; }
.xl .xl-who { white-space: nowrap; }
.xl .xl-who .portrait { vertical-align: middle; margin-right: 6px; }
.xl td.xl-who::before { display: flex; align-items: center; justify-content: center; } /* the row number level with the face */
.xl .xl-did { min-width: 200px; } /* on a phone the sheet scrolls sideways before this column squeezes to a word a line */
.embed .rv-chart-mini { max-width: 440px; border: none; }
/* In the report the chart is one pasted from the office programs of the day, not the review's monitor: a light ground,
   solid outlined bars and plain labels, so it reads at a glance. */
body:not([data-os="modern"]) .embed .rv-chart-mini { background: var(--window); }
body:not([data-os="modern"]) .embed .rv-chart-mini .grid { stroke: var(--shadow); }
body:not([data-os="modern"]) .embed .rv-chart-mini .bar { fill: #9999ff; stroke: var(--window-text); stroke-width: 1; }
body:not([data-os="modern"]) .embed .rv-chart-mini .axis { fill: var(--window-text); font-family: var(--font-doc); }
.qmail-end { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-top: 8px; }
.qmail-end .hint { margin: 0; }
.qmail-end .actions { margin: 0 0 0 auto; }
.deal-in { animation: dealIn 0.18s steps(3, end) both; }
@keyframes dealIn { 0% { opacity: 0; } 100% { opacity: 1; } }

/* ── Who's who: an address book. A toolbar under the menubar, a find row, a folder tree on the left, a list with
   column headers, the selected person's properties below, a status bar. ── */
/* The window fits the screen: the list and the properties box scroll inside it rather than the window growing */
.addressbook { max-width: 860px; max-height: calc(100dvh - 92px); display: flex; flex-direction: column; }
.cast-client { padding: 4px 6px 6px; display: flex; flex-direction: column; gap: 4px; flex: 1 1 auto; min-height: 0; }
.toolbar { display: flex; align-items: stretch; flex-wrap: wrap; gap: 0; padding: 2px 4px; border-bottom: 1px solid var(--shadow); box-shadow: 0 1px var(--hilight); }
.tool-btn { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px; min-width: 56px; min-height: 40px; padding: 3px 6px; font: inherit; font-size: 0.85rem; color: var(--window-text); background: transparent; border: 1px solid transparent; box-shadow: none; border-radius: 0; }
.tool-btn::before { content: attr(data-icon); font-size: 1.15rem; line-height: 1; }
.tool-btn[aria-hidden], button.tool-btn[disabled] { color: var(--disabled-text); }
button.tool-btn:not([disabled]):hover, button.tool-btn:focus-visible { border-color: var(--hilight) var(--dark) var(--dark) var(--hilight); box-shadow: inset -1px -1px var(--shadow), inset 1px 1px var(--face-light); background: var(--face); outline: none; }
.cast-find { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 8px; padding: 4px 2px; }
.cast-find input { flex: 1 1 200px; min-width: 0; }
.cast-find input::placeholder { color: transparent; }
.cast-main { display: grid; grid-template-columns: 160px minmax(0, 1fr); gap: 4px; min-height: 0; flex: 1 1 auto; }
/* The folders: a tree like the Help window's, with a root and three folders under it */
.cast-folders { display: flex; flex-direction: column; align-self: start; padding: 4px 4px 6px 6px; }
body:not([data-os="modern"]) .cast-folders::before { content: 'Contacts'; font-weight: 700; padding: 2px 4px; }
.cast-folder { position: relative; display: flex; align-items: center; gap: 6px; padding: 2px 4px 2px 32px; min-height: var(--target); text-align: left; font: inherit; color: var(--window-text); background: transparent; border: none; box-shadow: none; border-radius: 0; margin-left: 6px; }
body:not([data-os="modern"]) .cast-folder::before { content: ''; position: absolute; left: 4px; top: 0; bottom: 0; border-left: 1px dotted var(--shadow); }
body:not([data-os="modern"]) .cast-folder:last-child::before { bottom: 50%; }
body:not([data-os="modern"]) .cast-folder::after { content: ''; position: absolute; left: 12px; top: 50%; width: 13px; height: 10px; margin-top: -5px; border: 1px solid var(--dark); background: linear-gradient(180deg, #d9b64a 0 3px, #f0d878 3px); }
.cast-folder .count { margin-left: auto; color: var(--gray-text); font-size: 0.85rem; }
.cast-folder.active { background: var(--select); color: var(--select-text); }
.cast-folder.active .count { color: inherit; }
.cast-folder:focus-visible { outline: 1px dotted var(--window-text); outline-offset: -2px; }
/* The list: a ListView. One track list for the header strip and every row, so the columns line up */
.cast-body { --cast-cols: 26px minmax(140px, 1.6fr) minmax(120px, 1.4fr) minmax(100px, 1fr) 84px 76px; display: flex; flex-direction: column; min-height: 0; }
/* The folders sit beside the column headers and the list only; the Properties pane runs under both, the whole width of
   the window, so the corner under the folders is not left empty. The body's children join the window's grid for that
   (the column widths still come from --cast-cols on it); the modern look lays the body out its own way. */
body:not([data-os="modern"]) .cast-main { grid-template-rows: auto auto minmax(0, 1fr); }
body:not([data-os="modern"]) .cast-folders { grid-column: 1; grid-row: 1 / span 2; }
body:not([data-os="modern"]) .cast-body { display: contents; }
body:not([data-os="modern"]) .cast-cols { grid-column: 2; grid-row: 1; }
body:not([data-os="modern"]) .cast-list { grid-column: 2; grid-row: 2; }
body:not([data-os="modern"]) .cast-detail-box { grid-column: 1 / -1; grid-row: 3; }
/* The column heads take the list's width exactly, so each head sits over its column: the list's 1px border at each
   side, and its scroll bar's gutter (reserved only on an element that can scroll, hence overflow hidden, at the classic
   bar's width) */
.cast-cols { display: grid; grid-template-columns: var(--cast-cols); overflow: hidden; scrollbar-gutter: stable; padding: 0 1px; }
body:not([data-os="modern"]) .cast-cols::-webkit-scrollbar { width: 16px; }
.cast-cols span { font-size: 0.9rem; padding: 2px 6px; background: var(--face); border: 1px solid; border-color: var(--hilight) var(--shadow) var(--shadow) var(--hilight); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cast-list { list-style: none; flex: 0 1 auto; min-height: 96px; max-height: min(22vh, 168px); overflow: auto; scrollbar-gutter: stable; } /* about seven rows, then it scrolls: the card below gets the room */
.cast-row { display: grid; grid-template-columns: var(--cast-cols); align-items: center; min-height: var(--target); padding: 0; cursor: default; }
.cast-cell { padding: 2px 6px; font-size: 0.92rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cast-pic { padding: 2px 4px; display: flex; }
.cast-name { display: flex; align-items: center; gap: 6px; min-width: 0; }
.cast-name-text { overflow: hidden; text-overflow: ellipsis; }
.cast-row.selected .cast-cell, .cast-row.selected .mood-chip { color: inherit; border-color: var(--select-text); background: transparent; }
.cast-row.unmet { color: var(--disabled-text); }
.cast-group { display: none; }
.cast-list .hint { padding: 6px 8px; }
/* The selected person's properties: a group box under the list */
/* The frame holds the border and the label on it; the card scrolls inside, so the scroll does not clip the label */
.cast-detail-box { position: relative; display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0; border: 1px solid var(--shadow); box-shadow: inset 1px 1px var(--hilight), 1px 1px var(--hilight); margin: 12px 0 4px; background: var(--face); }
body:not([data-os="modern"]) .cast-detail-box::before { content: attr(data-legend); position: absolute; top: -9px; left: 8px; z-index: 1; background: var(--face); padding: 0 4px; font-size: 0.9rem; font-weight: 700; line-height: 1.2; }
.cast-detail { flex: 1 1 auto; min-height: 0; overflow: auto; padding: 14px 10px 10px; outline: none; } /* the rest of the window; it scrolls only when the card is taller than that */
.cast-detail:focus-visible { outline: 1px dotted var(--window-text); outline-offset: -3px; }
.cast-card { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; gap: 2px 10px; align-items: center; border-left: 4px solid var(--dept); padding-left: 4px; margin-left: -8px; } /* the edge in their department's colour (the pane's data-dept), drawn in the pane's padding so the header keeps its width */
.cast-card .portrait { grid-row: 1 / span 2; }
.cast-card-name, .cast-card-does { grid-column: 2; } /* the name over the job, whether or not a chip sits at the right */
/* At the header's right, on one line: how they stand and since when, then their influence (each chip its own width) */
.cast-card-chips { grid-column: 3; grid-row: 1 / span 2; align-self: center; justify-self: end; display: flex; flex-wrap: nowrap; gap: 4px; }
.cast-card-chip { display: inline-flex; align-items: center; gap: 3px; padding: 0 6px; font-size: 0.85rem; white-space: nowrap; color: var(--window-text); background: var(--window); border: 1px solid var(--shadow); }
/* How someone stands, on the meaning scale: warm in green, annoyed or fed up in red, neutral as it is (castRowModel tone) */
.cast-card-chip[data-tone="warm"], .cast-stands[data-tone="warm"] { color: var(--stamp-green); border-color: var(--stamp-green); }
.cast-card-chip[data-tone="cool"], .cast-stands[data-tone="cool"] { color: var(--stamp-red); border-color: var(--stamp-red); }
.cast-pull { border-color: var(--res-trust); }
.cast-pull.none { color: var(--gray-text); border-color: var(--shadow); }
.cast-pull .ic { --ic: 13px; }
.cast-card .portrait.lg { width: 66px; height: 66px; font-size: 1.6rem; }
.cast-card-name { margin: 0; font-size: 1rem; }
.cast-card-name .mood-chip { margin: 0 0 0 6px; }
.cast-card-does { color: var(--gray-text); font-size: 0.92rem; }
.cast-card-role { font-weight: 700; } /* Role: before the job (the owner's call of 2026-10-22) */
.cast-section-label { font-size: 0.85rem; font-weight: 700; margin: 10px 0 2px; }
/* Under the header, the Business box (a system entry's read-only fields) and the Notes box, side by side where they fit */
.cast-boxes { display: grid; grid-template-columns: repeat(auto-fill, minmax(max(230px, calc(50% - 6px)), 1fr)); gap: 0 12px; align-items: start; } /* two columns at most, one when narrow; auto-fill, so someone not met yet (no Notes box) keeps Business in its column (the owner's call of 2026-10-22) */
.cast-boxes > .file, .cast-boxes > .groupbox { margin: 14px 0 4px; font-size: 0.92rem; }
/* The Business box keeps the address book's label beside its field, in both looks; on a phone (below) each label goes
   above its field instead. Either way a line stays within two lines of
   its field (the build holds plain_job and wants to 60 characters, CHAR_LIMITS). */
.cast-brought, .cal-items { list-style: none; margin: 0; padding: 0; } /* what a person brought and a Calendar day's items: plain lists */
.cast-brought li + li { margin-top: 2px; }
.cast-brought .sym-ic { width: var(--ic-inline); height: var(--ic-inline); margin-right: 4px; vertical-align: -0.15em; } /* the status mark's picture (C.ICONS.status) */
.cast-brought .st-live .sym-ic { color: var(--act-on); } .cast-brought .st-unassessed .sym-ic { color: var(--stamp-red); }
.cast-brought .link-btn { min-height: 0; padding: 0; font-size: inherit; text-align: left; }
.cast-dept-sw { display: inline-block; width: 9px; height: 9px; background: var(--dept); border: 1px solid var(--dark); margin-right: 6px; vertical-align: -1px; }
/* Their line on a white panel, opened by a quote mark in their department's colour */
.cast-quote { position: relative; font-style: italic; margin: 0 0 4px; padding: 3px 6px 3px 22px; color: var(--window-text); background: var(--window); border: 1px solid; border-color: var(--shadow) var(--hilight) var(--hilight) var(--shadow); }
.cast-quote::before { content: '\201C'; position: absolute; left: 5px; top: -2px; font: 700 1.6rem/1 var(--font-serif); color: var(--dept); }
.cast-notes .hint { margin: 0; }
.cast-diary { list-style: none; font-size: 0.9rem; }
.cast-diary li { display: grid; grid-template-columns: 96px 1fr; gap: 8px; padding: 2px 0; border-bottom: 1px dotted var(--shadow); }
.cast-diary .diary-date { color: var(--gray-text); white-space: nowrap; font-weight: normal; }
.cast-diary .diary-date::after { content: none; }
.cast-status { margin-top: 2px; }
@media (max-width: 760px) {
  .cast-main { grid-template-columns: 1fr; }
  body:not([data-os="modern"]) .cast-main { grid-template-rows: none; }
  .file { grid-template-columns: minmax(0, 1fr); row-gap: 2px; } /* each label above its field: a System entry line and a person's Business box line stay within two lines */
  .file dt { padding-top: 0; }
  .file dd + dt { margin-top: 6px; }
  body:not([data-os="modern"]) :is(.cast-folders, .cast-cols, .cast-list, .cast-detail-box) { grid-column: 1; grid-row: auto; } /* one column on a phone: folders, list, card */
  .cast-folders { flex-direction: row; flex-wrap: wrap; padding: 4px; }
  body:not([data-os="modern"]) .cast-folders::before { content: none; }
  .cast-folder { margin: 0; padding-left: 24px; }
  body:not([data-os="modern"]) .cast-folder::before { content: none; }
  body:not([data-os="modern"]) .cast-folder::after { left: 6px; }
  .cast-body { --cast-cols: 26px minmax(0, 1.6fr) minmax(0, 1.4fr) 84px; }
  .cast-cols span:nth-child(4), .cast-cols span:nth-child(6), .cast-row .cast-dept, .cast-row .cast-met { display: none; }
  .cast-card { grid-template-columns: auto minmax(0, 1fr); }
  .cast-card .portrait { grid-row: 1 / span 3; }
  .cast-card-chips { grid-column: 2; grid-row: auto; justify-self: start; margin-top: 2px; } /* under the job, so the name keeps its width */
  .cast-card-met { display: none; } /* the stance alone, so the influence chip fits beside it on one line; when they were met is a desktop detail */
}

/* ── Timeline ── */
.timeline li { display: grid; grid-template-columns: 140px 1fr; gap: 12px; padding: 6px 8px; border-bottom: var(--row-rule); font-size: 0.95rem; }
.timeline li:last-child { border-bottom: none; }
.timeline li.now { background: var(--select); color: var(--select-text); }
.timeline li.now * { color: inherit; }
.timeline li.open .tl-when { color: var(--stamp-red); }
.tl-date { display: flex; flex-direction: column; align-items: flex-start; gap: 3px; font-weight: 700; }
.tl-when, .cal-legend li { display: inline-flex; align-items: center; gap: 3px; } /* a Timeline date's when and a Calendar key's entry: a mark beside its word */
.tl-date .state-chip { font-weight: 400; }
.timeline li.now .state-chip { --chip: var(--select-text); background: transparent; }
.tl-label { font-weight: 700; }
.tl-what { color: var(--gray-text); font-size: 0.92rem; }
.tl-turn { font-size: 0.85rem; color: var(--gray-text); margin-top: 2px; }

/* ── Reference: a docked window with a tree ── */
.drawer { position: fixed; inset: 0; z-index: 45; background: rgba(0,0,0,0.25); display: flex; justify-content: flex-end; }
.drawer-panel { position: relative; width: min(560px, 100%); height: 100%; display: flex; flex-direction: column; padding: 2px; }
.drawer-panel > .client { flex: 1; display: flex; flex-direction: column; min-height: 0; }
.drawer-tabs { display: flex; gap: 0; align-items: flex-end; margin-bottom: 0; padding: 0 2px; position: relative; z-index: 1; }
.drawer-tab { border-bottom: none; padding: 3px 10px 4px; margin-right: -1px; font-size: 0.95rem; min-height: calc(var(--target) - 2px); position: relative; top: 1px; color: var(--window-text); }
.drawer-tab.active { font-weight: 700; padding-bottom: 6px; margin-bottom: -1px; z-index: 2; }
.drawer-body { flex: 1; overflow: auto; padding: 4px 6px 4px 8px; margin-top: 0; }
.drawer-find { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 8px; padding: 2px 2px 8px; }
.drawer-find input { flex: 1 1 160px; min-width: 0; }
.drawer-met { color: var(--gray-text); font-size: 0.9rem; }
.drawer-panel .hint { padding: 6px 2px 4px; }
.drawer-entry { padding: 3px 0 3px 34px; position: relative; }
.drawer-entry summary { cursor: default; font-weight: 700; font-size: 0.95rem; display: flex; justify-content: space-between; gap: 8px; align-items: center; list-style: none; }
.drawer-entry summary::-webkit-details-marker { display: none; }
.drawer-entry summary::before { content: '+'; z-index: 1; position: absolute; left: 0; top: 4px; width: 11px; height: 11px; border: 1px solid var(--shadow); background: var(--window); font-size: 10px; line-height: 9px; text-align: center; font-weight: 400; font-family: var(--font-mono); }
.drawer-entry[open] summary::before { content: '−'; }
.drawer-entry summary:hover { background: var(--select); color: var(--select-text); }
.drawer-entry summary:hover .kind { color: inherit; }
.drawer-entry .kind { font-size: 0.85rem; color: var(--gray-text); white-space: nowrap; }
.drawer-entry .plain { margin: 6px 0 4px; font-size: 0.95rem; }
.drawer-entry .text { font-size: 0.9rem; color: var(--window-text); border-left: 2px solid var(--shadow); padding-left: 8px; margin-bottom: 4px; white-space: pre-wrap; font-family: var(--font-mono); }
.drawer-entry .text.current { border-left-color: var(--stamp-blue); }
.drawer-entry .wording-label { font-size: 0.85rem; color: var(--gray-text); margin: 6px 0 2px; }
.drawer-entry .src { font-size: 0.85rem; color: var(--gray-text); word-break: break-all; }
.drawer-entry.locked summary { color: var(--disabled-text); font-weight: 400; }

/* ── Report: a maximised window ── */
#screen-report { padding: 18px 12px; align-items: center; }
.report-wrap { max-width: 880px; width: 100%; }
.report-wrap h2 { margin: 18px 0 4px; }
.metric-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 6px; margin: 10px 0 6px; }
.metric-chip { display: flex; flex-direction: column; gap: 1px; padding: 6px 10px; }
.metric-label { font-size: 0.85rem; color: var(--gray-text); }
.metric-value { font-size: 1.3rem; font-weight: 700; }
.pane { padding: 0; overflow-x: auto; margin-bottom: 8px; }
.report-table { width: 100%; border-collapse: collapse; font-size: 0.92rem; }
.report-table th, .report-table td { text-align: left; padding: 3px 8px; vertical-align: top; }
.report-table th { font-weight: 400; background: var(--face); border: 1px solid; border-color: var(--hilight) var(--shadow) var(--shadow) var(--hilight); }
.report-table td { border-bottom: var(--row-rule); }
.report-table .st-due, .report-table .st-open { color: var(--stamp-red); font-weight: 700; } .report-table .st-funded { color: var(--stamp-green); }

/* ── Options, toast, tooltip ── */
/* Options is a property sheet of its era: etched group boxes with their captions on the line (the sheets' group box,
   further down), a checkbox or a labelled drop-down list on each row, and OK bottom right. The new desktop draws the
   same markup as a settings page (css/modern.css). */
.options-body { display: flex; flex-direction: column; gap: 4px; }
.options-body .opt-row { display: flex; gap: 6px; align-items: center; min-height: var(--target); }
.options-body select { padding: 2px 4px; }
.options-body .opt-group { margin: 6px 0 2px; padding: 12px 10px 8px; }
.options-body .opt-field { justify-content: space-between; gap: 10px; }
body:not([data-os="modern"]) .options-body .opt-field > .opt-text:has(+ select)::after { content: ':'; }   /* the colon the logon's field labels carry */
.options-body .opt-field > select { min-width: 150px; }
.options-body .opt-field:has(> .btn) { flex-wrap: wrap; }   /* on a narrow screen the button drops under its words */
.options-body .opt-field > .btn { margin-left: auto; }
/* An option that belongs to the one above it (the sound in mini games, under Sound): set in, and greyed while it
   cannot apply. */
.options-body .opt-sub { padding-left: 22px; }
.options-body .opt-sub:has(select:disabled) { color: var(--disabled-text); }
/* Story beats: the message box from the tray (revealStory in js/screens.js) */
#story-modal { z-index: 50; align-items: flex-start; padding: 28px 12px; }
#story-modal .sheet { margin: auto 0; }
.story-head { display: flex; align-items: center; gap: 8px; margin-bottom: 4px; }
.story-from { overflow-wrap: anywhere; }
/* A story message is a window that grows out of the tray (as-window). Under reduced motion it simply appears. */
.tutorial-note .client { background: var(--info); } /* the course's Helpdesk: the yellow client, docked at the tray corner */
body:not([data-os="modern"]) .tutorial-note::after { content: ''; position: absolute; right: 34px; bottom: -11px; border: 11px solid transparent; border-bottom: 0; border-top-color: var(--window-text); }
body:not([data-os="modern"]) .tutorial-note::before { content: ''; position: absolute; right: 35px; bottom: -9px; z-index: 1; border: 10px solid transparent; border-bottom: 0; border-top-color: var(--info); }
/* Helpdesk in the course. On the desk it is a note (the yellow client above, the tail to the tray) docked at the tray
   corner with no overlay behind it, so the desk stays in use; the desk gets room at
   its foot to scroll out from under it. Inside a sheet, a card or the assessment it is the short information bar at the
   top of the reading (the New contact bar's look), which never covers the sheet's contents or actions. */
.tutorial-hidden:not(#_):not(#_), .tutorial-coach[hidden]:not(#_):not(#_), .tutorial-coach [hidden]:not(#_):not(#_) { display: none; } /* the weight of two ids (as .act-btn:not(#_) is weighted), without the override the stylesheet keeps for .hidden alone */
.tutorial-note { position: fixed; right: 10px; bottom: 44px; z-index: 30; width: calc(100% - 20px); max-width: 360px; margin: 0; text-align: left; }
.tutorial-note.note-rise { --rise-y: 12px; animation: rise 0.25s ease-out; }
.tutorial-count { flex: none; font-weight: 400; font-size: 0.8rem; opacity: 0.85; }
/* The note's title bar is its fold (aria-expanded, the caret the fold bars draw): the client goes and comes back */
.tutorial-note > .titlebar { cursor: pointer; }
.tutorial-note > .titlebar:focus-visible { outline: 2px solid var(--action); outline-offset: -2px; }
.tutorial-caret { flex: none; width: 1em; text-align: center; }
.tutorial-coach-head[aria-expanded="true"] .tutorial-caret::before { content: '\25BE'; }
.tutorial-coach-head[aria-expanded="false"] .tutorial-caret::before { content: '\25B8'; }
body.course-note .desk { padding-bottom: 260px; }
.tutorial-title { margin: 2px 0 4px; }
.tutorial-objective { margin: 0; font-weight: 700; line-height: 1.35; }
.tutorial-text, .tutorial-hint { margin: 6px 0 0; line-height: 1.4; }
.tutorial-hint { padding-top: 6px; border-top: 1px dotted var(--shadow); }
.tutorial-coach-actions .btn { margin: 0; }
.tutorial-info { display: none; }
.tutorial-context { position: relative; margin: 6px 0 8px; color: var(--window-text); background: var(--info); border: 1px solid var(--shadow); }
.tutorial-context > .tutorial-coach-head { display: none; }
.tutorial-context > .tutorial-coach-body { display: block; padding: 6px 8px 6px 29px; }
.tutorial-context .tutorial-info { display: block; position: absolute; left: 8px; top: 7px; margin: 0; }
.tutorial-context .tutorial-objective { font-weight: 400; } /* one size with the text and the explanation under it (the owner, 2026-10-25) */
.tutorial-context .tutorial-text, .tutorial-context .tutorial-hint { margin-left: 12px; margin-right: 12px; color: var(--gray-text); } /* More info reads under the task: set in from it, in the secondary grey (the owner, 2026-10-25) */
.tutorial-context .tutorial-coach-actions { margin-top: 5px; }
/* The closing message: a card, centred as the quarter's cards are (its screen's rule is #screen-event's, above) */
.tutorial-complete-head { font-size: 1rem; margin: 10px 0 4px; }
.tutorial-complete-list { padding-left: 22px; margin: 0; }
.tutorial-complete-list li { margin-bottom: 4px; line-height: 1.45; }
/* The one rise-in: a tip's note, a desk tab, the folder, a card put down on the desk, the new desktop's splash and review rows, each setting how far (and how small, and how turned) it starts from */
@keyframes rise { from { opacity: 0; transform: translateY(var(--rise-y, 12px)) scale(var(--rise-scale, 1)) rotate(var(--rise-turn, 0deg)); } to { opacity: 1; transform: none; } }
#story-modal.as-window .sheet { transform-origin: 100% 100%; animation: windowOut 0.24s steps(4, end); }
@keyframes windowOut { from { transform: scale(0.1); opacity: 0.4; } to { transform: none; opacity: 1; } }
/* The tray's notice icon blinks while a message is on its way */
.tray-note { display: inline-flex; align-items: center; justify-content: center; width: 14px; height: 14px; margin-right: 6px; border-radius: 50%; background: var(--stamp-blue); color: var(--on-fill); font: 700 0.75rem/1 var(--font-glyph); animation: trayBlink 0.3s steps(2, end) infinite; }
@keyframes trayBlink { 50% { opacity: 0.15; } }
/* The toast (what someone says back, what an action did) sits three quarters of the way up the screen, where the eye is */
.toast { position: fixed; top: 25%; left: 50%; transform: translateX(-50%); max-width: min(560px, calc(100vw - 24px)); text-align: center; background: var(--info); color: var(--window-text); border: 1px solid var(--window-text); padding: 5px 12px; font-size: 0.95rem; z-index: 80; opacity: 0; transition: opacity 0.15s; }
.toast.show { opacity: 1; }
.tooltip { position: fixed; z-index: 100; max-width: 260px; background: var(--info); color: var(--window-text); border: 1px solid var(--window-text); padding: 3px 6px; font-size: 0.9rem; line-height: 1.35; pointer-events: none; opacity: 0; transition: opacity 0.1s; }
.tooltip.visible { opacity: 1; }

/* ── Play style: time on the desk ── */
.calendar { display: grid; grid-template-columns: 1fr; gap: 4px; padding: 4px; background: var(--window); font-family: var(--font-doc); }
.cal-head { display: block; width: 100%; padding: 0; font-family: inherit; color: inherit; cursor: inherit; font-weight: 700; font-size: 11px; text-align: center; background: var(--face); border: 1px solid var(--shadow); margin-bottom: 2px; line-height: 15px; }
.cal-grid { position: relative; display: grid; grid-template-columns: repeat(7, 1fr); gap: 1px; }
.cal-dow { font-size: 9px; color: var(--gray-text); text-align: center; border-bottom: 1px solid var(--shadow); line-height: 12px; }
.cal-day { font-size: 10px; text-align: center; line-height: 15px; position: relative; color: var(--window-text); }
.cal-day.past { color: var(--disabled-text); }
.cal-day.today { background: var(--select); color: var(--select-text); font-weight: 700; }
.cal-day.due::after { content: ''; position: absolute; left: 50%; bottom: 1px; width: 4px; height: 4px; margin-left: -2px; background: var(--stamp-red); }
.cal-day.last { outline: 1px dotted var(--window-text); outline-offset: -1px; }
/* The month's name between two arrows that page through the quarter; a day with something on it is a button that opens
   it in the panel under the month (fillCalendar in js/views.js). */
.cal-nav { display: grid; grid-template-columns: auto 1fr auto; align-items: center; gap: 2px; margin-bottom: 2px; }
.cal-nav .cal-head { margin-bottom: 0; }
.cal-arrow { font-family: inherit; font-size: 11px; line-height: 13px; width: 17px; padding: 0; color: var(--window-text); background: var(--face); border: 1px solid; border-color: var(--hilight) var(--dark) var(--dark) var(--hilight); cursor: pointer; }
.cal-arrow:active:not(:disabled) { border-color: var(--dark) var(--hilight) var(--hilight) var(--dark); }
.cal-arrow:disabled { color: var(--disabled-text); cursor: default; }
button.cal-day { display: block; width: 100%; margin: 0; padding: 0; border: 0; background: transparent; font-family: inherit; cursor: pointer; }
button.cal-day.today { background: var(--select); }
.cal-day.selected { box-shadow: inset 0 0 0 1px var(--window-text); }
.cal-day.today.selected { box-shadow: inset 0 0 0 1px var(--select-text); }
/* A date of the Act: a corner flag, as on the Year planner. */
.cal-day.act::before { content: '§'; position: absolute; top: -1px; right: 1px; font: 700 8px/1 var(--font-serif); color: var(--stamp-blue); } /* a date in the Act: the § of the symbol language */
.cal-day.today.act::before { border-top-color: var(--select-text); border-right-color: var(--select-text); }
/* A card on its way: a small square in the corner of the day it arrives. */
.cal-day.expected { background-image: linear-gradient(var(--stamp-blue), var(--stamp-blue)); background-size: 4px 4px; background-repeat: no-repeat; background-position: 1px 1px; }
/* Cards coming back next quarter: a bar under the quarter's last day. */
.cal-day.back { box-shadow: inset 0 -2px var(--stamp-blue); }
.cal-panel { margin-top: 3px; padding-top: 3px; border-top: 1px solid var(--shadow); font-size: 11px; line-height: 1.3; }
.cal-panel-head { display: flex; align-items: center; justify-content: space-between; gap: 4px; font-weight: 700; }
.cal-panel-close { font-family: inherit; font-size: 11px; line-height: 11px; width: 15px; height: 14px; padding: 0; color: var(--window-text); background: var(--face); border: 1px solid; border-color: var(--hilight) var(--dark) var(--dark) var(--hilight); cursor: pointer; }
.cal-group { margin-top: 3px; }
.cal-group-head { color: var(--gray-text); font-size: 10px; display: flex; align-items: center; gap: 3px; }
.cal-group-head .ic, .cal-legend .ic { --ic: 16px; } /* pixel icons keep their grid (16px): smaller, the hourglass reads as a § */
.cal-sym[data-kind="due"] { color: var(--stamp-red); } .cal-sym[data-kind="expected"], .cal-sym[data-kind="back"] { color: var(--stamp-blue); }
/* The key under the month: each day mark as it looks on a day, its symbol and its word */
.cal-legend { list-style: none; display: flex; flex-wrap: wrap; gap: 2px 10px; margin: 4px 0 0; padding: 0; font-size: 10px; color: var(--gray-text); }
.cal-legend .cal-mark { display: inline-block; width: 6px; height: 6px; }
.cal-legend li[data-kind="due"] .cal-mark { width: 4px; height: 4px; background: var(--stamp-red); }
.cal-legend li[data-kind="expected"] .cal-mark { width: 4px; height: 4px; background: var(--stamp-blue); }
.cal-legend li[data-kind="back"] .cal-mark { height: 2px; background: var(--stamp-blue); }
.cal-legend li[data-kind="act"] .cal-mark { display: none; } /* the § itself is the mark */
.cal-item { display: flex; flex-direction: column; width: 100%; padding: 1px 2px; text-align: left; font-family: inherit; font-size: 11px; color: var(--window-text); background: none; border: 0; }
button.cal-item { color: var(--link); cursor: pointer; }
button.cal-item .cal-item-text { text-decoration: underline; }
.cal-item small { color: var(--gray-text); font-size: 10px; }
.cal-empty { margin-top: 2px; color: var(--gray-text); }
.cal-wait-row { margin-top: 4px; }
.cal-wait { width: 100%; min-height: 0; padding: 2px 6px; font-size: 11px; }
.cal-wait-warn { margin-top: 2px; color: var(--stamp-red); font-size: 10px; }
/* The date moving on (calendarTravel in js/screens.js): today's marker, one square under the numbers, hops a day at a
   time to the new date; the cell it stands on shows its number as today's does. On arrival the new date blinks inside
   an outline; under reduced motion there is no travel and the outline stays, still. */
.cal-marker { position: absolute; background: var(--select); pointer-events: none; transition-property: none; }
.cal-moving .cal-day.today { background: transparent; color: inherit; font-weight: inherit; }
.cal-moving .cal-day.past.today { color: var(--disabled-text); }
.cal-moving .cal-day.under { color: var(--select-text); font-weight: 700; }
.cal-day.cal-arrive { outline: 2px solid var(--action); outline-offset: 1px; z-index: 2; animation: calArrive 0.36s steps(2, end) 3; }
@keyframes calArrive { 0% { background: var(--select); color: var(--select-text); } 50% { background: var(--window); color: var(--select); } }
.task-btn.task-flash { animation: taskFlash 0.4s steps(2, end) 3; }
@keyframes taskFlash { 0% { background: var(--select); color: var(--select-text); } }

/* ── Play style: triage cues ── */
#tab-intray .count-soft { font-weight: 700; color: var(--select); }
.doc:has(.time-chip[data-time="answer_by"].urgent) { border-left: 2px solid var(--stamp-red); } /* the answer-by chip's red clock says why */

/* ── Play style: assessment as a wizard ── */
.wizard { max-width: 640px; }
.wizard .client { display: grid; grid-template-columns: 150px 1fr; gap: 0; padding: 0; }
.wizard-banner { background: linear-gradient(180deg, var(--title-a), var(--title-b)); color: #fff; padding: 12px 10px; display: flex; align-items: flex-end; min-height: 320px; }
.wizard-banner .sheet-title { color: #fff; font-size: 1.05rem; margin: 0; }
.wizard-page { padding: 12px 14px 10px; display: flex; flex-direction: column; min-height: 320px; }
.wizard-page .sheet-meta { justify-content: flex-end; }
.wizard-page #assess-progress:not(:empty)::before { content: 'Step '; }
#assess-options .choice, #assess-options .choice.chosen, #assess-options .choice:active { border-color: transparent; box-shadow: none; background: transparent; padding: 4px 8px 4px 26px; position: relative; min-height: 26px; }
#assess-options .choice:hover { background: var(--face-light); }
#assess-options .choice::before { content: ''; position: absolute; left: 6px; top: 8px; width: 12px; height: 12px; border-radius: 50%; background: var(--window); border: 1px solid; border-color: var(--shadow) var(--hilight) var(--hilight) var(--shadow); box-shadow: inset 1px 1px var(--dark); }
#assess-options .choice.chosen::before { background: radial-gradient(circle, var(--window-text) 3px, var(--window) 3.5px); }
.wizard .outcome { border-top: 1px solid var(--shadow); box-shadow: inset 0 1px var(--hilight); margin-top: auto; padding-top: 8px; }
.wizard .actions { justify-content: flex-end; }
#assess-next-btn::after { content: ' >'; }

/* ── Play style: group boxes on property sheets ── */
.groupbox, .opt-group, .file, #prog-levels { position: relative; border: 1px solid var(--box-edge); box-shadow: var(--box-shadow); border-radius: var(--box-radius); padding: 14px 10px 10px; margin: 12px 0 14px; background: var(--box-bg); }
.groupbox > .legend, .opt-group > .legend, .file::before, #prog-levels::before { position: absolute; top: -9px; left: 8px; background: var(--face); padding: 0 4px; margin: 0; font-size: 0.9rem; font-weight: 700; line-height: 1.2; }
.file::before { content: attr(data-legend); } /* meta.ui.reg_box, set on the element (js/views.js) */
#prog-levels::before { content: attr(data-legend); } /* the word is content's (meta.ui prog_sizes_heading) */
#sys-controls-wrap .hint { margin-bottom: 8px; padding-bottom: 2px; }
/* The way out of an assessment started by mistake (stopAssessment in js/screens.js) */
.assess-stop-row { margin: 8px 0 0; font-size: 0.85rem; }
.assess-stop-row .link-btn { min-height: 0; font-size: inherit; }
/* The proposal, programme and one-off windows fit the screen: the title bar stays, the rest scrolls inside (the client's scroll rule is the Timeline list's, above) */
#modal-system > .sheet, #modal-programme > .sheet, #modal-intervention > .sheet, #modal-qmail > .sheet, #modal-timeline > .sheet { display: flex; flex-direction: column; max-height: calc(100dvh - var(--overlay-pad-y, 88px)); }
/* The System entry, the EU AI Act Profile, What it needs and the found pitch fold to their heading (wireFoldbox in
   js/views.js). On the system sheet the heading is a raised bar, since it can be pressed, with what the box holds on its
   right while it is folded (.box-sum). Every fold box is drawn this way: the two upper are .fold-bar; What it needs and
   then the pitch sit in #sys-lower */
.foldbox > h3 .box-toggle:focus-visible { outline: 1px dotted var(--window-text); }
.foldbox.folded > .box-body { display: none; }
.foldbox { margin: 8px 0 0; }
.foldbox > h3 { position: static; padding: 0; background: none; }
#sys-lower .foldbox > h3 { margin: 0; font-size: 0.9rem; line-height: 1.2; } /* the lower boxes' headings are a size smaller than the upper bars' (as the group-box legend was) */
.foldbox > h3 .box-toggle { all: unset; cursor: pointer; font: inherit; box-sizing: border-box; display: flex; flex-wrap: wrap; align-items: center; gap: 4px 8px; width: 100%; min-height: var(--target); padding: 2px 8px; background: var(--bar-bg); border: 1px solid; border-color: var(--bar-edge); box-shadow: var(--bar-shadow); border-radius: var(--bar-radius); }
.foldbox > .box-body { padding: 8px 10px; border: 1px solid var(--box-edge); border-top: none; background: var(--box-bg); }
/* The System entry and the Profile inside their folds: the bar is their heading, so the boxes lose their own frame */
.fold-bar .file { margin: 0; padding: 0; border: none; box-shadow: none; background: none; }
.fold-bar .file::before { content: none; }
/* A bar's own picture before its heading (foldbox icon): the register's on System entry, the law's § on the Profile */
.box-toggle > .box-ic { display: inline-flex; align-items: center; flex: none; --ic: 16px; }
.box-toggle > .box-ic .src-act { font-size: 1.05rem; line-height: 1; }
.box-toggle > .box-ic .duty-tile { --sym-tile: 18px; --sym-ic: 12px; } /* the register's picture on its paper tile, at the size a node's covers use */
/* The Profile's box takes the risk level's tone once assessed (fillSystemSheet data-tone, the tones of the tier badge):
   an edge along its bar and down its page; grey until then */
.foldbox[data-tone="red"] { --tier-tone: var(--stamp-red); } .foldbox[data-tone="amber"] { --tier-tone: var(--stamp-amber); } .foldbox[data-tone="blue"] { --tier-tone: var(--stamp-blue); }
.foldbox[data-tone="green"] { --tier-tone: var(--stamp-green); } .foldbox[data-tone="ink"] { --tier-tone: var(--gray-text); }
.fold-bar[data-tone] > h3 .box-toggle { box-shadow: inset 0 3px var(--tier-tone), var(--bar-shadow); padding-top: 5px; } /* the words keep clear of the edge (the owner's note of 2026-10-25) */
/* System entry is a form on a page, the Profile a page with the tone down its edge (the owner's calls of 2026-10-25) */
#sys-register-wrap > .box-body, #sys-legal-wrap > .box-body { background: var(--window); }
#sys-legal-wrap > .box-body { border-left: 4px solid var(--tier-tone, var(--shadow)); }
.box-toggle .box-label { white-space: nowrap; } /* the heading stays whole; what the box holds goes under it where the bar is too narrow for both */
.box-toggle .box-sum { margin-left: auto; display: inline-flex; flex-wrap: wrap; justify-content: flex-end; align-items: center; gap: 4px 8px; font-weight: 400; font-size: 0.85rem; color: var(--gray-text); }
.foldbox:not(.folded) .box-sum { display: none; }
/* The pitch's box (fillSystemSheet): the pitch is its own page, so the body adds no frame; before the tier is known the box
   has no bar (.no-bar) and the pitch stands as it always did. Once the tier is known the fill places it among the lower
   boxes, just above Story so far. */
#sys-pitch-wrap > .box-body { padding: 0; border: none; background: none; }
.foldbox.no-bar { margin: 0; }
.foldbox.no-bar > h3 { display: none; }
.actions-head { margin: 12px 0 -4px; font-size: 0.9rem; line-height: 1.2; }
/* A programme size's cost on its button's foot (costRow in fillProgrammeSheet): the figures with their pictures, then the days. */
.level-cost .figure-word { font-weight: 600; }
.box-sum .sum-tiles { display: inline-flex; gap: 2px; }
.box-sum .duty-tile { --sym-tile: 15px; --sym-ic: 11px; }
/* The system sheet scrolls as one window: its boxes fold instead of scrolling inside it (the owner's call of 2026-10-12) */
#modal-system > .sheet > .client > #sys-lower { margin-top: 6px; padding-top: 2px; border-top: 1px solid var(--shadow); box-shadow: 0 -1px var(--hilight); }

/* The New contact bar (fillContactBar): the first time someone is met on a message or a sheet, an information bar names
   them, each name a link to their card in People */
.contact-bar { display: flex; align-items: flex-start; gap: 6px; margin: 0 0 8px; padding: 4px 8px; font-size: 0.9rem; color: var(--window-text); background: var(--info); border: 1px solid var(--shadow); }
.msgbox .contact-bar { margin: 6px 0 0; }
.contact-bar-i { flex: none; width: 15px; height: 15px; margin-top: 1px; border-radius: 50%; background: var(--stamp-blue); color: var(--on-fill); font: italic 700 11px/15px var(--font-glyph); text-align: center; }
.contact-bar-text { min-width: 0; }
.link-btn.person-link { min-height: 0; padding: 0; font-size: inherit; vertical-align: baseline; }
/* A message's sender and the people copied in open their card: the face as a plain button, the copied as chips */
.portrait-btn { padding: 0; margin: 0; border: none; background: none; box-shadow: none; cursor: pointer; }
.portrait-btn:focus-visible, button.person-chip:focus-visible { outline: 1px dotted var(--window-text); outline-offset: 1px; }
button.person-chip { font: inherit; color: inherit; background: none; border: 1px solid transparent; box-shadow: none; padding: 0 4px 0 0; cursor: pointer; }
button.person-chip:hover { border-color: var(--shadow); }
/* The pitch: a page headed by the people in the room (fillSheetHeader, fromLine), drawn as the Message window's body.
   Each name is raised: it folds open on who they are, what the proposer's pull means, and their card in People
   (.person-note). The proposer's aside in their mood closes the pitch (.pitch-aside) */
.sheet-pitch { margin: 2px 0 10px; background: var(--window); color: var(--window-text); }
.sheet-pitch > .pitch-from { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 8px; margin: 1px 1px 0; padding: 4px 8px; background: var(--face); border-bottom: 1px solid var(--shadow); }
.pitch-from .from-label { font-size: 0.9rem; font-weight: 700; }
.pitch-from .people { flex: 1 1 12em; margin: 0; color: var(--window-text); } /* beside "From:", wrapping inside itself on a phone */
.sheet-pitch > .scene { margin: 0; padding: 8px 10px; font-family: var(--font-doc); }
.sheet-pitch > .pitch-aside { margin: -4px 0 0; padding: 0 10px 8px; font-family: var(--font-doc); font-style: italic; color: var(--gray-text); } /* how this meeting goes, by their mood */
.sheet-pitch > .pitch-foot { display: flex; flex-wrap: wrap; gap: 4px 8px; margin: 0 1px 1px; padding: 5px 10px; border-top: 1px dotted var(--shadow); } /* the claim signs off the pitch */
.person-note { margin: 0 1px; padding: 5px 10px; font-size: 0.9rem; color: var(--window-text); background: var(--info); border-bottom: 1px solid var(--shadow); }
.person-note p { margin: 0; } .person-note p + p { margin-top: 3px; }
.pitch-from button.person { gap: 5px; padding: 1px 6px 1px 1px; font: inherit; color: inherit; cursor: pointer; }
.pitch-from button.person:focus-visible { outline: 1px dotted var(--window-text); outline-offset: -3px; }
.person.lead .mood-chip { margin: 0; }
.lead-cue { display: inline-flex; align-items: center; gap: 3px; font-size: 0.85rem; color: var(--res-trust); white-space: nowrap; }
.lead-cue .ic { --ic: 13px; }
.lead-caret::before { font-size: 0.8rem; }
.person-note .note-card { font-size: inherit; padding: 0; } /* their card in People, on its own line, at the tap height a link button has */
/* The system entry's facts are read, not typed: a read-only field, sunken on the window's face */
dl.file dd { background: var(--face); }
/* The EU AI Act Profile (fillLegalBox): labelled rows */
.act-box .act-rows { display: grid; grid-template-columns: minmax(28px, max-content) minmax(0, 1fr); gap: 5px 10px; margin: 0; align-items: baseline; }
/* Each row leads with its symbol (fillLegalBox), its word kept for a screen reader; Why keeps its word */
.act-rows dt { font-size: 0.9rem; font-weight: 700; color: var(--gray-text); display: inline-flex; align-items: center; justify-content: center; --ic: 18px; align-self: center; }
.act-rows dd { margin: 0; line-height: 1.55; }
.act-rows dd > :is(.tier-badge, .tag, .state-chip) { margin: 0 6px 2px 0; }
.act-rows .tier-badge { font-size: 1rem; padding: 1px 8px; }
.act-unknown { margin: 0; display: flex; flex-wrap: wrap; align-items: center; gap: 4px 8px; color: var(--gray-text); }
.actions-note { display: flex; align-items: center; gap: 5px; margin: 6px 0 0; font-size: 0.85rem; color: var(--gray-text); }
.actions-note .ic { --ic: 14px; flex: none; }
/* A locked action (Build before the data lab): a lock in its corner, and the line under the buttons says what it needs */
.btn.is-locked { position: relative; }
.btn-lock { position: absolute; top: 5px; left: 5px; width: 14px; height: 14px; color: var(--disabled-text); }
.actions-needs { flex-wrap: wrap; color: var(--window-text); }
/* The test-build note and the form links (meta.test_note, meta.links): small, with the links underlined. */
.test-note { margin: 0 0 10px; font-size: 0.85rem; color: var(--gray-text); }
.test-note a { color: var(--link); text-decoration: underline; }
.rv-links { margin: -4px 0 10px; }

/* ── Play style: Reference as Windows Help ── */
body:not([data-os="modern"]) .drawer-entry::before { content: ''; position: absolute; left: 5px; top: 0; bottom: 0; border-left: 1px dotted var(--shadow); }
.drawer-entry summary > span:first-child::before { content: ''; display: inline-block; width: 10px; height: 12px; margin-right: 6px; vertical-align: -2px; border: 1px solid var(--dark); background: linear-gradient(90deg, #6d2323 0 3px, #b84040 3px); }
.drawer-entry[open] summary > span:first-child::before { background: linear-gradient(90deg, var(--window) 0 4px, var(--shadow) 4px 5px, var(--window) 5px); }
.help-status { display: flex; gap: 3px; margin-top: 4px; }
.help-status > * { flex: 1; margin: 0; padding: 2px 6px; font-size: 0.85rem; min-height: 20px; border: 1px solid; border-color: var(--shadow) var(--hilight) var(--hilight) var(--shadow); color: var(--window-text); }
.help-status .badge { flex: 2; color: var(--gray-text); }

/* ── Play style: logon ── */
.logon-banner { background: linear-gradient(90deg, var(--title-a), var(--title-b)); color: #fff; padding: 10px 12px 12px; margin: -10px -10px 12px; }
.logon-banner .menu-title { color: #fff; font-size: 1.4rem; margin: 0; }
.logon-fields { display: grid; grid-template-columns: 90px minmax(0, 320px); gap: 6px 8px; align-items: center; margin-bottom: 12px; }
.logon-label { font-size: 0.95rem; }
/* The logon paints in as the page loads (#screen-menu carries .logon-paint from index.html): an outline grows in steps,
   as the old machine drew a window opening, then the window comes up and its parts appear top to bottom, about half a
   second in all. Everything is visible unless an animation hides it, so under reduced motion the logon is simply
   there. Screens are never display:none, so it does not play again after Log off. The old machine's: the new desktop's logon
   comes up as its windows do. */
body:not([data-os="modern"]) .logon-paint .logon { position: relative; animation: logonPart 1ms steps(1) 0.3s both; }
body:not([data-os="modern"]) .logon-paint .logon::after { content: ''; position: absolute; inset: 0; border: 2px solid var(--face); visibility: visible; opacity: 0; pointer-events: none; animation: logonOutline 0.3s steps(3, end) both; }
body:not([data-os="modern"]) .logon-paint .logon .titlebar { animation: logonPart 1ms steps(1) 0.3s both; }
body:not([data-os="modern"]) .logon-paint .logon-banner { animation: logonPart 1ms steps(1) 0.38s both; }
body:not([data-os="modern"]) .logon-paint .logon-fields { animation: logonPart 1ms steps(1) 0.46s both; }
body:not([data-os="modern"]) .logon-paint .logon .client > :not(.logon-banner):not(.logon-fields) { animation: logonPart 1ms steps(1) 0.54s both; }
@keyframes logonPart { from { visibility: hidden; } to { visibility: visible; } }
@keyframes logonOutline { from { transform: scale(0.35); opacity: 1; } 99% { transform: none; opacity: 1; } to { opacity: 0; } }
/* The asset tag on the logon's desktop: no taskbar there, so it sits at the foot, under the window. */
#screen-menu .asset-tag { bottom: 12px; }
/* A filled-in field: the logon's user name and the system entry's values on a proposal sheet */
.logon-fields .field, .file dd { background: var(--window); color: var(--window-text); padding: 2px 6px; min-height: 22px; }
.logon-fields .field { border: 1px solid; border-color: var(--shadow) var(--hilight) var(--hilight) var(--shadow); box-shadow: inset 1px 1px var(--dark), inset -1px -1px var(--face-light); } /* its own bevel, not --field-*: the logon can be on screen with a modern save's look, and keeps the look it has there */

/* About: the old desktop's own About box. A banner in the title-bar colours with a thin stripe, the product and
   its version, an etched rule, a sunken text box that scrolls, and who the copy is licensed to. Tokens only. */
.about-box { max-width: 480px; }
.about-banner { position: relative; display: flex; align-items: center; gap: 12px; padding: 14px 16px 16px; background: linear-gradient(90deg, var(--title-a), var(--title-b)); color: var(--title-text); }
body:not([data-os="modern"]) .about-banner::after { content: ''; position: absolute; left: 0; right: 0; bottom: 0; height: 4px; background: linear-gradient(90deg, var(--stamp-red) 0 25%, var(--stamp-amber) 25% 50%, var(--stamp-green) 50% 75%, var(--stamp-blue) 75%); }
.about-glyph { display: flex; flex: none; align-items: center; justify-content: center; width: 40px; height: 40px; border: 2px solid var(--title-text); border-radius: 50%; font: italic 700 1.6rem var(--font-serif); }
.about-banner-text { min-width: 0; }
.about-banner-name { display: block; font-size: 1.3rem; font-weight: 700; line-height: 1.2; }
.about-banner-sub { display: block; font-size: 0.88rem; }
.about-version { margin: 0; font-size: 0.92rem; }
.about-rule { border: 0; border-top: 1px solid var(--shadow); border-bottom: 1px solid var(--hilight); margin: 10px 0; }
.about-body { max-height: 240px; overflow: auto; padding: 6px 10px; background: var(--window); color: var(--window-text); }
.about-body:focus-visible { outline: 1px dotted var(--window-text); outline-offset: 2px; }
.about-body h3 { font-size: 0.95rem; margin: 10px 0 2px; }
.about-body h3:first-child { margin-top: 2px; }
.about-body p { margin: 0 0 6px; font-size: 0.92rem; }
.about-links { margin: 0 0 6px; padding-left: 18px; font-size: 0.92rem; }
.about-links a { color: var(--link); text-decoration: underline; }
/* An anchor dressed as .btn (the forms in About, the services in the share window, the holding page's sign-up) sits and reads as a button. */
a.btn { display: inline-flex; align-items: center; justify-content: center; text-decoration: none; color: var(--window-text); }
/* The forms in About are buttons beside OK, ahead of it in the row, OK at the end. */
.actions a.about-form { order: -2; }
.about-privacy { margin: 8px 0 0; font-size: 0.9rem; }
/* Help (the Staff handbook until 0.8.46): a Help viewer (handbookModel in js/views.js, the owner's call of 2026-10-14),
   How to play its first book. Its contents down
   the left, the search over them and the books in a sunken tree box, a book opening to its pages as the old Help's
   Contents did; the page on the right, the About box's scrolling text box. */
.handbook-box { max-width: 780px; }
.handbook-main { display: grid; grid-template-columns: 210px minmax(0, 1fr); gap: 8px; }
.handbook-side { display: flex; flex-direction: column; gap: 6px; min-width: 0; height: 58vh; } /* as tall as the page beside it */
.hb-search { width: 100%; }
.handbook-nav { flex: 1; min-height: 0; overflow: auto; padding: 4px 2px; background: var(--window); }
.hb-book, .hb-topic { display: block; width: 100%; text-align: left; background: none; border: 1px dotted transparent; padding: 2px 4px; font: inherit; color: var(--window-text); cursor: pointer; }
.hb-book { font-weight: 700; }
.hb-book::before { display: inline-block; width: 1em; }
.hb-topics { list-style: none; margin: 0 0 4px; padding: 0 0 0 1em; }
.hb-topic { font-size: 0.92rem; }
.hb-topic.active { background: var(--select); color: var(--select-text); }
.hb-book:focus-visible, .hb-topic:focus-visible { border-color: var(--window-text); outline: none; }
.handbook-page { height: 58vh; max-height: none; padding: 8px 14px 10px; }
.handbook-page h3:first-child { margin-top: 2px; }
.hb-lead { margin: 0 0 4px; font-size: 0.85rem; }
.hb-rules { margin: 0 0 8px; padding-left: 18px; font-size: 0.92rem; } /* the rules pages a search finds, each heading a link to its page */
.hb-terms { display: grid; grid-template-columns: minmax(7em, 11em) 1fr; margin: 0 0 8px; } /* no gap between the columns, so the dotted rule under a term runs unbroken */
.hb-terms dt, .hb-terms dd { margin: 0; padding: 4px 0; border-bottom: 1px dotted var(--shadow); font-size: 0.92rem; }
.hb-terms dt { font-weight: 700; padding-right: 12px; }
.hb-key li { grid-template-columns: minmax(9.5em, auto) 1fr; }
.hb-button { min-width: 36px; display: inline-flex; justify-content: center; pointer-events: none; }
.hb-swatch { display: inline-block; flex: none; width: 26px; height: 14px; border: 1px solid var(--window-text); }
.hb-band.band-steady { background: var(--stamp-green); }
.hb-band.band-watchful { background: var(--stamp-amber); }
.hb-band.band-shaken { background: var(--stamp-red); }
.hb-depts { list-style: none; margin: 0 0 6px; padding: 0; display: flex; flex-wrap: wrap; gap: 4px 14px; }
.hb-depts li { display: inline-flex; align-items: center; gap: 6px; font-size: 0.88rem; }
.hb-depts .hb-swatch { width: 12px; height: 12px; }
.about-privacy a, .about-version a, .analytics-opt a, .options-body a { color: var(--link); text-decoration: underline; }

/* privacy.html: one old-desktop window on the desktop colour. The window's width sets the line length, so the
   text fills it with even padding on both sides. */
.policy-body { padding: 16px; }
.policy-page { max-width: 640px; margin: 0 auto; }
.policy-page .client { background: var(--window); padding: 16px 24px 18px; }
.policy-page h1 { font-size: 1.4rem; margin: 4px 0 10px; }
.policy-page h2 { font-size: 1.1rem; margin: 18px 0 6px; }
.policy-page ul { padding-left: 22px; margin: 0 0 8px; }
.policy-page a { color: var(--link); text-decoration: underline; }
.policy-page .terms-credit { font-style: italic; }
@media (max-width: 480px) { .policy-body { padding: 8px; } .policy-page .client { padding: 12px 14px 14px; } }

/* soon.html, the holding page: the old desktop with one setup program that never quite finishes, its last button the
   sign-up. The window is the assessment wizard's shape (a banner down the left, the page beside it) with the install
   screen's bar. The corners are the desk's: the asset tag bottom right, the small print bottom left. One column on a
   phone, where the small print follows the window. */
.soon-body { display: flex; flex-direction: column; justify-content: center; padding: 24px 16px 64px; }
.soon-body .asset-tag { bottom: 12px; }
.soon-desk { position: relative; z-index: 1; width: 100%; max-width: 600px; margin: 0 auto; }
.soon-setup .soon-setup-client { display: grid; grid-template-columns: 120px minmax(0, 1fr); padding: 0; }
.soon-banner { display: flex; align-items: flex-end; padding: 12px 10px; background: linear-gradient(180deg, var(--title-a), var(--title-b)); color: var(--title-text); font-weight: 700; font-size: 1.05rem; line-height: 1.2; }
.soon-page { min-width: 0; padding: 12px 14px 10px; }
.soon-title { font-size: 1.3rem; margin: 0 0 4px; }
/* The components: the old desktop's check boxes, drawn (a disabled input greys its tick away), ticked unless left out */
.soon-parts { list-style: none; }
.soon-parts li { position: relative; margin: 3px 0; padding-left: 20px; }
.soon-parts li::before { content: ''; position: absolute; left: 0; top: 0.1em; width: 13px; height: 13px; background: var(--window); }
.soon-parts li.soon-on::after { content: ''; position: absolute; left: 5px; top: calc(0.1em + 2px); width: 3px; height: 6px; border: solid var(--window-text); border-width: 0 2px 2px 0; transform: rotate(45deg); }
.soon-status { margin: 0 0 4px; }
.soon-bar .install-fill { width: 97%; transition: width 0.15s steps(2, end); }
.soon-eta { margin: 4px 0 8px; }
/* Back and Next greyed, the sign-up where Cancel would be: last in the row, though it is the default button */
.soon-actions { padding-top: 10px; border-top: 1px solid var(--shadow); box-shadow: inset 0 1px var(--hilight); }
.soon-actions .btn-primary { order: 0; }
/* The message box that comes up once: the old desktop's warning, over the setup window, its one button centred */
.soon-popup { position: absolute; z-index: 2; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 300px; max-width: calc(100vw - 32px); box-shadow: inset -1px -1px var(--shadow), inset 1px 1px var(--hilight), 2px 2px 0 rgba(0, 0, 0, 0.35); }
.soon-popup-text { display: flex; align-items: center; gap: 12px; margin: 6px 4px 10px; }
.soon-popup-icon { flex: none; display: inline-flex; align-items: flex-end; justify-content: center; width: 32px; height: 28px; padding-bottom: 3px; background: var(--stamp-amber); color: #000000; font-weight: 700; font-size: 1rem; line-height: 1; clip-path: polygon(50% 0, 100% 100%, 0 100%); }
.soon-popup-icon::before { content: '!'; }
/* The last visit is a stop: the old desktop's red circle with a white cross */
.soon-popup[data-kind="stop"] .soon-popup-icon { align-items: center; width: 30px; height: 30px; padding: 0; background: var(--stamp-red); color: #ffffff; font-size: 1.2rem; clip-path: circle(50%); }
.soon-popup[data-kind="stop"] .soon-popup-icon::before { content: '\00D7'; }
.soon-popup .actions { justify-content: center; margin: 0 0 2px; }
/* The small print, bottom left: the asset tag's twin, in the same white on the desktop */
.soon-corner { position: fixed; left: 12px; bottom: 12px; z-index: 1; color: #ffffff; font-size: 0.8rem; line-height: 1.35; }
.soon-corner p { margin: 0; }
.soon-corner a { color: #ffffff; text-decoration: underline; }
.soon-corner .analytics-opt { margin: 4px 0 0; color: #ffffff; font-size: 0.8rem; }
@media (max-width: 760px) {
  .soon-body { padding: 16px; }
  .soon-setup .soon-setup-client { grid-template-columns: minmax(0, 1fr); }
  .soon-banner { display: none; } /* the title bar and the heading name the game already */
  /* Here a log line may wrap: two lines are held, the text sitting on the bar, so a short line does not pull the bar up */
  .soon-status { display: flex; align-items: flex-end; min-height: 2.8em; }
  .soon-corner { position: static; margin: 12px auto 0; width: 100%; max-width: 600px; }
  .soon-popup { position: fixed; }
}

/* The analytics checkbox at the foot of the logon: a dialog checkbox in small print, with the privacy link beside it. */
.analytics-opt { display: flex; flex-wrap: wrap; align-items: center; gap: 2px 10px; margin: 8px 0 0; font-size: 0.85rem; color: var(--gray-text); }
.analytics-opt label { display: inline-flex; align-items: center; }
@media (max-width: 760px) {
  .about-banner { padding: 10px 12px 12px; }
  .about-banner-sub { display: none; }
  .about-glyph { width: 32px; height: 32px; font-size: 1.3rem; }
}

/* Chrome is not text: buttons, title bars, tabs, the taskbar and menus cannot be selected by a stray drag. */
button, .btn, .titlebar, .taskbar, .folder-tab, .more-menu, .menubar, .toolbar, .choice, .new-game-item { -webkit-user-select: none; user-select: none; }

/* Pieces only the new desktop shows (css/modern.css): the search pill, Start search, the user row, the tray
   glyphs and the weekday on the clock. The old desktop never had them. */
.task-search, .start-search, .start-user, .tray-glyphs, .tray-day { display: none; }

/* ── The ending: the crash screen when trust runs out, the win when a full run reaches its last date, the splash when a quick run is done ── */
#screen-ending { align-items: center; justify-content: center; padding: 16px; }
.ending { width: 100%; max-width: 760px; outline: none; cursor: pointer; }
#ending-box:focus, #ending-box:focus-visible { outline: none; } /* focused so keys land here; it is not a control */
.ending-prompt { margin-top: 18px; }
/* The old desktop's stop screen: blue, white monospace, a blinking cursor */
#screen-ending:has(.ending-crash.ending-classic) { background: #0000aa; }
.crash-classic { color: #ffffff; font-family: "Lucida Console", "Courier New", monospace; font-size: 1.05rem; line-height: 1.5; max-width: 68ch; }
.crash-classic p { margin: 0 0 12px; }
.crash-classic .crash-head { display: inline-block; background: #aaaaaa; color: #0000aa; padding: 0 8px; font-weight: 700; margin-bottom: 18px; }
.crash-classic .crash-code { font-weight: 700; letter-spacing: 0.04em; }
.crash-cursor { display: inline-block; margin-left: 4px; animation: crash-blink 1s steps(1) infinite; }
.crash-cursor.still { animation: none; }
@keyframes crash-blink { 50% { opacity: 0; } }
/* The old desktop's splash: a banner in the title-bar gradient, and a strip of blocks that fills */
.ending-splash.ending-classic .splash { padding: 0 0 16px; }
.ending-splash.ending-classic .splash-banner { background: linear-gradient(90deg, var(--title-a), var(--title-b)); color: #ffffff; padding: 22px 24px 20px; display: grid; grid-template-columns: auto 1fr; column-gap: 16px; align-items: center; }
.ending-splash.ending-classic .splash-icon { grid-row: 1 / span 2; font-size: 2.6rem; }
.ending-splash.ending-classic .splash-title { margin: 0; font-size: 1.9rem; line-height: 1.15; color: #ffffff; }
.ending-splash.ending-classic .splash-line { margin: 6px 0 0; color: #e6eefa; }
.ending-splash.ending-classic .splash-style { margin: 16px 24px 0; font-weight: 700; font-size: 1.1rem; }
.ending-splash.ending-classic .splash-progress { margin: 14px 24px 0; height: 18px; border: 1px solid; border-color: var(--shadow) var(--hilight) var(--hilight) var(--shadow); padding: 2px; background: var(--window); }
.ending-splash.ending-classic .splash-progress i { display: block; height: 100%; width: 100%; background: repeating-linear-gradient(90deg, var(--select) 0 10px, transparent 10px 12px); transform-origin: left; animation: splash-fill 1.6s steps(24) both; }
.ending-splash.ending-classic .splash-progress.still i { animation: none; }
.ending-splash.ending-classic .ending-prompt { margin: 14px 24px 0; color: var(--gray-text); }
@keyframes splash-fill { from { transform: scaleX(0); } to { transform: scaleX(1); } }
/* The old desktop's win: the black screen that said it was now safe to switch off, in large orange letters */
#screen-ending:has(.ending-win.ending-classic) { background: #000000; }
.win-classic { color: #ff8c00; font-family: Arial, Helvetica, sans-serif; text-align: center; max-width: 64ch; margin: 0 auto; }
.win-classic p { margin: 0 0 12px; }
.win-classic .win-line { font-size: 1.2rem; }
.win-classic .win-safe { font-size: clamp(1.7rem, 4.6vw, 2.7rem); font-weight: 700; line-height: 1.25; margin: 6px 0 30px; }
.win-classic .win-grade { color: #ffffff; font-weight: 700; font-size: 1.25rem; }
.win-classic .ending-prompt { margin-top: 26px; color: #aaaaaa; font-family: "Lucida Console", "Courier New", monospace; font-size: 0.95rem; }

/* Text for screen readers only */
.copy-image { display: block; max-width: 100%; height: auto; margin: 8px 0; border: 1px solid var(--shadow); }
.sr-only, .pass-tile.on:not(.is-cheaper) .pass-word { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; } /* the pass tile's word stays for a screen reader once its tick shows (Once set up stays written) */

/* ── The programme review (js/endscreen.js), old desktop: a tabbed properties window ── */
.rv-hero { background: var(--window); border: 1px solid; border-color: var(--shadow) var(--hilight) var(--hilight) var(--shadow); padding: 10px 12px; }
.rv-hero-main { display: grid; grid-template-columns: auto 1fr; gap: 12px; align-items: start; }
.rv-hero-icon { font-size: 2.2rem; line-height: 1; }
.rv-hero-title { margin: 0; font-size: 1.45rem; line-height: 1.2; }
.rv-hero-trust .rv-hero-title { color: var(--stamp-red); }
.rv-hero-line { margin: 4px 0 0; }
.rv-hero-meta { margin: 4px 0 0; color: var(--gray-text); font-size: 0.9rem; }
.rv-style { margin-top: 10px; padding-top: 8px; border-top: 1px solid var(--shadow); box-shadow: 0 -1px var(--hilight) inset; }
.rv-style-pill { font-weight: 700; font-size: 1.1rem; }
.rv-style-line { margin: 2px 0 0; }
/* A win's letter: the mail window's header rows and its sunken body, inside the review */
.rv-letter { padding: 2px 2px 0; }
.rv-letter .msg-head { margin-bottom: 6px; }
.rv-letter .msg-body { min-height: 0; }
.rv-letter-text { margin: 0; line-height: 1.5; }
.rv-actions-top { display: flex; justify-content: flex-end; }
.rv-panel-title { display: none; }
.rv-panel.rv-off { display: none; } /* the tab not chosen; its own class, so the new look can show every panel without fighting .hidden */
.rv-detail > summary { display: none; }
.rv-groups { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
.rv-group { display: flex; flex-wrap: wrap; gap: 8px 18px; align-content: flex-start; }
.rv-fig { display: flex; flex-direction: column; min-width: 110px; }
.rv-num { font-size: 1.9rem; line-height: 1.1; display: inline-flex; align-items: center; gap: 4px; }
.rv-label { font-size: 0.9rem; }
.rv-sub { font-size: 0.82rem; color: var(--gray-text); }
.rv-bad, .rv-bad .rv-num { color: var(--stamp-red); }
.rv-mark { font-size: 0.8em; }
.rv-safety { display: flex; gap: 14px; align-items: flex-start; flex-wrap: wrap; width: 100%; }
.rv-ring { width: 130px; height: 130px; flex: none; }
.rv-safety-figs { display: flex; flex-wrap: wrap; gap: 6px 18px; flex: 1; min-width: 200px; }
.rv-reasons { list-style: none; margin: 0; padding: 0; width: 100%; font-size: 0.9rem; }
.rv-reasons li { padding: 1px 0; }
.rv-banned { margin: 2px 0 0; width: 100%; font-size: 0.9rem; }
.ring-safe { fill: var(--stamp-green); }
.ring-safe.full { fill: none; stroke: var(--stamp-green); }
.ring-unsafe { fill: url(#rv-hatch); }
.ring-unsafe.full { fill: none; stroke: url(#rv-hatch); }
.ring-empty { fill: none; stroke: var(--shadow); }
.hatch-bg { fill: var(--stamp-red); }
.hatch-line { stroke: rgba(255, 255, 255, 0.55); stroke-width: 2; }
.ring-num { font-size: 28px; font-weight: 700; fill: var(--window-text); }
.ring-sub { font-size: 11px; fill: var(--gray-text); }
.rv-trust-figs, .rv-reading-figs { display: flex; gap: 18px; flex-wrap: wrap; width: 100%; } /* the trust group's figures and the reading's (below) in one row */
.rv-years { display: flex; flex-wrap: wrap; gap: 4px; width: 100%; }
.rv-year { width: 58px; min-height: 58px; padding: 3px; display: flex; flex-direction: column; align-items: center; justify-content: center; color: var(--on-fill); border: 1px solid var(--dark); font-size: 0.72rem; line-height: 1.15; text-align: center; }
.rv-year.band-steady { background: var(--stamp-green); }
.rv-year.band-watchful { background: var(--band-watchful); color: #000000; }
.rv-year.band-shaken { background: var(--stamp-red); }
.rv-year-num { font-size: 1.15rem; font-weight: 700; }
.rv-footline { margin: 0; font-size: 0.92rem; }
.rv-take-group, .rv-reading-group { margin-bottom: 10px; }
/* Your reading of the Act (fillReading in js/views.js): the figures in a row as the trust group's, then the weakest article and a case to try */
.rv-reading-body { width: 100%; }
.rv-reading-weakest, .rv-reading-none, .rv-reading-done { margin: 8px 0 0; font-size: 0.92rem; }
.rv-reading-actions { margin: 8px 0 0; }
.rv-take-body { width: 100%; }
.rv-take-list { list-style: none; margin: 0; padding: 0; width: 100%; display: grid; gap: 8px; }
.rv-take-head, .rv-take-line, .rv-take-none { margin: 0; }
.rv-take-head { display: flex; flex-wrap: wrap; gap: 0 10px; align-items: baseline; }
.rv-take-sys { font-size: 0.9rem; color: var(--gray-text); }
.rv-take-line { font-size: 0.92rem; }
/* Performance monitor: black panel, green grid, bright green line and bars */
.rv-perf { display: grid; gap: 10px; }
.rv-figure { margin: 0; }
.rv-figure-title { font-weight: 700; margin-bottom: 3px; }
.rv-chart { display: block; width: 100%; height: auto; background: var(--chart-bg); border: 1px solid; border-color: var(--shadow) var(--hilight) var(--hilight) var(--shadow); }
.rv-chart .grid { stroke: var(--chart-grid); stroke-width: 1; }
.rv-chart .zone { fill: none; }
.rv-chart .area { fill: none; }
.rv-chart .line { fill: none; stroke: var(--chart-line); stroke-width: 2; stroke-linejoin: round; }
.rv-chart .threshold { stroke: var(--chart-line); stroke-width: 1; stroke-dasharray: 2 4; opacity: 0.7; }
.rv-chart .axis, .rv-chart .label { fill: var(--chart-line); font-family: "Lucida Console", "Courier New", monospace; font-size: 11px; }
.rv-chart .bar { fill: var(--chart-line); }
.rv-chart .marker { fill: var(--chart-bg); stroke: var(--chart-mark); stroke-width: 2; }
.rv-chart .label { fill: var(--chart-mark); paint-order: stroke; stroke: var(--chart-bg); stroke-width: 4px; stroke-linejoin: round; }
.rv-chart .hit { fill: transparent; }
.rv-chart .hit:hover { fill: rgba(0, 255, 0, 0.12); }
.rv-caption { margin-top: 4px; font-size: 0.88rem; }
.rv-table-wrap { overflow-x: auto; }
.rv-table th { padding: 0; }
.rv-sort { width: 100%; text-align: left; padding: 2px 6px; font: inherit; font-weight: 700; background: var(--face); color: var(--window-text); border: 1px solid; border-color: var(--hilight) var(--dark) var(--dark) var(--hilight); cursor: pointer; }
.rv-result-unsafe { color: var(--stamp-red); font-weight: 700; }
.rv-result-safe { color: var(--stamp-green); font-weight: 700; }
.rv-result-turned_down { color: var(--window-text); }
.rv-actions { flex-wrap: wrap; }
@media (max-width: 760px) {
  .rv-groups { grid-template-columns: minmax(0, 1fr); }
  .rv-hero-title { font-size: 1.2rem; }
}

/* ── Responsive ── */
@media (max-width: 1000px) {
  .desk { grid-template-columns: minmax(0, 1fr) 260px; }
  .desk-left { grid-column: 2; grid-row: 2; position: static; } /* the planner and the diary stay a column, under the Calendar */
  .desk-main { grid-row: 1 / span 2; }
  .desk-side { grid-row: 1; position: static; }
  .log-peek { height: 240px; }
}
@media (max-width: 860px) {
  .desk { grid-template-columns: 1fr; padding: 10px 8px 60px; gap: 10px; }
  .desk-col { display: contents; }
  .status { order: -3; }
  .quarter { order: -2; }
  #intray-section { order: -1; }
  .planner { order: 0; }
  .notepad { order: 1; }
  .log-peek { height: 140px; min-height: 0; }
}
@media (max-width: 760px) {
  .choices.two { grid-template-columns: 1fr; }
  .desk-section > .client, .client { padding: 8px; }
  .notepad .client { padding: 2px; }
  .card-row { grid-template-columns: 1fr; }
  .taskbar { gap: 2px; }
  /* A phone's taskbar is icons only, as the new desktop's is at any width: each button keeps its name for a screen
     reader (aria-label, and Start's own text at no size). */
  .task-btn { position: relative; min-width: var(--target); flex: none; padding: 1px 8px; justify-content: center; font-size: 1.15rem; }
  /* Status's figures show their pictures without their words on a phone (the owner's call of 2026-10-14); each word
     stays for a screen reader, and the tooltip still says what the figure is. */
  .task-label, .status .res-word { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
  /* The planner's strip is itself the way to the whole run on a phone (a full-width target), so its link sits close under it */
  .planner .link-btn { min-height: 0; padding: 2px 0 4px; }
  .start-btn { min-width: var(--target); justify-content: center; gap: 0; font-size: 0; }
  .reg-item { grid-template-columns: 1fr; }
  .reg-tail { width: auto; padding: 2px 8px 4px; }
  .reg-fold { padding-left: 8px; }
  .desk-tools { flex-wrap: wrap; row-gap: 4px; }
  .desk-note { flex-basis: 100%; }
  .control { grid-template-columns: var(--sym-tile) 1fr auto; } /* the chip goes under the words, never without its word */
  .control .c-status { grid-column: 2; grid-row: 2; min-height: 0; }
  .control > .btn-small, .control > .c-cost { grid-column: 3; grid-row: 1 / span 2; }
  .timeline li { grid-template-columns: 1fr; gap: 2px; }
  .overlay, #screen-event { padding: 8px 4px 70px; }
  #event-sheet { --event-pad-y: 78px; }
  #event-sheet.is-ledger { max-height: calc(100dvh - 78px); } /* a phone scrolls down to the planner window */
  #modal-system > .sheet, #modal-programme > .sheet, #modal-intervention > .sheet, #modal-qmail > .sheet, #modal-timeline > .sheet { --overlay-pad-y: 78px; }
  .msgbox, .msgbox.is-ledger, .msgbox.is-review, .msgbox.is-report { max-width: none; }
  .ledger-quarters { grid-template-columns: repeat(2, 1fr); }
  .review-grid { grid-template-columns: 1fr 1fr; }
  .folder-tab { padding: 3px 8px 4px; font-size: 0.92rem; }
  .folder-tab.active { padding: 4px 10px 6px; }
  .actions .btn { flex: 1 1 auto; }
  #event-options .choice { flex: 0 0 auto; min-height: var(--target); }
  #event-options .choice + .choice { border-left-color: transparent; border-top-color: var(--shadow); box-shadow: inset 0 1px var(--hilight); }
  .msg-head { padding-right: 44px; }
  /* A phone shows Status, the Calendar, then the desk, so the first two are packed: smaller figures stacked over trust
     as one row and a shorter button, and the Calendar in one row, the quarter beside today's week (the leaf shows the
     quarter alone: the week shows the date). The calendar shows only today's week (its today marker, due dots and
     quarter end) and opens to the whole month with a tap. The diary peek is three lines. Each figure is one line;
     capacity is the number only, its people icons stay on wider screens. The Year planner comes after the desk. */
  .quarter .client { flex-direction: row; align-items: flex-start; gap: 6px; }
  .quarter .leaf { flex: none; align-self: stretch; justify-content: center; padding: 4px 8px; }
  .quarter .leaf-turn { display: none; }
  .quarter .calendar { flex: 1 1 auto; min-width: 0; }
  .leaf-period { font-size: 1.05rem; }
  .calendar { padding: 2px; gap: 2px; }
  .cal-head { margin-bottom: 1px; cursor: pointer; } /* its type and the week's are under Phone fit, at the end */
  .calendar:not(.open) .cal-day:not(.wk), .calendar:not(.open) .cal-blank:not(.wk) { display: none; }
  .cal-head::after { content: ' \25BE'; }
  .calendar.open .cal-head::after { content: ' \25B4'; }
  .num { flex-direction: row; align-items: baseline; gap: 4px; padding: 2px 4px; }
  .num strong { font-size: 1.1rem; }
  .trust { flex-direction: row; align-items: center; gap: 6px; padding: 4px 8px; }
  .trust-bar-wrap { flex: 1; }
  .end-btn { min-height: var(--target); margin-top: 0; }
  .status-row { flex-direction: column; gap: 5px; }
  .status-row .numbers, .status-row .trust { flex: 0 0 auto; }
  .status-row .end-btn { width: 100%; } /* full width under trust */
  .status > .client { gap: 5px; }
  .log-peek { height: 84px; min-height: 0; }
  .wizard .client { grid-template-columns: 1fr; }
  .wizard-banner { min-height: 0; padding: 8px 10px; }
  .wizard-page { min-height: 0; }
  .logon-fields { grid-template-columns: 80px 1fr; }
  .logon-banner { margin: -8px -8px 10px; }
  .logon-buttons { grid-template-columns: 1fr; justify-content: stretch; }
  .logon-balloon { grid-row: auto; margin: 4px 0 6px; }
  .logon-saved { text-align: left; }
  .ledger-wrap { overflow-x: auto; }
}
/* The new computers arrive (installNewDesktop in js/screens.js): the old machine's setup screen comes up over
   everything, its bar fills in steps, the desktop changes behind it, and it lifts on the new one before Marek's message
   opens. It keeps the old look whatever the desktop under it has become: its colours are the old desktop's, taken as it
   opens (--in-*), and its type is the old machine's. Reduced motion: no screen (the script skips it). */
.install-screen { position: fixed; inset: 0; z-index: 95; display: flex; align-items: center; justify-content: center; padding: 16px; background: var(--in-desktop, var(--desktop)); color: var(--in-text, var(--window-text)); font-family: Tahoma, "MS Sans Serif", Arial, sans-serif; opacity: 0; transition: opacity 0.3s; }
.install-screen.show { opacity: 1; }
.install-screen.lifting { opacity: 0; transition: opacity 0.8s ease; }
.install-win { width: 380px; max-width: 100%; background: var(--in-face, var(--face)); border: 2px solid; border-color: var(--in-hilight, var(--hilight)) var(--in-dark, var(--dark)) var(--in-dark, var(--dark)) var(--in-hilight, var(--hilight)); }
.install-titlebar { padding: 3px 6px; font-weight: 700; font-size: 0.95rem; color: var(--in-title-text, var(--title-text)); background: linear-gradient(90deg, var(--in-title-a, var(--title-a)), var(--in-title-b, var(--title-b))); }
.install-body { padding: 14px 14px 16px; }
.install-title { font-weight: 700; font-size: 1.05rem; }
.install-text { margin: 6px 0 12px; font-size: 0.92rem; }
.install-bar { height: 18px; border: 1px solid; border-color: var(--in-shadow, var(--shadow)) var(--in-hilight, var(--hilight)) var(--in-hilight, var(--hilight)) var(--in-shadow, var(--shadow)); background: var(--in-window, var(--window)); }
.install-fill { display: block; height: 100%; width: 0; background: repeating-linear-gradient(90deg, var(--in-select, var(--select)) 0 10px, transparent 10px 12px); }
.install-screen.show .install-fill { animation: installFill var(--install-fill, 2.4s) steps(18, end) 0.3s forwards; }
@keyframes installFill { to { width: 100%; } }

/* The startup screen as a run starts or is continued (playBoot in js/screens.js, fillBoot in js/views.js): over
   everything, opaque, the logon behind it. On the old machine it is the power-on self-test, grey type on black in
   any theme, as such a screen was: each row is printed as the script sets .on, the leaders are a dotted rule, and a
   value's tone is its colour (the text-mode palette). The new desktop's lock screen is in css/modern.css.
   Reduced motion: no screen (the script skips it). */
.boot-screen { position: fixed; inset: 0; z-index: 95; display: flex; flex-direction: column; overflow: hidden; }
.boot-screen[data-frame="post"] { padding: 28px 32px 24px; background: #000000; color: #aaaaaa; font-family: "Courier New", Courier, monospace; font-size: 1.15rem; line-height: 1.5; }
.boot-post { display: flex; flex-direction: column; flex: 1; max-width: 72ch; }
.boot-head { display: flex; flex-wrap: wrap; justify-content: space-between; gap: 0 3ch; color: #ffffff; }
.boot-tag { margin-bottom: 1.5em; }
.boot-tag span { margin-right: 1ch; }
.boot-rows { display: flex; flex-direction: column; max-width: 54ch; }
.boot-row { display: flex; align-items: baseline; gap: 1ch; visibility: hidden; }
.boot-row.on { visibility: visible; }
.boot-dots { flex: 1; min-width: 2ch; border-bottom: 2px dotted currentColor; opacity: 0.55; }
.boot-value[data-tone="ok"] { color: #55ff55; }
.boot-value[data-tone="warn"] { color: #ffff55; }
.boot-value[data-tone="bad"] { color: #ff5555; }
.boot-row.boot-last { gap: 0; margin-top: 1.5em; }
.boot-cursor { animation: crash-blink 1s steps(1) infinite; }
.boot-skip { margin-top: auto; padding-top: 16px; }

/* ── Mini games: a break between a quarter's close and its cards (js/minigames.js; the window is js/views.js) ──
   A small game program of its desktop: here a grey box with a sunken playing field, raised square tiles and a
   counter in lit digits; css/modern.css redraws the same markup for the new desktop. Nothing here is animated
   (the games step on a timer), so reduced motion changes nothing. Sizes follow the window's width down to a phone. */
/* While a game is open every screen is out of sight, so the game sits on the bare desktop, as a message does. A rule,
   not a class a script sets, so a screen that changes behind an open game cannot bring the desk back into view. */
#modal-minigame { background: transparent; }
body:has(#modal-minigame:not(.hidden)) .screen { opacity: 0; }
.sheet.mg { max-width: 600px; margin: auto; } /* centred where it fits; a tall one still starts at the top and scrolls */
.mg .actions { margin-top: 4px; }
/* The brief and the result: a picture of the game beside the words. The result adds the game's stamp and the figure that moved. */
.mg-intro { display: flex; align-items: flex-start; gap: 14px; padding: 4px 2px; }
.mg-art { display: none; flex: none; width: min(200px, 34vw); aspect-ratio: 4 / 3; background: center bottom / 84% auto no-repeat, 0 0 / 32px 32px; }
.mg-words { flex: 1; min-width: 0; }
.mg-stamp { font-size: 1.15rem; margin-bottom: 6px; }
/* The result's stamp, inked: a bordered, slightly turned rubber stamp in the result's colour, like the ones the games
   put on a screen or a letter; on the new desktop it is that desktop's pill, larger (css/modern.css). */
.mg[data-stage="result"] .mg-stamp { display: inline-flex; margin: 2px 0 8px 2px; padding: 0 10px; font-size: 1.35rem; border: 3px solid currentColor; rotate: -4deg; }
.mg[data-stage="result"] .mg-stamp::before { content: none; }
.mg[data-stage="result"] .mg-stamp.tone-green { color: var(--stamp-green); }
.mg[data-stage="result"] .mg-stamp.tone-red { color: var(--stamp-red); }
/* The score: a block for each thing counted, filled up to the score in the result's colour, with a notch after the
   block that wins (so a loss shows how near it came), and the tally beside it. */
.mg-score { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 10px; margin-top: 10px; }
.mg-score-bar { display: inline-flex; gap: 2px; padding: 3px; background: var(--window); }
.mg-score-blk { position: relative; width: 12px; height: 14px; background: color-mix(in srgb, var(--shadow) 35%, var(--window)); }
.mg[data-tone="green"] .mg-score-blk.mg-lit { background: var(--stamp-green); }
.mg[data-tone="red"] .mg-score-blk.mg-lit { background: var(--stamp-red); }
.mg-score-blk.mg-pass::after { content: ''; position: absolute; right: -2px; top: -6px; bottom: -6px; width: 2px; background: var(--window-text); }
.mg-score-tally { font-weight: 700; }
.mg-text { margin: 0; }
.mg-title { margin: 0 0 6px; }
.mg-guide { display: flex; flex-direction: column; gap: 3px; margin: 8px 0 0; padding: 0; list-style: none; color: var(--gray-text); font-size: 0.95rem; }
.mg-guide li { display: flex; align-items: center; gap: 7px; }
.mg-guide .ic { color: var(--action); }
.mg-stake { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-top: 10px; }
.mg-stake .deltas { margin: 0; }
.mg-how { margin: 0 2px; }
.mg-bar { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.mg-readout { min-width: 9ch; margin-left: auto; padding: 1px 8px; font-family: var(--font-mono); font-weight: 700; text-align: right; background: var(--chart-bg); color: var(--chart-line); }
.mg-field { display: flex; align-items: center; justify-content: center; min-height: 190px; padding: 10px 6px; background: var(--face); user-select: none; -webkit-user-select: none; }
.mg-field.mg-over { pointer-events: none; }
.mg-pc, .mg-tile, .mg-hold { touch-action: manipulation; }
/* Vendors: a ward of nine desks, each with a computer (img/minigames, drawn by tools/build-minigame-art.py). The rep
   rises from behind a computer as an install starts on it: the picture is one figure, moved up in two steps. The
   screen is a box laid over the picture's screen (the geometry is in the tool's header) and shows the install, the
   stamp of one cancelled, or the trial that got in. */
.mg[data-game="vendors"] .mg-art { display: block; background-image: url("../img/minigames/classic/rep.svg"), url("../img/minigames/classic/floor.svg"); }
.mg[data-game="vendors"][data-tone="green"] .mg-art { background-image: url("../img/minigames/classic/rep-glum.svg"), url("../img/minigames/classic/floor.svg"); }
.mg[data-game="vendors"][data-tone="red"] .mg-art { background-image: url("../img/minigames/classic/rep-grin.svg"), url("../img/minigames/classic/floor.svg"); }
.mg[data-game="vendors"] .mg-field { padding: 12px 6px 8px; background: url("../img/minigames/classic/floor.svg") 0 0 / 32px 32px; }
body.high-contrast .mg[data-game="vendors"] .mg-field { background: var(--window); } /* higher contrast: the computers on a plain ground, no floor pattern behind them */
.mg-pcs { --mg-pc: min(150px, calc((100vw - 76px) / 3)); display: grid; grid-template-columns: repeat(3, var(--mg-pc)); gap: 6px 10px; }
.mg-pc { position: relative; height: var(--mg-pc); min-width: 0; padding: 0; border: none; background: none; color: var(--window-text); font-size: calc(var(--mg-pc) * 0.1); line-height: 1.1; cursor: pointer; }
.mg-rep { position: absolute; left: 17%; top: 26%; width: 66%; aspect-ratio: 4 / 3; background: url("../img/minigames/classic/rep.svg") center / contain no-repeat; visibility: hidden; }
.mg-pc[data-rep="1"] .mg-rep { visibility: visible; top: 12%; }
.mg-pc[data-rep="2"] .mg-rep, .mg-pc[data-rep="3"] .mg-rep { visibility: visible; top: 0; }
.mg-pc[data-rep="3"] .mg-rep { background-image: url("../img/minigames/classic/rep-grin.svg"); }
.mg-pc-box { position: absolute; left: 10%; bottom: 0; width: 80%; aspect-ratio: 64 / 60; background: url("../img/minigames/classic/pc.svg") center / contain no-repeat; }
.mg-pc-screen { position: absolute; left: 12.5%; top: 10%; width: 75%; height: 46.67%; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 0.3em; overflow: hidden; background: var(--desktop); }
.mg-pc-tag { position: absolute; right: 15%; bottom: 8%; min-width: 1.3em; padding: 0 0.2em; font-size: 0.7em; font-weight: 700; text-align: center; background: var(--window); color: var(--window-text); outline: 1px solid var(--shadow); } /* an asset sticker */
.mg-pc-app, .mg-pc-trial, .mg-pc-stamp, .mg-pc-word, .mg-install { display: none; }
.mg-pc-app, .mg-pc-trial { width: 1.5em; height: 1.5em; }
.mg-install { gap: 1px; width: 80%; height: 0.8em; padding: 1px; background: var(--window); }
.mg-blk { flex: 1; }
.mg-blk.mg-lit { background: var(--select); }
.mg-pc[data-state="busy"] .mg-pc-screen { justify-content: flex-end; padding-bottom: 0.4em; background: var(--face); box-shadow: inset 0 0.55em var(--title-a); }
.mg-pc[data-state="busy"] .mg-pc-app { display: block; }
.mg-pc[data-state="busy"] .mg-install { display: flex; }
.mg-pc[data-state="stopped"] .mg-pc-screen { background: var(--window); }
.mg-pc[data-state="stopped"] .mg-pc-stamp { display: block; padding: 0.05em 0.35em; border: 2px solid var(--stamp-green); color: var(--stamp-green); font-weight: 700; rotate: -8deg; animation: stampDown 0.12s steps(2, end) backwards; }
@keyframes stampDown { from { scale: 1.6; } } /* it lands already inked: the screen is only stamped for half a second, so it does not fade in as the message stamps do */
.mg-pc[data-state="installed"] .mg-pc-screen { background: var(--res-trust); color: var(--select-text); }
.mg-pc[data-state="installed"] .mg-pc-trial, .mg-pc[data-state="installed"] .mg-pc-word { display: block; }
.mg-pc-word { font-size: 0.85em; font-weight: 700; }
.mg-pip[data-state="stopped"] { background: var(--stamp-green); }
.mg-pip[data-state="installed"] { background: var(--window); box-shadow: inset 0 0 0 3px var(--stamp-red); }
/* The word a round is stamped with, where a scene shows one (Hold for review by the reader or a tray, Workflow over
   its board): the same rubber stamp as on a Free trial screen, placed by the game and shown by the scene's state. */
.mg-ink { display: none; position: absolute; z-index: 2; translate: -50% -50%; padding: 0.05em 0.4em; border: 2px solid var(--stamp-green); background: var(--window); color: var(--stamp-green); font-weight: 700; white-space: nowrap; rotate: -8deg; pointer-events: none; animation: stampDown 0.12s steps(2, end) backwards; }
.mg-ink[data-tone="red"] { border-color: var(--stamp-red); color: var(--stamp-red); }
/* Hold for review: an office. The AI tool hangs from a rail and carries a letter along it; the reader sits under the
   rail at the round's zone; a Send tray stands at each end. Under the scene is the track, the old desktop's
   progress bar: the lit block is where the tool is, and the zone is the stretch between the two black rules, so it
   reads without the drawing and without colour. Sizes are shares of the rail's length, so a phone gets the same scene. */
.mg[data-game="oversight"] .mg-art { display: block; background-image: url("../img/minigames/classic/carrier.svg"), url("../img/minigames/classic/carpet.svg"); background-position: center; background-size: 70% auto, 32px 32px; }
.mg[data-game="oversight"][data-tone="green"] .mg-art { background-image: url("../img/minigames/classic/reader-read.svg"), url("../img/minigames/classic/carpet.svg"); background-position: center bottom, 0 0; }
.mg[data-game="oversight"][data-tone="red"] .mg-art { background-image: url("../img/minigames/classic/tray.svg"), url("../img/minigames/classic/carpet.svg"); }
.mg[data-game="oversight"] .mg-field { padding: 10px 8px 12px; background: url("../img/minigames/classic/carpet.svg") 0 0 / 32px 32px; }
body.high-contrast .mg[data-game="oversight"] .mg-field { background: var(--window); }
.mg-watch { display: flex; flex-direction: column; align-items: stretch; gap: 10px; width: 100%; padding: 0 4%; } /* room at each side: at an end of the rail the tool reaches past the track by half its width */
.mg-line { position: relative; aspect-ratio: 18 / 5; margin: 0 3px; overflow: visible; } /* 3px: the track's own edge, so the tool stands over the lit block */
.mg-rail { position: absolute; left: 0; right: 0; top: 2%; height: 4px; background: var(--dark); box-shadow: 0 1px var(--hilight); }
.mg-carrier, .mg-reader, .mg-send { position: absolute; aspect-ratio: 4 / 3; background: center / contain no-repeat; }
.mg-carrier { top: 2%; width: 12%; margin-left: -6%; background-image: url("../img/minigames/classic/carrier.svg"); }
.mg-letter { position: absolute; left: 31%; top: 90%; width: 38%; aspect-ratio: 3 / 2; background: linear-gradient(var(--shadow), var(--shadow)) 50% 35% / 60% 1px no-repeat, linear-gradient(var(--shadow), var(--shadow)) 35% 65% / 40% 1px no-repeat, var(--window); outline: 1px solid var(--dark); }
.mg-line[data-state="held"] .mg-letter, .mg-line[data-state="missed"] .mg-letter { display: none; }
.mg-reader { bottom: 0; width: 13%; margin-left: -6.5%; background-image: url("../img/minigames/classic/reader.svg"); background-position: center bottom; }
.mg-line[data-state="held"] .mg-reader { background-image: url("../img/minigames/classic/reader-read.svg"); }
.mg-send { bottom: 0; width: 11%; background-image: url("../img/minigames/classic/tray.svg"); background-position: center bottom; }
.mg-send-a { left: 0; }
.mg-send-b { right: 0; }
.mg-line .mg-ink { top: 52%; font-size: 0.95rem; }
.mg-line[data-state="held"] .mg-ink, .mg-line[data-state="missed"] .mg-ink { display: block; }
.mg-pips { display: flex; flex-wrap: wrap; justify-content: center; gap: 5px; }
.mg-pip { width: 12px; height: 12px; background: var(--face); }
.mg-pip[data-state="now"] { background: var(--window); }
.mg-pip[data-state="held"] { background: var(--stamp-green); }
.mg-pip[data-state="missed"] { background: var(--window); box-shadow: inset 0 0 0 3px var(--stamp-red); }
.mg-meter { display: flex; gap: 2px; height: 26px; padding: 2px; background: var(--window); }
.mg-cell { flex: 1; }
.mg-cell.mg-zone { background: color-mix(in srgb, var(--stamp-green) 30%, var(--window)); box-shadow: inset 0 3px var(--dark), inset 0 -3px var(--dark); }
.mg-cell.mg-lit { background: var(--select); }
.mg-meter[data-result="held"] .mg-lit { background: var(--stamp-green); }
.mg-meter[data-result="missed"] .mg-lit { background: var(--stamp-red); }
.mg-hold { align-self: center; min-width: 160px; min-height: 44px; } /* the one button of a timing game: easy to hit on a phone */
.mg-over .mg-hold { visibility: hidden; }
/* Workflow: a process map pinned to a cork board. Each piece is a sticky note with a thick marker track on it (drawn
   for turn 0, the whole of it turned), running to the note's edge so its two openings are plain; a square with no
   piece is bare cork with a faint outline. A piece the work runs through has its track in green and its note gone
   pale green, so the run reads without telling blue from green; the piece where the run stops has a red edge. The
   steps are the chart's shapes (img/minigames): the request and the decision on a note at each edge, with a stub of
   track to the board, the AI step and the check on a blue note and a pink one. The strip above the board is the
   workflow as it should run. The board keeps its own colours in the dark theme, as the other two scenes do; they are
   named once here (--wf-*) and again for the new desktop, and higher contrast swaps them for the theme's own. */
.mg[data-game="workflow"] .mg-field {
  --wf-note: #fff7b2; --wf-note-edge: #d9c95a; --wf-note-ai: #bfe0ff; --wf-note-check: #ffc9d6; --wf-note-on: #d9f2d0;
  --wf-track: #3d5a99; --wf-run: #1e8e3e; --wf-slot: #c69c6d; --wf-next: #c8102e; --wf-ink: #1a1a1a;
  --wf-shade: 2px 2px 0 color-mix(in srgb, var(--dark) 45%, transparent); --wf-casing: #fffdf0;
  padding: 12px 6px 14px; background: url("../img/minigames/classic/cork.svg") 0 0 / 64px 64px;
}
body.high-contrast .mg[data-game="workflow"] .mg-field {
  --wf-note: var(--window); --wf-note-edge: var(--window-text); --wf-note-ai: var(--window); --wf-note-check: var(--window); --wf-note-on: var(--window);
  --wf-track: var(--window-text); --wf-run: var(--select); --wf-slot: transparent; --wf-next: var(--stamp-red); --wf-ink: var(--window-text); --wf-casing: transparent;
  background: var(--window);
}
body.high-contrast .mg[data-game="workflow"] :is(.mg-tile, .mg-end) { border: 2px solid var(--wf-ink); box-shadow: none; } /* every note has its full edge; an empty square shows nothing */
body.high-contrast .mg[data-game="workflow"] .mg-tile.mg-next { border-color: var(--wf-next); box-shadow: inset 0 0 0 2px var(--wf-next); }
.mg[data-game="workflow"] .mg-art { display: block; background: url("../img/minigames/classic/step-ai.svg") center / 46% auto no-repeat, url("../img/minigames/classic/cork.svg") 0 0 / 64px 64px; }
.mg[data-game="workflow"][data-tone="green"] .mg-art { background-image: url("../img/minigames/classic/step-decision.svg"), url("../img/minigames/classic/cork.svg"); }
.mg[data-game="workflow"][data-tone="red"] .mg-art { background-image: url("../img/minigames/classic/step-check.svg"), url("../img/minigames/classic/cork.svg"); }
.mg-map { display: flex; flex-direction: column; align-items: center; gap: 12px; }
.mg-steps { display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 2px 6px; padding: 4px 12px; background: var(--window); color: var(--window-text); font-size: 0.92rem; box-shadow: 2px 2px 0 color-mix(in srgb, var(--dark) 30%, transparent); } /* a strip of paper on the cork */
.mg-steps-arrow { color: var(--gray-text); }
.mg-step { display: block; background: center / contain no-repeat; }
.mg-step[data-step="request"] { background-image: url("../img/minigames/classic/step-request.svg"); }
.mg-step[data-step="ai"] { background-image: url("../img/minigames/classic/step-ai.svg"); }
.mg-step[data-step="check"] { background-image: url("../img/minigames/classic/step-check.svg"); }
.mg-step[data-step="decision"] { background-image: url("../img/minigames/classic/step-decision.svg"); }
.mg-steps .mg-step { width: 28px; height: 28px; }
.mg-board { position: relative; }
.mg-board .mg-ink { left: 50%; top: 46%; font-size: 1.5rem; }
.mg-board[data-state] .mg-ink { display: block; }
.mg-flow { --mg-tile: min(76px, calc((100vw - 96px) / 5.9)); --mg-end: calc(var(--mg-tile) * 0.95); --mg-w: calc(var(--mg-tile) * 0.2); display: grid; grid-auto-rows: var(--mg-tile); gap: 4px; }
.mg-tile { position: relative; min-width: 0; padding: 0; overflow: hidden; border: none; border-right: 2px solid var(--wf-note-edge); border-bottom: 2px solid var(--wf-note-edge); background: var(--wf-note); box-shadow: var(--wf-shade); cursor: pointer; }
.mg-tile[data-role="ai"] { background: var(--wf-note-ai); }
.mg-tile[data-role="check"] { background: var(--wf-note-check); }
.mg-tile.mg-on { background: var(--wf-note-on); }
.mg-tile.mg-done { background: color-mix(in srgb, var(--wf-run) 35%, var(--wf-note-on)); }
.mg-tile.mg-next { box-shadow: inset 0 0 0 3px var(--wf-next), var(--wf-shade); }
.mg-tile:active { translate: 1px 1px; }
.mg-tile:focus-visible { outline: 2px dotted var(--wf-ink); outline-offset: -5px; }
.mg-blank { outline: 1px solid var(--wf-slot); outline-offset: -2px; }
.mg-pipe { position: absolute; inset: 0; }
.mg-tile[data-rot="1"] .mg-pipe { transform: rotate(90deg); }
.mg-tile[data-rot="2"] .mg-pipe { transform: rotate(180deg); }
.mg-tile[data-rot="3"] .mg-pipe { transform: rotate(270deg); }
.mg-arm, .mg-stub { background: var(--wf-track); }
.mg-arm { position: absolute; }
.mg-arm-a { left: calc(50% - var(--mg-w) / 2); width: var(--mg-w); top: 0; bottom: 0; }
.mg-tile[data-kind="corner"] .mg-arm { border-bottom-left-radius: var(--mg-w); } /* the bend: the two arms share their outer corner, rounded */
.mg-tile[data-kind="corner"] .mg-arm-a { bottom: auto; height: calc(50% + var(--mg-w) / 2); }
.mg-arm-b { left: calc(50% - var(--mg-w) / 2); right: 0; top: calc(50% - var(--mg-w) / 2); height: var(--mg-w); }
.mg-tile.mg-on .mg-arm, .mg-end.mg-on .mg-stub { background: var(--wf-run); }
.mg-tile .mg-step { position: absolute; left: 27%; top: 27%; width: 46%; height: 46%; }
/* The request and the decision are notes too, at the board's two edges, so their stub of track is read on paper as every other track is, not on the cork. */
.mg-end { display: flex; align-items: center; border-right: 2px solid var(--wf-note-edge); border-bottom: 2px solid var(--wf-note-edge); background: var(--wf-note); box-shadow: var(--wf-shade); }
.mg-end.mg-on { background: var(--wf-note-on); }
.mg-end-in { padding-left: 5%; }
.mg-end-out { padding-right: 5%; }
.mg-end .mg-step { flex: none; width: 58%; aspect-ratio: 1; }
.mg-stub { position: relative; flex: 1; height: var(--mg-w); box-shadow: 0 0 0 2px var(--wf-casing); } /* a pale casing, so the stub stands clear of whatever is behind it, cork included */
.mg-end-out .mg-stub { margin-right: calc(var(--mg-w) * 0.7); }
.mg-end-out .mg-stub::after { content: ''; position: absolute; left: 100%; top: 50%; translate: 0 -50%; border: var(--mg-w) solid transparent; border-right-width: 0; border-left: calc(var(--mg-w) * 0.7) solid var(--wf-track); } /* the arrowhead into the decision */
.mg-end-out.mg-on .mg-stub::after { border-left-color: var(--wf-run); }
.mg-end-out .mg-step { opacity: 0.7; } /* the decision is not reached yet */
.mg-end-out.mg-on .mg-step { opacity: 1; }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation: none !important; transition: none !important; }
}

/* ── Drawing the eye (the outline stays under reduced motion; only the pulse goes) ── */
/* What an assessment just changed on the sheet (flashUpdated in js/screens.js) */
.just-updated { outline: 2px solid var(--action); outline-offset: 2px; animation: justUpdated 0.8s ease-in-out 2; }
@keyframes justUpdated { 0%, 100% { background-color: transparent; } 50% { background-color: color-mix(in srgb, var(--action) 18%, transparent); } }
/* Something shown for the first time (drawEye in js/screens.js): it grows and flashes amber four times inside a thick
   outline. Used for trust moving at a close, a tab or the folder coming in, a new Status entry, and a window a tip
   opens. Whole windows grow less (--eye-scale). Under reduced motion the outline stays, still. */
.draw-eye, .eye-held { position: relative; z-index: 3; outline: 3px solid var(--action); outline-offset: 2px; }
.draw-eye { animation: drawEye 0.6s ease-in-out 2; }
/* eye-held: the same mark, held still, on the thing a tip that is open is talking about (the EU AI Act folder in the
   Start menu, under the Reference tip). Inside a menu the mark sits within the item, where the menu's edge cannot clip it. */
.more-menu .draw-eye, .more-menu .eye-held { outline-offset: -3px; }
@keyframes drawEye { 50% { transform: scale(var(--eye-scale, 1.08)); background-color: color-mix(in srgb, var(--stamp-amber) 40%, var(--window)); } }
.desk-section.draw-eye { --eye-scale: 1.02; }
/* Trust moved at the close (trustMoved in js/screens.js): the change shows in a badge by the figure */
.trust-delta { position: absolute; right: 8px; top: 50%; transform: translateY(-50%); padding: 0 8px; font-size: 1.6rem; font-weight: 700; line-height: 1.3; color: var(--on-fill); animation: deltaPop 2s ease-out forwards; }
.trust-delta.up { background: var(--stamp-green); }
.trust-delta.down { background: var(--stamp-red); }
@keyframes deltaPop { 0% { opacity: 0; transform: translateY(-50%) scale(0.4); } 12% { opacity: 1; transform: translateY(-50%) scale(1.25); } 22% { transform: translateY(-50%) scale(1); } 85% { opacity: 1; } 100% { opacity: 0; } }
/* A card put down on the desk (placeCards in js/screens.js): kept off it until the player is looking, so the cards
   already there sit at the top of the tray. Then those move down to make room, each from where it was (card-shift:
   --shift-x and --shift-y are the way back), and the new ones drop into the room made, from just above and a little
   turned, one after another (--i). Under reduced motion every card is simply in its place. */
.doc.card-waiting { display: none; }
.doc.card-shift { animation: shift 0.24s steps(5, end) backwards; }
@keyframes shift { from { transform: translate(var(--shift-x, 0), var(--shift-y, 0)); } to { transform: none; } }
.doc.card-arrive { --rise-y: -16px; --rise-scale: 1.05; --rise-turn: -2deg; animation: rise 0.22s steps(4, end) backwards; animation-delay: calc(0.2s + var(--i, 0) * 50ms); }
/* End quarter when nothing is left to do this quarter (Engine.quarterDone) */
.end-btn.ready { outline: 2px solid var(--action); outline-offset: 1px; animation: endReady 1.6s ease-in-out infinite; }
@keyframes endReady { 0%, 100% { outline-offset: 1px; outline-color: var(--action); } 50% { outline-offset: 5px; outline-color: color-mix(in srgb, var(--action) 45%, transparent); } } /* the outline pulses; the bevel (box-shadow) is left alone */

/* ── The hospital's machine: tray clock and asset tag (content: meta.desktop) ── */
/* The tray is the sunken well at the right of the taskbar, as system trays were drawn. */
.tray { margin-left: auto; display: flex; align-items: center; min-height: 22px; padding: 0 8px; font-size: 0.9rem; white-space: nowrap; border: 1px solid; border-color: var(--shadow) var(--hilight) var(--hilight) var(--shadow); }
body:not([data-os="modern"]) .taskbar:has(.tray)::after { content: none; }
.tray-clock { cursor: default; }
/* The tray speaker (js/music.js): the one live icon in the tray, flat with no bevel, as tray icons were drawn.
   Each press moves the sound setting on (sounds and music, sounds only, silent); its data-audio picks the glyph below. */
.tray-sound { display: inline-flex; align-items: center; justify-content: center; width: 20px; height: 18px; margin: 0 6px 0 -4px; padding: 0; border: none; background: transparent; color: inherit; cursor: pointer; font: inherit; }
.tray-sound:focus-visible { outline-offset: 0; }
/* The sound glyph (the tray speaker and the mini game window's button): a mask in the text colour, so it takes the
   text colour in both themes and in higher contrast. Its button's data-audio picks the shape (js/music.js): a note
   beside the speaker for sounds and music, waves for sounds only, a cross for silent. */
.audio-glyph { display: block; width: 14px; height: 12px; background: currentColor; --mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14 12' fill='none' stroke='%23000' stroke-width='1.2' stroke-linecap='round'%3E%3Cpath d='M1.5 4.3h2.4L7 1.8v8.4L3.9 7.7H1.5z' fill='%23000' stroke-linejoin='round'/%3E%3Cpath d='M9 4.2a2.6 2.6 0 0 1 0 3.6M10.8 2.4a5.2 5.2 0 0 1 0 7.2'/%3E%3C/svg%3E"); -webkit-mask: var(--mask) no-repeat center / contain; mask: var(--mask) no-repeat center / contain; }
[data-audio="all"] > .audio-glyph { --mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14 12' fill='none' stroke='%23000' stroke-width='1.2' stroke-linecap='round'%3E%3Cpath d='M1.5 4.3h2.4L7 1.8v8.4L3.9 7.7H1.5z' fill='%23000' stroke-linejoin='round'/%3E%3Cpath d='M11.4 2v6.2M11.4 2l2 0.9'/%3E%3Ccircle cx='10.1' cy='8.4' r='1.4' fill='%23000' stroke='none'/%3E%3C/svg%3E"); -webkit-mask-image: var(--mask); mask-image: var(--mask); }
[data-audio="silent"] > .audio-glyph { --mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14 12' fill='none' stroke='%23000' stroke-width='1.2' stroke-linecap='round'%3E%3Cpath d='M1.5 4.3h2.4L7 1.8v8.4L3.9 7.7H1.5z' fill='%23000' stroke-linejoin='round'/%3E%3Cpath d='M9.4 4.2l3.4 3.6M12.8 4.2L9.4 7.8'/%3E%3C/svg%3E"); -webkit-mask-image: var(--mask); mask-image: var(--mask); }
/* The asset tag is a desktop watermark, bottom right above the taskbar, the way the old system printed its
   build line on the wallpaper. It sits under the desk (which is raised above it), takes no clicks and is
   hidden from assistive technology, so it covers nothing. */
.asset-tag { position: fixed; right: 12px; bottom: 40px; z-index: 0; pointer-events: none; text-align: right; color: #ffffff; opacity: 0.75; font-family: var(--font); font-size: 0.8rem; line-height: 1.35; }
.asset-tag .asset-old, .asset-tag .asset-new { display: flex; flex-direction: column; }
.asset-tag .asset-new { display: none; }
[data-os="modern"] .asset-tag .asset-old { display: none; }
[data-os="modern"] .asset-tag .asset-new { display: flex; }
@media (max-width: 480px) { .tray { padding: 0 4px; font-size: 0.8rem; } }
/* On a narrow phone Start, the five program buttons and the tray are wider than the screen (by a few pixels at 375
   with a long date), so the date gives way (it is in Status and the Calendar); the sound button stays. Both looks
   (the id outranks modern.css). */
@media (max-width: 400px) { #tray-clock { display: none; } }

/* ── Dev panel (?debug only; developer tooling, not player-facing) ── */
.dev-panel { position: fixed; left: 4px; bottom: 36px; z-index: 80; width: 300px; max-width: calc(100vw - 16px); max-height: calc(100dvh - 48px); display: flex; flex-direction: column; font-size: 0.9rem; }
.dev-panel > .client { overflow: auto; padding: 6px 8px; }
.dev-sec { border-top: 1px solid var(--shadow); box-shadow: 0 -1px var(--hilight) inset; padding: 4px 0; }
.dev-sec:first-child { border-top: none; box-shadow: none; }
.dev-sec summary { cursor: default; font-weight: 700; color: var(--window-text); }
.dev-sec > div:not(.dev-row) { color: var(--window-text); font-family: var(--font-mono); font-size: 0.85rem; overflow-wrap: anywhere; }
.dev-row { display: flex; flex-wrap: wrap; gap: 4px; margin: 4px 0; }
.dev-row select { flex: 1 1 120px; min-width: 0; max-width: 100%; min-height: 24px; }
.dev-state { width: 100%; font-family: var(--font-mono); font-size: 0.8rem; color: var(--window-text); background: var(--window); border: 1px solid; border-color: var(--shadow) var(--hilight) var(--hilight) var(--shadow); resize: vertical; margin-top: 4px; }
.dev-reopen { position: fixed; left: 4px; bottom: 36px; z-index: 80; }

/* ── Phone fit (the owner's round of 2026-10-08) ──
   A phone gets the game at a size it can read and play with a thumb. The root goes to 16px, so everything sized in rem
   grows with it; the Calendar and the workbook sheets, drawn in the desktop's fixed pixels, go to rem; and every field
   is at least 16px, below which a phone zooms the page in when the field is tapped. Text grows on a narrow screen
   (under 761px) or a short touch one (a phone on its side). css/modern.css has the new desktop's twin of each rule. */
@media (max-width: 760px), (pointer: coarse) and (max-height: 520px) {
  html { font-size: 16px; }
  html:has(body.ui-large-text) { font-size: 18px; }
  .cal-head { font-size: 0.8rem; line-height: 1.6; }
  .cal-dow { font-size: 0.75rem; line-height: 1.5; }
  .cal-day { font-size: 0.85rem; line-height: 1.6; }
  .cal-arrow { width: 36px; font-size: 1rem; line-height: 1.6; }
  .cal-panel, .cal-item, .cal-wait { font-size: 0.85rem; }
  .cal-group-head, .cal-item small, .cal-wait-warn { font-size: 0.75rem; }
  .cal-panel-close { width: 32px; height: 28px; font-size: 1rem; line-height: 1; }
  .ledger { font-size: 0.8rem; }
  .ledger td.note, .ledger-q, .embed-cap { font-size: 0.75rem; }
  .ledger-q strong { font-size: 0.85rem; }
}
@media (max-width: 760px) {
  .asset-tag { display: none; }
  .cal-day { line-height: 36px; } /* the week strip's days: a row a thumb can hit */
  /* The review's buttons on a phone: two to a row across the width, not ragged to the right */
  .rv-actions { display: grid; grid-template-columns: 1fr 1fr; }
  .rv-actions .btn { width: 100%; min-width: 0; white-space: normal; } /* a label wraps rather than being cut at half the width */
  .rv-year { font-size: 0.78rem; } /* the trust years' labels stay at 12px or more at 16px */
}
@media (pointer: coarse) {
  input, select, textarea, .desk-sort select, .desk-filter select { font-size: max(16px, 1rem); }
  .cal-arrow { position: relative; }
  .cal-arrow::after { content: ''; position: absolute; inset: -8px -4px; } /* the arrow's touch area reaches past what it draws */
  .cal-wait { min-height: var(--target); }
  /* Touch targets of at least 44px on a touch screen (DESIGN.md's floor). Where growing a control would break the old
     desktop's look (its close box, the fold toggles drawn in a group box's border, Earlier in Status), an invisible area
     around it takes the tap instead. Left as they are: links inside running text, the Calendar's days (a week across a
     phone, 36px tall) and the desk toolbar's 30px menus (the owner's call). */
  body:not([data-os="modern"]) .close-btn { position: relative; }
  body:not([data-os="modern"]) .close-btn::after { content: ''; position: absolute; inset: -9px -6px; }
  input[type="checkbox"], input[type="radio"] { width: 22px; height: 22px; }
  .btn-small, .drawer-entry summary, .rv-sort, .more-menu button { min-height: var(--target); }
  .node-act { min-width: var(--target); } /* a programme's corner buttons: the node has the room */
  .tile-act { position: relative; min-height: 26px; }
  .tile-act::after { content: ''; position: absolute; inset: -9px -2px -9px -12px; } /* a tile's Do button keeps its desktop size, so it never covers the tile's name; an area around it, 44px square, takes the tap */
  #assess-options .choice, #assess-options .choice.chosen, #assess-options .choice:active { min-height: var(--target); padding: 8px 8px 8px 34px; }
  #assess-options .choice::before { top: 12px; width: 18px; height: 18px; }
  #assess-options .choice.chosen::before { background: radial-gradient(circle, var(--window-text) 5px, var(--window) 5.5px); }
  .assess-stop-row { margin: 13px 0 3px; } /* room in the window for the touch area of Stop for now, above and below its line */
  .assess-stop-row .link-btn { position: relative; }
  .assess-stop-row .link-btn::after { content: ''; position: absolute; inset: -13px -6px; } /* the touch area, without spreading its sentence over uneven lines */
  .logon-balloon-x::after { content: ''; position: absolute; inset: -10px; } /* the balloon's × keeps its size, with a finger's room around it */
  .tray-sound { width: var(--target); height: var(--target); }
  .foldbox > h3 .box-toggle, .news-more { position: relative; }
  .foldbox > h3 .box-toggle::after, .news-more::after { content: ''; position: absolute; inset: -14px -10px; }
  .menu-seed summary, .why > summary { padding: 12px 0; }
  .cal-head { min-height: 32px; }
  .rv-links a, .rv-links .link-btn { display: inline-block; padding: 12px 0; }
}
/* Two taps on a touch screen (armThenAct in js/views.js): the first opens a button, the second does it. At rest on a
   phone a reply is one line, its badge, its title and the figures it moves as icon and arrow; its line under the title
   is kept for a screen reader but not drawn. Opened (.armed), it shows that line, the figures in words and "Tap again
   to select". A proposal's and a one-off's tiles keep their picture and name; what they move and cost comes in the note
   the first tap puts above their row. A programme's sizes keep their lines and add the note's words when opened. */
.tap-note { grid-column: 1 / -1; order: -2; flex: 1 1 100%; padding: 6px 8px; font-size: 0.95rem; text-align: left; color: var(--window-text); background: var(--info); border: 1px solid var(--window-text); }
.control > .tap-note { order: 1; } /* a control's note goes under its row */
.tap-note .res-dots { margin: 3px 0; }
.tap-open { grid-column: 2; display: flex; flex-direction: column; gap: 2px; }
#prog-levels .choice > .tap-open { grid-column: 1 / -1; align-items: center; text-align: center; } /* under a size's centred dots, centred too */
.tap-note-text { font-size: 0.9rem; color: var(--gray-text); }
.tap-again { display: block; font-weight: 700; color: var(--select); }
:root[data-theme="dark"] .tap-again { color: var(--link); }
.btn.armed, .choice.armed { border-color: var(--shadow) var(--hilight) var(--hilight) var(--shadow); box-shadow: inset 1px 1px var(--dark), inset -1px -1px var(--face-light); background: var(--face-light); }
.sheet-res { display: none; }

@media (max-width: 760px), (max-height: 520px) {
  /* Every window a player reads or decides in takes the phone's width and keeps its frame. It is as tall as its content,
     up to the height of the screen, and centred when it is shorter, as a message box sits on the desktop, so a short
     window leaves no empty face below it and nothing in it stretches to fill the screen (the owner's check on a phone,
     2026-10-09). It scrolls as one: the inner boxes that scrolled on their own (a proposal's duties, the report's
     sheets, the email's body, About's text, the address book's list) let their content run on in the window instead.
     The small boxes (confirm, copy, error, a version's choice, Options) stay boxes. The email is a screen,
     not an overlay: its window grows with the message, and the screen scrolls when the window is taller than it. */
  .phone-window { padding: max(4px, env(safe-area-inset-top)) max(4px, env(safe-area-inset-right)) max(4px, env(safe-area-inset-bottom)) max(4px, env(safe-area-inset-left)); align-items: flex-start; }
  .phone-window > .sheet {
    display: flex; flex-direction: column; width: 100%; max-width: none; margin: auto 0;
    max-height: calc(100dvh - max(4px, env(safe-area-inset-top)) - max(4px, env(safe-area-inset-bottom)));
  }
  .phone-window > .sheet > .client { flex: 1 1 auto; min-height: 0; overflow: auto; }
  #modal-qmail .qmail-body, #modal-timeline #timeline-list, .cast-list, .cast-detail, .about-body, .handbook-page { flex: none; min-height: 0; max-height: none; overflow: visible; }
  /* the handbook's contents over its page, a short list of its own */
  .handbook-main { grid-template-columns: minmax(0, 1fr); }
  .handbook-side { height: auto; }
  .handbook-nav { flex: none; max-height: 32vh; }
  .handbook-page { height: auto; }
  .hb-terms { grid-template-columns: minmax(0, 1fr); } /* a term over its line, the screen too narrow for both side by side */
  .hb-terms dt { border-bottom: none; padding-bottom: 0; }
  .hb-terms dd { padding-top: 1px; }
  .cast-cols { scrollbar-gutter: auto; } /* the list no longer scrolls, so its heads keep no gutter either */
  #modal-cast .cast-main, #modal-cast .cast-body, #modal-cast .cast-detail-box { flex: none; }
  #screen-event { padding: max(4px, env(safe-area-inset-top)) max(4px, env(safe-area-inset-right)) max(4px, env(safe-area-inset-bottom)) max(4px, env(safe-area-inset-left)); align-items: stretch; }
  #event-sheet, #event-sheet.is-ledger { flex: 0 0 auto; width: 100%; max-width: none; max-height: none; margin: auto 0; }
  #event-sheet.is-ledger { margin-bottom: 0; } /* the year's ledger and the planner under it are centred together */
  #event-sheet > .client > .msg-body { flex: none; min-height: 0; overflow: visible; }
  #event-planner { margin: 6px 0 auto; max-width: none; }
  .wizard .client { align-content: start; } /* the assessment's banner keeps its own height */
  /* The email on a phone. The menu bars that only dress a window (File, Edit, View and the rest, marked aria-hidden) give
     their line to the message; the diary's, which opens the diary, stays. So do the address book's toolbar buttons that
     only dress it (New, Delete, Print, Action), which leaves Properties and Find people on one row. The header's labels
     make room for "Subject:" at 16px. Each reply is a row: its badge at the left, then its title, the line under it and
     the figures it moves, about half the height of the tiles they were; the row of replies and the status bar reach the
     window's edges. */
  .menubar[aria-hidden="true"], .toolbar > .tool-btn[aria-hidden="true"] { display: none; }
  #event-sheet > .client { padding: 8px; }
  .msg-head .msg-row { grid-template-columns: 76px minmax(0, 1fr); }
  #event-options.choices { flex-direction: column; margin: 6px -8px 0; gap: 6px; padding: 8px; }
  #event-options .choice { display: grid; grid-template-columns: 30px minmax(0, 1fr); column-gap: 10px; row-gap: 1px; align-items: center; justify-items: start; text-align: left; min-height: 48px; padding: 6px 10px; }
  #event-options .choice:active, #event-options .choice.chosen { padding: 7px 9px 5px 11px; }
  #event-options .choice > * { grid-column: 2; }
  #event-options .choice > .choice-badge, #event-options .choice::before { grid-column: 1; grid-row: 1 / span 3; justify-self: center; margin: 0; }
  #event-options .res-dots { justify-content: flex-start; margin-top: 2px; padding-top: 0; }
  .msg-status { margin: 6px -8px -8px; }
  .msg-cell, .msg-status .res-chip { gap: 4px; padding: 1px 5px; }
  /* The old desktop draws a reply and an assessment's answer flat until a pointer is over them, and a phone has no
     pointer to hover with. So on a phone each is a raised button at rest, set apart from the next, and sunk once it is
     pressed, chosen or opened (the owner's check on a phone, 2026-10-09). An answer keeps its round dot. */
  #event-options .choice, #event-options .choice + .choice, #assess-options .choice { border-color: var(--hilight) var(--dark) var(--dark) var(--hilight); box-shadow: inset -1px -1px var(--shadow), inset 1px 1px var(--face-light); background: var(--face); }
  #event-options .choice:active, #event-options .choice.chosen, #event-options .choice.armed, #assess-options .choice:active, #assess-options .choice.chosen { border-color: var(--shadow) var(--hilight) var(--hilight) var(--shadow); box-shadow: inset 1px 1px var(--dark), inset -1px -1px var(--face-light); background: var(--face); }
  /* A decision window (proposal, programme, one-off) on a phone covers the desk's figures, so it carries the email's
     status bar of the four figures under its client (resBar in js/views.js), lit by an action's hints as the desk's are.
     Its one row of buttons (a proposal's, a one-off's) stays pinned at the foot of the window while the rest scrolls;
     a programme's levels are the decision and can be tall, so they stay where they are, at the end. The desktop keeps
     the owner's call: no figures in the sheet (the bar is hidden above phone size). */
  :is(#modal-system, #modal-programme, #modal-intervention) > .sheet > .client { padding: 8px; }
  .sheet-res { display: flex; flex: none; margin: 0; padding: 3px; border-top: 1px solid var(--hilight); }
  /* A row of buttons pinned to the foot of a window that scrolls as one: a system's and a one-off's actions (which end the
     window, so no bottom margin), the mail's end row, and the About and How to play actions. */
  #sys-actions, #iv-actions, #modal-qmail .qmail-end, :is(#modal-about, #modal-handbook) > .sheet > .client > .actions { position: sticky; bottom: 0; z-index: 2; margin: 8px -8px -8px; padding: 6px 8px; background: var(--face); border-top: 1px solid var(--shadow); box-shadow: inset 0 1px var(--hilight); }
  #sys-actions, #iv-actions { margin-bottom: 0; }
  /* The quarter report on a phone. Its People sheet stacks each person as a row of their own (who and which way they
     moved, then what you did, then how they stand) instead of a sheet wider than the screen; the Figures sheet stays a
     sheet. Close stays pinned at the foot while the report scrolls, so focusing it as the mail opens moves nothing. */
  #modal-qmail > .sheet > .client { padding: 6px 8px 8px; }
  #qmail-people .xl { display: block; }
  #qmail-people .xl tr:first-child { display: none; }
  #qmail-people .xl tr { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 2px 10px; align-items: center; padding: 6px 8px; border-bottom: 1px solid var(--grid); }
  #qmail-people .xl td { padding: 0; border: 0; }
  #qmail-people .xl td.xl-who { grid-column: 1; padding-left: 0; white-space: normal; }
  #qmail-people .xl td.xl-who::before { display: none; }
  #qmail-people .xl td:nth-child(3) { grid-column: 2; grid-row: 1; }
  #qmail-people .xl td.xl-did, #qmail-people .xl td:nth-child(4) { grid-column: 1 / -1; min-width: 0; }
  /* About and How to play scroll as one window on a phone, so their row of buttons is pinned at the foot: focusing OK as
     the window opens then moves nothing, and How to play still opens at the section for the screen the player is on. */
  :is(#modal-about, #modal-handbook) > .sheet > .client { padding: 8px; }
  /* The mini games on a phone (the owner's preview of 2026-10-08): the window takes the screen's width like the others.
     The opening's picture is a banner across the top, over the title, the story and the three lines on how to play at
     full size, and Start and Skip sit at the foot, within a thumb's reach. The fields grow into the full width (the
     allowances in --mg-pc and --mg-tile were for the boxed window), the counter keeps to one line, and Check is a
     full-width bar. */
  .mg-intro { flex-direction: column; align-items: stretch; gap: 10px; }
  .mg-art { width: 100%; aspect-ratio: 16 / 7; }
  .mg[data-game="vendors"] .mg-art { background-size: auto 92%, 32px 32px; }
  .mg[data-game="oversight"] .mg-art { background-size: auto 80%, 32px 32px; }
  .mg[data-game="workflow"] .mg-art { background-size: auto 60%, 64px 64px; }
  .mg-guide { font-size: 1rem; color: var(--window-text); }
  .mg .actions { margin-top: auto; }
  .mg-pcs { --mg-pc: min(150px, calc((100vw - 52px) / 3)); }
  .mg-flow { --mg-tile: min(76px, calc((100vw - 60px) / 5.9)); }
  .mg-bar { flex-wrap: wrap; }
  .mg-readout { white-space: nowrap; }
  .mg-hold { align-self: stretch; min-height: 52px; font-size: 1.1rem; }
  /* The course's notice on a phone sits at the top of the desk's column rather than over the desk, and has no tail */
  .tutorial-note { position: static; width: auto; max-width: none; order: -4; }
  body:not([data-os="modern"]) .tutorial-note::before, body:not([data-os="modern"]) .tutorial-note::after { content: none; } /* the tail rules' own weight, so this later rule wins */
  body.course-note .desk { padding-bottom: 60px; }
  /* Safe areas: the page asks for the whole screen (viewport-fit=cover, index.html), so on a phone with a notch or a home
     bar the taskbar, the desk, the screens, the windows and the course's note keep clear of them. env() is 0 where a screen has
     none, so nothing moves elsewhere. */
  .taskbar { padding-left: max(2px, env(safe-area-inset-left)); padding-right: max(2px, env(safe-area-inset-right)); }
  .desk { grid-template-columns: minmax(0, 1fr); padding-left: max(8px, env(safe-area-inset-left)); padding-right: max(8px, env(safe-area-inset-right)); padding-bottom: calc(60px + env(safe-area-inset-bottom)); } /* one column: at 16px the swipeable In the air strip's widest pill would otherwise widen the column past a 320px screen */
  #screen-menu { padding: max(24px, env(safe-area-inset-top)) max(12px, env(safe-area-inset-right)) max(24px, env(safe-area-inset-bottom)) max(12px, env(safe-area-inset-left)); }
  #screen-report { padding: max(18px, env(safe-area-inset-top)) max(12px, env(safe-area-inset-right)) max(18px, env(safe-area-inset-bottom)) max(12px, env(safe-area-inset-left)); }
  #screen-ending { padding: max(16px, env(safe-area-inset-top)) max(16px, env(safe-area-inset-right)) max(16px, env(safe-area-inset-bottom)) max(16px, env(safe-area-inset-left)); }
  /* The old machine's startup screen on a phone: its text a size smaller, clear of the notch and the home bar, and its tag line on two lines */
  .boot-screen[data-frame="post"] { padding: max(16px, env(safe-area-inset-top)) 16px max(16px, env(safe-area-inset-bottom)); font-size: 0.8rem; }
  .boot-tag span { display: block; }
}
#event-options .choice.armed { background: var(--window); } /* after the phone block: its pressed face would win otherwise */
@media (pointer: coarse) and (max-width: 760px), (pointer: coarse) and (max-height: 520px) {
  #event-options:not(.one) .choice:not(.armed) { grid-template-columns: 30px minmax(0, 1fr) auto; }
  #event-options:not(.one) .choice:not(.armed) > .choice-sub { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
  #event-options:not(.one) .choice:not(.armed) > .res-dots { grid-column: 3; grid-row: 1; flex-wrap: nowrap; gap: 7px; margin: 0; }
  #event-options:not(.one) .choice:not(.armed) .res-dot { font-size: 0; gap: 1px; }
  #event-options:not(.one) .choice:not(.armed) .res-dot.has-ic::after { font-size: 0.7rem; }
  #event-options:not(.one) .choice:not(.armed) .res-dot .ic { --ic: 16px; }
  #sys-actions .btn { min-height: 52px; padding: 4px 2px; }
  #sys-actions .btn .res-dots, #iv-actions .btn .res-dots, #iv-actions .btn:not([disabled]) small { display: none; } /* a disabled one-off keeps its reason: no tap note comes for it */
  #event-options .choice, #sys-actions .btn, #iv-actions .btn, #prog-actions .btn, #prog-levels .choice, .control .btn-small, .reg-act { touch-action: manipulation; } /* a quick second tap is a tap, not a zoom */
}
/* The narrowest phones (360px and under): Start, five programs and the tray's sound button at 44px each are wider than
   the screen, so they give 4px each in width (still 44px tall). */
@media (pointer: coarse) and (max-width: 360px) {
  .start-btn, .task-btn { min-width: 40px; }
  .tray-sound { width: 40px; }
}

/* The programme and one-off cards (the owner's call of 2026-10-13): a header that says where it stands (the picture large,
   the title, the tree's chip), the branch's picture in the kicker, what it gives as the tree's tiles, what it costs on a
   line of its own, and sizes that show what each adds */
#prog-title, #iv-title { display: flex; align-items: center; flex-wrap: wrap; gap: 6px 10px; }
.title-icon { font-size: 1.9rem; line-height: 1; }
#prog-title .node-chip, #iv-title .node-chip { margin-top: 0; }
.kicker-icon { margin-right: 4px; }
#prog-gives .prog-tiles { margin: 4px 0 2px; }
/* Grants beside Unlocks (the owner's call of 2026-10-22): two white wells in one row, each headed by a band in the
   sheet's colour, the titlebar's. Grants widens with its tiles (--tiles, 1 to 4, set by fillProgrammeSheet: a 108px
   tile and its gap each), so they keep to one line where there is room; short of room for both, the wells stack. */
.prog-cols { display: flex; flex-wrap: wrap; align-items: stretch; gap: 16px 10px; margin: 16px 0 0; }
.prog-cols > .prog-well { min-width: 0; margin: 0; padding: 16px 10px 10px; background: var(--window); color: var(--window-text); border: 1px solid; border-color: var(--shadow) var(--hilight) var(--hilight) var(--shadow); box-shadow: inset 1px 1px var(--dark); border-radius: 0; }
#prog-gives { flex: var(--tiles, 1) 1 calc(var(--tiles, 1) * 114px + 22px); }
#prog-opens { flex: 2 1 200px; font-size: 0.92rem; }
.prog-well > .legend { padding: 0 6px; background: color-mix(in srgb, var(--dept) 80%, #000); color: #fff; border: 1px solid color-mix(in srgb, var(--dept) 55%, #000); }
body.high-contrast .prog-well > .legend { background: var(--window); color: var(--window-text); border: 2px solid var(--window-text); }
.sheet-costs { display: flex; align-items: center; gap: 6px; margin: 8px 0; font-size: 0.9rem; }
.sheet-costs strong { margin-right: 4px; }
.size-adds { display: inline-flex; align-items: center; gap: 6px; margin-left: 8px; vertical-align: middle; }
.size-adds .ic { --ic: 15px; }
.size-adds .duty-tile { --sym-tile: 16px; }
#prog-levels .node-chip { margin: 0 0 0 8px; vertical-align: 1px; }
