/* ============================================================================
   Printable dine-in QR table cards — the design a restaurant prints for its
   tables (one FRONT + one BACK). A physical card is its own surface, so like the
   TV board this stylesheet is self-contained: theme tokens, a full-bleed
   background, an optional featured-product overlay, and the table's own
   scan-to-order QR — the product and the QR anchored on the very same 3x3 grid
   the TV editor uses. Interior sizing is in container units (cqmin/cqh) relative
   to the CARD, so one card scales identically in the tiny editor preview and at
   full page size on paper.

   Loaded on the design editor preview and on the print sheet only.
   ========================================================================== */
:root {
  --qrc-bg: #f4f1ec;
  --qrc-ink: #1a1614;
  --qrc-ink-soft: #6b6259;
  --qrc-line: rgba(0, 0, 0, .10);
  --qrc-accent: #e11d2a;
  --qrc-font: "Poppins", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
}
.qrc[data-theme="dark"] {
  --qrc-bg: #17140f;
  --qrc-ink: #f6f1e8;
  --qrc-ink-soft: #b3a894;
  --qrc-line: rgba(255, 255, 255, .14);
}

* { box-sizing: border-box; }
/* No default body margin — the editor preview iframe is exactly viewport-height, so 8px of body
   margin would push the stage past it and force a scrollbar inside the frame. */
html, body { margin: 0; }

/* On-screen print toolbar (hidden on paper): back to the codes list + Print. */
.qrc-toolbar { position: sticky; top: 0; z-index: 10; display: flex; justify-content: center; gap: 12px; padding: 14px; background: #fff; border-bottom: 1px solid #e5e2dc; }
.qrc-tbtn { display: inline-flex; align-items: center; gap: 8px; border: 1px solid #d9d5cd; background: #fff; color: #1a1614; border-radius: 8px; padding: 9px 18px; font: 600 14px/1 var(--qrc-font); text-decoration: none; cursor: pointer; }
.qrc-tbtn:hover { border-color: #b9b3a8; }
.qrc-tbtn-primary { background: var(--qrc-accent); border-color: var(--qrc-accent); color: #fff; }

/* ---- The stage: centres one card (editor preview) or flows a stack of card
   pages (the print sheet). On screen the card sits on a soft mat; in print each
   page is a clean sheet. ---- */
.qrc-stage { margin: 0; background: #eceae5; display: flex; flex-direction: column; align-items: center; gap: 20px; padding: 22px; min-height: 100%; }
.qrc-stage.is-preview { background: transparent; padding: 0; justify-content: center; min-height: 100vh; }
.qrc-page { display: flex; align-items: center; justify-content: center; width: 100%; }

/* ---- The card ---- */
.qrc {
  position: relative;
  container-type: size;
  aspect-ratio: 1 / 1.4142;                 /* portrait A-series proportion */
  width: 100%;
  max-width: 460px;
  overflow: hidden;
  background: var(--qrc-bg);
  color: var(--qrc-ink);
  font-family: var(--qrc-font);
  border-radius: 12px;
  box-shadow: 0 10px 34px rgba(0, 0, 0, .18);
}
.qrc[data-orient="landscape"] { aspect-ratio: 1.4142 / 1; max-width: 660px; }
.qrc-stage.is-preview .qrc { width: auto; height: 96vh; max-width: 96vw; }
/* Force every card colour/background to print even when the browser's "Background graphics" is off —
   the accent price pill, the theme background and the photo below all depend on this on paper. */
.qrc, .qrc * { -webkit-print-color-adjust: exact; print-color-adjust: exact; }

/* Full-bleed background photo (a CSS background, so print-color-adjust forces it onto paper reliably);
   a gentle scrim over it keeps overlaid text and the QR legible on a busy image. */
.qrc-bg { position: absolute; inset: 0; background-size: cover; background-position: center; background-repeat: no-repeat; }
.qrc.has-bg .qrc-bg-scrim { position: absolute; inset: 0; background: linear-gradient(180deg, rgba(0, 0, 0, .10), rgba(0, 0, 0, .28)); }
/* Background-image slot shown in preview/template mode when no background is set (behind the content). */
.qrc-bg-ph { position: absolute; inset: 5cqmin; z-index: 0; display: flex; align-items: center; justify-content: center; border: 0.6cqmin dashed rgba(128, 128, 128, .45); border-radius: 3cqmin; pointer-events: none; }
/* Once a background is present (incl. a client-injected upload preview) the "add background" slot hides. */
.qrc.has-bg .qrc-bg-ph { display: none; }
.qrc-bg-ph-t { font-size: 3.4cqmin; font-weight: 700; letter-spacing: .05em; text-transform: uppercase; color: rgba(128, 128, 128, .8); text-align: center; padding: 0 4cqmin; }

/* --------------------------------------------------------------------------
   Featured-product overlay — dish name + description + an accent price pill,
   anchored to one of nine points (identical model to the TV board's overlay).
   --qrc-prod-scale (0.7–2.0, from the 0–10 size slider) grows the block as one.
   Over a photo the text is white with a soft shadow; on a plain themed card it
   uses the card ink so it never disappears.
   -------------------------------------------------------------------------- */
.qrc-product { --qrc-prod-scale: 1; position: absolute; z-index: 3; display: flex; flex-direction: column; gap: calc(2cqmin * var(--qrc-prod-scale)); max-width: 84%; padding: 1cqh 1cqw; }
.qrc-product-name { margin: 0; color: var(--qrc-ink); font-weight: 800; font-size: calc(6.2cqmin * var(--qrc-prod-scale)); line-height: 1.04; letter-spacing: .01em; }
.qrc-product-desc { margin: 0; color: var(--qrc-ink-soft); font-weight: 500; font-size: calc(3.3cqmin * var(--qrc-prod-scale)); line-height: 1.3; }
.qrc-product-price { background: var(--qrc-accent); color: #fff; font-weight: 800; font-size: calc(4.6cqmin * var(--qrc-prod-scale)); line-height: 1; padding: calc(1.6cqmin * var(--qrc-prod-scale)) calc(3.4cqmin * var(--qrc-prod-scale)); border-radius: 999px; box-shadow: 0 1cqmin 3cqmin rgba(0, 0, 0, .22); }
.qrc.has-bg .qrc-product-name { color: #fff; text-shadow: 0 .4cqh 1.6cqh rgba(0, 0, 0, .6); }
.qrc.has-bg .qrc-product-desc { color: #fff; text-shadow: 0 .3cqh 1.2cqh rgba(0, 0, 0, .6); }

/* --------------------------------------------------------------------------
   The table's own scan-to-order QR, anchored on the same 3x3 grid. A white quiet
   zone (with the caption on it) keeps the code scannable over any background.
   --qrc-qr-scale (0.6–1.7, from the 0–10 size slider) sizes the whole block.
   -------------------------------------------------------------------------- */
.qrc-qr { --qrc-qr-scale: 1; position: absolute; z-index: 4; display: flex; flex-direction: column; }
.qrc-qr-frame { position: relative; display: flex; flex-direction: column; align-items: center; gap: 1.8cqmin; background: #fff; padding: 3cqmin; border-radius: 3.4cqmin; box-shadow: 0 1.4cqmin 4.4cqmin rgba(0, 0, 0, .26); width: calc(30cqmin * var(--qrc-qr-scale)); }

/* ---- Frame variants (QrCard::QR_FRAMES), chosen per side in the designer ----------------------
   READ THIS BEFORE ADDING A FRAME. The 3cqmin of WHITE on .qrc-qr-frame is not decoration: it is the
   quiet zone the QR specification requires around the symbol, and it is what keeps the code readable
   over a dark theme or a full-bleed photo. A variant that tightens that padding, tints the plate, or
   puts anything over the code kills it at perfect contrast — the failure looks like nothing at all
   until the cards come back from the printer. So a frame may only:
     • add paint OUTSIDE the plate (a ring, corner brackets, a band along an edge),
     • change the plate's corner radius or drop its shadow.
   It may never reduce the padding, colour the plate behind the code, or overlay the symbol. There is
   deliberately no "no frame" option for the same reason.
   The light modules are always white and never inverted; the ink colour is a canvas concern, applied
   in assets/js/qr-card-draw.js and floored server-side by QrCard::inkError().

   "plate" is the frame this product has always drawn, so it adds nothing here — a card saved before
   frames existed defaults to it and renders exactly as it did. */
.qrc-qr-frame[data-frame="square"]  { border-radius: 0; box-shadow: none; }
/* The ring is added to the plate's width rather than taken out of it (box-sizing is border-box), so
   the code prints at the same size in this frame as in every other one. */
.qrc-qr-frame[data-frame="outline"] { border: 0.8cqmin solid var(--qrc-accent); border-radius: 1.8cqmin; box-shadow: none; width: calc(30cqmin * var(--qrc-qr-scale) + 1.6cqmin); }
/* Corner brackets sit on a pseudo-element pushed OUTSIDE the plate, so the quiet zone is untouched:
   eight hairline layers, two per corner (the horizontal arm and the vertical one). */
.qrc-qr-frame[data-frame="corners"] { border-radius: 0; box-shadow: none; }
.qrc-qr-frame[data-frame="corners"]::before {
  content: ""; position: absolute; inset: -1.8cqmin; pointer-events: none;
  background:
    linear-gradient(var(--qrc-accent), var(--qrc-accent)) 0 0        / 6cqmin 0.9cqmin no-repeat,
    linear-gradient(var(--qrc-accent), var(--qrc-accent)) 0 0        / 0.9cqmin 6cqmin no-repeat,
    linear-gradient(var(--qrc-accent), var(--qrc-accent)) 100% 0     / 6cqmin 0.9cqmin no-repeat,
    linear-gradient(var(--qrc-accent), var(--qrc-accent)) 100% 0     / 0.9cqmin 6cqmin no-repeat,
    linear-gradient(var(--qrc-accent), var(--qrc-accent)) 0 100%     / 6cqmin 0.9cqmin no-repeat,
    linear-gradient(var(--qrc-accent), var(--qrc-accent)) 0 100%     / 0.9cqmin 6cqmin no-repeat,
    linear-gradient(var(--qrc-accent), var(--qrc-accent)) 100% 100%  / 6cqmin 0.9cqmin no-repeat,
    linear-gradient(var(--qrc-accent), var(--qrc-accent)) 100% 100%  / 0.9cqmin 6cqmin no-repeat;
}
/* An accent bar along the foot of the plate — extra padding below the caption makes room for it, so
   the bar never encroaches on the quiet zone above. */
.qrc-qr-frame[data-frame="band"] { padding-bottom: 6cqmin; border-radius: 1.8cqmin; overflow: hidden; }
.qrc-qr-frame[data-frame="band"]::after { content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 2.6cqmin; background: var(--qrc-accent); }
/* Table number + zone, printed above the code (per-table dynamic data). */
.qrc-qr-table { display: flex; flex-direction: column; align-items: center; gap: .3cqmin; line-height: 1.05; text-align: center; }
.qrc-qr-table-label { color: #17140f; font-weight: 800; font-size: calc(3.6cqmin * var(--qrc-qr-scale)); letter-spacing: .01em; }
.qrc-qr-table-zone { color: #6b6259; font-weight: 600; font-size: calc(2.4cqmin * var(--qrc-qr-scale)); }
/* The code, with an optional restaurant logo dropped into its centre. The logo is a SIBLING of
   [data-qr] (not a child) so the qrcode.js redraw — which clears [data-qr] — never wipes it. */
.qrc-qr-media { position: relative; width: 100%; line-height: 0; }
.qrc-qr-code { width: 100%; line-height: 0; }
.qrc-qr-code img, .qrc-qr-code canvas { width: 100% !important; height: auto !important; display: block; }
/* The code's SLOT, drawn when the design carries a QR but has nothing to encode yet — a platform template
   (a pay link is tenant data, so it is stripped) or a vendor's card before they paste theirs. Same dashed
   language as the background slot, at the code's exact footprint, so the layout reads true. */
/* The two edges of the outline take the ink's two stops (top+left = the gradient's start, right+bottom
   = its end, matching the 135° sweep the code is painted with), so the chosen ink is visible on the one
   surface where it is picked. With no ink set both fall back to the neutral dash. */
.qrc-qr-ph { width: 100%; aspect-ratio: 1; border: 0.6cqmin dashed rgba(23, 20, 15, .3); border-color: var(--qrc-ink-a, rgba(23, 20, 15, .3)) var(--qrc-ink-b, rgba(23, 20, 15, .3)) var(--qrc-ink-b, rgba(23, 20, 15, .3)) var(--qrc-ink-a, rgba(23, 20, 15, .3)); border-radius: 1.4cqmin; }
.qrc-qr-logo { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 24%; aspect-ratio: 1; display: grid; place-items: center; background: #fff; border-radius: 16%; padding: 3%; box-shadow: 0 0 0 .6cqmin #fff; }
.qrc-qrlogo-img { width: 100%; height: 100%; object-fit: contain; display: block; }
.qrc-qrlogo-mark { width: 100%; height: 100%; display: grid; place-items: center; border-radius: 14%; color: #fff; font-weight: 800; font-size: calc(4.4cqmin * var(--qrc-qr-scale)); }
.qrc-qr-caption { color: #17140f; font-weight: 800; font-size: calc(3.2cqmin * var(--qrc-qr-scale)); line-height: 1.1; text-align: center; letter-spacing: .02em; text-transform: uppercase; }

/* Restaurant logo, anchored on the shared grid. --qrc-logo-scale (0.6–2.2, from the 0–10 slider). */
.qrc-logo { --qrc-logo-scale: 1; position: absolute; z-index: 3; display: flex; }
.qrc-logo-img { width: calc(17cqmin * var(--qrc-logo-scale)); height: auto; max-height: calc(17cqmin * var(--qrc-logo-scale)); object-fit: contain; display: block; filter: drop-shadow(0 .4cqh 1.2cqh rgba(0, 0, 0, .28)); }
.qrc-logo-mark { width: calc(14cqmin * var(--qrc-logo-scale)); height: calc(14cqmin * var(--qrc-logo-scale)); display: grid; place-items: center; border-radius: 22%; color: #fff; font-weight: 800; font-size: calc(6cqmin * var(--qrc-logo-scale)); letter-spacing: -.02em; }

/* A free-text heading, anchored on the shared grid — an alternative to featuring a product.
   --qrc-title-scale (0.6–2.2, from the 0–10 slider). */
.qrc-title { --qrc-title-scale: 1; position: absolute; z-index: 3; max-width: 84%; margin: 0; color: var(--qrc-ink); font-weight: 800; font-size: calc(5.6cqmin * var(--qrc-title-scale)); line-height: 1.08; letter-spacing: .01em; }
.qrc.has-bg .qrc-title { color: #fff; text-shadow: 0 .4cqh 1.6cqh rgba(0, 0, 0, .6); }

/* Shared 3x3 anchor grid for the logo, the product and the QR — vertical edge, horizontal edge and the
   matching justification. Bottom-row anchors clear the footer band by --qrc-foot so a low QR and the
   footer keep their spacing instead of colliding. */
.qrc { --qrc-foot: 0cqmin; }
.qrc.has-footer { --qrc-foot: 16cqmin; }
/* Every anchored element also honours a per-element offset nudge via --qrc-ox/--qrc-oy (appended to the
   anchor's own transform, so the direction is consistent no matter which edge it is pinned to). */
.qrc-logo, .qrc-title, .qrc-product, .qrc-qr { --qrc-ox: 0px; --qrc-oy: 0px; }
.qrc-logo[data-pos="top-left"],      .qrc-title[data-pos="top-left"],      .qrc-product[data-pos="top-left"],      .qrc-qr[data-pos="top-left"]      { top: 6cqmin; left: 6cqmin;  transform: translate(var(--qrc-ox), var(--qrc-oy)); align-items: flex-start; text-align: left; }
.qrc-logo[data-pos="top-center"],    .qrc-title[data-pos="top-center"],    .qrc-product[data-pos="top-center"],    .qrc-qr[data-pos="top-center"]    { top: 6cqmin; left: 50%;     transform: translateX(-50%) translate(var(--qrc-ox), var(--qrc-oy));      align-items: center;     text-align: center; }
.qrc-logo[data-pos="top-right"],     .qrc-title[data-pos="top-right"],     .qrc-product[data-pos="top-right"],     .qrc-qr[data-pos="top-right"]     { top: 6cqmin; right: 6cqmin; transform: translate(var(--qrc-ox), var(--qrc-oy)); align-items: flex-end;   text-align: right; }
.qrc-logo[data-pos="middle-left"],   .qrc-title[data-pos="middle-left"],   .qrc-product[data-pos="middle-left"],   .qrc-qr[data-pos="middle-left"]   { top: 50%;    left: 6cqmin;  transform: translateY(-50%) translate(var(--qrc-ox), var(--qrc-oy));      align-items: flex-start; text-align: left; }
.qrc-logo[data-pos="middle-center"], .qrc-title[data-pos="middle-center"], .qrc-product[data-pos="middle-center"], .qrc-qr[data-pos="middle-center"] { top: 50%;    left: 50%;     transform: translate(-50%, -50%) translate(var(--qrc-ox), var(--qrc-oy));  align-items: center;     text-align: center; }
.qrc-logo[data-pos="middle-right"],  .qrc-title[data-pos="middle-right"],  .qrc-product[data-pos="middle-right"],  .qrc-qr[data-pos="middle-right"]  { top: 50%;    right: 6cqmin; transform: translateY(-50%) translate(var(--qrc-ox), var(--qrc-oy));      align-items: flex-end;   text-align: right; }
.qrc-logo[data-pos="bottom-left"],   .qrc-title[data-pos="bottom-left"],   .qrc-product[data-pos="bottom-left"],   .qrc-qr[data-pos="bottom-left"]   { bottom: calc(6cqmin + var(--qrc-foot)); left: 6cqmin;  transform: translate(var(--qrc-ox), var(--qrc-oy)); align-items: flex-start; text-align: left; }
.qrc-logo[data-pos="bottom-center"], .qrc-title[data-pos="bottom-center"], .qrc-product[data-pos="bottom-center"], .qrc-qr[data-pos="bottom-center"] { bottom: calc(6cqmin + var(--qrc-foot)); left: 50%;     transform: translateX(-50%) translate(var(--qrc-ox), var(--qrc-oy));      align-items: center;     text-align: center; }
.qrc-logo[data-pos="bottom-right"],  .qrc-title[data-pos="bottom-right"],  .qrc-product[data-pos="bottom-right"],  .qrc-qr[data-pos="bottom-right"]  { bottom: calc(6cqmin + var(--qrc-foot)); right: 6cqmin; transform: translate(var(--qrc-ox), var(--qrc-oy)); align-items: flex-end;   text-align: right; }

/* Footer band pinned to the foot: an optional "powered by" credit ABOVE an optional disclaimer line. */
.qrc-footer { position: absolute; z-index: 5; left: 0; right: 0; bottom: 0; display: flex; flex-direction: column; align-items: center; gap: 1cqmin; padding: 2.4cqmin 5cqmin 2.8cqmin; text-align: center; }
.qrc-powered { display: inline-flex; align-items: center; gap: 1.2cqmin; font-size: 2.3cqmin; color: var(--qrc-ink-soft); white-space: nowrap; }
.qrc-powered img { height: 3cqmin; width: auto; object-fit: contain; }
.qrc-footer-text { color: var(--qrc-ink-soft); font-size: 2.4cqmin; line-height: 1.25; max-width: 94%; overflow-wrap: break-word; word-break: break-word; }
.qrc.has-bg .qrc-powered, .qrc.has-bg .qrc-footer-text { color: #fff; text-shadow: 0 .2cqh 1cqh rgba(0, 0, 0, .6); }

/* An empty side (no background, no product, no QR) still reads as a card. */
.qrc-blank { position: absolute; inset: 0; display: grid; place-items: center; color: var(--qrc-ink-soft); font-size: 3.4cqmin; opacity: .5; }

/* Management grid on the QR page: each table's FRONT card as a live preview tile with its actions. */
.qrc-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(210px, 1fr)); gap: 20px; }
/* Air between the two labelled entries (Table ordering QR / Payment QR) on the sheet page. */
.qrc-section-gap { margin-top: 28px; }
/* Payment-card tile name (a card grid item is named so several cards are told apart). */
.qrc-tile-name { text-align: center; font-weight: 600; color: var(--ink-800); margin: 0 0 6px; }
.qrc-tile { display: flex; flex-direction: column; gap: 10px; }
/* The card fills its cell in both the legacy .qrc-tile and the shared studio-grid object cell. */
.qrc-tile .qrc, .qm-studio-object .qrc { width: 100%; max-width: none; }
/* Hover (or keyboard focus) flips the tile in 3D to reveal the BACK design; the front sits in flow and
   sets the height, the back is stacked over it pre-rotated so it lands upright when the card turns. */
.qrc-flip { perspective: 1600px; }
.qrc-flip-inner { position: relative; width: 100%; transform-style: preserve-3d; transition: transform .7s cubic-bezier(.2, .75, .25, 1); }
.qrc-flip:hover .qrc-flip-inner,
.qrc-flip:focus-within .qrc-flip-inner { transform: rotateY(180deg); }
.qrc-flip-face { backface-visibility: hidden; -webkit-backface-visibility: hidden; }
/* The front needs its OWN transform: Chromium only applies backface culling to a face that carries a
   3D transform, so a transform-less front would keep painting over the back when the card is flipped. */
.qrc-flip-front { transform: rotateY(0deg); }
.qrc-flip-back { position: absolute; inset: 0; transform: rotateY(180deg); }
.qrc-flip-back .qrc { height: 100%; }
@media (prefers-reduced-motion: reduce) { .qrc-flip-inner { transition: none; } }
/* The printable cards live in a .qm-print-area block that is hidden on screen and shown on paper. */
.qrc-print { display: none; }

/* --------------------------------------------------------------------------
   Batch sheet — twelve table cards to one A4, so a 40-table restaurant prints
   4 sheets instead of 40. It is a third print flow on the same page, built the
   same way the payment run is: a body class picks which hidden block prints,
   and the run swaps its own @page rule into #qm-qr-page (A4 portrait, 10 mm).

   The arithmetic, because a 12-up whose cells do not divide the sheet exactly
   is exactly what makes the cut line drift by the bottom row:

     A4 210 x 297 mm, @page margin 10 mm   ->  page box  190 x 277 mm
     3 columns x 4 rows                    ->  cell   63.333 x 69.25 mm
     3 x 63.333 = 190 mm      4 x 69.25 = 277 mm      (exact, no remainder)

   Pagination itself is done in PHP (array_chunk by 12) and each page is one
   fixed-height block, so nothing can accumulate down the column — the top card
   and the bottom card on a page carry identical margins.

   Every cell renders a REAL .qrc through partials/qr-card-side.php. That is
   not a convenience: the colour-adjust rule near the top of this file is
   scoped to `.qrc, .qrc *`, so a cell built from fresh markup would look
   perfect on screen and drop the theme fill, the full-bleed photo and the
   accent on paper. The cut guides live outside .qrc, so they force their own.
   -------------------------------------------------------------------------- */
.qrc-batch-page { width: 190mm; height: 277mm; display: grid; grid-template-columns: repeat(3, 63.333mm); grid-auto-rows: 69.25mm; overflow: hidden; }
/* Cut guides are hairlines ON the cell edge, drawn as an outline so they occupy no layout space and
   the card keeps the full cell. A border would sit INSIDE the cell instead, and every cut would land
   off-centre by its width. outline-offset pulls the line just inside the edge so the outermost cells
   never paint into the page margin. */
.qrc-batch-cell { position: relative; overflow: hidden; outline: 0.15mm dashed rgba(0, 0, 0, .45); outline-offset: -0.075mm; -webkit-print-color-adjust: exact; print-color-adjust: exact; }

/* --------------------------------------------------------------------------
   Print: one card per page at the design's page shape. @page size (portrait /
   landscape) is emitted by the sheet view; here the card is fitted to the sheet
   and every page forces a break after it (the last one does not, so there is no
   trailing blank sheet).
   -------------------------------------------------------------------------- */
@media print {
  .qrc-noprint { display: none !important; }
  html, body { background: #fff; }
  .qrc-stage { background: #fff; gap: 0; padding: 0; }
  /* On the QR page: hide the management grid, reveal the printable cards. */
  .qrc-manage { display: none !important; }
  .qrc-print { display: block; }
  .qrc-page { break-after: page; page-break-after: always; height: 100vh; }
  .qrc-page:last-child { break-after: auto; page-break-after: auto; }
  .qrc { box-shadow: none; width: auto; height: 96vh; max-width: 96vw; }
  /* Independent print flows on the one page: the default run prints the table cards; a payment card's
     Print adds body.qm-print-pay + marks that card .is-printing, so only that ONE card emits (each has
     its own @page rule swapped in by JS). */
  .qrc-print[data-print="pay"] { display: none; }
  body.qm-print-pay .qrc-print[data-print="table"] { display: none; }
  body.qm-print-pay .qrc-print[data-print="pay"].is-printing { display: block; }

  /* Third flow: the 12-up batch sheet, chosen by body.qm-print-batch through the same mechanism. */
  .qrc-print[data-print="batch"] { display: none; }
  body.qm-print-batch .qrc-print[data-print="table"] { display: none; }
  body.qm-print-batch .qrc-print[data-print="batch"] { display: block; }
  .qrc-batch-page { break-after: page; page-break-after: always; }
  .qrc-batch-page:last-child { break-after: auto; page-break-after: auto; }
  /* The card fills its cell, so a cut piece is a finished card with no white border round it. The
     design's aspect-ratio is an inline style belonging to the one-card-per-sheet flow, hence the
     override; nothing is distorted by it, because every measurement inside the card is in container
     units and simply re-flows to the cell. */
  body.qm-print-batch .qrc-batch-cell > .qrc { width: 100%; height: 100%; max-width: none; aspect-ratio: auto !important; box-shadow: none; }
}


/* ==========================================================================
   QR CARD DESIGNER - vendor QR card form (was inline in vendor/qr-card-form.php)
   ========================================================================== */
  /* Settings: the controls flow across the full-width card, each sized to its job — selects grow to
     share the row, the colour swatches stay compact squares, the corner pad keeps its 2x2, and the
     Powered-by switch gets room. On phones/tablets the whole strip collapses behind a "Settings"
     tap-toggle, reusing the Orders filter-bar mechanism (the same .qm-of-* classes / :has() switch). */
  .qrcard-set-grid { display: flex; flex-wrap: wrap; gap: 14px 18px; align-items: flex-end; }
  .qrcard-set-grid > div { display: flex; flex-direction: column; gap: 6px; flex: 1 1 150px; min-width: 0; }
  .qrcard-set-grid .form-label { margin-bottom: 0; }
  .qrcard-set-grid .form-select { height: 42px; }
  /* Colour swatches: a compact square, not a stretched bar. */
  .qrcard-set-grid > div:has(> .qm-color-swatch-sq) { flex: 0 0 auto; }
  .qrcard-set-grid .qm-color-swatch-sq { width: 72px; height: 42px; }
  /* Corner-radius pad: self-sized, no dead cell space around it. */
  .qrcard-set-grid > div:has(.qrcard-corners) { flex: 0 0 auto; }
  /* Powered-by: a bit more room than before so the label sits on one line, without stretching the
     switch away from it (no flex-grow — the selects absorb the leftover width instead). */
  .qrcard-set-grid > .qrcard-set-switch { flex: 0 0 auto; flex-direction: row; align-items: center; height: 42px; }
  .qrcard-set-switch .qm-switch-row > span { white-space: nowrap; }
  .qrcard-set-switch .qm-switch-row { width: 100%; margin: 0; }

  /* Balanced two-card row: controls | live preview. */
  .qrcard-editor { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 20px; align-items: start; }
  @media (max-width: 992px) { .qrcard-editor { grid-template-columns: 1fr; } }

  /* Front / Back tab bar — sits inside the controls card so it never floats. */
  .qrcard-tabs { display: flex; justify-content: flex-end; gap: 4px; border-bottom: 1px solid var(--line); margin: -4px 0 18px; }
  .qrcard-tabs button { border: 0; background: none; border-bottom: 2px solid transparent; margin-bottom: -1px; padding: 10px 20px; font-weight: 600; font-size: 14px; color: var(--ink-500); cursor: pointer; display: inline-flex; align-items: center; gap: 8px; }
  .qrcard-tabs button:hover { color: var(--ink-800); }
  .qrcard-tabs button.is-on { color: var(--qm-primary); border-bottom-color: var(--qm-primary); }

  .qrcard-controls[hidden] { display: none; }
  .qrcard-controls { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; align-items: start; }
  @media (max-width: 560px) { .qrcard-controls { grid-template-columns: 1fr; } }
  .qrcard-col { min-width: 0; display: flex; flex-direction: column; gap: 16px; }
  .qrcard-block { border: 1px solid var(--line); border-radius: var(--r-md); padding: 14px; }
  .qrcard-block > .qm-ops-sub { margin: 0 0 10px; font-weight: 600; color: var(--ink-700); }

  /* Live-preview card: a dark stage so the printed card reads clearly, sticky beside the controls. */
  .qrcard-preview-card { position: sticky; top: 84px; }
  .qrcard-preview-head { text-align: center; margin: 0 0 12px; font-weight: 600; color: var(--ink-700); }
  .qrcard-preview[hidden] { display: none; }
  /* Thin, square-cornered stage — it stands in for the sheet of paper. */
  .qrcard-frame { background: #211d18; overflow: hidden; width: 100%; aspect-ratio: 1 / 1.414; padding: 6px; }
  .qrcard-frame iframe { width: 100%; height: 100%; border: 0; display: block; }

  /* Background presets grid. */
  .qrcard-creatives { display: grid; grid-template-columns: repeat(auto-fill, minmax(44px, 1fr)); gap: 6px; }
  .qrcard-creatives label { border-radius: var(--r-sm); overflow: hidden; cursor: pointer; aspect-ratio: 1; position: relative; }
  .qrcard-creatives input { position: absolute; opacity: 0; }
  .qrcard-creatives input:checked + img, .qrcard-creatives input:checked + .qrcard-cre-none { outline: 3px solid var(--qm-primary); outline-offset: -3px; }
  .qrcard-creatives img { width: 100%; height: 100%; object-fit: cover; display: block; }
  .qrcard-cre-none { display: grid; place-items: center; height: 100%; background: var(--surface-2, #f0ede7); font-size: 10px; color: var(--ink-500); }

  .qrcard-hideable[hidden] { display: none; }
  .tv-switch-group { border: 1px solid var(--line); border-radius: var(--r-md); overflow: hidden; }
  .tv-switch-group .qm-switch-row { border: 0; border-bottom: 1px solid var(--line); margin: 0; padding: 8px 12px; }
  .tv-switch-group .qm-switch-row:last-child { border-bottom: 0; }
  .tv-posgrid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 4px; width: 96px; }
  .tv-posgrid button { aspect-ratio: 1; border: 1px solid var(--line); background: transparent; border-radius: var(--r-sm); cursor: pointer; padding: 0; transition: border-color var(--t-fast), background var(--t-fast); }
  .tv-posgrid button:hover { border-color: var(--qm-primary); }
  .tv-posgrid button.is-on { background: var(--qm-primary); border-color: var(--qm-primary); box-shadow: inset 0 0 0 2px #fff; }
  .tv-size-out { min-width: 20px; text-align: center; font-weight: 700; font-size: 13px; color: var(--ink-600); }
  .qrcard-row { display: flex; align-items: center; gap: 10px; }
  /* QR ink swatches sit inline inside the QR block, at the same compact square the settings strip uses
     — without this they inherit .form-control's full width and stretch across the column. */
  .qrcard-block .qm-color-swatch-sq { flex: 0 0 auto; width: 72px; height: 42px; }
  .qrcard-actions-right { display: flex; justify-content: flex-end; gap: 10px; margin-top: 18px; }
  /* Pay link + its Save button on one row: the field takes the space, the button keeps its natural
     width (min-width:0 lets the field shrink just enough instead of pushing the button to a new line). */
  .qrcard-linkrow { display: flex; gap: 10px; align-items: center; }
  .qrcard-linkrow .form-control { flex: 1 1 auto; min-width: 0; }
  .qrcard-linkrow .qm-btn { flex: 0 0 auto; white-space: nowrap; }
  .qrcard-block .filepond--root { margin-bottom: 0; }
  /* 4-corner radius control (2x2 grid mirroring the card's corners) — compact so it sits level with
     the row's 42px controls instead of towering over them. */
  .qrcard-corners { display: grid; grid-template-columns: 1fr 1fr; gap: 4px; width: 104px; height: 42px; }
  .qrcard-corners input { width: 100%; min-height: 0; padding: 0 4px; border: 1px solid var(--line); border-radius: var(--r-sm); text-align: center; font-size: 11.5px; }
  /* Per-element offset nudge inputs — bare number inputs (like the corner fields) so the app's
     .form-control spinner reset never applies and the native up/down arrows stay clickable. */
  .qrcard-off { width: 84px; padding: 7px 8px; border: 1px solid var(--line); border-radius: var(--r-sm); text-align: center; font-size: 13px; background: var(--surface, #fff); color: var(--ink-900); }
  .qrcard-off:focus { outline: 0; border-color: var(--qm-primary); }
  /* Cropper.js modal. */
  .qrc-crop-ov { position: fixed; inset: 0; z-index: 3000; background: rgba(0, 0, 0, .62); display: flex; align-items: center; justify-content: center; padding: 20px; }
  .qrc-crop-box { background: var(--surface, #fff); border-radius: var(--r-md); padding: 16px; width: min(680px, 96vw); display: flex; flex-direction: column; gap: 14px; }
  .qrc-crop-stage { max-height: 70vh; overflow: hidden; }
  .qrc-crop-stage img { max-width: 100%; display: block; }
  .qrc-crop-actions { display: flex; justify-content: flex-end; gap: 10px; }

  /* Phones/tablets: collapse the settings strip behind the shared "Settings" tap-toggle — the exact
     Orders filter-bar dropdown. Its .qm-of-toggle / .qm-of-open-cb / chevron styling lives in app.css
     (reused, not duplicated); here we only hide the cells while closed. The toggle is a <label> and
     the checkbox an <input>, so "> div" targets the setting cells alone and leaves the toggle shown. */
  @media (max-width: 1024px) {
    .qrcard-set-grid:has(.qm-of-open-cb:not(:checked)) > div { display: none; }
  }
