/* BEAM web GUI - base style. THE RULES ARE IN beam_ui/DESIGN_RULES.md (the RailTools design rules, v1);
   tests/test_design_rules.py checks the ones a machine can check. In short:
   type    5 sizes: xs 12 (chips, captions, column heads, legends) · sm 13 (dense UI: tables, toolbars, navigator,
           compact controls) · md 14 (body, forms, h3) · lg 16 (h2) · xl 20 (h1); weights 400 and 600.
           Texts show exactly as written - no automatic capitals.
   space   4-px grid: 4 · 8 · 12 · 16 · 24.   radius  4 (small) · 6 (controls, boxes) · 10 (cards) · pill.
   control one height: 32 px (compact 26 px in tables, toolbars, side panels). Inputs, selects and buttons match.
   buttons primary (filled - at most ONE per area) · secondary · toggle · danger · icon; .small = compact.
           Links navigate, buttons act; a workflow step that navigates is an <a class="button secondary small">.
   chips   one shape (20 px, pill): ok / warn / bad / info / muted - status only, never an action.
   colour  only tokens (below); accent = interactive; ok / warn / bad / info = status only.
   Drawings (SVG on photos, diagrams, site plans) are exempt from the type sizes and weights. */
:root {
  --bg: #f4f5f7;
  --surface: #ffffff;
  --surface-2: #f8f9fb;        /* hover rows, quiet panels */
  --text: #1f2328;
  --muted: #5b6570;
  --faint: #858b92;            /* decoration only (>= 3:1 for graphics); never text - WCAG check 2026-09-28 */
  --border: #d8dce1;
  --accent: #36497b;           /* the logo's navy */
  --accent-text: #ffffff;
  --paper: #ffffff;        /* a drawing is paper: white in every theme (Correx, 1.8.0) */
  --report-band: #8abad4;  /* the report header band (template style 1): the logo preview, every theme (1.13.1) */
  --accent-bg: #eaeef7;        /* selection, current item: the logo's light blue, 20 % */
  --ok: #1e8e3e;   --ok-bg: #e6f4ea;     --ok-text: #1e5b30;     --ok-line: #b7dfc2;
  --warn: #b06000; --notice-bg: #fff6e0; --notice-text: #6b4a00; --warn-line: #f0d58c;
  --bad: #c00000;  --error-bg: #fdecea;  --error-text: #8a1c14;  --bad-line: #f1b8b3;
  --info: #36497b;
  --info-line: #c5d1ea;
  --on-bad: #ffffff;
  --input-bg: #ffffff;
  --code-bg: #eef0f3;
  --section-bg: #f0f3fa;       /* results: section rows */
  --group-bg: #dfe6f4;         /* results: group rows */
  --stage-bg: #eef0f3;         /* behind the photo / drawing */
  --plot-bg: #fbfbfc;          /* diagram panels */
  --plot-ink: #202124; --plot-muted: #80868b; --plot-mast: #333333; --plot-ground: #8a6d3b; --plot-halo: #ffffff;
  --shadow: 0 4px 16px rgba(0, 0, 0, .15);
  --radius-card: 10px;
  /* drawn ON a picture (markers, wires, results): dark mode inverts the picture, these follow */
  --pic-filter: none; --pic-blend: normal; --pic-toggle: none; --pic-ink: #000000; --pic-ink-2: #1a1a1a; --pic-halo: #ffffff;
  --pic-plot: #202124; --pic-muted: #80868b; --pic-blue: #36497b; --pic-red: #d93025; --pic-fill: #ffffff; --pic-green: #188038;
  /* translucent fills on a picture: marker ring, calibration marker, hovered marker, selection frame; dialog backdrop */
  --pic-glass: rgba(255, 255, 255, .35); --pic-cal-fill: rgba(54, 73, 123, .25); --pic-hover-fill: rgba(255, 213, 79, .55);
  --pic-sel-fill: rgba(54, 73, 123, .12); --backdrop: rgba(0, 0, 0, .35);
  --tension: #2f6fb5; --compression: #c0392b;                 /* an element's axial force (3D view) */
  --logo-light: inline-block; --logo-dark: none;              /* which logo file the scheme shows */
  --axis-x: #d93025; --axis-y: #188038; --axis-z: #36497b;   /* x / y / z in the UI (axis symbol), as the load arrows
  --missing-bg: #ffffb7;       /* Excel: required and empty */
  --na-bg: #e9ecef;            /* Excel: not used by this case */

  --fs-xs: 12px; --fs-sm: 13px; --fs-md: 14px; --fs-lg: 16px; --fs-xl: 20px;
  --sp-1: 4px; --sp-2: 8px; --sp-3: 12px; --sp-4: 16px; --sp-5: 24px;
  --brand-logo-h: initial; --preview-logo-h: initial;   /* 1.53.0: unset = the fallback (Admin -> appearance sets the first) */
  --link: initial; --topbar-bg: initial; --topbar-text: initial; --topbar-active: initial; --th-bg: initial; --zebra-bg: initial;
  --diag-line: initial; --diag-fill: initial; --doc-band: initial; --doc-sblue: initial; --doc-sorange: initial; --doc-sgreen: initial; --doc-sred: initial;   /* 1.55.0: appearance.py sets them */
  --ctl-h: 32px; --ctl-h-sm: 26px;
  --radius: 6px; --radius-sm: 4px; --radius-pill: 999px;   /* --radius-card (10px) is above */

  font-family: system-ui, -apple-system, "Segoe UI", Roboto, Arial, sans-serif;
  font-size: var(--fs-md);
  line-height: 1.5;
  color: var(--text);
  background: var(--bg);
}


/* ---- dark scheme (the theme switch in the top bar; "auto" follows the operating system) ------------- */
:root[data-theme="dark"] {
  --bg: #15171b; --surface: #1d2025; --surface-2: #252930; --text: #e6e8eb; --muted: #a0a8b2; --faint: #7a828c;
  --border: #343a42; --accent: #95acd9; --accent-text: #15171b; --accent-bg: #28324c; --info-line: #32436e;
  --ok: #3fb950; --ok-bg: #173323; --ok-text: #86e0a4; --ok-line: #2a5a3b;
  --warn: #d29922; --notice-bg: #372b10; --notice-text: #f0cd6a; --warn-line: #6a5316;
  --bad: #d03d34; --error-bg: #3a1d1d; --error-text: #ffa39b; --bad-line: #6e2b2b; --on-bad: #ffffff;
  --info: #95acd9; --missing-bg: #4a4418; --na-bg: #2a2e34;
  --input-bg: #15171b; --code-bg: #2a2e34; --section-bg: #222836; --group-bg: #263046; --stage-bg: #101215;
  --plot-bg: #181b1f; --plot-ink: #e3e5e8; --plot-muted: #8b939c; --plot-mast: #c9ccd1; --plot-ground: #b8945a;
  --plot-halo: #181b1f; --shadow: 0 6px 20px rgba(0, 0, 0, .5);
  --pic-filter: invert(1) hue-rotate(180deg); --pic-blend: lighten; --pic-toggle: inline-block; --pic-ink: #f2f2f2;
  --pic-ink-2: #f0f0f0; --pic-halo: #101215; --pic-plot: #e8eaed; --pic-muted: #9aa0a6; --pic-blue: #95acd9; --pic-red: #ff6b5e;
  --pic-fill: #101215; --pic-green: #81c995; --axis-x: #ff6b5e; --axis-y: #81c995; --axis-z: #95acd9; --logo-light: none; --logo-dark: inline-block; --tension: #7fb0e8; --compression: #ff7b6b;
  --pic-cal-fill: rgba(149, 172, 217, .30); --pic-sel-fill: rgba(149, 172, 217, .15);
  color-scheme: dark;
}
@media (prefers-color-scheme: dark) {
  :root[data-theme="auto"] {
  --bg: #15171b; --surface: #1d2025; --surface-2: #252930; --text: #e6e8eb; --muted: #a0a8b2; --faint: #7a828c;
  --border: #343a42; --accent: #95acd9; --accent-text: #15171b; --accent-bg: #28324c; --info-line: #32436e;
  --ok: #3fb950; --ok-bg: #173323; --ok-text: #86e0a4; --ok-line: #2a5a3b;
  --warn: #d29922; --notice-bg: #372b10; --notice-text: #f0cd6a; --warn-line: #6a5316;
  --bad: #d03d34; --error-bg: #3a1d1d; --error-text: #ffa39b; --bad-line: #6e2b2b; --on-bad: #ffffff;
  --info: #95acd9; --missing-bg: #4a4418; --na-bg: #2a2e34;
  --input-bg: #15171b; --code-bg: #2a2e34; --section-bg: #222836; --group-bg: #263046; --stage-bg: #101215;
  --plot-bg: #181b1f; --plot-ink: #e3e5e8; --plot-muted: #8b939c; --plot-mast: #c9ccd1; --plot-ground: #b8945a;
  --plot-halo: #181b1f; --shadow: 0 6px 20px rgba(0, 0, 0, .5);
  --pic-filter: invert(1) hue-rotate(180deg); --pic-blend: lighten; --pic-toggle: inline-block; --pic-ink: #f2f2f2;
  --pic-ink-2: #f0f0f0; --pic-halo: #101215; --pic-plot: #e8eaed; --pic-muted: #9aa0a6; --pic-blue: #95acd9; --pic-red: #ff6b5e;
  --pic-fill: #101215; --pic-green: #81c995; --axis-x: #ff6b5e; --axis-y: #81c995; --axis-z: #95acd9; --logo-light: none; --logo-dark: inline-block; --tension: #7fb0e8; --compression: #ff7b6b;
  --pic-cal-fill: rgba(149, 172, 217, .30); --pic-sel-fill: rgba(149, 172, 217, .15);
  color-scheme: dark;
}
}
:root[data-theme="light"] { color-scheme: light; }
.theme-switch button.icon { width: var(--ctl-h-sm); height: var(--ctl-h-sm); padding: 0; line-height: 1; }
.theme-switch svg { width: 15px; height: 15px; vertical-align: middle; fill: none; stroke: currentColor; stroke-width: 1.5;
  stroke-linecap: round; stroke-linejoin: round; }
.theme-switch svg .fill { fill: currentColor; }
.inline-label { display: inline; margin: 0; font-weight: 400; }
/* the photo and the drawings stay as they are: their markers are drawn for a light picture */

* { box-sizing: border-box; }
/* hidden means hidden - also for elements whose class sets a display (chips, buttons, grids) */
[hidden] { display: none !important; }
/* 1.31.0 (DESIGN_RULES §3a): every page is a column exactly as tall as the window - top bar, the page body taking
   what is left, the footer at the bottom edge - so a short page never scrolls by the footer's height */
body { margin: 0; min-height: 100dvh; display: flex; flex-direction: column; }
body > .page-body { flex: 1 0 auto; }

/* no automatic capitals (owner 2026-09-27): every text shows exactly as written in the text editor */
h1 { font-size: var(--fs-xl); font-weight: 600; margin: 0 0 var(--sp-4); line-height: 1.3; }
h2 { font-size: var(--fs-lg); font-weight: 600; margin: 0 0 var(--sp-3); }
h3 { font-size: var(--fs-md); font-weight: 600; margin: 0 0 var(--sp-2); }
h1 .muted { font-weight: 400; }
p.muted, .muted { color: var(--muted); }
.sub { color: var(--muted); font-size: var(--fs-xs); }
b, strong, th { font-weight: 600; }

.topbar {
  display: flex; align-items: center; gap: var(--sp-4); flex-wrap: wrap; min-height: 48px;
  padding: var(--sp-2) var(--sp-5); background: var(--topbar-bg, var(--surface)); color: var(--topbar-text, var(--text)); border-bottom: 1px solid var(--border);
}
.topbar .brand { font-weight: 600; font-size: var(--fs-lg); color: var(--accent); text-decoration: none; letter-spacing: .02em; }
.topbar .spacer { flex: 1; }
.topbar .who { color: var(--muted); font-size: var(--fs-sm); }
.topbar form { margin: 0; display: flex; align-items: center; gap: var(--sp-2); }
.topbar label { font-size: var(--fs-sm); }
.topbar select { width: auto; }

/* chips: one shape for every status */
.chip, .badge, .ws-lock, .pw-changes, .pw-outdated, .ws-res {
  display: inline-block; vertical-align: middle; text-align: center; height: 20px; line-height: 18px; padding: 0 var(--sp-2);
  border-radius: var(--radius-pill); font-size: var(--fs-xs); font-weight: 600; white-space: nowrap;
  border: 1px solid var(--border); background: var(--surface-2); color: var(--muted); font-variant-numeric: tabular-nums;
}
.chip.ok, .ws-lock.ok, .ws-res.ok { background: var(--ok-bg); color: var(--ok-text); border-color: var(--ok-line); }
.chip.warn, .badge, .ws-lock.busy, .pw-changes, .pw-outdated { background: var(--notice-bg); color: var(--notice-text); border-color: var(--warn-line); }
.chip.bad, .ws-res.over { background: var(--bad); color: var(--on-bad); border-color: var(--bad); }
.chip.info, .badge.mine { background: var(--accent-bg); color: var(--accent); border-color: var(--info-line); }
.chip.muted, .ws-lock.free { background: var(--surface); color: var(--muted); }

main { max-width: 960px; margin: var(--sp-5) auto; padding: 0 var(--sp-4); }
.card {
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-card);
  padding: var(--sp-4) var(--sp-5);
}
.card.narrow { max-width: 440px; margin: 0 auto; }

/* forms */
label { display: block; margin: var(--sp-3) 0 var(--sp-1); font-weight: 600; font-size: var(--fs-sm); }
input[type=text], input[type=email], input[type=password], input[type=number], select {
  width: 100%; height: var(--ctl-h); padding: 0 var(--sp-2); border: 1px solid var(--border); border-radius: var(--radius);
  font: inherit; font-size: var(--fs-md); background: var(--input-bg); color: var(--text);
}
input:focus, select:focus { outline: 2px solid var(--accent); outline-offset: -1px; border-color: var(--accent); }

/* buttons: primary / secondary (= .tool) / toggle / danger / icon; .small = compact height */
button, .button {
  display: inline-block; vertical-align: middle; text-align: center;
  height: var(--ctl-h); line-height: calc(var(--ctl-h) - 2px); padding: 0 var(--sp-4); border-radius: var(--radius); cursor: pointer;
  border: 1px solid var(--accent); background: var(--accent); color: var(--accent-text);
  font: inherit; font-size: var(--fs-md); font-weight: 600; text-decoration: none; white-space: nowrap;
}
button:hover:not(:disabled), .button:hover { filter: brightness(1.08); }
button.secondary, button.tool, .button.secondary {
  background: var(--surface); color: var(--text); border-color: var(--border); font-weight: 400; filter: none;
}
button.secondary:hover:not(:disabled), button.tool:hover:not(:disabled), .button.secondary:hover {
  border-color: var(--accent); color: var(--accent); filter: none; }
button[aria-pressed="true"], button.active { background: var(--accent); color: var(--accent-text); border-color: var(--accent); }
button.danger { color: var(--error-text); border-color: var(--bad-line); background: var(--surface); font-weight: 400; }
button.danger:hover:not(:disabled) { border-color: var(--bad); color: var(--bad); }
button.small, button.tool, .small.button { height: var(--ctl-h-sm); line-height: calc(var(--ctl-h-sm) - 2px); padding: 0 var(--sp-3); font-size: var(--fs-sm); }
button.icon { width: var(--ctl-h-sm); padding: 0; font-size: var(--fs-lg); font-weight: 400; }
button:disabled, button[disabled] { opacity: .45; cursor: not-allowed; filter: none; }
button:focus-visible, .button:focus-visible, a:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.actions { margin-top: var(--sp-4); display: flex; gap: var(--sp-2); align-items: center; flex-wrap: wrap; }
a { color: var(--accent); }

.error {
  background: var(--error-bg); color: var(--error-text); border-radius: var(--radius);
  padding: 10px 12px; margin-bottom: 12px;
}
.notice {
  background: var(--notice-bg); color: var(--notice-text); border-radius: var(--radius);
  padding: 10px 12px; margin: 12px 0;
}
p.ok, div.ok {
  background: var(--ok-bg); color: var(--ok-text); border-radius: var(--radius);
  padding: 10px 12px; margin: 12px 0;
}
.field-missing input { border-color: var(--error-text); }
ul.plain { padding-left: 18px; }
code { background: var(--code-bg); padding: 1px 5px; border-radius: var(--radius-sm); }

/* --- phase 8b: project screens --- */
.card + .card { margin-top: 16px; }
.card.wide { max-width: 640px; }
.card-head { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
.filters { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; margin: 4px 0 16px; }
.filters select, .filters input { width: auto; min-width: 160px; }
form.inline { margin-bottom: 8px; }
table.list { width: 100%; border-collapse: collapse; font-size: var(--fs-md); }
table.list th, table.list td { text-align: left; padding: 8px 10px; border-bottom: 1px solid var(--border); vertical-align: top; }
table.list th { color: var(--muted); font-weight: 600; font-size: var(--fs-sm); }
table.list tr:hover td { background: var(--surface-2); }
dl.facts { display: grid; grid-template-columns: max-content 1fr; gap: 6px 20px; margin: 8px 0 16px; }
dl.facts dt { color: var(--muted); }
dl.facts dd { margin: 0; }
.grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 0 20px; }
.readonly { padding: 8px 0; }
fieldset { border: 0; padding: 0; margin: 0; }
fieldset[disabled] input, fieldset[disabled] select { background: var(--na-bg); color: var(--muted); }
/* wide tables scroll inside their card instead of widening the whole page */
.card { overflow-x: auto; }

/* parts screen (module 7c) - Excel's colours: yellow = required and empty, red = invalid */
main.wide { max-width: none; }
.card.parts-card { overflow: visible; }
/* a fieldset is at least as wide as its content by default (min-width: min-content) - without this
   the whole page scrolls sideways instead of the table */
.parts-card fieldset { min-width: 0; }
/* the table scrolls inside its own box: header row and height column stay in view, and the
   buttons around the table never scroll away */
.table-scroll { position: relative; overflow: auto; max-height: 65vh; border: 1px solid var(--border); border-radius: var(--radius); }
table.parts { border-collapse: separate; border-spacing: 0; }
table.parts td { padding: 4px 6px; white-space: nowrap; }
table.parts thead th { position: sticky; top: 0; z-index: 2; background: var(--surface); }
table.parts td:first-child, table.parts th:first-child { position: sticky; left: 0; z-index: 1; background: var(--surface); }
table.parts thead th:first-child { z-index: 3; }
table.parts input[type=text] { width: 5em; padding: 4px 6px; }
table.parts select { padding: 4px 6px; }
table.parts tr.group-start td { border-top: 2px solid var(--border); }
table.parts td.missing input, table.parts td.missing select, .anchor-gap input.missing { background: var(--missing-bg); }
table.parts td.invalid input, table.parts td.invalid select { border-color: var(--error-text); background: var(--error-bg); }
/* inputs the row's case doesn't use: locked, shown greyed out like a disabled field (Excel marks
   them with a pattern in UI_parts); a leftover value stays visible, in red as in Excel */
table.parts td.na input, table.parts td.na select {
  background: var(--na-bg); border-color: var(--na-bg); color: var(--bad); cursor: not-allowed; box-shadow: none; }
table.parts td.na select { pointer-events: none; appearance: none; -webkit-appearance: none; }
ul.messages { margin: 0 0 12px; }
ul.messages .msg-error { color: var(--error-text); }
ul.messages .msg-info { color: var(--muted); }
.anchor-gap { display: flex; gap: 8px; align-items: center; margin-bottom: 12px; }
.anchor-gap input { width: 8em; }
.add-row { margin: 0 0 12px; }
.add-row input { min-width: 0; width: 7em; }

/* calculation + results (module 7d) */
.profile-list { display: flex; flex-wrap: wrap; gap: 6px 18px; margin: 6px 0 4px; }
.profile-list label.check { font-weight: 400; display: flex; gap: 6px; align-items: center; margin: 0; }
.results-scroll { max-height: none; }
table.results { table-layout: auto; width: 100%; }
table.results td { white-space: normal; }
/* label and unit as narrow as their text allows; the variant columns share the rest (colgroup) */
table.results col.c-label, table.results col.c-unit { width: 1%; }
table.results td.res-label { white-space: normal; min-width: 20em; }   /* long labels wrap to a 2nd line */
table.results td.res-unit { white-space: nowrap; padding-right: 12px; }
table.results td:nth-child(n+3) { text-align: right; overflow-wrap: anywhere; }
table.results thead th:nth-child(n+3) { text-align: right; }
table.results td.res-gov { text-align: right; }   /* 1.47.0: a topic's highest usage stands in its variant's column - right, like the numbers */
table.results tr.res-section td { background: var(--section-bg); font-weight: 600; }
table.results tr.res-group td { background: var(--group-bg); font-weight: 600; letter-spacing: .02em; padding-top: 10px; }
table.results tr.res-sub td { color: var(--muted); font-style: italic; }
table.results td.util-ok { background: var(--ok-bg); }
table.results td.util-bad { background: var(--error-bg); color: var(--error-text); font-weight: 600; }
/* collapsible topics (closed by default, like Excel's "alles verbergen") */
tbody.topic:not(.open) tr:not(.res-topic) { display: none; }
.topic-toggle { all: unset; cursor: pointer; display: flex; align-items: center; gap: 8px; width: 100%; font-weight: 600; }
.topic-toggle:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.topic-toggle .caret { width: 0; height: 0; border-left: 6px solid currentColor; border-top: 5px solid transparent;
  border-bottom: 5px solid transparent; transition: transform .15s; }
tbody.topic.open .topic-toggle .caret { transform: rotate(90deg); }
.res-toggle-all { display: flex; gap: 8px; }

/* photo tool (module 7e) */
.photo-work { display: grid; grid-template-columns: minmax(0, 1fr) 24rem; grid-template-rows: auto 1fr; gap: 6px 16px; align-items: start; }
.photo-zoom { grid-column: 1; display: flex; gap: 10px; align-items: center; }
.photo-side { grid-column: 2; grid-row: 1 / span 2; }

.photo-stage { grid-column: 1; overflow: auto; max-height: 85vh; border: 1px solid var(--border); border-radius: var(--radius); background: var(--stage-bg); }
.photo-canvas { position: relative; margin: 0 auto; }      /* width = picture pixels x zoom (photo.js) */
.photo-canvas img { position: absolute; inset: 0; width: 100%; height: 100%; user-select: none; -webkit-user-drag: none; }
.photo-canvas svg { position: absolute; inset: 0; width: 100%; height: 100%; touch-action: none; }
.photo-canvas svg.crosshair { cursor: crosshair; }
.mk { cursor: grab; }
.mk .mk-hit { fill: transparent; }
.mk .mk-ring { fill: var(--pic-glass); stroke-width: 3; vector-effect: non-scaling-stroke; }
.mk .mk-cross { stroke-width: 1.5; vector-effect: non-scaling-stroke; }
.mk.ok .mk-ring, .mk.ok .mk-cross { stroke: var(--ok); }
.mk.todo .mk-ring, .mk.todo .mk-cross { stroke: var(--pic-red); }
.mk.anchor .mk-ring, .mk.anchor .mk-cross { stroke: var(--pic-ink); }
.mk.hum .mk-ring { stroke: var(--pic-ink); fill: var(--pic-fill); } .mk.hum .mk-cross { stroke: var(--pic-ink); } .mk.hum { cursor: default; }
.mk.cal .mk-ring, .mk.cal .mk-cross { stroke: var(--pic-blue); } .mk.cal .mk-ring { fill: var(--pic-cal-fill); }
.mk.changed .mk-ring { stroke-dasharray: 4 2; }
.mk.sel .mk-ring { stroke-width: 5; }
.photo-side { display: flex; flex-direction: column; gap: 8px; }
.photo-info { margin: 0; padding: 8px 10px; border-radius: var(--radius); background: var(--bg); }
.photo-info.active { background: var(--accent-bg); } .photo-info.warn { background: var(--notice-bg); color: var(--notice-text); }
table.photo-rows td, table.photo-rows th { padding: 3px 6px; font-size: var(--fs-sm); }
table.photo-rows tr { cursor: pointer; } table.photo-rows tr.sel td { background: var(--accent-bg); } table.photo-rows tr.changed td { font-weight: 600; }
.photo-upload { border: 1px dashed var(--border); border-radius: var(--radius); padding: 12px 16px; margin-bottom: 12px; }
.pdf-view { position: relative; display: inline-block; max-width: 100%; margin-top: 8px; }
.pdf-view canvas { max-width: 100%; height: auto; border: 1px solid var(--border); cursor: crosshair; touch-action: none; }
.pdf-rect { position: absolute; border: 2px solid var(--pic-blue); background: var(--pic-sel-fill); pointer-events: none; }
.part-panel { border: 1px solid var(--border); border-radius: var(--radius); padding: 8px 10px; }
.part-panel h3 { margin: 0 0 6px; font-size: var(--fs-md); }
.part-grid { display: grid; grid-template-columns: auto 1fr; gap: 4px 8px; align-items: center; font-size: var(--fs-sm); }
.part-grid label { color: var(--muted); }
.part-grid input, .part-grid select { width: 100%; padding: 3px 6px; box-sizing: border-box; }
.part-grid .pf.missing input, .part-grid .pf.missing select { background: var(--missing-bg); }
.part-grid .pf.invalid input, .part-grid .pf.invalid select { border-color: var(--error-text); background: var(--error-bg); }
.part-grid .pf.na input, .part-grid .pf.na select { background: var(--na-bg); border-color: var(--na-bg); color: var(--bad); }
.part-panel .err { color: var(--error-text); }
@media (max-width: 900px) { .photo-work { grid-template-columns: 1fr; } .photo-zoom, .photo-stage, .photo-side { grid-column: 1; grid-row: auto; } }
.photo-canvas .ref-line { stroke: var(--pic-blue); stroke-width: 2; stroke-dasharray: 6 4; vector-effect: non-scaling-stroke; }
.photo-canvas .wire-line { fill: none; stroke-width: 2.5; vector-effect: non-scaling-stroke; }
.photo-canvas .wire-line.ok { stroke: var(--ok); } .photo-canvas .wire-line.todo { stroke: var(--pic-red); }
.photo-canvas .wire-line.sel { stroke-width: 4; }
.photo-canvas .wire-label { fill: var(--pic-ink-2); font-weight: 700; paint-order: stroke; stroke: var(--pic-halo); stroke-width: 3px; }
/* load combination breakdown on the results page (Excel frmLCInfo) */
table.results .lc { border-bottom: 1px dotted currentColor; cursor: help; }
table.results .lc:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.lc-pop { position: absolute; z-index: 20; background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
  box-shadow: var(--shadow); padding: 8px 10px; font-size: var(--fs-sm); }
.lc-pop .lc-title { font-weight: 600; margin-bottom: 4px; }
.lc-pop table { border-collapse: collapse; } .lc-pop td { padding: 1px 6px; white-space: nowrap; } .lc-pop td.num { text-align: right; font-variant-numeric: tabular-nums; }
.lc-pop td:first-child { color: var(--muted); }

/* Diagrams of a load combination (opened from its breakdown box on the results page) */
.lc-pop .lc-diag { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 6px; padding-top: 6px; border-top: 1px solid var(--border); }
dialog.diag { width: min(96vw, 1400px); height: min(92vh, 820px); min-width: 360px; min-height: 340px;
  max-width: 100vw; max-height: 100vh; resize: both; overflow: hidden;
  border: 1px solid var(--border); border-radius: var(--radius); padding: 12px 16px; }
dialog.diag[open] { display: flex; flex-direction: column; }
dialog.diag.max { width: 100vw; height: 100vh; margin: 0; border-radius: 0; resize: none; }
dialog.diag > :not(.diag-body) { flex: none; }        /* header, texts: their own height */
dialog.diag::backdrop { background: var(--backdrop); }
.diag-head { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; }
.diag-head { user-select: none; }
.diag-head #diag-max { margin-left: auto; min-width: 2.2em; font-size: var(--fs-md); line-height: 1; }
.diag-tabs { display: flex; gap: 4px; }
dialog.diag > .diag-body { flex: 1 1 0; min-height: 0; overflow: auto; display: flex; flex-wrap: wrap;
  align-content: flex-start; gap: 6px; cursor: crosshair; }
.diag-panel { border: 1px solid var(--border); border-radius: var(--radius); background: var(--plot-bg); }
.diag-panel .d-title { font-size: var(--fs-xs); font-weight: 600; }
.diag-panel .d-mast { stroke: var(--plot-mast); stroke-width: 3; }
.diag-panel .d-ground { stroke: var(--plot-ground); stroke-width: 2; stroke-dasharray: 4 3; }
/* value colour scale as in FE programs: fill colours are set per strip by results.js */
.diag-panel .d-fill { opacity: .85; }
.diag-panel .d-line { fill: none; stroke: var(--plot-ink); stroke-width: 1.4; }
.diag-panel .d-legend { stroke: var(--plot-muted); stroke-width: .5; }
.diag-panel .d-env { fill: var(--plot-muted); opacity: .22; stroke: var(--plot-muted); stroke-width: 1; stroke-dasharray: 3 2; }
.diag-panel .d-limit { stroke: var(--bad); stroke-dasharray: 3 3; }
.diag-panel .d-dot { fill: var(--plot-ink); }
.diag-panel .d-max { font-size: 11px; font-weight: 600; }
.diag-panel .d-z { font-size: 10px; fill: var(--muted); }
.diag-panel .d-probe { stroke: var(--plot-ink); stroke-width: 1; stroke-dasharray: 2 2; pointer-events: none; }
.diag-panel .d-probe-dot { fill: var(--plot-ink); pointer-events: none; }
.diag-panel .d-probe-v { font-size: 11px; font-weight: 700; paint-order: stroke; stroke: var(--plot-halo); stroke-width: 3px; pointer-events: none; }
/* two lines, fixed: a changing probe text must not change the panels' height (they follow it) */
.diag-probe { height: 2.9em; overflow: hidden; margin: 0 0 6px; font-size: var(--fs-sm); line-height: 1.45;
  font-variant-numeric: tabular-nums; }

/* ---- the iteration workspace (workspace.py, _ws_bar.html, _ws_nav.html) ---------------------------- */
.sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
.ws-bar { background: var(--surface); border-bottom: 1px solid var(--border); padding: 8px 24px 0; }
.ws-crumbs { display: flex; align-items: center; gap: 8px; font-size: var(--fs-md); flex-wrap: wrap; }
.ws-crumbs nav { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.ws-crumbs a { color: var(--muted); text-decoration: none; }
.ws-crumbs a:hover { color: var(--accent); text-decoration: underline; }
.ws-crumbs .ws-here { font-weight: 600; color: var(--text); }
.ws-crumbs .spacer { flex: 1; }
.ws-sep { color: var(--border); }
.ws-steps { list-style: none; display: flex; gap: 2px; margin: 8px 0 0; padding: 0; flex-wrap: wrap; align-items: flex-end; }
.ws-steps li > a, .ws-steps li > span { display: inline-flex; align-items: center; gap: 6px; padding: 8px 14px;
  font-size: var(--fs-md); color: var(--muted); text-decoration: none; border-bottom: 3px solid transparent; }
.ws-steps li > a:hover { color: var(--text); background: var(--surface-2); }
.ws-steps b { display: inline-grid; place-items: center; width: 20px; height: 20px; border-radius: 50%; font-size: var(--fs-xs);
  background: var(--bg); color: var(--muted); border: 1px solid var(--border); font-weight: 600; }
.ws-steps li.active > a { color: var(--accent); border-bottom-color: var(--accent); font-weight: 600; }
.ws-steps li.active b { background: var(--accent); color: var(--accent-text); border-color: var(--accent); }
.ws-steps li.disabled > span { opacity: .45; cursor: not-allowed; }
.ws-steps .ws-views { margin-left: auto; align-self: center; display: inline-flex; border: 1px solid var(--border);
  border-radius: var(--radius); overflow: hidden; margin-bottom: 6px; }
.ws-body { display: grid; grid-template-columns: 210px minmax(0, 1fr); align-items: start; }
body.has-ws { min-height: 100vh; display: flex; flex-direction: column; }
body.has-ws > .ws-body { flex: 1; align-items: stretch; }     /* the navigator reaches the bottom of the window */
.ws-nav { background: var(--surface); border-right: 1px solid var(--border); padding: 16px 10px; font-size: var(--fs-md); }
.ws-nav-head { font-size: var(--fs-xs); letter-spacing: .04em; color: var(--muted); padding: 0 8px 8px; }
.ws-nav ul { list-style: none; margin: 0; padding: 0; }
.ws-nav li a { display: grid; grid-template-columns: 20px 1fr auto; column-gap: 8px; padding: 7px 8px; border-radius: var(--radius);
  color: var(--text); text-decoration: none; }
.ws-nav li a:hover { background: var(--surface-2); }
.ws-nav li a.current { background: var(--accent-bg); box-shadow: inset 3px 0 0 var(--accent); }
.ws-nav .ws-state { grid-row: span 2; align-self: center; }
.ws-mast-name { font-weight: 600; }
.ws-mast-sub { font-size: var(--fs-xs); color: var(--muted); }
.ws-state svg { width: 16px; height: 16px; fill: none; stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; vertical-align: -3px; }
.ws-state.ready svg { stroke: var(--ok); }
.ws-state.incomplete svg { stroke: var(--warn); }
.ws-state.empty svg { stroke: var(--faint); }
/* a secondary button across the navigator; its label may wrap ("+ Masten hinzufügen / bearbeiten") */
.ws-add.button { display: block; margin: 10px 8px 0; height: auto; min-height: var(--ctl-h-sm); line-height: 1.3;
  padding: 4px var(--sp-3); white-space: normal; }
/* a workflow step that navigates: an <a> dressed as a secondary button (DESIGN_RULES.md §6.2) */
.btn-row { display: inline-flex; flex-wrap: wrap; gap: var(--sp-2); align-items: center; }
.pw-res-links { margin-top: var(--sp-3); }
.ws-empty { color: var(--muted); padding: 6px 8px; }
.ws-legend { margin: 18px 8px 0; padding-top: 10px; border-top: 1px solid var(--border); display: grid; gap: 4px;
  font-size: var(--fs-xs); color: var(--muted); }
.ws-legend > span { display: flex; align-items: center; gap: 6px; }
main.in-ws { max-width: none; margin: 20px 24px; padding: 0; }
@media (max-width: 800px) {
  .ws-body { grid-template-columns: 1fr; }
  .ws-nav { position: static; min-height: 0; border-right: 0; border-bottom: 1px solid var(--border); }
  .ws-nav ul { display: flex; flex-wrap: wrap; gap: 4px; }
  .ws-legend { display: none; }
}

/* ---- GUI stage 2: the photo workspace (photo.html) ------------------------------------------------------- */
main.pw-main-wrap.in-ws { margin: 12px 16px; }
.pw-notice { margin-bottom: 8px; padding: 6px 12px; }
.pw { display: flex; flex-direction: column; gap: 10px; }
.pw-toolbar { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 14px; padding: 6px 10px;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); }
.pw-title { font-size: var(--fs-md); margin-right: 4px; white-space: nowrap; }
.pw-group { display: inline-flex; align-items: center; gap: 4px; }
.pw-group + .pw-group { padding-left: 14px; border-left: 1px solid var(--border); }
.pw-zoom-level { min-width: 48px; text-align: center; font-size: var(--fs-sm); font-variant-numeric: tabular-nums; }
.pw-ref label { margin: 0; font-size: var(--fs-sm); font-weight: 400; color: var(--muted); white-space: nowrap; }
.pw-ref input { width: 5.5em; padding: 4px 6px; font-size: var(--fs-sm); }
.pw-spacer { flex: 1; }
.pw-save { display: inline-flex; align-items: center; gap: 6px; margin: 0; }
.pw-work { display: grid; grid-template-columns: minmax(0, 1fr) clamp(280px, 28vw, 380px); gap: 12px; height: calc(100vh - 215px); min-height: 300px; }
.pw-center { display: flex; flex-direction: column; gap: 6px; min-height: 0; }
.pw-work .photo-stage { flex: 1; min-height: 0; max-height: none; grid-column: auto; background: var(--stage-bg); }
.pw-center .photo-info { font-size: var(--fs-sm); }
.pw-inspector { display: flex; flex-direction: column; gap: 10px; min-height: 0; overflow: auto; }
.pw-section { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); padding: 10px 12px; }
.pw-section h3 { margin: 0 0 6px; font-size: var(--fs-md); }
.pw-inspector .part-panel { border: 0; padding: 0; }
.pw-inspector .part-panel h3 { font-size: var(--fs-md); margin-bottom: 8px; }
.pw-empty p { margin: 0 0 6px; }
.pw-keys { line-height: 1.6; }
.pw-list { flex: 1; min-height: 160px; }
.pw-list table.photo-rows { width: 100%; }
.pw-list table.photo-rows tr:hover td { background: var(--surface-2); }
.pw-legend { margin: 8px 0 0; font-size: var(--fs-xs); }
.pw-dot { display: inline-block; box-sizing: border-box; width: 10px; height: 10px; min-width: 10px; padding: 0;
  border-radius: 50%; border: 2px solid var(--faint); vertical-align: middle; }
.pw-list table.photo-rows td:first-child, .pw-list table.photo-rows th:first-child { width: 14px; padding-right: 0; }
.pw-dot.ok { border-color: var(--ok); } .pw-dot.todo { border-color: var(--bad); } .pw-dot.anchor { border-color: var(--text); }
.mk.hover .mk-ring { stroke-width: 6; fill: var(--pic-hover-fill); }
@media (max-width: 860px) {
  .pw-work { grid-template-columns: 1fr; height: auto; }
  .pw-work .photo-stage { height: 65vh; flex: none; }
}

/* ---- GUI stage 3: results on the photo ---------------------------------------------------------------------- */
.pw-calc select { width: auto; padding: 4px 6px; font-size: var(--fs-sm); }
.photo-canvas .res { pointer-events: none; }
.photo-canvas .res-fill { opacity: .5; }            /* the drawing stays readable underneath */
.photo-canvas .res-line { fill: none; stroke: var(--pic-plot); }
.photo-canvas .res-axis { stroke: var(--pic-plot); stroke-dasharray: 4 3; }
.photo-canvas .res-env { fill: var(--pic-muted); opacity: .28; }
.photo-canvas .res-max { font-weight: 700; fill: var(--pic-plot); paint-order: stroke; stroke: var(--pic-halo); stroke-width: 3px; }
.photo-canvas .res-probe { stroke: var(--pic-plot); stroke-dasharray: 3 3; }
/* acting loads (2026-09-27): x / y / z = red / green / blue, as the diagrams; every glyph also carries its letter */
.photo-canvas .ld-x { stroke: var(--pic-red); fill: var(--pic-red); }
.photo-canvas .ld-y { stroke: var(--pic-green); fill: var(--pic-green); }
.photo-canvas .ld-z { stroke: var(--pic-blue); fill: var(--pic-blue); }
.photo-canvas .ld-shaft { fill: none; }
.photo-canvas .ld-ring { fill: var(--pic-fill); fill-opacity: .9; }
.photo-canvas .ld-node { fill: var(--pic-fill); stroke: var(--pic-ink); }
.photo-canvas .ld-label { stroke: var(--pic-halo); stroke-width: 3px; paint-order: stroke; font-weight: 600;
  font-variant-numeric: tabular-nums; }
.photo-canvas g.ld-point.hot .ld-node, .photo-canvas g.ld-point.hot .ld-ring { stroke-width: 3px; }
.pw-results.is-loads .res-series-ctl { display: none; }
.pw-loads h4 { margin: 10px 0 4px; font-size: var(--fs-sm); }
.pw-loads table { width: 100%; border-collapse: collapse; font-size: var(--fs-sm); }
.pw-loads td, .pw-loads th { padding: 3px 4px; border-bottom: 1px solid var(--border); text-align: left; }
.pw-loads td.num, .pw-loads th.num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.pw-loads tr.sum td { font-weight: 600; border-top: 2px solid var(--border); }
.pw-loads tr.hot td { background: var(--surface-2); }
.pw-loads .ld-note { color: var(--muted); font-size: var(--fs-xs); margin: 4px 0 0; }
.pw-results { border-color: var(--accent); }
.pw-res-head { display: flex; align-items: center; gap: 8px; }
.pw-res-head h3 { margin: 0; flex: 1; }
.pw-summary { width: 100%; border-collapse: collapse; margin: 8px 0; font-size: var(--fs-sm); }
.pw-summary td { padding: 3px 4px; border-bottom: 1px solid var(--border); }
.pw-summary td:last-child { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.pw-summary tr.total td { font-weight: 600; }
.pw-summary td.util-ok { color: var(--ok-text); } .pw-summary td.util-bad { color: var(--on-bad); background: var(--bad); font-weight: 600; }
.pw-res-controls { display: grid; grid-template-columns: auto 1fr; gap: 6px 8px; align-items: center; font-size: var(--fs-sm); }
.pw-res-controls label { margin: 0; font-weight: 400; color: var(--muted); }
.pw-res-controls select { padding: 3px 6px; font-size: var(--fs-sm); }
.pw-res-controls .check { grid-column: 1 / -1; color: var(--text); }
.pw-kinds { grid-column: 1 / -1; display: flex; flex-wrap: wrap; gap: 4px; }
.pw-probe { margin: 8px 0 0; padding: 6px 8px; background: var(--bg); border-radius: var(--radius); font-variant-numeric: tabular-nums; min-height: 2.6em; }
.pw-probe div.cur { font-weight: 600; color: var(--text); }
.pw-results .err { color: var(--error-text); margin: 6px 0 0; font-size: var(--fs-sm); }

/* stored results in the navigator (results_store.py) */
.ws-nav .ws-res { grid-column: 3; grid-row: 1 / span 2; align-self: center; }
.ws-mast-sub { grid-column: 2; }


/* ---- the formatting rule applied to screens that had their own sizes ------------------------------------ */
.ws-res { min-width: 40px; }
.ws-res.stale { background: var(--surface-2); color: var(--muted); border-color: var(--border); text-decoration: line-through; }
.ws-steps .ws-views a { display: inline-flex; align-items: center; height: var(--ctl-h-sm); padding: 0 var(--sp-3);
  font-size: var(--fs-sm); color: var(--text); text-decoration: none; }
.ws-steps .ws-views a + a { border-left: 1px solid var(--border); }
.ws-steps .ws-views a.active { background: var(--accent); color: var(--accent-text); }
table.list th, table.parts th, table.results th, .pw-summary th { font-size: var(--fs-xs); color: var(--muted); font-weight: 600; }
table.list td, table.list th { padding: var(--sp-2) var(--sp-3); }
table.list { font-size: var(--fs-sm); }
table.parts input[type=text], table.parts select, .part-grid input, .part-grid select, .pw-ref input, .pw-calc select,
.pw-res-controls select, .add-row input, .filters input, .filters select {
  height: var(--ctl-h-sm); font-size: var(--fs-sm); padding: 0 var(--sp-2); }
.pw-toolbar { min-height: 42px; }
.pw-group { gap: var(--sp-1); }
.pw-res-head button.icon { width: var(--ctl-h-sm); height: var(--ctl-h-sm); }
.part-panel button.danger { margin-top: var(--sp-2); }
.diag-head #diag-max { min-width: var(--ctl-h-sm); }
.lc-pop .lc-diag button { height: 24px; }
.topbar button { height: var(--ctl-h-sm); line-height: calc(var(--ctl-h-sm) - 2px); font-size: var(--fs-sm); }
.topbar .nav { color: var(--topbar-text, var(--text)); text-decoration: none; font-weight: 600; }
.topbar .nav:hover { color: var(--accent); }
.topbar select { height: var(--ctl-h-sm); font-size: var(--fs-sm); padding: 0 var(--sp-1); }
.pw-section h3, .part-panel h3, .pw-inspector .part-panel h3 { font-size: var(--fs-md); }
.pw-toolbar button, .pw-toolbar select, .pw-toolbar input[type=text] { height: var(--ctl-h-sm); line-height: calc(var(--ctl-h-sm) - 2px);
  font-size: var(--fs-sm); }
.pw-toolbar select { line-height: normal; width: auto; }
.pw-title, .ws-crumbs a, .ws-crumbs .ws-here { display: inline-block; }
.diag-panel text { fill: var(--plot-ink); }

/* ---- the project hub (hub.html) ---------------------------------------------------------------------------- */
main.hub-main { max-width: none; margin: 0; padding: 0; }
/* 1.31.0: the hub fills the page body (not "the window minus the top bar", which put the footer below the fold) */
.page-body:has(> main.hub-main) { display: flex; flex-direction: column; }
main.hub-main { flex: 1 0 auto; display: flex; flex-direction: column; }
.hub { display: grid; grid-template-columns: 260px minmax(0, 1fr); flex: 1 0 auto; }
.hub-rail { background: var(--surface); border-right: 1px solid var(--border); padding: var(--sp-4) var(--sp-3);
  display: flex; flex-direction: column; gap: var(--sp-2); }
.hub-new { width: 100%; }
.hub-search { display: grid; grid-template-columns: 1fr; gap: var(--sp-2); margin: 0; }
.hub-search input, .hub-search select { height: var(--ctl-h-sm); font-size: var(--fs-sm); }
.hub-rail-head { font-size: var(--fs-xs); letter-spacing: .04em; color: var(--muted);
  padding: var(--sp-2) var(--sp-2) 0; display: flex; justify-content: space-between; }
.hub-count { font-size: var(--fs-xs); color: var(--muted); font-weight: 400; }
.hub-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 2px; overflow: auto; }
.hub-list a { display: grid; grid-template-columns: 1fr auto; column-gap: var(--sp-2); padding: 6px var(--sp-2);
  border-radius: var(--radius); color: var(--text); text-decoration: none; }
.hub-list a:hover { background: var(--surface-2); }
.hub-list a.current { background: var(--accent-bg); box-shadow: inset 3px 0 0 var(--accent); }
.hub-item-title { font-weight: 600; font-size: var(--fs-sm); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.hub-item-sub { grid-column: 1; font-size: var(--fs-xs); color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.hub-item-lock { grid-column: 2; grid-row: 1 / span 2; align-self: center; }
.hub-item-lock svg { width: 14px; height: 14px; fill: none; stroke-width: 1.5; }
.hub-item-lock.other svg { stroke: var(--warn); } .hub-item-lock.mine svg { stroke: var(--ok); }
.hub-empty-list { padding: 0 var(--sp-2); }
.hub-panel { padding: var(--sp-5); display: flex; flex-direction: column; gap: var(--sp-4); max-width: 1100px; min-width: 0; }
.hub-panel > .notice, .hub-panel > .error { margin: 0; }
.hub-head { display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; }
.hub-head-text { flex: 1; min-width: 240px; }
.hub-head h1 { margin: 0 0 2px; }
.hub-head form { margin: 0; }
.hub-card { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-card); padding: var(--sp-3) var(--sp-4); min-width: 0; }
.hub-card-head { display: flex; align-items: center; gap: var(--sp-2); margin-bottom: var(--sp-2); }
.hub-card-head h2 { flex: 1; margin: 0; }
.hub-card-head form { margin: 0; }
.hub-it { display: grid; grid-template-columns: 32px minmax(0, 1fr) auto auto; gap: var(--sp-3); align-items: center;
  padding: var(--sp-2) var(--sp-2); border-top: 1px solid var(--border); }
.hub-it.latest { background: var(--surface-2); border-radius: var(--radius); border-top-color: transparent; }
.hub-it form { margin: 0; }
.hub-it-index { color: var(--muted); font-variant-numeric: tabular-nums; text-align: center; }
.hub-it-title { font-weight: 600; }
.hub-it-masts { display: flex; flex-wrap: wrap; gap: var(--sp-1); justify-content: flex-end; max-width: 360px; }
.chip.stale { background: var(--surface-2); color: var(--muted); border-color: var(--border); text-decoration: line-through; }
.hub-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); gap: var(--sp-4); align-items: start; }
.hub-card > summary { list-style: none; cursor: pointer; display: flex; align-items: center; gap: var(--sp-2); }
.hub-card > summary::-webkit-details-marker { display: none; }
.hub-card > summary h2 { margin: 0; }
.hub-card > summary::before { content: ""; border-left: 6px solid var(--muted); border-top: 5px solid transparent;
  border-bottom: 5px solid transparent; transition: transform .15s; }
.hub-card[open] > summary::before { transform: rotate(90deg); }
.hub-card[open] > summary { margin-bottom: var(--sp-2); }
.hub-card dl.facts { margin: 0; font-size: var(--fs-sm); }
.hub-welcome { margin: 10vh auto 0; text-align: center; max-width: 440px; }
.ws-checkout { display: inline-flex; align-items: center; gap: var(--sp-2); margin: 0; }
@media (max-width: 800px) {
  .hub { grid-template-columns: 1fr; }
  .hub-rail { border-right: 0; border-bottom: 1px solid var(--border); }
  .hub-list { max-height: 40vh; }
  .hub-it { grid-template-columns: 24px minmax(0, 1fr) auto; }
  .hub-it-masts { grid-column: 2 / -1; justify-content: flex-start; }
}
.plus { width: 12px; height: 12px; vertical-align: -1px; margin-right: 4px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; }

/* ---- "something is running" (busy.js): a stripe along the top of the window, a spinner in the clicked button */
html.is-busy, html.is-busy * { cursor: progress !important; }
html.is-busy body::before { content: ""; position: fixed; left: 0; top: 0; z-index: 1000; height: 3px; width: 100%;
  background: linear-gradient(90deg, transparent 0, var(--accent) 30%, var(--accent) 60%, transparent 100%);
  background-size: 50% 100%; background-repeat: no-repeat; animation: busy-stripe 1.1s ease-in-out infinite; }
@keyframes busy-stripe { from { background-position: -50% 0; } to { background-position: 150% 0; } }
button.is-busy-btn { position: relative; color: transparent !important; pointer-events: none; }
button.is-busy-btn:disabled { opacity: .8; }
button.is-busy-btn::after { content: ""; position: absolute; left: 50%; top: 50%; width: 14px; height: 14px; margin: -7px 0 0 -7px;
  border-radius: 50%; border: 2px solid var(--accent-text); border-right-color: transparent; animation: busy-spin .7s linear infinite; }
button.secondary.is-busy-btn::after, button.tool.is-busy-btn::after, button.danger.is-busy-btn::after { border-color: var(--accent); border-right-color: transparent; }
@keyframes busy-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  html.is-busy body::before { animation: none; background: var(--accent); opacity: .6; }
  button.is-busy-btn::after { animation-duration: 2s; }
}
/* the hub's site plan preview (_hub_site.html) */
.hub-site { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: var(--sp-3); }
.hub-site-form { margin: 0; display: grid; gap: var(--sp-1); }
button.hub-site-thumb { position: relative; display: block; width: 100%; height: auto; max-height: 260px; padding: 0; line-height: 0;
  background: var(--stage-bg); border: 1px solid var(--border); border-radius: var(--radius); overflow: hidden; }
button.hub-site-thumb:hover:not(:disabled) { border-color: var(--accent); filter: none; box-shadow: 0 0 0 2px var(--accent-bg); }
.hub-site-thumb img, .hub-site-thumb svg { position: absolute; inset: 0; width: 100%; height: 100%; }
.hub-site-thumb img { object-fit: fill; }
.hub-site-wire { fill: none; stroke: var(--pic-red); stroke-width: 2.5; vector-effect: non-scaling-stroke; }
.hub-site-mast { fill: var(--pic-blue); stroke: var(--pic-halo); stroke-width: 2; vector-effect: non-scaling-stroke; }
.hub-site-label { fill: var(--pic-ink-2); font-weight: 700; paint-order: stroke; stroke: var(--pic-halo); stroke-width: 3px; vector-effect: non-scaling-stroke;
  font-family: system-ui, sans-serif; }
.hub-site-none { margin: 0; }

/* pictures in the dark scheme: inverted with their hues kept and blended into the background, so the
   white paper of a drawing disappears; "original colours" (photo toolbar, per browser) turns it off -
   for real photographs */
.photo-canvas img, .hub-site-thumb img { filter: var(--pic-filter); mix-blend-mode: var(--pic-blend); }
.pic-toggle { display: var(--pic-toggle); }
:root[data-pic="original"] { --pic-filter: none; --pic-blend: normal; --pic-toggle: none; --pic-ink: #000000; --pic-ink-2: #1a1a1a; --pic-halo: #ffffff;
  --pic-plot: #202124; --pic-muted: #80868b; --pic-blue: #36497b; --pic-red: #d93025; --pic-fill: #ffffff; --pic-green: #188038; --pic-toggle: inline-block; }
:root[data-theme="light"] { --pic-toggle: none; }
/* a pressed toggle keeps its colours under the mouse (the secondary hover rule is more specific) */
button[aria-pressed="true"]:hover:not(:disabled), button.active:hover:not(:disabled) {
  background: var(--accent); color: var(--accent-text); border-color: var(--accent); filter: brightness(1.08); }
/* the hub's mast images: tall pictures side by side, all the same height */
.hub-masts { grid-template-columns: repeat(auto-fill, minmax(96px, max-content)); align-items: start; }
.hub-mast-form button.hub-site-thumb { height: 240px; width: auto; max-width: 100%; max-height: none; }
.hub-mast-axis { stroke: var(--pic-blue); stroke-width: 2; stroke-dasharray: 6 4; vector-effect: non-scaling-stroke; }
/* the public report verification page (verify.html) */
.verify-row { display: flex; gap: var(--sp-2); }
.verify-row input { font-family: ui-monospace, Consolas, monospace; letter-spacing: .08em; text-transform: uppercase; }
.verify-result { margin: var(--sp-4) 0; padding: var(--sp-3) var(--sp-4); border-radius: var(--radius); border: 1px solid; }
.verify-result.ok { background: var(--ok-bg); color: var(--ok-text); border-color: var(--ok-line); }
.verify-result.bad { background: var(--error-bg); color: var(--error-text); border-color: var(--bad-line); }
.verify-result .sub { color: inherit; opacity: .85; margin-top: 2px; }
.verify dl.facts { font-size: var(--fs-sm); }
/* the demo banner's licence request; the admin area */
.demo-banner { display: flex; align-items: center; gap: var(--sp-3); flex-wrap: wrap; }
.demo-banner > span:first-child { flex: 1; }
.demo-banner form { margin: 0; }
.admin-decide { display: inline-flex; gap: var(--sp-1); align-items: center; margin: 0 var(--sp-1) 0 0; }
.admin-decide select { width: auto; height: var(--ctl-h-sm); font-size: var(--fs-sm); }
.admin-decide input[type=text] { width: 4.5em; height: var(--ctl-h-sm); font-size: var(--fs-sm); }
table.list td.num, table.list th.num { text-align: right; font-variant-numeric: tabular-nums; }
.admin-usage-wrap { max-height: none; border: 0; }
.topbar .nav .chip { margin-left: 2px; }

/* ---- the photo page's ribbon (photo.html): named groups Edit / View / Picture / Results / Save ------------ */
.pw-toolbar.ribbon { display: flex; flex-wrap: wrap; align-items: stretch; gap: 0; padding: 0; min-height: 0; }
.ribbon .rb-head { display: flex; flex-direction: column; justify-content: center; padding: var(--sp-2) var(--sp-3);
  border-right: 1px solid var(--border); min-width: 0; }
.ribbon .rb-head .pw-title { margin: 0; }
.ribbon .rb-head .muted { font-size: var(--fs-sm); }
.ribbon .rb-group { display: flex; flex-direction: column; justify-content: space-between; gap: var(--sp-1);
  padding: var(--sp-2) var(--sp-3) 3px; border-right: 1px solid var(--border); margin: 0; }
.ribbon .rb-row { display: flex; align-items: center; gap: var(--sp-1); }
.ribbon .rb-cap { font-size: var(--fs-xs); line-height: 1.2; color: var(--muted); text-align: center; letter-spacing: .03em; white-space: nowrap; }
.ribbon .rb-results { background: var(--surface-2); }
.ribbon .rb-save { margin-left: auto; border-right: 0; border-left: 1px solid var(--border); }
/* the three modes: one segmented control, exactly one pressed */
.ribbon .rb-seg { gap: 0; }
.ribbon .rb-seg button { border-radius: 0; margin-left: -1px; }
.ribbon .rb-seg button:first-child { border-radius: var(--radius) 0 0 var(--radius); margin-left: 0; }
.ribbon .rb-seg button:last-child { border-radius: 0 var(--radius) var(--radius) 0; }
.ribbon .rb-seg button[aria-pressed="true"] { position: relative; z-index: 1; }
/* icons */
.ribbon .rb-ico { width: 14px; height: 14px; vertical-align: -2px; margin-right: 5px; fill: none; stroke: currentColor;
  stroke-width: 1.4; stroke-linecap: round; stroke-linejoin: round; }
.ribbon .rb-ico .rb-fill { fill: currentColor; stroke: none; }
.ribbon button.icon .rb-ico { margin: 0; }
.ribbon .pw-ref label { font-size: var(--fs-sm); color: var(--muted); font-weight: 400; margin: 0; }
.ribbon .pw-ref input { width: 4.5em; }
/* save: the arrow opens "save as new iteration" (works without JavaScript) */
.ribbon .rb-more { position: relative; }
.ribbon .rb-more > summary { list-style: none; display: inline-flex; align-items: center; justify-content: center; cursor: pointer;
  width: var(--ctl-h-sm); height: var(--ctl-h-sm); border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--surface); color: var(--text); }
.ribbon .rb-more > summary::-webkit-details-marker { display: none; }
.ribbon .rb-more > summary:hover { border-color: var(--accent); color: var(--accent); }
.ribbon .rb-more[open] > summary { background: var(--accent-bg); }
.ribbon .rb-more .rb-menu { position: absolute; right: 0; top: calc(100% + 4px); z-index: 20; padding: var(--sp-1);
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); box-shadow: var(--shadow); }
.ribbon .rb-more .rb-menu button { white-space: nowrap; }
/* narrow windows: captions go, groups wrap as whole blocks */
@media (max-width: 1180px) {
  .ribbon .rb-cap { display: none; }
  .ribbon .rb-group { padding-bottom: var(--sp-2); }
  .ribbon .rb-head { display: none; }
}
/* the title repeats the breadcrumb and the step tabs - only on very wide screens */
.ribbon .rb-group { padding-left: 10px; padding-right: 10px; }
@media (max-width: 1700px) { .ribbon .rb-head { display: none; } }
/* the 3D pages (model3d, structures, OCL parts) keep their head: it holds the back button and the downloads - only
   the title and its sub-line go on narrower screens (1.30.0, owner: "the back button seems to be missing") */
.ribbon.m3d-bar .rb-head { display: flex; }
@media (max-width: 1700px) { .ribbon.m3d-bar .rb-head .pw-title, .ribbon.m3d-bar .rb-head > .muted { display: none; } }
/* hub: the panel uses the full width like the other pages; wide tables scroll inside their card */
.hub-panel { max-width: none; }
.hub-grid { grid-template-columns: repeat(auto-fill, minmax(360px, 1fr)); }
.hub-card { overflow-x: auto; }
.hub-card table.list { min-width: 100%; }
.hub-card table.list td form { margin: 0; }
/* admins: "texts of this page" and the text editor (admin_texts.html) */
.admin-texts-link { position: fixed; right: var(--sp-4); bottom: var(--sp-4); z-index: 50; font-size: var(--fs-xs);
  padding: 4px 10px; border-radius: var(--radius-pill); background: var(--surface); border: 1px solid var(--border); color: var(--muted);
  text-decoration: none; box-shadow: var(--shadow); opacity: .75; }
.admin-texts-link:hover { opacity: 1; color: var(--accent); border-color: var(--accent); }
@media print { .admin-texts-link { display: none; } }
table.texts-edit td { vertical-align: top; }
table.texts-edit td.texts-key { max-width: 16em; word-break: break-all; }
table.texts-edit textarea { width: 100%; min-width: 12em; font: inherit; font-size: var(--fs-sm); padding: 4px 6px;
  border: 1px solid var(--border); border-radius: var(--radius); background: var(--input-bg); color: var(--text); resize: vertical; }
table.texts-edit textarea.empty { background: var(--missing-bg); }
table.texts-edit tr.missing td { background: var(--notice-bg); }
table.texts-edit tr.just-saved td { background: var(--ok-bg); }
table.texts-edit td form { margin: 0; }
.filters input[type=checkbox] { min-width: 0; width: auto; height: auto; }
.filters label.check { display: inline-flex; align-items: center; gap: var(--sp-1); font-size: var(--fs-sm); margin: 0; }
.topbar a.who { color: var(--muted); text-decoration: none; }
.topbar a.who:hover { color: var(--accent); }
.login-forgot { display: block; width: 100%; }
.temp-password { font-family: ui-monospace, Consolas, monospace; font-size: var(--fs-lg); letter-spacing: .1em; }
/* footer: imprint + privacy on every page (not in the workspace: the photo area fills the window there) */
.site-footer { display: flex; gap: var(--sp-4); justify-content: center; flex-wrap: wrap; padding: var(--sp-4);
  font-size: var(--fs-xs); color: var(--muted); }
.site-footer a { color: var(--muted); text-decoration: none; }
.site-footer a:hover { color: var(--accent); text-decoration: underline; }
body.has-ws .site-footer { display: none; }
.register-privacy { margin-top: var(--sp-3); }
/* the legal pages */
.card.legal { max-width: 820px; margin: 0 auto; line-height: 1.6; }
.card.legal h2 { margin-top: var(--sp-5); }
.card.legal ul { padding-left: 1.2em; }
/* fixed field widths (were inline style="width: ..." in masts.html / photo.html) */
table.parts.masts input.w-name[type=text] { width: 8em; }
table.parts.masts input.w-num[type=text] { width: 5.5em; }
table.parts.masts input.w-short[type=text] { width: 5em; }
table.parts.masts select.w-mat { width: 7em; }
table.parts.masts select.w-slope { width: 11em; }
input.w-page[type=number] { width: 5em; }
/* the axes note (_axes_note.html): global right-handed axes and the AxisVM mapping, folded by default */
.axes-note { margin-top: var(--sp-3); font-size: var(--fs-sm); }
.axes-note > summary { cursor: pointer; color: var(--muted); display: flex; align-items: center; gap: var(--sp-2); }
.axes-note > summary:hover { color: var(--accent); }
.axes-note p { margin: var(--sp-2) 0 0; }
.axes-ico { width: var(--ctl-h); height: var(--ctl-h); flex: none; fill: none; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.axes-ico text { stroke: none; font-size: var(--fs-xs); font-weight: 600; }
.axes-ico .ax-x { stroke: var(--axis-x); } .axes-ico text.ax-x { fill: var(--axis-x); }
.axes-ico .ax-y { stroke: var(--axis-y); } .axes-ico text.ax-y { fill: var(--axis-y); }
.axes-ico .ax-z { stroke: var(--axis-z); } .axes-ico text.ax-z { fill: var(--axis-z); }
table.axes-map { border-collapse: collapse; margin-top: var(--sp-2); font-variant-numeric: tabular-nums; }
table.axes-map th, table.axes-map td { padding: var(--sp-1) var(--sp-2); border-bottom: 1px solid var(--border); text-align: center; }
table.axes-map th:first-child { text-align: left; font-weight: 400; color: var(--muted); }
table.axes-map thead th { font-size: var(--fs-xs); color: var(--muted); font-weight: 600; }
/* new project: Excel-like searchable line list and "where the km lies" (line-pick.js) */
.line-search { margin-bottom: var(--sp-1); }
select.line-list { height: auto; padding: var(--sp-1) 0; }
select.line-list option { padding: var(--sp-1) var(--sp-2); }
.km-place { min-height: 1.5em; margin: var(--sp-1) 0 0; }
.km-place.err { color: var(--error-text); }
/* the product logo left of the name in the top bar: transparent PNG; the dark scheme swaps to the reversed
   version (navy -> light), since the navy ink would vanish on a dark bar */
.topbar .brand { display: inline-flex; align-items: center; gap: var(--sp-2); }
.brand-logo { height: var(--brand-logo-h, var(--ctl-h)); width: auto; }
.brand-logo.logo-light { display: var(--logo-light); }
.brand-logo.logo-dark { display: var(--logo-dark); }
.brand-logo.logo-auto-dark { filter: invert(1) hue-rotate(180deg); }   /* 1.55.0: the dark logo made from the light one */
/* "Meine Lizenz" (account.html): how much of the plan is used - ok / warn (from 80 %) / over (100 %) */
.licence-card { margin-top: var(--sp-4); }
.licence-use { display: flex; align-items: center; gap: var(--sp-3); margin: var(--sp-2) 0 var(--sp-3); }
.licence-bar { flex: 1; height: var(--sp-2); border-radius: var(--radius-pill); background: var(--surface-2);
  border: 1px solid var(--border); overflow: hidden; }
.licence-bar > span { display: block; height: 100%; background: var(--ok); }
.licence-use.warn .licence-bar > span { background: var(--warn); }
.licence-use.over .licence-bar > span { background: var(--bad); }
.licence-pct { font-size: var(--fs-sm); font-variant-numeric: tabular-nums; white-space: nowrap; }
/* the help centre (help.html, help_manual.html; release 1.1.0): the hub's rail-and-panel layout, the
   legal pages' card; the top bar's "?" is an icon button-link */
.topbar a.help-link { width: var(--ctl-h-sm); padding: 0; display: inline-flex; align-items: center; justify-content: center; }
.topbar a.help-link svg { width: 15px; height: 15px; fill: none; stroke: currentColor; stroke-width: 1.5;
  stroke-linecap: round; stroke-linejoin: round; }
.topbar a.help-link svg .fill { fill: currentColor; stroke: none; }
.help-article ol, .help-article ul, .help-toc ol { padding-left: 1.2em; }
.help-article li + li { margin-top: var(--sp-1); }
.help-article h3 { margin-top: var(--sp-4); }
.help-pager { display: flex; justify-content: space-between; gap: var(--sp-3); margin-top: var(--sp-5);
  padding-top: var(--sp-3); border-top: 1px solid var(--border); }
.help-hits { list-style: none; padding: 0; margin: 0; display: grid; gap: var(--sp-3); }
.help-hits p { margin: var(--sp-1) 0 0; }
@media print {
  .topbar, .site-footer, .no-print { display: none; }
  .help-manual { border: 0; padding: 0; max-width: none; }
  .help-manual .help-article { break-before: page; }
  .help-manual h2, .help-manual h3, .help-manual h4 { break-after: avoid; }
}
/* the 3D view of a calculated mast (model3d.html, fem3d.js; release 1.2.0) - drawn from tokens only, x / y / z
   in the axis colours as everywhere; the mast image follows the pictures' dark-scheme inversion */
.m3d-bar { margin-bottom: var(--sp-3); }
.m3d-variant { margin: 0; display: flex; align-items: center; gap: var(--sp-1); }
.m3d-body { display: grid; grid-template-columns: minmax(0, 1fr) 300px; gap: var(--sp-4); align-items: start; }
.m3d-stage { background: var(--stage-bg); border: 1px solid var(--border); border-radius: var(--radius); overflow: hidden; }
.m3d-svg { display: block; width: 100%; height: 72vh; touch-action: none; cursor: grab; user-select: none; }
.m3d-svg:active { cursor: grabbing; }
.m3d-legend p { margin: var(--sp-1) 0; }
.f3d-el { fill: none; stroke: var(--text); stroke-width: 2.5; stroke-linecap: round; stroke-linejoin: round; }
.f3d-rigid { stroke: var(--muted); stroke-width: 1.5; stroke-dasharray: 4 3; }
.f3d-link { stroke: var(--muted); stroke-width: 1.5; stroke-dasharray: 8 3 2 3; }
.f3d-ghost .f3d-el { stroke: var(--faint); stroke-width: 1; }
.f3d-support { fill: var(--surface); stroke: var(--text); stroke-width: 1.5; }
.f3d-x { color: var(--axis-x); stroke: var(--axis-x); }
.f3d-y { color: var(--axis-y); stroke: var(--axis-y); }
.f3d-z { color: var(--axis-z); stroke: var(--axis-z); }
.f3d-n { color: var(--text); stroke: var(--text); }
.f3d-arrow { fill: none; stroke-width: 2; stroke-linecap: round; }
.f3d-q.f3d-arrow { stroke-width: 1.2; }
.f3d-head, .f3d-dot { fill: currentColor; stroke: none; }
.f3d-endon { fill: var(--surface); stroke-width: 1.5; }
.f3d-fill { fill: currentColor; fill-opacity: .18; stroke: none; }
.f3d-line { fill: none; stroke-width: 1.8; }
.f3d-label { fill: currentColor; stroke: var(--stage-bg); stroke-width: 3; paint-order: stroke; font-weight: 600; }
.f3d-triad .f3d-label { font-weight: 400; }
.f3d-image { filter: var(--pic-filter); mix-blend-mode: var(--pic-blend); opacity: .85; }
@media (max-width: 900px) { .m3d-body { grid-template-columns: 1fr; } .m3d-svg { height: 60vh; } }
/* 1.22.0 - the structure designer's 3D view (structure3d.js, WebGL): the stage holds the canvas + the axis symbol */
.s3d-stage { position: relative; height: 72vh; }
.s3d-canvas { display: block; width: 100%; height: 100%; touch-action: none; cursor: grab; outline: none; }
.s3d-canvas:active { cursor: grabbing; }
.s3d-canvas:focus-visible { box-shadow: inset 0 0 0 2px var(--accent); }
.s3d-triad { position: absolute; left: var(--sp-2); bottom: var(--sp-2); width: 60px; height: 60px; pointer-events: none; }
/* 1.29.0 - member labels over the 3D view (structure3d.js), and the fit / labels buttons */
.s3d-labels { position: absolute; inset: 0; pointer-events: none; overflow: hidden; }
.s3d-label { position: absolute; white-space: pre; font-size: var(--fs-xs); line-height: 14px; padding: 0 var(--sp-1);
  background: var(--surface); color: var(--text); border: 1px solid var(--border); border-radius: var(--radius-sm);
  opacity: 0.92; font-variant-numeric: tabular-nums; }
.s3d-label.is-sel { border-color: var(--accent); background: var(--accent-bg); opacity: 1; }
.s3d-side h3 { margin-top: var(--sp-3); }
.s3d-sections td, .s3d-sections th { font-size: var(--fs-sm); }
.s3d-checks { max-height: 180px; overflow: auto; }
.s3d-import { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); }
@media (max-width: 900px) { .s3d-stage { height: 60vh; } }
/* 1.25.0 - the structure editor: the preview a bit lower, the parameters in a card below it */
.s3d-stage-edit { height: 55vh; }
.s3d-editor { margin-top: var(--sp-4); }
.s3d-general { display: flex; flex-wrap: wrap; gap: var(--sp-3); align-items: end; }
.s3d-general label { display: flex; flex-direction: column; gap: var(--sp-1); font-size: var(--fs-sm); color: var(--muted); }
.s3d-general input[type=text] { width: 9rem; }
.s3d-general input[data-top=name] { width: 18rem; }
.s3d-segments td { padding: var(--sp-1); }
.s3d-segments .s3d-numin { width: 5rem; }
.s3d-segments .s3d-sec { width: 8.5rem; }
.s3d-rowtools { white-space: nowrap; }
.s3d-editor-actions { margin-top: var(--sp-3); }
/* structure editor 1.27.0: a segment's member groups (folded under its row), station overrides, the cut at a station */
tbody.s3d-seg + tbody.s3d-seg { border-top: 1px solid var(--border); }
.s3d-grprow > td { background: var(--surface-2); }
.s3d-groups { width: auto; margin: var(--sp-1) 0 var(--sp-2); }
.s3d-groups td, .s3d-groups th, .s3d-overrides td, .s3d-overrides th { padding: var(--sp-1); font-size: var(--fs-sm); }
.s3d-groups .s3d-numin, .s3d-overrides .s3d-numin { width: 5rem; }
.s3d-groups .s3d-sec, .s3d-overrides .s3d-sec { width: 8.5rem; }
.s3d-groups select, .s3d-overrides select { width: auto; max-width: 16rem; }
.s3d-station-pick { display: flex; align-items: center; gap: var(--sp-2); font-size: var(--fs-sm); color: var(--muted); }
.s3d-station-svg { display: block; width: 100%; height: 100%; }
/* structure editor 1.29.0, the workspace: the 3D view stays in place (sticky) beside the inspector; the cut inset in
   the 3D view's corner; the segment strip; inspector tabs; the contact badges */
.s3d-general { margin-bottom: var(--sp-3); }
.s3d-general-save { margin-left: auto; }
.s3d-work { display: grid; grid-template-columns: minmax(0, 1.4fr) minmax(340px, 1fr); gap: var(--sp-3); align-items: start; }
.s3d-left { position: sticky; top: var(--sp-2); display: flex; flex-direction: column; gap: var(--sp-2); }
.s3d-stage-wrap { position: relative; }
.s3d-stage-wrap .s3d-stage-edit { height: 60vh; }
.s3d-cut { position: absolute; right: var(--sp-2); bottom: var(--sp-2); width: 32%; min-width: 150px; max-width: 260px;
  height: 42%; margin: 0; padding: var(--sp-1); display: flex; flex-direction: column; background: var(--surface);
  border: 1px solid var(--border); border-radius: var(--radius-sm); pointer-events: none; }
.s3d-cut figcaption { font-size: var(--fs-sm); }
.s3d-cut .s3d-station-svg { flex: 1; min-height: 0; }
.s3d-nav { display: flex; flex-direction: column; gap: var(--sp-2); padding: var(--sp-2) var(--sp-3); }
.s3d-nav p { margin: 0; }
.s3d-strip { display: flex; flex-wrap: wrap; gap: var(--sp-1); }
.s3d-stripseg { flex: 1 1 auto; font-size: var(--fs-sm); }
.s3d-stripseg[aria-pressed=true] { background: var(--accent-bg); border-color: var(--accent); color: var(--text); }
.s3d-station-pick input[type=range] { flex: 1; }
.s3d-station-pick output { min-width: 5rem; font-weight: 600; color: var(--text); }
.s3d-right { display: flex; flex-direction: column; gap: var(--sp-3); min-width: 0; }
.s3d-tabs { margin-bottom: var(--sp-2); }
.s3d-tabs [aria-selected=true] { background: var(--accent-bg); border-color: var(--accent); color: var(--text); }
.s3d-insp-head { margin: 0 0 var(--sp-2); }
.s3d-inspector h4 { margin: var(--sp-3) 0 var(--sp-1); font-size: var(--fs-sm); }
.s3d-inspector .s3d-groups { width: 100%; margin: 0; }
.s3d-inspector .table-scroll { max-height: none; overflow-y: visible; }
.s3d-inspector .s3d-groups .s3d-sec { width: 7.5rem; }
.s3d-inspector .s3d-groups .s3d-numin { width: 4rem; }
.s3d-gsub th { text-align: left; font-weight: 400; color: var(--muted); padding-top: var(--sp-2); }
.s3d-gname { cursor: pointer; white-space: nowrap; }
.s3d-groups tr.is-sel td { background: var(--accent-bg); }
.s3d-diag { display: flex; align-items: center; gap: var(--sp-2); margin-top: var(--sp-2); font-size: var(--fs-sm); }
.s3d-diag input { width: 7.5rem; }
.s3d-diag-roll { display: flex; align-items: center; gap: var(--sp-1); }
.s3d-diag-roll input { width: 4rem; }
.s3d-insp-actions { margin-top: var(--sp-3); }
.s3d-fields { display: grid; grid-template-columns: repeat(auto-fill, minmax(9rem, 1fr)); gap: var(--sp-2); }
.s3d-fields label { display: flex; flex-direction: column; gap: var(--sp-1); font-size: var(--fs-sm); color: var(--muted); }
.s3d-fields input, .s3d-fields select { width: 100%; }
.s3d-badge { display: inline-block; padding: 0 var(--sp-1); border-radius: var(--radius-sm); font-size: var(--fs-sm); line-height: 1.5; }
.s3d-badge.ok { background: var(--ok-bg); color: var(--ok-text); }
.s3d-badge.bad { background: var(--error-bg); color: var(--error-text); }
.s3d-badge.warn { background: var(--notice-bg); color: var(--notice-text); }
.s3d-gaps li { margin: var(--sp-1) 0; }
.s3d-drawer { margin-top: var(--sp-3); }
.s3d-drawer > summary { cursor: pointer; font-weight: 600; }
/* 1.29.0 (milestone 3b): the loads tab - line loads beside the computed values, the class preview, the load cases */
.s3d-loadtable { width: 100%; margin-top: var(--sp-2); }
.s3d-loadtable td, .s3d-loadtable th { padding: var(--sp-1); font-size: var(--fs-sm); }
.s3d-loadtable input { width: 5rem; }
/* 1.29.0 - mast types: the picker, the drawing's notice, the foot & head tab */
.s3d-typepick { display: flex; flex-wrap: wrap; align-items: flex-end; gap: var(--sp-2); margin-top: var(--sp-2); }
.s3d-typepick label { display: flex; flex-direction: column; gap: var(--sp-1); font-size: var(--fs-sm); color: var(--muted); }
.s3d-typepick select { min-width: min(28rem, 100%); max-width: 100%; }
.s3d-typeinfo ul { margin: var(--sp-1) 0 0; }
.s3d-parts-box { margin-top: var(--sp-3); padding-top: var(--sp-2); border-top: 1px solid var(--border); }
.s3d-parts-sub { margin: var(--sp-2) 0 var(--sp-1); font-size: var(--fs-sm); color: var(--muted); }
.s3d-parts { width: 100%; }
.s3d-parts td, .s3d-parts th { padding: var(--sp-1); font-size: var(--fs-sm); white-space: nowrap; }
.s3d-parts input.s3d-numin { width: 4.5rem; }
.s3d-parts select { max-width: 9rem; }
.s3d-parts-support { display: flex; align-items: center; gap: var(--sp-1); font-size: var(--fs-sm); }
.s3d-classes, .s3d-cases { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-1); margin-top: var(--sp-2); }
.s3d-classes [aria-pressed=true], .s3d-cases [aria-pressed=true] { background: var(--accent-bg); border-color: var(--accent); color: var(--text); }
.s3d-loads-fields { display: flex; flex-wrap: wrap; gap: var(--sp-3); align-items: end; margin-bottom: var(--sp-3); }
.s3d-loads-fields label { display: flex; flex-direction: column; gap: var(--sp-1); font-size: var(--fs-sm); color: var(--muted); }
/* 1.30.0, DESIGN_RULES §3a: the folded general values and drawing notice; on a laptop and up the workspace fits the
   window - the 3D view takes the height left, the inspector scrolls in its own column (structure_editor.js sets
   --s3d-h exactly) */
.s3d-fold > summary { cursor: pointer; }
.s3d-fold[open] > summary { margin-bottom: var(--sp-2); }
details.s3d-typeinfo { margin-bottom: var(--sp-3); }
@media (min-width: 1000px) and (min-height: 620px) {
  body.s3d-fit .site-footer { display: none; }
  /* an open fold may make the page scroll on a small laptop: the toolbar (back, AxisVM, Save) stays in sight */
  body.s3d-fit .pw-toolbar { position: sticky; top: 0; z-index: 5; }
  body.s3d-fit .s3d-editor { margin-top: var(--sp-2); }
  body.s3d-fit .s3d-fold { margin-bottom: var(--sp-2); padding-top: var(--sp-2); padding-bottom: var(--sp-2); }
  body.s3d-fit .s3d-work { --s3d-h: calc(100dvh - 300px); height: var(--s3d-h); align-items: stretch; }
  body.s3d-fit .s3d-left { position: static; min-height: 0; }
  body.s3d-fit .s3d-stage-wrap { flex: 1 1 0; min-height: 0; }
  body.s3d-fit .s3d-stage-wrap .s3d-stage-edit { height: 100%; }
  body.s3d-fit .s3d-nav, body.s3d-fit #s3d-status { flex: none; margin: 0; }
  body.s3d-fit .s3d-right { min-height: 0; overflow-y: auto; }
  body.s3d-fit .s3d-right > .card { flex: none; margin: 0; }
  body.s3d-fit .s3d-drawer { margin-top: var(--sp-2); }
  body.s3d-fit .s3d-drawer[open] { max-height: 35dvh; overflow: auto; padding-top: 0; }
  body.s3d-fit .s3d-drawer[open] > summary { position: sticky; top: 0; z-index: 2; background: var(--surface);
    padding: var(--sp-2) 0; }
}
@media (max-width: 1000px) {
  .s3d-work { grid-template-columns: minmax(0, 1fr); }
  .s3d-left { position: static; }
  .s3d-stage-wrap .s3d-stage-edit { height: 50vh; }
}
.st-chord { fill: var(--muted); fill-opacity: .35; stroke: var(--text); }
.st-member { fill: var(--accent); fill-opacity: .45; stroke: var(--accent); }
.st-member.st-bad { fill: var(--bad); stroke: var(--bad); }
.st-rigid { stroke: var(--text); stroke-dasharray: 3 2; }
.st-node { fill: var(--surface); stroke: var(--text); stroke-width: .6; }
.st-chordnode { fill: var(--text); }
/* 1.29.0 (owner): the group row being edited, highlighted in the cut; the chords' names */
.st-chord.st-hl, .st-member.st-hl { fill: var(--accent); fill-opacity: .9; stroke: var(--accent); }
.st-label { fill: var(--text); }
.s3d-memberkey { grid-column: 1 / -1; }
/* 3D view, v1.2 additions: diagrams as on the photo (value-coloured strips - the colours are data, set by
   fem3d.js), value labels, the cross-section, and the selected support */
.f3d-strip { fill-opacity: .55; stroke-width: .5; }
.f3d-line { stroke: var(--text); stroke-width: 1.6; }
.f3d-max, .f3d-val { color: var(--text); }
.f3d-val { font-weight: 400; }
.f3d-section { fill: var(--surface-2); fill-opacity: .7; stroke: var(--muted); stroke-width: 1; }
.f3d-section-edge { stroke: var(--muted); stroke-width: .8; }
.f3d-support { cursor: pointer; }
.f3d-support.f3d-selected { stroke: var(--accent); stroke-width: 2.5; }
.f3d-ring { fill: none; stroke: var(--accent); stroke-width: 2; }
.f3d-reaction.f3d-arrow { stroke-width: 2.6; }
.m3d-support table { width: 100%; border-collapse: collapse; font-size: var(--fs-sm); }
.m3d-support td { padding: var(--sp-1); border-bottom: 1px solid var(--border); }
.m3d-support td.num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
/* 3D view (2026-09-28): an element with its own result (the anchor) - clickable; tension / compression */
.f3d-selected-el { stroke: var(--accent); stroke-width: 3.5; stroke-dasharray: none; }
.f3d-tension { color: var(--tension); stroke: var(--tension); }
.f3d-compression { color: var(--compression); stroke: var(--compression); }
/* a label keeps its halo: only the text takes the tension / compression colour (was a blue / red blob) */
.f3d-label.f3d-tension, .f3d-label.f3d-compression { stroke: var(--stage-bg); }
.m3d-state-tension { color: var(--tension); font-weight: 600; }
.m3d-state-compression { color: var(--compression); font-weight: 600; }
/* the error register (admin_errors.html) */
.error-entry + .error-entry { margin-top: var(--sp-2); }
.error-trace { font-size: var(--fs-xs); white-space: pre-wrap; overflow-x: auto; background: var(--code-bg); padding: var(--sp-2);
  border-radius: var(--radius); }
/* accessibility (WCAG check 2026-09-28): the skip link - off-screen until a keyboard user tabs to it */
.skip-link { position: absolute; left: var(--sp-2); top: -40px; z-index: 1100; padding: var(--sp-2) var(--sp-3);
  background: var(--accent); color: var(--accent-text); border-radius: var(--radius); text-decoration: none; }
.skip-link:focus { top: var(--sp-2); }
main:focus { outline: none; }

/* 1.6.0 - the first-run experience (onboarding.py): the hub's checklist, the one-line hint on every page,
   and empty states that say what to do next */
.onboarding { border-left: 3px solid var(--accent); }
.onb-head { display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; }
.onb-head h2 { margin: 0; }
.onb-head .sp, .onb-hint .sp { flex: 1; }
.onb-bar { height: 6px; border-radius: var(--radius-pill); background: var(--surface-2); margin: var(--sp-3) 0; overflow: hidden; }
.onb-fill { display: block; height: 100%; background: var(--accent); transition: width .3s; }
.onb-steps { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--sp-2); }
.onb-steps li { display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-2) var(--sp-3);
                border-radius: var(--radius); }
.onb-steps li.current { background: var(--accent-bg); }
.onb-steps li.done .onb-text strong { color: var(--muted); text-decoration: line-through; }
.onb-mark { flex: none; width: 24px; height: 24px; border-radius: 50%; display: inline-flex; align-items: center;
            justify-content: center; font-size: var(--fs-sm); border: 1px solid var(--border); color: var(--muted); }
.onb-steps li.current .onb-mark { border-color: var(--accent); color: var(--accent-text); background: var(--accent); }
.onb-steps li.done .onb-mark { border-color: var(--ok-line); background: var(--ok-bg); color: var(--ok-text); }
.onb-text { flex: 1; display: flex; flex-direction: column; gap: var(--sp-1); }
.onb-hint { display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; padding: var(--sp-2) var(--sp-3);
            margin: 0 0 var(--sp-3); border: 1px solid var(--info-line); border-radius: var(--radius); background: var(--surface); }
.onb-hint form { margin: 0; }
.empty-state { padding: var(--sp-4); border: 1px dashed var(--border); border-radius: var(--radius); text-align: center; }
.empty-state p { margin: var(--sp-1) 0; }
@media print { .onb-hint, .onboarding { display: none; } }

/* 1.8.0 - Correx (gui_correx.py): the drawing with its stamps, the panel beside it. The stamps' own look is
   correx_pdf.CSS (shared with the PDF) */
.cx { display: grid; grid-template-columns: minmax(0, 1fr) 300px; gap: var(--sp-3); align-items: start; }
@media (max-width: 900px) { .cx { grid-template-columns: minmax(0, 1fr); } }
.cx-scroll { overflow: auto; max-height: 78vh; border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface-2); }
.cx-stage { position: relative; overflow: hidden; background: var(--paper); }
.cx-tools { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin-bottom: var(--sp-2); }
.cx-group { display: inline-flex; gap: var(--sp-1); padding-right: var(--sp-2); border-right: 1px solid var(--border); }
.cx-group:last-child { border-right: 0; }
.cx-tools svg { width: 16px; height: 16px; fill: none; stroke: currentColor; stroke-width: 1.6; }
.cx-tools button[aria-pressed="true"] { border-color: var(--accent); color: var(--accent); }
#cx-layer .cx-handle { position: absolute; width: 8pt; height: 8pt; background: var(--accent); border: 1pt solid var(--paper);
  cursor: nwse-resize; touch-action: none; }
.cx-stage canvas { display: block; }
#cx-layer { position: absolute; left: 0; top: 0; transform-origin: 0 0; }
#cx-layer .cx-stamp { cursor: move; touch-action: none; }
#cx-layer .cx-stamp.sel { outline: 2px dashed var(--accent); outline-offset: 2px; }
.cx-panel h3 { margin: var(--sp-4) 0 var(--sp-2); }
.cx-row { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: var(--sp-2); align-items: center; margin: var(--sp-2) 0; }
.cx-upload { display: grid; gap: var(--sp-2); margin-bottom: var(--sp-3); }
.cx-gen, .cx-texts { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--sp-1); }
.cx-gen li, .cx-texts li { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-2); }
.cx-texts { max-height: 320px; overflow: auto; margin: var(--sp-2) 0; }
.cx-texts li { font-size: var(--fs-sm); padding: var(--sp-1) 0; border-bottom: 1px solid var(--border); }
.cx-swatches { display: inline-flex; gap: var(--sp-1); flex: none; }
.cx-swatch { width: 20px; height: 20px; min-width: 20px; padding: 0; border-radius: var(--radius-sm); border: 1px solid var(--border); }
.cx-swatch.on { outline: 2px solid var(--accent); outline-offset: 1px; }
.cx-selected textarea { width: 100%; }

/* 1.9.1 - the stamp texts per company (correx_texts.html) */
.cx-textrow { display: grid; grid-template-columns: 180px minmax(0, 1fr) 80px 80px auto; gap: var(--sp-2); align-items: start;
  padding: var(--sp-3) 0; border-bottom: 1px solid var(--border); }
.cx-textrow label { display: grid; gap: var(--sp-1); font-size: var(--fs-sm); }
.cx-textrow textarea { width: 100%; }
.cx-textrow .actions { grid-column: 1 / -1; margin: 0; }
.cx-textrow.readonly { grid-template-columns: 180px minmax(0, 1fr) auto; white-space: pre-wrap; }
.cx-colors { border: 0; margin: 0; padding: 0; display: grid; gap: var(--sp-1); font-size: var(--fs-sm); }
.cx-colors legend { padding: 0; margin-bottom: var(--sp-1); }
.cx-colors label { display: flex; align-items: center; gap: var(--sp-1); }
.cx-colors .cx-swatch, .cx-textrow .cx-swatch { display: inline-block; width: 14px; height: 14px; min-width: 14px; }
@media (max-width: 900px) { .cx-textrow, .cx-textrow.readonly { grid-template-columns: minmax(0, 1fr); } }

/* 1.11.0 - the licence plans (plans.html, admin_plans.html) */
.plans-scroll { max-height: none; }
.plans-table th[scope="row"] { text-align: left; font-weight: 400; display: grid; gap: var(--sp-1); }
.plans-table th[scope="row"] .chip { justify-self: start; }
.plans-table .plan-head { text-align: center; vertical-align: bottom; }
.plans-table .plan-head.mine .plan-name { color: var(--accent); }
.plans-table .plan-name { display: block; font-size: var(--fs-lg); font-weight: 600; }
.plans-table .plan-facts { text-align: center; vertical-align: top; }
.plans-table .plan-price { margin-top: var(--sp-1); font-weight: 600; }
.plans-table .plan-tick { text-align: center; vertical-align: middle; }
.plans-table .tick.yes { color: var(--ok-text); font-weight: 600; }
.plans-table .tick.no { color: var(--muted); }
.plans-table tr.plan-group th { text-align: left; background: var(--surface-2); padding-top: var(--sp-3); }
.plan-card .plan-fields { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: var(--sp-3); align-items: end; }
.plan-card .plan-fields label { display: grid; gap: var(--sp-1); font-size: var(--fs-sm); }
.plan-card .plan-check { display: flex; align-items: center; gap: var(--sp-2); font-size: var(--fs-sm); }
.plan-card .plan-features { border: 1px solid var(--border); border-radius: var(--radius); margin: var(--sp-3) 0; padding: var(--sp-3);
  display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: var(--sp-3); }
.plan-card .plan-fgroup { display: grid; gap: var(--sp-1); align-content: start; }

/* 1.20.0 - support (support.html, admin_support.html) */
.support-form { display: grid; gap: var(--sp-2); max-width: 44rem; }
.support-form textarea { width: 100%; font: inherit; }
.support-ctx { background: var(--surface-2); border-radius: var(--radius); padding: var(--sp-2) var(--sp-3); }
.support-item { border-top: 1px solid var(--border); padding: var(--sp-2) 0; }
.support-item summary { cursor: pointer; }
.support-msg, .support-answer { white-space: pre-wrap; margin: var(--sp-2) 0; }
.support-answer { border-left: 3px solid var(--accent); padding-left: var(--sp-3); }
.support-list tr.support-late td { background: var(--error-bg); }

/* 1.16.0 - the team page (team.html) */
.team-seats { margin-top: var(--sp-2); max-width: 28rem; }
.team-list td { vertical-align: middle; }
.team-act { text-align: right; }
.team-act form { display: inline-block; margin: var(--sp-1) 0 0 var(--sp-1); }
.team-invite { display: flex; flex-wrap: wrap; align-items: flex-end; gap: var(--sp-3); }
.team-invite label { display: grid; gap: var(--sp-1); font-size: var(--fs-sm); }
.team-link input { width: 100%; margin-top: var(--sp-2); }

/* 1.14.0 - comparing two iterations (compare.html): before struck through in grey, after in the text colour */
.cmp-pick { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); }
.cmp-pick select { max-width: 22rem; }
.cmp-arrow { color: var(--muted); }
.cmp-links { margin-left: auto; font-size: var(--fs-sm); }
.cmp-table { table-layout: fixed; }
.cmp-table col.cmp-what { width: 34%; }
.cmp-before { color: var(--muted); text-decoration: line-through; }
.cmp-after { color: var(--text); }
.cmp-added .cmp-after { color: var(--ok-text); }
.cmp-removed .cmp-before { color: var(--error-text); }
.cmp-kind { display: inline-block; font-size: var(--fs-xs); color: var(--muted); border: 1px solid var(--border);
  border-radius: var(--radius-sm); padding: 0 var(--sp-1); margin-right: var(--sp-1); }
.cmp-worse { color: var(--bad); font-weight: 600; }
.cmp-better { color: var(--ok); font-weight: 600; }
.cmp-mast h3 { margin: var(--sp-3) 0 var(--sp-1); font-size: var(--fs-sm); color: var(--muted); font-weight: 600; }

/* 1.13.0 - the company logo (account.html). 1.13.1: previewed on the report's header band, as it will print -
   straight on it (transparent) or on a white plate (white); a picture without transparency blends its white away */
.logo-preview { background: var(--report-band); height: 56px; padding: 0 var(--sp-3); box-sizing: border-box;
  display: flex; align-items: center; justify-content: flex-end; margin: var(--sp-2) 0; }
.logo-preview span { display: inline-flex; align-items: center; line-height: 0; }
.logo-preview span.logo-plate { background: var(--paper); border: 1px solid var(--report-band); align-self: stretch;
  margin-right: calc(-1 * var(--sp-3)); padding: 0 var(--sp-3); }
.logo-preview img { max-width: 240px; max-height: 40px; object-fit: contain; }
.logo-preview img.logo-blend { mix-blend-mode: multiply; }
.logo-bg { border: 0; padding: 0; margin: var(--sp-2) 0; display: flex; flex-wrap: wrap; gap: var(--sp-3); }
.logo-bg legend { font-size: var(--fs-sm); color: var(--muted); padding: 0; margin-bottom: var(--sp-1); }
.logo-bg-form { display: flex; flex-wrap: wrap; align-items: flex-end; gap: var(--sp-3); }

/* 1.12.0 - the catalogue editor (catalogue.html) */
.cat-tabs { display: flex; flex-wrap: wrap; gap: var(--sp-1) var(--sp-3); }
.cat-group { display: inline-flex; flex-wrap: wrap; align-items: center; gap: var(--sp-1); }
.cat-group-name { font-size: var(--fs-xs); color: var(--muted); margin-right: var(--sp-1); }
.cat-search { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); margin: var(--sp-2) 0; }
.cat-search input[type="search"] { max-width: 20rem; }
.cat-pages { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin: var(--sp-2) 0; font-size: var(--fs-sm); }
.cat-fields textarea { width: 100%; font: inherit; }
.cat-fields label:has(textarea) { grid-column: 1 / -1; }
.cat-tabs a { padding: var(--sp-1) var(--sp-3); border: 1px solid var(--border); border-radius: var(--radius-pill); text-decoration: none; }
.cat-tabs a.current { border-color: var(--accent); color: var(--accent); }
.cat-list th, .cat-list td { vertical-align: middle; white-space: nowrap; }
.cat-list th.num, .cat-list td.num { text-align: right; }
.cat-list td.cat-act { width: 1%; text-align: right; }
.cat-fields { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: var(--sp-3); margin: var(--sp-3) 0; }
.cat-fields label { display: grid; gap: var(--sp-1); font-size: var(--fs-sm); }
fieldset.cat-fields { border: 0; padding: 0; min-width: 0; }

/* 1.14.0 - wires and catenaries: derived values, checks and the engine's preview beside the fields */
.cat-side { display: grid; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); gap: var(--sp-4); margin-top: var(--sp-3); }
.cat-side h3 { margin: 0 0 var(--sp-2); }
.cat-kv { display: grid; grid-template-columns: max-content 1fr; gap: var(--sp-1) var(--sp-3); font-size: var(--fs-sm); margin: 0; }
.cat-kv dt { color: var(--muted); }
.cat-kv dd { margin: 0; font-variant-numeric: tabular-nums; }
.cat-checks { list-style: none; padding: 0; margin: 0; display: grid; gap: var(--sp-1); font-size: var(--fs-sm); }
.cat-checks .chip { margin-right: var(--sp-2); }
.cat-preview td.num, .cat-preview th.num { text-align: right; font-variant-numeric: tabular-nums; }
.diag-panel .sag-chart { width: 100%; height: auto; display: block; }
.diag-panel .sag-chart .sc-grid { stroke: var(--border); stroke-width: 1; }
.diag-panel .sag-chart .sc-tick { fill: var(--plot-muted); font-size: 11px; }
.diag-panel .sag-chart .sc-line { fill: none; stroke-width: 2; }
.diag-panel .sag-chart .sc-0 { stroke: var(--plot-ink); }
.diag-panel .sag-chart .sc-1 { stroke: var(--plot-muted); stroke-dasharray: 6 4; }
.sag-legend { display: flex; gap: var(--sp-3); font-size: var(--fs-xs); color: var(--muted); margin-top: var(--sp-1); }
.diag-panel .sag-chart .sc-zero { stroke: var(--plot-muted); }
.diag-panel .sag-chart .sc-point { fill: var(--plot-ink); stroke: var(--plot-halo); stroke-width: 1.5; }

/* 1.14.0 - the sag calculator (sag.html) */
.sag-systems { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: var(--sp-2); margin-top: var(--sp-3); }
.sag-systems a { display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-2) var(--sp-3); border: 1px solid var(--border);
  border-radius: var(--radius); text-decoration: none; color: var(--text); }
.sag-systems a:hover { background: var(--surface-2); }
.sag-systems a.current { background: var(--accent-bg); box-shadow: inset 3px 0 0 var(--accent); }
.sag-systems a > span { display: grid; }
.sag-picto { width: 48px; height: 24px; flex: none; fill: none; stroke: var(--text); stroke-width: 1.5; }
.sag-picto .fd { stroke-width: 2; }
.sag-picto .dr { stroke-width: 1; }
.sag-picto .wt { stroke-dasharray: 2 2; }
.sag-layout { display: grid; grid-template-columns: minmax(280px, 340px) 1fr; gap: var(--sp-4); align-items: start; }
.sag-inputs label { display: grid; gap: var(--sp-1); font-size: var(--fs-sm); margin-bottom: var(--sp-2); }
.sag-inputs label.plan-check { display: flex; align-items: center; gap: var(--sp-2); }
.sag-inputs label.field-error input, .sag-inputs label.field-error select { border-color: var(--error-text); background: var(--error-bg); }
.sag-group { border: 0; border-top: 1px solid var(--border); padding: var(--sp-2) 0 0; margin: var(--sp-2) 0 0; min-width: 0; }
.sag-group legend { font-size: var(--fs-sm); font-weight: 600; color: var(--muted); padding: 0 var(--sp-1) 0 0; }
.sag-results { display: grid; gap: var(--sp-4); min-width: 0; }
.sag-results > .card { margin: 0; }
.sag-tiles { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: var(--sp-2); margin-bottom: var(--sp-3); }
.sag-tile { border: 1px solid var(--border); border-radius: var(--radius); padding: var(--sp-2) var(--sp-3); display: grid; }
.sag-tile b { font-size: var(--fs-lg); font-variant-numeric: tabular-nums; }
.sag-cols { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: var(--sp-4); margin-top: var(--sp-3); }
/* 1.19.0 saving a new wire / a wire load (_sag_save.html) */
.sag-save .sag-names { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: var(--sp-2) var(--sp-3); margin-top: var(--sp-3); }
.sag-save .sag-names label, .sag-save-form > label { display: flex; flex-direction: column; gap: var(--sp-1); }
.sag-save-form .actions { margin-top: var(--sp-3); }
.sag-cols h3 { margin: 0 0 var(--sp-2); }
.sag-num td.num, .sag-num th.num { text-align: right; font-variant-numeric: tabular-nums; }
.sag-num tr.current td { background: var(--accent-bg); }
.sag-calc { border-top: 1px solid var(--border); padding: var(--sp-2) 0; }
.sag-calc summary { cursor: pointer; font-weight: 600; }
.sag-calc .sag-f { font-family: ui-monospace, Consolas, monospace; font-size: var(--fs-sm); }
.sag-calc .sag-n { font-family: ui-monospace, Consolas, monospace; font-size: var(--fs-xs); color: var(--muted); }
h3.inline { display: inline; }
.diag-panel .sag-span { width: 100%; height: auto; display: block; }
.diag-panel .sag-span .sp-pole { stroke: var(--plot-mast); stroke-width: 3; }
.diag-panel .sag-span .sp-name { fill: var(--plot-ink); font-size: 13px; font-weight: 700; }
.diag-panel .sag-span .sp-chord { stroke: var(--plot-muted); stroke-width: .8; stroke-dasharray: 2 4; }
.diag-panel .sag-span .sp-dropper { stroke: var(--plot-muted); stroke-width: 1; }
.diag-panel .sag-span .sp-wire { fill: none; stroke: var(--plot-muted); stroke-width: 1.4; }
.diag-panel .sag-span .sp-fd { stroke-width: 1.8; }
.diag-panel .sag-span .st-main { stroke: var(--plot-ink); stroke-width: 2.4; }
.diag-panel .sag-span .st-1 { stroke-dasharray: 8 5; }
.diag-panel .sag-span .st-2 { stroke-dasharray: 2 4; }
.diag-panel .sag-span .st-3 { stroke-dasharray: 10 4 2 4; }
.diag-panel .sag-span .st-4 { stroke-dasharray: 16 6; }
.diag-panel .sag-span .sp-dim { stroke: var(--plot-ink); stroke-width: 1; }
.diag-panel .sag-span .sp-mark-dim { stroke: var(--accent); stroke-width: 1.2; stroke-dasharray: 4 3; }
.diag-panel .sag-span .sp-mark-dot { fill: var(--accent); }
.diag-panel .sag-span .sp-mark-no { fill: var(--accent); font-size: 11px; font-weight: 700; }
.diag-panel .sag-span .sp-mark-label { fill: var(--accent); font-size: 11px; }
.diag-panel .sag-span .sp-label, .diag-panel .sag-span .sp-force { fill: var(--plot-ink); font-size: 12px; font-weight: 700;
  paint-order: stroke; stroke: var(--plot-halo); stroke-width: 3px; }
.diag-panel .sag-span .sp-note, .diag-panel .sag-span .sp-legend { fill: var(--plot-muted); font-size: 11px; }
@media (max-width: 900px) { .sag-layout { grid-template-columns: 1fr; } }
/* 1.29.0 (owner): the sag page fits one screen. Header in one row; inputs in collapsible groups (a closed group shows
   its values, sag.js); results = headline values, the drawing, ONE panel with tabs. The fitted mode below needs
   room (>= 1000 x 620 px); smaller screens keep the flowing page. */
.sag-head { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2) var(--sp-4); margin-bottom: var(--sp-3); }
.sag-head h1 { margin: 0; font-size: var(--fs-xl); white-space: nowrap; }
.sag-head .sag-systems { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin: 0; }
.sag-head .sag-systems a { padding: var(--sp-1) var(--sp-3); gap: var(--sp-2); }
.sag-head .sag-systems a .sub { display: none; }                  /* the hint is the link's tooltip */
.sag-intro { flex: 1 1 240px; margin: 0; }
.sag-inputs .sag-main-choice { display: grid; gap: var(--sp-1); }
.sag-group { border: 0; border-top: 1px solid var(--border); padding: 0; margin: var(--sp-2) 0 0; }
.sag-group > summary { display: flex; align-items: baseline; gap: var(--sp-2); padding: var(--sp-2) 0; cursor: pointer;
  list-style: none; font-size: var(--fs-sm); font-weight: 600; color: var(--muted); }
.sag-group > summary::-webkit-details-marker { display: none; }
.sag-group > summary::before { content: "▸"; color: var(--muted); width: 1em; flex: none; }
.sag-group[open] > summary::before { content: "▾"; }
.sag-gt { flex: none; }
.sag-sum { flex: 1; min-width: 0; text-align: right; font-weight: 400; color: var(--muted); white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis; font-variant-numeric: tabular-nums; }
.sag-group[open] > summary .sag-sum { visibility: hidden; }
.sag-fields { padding-bottom: var(--sp-2); }
.sag-inputs .sag-field { display: grid; grid-template-columns: 1fr minmax(96px, 46%); align-items: center;
  gap: var(--sp-1) var(--sp-2); margin-bottom: var(--sp-1); }
.sag-inputs .sag-field .sag-hint { grid-column: 1 / -1; display: none; }
.sag-inputs .sag-field:focus-within .sag-hint, .sag-inputs .sag-field.field-error .sag-hint { display: block; }
.sag-inputs .sag-field input, .sag-inputs .sag-field select { width: 100%; min-width: 0; }
.sag-results { gap: var(--sp-3); }
.sag-results .sag-tiles { margin: 0; grid-template-columns: repeat(auto-fit, minmax(130px, 1fr)); }
.sag-results .sag-tile { padding: var(--sp-1) var(--sp-3); }
.sag-drawing { margin: 0; }
.sag-drawing figcaption { margin-top: var(--sp-1); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.sag-panel { margin: 0; padding: 0; display: flex; flex-direction: column; min-height: 0; }
.sag-tabbar { display: flex; align-items: center; gap: var(--sp-3); padding: 0 var(--sp-3); border-bottom: 1px solid var(--border); }
.sag-tabs { display: flex; flex: 1; min-width: 0; overflow-x: auto; overflow-y: hidden; scrollbar-width: thin; }
.sag-tab { padding: var(--sp-2) var(--sp-3); color: var(--muted); text-decoration: none; white-space: nowrap; font-size: var(--fs-sm);
  border-bottom: 2px solid transparent; margin-bottom: -1px; }
.sag-tab:hover { color: var(--text); }
.sag-tab.current { color: var(--accent); border-bottom-color: var(--accent); font-weight: 600; }
.sag-pane { padding: var(--sp-3); min-height: 0; }
.sag-pane .sag-cols { margin-top: 0; }
.sag-pane .sag-save { border: 0; padding: 0; margin: 0; box-shadow: none; background: none; }
.sag-charts { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: var(--sp-4); }
.sag-pane h3 { margin: 0 0 var(--sp-2); }
/* the contact wire heights (1.29.0, owner: larger): the tiles and the ladder on the left, the two allowance tables
   stacked on the right */
.sag-hf { display: grid; grid-template-columns: minmax(0, 3fr) minmax(260px, 2fr); gap: var(--sp-2) var(--sp-4); align-items: start; }
.sag-hf > div:first-child { grid-row: span 2; }
.sag-hf .sag-tiles { grid-template-columns: repeat(auto-fit, minmax(110px, 1fr)); margin-bottom: var(--sp-2); }
.sag-hf .diag-panel .hf-ladder { max-width: 760px; margin: 0 auto; }
@media (max-width: 900px) { .sag-hf { grid-template-columns: 1fr; } .sag-hf > div:first-child { grid-row: auto; } }
@media (min-width: 1000px) and (min-height: 620px) {
  body.sag-fit .site-footer { display: none; }
  main.sag-main { margin: var(--sp-3) var(--sp-4); padding: 0; }
  body.sag-fit .sag-layout { --sag-h: calc(100dvh - 128px); height: var(--sag-h); align-items: stretch; }   /* sag.js sets --sag-h exactly */
  body.sag-fit .sag-inputs { margin: 0; overflow-y: auto; min-height: 0; padding: var(--sp-3); }
  body.sag-fit .sag-results { display: flex; flex-direction: column; min-height: 0; gap: var(--sp-2); }
  body.sag-fit .sag-results > .error, body.sag-fit .sag-results > .notice { margin: 0; flex: none; }
  body.sag-fit .sag-tiles { flex: none; }
  /* the drawing is as high as it is drawn at full width (owner: no empty band), at most 42 % of the window; the
     tab panel takes the rest */
  body.sag-fit .sag-drawing { flex: 0 0 auto; display: flex; flex-direction: column; padding: var(--sp-2); }
  body.sag-fit .sag-drawing .sag-span { width: 100%; height: auto; max-height: 42dvh; max-width: 1000px; align-self: center; }   /* labels stay readable, not huge */
  body.sag-fit .sag-panel { flex: 1 1 0; min-height: 160px; }
  body.sag-fit .sag-pane { flex: 1 1 0; overflow: auto; }
  body.sag-fit .sag-charts .sag-chart { max-height: 30vh; }
  /* the heights tab needs room: while it is open the panel may grow, the drawing above gives way */
  body.sag-fit .sag-results:has(#sag-pane-hf:not([hidden])) .sag-drawing .sag-span { max-height: 24dvh; }
  /* a long table scrolls with its tab, its head stays in sight (DESIGN_RULES §3a) */
  body.sag-fit .sag-pane .table-scroll { overflow: visible; max-height: none; }
  body.sag-fit .sag-pane thead th { position: sticky; top: calc(-1 * var(--sp-3)); background: var(--surface); z-index: 1; }
}
/* formulas in the help and the sag report (mathml.py; the browser draws MathML) */
.math { overflow-x: auto; margin: var(--sp-3) 0; padding: var(--sp-1) 0; }
/* the sliders on the sag pictures (sag.js) */
.diag-panel svg[data-hover] { cursor: crosshair; touch-action: pan-y; }
.diag-panel svg[data-hover]:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.diag-panel .sl-line { stroke: var(--plot-ink); stroke-width: 1; stroke-dasharray: 3 3; }
.diag-panel .sl-dot { fill: var(--plot-bg); stroke: var(--plot-ink); stroke-width: 1.5; }
.diag-panel .sl-dot.sl-main { fill: var(--plot-ink); }
.diag-panel .sl-bg { fill: var(--surface); stroke: var(--border); opacity: .95; }
.diag-panel .sl-text { fill: var(--plot-ink); font-size: 12px; }
.diag-panel .sl-head { font-weight: 700; }
/* the design contact wire heights (sag_svg.hf_ladder) */
.diag-panel .hf-ladder { width: 100%; height: auto; display: block; }
.diag-panel .hf-ladder .hl-grid { stroke: var(--border); stroke-width: 1; }
.diag-panel .hf-ladder .hl-tick, .diag-panel .hf-ladder .hl-col { fill: var(--plot-muted); font-size: 12px; }
.diag-panel .hf-ladder .hl-col { font-weight: 700; }
.diag-panel .hf-ladder .hl-block { stroke: var(--plot-ink); stroke-width: 1; }
.diag-panel .hf-ladder .hl-base { fill: var(--surface-2); }
.diag-panel .hf-ladder .hl-add { fill: var(--plot-bg); }
.diag-panel .hf-ladder .hl-label { fill: var(--plot-ink); font-size: 13px; }
.diag-panel .hf-ladder .hl-top { stroke: var(--plot-ink); stroke-width: 2; }
.diag-panel .hf-ladder .hl-band.hl-ok { fill: var(--ok-bg); stroke: var(--ok-line); }
.diag-panel .hf-ladder .hl-band.hl-bad { fill: var(--error-bg); stroke: var(--bad-line); }
.diag-panel .hf-ladder .hl-result { stroke: var(--plot-ink); stroke-width: 1.5; }
.diag-panel .hf-ladder .hl-result-label, .diag-panel .hf-ladder .hl-planned-label { fill: var(--plot-ink); font-size: 13px;
  font-weight: 700; paint-order: stroke; stroke: var(--plot-halo); stroke-width: 3px; }
.diag-panel .hf-ladder .hl-planned { stroke-width: 2; stroke-dasharray: 8 4; }
.diag-panel .hf-ladder .hl-planned.hl-ok { stroke: var(--ok); }
.diag-panel .hf-ladder .hl-planned.hl-bad { stroke: var(--bad); }

/* 1.22.0: RailTools' start page (home.html) - one tile per tool; the whole tile is the link */
.tool-tiles { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: var(--sp-4); margin-top: var(--sp-3); }
.tool-tile { display: flex; flex-direction: column; gap: var(--sp-2); padding: var(--sp-4); border: 1px solid var(--border);
  border-radius: var(--radius-card); background: var(--surface); color: var(--text); text-decoration: none; }
a.tool-tile:hover { border-color: var(--accent); }
a.tool-tile:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.tool-tile .tool-name { font-size: var(--fs-xl); font-weight: 600; letter-spacing: .02em; color: var(--accent); }
.tool-tile .tool-desc { color: var(--muted); flex: 1; }
.tool-tile .tool-go { font-weight: 600; color: var(--accent); }
.tool-tile.off .tool-name { color: var(--muted); }
/* 1.22.0: the admin page's areas (admin.html) - users and licences, WIRE, BEAM, OCL, system */
.admin-areas { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: var(--sp-4); margin-top: var(--sp-3); }
.admin-area { padding: var(--sp-3) var(--sp-4); border: 1px solid var(--border); border-radius: var(--radius); }
.admin-area h2 { margin: 0 0 var(--sp-1); }
.admin-area .sub { margin: 0 0 var(--sp-2); }
.admin-area ul { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--sp-1); }

/* 1.24.0 - the OCL parts designer (admin_ocl_part*.html, admin_ocl_catalogue*.html) */
.op-test label { margin: var(--sp-2) 0 0; }
.op-test h3 { margin-top: var(--sp-3); }
.op-test .btn-row { margin-top: var(--sp-3); }
.op-built { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--sp-4); align-items: start; }
.op-grid td, .op-grid th { padding: var(--sp-1); }
.op-grid input, .op-grid select { min-width: 0; font-size: var(--fs-sm); }
.op-grid .op-formula { min-width: 160px; }
.op-short { max-width: 90px; }
.op-general, .op-subs { display: grid; grid-template-columns: max-content minmax(0, 1fr); gap: var(--sp-1) var(--sp-3); align-items: center; }
.op-general label, .op-subs label { margin: 0; }
.op-catalogue td, .op-catalogue th { font-size: var(--fs-sm); white-space: nowrap; }
@media (max-width: 900px) { .op-built { grid-template-columns: 1fr; } }

/* ---- 1.31.0: fit the window, fold the rest (DESIGN_RULES §3a) - reusable for every working page ------------------
   body.fit (template block body_class): the page is exactly the window's height; .fit-fill = the card that takes it,
   .fit-grow = each box between that card and the one part that may be long, .fit-scroll = that part (a table, a list),
   which scrolls in its own box. Below 900 x 560 the page simply scrolls (DESIGN_RULES §3). */
@media (min-width: 900px) and (min-height: 560px) {
  body.fit { height: 100dvh; }
  body.fit > .page-body { flex: 1 1 auto; min-height: 0; }
  body.fit > .page-body:not(.ws-body) { display: flex; flex-direction: column; }
  body.fit > .ws-body { grid-template-rows: minmax(0, 1fr); }
  body.fit > .page-body:not(.ws-body) > main { width: 100%; }  /* in the workspace grid the cell gives the width (100% + margins would overflow) */
  body.fit > .page-body > main { flex: 1 1 auto; min-height: 0; min-width: 0; box-sizing: border-box;
    display: flex; flex-direction: column; overflow: auto; }
  body.fit > .page-body > main > *:not(.fit-fill) { flex: none; }
  body.fit details.fold > .fold-body { max-height: 6em; }
  body.fit .fit-fill { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; }
  body.fit .fit-grow { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; }
  body.fit .fit-scroll { flex: 1 1 auto; min-height: 140px; max-height: none; overflow: auto; }
  body.fit .fit-fill > *:not(.fit-grow):not(.fit-scroll), body.fit .fit-grow > *:not(.fit-grow):not(.fit-scroll) { flex: none; }
}
/* a folding row (details.fold): a caret, a summary that says what is inside (a count, a status), the body below.
   Closed by default; a section with an error is rendered open. */
details.fold { margin: 0 0 var(--sp-3); }
details.fold > summary { list-style: none; cursor: pointer; display: flex; align-items: center; gap: var(--sp-2);
  font-size: var(--fs-sm); color: var(--muted); }
details.fold > summary::-webkit-details-marker { display: none; }
details.fold > summary::before { content: ""; border-left: 6px solid var(--muted); border-top: 5px solid transparent;
  border-bottom: 5px solid transparent; transition: transform .15s; }
details.fold[open] > summary::before { transform: rotate(90deg); }
details.fold > .fold-body { margin-top: var(--sp-2); max-height: 9em; overflow: auto; }
details.help-fold > .fold-body { max-height: none; }   /* 1.52.0: a help article's folded table opens in full */
.help-table { margin: var(--sp-2) 0 var(--sp-4); }
/* 1.31.0 catalogue: set choice + folded introduction on one line, more compact tabs */
.cat-meta { display: flex; flex-wrap: wrap; align-items: flex-start; gap: var(--sp-2) var(--sp-4); margin-top: var(--sp-2); }
.cat-meta > .cx-row { margin: 0; }
.cat-meta > details.fold { flex: 1 1 20em; min-width: 0; margin: 0; }
.cat-intro > summary { min-width: 0; }
.cat-intro[open] > summary .fold-line { display: none; }
.cat-intro .fold-line { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
.cat-tabs a { padding: var(--sp-1) var(--sp-2); font-size: var(--fs-sm); line-height: 1.2; }
/* 1.31.0 mast image: the ribbon on one row (captions only on wide screens), the work area takes the rest of the window */
@media (max-width: 1500px) {
  .ribbon .rb-cap { display: none; }
  .ribbon .rb-group { padding: var(--sp-2) var(--sp-1); }
  .ribbon .pw-zoom-level { min-width: 40px; }
  .ribbon .pw-calc select { width: auto; min-width: 0; max-width: 8em; }
  /* only the pressed mode keeps its name (the others: icon + tooltip); "fit" becomes an icon */
  .ribbon .rb-seg button[aria-pressed="false"] .rb-label, .ribbon #zoom-reset .rb-label { display: none; }
  .ribbon .rb-seg button[aria-pressed="false"] .rb-ico, .ribbon #zoom-reset .rb-ico { margin-right: 0; }
}
.ribbon .rb-narrow { display: none; }
@media (max-width: 1500px) { .ribbon .rb-narrow { display: inline-block; } }
.ribbon .rb-tools .rb-menu { left: 0; right: auto; }
.ribbon .rb-menu a.button { white-space: nowrap; }
@media (min-width: 900px) and (min-height: 560px) {
  body.fit .pw.fit-fill > .pw-work:not([hidden]) { flex: 1 1 auto; height: auto; min-height: 300px; grid-template-rows: minmax(0, 1fr); }
  body.fit .pw-inspector .pw-list { overflow: auto; }
}
/* 1.31.0 a whole card that folds (iteration overview): the head is the summary, a triangle before the title */
details.fold-card > summary { list-style: none; cursor: pointer; margin-bottom: 0; }
details.fold-card > summary::-webkit-details-marker { display: none; }
details.fold-card > summary h2::before { content: ""; display: inline-block; margin-right: var(--sp-2); vertical-align: middle;
  border-left: 6px solid var(--muted); border-top: 5px solid transparent; border-bottom: 5px solid transparent; transition: transform .15s; }
details.fold-card[open] > summary h2::before { transform: rotate(90deg); }
details.fold-card[open] > summary { margin-bottom: var(--sp-3); }
details.fold > dl.facts.fold-body { max-height: none; }
/* 1.31.0 parts: the anchor gap and "new part" on one row; the hint beside the save buttons */
.parts-controls { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2) var(--sp-5); margin-bottom: 12px; }
.parts-controls > .anchor-gap, .parts-controls > .add-row { margin: 0; }
.parts-card .actions { align-items: center; }
/* Part template editor (1.30.0, admin_part_template.html, part_editor.js; layout owner 2026-09-30): a sticky bar with
   the tabs over two panes - left what is edited (sketch, block rows, one inspector), right the result (3D, loads,
   findings, test) */
.pt-bar { position: sticky; top: 0; z-index: 5; display: grid; gap: var(--sp-2); padding-top: var(--sp-2); padding-bottom: var(--sp-2); }
.pt-head { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); }
.pt-head .pw-title { margin: 0; }
.pt-barrow { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: center; gap: var(--sp-2) var(--sp-4); }
.pt-tabs { display: flex; flex-wrap: wrap; gap: var(--sp-1); }
.pt-tabs a { padding: var(--sp-1) var(--sp-3); border-radius: var(--radius); color: var(--muted); text-decoration: none; font-size: var(--fs-md); }
.pt-tabs a:hover { background: var(--surface-2); color: var(--text); }
.pt-tabs a.current { background: var(--accent-bg); color: var(--accent); font-weight: 600; box-shadow: inset 0 -3px 0 var(--accent); }
.pt-actions { flex-wrap: wrap; align-items: center; }
.pt-actions form { margin: 0; }
.pt-more { position: relative; }
.pt-more summary { list-style: none; }
.pt-more summary::-webkit-details-marker { display: none; }
.pt-more-menu { position: absolute; right: 0; top: calc(100% + var(--sp-1)); z-index: 6; display: grid; gap: var(--sp-2); min-width: 320px;
  padding: var(--sp-3); background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); box-shadow: var(--shadow); }
.pt-short { max-width: 160px; }
.pt-work { display: grid; grid-template-columns: minmax(0, 1.15fr) minmax(360px, 1fr); gap: var(--sp-4); align-items: start; margin-top: var(--sp-3); }
.pt-left { display: grid; gap: var(--sp-4); min-width: 0; }
.pt-pane { display: grid; gap: var(--sp-4); min-width: 0; }
.pt-pane.card, .pt-left .card { margin: 0; }
.pt-right { position: sticky; top: 112px; min-width: 0; }
.pt-right .card { margin: 0; padding: var(--sp-3); }
.pt-right h3 { margin-top: var(--sp-3); }
.pt-rtabs { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-1); margin-bottom: var(--sp-2); }
.pt-lasterr { margin: var(--sp-2) 0 0; padding: var(--sp-1) var(--sp-2); border-radius: var(--radius); font-size: var(--fs-sm); cursor: pointer; }
.pt-lasterr.bad { background: var(--error-bg); color: var(--error-text); }
.pt-lasterr.warn { background: var(--notice-bg); color: var(--notice-text); }
.pt-lasterr.ok { color: var(--muted); }
.pt-stage { height: 380px; position: relative; }
.pt-3dbar { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); margin-bottom: var(--sp-2); }
.pt-table td, .pt-table th { padding: var(--sp-1); }
.pt-table input[type="text"], .pt-table select { min-width: 80px; width: 100%; height: var(--ctl-h-sm); font-size: var(--fs-sm); }
.pt-table td:first-child input[type="text"] { min-width: 120px; }
.pt-row-tools { white-space: nowrap; }
.pt-fields { display: grid; grid-template-columns: max-content minmax(0, 1fr); gap: var(--sp-1) var(--sp-3); align-items: center; }
.pt-fields label { margin: 0; }
.pt-names code { margin-right: var(--sp-1); }
.pt-res tr.pt-pick, .pt-res tr.pt-sel { cursor: pointer; }
.pt-res tr.pt-sel td { background: var(--accent-bg); }
.pt-res td, .pt-res th { font-size: var(--fs-xs); white-space: nowrap; padding: var(--sp-1) var(--sp-2); }
.pt-test h3 { margin-top: var(--sp-3); }
.pt-choose { display: inline-flex; flex-wrap: wrap; gap: var(--sp-1); align-items: center; min-width: 0; }
.pt-choose select { max-width: 100%; }
.pt-other { width: 140px; }
.pt-check { display: inline-flex; align-items: center; gap: var(--sp-1); margin: 0 var(--sp-3) 0 0; font-weight: 400; }
.pt-checks { display: inline-flex; flex-wrap: wrap; }
.pt-add-block { flex-wrap: wrap; align-items: center; margin-bottom: var(--sp-2); }
.pt-blocklist { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--sp-1); }
.pt-brow { border: 1px solid var(--border); border-radius: var(--radius); }
.pt-brow.open { border-color: var(--accent); }
.pt-bhead { display: flex; align-items: center; gap: var(--sp-2); width: 100%; min-width: 0; padding: var(--sp-1) var(--sp-2); border: 0;
  background: transparent; color: var(--text); text-align: left; font: inherit; cursor: pointer; height: auto; }
.pt-bhead:hover { background: var(--surface-2); }
.pt-brow.open .pt-bhead { background: var(--accent-bg); }
.pt-bsum { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pt-insp { padding: var(--sp-2) var(--sp-3) var(--sp-3); display: grid; gap: var(--sp-2); }
.pt-insp-head { display: flex; align-items: center; gap: var(--sp-2); }
.pt-insp-head label { margin: 0; }
.pt-block-name { max-width: 220px; font-weight: 600; }
.pt-morefields summary { cursor: pointer; color: var(--accent); font-size: var(--fs-sm); margin-bottom: var(--sp-1); }
.pt-place { display: inline-flex; flex-wrap: wrap; align-items: center; gap: var(--sp-1); min-width: 0; }
.pt-coords { display: inline-flex; flex-wrap: wrap; align-items: center; gap: var(--sp-1); }
.pt-coords input.pt-coord { width: 88px; height: var(--ctl-h-sm); }
.pt-rule { display: flex; flex-wrap: wrap; align-items: flex-end; gap: var(--sp-2) var(--sp-4); padding: var(--sp-3) 0; border-bottom: 1px solid var(--border); }
.pt-rule form { margin: 0; }
.pt-rule-fields { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: var(--sp-1) var(--sp-3); align-items: end; }
.pt-rule-fields label { margin: 0; grid-row: auto; }
.pt-rule-form { flex: 1; min-width: 0; display: grid; gap: var(--sp-2); }
.pt-tests td, .pt-tests th { font-size: var(--fs-xs); white-space: nowrap; padding: var(--sp-1) var(--sp-2); }
.pt-brow.unused .pt-bhead strong, .pt-brow.unused .pt-bsum { color: var(--muted); }
.pt-brow.pt-flash { border-color: var(--accent); background: var(--accent-bg); }
.pt-sk-bar { flex-wrap: wrap; margin-bottom: var(--sp-2); }
.pt-sk-snap { width: auto; }
.pt-sk-svg { display: block; width: 100%; height: 340px; background: var(--stage-bg); border: 1px solid var(--border); border-radius: var(--radius); touch-action: none; user-select: none; }
.pt-sk-grid line { stroke: var(--border); stroke-width: 1; }
.pt-sk-face { stroke: var(--muted); stroke-width: 2; stroke-dasharray: 6 4; }
.pt-sk-label { fill: var(--muted); font-size: var(--fs-xs); }
.pt-sk-axis { fill: var(--muted); font-size: var(--fs-sm); font-weight: 600; }
.pt-sk-beam { stroke: var(--text); stroke-width: 4; }
.pt-sk-rigid { stroke: var(--muted); stroke-width: 2; stroke-dasharray: 5 3; }
.pt-sk-link { stroke: var(--warn); stroke-width: 3; }
.pt-sk-tube { stroke: var(--faint); stroke-linecap: round; }
.pt-sk-body { fill: var(--surface-2); stroke: var(--muted); stroke-width: 1.5; }
.pt-sk-beam.selected, .pt-sk-rigid.selected, .pt-sk-link.selected, .pt-sk-tube.selected, .pt-sk-body.selected { stroke: var(--accent); }
.pt-sk-node { fill: var(--surface); stroke: var(--text); stroke-width: 2; cursor: grab; }
.pt-sk-node.fixed { cursor: default; stroke: var(--muted); }
.pt-sk-node.attach { fill: var(--ok); }
.pt-sk-structure { stroke: var(--muted); stroke-width: 6; stroke-opacity: 0.45; stroke-dasharray: 10 6; }
.pt-sk-structure-name { fill: var(--muted); }
.pt-sk-handle { fill: none; stroke: var(--accent); stroke-width: 2; stroke-dasharray: 3 2; cursor: grab; }
.pt-sk-handle-dir { stroke: var(--accent); stroke-width: 2; }
/* the Inputs tab: the form as the user sees it, beside the cross-section with its drag handles */
.pt-form-two { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: var(--sp-3); align-items: start; }
@media (max-width: 900px) { .pt-form-two { grid-template-columns: minmax(0, 1fr); } }
.pt-form-box { border: 1px solid var(--border); border-radius: var(--radius); padding: var(--sp-2) var(--sp-3); min-width: 0; }
.pt-form-cell { display: flex; flex-direction: column; gap: var(--sp-1); min-width: 0; }
.pt-form-err { color: var(--error-text); font-size: var(--fs-sm); }
.pt-texts td { min-width: 9em; }
.pt-sets { display: flex; flex-direction: column; gap: var(--sp-2); min-width: 0; }
.pt-setlist { display: flex; flex-wrap: wrap; gap: var(--sp-2) var(--sp-3); margin: 0; padding-left: var(--sp-3); }
.pt-setlist li { display: inline-flex; align-items: center; gap: var(--sp-1); }
table.parts.pt-texts input[type="text"] { width: 100%; }
.pt-sk-node.selected { stroke: var(--accent); stroke-width: 3; }
.pt-sk-support { fill: none; stroke: var(--ok); stroke-width: 2; }
.pt-sk-rubber { stroke: var(--accent); stroke-width: 2; stroke-dasharray: 4 3; }
.pt-sk-info { min-height: var(--ctl-h); display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); margin-top: var(--sp-2); }
.pt-sk-locked { color: var(--warn); }
.pt-sk-input { display: inline-flex; gap: var(--sp-1); align-items: center; }
.pt-sk-input input { width: 150px; height: var(--ctl-h-sm); }
.pt-json-text { width: 100%; font-family: ui-monospace, Consolas, monospace; font-size: var(--fs-sm); }
.pt-new { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: var(--sp-2) var(--sp-3); align-items: end; }
@media (max-width: 1100px) { .pt-work { grid-template-columns: 1fr; } .pt-right { position: static; } .pt-bar { position: static; } }
/* 1.32.0 (DESIGN_RULES §3a): on a laptop and up the part editor fits the window - part_editor.js sets --pt-h to what is
   left below the bar; the sketch keeps its share, the blocks, a tab's tables and the right panel scroll inside */
@media (min-width: 1101px) and (min-height: 620px) {
  body.pt-fit .site-footer { display: none; }
  body.pt-fit .pt-work { --pt-h: calc(100dvh - 200px); height: var(--pt-h); align-items: stretch; }   /* part_editor.js sets --pt-h exactly */
  body.pt-fit .pt-left { display: flex; flex-direction: column; min-height: 0; }
  body.pt-fit .pt-left > .pt-pane:not([hidden]) { flex: 1 1 0; min-height: 0; }
  body.pt-fit .pt-left > .pt-pane.card:not([hidden]) { overflow: auto; }
  body.pt-fit #pt-pane-design:not([hidden]) { display: flex; flex-direction: column; gap: var(--sp-3); }
  body.pt-fit #pt-pane-design .pt-sketch { flex: none; padding: var(--sp-2) var(--sp-3); }
  body.pt-fit #pt-pane-design .pt-sketch h2 { margin: 0 0 var(--sp-1); }
  body.pt-fit .pt-sk-svg { height: clamp(170px, calc(var(--pt-h) * 0.5), 360px); }
  body.pt-fit #pt-pane-design > .card:last-child { flex: 1 1 0; min-height: 120px; overflow: auto; }
  body.pt-fit .pt-right { position: static; display: flex; min-height: 0; }
  body.pt-fit .pt-right > .card { flex: 1 1 auto; display: flex; flex-direction: column; min-height: 0; }
  body.pt-fit .pt-right [data-rpane]:not([hidden]) { flex: 1 1 0; min-height: 0; overflow: auto; }
  body.pt-fit .pt-right [data-rpane="3d"]:not([hidden]) { display: flex; flex-direction: column; overflow: hidden; }
  body.pt-fit .pt-right .pt-stage { flex: 1 1 0; height: auto; min-height: 180px; }
  body.pt-fit .pt-right .pt-lasterr { flex: none; }
  body.pt-fit .pt-right .table-scroll { overflow: visible; max-height: none; }
  /* a tab's tables scroll with their card (one scroll box per area), their heads stay in sight */
  body.pt-fit .pt-left .table-scroll { overflow: visible; max-height: none; }
  body.pt-fit .pt-left thead th { position: sticky; top: calc(-1 * var(--sp-4)); background: var(--surface); z-index: 1; }
  body.pt-fit .pt-right thead th { position: sticky; top: 0; background: var(--surface); z-index: 1; }
}
/* 1.33.0 mast image: the boxes beside the picture fold - the heading is the summary, a triangle before it; a closed box
   takes only its heading's height, the open ones share the column (the parts list scrolls inside its box) */
details.pw-fold > summary { list-style: none; cursor: pointer; display: flex; align-items: center; gap: var(--sp-2); }
details.pw-fold > summary::-webkit-details-marker { display: none; }
details.pw-fold > summary::before { content: ""; flex: none; border-left: 6px solid var(--muted); border-top: 5px solid transparent;
  border-bottom: 5px solid transparent; transition: transform .15s; }
details.pw-fold[open] > summary::before { transform: rotate(90deg); }
details.pw-fold > summary h3 { margin: 0; }
details.pw-fold[open] > summary { margin-bottom: var(--sp-2); }
details.pw-fold:not([open]).pw-list { flex: none; min-height: 0; }
details.pw-fold > summary .pw-outdated { margin-left: auto; }
/* 1.33.0 results page (calc.html, owner): the run row, the summary as tiles, the results fill the window */
.calc-run { padding-top: var(--sp-3); padding-bottom: var(--sp-3); }
.calc-run fieldset.run-row { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2) var(--sp-3); border: 0; padding: 0; margin: 0; }
.calc-run .run-row h1 { margin: 0 auto 0 0; font-size: var(--fs-lg); flex: 1 1 12em; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.run-pick { position: relative; }
.run-pick > summary { list-style: none; cursor: pointer; border: 1px solid var(--border); border-radius: var(--radius); padding: var(--sp-1) var(--sp-2);
  font-size: var(--fs-sm); white-space: nowrap; max-width: 19em; overflow: hidden; text-overflow: ellipsis; }
.run-pick > summary::-webkit-details-marker { display: none; }
.run-pick > summary::after { content: " ▾"; color: var(--muted); }
.run-pick > .run-menu { position: absolute; z-index: 20; top: calc(100% + 4px); right: 0; width: min(520px, 90vw); padding: var(--sp-3);
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); box-shadow: var(--shadow); }
.run-pick > .run-menu p { margin: 0 0 var(--sp-2); }
.run-seg { display: inline-flex; }
.run-seg button { border-radius: 0; margin-left: -1px; }
.run-seg button:first-child { border-radius: var(--radius) 0 0 var(--radius); margin-left: 0; }
.run-seg button:last-child { border-radius: 0 var(--radius) var(--radius) 0; }
.calc-tiles { display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)) auto; gap: var(--sp-2); margin-bottom: var(--sp-3); }
.calc-tile { padding: var(--sp-2) var(--sp-3); margin: 0; min-width: 0; }
.calc-tile .k { font-size: var(--fs-xs); color: var(--muted); line-height: 1.25; }
.calc-tile .v { font-size: var(--fs-lg); font-weight: 600; margin-top: var(--sp-1); overflow-wrap: anywhere; }
.calc-tile .v.ok { color: var(--ok-text, var(--accent)); }
.calc-tile .v.bad { color: var(--error-text); }
.calc-tile.total { border-color: var(--accent); }
.calc-bar { height: 6px; border-radius: var(--radius-pill); background: var(--surface-2); margin: var(--sp-1) 0; overflow: hidden; }
.calc-bar > i { display: block; height: 100%; background: currentColor; color: var(--accent); }
.calc-notes { display: flex; flex-direction: column; justify-content: center; align-items: flex-start; gap: var(--sp-1); }
.calc-notes:empty { display: none; }
.calc-results .results-scroll { border: 1px solid var(--border); border-radius: var(--radius); }
.calc-results table.results thead th { position: sticky; top: 0; z-index: 2; background: var(--surface-2); }
.calc-results table.results td.res-label { position: sticky; left: 0; z-index: 1; background: var(--surface); }
.calc-results table.results tr.res-section td:first-child { position: sticky; left: 0; z-index: 1; background: var(--section-bg); }
.calc-results table.results td.res-gov { font-weight: 600; font-variant-numeric: tabular-nums; }
.calc-results table.results td { --u: 0; }
.calc-results table.results td[style*="--u"] { background-image: linear-gradient(currentColor, currentColor);
  background-repeat: no-repeat; background-position: right bottom 3px; background-size: calc(var(--u) * 48px) 2px; }
.calc-results .card-head { gap: var(--sp-2); }
.calc-results .card-head h2 { margin-right: auto; }
.calc-results .m3d-links > .run-menu { width: auto; white-space: nowrap; }
.calc-results table.results tr.res-topic td:first-child { min-width: 20em; }
.calc-results .topic-toggle { white-space: nowrap; }
@media (max-width: 1100px) { .calc-tiles { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
/* 1.41.0 Admin -> rule sets: a check row whose value a release would change */
table.list tr.rule-changed td { background: var(--notice-bg); }
.rule-fields table.list input { width: 7em; }
/* 1.41.0 (owner): what lacks input stands out - the incomplete row (parts table and the photo's parts list) gets a
   tint and a bar on its left edge; the missing cell keeps its yellow and gets a border; an invalid value's field is red */
table.parts tr.incomplete > td, table.photo-rows tr.incomplete > td { background: var(--notice-bg); }
table.parts tr.incomplete > td:first-child, table.photo-rows tr.incomplete > td:first-child { box-shadow: inset 4px 0 0 var(--warn); }
table.parts td.missing input, table.parts td.missing select, .part-grid .pf.missing input, .part-grid .pf.missing select {
  background: var(--missing-bg); border-color: var(--warn); box-shadow: 0 0 0 1px var(--warn); }
table.parts td.invalid input, table.parts td.invalid select {
  background: var(--error-bg); border-color: var(--error-text); box-shadow: 0 0 0 1px var(--error-text); color: var(--error-text); }
.part-grid .pf.invalid input, .part-grid .pf.invalid select { box-shadow: 0 0 0 1px var(--error-text); }

/* 1.53.0: Admin -> appearance - the logo's height, previewed as typed (page.js data-logo-preview) */
.appearance-form { display: grid; gap: var(--sp-2); max-width: 40em; }
.appearance-row { display: flex; align-items: center; gap: var(--sp-3); }
.appearance-row input { width: 7em; }
.appearance-preview { display: inline-flex; align-items: center; min-height: 64px; padding: var(--sp-1) var(--sp-2); border: 1px dashed var(--border); border-radius: var(--radius); }
.appearance-preview .brand-logo { height: var(--preview-logo-h, var(--brand-logo-h, var(--ctl-h))); }

/* 1.54.0 - the OCL mast (templates/ocl_mast.html, static/ocl_mast.js): the left card's inputs, the wires, the results */
.ocl-grid { display: grid; grid-template-columns: 1fr; gap: var(--sp-1); margin: var(--sp-1) 0; }
.ocl-f { display: grid; grid-template-columns: 9.5em 1fr auto; align-items: center; gap: var(--sp-2); font-size: var(--fs-sm); }
.ocl-f > span:first-child { color: var(--muted); }
.ocl-f input, .ocl-f select { min-width: 0; width: 100%; }
.ocl-f .err { grid-column: 1 / -1; color: var(--bad); font-size: var(--fs-xs); }
.ocl-part > summary { font-weight: 600; }
.ocl-wire { border: 1px solid var(--border); border-radius: var(--radius-card); padding: var(--sp-1) var(--sp-2) var(--sp-2); margin: var(--sp-2) 0; }
.ocl-wire legend { font-size: var(--fs-xs); color: var(--muted); padding: 0 var(--sp-1); }
.ocl-add { display: flex; gap: var(--sp-2); margin-top: var(--sp-2); }
.ocl-add select { flex: 1; min-width: 0; }
.ocl-state { font-size: var(--fs-xs); color: var(--muted); margin-right: var(--sp-2); }
.ocl-state.err { color: var(--bad); }
.ocl-empty { position: absolute; inset: auto 0 45% 0; text-align: center; pointer-events: none; }
.ocl-table { font-size: var(--fs-xs); }
.ocl-fname { font-weight: 600; margin: var(--sp-2) 0 var(--sp-1); font-size: var(--fs-sm); }
.ocl-list .row-form { display: flex; gap: var(--sp-2); align-items: end; margin: var(--sp-3) 0; }
.ocl-tree { list-style: none; margin: 0; padding: 0; font-size: var(--fs-sm); }
.ocl-tree ul { list-style: none; margin: 0; padding: 0; }
.ocl-row { display: flex; align-items: center; gap: var(--sp-1); min-height: 24px; }
.ocl-fold, .ocl-label { background: none; border: 0; padding: 0 var(--sp-1); color: inherit; font: inherit; cursor: pointer; text-align: left; }
.ocl-fold { width: 16px; color: var(--muted); }
.ocl-fold-none { display: inline-block; width: 16px; }
.ocl-label { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; border-radius: var(--radius-pill); }
.ocl-node.sel > .ocl-row > .ocl-label { background: var(--accent-bg); color: var(--accent); font-weight: 600; }
.ocl-what { margin: 0 0 var(--sp-1); }
.ocl-add button[aria-pressed="true"] { background: var(--accent); color: var(--accent-text); }
.ocl-chooser { position: absolute; z-index: 5; width: 250px; padding: var(--sp-2); display: grid; gap: var(--sp-1); }
.ocl-chooser[hidden] { display: none; }
.ocl-chooser p { margin: 0; }
.ocl-chooser-btns { display: flex; gap: var(--sp-2); justify-content: flex-end; }

/* 1.54.0 (owner, DESIGN_RULES §3a "whatever folds shows it"): the folds that still showed the browser's own marker get
   the app's caret - right when closed, down when open (as .fold, .pw-fold, .hub-card, .cad-sec) */
.cad-howto > summary, .axes-note > summary, .s3d-fold > summary, .support-item > summary, .sag-calc > summary {
  list-style: none; display: flex; align-items: center; gap: var(--sp-2); }
.cad-howto > summary::-webkit-details-marker, .axes-note > summary::-webkit-details-marker, .s3d-fold > summary::-webkit-details-marker,
.support-item > summary::-webkit-details-marker, .sag-calc > summary::-webkit-details-marker { display: none; }
.cad-howto > summary::before, .axes-note > summary::before, .s3d-fold > summary::before, .support-item > summary::before,
.sag-calc > summary::before { content: ""; flex: none; border-left: 5px solid var(--muted); border-top: 4px solid transparent;
  border-bottom: 4px solid transparent; transition: transform .12s; }
.cad-howto[open] > summary::before, .axes-note[open] > summary::before, .s3d-fold[open] > summary::before,
.support-item[open] > summary::before, .sag-calc[open] > summary::before { transform: rotate(90deg); }
.ocl-res-pane .ocl-fem { position: absolute; inset: 0; width: 100%; height: 100%; }
.ocl-probe { position: absolute; left: var(--sp-2); bottom: var(--sp-1); margin: 0; pointer-events: none; }
/* 1.60.0 (design rules v2.0 §10): the view's caption, upper left, not interactive */
.ocl-main .s3d-window { position: relative; }
.view-caption:empty { display: none; }
#ocl-mode button[aria-pressed="true"] { background: var(--accent-bg); color: var(--accent); }
.ocl-check { display: flex; align-items: center; gap: var(--sp-2); font-size: var(--fs-sm); }
.ocl-check[hidden] { display: none; }
.f3d-solid-end { fill: var(--surface-2); fill-opacity: .55; stroke: var(--muted); stroke-width: .8; }
.f3d-solid-edge { stroke: var(--muted); stroke-width: .6; stroke-opacity: .8; }
.f3d-pivot { fill: none; stroke: var(--accent); stroke-width: 1.5; }
/* 1.55.0: the properties header's "x" (remove the picked part / mast), right-aligned in the summary */
.ocl-x { margin-left: auto; background: none; border: 0; padding: 0 var(--sp-1); font-size: var(--fs-lg); line-height: 1;
  color: var(--muted); cursor: pointer; border-radius: var(--radius); }
.ocl-x:hover { color: var(--bad); background: var(--error-bg); }
.ocl-x[hidden] { display: none; }
.ocl-add-mast { margin-top: var(--sp-1); }

/* 1.58.x (owner): the app's message box - every confirmation (data-confirm, page.js ask()) centred on the screen */
dialog.msgbox { width: min(92vw, 420px); padding: var(--sp-4); border: 1px solid var(--border); border-radius: var(--radius-card);
  background: var(--surface); color: var(--text); box-shadow: var(--shadow); }
dialog.msgbox::backdrop { background: var(--backdrop); }
.msgbox-title { font-size: var(--fs-md); margin: 0 0 var(--sp-2); }
.msgbox-text { margin: 0 0 var(--sp-4); }
.msgbox-btns { display: flex; justify-content: flex-end; gap: var(--sp-2); }
