/* ================================================================
   labels.css — the printed asset label, at its real physical size.

   READ css/print.css FIRST. Everything general about printing in this
   product is decided there and is not repeated here: colour is asked
   for explicitly because the marks ARE the meaning, navigation is
   removed, a table prints every row rather than one page of them.
   This file adds only the one thing that surface cannot express — a
   sheet of labels whose millimetres have to be the millimetres on the
   stationery, or the printed symbol lands half on the next label.

   WHY EVERY DIMENSION IS IN mm AND NOT px.
   A label is a physical object on a physical sheet. px is a screen
   unit and a printer resolves it through whatever scale factor the
   print dialogue happens to carry, so a QR laid out in px is a QR
   whose module size is a guess. mm survives the dialogue.

   WHY A NAMED @page.
   print.css sets `@page { margin: 14mm 12mm }`, which is right for a
   report and fatal for a label sheet: Avery stationery has its own
   margins printed into the die-cut, and adding fourteen more
   millimetres shifts every label down by fourteen. `@page labels`
   plus `page: labels` on the sheet scopes margin:0 to THESE pages
   only, so a report printed from any other surface still gets the
   margins print.css chose for it. Verified by rendering to PDF and
   measuring the result, not by reading the spec.

   THE NUMBERS BELOW ARE THE DEFAULT, NOT THE ONLY GEOMETRY.
   Avery L7160 / J8160, 63.5 x 38.1 mm, 3 x 7, 21 to an A4 sheet,
   measured from the die-cut and not invented: the print PDF is
   rasterised at 300 dpi, cut on exactly these millimetres, and every
   QR read back to its scan URL. Room for a QR a phone locks onto from
   arm's length, the tag in type somebody can read across a desk, and
   a Code 128 for the store's own scanner.

   ⚠ EVERY DIMENSION HERE IS A CUSTOM PROPERTY, AND THAT IS THE WHOLE
   MECHANISM. An organisation declares the stationery it actually buys
   on the Setup desk, in millimetres; surfaces/labels.js sets that
   declaration onto each .bcl-page as these same properties, and the
   grid below lays itself out to it. There is no second layout, no
   second print block and no branch — the sheet is drawn from
   variables that already existed, and the L7160 numbers stand here as
   what a page falls back to when nothing has been declared.

   ⚠ THERE USED TO BE A SECOND PRESET AND A SEGMENTED CONTROL TO
   CHOOSE IT, offering "21 per sheet" or "65 per sheet" beside the
   Print button. The control is not coming back and its removal was
   right: choosing a stationery product code is not a question to ask
   somebody who came here to print labels for devices they have
   already picked. What has come back is the FACT, in the place it
   belongs — declared once by an administrator, then used. The two are
   not the same thing, and losing the second with the first is how a
   customer whose supplier ships 99.1 x 38.1 mm sheets ends up with
   every label half onto the next one.

   And 65-up is no longer a special case at all. A 38.1 x 21.2 mm
   label leaves a 19.6 mm text column, which puts a Code 128 module at
   0.105 mm — under the 0.17 mm this product has actually had decoded
   — so labels.js measures that and prints no bar, and says on the
   desk how many labels that is and why. The same conclusion the
   preset was deleted over, reached by measuring the die cut the
   customer declared instead of by removing their stationery.
   ================================================================ */

/* ⚠ EVERY CLASS HERE IS PREFIXED `bcl-`, AND THE BARE ONE IS `.bcl`.
   The obvious name for a label was `.lbl`, and `.lbl` is already taken —
   three times, by tokens.css, shell.css and physical.css, none of which
   this file can see. Using it silently handed every printed label those
   three rules' width, padding and font, and the sheet rendered as a grid
   of 9 x 8 mm stamps that looked deliberate. A CSS class in a product with
   one global stylesheet scope is a global name, exactly as a top-level
   const in this product's JavaScript is; both need a prefix nobody else
   owns. */

/* the sheet as a whole */
.bcl-sheet { display: block; }
/* ⚠ `display:block` on a class beats the user agent's `[hidden]{display:none}`,
   which is a bare attribute selector — so the sheet stayed on screen behind
   faces that had no sheet, with a full A4 preview of labels below a denial
   card. A `hidden` element that renders is worse than one that never hides,
   because every reader assumes hidden works. */
.bcl-sheet[hidden] { display: none; }

.bcl-page {
  /* Avery L7160 / J8160 — 21 per A4 sheet */
  --bcl-w: 63.5mm;  --bcl-h: 38.1mm;
  --bcl-cols: 3;
  --bcl-pitch-x: 66mm; --bcl-pitch-y: 38.1mm;
  --bcl-margin-x: 7.25mm; --bcl-margin-y: 15.15mm;
  --bcl-qr: 26mm;

  box-sizing: border-box;
  /* the sheet that goes in the tray, declared on Setup. A4 unless somebody
     said otherwise, which is what every stationery this product ships is. */
  width: var(--bcl-page-w, 210mm); height: var(--bcl-page-h, 297mm);
  padding: var(--bcl-margin-y) var(--bcl-margin-x);
  margin: 0 auto 14px;
  background: #fff;
  color: #000;
  display: grid;
  grid-template-columns: repeat(var(--bcl-cols), var(--bcl-w));
  grid-auto-rows: var(--bcl-h);
  column-gap: calc(var(--bcl-pitch-x) - var(--bcl-w));
  row-gap: calc(var(--bcl-pitch-y) - var(--bcl-h));
  /* on screen only — a printed sheet must show no chrome at all */
  box-shadow: 0 1px 3px rgba(23, 23, 26, .14), 0 0 0 1px var(--hairline);
}

/* ---- one label ----------------------------------------------------

   ONE ZONE. `.bcl-main` is the whole label: the QR beside the
   identifying text, for whoever is standing in front of the device.
   The content box is 63.5 - 3.2 = 60.3 mm wide and 38.1 - 3.2 =
   34.9 mm tall, and the QR is 26 mm. `.bcl-main` is top-aligned so the
   organisation line starts level with the top of the QR. */
.bcl {
  box-sizing: border-box;
  width: var(--bcl-w); height: var(--bcl-h);
  padding: 1.6mm;
  display: flex; flex-direction: column;
  overflow: hidden;
  /* the die-cut edge, on screen only, so somebody can see the layout
     before they commit a sheet of stationery to it */
  outline: 0.2mm dashed #c9c9cf; outline-offset: -0.1mm;
  break-inside: avoid;
}
.bcl-main { flex: 1; min-height: 0; display: flex; align-items: flex-start; gap: 1.8mm; }

.bcl-qr { flex: none; width: var(--bcl-qr); height: var(--bcl-qr); display: block; }
.bcl-qr svg { display: block; width: 100%; height: 100%; }

.bcl-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 0.6mm; }

/* WHOSE it is. Small caps above the tag rather than bigger than it:
   this answers a question that is asked once in a device's life, and
   the tag answers one that is asked every stock check. */
.bcl-org {
  font-family: var(--sans, system-ui, sans-serif);
  font-size: 2.1mm; line-height: 1.1; font-weight: 700;
  letter-spacing: 0.045em; text-transform: uppercase; color: #000;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* WHICH device it is — the largest thing on the label, and the one
   value that may never be cut.

   ⚠ THE BODY COLUMN IS ONLY 32.5 mm (60.3 - 26 QR - 1.8 gap) and this
   register carries asset tags up to 17 characters. At 3.4 mm a
   monospace glyph advances about 2.04 mm, so 17 of them want 34.7 mm
   and the old rule silently ellipsed them — a truncated identifier is
   a WRONG identifier, and it is wrong in the field where being right
   is the whole point. So the type steps down by tag length instead
   (surfaces/labels.js picks the class), and the step sizes are checked
   by measuring scrollWidth against clientWidth on every rendered
   label rather than by looking at the sheet. */
.bcl-tag {
  font-family: var(--mono, ui-monospace, monospace);
  font-size: 3.4mm; font-weight: 700; line-height: 1.05;
  letter-spacing: -0.01em;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.bcl-tag.long   { font-size: 2.8mm; }   /* 14-18 characters */
.bcl-tag.longer { font-size: 2.2mm; }   /* 19 and over */

/* ⚠ THIS LINE WRAPS, AND THE TAG ABOVE IT DOES NOT. That is deliberate.
   Measured across the register's own labels, 24 of 200 make+model
   values overflowed 32.5 mm on one line and were being ellipsed —
   "Assembled Bulk-Build AR-Desk Gen3" is 33 characters and the column
   holds about 29. Ellipsing an identifier is dangerous, which is why
   .bcl-tag steps its type down instead; ellipsing a MODEL NAME just
   loses the end of a phrase a human is reading, and a phrase reads
   perfectly well over two lines. So this one is allowed to take a
   second line and is clamped there, which costs 2.5 mm out of the
   8 mm the body column had spare and loses nothing. */
.bcl-kit {
  font-family: var(--sans, system-ui, sans-serif);
  font-size: 2.2mm; line-height: 1.15; color: #333;
  white-space: normal; overflow: hidden;
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2;
  max-height: 5.1mm;   /* belt and braces: two lines at 1.15 line-height */
}
/* The verification field. Monospace because it is read one character
   at a time against a sticker on the underside of the device, and the
   "S/N" tag is set apart so the value itself is what the eye lands on.
   Drawn only when the register holds a serial that is really a serial —
   see printableSerial() in surfaces/labels.js. */
.bcl-sn {
  font-family: var(--mono, ui-monospace, monospace);
  font-size: 2mm; line-height: 1.15; color: #222;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* ⚠ THE SERIAL STEPS DOWN, LIKE THE TAG ABOVE IT. It was fixed at 2 mm
   under the ellipsis rule, so a register row carrying a hand-typed
   "HP laptop 15s (5CD422F9MK)" printed "HP laptop 15s (5CD422F9M…" on the
   sticker. A serial is read one character at a time against the underside
   of a machine; two thirds of one is not a shorter answer, it is a wrong
   one. surfaces/labels.js picks the class off the measured step, and where
   even the smallest step is too narrow the value is replaced by a plate
   rather than cut. */
.bcl-sn.long   { font-size: 1.8mm; }
.bcl-sn.longer { font-size: 1.6mm; }
.bcl-sn span {
  font-family: var(--sans, system-ui, sans-serif);
  color: #6a6a72; letter-spacing: 0.04em; font-size: 1.7mm;
}
.bcl-own {
  font-family: var(--sans, system-ui, sans-serif);
  font-size: 1.9mm; line-height: 1.15; color: #555;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* ⚠ 8 mm, and the extra 2 mm is not decoration. The body column is
   32.5 mm wide, and a Code 128 of this register's 12-character tags
   comes out at 187 modules — 0.174 mm each, measured off the rendered
   sheet, against the 0.19 mm a general-purpose scanner nominally
   wants. The width is fixed by the die-cut and is not this file's to
   change, but bar HEIGHT is free here: the label has unused white
   below the text stack, and a taller bar gives a scanner more scan
   lines to find the symbol on, which is the one lever left for a
   symbol that is narrow. */
.bcl-bar { height: 8mm; margin-top: 0.6mm; }
.bcl-bar svg { display: block; width: 100%; height: 100%; }

/* an empty cell on a part-used sheet, so the reader can see that the
   labels start where the stationery does */
.bcl.bcl-blank { outline-color: #ececf0; }

/* ---- the desk around it, ON SCREEN ONLY ---------------------------

   ⚠ EVERY RULE IN THIS SECTION IS INSIDE `@media screen`, AND THAT IS
   NOT TIDINESS. The desk is a two-column grid — the picker on the left,
   the real sheet on the right — declared on `.wrap` itself. A grid left
   visible to the printer would have been inherited by the page the
   stationery is measured against, and `.wrap` must arrive at the
   printer as a plain zero-margin block or the sheet's absolute
   millimetres stop being absolute. Screen layout and paper layout share
   this file and share nothing else.

   ⚠ AND THE SHEET'S OWN TOOLBAR IS A SIBLING OF `.bcl-sheet`, NEVER A
   CHILD. @media print below keeps exactly one child of `.wrap` — the
   sheet — and removes the rest. A Print button, the count of what is
   about to print, or the honesty flags beside it, placed INSIDE the
   sheet, would have been printed onto the
   Avery stationery, which is the same defect the `.bcl-note` warning
   further down records. As a sibling it is removed by the rule that is
   already there, and not one line of the print block had to change to
   put a toolbar beside the preview. */
@media screen {
  .bcl-wrap { display: grid; grid-template-columns: 340px minmax(0, 1fr); column-gap: 22px; align-items: start; }
  .bcl-wrap > .page-head       { grid-column: 1 / -1; grid-row: 1; }
  .bcl-wrap > [data-face-body] { grid-column: 1; grid-row: 2 / span 2; min-width: 0; }
  .bcl-wrap > .bcl-sheet-top   { grid-column: 2; grid-row: 2; min-width: 0; }
  .bcl-wrap > .bcl-sheet       { grid-column: 2; grid-row: 3; min-width: 0; }

  /* An A4 preview is 210 mm wide and does not negotiate. Below the width
     where the picker and a full sheet both fit, they stack rather than
     letting the sheet shrink: a preview at 80% of the stationery is a
     preview of something that will not be printed.

     ⚠ 1479 px, AND THE OLD 1180 px WAS THE ON-SCREEN HALF OF "the right
     side is cut off". The two columns are 340 px of picker, a 22 px gap
     and a sheet that is 210 mm, which is 794 px and does not negotiate;
     with the rail and the page's own padding the desk needs 1472 px
     before all three fit. Measured by sweeping the viewport 1000 px to
     1700 px in 20 px steps and comparing .bcl-scroll's scrollWidth with
     its clientWidth: at every width from 1200 px to 1460 px the sheet
     was 794 px of content in as little as 522 px of scroller, so the
     right-hand column of labels sat off the edge behind a scrollbar. A
     1366 px laptop and a half-screen 1440 px window both land in that
     band. Below this the picker and the sheet stack, and the sheet gets
     the whole width. */
  @media (max-width: 1479px) {
    .bcl-wrap { grid-template-columns: minmax(0, 1fr); }
    .bcl-wrap > [data-face-body] { grid-column: 1; grid-row: 2; }
    .bcl-wrap > .bcl-sheet-top   { grid-column: 1; grid-row: 3; margin-top: 18px; }
    .bcl-wrap > .bcl-sheet       { grid-column: 1; grid-row: 4; }
    .bcl-pick { position: static; }
    .bcl-pick-list { max-height: 340px; }
  }

  /* ---- the picker. Deliberately not a data grid ----------------------
     Four of the seven columns it replaced repeated the same value on
     every row — Issued "today", Scans "0", "NEVER SCANNED", State "In
     use" — so they are gone. A chip appears on a row only where that row
     has something the others do not. */
  .bcl-pick { position: sticky; top: 14px; border: 1px solid var(--hairline);
    border-radius: var(--r-card); background: var(--surface); overflow: hidden; }
  .bcl-pick-top { display: flex; flex-wrap: wrap; gap: 10px; padding: 13px 14px;
    border-bottom: 1px solid var(--hairline); }
  .bcl-pick-top .grow { flex: 1 1 150px; min-width: 130px; }
  .bcl-pick-head { display: flex; align-items: center; justify-content: space-between; gap: 10px;
    padding: 7px 10px 7px 14px; border-bottom: 1px solid var(--hairline); background: var(--surface-2); }
  .bcl-all { display: flex; align-items: center; gap: 8px; font-size: 11.5px; color: var(--ink-3); cursor: pointer; }
  .bcl-pick-list { max-height: calc(100vh - 320px); min-height: 120px; overflow-y: auto; }

  .bcl-row { display: flex; align-items: center; gap: 6px; padding: 0 10px 0 14px;
    border-bottom: 1px solid var(--hairline-2); }
  .bcl-row:last-child { border-bottom: 0; }
  .bcl-row:hover { background: var(--surface-2); }
  .bcl-row.off .bcl-rt { text-decoration: line-through; }
  .bcl-rl { flex: 1; min-width: 0; display: flex; align-items: flex-start; gap: 9px; padding: 9px 0; cursor: pointer; }
  .bcl-rl input { margin: 2px 0 0; flex: none; }
  .bcl-rm { min-width: 0; display: block; }
  .bcl-rt { display: block; font-family: var(--mono, ui-monospace, monospace);
    font-size: 11.5px; font-weight: 600; color: var(--ink); }
  .bcl-rk { display: block; font-size: 11px; color: var(--ink-3); margin-top: 1px;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .bcl-rc { display: flex; gap: 5px; flex-wrap: wrap; margin-top: 5px; }
  /* the row is not the control; one short control opens the record */
  .bcl-open { flex: none; opacity: 0; transition: opacity var(--t-fast) ease; }
  .bcl-row:hover .bcl-open, .bcl-open:focus-visible { opacity: 1; }

  /* ---- the strip above the sheet ---- */
  .bcl-sheet-top { display: block; margin-bottom: 12px; }
  .bcl-sheet-top[hidden] { display: none; }
  .bcl-sheet-line { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; justify-content: space-between; }
  /* What replaced the 21-up / 65-up picker. It is a STATEMENT, so it is
     type and not a control — the reader is being told what will come out
     of the printer, not asked a question about Avery's catalogue. */
  .bcl-willprint { font-size: 13px; color: var(--ink-2); display: flex; align-items: baseline; gap: 6px; }
  .bcl-willprint b { font-size: 15px; font-weight: 650; color: var(--ink); }
  .bcl-willprint span { color: var(--ink-3); }
  /* The two things the sheet cannot say on the labels themselves. Set apart
     from .bcl-note, which is neutral guidance, because these are claims
     about THIS sheet that somebody may want to go and fix first. */
  .bcl-flag { flex-direction: column; gap: 4px; color: var(--ink-2); }
  .bcl-flag span {
    border-left: 2px solid var(--hairline); padding-left: 9px; line-height: 1.45;
  }
  .bcl-acts { display: flex; flex-wrap: wrap; align-items: flex-end; gap: 8px; }
  /* the stationery picker, beside the button it governs. Narrow on purpose:
     it is one choice out of a short list and not a form. */
  .bcl-stat { min-width: 190px; }
  /* ⚠ The kit styles a disabled INPUT and never a disabled BUTTON, so a
     control this desk shows-and-disables looked exactly like one that works.
     The controls still disabled here are the ones waiting on a choice, not on
     a permission: Revoke and Issue until something is picked, Print sheet
     until there is something to print. Scoped to this desk and to the drawer
     foot it opens, because tokens.css is not this file's to change; the same
     gap is worth closing there for every surface. */
  .bcl-wrap .btn:disabled, .bcl-foot .btn:disabled { opacity: .42; cursor: not-allowed; box-shadow: none; }
  .bcl-wrap .btn:disabled:hover, .bcl-foot .btn:disabled:hover {
    color: var(--ink-2); border-color: var(--hairline); box-shadow: none; }
  .bcl-wrap .btn.accent:disabled, .bcl-foot .btn.accent:disabled,
  .bcl-wrap .btn.accent:disabled:hover, .bcl-foot .btn.accent:disabled:hover {
    background: var(--accent); border-color: var(--accent); color: #fff; }

  .bcl-muted { font-size: 11.5px; color: var(--ink-3); margin: 0; }
  .bcl-pad { padding: 14px; }
  .bcl-card { padding: 16px 18px; }
  .bcl-foot { display: flex; align-items: center; justify-content: space-between; gap: 12px; width: 100%; }
}

.bcl-note {
  font-size: 11.5px; color: var(--ink-3); margin: 8px 0 0;
  display: flex; flex-wrap: wrap; gap: 4px 14px;
}
.bcl-scroll { overflow-x: auto; padding-bottom: 4px; }

/* ================================================================
   THERE IS NO PRINT BLOCK IN THIS FILE ANY MORE, AND THAT IS THE FIX.

   What stood here was a print stylesheet: `@page labels { size: A4;
   margin: 0 }`, `page: labels` on the body while a print was running, a
   rule removing every child of `.wrap` but the sheet, four ancestors
   giving up their padding, a page height one millimetre short of the
   sheet to dodge Chromium's rounding, and a media query that refused the
   sheet outright when the printable area looked too small. Every line of
   it was written against a measured defect and every line of it was
   correct about the defect it was written for. The sheet still printed
   wrong, five times.

   The reason is not in any of those rules. window.print() hands the page
   box, the margins and the scale to the browser, and the browser then
   does what the print dialogue and the paper in the tray tell it:

     · named `@page` rules are not honoured everywhere, so print.css's
       `@page { margin: 14mm 12mm }` won and every label moved 14 mm down;
     · the dialogue's own margin setting shrinks the box a print media
       query reports while the CSS `margin: 0` still governs the layout,
       so the refusal rule fired on sheets that would have printed
       perfectly — 610,575 ink pixels at 12 mm of margin, 7,832 at 13 mm,
       measured at 300 dpi on the declared L7159;
     · Letter in the tray and Chromium scales the whole sheet by
       279.4 / 297 = 0.941 and centres it, ink 19.56 -> 196.68 mm instead
       of 10.92 -> 199.22 mm. That is the right-hand column being cut, and
       no rule in this file could see it, let alone stop it.

   So the sheet is not printed from this document at all. js/label-pdf.js
   writes it as a PDF at absolute millimetre coordinates, and "Print
   sheet" hands the person that file: its own page size, no margins but
   the ones written into it, the same file on any paper and in any
   dialogue. What is left in this file is the SCREEN preview, which was
   correct all along and is what the printed sheet is now drawn to match.

   ⚠ SO NOTHING HERE MAY GROW A PRINT RULE AGAIN. A `@media print` block
   in this file can only be an opinion about a page the product no longer
   asks the browser to lay out. css/print.css still governs Ctrl+P of the
   desk itself, as it does for every other surface, and that is right: a
   person who prints the desk gets the desk.
   ================================================================ */
