/* Vinci 4D — Instrument Dark
   Chrome is strictly neutral. Saturated colour is reserved for physics. */

/* Dark is the default: emissive thermal data needs darkness to read, and this
   is a tool used in long focused sessions. Light exists because the product is
   light today and the argument has to survive in the client's own theme. */
:root, [data-theme="dark"] {
  --ground: oklch(0.16 0.014 250);
  --panel:  oklch(0.20 0.016 250);
  --raise:  oklch(0.245 0.018 250);
  --line:   oklch(0.30 0.020 250);
  --line-hi:oklch(0.38 0.024 250);

  --ink:    oklch(0.965 0.006 250);
  /* RAISED 2026-09-01. Multi-line body copy in the left rail sat on --ink-mid
     and read as greyed-out rather than as prose. Each step moved up so that
     the ladder still separates cleanly but the LOWEST rung is comfortably
     above the AA floor on --panel, not sitting on it. Small type is the whole
     population here, so "technically passing" is the wrong target. */
  --ink-mid:oklch(0.830 0.018 250);
  --ink-lo: oklch(0.742 0.022 250);
  --ink-dim:oklch(0.668 0.022 250);

  /* Physics only. Never used for chrome. */
  --pass: #48D06A;
  --fail: #E8563F;
  --src:  #F2A93B;

  /* Canvas substrate, read by the renderer. */
  --plate-hi: 38 52 70;
  --plate-lo: 20 29 42;
  --plate-edge: 126 156 190;
  --field-mode: lighter;
  --field-alpha: 0.62;
  --field-gamma: 1.85;
  --shadow-rgb: 6 10 16;
}

/* Light theme. The ramp is unchanged: physics colour is a measurement scale,
   not decoration, so inverting it would make the two themes disagree about
   what a temperature looks like. Signal colours darken to hold contrast on
   white; the thermal ramp itself is never re-hued. */
[data-theme="light"] {
  --ground: oklch(0.985 0.002 250);
  --panel:  oklch(1 0 0);
  --raise:  oklch(0.965 0.004 250);
  --line:   oklch(0.905 0.006 250);
  --line-hi:oklch(0.835 0.010 250);

  --ink:    oklch(0.245 0.020 250);
  --ink-mid:oklch(0.420 0.022 250);
  --ink-lo: oklch(0.490 0.020 250);
  --ink-dim:oklch(0.545 0.018 250);

  --pass: #157A38;
  --fail: #A82D18;
  --src:  #8A5208;

  --plate-hi: 226 234 243;
  --plate-lo: 196 208 222;
  --plate-edge: 96 122 152;
  --field-mode: multiply;
  --field-alpha: 0.92;
  --field-gamma: 1.45;
  --shadow-rgb: 120 140 165;
}

/* ============================================================
   DESIGN TOKENS -- THEME INDEPENDENT

   BUG FIXED 2026-09-01. Type, radius, spacing, easing and z-index used to be
   declared inside the [data-theme="light"] block. A cascade rule cannot be
   more literal: in DARK mode -- which is the default, and the mode the
   proposal embeds -- --sans, --mono, --r-*, --ease and --z-* were UNDEFINED.
   Every `font-family: var(--sans)` fell back to the initial value and the
   whole instrument rendered in Times New Roman with square corners and no
   easing curves. Verified in headless Chromium: computed bodyFont was
   "Times New Roman", computed button radius was 0px.

   Nobody caught it because the light theme -- what a reviewer on a light
   desktop sees -- was correct, and the dark screenshots were read as an
   aesthetic choice rather than a broken cascade.

   The lesson generalises: only tokens that DIFFER between themes belong in a
   theme block. Type, geometry and motion are theme-independent, so they live
   here, at :root, unconditionally.
   ============================================================ */
:root {
  /* Type. Inter Tight is deliberate rather than default: this is an
     instrument, and Inter Tight's narrower set width holds dense numeric
     labels without the cramped feel of condensing a wider face. */
  --sans: 'Inter Tight', system-ui, -apple-system, 'Segoe UI', sans-serif;
  --mono: 'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace;

  /* Type scale. Fixed steps, not ad-hoc px values scattered through the file.
     Ratio is deliberately tight (~1.16) because this is a dense tool: big
     jumps waste vertical space that readings and layer rows need. */
  --t-micro: 10.5px;   /* uppercase meta labels only */
  --t-xs:    11.5px;
  --t-sm:    12.5px;
  --t-base:  13.5px;
  --t-md:    15px;
  --t-lg:    18px;
  --t-xl:    24px;
  --t-hero:  clamp(38px, 3.4vw, 52px);   /* the peak reading, and nothing else */

  /* Weights: three, not seven. */
  --w-normal: 400;
  --w-medium: 500;
  --w-semi:   600;

  /* 4px spacing rhythm. Every padding and gap resolves to one of these. */
  --s-1: 4px;  --s-2: 8px;  --s-3: 12px; --s-4: 16px;
  --s-5: 20px; --s-6: 24px; --s-8: 32px; --s-10: 40px;

  /* Radius: one system. Controls 8, surfaces 12, pills full. */
  --r-sm: 8px;
  --r-md: 12px;
  --r-lg: 16px;
  --r-pill: 999px;

  /* Motion. Standard = UI response, entrance = arrival, spring = physical. */
  --ease: cubic-bezier(0.22, 1, 0.36, 1);
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --dur-fast: .12s;
  --dur: .18s;
  --dur-slow: .32s;

  --z-top: 40;
  --z-drawer: 60;

  /* Control geometry. A 32px control is a demo; 34-38px is a tool. */
  --ctl-h: 34px;
  --ctl-h-lg: 38px;
  --row-h: 30px;
}

@media (prefers-reduced-motion: reduce) {
  :root { --dur-fast: .01ms; --dur: .01ms; --dur-slow: .01ms; }
}

* { box-sizing: border-box; margin: 0; }

html { scroll-behavior: smooth; }

body {
  background: var(--ground);
  color: var(--ink);
  font-family: var(--sans);
  font-size: var(--t-base);
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  /* Optical sizing + tighter tracking at UI sizes. Inter Tight ships with a
     slight default looseness that reads as "web page" rather than "tool". */
  letter-spacing: -0.006em;
  font-feature-settings: 'cv05' 1, 'ss03' 1;
}

.mono, .num, input[type="range"] + * , .chip.mono {
  font-family: var(--mono);
  font-variant-numeric: tabular-nums lining-nums;
}

/* Any number that can CHANGE must be tabular, or the layout twitches as
   digits swap width. The readouts update live off the sweep, so they are the
   exact population that needs it. */
.reading-value, .axis-readout, .axis-marks, .prow, .cbar-head, .rrow-head,
.scope-state, .layers .idx {
  font-variant-numeric: tabular-nums lining-nums;
}

.sr, .skip:not(:focus) {
  position: absolute; width: 1px; height: 1px;
  padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap;
}

.skip:focus {
  position: fixed; inset: 12px auto auto 12px; z-index: 100;
  background: var(--raise); color: var(--ink);
  padding: 10px 16px; border-radius: var(--r-sm);
  border: 1px solid var(--line-hi);
}

:focus-visible {
  outline: 2px solid oklch(0.80 0.02 250);
  outline-offset: 2px;
  border-radius: 3px;
}

button { font: inherit; color: inherit; cursor: pointer; }

/* ---------- topbar ---------- */

.topbar {
  display: flex; align-items: center; gap: var(--s-4);
  padding: 0 var(--s-5); height: 60px;
  border-bottom: 1px solid var(--line);
  background: var(--panel);
  position: relative; z-index: var(--z-top);
}

.mark { width: 22px; height: 22px; color: var(--ink); flex: none; }
.mark svg { width: 100%; height: 100%; display: block; }

.title h1 {
  font-size: var(--t-md); font-weight: var(--w-semi);
  letter-spacing: -0.018em; line-height: 1.25;
}
.title p  {
  font-size: var(--t-xs); color: var(--ink-lo);
  line-height: 1.4; margin-top: 1px;
}

.topbar-right { margin-left: auto; display: flex; gap: 8px; align-items: center; }

/* One button system.
   .ghost   = secondary, the default for chrome actions
   .is-on   = the selected member of a segmented group
   Tactile: every control depresses 1px on :active. A control that does not
   acknowledge the press reads as a mockup. */
.ghost {
  display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  height: var(--ctl-h);
  background: transparent; color: var(--ink-mid);
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  padding: 0 var(--s-3); font-size: var(--t-sm);
  font-weight: var(--w-medium); letter-spacing: -0.005em;
  text-decoration: none; white-space: nowrap;
  transition: color var(--dur) var(--ease), border-color var(--dur) var(--ease),
              background var(--dur) var(--ease), transform var(--dur-fast) var(--ease);
}
.ghost:hover { color: var(--ink); border-color: var(--line-hi); background: var(--raise); }
.ghost:active { transform: translateY(1px); }

.theme-ico {
  width: 14px; height: 14px; flex: none;
  fill: none; stroke: currentColor; stroke-width: 1.5;
  stroke-linecap: round;
}

.dot-demo, .dot-model {
  width: 7px; height: 7px; border-radius: 50%; display: inline-block; flex: none;
}
.dot-demo  { background: var(--ink-mid); }
.dot-model { background: transparent; border: 1px solid var(--ink-dim); }

/* ---------- workspace ---------- */

.workspace {
  display: grid;
  /* Panes are variables, not constants: the workspace reallocates width to
     whatever the engineer is currently attending to. Dragging a divider
     overrides the automatic preset until reset. */
  grid-template-columns:
    var(--rail-l, 310px)
    minmax(0, 1fr)
    var(--rail-r, 330px);
  height: calc(100dvh - 56px);
  min-height: 620px;
  transition: grid-template-columns .42s cubic-bezier(.22,.61,.36,1);
}
.workspace.is-dragging { transition: none; user-select: none; }
@media (prefers-reduced-motion: reduce) { .workspace { transition: none; } }

.rail {
  background: var(--panel);
  display: flex; flex-direction: column;
  min-height: 0; overflow: hidden;
}
.rail-left  { border-right: 1px solid var(--line); }
.rail-right { border-left: 1px solid var(--line); overflow-y: auto; }

.rail-head, .panel-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--s-3); padding: var(--s-4) var(--s-5) var(--s-3);
  /* Dividers were on EVERY head, which drew a ladder of hairlines down both
     rails and made the page read as a wireframe. Section separation now comes
     from space; a line is only drawn where two scroll regions actually meet. */
  border-bottom: none;
}
.rail-head {
  border-bottom: 1px solid var(--line);
  padding-block: var(--s-4);
}
.rail-head h2, .panel-head h2 {
  font-size: var(--t-sm); font-weight: var(--w-semi);
  letter-spacing: -0.01em; color: var(--ink);
}
/* Panels after the first get a top rule instead, so the rhythm is
   one line BETWEEN sections rather than one line under every title. */
.rail-right .panel + .panel { border-top: 1px solid var(--line); }

.chip {
  font-size: var(--t-micro); color: var(--ink-lo);
  background: var(--raise); border: 1px solid var(--line);
  padding: 4px var(--s-2); border-radius: var(--r-pill); white-space: nowrap;
  font-weight: var(--w-medium); letter-spacing: 0.01em;
  font-variant-numeric: tabular-nums;
}

/* ---------- thread ---------- */

.thread {
  flex: 1; min-height: 0; overflow-y: auto;
  padding: var(--s-5); display: flex; flex-direction: column; gap: var(--s-5);
  scroll-behavior: smooth;
}

.msg { font-size: var(--t-base); line-height: 1.68; max-width: 62ch; }
.msg .who {
  font-size: var(--t-micro); letter-spacing: 0.09em; text-transform: uppercase;
  color: var(--ink-dim); display: block; margin-bottom: 6px;
  font-weight: var(--w-medium);
}
/* The user's own turn is set apart as a surface, the way every modern
   assistant does it: the reader must be able to find their question at a
   glance while scanning back through a long thread. The answer stays
   unboxed so the reasoning reads as the page's own voice, not as a reply
   card -- boxing both sides is what makes a thread feel like a chat toy. */
.msg.user {
  color: var(--ink-mid);
  background: var(--raise);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  padding: var(--s-3) var(--s-4);
}
.msg.user .who { color: var(--ink-dim); }
.msg.otto { color: var(--ink); }
.msg p + p { margin-top: 8px; }
.msg b { font-weight: 600; }
.msg .mono { font-size: 13px; }

.msg-enter { animation: rise .28s var(--ease) both; }
@keyframes rise { from { opacity: 0; transform: translateY(5px); } }

.asks {
  padding: 0 var(--s-5) var(--s-3);
  display: flex; flex-direction: column; gap: var(--s-2);
}
.asks button {
  text-align: left; background: transparent;
  border: 1px solid var(--line); border-radius: var(--r-md);
  color: var(--ink-mid);
  padding: var(--s-3) var(--s-4);
  font-size: var(--t-sm); line-height: 1.45;
  transition: color var(--dur) var(--ease), border-color var(--dur) var(--ease),
              background var(--dur) var(--ease), transform var(--dur-fast) var(--ease);
}
.asks button:hover {
  color: var(--ink); border-color: var(--line-hi); background: var(--raise);
}
.asks button:active { transform: translateY(1px); }

/* The composer is the one control every visitor touches, so it gets the
   most care: a single rounded field that owns its send button, a real focus
   ring rather than a border tint, and a 44px target. It was a 38px square
   button beside a 34px input -- two mismatched rectangles reading as a form,
   not as an input surface. */
.composer {
  display: flex; gap: var(--s-2); padding: var(--s-3) var(--s-5) var(--s-5);
  border-top: 1px solid var(--line);
  align-items: center;
}
.composer-field {
  flex: 1; min-width: 0; position: relative;
  display: flex; align-items: center; gap: var(--s-2);
  background: var(--ground);
  border: 1px solid var(--line);
  border-radius: var(--r-pill);
  padding-right: var(--s-1);
  transition: border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
}
.composer-field:focus-within {
  border-color: var(--line-hi);
  box-shadow: 0 0 0 3px color-mix(in oklch, var(--line-hi) 28%, transparent);
}
.composer input {
  flex: 1; min-width: 0;
  background: transparent; border: 0;
  color: var(--ink);
  padding: 0 var(--s-2) 0 var(--s-4);
  height: 42px;
  font: inherit; font-size: var(--t-base);
}
.composer input::placeholder { color: var(--ink-dim); }
.composer input:focus { outline: none; }
.composer button {
  width: 34px; height: 34px; flex: none;
  background: var(--raise); border: 1px solid var(--line);
  border-radius: var(--r-pill); display: grid; place-items: center;
  transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease),
              transform var(--dur-fast) var(--ease);
}
.composer button:hover { border-color: var(--line-hi); background: var(--line); }
.composer button:active { transform: scale(0.94); }
.composer svg { width: 15px; height: 15px; fill: var(--ink-mid); }
.composer button:hover svg { fill: var(--ink); }

/* ---------- stage ---------- */

.stage { position: relative; min-width: 0; overflow: hidden; }
.stage:focus { outline: none; }

#scene {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  display: block; cursor: grab;
  touch-action: none;
}
#scene.dragging { cursor: grabbing; }
#scene.probing  { cursor: crosshair; }

.stage-top { position: absolute; top: var(--s-6); left: var(--s-8); }

.reading-label {
  font-size: var(--t-micro); letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--ink-dim); display: block; font-weight: var(--w-medium);
}
.reading-value { display: flex; align-items: baseline; gap: 6px; margin-top: 4px; }
.reading-value .num {
  font-family: var(--mono); font-variant-numeric: tabular-nums lining-nums;
  font-size: var(--t-hero); font-weight: var(--w-medium);
  letter-spacing: -0.035em; line-height: 1;
  transition: color var(--dur-slow) var(--ease);
  /* The peak reading is the page's single most important pixel. It gets a
     faint glow of its OWN colour so it reads as emissive measurement rather
     than as red text -- and because the colour is the value, the glow tracks
     the value automatically. */
  text-shadow: 0 0 32px color-mix(in oklch, currentColor 26%, transparent);
}
.reading-value .unit {
  font-family: var(--mono); font-size: var(--t-md); color: var(--ink-lo);
  font-weight: var(--w-normal);
}
.prov {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: var(--t-xs); color: var(--ink-dim); margin-top: var(--s-2);
}

.scale {
  position: absolute; right: var(--s-8); top: 50%; transform: translateY(-50%);
  display: flex; flex-direction: column; align-items: center; gap: var(--s-2);
  font-family: var(--mono); font-size: var(--t-xs); color: var(--ink-mid);
  font-variant-numeric: tabular-nums;
  /* The legend sits ON the canvas, not on a panel, so it cannot rely on panel
     contrast. A faint ground shadow keeps it legible over both the dark
     substrate and the bright end of the thermal ramp. */
  text-shadow: 0 1px 3px rgb(var(--shadow-rgb) / 0.85);
}
.scale small { color: var(--ink-lo); }
.scale-bar {
  width: 6px; height: 190px; border-radius: var(--r-pill); position: relative;
  background: linear-gradient(to top,
    #0B1E6B, #1049B8, #0E86D4, #17B8A6, #48D06A, #C6D93A, #F2A93B, #E8563F, #D6203C);
}
.scale-cursor {
  position: absolute; left: -5px; right: -5px; height: 2px;
  background: var(--ink); border-radius: 2px;
  bottom: 0; opacity: 0;
  transition: bottom .12s linear, opacity .2s var(--ease);
}
.scale small { color: var(--ink-dim); }

/* ---------- fourth axis ---------- */

.axis-4d {
  position: absolute; left: var(--s-8); right: var(--s-8); bottom: 82px;
  /* Near-opaque: this panel floats over the field, and a translucent ground
     drags its small labels under the contrast floor. */
  background: color-mix(in oklch, var(--panel) 96%, transparent);
  backdrop-filter: blur(14px) saturate(140%);
  -webkit-backdrop-filter: blur(14px) saturate(140%);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  padding: var(--s-4) var(--s-5) var(--s-5);
  /* Elevation says "this floats above the object". A 1px border alone said
     "this is a box drawn on the object". The inset highlight is the top edge
     catching light, which is what separates a real surface from a rectangle. */
  box-shadow:
    0 1px 0 0 color-mix(in oklch, var(--ink) 6%, transparent) inset,
    0 12px 32px -8px rgb(var(--shadow-rgb) / 0.42),
    0 2px 8px -2px rgb(var(--shadow-rgb) / 0.28);
}

.axis-head {
  display: flex; justify-content: space-between; align-items: baseline;
  font-size: var(--t-xs); color: var(--ink-lo); letter-spacing: 0.01em;
  font-weight: var(--w-medium);
}
.axis-state { font-family: var(--mono); color: var(--ink-lo); }

.axis-track { position: relative; margin: 12px 0 6px; }

input[type="range"] {
  -webkit-appearance: none; appearance: none;
  width: 100%; height: 22px; background: transparent; display: block; cursor: ew-resize;
}
input[type="range"]::-webkit-slider-runnable-track {
  height: 3px; border-radius: 2px;
  background: linear-gradient(90deg, var(--fail) 0%, var(--fail) var(--fill,0%), var(--line) var(--fill,0%));
}
input[type="range"]::-moz-range-track {
  height: 3px; border-radius: 2px;
  background: linear-gradient(90deg, var(--fail) 0%, var(--fail) var(--fill,0%), var(--line) var(--fill,0%));
}
/* 17px thumb with a ring shadow: large enough to grab confidently, and the
   shadow gives it physical lift off the track instead of sitting flush. */
input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none;
  width: 17px; height: 17px; border-radius: 50%;
  background: var(--ink); margin-top: -7px;
  border: 3px solid var(--ground);
  box-shadow: 0 1px 4px rgb(var(--shadow-rgb) / 0.5);
  transition: transform var(--dur) var(--ease);
}
input[type="range"]:hover::-webkit-slider-thumb { transform: scale(1.12); }
input[type="range"]:active::-webkit-slider-thumb { transform: scale(1.04); }
input[type="range"]::-moz-range-thumb {
  width: 17px; height: 17px; border-radius: 50%;
  background: var(--ink); border: 3px solid var(--ground);
  box-shadow: 0 1px 4px rgb(var(--shadow-rgb) / 0.5);
}

.axis-marks { position: relative; height: 30px; }
/* One tick per MEASURED point. Their uneven spacing is the log axis telling
   the truth about where the product actually has data. */
.axis-marks span {
  position: absolute; left: var(--at); transform: translateX(-50%);
  display: flex; flex-direction: column; align-items: center; gap: 1px;
  font-family: var(--mono); font-size: 9px; color: var(--ink-dim);
  letter-spacing: 0;
}
.axis-marks span::before {
  content: ''; width: 1px; height: 4px; background: var(--line-hi); margin-bottom: 2px;
}
.axis-marks b {
  font-family: var(--mono); font-size: 10.5px; font-weight: 500;
  color: var(--ink-lo); letter-spacing: 0;
}
.axis-marks span.is-bare { gap: 0; }
.axis-marks span.is-bare::before { height: 3px; opacity: .55; }
.axis-marks span.is-pass b { color: var(--pass); }
.axis-marks span.is-fail b { color: var(--fail); }

.regime {
  font-weight: 500; color: var(--ink-mid);
  border: 1px solid var(--line); border-radius: 99px;
  padding: 1px 8px; margin-left: 6px; font-size: 10px;
}

.axis-readout {
  display: flex; align-items: center; gap: var(--s-8);
  padding-top: var(--s-4); margin-top: var(--s-1);
  border-top: 1px solid var(--line);
}
.axis-readout > div { display: flex; align-items: baseline; gap: 7px; }
.axis-readout span {
  font-size: var(--t-micro); letter-spacing: 0.11em; text-transform: uppercase;
  color: var(--ink-lo); font-weight: var(--w-medium);
}
.axis-readout b {
  font-size: var(--t-xl); font-weight: var(--w-medium); letter-spacing: -0.028em;
  font-variant-numeric: tabular-nums;
}
.axis-readout small { font-size: var(--t-micro); color: var(--ink-dim); font-family: var(--mono); }

/* The verdict is the answer to the whole study, so it is filled rather than
   outlined: an outline reads as one more label in a row of labels. */
.verdict {
  margin-left: auto; font-size: var(--t-xs); letter-spacing: 0.08em;
  text-transform: uppercase; font-weight: var(--w-semi);
  padding: 6px var(--s-3); border-radius: var(--r-pill); border: 1px solid;
  transition: color var(--dur) var(--ease), background var(--dur) var(--ease),
              border-color var(--dur) var(--ease);
}
.verdict.is-fail {
  color: var(--fail);
  border-color: color-mix(in oklch, var(--fail) 42%, transparent);
  background: color-mix(in oklch, var(--fail) 13%, transparent);
}
.verdict.is-pass {
  color: var(--pass);
  border-color: color-mix(in oklch, var(--pass) 42%, transparent);
  background: color-mix(in oklch, var(--pass) 13%, transparent);
}

/* ---------- tools ---------- */

/* Orbit / Probe / Isolate are MUTUALLY EXCLUSIVE modes, so they are drawn as
   one segmented control on a shared floating surface rather than as three
   free-standing buttons. Separate buttons implied three independent toggles
   and gave the selected state nothing to be selected WITHIN. */
.tools {
  position: absolute; left: var(--s-8); bottom: var(--s-6);
  display: flex; gap: var(--s-2); align-items: center;
}
.toolgroup {
  display: flex; gap: 2px; padding: 3px;
  background: color-mix(in oklch, var(--panel) 92%, transparent);
  backdrop-filter: blur(14px) saturate(140%);
  -webkit-backdrop-filter: blur(14px) saturate(140%);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  box-shadow:
    0 1px 0 0 color-mix(in oklch, var(--ink) 6%, transparent) inset,
    0 8px 24px -8px rgb(var(--shadow-rgb) / 0.40);
}
.tools button {
  background: transparent;
  border: 1px solid transparent; border-radius: 9px;
  color: var(--ink-lo);
  height: 30px; padding: 0 var(--s-3);
  font-size: var(--t-sm); font-weight: var(--w-medium);
  letter-spacing: -0.005em;
  transition: color var(--dur) var(--ease), background var(--dur) var(--ease),
              border-color var(--dur) var(--ease), transform var(--dur-fast) var(--ease);
}
.tools button:hover { color: var(--ink); background: color-mix(in oklch, var(--ink) 7%, transparent); }
.tools button:active { transform: translateY(1px); }
.tools button[aria-pressed="true"] {
  color: var(--ink); background: var(--raise); border-color: var(--line-hi);
  box-shadow: 0 1px 3px rgb(var(--shadow-rgb) / 0.30);
}

.hint {
  position: absolute; right: var(--s-8); bottom: var(--s-8);
  font-size: var(--t-xs); color: var(--ink-dim);
  transition: opacity var(--dur-slow) var(--ease);
}

/* ---------- inspector ---------- */

.panel { border-bottom: 1px solid var(--line); }
.panel:last-child { border-bottom: none; }

.profile { padding: var(--s-2) var(--s-5) var(--s-5); }
.empty { font-size: var(--t-sm); color: var(--ink-dim); line-height: 1.6; }

.prow {
  display: grid; grid-template-columns: 92px 1fr 52px;
  align-items: center; gap: 9px;
  padding: 2.5px 0; font-size: 11.5px;
}
.prow .pname {
  font-family: var(--mono); font-size: 10.5px; color: var(--ink-lo);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.prow.unlabelled .pname { color: var(--ink-dim); font-style: normal; }
.prow .pbar { height: 5px; border-radius: 2px; background: var(--raise); overflow: hidden; }
.prow .pbar i { display: block; height: 100%; border-radius: 2px; }
.prow .pval { font-family: var(--mono); font-size: 11px; text-align: right; color: var(--ink-mid); }
.prow.is-source .pname { color: var(--src); }

/* 18 rows at 22px was a data dump. At --row-h each row is a real target and
   the list becomes scannable; the selected row gets a left marker so the
   selection survives peripheral vision. */
.layers { list-style: none; padding: var(--s-1) var(--s-3) var(--s-3); margin: 0; }
.layers li { margin: 0; }
.layers button {
  width: 100%; display: grid;
  grid-template-columns: 22px 1fr auto; align-items: center; gap: var(--s-3);
  background: transparent; border: none; border-radius: var(--r-sm);
  min-height: var(--row-h); padding: 0 var(--s-2); text-align: left;
  position: relative;
  transition: background var(--dur) var(--ease);
}
.layers button::before {
  content: ''; position: absolute; left: 0; top: 50%;
  width: 2px; height: 0; border-radius: var(--r-pill);
  background: var(--ink-mid);
  transform: translateY(-50%);
  transition: height var(--dur) var(--ease);
}
.layers button:hover { background: var(--raise); }
.layers button[aria-pressed="true"] { background: var(--raise); }
.layers button[aria-pressed="true"]::before { height: 60%; }
.layers .idx {
  font-family: var(--mono); font-size: var(--t-micro); color: var(--ink-dim);
  font-variant-numeric: tabular-nums;
}
.layers .nm  { font-family: var(--mono); font-size: var(--t-xs); color: var(--ink-mid);
               overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.layers .nm.dim { color: var(--ink-dim); }
.layers .sw { width: 20px; height: 4px; border-radius: var(--r-pill); }

.conc { padding: var(--s-2) var(--s-5) var(--s-2); display: flex; flex-direction: column; gap: var(--s-4); }
.cbar { }
.cbar-head {
  display: flex; justify-content: space-between; font-size: 11.5px;
  color: var(--ink-lo); margin-bottom: 5px;
}
.cbar-head b { font-family: var(--mono); color: var(--ink); font-weight: 500; }
.cbar-track { height: 5px; border-radius: var(--r-pill); background: var(--raise); overflow: hidden; }
.cbar-track i {
  display: block; height: 100%; background: var(--src); border-radius: var(--r-pill);
  transition: width var(--dur-slow) var(--ease-out);
}
.cbar-track i.alt { background: color-mix(in oklch, var(--src) 55%, var(--panel)); }

.note { padding: 0 var(--s-5) var(--s-5); font-size: var(--t-xs); color: var(--ink-dim); line-height: 1.55; }

.resist { padding: var(--s-2) var(--s-5) var(--s-5); display: flex; flex-direction: column; gap: var(--s-3); }
.rrow { }
.rrow-head { display: flex; justify-content: space-between; font-size: 11.5px; color: var(--ink-mid); }
.rrow-head b { font-family: var(--mono); font-weight: 500; }
.rrow-track { height: 4px; border-radius: var(--r-pill); background: var(--raise); margin-top: 6px; overflow: hidden; }
.rrow-track i {
  display: block; height: 100%; background: var(--ink-dim); border-radius: var(--r-pill);
  transition: width var(--dur-slow) var(--ease-out);
}
.rrow.lead .rrow-head { color: var(--ink); }
.rrow.lead .rrow-track i { background: var(--ink-lo); }

/* ---------- physics scope ----------
   Three states, encoded in weight and opacity rather than in three different
   hues. Colour on this page means physics; spending an accent on a roadmap
   label would break that rule for a list that is not a measurement.

   The live rows carry the pass colour ONLY on the dot, because "in the model"
   is a verified fact about the product, and the dot is the smallest possible
   place to say it. */
.scope { list-style: none; margin: 0; padding: var(--s-1) var(--s-5) var(--s-3); }

.scope-row {
  display: grid; grid-template-columns: 8px 1fr auto;
  align-items: center; gap: var(--s-3);
  min-height: var(--row-h);
  font-size: var(--t-xs);
  border-bottom: 1px solid color-mix(in oklch, var(--line) 55%, transparent);
}
.scope-row:last-child { border-bottom: none; }

.scope-dot {
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--line-hi);
}
.scope-name { color: var(--ink-mid); letter-spacing: -0.005em; }
.scope-name b { color: var(--ink-dim); font-weight: var(--w-normal); }
.scope-state {
  font-size: var(--t-micro); color: var(--ink-dim);
  font-variant-numeric: tabular-nums; white-space: nowrap;
}

/* Shipped: solid dot in the pass colour, full-strength name. */
.scope-row.is-live .scope-dot { background: var(--pass); }
.scope-row.is-live .scope-name { color: var(--ink); font-weight: var(--w-medium); }
.scope-row.is-live .scope-state { color: var(--ink-lo); }

/* Next: hollow dot. Present, outlined, not filled in yet -- which is
   literally what "on the near-term roadmap" means. */
.scope-row.is-next .scope-dot {
  background: transparent;
  box-shadow: inset 0 0 0 1.5px var(--ink-lo);
}
.scope-row.is-next .scope-name { color: var(--ink-mid); }

/* Further out: recedes, but is never hidden. A roadmap the client can read is
   the point; a roadmap we quietly imply is the over-claim. */
.scope-row.is-later { opacity: 0.62; }
.scope-row.is-later .scope-dot { background: transparent; box-shadow: inset 0 0 0 1px var(--ink-dim); }

/* ---------- provenance drawer ---------- */

.drawer {
  position: fixed; inset: 0; z-index: var(--z-drawer);
  background: color-mix(in oklch, var(--ground) 72%, transparent);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  display: grid; place-items: center; padding: var(--s-6);
  animation: scrim var(--dur) var(--ease) both;
}
@keyframes scrim { from { opacity: 0; } }
.drawer[hidden] { display: none; }
.drawer-inner {
  max-width: 620px; width: 100%;
  max-height: min(80dvh, 720px); overflow-y: auto;
  background: var(--panel); border: 1px solid var(--line-hi);
  border-radius: var(--r-lg); padding: var(--s-8);
  animation: rise var(--dur-slow) var(--ease-out) both;
  box-shadow: 0 24px 64px -12px rgb(var(--shadow-rgb) / 0.55);
}
.drawer h2 { font-size: var(--t-xl); font-weight: var(--w-semi); letter-spacing: -0.024em; }
.drawer > .drawer-inner > p { font-size: var(--t-base); color: var(--ink-mid); margin-top: 9px; max-width: 62ch; }

/* ---- "Why we built this" ----
   This drawer is read, not scanned, so it is set as a document: one measure,
   real paragraph spacing, and section headings that carry the argument on
   their own if someone only reads the headings. Which they will. */
.drawer-inner.why { max-width: 660px; padding: var(--s-8) var(--s-10) var(--s-6); }

.why-lede {
  font-size: var(--t-md) !important;
  line-height: 1.6;
  color: var(--ink) !important;
  margin-top: var(--s-4) !important;
  max-width: 56ch;
}

.why-block { margin-top: var(--s-8); }
.why-block h3 {
  font-size: var(--t-base); font-weight: var(--w-semi);
  letter-spacing: -0.012em; color: var(--ink);
  margin-bottom: var(--s-3);
}
.why-block p {
  font-size: var(--t-base); line-height: 1.66;
  color: var(--ink-mid); max-width: 62ch;
}
.why-block p + p { margin-top: var(--s-3); }

/* The limits section is the one that earns trust, so it gets a surface --
   it should read as something we chose to put in front of them, not as fine
   print at the bottom. */
.why-block:has(.prov-list) {
  background: var(--raise);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  padding: var(--s-5) var(--s-5) var(--s-4);
}
.why-fine {
  font-size: var(--t-sm) !important; color: var(--ink-lo) !important;
  margin-top: var(--s-4); line-height: 1.6;
}
.why-sign {
  margin-top: var(--s-8) !important; padding-top: var(--s-4);
  border-top: 1px solid var(--line);
  font-size: var(--t-xs) !important; color: var(--ink-dim) !important;
}
.drawer-inner.why #drawer-close { margin-top: var(--s-5); }

.prov-list { margin: var(--s-4) 0 0; display: flex; flex-direction: column; gap: 15px; }
.prov-list dt {
  display: flex; align-items: center; gap: 8px;
  font-size: 11px; letter-spacing: 0.12em; text-transform: uppercase; color: var(--ink-lo);
}
.prov-list dd {
  margin: 6px 0 0; font-size: 13px; color: var(--ink-mid);
  line-height: 1.62; max-width: 66ch;
}
.prov-foot { font-size: 12.5px; color: var(--ink-dim); margin-top: 18px; }
#drawer-close { margin-top: 20px; }

/* ---------- argument ---------- */

.argument { padding: 96px 26px 40px; max-width: 1180px; margin: 0 auto; }
.arg-head h2 { font-size: 30px; font-weight: 600; letter-spacing: -0.025em; text-wrap: balance; }
.arg-head p {
  font-size: 15px; color: var(--ink-mid); margin-top: 12px;
  max-width: 68ch; line-height: 1.6; text-wrap: pretty;
}

.arg-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(272px, 1fr));
  gap: 30px; margin-top: 44px;
  padding-top: 34px; border-top: 1px solid var(--line);
}
.arg-grid h3 { font-size: 15.5px; font-weight: 600; letter-spacing: -0.01em; }
.arg-grid p { font-size: 13.5px; color: var(--ink-mid); margin-top: 9px; line-height: 1.68; }

.arg-rule { margin-top: 44px; padding-top: 30px; border-top: 1px solid var(--line); max-width: 68ch; }
.arg-rule h3 { font-size: 15.5px; font-weight: 600; }
.arg-rule p { font-size: 13.5px; color: var(--ink-mid); margin-top: 9px; line-height: 1.68; }

.foot {
  padding: 34px 26px 44px; max-width: 1180px; margin: 0 auto;
  border-top: 1px solid var(--line);
  display: flex; justify-content: space-between; gap: 20px; flex-wrap: wrap;
  font-size: 12px; color: var(--ink-dim);
}

/* ---------- responsive ---------- */

/* Laptop range. Both rails tighten so the object keeps the majority of the
   width. Below this the three-column shell squeezes the canvas into a narrow
   portrait strip, which defeats the entire premise. */
@media (max-width: 1440px) {
  .workspace { grid-template-columns: 286px minmax(0, 1fr) 306px; }
}

@media (max-width: 1280px) {
  .workspace { grid-template-columns: 258px minmax(0, 1fr) 276px; }
  .reading-value .num { font-size: 38px; }
  .axis-readout { gap: 18px; }
}

/*
  Phone layout. Standalone: below 1100px wide. Embedded (?embed=1): the frame
  is often 900–1100px wide inside a proposal column but 750px+ tall, and the
  three-pane workspace reads perfectly there, so embedded mode keeps the panes
  until the frame is genuinely narrow (760px). Stacking a 1000px-wide embed
  into a phone column was the "squished" instrument Scott saw on 2026-09-03.
*/
@media (max-width: 1100px) and (min-width: 761px) {
  html[data-embed="1"] .workspace { grid-template-columns: 236px minmax(0, 1fr) 256px; }
  html[data-embed="1"] .reading-value .num { font-size: 36px; }
}

@media (max-width: 1100px) {
  .topbar { height: auto; padding: 10px 16px; flex-wrap: wrap; }
  .title p { display: none; }
  html:not([data-embed="1"]) .workspace {
    grid-template-columns: 1fr;
    height: auto; min-height: 0;
  }
  html:not([data-embed="1"]) /* Stack the object vertically instead of overlaying it: on a phone the
     axis panel and readout cover the very thing they describe. */
  .stage {
    order: -1;
    display: flex; flex-direction: column;
    height: auto; min-height: 0;
  }
  html:not([data-embed="1"]) /* dvh, html:not([data-embed="1"]) not vh: mobile browser chrome collapses on scroll and vh would
     leave the object clipped behind it. */
  #scene {
    position: relative; inset: auto;
    height: clamp(320px, 52dvh, 560px);
    order: 2;
  }
  html:not([data-embed="1"]) .stage-top {
    position: relative; inset: auto;
    order: 1; padding: 14px 16px 0;
    display: flex; align-items: baseline; gap: 12px;
  }
  html:not([data-embed="1"]) .reading-label { flex: none; max-width: 8.5em; line-height: 1.25; }
  html:not([data-embed="1"]) .prov { margin-top: 0; margin-left: auto; }
  html:not([data-embed="1"]) .scale {
    position: absolute; right: 14px; top: 42%;
    transform: none;
  }
  html:not([data-embed="1"]) .scale-bar { height: 120px; }
  html:not([data-embed="1"]) .axis-4d {
    position: relative; inset: auto;
    order: 3; margin: 12px 16px 0;
    background: var(--panel);
  }
  html:not([data-embed="1"]) .tools {
    position: relative; inset: auto;
    order: 4; margin: 12px 16px 16px;
    flex-wrap: wrap;
  }
  html:not([data-embed="1"]) .hint { display: none; }
  html:not([data-embed="1"]) .rail { max-height: none; border: none; border-top: 1px solid var(--line); }
  html:not([data-embed="1"]) .rail-left { border-right: none; }
  html:not([data-embed="1"]) .rail-right { border-left: none; overflow: visible; }
  html:not([data-embed="1"]) .thread { max-height: 300px; }
  .argument { padding-top: 60px; }
  .arg-head h2 { font-size: 25px; }
}

/* Embedded: the stacked phone layout only below 760px. */
@media (max-width: 760px) {
  html[data-embed="1"] .workspace {
    grid-template-columns: 1fr;
    height: auto; min-height: 0;
  }
  html[data-embed="1"] /* Stack the object vertically instead of overlaying it: on a phone the
     axis panel and readout cover the very thing they describe. */
  .stage {
    order: -1;
    display: flex; flex-direction: column;
    height: auto; min-height: 0;
  }
  html[data-embed="1"] /* dvh, html[data-embed="1"] not vh: mobile browser chrome collapses on scroll and vh would
     leave the object clipped behind it. */
  #scene {
    position: relative; inset: auto;
    height: clamp(320px, 52dvh, 560px);
    order: 2;
  }
  html[data-embed="1"] .stage-top {
    position: relative; inset: auto;
    order: 1; padding: 14px 16px 0;
    display: flex; align-items: baseline; gap: 12px;
  }
  html[data-embed="1"] .reading-label { flex: none; max-width: 8.5em; line-height: 1.25; }
  html[data-embed="1"] .prov { margin-top: 0; margin-left: auto; }
  html[data-embed="1"] .scale {
    position: absolute; right: 14px; top: 42%;
    transform: none;
  }
  html[data-embed="1"] .scale-bar { height: 120px; }
  html[data-embed="1"] .axis-4d {
    position: relative; inset: auto;
    order: 3; margin: 12px 16px 0;
    background: var(--panel);
  }
  html[data-embed="1"] .tools {
    position: relative; inset: auto;
    order: 4; margin: 12px 16px 16px;
    flex-wrap: wrap;
  }
  html[data-embed="1"] .hint { display: none; }
  html[data-embed="1"] .rail { max-height: none; border: none; border-top: 1px solid var(--line); }
  html[data-embed="1"] .rail-left { border-right: none; }
  html[data-embed="1"] .rail-right { border-left: none; overflow: visible; }
  html[data-embed="1"] .thread { max-height: 300px; }
}

@media (max-width: 560px) {
  .axis-readout { gap: 14px 20px; flex-wrap: wrap; }
  .verdict { margin-left: 0; }
  .reading-value .num { font-size: 34px; }
  .scale { top: 40%; }
  .scale-bar { height: 96px; }
  .foot { flex-direction: column; gap: 10px; }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
  }
}


/* ---------- resizable dividers ---------- */
/* Sits on the seam between panes. Wide enough to grab, invisible until used. */
.divider {
  position: absolute; top: 0; bottom: 0; width: 11px;
  transform: translateX(-50%);
  cursor: col-resize; z-index: 6;
  background: transparent; border: 0; padding: 0;
  touch-action: none;
}
.divider::after {
  content: ''; position: absolute; inset: 0 5px;
  background: var(--accent, #6ea8ff); opacity: 0;
  transition: opacity .16s ease;
}
.divider:hover::after,
.divider:focus-visible::after,
.divider.is-active::after { opacity: .55; }
.divider:focus-visible { outline: none; }

.workspace { position: relative; }

/* ---------- reasoning states ---------- */
/* The rail must show the machine working, not just the answer. */
.think {
  display: flex; align-items: center; gap: .5rem;
  padding: .55rem .7rem; margin: .35rem 0;
  font-size: .82rem; color: var(--muted);
  border-left: 2px solid var(--accent, #6ea8ff);
  background: color-mix(in srgb, var(--accent, #6ea8ff) 7%, transparent);
  border-radius: 0 6px 6px 0;
}
.think-dots { display: inline-flex; gap: 3px; }
.think-dots i {
  width: 4px; height: 4px; border-radius: 50%;
  background: currentColor; opacity: .35;
  animation: think-pulse 1.05s ease-in-out infinite;
}
.think-dots i:nth-child(2) { animation-delay: .16s; }
.think-dots i:nth-child(3) { animation-delay: .32s; }
@keyframes think-pulse {
  0%, 100% { opacity: .28; transform: translateY(0); }
  50%      { opacity: 1;   transform: translateY(-2px); }
}
@media (prefers-reduced-motion: reduce) {
  .think-dots i { animation: none; opacity: .6; }
}
.think-label { font-variant-numeric: tabular-nums; letter-spacing: .01em; }

/* ============================================================
   PHONE PASS (<=560px) — QA at 390px found a desktop widget in a phone
   Findings: legend overlapping the canvas edge, sweep ticks unreadable and
   untappable, controls below 44px. On a phone the object gets the full width
   and every control is thumb-sized.
   ============================================================ */
@media (max-width: 560px) {
  /* The colour scale was floating over the right edge of the object it
     describes. Below it, full width, where it can be read. */
  .scale {
    position: relative; right: auto; top: auto;
    order: 3; display: flex; align-items: center; gap: 10px;
    padding: 10px 16px 0; transform: none;
  }
  .scale-bar { height: 10px; width: 100%; flex: 1; }
  .scale-hi, .scale-lo { font-size: 11px; white-space: nowrap; }

  #scene { height: clamp(300px, 46dvh, 460px); }

  /* Thumbs, not cursors: 44px minimum on every interactive target. */
  .asks button {
    min-height: 44px; padding: .6rem .8rem;
    font-size: .82rem; line-height: 1.35;
  }
  .composer input {
    min-height: 46px;
    font-size: 16px;           /* iOS zooms any input under 16px on focus */
  }
  .composer button { min-width: 46px; min-height: 46px; }
  .ghost, .topbar .ghost { min-height: 40px; padding: 0 12px; }

  /* The sweep had ~8 tick labels in 390px — an unreadable smear. Show the
     endpoints and the threshold; the readout carries the exact value. */
  #axis-marks span { font-size: 10px; }
  #axis-marks span:not(:first-child):not(:last-child):not(.is-key) { display: none; }
  #sweep { height: 34px; }                 /* fat enough to grab */
  #sweep::-webkit-slider-thumb { width: 26px; height: 26px; }
  #sweep::-moz-range-thumb { width: 26px; height: 26px; }

  /* Dense numerics were rendering at ~10px. */
  .reading-value .num { font-size: 34px; }
  .rrow-head { font-size: 12px; }
  .msg { font-size: .84rem; line-height: 1.5; }

  /* Dividers are a pointer affordance; they mean nothing on a phone where
     the layout is stacked. */
  .divider { display: none; }
}

/* Co-brand mark: this is a Vinci artefact made by SVZ, and the corner should
   say so before anyone reads a word. */
.mark.cobrand {
  display: flex; align-items: center; gap: 8px;
  width: auto; padding: 0 2px;
}
.mark.cobrand img { display: block; width: auto; }
.mark-vinci { height: 20px; }
.mark-svz   { height: 14px; opacity: .82; }
.mark-x { font-size: 12px; opacity: .38; line-height: 1; }
@media (max-width: 560px) {
  .mark-vinci { height: 17px; }
  .mark-svz { height: 12px; }
}

/* ---------- zoom cluster ---------- */
/*
  Grouped and set slightly apart from the tool buttons: orbit/probe/isolate are
  MODES (one is always active, they are aria-pressed), zoom is an ACTION that
  repeats. Rendering them identically implied zoom was a fourth mode.
*/
/* Zoom sits in its own .toolgroup, so it inherits the floating surface and
   only needs its own square-ish glyph geometry. */
.tool-zoom button {
  width: 34px; padding: 0; text-align: center;
  font-size: var(--t-md); line-height: 1; font-variant-numeric: tabular-nums;
}

/* ---------- scrollbars ----------
   The right rail's default scrollbar was a bright OS chrome stripe cutting
   through a dark instrument, and it is visible in every screenshot of the
   product. Thin, theme-aware, and only present where a region actually
   scrolls. */
.rail-right, .thread, .drawer-inner {
  scrollbar-width: thin;
  scrollbar-color: var(--line-hi) transparent;
}
.rail-right::-webkit-scrollbar,
.thread::-webkit-scrollbar,
.drawer-inner::-webkit-scrollbar { width: 10px; height: 10px; }
.rail-right::-webkit-scrollbar-track,
.thread::-webkit-scrollbar-track,
.drawer-inner::-webkit-scrollbar-track { background: transparent; }
.rail-right::-webkit-scrollbar-thumb,
.thread::-webkit-scrollbar-thumb,
.drawer-inner::-webkit-scrollbar-thumb {
  background: var(--line);
  border-radius: var(--r-pill);
  border: 3px solid transparent;
  background-clip: content-box;
}
.rail-right:hover::-webkit-scrollbar-thumb,
.thread:hover::-webkit-scrollbar-thumb,
.drawer-inner:hover::-webkit-scrollbar-thumb { background-clip: content-box; background-color: var(--line-hi); }

/* ---------- embed mode ---------- */
/*
  ?embed=1 — the instrument is being shown inside the proposal's single
  absolute frame. Strip every page-level element that belongs to THIS page as a
  standalone document: the site header, the long argument section, the footer.
  Whatever remains must fill the frame exactly, with no inner scroll, because
  the proposal already owns the scroll.

  Nothing here is display:none-ing evidence: the provenance drawer stays
  reachable from inside the frame, and the standalone URL keeps all of it.
*/
html[data-embed="1"], html[data-embed="1"] body {
  height: 100%; overflow: hidden;
}
html[data-embed="1"] .topbar,
html[data-embed="1"] .argument,
html[data-embed="1"] .foot,
html[data-embed="1"] .skip { display: none; }

/* The workspace is the whole frame now, not the frame minus a 56px header. */
html[data-embed="1"] .workspace {
  height: 100dvh;
  min-height: 0;   /* 620px min-height forced an inner scrollbar in short frames */
}

/*
  Provenance still has to be openable without the header button, otherwise
  embedding would quietly remove the page's own evidence trail. A compact
  affordance rides in the corner of the stage instead.
*/
html[data-embed="1"] .embed-prov { display: inline-flex; }
.embed-prov { display: none; position: absolute; right: 22px; top: 22px; z-index: 4; }

/*
  Short frames: below roughly 640px of height the three-pane workspace cannot
  hold a readable object plus two rails. The rails collapse and the object
  keeps the frame, since the object is the argument.
*/
@media (max-height: 640px) {
  /*
    BUG FIXED 2026-09-01 (Scott: "instrument not loading?"). The frame rendered
    an empty black box at the proposal's embed size (~1200x620) while reporting
    itself perfectly healthy: it posted `vinci-instrument:ready`, threw no
    errors, logged no 404s. Nothing was failing to load. The object pane was
    0px wide.

    Cause: `display: none` on the rails does not merely hide them, it REMOVES
    them as grid items. The three declared tracks stayed, but .stage -- now the
    only child -- was auto-placed into the FIRST track, which this rule had set
    to 0. The canvas resolved to 1px x 620px and painted nothing.

    That is why it looked like a load failure and why the liveness handshake
    could never catch it: a booted instrument in a zero-width pane is, to every
    signal the parent can observe, indistinguishable from a healthy one. See
    the stage-width assertion added to instrument-qa.mjs -- "ready" must also
    mean "visible".

    Fix: when the rails are gone, stop declaring tracks for them. One child,
    one track. Track count now follows child count instead of contradicting it,
    so no width breakpoint can silently reintroduce the mismatch.
  */
  html[data-embed="1"] .workspace {
    grid-template-columns: minmax(0, 1fr);
  }
  html[data-embed="1"] .rail { display: none; }
}

/* DESIGN NOTES LAYER REMOVED 2026-09-01 (Scott).
   The hover-annotation layer explained OUR design decisions to the reader. It
   was a conversation we were having with ourselves in the client's margin.
   Replaced by one "Why we built this" drawer that makes the actual argument.
   The prototype-values disclaimer below stays: that is a claim about evidence,
   not about craft, and it belongs to everyone. */

/* ---- prototype-values disclaimer ----
   Scott: "we should have a hover-over disclaimer ... we did our best, these are
   prototypes, they're hiring us to do design and development."
   Framed as capability rather than apology: the honest limit AND the fact that
   swapping in real data costs nothing structurally. Available to everyone, not
   just design-notes mode, because it is a claim about evidence, not craft. */
#reading-prov { cursor: help; position: relative; }
#reading-prov:hover, #reading-prov:focus-visible { outline: none; }

.prov-hint {
  position: absolute; z-index: 40;
  left: 0; top: calc(100% + 9px);
  width: min(310px, calc(100vw - 32px));
  padding: 11px 13px;
  font-size: 11.6px; line-height: 1.55;
  color: var(--text-dim);
  background: color-mix(in srgb, var(--panel) 94%, black);
  border: 1px solid var(--line);
  border-radius: 10px;
  box-shadow: 0 14px 34px rgba(0,0,0,.42);
  opacity: 0; visibility: hidden; pointer-events: none;
  transform: translateY(-3px);
  transition: opacity .16s ease, transform .16s ease, visibility .16s;
}
.prov-hint b { color: var(--text); font-weight: 600; }
#reading-prov:hover .prov-hint,
#reading-prov:focus-visible .prov-hint,
#reading-prov:focus-within .prov-hint {
  opacity: 1; visibility: visible; transform: none;
}
@media (prefers-reduced-motion: reduce) { .prov-hint { transition: none; } }
/* On phones the readout sits near the left edge; keep the card on screen. */
@media (max-width: 560px) {
  .prov-hint { left: auto; right: 0; width: min(280px, calc(100vw - 28px)); }
}
