/* The in-app QR tag scanner overlay (public/assets/js/scan-tag.js).
   Body-level, on EVERY authenticated page, exactly like photo-lightbox.css.

   ⛔ THESE RULES USED TO LIVE IN inspection_show.css AND THAT WAS A REAL DEFECT,
      not untidiness. The markup ships from layout/app.php on every authenticated
      page while that stylesheet is linked only on inspection-show, so anywhere else
      the modal computed `position: static; z-index: auto; display: block` and, once
      opened, rendered as bare inline text pushed into the page flow. Confirmed in a
      browser on the dashboard. A stylesheet's load gate must match its markup's.

   ── THE Z-INDEX, CHOSEN RATHER THAN INHERITED ────────────────────────────────
   The ladder is not what it looks like from any single file, so here it is once:

     2110  .modal            >= 1367px          (desktop.css, media-gated)
     2000  .modal            769px .. 1366px    (tablet.css, media-gated)
     2130  .modal            <= 768px           (style.css, the ungated base)
     2125  .modal-backdrop   style.css
     2140  .label-modal      inspection_show.css
     2200  .fss-cap.is-capturing   Fire Stopping capture, portalled to <body>
     2210  .fss-pen-modal    (see fire-stopping-survey-show.css — raised for that
                              overlay; it inherited plain .modal and opened BEHIND it)
     2600  .photo-lightbox   every page
     2610  .scan-modal       this file (reasoning below)
     2620  .iac              in-app camera (in-app-camera.css) — opened from Fire Stopping
                             capture and the penetration modal, so it must clear 2210
     9999  toasts
    10000  .fd-confirm-sheet  window.fdConfirm() (utils/confirm-sheet.js, style.css) — the
                             app's own OK/Cancel question, opened over any of the above

   ⚠ `.modal` HAS THREE VALUES, NOT TWO. The plan for this work recorded "2110 above
   1367px and 2130 everywhere else"; measured in a browser at eight widths, `tablet.css`
   also sets it to **2000** across 769–1366px, which is every tablet and most laptops.
   All three are pinned by the nightly render spec so the next person does not have to
   re-derive it. It changes nothing here — 2610 clears all three — but a choice made
   against a two-value ladder was being made against the wrong facts.

   `.scan-modal` is 2610 — ABOVE the photo lightbox, deliberately, and that is the
   only interesting part of the choice:

     • It must clear 2200. The scanner is openable from inside Fire Stopping capture,
       whose root is portalled to <body> at 2200; anything below that opens invisibly
       behind a full-viewport overlay with the camera running.
     • Clearing 2600 is the deliberate part. The lightbox and the scanner are not
       expected to be open together — but if they ever are, the scanner is the one
       holding a live camera stream that the user just asked for, and burying a
       running camera under a still image is the worse of the two failures. It stays
       below toasts so a sync or error toast is still readable over it.

   Do not raise this to "make it win" against something new. Add the new thing to the
   ladder above, then decide. */

.scan-modal {
    position: fixed;
    inset: 0;
    display: none;
    align-items: center;
    justify-content: center;
    /* No padding on the container: the dialog is already width: 92vw, and 92vw plus
       two 16px gutters overflows the viewport below 400px — a horizontal scrollbar on
       every phone the moment the scanner opens. */
    z-index: 2610;
}

.scan-modal.is-open {
    display: flex;
}

/* A dedicated overlay element rather than a background on the container.
   Fire Stopping had this and Fire Door did not: with the scrim painted on the
   container, "click outside to close" can only be expressed as
   `event.target === container`, which fails the moment anything is layered over it. */
.scan-modal__overlay {
    position: absolute;
    inset: 0;
    background: rgba(15, 23, 42, 0.6);
}

.scan-modal__dialog {
    position: relative;
    z-index: 1;
    /* A phone in landscape, or an iPhone SE under Safari's bars, is ~390-550px tall
       and the dialog with the bind panel open is ~650px. Without these the save
       buttons sat below the screen with no way to reach them. */
    max-height: calc(100vh - 16px);
    max-height: calc(100dvh - 16px);
    overflow-y: auto;
    overscroll-behavior: contain;
    background: var(--card, #ffffff);
    border-radius: 14px;
    padding: 16px;
    max-width: 420px;
    width: 92vw;
    box-shadow: 0 18px 48px rgba(0, 0, 0, 0.2);
}

/* The video and what sits over it: the barcode band and the torch. */
.scan-modal__stage {
    position: relative;
}

.scan-modal__video {
    display: block;
    width: 100%;
    /* A FIXED height with object-fit: cover, not a max-height with the default contain.
       An iPhone gives an UPRIGHT (portrait) stream; contained in a wide, short box it
       showed as a narrow sliver in the middle, too small to aim a barcode at. Covered,
       the whole box is camera, and what shows vertically is close to the band
       scan-tag.js reads barcodes from. */
    height: 260px;
    height: min(260px, 35dvh);
    object-fit: cover;
    background: #0f172a;
    border-radius: 10px;
}

/* Where to hold a barcode: across the middle. scan-tag.js reads 1D codes from rows
   close to the centre of the frame, so the red line is the aim. A guide, not a crop:
   QR codes and Data Matrix are read from the whole frame. */
.scan-modal__guide {
    position: absolute;
    left: 6%;
    right: 6%;
    top: 22%;
    bottom: 22%;
    border: 2px solid rgba(255, 255, 255, 0.7);
    border-radius: 8px;
    pointer-events: none;
}

.scan-modal__guide::after {
    content: "";
    position: absolute;
    left: 4%;
    right: 4%;
    top: 50%;
    height: 2px;
    margin-top: -1px;
    background: rgba(239, 68, 68, 0.85);
}

.scan-modal__torch {
    position: absolute;
    right: 8px;
    bottom: 8px;
    min-height: 36px;
    padding: 0 14px;
    border: 0;
    border-radius: 999px;
    background: rgba(15, 23, 42, 0.72);
    color: #ffffff;
    font-size: 13px;
    font-weight: 600;
}

.scan-modal__torch[aria-pressed="true"] {
    background: #fbbf24;
    color: #0f172a;
}

.scan-modal__status {
    margin: 8px 0 4px;
}

/* DIAGNOSTICS — COMMENTED OUT 2026-09-13 (owner), kept for later. Re-enable with the markup
   in layout/app.php and the code in scan-tag.js (search "DIAGNOSTICS").

.scan-modal__diagview {
    display: block;
    width: 100%;
    height: auto;
    margin: 0 0 6px;
    background: #0f172a;
    border-radius: 4px;
}

.scan-modal__diag {
    margin: 0 0 4px;
    font-size: 11px;
    line-height: 1.35;
    color: var(--text-muted, #6b6458);
    word-break: break-word;
}
*/

/* Type the code. 16px is the iOS zoom guard, as on the bind picker below. */
.scan-modal__manual {
    margin-top: 10px;
}

.scan-modal__manualrow {
    display: flex;
    gap: 8px;
}

.scan-modal__manualrow .f-input {
    flex: 1 1 auto;
    min-width: 0;
    font-size: 16px;
    min-height: 44px;
}

.scan-modal__manualrow .btn {
    flex: 0 0 auto;
    min-height: 44px;
}

/* While the bind panel asks its question, the type box would be a second, competing
   answer. A class rather than [hidden], so scan-tag.js owns one switch. */
.scan-modal.is-binding .scan-modal__manual {
    display: none;
}

.scan-modal__header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 8px;
}

/*
  THE BIND PANEL — filled and shown by a page through firedoorScanner.showBindPanel().

  Hidden with the [hidden] attribute, which style.css makes !important, so no
  display rule here can fight it. Revealed by clearing the attribute, never by
  setting display.

  ⚠ 16px on the select is the iOS zoom guard, not a taste choice: anything
  smaller makes Safari zoom the whole page when the picker takes focus, and this
  panel exists to be used one-handed at a door.
*/
.scan-modal__bind {
    margin-top: 12px;
    padding-top: 12px;
    border-top: 1px solid var(--border, #e2e8f0);
}

.scan-modal__bindcode {
    margin: 0 0 8px;
    font-size: 14px;
}

.scan-modal__bindcode code {
    /* A customer code can be 120 characters and must not widen the dialog. */
    word-break: break-all;
}

.scan-modal__bind .f-input {
    width: 100%;
    font-size: 16px;
    min-height: 44px;
}

.scan-modal__bindactions {
    display: flex;
    gap: 8px;
    justify-content: flex-end;
    margin-top: 12px;
}

.scan-modal__bindactions .btn {
    min-height: 44px;
}

/*
  "THIS DOOR" — the choices a scan from the dashboard found (scan-a-door plan, Stage 4),
  filled by door-lookup.js through firedoorScanner.showChoicePanel(). While it shows, the
  camera is paused and the stage, hint and type box step aside: a scan has answered, and
  "Scan another door" brings them back. Hidden with [hidden], like the bind panel.
*/
.scan-modal.is-choosing .scan-modal__stage,
.scan-modal.is-choosing .scan-modal__manual,
.scan-modal.is-choosing [data-scan-hint],
.scan-modal.is-choosing .scan-modal__status {
    display: none;
}

.scan-modal__choice {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.scan-modal__choicecode {
    margin: 0;
    font-size: 12.5px;
    font-weight: 600;
    color: var(--success, #1e7a45);
    word-break: break-all;
}

.scan-modal__choicetitle {
    margin: 0;
    font-family: var(--font-display, inherit);
    font-size: 19px;
    font-weight: 700;
    line-height: 1.25;
    color: var(--ink, #1a1815);
}

.scan-modal__choicesub {
    margin: 0 0 4px;
}

.scan-modal__choicelist {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.scan-modal__choiceitem {
    display: flex;
    align-items: center;
    gap: 12px;
    min-height: 60px;
    padding: 10px 12px;
    border: 1px solid var(--rule-strong, rgba(26, 24, 21, 0.14));
    border-radius: 12px;
    background: var(--surface-card, #ffffff);
    color: var(--ink, #1a1815);
    text-decoration: none;
}

.scan-modal__choiceitem:hover,
.scan-modal__choiceitem:focus-visible {
    border-color: var(--ink, #1a1815);
}

.scan-modal__choicedot {
    flex: 0 0 auto;
    width: 10px;
    height: 10px;
    border-radius: 50%;
    background: var(--ink-4, #9a9188);
}

.scan-modal__choiceitem[data-tone="progress"] .scan-modal__choicedot { background: var(--accent, #c49510); }
.scan-modal__choiceitem[data-tone="fail"] .scan-modal__choicedot { background: var(--danger, #b03030); }
.scan-modal__choiceitem[data-tone="info"] .scan-modal__choicedot { background: var(--info, #2563a8); }
.scan-modal__choiceitem[data-tone="await"] .scan-modal__choicedot {
    background: transparent;
    box-shadow: inset 0 0 0 2px var(--ink-3, #6b6458);
}

.scan-modal__choicetext {
    display: flex;
    flex-direction: column;
    min-width: 0;
}

.scan-modal__choicelabel {
    font-size: 14px;
    font-weight: 600;
    line-height: 1.3;
}

.scan-modal__choicemeta {
    font-size: 12px;
    color: var(--ink-3, #6b6458);
    line-height: 1.35;
}

.scan-modal__choicego {
    margin-left: auto;
    flex: 0 0 auto;
    font-size: 12.5px;
    font-weight: 600;
    white-space: nowrap;
}

.scan-modal__choiceagain {
    min-height: 46px;
    margin-top: 4px;
}

/* A page handler's refusal ("No door in your workspace has this code", "This code isn't
   on a door you have access to") — scan-tag.js sets data-tone="warn" on the status line
   for it, and clears it on the next ordinary status. */
.scan-modal__status[data-tone="warn"] {
    margin: 10px 0 6px;
    padding: 10px 12px;
    border-radius: 10px;
    border: 1px solid color-mix(in srgb, var(--accent, #c49510) 30%, transparent);
    background: color-mix(in srgb, var(--accent, #c49510) 9%, var(--surface-card, #ffffff));
    color: var(--ink-2, #3d3a34);
    font-size: 13px;
}
