/* ══════════════════════════════════════════════════════════════════════════
   BENCH-CANON.CSS — the duct-design workspace (app.html) on the canon.
   "A · The Bench". Flag: feature_canvas_bench, gate class html.bench-v1.

   EVERY rule here is scoped to html.bench-v1. Flag-off is the shipped editor,
   byte for byte, and the file costs one small request. The source of the design
   is public/_canvas-canon-mockup.html; js/canvas/bench.js builds the containers
   and MOVES the editor's own controls into them.

   LOAD ORDER IS LOAD-BEARING. This file is linked LAST in app.html, after
   tailwind.css. ui-next.css is always on and its rules are `body.ui-next …`
   (0,2,0); ours are `html.bench-v1 …` (0,2,0). They tie, so source order is what
   decides — move this link up and half the file stops applying.

   NO plenum.css AND NO auth.css. plenum ships `*{}`, `body{}`, `a{}` and
   `.topbar .stat .menu .wrap` as real components, and app.html's own shell is
   `.app` wrapping `.topbar`. auth.css ships bare `.btn-primary` (app.html has
   TWENTY), `.btn-link`, `.spinner`, `.sr-only`. Linking either would restyle the
   live editor from under the flag. Their tokens live in tokens.css
   (html.bench-v1) and the one component we need — the record card — is copied in
   below, containerised under .cv-rec.

   THE COLOUR LAW: the chrome is monochrome. Ice-blue marks exactly one thing at
   a time and hot red means a fault. Every other hue is spent on the DRAWING,
   where it is the legend and therefore information. The drawing's own palette is
   physics.js DUCT_COLORS, not this file — the canvas is painted, not styled.
   ══════════════════════════════════════════════════════════════════════════ */

html.bench-v1 {
  --cv-top: 52px; --cv-strip: 44px; --cv-status: 30px; --cv-pane: 250px;
  --cv-rec: clamp(300px, 23vw, 344px);
}

/* An author `display:flex` beats the UA sheet's [hidden], so every state toggle
   in the port silently does nothing without this. Scoped, so it cannot leak. */
html.bench-v1 [hidden] { display: none !important; }

/* ══ 0 · THE SHELL ══════════════════════════════════════════════════════════
   app.html already has `.app` wrapping everything, so the grid goes there
   rather than adding a container. style.css:70 sizes it as a flex column. */
html.bench-v1,
html.bench-v1 body { height: 100%; }
html.bench-v1 body { margin: 0; overflow: hidden; background: var(--paper); color: var(--ink); font-family: var(--font); }
html.bench-v1 .app {
  position: relative;             /* the containing block for the pre-ready .main */
  display: grid;
  /* An explicit minmax(0,1fr): a bare grid sizes its single column to
     max-content, so one wide child drags the page past the viewport and every
     fixed-width row hangs off the right edge on a phone. */
  grid-template-columns: minmax(0, 1fr);
  grid-template-rows: var(--cv-top) var(--cv-strip) minmax(0, 1fr) var(--cv-status);
  height: 100vh; height: 100dvh; min-height: 0; padding: 0; gap: 0;
}
html.bench-v1 button { font: inherit; color: inherit; }

/* The old chrome is HIDDEN, never removed — its children have been relocated and
   app.js still writes to it by id. Hiding the shells alone keeps every handler
   attached and makes flag-off a complete revert with no deploy. */
html.bench-v1 .topbar,
html.bench-v1 .toolbar,
html.bench-v1 .status-bar,
html.bench-v1 #modeIndicatorLabel,
html.bench-v1 #colorPalette,
html.bench-v1 .toolbar-mobile-trigger,
html.bench-v1 .sidebar-mobile-header { display: none !important; }

/* .main IS DIFFERENT, AND THIS IS LOAD-BEARING.
   app.js ends with a synchronous resizeCanvas() at parse time — long before
   DOMContentLoaded, so before bench.js has moved #canvasArea out of .main.
   display:none on .main at that moment makes the canvas measure 0x0,
   resizeCanvas sizes the backing store to zero, render() calls drawImage on it
   and THROWS. The throw kills the rest of app.js's tail, initAuth() is never
   reached, and the page sits on "Checking session" for ever.

   So until bench.js signals it has relocated, .main keeps a real box: taken out
   of the grid flow, given the .app box to measure against, and made invisible
   rather than displayless. Then, and only then, it is hidden properly. */
html.bench-v1:not(.bench-ready) .main {
  position: absolute; inset: 0; z-index: -1;
  opacity: 0; pointer-events: none;
}
html.bench-v1.bench-ready .main { display: none !important; }

/* updatePropertiesPanel writes floatingPanel.style.display='block' from four
   places; the record column has taken its content, so an inline display must
   lose. !important is the mechanism, not laziness — see the header. */
html.bench-v1 #floatingPropsPanel { display: none !important; }

/* THE PANELS THAT PARK OFF-SCREEN.
   .chat-panel and #teamChatPanel are never display:none — they sit inside
   #canvasArea at right:0 and hide by translateX(100%), i.e. just past the
   canvas's right edge, clipped by its overflow. That works when the canvas runs
   to the edge of the window. It does not work here: the record column pulls the
   canvas's right edge into the middle of the screen, so the parked panel and
   its left-casting shadow surface next to the record and read as a second
   window behind it. Under the bench they are hidden outright until opened. */
html.bench-v1 .chat-panel:not(.open),
html.bench-v1 #teamChatPanel:not(.open) { display: none !important; }

/* ── the one filled control, borrowed from auth.css but sized for a toolbar ── */
html.bench-v1 .cv-cta {
  display: inline-flex; align-items: center; gap: 7px; height: 32px; padding: 0 13px;
  border: 1px solid transparent; border-radius: 9px; cursor: pointer;
  /* THE FILLED CONTROL IS BLUE — the user's call, over an ink-filled version.
     --nr-cta, not --accent: the canon's designated call-to-action blue is
     #0f76bf in light, and white on it is ~4.6:1. White on --accent (#1493e6) is
     ~3.0:1, which fails AA for text this size — 12.5px/600 is not "large text",
     so the deeper blue is the accessible one as well as the intended one. It
     also happens to sit a step away from --d-sup, so in light the button is not
     quite the supply-duct hue. In dark they do coincide. */
  background: var(--nr-cta); color: var(--nr-cta-ink); font-size: 12.5px; font-weight: 600;
  letter-spacing: -.008em; white-space: nowrap;
  transition: background var(--dur) var(--out), box-shadow var(--dur) var(--out);
}
html.bench-v1 .cv-cta:hover { background: var(--nr-cta-hover); box-shadow: var(--sh-2); }

/* EVERY .btn-primary, not just the ones inside the new containers. This is the
   app's primary-action class — the pane's Auto-generate layout, Save in the
   project-info modal, Set scale, Add to schedule, the auth gate's Sign in, about
   twenty in all. They are one role and they take one fill; scoping this to the
   pane and the record left every modal on style.css's --accent, which is the
   3.0:1 blue. Colour only here — shape and size stay where each button lives,
   because a modal's Save and a 250px pane's full-width action are not the same
   object. */
html.bench-v1 .btn-primary {
  background: var(--nr-cta); color: var(--nr-cta-ink);
  border: 1px solid transparent; box-shadow: none;
}
html.bench-v1 .btn-primary:hover:not(:disabled) { background: var(--nr-cta-hover); box-shadow: var(--sh-1); }
html.bench-v1 .btn-primary:disabled { opacity: .45; }

/* The pane's and the record's own primary buttons additionally take the bench's
   shape, because they sit in the new chrome rather than in a shipped modal. */
html.bench-v1 .cv-pane-body .btn-primary,
html.bench-v1 .cv-rec .btn-primary {
  border-radius: 9px; font-size: 12.5px; font-weight: 600;
  letter-spacing: normal; text-transform: none;
}
html.bench-v1 .cv-cta i { font-size: 15px; }

/* ══ 1 · SHELL BAR ══ the only place identity, project and account live ══ */
html.bench-v1 .cv-top {
  display: flex; align-items: center; gap: 10px; padding: 0 12px 0 8px;
  background: var(--panel); border-bottom: 1px solid var(--hair); min-width: 0;
  /* THE CONTAINING BLOCK FOR THE PHONE MENU, and without it the phone had no
     menu at all. Below 768px #topbarActions becomes a dropdown positioned
     `absolute; top: 100%` against its nearest positioned ancestor — .topbar in
     the shipped shell, which is `position: relative`. Moved into a static
     .cv-top, it resolved against .app instead, so `top: 100%` meant 100% of the
     APP: the menu carrying AI, Project, Tools, Share, Messages and the account
     opened one viewport-height below the fold. Every action in the bar,
     unreachable on a phone, with nothing on screen to say so. */
  position: relative;
}
html.bench-v1 .cv-ico {
  display: inline-grid; place-items: center; width: 32px; height: 32px; flex: none;
  border: 1px solid transparent; border-radius: 9px; background: transparent;
  color: var(--ink-2); font-size: 17px; cursor: pointer;
  transition: background var(--dur) var(--out), color var(--dur) var(--out), border-color var(--dur) var(--out);
}
html.bench-v1 .cv-ico:hover { background: var(--panel-2); color: var(--ink); border-color: var(--hair); }
html.bench-v1 .cv-mark { display: flex; align-items: center; gap: 8px; flex: none; padding-left: 2px; }
html.bench-v1 .cv-mark img,
html.bench-v1 .cv-mark svg { width: 22px; height: 22px; display: block; }
html.bench-v1 .cv-mark span { font-size: 14.5px; letter-spacing: var(--track-snug); color: var(--ink-2); }
html.bench-v1 .cv-mark b { font-weight: 700; color: var(--ink); }

/* the project chip: name, address and save state as ONE object, not three */
html.bench-v1 .cv-proj {
  display: flex; align-items: center; gap: 9px; min-width: 0; margin-left: 6px;
  height: 34px; padding: 0 11px; border: 1px solid var(--hair); border-radius: 10px;
  background: var(--sunken); cursor: pointer;
  transition: border-color var(--dur) var(--out), background var(--dur) var(--out);
}
html.bench-v1 .cv-proj:hover { border-color: var(--hair-2); background: var(--panel-2); }
html.bench-v1 .cv-proj .pn { font-size: 12.5px; font-weight: 600; letter-spacing: -.012em; white-space: nowrap; }
html.bench-v1 .cv-proj .pa { font-size: 11.5px; color: var(--ink-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; }
html.bench-v1 .cv-proj .dot { width: 6px; height: 6px; border-radius: 50%; background: var(--accent); flex: none; }
html.bench-v1 .cv-proj .sv { font-size: 11px; color: var(--ink-2); white-space: nowrap; flex: none; }

/* floors: the canon's segmented sunken track, one filled */
html.bench-v1 .cv-track {
  display: flex; align-items: center; gap: 2px; flex: none;
  padding: 3px; border-radius: 10px; background: var(--sunken); border: 1px solid var(--hair);
}
/* THE STOREY TRACK IS THE ONE THING IN THE BAR WITH NO CEILING. flex:none on a
   row of nowrap buttons means six floors simply make the bar longer than the
   window, and the bar's last item — the account menu, then Messages, then
   Share — is what leaves the screen, with no overflow affordance above 768px to
   reach any of them. The track gives instead: it shrinks and scrolls, exactly
   as .cv-tools does in the strip below it. Scoped to the shell bar so the mode
   track and the pane's tab track keep sizing to their content. */
html.bench-v1 .cv-top .cv-track.floors {
  flex: 0 1 auto; min-width: 0;
  overflow-x: auto; overflow-y: hidden;
  scrollbar-width: none; -webkit-overflow-scrolling: touch;
}
html.bench-v1 .cv-top .cv-track.floors::-webkit-scrollbar { display: none; }
html.bench-v1 .cv-top .cv-track.floors > * { flex: none; }
html.bench-v1 .cv-track button {
  height: 26px; padding: 0 11px; border: 0; border-radius: 7px; background: transparent;
  color: var(--ink-2); font-size: 12px; font-weight: 500; cursor: pointer; white-space: nowrap;
  display: inline-flex; align-items: center; gap: 6px;
  transition: background var(--dur) var(--out), color var(--dur) var(--out);
}
html.bench-v1 .cv-track button:hover { color: var(--ink); }
html.bench-v1 .cv-track button.on,
html.bench-v1 .cv-track button.active { background: var(--panel); color: var(--ink); font-weight: 600; box-shadow: var(--sh-1); }
html.bench-v1 .cv-track button i { font-size: 14px; }

html.bench-v1 .cv-sp { flex: 1 1 auto; min-width: 8px; }
html.bench-v1 .cv-find {
  display: flex; align-items: center; gap: 8px; height: 32px; padding: 0 10px; flex: none;
  min-width: 0; width: clamp(150px, 17vw, 240px);
  border: 1px solid var(--hair); border-radius: 9px; background: var(--sunken); cursor: text;
  color: var(--ink-3); font-size: 12.5px;
  transition: border-color var(--dur) var(--out);
}
html.bench-v1 .cv-find:hover { border-color: var(--hair-2); }
html.bench-v1 .cv-find i { font-size: 15px; flex: none; }
html.bench-v1 .cv-find span { flex: 1 1 auto; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
html.bench-v1 .cv-find kbd {
  font-family: var(--mono); font-size: 11px; color: var(--ink-3); flex: none;
  border: 1px solid var(--hair-2); border-radius: 5px; padding: 1px 5px; background: var(--panel);
}
html.bench-v1 .cv-cred {
  display: inline-flex; align-items: center; gap: 6px; height: 32px; padding: 0 10px; flex: none;
  border: 1px solid var(--hair); border-radius: 9px; background: transparent;
  color: var(--ink-2); font-size: 12px; cursor: pointer;
}
html.bench-v1 .cv-cred:hover { border-color: var(--hair-2); color: var(--ink); }
html.bench-v1 .cv-cred b { font-family: var(--num); font-variant-numeric: tabular-nums; color: var(--ink); font-weight: 600; }

/* THE RELOCATED ACTION CLUSTER. #topbarActions travels whole so each dropdown
   keeps its state, and it arrives wearing style.css's toolbar sizing — 16px
   text on a 52px bar whose own grammar is 12.5px. Four words at 16px made the
   shell bar the loudest thing on a page that is supposed to be a drawing. */
html.bench-v1 .cv-top #topbarActions { display: flex; align-items: center; gap: 4px; min-width: 0; }
html.bench-v1 .cv-top #topbarActions .btn,
html.bench-v1 .cv-top #topbarActions .btn-icon,
html.bench-v1 .cv-top #topbarActions .user-avatar-btn {
  height: 32px; padding: 0 9px; font-size: 12.5px; font-weight: 400;
  border: 1px solid transparent; border-radius: 9px; background: transparent;
  color: var(--ink-2); box-shadow: none; text-transform: none; letter-spacing: normal;
  gap: 6px; white-space: nowrap;
}
html.bench-v1 .cv-top #topbarActions .btn:hover,
html.bench-v1 .cv-top #topbarActions .btn-icon:hover,
html.bench-v1 .cv-top #topbarActions .user-avatar-btn:hover {
  background: var(--panel-2); color: var(--ink); border-color: var(--hair);
}
html.bench-v1 .cv-top #topbarActions .btn i { font-size: 16px; color: inherit; }
html.bench-v1 .cv-top #topbarActions .btn-chevron { font-size: 10px; color: var(--ink-3); }
/* The AI button was the accent-filled one; the bench already spends its one
   filled control on Auto-design, and two filled buttons side by side means
   neither is the primary. */
html.bench-v1 .cv-top #topbarActions .btn-ai { background: transparent; color: var(--ink-2); }
html.bench-v1 .cv-top #topbarActions .btn-ai:hover { background: var(--panel-2); color: var(--ink); }
/* The avatar reads as a person, not as a button with a label. */
html.bench-v1 .cv-top .user-avatar-btn .topbar-action-label { display: none; }
html.bench-v1 .cv-top .user-avatar-initials {
  width: 26px; height: 26px; border-radius: 50%; display: grid; place-items: center;
  background: var(--panel-2); border: 1px solid var(--hair-2);
  color: var(--ink-2); font-size: 11px; font-weight: 600;
}
html.bench-v1 .cv-top #aiCreditsChip {
  height: 30px; padding: 0 9px; border: 1px solid var(--hair); border-radius: 9px;
  background: transparent; color: var(--ink-2); font-size: 12px; font-weight: 600;
  font-family: var(--num); font-variant-numeric: tabular-nums;
}

/* ══ 2 · CONTEXT STRIP ══ one row. It shows the ACTIVE mode's tools and the
   ACTIVE tool's options — never both modes, never thirteen overlay toggles ══ */
html.bench-v1 .cv-strip {
  display: flex; align-items: center; gap: 6px; padding: 0 12px; min-width: 0;
  background: var(--panel); border-bottom: 1px solid var(--hair);
  /* NOT overflow:hidden. The strip is 44px tall and the Snap and View menus open
     BELOW it, so hidden clipped them away completely — the panels had a real
     224x381 box, were not [hidden], and still never painted: a hit test at the
     menu's own centre returned the record behind it. Twelve controls
     unreachable, and nothing to see when you clicked. The horizontal clipping
     the strip appeared to be doing is .cv-tools's job and it already does it
     with its own overflow-x. */
  overflow: visible;
}
html.bench-v1 .cv-div { width: 1px; height: 20px; background: var(--hair); flex: none; margin: 0 3px; }
/* The tool set is the one thing in this row allowed to scroll rather than
   vanish — a shrink-to-zero flex child takes the tools off a narrow screen. */
html.bench-v1 .cv-tools {
  display: flex; align-items: center; gap: 2px; min-width: 0; flex: 0 1 auto;
  overflow-x: auto; overflow-y: hidden; scrollbar-width: none;
}
html.bench-v1 .cv-tools::-webkit-scrollbar { display: none; }
/* The class comes from bench.js, which is the only thing that can know whether
   the row actually overflows. A word cut clean off at the edge reads as a bug;
   a word fading out reads as "there is more, scroll". */
html.bench-v1 .cv-tools.scrolls {
  mask-image: linear-gradient(90deg, black calc(100% - 24px), transparent);
}
/* The tool buttons are app.html's own .btn nodes, moved here with their ids and
   their onclick attributes. style.css's .btn is overridden rather than replaced
   so setTool's .active toggle keeps working untouched. */
html.bench-v1 .cv-tools .btn,
html.bench-v1 .cv-t {
  display: inline-flex; align-items: center; gap: 6px; height: 30px; padding: 0 9px; flex: none;
  border: 1px solid transparent; border-radius: 8px; background: transparent;
  color: var(--ink-2); font-size: 12.5px; font-weight: 400; cursor: pointer;
  box-shadow: none; text-transform: none; letter-spacing: normal; min-width: 0;
  transition: background var(--dur) var(--out), color var(--dur) var(--out), border-color var(--dur) var(--out);
}
html.bench-v1 .cv-tools .btn:hover,
html.bench-v1 .cv-t:hover { background: var(--panel-2); color: var(--ink); }
html.bench-v1 .cv-tools .btn i,
html.bench-v1 .cv-t i { font-size: 16px; flex: none; color: inherit; }
/* ONE tool is armed at a time, and it is the only recessed thing in the strip. */
html.bench-v1 .cv-tools .btn.active,
html.bench-v1 .cv-t.on {
  background: var(--accent-wash); color: var(--nr-on-wash);
  border-color: var(--accent-edge); font-weight: 600; box-shadow: none;
}
html.bench-v1[data-theme="dark"] .cv-tools .btn.active,
html.bench-v1[data-theme="dark"] .cv-t.on { color: var(--accent-2); }
html.bench-v1 .cv-tools .btn kbd,
html.bench-v1 .cv-t kbd {
  font-family: var(--mono); font-size: 11px; color: var(--ink-3); background: transparent;
  border: 1px solid var(--hair-2); border-radius: 4px; padding: 0 4px; line-height: 15px;
}
html.bench-v1 .cv-tools .btn.active kbd,
html.bench-v1 .cv-t.on kbd { border-color: currentcolor; color: inherit; opacity: .7; }

/* Options belong to the armed tool and disappear with it. setTool already drives
   their display by id — this only gives them the strip's grammar. */
html.bench-v1 .cv-opt { display: flex; align-items: center; gap: 7px; flex: none; min-width: 0; }
html.bench-v1 .cv-opt label,
html.bench-v1 .cv-opt .toolbar-label {
  font-size: 11px; letter-spacing: .05em; text-transform: uppercase;
  color: var(--ink-3); font-weight: 600; margin: 0;
}
html.bench-v1 .cv-opt select,
html.bench-v1 .cv-sel {
  height: 28px; padding: 0 26px 0 9px; border: 1px solid var(--hair-2); border-radius: 8px;
  background: var(--panel); color: var(--ink); font-size: 12px; cursor: pointer;
  appearance: none; font-family: var(--num); font-variant-numeric: tabular-nums;
  background-image: linear-gradient(45deg, transparent 50%, currentcolor 50%), linear-gradient(135deg, currentcolor 50%, transparent 50%);
  background-position: calc(100% - 14px) 12px, calc(100% - 9px) 12px;
  background-size: 5px 5px, 5px 5px; background-repeat: no-repeat;
}
/* The two tool GROUPS travel whole, because setToolbarMode flips their
   style.display by id. Inside the strip each is a flex row of its own buttons. */
html.bench-v1 .cv-tools > #toolbar-plan-tools,
html.bench-v1 .cv-tools > #toolbar-duct-tools { align-items: center; gap: 2px; min-width: 0; }
/* The shipped rows carry vertical rules between clusters; the strip is one row
   and reads as one, so they go. The strip's own .cv-div does that job. */
html.bench-v1 .cv-strip .tool-divider,
html.bench-v1 .cv-strip .toolbar-spacer { display: none; }

html.bench-v1 .cv-more-wrap { position: relative; flex: none; }
html.bench-v1 .cv-more {
  display: inline-flex; align-items: center; gap: 6px; height: 30px; padding: 0 10px; flex: none;
  border: 1px solid var(--hair); border-radius: 8px; background: transparent;
  color: var(--ink-2); font-size: 12.5px; cursor: pointer;
}
html.bench-v1 .cv-more:hover { border-color: var(--hair-2); color: var(--ink); }
html.bench-v1 .cv-more.open { border-color: var(--hair-2); background: var(--panel-2); color: var(--ink); }
html.bench-v1 .cv-more b { font-family: var(--num); font-variant-numeric: tabular-nums; font-weight: 600; color: var(--ink); }
html.bench-v1 .cv-more i.ti-chevron-down { font-size: 11px; color: var(--ink-3); }

/* The folded menus. Snap and View are not new controls — they are the editor's
   own toggle buttons, moved in here so the strip carries one row instead of
   thirteen. Each keeps its id, its onclick and its .active class. */
html.bench-v1 .cv-menu {
  position: absolute; top: calc(100% + 6px); right: 0; z-index: 60; min-width: 224px;
  padding: 6px; border: 1px solid var(--hair-2); border-radius: 12px;
  background: var(--panel); box-shadow: var(--sh-pop);
  display: flex; flex-direction: column; gap: 1px;
}
html.bench-v1 .cv-menu h4 {
  margin: 7px 8px 4px; font-size: 10.5px; font-weight: 600; letter-spacing: .06em;
  text-transform: uppercase; color: var(--ink-3);
}
html.bench-v1 .cv-menu h4:first-child { margin-top: 3px; }
html.bench-v1 .cv-menu .btn {
  display: flex; align-items: center; gap: 9px; width: 100%; height: 32px; padding: 0 9px;
  border: 1px solid transparent; border-radius: 8px; background: transparent;
  color: var(--ink-2); font-size: 12.5px; font-weight: 400; text-align: left;
  justify-content: flex-start; box-shadow: none; text-transform: none; letter-spacing: normal;
}
html.bench-v1 .cv-menu .btn:hover { background: var(--panel-2); color: var(--ink); }
html.bench-v1 .cv-menu .btn i { font-size: 16px; flex: none; color: inherit; }
/* A toggle inside a menu says ON with a mark, not with a fill — a row of filled
   rows reads as a selection, and these are independent switches. */
html.bench-v1 .cv-menu .btn.active { color: var(--ink); font-weight: 600; background: transparent; }
html.bench-v1 .cv-menu .btn.active::after {
  content: "\ea5e"; font-family: "tabler-icons" !important; margin-left: auto;
  font-size: 15px; color: var(--accent); line-height: 1;
}
html.bench-v1 .cv-menu .btn kbd { display: none; }
html.bench-v1 .cv-menu .btn[data-bench-label]::before { content: attr(data-bench-label); }

/* The project-info form is a two-column grid, and the Calibrate button sits in
   one cell — so "Calibrate from floor plan (recommended)" wrapped onto three
   lines inside a ~155px column while the cell beside it sat empty. It and the
   scale help line are full-width remarks, not paired fields. */
html.bench-v1 .lib-form-grid > div:not(.lib-form-row) { grid-column: 1 / -1; }
html.bench-v1 .lib-form-grid .btn-secondary { width: auto; white-space: nowrap; }

/* THE SHIPPED DROPDOWNS, ON THE MENU GRAMMAR.
   AI, Project, Tools, Share and the account menu are style.css's
   .export-dropdown / .user-dropdown. They already inherit the canon palette
   through the token remap, but they kept their own shape: a hairline under
   every row, a 210px min-width that wrapped half the labels onto two lines, and
   square-ish corners beside the strip's own 12px panels. Two menu grammars on
   one bar is the inconsistency; the rows are separated by hover, as in .cv-menu,
   not by a rule per row. */
html.bench-v1 .export-dropdown,
html.bench-v1 .user-dropdown {
  min-width: 244px; padding: 6px; border: 1px solid var(--hair-2);
  border-radius: 12px; background: var(--panel); box-shadow: var(--sh-pop);
}
html.bench-v1 .export-dropdown-item,
html.bench-v1 .user-dropdown-item {
  gap: 9px; min-height: 32px; padding: 7px 9px; border-radius: 8px;
  color: var(--ink-2); font-size: 12.5px; line-height: 1.35;
}
html.bench-v1 .export-dropdown-item + .export-dropdown-item,
html.bench-v1 .user-dropdown-item + .user-dropdown-item { border-top: 0; }
html.bench-v1 .export-dropdown-item:hover,
html.bench-v1 .user-dropdown-item:hover { background: var(--panel-2); color: var(--ink); }
html.bench-v1 .export-dropdown-item i,
html.bench-v1 .user-dropdown-item i { font-size: 16px; color: var(--ink-3); }
html.bench-v1 .export-dropdown-item:hover i { color: var(--ink-2); }
html.bench-v1 .dropdown-section-label {
  margin: 7px 8px 4px; padding: 0; font-size: 10.5px; font-weight: 600;
  letter-spacing: .06em; text-transform: uppercase; color: var(--ink-3); border: 0;
}
html.bench-v1 .user-dropdown-divider { background: var(--hair); margin: 5px 8px; }
html.bench-v1 .user-dropdown-header { padding: 8px 9px 9px; border-bottom: 1px solid var(--hair); margin-bottom: 4px; }
html.bench-v1 .user-dropdown-name { font-size: 13px; font-weight: 600; color: var(--ink); }
html.bench-v1 .user-dropdown-email { font-size: 11.5px; color: var(--ink-3); }
html.bench-v1 .ai-cost-badge {
  margin-left: auto; font-family: var(--num); font-variant-numeric: tabular-nums;
  font-size: 11px; color: var(--ink-3);
}
html.bench-v1 #aiProgressHeader:not(:empty) {
  margin: 2px 2px 6px; padding: 7px 9px; border-radius: 8px;
  background: var(--sunken); color: var(--ink-2); font-size: 11.5px;
}

/* The floating messenger bubble is pinned bottom-left, which is where the pane's
   foot line now lives — it sat on top of the supply total. The messenger has a
   top-bar button on this page, so the redundant bubble goes. */
html.bench-v1 .dm-launch { display: none !important; }

/* ══ 3 · BODY ══ the pane, the sheet, and the record it opens ══
   The record is a COLUMN, not a floating card. A panel that covers a quarter of
   a drawing is the thing every CAD tool gets wrong.

   AND IT DOES NOT ANIMATE. resizeCanvas() runs remapElementsForCanvas() whenever
   #canvasArea's box changes with a plan image loaded, rewriting elements[],
   walls[], dimensions[] and manualRooms[] in place. Animating this grid open on
   every selection would rewrite the saved geometry of the drawing, repeatedly.
   The column is width-reserved instead, and carries an empty state. */
/* THE TWO PANELS SLIDE OVER THE DRAWING; THEY DO NOT PUSH IT.
   They used to be grid COLUMNS, so opening or closing one re-laid the sheet and
   the drawing jumped sideways. Worse, every one of those width changes ran
   resizeCanvas -> remapElementsForCanvas, which re-derives every element's
   coordinates against the new box: the panels were literally rewriting the
   drawing's geometry each time they moved.

   As overlays the sheet NEVER changes size, so that whole class of problem is
   gone, and the motion is a transform — one compositor property, no layout, no
   reflow of a canvas the size of the window. The cost is honest and visible:
   an open panel covers the edge of the drawing rather than sitting beside it. */
html.bench-v1 .cv-body { position: relative; display: block; min-height: 0; min-width: 0; }

html.bench-v1 .cv-pane,
html.bench-v1 .cv-rec {
  position: absolute; top: 0; bottom: 0; z-index: 8;
  transition: transform .22s var(--out);
  will-change: transform;
}
html.bench-v1 .cv-pane { left: 0; width: var(--cv-pane); box-shadow: var(--sh-2); }
html.bench-v1 .cv-rec { right: 0; width: var(--cv-rec); box-shadow: var(--sh-2); }
/* Closed = off its own edge. translateX(-100%) rather than a width or a left,
   so nothing in the layout is touched while it moves. */
html.bench-v1 body.pane-collapsed .cv-pane { transform: translateX(-100%); }
html.bench-v1 body.rec-collapsed .cv-rec { transform: translateX(100%); }
@media (prefers-reduced-motion: reduce) {
  html.bench-v1 .cv-pane,
  html.bench-v1 .cv-rec { transition: none; }
}

html.bench-v1 .cv-pane {
  display: flex; flex-direction: column; min-height: 0; min-width: 0;
  background: var(--panel); border-right: 1px solid var(--hair);
}
/* An overlay sits ON the drawing, so it needs a real ground — a translucent or
   partial panel over a plan is unreadable. */
html.bench-v1 .cv-pane,
html.bench-v1 .cv-rec { background: var(--panel); }
/* ── COLLAPSED ──────────────────────────────────────────────────────────────
   Collapsed means fully off its own edge (see .cv-body above), not a rail. Now
   that the panels are overlays a rail would be pure occlusion — 44px of opaque
   stripe over a drawing that never got the width back anyway.

   What the rail was really carrying was the WAY BACK, and only the way back. A
   panel's dismiss is pressed while the panel is under your cursor, so it belongs
   on the panel; what cannot live there is the chevron that re-opens it, because
   that one would slide off with it. So the dismiss goes back onto each panel and
   the return trip gets a 20px handle on the edge the panel left from. Neither
   panel has a control in the shell bar. */
html.bench-v1 body.rec-collapsed .cv-rec,
html.bench-v1 body.pane-collapsed .cv-pane { box-shadow: none; }

/* ── THE EDGE HANDLES ───────────────────────────────────────────────────────
   Pinned to .cv-body — the same box the panels are positioned against — so each
   handle sits on exactly the edge its panel left from, at every width. z-index 7
   is UNDER the panels at 8 on purpose: an open panel passes over its own handle
   rather than the two fighting for the same 20px. Nothing about them animates
   the layout; the panel it summons does the moving. */
html.bench-v1 .cv-handle {
  position: absolute; top: 50%; z-index: 7; display: none;
  /* 24px wide, not the 20 it looks like it wants: flush to the viewport edge it
     is still a real target, and 24 is the floor a target is allowed to have. */
  width: 24px; height: 56px; margin-top: -28px; padding: 0;
  place-items: center;
  background: var(--panel); border: 1px solid var(--hair-2);
  color: var(--ink-3); font-size: 15px; cursor: pointer; box-shadow: var(--sh-1);
  transition: background var(--dur) var(--out), color var(--dur) var(--out);
}
html.bench-v1 .cv-handle:hover { background: var(--panel-2); color: var(--ink); }
html.bench-v1 .cv-handle:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
html.bench-v1 .cv-handle-l { left: 0; border-left: 0; border-radius: 0 9px 9px 0; }
html.bench-v1 .cv-handle-r { right: 0; border-right: 0; border-radius: 9px 0 0 9px; }
/* Shown only while its own side is shut — the one state in which the panel
   cannot offer the control itself. */
html.bench-v1 body.pane-collapsed .cv-handle-l,
html.bench-v1 body.rec-collapsed .cv-handle-r { display: grid; }

html.bench-v1 .cv-pane-track { padding: 10px 10px 0; flex: none; display: flex; align-items: center; gap: 6px; }
html.bench-v1 .cv-pane-track .cv-track { flex: 1 1 auto; min-width: 0; }
html.bench-v1 .cv-pane-track .cv-track button { flex: 1 1 0; justify-content: center; padding: 0 6px; min-width: 0; }
/* THE WORD IS THE IDENTITY, so the icon goes rather than the label. Three icons
   plus three words plus the Design badge do not fit 250px minus the collapse
   control — they crowded until "Library" ran into "Design". The collapsed rail
   is the one place the icon has to carry it, and it comes back there. */
html.bench-v1 .cv-pane-track .sidebar-tab i { display: none; }
html.bench-v1 .cv-pane-track .s-tab-badge {
  min-width: 16px; padding: 0 4px; border-radius: 99px; font-size: 10px;
  background: var(--sunken); color: var(--ink-3); font-family: var(--num);
}
html.bench-v1 #sidebarCollapseBtn {
  flex: none; display: inline-grid; place-items: center; width: 30px; height: 30px;
  border: 1px solid var(--hair); border-radius: 9px; background: transparent;
  color: var(--ink-3); font-size: 16px; cursor: pointer; box-shadow: none; padding: 0;
  transition: background var(--dur) var(--out), color var(--dur) var(--out), border-color var(--dur) var(--out);
}
html.bench-v1 #sidebarCollapseBtn:hover { background: var(--panel-2); color: var(--ink); border-color: var(--hair-2); }
/* The panes are app.html's own #pane-plan / #pane-design / #pane-library, moved.
   switchSidebarTab toggles .active on them, so .active is what shows. */
html.bench-v1 .cv-pane-body { flex: 1 1 auto; min-height: 0; overflow-y: auto; }
html.bench-v1 .cv-pane-body .sidebar-pane { display: none; padding: 12px 12px 18px; }
html.bench-v1 .cv-pane-body .sidebar-pane.active { display: block; }
html.bench-v1 .cv-pane .sidebar-hint {
  flex: none; padding: 8px 14px 0; font-size: 11.5px; color: var(--ink-3);
  background: transparent; border: 0;
}

/* the stage rail — the canon's rung grammar: one filled, the done ones recessed,
   the rest ghost. It is the editor's own #onboardingTracker, restyled. */
html.bench-v1 .cv-stage { padding: 14px 14px 13px; border-bottom: 1px solid var(--hair); flex: none; }
html.bench-v1 .cv-stage h3,
html.bench-v1 .cv-stage-h {
  margin: 0 0 10px; font-size: 11px; font-weight: 600; letter-spacing: .06em;
  text-transform: uppercase; color: var(--ink-3);
}
/* #onboardingTracker's own container padding and border came from the sidebar
   it used to sit in; .cv-stage supplies both now. */
html.bench-v1 .cv-stage #onboardingTracker { padding: 0; border: 0; }
/* The four steps keep their ids and their writer (updateOnboardingTracker sets
   inline colour and background on .ob-step / .ob-num). The numbered circle is
   what the rung replaces, so it is taken out of the flow entirely rather than
   restyled — a circle and a rung node at the same baseline read as two markers
   for one step. */
/* !important because the numbered circle carries display:flex INLINE in the
   markup, and updateOnboardingTracker keeps rewriting its background — so it was
   still drawing an accent-blue disc beside the rung dot: two markers for one
   step, one of them in the supply-duct hue. */
html.bench-v1 .cv-rung .ob-num { display: none !important; }
/* The chip is name + save state; with no project open it is an empty pill. */
html.bench-v1 .cv-top .cv-proj.is-empty { display: none; }
html.bench-v1 .cv-rung { color: var(--ink-2) !important; font-size: 12.5px !important; }
html.bench-v1 .cv-rung.done,
html.bench-v1 .cv-rung.completed { color: var(--ink-2) !important; }
html.bench-v1 .cv-rungs { list-style: none; margin: 0; padding: 0 0 0 17px; position: relative; }
html.bench-v1 .cv-rungs::before { content: ""; position: absolute; left: 0; top: 8px; bottom: 9px; width: 1px; background: var(--hair-2); }
html.bench-v1 .cv-rung { position: relative; display: flex; align-items: baseline; gap: 8px; padding: 5px 0; font-size: 12.5px; color: var(--ink-2); }
html.bench-v1 .cv-rung::before {
  content: ""; position: absolute; left: -21px; top: 9px; width: 7px; height: 7px; border-radius: 50%;
  background: var(--panel); border: 1.5px solid var(--hair-2);
}
html.bench-v1 .cv-rung.done::before { background: var(--ink-3); border-color: var(--ink-3); }
html.bench-v1 .cv-rung.now::before { background: var(--accent); border-color: var(--accent); width: 9px; height: 9px; left: -22px; top: 8px; }
html.bench-v1 .cv-rung.now { color: var(--ink); font-weight: 600; }
html.bench-v1 .cv-rung.next { color: var(--ink-3); }
html.bench-v1 .cv-rung .n {
  margin-left: auto; font-family: var(--num); font-variant-numeric: tabular-nums;
  font-size: 11.5px; color: var(--ink-3); font-weight: 400;
}
html.bench-v1 .cv-rung.now .n { color: var(--nr-on-wash); }
html.bench-v1[data-theme="dark"] .cv-rung.now .n { color: var(--accent-2); }

/* Stacked, not a row. "Supply on the drawing" plus its figure needs ~220px and
   the pane has 222px minus padding, so as a row it wrapped mid-phrase on every
   load. A label above its measurement never wraps and reads faster anyway. */
html.bench-v1 .cv-pane-foot {
  border-top: 1px solid var(--hair); padding: 9px 14px 11px; flex: none;
  display: grid; gap: 1px; font-size: 11.5px; color: var(--ink-2);
}
html.bench-v1 .cv-pane-foot > i { display: none; }
html.bench-v1 .cv-pane-foot .tot {
  font-family: var(--num); font-variant-numeric: tabular-nums;
  color: var(--ink); font-weight: 600; font-size: 14px;
  /* a measurement that wraps between its figure and its unit is two things */
  white-space: nowrap;
}
html.bench-v1 .cv-pane-foot > span { min-width: 0; }

/* ══ THE SHEET ══ */
/* absolute + inset:0, NOT relative. The panels are overlays now, so the sheet
   fills .cv-body outright and never resizes when one slides. Declared here, on
   the canonical .cv-sheet rule, because an earlier duplicate would lose to this
   one on source order and leave the sheet 0px tall — which it did. */
html.bench-v1 .cv-sheet { position: absolute; inset: 0; min-width: 0; min-height: 0; background: var(--sunken); overflow: hidden; }
/* #canvasArea must resolve its size against this box, not against its content,
   or the canvas never gets a definite height to measure.

   AND THE SHEET IS A SHEET. ui-next.css:48 paints it with a blue vignette and a
   STATIC dotted grid — a grid that does not pan or zoom, sitting underneath the
   world-space grid app.js draws on the canvas itself and the user toggles with
   the Grid button. Two grids that disagree the moment you scroll. Here the sheet
   is --d-sheet and nothing else, so the only marks on it are the drawing's. */
html.bench-v1 .cv-sheet #canvasArea {
  position: absolute; inset: 0; width: auto; height: auto; min-height: 0;
  border: 0; border-radius: 0;
  background-color: var(--d-sheet);
  background-image: none;
}

/* the armed tool says what it is and how to leave — bottom-left, out of the way */
html.bench-v1 .cv-pill,
html.bench-v1 .cv-sheet #canvasToolPill {
  position: absolute; left: 16px; bottom: 16px; top: auto; right: auto; z-index: 4;
  max-width: calc(100% - 190px); white-space: nowrap; min-width: 0;
  display: flex; align-items: center; gap: 9px; height: 34px; padding: 0 13px;
  border: 1px solid var(--hair-2); border-radius: 99px; background: var(--panel);
  box-shadow: var(--sh-2); font-size: 12.5px; color: var(--ink-2);
  transform: none;
}
html.bench-v1 .cv-pill i { font-size: 15px; color: var(--accent); flex: none; }
html.bench-v1 .cv-pill b { color: var(--ink); font-weight: 600; }
html.bench-v1 .cv-pill kbd {
  font-family: var(--mono); font-size: 11px; color: var(--ink-3); flex: none;
  border: 1px solid var(--hair-2); border-radius: 4px; padding: 1px 5px; background: transparent;
}

/* zoom cluster — the only floating control on the sheet */
html.bench-v1 .cv-zoom {
  position: absolute; right: 16px; bottom: 16px; z-index: 4;
  display: flex; align-items: center; padding: 3px; gap: 2px;
  border: 1px solid var(--hair); border-radius: 10px; background: var(--panel); box-shadow: var(--sh-1);
}
html.bench-v1 .cv-zoom button,
html.bench-v1 .cv-zoom .btn {
  width: 28px; height: 28px; min-width: 0; padding: 0; border: 0; border-radius: 7px;
  background: transparent; cursor: pointer; color: var(--ink-2); font-size: 15px;
  display: grid; place-items: center; box-shadow: none;
}
html.bench-v1 .cv-zoom button:hover,
html.bench-v1 .cv-zoom .btn:hover { background: var(--panel-2); color: var(--ink); }
html.bench-v1 .cv-zoom .z,
html.bench-v1 .cv-zoom #zoomLevel {
  padding: 0 8px; font-family: var(--num); font-variant-numeric: tabular-nums;
  font-size: 11.5px; color: var(--ink-2); min-width: 42px; text-align: center;
}

/* ── the proposal bar: the one moment the app asks for a decision ── */
html.bench-v1 .cv-sheet #aiProposalBar {
  position: absolute; left: 50%; top: 16px; right: auto; bottom: auto;
  transform: translateX(-50%); z-index: 6;
  display: flex; align-items: center; gap: 14px; max-width: calc(100% - 32px);
  padding: 11px 12px 11px 16px; border: 1px solid var(--accent-edge);
  border-radius: 13px; background: var(--panel); box-shadow: var(--sh-pop);
}
html.bench-v1 .cv-ghost {
  display: inline-flex; align-items: center; gap: 6px; height: 32px; padding: 0 12px;
  border: 1px solid var(--hair-2); border-radius: 9px; background: var(--panel);
  color: var(--ink-2); font-size: 12.5px; cursor: pointer;
  transition: border-color var(--dur) var(--out), color var(--dur) var(--out);
}
html.bench-v1 .cv-ghost:hover { border-color: var(--ink-3); color: var(--ink); }

/* ══ THE RECORD ══ the selected element, in auth.css's own card.
   .tray/.rec/.att below are COPIED from auth.css:115-205 and containerised under
   .cv-rec. The class names are unchanged on purpose — the record here is
   literally the same object as a sign-in record and a dispatch job — but auth.css
   itself is never linked, because it ships bare .btn-primary and app.html has
   twenty of them. If this component is ever extracted to a shared record.css,
   this block is a delete. ══ */
html.bench-v1 .cv-rec {
  min-width: 0; min-height: 0; overflow: hidden auto;
  background: var(--paper); border-left: 1px solid var(--hair);
}
/* THE NESTING COSTS TOO MUCH IN A COLUMN. auth.css's tray/rec grammar was drawn
   for a ~600px sign-in panel, where three concentric paddings are nothing. Here
   they took 57px off a 344px column before any content, leaving a 118px input
   that clipped its own value. The card structure is kept — it is the whole point
   of the record — but each ring gives back what it can spare. */
html.bench-v1 .cv-rec-in { padding: 10px 8px 16px; min-width: 0; }
html.bench-v1 .cv-rec .tray {
  position: relative; max-width: none;
  padding: 0 7px 9px; border-radius: 14px;
  background: var(--sunken); border: 1px solid var(--hair); box-shadow: var(--sh-2);
}
html.bench-v1 .cv-rec .divs { display: flex; align-items: flex-end; gap: 5px; padding: 0 6px; height: 31px; overflow: hidden; }
html.bench-v1 .cv-rec .div-t {
  flex: 0 1 auto; min-width: 0; height: 25px; padding: 0 10px;
  border-radius: 7px 7px 0 0;
  background: var(--panel-2); border: 1px solid var(--hair); border-bottom: 0;
  font-size: 11.5px; line-height: 23px; color: var(--ink-2);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* The chevron sits at the end of the record's own tab row, on the card's
   shoulder — the same place the pane's control sits relative to its tabs. */
html.bench-v1 .cv-rec .cv-rec-tog {
  margin-left: auto; flex: none; align-self: center;
  display: inline-grid; place-items: center; width: 28px; height: 28px;
  border: 1px solid transparent; border-radius: 8px; background: transparent;
  color: var(--ink-3); font-size: 16px; cursor: pointer; padding: 0;
  transition: background var(--dur) var(--out), color var(--dur) var(--out), border-color var(--dur) var(--out);
}
html.bench-v1 .cv-rec .cv-rec-tog:hover { background: var(--panel-2); color: var(--ink); border-color: var(--hair); }

html.bench-v1 .cv-rec .div-t.on {
  flex: none; height: 31px; line-height: 29px;
  background: var(--panel); border-color: var(--hair-2);
  color: var(--ink); font-weight: 600;
}
html.bench-v1 .cv-rec .rec {
  position: relative; border: 1px solid var(--hair-2); border-radius: 12px;
  background: var(--panel); box-shadow: var(--sh-2); padding: 13px 12px 13px;
}
html.bench-v1 .cv-rec .rec-top { display: flex; align-items: center; gap: 12px; padding-bottom: 11px; border-bottom: 1px solid var(--hair); }
html.bench-v1 .cv-rec .rec-ref {
  font-family: var(--mono); font-size: 10.5px; letter-spacing: .06em; color: var(--ink-2);
  border: 1px solid var(--hair-2); border-radius: 99px; padding: 3px 9px;
}
html.bench-v1 .cv-rec .rec-since { margin-left: auto; font-size: 11.5px; color: var(--ink-2); }
html.bench-v1 .cv-rec .rec-name { font-size: 16.5px; font-weight: 600; letter-spacing: -.026em; margin-top: 10px; }
/* auth.css runs .rec-meta at three columns because a sign-in panel is half a
   screen wide. In a 344px column that puts a two-word value on three lines. */
html.bench-v1 .cv-rec .rec-meta { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px 12px; margin-top: 11px; }
html.bench-v1 .cv-rec .rec-meta dt {
  font-size: 10.5px; font-weight: 600; letter-spacing: .06em;
  text-transform: uppercase; color: var(--ink-3);
}
html.bench-v1 .cv-rec .rec-meta dd { font-size: 12.5px; color: var(--ink); margin-top: 3px; line-height: 1.4; }
html.bench-v1 .cv-rec .rec-meta dd small { display: block; color: var(--ink-2); font-size: 11.5px; }
html.bench-v1 .cv-rec .att { margin-top: 15px; padding-top: 13px; border-top: 1px solid var(--hair); }
html.bench-v1 .cv-rec .att-h {
  font-size: 10.5px; font-weight: 600; letter-spacing: .06em;
  text-transform: uppercase; color: var(--ink-3); margin-bottom: 9px;
}
html.bench-v1 .cv-rec .att-l { list-style: none; position: relative; margin-left: 5px; padding-left: 17px; }
html.bench-v1 .cv-rec .att-l::before { content: ""; position: absolute; left: 0; top: 6px; bottom: 8px; width: 1px; background: var(--hair-2); }
html.bench-v1 .cv-rec .att-i {
  position: relative; display: grid; grid-template-columns: minmax(0, 1fr) auto;
  gap: 2px 10px; align-items: baseline; padding: 6px 0;
}
html.bench-v1 .cv-rec .att-i::before {
  content: ""; position: absolute; left: -21.5px; top: 11px;
  width: 7px; height: 7px; border-radius: 50%;
  background: var(--panel); border: 1.5px solid var(--accent);
}
html.bench-v1 .cv-rec .att-i b { font-size: 12.5px; font-weight: 600; letter-spacing: -.01em; }
html.bench-v1 .cv-rec .att-i .st { font-size: 11.5px; color: var(--ink-2); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
html.bench-v1 .cv-rec .att-i .amt {
  font-family: var(--num); font-variant-numeric: tabular-nums;
  font-size: 12.5px; font-weight: 600; color: var(--ink); white-space: nowrap; text-align: right;
}

/* the relocated #propsContent, wearing the record's grammar rather than the
   floating panel's. Its markup is app.js's, generated by template literals. */
html.bench-v1 .cv-rec #propertiesPanel,
html.bench-v1 .cv-rec #propsNoSel,
html.bench-v1 .cv-rec #wallProps { background: transparent; border: 0; padding: 0; box-shadow: none; }
html.bench-v1 .cv-rec #propsNoSel { font-size: 12.5px; color: var(--ink-3); padding: 22px 4px; text-align: center; }
/* The value is the part that runs long — a duct label, a room name. The label
   beside it is two short words and does not need an equal share. */
/* ONE GRAMMAR FOR .prop-*, WHEREVER IT APPEARS. The pane's workflow settings
   (Home size, Climate, Zones) use the same three classes as the record's
   property rows, and scoping the styling to .cv-rec left the pane on style.css's
   version — same markup, two looks, and selects narrow enough to clip
   "Medium 150-250m2" and "Zone 5 - Warm t...". */
html.bench-v1 .cv-rec .prop-row,
html.bench-v1 .cv-pane-body .prop-row { display: grid; grid-template-columns: minmax(0, .78fr) minmax(0, 1.22fr); align-items: center; gap: 8px 9px; padding: 5px 0; }
html.bench-v1 .cv-rec .prop-label,
html.bench-v1 .cv-pane-body .prop-label { font-size: 11.5px; color: var(--ink-2); margin: 0; }
html.bench-v1 .cv-pane-body .prop-row { grid-template-columns: minmax(0, 1fr); gap: 3px; padding: 6px 0; }
html.bench-v1 .cv-rec .prop-input,
html.bench-v1 .cv-pane-body .prop-input {
  height: 28px; width: 100%; min-width: 0; padding: 0 8px;
  border: 1px solid var(--hair-2); border-radius: 7px;
  background: var(--panel); color: var(--ink); font-size: 12px;
  font-family: var(--num); font-variant-numeric: tabular-nums;
}
html.bench-v1 .cv-rec .prop-input:focus-visible,
html.bench-v1 .cv-pane-body .prop-input:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; border-color: var(--accent); }
/* A select needs room for its own chevron before its value starts truncating. */
html.bench-v1 .cv-pane-body select.prop-input { height: 30px; padding-right: 26px; }

html.bench-v1 .cv-checks { margin-top: 13px; padding-top: 12px; border-top: 1px solid var(--hair); display: grid; gap: 7px; }
html.bench-v1 .cv-check { display: grid; grid-template-columns: 16px minmax(0, 1fr) auto; align-items: baseline; gap: 9px; font-size: 12px; color: var(--ink-2); }
html.bench-v1 .cv-check i { font-size: 14px; color: var(--accent); justify-self: center; }
html.bench-v1 .cv-check.warn i { color: var(--hot); }
html.bench-v1 .cv-check b { font-family: var(--num); font-variant-numeric: tabular-nums; font-size: 12.5px; font-weight: 600; color: var(--ink); }
html.bench-v1 .cv-check.warn b { color: var(--nr-danger-ink); }
html.bench-v1[data-theme="dark"] .cv-check.warn b { color: var(--hot); }
html.bench-v1 .cv-rec-acts { display: flex; gap: 7px; margin-top: 14px; padding-top: 12px; border-top: 1px solid var(--hair); }
html.bench-v1 .cv-rec-acts .btn,
html.bench-v1 .cv-rec-acts .btn-icon {
  flex: 1 1 0; justify-content: center; display: inline-flex; align-items: center; gap: 6px;
  height: 32px; width: auto; min-width: 0; padding: 0 10px;
  border: 1px solid var(--hair-2); border-radius: 9px; background: var(--panel);
  color: var(--ink-2); font-size: 12.5px; box-shadow: none;
}
html.bench-v1 .cv-rec-acts .btn-icon:hover:not(:disabled) { border-color: var(--ink-3); color: var(--ink); }
html.bench-v1 .cv-rec-acts .btn-danger:hover:not(:disabled) { border-color: var(--hot); color: var(--nr-danger-ink); }
html.bench-v1[data-theme="dark"] .cv-rec-acts .btn-danger:hover:not(:disabled) { color: var(--hot); }
html.bench-v1 .cv-rec-acts .btn-icon:disabled { opacity: .4; }
/* The icon-only buttons say what they do once they are the record's actions and
   not a dense toolbar cluster — there is room, and "trash" beside a design is
   worth a word. */
html.bench-v1 .cv-rec-acts .btn-icon::after { content: attr(data-bench-label); }

/* ══ 4 · STATUS ══ measurement, not decoration ══ */
html.bench-v1 .cv-status {
  display: flex; align-items: center; gap: 14px; padding: 0 12px; min-width: 0;
  background: var(--panel); border-top: 1px solid var(--hair);
  font-size: 11.5px; color: var(--ink-2); overflow: hidden;
}
html.bench-v1 .cv-status .m { display: flex; align-items: center; gap: 6px; flex: none; white-space: nowrap; }
/* The shipped bar separated its readings with vertical rules and a fixed height.
   Four measurements on one ground need neither — the gap does that work. */
html.bench-v1 .cv-status .status-item { border: 0; padding: 0; height: auto; }
html.bench-v1 .cv-status .m i { font-size: 14px; color: var(--ink-3); }
html.bench-v1 .cv-status b,
html.bench-v1 .cv-status .status-value { font-family: var(--num); font-variant-numeric: tabular-nums; color: var(--ink); font-weight: 600; }
html.bench-v1 .cv-status .m.k { font-family: var(--mono); font-size: 11px; }
html.bench-v1 .cv-bar { display: flex; align-items: center; gap: 7px; flex: none; }
html.bench-v1 .cv-bar .rule { width: 76px; height: 7px; border-left: 1px solid var(--ink-3); border-right: 1px solid var(--ink-3); border-bottom: 1px solid var(--ink-3); }
html.bench-v1 .cv-health,
html.bench-v1 .cv-status #healthScorePill {
  display: inline-flex; align-items: center; gap: 6px; height: 20px; padding: 0 9px; flex: none;
  border: 1px solid var(--accent-edge); border-radius: 99px;
  background: var(--accent-wash); color: var(--nr-on-wash); font-size: 11px; font-weight: 600;
}
html.bench-v1[data-theme="dark"] .cv-health,
html.bench-v1[data-theme="dark"] .cv-status #healthScorePill { color: var(--accent-2); }
html.bench-v1 .cv-health i { font-size: 13px; }

/* ══ responsive ══ the pane is the first thing to go; the sheet never is ══ */
@media (max-width: 1400px) {
  html.bench-v1 { --cv-rec: clamp(288px, 22vw, 320px); }
  /* Below this the column cannot hold a label and a value side by side without
     the value losing — and the value is the part that runs long. The label goes
     above it and the field takes the whole width. */
  html.bench-v1 .cv-rec .prop-row { grid-template-columns: minmax(0, 1fr); gap: 3px; padding: 6px 0; }
  html.bench-v1 .cv-rec .prop-label { font-size: 11px; letter-spacing: .01em; }
}
@media (max-width: 1280px) {
  html.bench-v1 .cv-proj .pa { display: none; }
  html.bench-v1 .cv-find { width: 150px; }
}
@media (max-width: 1080px) {
  html.bench-v1 { --cv-pane: 214px; }
  html.bench-v1 .cv-find span { display: none; }
  html.bench-v1 .cv-find { width: auto; padding: 0 9px; }
  /* THE TOOL LABELS STAY, AT EVERY WIDTH, AND THE STRIP SCROLLS INSTEAD.
     Supply and Return are both ti-minus, and Fresh and Exhaust are a breeze and
     a pair of arrows — the four were told apart by their colour stripe, which
     the colour law has just taken out of the chrome. Collapsing them to icons
     would leave two identical buttons side by side. The word is the identity
     now, so the shortcut keys go and .cv-tools uses the overflow it was given. */
  html.bench-v1 .cv-tools .btn kbd { display: none; }
  html.bench-v1 .cv-tools .btn { padding: 0 8px; }

}
/* Below 860 a phone is a REVIEW surface, not a drawing surface: the pane and the
   record both become overlays the drawing survives, and neither opens on
   arrival. What a contractor does here is look at the design and read a run. */
@media (max-width: 860px) {
  html.bench-v1 { --cv-top: 50px; --cv-strip: 42px; }
  html.bench-v1 { --cv-pane: min(264px, 84%); --cv-rec: min(320px, 92%); }
  html.bench-v1 .cv-mark span,
  html.bench-v1 .cv-proj,
  html.bench-v1 .cv-track.floors,
  html.bench-v1 .cv-cred,
  html.bench-v1 .cv-find { display: none; }
  /* On a phone the OPTIONS give way, never the tools. Every fixed-width sibling
     in this row is flex:none, so leaving them in is what squeezed the tool set
     to nothing — the one control the row exists for. */
  html.bench-v1 .cv-strip .cv-opt,
  html.bench-v1 .cv-strip .cv-div,
  html.bench-v1 .cv-strip .cv-more { display: none; }
  html.bench-v1 .cv-tools { flex: 1 1 auto; }
  html.bench-v1 .cv-rec .tray { box-shadow: none; background: transparent; border: 0; padding: 0; }
  /* The tab row's LABEL goes — on a phone the record is simply whatever you just
     tapped — but its CHEVRON stays. With no panel control in the shell bar, that
     chevron is the only way to put the record away. */
  html.bench-v1 .cv-rec .divs { height: auto; padding: 2px 0 6px; justify-content: flex-end; }
  html.bench-v1 .cv-rec .div-t { display: none; }
  /* Here the pane is a DRAWER, not a collapsible column: it starts off its edge
     and the shell bar's burger is the door. So the left handle would be a second
     door to the same room, and the burger — whose rule went missing when the
     panels became overlays, leaving it wired to nothing — gets it back. */
  html.bench-v1 .cv-pane { transform: translateX(-100%); box-shadow: var(--sh-pop); }
  html.bench-v1 body.pane-open .cv-pane { transform: none; }
  html.bench-v1 .cv-handle-l,
  html.bench-v1 body.pane-collapsed .cv-handle-l { display: none; }
  html.bench-v1 .cv-sheet #aiProposalBar { left: 10px; right: 10px; transform: none; max-width: none; }
  html.bench-v1 .cv-status .m.hide-s { display: none; }
  html.bench-v1 body.rec-open .cv-pill,
  html.bench-v1 body.rec-open .cv-zoom { display: none; }
}
@media (min-width: 861px) {
  html.bench-v1 .cv-burger { display: none; }
}
@media (max-width: 560px) {
  html.bench-v1 .cv-pill { left: 10px; bottom: 10px; font-size: 12px; }
  html.bench-v1 .cv-zoom { right: 10px; bottom: 10px; }
  html.bench-v1 .cv-rec .rec-meta { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  /* A phone is a REVIEW surface. The footer keeps what you READ — the air on the
     drawing and whether it passes — and drops what you only need while drawing.
     Clipping them instead (the bar is overflow:hidden) leaves a half-word at the
     edge, which reads as a bug rather than as a decision. */
  html.bench-v1 .cv-status .m { display: none; }
  html.bench-v1 .cv-status #statusFlowBar,
  html.bench-v1 .cv-status .health-pill-wrap { display: flex; }
  html.bench-v1 .cv-status { gap: 10px; }
}
@media (prefers-reduced-motion: reduce) {
  html.bench-v1 .cv-pane { transition: none; }
}
