/* ================================================================
   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;
}
.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; gap: 8px; }
  /* ⚠ 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; }

/* ================================================================
   PRINT
   ================================================================ */
/* ⚠ A4 IS THE DEFAULT AND NOT THE ONLY ANSWER, and this rule cannot say so
   itself: `@page` takes no custom properties in any shipping browser, so a
   declared sheet that is not A4 needs a real rule written for it. That is what
   surfaces/labels.js's applyPageRule does — one <style> element carrying
   `@page labels { size: <w>mm <h>mm; margin: 0 }`, rewritten in place whenever
   the declaration changes, and named `labels` so it scopes to these pages
   exactly as this one does. This stays as the value in force until it is.

   The margin is nought and stays nought whatever the size: label stationery
   has its own margins printed into the die-cut, and print.css's 14 mm would
   shift every label down by fourteen. */
@page labels { size: A4; margin: 0; }

@media print {
  /* Everything print.css removes stays removed. This removes the one
     thing it cannot know about: the desk AROUND the sheet. A label
     sheet is the only thing in this product where printing the page
     the reader is looking at would be wrong — they are looking at a
     preview and a toolbar, and they want the stationery. */
  body.bcl-printing .wrap > *:not(.bcl-sheet) { display: none !important; }
  body.bcl-printing .bcl-sheet { display: block !important; }

  /* ⚠ The sheet count and the "print at 100%" warning are guidance for the
     person at the screen. Left visible they printed as the first thing in
     the document — which, because they sit OUTSIDE any .bcl-page, came out
     on a page using print.css's default @page and produced a leading sheet
     of stationery with one line of text on it and 21 labels wasted. Caught
     by rasterising the print PDF and finding page 1 blank at 210.2 x 297.3
     mm while every later page measured 209.9 x 297.0 — the size difference
     was the tell that a second, unnamed @page was in play. */
  body.bcl-printing .bcl-note { display: none !important; }
  /* the horizontal scroller is a screen affordance; in print it would clip */
  body.bcl-printing .bcl-scroll { overflow: visible !important; }

  /* `page` inherits, so naming it on the root while a label print is running
     puts the WHOLE document on the zero-margin sheet. Without this the
     document still begins on the default page even with nothing on it. */
  body.bcl-printing { page: labels; }

  /* ⚠ And every ancestor gives up its own spacing. The shell's own padding is
     invisible on paper but it is not zero, and a few millimetres above the
     first sheet is enough to push that sheet's last row onto a page of its
     own — which is how a five-sheet job kept printing as six with page 2
     blank, even after the sheet itself had been shortened. Print geometry is
     absolute or it is nothing. */
  body.bcl-printing,
  body.bcl-printing .shell,
  body.bcl-printing #view,
  body.bcl-printing .wrap,
  body.bcl-printing .wrap.wide,
  body.bcl-printing .bcl-sheet,
  /* ⚠ AND .bcl-scroll, WHOSE 4 px OF BOTTOM PADDING COST A SHEET OF
     STATIONERY. It is the screen scroller's own breathing room, 1.06 mm,
     and it sat below the last sheet: a one-sheet Letter job measured
     279.46 mm of document against a 279.40 mm page and Chromium emitted a
     second, blank sheet for the 0.06 mm. Measured on the real print output
     at 300 dpi, on the declared 215.9 x 279.4 mm stationery: every job came
     out with one blank sheet more than it needed. A4 survived it only by
     luck of where its own rounding fell. */
  body.bcl-printing .bcl-scroll {
    margin: 0 !important; padding: 0 !important; border: 0 !important;
  }

  .bcl-page {
    page: labels;                 /* margin:0, so the die-cut decides */
    box-shadow: none !important;
    margin: 0 !important;
    /* ⚠ break-BEFORE on every sheet but the first, never break-after.
       break-after: page emitted a blank sheet after the run and another
       after the first one — 95 labels came out as seven A4 pages instead of
       five, and blank Avery stationery is money. A break before each
       subsequent sheet says the same thing without ever asking for a page
       that has nothing on it. */
    break-inside: avoid;
    /* ⚠ 296 mm, not 297, and no bottom padding.

       At exactly 297 mm this box fills the A4 page to the last sub-pixel and
       Chromium's own rounding (it reports the page as 209.9 x 297.0) pushed
       it over, emitting a blank sheet. 93 labels came out as SEVEN A4 pages
       instead of five — and a blank sheet of Avery stationery through a
       laser printer is money and a jam risk, not a cosmetic complaint.
       Diagnosed by rasterising the print PDF at 300 dpi and finding page 2
       empty with page 1 and 3 both full.

       Nothing physical moves. Every label is positioned from the TOP edge —
       15.15 mm of padding, then rows at a fixed 38.1 mm pitch — so the last
       row still ends 281.85 mm down whatever the box height is. The
       millimetre comes out of the stationery's empty bottom margin, and the
       bottom padding goes with it so the grid never has to overflow.

       ⚠ AND IT IS ONE MILLIMETRE OFF WHATEVER SHEET WAS DECLARED, not off
       297 mm. The rounding this defends against is Chromium's, on any page
       size, so a declared sheet that is not A4 needs the same millimetre or
       it emits the same blank sheet — and blank stationery through a laser
       printer is money and a jam risk on any size. */
    height: var(--bcl-page-print-h, 296mm);
    padding-bottom: 0;
    -webkit-print-color-adjust: exact; print-color-adjust: exact;
  }
  .bcl-page + .bcl-page { break-before: page; }

  /* the die-cut guide is a screen affordance; on paper it would print
     a dashed rectangle onto every label */
  .bcl { outline: none !important; }
}
