/* ==========================================================================
   THE SITE DESIGNER — the workspace.

   THREE REGIONS, NOT FIVE PANES. The first version was a five-column grid —
   materials, plan, 3D, stack, take-off — all the same weight, all fighting for
   the same screen. Nothing was primary, so it read as a dashboard of leftovers
   rather than as a tool.

   The shape every serious editor converges on is: NAVIGATION on the left,
   the WORK in the middle at whatever size is left, and an INSPECTOR on the
   right that changes with what is selected. One thing is the subject, and it
   is the canvas.

   THE IDIOM IS THE CURRENT ONE, DELIBERATELY. Floating panels on a darker
   page, 12px radii, hairlines at 8% rather than hard borders, generous row
   heights, one saturated accent used only for state. That is what Linear,
   Figma and every current AI product look like, and it is not fashion — the
   gutter between panels is what lets an eye find a region without a heavy
   border, and heavy borders on a dense tool are what make it look cheap.

   IT INHERITS THE PORTAL'S TOKENS. Colours, type and radii all come from
   office.css, so this page cannot drift from the rest of /admin.
   ========================================================================== */

#design {
  --dz-gut: 12px;
  --dz-side: 272px;
  --dz-insp: 340px;
  --dz-top: 64px;
  --dz-panel: #161A1D;
  --dz-line: #232A30;
  --dz-raised: #1D2226;
  display: grid;
  grid-template-columns: var(--dz-side) minmax(0, 1fr) var(--dz-insp);
  grid-template-rows: var(--dz-top) minmax(0, 1fr);
  grid-template-areas: 'side top top' 'side work insp';
  gap: var(--dz-gut);
  padding: var(--dz-gut);
  height: 100dvh;
  background: var(--o-bg);
  overflow: hidden;
}
#design .dz-card {
  background: var(--dz-panel);
  border: 1px solid var(--dz-line);
  border-radius: 12px;
  min-width: 0;
  min-height: 0;
}

/* ---- sidebar ------------------------------------------------------------ */
#design .dz-side { grid-area: side; display: flex; flex-direction: column; overflow: hidden; }
#design .dz-brand {
  display: flex; align-items: center; gap: 0.7rem;
  padding: 0.95rem 1rem; border-bottom: 1px solid var(--dz-line);
}
#design .dz-brand img { width: 34px; height: 34px; border-radius: 9px; flex: none; }
#design .dz-brand b { display: block; font-family: var(--display); font-size: 1rem; font-weight: 800; color: var(--o-text); letter-spacing: -0.01em; }
#design .dz-brand span { display: block; font-size: 0.72rem; color: var(--o-faint); }

#design .dz-nav { flex: 1; overflow: auto; padding: 0.85rem 0.6rem 1.4rem; }
#design .dz-grp {
  margin: 1.1rem 0 0.45rem; padding: 0 0.55rem;
  font-family: var(--display); font-size: 0.625rem; font-weight: 700;
  letter-spacing: 0.14em; text-transform: uppercase; color: var(--o-faint);
}
#design .dz-nav > .dz-grp:first-child { margin-top: 0; }
/* 34px rows. A dense 24px list is a settings screen; this is a workflow and
   each row is a decision, so it gets a decision's worth of space. */
#design .dz-step {
  display: flex; align-items: center; gap: 0.65rem; width: 100%;
  padding: 0.5rem 0.55rem; border: 0; border-radius: 9px;
  background: none; color: var(--o-dim); cursor: pointer;
  font: 400 0.8125rem/1.2 var(--body); text-align: left;
}
#design .dz-step:hover { background: var(--o-hover); color: var(--o-text); }
#design .dz-step.is-on { background: var(--o-accent-wash); color: var(--o-text); font-weight: 600; }
#design .dz-step__i {
  width: 15px; height: 15px; flex: none; border-radius: 4px;
  border: 1.5px solid currentColor; opacity: 0.55;
}
#design .dz-step.is-on .dz-step__i { border-color: var(--o-accent); opacity: 1; }
/* The examples picker wears the same chrome as the buttons beside it, so the
   rail reads as one list rather than a list with a form control dropped in. */
#design .dz-step--sel { gap: 0.5rem; }
#design .dz-step--sel select {
  flex: 1; min-width: 0; margin-left: auto;
  border: 0; border-radius: 6px; padding: 0.2rem 0.25rem;
  background: var(--o-hover); color: inherit;
  font: inherit; cursor: pointer;
}
#design .dz-step--sel select:focus-visible { outline: 2px solid var(--o-accent); outline-offset: 1px; }
/* The size field reads as a measurement, not as a search box. */
#design .dz-size input {
  width: 5.6rem; margin: 0 0.4rem; padding: 0.15rem 0.35rem;
  border: 1px solid var(--o-line, rgba(255,255,255,.14)); border-radius: 5px;
  background: var(--o-hover); color: inherit;
  font: 400 0.8125rem/1.3 ui-monospace, SFMono-Regular, Menlo, monospace;
}
#design .dz-size input:focus-visible { outline: 2px solid var(--o-accent); outline-offset: 1px; }
/* THE ONE CHECKBOX AMONG THE SLIDERS. Every other control on this row is a
   range with a value beside it, so a bare checkbox sits on a different
   baseline and reads as something that fell in from another panel. The note
   after it is empty most of the time and only fills when the setting cannot
   take effect — a garage ticked on a building no paving reaches — so it must
   collapse to nothing rather than reserve a gap. */
#design .dz-chk { display: inline-flex; align-items: center; gap: 0.35rem; }
#design .dz-chk input { margin: 0; accent-color: var(--o-accent); }
#design .dz-chk b { font-weight: 400; opacity: 0.7; }
#design .dz-chk b:empty { display: none; }
/* The headline: three figures, always on screen, reading as numbers rather
   than as prose. Tabular figures so they do not jitter as they change. */
#design .dz-head {
  display: flex; flex-wrap: wrap; gap: 0.15rem 1.1rem;
  margin: 0 0 0.5rem; padding: 0.45rem 0.6rem;
  border-radius: 8px; background: var(--o-hover);
  font: 400 0.8125rem/1.35 var(--body); color: var(--o-dim);
  font-variant-numeric: tabular-nums;
}
#design .dz-head b { color: var(--o-text); font-weight: 600; }
/* ---- the project's open problems ----------------------------------------
   Sits directly under the headline, above the tabs, so it is on screen no
   matter which tab the operator is working in. It was previously the single
   hint line under the plan, which holds one message and is overwritten by the
   next thing that happens.

   RANKED BY A LEFT EDGE, not by a background wash: three of these can be open
   at once and three washes stacked read as an error state for the whole panel.
   The bar says how bad, the text says what. */
#design .dz-issues {
  margin: 0 0 0.5rem; display: flex; flex-direction: column; gap: 0.3rem;
}
#design .dz-issues__h {
  margin: 0; font: 600 0.6875rem/1.3 var(--body); letter-spacing: 0.08em;
  text-transform: uppercase; color: var(--o-warn-ink);
}
#design .dz-issue {
  display: block; width: 100%; text-align: left; margin: 0;
  padding: 0.4rem 0.55rem 0.4rem 0.6rem;
  border: 0; border-left: 3px solid var(--o-faint); border-radius: 0 6px 6px 0;
  background: var(--o-hover); color: var(--o-dim);
  font: 400 0.75rem/1.4 var(--body);
}
#design button.dz-issue { cursor: pointer; }
#design button.dz-issue:hover { background: var(--o-accent-wash); color: var(--o-text); }
#design .dz-issue--3 { border-left-color: var(--o-warn); color: var(--o-warn-ink); }
#design .dz-issue--2 { border-left-color: var(--o-warn); }
#design .ofc-table tbody tr { cursor: pointer; }
#design .ofc-table tbody tr:hover { background: var(--o-hover); }
#design .ofc-table tbody tr.is-sel { background: var(--o-accent-wash); }
#design .dz-step__n { margin-left: auto; font-size: 0.6875rem; color: var(--o-faint); font-variant-numeric: tabular-nums; }
/* THE TAPES UNDER THE SCALE STEP. Each measurement with its own disagreement
   and a way to drop it — see `renderTapes`. Indented under the step it belongs
   to, small, and out of the way until there is something in it. */
#design .tapes { list-style: none; margin: 0.125rem 0 0.375rem; padding: 0 0 0 1.5rem; }
#design .tape { display: flex; align-items: center; gap: 0.375rem;
  font-size: 0.6875rem; color: var(--o-faint); font-variant-numeric: tabular-nums;
  padding: 0.0625rem 0; }
/* An ignored tape is struck through, because "ignored" is a fact about the
   measurement and not a warning about the project. */
#design .tape.is-out { color: var(--o-warn, #D9A441); text-decoration: line-through; }
#design .tape__x { margin-left: auto; border: 0; background: none; cursor: pointer;
  color: var(--o-faint); font-size: 0.875rem; line-height: 1; padding: 0 0.25rem; }
#design .tape__x:hover { color: var(--o-warn, #D9A441); }

/* ---- top bar ------------------------------------------------------------ */
#design .dz-top {
  grid-area: top; display: flex; align-items: center; gap: 1rem;
  padding: 0 0.75rem 0 1.1rem;
}
#design .dz-title { min-width: 0; }
#design .dz-title input {
  display: block; width: 100%; background: none; border: 0; padding: 0;
  font-family: var(--display); font-size: 1.0625rem; font-weight: 700;
  color: var(--o-text); letter-spacing: -0.012em;
}
#design .dz-title input::placeholder { color: var(--o-faint); }
#design .dz-title p { margin: 0.1rem 0 0; font-size: 0.75rem; color: var(--o-faint); font-variant-numeric: tabular-nums; }

/* A segmented control, which is the right thing for "which of these three am I
   looking at" and the wrong thing for anything with more than four options. */
#design .dz-seg { display: flex; gap: 2px; padding: 3px; margin-left: auto; background: var(--dz-raised); border: 1px solid var(--dz-line); border-radius: 9px; }
#design .dz-seg button {
  border: 0; border-radius: 7px; background: none; color: var(--o-dim);
  padding: 0.34rem 0.85rem; font: 600 0.75rem/1 var(--body); cursor: pointer;
}
#design .dz-seg button:hover { color: var(--o-text); }
#design .dz-seg button.is-on { background: var(--o-raised); color: var(--o-text); }

/* The viewpoint control sits ON the 3D view, top right — opposite the `3D`
   key and clear of the sun panel at the bottom. Same segmented control as the
   header, so it reads as the same kind of thing, but it has to shed the
   header's `margin-left:auto` and take a solid ground because it is over a
   render rather than over a card. Tighter padding: five buttons have to fit
   the split pane, which is about half the window. */
#design .dz-views {
  position: absolute; top: 8px; right: 12px; z-index: 2;
  margin-left: 0; flex-wrap: wrap; max-width: calc(100% - 24px);
  background: rgba(11, 14, 12, 0.86);
}
#design .dz-views button { padding: 0.3rem 0.6rem; }
/* Fit is an action, not one of the four states, and must not look selectable. */
#design .dz-views #camfit {
  margin-left: 3px; padding-left: 0.62rem;
  border-left: 1px solid var(--dz-line); border-radius: 0 7px 7px 0;
}

/* THE TWO DELIVERABLES, BOTTOM left. Not top right — the viewpoint segment
   holds five buttons there and already wraps onto two rows in the split pane.
   Not top left either, which is where `.dz-view__k` puts the "3D" key at
   top:10px left:12px: the segment is opaque and would have covered it. Same
   treatment otherwise: it sits over the render, not over a card. */
#design .dz-modes {
  position: absolute; bottom: 8px; left: 12px; z-index: 2;
  margin-left: 0; background: rgba(11, 14, 12, 0.86);
}
#design .dz-modes button { padding: 0.3rem 0.6rem; }

/* QUALITY sits directly above the two deliverables, same corner and same
   treatment, because they are the same kind of thing: a choice about how this
   view is drawn that cannot touch a quantity. Above rather than beside, so the
   pair still fits the split pane, which is about half a window wide. */
#design .dz-qual {
  position: absolute; bottom: 46px; left: 12px; z-index: 2;
  margin-left: 0; background: rgba(11, 14, 12, 0.86);
}
#design .dz-qual button { padding: 0.3rem 0.6rem; }
/* The measurement, INSIDE the control that changes it — a flex item after the
   three buttons, so it sits where it belongs at any button width instead of at
   a pixel offset guessed from one font. Tabular figures so a number that is
   climbing does not also jitter sideways while it does. */
#design .dz-qms {
  align-self: center; padding: 0 0.5rem 0 0.35rem;
  font: 600 0.7rem/1 var(--body); color: var(--o-faint);
  font-variant-numeric: tabular-nums; white-space: nowrap;
}

#design .dz-acts { display: flex; gap: 0.4rem; }
#design .dz-btn {
  border: 1px solid var(--dz-line); border-radius: 9px; background: var(--dz-raised);
  color: var(--o-dim); padding: 0.42rem 0.8rem; font: 600 0.75rem/1 var(--body); cursor: pointer;
}
#design .dz-btn:hover:not(:disabled) { color: var(--o-text); border-color: var(--o-line-2); }
#design .dz-btn:disabled { opacity: 0.4; cursor: default; }
#design .dz-btn--go { background: var(--o-accent-deep); border-color: var(--o-accent-deep); color: var(--o-bg); }
#design .dz-btn--go:hover { background: var(--o-accent-hi); border-color: var(--o-accent-hi); color: var(--o-bg); }

/* ---- the work ----------------------------------------------------------- */
/* WIDE: the rail and the inspector fold away and the work takes the window.
   Driven off the same custom properties the grid is already built from, so
   there is one definition of the layout and this is a different value of it
   rather than a second layout. The canvases are sized from their client box in
   JS, and a class change fires no resize event, so app.mjs redraws both. */
#design.is-wide { --dz-side: 0px; --dz-insp: 0px; }
#design.is-wide .dz-side,
#design.is-wide .dz-insp { display: none; }

/* FULL: the 3D pane leaves the grid and takes the viewport.
   NOT the Fullscreen API, which was the first attempt and did not work — the
   pane is a grid item, and a grid item handed to `requestFullscreen` is still
   laid out by rules that size it from `.dz-work`'s columns, so the plan's half
   of the split kept its claim on the box and the render stayed penned in it.
   Reported as "full dont work, plan box overrides", which is exactly what was
   happening. Fixed positioning owes the grid nothing, works the same in every
   browser, needs no permission, and cannot be refused by a policy. */
#design.is-full .dz-view--gl {
  position: fixed; inset: 0; z-index: 60;
  border-radius: 0; border: 0;
}
#design.is-full .dz-view--plan { display: none; }
#design.is-full .dz-view--gl .dz-view__k::after { content: ' — Esc to exit'; opacity: 0.7; }

#design .dz-work { grid-area: work; display: grid; gap: 1px; background: var(--dz-line); overflow: hidden; }
#design .dz-work[data-view="split"] { grid-template-columns: 1fr 1fr; }
#design .dz-work[data-view="plan"] .dz-view--gl,
#design .dz-work[data-view="gl"] .dz-view--plan { display: none; }
#design .dz-view { position: relative; background: var(--o-bg); min-width: 0; overflow: hidden; }
#design .dz-view canvas { display: block; width: 100%; height: 100%; touch-action: none; }
#design .dz-view__k {
  position: absolute; top: 10px; left: 12px; z-index: 2; pointer-events: none;
  font-family: var(--display); font-size: 0.625rem; font-weight: 700;
  letter-spacing: 0.14em; text-transform: uppercase; color: var(--o-faint);
}
#design .dz-hint {
  position: absolute; left: 12px; right: 12px; bottom: 12px; z-index: 2;
  padding: 0.5rem 0.7rem; border-radius: 9px;
  background: rgba(11, 14, 12, 0.86); border: 1px solid var(--dz-line);
  font-size: 0.75rem; color: var(--o-dim);
}
#design .dz-hint.is-warn { color: var(--o-warn-ink); border-color: var(--o-warn); }
/* The sun controls belong ON the 3D view, not in a far panel — they change
   what you are looking at while you are looking at it. */
#design .dz-sun {
  position: absolute; right: 12px; bottom: 12px; z-index: 2; display: grid; gap: 0.3rem;
  padding: 0.6rem 0.75rem; border-radius: 10px; min-width: 15rem;
  background: rgba(11, 14, 12, 0.86); border: 1px solid var(--dz-line);
}
#design .dz-sun label { display: flex; align-items: center; gap: 0.55rem; font-size: 0.6875rem; color: var(--o-faint); }
#design .dz-sun input { flex: 1; accent-color: var(--o-accent); }
#design .dz-sun b { color: var(--o-text); font-variant-numeric: tabular-nums; min-width: 3.4rem; text-align: right; }

/* ---- the dig -------------------------------------------------------------
   `.vol-hero` was WRITTEN BUT NEVER DEFINED — in this file or in any of the
   three the page loads. The excavation total, the one number the operator
   reads out to a haulier, was rendering as body text the same size as the
   layer table under it. A class that names nothing is not a small miss: it
   looks deliberate in the markup and is invisible on screen. */
#design .vol-hero {
  margin: 0 0 0.15rem; font-size: 0.8125rem; color: var(--o-faint);
  letter-spacing: 0.04em; text-transform: uppercase;
}
#design .vol-hero b {
  display: block; font-family: var(--display); font-size: 2rem; line-height: 1.05;
  font-weight: 700; color: var(--o-text); font-variant-numeric: tabular-nums;
  letter-spacing: -0.01em; text-transform: none;
}
/* An unfinished layer, in the warn family the office already uses — not a new
   colour, and TEXT ink rather than the mark, which is a 3:1 token. */
#design .vol-warn {
  margin: 0.6rem 0 0; padding: 0.45rem 0.6rem; border-radius: 8px;
  background: var(--o-warn-bg); border-left: 2px solid var(--o-warn);
  font-size: 0.75rem; line-height: 1.45; color: var(--o-warn-ink);
}

/* ---- inspector ---------------------------------------------------------- */
#design .dz-insp { grid-area: insp; display: flex; flex-direction: column; overflow: hidden; }
#design .dz-tabs { display: flex; gap: 2px; padding: 0.5rem 0.5rem 0; border-bottom: 1px solid var(--dz-line); }
#design .dz-tabs button {
  flex: 1; border: 0; background: none; color: var(--o-dim); cursor: pointer;
  padding: 0.5rem 0.3rem 0.6rem; font: 600 0.75rem/1 var(--body);
  border-bottom: 2px solid transparent; margin-bottom: -1px;
}
#design .dz-tabs button.is-on { color: var(--o-text); border-bottom-color: var(--o-accent); }
#design .dz-body { flex: 1; overflow: auto; padding: 0.9rem 0.9rem 2rem; }
#design .dz-tab[hidden] { display: none; }

#design .dz-h {
  margin: 1.15rem 0 0.5rem; font-family: var(--display); font-size: 0.625rem;
  font-weight: 700; letter-spacing: 0.14em; text-transform: uppercase; color: var(--o-faint);
}
#design .dz-body > .dz-h:first-child { margin-top: 0; }

/* An export sitting on the heading it exports, rather than another button in
   the sidebar a long way from the thing it acts on. */
#design .dz-mini {
  float: right; margin-top: -2px;
  border: 1px solid var(--dz-line); border-radius: 6px; background: var(--dz-raised);
  color: var(--o-dim); padding: 0.12rem 0.42rem;
  font: 700 0.5625rem/1.5 var(--display); letter-spacing: 0.1em; cursor: pointer;
}
#design .dz-mini:hover { color: var(--o-text); border-color: var(--o-line-2); }

/* The measurement bar. Sits where the hint does, over the drawing, so the two
   points being measured stay visible while the number is typed — which is the
   whole reason it is not a modal. Centred rather than corner-pinned because it
   is the only thing the operator is doing at that moment. */
#design .dz-ask {
  position: absolute; left: 50%; transform: translateX(-50%); bottom: 64px;
  z-index: 4; display: flex; align-items: center; gap: 0.5rem;
  padding: 0.55rem 0.7rem; border-radius: 10px;
  background: rgba(11, 14, 12, 0.94); border: 1px solid var(--o-accent);
  box-shadow: 0 8px 28px rgba(0, 0, 0, 0.45);
}
#design .dz-ask[hidden] { display: none; }
#design .dz-ask label { font-size: 0.75rem; color: var(--o-dim); }
#design .dz-ask input {
  width: 7rem; padding: 0.32rem 0.45rem; border-radius: 7px;
  border: 1px solid var(--dz-line); background: var(--o-bg); color: var(--o-text);
  font: 600 0.875rem/1 var(--body); font-variant-numeric: tabular-nums;
}
#design .dz-ask span { font-size: 0.75rem; color: var(--o-faint); }

/* A total is not another line. It gets a rule above it and the weight, so the
   eye separates "how much concrete altogether" from the five rows it came
   from without having to read the labels. */
#design .ord-total td {
  border-top: 1px solid var(--o-line-2);
  font-weight: 700; color: var(--o-text);
}

/* A heading's own footnote — what a group of order lines IS, so nobody rings a
   merchant to buy fourteen cubic yards of trench spoil. */
#design .dz-note {
  margin: -0.3rem 0 0.45rem; font-size: 0.6875rem; line-height: 1.45;
  color: var(--o-faint);
}

/* The section detail. `display:block` on the SVG kills the inline-baseline gap
   that otherwise leaves a stripe of panel under the drawing. */
#design .dz-section {
  border: 1px solid var(--dz-line); border-radius: 9px; overflow: hidden;
  background: #101418;
}
#design .dz-section svg { display: block; width: 100%; height: auto; }

/* materials */
#design .dz-mats { display: grid; grid-template-columns: 1fr 1fr; gap: 3px; }
#design .mat {
  display: flex; align-items: center; gap: 0.45rem; padding: 0.4rem 0.45rem;
  border: 1px solid transparent; border-radius: 8px; background: none;
  color: var(--o-dim); font: 400 0.75rem/1.15 var(--body); text-align: left; cursor: pointer;
  min-width: 0;
}
/* The NAME span, addressed by position rather than by being last. It was
   `span:last-child`, which stopped matching the moment a <kbd> shortcut badge
   was appended after it — the name would have silently lost its ellipsis and
   overflowed the button instead. Children are: swatch, name, optional key. */
#design .mat > span:nth-child(2) { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
#design .mat-k {
  margin-left: auto; flex: none; padding: 0 0.28rem; border-radius: 4px;
  border: 1px solid var(--dz-line); background: var(--o-hover);
  font: 500 0.62rem/1.5 var(--body); color: var(--o-dim);
}
#design .mat.is-on .mat-k { color: var(--o-text); }
#design .mat:hover { background: var(--o-hover); color: var(--o-text); }
#design .mat.is-on { background: var(--o-accent-wash); color: var(--o-text); border-color: var(--dz-line); }
#design .sw { width: 13px; height: 13px; border-radius: 3px; flex: none; border: 1px solid rgba(0,0,0,0.35); }

/* the build stack */
#design .lyrs { list-style: none; margin: 0; padding: 0; }
#design .lyr {
  display: flex; align-items: center; gap: 0.5rem; padding: 0.38rem 0.4rem;
  border-radius: 8px; font-size: 0.8125rem; color: var(--o-dim); cursor: pointer;
}
#design .lyr:hover { background: var(--o-hover); color: var(--o-text); }
#design .lyr.is-sel { background: var(--o-accent-wash); color: var(--o-text); }
#design .lyr.is-off { opacity: 0.4; }
#design .lyr__n { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
#design .lyr__d { font-size: 0.6875rem; color: var(--o-faint); font-variant-numeric: tabular-nums; }
#design .lyr__eye, #design .lyr__x {
  background: none; border: 0; color: var(--o-faint); cursor: pointer; padding: 0 0.1rem;
  font-size: 0.6875rem; line-height: 1;
}
#design .lyr__eye[aria-pressed="true"] { color: var(--o-accent); }
/* ---- THE TRACE-ORDER ARROWS ON A SHAPE ROW -------------------------------
   Pushed to the right of the row and only fully visible on the row the pointer
   is on or the one that is selected, because there is one pair per shape and a
   forty-shape list of arrows is a wall of chevrons. They are always in the
   DOM and always clickable — a control that appears on hover and nowhere else
   is one a keyboard cannot reach — they simply recede. */
#design .lyr-mv { margin-left: auto; display: flex; gap: 0.1rem; opacity: 0.28; }
#design .lyr:hover .lyr-mv, #design .lyr.is-sel .lyr-mv { opacity: 1; }
#design .lyr-mv button {
  background: none; border: 0; color: var(--o-faint); cursor: pointer;
  padding: 0 0.2rem; font-size: 0.75rem; line-height: 1;
}
#design .lyr-mv button:hover:not(:disabled) { color: var(--o-accent); }
#design .lyr-mv button:disabled { opacity: 0.25; cursor: default; }
#design .lyr-tools { display: flex; align-items: center; gap: 0.5rem; margin-top: 0.6rem; }
#design .lyr-ex { display: flex; align-items: center; gap: 0.45rem; flex: 1; font-size: 0.6875rem; color: var(--o-faint); }
#design .lyr-ex input { flex: 1; min-width: 3rem; accent-color: var(--o-accent); }
#design .lyr-ex b { color: var(--o-text); font-variant-numeric: tabular-nums; }
#design .lyr-edit { display: grid; gap: 0.4rem; margin-top: 0.8rem; padding-top: 0.8rem; border-top: 1px solid var(--dz-line); }
#design .lyr-edit label { display: flex; align-items: center; gap: 0.5rem; font-size: 0.6875rem; color: var(--o-faint); }
#design .lyr-edit input {
  flex: 1; min-width: 0; background: var(--o-bg); border: 1px solid var(--dz-line);
  border-radius: 7px; padding: 0.3rem 0.45rem; color: var(--o-text);
  font: 400 0.75rem/1.2 var(--body); font-variant-numeric: tabular-nums;
}

/* the one number that matters */
#design .vol {
  margin: 0.4rem 0 0.2rem; display: flex; align-items: baseline; gap: 0.4rem;
}
#design .vol b { font-family: var(--display); font-size: 2rem; font-weight: 800; color: var(--o-text); font-variant-numeric: tabular-nums; letter-spacing: -0.02em; }
#design .vol span { font-size: 0.8125rem; color: var(--o-dim); }
#design .dz-note { margin: 0.2rem 0 0; font-size: 0.75rem; color: var(--o-faint); }

#design .ofc-table td { padding: 0.34rem 0.2rem; font-size: 0.75rem; }
#design .ofc-table th { font-size: 0.625rem; }

@media (max-width: 1180px) {
  #design { grid-template-columns: 1fr; grid-template-rows: auto auto minmax(22rem, 1fr) auto;
            grid-template-areas: 'top' 'side' 'work' 'insp'; height: auto; overflow: auto; }
  #design .dz-side { max-height: 16rem; }
  #design .dz-insp { max-height: 28rem; }
}


/* THE GESTURE LINE. Quiet enough to ignore once learned, present enough to be
   found on the first project. Wraps rather than scrolls, because a keyboard
   reference the operator has to scroll is a reference they stop reading. */
.dz-keys {
  margin-top: .35rem;
  line-height: 1.7;
  opacity: .72;
}
.dz-keys b {
  font-weight: 600;
  opacity: .95;
  white-space: nowrap;
}


/* ==========================================================================
   §  THE GATE SCREEN                                               2026-09-08
   What somebody who is not the owner sees at /admin/design.html.
   ========================================================================== */
.dz-gate { display: grid; place-items: center; min-height: 100vh; padding: 2rem; }
.dz-gate__card {
  max-width: 34rem;
  padding: 2rem;
  background: var(--dz-panel);
  border: 1px solid var(--dz-line);
  border-radius: var(--o-r);
}
.dz-gate__card h1 {
  margin: 0 0 0.75rem;
  font-family: var(--display);
  font-size: 1.35rem;
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--o-text);
}
.dz-gate__card p { margin: 0 0 1rem; color: var(--o-dim); font-size: var(--o-t-sm); line-height: 1.6; }
.dz-gate__who { color: var(--o-faint); font-size: var(--o-t-xs); }
.dz-gate__who b { color: var(--o-dim); font-weight: 600; }
.dz-gate__card .ofc-primary { display: inline-block; margin-top: 0.5rem; }

/* ==========================================================================
   §  THE INSTRUMENT LOOK                                           2026-09-08
   Owner's brief: "more fun and pro, like Iron Man's Jarvis." The half of that
   which is real design direction — and the half worth taking — is that a
   Jarvis panel reads as an INSTRUMENT rather than a document: it is drawn on
   a dark ground in a single accent, its edges are lit rather than outlined,
   its labels are small tracked caps, and every number is monospaced and
   present even when idle. What is NOT worth taking is the film's decoration:
   spinning rings, scan lines, glows on everything. Those read as a toy in a
   tool somebody uses for six hours to price a job, and they cost legibility
   for nothing.

   So: the accent is the badge's steel, used as LIGHT. Panels get a hairline
   top edge that catches it, the active tool gets a left rule rather than a
   wash, section labels become tracked caps, and figures go monospaced and
   tabular. No animation on anything the eye rests on.
   ========================================================================== */

/* Panels are lit along their top edge, the way a machined surface is. */
#design .dz-card {
  position: relative;
  background:
    linear-gradient(180deg, rgba(158, 169, 179, 0.055), transparent 38%),
    var(--dz-panel);
}
#design .dz-card::before {
  content: '';
  position: absolute;
  inset: 0 0 auto;
  height: 1px;
  background: linear-gradient(90deg, transparent, rgba(158, 169, 179, 0.42) 22%,
                              rgba(158, 169, 179, 0.42) 78%, transparent);
  pointer-events: none;
}

/* The brand block is the way back, so it has to look like a control. */
#design .dz-brand {
  text-decoration: none;
  color: inherit;
  position: relative;
  transition: background 0.15s;
}
#design .dz-brand:hover { background: rgba(158, 169, 179, 0.06); }
#design .dz-brand__back {
  width: 18px; height: 18px;
  margin-left: auto;
  color: var(--o-faint);
  flex: none;
}
#design .dz-brand:hover .dz-brand__back { color: var(--o-accent); }

/* GROUP LABELS AS INSTRUMENT LABELS: small, tracked, and ruled to the panel
   edge so the rail reads as a stack of sections rather than a list of words. */
#design .dz-grp {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  font-size: 0.625rem;
  font-weight: 700;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--o-faint);
}
#design .dz-grp::after {
  content: '';
  flex: 1;
  height: 1px;
  background: var(--dz-line);
}

/* THE ACTIVE TOOL IS A LIT EDGE, not a filled wash. A wash says "this block is
   selected"; a lit edge says "this instrument is live", which is what a mode
   actually is. */
#design .dz-step { position: relative; border-radius: 0 var(--o-r-sm) var(--o-r-sm) 0; }
#design .dz-step.is-on {
  background: linear-gradient(90deg, rgba(158, 169, 179, 0.14), transparent 60%);
  box-shadow: inset 2px 0 0 var(--o-accent);
}
#design .dz-step.is-on .dz-step__i { border-color: var(--o-accent); opacity: 1; }

/* EVERY FIGURE IS MONOSPACED AND TABULAR. A take-off is a column of numbers
   that get compared to each other; proportional digits make that column
   jitter, and a readout that jitters does not read as an instrument. */
#design .dz-step__n, #design .tape, #design .dz-read, #design .dz-num,
#design [data-num], #design .dz-insp b, #design .dz-insp .num {
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
  letter-spacing: 0;
}


/* The shortcut reference, as a disclosure rather than a wall. */
#design .dz-keys__d { margin-top: 0.5rem; }
#design .dz-keys__d > summary {
  display: flex;
  align-items: center;
  gap: 0.45rem;
  width: fit-content;
  padding: 0.35rem 0.6rem;
  list-style: none;
  cursor: pointer;
  border: 1px solid var(--dz-line);
  border-radius: var(--o-r-sm);
  color: var(--o-faint);
  font-size: var(--o-t-xs);
  font-weight: 600;
  letter-spacing: 0.04em;
}
#design .dz-keys__d > summary::-webkit-details-marker { display: none; }
#design .dz-keys__d > summary svg { width: 15px; height: 15px; }
#design .dz-keys__d > summary:hover { color: var(--o-text); border-color: var(--o-accent); }
#design .dz-keys__d[open] > summary { color: var(--o-text); border-color: var(--o-accent); }
#design .dz-keys__d .dz-keys {
  margin-top: 0.5rem;
  max-height: 42vh;
  overflow: auto;
  padding: 0.6rem 0.75rem;
  background: var(--dz-raised);
  border: 1px solid var(--dz-line);
  border-radius: var(--o-r-sm);
}


/* ==========================================================================
   §  THE THINGS THAT WERE WRONG ON THIS SCREEN, ONE BY ONE      2026-09-08
   ========================================================================== */

/* 1. THE TAB INDICATOR WAS A STUCK FOCUS RING. `.dz-tabs button` sets
   `border: 0` then `border-bottom: 2px`, which is correct — but the generic
   button in app.css also sets a radius, so the one remaining border rendered
   as a rounded tab outline hanging BELOW the row. Square it, and give the
   inactive tabs somewhere to sit. */
#design .dz-tabs button { border-radius: 0; }
#design .dz-tabs button:hover { color: var(--o-text); background: rgba(158,169,179,0.05); }
#design .dz-tabs button.is-on { border-bottom-color: var(--o-accent); background: none; }

/* 2. EVERY SLIDER WAS BROWSER BLUE. Time, date, size, height, explode — all of
   them the OS accent, which is a colour that appears nowhere in this business.
   One rule, because a range input has to be styled in three vendor pieces or
   it silently keeps the default in one of them. */
#design input[type="range"] {
  -webkit-appearance: none;
  appearance: none;
  height: 2px;
  background: var(--dz-line);
  border-radius: 2px;
  outline: none;
}
#design input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 13px; height: 13px;
  border-radius: 50%;
  background: var(--o-accent);
  border: 2px solid var(--dz-panel);
  cursor: grab;
}
#design input[type="range"]::-moz-range-thumb {
  width: 13px; height: 13px;
  border: 2px solid var(--dz-panel);
  border-radius: 50%;
  background: var(--o-accent);
  cursor: grab;
}
#design input[type="range"]::-moz-range-track { height: 2px; background: var(--dz-line); }
#design input[type="range"]:active::-webkit-slider-thumb { cursor: grabbing; background: var(--o-accent-hi, var(--o-accent)); }

/* 3. THE PANE KEY WAS UNDER THE CAMERA PILL. "3D preview" sits top-left of the
   canvas and the camera row was centred over the top of the same pane, so the
   two collided and the word was half-covered. The key goes to a chip that
   reads on the render, and the camera row moves off the top edge entirely. */
#design .dz-view__k {
  z-index: 3;
  padding: 0.2rem 0.5rem;
  background: rgba(8, 10, 12, 0.72);
  border: 1px solid rgba(158, 169, 179, 0.16);
  border-radius: 3px;
  font-size: 0.625rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--o-dim);
  backdrop-filter: blur(6px);
}

/* 4. THE "SVG" BUTTON HUNG OFF THE SECTION CARD. `.dz-h` is a heading with a
   button in it; the button was floating out of the card's right edge and
   overlapping its border. Put the heading on a row and let the button sit in
   it. */
#design .dz-h {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  margin: 1.1rem 0 0.5rem;
}
#design .dz-mini {
  position: static;
  flex: none;
  padding: 0.25rem 0.5rem;
  font-size: 0.625rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  border: 1px solid var(--dz-line);
  border-radius: var(--o-r-sm);
  background: var(--dz-raised);
  color: var(--o-dim);
  cursor: pointer;
}
#design .dz-mini:hover { color: var(--o-text); border-color: var(--o-accent); }

/* 5. THE SECTION DRAWING WAS CLIPPED on the right and the bottom — its caption
   ran past the card ("… — 1,792" cut mid-number) and the note under it was
   sliced in half. It is a drawing: let it scale to the box instead of being
   cropped by it. */
#design .dz-sec, #design .dz-section, #design .dz-sec svg, #design .dz-section svg {
  max-width: 100%;
  height: auto;
  overflow: visible;
}

/* 6. THE HERO FIGURE REPEATED ITS OWN UNIT. "487.5" then "CU YD EXCAVATION"
   under it, then a sentence at nearly the same size as the label. Three sizes,
   three jobs: the figure, its unit small and tracked beside it, the working
   underneath in body ink. */
#design .dz-big, #design .dz-hero__n {
  font-family: var(--display);
  font-size: 2.75rem;
  font-weight: 800;
  line-height: 1;
  letter-spacing: -0.03em;
  font-variant-numeric: tabular-nums;
  color: var(--o-text);
}
#design .dz-big + *, #design .dz-hero__u {
  font-size: 0.625rem;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--o-faint);
}

/* `float: right` was the culprit on the SVG button: a float inside a flex row
   is ignored for layout but still takes the element out of the line box, which
   is why it sat proud of the card. Clear it, and let the flex row place it. */
#design .dz-mini { float: none; margin-top: 0; }

/* The section drawing is an SVG the renderer sizes in absolute units, so it
   overflowed its card on the right and was cut at the bottom. Scale it to the
   box and let the box grow to what it needs. */
#design .dz-section { overflow: visible; }
#design .dz-section > svg {
  display: block;
  width: 100%;
  height: auto;
  max-width: 100%;
}


/* Same rule in the designer: a control is not a pill. Its buttons inherit the
   office's classes, so this is only the ones it defines itself. */
#design .dz-btn, #design .dz-seg button, #design .dz-step,
#design .dz-mini, #design .dz-keys__d > summary { border-radius: var(--o-r-sm); }
#design .dz-step { border-radius: 0 var(--o-r-sm) var(--o-r-sm) 0; }
#design .dz-brand img { border-radius: var(--o-r); }
