/* ============================================================
   Wunvit Stamp Book
   Design system ported from the MentoScope reference and
   hue-shifted onto the provided navy-teal artwork.
   Surfaces -> ink ramp -> one reserved accent -> tokens.
   ============================================================ */
:root{
  /* Surfaces — deep navy-teal, never pure black */
  --bg:        #0a141c;
  --bg-deep:   #060e14;
  --surface:   rgba(19, 33, 43, 0.82);
  --surface-2: rgba(28, 45, 57, 0.88);
  --sunken:    rgba(8, 17, 24, 0.62);
  --line:      rgba(226, 242, 248, 0.16);
  --line-soft: rgba(226, 242, 248, 0.10);

  /* Ink — warm off-white, never pure #fff */
  --text:       #eef4f7;
  --text-soft:  #a9bfca;
  --text-faint: #7c95a2;

  /* Accent — the cyan already in the artwork. Interactive + stamped only. */
  --accent:        #3ccfe2;
  --accent-strong: #29bed2;
  --accent-deep:   #1a8ea1;
  --accent-tint:   rgba(60, 207, 226, 0.14);
  --on-accent:     #05222a;

  /* Status */
  --ok:        #54d9a6;
  --ok-tint:   rgba(84, 217, 166, 0.14);
  --warn:      #f0b45c;
  --warn-tint: rgba(240, 180, 92, 0.14);
  --bad:       #f08163;
  --bad-tint:  rgba(240, 129, 99, 0.14);

  --font-thai: "IBM Plex Sans Thai", system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-mono: "IBM Plex Mono", ui-monospace, Consolas, monospace;
  /* Osiris is latin-only display — the wordmark and nothing else. */
  --font-display: "Osiris", "IBM Plex Sans Thai", sans-serif;

  --s1:0.25rem; --s2:0.5rem; --s3:0.75rem; --s4:1rem; --s5:1.5rem; --s6:2rem; --s7:3rem;
  --r-sm:6px; --r-md:10px; --r-lg:16px; --r-full:999px;

  --shadow-md: 0 2px 8px rgba(0,0,0,0.32), 0 12px 36px rgba(0,0,0,0.34);

  --ease-quart: cubic-bezier(0.25,1,0.5,1);
  --ease-expo:  cubic-bezier(0.16,1,0.3,1);
  --dur-fast:150ms; --dur:220ms; --dur-slow:440ms;
}

*,*::before,*::after{ box-sizing:border-box; }
html{ -webkit-text-size-adjust:100%; text-size-adjust:100%; }

@font-face{
  font-family:"Osiris";
  src:url("../fonts/Osiris.woff2") format("woff2"),
      url("../fonts/Osiris.otf") format("opentype");
  font-weight:400; font-style:normal; font-display:swap;
}

body{
  margin:0; min-height:100vh;
  background:var(--bg-deep);
  font-family:var(--font-thai); color:var(--text);
  line-height:1.6; -webkit-font-smoothing:antialiased; text-rendering:optimizeLegibility;
  overflow-x:hidden;
}
h1,h2,h3{ margin:0; font-weight:600; line-height:1.2; }
p{ margin:0; }
a{ color:var(--accent); }
.mono{ font-family:var(--font-mono); font-feature-settings:"tnum" 1; }
:focus-visible{ outline:2px solid var(--accent); outline-offset:2px; border-radius:4px; }
[hidden]{ display:none !important; }

/* ------------------------------------------------------------
   Background art + the black overlay.
   Transparent enough to read the stickers, opaque enough that
   every bit of text and card sits cleanly on top of it.
   ------------------------------------------------------------ */
.bg{
  position:fixed; inset:0; z-index:-2;
  background:url("../img/bg-landing.webp") center center / cover no-repeat;
  background-color:var(--bg);
}
.bg-scrim{
  position:fixed; inset:0; z-index:-1; pointer-events:none;
  background:
    radial-gradient(120% 90% at 50% 42%, rgba(0,0,0,0.42) 0%, rgba(0,0,0,0.66) 58%, rgba(0,0,0,0.80) 100%),
    linear-gradient(180deg, rgba(6,14,20,0.42) 0%, rgba(6,14,20,0.30) 45%, rgba(6,14,20,0.62) 100%);
}
/* Reading views carry a flatter, heavier scrim than the landing — they hold body copy. */
body[data-route="page"] .bg-scrim{
  background:linear-gradient(180deg, rgba(4,10,15,0.80) 0%, rgba(4,10,15,0.72) 100%);
}

.view{ position:relative; z-index:1; }

/* ============================================================
   LANDING — orbital hero
   A 3D ring of card panels orbiting the wordmark: drag or scroll
   to spin, momentum carries, slow auto-drift when idle.
   ============================================================ */
.view--landing{
  height:100vh; height:100dvh; overflow:hidden;
  display:flex; align-items:center; justify-content:center;
}
.orbit-aura{
  position:absolute; inset:-20%; z-index:0; pointer-events:none;
  background:radial-gradient(circle at 50% 44%, var(--accent-tint), transparent 60%);
}
.orbit-stage{
  position:absolute; inset:0; z-index:1;
  display:flex; align-items:center; justify-content:center;
  perspective:1400px; cursor:grab; touch-action:pan-y;
  user-select:none; -webkit-user-select:none;
}
.orbit-stage.is-dragging, .orbit-stage.is-dragging .orbit-panel{ cursor:grabbing; }
.orbit-parallax{ position:relative; width:1px; height:1px; transform-style:preserve-3d; transition:transform 0.6s var(--ease-quart); }
/* The ring orbits BELOW the wordmark. The reference lets panels sweep across
   its title; here the title has to stay unambiguously readable, so the ring
   centre is pushed down and the wordmark lifted up out of its path. */
.orbit-tilt{ position:absolute; top:0; left:0; transform-style:preserve-3d; transform:translateY(120px) rotateX(-16deg); }
.orbit-ring{ position:absolute; top:0; left:0; transform-style:preserve-3d; will-change:transform; }

.orbit-panel{
  position:absolute; top:0; left:0;
  width:172px; height:227px; margin:-114px 0 0 -86px;
  border-radius:var(--r-lg); overflow:hidden; display:block; text-decoration:none;
  background:var(--surface); border:1px solid var(--line-soft); box-shadow:var(--shadow-md);
  transform:rotateY(var(--ry)) translateZ(var(--tz)) rotateZ(var(--rz));
  transition:border-color var(--dur) var(--ease-quart), box-shadow var(--dur) var(--ease-quart), transform 0.7s var(--ease-quart);
  cursor:pointer;
}
.orbit-panel:hover,.orbit-panel:focus-visible{ border-color:var(--accent-deep); box-shadow:0 0 0 1px var(--accent-deep), var(--shadow-md); }
.orbit-panel img{
  position:absolute; inset:0; width:100%; height:100%; object-fit:cover; display:block;
  filter:brightness(0.86);
  transition:filter var(--dur) var(--ease-quart), transform 900ms var(--ease-expo);
}
.orbit-panel:hover img{ filter:brightness(1.05); transform:scale(1.035); }
.orbit-scrim{
  position:absolute; inset:0;
  background:linear-gradient(to top, rgba(4,11,16,0.95) 0%, rgba(4,11,16,0.34) 44%, transparent 64%);
}
.orbit-cap{ position:absolute; left:0; right:0; bottom:0; padding:var(--s3) var(--s4) var(--s4); }
.orbit-kicker{ display:block; font-family:var(--font-mono); font-size:0.72rem; font-weight:500; letter-spacing:0.10em; color:var(--text); }
.orbit-sub{ display:block; margin-top:2px; font-size:0.76rem; color:var(--text-soft); }
.orbit-badge{
  position:absolute; top:10px; right:10px; z-index:2;
  font-family:var(--font-mono); font-size:0.66rem; font-weight:500; letter-spacing:0.06em;
  color:var(--accent); background:rgba(4,11,16,0.72);
  border:1px solid var(--accent-deep); border-radius:var(--r-full); padding:2px 8px;
}
/* The reward card wears a green badge the moment both thresholds are met. */
.orbit-badge[data-role="reward-badge"]{ color:var(--ok); border-color:var(--ok); }

.orbit-center{
  position:absolute; top:50%; left:50%;
  transform:translate(-50%,-50%) translateY(-170px) translateZ(30px);
  text-align:center; width:94vw; max-width:560px; pointer-events:none; z-index:2;
}
.orbit-eyebrow{ font-family:var(--font-mono); font-size:0.72rem; letter-spacing:0.16em; color:var(--accent); margin-bottom:var(--s3); }
/* Osiris on the latin wordmark only — Thai copy below uses Plex Sans Thai. */
.wordmark{
  font-family:var(--font-display); font-weight:400;
  font-size:clamp(1.75rem, 9.5vw, 4rem); letter-spacing:0.01em; line-height:1.05;
  white-space:nowrap; max-width:100%;
  text-shadow:0 2px 26px rgba(0,0,0,0.8);
}
.orbit-sub-text{
  margin-top:var(--s3); color:var(--text-soft); font-size:1rem;
  max-width:30ch; margin-inline:auto; text-wrap:pretty;
  text-shadow:0 1px 12px rgba(0,0,0,0.8);
}
.orbit-tally{
  margin-top:var(--s3); font-size:0.84rem; letter-spacing:0.01em;
  color:var(--accent); text-shadow:0 1px 10px rgba(0,0,0,0.8);
}
/* Brand tag. The orbiting cards sweep through this corner of the screen, so it
   carries its own pill rather than relying on whatever happens to be behind. */
.orbit-hint{
  position:absolute; left:50%; bottom:calc(clamp(12px,3vh,28px) + env(safe-area-inset-bottom, 0px));
  transform:translateX(-50%); z-index:3; margin:0;
  padding:0.32rem 0.9rem; border-radius:var(--r-full);
  background:rgba(6,14,20,0.72); border:1px solid var(--line-soft);
  backdrop-filter:blur(8px); -webkit-backdrop-filter:blur(8px);
  font-size:0.78rem; font-weight:500; letter-spacing:0.04em;
  color:var(--text-soft); pointer-events:none; white-space:nowrap;
}

@media (max-width:720px){
  .orbit-panel{ width:126px; height:166px; margin:-83px 0 0 -63px; }
  .orbit-tilt{ transform:translateY(98px) rotateX(-12deg); }
  .orbit-center{ transform:translate(-50%,-50%) translateY(-146px) translateZ(30px); max-width:360px; }
  .orbit-sub-text{ font-size:0.92rem; }
}
@media (max-height:620px){
  .orbit-tilt{ transform:translateY(74px) rotateX(-12deg); }
  .orbit-center{ transform:translate(-50%,-50%) translateY(-118px) translateZ(30px); }
  .orbit-sub-text{ font-size:0.86rem; }
}

/* ============================================================
   SHARED PAGE CHROME
   ============================================================ */
.view--page{ min-height:100vh; min-height:100dvh; }
.shell{
  max-width:1080px; margin:0 auto;
  padding:0 clamp(1rem,4vw,2.5rem) calc(var(--s7) + env(safe-area-inset-bottom, 0px));
}
.topbar{
  display:flex; align-items:center; justify-content:space-between; gap:var(--s4);
  padding:calc(var(--s4) + env(safe-area-inset-top, 0px)) 0 var(--s5); flex-wrap:wrap;
}
.back{
  display:inline-flex; align-items:center; gap:var(--s2);
  font-size:0.9rem; color:var(--text-soft); text-decoration:none;
  padding:var(--s2) var(--s3); margin-left:calc(var(--s3) * -1); border-radius:var(--r-sm);
  transition:color var(--dur) var(--ease-quart), background var(--dur) var(--ease-quart);
  min-height:40px;
}
.back:hover{ color:var(--text); background:var(--surface); }
.back svg{ width:15px; height:15px; flex:none; }

.mode{
  display:inline-flex; align-items:center; gap:var(--s2);
  padding:0.4rem 0.85rem 0.4rem 0.7rem;
  background:var(--surface); border:1px solid var(--line-soft); border-radius:var(--r-full);
}
.mode__dot{ width:8px; height:8px; border-radius:50%; background:var(--text-faint); flex:none; transition:background var(--dur) var(--ease-quart); }
.mode__label{ font-family:var(--font-mono); font-size:0.72rem; font-weight:500; color:var(--text-soft); letter-spacing:0.04em; }
.mode[data-mode="live"] .mode__dot{ background:var(--accent); animation:pulse-dot 1.1s var(--ease-quart) infinite; }
.mode[data-mode="ok"] .mode__dot{ background:var(--ok); box-shadow:0 0 0 3px var(--ok-tint); }
.mode[data-mode="warn"] .mode__dot{ background:var(--warn); }
.mode[data-mode="error"] .mode__dot{ background:var(--bad); }
@keyframes pulse-dot{ 0%,100%{opacity:1;} 50%{opacity:0.28;} }

.page-head{ margin-bottom:var(--s5); }
.kicker{
  font-family:var(--font-mono); font-size:0.68rem; letter-spacing:0.14em; text-transform:uppercase;
  color:var(--accent); margin-bottom:var(--s2);
}
.page-title{ font-size:clamp(1.4rem,1.1rem+1.4vw,2rem); }
.page-sub{ margin-top:var(--s2); color:var(--text-soft); max-width:52ch; text-wrap:pretty; }

.panel{
  background:var(--surface); border:1px solid var(--line-soft); border-radius:var(--r-lg);
  padding:clamp(1rem,3vw,1.5rem); backdrop-filter:blur(10px); -webkit-backdrop-filter:blur(10px);
}

.btn{
  width:100%; display:inline-flex; align-items:center; justify-content:center; gap:0.6rem;
  min-height:50px; padding:0 1.2rem;
  font-family:var(--font-thai); font-size:1rem; font-weight:600; text-decoration:none;
  border-radius:var(--r-md); border:1px solid transparent; cursor:pointer;
  transition:background var(--dur) var(--ease-quart), color var(--dur) var(--ease-quart),
             border-color var(--dur) var(--ease-quart), transform var(--dur-fast) var(--ease-quart);
}
.btn:active{ transform:scale(0.985); }
.btn--primary{ background:var(--accent); color:var(--on-accent); }
.btn--primary:hover{ background:var(--accent-strong); }
.btn--ghost{ background:transparent; color:var(--text); border-color:var(--line); }
.btn--ghost:hover{ background:var(--surface-2); border-color:var(--accent-deep); }
.btn--danger{ background:transparent; color:var(--text-faint); border-color:var(--line-soft); font-weight:500; min-height:42px; font-size:0.88rem; }
.btn--danger:hover{ color:var(--bad); border-color:var(--bad); background:var(--bad-tint); }
.btn[disabled]{ opacity:0.55; cursor:not-allowed; }

/* ============================================================
   SCAN
   ============================================================ */
.scan-grid{
  display:grid; grid-template-columns:minmax(0,1.05fr) minmax(300px,0.95fr);
  gap:clamp(1rem,3vw,1.75rem); align-items:start;
}
@media (max-width:900px){ .scan-grid{ grid-template-columns:1fr; } }

.cam{
  position:relative; width:100%; max-width:420px; margin:0 auto;
  aspect-ratio:3/4; border-radius:var(--r-lg); overflow:hidden;
  background:var(--sunken) url("../img/card-scan.webp") center center / cover no-repeat;
  border:1px solid var(--line-soft); box-shadow:var(--shadow-md);
}
.cam video{
  position:absolute; inset:0; width:100%; height:100%; object-fit:cover; display:none;
  transform-origin:center center; will-change:transform;
}
.cam.is-live video{ display:block; }
.cam.is-live{ background-image:none; background:#04090d; }

.cam__placeholder{
  position:absolute; inset:0; z-index:3;
  display:flex; flex-direction:column; align-items:center; justify-content:center; gap:var(--s2);
  padding:14%; text-align:center; color:var(--text-soft);
  background:linear-gradient(to top, rgba(4,11,16,0.86) 0%, rgba(4,11,16,0.42) 55%, rgba(4,11,16,0.30) 100%);
}
.cam.is-live .cam__placeholder{ display:none; }
.cam__placeholder svg{ width:34px; height:34px; color:var(--accent); }
.cam__placeholder-title{ font-size:0.98rem; font-weight:500; color:var(--text); }
.cam__placeholder-hint{ font-size:0.8rem; color:var(--text-faint); max-width:22ch; }

.cam__frame{ position:absolute; inset:12%; z-index:4; pointer-events:none; opacity:0; transition:opacity var(--dur) var(--ease-quart); }
.cam.is-live .cam__frame{ opacity:1; }
.bracket{ position:absolute; width:26px; height:26px; border:2px solid var(--accent); border-radius:3px; }
.bracket--tl{ top:0; left:0; border-right:0; border-bottom:0; border-radius:6px 0 0 0; }
.bracket--tr{ top:0; right:0; border-left:0; border-bottom:0; border-radius:0 6px 0 0; }
.bracket--bl{ bottom:0; left:0; border-right:0; border-top:0; border-radius:0 0 0 6px; }
.bracket--br{ bottom:0; right:0; border-left:0; border-top:0; border-radius:0 0 6px 0; }
.cam__target{ position:absolute; inset:6%; border:1.5px dashed rgba(60,207,226,0.34); border-radius:10px; }
.cam__sweep{
  position:absolute; left:0; right:0; top:0; height:26%; opacity:0;
  background:linear-gradient(to bottom, transparent 0%, var(--accent-tint) 60%, rgba(60,207,226,0.55) 100%);
  border-bottom:1.5px solid rgba(60,207,226,0.8);
}
.cam.is-live .cam__frame .bracket{ animation:bracket-lock 1.6s var(--ease-quart) infinite; }
.cam.is-live .cam__sweep{ opacity:1; animation:scan-sweep 1.9s var(--ease-quart) infinite; }
@keyframes bracket-lock{ 0%,100%{opacity:0.5;} 50%{opacity:1;} }
@keyframes scan-sweep{ from{ transform:translateY(-26%);} to{ transform:translateY(385%);} }

.cam__caption{
  position:absolute; left:0; right:0; bottom:4.5%; z-index:4; text-align:center;
  font-family:var(--font-mono); font-size:0.72rem; font-weight:500; letter-spacing:0.22em;
  color:var(--accent); pointer-events:none; opacity:0; transition:opacity var(--dur) var(--ease-quart);
}
.cam.is-live .cam__caption{ opacity:0.8; }

.cam.is-hit{ animation:hit-flash 520ms var(--ease-quart); }
@keyframes hit-flash{
  0%{ box-shadow:0 0 0 0 var(--ok), var(--shadow-md); }
  100%{ box-shadow:0 0 0 14px rgba(84,217,166,0), var(--shadow-md); }
}

.controls{ max-width:420px; margin:var(--s5) auto 0; display:flex; flex-direction:column; gap:var(--s3); }
.zoom{ display:flex; align-items:center; gap:var(--s3); background:var(--sunken); border:1px solid var(--line-soft); border-radius:var(--r-md); padding:0.55rem 0.85rem; }
.zoom__label{ font-size:0.86rem; color:var(--text-soft); flex:none; }
.zoom__range{ flex:1; min-width:0; accent-color:var(--accent); height:26px; }
.zoom__value{ flex:none; font-size:0.8rem; color:var(--accent); min-width:3.4ch; text-align:right; }

/* result */
.result{ display:flex; flex-direction:column; gap:var(--s4); }
.result__body{ display:flex; align-items:flex-start; gap:var(--s3); }
.result__icon{
  flex:none; width:44px; height:44px; border-radius:var(--r-md);
  display:grid; place-items:center; font-size:1.35rem; line-height:1;
  background:var(--surface-2); border:1px solid var(--line-soft); color:var(--text-faint);
}
.result__title{ font-size:1.05rem; font-weight:600; text-wrap:balance; }
.result__text{ margin-top:2px; font-size:0.9rem; color:var(--text-soft); text-wrap:pretty; }
.result[data-state="ok"]{ border-color:var(--ok); }
.result[data-state="ok"] .result__icon{ background:var(--ok-tint); border-color:var(--ok); color:var(--ok); }
.result[data-state="ok"] .result__title{ color:var(--ok); }
.result[data-state="dup"]{ border-color:var(--warn); }
.result[data-state="dup"] .result__icon{ background:var(--warn-tint); border-color:var(--warn); color:var(--warn); }
.result[data-state="dup"] .result__title{ color:var(--warn); }
.result[data-state="bad"]{ border-color:var(--bad); }
.result[data-state="bad"] .result__icon{ background:var(--bad-tint); border-color:var(--bad); color:var(--bad); }
.result[data-state="bad"] .result__title{ color:var(--bad); }
.result[data-state="ok"] .result__icon,
.result[data-state="dup"] .result__icon,
.result[data-state="bad"] .result__icon{ animation:pop 260ms var(--ease-expo) both; }
@keyframes pop{ from{ transform:scale(0.5); opacity:0; } to{ transform:scale(1); opacity:1; } }

.meter{ height:6px; border-radius:var(--r-full); background:var(--sunken); overflow:hidden; }
.meter__fill{ display:block; height:100%; width:0%; border-radius:var(--r-full); background:var(--accent); transition:width var(--dur-slow) var(--ease-expo), background var(--dur) var(--ease-quart); }

/* ---- criteria rows: one per group, shown on both scan and progress ----
   The bar fills toward that group's threshold, not toward its station count —
   what the kid needs to know is "how far to the prize". */
.crit-list{ display:flex; flex-direction:column; gap:var(--s3); }
.crit__top{ display:flex; align-items:baseline; justify-content:space-between; gap:var(--s2); margin-bottom:5px; }
.crit__label{ font-size:0.82rem; color:var(--text-soft); line-height:1.3; }
.crit__count{ flex:none; font-size:0.78rem; color:var(--text-faint); }
.crit__count b{ color:var(--accent); font-weight:600; }
.crit.is-pass .crit__count b{ color:var(--ok); }
.crit.is-pass .meter__fill{ background:var(--ok); }
.crit.is-pass .crit__label{ color:var(--text); }

/* ============================================================
   PROGRESS
   ============================================================ */
.progress-grid{
  display:grid; grid-template-columns:minmax(240px,0.8fr) minmax(0,1.2fr);
  gap:clamp(1rem,3vw,1.75rem); align-items:start;
}
@media (max-width:820px){ .progress-grid{ grid-template-columns:1fr; } }

.tally{ display:flex; flex-direction:column; align-items:center; text-align:center; gap:var(--s2); position:relative; }
.tally__ring{ position:relative; width:150px; height:150px; }
.ring{ width:150px; height:150px; transform:rotate(-90deg); display:block; }
.ring__track{ fill:none; stroke:var(--sunken); stroke-width:9; }
.ring__fill{
  fill:none; stroke:var(--accent); stroke-width:9; stroke-linecap:round;
  stroke-dasharray:326.7; stroke-dashoffset:326.7;
  transition:stroke-dashoffset 640ms var(--ease-expo), stroke var(--dur) var(--ease-quart);
}
.tally.is-done .ring__fill{ stroke:var(--ok); }
.tally__num{
  position:absolute; top:50%; left:50%; transform:translate(-50%,-50%);
  font-family:var(--font-mono); font-size:1.9rem; font-weight:600; line-height:1; color:var(--text);
  white-space:nowrap;
}
.tally__num span{ font-size:1rem; color:var(--text-faint); }
.tally__label{ margin-top:var(--s2); font-size:0.9rem; color:var(--text-soft); }
.tally__done{ font-size:0.92rem; font-weight:600; color:var(--ok); }
.tally .btn{ margin-top:var(--s2); }

.grp + .grp{ margin-top:var(--s5); }
.grp__head{ display:flex; align-items:center; justify-content:space-between; gap:var(--s3); }
.grp__head .kicker{ margin-bottom:0; }
.grp__count{
  flex:none; font-size:0.72rem; padding:2px 9px; border-radius:var(--r-full);
  color:var(--text-faint); background:var(--sunken); border:1px solid var(--line-soft);
}
.grp__count.is-pass{ color:var(--ok); border-color:rgba(84,217,166,0.45); background:var(--ok-tint); }

.stamp-list{ list-style:none; margin:var(--s3) 0 0; padding:0; display:flex; flex-direction:column; gap:var(--s2); }
.stamp{
  display:flex; align-items:center; gap:var(--s3);
  padding:var(--s3); border-radius:var(--r-md);
  background:var(--sunken); border:1px solid var(--line-soft);
  transition:border-color var(--dur) var(--ease-quart), background var(--dur) var(--ease-quart);
}
.stamp__icon{
  flex:none; width:38px; height:38px; border-radius:9px; display:grid; place-items:center;
  font-size:1.15rem; line-height:1; background:var(--surface-2); border:1px solid var(--line-soft);
  filter:grayscale(1) opacity(0.5); transition:filter var(--dur) var(--ease-quart);
}
.stamp__icon--code{ font-size:0.7rem; font-weight:600; letter-spacing:0.02em; color:var(--text-soft); }
.stamp.is-done .stamp__icon--code{ color:var(--ok); }
.stamp__main{ flex:1; min-width:0; }
.stamp__name{
  display:flex; align-items:center; gap:var(--s2); flex-wrap:wrap;
  font-size:0.98rem; font-weight:500; color:var(--text-soft);
}
.stamp__check{ flex:none; width:19px; height:19px; color:var(--ok); opacity:0; transform:scale(0.4); transition:opacity var(--dur) var(--ease-expo), transform var(--dur) var(--ease-expo); }

.stamp.is-done{ background:var(--ok-tint); border-color:rgba(84,217,166,0.42); }
.stamp.is-done .stamp__icon{ filter:none; border-color:rgba(84,217,166,0.42); }
.stamp.is-done .stamp__name{ color:var(--text); font-weight:600; }
.stamp.is-done .stamp__check{ opacity:1; transform:scale(1); }
.stamp.is-fresh .stamp__check{ animation:pop 320ms var(--ease-expo) both; }

/* ============================================================
   TOAST
   ============================================================ */
.toast{
  position:fixed; left:50%; bottom:calc(22px + env(safe-area-inset-bottom, 0px));
  transform:translate(-50%, 14px); z-index:50;
  max-width:min(92vw, 460px); padding:0.7rem 1.1rem;
  background:var(--surface-2); border:1px solid var(--line); border-radius:var(--r-full);
  box-shadow:var(--shadow-md); font-size:0.9rem; color:var(--text);
  opacity:0; transition:opacity var(--dur) var(--ease-quart), transform var(--dur) var(--ease-quart);
  backdrop-filter:blur(10px); -webkit-backdrop-filter:blur(10px);
  text-align:center;
}
.toast.is-open{ opacity:1; transform:translate(-50%, 0); }
.toast[data-tone="ok"]{ border-color:var(--ok); color:var(--ok); }
.toast[data-tone="warn"]{ border-color:var(--warn); color:var(--warn); }
.toast[data-tone="bad"]{ border-color:var(--bad); color:var(--bad); }

/* ============================================================
   REDUCED MOTION
   ============================================================ */
@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{
    animation-duration:0.01ms !important; animation-iteration-count:1 !important;
    transition-duration:0.01ms !important;
  }
  .cam__sweep{ display:none; }
}

/* ============================================================
   REWARD — the rules, and the card a teacher actually inspects
   ============================================================ */
.reward-grid{
  display:grid; grid-template-columns:minmax(0,1fr) minmax(0,1fr);
  gap:clamp(1rem,3vw,1.75rem); align-items:start;
}
@media (max-width:900px){ .reward-grid{ grid-template-columns:1fr; } }

.rules{ display:flex; flex-direction:column; gap:var(--s4); }
.rulelist{ margin:0; padding-left:1.3rem; display:flex; flex-direction:column; gap:var(--s3); }
.rulelist li{ font-size:0.94rem; color:var(--text-soft); text-wrap:pretty; }
.rulelist li b{ color:var(--text); font-weight:600; }
.rulelist__of{ color:var(--text-faint); font-size:0.84rem; }

.verify{ display:flex; flex-direction:column; gap:var(--s4); }
.verify[data-state="open"]{ border-color:var(--ok); box-shadow:0 0 0 1px var(--ok), var(--shadow-md); }

.verify__locked{ display:flex; flex-direction:column; align-items:center; text-align:center; gap:var(--s2); padding:var(--s4) 0; }
.verify__icon{ font-size:1.9rem; line-height:1; }
.verify__title{ font-size:1.05rem; font-weight:600; }
.verify__text{ font-size:0.88rem; color:var(--text-soft); text-wrap:pretty; }

.verify__open{ display:flex; flex-direction:column; gap:var(--s3); }
.verify__pass{
  font-size:1.15rem; font-weight:700; color:var(--ok);
  display:flex; align-items:center; gap:var(--s2);
}
.verify__pass::before{
  content:""; width:10px; height:10px; border-radius:50%; background:var(--ok);
  box-shadow:0 0 0 4px var(--ok-tint); flex:none;
  animation:pulse-dot 1.6s var(--ease-quart) infinite;
}

/* The readout a teacher reads. Monospace so the code can't be misread. */
.vcard{ background:var(--sunken); border:1px solid var(--line-soft); border-radius:var(--r-md); overflow:hidden; }
.vcard__row{
  display:flex; align-items:center; justify-content:space-between; gap:var(--s3);
  padding:0.6rem 0.85rem;
}
.vcard__row + .vcard__row{ border-top:1px solid var(--line-soft); }
.vcard__k{ font-size:0.82rem; color:var(--text-soft); }
.vcard__v{ font-size:0.9rem; color:var(--text); text-align:right; }

.vlog{ font-size:0.86rem; }
.vlog summary{ cursor:pointer; color:var(--text-soft); padding:var(--s2) 0; }
.vlog summary:hover{ color:var(--text); }
.vlog__list{ list-style:none; margin:var(--s2) 0 0; padding:0; display:flex; flex-direction:column; gap:4px; }
.vlog__list li{
  display:flex; align-items:baseline; justify-content:space-between; gap:var(--s3);
  padding:0.35rem 0.6rem; border-radius:var(--r-sm); background:var(--sunken);
  font-size:0.82rem; color:var(--text-soft);
}
.vlog__list li .mono{ flex:none; color:var(--text-faint); font-size:0.76rem; }
