/* ===========================================================================
   scan.css — the card scanner (scan.js): a full-screen camera with a
   card-shaped guide, a shutter, and a sheet of matches that slides up.

   The camera chrome is dark in either theme, as a camera's always is: white
   controls over the picture, on scrims that keep them readable over any
   table. The sheet and the problem card are the app's own surfaces and follow
   the theme.

   Layout, by custom property on .scan:
     --scan-top   height of the top bar (close, game, torch, keep scanning)
     --scan-bar   height of the bottom controls (photo, shutter, auto) — 0 in
                  landscape, where they are a column down the right instead
     --scan-side  width of that column
   The guide centres itself in what is left.
   =========================================================================== */

.scan {
  --scan-top: calc(60px + env(safe-area-inset-top, 0px));
  --scan-bar: calc(136px + env(safe-area-inset-bottom, 0px));
  --scan-side: 0px;
  --scan-glass: rgb(16 18 24 / .58);
  --scan-line: rgb(255 255 255 / .2);
  position: fixed; inset: 0; z-index: 78;
  overflow: hidden;
  background: #000; color: #fff;
  color-scheme: dark;
  outline: none;
  animation: scan-fade var(--t-2) var(--ease-out);
  transition: opacity var(--t-2) var(--ease-out);
  -webkit-tap-highlight-color: transparent;
}
.scan.is-out { opacity: 0; pointer-events: none; }

/* ------------------------------------------------------------------ picture */
.scan-stage { position: absolute; inset: 0; }
.scan-video, .scan-still {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; background: #000;
}
/* A photo is shown whole: the reader looks for the card in all of it. */
.scan-still { object-fit: contain; }
.scan.is-photo .scan-frame { visibility: hidden; }

/* The guide: centred in what the bars leave, as big as fits, card-shaped. */
.scan-guide {
  position: absolute;
  top: var(--scan-top); bottom: var(--scan-bar); left: 0; right: var(--scan-side);
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 12px;
  pointer-events: none;
}
.scan-frame {
  --steady: 0;
  position: relative; flex: none;
  height: min(calc(100% - 58px), calc((100vw - var(--scan-side) - 56px) * 88 / 63));
  aspect-ratio: 63 / 88;
  /* A card's 3mm corners: 3/63 across, 3/88 down. */
  border-radius: 4.8% / 3.4%;
  /* Everything outside the card is dimmed, so the eye goes to the frame. */
  box-shadow: 0 0 0 100vmax rgb(0 0 0 / .46);
  outline: 1px solid rgb(255 255 255 / .28);
  transition: outline-color var(--t-2) var(--ease-out);
}
.scan-corner {
  position: absolute; width: 13%; aspect-ratio: 1;
  border: 0 solid color-mix(in srgb, var(--accent) calc(var(--steady) * 100%), #fff);
  transition: border-color var(--t-1) linear, transform var(--t-2) var(--ease-out);
  filter: drop-shadow(0 1px 3px rgb(0 0 0 / .5));
}
.scan-corner.is-tl { left: -3px; top: -3px; border-left-width: 4px; border-top-width: 4px; border-top-left-radius: 14px; }
.scan-corner.is-tr { right: -3px; top: -3px; border-right-width: 4px; border-top-width: 4px; border-top-right-radius: 14px; }
.scan-corner.is-bl { left: -3px; bottom: -3px; border-left-width: 4px; border-bottom-width: 4px; border-bottom-left-radius: 14px; }
.scan-corner.is-br { right: -3px; bottom: -3px; border-right-width: 4px; border-bottom-width: 4px; border-bottom-right-radius: 14px; }
/* Holding steady draws the corners in a touch, as a lens settling. Full motion only. */
:root[data-motion="full"] .scan-frame[data-steady="settling"] .scan-corner,
:root[data-motion="full"] .scan-frame[data-steady="ready"] .scan-corner { transform: scale(.92); }
.scan-frame[data-steady="ready"] { outline-color: var(--accent); }

/* The shutter's flash, inside the frame only. */
.scan-flash { position: absolute; inset: 0; border-radius: inherit; background: #fff; opacity: 0; pointer-events: none; }
.scan-frame.is-flash .scan-flash { animation: scan-flash 360ms var(--ease-out); }
@keyframes scan-flash { 0% { opacity: .75; } 100% { opacity: 0; } }

/* Reading: a line sweeps down the held picture (Full motion); otherwise the words say it. */
.scan.is-reading .scan-frame::after {
  content: ""; position: absolute; left: 6%; right: 6%; top: 0; height: 100%;
  background: linear-gradient(90deg, transparent, var(--accent), transparent) top / 100% 2px no-repeat;
  filter: drop-shadow(0 0 5px var(--accent));
  animation: scan-sweep 1.3s var(--ease-in-out) infinite alternate;
}
@keyframes scan-sweep { from { transform: translateY(0); } to { transform: translateY(calc(100% - 2px)); } }
:root:not([data-motion="full"]) .scan.is-reading .scan-frame::after { display: none; }

.scan-status {
  display: inline-flex; align-items: center; gap: 8px; margin: 0; flex: none;
  max-width: calc(100% - 32px); min-height: 34px; padding: 7px 14px;
  border-radius: var(--radius-pill);
  background: var(--scan-glass);
  backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);
  font-size: 13.5px; font-weight: 600; line-height: 1.3; text-align: center;
  text-shadow: 0 1px 2px rgb(0 0 0 / .4);
}
.scan-status-dot {
  flex: none; width: 8px; height: 8px; border-radius: 50%;
  background: rgb(255 255 255 / .55);
  transition: background var(--t-1) linear;
}
/* With the matches up, the picture they came from stays; what the guide was saying does not. */
.scan.has-sheet .scan-status { visibility: hidden; }
.scan-frame[data-steady="settling"] + .scan-status .scan-status-dot,
.scan-frame[data-steady="ready"] + .scan-status .scan-status-dot { background: var(--accent); }
.scan.is-reading .scan-status-dot { background: var(--accent); animation: scan-pulse 900ms ease-in-out infinite alternate; }
:root:not([data-motion="full"]) .scan.is-reading .scan-status-dot { animation: none; }
@keyframes scan-pulse { from { opacity: .35; } to { opacity: 1; } }

/* ------------------------------------------------------------------- bars */
.scan-top {
  position: absolute; top: 0; left: 0; right: var(--scan-side);
  display: flex; align-items: center; gap: 8px;
  padding: calc(10px + env(safe-area-inset-top, 0px)) max(12px, env(safe-area-inset-right, 0px)) 14px max(12px, env(safe-area-inset-left, 0px));
  background: linear-gradient(rgb(0 0 0 / .62), rgb(0 0 0 / 0));
}
.scan-gap { flex: 1; }

.scan-btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 7px; flex: none;
  height: 42px; min-width: 42px; padding: 0 14px;
  border: 1px solid var(--scan-line); border-radius: var(--radius-pill);
  background: var(--scan-glass); color: #fff;
  backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);
  font: inherit; font-size: 13.5px; font-weight: 600; white-space: nowrap;
  cursor: pointer;
  transition: background var(--t-1) var(--ease-out), color var(--t-1) var(--ease-out), border-color var(--t-1) var(--ease-out);
}
.scan-btn:hover { background: rgb(40 44 54 / .72); }
.scan-btn:focus-visible, .scan-shutter:focus-visible, .scan-undo:focus-visible, .scan-game:focus-visible {
  outline: 2px solid #fff; outline-offset: 2px;
}
.scan-btn[aria-pressed="true"] { background: var(--accent-fill); color: var(--accent-ink); border-color: transparent; }
.scan-x, .scan-torch { width: 42px; padding: 0; }
.scan-ico { display: inline-grid; place-items: center; line-height: 0; }

.scan-game-wrap { min-width: 0; flex: 0 1 auto; }
.scan-game {
  height: 42px; max-width: min(46vw, 260px); padding: 0 34px 0 14px;
  border: 1px solid var(--scan-line); border-radius: var(--radius-pill);
  background: var(--scan-glass) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M3 4.5l3 3 3-3' fill='none' stroke='white' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") no-repeat right 13px center / 11px;
  backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);
  color: #fff; font: inherit; font-size: 14px; font-weight: 600;
  appearance: none; -webkit-appearance: none;
  text-overflow: ellipsis; cursor: pointer;
}
.scan-game option { color: var(--ink); background: var(--bg-2); }

.scan-bar {
  position: absolute; left: 0; right: 0; bottom: 0;
  display: flex; flex-direction: column; align-items: center; justify-content: flex-end; gap: 10px;
  min-height: var(--scan-bar);
  padding: 12px max(16px, env(safe-area-inset-right, 0px)) calc(18px + env(safe-area-inset-bottom, 0px)) max(16px, env(safe-area-inset-left, 0px));
  background: linear-gradient(rgb(0 0 0 / 0), rgb(0 0 0 / .66));
  pointer-events: none;
}
.scan-bar > * { pointer-events: auto; }
.scan-controls {
  display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; gap: 12px;
  width: min(440px, 100%);
}
.scan-photo { justify-self: start; }
.scan-auto { justify-self: end; }
.scan[data-state="photo"] .scan-auto, .scan[data-state="error"] .scan-auto { visibility: hidden; }

.scan-shutter {
  display: grid; place-items: center;
  width: 76px; height: 76px; padding: 5px;
  border: 4px solid #fff; border-radius: 50%;
  background: rgb(0 0 0 / .18);
  box-shadow: 0 4px 18px rgb(0 0 0 / .45);
  cursor: pointer;
}
.scan-shutter-ring {
  width: 100%; height: 100%; border-radius: 50%; background: #fff;
  transition: transform var(--t-1) var(--ease-out), background var(--t-1) var(--ease-out);
}
.scan-shutter:hover .scan-shutter-ring { background: color-mix(in srgb, var(--accent) 22%, #fff); }
.scan-shutter:active .scan-shutter-ring { transform: scale(.88); }
.scan.is-reading .scan-shutter { opacity: .55; pointer-events: none; }

/* The running count in continuous mode, with Undo for the last card. */
.scan-tally {
  display: inline-flex; align-items: center; gap: 10px; max-width: 100%;
  padding: 5px 5px 5px 14px; border-radius: var(--radius-pill);
  background: var(--scan-glass); border: 1px solid var(--scan-line);
  backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);
  font-size: 13.5px; font-weight: 600;
}
.scan-tally-t { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-variant-numeric: tabular-nums; }
.scan-tally.is-bump { animation: scan-bump 420ms var(--ease-spring); }
@keyframes scan-bump { 0% { transform: scale(1); } 40% { transform: scale(1.06); } 100% { transform: scale(1); } }
.scan-undo {
  display: inline-flex; align-items: center; gap: 6px; flex: none;
  height: 32px; padding: 0 12px; border: none; border-radius: var(--radius-pill);
  background: rgb(255 255 255 / .16); color: #fff;
  font: inherit; font-size: 13px; font-weight: 650; cursor: pointer;
}
.scan-undo:hover { background: rgb(255 255 255 / .26); }

/* ---------------------------------------------------------------- the sheet */
.scan-sheet {
  position: absolute; left: 0; right: 0; bottom: 0; margin-inline: auto;
  width: min(580px, 100%);
  max-height: min(80dvh, 660px);
  display: flex; flex-direction: column; gap: 10px;
  padding: 6px 14px calc(14px + env(safe-area-inset-bottom, 0px));
  background: var(--bg-2); color: var(--ink);
  color-scheme: light dark;
  border: 1px solid var(--line); border-bottom: none;
  border-radius: 20px 20px 0 0;
  box-shadow: 0 -18px 50px rgb(0 0 0 / .5);
  animation: scan-sheet-up var(--t-3) var(--ease-out);
}
:root[data-theme="light"] .scan-sheet { color-scheme: light; }
:root[data-theme="dark"] .scan-sheet { color-scheme: dark; }
@keyframes scan-sheet-up { from { transform: translateY(40px); opacity: 0; } }
:root[data-motion="reduced"] .scan-sheet { animation: scan-fade var(--t-2) var(--ease-out); }
@keyframes scan-fade { from { opacity: 0; } }
.scan-sheet-grip { width: 40px; height: 5px; margin: 2px auto 0; border-radius: 3px; background: var(--line); flex: none; }
.scan-sheet-head { display: flex; align-items: flex-start; gap: 10px; flex: none; }
.scan-sheet-titles { flex: 1; min-width: 0; }
.scan-sheet-t { margin: 0; font-size: var(--fs-h2); }
.scan-sheet.is-sure .scan-sheet-t { color: var(--accent-text); }
.scan-sheet-note { margin: 3px 0 0; font-size: var(--fs-sm); color: var(--ink-2); }
.scan-sheet-note:empty { display: none; }
.scan-again { flex: none; gap: 6px; }

.scan-fix { position: relative; display: block; flex: none; }
.scan-fix-ico { position: absolute; left: 12px; top: 50%; transform: translateY(-50%); color: var(--ink-3); line-height: 0; pointer-events: none; }
.scan-fix .scan-fix-q { height: 42px; padding-left: 34px; border-radius: var(--radius-pill); font-size: 16px; }

.scan-sheet-row { display: flex; align-items: center; justify-content: space-between; gap: 10px; flex-wrap: wrap; flex: none; }
.scan-where { margin: 0; font-size: var(--fs-sm); color: var(--ink-2); }
.scan-own { display: inline-flex; margin: 0; padding: 3px; border: 1px solid var(--line); border-radius: var(--radius-pill); background: var(--bg); }
.scan-own-opt { position: relative; display: inline-flex; cursor: pointer; }
.scan-own-opt input { position: absolute; opacity: 0; inset: 0; margin: 0; cursor: pointer; }
.scan-own-opt span {
  padding: 5px 13px; border-radius: var(--radius-pill);
  font-size: 12.5px; font-weight: 650; color: var(--ink-2);
  transition: background var(--t-1) var(--ease-out), color var(--t-1) var(--ease-out);
}
.scan-own-opt input:checked + span { background: var(--accent-fill); color: var(--accent-ink); }
.scan-own-opt input:focus-visible + span { outline: 2px solid var(--accent); outline-offset: 2px; }

.scan-cands {
  list-style: none; margin: 0; padding: 0 2px 2px;
  display: grid; gap: 7px; align-content: start;
  overflow: auto; overscroll-behavior: contain;
  flex: 1 1 auto; min-height: 0;
}
.scan-cand {
  display: grid; grid-template-columns: 50px minmax(0, 1fr) auto; align-items: center; gap: 12px;
  width: 100%; padding: 8px 10px 8px 8px;
  border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--bg-3); color: var(--ink);
  font: inherit; text-align: left; cursor: pointer;
  box-shadow: var(--glass-edge);
  transition: border-color var(--t-1) var(--ease-out), background var(--t-1) var(--ease-out);
}
.scan-cand:hover { border-color: color-mix(in srgb, var(--ink) 22%, var(--line)); background: color-mix(in srgb, var(--ink) 5%, var(--bg-3)); }
.scan-cand:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.scan-cand.is-best {
  border-color: color-mix(in srgb, var(--accent) 60%, transparent);
  background: color-mix(in srgb, var(--accent) 9%, var(--bg-3));
  box-shadow: var(--glass-edge), var(--glow-accent);
}
.scan-cand-art {
  width: 50px; aspect-ratio: 63 / 88; border-radius: 4px; overflow: hidden;
  background: var(--pocket); box-shadow: var(--shadow-1);
}
.scan-cand-art img { width: 100%; height: 100%; object-fit: cover; display: block; }
.scan-cand-art img.is-broken { visibility: hidden; }
.scan-cand-body { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.scan-cand-name { font-weight: 650; font-size: 14.5px; line-height: 1.25; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.scan-cand-meta { font-size: var(--fs-sm); color: var(--ink-2); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.scan-cand-conf { display: flex; align-items: center; gap: 7px; margin-top: 3px; }
.scan-cand-bar {
  position: relative; width: 64px; height: 4px; border-radius: 2px; overflow: hidden;
  background: color-mix(in srgb, var(--ink) 12%, transparent);
}
.scan-cand-bar::after {
  content: ""; position: absolute; inset: 0 auto 0 0; width: calc(var(--c, 0) * 100%);
  border-radius: inherit; background: var(--accent);
}
.scan-cand-pct { font-size: 11px; font-weight: 650; color: var(--ink-3); font-variant-numeric: tabular-nums; }
.scan-cand-side { display: flex; flex-direction: column; align-items: flex-end; gap: 5px; }
.scan-cand-price { font-weight: 650; color: var(--gold-text); font-variant-numeric: tabular-nums; }
.scan-cand-add {
  padding: 4px 11px; border-radius: var(--radius-pill);
  background: var(--accent-fill); color: var(--accent-ink);
  font-size: 12px; font-weight: 700; white-space: nowrap;
}
.scan-none { padding: 18px 8px; text-align: center; color: var(--ink-2); font-size: var(--fs-sm); }

/* ---------------------------------------------------- no camera, no reader */
.scan-problem {
  position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%);
  width: min(420px, calc(100% - 32px));
  padding: 22px 20px 18px; text-align: center;
  background: var(--bg-2); color: var(--ink);
  border: 1px solid var(--line); border-radius: var(--radius-lg);
  box-shadow: var(--glass-edge), var(--shadow-2);
}
.scan-problem-t { margin: 0 0 6px; font-size: var(--fs-h2); }
.scan-problem-s { margin: 0; color: var(--ink-2); font-size: var(--fs-body); }
.scan-problem-actions { display: flex; flex-direction: column; gap: 8px; margin-top: 16px; }
.scan-problem-actions .btn { height: 40px; justify-content: center; }

/* The page behind: toasts come to the top, clear of the shutter and the sheet. */
.is-scanning .toast-stack {
  top: calc(66px + env(safe-area-inset-top, 0px)) !important; bottom: auto !important;
  left: 50% !important; right: auto !important;
  transform: translateX(-50%) !important; align-items: center !important;
  width: max-content !important; max-width: calc(100vw - 32px) !important;
}

/* --------------------------------------------------------------- landscape
   A phone on its side: the controls become a column down the right, and the
   matches a panel there too, so the guide keeps the height it needs. */
@media (orientation: landscape) and (max-height: 600px) {
  .scan {
    --scan-top: calc(58px + env(safe-area-inset-top, 0px));
    --scan-bar: 12px;
    --scan-side: calc(118px + env(safe-area-inset-right, 0px));
  }
  .scan-bar {
    left: auto; top: 0; bottom: 0; right: 0;
    width: var(--scan-side); min-height: 0;
    justify-content: center;
    padding: calc(10px + env(safe-area-inset-top, 0px)) calc(10px + env(safe-area-inset-right, 0px)) calc(10px + env(safe-area-inset-bottom, 0px)) 10px;
    background: linear-gradient(90deg, rgb(0 0 0 / 0), rgb(0 0 0 / .66));
  }
  .scan-controls {
    grid-template-columns: auto; grid-template-rows: 1fr auto 1fr;
    width: auto; height: min(320px, 100%); justify-items: center;
  }
  .scan-photo { align-self: start; justify-self: center; }
  .scan-auto { align-self: end; justify-self: center; }
  .scan-controls .scan-btn-t { display: none; }
  .scan-controls .scan-btn { width: 44px; padding: 0; }
  .scan-tally {
    position: absolute; right: calc(var(--scan-side) + 12px); bottom: calc(12px + env(safe-area-inset-bottom, 0px));
    max-width: 60vw;
  }
  .scan-top { padding-bottom: 8px; }
  .scan-mode .scan-btn-t { display: none; }
  .scan-mode { width: 42px; padding: 0; }
  .scan-guide { gap: 8px; }
  .scan-frame { height: min(calc(100% - 50px), calc((100vw - var(--scan-side) - 40px) * 88 / 63)); }

  .scan-sheet {
    left: auto; top: 0; bottom: 0; right: 0; margin: 0;
    width: min(430px, 58vw); max-height: none;
    padding: calc(10px + env(safe-area-inset-top, 0px)) calc(12px + env(safe-area-inset-right, 0px)) calc(10px + env(safe-area-inset-bottom, 0px)) 12px;
    border-radius: 18px 0 0 18px; border: 1px solid var(--line); border-right: none;
    animation-name: scan-sheet-side;
  }
  .scan-sheet-grip { display: none; }
}
@keyframes scan-sheet-side { from { transform: translateX(40px); opacity: 0; } }

/* A big screen (a webcam on a desktop): the matches stand to the right of the guide. */
@media (min-width: 1000px) and (min-height: 601px) {
  .scan-sheet {
    left: auto; right: 24px; top: calc(var(--scan-top) + 8px); bottom: 24px; margin: 0;
    width: 400px; max-height: none;
    border: 1px solid var(--line); border-radius: var(--radius-lg);
    padding-bottom: 14px;
    animation-name: scan-sheet-side;
  }
  .scan-sheet-grip { display: none; }
}

/* Phones: "Keep scanning" gives its words up to its icon (its label still says them), so the
   game's name has the room. */
@media (max-width: 460px) {
  .scan-mode .scan-btn-t { display: none; }
  .scan-mode { width: 42px; padding: 0; }
  .scan-game { max-width: calc(100vw - 180px); }
}
