/* Full-bleed workspace band: collapsible editor rail + hero stage.
   Shared by the DSL tools (roadmap, tree, why).

   Page spatial system: every band (header, workspace, about, footer) shares
   one gutter and one max width, so edges align down the whole page. */
:root{
  --page-max: var(--w-band);
  --page-gutter: 24px;
}
.wrap{
  max-width: var(--page-max);
  margin: 0 auto;
  padding: 0 var(--page-gutter);
}
.workspace{
  --workspace-rail-width: 420px;
  display: grid;
  grid-template-columns: var(--workspace-rail-width) minmax(0, 1fr);
  position: relative;
  align-items: stretch;
  box-sizing:border-box;
  width:calc(100% - var(--page-gutter) * 2);
  max-width:calc(var(--page-max) - var(--page-gutter) * 2);
  margin: 28px auto 0;
  padding:0;
  background:var(--card);
}
@media (prefers-reduced-motion: no-preference){
  .workspace{transition: grid-template-columns .28s cubic-bezier(.2,.8,.2,1)}
  .rail{transition: opacity .2s ease, visibility 0s linear .28s}
  .stage .preview svg{transition: width .28s cubic-bezier(.2,.8,.2,1)}
}
.workspace.collapsed,.workspace.focus-artefact{grid-template-columns:0px minmax(0,1fr)}
.workspace.collapsed::before,.workspace.focus-artefact::before{
  content:'';position:absolute;z-index:1;inset:0 auto 0 0;width:1px;background:var(--border);pointer-events:none;
}
.rail{
  min-width:0;overflow:hidden;background:transparent;border:0;border-right:1px solid var(--border);border-radius:0;box-shadow:none;padding:18px;
  overflow-y:visible;
}
/* Reserve editor height to avoid load shift. */
#cmhost{min-height: 440px}
.workspace.collapsed .rail,.workspace.focus-artefact .rail{opacity:0;visibility:hidden;padding-left:0;padding-right:0;border-color:transparent;pointer-events:none}
/* indent/outdent buttons for indented DSLs — fingers have no Tab key.
   Hidden wherever a keyboard is likely; shown for coarse pointers. */
.cm-indentbar{display: none}
@media (pointer: coarse){
  .cm-indentbar{display: flex; gap: 8px; margin: 0 0 8px}
  .cm-indentbar button{min-height: 44px; flex: 1 1 auto; font-family: inherit;
    font-size: 13px; color: var(--ink); background: none;
    border: 1px solid var(--border); border-radius:0}
  .cm-indentbar button:active{border-color: var(--accent); color: var(--accent-ink)}
}

.railtab{
  position:absolute;z-index:4;top:56px;left:var(--workspace-rail-width);width:44px;min-height:44px;margin:0;padding:0;transform:translateX(-50%);
  border:0;border-radius:0;background:transparent;color:var(--muted);cursor:pointer;font-size:0;line-height:1;letter-spacing:0;opacity:.48;
}
.railtab::after{content:'‹';font:400 22px/1 Arial,sans-serif}
.workspace:hover .railtab,.railtab:hover,.railtab:focus-visible{opacity:1}
.railtab:hover{color:var(--accent-ink)}
.railtab:focus-visible{outline:2px solid var(--accent);outline-offset:2px;color:var(--accent-ink)}
.workspace.collapsed .railtab,.workspace.focus-artefact .railtab{
  top:44px;left:0;width:44px;transform:none;border:0;background:transparent;color:var(--accent-ink);font:700 0/1 inherit;letter-spacing:0;padding:0;opacity:.72;
}
.workspace.collapsed .railtab::before,.workspace.focus-artefact .railtab::before{
  content:'';position:absolute;left:0;top:12px;width:2px;height:20px;background:var(--accent);
}
.workspace.collapsed .railtab::after,.workspace.focus-artefact .railtab::after{
  content:'›';position:relative;font:400 22px/1 Arial,sans-serif;
}
.stage{
  min-width: 0;
  background:transparent; border:0; border-radius:0;
  box-shadow:none; padding:18px;
}
.stage .preview{overflow: auto}
.fit-readability-advisory{
  display:flex; align-items:center; justify-content:space-between; gap:14px;
  margin:0 0 10px; padding:8px 10px;
  color:var(--muted); background:var(--bg); border-block:1px solid var(--border);
  font-size:11.5px; line-height:1.35;
}
.fit-readability-advisory[hidden]{display:none}
.fit-readability-advisory button{
  flex:none; border:0; border-left:1px solid var(--border); padding:3px 2px 3px 12px;
  color:var(--accent-ink); background:none; font-family:inherit; font-size:11.5px;
  font-weight:600; line-height:1.35; cursor:pointer;
}
.fit-readability-advisory button:hover{text-decoration:underline}
.fit-readability-advisory button:focus-visible{outline:2px solid var(--accent); outline-offset:3px}
/* centring is applied inline by workspace.js, ONLY when Fit caps the width to the
   fold — a blanket margin-inline:auto here would also recentre a zoomed-OUT board,
   which is a silent change to how zoom has always looked */
.stage .preview svg{display: block; width: 100%; height: auto}
/* Load-grace: the placeholder reserves the artefact's own footprint, so the
   autoloaded diagram lands into space that already exists instead of shoving
   .actions/.about down (measured CLS 0.17–0.33 desktop, 0.34–0.50 cycles-phone).
   Each tool sets --reserve-ar to its default example's viewBox ratio — an aspect,
   not a px height, so the reservation tracks the landing height at any pane width
   (svg is width:100%/height:auto). Capped at the fold, mirroring workspace.js's
   fit cap (FIT_FLOOR 560 / fold ≈ 100vh − header ~280), because Fit never lets a
   board land taller than that. Reserving the PLACEHOLDER (not the pane) means a
   rendered artefact can never sit above stranded whitespace — the reservation is
   gone the moment the svg exists. Default auto = no reservation (old behaviour). */
.stage .preview .placeholder{
  aspect-ratio: var(--reserve-ar, auto);
  max-height: max(560px, calc(100vh - 280px));
  /* centre the hint in the reserved box; flex (not grid) so the anonymous text
     item can shrink and wrap on narrow panes instead of clipping at max-content */
  display: flex; align-items: center; justify-content: center;
}
/* real HTML mirror of the diagram's quotable verdict/readout — screen readers
   get it via aria-live (set on the element in each tool's markup); sighted
   users get it too, so the answer is never SVG-text-only. Empty until a
   render computes one. */
.verdict{font-family: "Helvetica Neue", Helvetica, "Segoe UI", Roboto, sans-serif; font-weight:700; font-size: 15px; line-height: 1.5;
  color: var(--ink); margin: 10px 2px 0; max-width: 74ch}
.verdict:empty{display: none}
.verdict p{margin: 0 0 8px}
.verdict p:last-child{margin-bottom: 0}
/* Type, borders and the ink-active state come from the shared .segmented
   control (assets/controls.css, Swiss 6c). Two things stay local: the settled
   min-size of the four injected buttons (Fit/100%/−/+), so the actions row
   doesn't reflow when workspace.js mounts them (load-grace), and tighter
   padding on the −/+ glyphs — a letterspaced single character otherwise sits
   visibly left of centre. */
.zoomctl{min-width: 191px; min-height: 33px}
.zoomctl button[data-z="minus"], .zoomctl button[data-z="plus"]{
  padding: 8px 10px; letter-spacing: 0}
/* nothing on stage yet → the action row has nothing to act on */
.actions button:disabled, .actions select:disabled{opacity: .45; cursor: default}
.actions button:disabled:hover{border-color: var(--border); color: inherit}
/* section rhythm after the hero: reading column shares the page's left edge
   (a centred 65ch island under the full-bleed stage read as detached) */
.about{margin: 56px 0 0}
footer{margin: 48px 0 8px}
@media (max-width: 900px){
  .workspace{display:flex; flex-direction:column; gap:16px; width:auto; max-width:var(--page-max); margin-top:20px; background:transparent}
  .rail{width: auto; max-height: none; overflow: visible; opacity: 1 !important;
    padding:18px !important;background:var(--card);border:1px solid var(--border) !important}
  #cmhost{min-height: 280px}   /* matches the tools' narrow .cm-editor height */
  .stage{order:-1;background:var(--card);border:1px solid var(--border)} /* phones are for viewing: diagram above the editor */
  .rail{ order: 0; }
  /* indent/outdent buttons for indented DSLs — fingers have no Tab key.
   Hidden wherever a keyboard is likely; shown for coarse pointers. */
.cm-indentbar{display: none}
@media (pointer: coarse){
  .cm-indentbar{display: flex; gap: 8px; margin: 0 0 8px}
  .cm-indentbar button{min-height: 44px; flex: 1 1 auto; font-family: inherit;
    font-size: 13px; color: var(--ink); background: none;
    border: 1px solid var(--border); border-radius:0}
  .cm-indentbar button:active{border-color: var(--accent); color: var(--accent-ink)}
}

.railtab{display: none}
}

/* Fingers get full-size controls; mouse pointers keep the compact look. */
@media (pointer: coarse){
  .chip, .btn{min-height: 44px; display: inline-flex; align-items: center}
  /* .segmented already gives 44px; the zoom group only needs a wider hit box
     (its labels are the shortest on the suite). Font size stays the shared
     10.5px micro — a 13px zoom row would be the one un-Swiss control left. */
  .zoomctl button{padding: 13px 15px}
  .eip-pop button{min-height:44px; padding: 12px 12px}
}
/* Touch Undo (mobile-input Rule 2): phones have no ⌘Z. Hidden wherever a
   keyboard is likely; the coarse block above already supplies the 44px hit. */
.btn.touch-undo{display: none}
@media (pointer: coarse){
  .btn.touch-undo{display: inline-flex}
}
/* phones are for viewing and zooming: the zoom control gets the full row */
@media (max-width: 900px) and (pointer: coarse){
  .zoomctl{display: flex; width: 100%}
  .zoomctl button{flex: 1 1 auto}
}

/* edit-in-place overlay */
[data-edit]{cursor: text}
[data-edit]:hover{text-decoration: underline; text-decoration-style: dotted}
.eip-input{
  position: fixed; z-index: 60;
  font: 600 13px ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  color: var(--ink); background: var(--card);
  border: 1.5px solid var(--accent); border-radius:0;
  padding: 4px 8px; box-shadow: var(--shadow);
}
.eip-input:focus{outline: none}
/* Fingers: the phone bar's own rule — a focused input under 16px makes iOS zoom
   the page. The eip input is the shared text-entry surface for every tool's
   edit-in-place, so the floor lives here once. Asserted in dev/pw/check-eip.mjs. */
@media (pointer: coarse){ .eip-input{font-size: 16px} }
.eip-input.invalid{border-color: var(--err); animation: eip-shake .3s}
@keyframes eip-shake{
  20%{transform: translateX(-3px)} 40%{transform: translateX(3px)}
  60%{transform: translateX(-2px)} 80%{transform: translateX(2px)}
}
@media (prefers-reduced-motion: reduce){
  .eip-input.invalid{animation: none}
}

.eip-pop{
  position: fixed; z-index: 60; display: flex; flex-direction: column;
  background: var(--card); border: 1px solid var(--border); border-radius:0;
  box-shadow: var(--shadow); padding: 4px; min-width: 130px;
  max-height: calc(100vh - 24px); overflow-y: auto;
}
.eip-pop button{
  border: none; background: none; text-align: left; cursor: pointer;
  font-family: inherit; font-size: 12.5px; color: var(--ink);
  padding: 6px 10px; border-radius:0;
}
.eip-pop button:hover{background: var(--bg); color: var(--accent-ink)}
.eip-pop button.on{color: var(--accent-ink); font-weight: 600}
.eip-sep{height: 1px; background: var(--border); margin: 4px 2px}
.eip-pop button.danger{color: var(--err)}
.eip-pop button.danger:hover{background: color-mix(in srgb, var(--err) 10%, transparent); color: var(--err)}
[data-edit]:not(text):hover{opacity: .8}

/* Phone edge system — "16px prose / 10px surface" (Camp A). On a 390px phone the
   24px gutter + workspace padding + card borders left the tool surface at ~304px
   (78% of the screen). Below 640px (mobile.css's fold breakpoint — this is its
   horizontal sibling): prose keeps a 16px reading gutter via --page-gutter (.wrap
   follows the token), but the tool SURFACES full-bleed to the viewport edge —
   side borders and radius dropped, top/bottom hairlines KEPT so the bands read
   as native sheets, not broken cards. Surface lands at ~370px (95%).
   !important + end-of-file: the 900px block above sets .rail padding/border-color
   with !important, so these must match specificity AND come later to win.
   Asserted in dev/pw/mobile.mjs (workspace surface >= 90% of viewport width). */
@media (max-width: 640px){
  :root{ --page-gutter: 16px }
  .workspace{ padding: 0 }
  .stage, .rail{
    border-inline: none !important;
    border-radius: 0;
    padding: 14px 10px !important;
  }
}
