/* ==========================================================================
   GLOW · scan — the face scan hero and the viewfinder. Owner: "face".
   Markup comes from js/face.js (renderScan / renderViewfinder). Only .scan* and
   .viewfinder* classes live here. Colours are ink and paper only (R = G = B).

   The print itself (greyscale, levels, tone curve, vignette, grain) is painted
   into the <canvas> by face.js; --scan-mode tells it which recipe to use, so the
   photo always follows the same theme as these rules.
   ========================================================================== */

/* ---------- 1. Scan tokens (per theme) ----------------------------------- */

.scan,
.viewfinder {
  /* white theme: high-key print with an INK mesh (amendment 13) */
  --scan-mode: light;
  --scan-ink: #0A0A0A;            /* mesh, measures, scan line                  */
  --scan-knock: #FFFFFF;          /* knocked-out nodes and the halo under lines */
  --scan-t1: .32;                 /* tessellation by depth: eyes and nose …     */
  --scan-t2: .22;
  --scan-t3: .15;
  --scan-t4: .09;                 /* … towards the oval                         */
  --scan-feat: .7;                /* contours: oval, eyes, brows, lips, irises  */
  --scan-halo: .62;
  --scan-glow: rgba(10, 10, 10, .10);
  --scan-plate-edge: rgba(10, 10, 10, .16);
  --scan-e: cubic-bezier(.45, .05, .25, 1);
}

[data-theme="dark"] .scan,
[data-theme="dark"] .viewfinder {
  /* black theme: low-key print with a WHITE mesh */
  --scan-mode: dark;
  --scan-ink: #FFFFFF;
  --scan-knock: #000000;
  --scan-t1: .5;
  --scan-t2: .34;
  --scan-t3: .22;
  --scan-t4: .13;
  --scan-feat: .86;
  --scan-halo: .55;
  --scan-glow: rgba(255, 255, 255, .15);
  --scan-plate-edge: rgba(242, 242, 242, .2);
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme]) .scan,
  :root:not([data-theme]) .viewfinder {
    --scan-mode: dark;
    --scan-ink: #FFFFFF;
    --scan-knock: #000000;
    --scan-t1: .5;
    --scan-t2: .34;
    --scan-t3: .22;
    --scan-t4: .13;
    --scan-feat: .86;
    --scan-halo: .55;
    --scan-glow: rgba(255, 255, 255, .15);
    --scan-plate-edge: rgba(242, 242, 242, .2);
  }
}

/* ---------- 2. The frame -------------------------------------------------- */

.scan { position: relative; margin: 0; }

/* 390 × 320 on a phone (≈ Atelier's 390 × 312): face + plates, a strip under the chin, no torso */
.scan__frame {
  position: relative;
  overflow: hidden;
  width: 100%;                    /* explicit: max-height must not shrink the width via the ratio */
  aspect-ratio: 390 / 320;
  max-height: 330px;
  background: var(--bg-2, #F3F3F3);
  isolation: isolate;
  contain: layout paint;
  -webkit-user-select: none;
  user-select: none;
}

.scan__photo,
.scan__veil,
.scan__mesh,
.scan__measure,
.scan__plates,
.scan__line { position: absolute; inset: 0; }

.scan__photo { display: block; width: 100%; height: 100%; }

/* crop marks of the print (decor, nothing to tap) */
.scan__c {
  position: absolute; width: 12px; height: 12px;
  border: 0 solid var(--scan-ink); opacity: .72;
  pointer-events: none;
}
.scan__c--tl { left: 10px; top: 10px; border-width: 1px 0 0 1px; }
.scan__c--tr { right: 10px; top: 10px; border-width: 1px 1px 0 0; }
.scan__c--bl { left: 10px; bottom: 10px; border-width: 0 0 1px 1px; }
.scan__c--br { right: 10px; bottom: 10px; border-width: 0 1px 1px 0; }
.scan.is-revealing .scan__c { animation: scan-fade 600ms var(--e-std, cubic-bezier(.2, 0, 0, 1)) var(--t-measure, 1440ms) both; }
.scan__mesh,
.scan__measure { display: block; width: 100%; height: 100%; overflow: visible; pointer-events: none; }
.scan__plates { pointer-events: none; }

/* ---------- 3. Mesh: four depth layers + contours ------------------------ */

.scan__t { fill: none; stroke: var(--scan-ink); stroke-width: .5; }
.scan__t--1 { stroke-opacity: var(--scan-t1); }
.scan__t--2 { stroke-opacity: var(--scan-t2); }
.scan__t--3 { stroke-opacity: var(--scan-t3); }
.scan__t--4 { stroke-opacity: var(--scan-t4); }

.scan__feat,
.scan__iris {
  fill: none; stroke: var(--scan-ink); stroke-opacity: var(--scan-feat);
  stroke-width: .9; stroke-linejoin: round; stroke-linecap: round;
}

/* ---------- 4. Tailor's measures ----------------------------------------- */

.scan__ln { fill: none; stroke: var(--scan-ink); stroke-width: 1; }
.scan__ln--dash { stroke-dasharray: 4 3; }
.scan__ln--dot { stroke-dasharray: 1 2.5; stroke-opacity: .92; }
.scan__ln--thin { stroke-width: .8; stroke-opacity: .9; }
.scan__ln--lead { stroke-opacity: .82; }

/* a soft knock-out under the long lines keeps them legible over hair or a dark suit
   (05 / 06 / 08 sit on the eyes and lips and go without it — face.js) */
.scan__halo {
  fill: none; stroke: var(--scan-knock); stroke-opacity: var(--scan-halo);
  stroke-width: 3; stroke-linecap: round; stroke-linejoin: round;
}
.scan__m .scan__halo { stroke-dasharray: none; }

/* key measuring nodes, knocked out with the paper colour */
.scan__node { fill: var(--scan-knock); stroke: var(--scan-ink); stroke-width: 1; }

/* ---------- 5. Plates: number + caps caption above a serif value --------- */

.scan__plates.is-measuring .scan__plate { visibility: hidden; }

.scan__plate {
  position: absolute; left: 0; top: 0;
  display: block;
  padding: 5px 8px 6px;
  background: var(--bg, #FFFFFF);
  color: var(--ink, #0A0A0A);
  box-shadow: inset 0 0 0 1px var(--scan-plate-edge);
  white-space: nowrap;
  text-align: left;
}
/* text leans towards the face: left column flush right, top/bottom centred; the edge the
   leader comes in through is a full ink rule — a flag on the measure, not a floating box */
.scan__plate[data-side="left"] { text-align: right; box-shadow: inset -1px 0 0 var(--scan-ink), inset 0 0 0 1px var(--scan-plate-edge); }
.scan__plate[data-side="right"] { box-shadow: inset 1px 0 0 var(--scan-ink), inset 0 0 0 1px var(--scan-plate-edge); }
.scan__plate[data-side="top"] { text-align: center; box-shadow: inset 0 -1px 0 var(--scan-ink), inset 0 0 0 1px var(--scan-plate-edge); }
.scan__plate[data-side="bottom"] { text-align: center; box-shadow: inset 0 1px 0 var(--scan-ink), inset 0 0 0 1px var(--scan-plate-edge); }

.scan__plate-head {
  display: block;
  font: 500 11px/13px var(--sans, "Geist", "Helvetica Neue", Arial, sans-serif);
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--ink-2, #464646);
}
.scan__plate-no {
  margin-right: 6px;
  font: 400 11px/13px var(--serif, "Noto Serif Display", "Geist", Georgia, serif);
  letter-spacing: .02em;
  font-variant-numeric: lining-nums tabular-nums;
  color: var(--ink-3, #6B6B6B);
}
.scan__plate-sep { font-style: normal; }
.scan__plate[data-level="wrap"] .scan__plate-sep { display: block; height: 0; overflow: hidden; }

.scan__plate-val,
.scan__plate-short {
  display: block;
  font: 400 17px/19px var(--serif, "Noto Serif Display", "Geist", Georgia, serif);
  letter-spacing: -.01em;
  font-variant-numeric: lining-nums;
  color: var(--ink, #0A0A0A);
}
.scan__plate-val { margin-top: 3px; }
.scan__plate-short { display: none; }

/* out of the reference range: an arrow, never a colour (Geist has ↑ ↓) */
.scan__plate[data-status="low"] :is(.scan__plate-val, .scan__plate-short)::after,
.scan__plate[data-status="high"] :is(.scan__plate-val, .scan__plate-short)::after {
  margin-left: 3px;
  font: 500 12px/1 var(--sans, "Geist", sans-serif);
  vertical-align: 2px;
  color: var(--ink-2, #464646);
}
.scan__plate[data-status="low"] :is(.scan__plate-val, .scan__plate-short)::after { content: "↓"; }
.scan__plate[data-status="high"] :is(.scan__plate-val, .scan__plate-short)::after { content: "↑"; }

/* graceful degradation, chosen in JS from measured sizes:
   full → wrap (caption on two lines) → compact (number + value) → mini (number) */
.scan__plate[data-level="compact"] { padding: 4px 8px 5px 7px; }
.scan__plate[data-level="compact"] .scan__plate-head,
.scan__plate[data-level="mini"] .scan__plate-head { display: inline; }
.scan__plate[data-level="compact"] .scan__plate-cap,
.scan__plate[data-level="compact"] .scan__plate-val,
.scan__plate[data-level="mini"] .scan__plate-cap,
.scan__plate[data-level="mini"] .scan__plate-val,
.scan__plate[data-level="mini"] .scan__plate-short { display: none; }
.scan__plate[data-level="compact"] .scan__plate-short { display: inline; font-size: 16px; line-height: 18px; }

.scan__plate[data-level="mini"] { padding: 4px 6px 5px; }
.scan__plate[data-level="mini"] .scan__plate-no { margin-right: 0; color: var(--ink, #0A0A0A); }

.scan__plate[data-level="none"] { display: none; }

/* ---------- 6. Caption strip under the print ------------------------------ */

/* date ……… yaw on the first line (the yaw drops below when they do not fit), points under them */
.scan__strip {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: baseline;
  column-gap: 12px;
  row-gap: 6px;
  padding: 12px var(--gutter, 24px) 2px;
  font: 500 11px/14px var(--sans, "Geist", "Helvetica Neue", Arial, sans-serif);
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--ink-3, #6B6B6B);
}
.scan__strip b { font-weight: 500; color: var(--ink, #0A0A0A); }
.scan__cap { white-space: nowrap; }
.scan__cap--date { order: 1; }
.scan__cap--yaw { order: 2; display: inline-flex; align-items: center; gap: 7px; }
.scan__cap--pts { order: 3; flex-basis: 100%; }
.scan__flag { flex: none; width: 7px; height: 7px; background: var(--ink, #0A0A0A); }
.scan__cap--yaw[data-state="turned"] { color: var(--ink, #0A0A0A); font-weight: 600; }
.scan__cap--yaw[data-state="turned"] .scan__flag { background: transparent; box-shadow: inset 0 0 0 1px var(--ink, #0A0A0A); }

/* AI at work (setBusy): the strip says what the sweeping line is — same two rows, no reflow */
.scan__cap--busy,
.scan__cap--eta,
.scan__cap--note { display: none; }
.scan.is-busy .scan__cap--date,
.scan.is-busy .scan__cap--yaw,
.scan.is-busy .scan__cap--pts { display: none; }
.scan.is-busy .scan__cap--busy { display: block; order: 1; color: var(--ink, #0A0A0A); }
.scan.is-busy .scan__cap--eta { display: inline; order: 2; }
.scan.is-busy .scan__cap--note { display: inline; order: 3; flex-basis: 100%; }
.scan__lens { display: inline-block; width: 13px; height: 13px; margin-right: 8px; vertical-align: -2px; }

/* ---------- 7. Reveal: line sweeps, mesh behind it, then measures, then plates */

.scan__veil { background: var(--bg, #FFFFFF); opacity: 0; pointer-events: none; }

.scan__line {
  pointer-events: none;
  opacity: 0;
  transform: translateY(-100%);
  border-bottom: 1px solid var(--scan-ink);
  background: linear-gradient(to bottom, transparent 58%, var(--scan-glow));
  will-change: transform;
}

.scan.is-revealing .scan__line {
  animation:
    scan-sweep var(--sweep, 1700ms) var(--scan-e) both,
    scan-line-out 420ms linear calc(var(--sweep, 1700ms) - 60ms) both;
}
.scan.is-revealing .scan__mesh { animation: scan-wipe var(--sweep, 1700ms) var(--scan-e) both; }
.scan.is-revealing .scan__veil { animation: scan-unveil var(--sweep, 1700ms) var(--scan-e) both; }
.scan.is-revealing .scan__m {
  animation: scan-fade 520ms var(--e-std, cubic-bezier(.2, 0, 0, 1)) both;
  animation-delay: calc(var(--t-measure, 1440ms) + var(--i, 0) * 85ms);
}
.scan.is-revealing .scan__node {
  transform-box: fill-box;
  transform-origin: center;
  animation: scan-pop 320ms var(--e-out, cubic-bezier(.16, 1, .3, 1)) both;
  animation-delay: calc(var(--t-measure, 1440ms) + 140ms + var(--i, 0) * 26ms);
}
.scan.is-revealing .scan__lead {
  animation: scan-fade 360ms var(--e-std, cubic-bezier(.2, 0, 0, 1)) both;
  animation-delay: var(--d, 0ms);
}
.scan.is-revealing .scan__plate {
  animation: plate-in-r 520ms var(--e-out, cubic-bezier(.16, 1, .3, 1)) both;
  animation-delay: var(--d, 0ms);
}
.scan.is-revealing .scan__plate[data-side="left"] { animation-name: plate-in-l; }
.scan.is-revealing .scan__plate[data-side="top"] { animation-name: plate-in-t; }
.scan.is-revealing .scan__plate[data-side="bottom"] { animation-name: plate-in-b; }

@keyframes scan-sweep { from { transform: translateY(-100%); } to { transform: translateY(0); } }
@keyframes scan-line-out { from { opacity: 1; } to { opacity: 0; } }
@keyframes scan-wipe { from { clip-path: inset(0 0 100% 0); } to { clip-path: inset(0 0 0 0); } }
@keyframes scan-unveil {
  from { opacity: .58; clip-path: inset(0 0 0 0); }
  to { opacity: .58; clip-path: inset(100% 0 0 0); }
}
@keyframes scan-fade { from { opacity: 0; } to { opacity: 1; } }
@keyframes scan-pop { from { transform: scale(0); } to { transform: scale(1); } }
/* plates unfold from the side their leader comes in */
@keyframes plate-in-l { from { opacity: 0; clip-path: inset(0 0 0 100%); } to { opacity: 1; clip-path: inset(0 0 0 0); } }
@keyframes plate-in-r { from { opacity: 0; clip-path: inset(0 100% 0 0); } to { opacity: 1; clip-path: inset(0 0 0 0); } }
@keyframes plate-in-t { from { opacity: 0; clip-path: inset(100% 0 0 0); } to { opacity: 1; clip-path: inset(0 0 0 0); } }
@keyframes plate-in-b { from { opacity: 0; clip-path: inset(0 0 100% 0); } to { opacity: 1; clip-path: inset(0 0 0 0); } }

/* AI analysis in progress: the line sweeps over the finished mesh, measures step back */
.scan__measure,
.scan__plates { transition: opacity 320ms var(--e-std, cubic-bezier(.2, 0, 0, 1)); }
.scan.is-busy .scan__measure,
.scan.is-busy .scan__plates { opacity: 0; }
.scan.is-busy .scan__line { opacity: 1; animation: scan-busy 2.2s var(--e-io, cubic-bezier(.77, 0, .175, 1)) infinite alternate; }
@keyframes scan-busy { from { transform: translateY(-97%); } to { transform: translateY(-2%); } }
.scan.is-paused .scan__line { animation-play-state: paused; }

/* ---------- 8. Viewfinder (empty state) ----------------------------------- */

.viewfinder { position: relative; margin: 0; }

.viewfinder__frame {
  position: relative;
  overflow: hidden;
  aspect-ratio: var(--vf-ratio, 342 / 236);
  background: var(--bg-2, #F3F3F3);
  contain: layout paint;
}

.viewfinder__art { position: absolute; inset: 0; display: block; width: 100%; height: 100%; }
.viewfinder__mesh {
  fill: none; stroke: var(--ink, #0A0A0A); stroke-opacity: .13; stroke-width: .6;
  vector-effect: non-scaling-stroke;
}
.viewfinder__mesh--1 { stroke-opacity: .22; }
.viewfinder__mesh--2 { stroke-opacity: .14; }
.viewfinder__mesh--3 { stroke-opacity: .085; }
.viewfinder__feat {
  fill: none; stroke: var(--ink, #0A0A0A); stroke-opacity: .46; stroke-width: .8;
  stroke-linejoin: round; vector-effect: non-scaling-stroke;
}
.viewfinder__oval {
  fill: none; stroke: var(--ink-3, #6B6B6B); stroke-width: 1; stroke-dasharray: 3 3;
  vector-effect: non-scaling-stroke;
}
.viewfinder__guide {
  fill: none; stroke: var(--ink-4, #A8A8A8); stroke-width: 1; stroke-dasharray: 2 3;
  vector-effect: non-scaling-stroke;
}

.viewfinder__c { position: absolute; width: 18px; height: 18px; border: 0 solid var(--ink, #0A0A0A); }
.viewfinder__c--tl { left: 12px; top: 12px; border-width: 1px 0 0 1px; }
.viewfinder__c--tr { right: 12px; top: 12px; border-width: 1px 1px 0 0; }
.viewfinder__c--bl { left: 12px; bottom: 12px; border-width: 0 0 1px 1px; }
.viewfinder__c--br { right: 12px; bottom: 12px; border-width: 0 1px 1px 0; }

.viewfinder__hint {
  position: absolute; left: 36px; right: 36px; bottom: 15px;
  margin: 0;
  text-align: center;
  font: 500 11px/1.2 var(--sans, "Geist", "Helvetica Neue", Arial, sans-serif);
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--ink-2, #464646);
}

.viewfinder__sweep {
  position: absolute; inset: 0;
  pointer-events: none;
  opacity: 0;
  transform: translateY(-100%);
  border-bottom: 1px solid var(--ink, #0A0A0A);
  background: linear-gradient(to bottom, transparent 58%, var(--scan-glow));
}
.viewfinder[data-status="scanning"] .viewfinder__sweep {
  opacity: 1;
  animation: scan-busy 2.2s var(--e-io, cubic-bezier(.77, 0, .175, 1)) infinite alternate;
}
.viewfinder[data-status="scanning"] .viewfinder__hint { color: var(--ink, #0A0A0A); }

/* status line: label ——— track ——— state */
.viewfinder__status {
  display: flex; align-items: center; gap: 14px;
  min-height: 44px;
  font: 500 11px/1.2 var(--sans, "Geist", "Helvetica Neue", Arial, sans-serif);
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--ink-2, #464646);
}
.viewfinder__label { flex: none; }
.viewfinder__state { flex: none; color: var(--ink, #0A0A0A); }
.viewfinder__track {
  position: relative; flex: 1 1 auto; min-width: 24px;
  height: 1px; overflow: hidden;
  background: var(--rule-2, #D4D4D4);
}
.viewfinder__track i {
  position: absolute; left: 0; top: 0; bottom: 0; width: 30%;
  background: var(--ink, #0A0A0A);
  animation: vf-run 1.4s var(--e-io, cubic-bezier(.77, 0, .175, 1)) infinite;
}
@keyframes vf-run { from { transform: translateX(-100%); } to { transform: translateX(340%); } }
.viewfinder[data-status="ready"] .viewfinder__track i { width: 100%; animation: none; transform: none; }
.viewfinder.is-paused .viewfinder__sweep,
.viewfinder.is-paused .viewfinder__track i { animation-play-state: paused; }

.viewfinder__error { display: none; }
.viewfinder[data-status="error"] .viewfinder__label,
.viewfinder[data-status="error"] .viewfinder__track,
.viewfinder[data-status="error"] .viewfinder__state { display: none; }
.viewfinder[data-status="error"] .viewfinder__error {
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
  width: 100%;
  padding: 6px 0;
}
.viewfinder__error-text {
  font: 400 14px/1.45 var(--sans, "Geist", "Helvetica Neue", Arial, sans-serif);
  letter-spacing: 0;
  text-transform: none;
  color: var(--ink, #0A0A0A);
}
.viewfinder__retry {
  position: relative; flex: none;
  min-height: 44px; padding: 0 2px;
  font: 500 11px/1 var(--sans, "Geist", "Helvetica Neue", Arial, sans-serif);
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--ink, #0A0A0A);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 5px;
  background: none; border: 0; cursor: pointer;
}
.viewfinder__retry[hidden] { display: none; }

/* old WebViews without aspect-ratio (iOS < 15): the frames would collapse to 0 px */
@supports not (aspect-ratio: 1 / 1) {
  .scan__frame { height: 0; padding-top: 82.05%; }
  .viewfinder__frame { height: 0; padding-top: 69%; }
}

/* ---------- 9. Reduced motion: final state at once ------------------------ */

@media (prefers-reduced-motion: reduce) {
  .scan.is-revealing .scan__line,
  .scan.is-revealing .scan__mesh,
  .scan.is-revealing .scan__veil,
  .scan.is-revealing .scan__m,
  .scan.is-revealing .scan__node,
  .scan.is-revealing .scan__lead,
  .scan.is-revealing .scan__plate,
  .scan.is-revealing .scan__c { animation: none; }
  .scan.is-busy .scan__line,
  .viewfinder[data-status="scanning"] .viewfinder__sweep { animation: none; transform: translateY(-50%); }
  .viewfinder__track i { animation: none; left: 35%; }
  .scan__measure,
  .scan__plates { transition: none; }
}
