/* V12 — deliberate exceptions to the ported design stylesheet.
   ===========================================================================
   v2_design.css is the design handoff's own CSS and it WINS by default. This
   file loads after it, so anything here overrides the design — which means
   every rule below has to earn its place with a reason. "I preferred it" is
   not a reason. The bar is: the design prototype could not have known about
   this, because it had no real data, no saw, and no shop floor.

   If you are tempted to add a rule here to fix how something looks, fix it in
   the JSX instead — the design's CSS is almost certainly right and the markup
   is almost certainly using the wrong class.
   =========================================================================== */

/* ---------------------------------------------------------------- motion -- */
/* The design prototype has no reduced-motion handling; it was never going to
   run on a shop-floor tablet. Ours does, and the sweep in particular is a
   large moving element. This block is additive — it changes nothing unless
   the operating system asks for it. */
@media (prefers-reduced-motion: reduce) {
  [data-ui="v12"] *,
  [data-ui="v12"] *::before,
  [data-ui="v12"] *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }
}

/* ------------------------------------------------------------- print ------ */
/* Labels, cut lists and quotes print from this app on real paper at the saw.
   The design has no print stylesheet at all, so without this the chrome
   prints too — a header, a command bar and a status bar wasting the top third
   of every label sheet. */
@media print {
  [data-ui="v12"] .webhdr,
  [data-ui="v12"] .cmdwrap,
  [data-ui="v12"] .tabrow,
  [data-ui="v12"] .dock,
  [data-ui="v12"] .split,
  [data-ui="v12"] .statusbar { display: none !important; }
  [data-ui="v12"] .docbody { overflow: visible !important; }
}

/* ------------------------------------------------------------ real data --- */
/* The design's tables hold six tidy mock rows. Ours hold a shop's whole job
   history, so the body scrolls inside the document and the header has to stay
   put. v7 already sets `position:sticky` on .tbl th — this only supplies the
   background it needs to not have rows show through, which the prototype
   never hit because nothing ever scrolled under it. */
[data-ui="v12"] .tbl th { background: var(--srf); }

/* A real reference can be long (FREE-8H2K1P — OPAL Corpus). The design's tab
   never had to truncate because its mock labels were short. */
[data-ui="v12"] .dtab {
  max-width: 260px;
  overflow: hidden;
}
[data-ui="v12"] .dtab > span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* ------------------------------------------------- primary button in dark -- */
/* The design defines --ac-ink for exactly this — the ink that goes ON the
   accent — and sets it to #00243d in its dark theme, because there the accent
   is a LIGHT blue (#4cc2ff). Its v7 layer uses it correctly; its v11 layer
   then hardcodes `color:#fff` and loses it. So in the design's own dark mode a
   primary button is white on light blue at a 2.01 contrast ratio.
   Measured, not guessed: "Send to saw" was the worst text on the cutting plan.

   That button hands a program to a running beam saw and it is read on a
   shop-floor tablet, so this is one bug in the handoff I am not reproducing.
   Using the design's own token is not a deviation — it is what the token is
   for, and in light mode --ac-ink is #ffffff, so nothing changes there. */
[data-ui="v12"] .btn.pri,
[data-ui="v12"] .cmd.pri { color: var(--ac-ink); }
[data-ui="v12"] .btn.pri svg,
[data-ui="v12"] .cmd.pri svg { color: var(--ac-ink); }
/* .stepno is the SAME v11 rule with the same hardcoded #fff: the numbered
   badges beside "Parts", "Material & sheet", "The board". A dark-mode contrast
   sweep measured them at 2.01 — white on the light accent, the digit barely
   legible. Every white-on-accent literal in the ported sheet now routes
   through the token. */
[data-ui="v12"] .stepno { color: var(--ac-ink); }
/* …and the HOVER state, which is a separate rule carrying its own `color:#fff`
   at one specificity step higher than the resting override, so it won the
   moment the pointer landed. Dark-mode hover measured 1.82 — WORSE than the
   2.01 resting state this file already fixed, and invisible on a tablet where
   the button stays in its hover style after a tap. (The close-button hover is
   the other #fff literal in the sheet; it sits on a fixed red, so it stays.) */
[data-ui="v12"] .btn.pri:hover,
[data-ui="v12"] .btn.pri:focus,
[data-ui="v12"] .btn.pri:active,
[data-ui="v12"] .cmd.pri:hover,
[data-ui="v12"] .cmd.pri:focus { color: var(--ac-ink); }
[data-ui="v12"] .btn.pri:hover svg,
[data-ui="v12"] .cmd.pri:hover svg { color: var(--ac-ink); }
/* The brand mark and the account avatar are the last two. They were already
   given the token in v2.css — but v2.css loads BEFORE the ported design, so
   the design's literal won and the fix never took. They carry no text node
   (a glyph and the user's initials), which is why a text-contrast sweep walked
   straight past them; they were caught by auditing the SHEET instead. */
[data-ui="v12"] .wbrand .bm,
[data-ui="v12"] .avatar { color: var(--ac-ink); }
[data-ui="v12"] .wbrand .bm svg { color: var(--ac-ink); }

/* ------------------------------------------------ the faintest ink tier --- */
/* --ink-4 / --tx-4 is #8a8886 in light: 3.53 against white, under the 4.5
   floor for text at these sizes. As DECORATION that is a legitimate choice and
   it stays everywhere else — but the design puts it on things the shop
   actually reads: the sheet thumbnails' number and yield (#2 · 87%), the job
   number in the console list, and the unit beside every KPI figure. A light-
   mode sweep measured 30 such runs at 3.53 across the console, the cutting
   plan and the catalog.
   One tier up, --ink-3 (#605e5c), measures 5.87 and is still unmistakably
   muted — the design's own token, not a new colour, and in dark mode it is
   the brighter of the two, so both themes improve. Decoration keeps --ink-4;
   only data moves. */
[data-ui="v12"] .jn,
[data-ui="v12"] .cell .u,
[data-ui="v12"] .telcell .u,
[data-ui="v12"] .ftime,
[data-ui="v12"] .rthumb .rl { color: var(--ink-3); }

/* ------------------------------------------------------------ narrow ------ */
/* The design was drawn for a desktop window and has no breakpoints below
   1080px at all. This app runs in a docked pane, in a half-screen window and
   on the office tablet, where the console's fixed 344px side column and the
   four-across KPI deck simply overflow. Collapsing them is additive: above
   these widths the design's own layout is untouched. */
@media (max-width: 1000px) {
  [data-ui="v12"] .cols { grid-template-columns: minmax(0, 1fr); }
  [data-ui="v12"] .deck { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 620px) {
  [data-ui="v12"] .deck { grid-template-columns: minmax(0, 1fr); }
  /* the thumbnail and the trailing chevron are the first things to go — the
     ref, the yield and the status are what the row is FOR */
  [data-ui="v12"] .jrow { grid-template-columns: 26px minmax(0, 1.4fr) 92px 86px; }
  [data-ui="v12"] .jrow > .thumb,
  [data-ui="v12"] .jrow > .yv,
  [data-ui="v12"] .jrow > *:nth-child(4),
  [data-ui="v12"] .jrow > *:last-child { display: none; }
}

/* ------------------------------------------------- parts-table cells ------ */
/* The design's parts grid puts the SPACING in the input (.cellinp pads 7px 9px
   and fills the cell) and none in the cell itself. The ported generic .tbl td
   keeps 5px 10px, which is right for text tables and wrong for an input grid —
   it shrank every editable cell by 20px and left the inputs floating in dead
   space. Scoped to .parts-tbl so ordinary tables keep the design's padding. */
[data-ui="v12"] .parts-tbl td { padding: 2px 3px; }
/* Only the row-number COLUMN gets an indent. The classic table marks every
   numeric VALUE cell .num too, so padding .num shrank the qty/L/W inputs by
   16px each — the indent has to key off position, not the class. */
[data-ui="v12"] .parts-tbl td:first-child { padding: 2px 8px; }

/* The hosted admin's eight section tabs are a nowrap flex — the single element
   that overflowed a 768px pane in the whole-app sweep. Wrapping is scoped to
   the V12 host; the classic route has no rule for this class. */
[data-ui="v12"] .admin-tabs { flex-wrap: wrap; row-gap: 2px; }

/* The editor's floating optimize bar is REDUNDANT on a wide V12 pane: the
   totals rail beside the form carries the same numbers and the same Optimize
   button, so the bar just hovered over the stock table looking broken. It
   comes back exactly when the rail stacks below the fold (the je-grid
   collapse at 1060px), which is when it earns its keep. Classic keeps it
   always — there is no rail on "/" narrow layouts to take over. */
@container (min-width: 1061px) {
  /* !important because the bar sets display:flex INLINE — a stylesheet rule
     cannot beat that at any specificity. */
  [data-ui="v12"] .je-sticky { display: none !important; }
}

/* --------------------------------------------------------- touch targets -- */
/* Cut mode runs on a tablet next to a running beam saw, operated with gloves
   on. The design's 34px control height is a mouse target. This raises ONLY
   the cut-mode screen's controls; everywhere else keeps the design's metrics. */
[data-ui="v12"] .v2cutmode .btn { min-height: 48px; font-size: 15px; }

/* -------------------------------------------------------- free-mode rail -- */
/* The part-row header is [swatch][name input][0/1 tag][Place][x] in a 244px
   rail. The design's generic .inp carries a fixed width, so the name input
   refused to shrink and pushed Place and the delete button ~70px past the
   rail's right edge (measured, not theoretical). The input is the one child
   that may yield; the buttons and the count tag must stay whole. */
[data-ui="v12"] .v2partrow-hd .inp { flex: 1 1 40px; width: auto; min-width: 0; }
[data-ui="v12"] .v2partrow-hd .btn,
[data-ui="v12"] .v2partrow-hd .tag { flex: 0 0 auto; }

/* The two placement buttons used to sit in that same header. Six children do
   not fit 244px whatever they are allowed to shrink to, so "Anywhere" hung
   outside the row's own border. They now have their own line and split it
   evenly — flex-basis 0 so a long label ("Click the board…") takes its share
   of the rail instead of the other button's. */
[data-ui="v12"] .v2partrow-act { display: flex; gap: 6px; margin-top: 8px; }
[data-ui="v12"] .v2partrow-act .btn {
  flex: 1 1 0; min-width: 0; justify-content: center;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* Same defect one level up: every link in railL → plate-bd → part-row keeps
   min-width:auto, so the row's intrinsic width (name input's 20-char default)
   ripples outward and the 244px rail renders 312px of content. Constrain the
   chain; the fields grid then wraps exactly as its auto-fit intends. */
[data-ui="v12"] .v2railL, [data-ui="v12"] .v2railR { min-width: 0; }
[data-ui="v12"] .v2railL .plate-bd { grid-template-columns: minmax(0, 1fr); }
[data-ui="v12"] .v2partrow { min-width: 0; max-width: 100%; }

/* ------------------------------------------------------- .thumb collision -- */
/* The design's .thumb is a 56x38 job-list preview thumbnail (v7.css:187).
   The classic toggle switch ALSO names its knob .thumb — so every switch
   hosted in V12 grew a 56x38 white slab overlapping its own label. Restore
   the switch's knob geometry; the design's real thumbnails (.jrow .thumb)
   never sit inside a .switch, so they keep the design rule. */
[data-ui="v12"] .switch .thumb {
  width: 16px; height: 16px; top: 3px; left: 3px;
  border-radius: 50%; background: #fff; border: none;
  box-shadow: var(--shadow-sm); overflow: visible;
}

/* ------------------------------------------------- toolbar labels, again -- */
/* The design hides every toolbar label below a 1340px WINDOW:
     @media (max-width: 1340px) { .tlabel { display: none } }
   In a docked app the window is the wrong thing to measure. On a 1261px
   laptop the drawing column can still be 660px wide with room for words, and
   the operator gets a row of unlabelled glyphs instead — two of which (the
   Cuts toggle and the Cut mode link) were drawn with the SAME icon, so they
   were not merely terse, they were ambiguous.

   Measure the column instead. Labels come back as soon as the drawing has
   room for them, and the design's rule still governs genuinely narrow panes. */
[data-ui="v12"] .ncol.mid { container-type: inline-size; container-name: v2mid; }
@container v2mid (min-width: 980px) {
  [data-ui="v12"] .nhead .tlabel { display: inline; }
}

/* ============================================================ .v2bar ========
   THE TOOLBAR PRIMITIVE — one rule, every button row.

   The design draws its toolbars `nowrap` + `overflow-x: auto` with the
   scrollbar hidden by ::-webkit-scrollbar. On a wide screen that never shows.
   Narrow the column and the row does not scroll visibly and does not wrap: it
   silently swallows whatever is past its right edge, with nothing on screen to
   say anything is missing. This has now been found and fixed FOUR separate
   times — the drawing header (627px of content in a 414px box: the
   Cuts/Grain/Offcuts toggle, Edit, Cut mode and Panels all gone), the cutting
   plan's tool strip (Fill offcut, Bank offcut, Export — 224px of it), the
   command bar, and the new job parts toolbar. Each was fixed on its own, which
   is why it kept coming back on the next row somebody added.

   So: one class. Put `v2bar` on any horizontal row of controls and it can no
   longer hide one. It WRAPS first — two short rows beat one row with a hidden
   half — and scrolls only if a single child is too wide to wrap, where the
   scrollbar is left VISIBLE, because an invisible scrollbar is what caused
   this in the first place. `height: auto` is part of the primitive: a fixed
   height on a wrapping flex container clips the second row instead of growing
   for it, which is how .cmdbar's 44px hid its own overflow.

   Wrapping only engages when the content genuinely does not fit, so on a wide
   screen every one of these rows looks exactly as the design drew it. */
[data-ui="v12"] .v2bar {
  flex-wrap: wrap;
  row-gap: 6px;
  overflow-x: auto;
  overflow-y: hidden;
  height: auto;
  scrollbar-width: thin;
}
[data-ui="v12"] .v2bar::-webkit-scrollbar { display: block; height: 6px; }
[data-ui="v12"] .v2bar::-webkit-scrollbar-thumb {
  background: var(--bd-2); border-radius: 3px;
}
/* A `.grow` spacer inside a wrapping row becomes the line break, which is what
   puts the controls on the second line rather than splitting them mid-group. */
[data-ui="v12"] .v2bar > .grow { flex: 1 0 12px; }
@container v2mid (max-width: 620px) {
  [data-ui="v12"] .v2bar > .grow { flex-basis: 100%; height: 0; }
  /* .v2toolbar is the full-width bar around .v2tools; it measures zero overflow
     itself, so it needs to grow rather than be scrolled. */
  [data-ui="v12"] .v2toolbar { flex-wrap: wrap; row-gap: 7px; }
}

/* ------------------------------------------------ captions vs paragraphs -- */
/* .jsub is the design's ONE-LINE caption: nowrap + ellipsis + overflow hidden.
   That is right in a list row, where a long customer name must not push the
   row wider. But the app also uses .jsub for PROSE — the sentence under a
   setting that explains what it does — and there the same rule silently cuts
   the explanation off mid-word. Measured at 1920x1080, where there is no
   shortage of room:

     "Pinned. The PANHANS .NCR header declares a 4.4…"      cut by 430px
     "How far the machine can actually reach. A shee…"      cut by 250px
     "Yield is measured against the whole board, the…"      cut by 482px

   The kerf one is the worst of them: it explains why the field is locked, on
   a value that is saw-critical.

   So prose wraps by default and the ROW contexts keep the truncation they
   need. Listed explicitly rather than guessed, because a row that starts
   wrapping changes its height and the lists are dense on purpose. */
[data-ui="v12"] .jsub { white-space: normal; overflow: visible; text-overflow: clip; }
[data-ui="v12"] .jrow .jsub,
[data-ui="v12"] .prow .jsub,
[data-ui="v12"] .rthumb .jsub,
[data-ui="v12"] .dtab .jsub,
[data-ui="v12"] .tnode .jsub,
[data-ui="v12"] .v2pick .jsub,
[data-ui="v12"] .v2partrow .jsub,
/* the workspace footer's chips ("Saved 22:52", the job ref) are captions, not
   prose — the prose rule let them wrap at a space or the ref's hyphen into a
   two-line box, and the text then sat ~10px ABOVE the row's midline ("the job
   name is higher than the other texts", measured 39px tall for one line) */
[data-ui="v12"] .wsfoot .jsub,
[data-ui="v12"] .plate-hd .jsub {
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

/* ------------------------------------------------------- page head rows -- */
/* The design makes the page head's spacer a full-width line break
     .docbody .phead .grow { flex-basis: 100%; height: 0 }
   so the actions always wrap onto their own row. In a narrow docked pane that
   is right. On the job editor at 1280 it cost a whole band: breadcrumb, then
   a 26px title, then two lines of description, then a fourth strip holding a
   status chip and three buttons — before any field. Measured 188px of head
   above a form.

   With room, put the actions back on the title row where they belong (title
   left, actions right, the pattern every other screen here uses). Below 900px
   the design's wrap returns untouched. */
@container (min-width: 900px) {
  [data-ui="v12"] .docbody .phead .grow { flex-basis: 0; flex-grow: 1; height: auto; }
}

/* ------------------------------------------------------- a canvas to sit on */
/* v12.css puts the document area on --srf, which is pure white — and every
   panel on it is ALSO pure white, separated by one #e5e5e5 hairline. Measured
   on the job editor: docbody #ffffff, section #ffffff, card #ffffff, card head
   #fafafa. Five stacked blocks (stock, material settings, offcuts, parts,
   defects) with no edge you can actually see, which is why the page reads as
   one undifferentiated sheet of controls.
   
   The design system already carries the tone for this: --win, the window
   colour, #f3f3f3 light and #202020 dark. Putting the DOCUMENT on the window
   tone and leaving panels white is the ordinary Fluent arrangement — grey
   canvas, white surfaces — and it costs nothing but a background. Panel
   borders move to --bd-2 so the edge is still there when a panel sits on
   white (dialogs, the drawing well). */
[data-ui="v12"] .docbody { background: var(--win); }
[data-ui="v12"] .je-sec,
[data-ui="v12"] .je-main .card,
[data-ui="v12"] .je-rail .card { border-color: var(--bd-2); }
/* The head of a panel earns a touch more separation from its own body than
   #fafafa-on-#ffffff gives it. */
[data-ui="v12"] .je-main .card > .card-head,
[data-ui="v12"] .je-sec-h { background: var(--srf-3); }

/* ------------------------------------------------- editable cells read as cells */
/* The design's table input (cellinp) is borderless and transparent: it relies
   on the reader inferring "this is editable" from context. Measured on the job
   editor, 5 of 9 fields on the page had NO border and NO fill — edge contrast
   1.00 against the cell behind them. On a stock table with two rows there is
   no context to infer from, so board sizes, quantities and costs looked like
   printed text until you clicked them.

   Editable cells now carry a real edge (--bd, 1.27 on white) and a faint fill,
   so a glance separates "you can type here" from "this is a label". Focus and
   hover keep the design's accent treatment on top. Density is unchanged — this
   is a border and a background, not padding. */
[data-ui="v12"] .input-cell {
  background: var(--srf-2);
  box-shadow: inset 0 0 0 1px var(--bd);
  border-radius: var(--r-xs);
}
[data-ui="v12"] .input-cell:hover { background: var(--srf-3); box-shadow: inset 0 0 0 1px var(--bd-2); }
[data-ui="v12"] .input-cell:focus,
[data-ui="v12"] .input-cell:focus-visible {
  background: var(--srf); box-shadow: inset 0 0 0 2px var(--acc); outline: none;
}

/* A hint must not look like a value. `.inp::placeholder` and
   `.input::placeholder` are both dimmed, but `.input-cell` — the parts and
   stock table cells — has no rule, so its placeholder inherits the element's
   own ink and renders at full strength. In a grid of numbers that means
   "DEST / location" reads exactly like a destination somebody typed. Use the
   same tier the design gives every other placeholder. */
[data-ui="v12"] .input-cell::placeholder { color: var(--ink-4); }

/* ---------------------------------------------------- material tabs edge -- */
/* The ported design carries an element reset —
     [data-ui="v12"] button { background: none; border: none }
   — at (0,1,1), which OUTRANKS any classic rule written as a single class
   (0,1,0). The editor's material tabs are exactly that: .je-tab lost its
   border and surface wholesale, and .je-tab.on (0,2,0) survived but only sets
   border-COLOR, so the active tab kept an accent colour on a 0px border.
   Measured: the selected material was #eff6fc on the #f3f3f3 canvas with no
   edge — near-invisible, and it is the control that says WHICH material's
   parts you are editing.

   Restore the classic affordance in design vocabulary. Anything else the
   reset flattens is already re-dressed by the v12 skin at (0,2,0)+. */
[data-ui="v12"] .je-tab {
  border: 1px solid var(--bd-2);
  background: var(--srf);
  border-radius: var(--r-s);
}
[data-ui="v12"] .je-tab:hover { border-color: var(--bd-3); }
[data-ui="v12"] .je-tab.on {
  border-color: var(--acc);
  background: var(--acc-soft);
  box-shadow: inset 0 0 0 1px var(--acc);
}

/* ------------------------------------------------------- edge-banding cell */
/* The edge cell is a real button — it opens the banding editor — but it is
   inline-styled flat (background:none; border:none), so in a row of bordered
   input cells it reads as printed text. On a part with no banding its entire
   label is "—", which is the weakest possible affordance.

   Give it the same edge the editable cells now have, so one glance says "this
   column is something you set" — consistent with its neighbours rather than a
   new invention. !important is unavoidable: the flatness is an inline style
   and no stylesheet can outrank that. */
[data-ui="v12"] .parts-tbl button[title="Edit edge banding"] {
  background: var(--srf-2) !important;
  box-shadow: inset 0 0 0 1px var(--bd);
  border-radius: var(--r-xs);
}
[data-ui="v12"] .parts-tbl button[title="Edit edge banding"]:hover {
  background: var(--srf-3) !important;
  box-shadow: inset 0 0 0 1px var(--bd-2);
}
[data-ui="v12"] .parts-tbl button[title="Edit edge banding"]:focus-visible {
  outline: none; box-shadow: inset 0 0 0 2px var(--acc);
}

/* =========================================================== type scale === */
/* Bigger text across the app, on request. Worth recording WHY this is not
   simply "matching the design": the handoff's own base is 14px (v11 body) and
   v7's is 14.5 — this app was already at 14.5, so the design files are not
   larger, they are marginally smaller. The ask is a real one all the same:
   this runs on a shop screen, often read standing up and at arm's length, and
   the app is dense with numbers that decide how a board gets cut.
   So: one deliberate step up, applied to the type only. Spacing, control
   heights and the drawing are untouched — a bigger font in the same box is a
   readability change; a bigger everything is a different layout, and the
   toolbars were fitted to the pixel two commits ago. Measured after: header,
   tool strip and parts table all still fit at 1280 and 1920. */
[data-ui="v12"] { font-size: 15.5px; }
[data-ui="v12"] .jsub { font-size: 13px; }
[data-ui="v12"] .lab { font-size: 12.5px; }
[data-ui="v12"] .pgrid { font-size: 14px; }
[data-ui="v12"] .tbl { font-size: 14px; }
[data-ui="v12"] .tree { font-size: 14px; }
[data-ui="v12"] .tag { font-size: 12px; }
[data-ui="v12"] .prow .pid { font-size: 13.5px; }
[data-ui="v12"] .prow .pdim,
[data-ui="v12"] .prow .pqty { font-size: 12.5px; }
[data-ui="v12"] .spec,
[data-ui="v12"] .spec b { font-size: 13px; }
[data-ui="v12"] .srank .n { font-size: 13px; }
[data-ui="v12"] .srank .p { font-size: 12px; }
[data-ui="v12"] .telcell .lab { font-size: 12.5px; }
[data-ui="v12"] .telcell .v { font-size: 26px; }
[data-ui="v12"] .agent p { font-size: 13.5px; }
[data-ui="v12"] .input-cell { font-size: 13.5px; }
[data-ui="v12"] .inp, [data-ui="v12"] .input, [data-ui="v12"] .select { font-size: 14px; }

/* WHY THE CHROME DID NOT GROW WITH IT. Not because it could not: the uplift
   was first blamed for a 213px header overflow at 1280, and that was wrong —
   the overflow measures 213px at 15.5px, 14.5px AND 13px, because its cause is
   the Properties dock squeezing the drawing column to 416px, not the type.
   (That one is fixed above, by letting the header wrap.)
   The uplift is still confined to what is READ — lists, tables, telemetry,
   properties, the part index, field text — and kept off toolbars, tabs and the
   command bar. Those are dense rows of controls fitted to the pixel, and every
   px of label there costs horizontal room the drawing wants. Measured after:
   header and tool strip at zero overflow with every button inside, at 1280 and
   1920, dock open and dock closed. */
[data-ui="v12"] .pgrow span, [data-ui="v12"] .pgrow b { font-size: 14px; }
[data-ui="v12"] .jref { font-size: 14.5px; }
[data-ui="v12"] .phead p { font-size: 15px; }

/* ============================================== defect zones in a narrow rail === */
/* Adding a zone in quick job left its coordinates unreachable. DefectSection is
   the FULL EDITOR's component and its zone table is built for a wide card: the
   inputs carry INLINE widths (label 120px, then 60px each for X/Y/W/H) totalling
   514px of content. Quick job hosts it in a 330px board rail — 278px of usable
   table — and the result was not merely clipped, it was UNREACHABLE: inline
   widths overflow their cells without widening the table, so the wrapper's
   `overflow-x: auto` never engaged (measured scrollWidth 278 === clientWidth
   278). Y, W, H and the delete button were gone, with no scrollbar to reach them.

   First attempt was to make the table fluid in place. Measured, that fails on
   its own terms: at 278px each number column lands at 36px while a real
   four-digit coordinate (2800) needs 62px, so every value would be clipped
   inside its own box — a quieter version of the same bug.

   So the row STACKS instead: the label and the delete button on one line, the
   four numbers four-up beneath, each keyed by the `data-c` its cell carries.
   That is what the header row used to do, and the header is hidden here because
   it no longer lines up with anything. ~64px per number at 4px padding fits
   2800 with room to spare.

   !important is the right tool and not laziness: those widths are INLINE styles
   in a component the frozen classic editor also renders, so they cannot be
   removed at source without touching "/", and nothing but !important beats an
   inline style. Everything here is scoped to this plate in this UI. */
[data-ui="v12"] .v2qjdefect { container-type: inline-size; container-name: v2qjdefect; }
@container v2qjdefect (max-width: 560px) {
  [data-ui="v12"] .v2qjdefect table.tbl,
  [data-ui="v12"] .v2qjdefect table.tbl tbody { display: block; width: 100%; }
  [data-ui="v12"] .v2qjdefect table.tbl thead { display: none; }
  /* The board preview is authored 520px wide. In a 278px rail that overflowed
     into a horizontal scroller AND stood 384px tall — most of the plate, for a
     picture you glance at. Scale it to the rail instead; the viewBox added
     alongside its width/height is what makes that scale the drawing rather than
     crop it.

     NO max-height here, deliberately, and it was tried: a height cap does not
     crop a viewBox'd svg, it LETTERBOXES it — the picture stays centred at its
     own aspect inside a box of the wrong shape. The drag maths converts pointer
     pixels to svg units with W/rect.width and H/rect.height, so the moment
     those two ratios differ the vertical mapping is wrong and a dragged zone
     is recorded at the wrong height. Defects decide where parts may not land,
     so that is a correctness bug, not a cosmetic one. width:100% + height:auto
     keeps the box exactly on the viewBox aspect and the two ratios equal. */
  [data-ui="v12"] .v2qjdefect svg[style*="crosshair"] {
    width: 100% !important; height: auto !important;
  }
  [data-ui="v12"] .v2qjdefect svg[style*="crosshair"] + div,
  [data-ui="v12"] .v2qjdefect > .card-pad > div:first-child > div { min-width: 0; }

  [data-ui="v12"] .v2qjdefect table.tbl tbody tr {
    position: relative;
    display: grid; grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 9px 6px; padding: 9px 10px; margin-bottom: 7px;
    border: 1px solid var(--bd-2); border-radius: var(--r-s); background: var(--srf-2);
  }
  /* height: auto is the load-bearing one. styles.css pins every table cell with
     `table.tbl tbody td { height: var(--row-h) }` — 42px, right for a cell
     holding one input on a single line. A stacked cell holds a caption AND an
     input: 15px + 2px + 42px = 59px. The cell stays 42px, overflow is visible,
     so the input hangs 17px out of its own cell and 7px past the card's border,
     which is exactly the "fields going outside boundary" in the report.
     Letting the cell size to its content is what makes the card grow to fit. */
  [data-ui="v12"] .v2qjdefect table.tbl tbody td {
    display: block; border: 0; padding: 0; min-width: 0; height: auto;
  }
  /* the column name, since the header row is gone */
  [data-ui="v12"] .v2qjdefect table.tbl tbody td::before {
    content: attr(data-c); display: block; margin-bottom: 2px;
    font-size: 10px; font-weight: 650; letter-spacing: .06em;
    text-transform: uppercase; color: var(--ink-3);
  }
  /* Explicit placement, not auto-flow: left to itself the grid put X beside the
     label on line 1 and pushed the delete button under it. Line 1 is what the
     zone IS, line 2 is where it is.
     The label takes the FULL width and the delete button is lifted out of the
     grid into the card's top-right corner — parking it in a fourth column stole
     a quarter of the name field to hold one 30px icon, which is what made the
     card look starved. */
  [data-ui="v12"] .v2qjdefect table.tbl tbody td[data-c="Label"] {
    grid-column: 1 / -1; grid-row: 1; padding-right: 34px;
  }
  [data-ui="v12"] .v2qjdefect table.tbl tbody td[data-c="del"] {
    /* on the card's padding edge, not 2-3px outside it */
    position: absolute; top: 9px; right: 10px; z-index: 1;
  }
  [data-ui="v12"] .v2qjdefect table.tbl tbody td[data-c="X"] { grid-column: 1; grid-row: 2; }
  [data-ui="v12"] .v2qjdefect table.tbl tbody td[data-c="Y"] { grid-column: 2; grid-row: 2; }
  [data-ui="v12"] .v2qjdefect table.tbl tbody td[data-c="W"] { grid-column: 3; grid-row: 2; }
  [data-ui="v12"] .v2qjdefect table.tbl tbody td[data-c="H"] { grid-column: 4; grid-row: 2; }
  [data-ui="v12"] .v2qjdefect table.tbl tbody td[data-c="del"]::before { content: ""; margin: 0; }
  /* height: auto is as load-bearing as the cell's. styles.css gives
     `.input-cell { height: 100% }`, which is right when the input IS the cell.
     Here the cell also holds a caption above it, so 100% of the cell is always
     exactly the caption's height too much — the input overflowed by 17px no
     matter how tall the cell grew, because growing the cell grew the input with
     it. Sizing the input to itself breaks that loop: cell = caption + input,
     and it fits. */
  [data-ui="v12"] .v2qjdefect table.tbl tbody td input {
    width: 100% !important; min-width: 0; height: auto !important;
    padding-left: 4px; padding-right: 4px;
  }

  /* The ADD row above the table has the same fixed-width problem one row up:
     five fields and a button on a flex line that wraps into a ragged column.
     Give it the same four-up grid so it reads as the same control. */
  /* `display: grid` needs !important for the same reason the widths do — the
     component sets `display: flex` INLINE, and at 278px that flex line wrapped
     to one field per row, making the add form five inputs tall. */
  [data-ui="v12"] .v2qjdefect .section-label + div {
    display: grid !important; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 7px;
  }
  [data-ui="v12"] .v2qjdefect .section-label + div > .field { min-width: 0; }
  [data-ui="v12"] .v2qjdefect .section-label + div > .field input {
    width: 100% !important; min-width: 0; padding-left: 6px; padding-right: 6px;
  }
  [data-ui="v12"] .v2qjdefect .section-label + div > .field:nth-child(5) { grid-column: 1 / 4; }
  [data-ui="v12"] .v2qjdefect .section-label + div > button { align-self: end; }
}

/* ================================================ the command bar wraps ==== */
/* The design gives this bar `overflow-x: auto` and then hides the scrollbar,
   which means it does not scroll — it SILENTLY SWALLOWS whatever does not fit.
   Measured at 1100px once Materials / Production / Analytics / Settings were
   promoted onto it: 163px over, with Analytics and Settings simply gone and no
   affordance to reach them.

   This is the third time this exact pattern has cost a control here — the
   drawing header and the cutting-plan tool strip were the other two — so the
   bar gets the same treatment they did: let it wrap. On a wide screen nothing
   changes, the row fits and the bar stays 44px tall; on a narrow one it becomes
   two rows and every command stays clickable.

   In the OVERRIDES layer because v2_design.css restates .cmdbar after v2.css
   and would win otherwise. `height` must be beaten explicitly: the design sets
   a fixed 44px, and a fixed height on a wrapping flex container clips the
   second row instead of growing for it. */
[data-ui="v12"] .cmdwrap { align-items: stretch; }
[data-ui="v12"] .cmdwrap .cmdbar {
  height: auto; min-height: 44px;
  flex-wrap: wrap; row-gap: 4px; padding-top: 5px; padding-bottom: 5px;
  overflow-x: visible;
}
/* the ⋯ button keeps to the first row rather than centring against two */
[data-ui="v12"] .cmdwrap > div:has(> .ovbtn) { align-self: flex-start; margin-top: 5px; }

/* "Advanced new job" is 153px where "New job" was ~95, which tipped the command
   bar onto a second row at 1280 — it now needs about 1261px against 1240px of
   bar. It misses by ~21px, and most of that is separator margin, so a small
   tightening on anything narrower than a big desktop buys the row back without
   touching what the design looks like at full width. 2px per side per command
   is imperceptible; a second row of chrome on every screen is not. */
@media (max-width: 1600px) {
  [data-ui="v12"] .cmd { padding: 0 8px; }
  [data-ui="v12"] .csep { margin: 0 4px; }
}

/* ========================================= the optimizer run overlay ======= */
/* The handoff ships this one as a standalone runnable file with "copy these
   five rules verbatim". Most of it HAD been ported into v2_design.css already —
   what stopped it looking like the reference were three things in that same
   ported sheet, all of which have to be undone from a later layer:

   1. `.led i { animation: none !important }`. The port flattened every LED in
      the app to a static dot, which is right for the status bar's steady green
      but kills the amber blink that tells you the engine is still going. Only
      the blinking variant is restored, and only inside the overlay.
   2. `.optbox { border-radius: 8px; border: 1px solid var(--bd-2) }`, restated
      further down the ported sheet and beating the 16px the handoff calls for.
      16px is deliberate there — it is the one radius in the system reserved for
      this card, which is why the token table lists it separately.
   3. no `.title` rule at all, so the card's headline rendered at body size.

   Everything else — .opt, .sweep, .optbox, .oh, .ob, .optlog, .gauge — is the
   ported design and is left alone. */
[data-ui="v12"] .optbox { border-radius: 16px; border: none; }
[data-ui="v12"] .optbox .title {
  font: 600 19px/1 var(--d); letter-spacing: .05em; color: var(--ink); margin-bottom: 10px;
}
[data-ui="v12"] .optbox .oh .lab.optrun {
  color: var(--acc); font-size: 10.5px; letter-spacing: .09em; text-transform: uppercase;
}
[data-ui="v12"] .optbox .oh .lab.mono {
  font-family: var(--m); font-size: 10.5px; letter-spacing: .06em;
  text-transform: uppercase; color: var(--ink-4);
}
@keyframes v12optblink { 50% { opacity: .25; } }
[data-ui="v12"] .optbox .led i.blink {
  animation: v12optblink 1s steps(1, end) infinite !important;
}
/* The handoff's own reduced-motion rule: drop the sweep, the blink and the
   slide-in; keep the card and its final state. */
@media (prefers-reduced-motion: reduce) {
  [data-ui="v12"] .opt .sweep { display: none; }
  [data-ui="v12"] .optbox .led i.blink { animation: none !important; }
  [data-ui="v12"] .optlog span { animation: none; }
  [data-ui="v12"] .gauge i { transition: none; }
}

/* The overlay is `position: absolute` because on the cutting plan it covers one
   thing — the drawing — inside a positioned canvas box, and the parts list and
   telemetry stay readable beside it. Quick job has no canvas: the engine run
   there is a blocking moment that ends by navigating to the plan, so the card
   covers the window instead. Same card, same timings, different host. */
[data-ui="v12"] .opt.optfixed { position: fixed; z-index: 60; }

/* ==================================== new job: the rail's dense number cells === */
/* The handoff sizes the stock table by its GRID — 40 | 1fr | 1fr | 42 | 50 | 22 —
   and those numbers assume the design's own field padding. Ours is wider (9px a
   side against the design's 7, on a 13.5px face), so four of the five inputs
   clipped their own value at a 295px rail: "2800" needs 38px of content box and
   had 38px of border box. Tighten the padding rather than widen the columns —
   the columns are the design's and the rail has no room to spare. */
[data-ui="v12"] .stockrow .inp,
[data-ui="v12"] .trimgrid .inp,
[data-ui="v12"] .setrow .inp {
  padding-left: 5px; padding-right: 5px; text-align: right;
}
[data-ui="v12"] .stockrow .inp:first-child { text-align: left; }
/* the caption row above the stock table lines up with the fields under it */
[data-ui="v12"] .stockrow > .lab { padding: 0 5px; }

/* The new-job grid carries four banding columns instead of one, so the table's
   floor moves with it. The handoff's 824px was for its own column set; these
   add ~248px, and a floor that is too small lets the browser crush the numeric
   columns instead of scrolling, which is the one thing the handoff says this
   table must never do. */
[data-ui="v12"] .jobws .gridwrap .tbl { min-width: 940px; }

/* --- the parts toolbar, lifted from the job editor -------------------------
   Only what makes it look like a toolbar. Not hiding a button is .v2bar's job,
   which this row carries — see the primitive above. */
[data-ui="v12"] .njtools {
  display: flex; align-items: center; gap: 6px;
  padding: 8px 12px;
  border-bottom: 1px solid var(--bd);
  background: var(--srf-2);
}

/* --- a box around every cell you can type in -------------------------------
   The ported design draws grid cells chrome-free: no border at rest, a tint on
   hover, an inset ring on focus. In a docket that is elegant; in a parts table
   it means nothing on screen says where one field ends and the next begins,
   and the four 50px banding cells in particular read as empty table, not as
   inputs. Blendi asked for the boxes, so every typed cell carries the same one
   at rest — one width, one radius, one colour, whatever the column.

   Hover and focus keep the design's own treatment on top; only the resting
   state changes. Non-inputs (the grain toggle, the seq checkbox) are already
   bounded controls and are left alone, or the row grows boxes inside boxes. */
[data-ui="v12"] .gridwrap .cellinp {
  border: 1px solid var(--bd-2);
  background: var(--srf);
}
[data-ui="v12"] .gridwrap .cellinp:hover { border-color: var(--bd-3, var(--ink-4)); }
[data-ui="v12"] .gridwrap .cellinp:focus {
  border-color: var(--acc);
  box-shadow: 0 0 0 1px var(--acc);
}
/* The table's own cell padding has to leave room for the border, or adjacent
   boxes touch and read as one long field. */
[data-ui="v12"] .gridwrap .tbl td { padding: 4px 5px; }

/* ============================================ Plan a cut list (#/intake) ====
   The handoff's §2 wearing §1's clothes: it reuses .jobws / .wsbody / .wscol /
   .docketbar / .plate from the ported design, so only what is genuinely its
   own lives here. */
[data-ui="v12"] .ixassume {
  display: flex; align-items: center;
  color: var(--ink-3); font-size: 12.5px; white-space: nowrap;
}
[data-ui="v12"] .ixpaste { padding: 12px; }
[data-ui="v12"] .ixta {
  width: 100%; resize: vertical;
  font-family: var(--m); font-size: 13.5px; line-height: 1.7;
}
[data-ui="v12"] .ixbar { flex: 0 1 auto; min-width: 0; }
[data-ui="v12"] .ixbar-in { display: flex; align-items: center; gap: 6px; }

/* An exception row. The icon tile is the handoff's 30px rounded square; the
   actions sit at the end and WRAP rather than squeezing the sentence that
   explains why the row is there. */
[data-ui="v12"] .ixrow {
  display: flex; align-items: flex-start; gap: 12px; flex-wrap: wrap;
  padding: 12px 14px; border-bottom: 1px solid var(--bd);
}
[data-ui="v12"] .ixrow:last-child { border-bottom: none; }
[data-ui="v12"] .ixico {
  width: 30px; height: 30px; border-radius: 9px; flex: 0 0 auto;
  display: grid; place-items: center; margin-top: 1px;
}
[data-ui="v12"] .ixtxt { flex: 1 1 220px; min-width: 0; }
[data-ui="v12"] .ixtitle { font: 700 14.5px var(--f); letter-spacing: -.02em; color: var(--ink); }
/* .jsub is the design's ONE-LINE caption — this one is prose and must wrap. */
[data-ui="v12"] .ixdetail { white-space: normal; overflow: visible; text-overflow: clip; }
[data-ui="v12"] .ixacts { display: flex; gap: 6px; flex: 0 0 auto; flex-wrap: wrap; }

[data-ui="v12"] .ixclear { display: flex; gap: 14px; align-items: center; padding: 20px 16px; }
[data-ui="v12"] .ixclear-h { font: 700 15px var(--f); letter-spacing: -.02em; color: var(--ink); }

[data-ui="v12"] .ixdeck {
  grid-template-columns: repeat(2, minmax(0, 1fr));
  border-bottom: 1px solid var(--bd);
}
/* The honesty line where the design drew a nest. Not a placeholder for a
   drawing that is coming — the engine is the only thing that packs. */
[data-ui="v12"] .ixnonest {
  padding: 12px 14px; background: var(--srf-2);
  border-bottom: 1px solid var(--bd);
  color: var(--ink-3); font-size: 12.5px; line-height: 1.55;
}
[data-ui="v12"] .ixspecs { padding: 4px 0; }
[data-ui="v12"] .ixspecs .spec {
  display: flex; align-items: center; justify-content: space-between;
  gap: 10px; padding: 7px 14px; font-size: 13px; color: var(--ink-3);
}
[data-ui="v12"] .ixspecs .spec b { color: var(--ink); }
[data-ui="v12"] .ixgo {
  display: grid; gap: 8px; padding: 12px 14px; border-top: 1px solid var(--bd);
}
[data-ui="v12"] .ixgo .btn { width: 100%; justify-content: center; }
[data-ui="v12"] .ixblock { font-size: 12.5px; color: var(--err); text-align: center; margin: 0; }
[data-ui="v12"] .ixempty {
  padding: 24px 16px; color: var(--ink-3); font-size: 13.5px; line-height: 1.65;
}

/* --- the brand mark is a link home ----------------------------------------
   It became a <button> so it is tabbable and answers to Enter. A button drags
   in the UA's own chrome — background, border, padding, inherited font — and
   the design draws this as bare marks, so it is stripped back to what .wbrand
   already lays out. Only the affordances are added. */
[data-ui="v12"] button.wbrand {
  background: none; border: none; padding: 0; margin: 0;
  font: inherit; color: inherit; cursor: pointer;
  border-radius: var(--r-s);
}
[data-ui="v12"] button.wbrand:hover .bn { color: var(--acc); }
[data-ui="v12"] button.wbrand:focus-visible {
  outline: none; box-shadow: 0 0 0 2px color-mix(in srgb, var(--acc) 35%, transparent);
}

/* --- Settings → Machine: one row per saw the build can drive ---------------
   The page used to render only the ENABLED saws, so a shop that had not turned
   HOLZHER on had no way to see it, let alone turn it on. These rows are the
   chooser AND the on/off, and they come from the server's post-processor
   registry — a machine added there appears here with no list in the client to
   keep in step.

   Named .sawsw, not .v2sw: v2.css already uses .v2sw for a 10px status square
   and reusing the name would have styled a switch as a dot. */
[data-ui="v12"] .sawrow {
  display: flex; align-items: center; gap: 10px;
  padding: 10px 14px; border-bottom: 1px solid var(--bd);
  cursor: pointer;
}
[data-ui="v12"] .sawrow:hover { background: var(--srf-2); }
[data-ui="v12"] .sawrow.sel { background: var(--acc-soft); }
[data-ui="v12"] .sawname { display: flex; align-items: center; gap: 7px; min-width: 0; }
[data-ui="v12"] .sawname b { font: 600 13.5px var(--f); color: var(--ink); }
[data-ui="v12"] .sawnote { padding: 10px 14px; line-height: 1.55; white-space: normal; }

[data-ui="v12"] .sawsw {
  width: 34px; height: 20px; border-radius: 999px; flex: 0 0 auto;
  background: var(--bd-2); border: none; padding: 0; cursor: pointer;
  position: relative; transition: background .15s;
}
[data-ui="v12"] .sawsw.on { background: var(--acc); }
[data-ui="v12"] .sawsw > i {
  position: absolute; top: 2px; left: 2px; width: 16px; height: 16px;
  border-radius: 999px; background: var(--srf); transition: left .15s;
  box-shadow: var(--sh);
}
[data-ui="v12"] .sawsw.on > i { left: 16px; }
[data-ui="v12"] .sawsw:focus-visible {
  outline: none; box-shadow: 0 0 0 2px color-mix(in srgb, var(--acc) 35%, transparent);
}

/* --- the plan rail's layout-history block ---------------------------------- */
[data-ui="v12"] .v2histlist { display: grid; gap: 6px; margin-top: 8px; }
[data-ui="v12"] .v2histrow {
  display: flex; align-items: center; gap: 8px;
  padding: 7px 9px; border: 1px solid var(--bd); border-radius: var(--r-s);
  background: var(--srf-2);
}
[data-ui="v12"] .v2histmeta { display: grid; gap: 1px; min-width: 0; }
[data-ui="v12"] .v2histmeta b { font-size: 12px; }
[data-ui="v12"] .v2histrow .btn { margin-left: auto; flex: 0 0 auto; }

/* --- "this job already has a layout" note (edit mode) ---------------------- */
[data-ui="v12"] .njlayoutnote {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  padding: 9px 16px; border-bottom: 1px solid var(--bd);
  background: var(--acc-soft);
}
[data-ui="v12"] .njlayoutnote.stale {
  background: color-mix(in srgb, var(--amb) 12%, transparent);
}
[data-ui="v12"] .njlayouttxt { font-size: 13px; color: var(--ink-2); min-width: 0; }
[data-ui="v12"] .njlayouttxt b { color: var(--ink); }
[data-ui="v12"] .njlayoutnote .btn { margin-left: auto; flex: 0 0 auto; }

/* --- the raw machine-bits editor (expert path) ----------------------------- */
[data-ui="v12"] .rawbits {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  padding: 11px 16px; border-top: 1px solid var(--bd); background: var(--srf-2);
}
[data-ui="v12"] .rawbits.open { display: grid; gap: 8px; }
[data-ui="v12"] .rawbits .btn { flex: 0 0 auto; margin-left: auto; }
[data-ui="v12"] .rawbits.open .btn { margin-left: 0; }
[data-ui="v12"] .rawbits-inp { width: 100%; letter-spacing: 2px; font-size: 13px; }
[data-ui="v12"] .rawbits-err { color: var(--err); font-size: 12.5px; }
[data-ui="v12"] .rawbits-diff { display: grid; gap: 4px; }
[data-ui="v12"] .rawbits-row {
  display: grid; gap: 1px; padding: 6px 9px;
  border: 1px solid var(--bd); border-radius: var(--r-s); background: var(--srf);
}
[data-ui="v12"] .rawbits-row.bad { border-color: var(--err); }
[data-ui="v12"] .rawbits-row.bad .jsub { color: var(--err); }
[data-ui="v12"] .rawbits-ack {
  display: flex; gap: 9px; align-items: flex-start; font-size: 12.5px;
  color: var(--ink-2); line-height: 1.5; cursor: pointer;
}
[data-ui="v12"] .rawbits-ack input { margin-top: 2px; }
[data-ui="v12"] .rawbits-btns { display: flex; gap: 8px; justify-content: flex-end; }

/* Explorer: the per-job delete stays out of the way until you want it.
   Visible on hover and on keyboard focus — hover-only would make it
   unreachable by keyboard, and always-on would put a delete button beside
   every job in a list you scroll past constantly. */
[data-ui="v12"] .tnode .trash { opacity: 0; margin-left: 4px; flex: 0 0 auto; }
[data-ui="v12"] .tnode:hover .trash,
[data-ui="v12"] .tnode .trash:focus-visible { opacity: 1; }
[data-ui="v12"] .tnode .trash:hover { color: var(--bad, #d33); }

/* ---- sign in ------------------------------------------------------------
   The only office screen that still wore the classic app's clothes, and the
   first one anyone sees. Structure follows the saw terminal's login (the one
   login the design handoffs do contain): one calm column, product's own
   voice, nothing on screen that is not needed to get in. */
[data-ui="v12"] .v2auth { display:grid; grid-template-columns:minmax(0,1fr) minmax(0,1fr);
  height:100%; background:var(--bg); }
[data-ui="v12"] .v2auth-form { display:grid; place-items:center; padding:32px; overflow-y:auto; }
[data-ui="v12"] .v2auth-card { width:100%; max-width:392px; }
[data-ui="v12"] .v2auth-brand { display:flex; align-items:center; gap:10px; margin-bottom:30px; }
[data-ui="v12"] .v2auth-mark { width:30px; height:30px; border-radius:9px; display:grid;
  place-items:center; background:var(--acc); color:#fff; flex:none; }
[data-ui="v12"] .v2auth-word { font-size:20px; font-weight:700; letter-spacing:-.02em; }
[data-ui="v12"] .v2auth-word i { font-style:italic; color:var(--acc); }
[data-ui="v12"] .v2auth-card h1 { font-size:26px; font-weight:700; letter-spacing:-.025em; margin:0; }
[data-ui="v12"] .v2auth-fields { display:flex; flex-direction:column; gap:14px; margin-top:24px; }
[data-ui="v12"] .v2auth-field { display:flex; flex-direction:column; gap:6px; }
[data-ui="v12"] .v2auth-field .inp { width:100%; height:42px; }
[data-ui="v12"] .v2auth-field .inp.bad { border-color:var(--bad,#d33); }
[data-ui="v12"] .v2auth-eye { position:absolute; right:6px; top:50%; transform:translateY(-50%);
  background:none; border:none; cursor:pointer; font-size:12px; font-weight:650;
  color:var(--ink-3); padding:6px 8px; }
[data-ui="v12"] .v2auth-eye:hover { color:var(--ink); }
[data-ui="v12"] .v2auth-go { width:100%; height:44px; justify-content:center; }
[data-ui="v12"] .v2auth-err { font-size:13px; color:var(--bad,#d33); }
[data-ui="v12"] .v2auth-link { background:none; border:none; padding:0; cursor:pointer;
  font-size:12.5px; font-weight:650; color:var(--acc); }
[data-ui="v12"] .v2auth-link:hover { text-decoration:underline; }
[data-ui="v12"] .v2auth-or { display:flex; align-items:center; gap:12px; margin:20px 0 14px;
  color:var(--ink-3); font-size:12px; }
[data-ui="v12"] .v2auth-or::before, [data-ui="v12"] .v2auth-or::after {
  content:""; flex:1; height:1px; background:var(--bd); }
[data-ui="v12"] .v2auth-demo { margin-top:16px; padding:12px; border:1px dashed var(--bd);
  border-radius:10px; background:var(--srf-2); }
/* The aside is the product, drawn the way the product draws. It is the first
   thing to go when the window is narrow — the form must never be crowded. */
[data-ui="v12"] .v2auth-aside { display:grid; place-items:center; padding:40px;
  background:linear-gradient(150deg, #171b21, #10131a 60%, #1b232e); }
[data-ui="v12"] .v2auth-aside h2 { font-size:22px; font-weight:700; letter-spacing:-.02em;
  line-height:1.3; margin:26px 0 10px; color:#f2f0ec; }
[data-ui="v12"] .v2auth-aside p { font-size:14px; line-height:1.6; color:rgba(242,240,236,.72); margin:0; }
@media (max-width: 900px) {
  [data-ui="v12"] .v2auth { grid-template-columns:minmax(0,1fr); }
  [data-ui="v12"] .v2auth-aside { display:none; }
}
