/* What the app needs that design/ does not carry. NOT a copy of anything, so the
 * drift gate does not cover it — keep it to rules the app's own markup needs.
 * Linked on every page from layout.html, so a bare element selector here lands
 * everywhere: scope new rules to a class.
 * A style attribute would do this in one line, and the CSP (style-src 'self')
 * refuses style attributes as well as <style> blocks. */

/* Read by a screen reader, not drawn. The bench's settled-total announcement
 * lives here: the visible total changes on every keystroke and is deliberately
 * not a live region (docs/ADR/0021). */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* The option rows are native <details name> (docs/ADR/0022), and bench.css was
 * drawn for a .is-open class toggled by script. These are its .is-open rules
 * restated for [open], plus the disclosure marker every engine draws on a
 * <summary> by default. */
.row[open] > .row__panel { display: block; }
.row[open] { background: var(--color-paper-2); }
.row__head { list-style: none; }
.row__head::-webkit-details-marker { display: none; }

/* Glazing is a plain row for a shop with no glazing rows (FRM-133). bench.css styles every .row__head as pressable; a row that opens onto
 * nothing must not hover, depress or show a pointer. */
div.row__head { cursor: default; }
div.row__head:hover { background: none; }
div.row__head:active { transform: none; }

/* Which boxes a segment shows, read off the checked radio with no script. The
 * hidden boxes are still SUBMITTED — display is not submission — because
 * switching mode keeps what was typed, and parseDesign reads only the active
 * ones (docs/ADR/0024). Every segment arrives with one option checked
 * (benchView.Checked), so exactly one side of each pair is drawn. */
form:has([name="mode"][value="image"]:checked) [data-show="coverage"],
form:has([name="mode"][value="coverage"]:checked) [data-show="image"],
form:has([name="mats"][value="single"]:checked) [data-show="double"],
form:has([name="borders"][value="even"]:checked) [data-show="each"],
form:has([name="borders"][value="each"]:checked) [data-show="even"] { display: none; }

/* The bench is one screen (FRM-144). bench.css's .app grid has the mockup's
 * nesting except at one link: here the form wraps .bench, so the stage's
 * Dimensions toggle stays outside it, and the form is the .app__body grid item.
 * It must pass the pane's height through, or .bench's minmax(0, 1fr) scroll row
 * has nothing to divide and the rows push Save off the screen. */
.app__body > form { display: grid; grid-template-rows: minmax(0, 1fr); min-height: 0; min-width: 0; }

/* The preview region is the stage's 1fr row: the toggle, then the drawing in
 * what is left — .preview__stage sizes the piece in container units, so it needs
 * this definite height — then the corner window while the mat row is open. */
.bench-preview { display: grid; grid-template-rows: auto minmax(0, 1fr) auto; min-height: 0; min-width: 0; }
.bench-preview > .toggle { justify-self: end; padding: var(--space-sm) var(--space-lg) 0; }
/* Placed by row, not by order: a depth bind hides the toggle (FRM-144), and
 * auto-placement would then put the drawing in the auto row, collapsed to its
 * padding, and hand the 1fr to the corner window. */
.bench-preview > .preview { grid-row: 2; }
.bench-preview > .stage__detail { grid-row: 3; }
/* A remedy is a way out, not a refusal: bench.css draws every .remedy in the
 * block red. One that closes the package alone takes the control border; only
 * a partial one, "not enough alone" (gate.js remediesFor), keeps a warning. */
.remedy { border-color: var(--color-rule-2); }
.remedy--partial { border-color: var(--color-warn); }

/* Tablet: the preview keeps its band on a refusal. The stage is a fixed share
 * of the screen, and #bench-refused sits in its foot, so an auto foot took its
 * height out of the drawing (238px down to 56px with the mat row open). The
 * drawing keeps a 10rem floor, which still leaves the "Doesn't fit yet" heading
 * and the fork's first row of remedies whole with the mat row open at 768×1024;
 * the foot scrolls in what is left. The rows' pane is untouched: design/s1-bench.html
 * kept the depth block out of a pinned foot because it squeezed the rows "to
 * nothing", and this squeezes neither. */
@media (max-width: 900px) {
  .stage { grid-template-rows: minmax(min-content, 1fr) minmax(0, max-content); }
  .bench-preview > .preview { min-height: 10rem; }
  .stage > .stage__foot { min-height: 0; overflow-y: auto; }
}
/* With #preview-region hidden (no JS, bare bench, any non-depth refusal) the foot would take the stage's 1fr row and stretch its border and background over the whole customer side. */
.stage > .stage__foot { grid-row: 2; }

/* The overlay's leaders. The mockup positions each with an inline style, which
 * the CSP refuses; these are the same values as classes, with three departures
 * below. Each reads the custom properties static/preview.js sets on
 * .preview__piece. */
.ovl-at--coverage { top: var(--ghost-t); right: var(--ghost-r); bottom: var(--ghost-b); left: var(--ghost-l); }
.ovl-at--opening  { top: 50%; left: var(--art-l); right: var(--art-r); }
.ovl-at--border   { top: 32%; left: var(--mat-x); right: calc(100% - var(--op-l)); }
.ovl-at--package  { bottom: -1.75rem; left: var(--mat-x); right: var(--mat-x); }
/* DEPARTS FROM THE MOCKUP. Its right:-3.5rem leaves the box's width to the
 * label, so the leader (the box's left border) lands a label's width inside
 * the piece and runs down through the artwork: measured 13px inside the art's
 * right edge on 16 × 20. Anchored by its left edge, the leader sits just
 * outside the frame. bench.css's translate(50% + 5px) assumes the label is
 * centred ON the line; here the box is the label's own width with the line at
 * its left edge, so that translate floated the label ~60px off its leader. */
.ovl-at--frame    { left: calc(100% + 0.75rem); top: var(--fr-y); bottom: var(--fr-y); }
.ovl-at--frame > .ovl__label { transform: translateX(5px); }
/* DEPARTS FROM THE MOCKUP. bench.css centres the border label on its leader,
 * which spans the border alone. In the one-screen shell (FRM-144) the piece is
 * smaller: at 1280×720 with the mat row open and Dimensions on, a 2″ border is
 * ~16px and its label ~25px, so centred it crossed the artwork (measured). Text
 * too wide for its dimension goes outside the extension, as on a drawing: here
 * the label ends 5px short of the leader's outer end, over the moulding. */
.ovl-at--border > .ovl__label { justify-self: start; transform: translateX(calc(-100% - 5px)); }
/* DEPARTS FROM THE MOCKUP. bench.css centres the coverage label on the ghost
 * line, which on a ¼″ coverage straddles the artwork's top edge. Above the
 * line it sits in the mat. */
.ovl--ghost > .ovl__label { top: auto; bottom: calc(100% + 2px); }

/* The corner window's artwork, from the reveal. The 1½″ window holds ¾″ of top
 * mat, then the reveal, then artwork, so a ⅛″ reveal must leave more artwork
 * than a ¼″ one. bench.css fixes it at 33.333%, which is the ¼″ case only and
 * would draw every reveal the same. */
.corner__art { width: var(--corner-art, 33.333%); height: var(--corner-art, 33.333%); }
.corner__key--top   { background: var(--mat-top, var(--swatch-antique-white)); }
.corner__key--under { background: var(--mat-under, var(--swatch-black)); }
.corner__key--art   { background: linear-gradient(148deg, var(--preview-artwork), var(--preview-glass)); }

/* Material rows are native radios (FRM-133), where bench.css drew buttons with
 * aria-pressed. The radio covers its row, invisible, so a click anywhere on the
 * row checks it and the selected state reads off :checked rather than script. */
.mat-row { position: relative; }
.mat-row > input { position: absolute; inset: 0; margin: 0; opacity: 0; cursor: pointer; }
.mat-row > input + .mat-row__body { grid-column: 1 / 3; }
.mat-row:has(> input:checked) { border-color: var(--color-ink); background: var(--color-paper-2); }
.mat-row:has(> input:checked) .mat-row__name::after { content: " \2713"; }
.mat-row:has(> input:focus-visible) { outline: 2px solid var(--color-focus); outline-offset: 2px; }

/* Swatches are native radios too. The colour is a class, not a style
 * attribute, because the CSP (style-src 'self') refuses style attributes. */
.swatch { position: relative; }
.swatch > input { position: absolute; inset: 0; margin: 0; opacity: 0; cursor: pointer; }
.swatch:has(> input:checked) .swatch__chip { box-shadow: 0 0 0 2px var(--color-ink); border-color: var(--color-ink); }
.swatch:has(> input:checked) .swatch__name { color: var(--color-ink); font-weight: var(--weight-medium); }
.swatch:has(> input:focus-visible) .swatch__chip { outline: 2px solid var(--color-focus); outline-offset: 2px; }
.swatch--antique-white { --swatch: var(--swatch-antique-white); }
.swatch--bright-white  { --swatch: var(--swatch-bright-white); }
.swatch--ivory         { --swatch: var(--swatch-ivory); }
.swatch--warm-grey     { --swatch: var(--swatch-warm-grey); }
.swatch--sage          { --swatch: var(--swatch-sage); }
.swatch--ochre         { --swatch: var(--swatch-ochre); }
.swatch--oxblood       { --swatch: var(--swatch-oxblood); }
.swatch--black         { --swatch: var(--swatch-black); }

/* The moulding <select> in a measurement box (FRM-145). bench.css drew .mi for
 * text inputs only: drop the platform chrome, fill the box so the whole of it
 * opens the list, and draw the caret in the slot a text box keeps for its unit.
 * .mi:focus-within already rings it. */
select.mi__input { appearance: none; align-self: stretch; padding-inline-end: 2rem; cursor: pointer; }
.mi:has(> select)::after { content: "▾" / ""; position: absolute; inset-inline-end: var(--space-sm);
                           pointer-events: none; color: var(--color-neutral); }

/* The page inset and flow spacing for every screen that has no layout of its own
 * yet (FRM-143). bench.css zeroes body, heading and paragraph margins at every
 * depth, so the spacing is restored at every depth too — one level deep left the
 * order page's customer copy and tickets, all nested in sections, touching. The
 * bench is excluded: its .app is a full-viewport shell. Specificity is held at
 * (0,0,1): :where() zeroes everything but the final :is(), which ties bench.css's
 * own `p { margin: 0 }` and wins by loading later, while any component class,
 * at (0,1,0), still wins over it. */
:where(main:not(.app)) { padding: var(--space-lg); max-inline-size: 48rem; }
:where(main:not(.app) *) + :is(h1, h2, h3, h4, p, ul, ol, table, form, article, section, div) {
  margin-block-start: var(--space-md);
}

/* A link drawn as a button (FRM-150): Continue on measure, the no-mockup
 * screens' single actions. bench.css's .btn was drawn for <button> and leaves
 * the link underline on. The element stays a link — signed-in.spec.ts:69 finds
 * "Continue to the bench" by role. */
a.btn { text-decoration: none; }

/* A table's caption as a section label (FRM-146, folded into FRM-150): the
 * order's Totals and the bench's Charges. The caption is the table's
 * accessible name — six specs find getByRole("table", { name: "Charges" }) —
 * so it is styled, never replaced by a heading. Same face as bench.css .label. */
.tbl > caption { caption-side: top; text-align: start; padding-block-end: var(--space-xs);
                 font-size: var(--text-micro); font-weight: var(--weight-medium);
                 letter-spacing: var(--track-label); text-transform: uppercase; color: var(--color-muted); }

/* S3's gate (FRM-150), ported from design/s3-measure.html:22-27, in one
 * column. The mockup's overflow-y and min-height belong to its full-viewport
 * shell and are dropped; its preview, segment, slider and flags are not built. */
.gate { display: grid; gap: var(--space-lg); align-content: start; max-inline-size: 36rem; }
.gate__pair { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(9rem, 100%), 1fr));
              gap: var(--space-md); }
.gate__foot { display: flex; flex-wrap: wrap; gap: var(--space-sm); }
.gate *, .derived * { margin-block-start: 0; }

/* Derived readouts (s3-measure.html:28-32; s1-bench.html:24-26), on measure and
 * on the bench. The labels the mockups draw as <span class="muted"> are h2s here
 * — signed-in.spec.ts finds "Mat opening" and "Frame" as headings — so they take
 * the muted label's face at body size. */
.derived { display: grid; gap: var(--space-xs); padding: var(--space-md);
           background: var(--color-paper-3); border-radius: var(--radius-md); }
.derived__row { display: flex; justify-content: space-between; gap: var(--space-md);
                align-items: baseline; flex-wrap: wrap; }
.derived__row .dim { font-size: var(--text-md); }
.derived h2 { font-size: var(--text-body); font-weight: var(--weight-medium); color: var(--color-muted);
              letter-spacing: normal; text-transform: none; }

/* The readouts and the Charges inside the bench pane's inset (FRM-146, folded
 * into FRM-150). .bench__scroll has no padding of its own; the foot's is
 * --space-lg, so this matches it. The Charges caption is .tbl > caption above. */
#bench-result { display: grid; gap: var(--space-md); padding: var(--space-md) var(--space-lg); }

/* fit-content(50%), not the mockup's auto: Use wraps (.btn--wrap), so an auto
 * column would grow to the unwrapped label and leave the name 0px at 320. */
/* S10's search results (FRM-150), from design/tier2.html:151-160. The mockup's
 * .result is a <button>; here it is the row's <form>, so the button's own
 * cursor and font resets are dropped and Use is the control. */
.results { display: grid; gap: var(--space-2xs); }
.result { display: grid; grid-template-columns: minmax(0, 1fr) fit-content(50%);
          gap: var(--space-xs); align-items: center;
          min-height: var(--control-h); padding: var(--space-2xs) var(--space-sm);
          border: var(--rule-hair) solid var(--color-rule-2);
          border-radius: var(--radius-md); background: var(--color-paper); }
.result__sub { font-size: var(--text-micro); color: var(--color-muted); }
.results > *, .result * { margin-block-start: 0; }

/* A button whose label carries user-supplied text — a client name (up to 200
 * characters), a shop name. bench.css's .btn is white-space: nowrap and html
 * and body are overflow-x: clip, so at 320px a long name would run off the
 * page with no way to scroll to it. Fixed labels keep nowrap. */
.btn--wrap { white-space: normal; text-align: start; line-height: var(--lh-body);
             padding-block: var(--space-2xs); }

/* A search box with its button beside it: client and home. */
.search-row { display: flex; flex-wrap: wrap; gap: var(--space-xs); align-items: center; }
.search-row > .mi { flex: 1 1 14rem; }
.search-row * { margin-block-start: 0; }

/* The new-client fields: S10's create, as a column of .mi boxes. */
.client-fields { display: grid; gap: var(--space-sm); max-inline-size: 28rem; }
.client-fields * { margin-block-start: 0; }

/* Tier 3's empty state (FRM-150), from design/tier3.html:44-52. */
.empty { display: grid; gap: var(--space-xs); justify-items: center;
         text-align: center; padding: var(--space-lg) var(--space-md);
         border: 1px dashed var(--color-rule-2); border-radius: var(--radius-md);
         background: var(--color-paper); }
.empty__glyph { font-family: var(--font-dim); font-size: var(--text-md); color: var(--color-rule-2); }
.empty__why { font-size: var(--text-micro); color: var(--color-muted); max-width: 42ch; }
.empty__acts { display: flex; flex-wrap: wrap; gap: var(--space-xs);
               justify-content: center; margin-top: var(--space-2xs); }
.empty > * { margin-block-start: 0; }

/* choose-shop's shops: a column of buttons, not bullets. */
.choices { list-style: none; padding: 0; display: grid; gap: var(--space-xs); justify-items: start; }
.choices > * { margin-block-start: 0; }

/* The shop bar (FRM-164, layout.html). One row that wraps; the shop name
 * leads in the heading weight. Hidden in print on every page, since
 * board.css and order.css are the only sheets that define .no-print. */
.bar { display: flex; flex-wrap: wrap; gap: var(--space-xs) var(--space-md); align-items: baseline;
       padding: var(--space-xs) var(--space-md); border-block-end: 1px solid var(--color-rule-2); }
.bar > * { margin-block-start: 0; }
.bar__shop { font-weight: 600; margin-inline-end: auto; }
@media print { .bar { display: none !important; } }
/* The bench is one viewport (bench.css: body:has(.app) is a 100dvh flex
 * column and .app takes the rest). The bar is a fixed-height row there: it
 * never wraps and never grows, and scrolls sideways before it costs the bench
 * a second line. bench-layout.spec.ts holds the bench's panes in view at
 * 1280×720, so this rule is checked right after it lands (Task 2 Step 8b). */
body:has(.app) .bar { flex: none; flex-wrap: nowrap; overflow-x: auto; padding-block: var(--space-2xs); }

/* /orders, /clients and a client's page (FRM-164). */
.list { width: 100%; border-collapse: collapse; }
.list th, .list td { text-align: start; padding: var(--space-2xs) var(--space-xs);
                     border-block-end: 1px solid var(--color-rule-2); }

/* FRM-165 (UX-19). A finger is not a cursor. --control-h already makes every
 * .mi box 44px, but the input inside it was a 19px band, so most of the box
 * did not take a tap; stretched, the whole height does. .btn--sm is 32px
 * (bench.css) and is raised to the floor on a coarse pointer only, so a mouse
 * keeps the compact rows. */
@media (pointer: coarse) {
  .mi__input { align-self: stretch; }
  .btn--sm { min-height: var(--control-h); }
}
