/* ==========================================================================
   Tepegöz PLATFORM — the sheet every page is written against.

   WHY THIS FILE EXISTS
   --------------------
   A token set and a component vocabulary that the platform pages are WRITTEN
   AGAINST, so nothing here has to shout. The three engine pages that once
   wore theme.css (site, graph, console) were rewritten against this sheet
   or deleted, and theme.css itself is deleted. Every component
   rule is still scoped to one of three things, so a page that brings its
   own furniture keeps it:

     #rail ............ the rail, drawn by platform.js on every page. It reads
                        the look through names of its own (--ink, --rail-tick,
                        ...) set on the element itself.
     .page / .drawer .. the platform's own components.
     :root ............ the two looks below, on every page that loads this
                        sheet - the canvases included.

   TWO LOOKS: LIGHT AND DARK
   -------------------------
   The owner's decision of 30 Sep 2026 (docs/design/RENEWAL.md, DECISIONS.md
   D20): two looks and no others. A browser that has not chosen opens in
   LIGHT. Dark is the person's choice, made at the foot of the rail and kept
   in that browser; it is never the operating system's (there is no
   prefers-color-scheme here, on purpose).

   The colours are the redesign's (docs/design/redesign/_src/base.css, the
   Light and Dark token blocks). They are written onto THIS sheet's names, so
   every page kept working when the looks changed:

     redesign        this sheet          redesign        this sheet
     --bg            --bg                --text          --text
     --hover         --bg2               --text-2        --dim
     --surface       --panel             --text-3        --faint
     --surface-2     --panel2            --line          --line, --rail-line
     --line-strong   --line2             --side-bg       --rail-bg
     --shadow-1      --shadow            --port-<type>   --cv-port-<type>

   and the redesign's own names where this sheet had none: --sunken, --edge,
   --acc-soft, --ok-soft .. --info-soft, --focus, --scrim, --shadow-2.

   A look changes colour and corner radius. It never changes structure: the
   components below are drawn once, for both. (Until 30 Sep there were five
   looks - Clear, Night, Slate, Paper, Dusk - each a palette with structure
   of its own. The structure the two looks share is Dusk's, which every
   browser wore by then: surfaces with an edge, raised buttons, recessed
   fields, state as a badge, a rail of words rather than numbered ticks.)

   One accent per look - blue in Light, amber in Dark - and a status colour
   is never the accent. Every colour a component uses is a token; a hex
   value outside the two look blocks is a third look by accident.

   TYPE
   ----
   Unchanged by the looks, and the redesign's (DESIGN.md §4.4): ONEST for the
   interface and for titles - Latin, Cyrillic, and Uzbek's letters - and
   JETBRAINS MONO for the things that literally are numbers and code:
   versions, ids, frame rates, milliseconds, times; the faces before them are
   gone (30 Sep). Both are BUNDLED, under /assets/fonts/: one variable woff2 per
   script, fetched once from Google Fonts' own files, each face's SIL Open
   Font License beside it (OFL-Onest.txt, OFL-JetBrainsMono.txt). Nothing is
   asked of Google at run time - a site's box is routinely offline - and a
   page loads only the scripts its words use (unicode-range). Behind each face
   a fallback a Windows plant PC has: Segoe UI, Consolas, Georgia.

   THE MARK
   --------
   The logo is monochrome (checked: every opaque pixel of logo.png is one
   value), so it takes no colour from the look but its ink: dark riders on
   Light, light riders on Dark, on the ground itself with no plaque. The rail
   loads logo-rail.png / logo-rail-dark.png rather than the two originals:
   same mark, 330 px wide (twice the 158 px it is drawn at) and quantised to
   64 colours, which is lossless for a one-colour mark. The originals stay
   where they are for print and for anyone who needs the full-size file.
   ========================================================================== */

/* --------------------------------------------------------------- faces ----
   Onest and JetBrains Mono, variable (400 to 700 in one file), one file per
   script as Google Fonts cuts them: Latin (with Uzbek's oʻ and gʻ, U+02BB),
   Latin extended, Cyrillic, Cyrillic extended. The browser fetches a file only
   when the page holds a letter in its range. */
@font-face { font-family:"Onest"; font-style:normal; font-weight:400 700; font-display:swap;
  src:url(/assets/fonts/onest-latin.woff2) format("woff2");
  unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC,
    U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215,
    U+FEFF, U+FFFD; }
@font-face { font-family:"Onest"; font-style:normal; font-weight:400 700; font-display:swap;
  src:url(/assets/fonts/onest-latin-ext.woff2) format("woff2");
  unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304,
    U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0,
    U+2113, U+2C60-2C7F, U+A720-A7FF; }
@font-face { font-family:"Onest"; font-style:normal; font-weight:400 700; font-display:swap;
  src:url(/assets/fonts/onest-cyrillic.woff2) format("woff2");
  unicode-range:U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; }
@font-face { font-family:"Onest"; font-style:normal; font-weight:400 700; font-display:swap;
  src:url(/assets/fonts/onest-cyrillic-ext.woff2) format("woff2");
  unicode-range:U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; }
@font-face { font-family:"JetBrains Mono"; font-style:normal; font-weight:400 700;
  font-display:swap; src:url(/assets/fonts/jetbrains-mono-latin.woff2) format("woff2");
  unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC,
    U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215,
    U+FEFF, U+FFFD; }
@font-face { font-family:"JetBrains Mono"; font-style:normal; font-weight:400 700;
  font-display:swap; src:url(/assets/fonts/jetbrains-mono-latin-ext.woff2) format("woff2");
  unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304,
    U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0,
    U+2113, U+2C60-2C7F, U+A720-A7FF; }
@font-face { font-family:"JetBrains Mono"; font-style:normal; font-weight:400 700;
  font-display:swap; src:url(/assets/fonts/jetbrains-mono-cyrillic.woff2) format("woff2");
  unicode-range:U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; }
@font-face { font-family:"JetBrains Mono"; font-style:normal; font-weight:400 700;
  font-display:swap; src:url(/assets/fonts/jetbrains-mono-cyrillic-ext.woff2) format("woff2");
  unicode-range:U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; }

/* ------------------------------------------------------------- neutral ---- */
/* What does not change with the look. */

:root {
  --sans: "Onest", "Segoe UI", system-ui, -apple-system, "Helvetica Neue", Arial, sans-serif;
  --mono: "JetBrains Mono", "Cascadia Mono", Consolas, ui-monospace, "Courier New", monospace;
  --serif: "Iowan Old Style", "Palatino Linotype", Palatino, Georgia, "Times New Roman", serif;
  /* the redesign's rail (DESIGN.md §2.3): 236 px on every page; folded to
     its marks on a phone, below */
  --rail-w:236px;
}

/* ================================================================ looks ====
   LIGHT is the root itself: every page, and every browser that never chose.
   DARK is the same names under [data-theme="dark"], which platform.js (or a
   page's first script) puts on the root only when the person chose it.

   The selector lists are wider than :root on purpose. A generated product
   page (solutions/app.py) sets its brand accent on :root[data-tz="platform"]
   after this sheet; the look's accent has always won over it there, by the
   :has(main.page) branch, and it still does - the customer's own skin is a
   decision not yet taken (DESIGN.md §8 item 3), so this sheet does not take
   it by accident either. Each Dark selector outranks its Light twin. */

:root, :root:has(main.page), :root[data-tz="platform"] {
  color-scheme: light;
  --bg:#f3f4f6; --bg2:#eef1f5; --panel:#ffffff; --panel2:#f8f9fb; --sunken:#f1f3f6;
  --line:#e3e6ea; --line2:#cdd2d9; --edge:#8b93a1;
  --text:#111827; --dim:#465063; --faint:#626b7a;
  --acc:#2458d6; --acc-ink:#ffffff; --acc-soft:#e9effd; --acc-text:#1f4fc4;
  --ok:#17703f; --warn:#9a5500; --err:#c42f2a; --info:#0e6699;
  --ok-soft:#e4f4ea; --warn-soft:#fdf0db; --err-soft:#fcebea; --info-soft:#e3f1f8;
  --focus:rgba(36,88,214,.35);
  --rail-bg:#fbfbfc; --rail-line:#e3e6ea;
  /* each look's own ground, for the look's swatch in the account menu - the
     one place a look must show the other */
  --sw-light:#ffffff; --sw-dark:#121922;
  /* the ink of a letter on a customer's own colour (--brand, which is data):
     white, or near-black on a brand too light for white - the server says
     which. The same in both looks: a brand does not change with the look. */
  --on-brand:#ffffff; --on-brand-dark:#111827;
  --radius:8px;
  --shadow:0 1px 2px rgba(16,24,40,.06);
  --shadow-2:0 18px 44px rgba(16,24,40,.18);
  --scrim:rgba(17,24,39,.34);
  /* the two shapes the structure needs by name: --lift is what a RAISED
     thing (a button, a card) has on its top edge, --sunk what a RECESSED
     thing (a field) has. In Light the drop shadow does the raising. */
  --lift:inset 0 1px 0 rgba(255,255,255,.6);
  --sunk:inset 0 1px 2px rgba(16,24,40,.05);
  --logo:url(/assets/logo-rail-dark.png);

  /* The drawing surfaces read these at draw time (site.html through PAL,
     the node editors for ports and bands), so a change of
     look re-skins the slab, the rooms, the cones, the DORI bands, the node
     bands and the wires in one repaint. The twelve port colours are the
     redesign's: a port type is never a status colour - events are ink, not
     red; tracks are not "ok" green. */
  --cv-floor:#e8eaee; --cv-floor-line:#9aa3af; --cv-grid:#d3d8df;
  --cv-vig:rgba(17,24,39,.06); --cv-slab:rgba(17,24,39,.18);
  --cv-dot-ring:#ffffff;
  --cv-room-fill:rgba(70,80,99,.05); --cv-room-line:#8b93a1;
  --cv-wall-fill:rgba(70,80,99,.09); --cv-wall-line:rgba(70,80,99,.32);
  --cv-handle:#6b7484; --cv-label:#465063; --cv-ink:#111827;
  --cv-blind:rgba(196,47,42,.12); --cv-mast:#6b7484;
  --cv-person:rgba(36,88,214,.95); --cv-link:23,112,63; --cv-draw:#9a5500;
  --cv-ident-fill:rgba(23,112,63,.16); --cv-ident-line:rgba(23,112,63,.85);
  --cv-olap-fill:rgba(154,85,0,.10); --cv-olap-line:rgba(154,85,0,.55);
  --cv-chip-bg:rgba(255,255,255,.94); --cv-chip-line:#e3e6ea;
  --cv-ghost:36,88,214;
  --cv-hue-s:62%; --cv-hue-l:46%;
  --cv-cat-source:#06779a; --cv-cat-model:#6d48c9; --cv-cat-logic:#86653a;
  --cv-cat-output:#0b7a6f; --cv-cat-lab:#b33a7a; --cv-cat-ink:#ffffff;
  --cv-port-frame:#78818f; --cv-port-detections:#6b7200; --cv-port-tracks:#3f7d20;
  --cv-port-crops:#b33a7a; --cv-port-embeddings:#6d48c9; --cv-port-identities:#0b7a6f;
  --cv-port-events:#1f2937; --cv-port-zones:#06779a; --cv-port-assertions:#4b4fc2;
  --cv-port-readings:#6e6a3a; --cv-port-dataset:#86653a; --cv-port-model:#8a4f9e;
  background:var(--bg); color:var(--text);
}

:root[data-theme="dark"], :root:has(main.page)[data-theme="dark"],
:root[data-tz="platform"][data-theme="dark"] {
  color-scheme: dark;
  --bg:#0b0f14; --bg2:#1b2530; --panel:#121922; --panel2:#18212b; --sunken:#0e141b;
  --line:#1f2a35; --line2:#2f3d4b; --edge:#5b6979;
  --text:#e9eff4; --dim:#b0bdc9; --faint:#8a99a8;
  --acc:#f0a500; --acc-ink:#0b0f14; --acc-soft:rgba(240,165,0,.14); --acc-text:#f5b93a;
  --ok:#47c48c; --warn:#f28c4e; --err:#f2637c; --info:#5eb1e8;
  --ok-soft:rgba(71,196,140,.14); --warn-soft:rgba(242,140,78,.15);
  --err-soft:rgba(242,99,124,.15); --info-soft:rgba(94,177,232,.14);
  --focus:rgba(240,165,0,.40);
  --rail-bg:#0e141b; --rail-line:#1f2a35;
  --sw-light:#ffffff; --sw-dark:#121922;
  --on-brand:#ffffff; --on-brand-dark:#111827;
  --radius:6px;
  --shadow:0 1px 0 rgba(0,0,0,.35);
  --shadow-2:0 20px 50px rgba(0,0,0,.55);
  --scrim:rgba(0,0,0,.55);
  --lift:inset 0 1px 0 rgba(255,255,255,.04);
  --sunk:inset 0 1px 2px rgba(0,0,0,.38);
  --logo:url(/assets/logo-rail.png);

  --cv-floor:#161e27; --cv-floor-line:#38495a; --cv-grid:#1b2530;
  --cv-vig:rgba(0,0,0,.50); --cv-slab:rgba(0,0,0,.65);
  --cv-dot-ring:#0b0f14;
  --cv-room-fill:rgba(176,189,201,.05); --cv-room-line:#55697a;
  --cv-wall-fill:rgba(176,189,201,.08); --cv-wall-line:rgba(176,189,201,.28);
  --cv-handle:#6d7f8e; --cv-label:#b0bdc9; --cv-ink:#e9eff4;
  --cv-blind:rgba(242,99,124,.16); --cv-mast:#6d7f8e;
  --cv-person:rgba(94,177,232,.95); --cv-link:71,196,140; --cv-draw:#f28c4e;
  --cv-ident-fill:rgba(71,196,140,.20); --cv-ident-line:rgba(71,196,140,.85);
  --cv-olap-fill:rgba(242,140,78,.12); --cv-olap-line:rgba(242,140,78,.55);
  --cv-chip-bg:rgba(11,15,20,.92); --cv-chip-line:#2f3d4b;
  --cv-ghost:240,165,0;
  --cv-hue-s:58%; --cv-hue-l:62%;
  --cv-cat-source:#5cc4ef; --cv-cat-model:#b49cfa; --cv-cat-logic:#d0b07e;
  --cv-cat-output:#4fd0c2; --cv-cat-lab:#f07ab8; --cv-cat-ink:#0b0f14;
  --cv-port-frame:#8f9bad; --cv-port-detections:#cddc5a; --cv-port-tracks:#8fd46a;
  --cv-port-crops:#f07ab8; --cv-port-embeddings:#b49cfa; --cv-port-identities:#4fd0c2;
  --cv-port-events:#eef2f6; --cv-port-zones:#5cc4ef; --cv-port-assertions:#9ea4ff;
  --cv-port-readings:#c8c08a; --cv-port-dataset:#d0b07e; --cv-port-model:#d69be6;
}

/* Shared by both looks. Titles are set in the interface face: the looks have
   done so since Dusk, and the display serif is kept declared above for
   nothing to lose if a look ever wants it back. */
:root { --serif: var(--sans); }

/* ================================================================= rail ====
   The redesign's rail (DESIGN.md §2.3, §4.6; redesign/_src/base.css .side),
   drawn by platform.js on every page: the mark and this computer's name;
   Find anything; the places a person goes, a line, System; This computer;
   the account and its menu. 236 px; on a phone it folds to its marks,
   60 px (below, "responsive"). The rail reads
   the look through names of its own, so its rules below never name a page
   token directly - except the accent's, which is the look's own. */

#rail {
  --ink:var(--text); --ink-dim:var(--dim); --ink-faint:var(--faint);
  --rail-tick:var(--line2); --rail-ok:var(--ok); --rail-warn:var(--warn);
  --rail-hover:var(--bg2); --rail-card:var(--panel); --rail-card2:var(--panel2);
  position:fixed; top:0; left:0; bottom:0; width:var(--rail-w); z-index:999;
  box-sizing:border-box;
  background:var(--rail-bg); color:var(--ink-dim);
  border-right:1px solid var(--rail-line);
  display:flex; flex-direction:column;
  padding:0;
  font-family:var(--sans); font-size:14px; line-height:1.45;
  overflow:hidden auto; scrollbar-width:thin;
}
#rail *, #rail *::before, #rail *::after { box-sizing:border-box; }
#rail svg { display:block; }

/* The riders ride on the ground itself — no plaque, no box, no border. */
#rail .tz-brand {
  display:flex; align-items:center; gap:10px; text-decoration:none; flex:none;
  padding:18px 18px 14px; color:var(--ink);
}
#rail .tz-logo {
  display:block; flex:none; width:50px; height:30px;
  background:var(--logo) no-repeat center / contain;
}
#rail .tz-wordmark { display:flex; flex-direction:column; line-height:1.1; min-width:0; }
#rail .tz-wordmark b { font-size:16px; font-weight:600; letter-spacing:-.01em; color:var(--ink); }
#rail .tz-wordmark span {
  font-size:11.5px; color:var(--ink-faint); margin-top:3px;
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
}

/* Find anything · Ctrl K: a field that opens the palette. */
#rail .tz-find {
  display:flex; align-items:center; gap:8px; flex:none;
  margin:2px 14px 12px; height:34px; padding:0 10px;
  border:1px solid var(--rail-line); border-radius:var(--radius);
  background:var(--rail-card); color:var(--ink-faint);
  font-family:var(--sans); font-size:13px; line-height:1; text-align:left; cursor:pointer;
}
#rail .tz-find svg { width:16px; height:16px; flex:none; }
#rail .tz-find .tz-lbl { flex:1; min-width:0; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
#rail .tz-find:hover { border-color:var(--rail-tick); color:var(--ink-dim); }
#rail .tz-find:focus-visible { outline:2px solid var(--acc); outline-offset:1px; }
#rail kbd {
  font-family:var(--mono); font-size:11px; line-height:1.4; padding:1px 6px; border-radius:4px;
  border:1px solid var(--rail-tick); color:var(--ink-faint); background:var(--rail-card2);
  white-space:nowrap; flex:none;
}

/* The places: a mark and a word; where you are gets the soft accent and a
   3 px bar at the rail's edge. A count only when something needs a person. */
#rail .tz-nav { display:flex; flex-direction:column; gap:2px; padding:4px 10px; flex:none; }
#rail .tz-tab {
  display:flex; align-items:center; gap:11px; height:36px; padding:0 10px;
  border-radius:var(--radius); color:var(--ink-dim); text-decoration:none;
  font-size:14px; line-height:1.2; position:relative;
  transition:color .14s, background .14s;
}
#rail .tz-tab:hover { background:var(--rail-hover); color:var(--ink); }
#rail .tz-tab:focus-visible { outline:2px solid var(--acc); outline-offset:-2px; }
#rail .tz-tab.here { background:var(--acc-soft); color:var(--ink); font-weight:600; }
#rail .tz-tab.here::before {
  content:""; position:absolute; left:-10px; top:8px; bottom:8px; width:3px;
  border-radius:0 3px 3px 0; background:var(--acc);
}
#rail .tz-tab .tz-ico { width:18px; height:18px; flex:none; display:block; }
#rail .tz-tab .tz-ico svg { width:18px; height:18px; }
#rail .tz-tab .tz-lbl { flex:1; min-width:0; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
#rail .tz-badge {
  margin-left:auto; flex:none; font-style:normal; font-size:11.5px; font-weight:600;
  min-width:20px; height:20px; padding:0 6px; border-radius:10px;
  display:inline-flex; align-items:center; justify-content:center; font-variant-numeric:tabular-nums;
  background:var(--rail-card2); color:var(--ink-dim); border:1px solid var(--rail-line);
}
#rail .tz-badge:empty { display:none; }
#rail .tz-badge.warn { background:var(--warn-soft); color:var(--warn); border-color:transparent; }
#rail .tz-badge.err { background:var(--err-soft); color:var(--err); border-color:transparent; }
#rail .tz-sep { height:1px; background:var(--rail-line); margin:10px 8px; flex:none; }
#rail .tz-grow { flex:1 1 auto; min-height:12px; }

/* While the builder has no account: said once, with the way out. */
#rail .tz-ws { flex:none; padding:0 12px 10px; }
#rail .tz-note {
  display:block; padding:9px 11px; border-radius:var(--radius); text-decoration:none;
  background:var(--warn-soft); color:var(--ink); font-size:12px; line-height:1.45;
}
#rail .tz-note b { color:var(--rail-warn); font-weight:600; }
#rail .tz-note u { color:var(--acc-text); text-underline-offset:2px; }

/* This computer: what it tries, its cameras and failing nodes, Open, Stop. */
#rail .tz-here {
  margin:0 12px 10px; padding:10px 12px; flex:none;
  border:1px solid var(--rail-line); border-radius:var(--radius); background:var(--rail-card);
  font-size:12.5px; line-height:1.35; color:var(--ink-dim);
}
#rail .tz-here .tz-ht { display:flex; align-items:center; gap:7px; color:var(--ink-faint); font-size:11.5px; }
#rail .tz-here .tz-hv { color:var(--ink); font-weight:600; margin-top:4px; }
#rail .tz-here .tz-hm { margin-top:2px; }
#rail .tz-here .tz-herr { margin-top:6px; color:var(--rail-warn); font-size:11.5px; }
#rail .tz-here .tz-ha { margin-top:7px; display:flex; gap:12px; align-items:center; }
#rail .tz-here .tz-ha a { color:var(--acc-text); text-decoration:none; font-weight:600; }
#rail .tz-here .tz-ha a:hover { text-decoration:underline; }
#rail .tz-stop {
  border:none; background:none; padding:0; cursor:pointer; font-family:var(--sans);
  font-size:12.5px; line-height:1.35; font-weight:600; color:var(--acc-text);
}
#rail .tz-stop:hover { text-decoration:underline; }
#rail .tz-dot { width:8px; height:8px; border-radius:50%; display:inline-block; flex:none; background:var(--ink-faint); }
#rail .tz-dot.ok { background:var(--rail-ok); }
#rail .tz-dot.warn { background:var(--rail-warn); }

/* The account, and its menu (hq-home-dark): my account and password, the
   look, sign out. */
#rail .tz-foot {
  flex:none; padding:10px 10px 12px; border-top:1px solid var(--rail-line);
}
#rail .tz-acct {
  display:flex; align-items:center; gap:10px; width:100%; padding:6px 8px;
  border:none; border-radius:var(--radius); background:transparent; color:var(--ink);
  font-family:var(--sans); text-align:left; cursor:pointer;
}
#rail .tz-acct:hover, #rail .tz-acct[aria-expanded="true"] { background:var(--rail-hover); }
#rail .tz-acct:focus-visible { outline:2px solid var(--acc); outline-offset:-2px; }
#rail .tz-acct > svg { width:16px; height:16px; color:var(--ink-faint); flex:none; }
#rail .tz-avatar {
  width:30px; height:30px; border-radius:50%; flex:none; display:inline-flex;
  align-items:center; justify-content:center; font-size:12.5px; font-weight:600;
  background:var(--acc-soft); color:var(--acc-text);
}
#rail .tz-who { display:flex; flex-direction:column; line-height:1.25; min-width:0; flex:1; }
#rail .tz-who b {
  font-size:13.5px; font-weight:600; color:var(--ink);
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
}
#rail .tz-who span {
  font-size:12px; color:var(--ink-faint); white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
}
#rail .tz-menu {
  position:fixed; left:12px; bottom:66px; z-index:1300; width:250px; padding:6px;
  background:var(--rail-card); border:1px solid var(--rail-line);
  border-radius:calc(var(--radius) + 4px); box-shadow:var(--shadow-2);
  color:var(--ink); font-size:13.5px;
}
#rail .tz-menu[hidden] { display:none; }
#rail .tz-mwho { display:flex; gap:10px; align-items:center; padding:8px 10px 10px; }
#rail .tz-mi {
  display:flex; align-items:center; gap:10px; width:100%; height:34px; padding:0 10px;
  border:none; border-radius:var(--radius); background:transparent; color:var(--ink);
  font-family:var(--sans); font-size:13.5px; text-decoration:none; text-align:left; cursor:pointer;
}
#rail .tz-mi:hover, #rail .tz-mi:focus-visible { background:var(--rail-hover); outline:none; }
#rail .tz-mi svg { width:16px; height:16px; color:var(--ink-faint); flex:none; }
#rail .tz-ml { font-size:11.5px; color:var(--ink-faint); padding:8px 10px 4px; }
#rail .tz-msep { height:1px; background:var(--rail-line); margin:6px 4px; }
/* The look: Light and Dark, both named, each with its swatch, the one in
   use ticked. Drawn, not typed. */
#rail .tz-looks { display:flex; flex-direction:column; }
#rail .tz-looks .tz-mi[aria-pressed="true"] { background:var(--rail-hover); }
#rail .tz-sw { width:14px; height:14px; border-radius:4px; border:1px solid var(--rail-tick); flex:none; }
#rail .tz-sw[data-sw="light"] { background:var(--sw-light); }
#rail .tz-sw[data-sw="dark"] { background:var(--sw-dark); }
#rail .tz-mi .tz-grow { flex:1; min-height:0; }
#rail .tz-tick { width:16px; height:16px; flex:none; color:var(--acc-text); visibility:hidden; }
#rail .tz-tick svg { width:16px; height:16px; color:var(--acc-text); }
#rail .tz-mi[aria-pressed="true"] .tz-tick { visibility:visible; }
/* Sign out: a control of its own, drawn in both looks. (It once borrowed the
   look switch's class, and went when a look hid that switch.) */
#rail .tz-signout {
  display:flex; align-items:center; gap:10px; width:100%; height:34px; padding:0 10px;
  border:none; border-radius:var(--radius); background:transparent; color:var(--ink);
  font-family:var(--sans); font-size:13.5px; text-align:left; cursor:pointer;
}
#rail .tz-signout svg { width:16px; height:16px; flex:none; color:var(--ink-faint); }
#rail .tz-signout:hover { background:var(--rail-hover); }
#rail .tz-signout:focus-visible { outline:2px solid var(--acc); outline-offset:-2px; }

/* ===================================================== Find anything ======
   Ctrl K, over any page (hq-search, hq-studio-dark): the query, where it
   looks, results grouped as the server says, the chosen one's acts, and the
   keys. It hangs over the page's own area, clear of the rail. */
.tz-kscrim { position:fixed; inset:0; z-index:1450; background:var(--scrim); }
.tz-kscrim[hidden], .tz-k[hidden] { display:none; }
.tz-k {
  position:fixed; z-index:1460; top:84px;
  left:max(16px, calc(var(--rail-w) + (100vw - var(--rail-w)) / 2 - 340px));
  width:min(680px, calc(100vw - 32px)); max-height:calc(100vh - 120px);
  display:flex; flex-direction:column; overflow:hidden; box-sizing:border-box;
  background:var(--panel); color:var(--text); border:1px solid var(--line);
  border-radius:calc(var(--radius) + 4px); box-shadow:var(--shadow-2);
  font-family:var(--sans); font-size:14px; line-height:1.45;
}
.tz-k * { box-sizing:border-box; }
.tz-k svg { display:block; }
.tz-k kbd {
  font-family:var(--mono); font-size:11px; line-height:1.4; padding:1px 6px; border-radius:4px;
  border:1px solid var(--line2); color:var(--faint); background:var(--panel2); white-space:nowrap;
}
.tz-kq {
  display:flex; align-items:center; gap:10px; height:54px; padding:0 18px; flex:none;
  border-bottom:1px solid var(--line); cursor:text;
}
.tz-kq svg { width:19px; height:19px; color:var(--faint); flex:none; }
.tz-kq input {
  flex:1; min-width:0; border:none; outline:none; background:transparent; padding:0;
  color:var(--text); font-family:var(--sans); font-size:16px; caret-color:var(--acc);
}
.tz-kq input::placeholder { color:var(--faint); }
.tz-kscopes { display:flex; gap:6px; padding:10px 18px 2px; flex:none; }
.tz-kscope {
  height:26px; display:inline-flex; align-items:center; padding:0 10px; border-radius:13px;
  font-family:var(--sans); font-size:12.5px; font-weight:600; color:var(--dim);
  border:1px solid var(--line); background:transparent; cursor:pointer;
}
.tz-kscope:hover { color:var(--text); }
.tz-kscope.on { background:var(--acc-soft); color:var(--acc-text); border-color:transparent; }
.tz-klist { flex:1; min-height:0; overflow:auto; padding:0 0 6px; }
.tz-kgrp { font-size:11.5px; font-weight:600; color:var(--faint); padding:10px 18px 4px; }
.tz-kit {
  display:flex; align-items:center; gap:12px; min-height:44px; padding:6px 18px; cursor:pointer;
}
.tz-kit.on { background:var(--acc-soft); box-shadow:inset 3px 0 0 var(--acc); }
.tz-kic {
  width:30px; height:30px; border-radius:var(--radius); flex:none;
  display:inline-flex; align-items:center; justify-content:center;
  background:var(--panel2); border:1px solid var(--line); color:var(--dim);
}
.tz-kic svg { width:16px; height:16px; }
.tz-kt { display:flex; flex-direction:column; min-width:0; flex:1; }
.tz-kt b { font-weight:600; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.tz-kt b.tz-mono { font-family:var(--mono); font-size:13.5px; font-weight:500; }
.tz-kt b mark { background:transparent; color:var(--acc-text); font-weight:700; }
.tz-kt span { font-size:12.5px; color:var(--faint); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.tz-kr { margin-left:auto; display:flex; align-items:center; gap:8px; flex:none; }
.tz-chip {
  display:inline-flex; align-items:center; gap:6px; height:22px; padding:0 9px 0 8px; border-radius:11px;
  font-size:12px; font-weight:600; white-space:nowrap;
  background:var(--panel2); color:var(--dim); border:1px solid var(--line);
}
.tz-chip::before { content:""; width:7px; height:7px; border-radius:50%; background:currentColor; flex:none; }
.tz-chip.ok { background:var(--ok-soft); color:var(--ok); border-color:transparent; }
.tz-chip.warn { background:var(--warn-soft); color:var(--warn); border-color:transparent; }
.tz-chip.err { background:var(--err-soft); color:var(--err); border-color:transparent; }
.tz-chip.info { background:var(--info-soft); color:var(--info); border-color:transparent; }
.tz-kacts { display:flex; flex-wrap:wrap; gap:6px; padding:0 18px 10px 60px; background:var(--acc-soft); }
.tz-kact {
  display:inline-flex; align-items:center; gap:7px; height:28px; padding:0 10px;
  border-radius:var(--radius); border:1px solid var(--line2); background:var(--panel);
  box-shadow:var(--shadow); color:var(--text); cursor:pointer; white-space:nowrap;
  font-family:var(--sans); font-size:12.5px; font-weight:600;
}
.tz-kact svg { width:15px; height:15px; flex:none; }
.tz-kact:hover { border-color:var(--acc); }
.tz-kact.on { border-color:var(--acc); box-shadow:0 0 0 3px var(--focus); }
.tz-kfoot {
  display:flex; align-items:center; gap:16px; padding:10px 18px; flex:none; overflow:hidden;
  border-top:1px solid var(--line); background:var(--panel2); font-size:12px; color:var(--faint);
}
.tz-kfoot span { display:inline-flex; align-items:center; gap:6px; white-space:nowrap; }
.tz-kfoot kbd + kbd { margin-left:-2px; }
.tz-kfoot .tz-kcount { margin-left:auto; min-width:0; overflow:hidden; text-overflow:ellipsis; }
.tz-knone { padding:18px; color:var(--dim); font-size:13.5px; }
.tz-knote {
  margin:10px 18px 0; padding:8px 12px; border-radius:var(--radius);
  background:var(--err-soft); color:var(--text); font-size:12.5px;
}

/* ============================ PLATFORM PAGES ==============================
   Everything below is scoped to .page or .drawer, so a page's own furniture
   (an App's panes, the canvases' toolbars) is never touched by it. */

body { margin:0; }

.page {
  margin-left:var(--rail-w); min-height:100vh; box-sizing:border-box;
  background:var(--bg); color:var(--text);
  font-family:var(--sans); font-size:13px; line-height:1.5;
  padding:26px 28px 64px; max-width:100%; overflow-x:hidden;
}
.page *, .drawer * { box-sizing:border-box; }
.page a { color:var(--acc); text-decoration:none;
          text-underline-offset:2px; text-decoration-thickness:1px; }
.page a:hover { text-decoration:underline; }

:is(.page, .drawer) .mono { font-family:var(--mono); font-variant-numeric:tabular-nums;
                            letter-spacing:-.005em; }
:is(.page, .drawer) .muted { color:var(--dim); }
:is(.page, .drawer) .faint { color:var(--faint); }
:is(.page, .drawer) .num { font-family:var(--mono); font-variant-numeric:tabular-nums;
                           text-align:right; }

/* ONE considered reveal: the page is laid on the table, top first. Nothing
   moves again after that — a surface an operator watches all day must be
   still. Skipped entirely where the reader has asked for less motion. */
@keyframes tz-lay { from { opacity:0; transform:translateY(7px); } }
@media (prefers-reduced-motion: no-preference) {
  main.page > * { animation:tz-lay .42s cubic-bezier(.2,.7,.3,1) both; }
  main.page > :nth-child(1) { animation-delay:0s; }
  main.page > :nth-child(2) { animation-delay:.045s; }
  main.page > :nth-child(3) { animation-delay:.09s; }
  main.page > :nth-child(4) { animation-delay:.13s; }
  main.page > :nth-child(5) { animation-delay:.165s; }
  main.page > :nth-child(n+6) { animation-delay:.195s; }
}

/* ----------------------------------------------------------- page head ----
   The airiest thing on the page: the title carries weight, not a serif, and
   one hairline closes it. */

.page .pagehead {
  display:flex; align-items:flex-end; gap:28px; flex-wrap:wrap;
  padding-bottom:14px; margin-bottom:20px; position:relative;
  border-bottom:1px solid var(--line);
}
.page .pagehead h1.title {
  font-family:var(--serif); font-size:31px; font-weight:650; margin:0;
  letter-spacing:-.02em; line-height:1.03; color:var(--text);
  font-optical-sizing:auto;
}
.page .pagehead p.lede {
  margin:11px 0 0; font-size:13px; color:var(--dim); max-width:82ch;
  line-height:1.62;
}
.page .pagehead .actions { margin-left:auto; display:flex; gap:8px;
                           align-items:center; flex-wrap:wrap; }

/* ----------------------------------------------------------------- kpi ----
   Measurements, so they are set in mono, each on a surface of its own. */

.page .kpis {
  display:grid; grid-template-columns:repeat(auto-fit, minmax(168px, 1fr));
  gap:11px; margin-bottom:26px;
}
.page .kpi {
  background:var(--panel); border:1px solid var(--line);
  border-radius:var(--radius); box-shadow:var(--shadow), var(--lift);
  padding:13px 15px 14px; position:relative;
  display:flex; flex-direction:column; gap:2px; min-width:0;
}
.page .kpi b.value {
  font-family:var(--mono); font-size:29px; font-weight:400; line-height:1.02;
  letter-spacing:-.03em; color:var(--text); font-variant-numeric:tabular-nums;
}
.page .kpi b.value small { font-size:15px; color:var(--faint); font-weight:400;
                           letter-spacing:0; }
.page .kpi span.label {
  font-size:10px; letter-spacing:.16em; text-transform:uppercase;
  color:var(--dim); margin-top:7px; font-weight:600;
}
.page .kpi i.delta { font-style:normal; font-family:var(--mono); font-size:10.5px;
                     color:var(--dim); }
.page .kpi i.delta.up { color:var(--ok); }
.page .kpi i.delta.down { color:var(--err); }
.page .kpi.accent b.value { color:var(--acc); }

/* ---------------------------------------------------------------- grid ---- */

.page .grid { display:grid; gap:16px; align-items:start; }
.page .grid.cols-2 { grid-template-columns:repeat(2, minmax(0,1fr)); }
.page .grid.cols-3 { grid-template-columns:repeat(3, minmax(0,1fr)); }
.page .grid.cols-4 { grid-template-columns:repeat(4, minmax(0,1fr)); }

/* ---------------------------------------------------------------- card ----
   A surface lying on the page: its own ground, an edge, and a header with a
   ground of its own. */

:is(.page, .drawer) .card {
  background:var(--panel); border:1px solid var(--line);
  border-radius:var(--radius); min-width:0; overflow:hidden;
  box-shadow:var(--shadow), var(--lift);
}
:is(.page, .drawer) .card > header.cardhead {
  display:flex; align-items:center; gap:10px; padding:9px 14px;
  border-bottom:1px solid var(--line); background:var(--panel2); min-height:38px;
  position:relative;
}
:is(.page, .drawer) .card > header.cardhead h2 {
  margin:0; font-family:var(--sans); font-size:10px; font-weight:600;
  letter-spacing:.13em; text-transform:uppercase; color:var(--dim);
}
:is(.page, .drawer) .card > header.cardhead .cardtools {
  margin-left:auto; display:flex; gap:8px; align-items:center;
  font-size:11px; color:var(--faint);
}
:is(.page, .drawer) .card > .cardbody { padding:13px 14px; }
:is(.page, .drawer) .card > .cardbody.flush { padding:0; }
:is(.page, .drawer) .card > .cardbody.scroll { max-height:470px; overflow:auto; }

/* --------------------------------------------------------------- table ----
   The dense end of the page. Ruled, not striped; the rule is the lightest
   line on the page because there are a hundred of them. */

/* ui.py emits `class="table data"`, and a plain `class="table"` turns up in
   hand-written markup too, so the class carries the reset on its own and
   `.data` adds the ruling. Neither is a decoration: a table with a browser's
   default 2px outset border looks like a spreadsheet someone pasted in. */
:is(.page, .drawer) .table {
  width:100%; border-collapse:collapse; font-size:12.5px;
}
:is(.page, .drawer) table.data {
  width:100%; border-collapse:collapse; font-size:12.5px;
}
:is(.page, .drawer) table.data th {
  text-align:left; font-size:9px; letter-spacing:.15em; text-transform:uppercase;
  color:var(--dim); font-weight:600; padding:7px 12px;
  border-bottom:1px solid var(--line2); background:var(--panel2);
  position:sticky; top:0; z-index:1; white-space:nowrap;
}
:is(.page, .drawer) table.data th[data-sort] { cursor:pointer; user-select:none; }
:is(.page, .drawer) table.data th[data-sort]:hover { color:var(--text); }
:is(.page, .drawer) table.data th[data-sort].asc::after  { content:" ↑"; font-size:9px;
                                                           color:var(--acc); }
:is(.page, .drawer) table.data th[data-sort].desc::after { content:" ↓"; font-size:9px;
                                                           color:var(--acc); }
:is(.page, .drawer) table.data td {
  padding:6px 12px; border-bottom:1px solid var(--line);
  vertical-align:middle; color:var(--text);
}
:is(.page, .drawer) table.data td.mono {
  font-family:var(--mono); font-size:11.5px; font-variant-numeric:tabular-nums;
}
:is(.page, .drawer) table.data td.num {
  font-family:var(--mono); text-align:right; font-variant-numeric:tabular-nums;
}
:is(.page, .drawer) table.data tbody tr:hover td { background:var(--bg2); }
:is(.page, .drawer) table.data tbody tr.sel td {
  background:var(--acc-soft); box-shadow:inset 2px 0 0 var(--acc); }
:is(.page, .drawer) table.data tbody tr:last-child td { border-bottom:none; }
:is(.page, .drawer) .tablewrap { overflow-x:auto; }

/* ----------------------------------------------------- pills and chips ----
   A pill is a STATE: a badge on an instrument, small and in mono, with a
   ground of its own so state is findable at a glance across a dense table. */

:is(.page, .drawer) .pill {
  display:inline-flex; align-items:center; gap:5px; font-family:var(--mono);
  font-size:9.5px; letter-spacing:.09em; padding:2px 7px; border-radius:var(--radius);
  border:1px solid color-mix(in srgb, var(--dim) 34%, transparent); color:var(--dim);
  background:color-mix(in srgb, var(--dim) 12%, transparent);
  white-space:nowrap; text-transform:uppercase; font-weight:600;
}
:is(.page, .drawer) .pill.ok   { color:var(--ok);
  border-color:color-mix(in srgb,var(--ok) 45%,transparent);
  background:color-mix(in srgb, var(--ok) 14%, transparent); }
:is(.page, .drawer) .pill.warn { color:var(--warn);
  border-color:color-mix(in srgb,var(--warn) 45%,transparent);
  background:color-mix(in srgb, var(--warn) 14%, transparent); }
:is(.page, .drawer) .pill.err  { color:var(--err);
  border-color:color-mix(in srgb,var(--err) 45%,transparent);
  background:color-mix(in srgb, var(--err) 14%, transparent); }
:is(.page, .drawer) .pill.info { color:var(--info);
  border-color:color-mix(in srgb,var(--info) 45%,transparent);
  background:color-mix(in srgb, var(--info) 14%, transparent); }
:is(.page, .drawer) .pill.acc  { color:var(--acc);
  border-color:color-mix(in srgb, var(--acc) 55%, transparent);
  background:color-mix(in srgb, var(--acc) 15%, transparent); }
:is(.page, .drawer) .pill.dim  { color:var(--faint); border-color:var(--line);
  background:transparent; }

:is(.page, .drawer) .chip {
  display:inline-flex; align-items:center; gap:6px; font-size:11.5px;
  padding:3px 9px; border-radius:var(--radius); background:transparent;
  border:1px solid var(--line); color:var(--dim); white-space:nowrap;
}
:is(.page, .drawer) .chip b { color:var(--text); font-weight:500;
                              font-family:var(--mono); font-size:11px; }
:is(.page, .drawer) .chip.on { border-color:var(--acc); color:var(--text);
                               background:var(--acc-soft); }

/* status dot - a camera's health in 8 pixels */
:is(.page, .drawer) .dot {
  width:7px; height:7px; border-radius:50%; flex:none; display:inline-block;
  background:var(--faint);
}
:is(.page, .drawer) .dot.ok      { background:var(--ok); }
:is(.page, .drawer) .dot.live    { background:var(--ok);
  box-shadow:0 0 0 3px color-mix(in srgb,var(--ok) 22%,transparent); }
:is(.page, .drawer) .dot.warn    { background:var(--warn); }
:is(.page, .drawer) .dot.err     { background:var(--err); }
:is(.page, .drawer) .dot.offline { background:transparent; border:1px solid var(--faint); }

/* -------------------------------------------------------------- button ----
   An action is RAISED - its own surface, an edge, a lift - and a field is
   RECESSED, so the two can never share a shape. The primary is the one
   place the accent fills a shape, which is why there is never more than one
   of them on a screen. The confirm box hangs on <body>, outside every page,
   and its two buttons are dressed here all the same. */

:is(.page, .drawer, .tz-confirm) .btn {
  display:inline-flex; align-items:center; gap:7px; cursor:pointer;
  font-family:var(--sans); font-size:12px; line-height:1.2; font-weight:500;
  padding:7px 14px; border-radius:var(--radius); letter-spacing:.015em;
  background:var(--panel); color:var(--text); border:1px solid var(--line2);
  box-shadow:var(--shadow), var(--lift);
  transition:border-color .14s, background .14s, color .14s;
  text-decoration:none; white-space:nowrap;
}
:is(.page, .drawer, .tz-confirm) .btn:hover {
  background:color-mix(in srgb, var(--acc) 10%, var(--panel));
  border-color:var(--acc); color:var(--text); text-decoration:none;
}
:is(.page, .drawer, .tz-confirm) .btn:active { transform:translateY(1px); }
:is(.page, .drawer, .tz-confirm) .btn:focus-visible {
  outline:none; box-shadow:0 0 0 3px var(--focus);
}
:is(.page, .drawer, .tz-confirm) .btn[disabled], :is(.page, .drawer, .tz-confirm) .btn.disabled {
  opacity:.4; pointer-events:none; box-shadow:none;
}
:is(.page, .drawer, .tz-confirm) .btn.primary {
  background:var(--acc); color:var(--acc-ink); border-color:var(--acc); font-weight:600;
}
:is(.page, .drawer, .tz-confirm) .btn.primary:hover {
  background:color-mix(in srgb, var(--acc) 86%, var(--text)); color:var(--acc-ink);
  border-color:color-mix(in srgb, var(--acc) 86%, var(--text));
}
:is(.page, .drawer, .tz-confirm) .btn.ghost {
  background:transparent; color:var(--dim); border-color:var(--line); box-shadow:none;
}
:is(.page, .drawer, .tz-confirm) .btn.ghost:hover { background:var(--bg2); color:var(--text);
                                       border-color:var(--line2); }
:is(.page, .drawer, .tz-confirm) .btn.small { font-size:11px; padding:5px 10px; }
:is(.page, .drawer, .tz-confirm) .btn.danger { color:var(--err);
  border-color:color-mix(in srgb,var(--err) 45%,transparent); }
:is(.page, .drawer, .tz-confirm) .btn.danger:hover { border-color:var(--err); color:var(--err);
  background:var(--err-soft); }
:is(.page, .drawer, .tz-confirm) .btn.ok { background:var(--ok); color:var(--acc-ink);
                              border-color:var(--ok); }
/* `.stack` is a flex column, so any button inside one would stretch to the
   full column width and arrive on screen shaped exactly like the text input
   under it. A control sizes to its label. */
:is(.page, .drawer) .stack > .btn,
:is(.page, .drawer) .field > .btn { align-self:flex-start; width:auto; }

/* --------------------------------------------------------------- field ----
   A blank to be filled in: recessed, with an edge that reads at 3:1, and the
   accent round it while it has focus. */

:is(.page, .drawer) .field { display:flex; flex-direction:column; gap:5px; min-width:0; }
:is(.page, .drawer) .field label {
  font-size:9.5px; letter-spacing:.15em; text-transform:uppercase;
  color:var(--faint); font-weight:600;
}
:is(.page, .drawer) .field input,
:is(.page, .drawer) .field select,
:is(.page, .drawer) .field textarea {
  background:var(--sunken); color:var(--text);
  border:1px solid var(--edge);
  border-radius:var(--radius); padding:7px 10px; font-family:var(--sans);
  font-size:13px; width:100%; outline:none; box-shadow:var(--sunk);
  transition:border-color .14s, box-shadow .14s;
}
:is(.page, .drawer) .field input.mono, :is(.page,.drawer) .field textarea.mono {
  font-family:var(--mono); font-size:12px;
}
:is(.page, .drawer) .field input:focus,
:is(.page, .drawer) .field select:focus,
:is(.page, .drawer) .field textarea:focus {
  border-color:var(--acc); background:var(--panel);
  box-shadow:var(--sunk), 0 0 0 3px var(--focus);
}
/* A tick box or a radio inside a field is a mark, not a blank: it keeps its
   own size and takes the accent. */
:is(.page, .drawer) .field input[type=checkbox],
:is(.page, .drawer) .field input[type=radio] {
  width:auto; padding:0; border:none; background:none; box-shadow:none;
  accent-color:var(--acc);
}
/* A colour is a swatch: the text blank's padding squeezed it to a line. */
:is(.page, .drawer) .field input[type=color] {
  height:34px; padding:4px; cursor:pointer;
}
:is(.page, .drawer) .field .hint { font-size:10.5px; color:var(--faint); line-height:1.5; }

/* -------------------------------------------------------------- search ----
   The query box is the loudest control on an investigation surface, so it is
   physically the largest thing on the page and monospace - what you type is
   a key, not prose. */

.page .search { margin-bottom:24px; }
.page .search input {
  width:100%; background:var(--sunken); color:var(--text);
  border:1px solid var(--edge); border-radius:var(--radius); box-shadow:var(--sunk);
  padding:13px 12px; font-family:var(--mono); font-size:16px; outline:none;
  letter-spacing:-.01em;
}
.page .search input:focus { border-color:var(--acc);
  box-shadow:var(--sunk), 0 0 0 3px var(--focus); }
.page .search input::placeholder { color:var(--faint); }
.page .search .hint {
  margin-top:9px; font-size:11px; color:var(--faint); font-family:var(--mono);
  display:flex; gap:16px; flex-wrap:wrap;
}
.page .search .hint b { color:var(--dim); font-weight:500; }

/* --------------------------------------------------------------- empty ----
   An empty state that just says "no data" is a dead end. Every one of these
   says WHY it is empty and what the next move is. */

:is(.page, .drawer) .empty {
  display:flex; flex-direction:column; align-items:flex-start; gap:9px;
  padding:30px 26px; border:1px dashed var(--line2); border-radius:var(--radius);
  background:transparent; color:var(--dim);
}
:is(.page, .drawer) .empty h3 {
  margin:0; font-family:var(--serif); font-size:20px; font-weight:500;
  color:var(--text); line-height:1.2;
}
:is(.page, .drawer) .empty p { margin:0; font-size:13px; max-width:58ch; line-height:1.6; }
:is(.page, .drawer) .empty .btn { margin-top:6px; }

/* ------------------------------------------------------------ timeline ---- */

:is(.page, .drawer) .timeline { display:flex; flex-direction:column; }
:is(.page, .drawer) .tl-item {
  display:grid; grid-template-columns:64px 78px 1fr; gap:12px;
  padding:6px 14px; border-bottom:1px solid var(--line); align-items:baseline;
  font-size:12.5px;
}
:is(.page, .drawer) .tl-item:last-child { border-bottom:none; }
:is(.page, .drawer) .tl-item:hover { background:var(--bg2); }
:is(.page, .drawer) .tl-item > time {
  font-family:var(--mono); font-size:11px; color:var(--faint);
  font-variant-numeric:tabular-nums;
}
:is(.page, .drawer) .tl-kind {
  font-family:var(--mono); font-size:9px; letter-spacing:.1em;
  text-transform:uppercase; color:var(--dim); border:1px solid var(--line2);
  border-radius:var(--radius); padding:1px 6px; text-align:center; white-space:nowrap;
  justify-self:start;
}
:is(.page, .drawer) .tl-kind.rebinding, :is(.page,.drawer) .tl-kind.revised {
  color:var(--warn); border-color:color-mix(in srgb,var(--warn) 45%,transparent); }
:is(.page, .drawer) .tl-kind.event { color:var(--acc);
  border-color:color-mix(in srgb,var(--acc) 45%,transparent); }
:is(.page, .drawer) .tl-kind.access { color:var(--info);
  border-color:color-mix(in srgb,var(--info) 45%,transparent); }
:is(.page, .drawer) .tl-body { color:var(--text); line-height:1.5; min-width:0; }
:is(.page, .drawer) .tl-body b { font-family:var(--mono); font-size:11.5px;
                                 font-weight:500; color:var(--acc); }
:is(.page, .drawer) .tl-body .why { color:var(--faint); font-size:11.5px; }

/* ---------------------------------------------------------- provenance ----
   The chain of claims behind one fact. Superseded steps stay visible and
   struck through, because an audit trail that hides its corrections is a
   current-state table wearing a costume. */

:is(.page, .drawer) .provenance {
  display:flex; flex-direction:column; padding-left:16px;
  border-left:1px solid var(--line2); margin:6px 0;
}
:is(.page, .drawer) .prov-step {
  position:relative; padding:9px 0 9px 14px; font-size:12.5px; color:var(--dim);
}
:is(.page, .drawer) .prov-step::before {
  content:""; position:absolute; left:-21px; top:14px; width:9px; height:9px;
  border-radius:50%; background:var(--bg); border:1px solid var(--line2);
  box-sizing:border-box;
}
:is(.page, .drawer) .prov-step.superseded { text-decoration:line-through;
  color:var(--faint); text-decoration-color:var(--err); }
:is(.page, .drawer) .prov-step.live { color:var(--text); }
:is(.page, .drawer) .prov-step.live::before { border-color:var(--acc);
  background:var(--acc); box-shadow:0 0 0 3px color-mix(in srgb,var(--acc) 18%,transparent); }
:is(.page, .drawer) .prov-step time { font-family:var(--mono); font-size:10.5px;
  color:var(--faint); display:block; }
:is(.page, .drawer) .prov-step .what { font-family:var(--mono); font-size:12px; }

/* --------------------------------------------------------------- split ---- */

.page .split { display:grid; grid-template-columns:minmax(260px, 360px) minmax(0,1fr);
               gap:22px; align-items:start; }
.page .split > .splitlist { min-width:0; }
.page .split > .splitdetail { min-width:0; }

/* --------------------------------------------------- floor and legend ---- */

:is(.page, .drawer) .floor {
  position:relative; background:var(--panel); border:1px solid var(--line);
  border-radius:var(--radius); overflow:hidden;
}
:is(.page, .drawer) .floor canvas { display:block; width:100%; }
:is(.page, .drawer) .floor .legend {
  position:absolute; left:14px; bottom:14px;
  background:color-mix(in srgb, var(--panel) 94%, transparent);
  border:1px solid var(--line); border-radius:var(--radius); padding:9px 11px;
  display:flex; flex-direction:column; gap:5px;
}
:is(.page, .drawer) .legend { display:flex; gap:14px; flex-wrap:wrap; }
:is(.page, .drawer) .legend .lg {
  display:flex; align-items:center; gap:6px; font-size:10.5px; color:var(--dim);
  font-family:var(--mono);
}
:is(.page, .drawer) .legend .lg i.swatch {
  width:10px; height:10px; border-radius:1px; background:var(--faint);
  flex:none; display:inline-block;
}

/* -------------------------------------------------------------- drawer ----
   Right-hand detail panel. Every surface opens the same one, so a detail view
   never costs a page navigation and never loses the list behind it. It is a
   thing that floats, so it casts the floating shadow over the look's scrim. */

.drawer {
  position:fixed; top:0; right:0; bottom:0; width:min(540px, 92vw); z-index:1400;
  background:var(--panel); border-left:1px solid var(--line2);
  box-shadow:var(--shadow-2);
  display:flex; flex-direction:column;
  font-family:var(--sans); font-size:13px; line-height:1.5; color:var(--text);
  transform:translateX(100%); transition:transform .2s cubic-bezier(.2,.7,.3,1);
}
.drawer.open { transform:translateX(0); }
.drawer > header {
  display:flex; align-items:center; gap:12px; padding:18px 22px 14px;
  border-bottom:1px solid var(--line2); background:transparent; flex:none;
}
.drawer > header h2 {
  margin:0; font-family:var(--serif); font-size:21px; font-weight:600;
  letter-spacing:-.01em; color:var(--text); flex:1; min-width:0; line-height:1.15;
}
.drawer > header .x {
  cursor:pointer; background:transparent; border:1px solid var(--line2);
  color:var(--dim); border-radius:var(--radius); width:26px; height:26px; flex:none;
  font-size:12px; line-height:1; font-family:var(--sans);
}
.drawer > header .x:hover { border-color:var(--acc); color:var(--acc); }
.drawer > .drawerbody { padding:18px 22px 36px; overflow:auto; flex:1; }
.drawer .kv { display:grid; grid-template-columns:132px 1fr; gap:0 14px;
              font-size:12.5px; margin-bottom:16px; }
.drawer .kv dt { color:var(--faint); font-size:10px; letter-spacing:.12em;
                 text-transform:uppercase; padding:5px 0;
                 border-bottom:1px solid var(--line); }
.drawer .kv dd { margin:0; font-family:var(--mono); font-size:11.5px;
                 word-break:break-word; padding:5px 0;
                 border-bottom:1px solid var(--line); }
.drawer pre {
  background:var(--sunken); border:1px solid var(--line); border-radius:var(--radius);
  padding:11px 13px; font-family:var(--mono); font-size:11px; overflow:auto;
  color:var(--dim); margin:0 0 16px;
}
.drawer-scrim {
  position:fixed; inset:0; z-index:1399; background:var(--scrim);
  opacity:0; pointer-events:none; transition:opacity .2s;
}
.drawer-scrim.open { opacity:1; pointer-events:auto; }

/* -------------------------------------------------------------- toasts ---- */

.tz-toasts {
  position:fixed; right:22px; bottom:22px; z-index:1500;
  display:flex; flex-direction:column; gap:8px; align-items:flex-end;
  pointer-events:none; font-family:var(--sans);
}
.tz-toast {
  background:var(--panel); color:var(--text); border:1px solid var(--line2);
  border-left:2px solid var(--faint); border-radius:var(--radius);
  padding:10px 15px; font-size:12.5px; max-width:390px; box-shadow:var(--shadow-2);
  animation:tzin .18s ease;
}
.tz-toast.ok   { border-left-color:var(--ok); }
.tz-toast.warn { border-left-color:var(--warn); }
.tz-toast.err  { border-left-color:var(--err); }
.tz-toast.info { border-left-color:var(--info); }
@keyframes tzin { from { opacity:0; transform:translateY(6px); } }

/* --------------------------------------------------------- confirm box ---- */

.tz-confirm {
  position:fixed; inset:0; z-index:1600; display:flex;
  align-items:center; justify-content:center; background:var(--scrim);
  font-family:var(--sans);
}
.tz-confirm > div {
  background:var(--panel); border:1px solid var(--line2); border-radius:var(--radius);
  padding:24px 26px; max-width:430px; box-shadow:var(--shadow-2); color:var(--text);
}
.tz-confirm p { margin:0 0 18px; font-size:13.5px; line-height:1.6; }
.tz-confirm .row { display:flex; gap:8px; justify-content:flex-end; }

/* ------------------------------------------------------------ utilities ---- */

.page .row { display:flex; gap:9px; align-items:center; flex-wrap:wrap; }
.page .stack { display:flex; flex-direction:column; gap:11px; }
.page .spacer { flex:1; }
/* a section title is a note in the margin: an accent tick, the words, then
   the rule running out to the edge of the page */
.page .sectiontitle {
  font-family:var(--sans); font-size:9.5px; letter-spacing:.18em;
  text-transform:uppercase; color:var(--faint); margin:26px 0 11px;
  font-weight:600; display:flex; align-items:center; gap:10px;
}
.page .sectiontitle::before {
  content:""; width:14px; height:1px; background:var(--acc); flex:none;
}
.page .sectiontitle::after {
  content:""; height:1px; background:var(--line); flex:1;
}
.page hr { border:none; border-top:1px solid var(--line); margin:28px 0; }
.page ::-webkit-scrollbar { width:9px; height:9px; }
.page ::-webkit-scrollbar-thumb, .drawer ::-webkit-scrollbar-thumb {
  background:var(--line2); border-radius:0;
}

/* ---------------------------------------------------------- responsive ---- */

@media (max-width:1100px) {
  /* A rail of bare icons is a rail nobody can learn: on a narrow window it
     narrows, it does not go mute. The words and the counts stay; the key
     hint goes. */
  :root { --rail-w:200px; }
  #rail .tz-find kbd { display:none; }
  #rail .tz-brand { padding:16px 14px 12px; }
  .page { padding:20px 16px 56px; }
  .page .pagehead h1.title { font-size:27px; }
  .page .grid.cols-3, .page .grid.cols-4 { grid-template-columns:repeat(2, minmax(0,1fr)); }
  .page .split { grid-template-columns:minmax(0,1fr); }
}
@media (max-width:760px) {
  .page .grid.cols-2, .page .grid.cols-3, .page .grid.cols-4 {
    grid-template-columns:minmax(0,1fr);
  }
  .page .pagehead .actions { margin-left:0; }
}
/* A phone: the rail folds to its marks, so the page keeps the width it
   needs; the words come back on a wider window. */
@media (max-width:640px) {
  :root { --rail-w:60px; }
  #rail { align-items:center; }
  #rail .tz-brand { padding:16px 0 12px; }
  #rail .tz-logo { width:42px; height:26px; }
  #rail .tz-wordmark, #rail .tz-lbl, #rail .tz-find kbd, #rail .tz-acct .tz-who,
  #rail .tz-acct > svg, #rail .tz-ws, #rail .tz-here { display:none; }
  #rail .tz-find {
    width:40px; height:38px; margin:0 0 3px; padding:0; justify-content:center;
    border-color:transparent; background:transparent; color:var(--ink-dim);
  }
  #rail .tz-find svg, #rail .tz-tab .tz-ico, #rail .tz-tab .tz-ico svg { width:19px; height:19px; }
  #rail .tz-nav { padding:0; align-items:center; gap:3px; }
  #rail .tz-tab { width:40px; height:38px; padding:0; justify-content:center; }
  #rail .tz-tab.here { color:var(--acc-text); }
  #rail .tz-badge {
    position:absolute; top:7px; right:7px; min-width:0; width:8px; height:8px; padding:0;
    border:none; font-size:0; box-shadow:0 0 0 2px var(--rail-bg);
  }
  #rail .tz-badge.warn { background:var(--rail-warn); }
  #rail .tz-badge.err { background:var(--err); }
  #rail .tz-sep { width:28px; margin:7px 0; }
  #rail .tz-foot { border-top:none; padding:6px 0 12px; }
  #rail .tz-acct { width:auto; padding:0; }
}

/* ==========================================================================
   COMMAND — components that only the operations screens need.

   Each block below exists because a surface needs a shape the generic
   vocabulary does not have: a banner that states what the building STOPPED
   being able to see, an alert row that can render itself inadmissible, a KPI
   that flips over to show its own denominator, a camera row that only
   fetches video when it is pointed at.
   ========================================================================== */

/* ------------------------------------------------------------- banners ----
   Severity first, dismissible, never more than a few: a banner rail that is
   always full is wallpaper. A rule down the left, the words in ink, a tint
   of the severity behind them and no more. */

.page .banners { display:flex; flex-direction:column; margin-bottom:24px;
                 border-top:1px solid var(--line); border-bottom:1px solid var(--line); }
.page .banner {
  display:flex; align-items:flex-start; gap:12px; padding:12px 14px;
  border:none; border-left:2px solid var(--line2);
  border-radius:0; background:transparent; font-size:13px; line-height:1.55;
}
.page .banners > .banner + .banner { border-top:1px solid var(--line); }
.page .banner.err  { border-left-color:var(--err);
  background:color-mix(in srgb, var(--err) 5%, transparent); }
.page .banner.warn { border-left-color:var(--warn);
  background:color-mix(in srgb, var(--warn) 5%, transparent); }
.page .banner.info { border-left-color:var(--info); }
.page .banner.ok   { border-left-color:var(--ok); }
.page .banner .bmark { font-size:10px; line-height:1.8; flex:none; }
.page .banner.err .bmark  { color:var(--err); }
.page .banner.warn .bmark { color:var(--warn); }
.page .banner.info .bmark { color:var(--info); }
.page .banner.ok .bmark   { color:var(--ok); }
.page .banner .btext { flex:1; min-width:0; color:var(--text); }
.page .banner .bx {
  background:none; border:none; color:var(--faint); cursor:pointer;
  font-size:13px; line-height:1; padding:2px 4px; flex:none; font-family:var(--sans);
}
.page .banner .bx:hover { color:var(--acc); }

/* ---------------------------------------------------------- kpi extras ----
   A number a viewer cannot interrogate is a number they eventually ignore, so
   every tile carries its own definition on its back. */

.page .kpi .fx {
  position:absolute; top:11px; right:12px; background:none; border:none;
  color:var(--faint); font-family:var(--serif); font-size:13px; font-style:italic;
  cursor:pointer; line-height:1; padding:2px 4px; border-radius:var(--radius);
}
.page .kpi .fx:hover { color:var(--acc); }
.page .kpi .spark { display:block; width:100%; height:22px; margin-top:8px; }
.page .kpi .spark path.line { fill:none; stroke:var(--dim); stroke-width:1;
  vector-effect:non-scaling-stroke; }
.page .kpi.accent .spark path.line { stroke:var(--acc); }
.page .kpi .spark path.area { fill:color-mix(in srgb, var(--dim) 10%, transparent);
  stroke:none; }
.page .kpi.accent .spark path.area { fill:color-mix(in srgb, var(--acc) 12%, transparent); }
.page .kpi .spark line.ceiling { stroke:var(--err); stroke-width:1;
  stroke-dasharray:3 3; vector-effect:non-scaling-stroke; }
.page .kpi .def {
  font-family:var(--mono); font-size:10.5px; line-height:1.6; color:var(--dim);
  white-space:pre-wrap; word-break:break-word; margin-top:6px;
}
.page .kpi .def b { color:var(--text); font-weight:500; }
.page .kpi .why { font-size:11px; color:var(--faint); line-height:1.55; margin-top:5px; }
.page .kpi.over b.value { color:var(--err); }

/* -------------------------------------------------------------- alerts ---- */

.page .alerts { display:flex; flex-direction:column; }
.page .alert {
  display:grid; grid-template-columns:auto 1fr auto; gap:12px;
  padding:9px 14px; border-bottom:1px solid var(--line); align-items:start;
}
.page .alert:last-child { border-bottom:none; }
.page .alert:hover { background:var(--bg2); }
.page .alert.sel { background:var(--acc-soft); box-shadow:inset 2px 0 0 var(--acc); }
.page .alert.done { opacity:.42; }
.page .alert .ev {
  width:60px; height:45px; border-radius:var(--radius); border:1px solid var(--line2);
  background:var(--bg2) center/cover no-repeat; flex:none;
  display:flex; align-items:center; justify-content:center;
  color:var(--faint); font-size:14px;
}
.page .alert .who { min-width:0; }
.page .alert .who .top { display:flex; align-items:center; gap:8px; flex-wrap:wrap; }
.page .alert .who .name {
  font-family:var(--mono); font-size:12.5px; font-weight:500; color:var(--text);
}
.page .alert .who .meta {
  font-size:11px; color:var(--faint); font-family:var(--mono); margin-top:4px;
  display:flex; gap:10px; flex-wrap:wrap; align-items:center;
}
.page .alert .acts { display:flex; gap:5px; align-items:center; flex:none; }

/* The confidence bar. Hatched rather than solid when the geometry could not
   support the claim: an inadmissible alert must not LOOK like a confident
   one. EN 62676-4 identification grade - see api/overview.py. */
.page .conf {
  width:56px; height:3px; border-radius:0; background:var(--line);
  overflow:hidden; flex:none;
}
.page .conf i { display:block; height:100%; background:var(--acc); }
.page .conf.hatched i {
  background:repeating-linear-gradient(45deg, var(--warn) 0 2px, transparent 2px 4px);
}
.page .inadmissible {
  grid-column:1 / -1; margin-top:8px; padding:7px 10px; font-size:11.5px;
  line-height:1.55; border-radius:0; color:var(--warn); background:transparent;
  border-left:2px solid color-mix(in srgb, var(--warn) 55%, transparent);
}

/* ------------------------------------------------------------- cameras ----
   Sorted worst-first and never auto-playing: sixteen MJPEG streams on a page
   left open all day is how the box is lost. */

.page .camrow {
  display:grid; grid-template-columns:10px 1fr auto; gap:11px;
  padding:8px 14px; border-bottom:1px solid var(--line); align-items:center;
  cursor:pointer; font-size:12.5px;
}
.page .camrow:last-child { border-bottom:none; }
.page .camrow:hover { background:var(--bg2); }
.page .camrow .cname { font-weight:500; color:var(--text); }
.page .camrow .cmeta {
  font-family:var(--mono); font-size:10.5px; color:var(--faint); margin-top:3px;
  display:flex; gap:10px; flex-wrap:wrap;
}
.page .camrow .cmeta .bad { color:var(--err); }
.page .camrow .cnum {
  font-family:var(--mono); font-size:11px; color:var(--dim); text-align:right;
  white-space:nowrap; font-variant-numeric:tabular-nums;
}
/* fps delivered against fps allocated, in one two-tone bar. */
.page .fpsbar { width:58px; height:3px; border-radius:0; background:var(--line);
                overflow:hidden; margin-top:5px; margin-left:auto; }
.page .fpsbar i { display:block; height:100%; background:var(--ok); }
.page .fpsbar i.starved { background:var(--warn); }
.page .camshot {
  grid-column:1 / -1; margin-top:10px; border-radius:var(--radius); overflow:hidden;
  border:1px solid var(--line2); background:var(--bg2);
}
.page .camshot img { display:block; width:100%; }

/* -------------------------------------------------------------- engine ---- */

.page .enginestrip {
  display:grid; grid-template-columns:repeat(auto-fit, minmax(152px, 1fr));
  gap:0; background:transparent; border-top:1px solid var(--line2);
  border-bottom:1px solid var(--line); border-radius:0;
}
.page .enginestrip > div { background:transparent; padding:13px 16px;
                           border-left:1px solid var(--line); }
.page .enginestrip > div:first-child { border-left:none; padding-left:0; }
.page .enginestrip .k {
  font-size:9.5px; letter-spacing:.16em; text-transform:uppercase;
  color:var(--faint); margin-bottom:5px; font-weight:600;
}
.page .enginestrip .v { font-family:var(--mono); font-size:14px; color:var(--text);
                        font-variant-numeric:tabular-nums; }
.page .enginestrip .v.ok { color:var(--ok); }
.page .enginestrip .v.warn { color:var(--warn); }
.page .enginestrip .sub { font-size:10.5px; color:var(--faint); margin-top:4px;
                          line-height:1.5; }

/* Allocated frame rate against the budget, headroom shaded. NVIDIA's own
   DeepStream guidance is to leave 10-15% of it - drawn as the mark. */
.page .budget { height:5px; border-radius:0; background:var(--line);
                overflow:hidden; position:relative; margin-top:6px; }
.page .budget i { display:block; height:100%; background:var(--acc); }
.page .budget u { position:absolute; top:-2px; bottom:-2px; width:1px;
                  background:var(--ok); }

/* -------------------------------------------------------- pending tray ---- */

.page .tray {
  display:flex; gap:16px; align-items:center; flex-wrap:wrap;
  padding:10px 16px; border-top:1px solid var(--line);
  font-family:var(--mono); font-size:11px; color:var(--dim);
}
.page .tray b { color:var(--text); font-weight:500; }
.page .tray button {
  background:none; border:none; color:var(--acc); cursor:pointer;
  font:inherit; padding:0; text-decoration:underline;
}
.page .ripe { width:13px; height:13px; flex:none; transform:rotate(-90deg); }
.page .ripe circle.track { fill:none; stroke:var(--line2); stroke-width:2.5; }
.page .ripe circle.fill  { fill:none; stroke:var(--acc); stroke-width:2.5;
                           stroke-linecap:round; }

/* The alert queue is the biggest block on Command and must outweigh the two
   health columns beside it, so one grid child is allowed to take two tracks. */
.page .grid > .span2 { grid-column:span 2; }
@media (max-width:760px) { .page .grid > .span2 { grid-column:span 1; } }

/* ---------------------------------------------------- caveats and notes ----
   ui.py emits .caveats on generated screens, and the builder and apps
   surfaces emit it too, so one rule covers both rather than two copies. */

:is(.page, .drawer) .caveats { margin:0; padding:0; list-style:none;
  display:flex; flex-direction:column; gap:7px; }
:is(.page, .drawer) .caveats li { position:relative; padding-left:17px;
  font-size:12.5px; line-height:1.55; color:var(--warn); }
:is(.page, .drawer) .caveats li::before { content:"▲"; position:absolute; left:0;
  font-size:8px; top:4px; }

/* ------------------------------------------------- investigate and apps ----
   Four class names the platform pages use that had no rule here, so a page
   written against the sheet still had one detail dressed by nothing. They are
   listed together because they are all HOOKS FIRST - the page's JavaScript
   finds elements by them - and only then things that must look drawn.

   `.ghead` and `.evthumb` were written with inline styles before this sheet
   existed, and an inline declaration beats a stylesheet one; the one
   property marked below is the only place in this file that has to say so
   out loud, and it is marked rather than silently duplicated. */

:is(.page, .drawer) .egroup { border:1px solid var(--line); margin-bottom:10px;
  background:var(--panel); }
:is(.page, .drawer) .egroup.sel { border-color:var(--line2); }
:is(.page, .drawer) .ghead { user-select:none; }
:is(.page, .drawer) .ghead:hover { background:var(--panel2); }

/* A frame the engine kept. The pointer says it opens, because clicking it is
   how an operator checks the claim. */
:is(.page, .drawer) .evthumb { border-radius:var(--radius) !important;
  border:1px solid var(--line2); background:var(--bg2); cursor:zoom-in;
  transition:border-color .12s ease; }
:is(.page, .drawer) .evthumb:hover { border-color:var(--acc); }

/* The link out of a claim into the chain behind it: underlined, in the
   accent, because it is the one place a timeline row is clickable. */
:is(.page, .drawer) .provlink { color:var(--acc); text-decoration:underline;
  text-underline-offset:2px; text-decoration-thickness:1px;
  font-size:11.5px; white-space:nowrap; }
:is(.page, .drawer) .provlink:hover { text-decoration-thickness:2px; }

/* The camera checkboxes in a deploy dialog and in the Connect drawer.
   `.camopt` dresses the row; these are the inputs inside it, sized so a list
   of twenty reads as a column of ticks rather than a column of default
   browser boxes. */
:is(.page, .drawer) .dp-cam, :is(.page, .drawer) .chk {
  width:13px; height:13px; accent-color:var(--acc); margin:0 2px 0 0;
  flex:none; vertical-align:-2px;
}

/* =============================== the two drawing surfaces ==================
   Site model and Pipeline are not documents: each is one instrument filling
   the window - a headline strip, a drawing that takes the rest of the glass,
   and an inspector down one side. They wear the sheet's vocabulary (.btn,
   .card, .field, .pill, .chip) and so they carry `.page`, but not `.page`'s
   document layout, which is what the two resets below undo.

   Everything here is prefixed .site- / .graph- or scoped to one of those two
   wrappers, so no rule above changes meaning for any other surface.
   ========================================================================== */

.page.site-app, .page.graph-app {
  margin-left:0; padding:0; min-height:0; overflow:visible;
  font-family:var(--sans); font-size:13.5px; line-height:1.5;
  background:transparent;
}

/* A segmented control: ONE bordered block with hairlines inside it, used
   only where the buttons are the same decision (3d | 2d plan, run | stop). */
.site-seg, .graph-seg {
  display:inline-flex; align-items:stretch; flex:none;
  border:1px solid var(--line2); border-radius:var(--radius); overflow:hidden;
  background:var(--panel);
}
.site-seg > .btn, .graph-seg > .btn {
  border:none; border-radius:0; margin:0; background:transparent;
  color:var(--dim); box-shadow:none;
}
.site-seg > .btn + .btn, .graph-seg > .btn + .btn { border-left:1px solid var(--line2); }
.site-seg > .btn:hover, .graph-seg > .btn:hover { background:var(--panel2); color:var(--text); }
.site-seg > .btn:active, .graph-seg > .btn:active { transform:none; }
.site-seg > .btn.primary, .graph-seg > .btn.primary {
  background:var(--acc); color:var(--acc-ink);
}
.site-seg > .btn.danger, .graph-seg > .btn.danger {
  background:var(--err); color:var(--acc-ink); border-color:var(--err);
}

/* A dropdown is a small card hung under the button that opened it - the same
   surface as everything else, never a floating dark slab. */
.site-menuwrap, .graph-menuwrap { position:relative; flex:none; }
.site-menu, .graph-menu {
  position:absolute; top:calc(100% + 7px); left:0; min-width:252px; z-index:120;
  background:var(--panel); border:1px solid var(--line2);
  border-radius:var(--radius); box-shadow:var(--shadow-2); padding:5px;
  display:none;
}
.site-menu.open, .graph-menu.open { display:block; }
.site-mrow, .graph-mrow {
  display:flex; align-items:center; gap:9px; padding:7px 10px; cursor:pointer;
  font-size:13px; color:var(--text); border-radius:var(--radius); line-height:1.35;
}
.site-mrow:hover, .graph-mrow:hover { background:var(--bg2); color:var(--acc); }
.site-mrow input[type=checkbox] { width:13px; height:13px; accent-color:var(--acc);
  margin:0; flex:none; }
.site-mrow svg, .graph-mrow svg { width:15px; height:15px; flex:none; color:var(--faint); }
.site-mrow:hover svg, .graph-mrow:hover svg { color:var(--acc); }

/* Two classes the restyled Site page wears that nothing dressed: a tiny
   button for the per-row actions (test, preview, delete) and the row that
   holds them. Sized to sit inside a list line without pushing it taller. */
.page .btn.mini { padding:1px 7px; font-size:11px; line-height:1.5; min-height:0; }
.page .srow { display:flex; align-items:center; gap:6px; flex-wrap:wrap; }

/* =============================================================== embedded ==
   A page an App's page shows as one of its parts (?embed=1, stamped on the
   root by platform.js) sits inside that page, whose rail is the only rail
   on screen: this one is not drawn and takes no width.

   !important, because a plain :root rule loses this fight: the platform
   pages set --rail-w at (0,2,1) and the 1100px breakpoint sets it again. An
   !important declaration outranks every one of them without this sheet
   having to out-count selectors it does not own. */
:root[data-embed="1"] { --rail-w:0px !important; }
:root[data-embed="1"] #rail { display:none !important; }

/* console.html predates --rail-w: its headline and its three columns are
   pinned 216px from the left in inline style attributes, which a stylesheet
   can only outrank with !important. The attribute match keeps this to those
   two elements - the canvas pages' #bar carries no inline style at all. */
:root[data-embed="1"] body > #bar[style*="216px"],
:root[data-embed="1"] body > #layout[style*="216px"] { left:0 !important; }
