/* ── Scanner ───────────────────────────────────────── */
.scan-trigger {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 14px;
  margin-bottom: 22px;
  flex-wrap: wrap;
}
.scan-trigger .btn-scan {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  background: var(--bg-card);
  border: 1px solid var(--accent-dim);
  color: var(--accent);
  padding: 10px 22px;
  border-radius: 6px;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  transition: all 0.25s;
  letter-spacing: 0.5px;
}
.scan-trigger .btn-scan:hover {
  background: rgba(245, 158, 11, 0.1);
  border-color: var(--accent);
  box-shadow: 0 0 20px rgba(245, 158, 11, 0.15);
  transform: translateY(-1px);
}
.scan-trigger .btn-scan .scan-icon { font-size: 18px; line-height: 1; }
.scan-trigger .scan-reference {
  display: flex;
  align-items: center;
  gap: 10px;
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 6px 10px;
}
.scan-trigger .scan-reference .ref-codes {
  font-size: 11px;
  color: var(--accent);
}
.scan-trigger .scan-reference .ref-summary {
  font-size: 11px;
  color: var(--text-dim);
}
.scan-trigger .scan-reference .ref-marks {
  font-size: 11px;
  color: var(--accent);
}
/* SC-WORDS-ENTRY: the words box under the three capture buttons. The box
   spans the whole wrapping row, so it sits on its own line. Use Words and
   Open stand 44 pixels tall, the touch target height. */
.scan-trigger .btn-use-words { min-height: 44px; }
.scan-trigger .btn-use-words.active {
  background: rgba(245, 158, 11, 0.1);
  border-color: var(--accent);
}
.scan-trigger .words-entry {
  flex-basis: 100%;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 8px;
}
.scan-trigger .words-entry .btn-scan { min-height: 44px; }
.words-entry-input {
  flex: 1 1 160px;
  min-width: 0;
  padding: 12px 14px;
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 6px;
  color: var(--text-primary);
  font-family: var(--font-body);
  font-size: 16px;
  transition: border-color 0.2s;
}
.words-entry-input::placeholder { color: var(--text-dim); }
.words-entry-input:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 8px rgba(245, 158, 11, 0.1);
}
.words-entry-input.words-entry-input-bad { border-color: var(--danger); }
.words-entry-error {
  flex-basis: 100%;
  text-align: center;
  color: var(--danger);
  font-size: 12px;
  line-height: 1.4;
}
.scanner-overlay {
  position: fixed;
  inset: 0;
  height: 100vh;
  height: 100dvh;
  z-index: 300;
  background: var(--bg-deep);
  display: none;
  flex-direction: column;
}
.scanner-overlay.active {
  display: flex;
  animation: viewFadeIn 0.3s ease;
}
/* SC-CAPTURE-RESKIN: the handwriting face for the notepad panel below the
   camera view -- the heading, the SIGNAL/TRACE word, and the count. Times
   and icons use the game's normal faces. The file is Caveat (owner's pick
   2026-09-02), a variable-weight TrueType under the SIL Open Font License;
   the licence text sits beside it as assets/fonts/OFL-Caveat.txt.
   font-display swap draws the fallback stack until the file arrives, so
   the panel never shows blank text. tests/capture-notepad.test.js checks
   that the file this rule names is on disk. */
@font-face { font-family: "StarCode Hand"; src: url("../assets/fonts/hand.ttf") format("truetype"); font-weight: 400 700; font-style: normal; font-display: swap; }
:root { --font-hand: "StarCode Hand", "Segoe Print", "Bradley Hand", "Comic Sans MS", cursive; }
/* SC-CAPTURE-RESKIN: no header band. The close control floats over the
   top-right corner of the camera view (the flashlight floats top-left,
   css/cosmos-controls.css .scanner-torch): a 56px round hit area, above
   every other viewfinder layer (photo 2, boxes 3, rotate 4, torch 5,
   zoom 6). The inset is max(10px, safe-area inset): the safe-area value is
   0 until index.html's viewport meta opts into viewport-fit=cover (an
   app-wide decision no single screen makes), so today the inset is 10px. */
.scanner-close {
  position: absolute;
  top: max(10px, env(safe-area-inset-top));
  right: max(10px, env(safe-area-inset-right));
  z-index: 7;
  width: 56px;
  height: 56px;
  padding: 0;
  border-radius: 50%;
  border: 1px solid rgba(255, 255, 255, 0.28);
  background: rgba(4, 8, 16, 0.62);
  color: #f1f5f9;
  font-size: 32px;
  line-height: 1;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: border-color 0.2s, color 0.2s;
}
.scanner-close:hover,
.scanner-close:active {
  border-color: var(--accent);
  color: var(--accent);
}
.scanner-body {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-height: 0;
  overflow: hidden;
}
.scanner-viewfinder {
  position: relative;
  flex: 1;
  min-height: 0;
  background: #000;
  display: flex;
  align-items: center;
  justify-content: center;
  /* DCOSMOS-SCANZOOM: a zoomed still magnifies past the frame; the frame
     crops it like a camera moving closer instead of spilling over the
     controls around it. */
  overflow: hidden;
}
/* The still image and the detection-box layer zoom together about the
   same center, so every box stays glued to its code at any zoom. */
.scanner-viewfinder .scanner-captured-img,
.scanner-viewfinder .barcode-box-layer {
  transform-origin: center center;
}
.scanner-viewfinder video {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.scanner-viewfinder .scanner-captured-img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
  background: #000;
  z-index: 2;
}
.scanner-reticle {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 220px;
  height: 140px;
  transform: translate(-50%, -50%);
  pointer-events: none;
}
.scanner-reticle::before,
.scanner-reticle::after {
  content: "";
  position: absolute;
  border: 2px solid var(--accent);
}
.scanner-reticle::before {
  top: 0; left: 0;
  width: 30px; height: 30px;
  border-right: none; border-bottom: none;
}
.scanner-reticle::after {
  bottom: 0; right: 0;
  width: 30px; height: 30px;
  border-left: none; border-top: none;
}
.scanner-reticle .corner-tl,
.scanner-reticle .corner-br {
  position: absolute;
  width: 30px;
  height: 30px;
  border: 2px solid var(--accent);
}
.scanner-reticle .corner-tl {
  top: 0; right: 0;
  border-left: none; border-bottom: none;
}
.scanner-reticle .corner-br {
  bottom: 0; left: 0;
  border-right: none; border-top: none;
}
/* Rotate button (photo mode only): the same 56px round shape as the close
   control, in the top-left corner of the view, above the displayed photo
   (z 2) and the flash frame (z 3). That corner is free in photo mode: the
   flashlight (also top-left) shows only while a live camera track reports a
   torch, and photo mode has no camera. The photo arrows (.btn-photo-nav)
   sit at mid-height, and the camera view is never shorter than 322px (the
   notepad cap below), so an arrow starts at 133px or lower and the rotate
   control, ending at 66px, never reaches it. tests/capture-notepad.test.js
   checks those numbers. */
.btn-rotate-photo {
  position: absolute;
  top: max(10px, env(safe-area-inset-top));
  left: max(10px, env(safe-area-inset-left));
  z-index: 4;
  width: 56px;
  height: 56px;
  padding: 0;
  background: rgba(8, 14, 26, 0.55);
  border: 1px solid var(--border);
  border-radius: 50%;
  color: var(--text-dim);
  font-size: 30px;
  line-height: 1;
  cursor: pointer;
  transition: all 0.2s;
}
.btn-rotate-photo:hover,
.btn-rotate-photo:active {
  border-color: var(--accent);
  color: var(--accent);
}
.btn-rotate-photo[hidden] { display: none; }
/* Photo navigation arrows (photo mode, 2+ photos only): same ghost style as
   the rotate button, floated mid-left / mid-right over the photo. */
.btn-photo-nav {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  z-index: 4;
  width: 40px;
  height: 56px;
  padding: 0;
  background: rgba(8, 14, 26, 0.55);
  border: 1px solid var(--border);
  border-radius: 4px;
  color: var(--text-dim);
  font-size: 26px;
  line-height: 1;
  cursor: pointer;
  transition: all 0.2s;
}
.btn-photo-prev { left: 10px; }
.btn-photo-next { right: 10px; }
.btn-photo-nav:hover,
.btn-photo-nav:active {
  border-color: var(--accent);
  color: var(--accent);
}
.btn-photo-nav:disabled {
  opacity: 0.35;
  cursor: default;
  border-color: var(--border);
  color: var(--text-dim);
}
.btn-photo-nav[hidden] { display: none; }
/* "2 / 4" position chip (photo mode, 2+ photos only): bottom-left corner of
   the viewfinder, monospace and dim — information, not a control. */
.photo-counter {
  position: absolute;
  left: 10px;
  bottom: 10px;
  z-index: 4;
  padding: 3px 8px;
  background: rgba(8, 14, 26, 0.55);
  border-radius: 4px;
  font-family: var(--font-data);
  font-size: 11px;
  color: var(--text-dim);
  pointer-events: none;
}
.photo-counter[hidden] { display: none; }
/* DCOSMOS-SCANZOOM (owner 2026-08-23, SC-FB16): the still-image scan zoom
   slider, overlaid across the viewfinder's bottom edge -- right above
   where scan results appear below the frame. Shows only while a still
   image is displayed (js/scanner-zoom.js toggles hidden). */
.scan-zoom {
  position: absolute;
  left: 50%;
  bottom: 10px;
  transform: translateX(-50%);
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 12px;
  border-radius: 999px;
  background: rgba(5, 8, 14, 0.78);
  border: 1px solid rgba(255, 255, 255, 0.12);
  z-index: 6;
}
.scan-zoom[hidden] { display: none; }
.scan-zoom-label {
  font-size: 11px;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--text-dim);
  white-space: nowrap;
}
.scan-zoom input[type="range"] { width: 140px; }
.scan-zoom-readout {
  font-size: 12px;
  color: var(--text-primary);
  min-width: 44px;
  text-align: right;
  font-variant-numeric: tabular-nums;
}
/* SC-CAPTURE-RESKIN: the notebook footer under the camera view -- a flex
   sibling of the viewfinder, never an overlay, so it cannot cover the
   reticle. It holds the plate image (assets/ui/notebook.png, the notepad
   in a gloved hand; the same plate as the ship's notebook,
   css/cosmos-notebook.css) and the page box on its paper with the heading,
   the list and Done. js/capture-notepad.js layoutCaptureNotepad places both
   with js/notebook-plate.js notebookFrame for the footer's size; the plate's
   hand and arm run off the footer's bottom and right edges and overflow
   hidden clips them. The footer's height is the smaller of 560px and
   (screen height - 322px), so the camera view always keeps 322px: the 190px
   phone reticle (css/cosmos-scanfx.css) plus 66px above and below it for the
   56px corner controls and their 10px inset. The paper never gets narrower
   than 230px (js/notebook-plate.js MODES.capture.minPaperW). On a phone the
   sheet is 88% of the footer's width with the ring row at the footer's top
   (the owner's mockup, assets/textures/capture_screen_mockup.jpg); it runs
   off the footer's bottom edge and the page box is clipped to the part that
   shows, so the list inside scrolls sooner. The page box arrives already
   inset from the sheet's side edges and the paper's top, so it has no side or
   top padding. The footer keeps
   its full height even with nothing captured: the notepad in the hand is
   always on screen, and the camera view keeps its 322px above it. */
.capture-notepad {
  --ink: #1f2a44;
  --ink-dim: #5c657a;
  position: relative;
  flex-shrink: 0;
  height: min(560px, calc(100vh - 322px));
  height: min(560px, calc(100dvh - 322px));
  max-height: min(560px, calc(100vh - 322px));
  max-height: min(560px, calc(100dvh - 322px));
  overflow: hidden;
  background: var(--bg-deep);
  color: var(--ink);
}
.capture-notepad .notebook-plate {
  position: absolute;
  z-index: 0;
  display: block;
  max-width: none;
  pointer-events: none;
  user-select: none;
}
/* The page box on the paper: a column of the heading row, the list and the Done row. */
.capture-notepad-page {
  position: absolute;
  z-index: 1;
  display: flex;
  flex-direction: column;
  box-sizing: border-box;
  padding: 0 0 calc(8px + env(safe-area-inset-bottom));
  overflow: hidden;
}
/* The heading row: the word FINDINGS in the handwriting face (level: the page
   warp carries the lean), and the "N items" count beside it. */
.capture-notepad-head {
  flex-shrink: 0;
  display: flex;
  align-items: baseline;
  gap: 10px;
  margin: 0 0 10px;
}
.capture-notepad-title {
  font-family: var(--font-hand);
  font-size: 24px;
  line-height: 1;
  letter-spacing: 1px;
  color: var(--ink);
  border-bottom: 2px solid var(--ink);
  padding-bottom: 2px;
}
.capture-count {
  font-family: var(--font-hand);
  font-size: 16px;
  color: var(--ink-dim);
  white-space: nowrap;
}
/* Inside the footer the list takes the paper's height and scrolls past it;
   the base rule's four-line cap (css/cosmos-scan-results.css) is lifted. */
.capture-notepad .scanner-results { flex: 1 1 auto; max-height: none; min-height: 48px; }
/* Bottom row: Done on the right. */
.capture-notepad-foot {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 12px;
  margin-top: 10px;
}
/* Done sits on the paper: the game's amber button with an ink outline and a
   short drop edge, 44px tall. Hidden until the first catch
   (js/scanner-state.js markCaptured). */
.capture-notepad-foot .btn-primary {
  min-height: 44px;
  padding: 10px 26px;
  font-size: 15px;
  font-weight: 700;
  letter-spacing: 1.5px;
  border: 1px solid rgba(60, 40, 10, 0.4);
  box-shadow: 0 2px 0 rgba(60, 40, 10, 0.25);
}
.capture-notepad-foot .btn-primary:hover {
  box-shadow: 0 2px 0 rgba(60, 40, 10, 0.25), 0 0 16px rgba(245, 158, 11, 0.35);
}
