/*
 * Dalia — in-portal QR card scanner (couple portal + guest nadportal).
 *
 * Built to Rasmus' audit (docs/RASMUS_QR_SKENER_AUDIT.md): a Dalia surface that
 * happens to look through the camera, not an OS camera chrome. Every pixel of the
 * scrim carries the brand — warm ink, never pure black; mauve reticle in BOTH
 * portals (brand constant); one motion (search → lock → work), not three screens.
 *
 * Tokens only (from dalia-portal.css): --ink / --paper / --color-deep-mauve /
 * --font-display (Cardo) / --font-body (Manrope) / --font-mono (JetBrains Mono) /
 * --ease / --line-strong / --shadow-lg. No new raw hex — inline fallbacks mirror
 * the token defaults for render-before-:root safety only.
 */

/* ── Overlay + scrim ─────────────────────────────────────────────
   position:fixed inset:0; z-index above everything incl. couple docks
   (radio/chat/vinyl top out at 10002). Rasmus: >2000 — a fullscreen modal
   that captures the whole viewport. Does not touch document flow → deck-safe. */
.qr-scan-modal {
  position: fixed;
  inset: 0;
  z-index: 20000;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  animation: qrModalIn 0.2s var(--ease, ease) both;
}
.qr-scan-modal[hidden] { display: none; }

/* Scrim = warm ink at ~0.92 (NEVER pure black — a black square reads "broken"). */
.qr-scan-backdrop {
  position: absolute;
  inset: 0;
  background: var(--ink, #3f3138);
  opacity: 0.92;
}

/* ⚠️ STROP VISINE (Vedran 2026-08-09: „popup bude prevelik, ne vidi se sve").
   Ploča je centrirana flexom u `position:fixed` sloju s `overflow:visible` —
   višak visine tada visi JEDNAKO van na obje strane i ne može se doskrolati
   nikako. Desktop varijanta je strop dobila naknadno (niže), mobilna nikad.
   Izmjereno na 390x320 (telefon s otvorenom tipkovnicom): 9px van gore I 9px
   van dolje istovremeno. `dvh` uz `vh` jer mobilni Safari `vh` računa preko
   adresne trake. */
.qr-scan-sheet {
  max-height: calc(100vh - 32px);
  max-height: calc(100dvh - 32px);
  overflow-y: auto;
  overscroll-behavior: contain;
  position: relative;
  z-index: 1;
  width: min(92vw, 420px);
  text-align: center;
}

/* Close — fixed to viewport corner, thumb-safe. */
.qr-scan-x {
  position: fixed;
  top: max(14px, env(safe-area-inset-top));
  right: 14px;
  z-index: 2;
  width: 44px;
  height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 0;
  border-radius: 50%;
  background: none;
  color: var(--paper, #fffaf6);
  font-size: 28px;
  line-height: 1;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.qr-scan-x:hover { opacity: 0.75; }

.qr-scan-title {
  margin: 0 0 22px;
  font-family: var(--font-display, 'Cardo', Georgia, serif);
  font-weight: 400;
  font-size: 24px;
  letter-spacing: 0.005em;
  color: var(--paper, #fffaf6);
}

/* ── Viewfinder ──────────────────────────────────────────────────
   Centered rounded square, ~72vw / max 320px. Live camera fills it.
   Before permission: warm paper/mauve placeholder + camera glyph — never
   a dead black square. */
.qr-scan-cam {
  position: relative;
  /* `min()` s `dvh`: na 390x844 vraća današnjih 280.8px (nula pomaka na
     referentnom telefonu), ali na niskom ekranu tražilac popusti prvi. */
  width: min(72vw, 320px, 46dvh);
  max-width: 320px;
  aspect-ratio: 1 / 1;
  margin: 0 auto;
  border-radius: 18px;
  overflow: hidden;
  background:
    radial-gradient(ellipse 80% 80% at 50% 40%, var(--mauve-100, #f0e2ea), var(--paper, #fffaf6));
}
/* Vedran 2026-08-08: „makni sa sredine kamere tu zvijezdu; možda bi prava
   ikonica kamere bila bolja."

   Bio je `--ornament-fleuron` — dekorativni cvjetni znak iz ornament knjižnice,
   koji na mjestu gdje se čeka SLIKA čita kao zvjezdica bez značenja. Sada stoji
   fotoaparat (`static/img/kamera.svg`).

   `mask-image`, ne `background-image`: maska uzima OBLIK iz datoteke, a boju iz
   `background-color` — pa znak prati mauve token i tamnu temu, a u samoj SVG
   datoteci nema nijednog heksa koji bi se s temom razišao. */
.qr-scan-cam::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  background-color: var(--color-deep-mauve, #b56b8d);
  -webkit-mask: url("/static/img/kamera.svg") no-repeat center / 46px;
  mask: url("/static/img/kamera.svg") no-repeat center / 46px;
  opacity: 0.26;
  pointer-events: none;
}
/* Tražilo dok kamera spava (Vedran 29.8.2026.): ista ružičasta ploha i isti
   fotoaparat kao dosad — mijenja se samo to što je sada DODIRLJIVA. Kamera se
   pali tek kad je korisnik zatraži, pa se dozvola ne traži na otvaranje ploče.
   Bez vlastite boje i bez novog znaka: ploha već govori „ovdje će biti slika",
   nedostajalo joj je samo da izgleda kao da čeka dodir. */
.qr-scan-cam.is-idle { cursor: pointer; }
.qr-scan-cam.is-idle::before { opacity: 0.34; transition: opacity .24s var(--ease, ease); }
.qr-scan-cam.is-idle:hover::before,
.qr-scan-cam.is-idle:focus-visible::before { opacity: 0.5; }
.qr-scan-cam.is-idle:focus-visible {
  outline: 2px solid var(--color-deep-mauve, #b56b8d);
  outline-offset: 3px;
}

.qr-scan-video {
  position: absolute;
  inset: 0;
  z-index: 1;
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* Nišan = četiri L-ugla u mauveu (Vedran 2026-08-08: „da postane mauve, naša
   boja, ne ta ljubičasta"). Ljubičasta je bila boja skenera, a ne marke —
   dvije različite tinte na dvije susjedne plohe istog portala. */
.qr-scan-corner {
  position: absolute;
  z-index: 2;
  width: 26px;
  height: 26px;
  border: 3px solid var(--color-deep-mauve, #b56b8d);
  opacity: 0.6;
}
.qr-scan-corner--tl { top: 14px; left: 14px; border-right: 0; border-bottom: 0; border-top-left-radius: 8px; }
.qr-scan-corner--tr { top: 14px; right: 14px; border-left: 0; border-bottom: 0; border-top-right-radius: 8px; }
.qr-scan-corner--bl { bottom: 14px; left: 14px; border-right: 0; border-top: 0; border-bottom-left-radius: 8px; }
.qr-scan-corner--br { bottom: 14px; right: 14px; border-left: 0; border-top: 0; border-bottom-right-radius: 8px; }

/* Lock ring — puni mauve okvir koji se pojavi na očitanju. */
.qr-scan-ring {
  position: absolute;
  inset: 10px;
  z-index: 2;
  border: 3px solid var(--color-deep-mauve, #b56b8d);
  border-radius: 14px;
  opacity: 0;
  transform: scale(0.96);
  pointer-events: none;
}

/* Working hairline — tanki mauve prijelaz (rod s .dp-progress). */
.qr-scan-hairline {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 3;
  height: 2px;
  background: linear-gradient(90deg, transparent, var(--color-deep-mauve, #b56b8d), transparent);
  opacity: 0;
  transform: scaleX(0);
  transform-origin: left;
}

/* ── State 1: tražim (corners breathe) ── */
.qr-scan-cam.is-searching .qr-scan-corner {
  animation: qrBreathe 1.8s var(--ease, ease-in-out) infinite;
}

/* ── State 2: našao (corners fade, ring locks in 180ms Dalia ease) ── */
.qr-scan-cam.is-locked .qr-scan-corner {
  opacity: 0;
  animation: none;
  transition: opacity 120ms var(--ease, ease);
}
.qr-scan-cam.is-locked .qr-scan-ring {
  opacity: 1;
  transform: scale(1);
  transition: opacity 180ms cubic-bezier(0.22, 1, 0.36, 1),
              transform 180ms cubic-bezier(0.22, 1, 0.36, 1);
}

/* ── State 3: radim (hairline sweeps) ── */
.qr-scan-cam.is-working .qr-scan-corner { opacity: 0; animation: none; }
.qr-scan-cam.is-working .qr-scan-ring { opacity: 1; transform: scale(1); }
.qr-scan-cam.is-working .qr-scan-hairline {
  opacity: 1;
  animation: qrHairline 1s linear infinite;
}

/* ── Captions ── */
.qr-scan-caption {
  margin: 20px 0 0;
  font-family: var(--font-body, 'Manrope', system-ui, sans-serif);
  font-size: 15px;
  line-height: 1.5;
  color: var(--paper, #fffaf6);
}
/* Couple name on lock — Cardo, the warm "we recognise you". */
.qr-scan-couple {
  margin: 8px 0 0;
  font-family: var(--font-display, 'Cardo', Georgia, serif);
  font-style: italic;
  font-size: 22px;
  line-height: 1.2;
  color: var(--paper, #fffaf6);
}
.qr-scan-couple[hidden] { display: none; }

/* Rescan (only for info results that don't route). */
.qr-scan-rescan {
  margin-top: 16px;
  min-height: 44px;
  padding: 10px 24px;
  font-family: var(--font-body, 'Manrope', system-ui, sans-serif);
  font-size: 14px;
  font-weight: 600;
  color: var(--ink, #3f3138);
  background: var(--paper, #fffaf6);
  border: 0;
  border-radius: 999px;
  cursor: pointer;
}
.qr-scan-rescan[hidden] { display: none; }

/* ── Manual short-code path ──────────────────────────────────────
   Visible link from the first second (mercy, not a hidden last exit). */
.qr-scan-manual-link {
  display: inline-block;
  margin-top: 18px;
  min-height: 44px;
  padding: 10px 12px;
  background: none;
  border: 0;
  font-family: var(--font-body, 'Manrope', system-ui, sans-serif);
  font-size: 14px;
  color: var(--mauve-300, #c8a6bd);
  text-decoration: underline;
  text-underline-offset: 3px;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.qr-scan-manual-link:hover { color: var(--mauve-100, #f0e2ea); }
.qr-scan-manual-link[hidden] { display: none; }

/* Manual panel = paper card, NOT the camera scrim. */
.qr-scan-manual {
  margin-top: 22px;
  text-align: left;
  background: var(--paper, #fffaf6);
  border-radius: 18px;
  padding: 24px 20px;
  box-shadow: var(--shadow-lg, 0 30px 70px -36px rgba(45, 34, 56, 0.42));
}
.qr-scan-manual[hidden] { display: none; }
.qr-scan-manual-title {
  margin: 0 0 6px;
  font-family: var(--font-display, 'Cardo', Georgia, serif);
  font-weight: 400;
  font-size: 20px;
  color: var(--ink, #3f3138);
}
.qr-scan-manual-label {
  display: block;
  margin-bottom: 14px;
  font-family: var(--font-body, 'Manrope', system-ui, sans-serif);
  font-size: 14px;
  color: var(--ink-soft, #8B7F6E);
}
.qr-scan-input {
  width: 100%;
  box-sizing: border-box;
  padding: 14px 12px;
  font-family: 'JetBrains Mono', var(--font-mono, ui-monospace, monospace);
  font-size: 20px;
  text-transform: uppercase;
  letter-spacing: 0.18em;
  text-align: center;
  color: var(--ink, #3f3138);
  background: var(--paper-soft, #fffaf6);
  border: 1px solid var(--line-strong, rgba(63, 49, 56, 0.22));
  border-radius: 12px;
  outline: none;
}
.qr-scan-input::placeholder { color: var(--ink-faint, #c8bfbe); }
.qr-scan-input:focus {
  border-color: var(--color-deep-mauve, #b56b8d);
  box-shadow: 0 0 0 2px var(--mauve-100, #f0e2ea);
}
.qr-scan-submit {
  width: 100%;
  min-height: 48px;
  margin-top: 14px;
  font-family: var(--font-body, 'Manrope', system-ui, sans-serif);
  font-size: 15px;
  font-weight: 600;
  color: #fff;
  background: var(--color-deep-mauve, #b56b8d);
  border: 0;
  border-radius: 999px;
  cursor: pointer;
  transition: background 0.18s var(--ease, ease);
}
.qr-scan-submit:hover { background: var(--mauve-700, #a55779); }

/* ── Keyframes ── */
@keyframes qrModalIn {
  from { opacity: 0; }
  to   { opacity: 1; }
}
@keyframes qrBreathe {
  0%, 100% { opacity: 0.5; transform: scale(1); }
  50%      { opacity: 1;   transform: scale(1.06); }
}
@keyframes qrHairline {
  0%        { transform: scaleX(0); transform-origin: left; }
  50%       { transform: scaleX(1); transform-origin: left; }
  50.01%    { transform: scaleX(1); transform-origin: right; }
  100%      { transform: scaleX(0); transform-origin: right; }
}

/* ── Mobile-first (390px): sizes already fluid; guard the smallest phones. ── */
@media (max-width: 400px) {
  .qr-scan-modal { padding: 16px; }
  .qr-scan-title { font-size: 22px; margin-bottom: 18px; }
  .qr-scan-cam { width: 72vw; }
}

/* ── Reduced motion: lock is instant, no breathing/morph (IK#10). ── */
@media (prefers-reduced-motion: reduce) {
  .qr-scan-modal { animation: none; }
  .qr-scan-cam.is-searching .qr-scan-corner { animation: none; opacity: 0.7; }
  .qr-scan-cam.is-locked .qr-scan-ring { transition: none; }
  .qr-scan-cam.is-working .qr-scan-hairline { animation: none; opacity: 1; transform: scaleX(1); }
  .qr-scan-submit { transition: none; }
}

/* ════════════════════════════════════════════════════════════════
   DESKTOP MODAL — tri puta odjednom (BRIEF_GOSTI_REORG § 11)
   ════════════════════════════════════════════════════════════════
   Mobilna ladica ostaje kakva je: kamera pa milost (ručni kod). Na
   desktopu se kamera, fotografija koda i upis koda vide ISTOVREMENO —
   pa slijepa ulica ne može ni nastati. Kad kamere nema, njezin stupac
   kaže ZAŠTO, a druga dva puta ostaju živa.

   Ploha je paper kartica na istom warm-ink scrimu (nije druga aplikacija,
   nego ista soba pri drugom svjetlu). position:fixed → deck-safe. */

.qr-scan-modal--desk { padding: 32px 24px; }

.qr-scan-modal--desk .qr-scan-sheet {
  width: min(94vw, 760px);
  max-height: calc(100vh - 48px);
  max-height: calc(100dvh - 48px);
  overflow-y: auto;
  overscroll-behavior: contain;
  text-align: left;
  padding: 26px 28px 24px;
  border-radius: 20px;
  background: var(--paper-soft);
  color: var(--ink);
  box-shadow: var(--shadow-lg);
}
.qr-scan-modal--desk .qr-scan-sheet:focus { outline: none; }

/* ── Zaglavlje ── */
.qr-scan-desk-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 22px;
}
.qr-scan-desk-headings { min-width: 0; }
.qr-scan-modal--desk .qr-scan-title {
  margin: 0;
  font-size: 26px;
  color: var(--ink);
}
.qr-scan-desk-sub {
  margin: 6px 0 0;
  font-family: var(--font-body);
  font-size: 14px;
  line-height: 1.5;
  color: var(--ink-soft);
}
.qr-scan-desk-x {
  flex-shrink: 0;
  width: 40px;
  height: 40px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 0;
  border-radius: 50%;
  background: none;
  color: var(--ink-soft);
  cursor: pointer;
  transition: background-color 0.18s var(--ease), color 0.18s var(--ease);
}
.qr-scan-desk-x:hover { background: var(--mauve-100); color: var(--ink); }

/* ── Tri puta: kamera lijevo, alternative desno ──
   Grid apsorbira (canon §4.3): pod 820px se slaže u jedan stupac. */
.qr-scan-desk-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 24px;
  align-items: start;
}
.qr-scan-desk-alts {
  display: flex;
  flex-direction: column;
  gap: 18px;
  min-width: 0;
}
.qr-scan-way { min-width: 0; }
.qr-scan-way-title {
  margin: 0 0 4px;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: 17px;
  color: var(--ink);
}
.qr-scan-way-hint {
  display: block;
  margin: 0 0 12px;
  font-family: var(--font-body);
  font-size: 13px;
  line-height: 1.5;
  color: var(--ink-soft);
}

/* Kamera: isti tražilac, samo puni širinu stupca. Kvadrat je mobilni format
   (stražnja kamera, kartica u ruci); web kamera je 4:3 pa desktop dobiva 4:3 —
   manje praznog kadra i niža kartica, bez scrolla na 1440×900. */
.qr-scan-modal--desk .qr-scan-cam {
  width: 100%;
  max-width: none;
  margin: 0;
  aspect-ratio: 4 / 3;
}
.qr-scan-cam-note {
  margin: 12px 0 0;
  font-family: var(--font-body);
  font-size: 13px;
  line-height: 1.5;
  color: var(--ink-soft);
  min-height: 40px;
}
/* Kamera odbijena ili je nema: tražilac ostaje topla ploha s fleuronom
   (nikad mrtvi crni kvadrat), a note nosi razlog. */
.qr-scan-cam.is-off .qr-scan-video,
.qr-scan-cam.is-off .qr-scan-ring,
.qr-scan-cam.is-off .qr-scan-hairline { display: none; }
.qr-scan-cam.is-off .qr-scan-corner { animation: none; opacity: 0.28; }

/* Fotografija koda: jedini okvir na kartici, i to zato što je drop-zona.
   Crtkano = "ovdje se nešto ostavlja" (IK#8: crtkano-prigušeno, nikad crveno). */
.qr-scan-way--file {
  padding: 16px;
  border: 1px dashed var(--line-strong);
  border-radius: 14px;
  transition: border-color 0.18s var(--ease), background-color 0.18s var(--ease);
}
.qr-scan-way--file.is-dragover {
  border-color: var(--color-deep-mauve);
  background: var(--mauve-100);
}
.qr-scan-way-msg {
  margin: 10px 0 0;
  font-family: var(--font-body);
  font-size: 13px;
  line-height: 1.45;
  color: var(--ink-soft);
  min-height: 19px;
}
.qr-scan-way-msg.is-error { color: var(--rose-700); }

/* Kod s kartice: polje i potvrda u istom redu (desktop ima širinu za to). */
.qr-scan-code-row { display: flex; align-items: stretch; gap: 10px; }
.qr-scan-code-row .qr-scan-input { flex: 1; min-width: 0; font-size: 17px; }
.qr-scan-submit--inline {
  width: auto;
  margin-top: 0;
  padding: 0 22px;
  flex-shrink: 0;
}

/* Tihi gumb (ponovni pokušaj, odabir slike, ponovno skeniranje). */
.qr-scan-ghost {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  padding: 10px 18px;
  font-family: var(--font-body);
  font-size: 14px;
  font-weight: 600;
  color: var(--mauve-700);
  background: none;
  border: 1px solid var(--mauve-300);
  border-radius: 999px;
  cursor: pointer;
  transition: background-color 0.18s var(--ease), border-color 0.18s var(--ease), color 0.18s var(--ease);
}
.qr-scan-ghost:hover { background: var(--mauve-100); border-color: var(--color-deep-mauve); color: var(--mauve-700); }
.qr-scan-ghost:disabled { opacity: 0.55; cursor: default; }
.qr-scan-ghost--wide { width: 100%; }
.qr-scan-ghost[hidden] { display: none; }
.qr-scan-way--cam .qr-scan-ghost { margin-top: 10px; }

/* Podnožje = jedna polica za ishod (Trenutak… / poruka / ime para), zajednička
   za sva tri puta. Bez linije: prazna polica ne smije crtati ukras. Visina je
   rezervirana pa kartica ne poskoči kad tekst stigne (canon §4.4). */
.qr-scan-desk-foot {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 12px;
  margin-top: 18px;
}
.qr-scan-modal--desk .qr-scan-caption {
  margin: 0;
  min-height: 21px;
  font-size: 14px;
  color: var(--ink-soft);
}
.qr-scan-modal--desk .qr-scan-couple {
  margin: 0;
  font-size: 20px;
  color: var(--ink);
}

/* Fokus je vidljiv i tipkovnica dođe svugdje kamo i miš (IK#10). */
.qr-scan-modal--desk button:focus-visible,
.qr-scan-modal--desk input:focus-visible {
  outline: 2px solid var(--color-deep-mauve);
  outline-offset: 2px;
}

/* Ispod 820px grid pada u JEDAN stupac i visina ploče skoči s 507 na 796px, a
   strop je bio 88vh — pa treći put („Kod s kartice") ispadne ispod pregiba.
   Skrol postoji, ali macOS ne crta traku dok se ne skrola, pa ploha izgleda
   odrezano, a ne skrolabilno. Izmjereno na 768x700: skriveno 179px, cijeli
   treći put izvan kadra. Ovi redci skidaju ~114px (Vedran 2026-08-09). */
@media (max-width: 820px) {
  .qr-scan-desk-grid { grid-template-columns: 1fr; gap: 16px; }
  .qr-scan-desk-alts { gap: 12px; }
  .qr-scan-modal--desk .qr-scan-sheet { padding: 22px 18px 20px; }
  .qr-scan-modal--desk .qr-scan-title { font-size: 23px; }
  /* Složeno u jedan stupac tražilac se NE širi preko cijele kartice — inače
     pojede prvi ekran i druga dva puta padnu pod pregib (obećanje je da se
     sva tri vide odjednom). */
  .qr-scan-modal--desk .qr-scan-cam { max-width: 260px; max-height: 195px; }
  /* Rezerva visine za poruku o kameri (canon §4.4) pada pod 820px: kartica
     smije poskočiti za jedan redak, ali treći put ne smije ispasti iz kadra. */
  .qr-scan-cam-note { min-height: 0; }
  .qr-scan-way-msg { min-height: 0; }
}

/* ── Tamni način ────────────────────────────────────────────────
   Mijenjaju se SAMO boje: nijedna deklaracija ne dira razmak, veličinu
   ni okvir-širinu, pa promjena teme ne pomiče layout. Tokeni dolaze iz
   components/design_tokens.html (body.dark-mode blok).
   Uz desktop karticu ovdje se zacjeljuje i mobilni ručni panel, koji je
   u tamnom načinu bio tamni tekst na tamnoj plohi (--paper prati
   --body-bg, --ink ne prati). */
body.dark-mode .qr-scan-modal--desk .qr-scan-sheet {
  background: var(--card-bg);
  color: var(--text-primary);
}
body.dark-mode .qr-scan-modal--desk .qr-scan-title,
body.dark-mode .qr-scan-modal--desk .qr-scan-couple,
body.dark-mode .qr-scan-way-title { color: var(--text-primary); }
body.dark-mode .qr-scan-desk-sub,
body.dark-mode .qr-scan-way-hint,
body.dark-mode .qr-scan-way-msg,
body.dark-mode .qr-scan-cam-note,
body.dark-mode .qr-scan-modal--desk .qr-scan-caption { color: var(--text-tertiary); }
body.dark-mode .qr-scan-desk-x { color: var(--text-tertiary); }
body.dark-mode .qr-scan-desk-x:hover { background: var(--hover-bg); color: var(--text-primary); }
/* Tražilac bez slike: u svijetlom je topla ploha, u tamnom bi ista ploha bila
   najsvjetlija stvar na kartici i vukla oko na ono što NE radi. Ostaje topla,
   samo prigušena; mauve kutovi i dalje drže okvir (nikad mrtvi crni kvadrat). */
body.dark-mode .qr-scan-modal--desk .qr-scan-cam {
  background: radial-gradient(ellipse 80% 80% at 50% 40%, var(--hover-bg), var(--input-bg));
}
body.dark-mode .qr-scan-way--file { border-color: var(--input-border); }
body.dark-mode .qr-scan-way--file.is-dragover {
  border-color: var(--color-deep-mauve);
  background: var(--hover-bg);
}
body.dark-mode .qr-scan-ghost { color: var(--mauve-300); border-color: var(--input-border); }
body.dark-mode .qr-scan-ghost:hover { background: var(--hover-bg); border-color: var(--color-deep-mauve); color: var(--mauve-100); }
body.dark-mode .qr-scan-input {
  background: var(--input-bg);
  border-color: var(--input-border);
  color: var(--text-primary);
}
body.dark-mode .qr-scan-manual { background: var(--card-bg); }
body.dark-mode .qr-scan-manual-title { color: var(--text-primary); }
body.dark-mode .qr-scan-manual-label { color: var(--text-tertiary); }

/* ── Reduced motion (desktop dio): boje se i dalje mijenjaju, samo bez tweena. ── */
@media (prefers-reduced-motion: reduce) {
  .qr-scan-desk-x,
  .qr-scan-ghost,
  .qr-scan-way--file { transition: none; }
}
