/* Structora app shell — release feature 5.
   Layout contract: top whole-deck menu / icon tool-rail / left context table /
   center viewport / right inspector (hidden until enabled).

   Visual language (2026-06-19 reskin, matched to the Structora.ca marketing
   site): a single warm-tan "in-between" theme — a tan SHELL (topbar + icon
   rail + viewport) wrapping CREAM working panels (context table + inspector),
   with dark espresso reserved for floating viewport glass + status accents.
   Type: IBM Plex Serif (display), IBM Plex Sans (UI), IBM Plex Mono (every
   number / ratio / label). Two role families of tokens — `--chrome*` (tan
   shell) and `--panel*` (cream content). No dark/light toggle; theme.js now
   just supplies the matching Three.js scene colours. */

@import url('./fonts.css');

:root {
  /* Single warm "in-between" theme (2026-06-19 reskin) — lifted from the
     Structora.ca marketing site. The whole SHELL is now warm tan (topbar +
     icon rail + viewport) wrapping CREAM working panels, with dark espresso
     reserved for floating viewport glass + status accents. No dark/light
     toggle — one cohesive palette. */

  /* --- Shell / chrome (warm tan) --- */
  --app-bg:          #c9ba9d;   /* viewport / app field */
  --chrome:          #d4c7ac;   /* topbar */
  --chrome-rail-top: #d0c3a8;   /* icon rail gradient top */
  --chrome-rail-bot: #c7b997;   /* icon rail gradient bottom */
  --chrome-2:        #bfb093;   /* inset wells (segmented controls) */
  --chrome-border:   #b3a184;
  --on-chrome:       #2d231a;   /* dark text on the warm shell */
  --on-chrome-dim:   #5f4f3b;
  --on-chrome-faint: #877559;
  --rail-label:      #8a785e;

  /* Cream glass for chips/buttons that float over the viewport (so their
     dark --on-chrome text stays legible against the tan 3D field). */
  --vp-glass:        rgba(248,242,230,0.90);
  --vp-glass-strong: rgba(249,244,233,0.94);

  /* --- Content panels (cream) --- */
  --panel:        #e9dfc9;      /* left context table */
  --panel-2:      #f2ead9;      /* cards inside panels */
  --panel-3:      #f8f2e6;      /* input wells / deepest cream */
  --panel-border: #d8cbb0;
  --text:         #2d231a;      /* dark text on cream */
  --text-dim:     #6e5d46;
  --text-faint:   #978468;

  /* --- Accent (burnt orange — matches the site) --- */
  --accent:    #a85f2c;
  --accent-2:  #9a5a28;         /* darker hover / active-text tone (legible on light) */
  --on-accent: #f7efe2;

  /* --- Status ---
     Four states, not three. `needs` is deliberately the only NON-traffic-light
     colour: a slate blue-grey that reads as informational, so "we could not
     check this because it was not entered" stops competing with "this is close
     to its limit" (--warn) for the user's alarm. Kept warm enough not to fight
     the tan shell. */
  --good:  #5d7d39;
  --needs: #5a6b7a;
  --warn:  #a87f1c;
  --fail:  #c0492f;
  /* Soft zone fills for the "how hard it's working" track */
  --util-good: #d2dcc4;
  --util-warn: #efe2c2;
  --util-fail: #efd4c6;

  /* --- Geometry + type (IBM Plex, matching the site) --- */
  --radius:    8px;
  --radius-lg: 11px;
  --radius-sm: 6px;
  --font-ui:    'IBM Plex Sans', system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  --font-mono:  'IBM Plex Mono', ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace;
  --font-serif: 'IBM Plex Serif', Georgia, 'Times New Roman', serif;
}

* {
  box-sizing: border-box;
  scrollbar-width: thin;                            /* Firefox */
  scrollbar-color: var(--panel-border) transparent;
}
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb {
  background: var(--panel-border); border-radius: 5px;
  border: 2px solid transparent; background-clip: padding-box;
}
::-webkit-scrollbar-thumb:hover { background: var(--text-faint); }
::-webkit-scrollbar-corner { background: transparent; }

html, body {
  margin: 0; height: 100%;
  background: var(--app-bg); color: var(--on-chrome);
  font: 13px/1.45 var(--font-ui);
  overflow: hidden;
  -webkit-font-smoothing: antialiased;
}
body { display: grid; grid-template-rows: auto auto minmax(0, 1fr); }

/* ---------------------------------------------------------------- topbar */
#topbar {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap; row-gap: 6px;
  min-height: 54px; padding: 7px 16px;
  background: linear-gradient(rgba(255,255,255,0.18), rgba(90,60,25,0.05)), var(--chrome);
  border-bottom: 1px solid var(--chrome-border);
  position: relative; z-index: 30;
}
#brand {
  display: inline-flex; align-items: center; gap: 9px;
  font-size: 16px; font-weight: 700; letter-spacing: -0.02em;
  white-space: nowrap; color: var(--on-chrome);
}
/* Logo mark — two stacked rails echoing a deck frame */
#brand .brand-mark {
  display: flex; flex-direction: column; gap: 3px; width: 20px;
}
#brand .brand-mark i { height: 4px; border-radius: 2px; background: var(--accent); }
#brand .brand-mark i:last-child { width: 70%; background: var(--accent-2); }
#brand .dim { color: var(--on-chrome-faint); font-weight: 500; font-size: 12px; letter-spacing: 0; }
.topbar-sep { width: 1px; height: 24px; background: var(--chrome-border); }
#topbar .spacer { flex: 1; }
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}

/* Persistent launch-scope notice shared by the deck designer and framing prototype. */
.code-basis-notice {
  display: flex; align-items: flex-start; justify-content: center; gap: 9px;
  padding: 7px 16px; background: #f1dfb9; color: var(--on-chrome);
  border-bottom: 1px solid var(--warn); font: 500 12px/1.4 var(--font-ui);
  position: relative; z-index: 20;
}
.code-basis-notice .notice-icon { flex: 0 0 auto; color: var(--accent-2); font-weight: 700; }
.code-basis-notice > span:not(.notice-icon) { min-width: 0; }
.code-basis-notice strong { font-weight: 700; }
.code-basis-notice[hidden] { display: none; }
.code-basis-close {
  display: inline-grid; place-items: center; flex: 0 0 auto; align-self: center;
  width: 25px; height: 25px; margin: -4px -6px -4px auto; padding: 0;
  border: 1px solid transparent; border-radius: var(--radius-sm);
  background: transparent; color: var(--on-chrome-dim);
  font: 600 20px/1 var(--font-ui); cursor: pointer;
}
.code-basis-close:hover { background: rgba(45,35,26,.08); color: var(--on-chrome); }
.code-basis-close:focus-visible { outline: 2px solid var(--accent-2); outline-offset: 1px; }

@media (max-width: 700px) {
  .code-basis-notice { justify-content: flex-start; padding: 7px 10px; font-size: 11px; }
  .code-basis-close { margin-right: -3px; }
}

/* Project-local workspace switcher. The project remains loaded while these
   controls update only the workspace + assembly URL state. */
#workspace-nav {
  display: inline-flex; align-items: center; gap: 3px; padding: 2px;
  border: 1px solid var(--chrome-border); border-radius: var(--radius);
  background: var(--chrome-2);
}
#workspace-nav button, #workspace-nav select {
  min-height: 30px; border: 1px solid transparent; border-radius: var(--radius-sm);
  color: var(--on-chrome-dim); background: transparent;
  font: 600 11.5px var(--font-ui); cursor: pointer;
}
#workspace-nav button { padding: 5px 10px; }
#workspace-nav select { max-width: 220px; padding: 5px 27px 5px 9px; }
#workspace-nav button:hover, #workspace-nav select:hover { color: var(--on-chrome); border-color: var(--chrome-border); }
#workspace-nav .workspace-deck.active { color: var(--on-accent); background: var(--accent); }
#workspace-nav .workspace-add { color: var(--accent-2); }
#workspace-nav .workspace-add.locked::after {
  content: '🔒'; font-size: 9px; margin-left: 5px; opacity: .8;
}
#workspace-nav select:disabled { opacity: .55; cursor: default; }

/* mode switch — Deck vs Angled field pipelines */
.mode-switch {
  display: inline-flex; gap: 2px; padding: 2px;
  border-radius: var(--radius); background: var(--chrome-2);
  border: 1px solid var(--chrome-border);
}
.mode-switch button {
  background: transparent; border: 0; color: var(--on-chrome-dim);
  padding: 5px 11px; font: 600 12px var(--font-ui); cursor: pointer;
  white-space: nowrap; border-radius: var(--radius-sm);
}
.mode-switch button:hover { color: var(--on-chrome); }
.mode-switch button.active { background: var(--accent); color: var(--on-accent); }
/* Premium-gated control cue: the Angled mode button on a Standard license. The
   gate is enforced on click + at save (gating.js); this is just the visual hint. */
.mode-switch button.locked::after { content: '🔒'; font-size: 9px; margin-left: 5px; opacity: 0.8; }

/* Upsell toast (feature-gating, gating.js): names the premium feature + Upgrade. */
.gate-toast {
  position: fixed; left: 50%; bottom: 22px;
  transform: translateX(-50%) translateY(12px);
  display: flex; align-items: center; gap: 12px;
  max-width: min(92vw, 560px); padding: 10px 12px 10px 15px;
  background: var(--panel-2); color: var(--text);
  border: 1px solid var(--accent); border-radius: var(--radius-lg);
  box-shadow: 0 8px 28px rgba(0,0,0,0.18);
  font: 500 13px var(--font-ui);
  opacity: 0; pointer-events: none; z-index: 9999;
  transition: opacity .18s ease, transform .18s ease;
}
.gate-toast.show { opacity: 1; transform: translateX(-50%) translateY(0); pointer-events: auto; }
.gate-toast-msg { line-height: 1.35; }
.gate-toast-btn {
  flex: 0 0 auto; background: var(--accent); color: var(--on-accent); border: 0;
  padding: 6px 13px; border-radius: var(--radius-sm);
  font: 600 12.5px var(--font-ui); cursor: pointer;
  box-shadow: 0 2px 8px color-mix(in srgb, var(--accent) 35%, transparent);
}
.gate-toast-btn:hover { background: color-mix(in srgb, var(--accent) 88%, #000); }

/* whole-field dropdown menus (Field mode only — angled/topbar.js) */
#deck-menus { display: flex; gap: 2px; flex-wrap: wrap; }
#deck-menus.hidden { display: none; }
.menu { position: relative; }
.menu > button {
  background: transparent; border: 1px solid transparent; border-radius: var(--radius);
  color: var(--on-chrome-dim); padding: 6px 11px; font: 500 13px var(--font-ui); cursor: pointer;
}
.menu > button:hover, .menu.open > button {
  background: rgba(0,0,0,0.06); border-color: var(--chrome-border); color: var(--on-chrome);
}
.menu-pop {
  position: absolute; top: calc(100% + 6px); left: 0; min-width: 264px;
  max-height: calc(100vh - 96px); overflow-y: auto;
  background: var(--panel-2); color: var(--text);
  border: 1px solid var(--panel-border); border-radius: var(--radius-lg);
  padding: 14px 15px; box-shadow: 0 16px 44px rgba(0,0,0,0.45);
  display: none; z-index: 40;
}
.menu.open .menu-pop { display: block; }
.menu-pop .row {
  display: grid; grid-template-columns: 1fr auto; align-items: center;
  gap: 4px 10px; padding: 5px 0; border-bottom: 1px solid var(--panel-border);
}
.menu-pop .row:last-child { border-bottom: 0; }
.menu-pop .row > label:first-child { color: var(--text-dim); }
.menu-pop hr { border: 0; border-top: 1px solid var(--panel-border); margin: 8px 0; }
.menu-pop .hint { color: var(--text-faint); font-size: 11px; margin-top: 8px; line-height: 1.5; }

/* A list row the design is waiting on — e.g. a stair flight the code screen says
   needs a handrail. Uses the NEEDS palette, not amber: it is an unentered item,
   not a member close to its limit. */
.row-attention .val { color: var(--needs); font-weight: 600; }

/* "Name this deck" — shown once, on the first save (walkthrough #5). */
.name-backdrop {
  position: fixed; inset: 0; z-index: 60; display: grid; place-items: center;
  background: rgba(45, 35, 26, 0.34); backdrop-filter: blur(3px);
}
.name-card {
  width: min(420px, calc(100vw - 32px));
  background: var(--panel); border: 1px solid var(--panel-border);
  border-radius: var(--radius-lg); padding: 18px 18px 14px;
  box-shadow: 0 18px 48px rgba(45, 35, 26, 0.3);
}
.name-card h2 { margin: 0 0 6px; font: 600 16px var(--font-serif); color: var(--text); }
.name-card p { margin: 0 0 12px; font-size: 12.5px; color: var(--text-dim); line-height: 1.5; }
.name-card input { width: 100%; text-align: left; }
.name-actions { display: flex; justify-content: flex-end; gap: 8px; margin-top: 14px; }

/* B05 Mission 1 — one page, not a blocking wizard chain. */
.mission1-backdrop { overflow-y: auto; padding: 20px 0; }
.mission1-card { width: min(900px, calc(100vw - 32px)); padding: 24px; }
.mission1-card header { position: relative; }
.mission1-card .eyebrow { color: var(--accent); font: 700 11px var(--font-ui); text-transform: uppercase; letter-spacing: .08em; }
.mission1-card h2 { margin-top: 5px; font-size: 24px; }
.mission1-close { position: absolute; top: -8px; right: -6px; border: 0; background: transparent; color: var(--text-dim); font-size: 24px; cursor: pointer; }
.mission1-grid { display: grid; grid-template-columns: minmax(0, 1.15fr) minmax(250px, .85fr); gap: 22px; margin-top: 18px; }
.mission1-form { display: grid; grid-template-columns: 1fr 1fr; gap: 13px; }
.mission1-field { display: grid; gap: 5px; color: var(--text); font-size: 12px; }
.mission1-field:first-child { grid-column: 1 / -1; }
.mission1-field small, .mission1-choice small { color: var(--text-dim); line-height: 1.35; }
.mission1-error { min-height: 1.1em; color: var(--needs); font-size: 11px; }
/* A fieldset's error is a sibling of its radios, not a grid cell like the field
   errors above, so it needs its own block box to reserve the same space. */
.mission1-choice .mission1-error { display: block; margin-top: 8px; }
.mission1-preview { display: grid; align-content: center; gap: 10px; min-height: 280px; padding: 14px 16px; border: 1px solid var(--panel-border); border-radius: var(--radius); background: var(--bg); overflow: hidden; }
.mission1-deck-preview { display: block; width: 100%; min-height: 190px; max-height: 235px; overflow: visible; }
.mission1-deck-top { fill: color-mix(in srgb, var(--accent) 14%, var(--panel)); stroke: var(--accent); stroke-width: 2; stroke-linejoin: round; }
.mission1-deck-front, .mission1-deck-side { fill: color-mix(in srgb, var(--accent) 28%, var(--panel)); stroke: var(--accent); stroke-width: 1.5; stroke-linejoin: round; }
.mission1-deck-side { fill: color-mix(in srgb, var(--accent) 22%, var(--panel)); }
.mission1-deck-model [data-preview-posts] line { stroke: var(--accent-2); stroke-width: 5; stroke-linecap: square; }
.mission1-dimensions line { stroke: var(--text-dim); stroke-width: 1; stroke-dasharray: 3 3; }
.mission1-dimensions text { fill: var(--text); font: 700 11px var(--font-ui); text-anchor: middle; paint-order: stroke; stroke: var(--bg); stroke-width: 5px; stroke-linejoin: round; }
.mission1-dimensions [data-preview="surfaceHeight"] { text-anchor: end; dominant-baseline: middle; }
.mission1-preview p { margin: 0; }
.mission1-paid { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; margin-top: 18px; }
.mission1-choice { margin: 0; padding: 12px; border: 1px solid var(--panel-border); border-radius: var(--radius); }
.mission1-choice legend { padding: 0 5px; color: var(--text); font-weight: 700; font-size: 12.5px; }
.mission1-choice label { display: grid; grid-template-columns: 18px minmax(0, 1fr); align-items: start; gap: 9px; margin-top: 9px; font-size: 12px; }
.mission1-choice input[type="radio"] { width: 16px; height: 16px; margin: 2px 0 0; padding: 0; justify-self: start; accent-color: var(--accent); }
.mission1-choice label span { display: grid; gap: 2px; }
.mission1-footer { display: flex; align-items: center; justify-content: space-between; gap: 18px; margin-top: 16px; }
.mission1-create-help { flex: 1 1 auto; margin: 0 !important; color: var(--text-dim); }
.mission1-actions { flex: 0 0 auto; align-items: center; margin-top: 0; }
.mission1-actions button { min-height: 38px; padding: 8px 14px; border-radius: var(--radius); font: 600 12.5px var(--font-ui); cursor: pointer; white-space: nowrap; }
.mission1-actions .mission1-primary { border: 1px solid var(--accent); background: var(--accent); color: var(--on-accent); box-shadow: 0 2px 5px rgba(45, 35, 26, .15); }
.mission1-actions .mission1-primary:hover { background: var(--accent-2); border-color: var(--accent-2); }
.mission1-actions button:focus-visible { outline: 2px solid var(--accent-2); outline-offset: 2px; }
@media (max-width: 720px) {
  .mission1-grid, .mission1-paid { grid-template-columns: 1fr; }
  .mission1-form { grid-template-columns: 1fr; }
  .mission1-field:first-child { grid-column: auto; }
  .mission1-footer { flex-direction: column; align-items: stretch; }
  .mission1-actions { flex-direction: column-reverse; align-items: stretch; }
}

/* Export gate (walkthrough B6) — the failing checks are named IN the dialog,
   because the complaint was that export said nothing about them at all. */
.export-gate-card { width: min(460px, calc(100vw - 32px)); }
.export-gate-card .gate-list {
  list-style: none; margin: 0 0 12px; padding: 10px 12px;
  background: var(--bg); border: 1px solid var(--panel-border);
  border-radius: var(--radius-sm); font-size: 12.5px;
}
.export-gate-card .gate-list li {
  display: flex; justify-content: space-between; align-items: baseline; gap: 12px;
  padding: 3px 0;
}
.export-gate-card .gate-check { color: var(--text); }
.export-gate-card .gate-detail {
  color: var(--fail); font-weight: 600; font-variant-numeric: tabular-nums;
  text-align: right;
}
/* "Close to its limit" is not a failure and must not be painted like one — same
   distinction the report bands make. */
.export-gate-card[data-decision="confirm"] .gate-detail { color: var(--warn); }
.export-gate-card .gate-more { color: var(--text-dim); font-style: italic; }
.export-gate-card .gate-more .gate-detail { display: none; }
/* The actions row leads with "Show me what fails", so let it sit left of the
   dismiss/confirm pair rather than crowding them. */
.export-gate-card .name-actions { justify-content: space-between; }
.export-gate-card .name-actions [data-cancel] { margin-left: auto; }

/* verdict badge — the one rollup the everyday user needs. Clickable: it opens
   the report on whatever it is shouting about (walkthrough B10), so it needs to
   LOOK clickable too. */
.verdict {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 5px 13px 5px 11px; border-radius: 999px;
  font: 600 12.5px var(--font-ui); letter-spacing: 0.01em; white-space: nowrap;
  border: 1px solid var(--chrome-border); background: rgba(0,0,0,0.045);
  color: var(--on-chrome-dim);
  cursor: pointer; user-select: none;
}
.verdict:hover { filter: brightness(1.06); }
.verdict:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.verdict::before {
  content: ""; width: 16px; height: 16px; border-radius: 50%;
  background: var(--on-chrome-faint); flex: 0 0 auto;
}
.verdict-ok      { color: var(--good); border-color: color-mix(in srgb, var(--good) 45%, transparent); background: color-mix(in srgb, var(--good) 12%, transparent); }
.verdict-ok::before   { background: var(--good); }
.verdict-needs   { color: var(--needs); border-color: color-mix(in srgb, var(--needs) 42%, transparent); background: color-mix(in srgb, var(--needs) 11%, transparent); }
.verdict-needs::before { background: var(--needs); }
.verdict-warn    { color: var(--warn); border-color: color-mix(in srgb, var(--warn) 45%, transparent); background: color-mix(in srgb, var(--warn) 14%, transparent); }
.verdict-warn::before { background: var(--warn); }
.verdict-fail    { color: var(--fail); border-color: color-mix(in srgb, var(--fail) 50%, transparent); background: color-mix(in srgb, var(--fail) 14%, transparent); }
.verdict-fail::before { background: var(--fail); }
.verdict-unknown { color: var(--on-chrome-faint); }

/* Plain / Engineer segmented toggle (replaces the eng-view checkbox up top) */
.eng-seg {
  display: inline-flex; gap: 2px; padding: 2px;
  background: var(--chrome-2); border: 1px solid var(--chrome-border);
  border-radius: var(--radius);
}
.eng-seg button {
  border: 0; border-radius: var(--radius-sm); padding: 5px 11px; cursor: pointer;
  font: 600 12px var(--font-ui); background: transparent; color: var(--on-chrome-dim);
}
.eng-seg button:hover { color: var(--on-chrome); }
.eng-seg button.active { background: var(--accent); color: var(--on-accent); }

.api-pill {
  padding: 3px 9px; border-radius: 999px; font: 500 11px var(--font-mono);
  border: 1px solid var(--chrome-border); background: rgba(0,0,0,0.045);
  color: var(--on-chrome-faint); white-space: nowrap;
}
.api-pill-online  { color: var(--good); border-color: color-mix(in srgb, var(--good) 45%, transparent); }
.api-pill-offline { color: var(--on-chrome-faint); }
.api-pill-error   { color: var(--fail); border-color: color-mix(in srgb, var(--fail) 50%, transparent); }

/* account chip (signed-in user + sign out) */
#account { display: inline-flex; align-items: center; gap: 8px; white-space: nowrap; }
#account .who {
  color: var(--on-chrome-dim); font-size: 12px;
  max-width: 180px; overflow: hidden; text-overflow: ellipsis;
}
/* signed-in avatar (added by main.js if present) */
#account .avatar {
  width: 30px; height: 30px; border-radius: 50%; flex: 0 0 auto;
  display: grid; place-items: center; color: var(--on-accent);
  font: 600 13px var(--font-ui);
  background: linear-gradient(135deg, var(--accent-2), var(--accent));
}
.project-status {
  color: var(--on-chrome-dim); font-size: 12px;
  max-width: 200px; overflow: hidden; text-overflow: ellipsis;
}
.project-status.error { color: var(--fail); }
.buy, .buy-menu { display: inline-flex; align-items: center; gap: 6px; }
.buy.hidden, .buy-menu.hidden { display: none; }

/* ---------------------------------------------------------------- layout */
#layout {
  display: grid;
  grid-template-columns: 84px 344px minmax(0, 1fr) auto;
  min-height: 0;
}
#layout.left-panel-collapsed { grid-template-columns: 84px 0 minmax(0, 1fr) auto; }
/* ⚠ A studio KEEPS the 84px rail column (#15). Collapsing it to 0 and hiding the
   rail moved every other column sideways, so entering a studio looked like the
   whole app had been replaced — the main reason the context switch read as
   jarring. The rail stays put and is merely subdued; clicking a tool in it is a
   deliberate way out (see #tool-rail below). */
#layout.stair-workspace,
#layout.roof-workspace { grid-template-columns: 84px 344px minmax(0, 1fr) auto; }
#layout.stair-workspace.left-panel-collapsed,
#layout.roof-workspace.left-panel-collapsed { grid-template-columns: 84px 0 minmax(0, 1fr) auto; }
/* Subdued, not disabled: it says "this is still here, but you are not in it".
   Full opacity returns on hover so it never feels broken. */
#layout.stair-workspace #tool-rail,
#layout.roof-workspace #tool-rail,
#layout.member-workspace #tool-rail { opacity: .5; transition: opacity .12s ease; }
#layout.stair-workspace #tool-rail:hover,
#layout.roof-workspace #tool-rail:hover,
#layout.member-workspace #tool-rail:hover,
/* focus-within too, or a keyboard user lands on a control stuck at half opacity */
#layout.stair-workspace #tool-rail:focus-within,
#layout.roof-workspace #tool-rail:focus-within,
#layout.member-workspace #tool-rail:focus-within { opacity: 1; }
#viewport-wrap { grid-column: 3; position: relative; min-width: 0; min-height: 0; background: var(--app-bg); }
/* ⚠ `touch-action: none` IS LOAD-BEARING (mobile package M0), not a polish tweak.
   Without it the browser claims every touch drag for its own scroll and
   pinch-zoom before flyControls sees a pointermove, so the camera cannot be
   turned, panned or flown by finger at all. Scoped to the canvas ONLY — the
   panels around it must keep scrolling normally. The callout/selection rules
   stop a long press on the deck raising the iOS text-selection bubble over a
   gesture that is meant to reach the camera. */
#viewport {
  display: block; width: 100%; height: 100%;
  touch-action: none; -webkit-user-select: none; user-select: none;
  -webkit-touch-callout: none;
}
#viewport-hint {
  position: absolute; left: 50%; bottom: 14px; transform: translateX(-50%);
  background: var(--vp-glass-strong); border: 1px solid var(--chrome-border);
  border-radius: var(--radius); padding: 6px 12px; color: var(--on-chrome-dim);
  font-size: 12px; pointer-events: none;
}
#viewport-hint.hidden, .hidden { display: none; }
.workspace-context {
  position: absolute; left: 14px; top: 56px; z-index: 5;
  display: flex; align-items: center; gap: 9px; max-width: calc(100% - 28px);
  padding: 7px 9px; color: var(--on-chrome); background: var(--vp-glass-strong);
  border: 1px solid var(--accent); border-radius: var(--radius); backdrop-filter: blur(8px);
  box-shadow: 0 5px 18px rgba(0,0,0,.18);
}
.workspace-context.hidden { display: none; }
/* Focused studios keep more viewport controls visible. Their toolbar can wrap
   in the narrower centre column, so put the clickable context trail below its
   second row instead of allowing an invisible toolbar box to cover the crumbs. */
#layout.stair-workspace .workspace-context,
#layout.roof-workspace .workspace-context,
#layout.member-workspace .workspace-context { top: 92px; }
.workspace-context .workspace-kicker {
  color: var(--accent); font: 600 9px var(--font-mono); text-transform: uppercase;
  letter-spacing: .12em; white-space: nowrap;
}
.workspace-context .workspace-scope {
  flex: 0 1 38%; min-width: 0; overflow: hidden; text-overflow: ellipsis;
  color: var(--on-chrome-faint); font-size: 11px; white-space: nowrap;
}
/* Breadcrumb (#15). The ancestors LEAD the trail and read at the same weight as
   it — the old bar ended with a faint "Back to Deck", which is why the only way
   out was easy to miss. */
.workspace-crumbs {
  display: flex; flex: 1 1 auto; align-items: center; gap: 6px; min-width: 0;
  font-size: 12.5px; overflow: hidden;
}
.workspace-crumbs .crumb-link {
  color: var(--on-chrome-dim); background: transparent; border: 0; padding: 2px 4px;
  border-radius: var(--radius-sm); font: inherit; cursor: pointer; white-space: nowrap;
  text-decoration: underline; text-underline-offset: 3px;
  text-decoration-color: color-mix(in srgb, var(--accent) 55%, transparent);
}
.workspace-crumbs .crumb-link:hover { color: var(--on-chrome); background: rgba(168,95,44,0.14); }
.workspace-crumbs .crumb-link:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.workspace-crumbs .crumb {
  color: var(--on-chrome-dim); white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis;
}
.workspace-crumbs .crumb-here { color: var(--on-chrome); font-weight: 600; }
.workspace-crumbs .crumb-sep { color: var(--on-chrome-faint); font-size: 10px; }
.workspace-notice {
  position: absolute; left: 50%; top: 14px; transform: translateX(-50%); z-index: 12;
  max-width: min(560px, calc(100% - 28px)); padding: 8px 12px;
  color: var(--on-chrome); background: var(--vp-glass-strong);
  border: 1px solid var(--warn); border-radius: var(--radius); box-shadow: 0 5px 18px rgba(0,0,0,.18);
}
.workspace-notice.hidden { display: none; }
body[data-workspace="stairs"] .member-editor [data-act="close"] { display: none; }
body[data-workspace="roof"] .member-editor [data-act="close"] { display: none; }
body[data-workspace="member"] .member-editor [data-act="close"] { display: none; }

.member-piece-id {
  max-width: 12rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* viewport overlays — orbit hint (bottom-left) + view-mode chips (top-right) */
.vp-hint {
  position: absolute; left: 14px; bottom: 14px;
  font: 500 11px var(--font-mono); color: var(--on-chrome-faint);
  pointer-events: none; letter-spacing: 0.02em;
}
.view-chips {
  position: absolute; right: 14px; top: 14px; display: flex; gap: 2px; z-index: 6;
  padding: 3px; border-radius: var(--radius);
  background: var(--vp-glass); border: 1px solid var(--chrome-border);
  backdrop-filter: blur(6px);
}
.view-chips.hidden { display: none; }
.view-chips button {
  border: 0; border-radius: var(--radius-sm); padding: 5px 11px; cursor: pointer;
  font: 600 11.5px var(--font-ui); background: transparent; color: var(--on-chrome-dim);
}
.view-chips button:hover { color: var(--on-chrome); }
.view-chips button.active { background: var(--accent); color: var(--on-accent); }
.view-chips button:focus-visible {
  outline: 2px solid var(--on-chrome); outline-offset: 2px;
}
.member-view-chips { flex-wrap: wrap; justify-content: flex-end; max-width: min(430px, calc(100% - 28px)); }

.member-context-menu {
  position: fixed; z-index: 10000; min-width: 225px; padding: 6px;
  color: var(--text); background: var(--panel); border: 1px solid var(--panel-border);
  border-radius: var(--radius); box-shadow: 0 12px 34px rgba(45,35,26,.28);
}
.member-context-menu button {
  width: 100%; display: grid; gap: 2px; padding: 8px 9px; text-align: left;
  color: var(--text); background: transparent; border: 0; border-radius: var(--radius-sm);
  font: 600 12px var(--font-ui); cursor: pointer;
}
.member-context-menu button:hover,
.member-context-menu button:focus-visible { background: var(--panel-2); outline: none; }
.member-context-menu small { color: var(--text-dim); font-size: 10.5px; font-weight: 500; }

.stress-legend {
  position: absolute; right: 14px; top: 55px; z-index: 5;
  width: min(300px, calc(100% - 28px)); padding: 9px 11px 8px;
  color: var(--on-chrome-dim); background: var(--vp-glass-strong);
  border: 1px solid var(--chrome-border); border-radius: var(--radius);
  box-shadow: 0 5px 16px rgba(45,35,26,.14); backdrop-filter: blur(7px);
  pointer-events: none;
}
.stress-legend.hidden { display: none; }
.stress-legend-title { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }
.stress-legend-title strong { color: var(--on-chrome); font: 600 11.5px var(--font-ui); }
.stress-legend-title span { color: var(--on-chrome-faint); font: 500 9.5px var(--font-mono); }
.stress-legend-scale {
  height: 7px; margin-top: 7px; border-radius: 999px;
  background: linear-gradient(90deg, #3b4cbf 0%, #f2f2f2 50%, #b42d32 100%);
  box-shadow: inset 0 0 0 1px rgba(255,255,255,.18);
}
.stress-legend-labels {
  display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 6px;
  margin-top: 3px; color: var(--on-chrome-faint);
  font: 500 8.2px/1.25 var(--font-mono); white-space: nowrap;
}
.stress-legend-labels sub { font-size: .72em; }
.stress-legend-labels span:nth-child(2) { text-align: center; }
.stress-legend-labels span:last-child { text-align: right; }
.stress-legend-status {
  display: flex; align-items: center; gap: 5px; margin-top: 6px;
  color: var(--on-chrome-dim); font: 600 9px/1.2 var(--font-ui);
}
.stress-legend-status span {
  width: 8px; height: 8px; flex: 0 0 8px; border-radius: 2px;
  background: #b42d32; box-shadow: inset 0 0 0 1px rgba(255,255,255,.2);
}
.stress-legend p { margin: 6px 0 0; color: var(--on-chrome-faint); font: 500 9.5px/1.3 var(--font-ui); }

/* drag-mode read-out (feature 1): live dimension + step hints. Sits BELOW the
   viewport toolbar / view chips row (top 56px, z-index under the controls) so it
   never covers Undo/Redo or the Solid/Stress/Framing chips (Dan 2026-06-19). */
.drag-hud {
  position: absolute; left: 50%; top: 56px; transform: translateX(-50%);
  background: var(--vp-glass-strong); border: 1px solid var(--accent);
  border-radius: var(--radius); padding: 5px 12px; color: var(--on-chrome);
  font: 12px/1 var(--font-mono); pointer-events: none;
  z-index: 4; white-space: nowrap; max-width: calc(100% - 28px);
  overflow: hidden; text-overflow: ellipsis;
}

/* Boot state (walkthrough #3) — covers the canvas while there is genuinely
   nothing to draw. Opaque, because a translucent panel over an empty viewport
   still reads as an empty viewport. */
.boot-overlay {
  position: absolute; inset: 0;
  /* Above the viewport chrome (tools 6, chips 6, workspace context / bottom edit
     12) so Undo, Free drag and the view chips are not offered on an app with no
     world yet — clicking them during boot does nothing useful. Still below the
     modal backdrop (60) and the toast (9999), which must never be covered. */
  z-index: 14;
  display: grid; place-items: center;
  background: var(--bg);
  transition: opacity .28s ease;
}
/* Whole-app scope (walkthrough #4): boot can still redirect to /login/,
   /accept/ or /dashboard/, so until that is decided the designer must not be on
   screen at all. `fixed` escapes #viewport-wrap's containing block and covers
   the topbar (z 30) and panels (z 20) too; 70 clears the modal backdrop (60),
   which cannot be open this early anyway. Dropped by main.js the instant boot
   knows the user is staying. */
.boot-overlay.full { position: fixed; z-index: 70; }
/* Faded out rather than removed, so the deck appears THROUGH it instead of the
   overlay vanishing a frame before the first render lands. `visibility` (not
   `display`) keeps the transition and then takes it out of the hit-testing and
   accessibility trees, so it can never swallow a click on the viewport. */
.boot-overlay.done { opacity: 0; visibility: hidden; }
.boot-card { display: grid; justify-items: center; gap: 12px; padding: 0 24px; text-align: center; }
.boot-spinner {
  width: 26px; height: 26px; border-radius: 50%;
  border: 2px solid var(--panel-border); border-top-color: var(--accent);
  animation: boot-spin 0.9s linear infinite;
}
/* A stopped spinner would claim work is still happening after boot has given up. */
.boot-overlay.failed .boot-spinner { display: none; }
.boot-status { margin: 0; font: 600 14px var(--font-serif); color: var(--text); }
.boot-detail { margin: 0; max-width: 42ch; font-size: 12.5px; line-height: 1.5; color: var(--text-dim); }
@keyframes boot-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  .boot-spinner { animation: none; border-top-color: var(--panel-border); }
}

/* Instruction state (walkthrough B8). The gesture hints are a sentence long and
   were being cut off mid-word by the ellipsis above — "Shift-click or…" — so the
   thing the banner existed to explain was the thing you could not read. They
   wrap instead. The nowrap default is kept for the LIVE read-outs, which change
   on every pointer move and must not reflow under the cursor. */
.drag-hud.hint {
  white-space: normal;
  text-overflow: clip;
  max-width: min(620px, calc(100% - 28px));
  text-align: center;
  line-height: 1.5;
}

/* The area-load HUD shares .drag-hud's styling but must not sit on top of it —
   the free-drag HUD is absolutely positioned at the same spot. */
.area-hud { top: 92px; }

/* ----------------------------------------------------------- icon rail */
#tool-rail {
  grid-column: 1;
  background: linear-gradient(var(--chrome-rail-top), var(--chrome-rail-bot));
  border-right: 1px solid var(--chrome-border);
  overflow-y: auto; padding: 10px 0 18px;
  display: flex; flex-direction: column; align-items: stretch; gap: 2px;
  /* A grid item defaults to min-height:auto, so on a short viewport the rail
     grew past its track and CLIPPED the last tool instead of scrolling
     (walkthrough B15: "Load" cut off). min-height:0 lets overflow-y do its job. */
  min-height: 0;
  scrollbar-width: thin;
}
#tool-rail.hidden, #export-btn.hidden { display: none; }
#tool-rail .rail-label {
  font: 600 9px var(--font-mono); letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--rail-label); text-align: center; margin: 8px 0 3px;
}
#tool-rail .rail-label:first-child { margin-top: 0; }
.rail-btn {
  display: flex; flex-direction: column; align-items: center; gap: 4px;
  background: transparent; border: 0; cursor: pointer;
  color: var(--on-chrome-dim); padding: 8px 2px; margin: 0 8px;
  border-radius: var(--radius); font: 600 9.5px var(--font-ui);
}
.rail-btn svg { width: 22px; height: 22px; stroke: currentColor; fill: none;
  stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }
.rail-btn:hover { background: rgba(0,0,0,0.06); color: var(--on-chrome); }
.rail-btn.active { background: rgba(168,95,44,0.16); color: var(--accent-2); }

/* ------------------------------------------------------ left context panel */
#left-panel {
  grid-column: 2;
  background: var(--panel); color: var(--text);
  border-right: 1px solid var(--chrome-border);
  position: relative; min-width: 0; overflow: hidden;
}
#left-table {
  width: 344px; height: 100%; overflow-y: auto;
  overflow-anchor: none;
  padding: 22px 16px 24px;
}
#left-table > .panel-title:first-child { min-height: 30px; padding-right: 38px; }
#layout.left-panel-collapsed #left-panel {
  opacity: 0; border-right-width: 0; border-right-color: transparent; pointer-events: none;
}
.panel-toggle {
  width: 32px; height: 30px; padding: 0; flex: 0 0 auto;
  display: grid; place-items: center; cursor: pointer;
}
.panel-toggle svg {
  width: 18px; height: 18px; fill: none; stroke: currentColor;
  stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round;
}
.panel-toggle-close {
  position: absolute; z-index: 5; top: 22px; right: 12px;
  color: var(--text-dim); background: var(--panel-3);
  border: 1px solid var(--panel-border); border-radius: var(--radius);
}
.panel-toggle-close:hover { color: var(--accent); border-color: var(--accent); }
.panel-toggle:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
#left-panel h2, #right-panel h2 {
  font: 600 10px var(--font-mono); text-transform: uppercase; letter-spacing: 0.12em;
  color: var(--text-faint); margin: 16px 0 8px;
}
#left-panel h2:first-child { margin-top: 0; }

.edit-table { display: flex; flex-direction: column; gap: 2px; }
.edit-row {
  display: grid; grid-template-columns: 1fr auto; align-items: center;
  gap: 8px; padding: 8px 9px; border-radius: var(--radius);
  background: transparent; border: 1px solid transparent;
}
.edit-row:hover { background: var(--panel-2); }
.edit-row .name { color: var(--text); font-size: 13px; }
.edit-row .meta { color: var(--text-dim); font: 500 11.5px var(--font-mono); }
.edit-row .dot {
  width: 8px; height: 8px; border-radius: 50%; display: inline-block;
  margin-right: 8px; vertical-align: 0.5px;
  background: var(--text-faint);
}
.dot-ok    { background: var(--good); }
.dot-needs { background: var(--needs); }
.dot-warn  { background: var(--warn); }
.dot-fail  { background: var(--fail); }

.edit-row.clickable { cursor: pointer; }
.edit-row.selected { border-color: var(--accent); background: var(--panel-2); }
.edit-row .edited { color: var(--accent); font: 500 10.5px var(--font-mono); }

/* member editor / inspector card */
.member-editor {
  background: var(--panel-2); border: 1px solid var(--panel-border); border-radius: var(--radius-lg);
  padding: 13px 14px; margin-bottom: 14px;
}
.member-editor .row {
  display: grid; grid-template-columns: 1fr auto; align-items: center;
  gap: 4px 10px; padding: 6px 0; border-bottom: 1px solid var(--panel-border);
}
.member-editor .row:last-child { border-bottom: 0; }
.member-editor .row > label { color: var(--text-dim); }
.member-editor select { width: 150px; }
.member-editor .editor-actions { display: flex; gap: 6px; margin-top: 10px; }
.member-editor .editor-sub {
  margin-top: 8px; padding-top: 8px; border-top: 1px solid var(--panel-border);
}
.member-editor input[type=number] { width: 90px; }
.member-editor .editor-actions button { padding: 5px 9px; font-size: 11px; }
.add-list select { width: auto; min-width: 110px; padding: 5px 7px; }

.add-list { display: flex; flex-wrap: wrap; gap: 6px; }
.add-list button {
  background: var(--panel-2); border: 1px dashed var(--panel-border); border-radius: var(--radius);
  color: var(--text-dim); padding: 6px 11px; font: 500 12px var(--font-ui); cursor: pointer;
}
.add-list button:hover:not([disabled]) { color: var(--accent); border-color: var(--accent); }
.add-list button[disabled] { opacity: 0.45; cursor: default; }

/* section title with an accent bar (panel headers, inspector heading) */
.panel-title { display: flex; align-items: center; gap: 10px; margin-bottom: 4px; }
.panel-title .bar { flex: 0 0 auto; width: 4px; height: 20px; border-radius: 2px; background: var(--accent); }
.panel-title h2 { margin: 0; font: 700 17px var(--font-ui); letter-spacing: -0.01em; color: var(--text); text-transform: none; }
.panel-hint { margin: 6px 0 16px; font-size: 12.5px; line-height: 1.5; color: var(--text-dim); }
.control-scope-note { margin: 6px 0 12px; font-size: 11px; line-height: 1.45; color: var(--text-dim); }
.control-scope-note.deck-surface-scope {
  margin: -6px 0 14px; padding: 9px 11px; border-left: 3px solid var(--warn);
  background: color-mix(in srgb, var(--warn) 8%, transparent);
}
.deck-surface-scope strong { color: var(--warn); }
.customize-stair-callout, .custom-premium-lock {
  display: grid; gap: 7px; margin: 12px 0; padding: 11px;
  background: color-mix(in srgb, var(--accent) 8%, var(--panel-2));
  border: 1px solid color-mix(in srgb, var(--accent) 42%, var(--panel-border));
  border-radius: var(--radius);
}
.customize-stair-callout strong, .custom-premium-lock strong { color: var(--text); font-size: 12px; }
.customize-stair-callout span, .custom-premium-lock span { color: var(--text-dim); font-size: 11px; line-height: 1.4; }
.premium-locked-fields { min-width: 0; margin: 0; padding: 0; border: 0; }
.premium-locked-fields:disabled { opacity: .58; }
.custom-coverage-card {
  display: grid; gap: 3px; margin-bottom: 12px; padding: 10px 11px;
  background: color-mix(in srgb, var(--warn) 10%, var(--panel-2));
  border: 1px solid color-mix(in srgb, var(--warn) 50%, var(--panel-border));
  border-radius: var(--radius);
}
.custom-coverage-card strong { color: var(--warn); font: 700 11px var(--font-mono); letter-spacing: .08em; }
.custom-coverage-card span { color: var(--text-dim); font-size: 11px; }
.custom-member-list { display: grid; gap: 5px; }
.custom-member-list > button:not(.cta) {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  width: 100%; padding: 7px 9px; color: var(--text-dim); text-align: left;
  background: var(--panel-2); border: 1px solid var(--panel-border); border-radius: var(--radius);
}
.custom-member-list > button:not(.cta).active { color: var(--text); border-color: var(--accent); }
.custom-member-list small { color: var(--text-faint); font: 10px var(--font-mono); }
.custom-member-editor { margin-top: 12px; }
.custom-axis {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 6px;
  margin: 10px 0; padding: 8px; border: 1px solid var(--panel-border); border-radius: var(--radius);
}
.custom-axis legend { padding: 0 4px; color: var(--text-dim); font-size: 10px; }
.custom-axis label { display: grid; gap: 3px; color: var(--text-faint); font: 9px var(--font-mono); }
.custom-axis input { width: 100% !important; min-width: 0; }
.custom-limitations { margin: 12px 0; color: var(--text-dim); font-size: 11px; }
.custom-limitations summary { cursor: pointer; color: var(--text); }
.custom-limitations ul { padding-left: 18px; line-height: 1.45; }
.roof-confirmation {
  display: grid; grid-template-columns: auto 1fr; align-items: start; gap: 7px;
  margin: 7px 0; color: var(--text-dim); font-size: 11px; line-height: 1.4;
}
.roof-confirmation input { margin-top: 2px; }
.roof-preview-reasons {
  margin: 7px 0 0; padding-left: 18px; color: var(--text-dim); font-size: 11px; line-height: 1.45;
}
.roof-preview-note {
  margin: 9px 0; padding: 8px 9px; color: var(--text-dim); font-size: 10.5px; line-height: 1.4;
  border-left: 3px solid var(--warn); background: color-mix(in srgb, var(--warn) 7%, transparent);
}
.roof-reaction-list { display: grid; gap: 7px; }
.roof-reaction-card {
  display: grid; grid-template-columns: 28px minmax(0, 1fr); gap: 8px;
  padding: 8px 9px; border: 1px solid var(--panel-border); border-radius: var(--radius);
  background: color-mix(in srgb, var(--panel-2) 88%, var(--accent) 12%);
}
.roof-reaction-card > strong { color: var(--warn); font: 700 12px var(--font-mono); }
.roof-reaction-card dl { display: grid; gap: 4px; margin: 0; }
.roof-reaction-card dl > div { display: flex; justify-content: space-between; gap: 8px; }
.roof-reaction-card dt { color: var(--text-dim); font-size: 10px; }
.roof-reaction-card dd { margin: 0; color: var(--text); font: 10px var(--font-mono); white-space: nowrap; }
.member-editor .editor-actions button.danger { color: var(--fail); }

/* "How hard it's working" utilization bar */
.util { background: var(--panel-2); border: 1px solid var(--panel-border); border-radius: var(--radius-lg); padding: 12px 13px; margin: 10px 0; }
.util-head { display: flex; align-items: baseline; justify-content: space-between; margin-bottom: 9px; }
.util-label { font: 500 11.5px var(--font-ui); color: var(--text-dim); }
.util-pct { font: 600 15px var(--font-mono); color: var(--good); }
.util-pct.warn { color: var(--warn); }
.util-pct.fail { color: var(--fail); }
.util-track {
  position: relative; height: 9px; border-radius: 5px; overflow: hidden;
  background: linear-gradient(90deg,
    var(--util-good) 0%, var(--util-good) 70%,
    var(--util-warn) 70%, var(--util-warn) 85%,
    var(--util-fail) 85%, var(--util-fail) 100%);
}
.util-marker { position: absolute; top: -2px; bottom: -2px; width: 2px; background: var(--text); border-radius: 1px; }
.util-scale { display: flex; justify-content: space-between; margin-top: 5px; font: 500 9px var(--font-mono); letter-spacing: 0.06em; color: var(--text-faint); text-transform: uppercase; }
/* compact variant for result cards */
.util.mini { padding: 0; margin: 8px 0 2px; background: none; border: 0; }

/* ----------------------------------------------------------- right panel */
#right-panel {
  grid-column: 4;
  width: 330px; background: var(--panel); color: var(--text);
  border-left: 1px solid var(--chrome-border);
  overflow-y: auto; padding: 16px 16px 24px;
}
#right-panel.collapsed { display: none; }
.right-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-bottom: 4px; }
.right-head h2 { margin: 0; font: 700 17px var(--font-ui); letter-spacing: -0.01em; color: var(--text); text-transform: none; }
.eng-toggle { color: var(--text-dim); font-size: 11px; display: flex; gap: 5px; align-items: center; cursor: pointer; }
.eng-note { font: 500 10px var(--font-mono); color: var(--text-faint); margin-top: 12px; line-height: 1.5; letter-spacing: 0.02em; }

.result-card {
  background: var(--panel-2); border: 1px solid var(--panel-border); border-radius: var(--radius-lg);
  padding: 12px 13px; margin-top: 10px;
}
.result-card .head { display: flex; justify-content: space-between; align-items: baseline; gap: 8px; }
.result-card .head .name { font: 600 13.5px var(--font-ui); color: var(--text); }
.result-card .friendly { color: var(--text-dim); margin-top: 5px; line-height: 1.5; }
/* engineering numbers — always shown now (no Plain/Engineer gating); used in
   the report part cards AND the left inspector's Engineering check. */
.eng {
  margin-top: 9px; padding-top: 9px; border-top: 1px solid var(--panel-border);
  font: 11.5px/1.5 var(--font-mono); font-variant-numeric: tabular-nums;
}
.eng .kv { display: grid; grid-template-columns: 1fr auto; gap: 2px 10px; }
.eng .k { color: var(--text-faint); }
.eng .v { text-align: right; color: var(--text); }

.pill {
  display: inline-block; padding: 2px 9px; border-radius: 999px; font: 700 10.5px var(--font-mono);
  letter-spacing: 0.04em; border: 1px solid var(--panel-border); color: var(--text-dim);
}
.pill-ok    { color: var(--good); border-color: color-mix(in srgb, var(--good) 50%, transparent); background: color-mix(in srgb, var(--good) 10%, transparent); }
/* "NEEDS INPUT" is two words, so it needs to breathe a little more than OK/FAIL. */
.pill-needs { color: var(--needs); border-color: color-mix(in srgb, var(--needs) 45%, transparent); background: color-mix(in srgb, var(--needs) 9%, transparent); letter-spacing: 0.02em; }
.pill-warn { color: var(--warn); border-color: color-mix(in srgb, var(--warn) 50%, transparent); background: color-mix(in srgb, var(--warn) 12%, transparent); }
.pill-fail { color: var(--fail); border-color: color-mix(in srgb, var(--fail) 55%, transparent); background: color-mix(in srgb, var(--fail) 12%, transparent); }

.error-box {
  margin-top: 12px; padding: 10px 12px; border-radius: var(--radius-lg);
  border: 1px solid color-mix(in srgb, var(--fail) 55%, transparent); color: var(--fail); font-size: 12px;
  background: color-mix(in srgb, var(--fail) 8%, transparent);
}

/* --------------------------------------------------------------- inputs */
input[type=number], input[type=text], select {
  background: var(--panel-3); color: var(--text);
  border: 1px solid var(--panel-border); border-radius: var(--radius-sm);
  padding: 5px 8px; font: inherit; width: 108px; text-align: right;
  font-variant-numeric: tabular-nums;
}
select { text-align: left; width: 126px; }
/* Custom chevron for the cream-panel selects so long values (e.g.
   "Deck default (2x8)") clear the dropdown arrow instead of running under the
   native OS arrow. Scoped with :not(.vp-select) so the dark-chrome viewport
   select keeps its native arrow. */
select:not(.vp-select) {
  appearance: none; -webkit-appearance: none; -moz-appearance: none;
  padding-right: 26px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='11' height='11' viewBox='0 0 12 12'%3E%3Cpath d='M2.5 4.5l3.5 3.5 3.5-3.5' fill='none' stroke='%237c6a52' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 9px center;
}
input:focus, select:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent) 22%, transparent); }
input[type=checkbox] { accent-color: var(--accent); }

/* primary CTA — full-width accent action (panel footers) */
.cta {
  width: 100%; margin-top: 4px; padding: 11px; border: 0; border-radius: var(--radius);
  background: var(--accent); color: var(--on-accent); font: 600 13.5px var(--font-ui);
  cursor: pointer; box-shadow: 0 2px 8px color-mix(in srgb, var(--accent) 35%, transparent);
}
.cta:hover { background: color-mix(in srgb, var(--accent) 88%, #000); }
/* An ARMED call-to-action: the app is waiting on a viewport gesture (placing a
   load area). Reads as "cancel this" rather than "do it again" — hollow, so it
   is clearly not the same button state that started the action. */
.cta.armed {
  background: transparent; color: var(--accent-2);
  box-shadow: inset 0 0 0 1.5px var(--accent);
}
.cta.armed:hover { background: rgba(168,95,44,0.12); }

button.ghost {
  background: rgba(0,0,0,0.045); color: var(--on-chrome-dim);
  border: 1px solid var(--chrome-border); border-radius: var(--radius);
  padding: 6px 12px; font: 500 12.5px var(--font-ui); cursor: pointer;
}
button.ghost:hover { border-color: var(--accent); color: var(--on-chrome); }
button.ghost[aria-pressed="true"] { color: var(--accent-2); border-color: var(--accent); background: rgba(168,95,44,0.14); }
/* ghost buttons inside the cream panels (e.g. member editor) read on cream */
#left-panel button.ghost, #right-panel button.ghost {
  background: var(--panel-3); color: var(--text-dim);
  border-color: var(--panel-border);
}
#left-panel button.ghost:hover, #right-panel button.ghost:hover { color: var(--accent); border-color: var(--accent); }

/* ---------------------------------------- left tool panels (toolPanels.js) */
.tool-group { margin-bottom: 4px; }
.tool-group .group-label,
.parts-group .group-label {
  font: 600 10px var(--font-mono); letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--text-faint); margin: 16px 0 6px;
}
.tool-group:first-of-type .group-label { margin-top: 10px; }
.tool-group .row {
  display: grid; grid-template-columns: 1fr auto; align-items: center;
  gap: 4px 10px; padding: 7px 0; border-bottom: 1px solid var(--panel-border);
}
.tool-group .row:last-child { border-bottom: 0; }
.tool-group .row > label { color: var(--text-dim); font-size: 12.5px; }
.tool-group .row input, .tool-group .row select { width: 160px; }
.tool-group .row.read .val { color: var(--text); font: 500 12.5px var(--font-mono); text-align: right; }
.tool-group .row .val.muted { color: var(--text-faint); }
.clickable-row { cursor: pointer; }
.clickable-row:hover > label, .clickable-row:hover .val { color: var(--accent); }
.tool-group .row [data-open-stair] { grid-column: 1 / -1; justify-self: stretch; }

/* ---------------------------------------- right: status card + parts list */
.status-card {
  border: 1px solid var(--panel-border); border-radius: var(--radius-lg);
  padding: 14px 15px; margin-bottom: 14px;
}
.status-head { display: flex; align-items: center; gap: 10px; margin-bottom: 8px; }
.status-ico {
  width: 26px; height: 26px; border-radius: 50%; flex: 0 0 auto;
  display: grid; place-items: center; color: #fff; font: 700 15px var(--font-ui);
}
.status-label { font: 700 16px var(--font-ui); letter-spacing: -0.01em; }
.status-sub { font-size: 13px; line-height: 1.55; color: var(--text-dim); }
.report-scope { margin: -3px 0 16px; padding: 9px 11px; border-left: 3px solid var(--warn); background: color-mix(in srgb, var(--warn) 8%, transparent); font-size: 11.5px; line-height: 1.5; color: var(--text-dim); }
/* Host-deck lock note (#15). Accent, not amber: the deck being read-only while
   you edit a stair on it is information, not a deficiency in the design. */
.report-lock { margin: -6px 0 12px; padding: 8px 11px; border-left: 3px solid var(--accent); background: rgba(168,95,44,0.10); font-size: 11.5px; line-height: 1.5; color: var(--text-dim); }
.status-ok   { background: color-mix(in srgb, var(--good) 13%, var(--panel)); border-color: color-mix(in srgb, var(--good) 38%, transparent); }
.status-ok   .status-ico { background: var(--good); } .status-ok .status-label { color: var(--good); }
.status-needs { background: color-mix(in srgb, var(--needs) 12%, var(--panel)); border-color: color-mix(in srgb, var(--needs) 36%, transparent); }
.status-needs .status-ico { background: var(--needs); } .status-needs .status-label { color: var(--needs); }
.status-warn { background: color-mix(in srgb, var(--warn) 14%, var(--panel)); border-color: color-mix(in srgb, var(--warn) 40%, transparent); }
.status-warn .status-ico { background: var(--warn); } .status-warn .status-label { color: var(--warn); }
.status-fail { background: color-mix(in srgb, var(--fail) 13%, var(--panel)); border-color: color-mix(in srgb, var(--fail) 42%, transparent); }
.status-fail .status-ico { background: var(--fail); } .status-fail .status-label { color: var(--fail); }

/* Standard-deck path: a game-like sense of progress without turning report
   coverage into a score for structural safety. It uses the report's existing
   bands and points to exactly one next card. */
.workflow-card {
  --workflow-tone: var(--accent);
  margin: -2px 0 14px; padding: 12px 13px; border: 1px solid var(--panel-border);
  border-top: 3px solid var(--workflow-tone); border-radius: var(--radius-lg);
  background: var(--panel-2);
}
.workflow-fail { --workflow-tone: var(--fail); }
.workflow-warn { --workflow-tone: var(--warn); }
.workflow-needs { --workflow-tone: var(--needs); }
.workflow-ok { --workflow-tone: var(--good); }
.workflow-meta, .workflow-score {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  font: 600 9.5px var(--font-mono); letter-spacing: .08em; text-transform: uppercase;
  color: var(--text-faint);
}
.workflow-steps { display: grid; grid-template-columns: repeat(4, 1fr); gap: 4px; margin: 10px 0 8px; }
.workflow-step {
  display: flex; flex-direction: column; align-items: center; gap: 4px;
  min-width: 0; color: var(--text-faint); font: 600 9.5px var(--font-mono);
}
.workflow-step-mark {
  width: 21px; height: 21px; display: grid; place-items: center;
  border: 1px solid var(--panel-border); border-radius: 50%; background: var(--panel);
  color: var(--text-faint); font-size: 10px;
}
.workflow-step.complete { color: var(--good); }
.workflow-step.complete .workflow-step-mark { color: #fff; border-color: var(--good); background: var(--good); }
.workflow-step.current { color: var(--workflow-tone); }
.workflow-step.current .workflow-step-mark {
  color: var(--workflow-tone); border-color: var(--workflow-tone);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--workflow-tone) 14%, transparent);
}
.workflow-score { padding: 7px 0 9px; border-bottom: 1px solid var(--panel-border); }
.workflow-next-label {
  margin-top: 10px; color: var(--workflow-tone);
  font: 700 9.5px var(--font-mono); letter-spacing: .1em; text-transform: uppercase;
}
.workflow-next-title { margin-top: 3px; color: var(--text); font: 650 14px var(--font-ui); }
.workflow-card p { margin: 4px 0 10px; color: var(--text-dim); font-size: 11.5px; line-height: 1.45; }
.workflow-action { width: 100%; }
/* Mission 2's compact site-basis sequence (B06). Sits directly under the
   guidance strip and shares its chrome, because it IS the same card advancing
   in place rather than a second panel competing with it. */
.mission2-card {
  margin-top: 10px; padding: 11px 12px 12px;
  border: 1px solid var(--panel-border); border-radius: var(--radius);
  background: var(--panel);
}
.m2-question { margin-top: 8px; color: var(--text); font: 650 13.5px var(--font-ui); }
.m2-helper { margin: 4px 0 9px; color: var(--text-dim); font-size: 11.5px; line-height: 1.45; }
.m2-choices { display: grid; gap: 6px; }
.m2-choice {
  padding: 8px 10px; border: 1px solid var(--panel-border); border-radius: var(--radius);
  background: var(--bg); color: var(--text); font: 500 12px var(--font-ui);
  text-align: left; cursor: pointer;
}
.m2-choice:hover { border-color: var(--accent); }
.m2-choice:focus-visible { outline: 2px solid var(--accent-2); outline-offset: 2px; }
.m2-answered { margin: 10px 0 0; padding: 9px 0 0; border-top: 1px solid var(--panel-border); list-style: none; }
.m2-answered li {
  display: grid; grid-template-columns: minmax(0, 1fr) auto auto; gap: 8px;
  align-items: baseline; padding: 3px 0; color: var(--text-dim); font-size: 11.5px;
}
.m2-answered strong { color: var(--text); font-weight: 600; }
.m2-change {
  border: 0; background: transparent; color: var(--accent);
  font: 600 11.5px var(--font-ui); cursor: pointer; padding: 0;
}
.m2-change:focus-visible { outline: 2px solid var(--accent-2); outline-offset: 2px; }
/* Mission 3's supported-surface claims. Deliberately a plain list rather than a
   product card grid: there is one implemented surface, and a grid of one reads
   as a chooser with the other options missing. */
.m3-claims { margin: 8px 0 10px; padding-left: 18px; color: var(--text-dim); font-size: 11.5px; line-height: 1.5; }
.m3-claims li { margin: 2px 0; }

/* Mission 6's foundation plan. The bounded summary is a label/value list that
   stays visible after every question is answered: the parts Structora never
   modelled do not stop existing once the ones it did modelled pass. */
.m6-summary {
  margin: 10px 0 0; padding: 9px 0 0; border-top: 1px solid var(--panel-border);
  list-style: none;
}
.m6-summary li {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.25fr); gap: 8px;
  align-items: baseline; padding: 3px 0; font-size: 11.5px; line-height: 1.4;
}
.m6-line-label { color: var(--text-dim); }
.m6-line-value { color: var(--text); font-weight: 600; }
/* A choice that carries its own caveat. */
.m6-choice-note {
  display: block; margin-top: 3px; color: var(--text-faint);
  font-size: 11px; font-weight: 400; line-height: 1.35;
}
/* ⚠ Shown and EXPLAINED, never hidden. Silently dropping a system the user has
   seen built would leave them wondering where it went. */
.m6-choice-blocked { opacity: 0.6; cursor: default; }
.m6-choice-blocked:hover { border-color: var(--panel-border); }
/* Mission 6's outcome. ⚠ The concept-package outcome is NOT a failure and is not
   tinted like one — it says what the design can still do. The permit outcome is
   not green either: survey, zoning and authority review are all still outside it. */
.m6-outcome { border-left: 3px solid var(--panel-border); }
.m6-outcome-permit_ready { border-left-color: var(--good); }
.m6-outcome-concept_only { border-left-color: var(--needs); }
.m6-outcome .m2-question { margin-top: 0; }
/* The planning-size search. Sits under the summary because it is a STATE ("there
   is no size yet"), not a step in the question sequence. */
.m6-pad-search { margin-top: 10px; padding-top: 9px; border-top: 1px solid var(--panel-border); }
.m6-pad-search .m2-choice { width: 100%; }
.m6-pad-found { color: var(--good); font: 650 12.5px var(--font-ui); margin-bottom: 3px; }

/* Mission 5's framing proposal (B10). A read-only description of the system, so
   it is a label/summary list rather than the answered-question grid Missions 2-4
   use — there is nothing here to change from this card. */
.m5-parts { margin: 9px 0 10px; padding: 9px 0 0; border-top: 1px solid var(--panel-border); list-style: none; }
.m5-parts li {
  display: grid; grid-template-columns: 84px minmax(0, 1fr); gap: 8px;
  align-items: baseline; padding: 3px 0; font-size: 11.5px; line-height: 1.45;
}
.m5-part { color: var(--text); font-weight: 600; }
.m5-summary { color: var(--text-dim); }
/* Mission 5's two per-row links (B13). They sit in the SUMMARY column so the
   84px label column stays a label column, and the detail block below them lines
   up with the text it belongs to rather than with the part name. */
.m5-links { grid-column: 2; display: flex; flex-wrap: wrap; gap: 12px; margin: 1px 0 2px; }
.m5-link {
  border: 0; background: transparent; color: var(--accent);
  font: 600 11px var(--font-ui); cursor: pointer; padding: 0; text-align: left;
}
.m5-link:focus-visible { outline: 2px solid var(--accent-2); outline-offset: 2px; }
/* The construction detail: a quantities read-out, so it is a label/value list
   like the engineering blocks elsewhere rather than another card. */
.m5-detail {
  grid-column: 2; margin: 2px 0 6px; padding: 7px 9px;
  border: 1px solid var(--panel-border); border-radius: 6px; background: var(--panel-2, transparent);
}
.m5-detail-head {
  color: var(--text-faint); font-size: 10px; font-weight: 700;
  text-transform: uppercase; letter-spacing: .04em; margin: 4px 0 3px;
}
.m5-detail-head:first-child { margin-top: 0; }
.m5-detail-list { margin: 0; padding: 0; list-style: none; }
.m5-detail-list li {
  display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 10px;
  align-items: baseline; padding: 1px 0; font-size: 11px; line-height: 1.4;
  color: var(--text-dim);
}
.m5-detail-list strong { color: var(--text); font-weight: 600; white-space: nowrap; }
.m5-detail-empty { display: block !important; color: var(--text-faint); font-style: italic; }
/* Scope, never optional: an omitted limit reads as a limit that does not apply. */
.m5-detail-scope { margin: 6px 0 0; color: var(--text-faint); font-size: 10.5px; line-height: 1.4; }
/* A bill category no system part claimed. Stated rather than dropped. */
.m5-orphans { margin: 0 0 8px; color: var(--text-faint); font-size: 11px; line-height: 1.4; }

/* The stale state is PROGRESS, not a control: the app is already re-solving, so
   a button here would do visibly nothing. */
.m5-progress { margin: 0; color: var(--text-faint); font-size: 11.5px; font-style: italic; }
/* Follows the load-path highlight, one beat at a time. Reserves its line so the
   card does not jump as the caption appears and clears. */
.m5-caption {
  margin: 8px 0 0; min-height: 15px; color: var(--accent);
  font-size: 11.5px; line-height: 1.3;
}

/* The Review surface (B13). Deliberately QUIET: everything in it is external
   future work, so it borrows none of the status colours. Red is reserved for a
   real modeled failure, and an unanswered future observation is not one. */
.review-card {
  margin: 10px 0; padding: 10px 11px; border: 1px solid var(--panel-border);
  border-radius: 8px; background: transparent;
}
.review-band { margin: 9px 0 0; }
.review-band-label {
  color: var(--text-faint); font-size: 10px; font-weight: 700;
  text-transform: uppercase; letter-spacing: .04em; margin: 0 0 4px;
}
.review-items { margin: 0; padding: 0; list-style: none; }
.review-items li {
  padding: 6px 0; border-top: 1px solid var(--panel-border); font-size: 11.5px;
  line-height: 1.45;
}
.review-items li:first-child { border-top: 0; }
.review-item-top {
  display: flex; gap: 8px; align-items: baseline; justify-content: space-between;
}
.review-item-title { color: var(--text); font-weight: 600; }
.review-state {
  flex: none; font-size: 10px; font-weight: 700; text-transform: uppercase;
  letter-spacing: .03em; color: var(--text-faint); white-space: nowrap;
}
/* Evidence recorded is a real step forward, so it reads slightly warmer than
   Open — but never as a pass, and never green. */
.review-state-evidence_recorded { color: var(--text-dim); }
.review-why { margin: 3px 0 0; color: var(--text-dim); }
/* The value in use is shown WITH its outstanding confirmation, never instead. */
.review-assumption { margin: 3px 0 0; color: var(--text-dim); }
.review-assumption strong { color: var(--text); font-weight: 600; }
.review-meta { margin: 3px 0 0; color: var(--text-faint); font-size: 10.5px; }
/* Why there is no checkbox. Stated, not silently absent. */
.review-note {
  margin: 10px 0 0; padding: 7px 0 0; border-top: 1px solid var(--panel-border);
  color: var(--text-faint); font-size: 10.5px; line-height: 1.45;
}

/* Landing feedback for a Next move that opened the left editor. The focus ring
   stays on the actual input; this brief row pulse answers "where did it go?". */
.workflow-target-focus {
  border-radius: var(--radius-sm);
  outline: 2px solid color-mix(in srgb, var(--accent) 72%, transparent);
  outline-offset: 2px;
  animation: workflow-target-pulse 5.2s ease-out;
}
@keyframes workflow-target-pulse {
  0%, 46% { background: color-mix(in srgb, var(--accent) 25%, transparent); box-shadow: 0 0 0 5px color-mix(in srgb, var(--accent) 19%, transparent); }
  100% { background: transparent; box-shadow: 0 0 0 0 transparent; outline-color: transparent; }
}
@media (prefers-reduced-motion: reduce) {
  .workflow-target-focus { animation: none; background: color-mix(in srgb, var(--accent) 16%, transparent); }
}

.parts-head { display: flex; align-items: baseline; justify-content: space-between; margin: 4px 2px 2px; }
.parts-head > span:first-child { font: 700 15px var(--font-ui); letter-spacing: -0.01em; color: var(--text); }
.parts-count { font: 500 11.5px var(--font-mono); color: var(--text-faint); }
.parts-group { margin-bottom: 2px; }
.part-row {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  padding: 8px 9px; border-radius: var(--radius); cursor: pointer;
  border: 1px solid transparent;
}
.part-row:hover { background: var(--panel-2); }
.part-row.selected { background: var(--panel-2); border-color: var(--accent); box-shadow: inset 3px 0 0 var(--accent); }
.part-name { display: flex; align-items: center; font-size: 13px; color: var(--text); }
.part-meta { display: flex; align-items: center; gap: 9px; }
.part-note { font-size: 11.5px; color: var(--text-dim); }
.part-pct { font: 500 11.5px var(--font-mono); color: var(--text-dim); display: none; }
body.eng-view .part-pct { display: inline; }

/* ---------------------------------------- viewport overlay controls */
.vp-tools {
  position: absolute; left: 14px; top: 14px; display: flex; flex-wrap: wrap; gap: 6px; z-index: 6;
  max-width: calc(100% - 210px);
}
.vp-btn {
  background: var(--vp-glass); border: 1px solid var(--chrome-border);
  color: var(--on-chrome-dim); border-radius: var(--radius);
  padding: 6px 11px; font: 600 11.5px var(--font-ui); cursor: pointer;
  backdrop-filter: blur(6px);
}
.vp-btn.panel-toggle { padding: 0; }
.vp-btn:hover { color: var(--on-chrome); }
.vp-btn[aria-pressed="true"] { background: var(--accent); color: var(--on-accent); border-color: var(--accent); }
.vp-btn:disabled { opacity: 0.4; cursor: default; }
.vp-btn:disabled:hover { color: var(--on-chrome-dim); }
.vp-btn.hidden { display: none; }
.vp-select {
  background: var(--vp-glass); border: 1px solid var(--chrome-border);
  color: var(--on-chrome-dim); border-radius: var(--radius);
  padding: 5px 7px; font: 600 11.5px var(--font-ui); cursor: pointer;
  backdrop-filter: blur(6px);
}
.vp-select:hover { color: var(--on-chrome); }
.vp-select:disabled { opacity: 0.45; cursor: default; }
.vp-select.hidden { display: none; }

/* ------------------------------------------------ imported site tool window
   Non-modal on purpose: its controls stay separate from the inspector while
   the canvas remains directly clickable for ground/wall/reference picks. */
.site-model-window {
  position: absolute; right: 14px; top: 58px; z-index: 12;
  width: min(370px, calc(100% - 28px)); max-height: calc(100% - 76px); overflow: hidden;
  display: grid; grid-template-rows: auto minmax(0, 1fr);
  background: color-mix(in srgb, var(--panel) 96%, transparent); color: var(--text);
  border: 1px solid var(--panel-border); border-radius: var(--radius-lg);
  box-shadow: 0 16px 44px rgba(45,35,26,0.28); backdrop-filter: blur(10px);
}
.site-model-window.hidden { display: none; }
.site-model-window > header {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 12px 14px 10px; border-bottom: 1px solid var(--panel-border);
  background: var(--panel-2);
}
.site-model-window .eyebrow {
  display: block; margin-bottom: 1px; color: var(--text-faint);
  font: 600 9px var(--font-mono); letter-spacing: .13em; text-transform: uppercase;
}
.site-model-window h2 { margin: 0; color: var(--text); font: 700 17px var(--font-serif); }
#site-model-close {
  width: 28px; height: 28px; border: 1px solid var(--panel-border); border-radius: 50%;
  background: var(--panel-3); color: var(--text-dim); cursor: pointer; font: 20px/1 var(--font-ui);
}
#site-model-close:hover { color: var(--accent); border-color: var(--accent); }
#site-model-body { overflow-y: auto; padding: 12px 14px 15px; }
.site-intro { margin: 0 0 11px; color: var(--text-dim); line-height: 1.5; }
.site-scope-note {
  margin: 10px 0; padding: 8px 10px; border-left: 3px solid var(--warn);
  background: color-mix(in srgb, var(--warn) 9%, var(--panel)); color: var(--text-dim);
  font-size: 11.5px; line-height: 1.45;
}
.site-file-row { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 10px; }
.site-file-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font: 500 11px var(--font-mono); color: var(--text-dim); }
.site-step {
  margin-top: 9px; padding: 10px; background: var(--panel-2);
  border: 1px solid var(--panel-border); border-radius: var(--radius);
}
.site-step-head { display: flex; justify-content: space-between; align-items: baseline; gap: 8px; }
.site-step-title { font-weight: 650; color: var(--text); }
.site-step-count { font: 500 10px var(--font-mono); color: var(--text-faint); }
.site-step p { margin: 4px 0 8px; color: var(--text-dim); font-size: 11.5px; line-height: 1.4; }
.site-step-actions { display: flex; align-items: center; gap: 7px; flex-wrap: wrap; }
.site-step-actions input[type=number] { width: 90px; }
.site-step-actions .unit { color: var(--text-faint); font: 500 10px var(--font-mono); }
.site-action {
  border: 1px solid var(--panel-border); border-radius: var(--radius-sm); padding: 6px 9px;
  background: var(--panel-3); color: var(--text-dim); cursor: pointer; font: 600 11.5px var(--font-ui);
}
.site-action:hover { color: var(--accent); border-color: var(--accent); }
.site-action[aria-pressed="true"] { background: var(--accent); color: var(--on-accent); border-color: var(--accent); }
.site-action.primary { background: var(--accent); color: var(--on-accent); border-color: var(--accent); }
.site-action.primary:disabled { opacity: .45; cursor: default; }
.site-action.danger { color: var(--fail); }
.site-presentation { display: grid; grid-template-columns: auto 1fr auto; align-items: center; gap: 8px; margin: 8px 0; }
.site-presentation input[type=range] { width: 100%; accent-color: var(--accent); }
.site-presentation output { width: 34px; text-align: right; font: 500 10px var(--font-mono); color: var(--text-dim); }
.site-status { margin: 10px 0 0; padding: 8px 10px; border-radius: var(--radius-sm); font-size: 11.5px; line-height: 1.45; }
.site-status.good { background: color-mix(in srgb, var(--good) 12%, var(--panel)); color: var(--good); }
.site-status.warn { background: color-mix(in srgb, var(--warn) 12%, var(--panel)); color: var(--warn); }
.site-status.fail { background: color-mix(in srgb, var(--fail) 10%, var(--panel)); color: var(--fail); }
.site-footer-actions { display: flex; justify-content: space-between; gap: 8px; margin-top: 11px; }

@media (max-width: 780px) {
  #workspace-nav { order: 10; flex: 1 1 100%; }
  #workspace-nav .workspace-picker { flex: 1; }
  #workspace-nav select { width: 100%; max-width: none; }
  .vp-tools { max-width: calc(100% - 28px); }
  .site-model-window { top: 96px; max-height: calc(100% - 112px); }
  .workspace-context { top: 92px; }
  .workspace-context .workspace-scope { display: none; }
}

/* Bottom aspect toolbar — a small rounded pill of icon/label buttons for the
   selected part; clicking one opens that control on the LEFT table. */
.bottom-edit {
  position: absolute; left: 50%; transform: translateX(-50%); bottom: 16px; z-index: 6;
  display: flex; align-items: stretch; gap: 2px;
  background: var(--vp-glass-strong); border: 1px solid var(--chrome-border);
  border-radius: 14px; padding: 6px; backdrop-filter: blur(8px);
  box-shadow: 0 6px 20px rgba(0,0,0,0.28);
}
.bottom-edit.hidden { display: none; }
.aspect-btn {
  display: flex; flex-direction: column; align-items: center; gap: 4px;
  background: transparent; border: none; cursor: pointer;
  color: var(--on-chrome-dim); padding: 7px 14px; border-radius: 9px;
  font: 600 11px var(--font-ui);
}
.aspect-btn svg { width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }
.aspect-btn:hover { color: var(--on-chrome); }
.aspect-btn.active { background: var(--accent); color: var(--on-accent); }
/* a length field with its ⅛" steppers */
.len-field { display: flex; align-items: stretch; gap: 0; }
.len-field input { border-radius: var(--radius) 0 0 var(--radius); }
.len-step {
  border: 1px solid var(--panel-border); border-left: none; background: var(--panel-2);
  color: var(--text-dim); cursor: pointer; font: 600 12px var(--font-ui);
  width: 22px; display: grid; place-items: center;
}
.len-step:last-child { border-radius: 0 var(--radius) var(--radius) 0; }
.len-step:hover { color: var(--text); border-color: var(--accent); }
.len-step { flex: 0 0 auto; }
/* The custom − / + steppers replace the browser's native number spinner on any
   field we wrap, so suppress the spinner to avoid a doubled control. */
.len-field input[type=number]::-webkit-outer-spin-button,
.len-field input[type=number]::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.len-field input[type=number] { -moz-appearance: textfield; appearance: textfield; }
/* Keep a stepped field in the tool panel the same overall width as a plain one
   (160px = 116px input + two 22px steppers) so labels and controls stay aligned. */
.tool-group .row .len-field input { width: 116px; }

/* top-bar icon button (theme) + API status dot */
.icon-btn {
  background: rgba(0,0,0,0.045); border: 1px solid var(--chrome-border);
  color: var(--on-chrome-dim); border-radius: var(--radius);
  width: 32px; height: 30px; cursor: pointer; font-size: 14px;
  display: grid; place-items: center;
}
.icon-btn:hover { color: var(--on-chrome); border-color: var(--accent); }
/* "Export" is a text label, not a 2-char icon — let the button size to its
   content (incl. the transient "Exporting…/Exported ✓/Export failed" states)
   instead of the fixed 32px icon square, which clipped the label and ran it
   into the API status dot. */
#export-btn { width: auto; padding: 0 12px; }
.api-dot { width: 8px; height: 8px; border-radius: 50%; display: inline-block; background: var(--on-chrome-faint); flex: 0 0 auto; }
.api-dot-online { background: var(--good); }
.api-dot-offline { background: var(--on-chrome-faint); }
.api-dot-error { background: var(--fail); }

/* Report toggle (top bar) — shows / hides the right-hand report panel */
.report-toggle {
  background: rgba(0,0,0,0.045); border: 1px solid var(--chrome-border);
  color: var(--on-chrome-dim); border-radius: var(--radius);
  padding: 6px 13px; font: 600 12.5px var(--font-ui); cursor: pointer;
}
.report-toggle:hover { color: var(--on-chrome); border-color: var(--accent); }
.report-toggle[aria-pressed="true"] { background: var(--accent); color: var(--on-accent); border-color: var(--accent); }

/* Report part CARDS — friendly verdict + always-on engineering numbers */
.part-card {
  background: var(--panel-2); border: 1px solid var(--panel-border);
  border-left: 3px solid transparent; border-radius: var(--radius);
  padding: 11px 12px; margin-bottom: 8px; cursor: pointer;
}
.part-card:hover { border-color: var(--accent); }
.part-card.selected { border-color: var(--accent); border-left-color: var(--accent); }
.part-card.next-card { border-left-color: var(--accent); }
.part-card-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.part-card .part-name { display: flex; align-items: center; font: 600 13px var(--font-ui); color: var(--text); }
.next-tag {
  margin-left: 7px; padding: 1px 5px; border-radius: 999px;
  background: color-mix(in srgb, var(--accent) 13%, transparent); color: var(--accent);
  font: 700 8.5px var(--font-mono); letter-spacing: .08em;
}
.part-card .part-note { font-size: 11.5px; color: var(--text-dim); margin-top: 3px; }
.part-card .util.mini { margin: 8px 0 0; }
.part-card-top { cursor: pointer; }
.card-right { display: flex; align-items: center; gap: 8px; flex: 0 0 auto; }
.chev { color: var(--text-faint); font-size: 10px; width: 10px; text-align: center; }
.card-next-step {
  margin: 10px 0 2px; padding: 10px 11px; cursor: default;
  border: 1px solid color-mix(in srgb, var(--accent) 34%, var(--panel-border));
  border-radius: var(--radius-sm); background: color-mix(in srgb, var(--accent) 8%, var(--panel));
}
.card-next-label {
  color: var(--accent); font: 700 9px var(--font-mono);
  letter-spacing: .1em; text-transform: uppercase;
}
.card-next-title { margin-top: 3px; color: var(--text); font: 650 12.5px var(--font-ui); }
.card-next-body { margin: 4px 0 9px; color: var(--text-dim); font-size: 11px; line-height: 1.45; }

/* drill-down: group → member sub-list → full-detail block */
.sub-list { margin: 9px 0 2px; padding-top: 7px; border-top: 1px solid var(--panel-border); display: flex; flex-direction: column; gap: 1px; }
.sub-row { display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 5px 7px; border-radius: var(--radius-sm); cursor: pointer; border: 1px solid transparent; }
.sub-row:hover { background: var(--panel-3); }
.sub-row.selected { background: var(--panel-3); border-color: var(--accent); }
.sub-name { display: flex; align-items: center; font-size: 12px; color: var(--text); }
.sub-name .dot { width: 6px; height: 6px; margin-right: 7px; }
.sub-meta { display: flex; align-items: center; gap: 7px; }
.sub-pct { font: 500 11px var(--font-mono); }
.member-detail { margin: 4px 2px 10px 14px; cursor: pointer; }   /* click anywhere to collapse */
.member-detail:hover { opacity: 0.92; }
.member-detail .eng { margin-top: 0; padding-top: 6px; }   /* inspector fallback */
.detail-group-label { font: 600 9.5px var(--font-mono); letter-spacing: 0.1em; text-transform: uppercase; color: var(--text-faint); margin: 11px 0 2px; }
.detail-group-label:first-child { margin-top: 4px; }
.detail-row { display: flex; align-items: baseline; justify-content: space-between; gap: 14px; padding: 4px 0; border-bottom: 1px dotted var(--panel-border); }
.detail-rows .detail-row:last-child { border-bottom: 0; }
.detail-row .dk { color: var(--text-dim); font-size: 12px; line-height: 1.35; }
.detail-row .dv { flex: 0 0 auto; color: var(--text); font: 500 12px var(--font-mono); font-variant-numeric: tabular-nums; white-space: nowrap; text-align: right; }
.detail-empty { font-size: 11.5px; color: var(--text-faint); padding: 4px 0; }

/* ---------------------------------------- verified fixes on a failing card
   "Joists — over its limit — 437%" is a dead end on its own. Each option here
   was run through a real solve before being shown, so the panel only offers
   changes the ENGINE said clear the check. Wording stays deliberately short of
   "safe" / "fixed" — passing what Structora models is not a P.Eng review. */
.fix-block { margin-top: 9px; padding-top: 8px; border-top: 1px solid var(--panel-border); }
.fix-head {
  font: 600 10px var(--font-mono); letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--text-faint); margin-bottom: 6px;
}
.fix-btn { width: 100%; }
.fix-note { font-size: 11.5px; color: var(--text-dim); line-height: 1.45; margin-top: 6px; }
.fix-option {
  display: flex; align-items: flex-start; justify-content: space-between; gap: 10px;
  padding: 7px; border-radius: var(--radius-sm); border: 1px solid transparent;
}
.fix-option + .fix-option { margin-top: 2px; }
.fix-option:hover { background: var(--panel-3); }
/* The cheapest option that leaves nothing else broken — ranked first by the
   engine's own material total, not by a guess made in the renderer. */
.fix-option.fix-best { background: var(--panel-3); border-color: var(--panel-border); }
.fix-option-main { min-width: 0; }
.fix-label { font-size: 12.5px; color: var(--text); line-height: 1.35; }
/* What this one option is proved to have cleared. Green because it is a real
   modeled result — but the word "modeled" is in the text itself, so the colour
   never has to carry the qualifier on its own. */
.fix-passes { font-size: 11px; color: var(--good); font-weight: 600; margin-top: 3px; }
.fix-summary { font-size: 11.5px; color: var(--text-dim); margin-top: 2px; }
.fix-caution { font-size: 11px; color: var(--warn); margin-top: 2px; }
.fix-apply { flex: 0 0 auto; }
/* Preview + Apply stack in one column so a long option label never squeezes
   either into an unreadable sliver. */
.fix-option-actions { flex: 0 0 auto; display: grid; gap: 4px; justify-items: stretch; }
.fix-preview {
  background: transparent; border: 1px solid var(--panel-border); color: var(--text-dim);
}
.fix-preview:hover { border-color: var(--accent); color: var(--text); }
.fix-preview.fix-preview-on { border-color: var(--accent); color: var(--accent); }
.fix-option.fix-previewing { border-color: var(--accent); }
/* ⚠ Says "not applied" in as many words. The viewport is showing a deck the user
   does not have, and a tint alone is not a statement. */
.fix-preview-banner {
  margin: 0 0 6px; padding: 6px 8px; border-radius: var(--radius-sm);
  border: 1px solid var(--accent); color: var(--text);
  background: color-mix(in srgb, var(--accent) 10%, transparent);
  font-size: 11.5px; line-height: 1.4;
}

/* ------------------------------------------- "Show engineering detail"
   Release-vision item 5: the plain verdict and the % bar lead; the raw ratio
   table is one click away, not in a homeowner's face. Deliberately quiet — a
   faint text button, not a control competing with the verdict above it. */
.insp-eng { margin-top: 10px; }
.insp-eng .eng { margin-top: 4px; }
.eng-toggle {
  display: flex; align-items: center; gap: 6px; width: 100%;
  background: none; border: 0; padding: 3px 0; cursor: pointer; text-align: left;
  font: 600 10px var(--font-mono); letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--text-faint);
}
.eng-toggle:hover { color: var(--text-dim); }
.eng-toggle .chev { width: 9px; }
.result-card .insp-eng { margin-top: 8px; }

/* ------------------------------------------------- serif display titles
   Echo the marketing site, where prominent headings are IBM Plex Serif.
   Scoped to the big panel / card titles only — the small uppercase mono
   labels and all numeric read-outs stay in IBM Plex Mono / Sans. */
.panel-title h2,
.right-head h2,
.parts-head > span:first-child,
.status-label {
  font-family: var(--font-serif);
  font-weight: 600;
  letter-spacing: -0.01em;
}
/* A successful export finalizes the design. Keep camera/report/export controls
   available, but make every design-authoring surface visibly read-only. */
body.project-finalized #tool-rail,
body.project-finalized #left-table,
body.project-finalized #bottom-edit,
body.project-finalized #workspace-nav,
body.project-finalized [data-fix],
body.project-finalized [data-apply] {
  pointer-events: none;
  opacity: .58;
}
