/* ripvault.css — The Vault kiosk.
 *
 * Lines 86-261 of the approved mockup (dt-vault-builder v2), verbatim, with
 * exactly three deliberate edits, each marked EDIT below:
 *
 *   1. :root tokens added (the mockup's page-level block, minus the builder-only
 *      ones). --ink is the repo's #FAF5EE, not the mockup's #F5F1E6: a five-point
 *      difference is not worth a second ink token in a codebase that already has
 *      44 uses of the first. Founder call, 2026-08-20.
 *   2. .cabinet stays the mockup's 9:17 object everywhere. It was full-viewport
 *      under body.rv-kiosk until the kiosk was removed (2026-08-21); the game
 *      now mounts inside the run screen beside the seller's own numbers.
 *
 * Everything else — every keyframe, every delay, every magic number in the rip
 * sequence — is byte-identical to the approved file. The v2 card-visibility fix
 * (.cardout opacity:0 + backface-visibility, .wrap.back translateZ(2px), opacity
 * pinned across @keyframes emerge) is carried in as part of that verbatim range.
 * Do not "tidy" the timings: 1.85s tear / 2.3s crimp / 2.45s split / 2.5s emerge
 * are load-bearing against the pull request's latency budget.
 */

/* ---------- EDIT 1: tokens ---------- */
:root{
  --cosmos:#080D1A;--cosmos-2:#0D1426;--cosmos-3:#121B31;
  --gold:#C9A84C;--gold-hi:#F1DDA0;--teal:#00B8A9;--silver:#A8B5BD;--ink:#FAF5EE;
  /* --silver-dim is NOT a text colour. Measured against every ground this app
     paints (#080D1A / #0D1426 / .card / #121B31) it lands at 3.02-3.42:1 and
     fails WCAG AA at every size. It is kept for hairlines, dividers and
     disabled states only; text uses --silver (8.2-9.2:1) or --ink at 80%
     (10.4-11.5:1). Retired as text 2026-08-20. */
  --silver-dim:#5E6872;
  --danger:#E06C6C;--ok:#58C99A;
  --vendor:#C9A84C; /* overwritten per vendor from the page payload */
  --display:'Cinzel',serif;--body:'Exo 2',sans-serif;--mono:'DM Mono',monospace;
}
*{box-sizing:border-box;margin:0;padding:0}
html,body{height:100%}
body{background:#04070F;color:var(--ink);font-family:var(--body);font-size:14px;line-height:1.5;
  background-image:radial-gradient(ellipse at 80% -10%,#132040 0%,transparent 50%),radial-gradient(ellipse at 0% 110%,#0d1a2e 0%,transparent 50%)}
a{color:inherit}
h1,h2,h3{font-family:var(--display);letter-spacing:.04em;font-weight:700}
.eyebrow{font-family:var(--mono);font-size:11px;letter-spacing:.28em;text-transform:uppercase;color:var(--teal)}
.mono{font-family:var(--mono)}
/* Secondary body copy on a dark panel: ink at 80% reads as secondary
   without dropping to a grey that fails AA (11.0:1 on .card). */
.muted{color:rgba(250,245,238,.8)}
.dim{color:var(--silver)}
button{font-family:inherit}
.btn{appearance:none;border:0;cursor:pointer;font-family:var(--display);font-weight:700;letter-spacing:.14em;text-transform:uppercase;
  font-size:12px;padding:14px 20px;border-radius:8px;color:var(--cosmos);
  background:linear-gradient(180deg,var(--gold-hi),var(--gold));box-shadow:0 8px 24px rgba(201,168,76,.22),inset 0 1px 0 rgba(255,255,255,.5);transition:transform .12s}
.btn:active{transform:translateY(1px)}
.btn.ghost{background:transparent;color:var(--silver);box-shadow:inset 0 0 0 1px rgba(168,181,189,.35)}
.btn:focus-visible{outline:2px solid var(--teal);outline-offset:2px}
.btn[disabled]{opacity:.45;pointer-events:none}

/* ---------- verbatim: mockup lines 86-261 ---------- */
/* ---------- cabinet (shared with kiosk) ---------- */
.cabinet{position:relative;width:min(400px,100%);aspect-ratio:9/17;border-radius:26px;padding:14px;margin:0 auto;
  background:linear-gradient(160deg,#1a2236,#0b1020 45%,#141b2e);box-shadow:0 0 0 1px #2a3349,0 40px 80px rgba(0,0,0,.7)}
.cabinet.small{width:min(300px,100%)}
.screen{position:relative;width:100%;height:100%;border-radius:16px;overflow:hidden;background:var(--cosmos);box-shadow:inset 0 0 0 1px rgba(201,168,76,.18)}
.view{position:absolute;inset:0;display:flex;flexDirection:column;flex-direction:column;opacity:0;pointer-events:none;transition:opacity .4s}
.view.active{opacity:1;pointer-events:auto}
.topbar{display:flex;align-items:center;justify-content:space-between;padding:16px 18px 0;font-family:var(--mono);font-size:11px;letter-spacing:.18em;color:var(--silver);text-transform:uppercase}
.topbar b{color:var(--vendor);font-weight:500}
.cobrand{display:flex;align-items:center;justify-content:center;gap:12px;padding:18px 0 0}
.cobrand .logo{width:44px;height:44px;border-radius:10px;background:#fff;display:grid;place-items:center;overflow:hidden;font-family:var(--display);font-weight:900;color:#111;font-size:16px}
.cobrand .logo img{width:100%;height:100%;object-fit:cover}
.cobrand .x{font-family:var(--mono);font-size:11px;color:var(--silver)}
.cobrand .dt{width:44px;height:44px}
.seal{width:100%;height:100%}
.seal circle{fill:none;stroke:var(--vendor);stroke-width:.6;opacity:.85}
.seal .outer{stroke-width:1;opacity:1}.seal .tick{stroke:var(--vendor);stroke-width:.8}

/* ---------- .seal.mark — the Civitas Seal AS A BRAND MARK ----------
 * Sidebar, landing nav, kiosk co-brand row, share-card footer. Full opacity,
 * always Sacred Gold (never the vendor accent — the seal is Digital Towns'
 * half of the co-brand and must not repaint itself per shop), 1.2px stroke so
 * the geometry survives at 26-44px instead of dissolving into a smudge.
 *
 * Watermark uses are deliberately NOT this: the big idle seal and the rotating
 * one behind the rip screen stay faint on purpose. */
/* vector-effect:non-scaling-stroke is load-bearing, not a flourish. The seal is
 * drawn in a 200-unit viewBox and rendered at 22-44px, so a plain stroke-width
 * of 1.2 comes out at 1.2 x (44/200) = 0.26 device px — a grey smudge. With
 * non-scaling-stroke the number means device pixels at any size, so "1.2px"
 * is literally 1.2px in the sidebar, the nav and the co-brand row alike. */
.seal.mark circle,.seal.mark line{vector-effect:non-scaling-stroke}
.seal.mark circle{stroke:var(--gold);stroke-width:1.2;opacity:1}
.seal.mark .outer{stroke:var(--gold);stroke-width:1.2;opacity:1}
.seal.mark .tick{stroke:var(--gold);stroke-width:1.2}
/* At 44px the inner bloom and the 36 ticks turn into noise; the co-brand mark
 * keeps the outer ring, the hex of six and the centre. */
.cobrand .seal.mark .tick{display:none}
.cobrand .seal.mark circle[opacity="0.35"],.cobrand .seal.mark circle[opacity=".35"]{display:none}
.k-idle{justify-content:space-between;text-align:center}
.k-seal{position:relative;width:56%;margin:6px auto 0;aspect-ratio:1}
.k-seal .seal{animation:spin 90s linear infinite}
.k-seal::after{content:"";position:absolute;inset:30%;border-radius:50%;background:radial-gradient(circle,rgba(0,184,169,.3),transparent 70%);animation:breathe 4s ease-in-out infinite}
@keyframes spin{to{transform:rotate(360deg)}}
@keyframes breathe{0%,100%{opacity:.5;transform:scale(.9)}50%{opacity:1;transform:scale(1.05)}}
.k-copy{padding:0 22px}
.k-copy h2{font-size:24px;line-height:1.05;margin:8px 0 6px}
.k-copy h2 span{color:var(--vendor)}
.k-copy p{color:rgba(250,245,238,.8);font-weight:300;font-size:13px}
.stats{display:grid;grid-template-columns:repeat(3,1fr);margin:10px 22px 10px;border:1px solid rgba(201,168,76,.25);border-radius:8px;overflow:hidden}
.stats div{padding:8px 4px;text-align:center;border-left:1px solid rgba(201,168,76,.2)}
.stats div:first-child{border-left:0}
.stats span{display:block;font-family:var(--mono);font-size:11px;letter-spacing:.2em;color:var(--silver);text-transform:uppercase}
.stats b{display:block;font-family:var(--display);font-size:16px;color:var(--vendor);margin-top:2px;transition:color .3s}
.stats b.bump{color:var(--teal)}
.k-cta{padding:0 22px 12px;display:grid;gap:8px}
.k-cta .btn{width:100%;padding:13px}
.k-cta .btn.primary{background:linear-gradient(180deg,color-mix(in srgb,var(--vendor) 55%,#fff),var(--vendor))}
.k-foot{border-top:1px solid rgba(201,168,76,.2);font-family:var(--mono);font-size:11px;letter-spacing:.16em;color:var(--silver);padding:9px 16px;display:flex;justify-content:space-between}
.k-foot b{color:var(--gold);font-weight:500}
/* set */
.k-set{padding-bottom:14px}
/* Three tiles since the Expected-pull/Avg-value duplication was removed. */
.set-head{display:grid;grid-template-columns:repeat(3,1fr);gap:6px;padding:12px 12px 8px}
.set-stat{background:var(--cosmos-2);border-radius:8px;padding:10px 6px;text-align:center;box-shadow:inset 0 0 0 1px rgba(168,181,189,.18)}
.set-stat span{display:block;font-family:var(--mono);font-size:11px;letter-spacing:.16em;color:var(--silver);text-transform:uppercase}
.set-stat b{display:block;font-family:var(--display);font-size:16px;color:var(--vendor);margin-top:4px;transition:color .3s}
.set-stat b.bump{color:var(--teal)}
.set-list{flex:1;overflow:auto;padding:2px 12px}
.row-card{display:grid;grid-template-columns:30px 1fr auto;gap:9px;align-items:center;padding:8px 0;border-top:1px solid rgba(168,181,189,.1)}
.row-card .g{width:30px;height:30px;border-radius:6px;display:grid;place-items:center;background:linear-gradient(160deg,#2a1d0c,#0f1a2b);font-family:var(--display);color:var(--vendor);font-size:12px;box-shadow:inset 0 0 0 1px rgba(201,168,76,.3)}
.row-card .n{font-size:11.5px;font-weight:600;line-height:1.15}
.row-card .m{font-family:var(--mono);font-size:11px;color:var(--silver);letter-spacing:.06em;margin-top:2px}
.row-card .r{text-align:right}
.row-card .p{font-family:var(--display);font-size:13px;color:var(--gold-hi)}
.row-card .o{font-family:var(--mono);font-size:11px;color:var(--teal)}
.row-card.pulled{opacity:.35}
.row-card.pulled .o{text-decoration:line-through;color:var(--silver)}
.set-foot{display:flex;gap:8px;padding:8px 12px 0}
.set-foot .btn{flex:1;padding:12px 8px;font-size:10px}
/* rip */
.k-rip{align-items:center;justify-content:center;overflow:hidden;position:absolute}
.bgseal{position:absolute;inset:-20%;display:grid;place-items:center;pointer-events:none;opacity:.14}
.bgseal svg{width:140%;height:140%;animation:spin 120s linear infinite}
.bgrays{position:absolute;inset:0;pointer-events:none;opacity:.0;background:repeating-conic-gradient(from 0deg,color-mix(in srgb,var(--vendor) 22%,transparent) 0 3deg,transparent 3deg 9deg);mask:radial-gradient(circle at 50% 50%,#000 0,transparent 70%)}
.bgmark{position:absolute;left:0;right:0;bottom:14px;text-align:center;font-family:var(--display);font-size:10px;letter-spacing:.42em;color:var(--silver);opacity:.7;pointer-events:none}
.bgmark b{color:var(--gold);font-weight:700}
.stage{position:relative;width:230px;height:360px;perspective:1200px;z-index:2}
.spinner{position:absolute;inset:0;transform-style:preserve-3d;animation:idleSpin 9s ease-in-out infinite}
@keyframes idleSpin{0%{transform:rotateY(-18deg) translateY(0)}50%{transform:rotateY(18deg) translateY(-10px)}100%{transform:rotateY(-18deg) translateY(0)}}
.cardout{position:absolute;left:22px;right:22px;top:30px;bottom:30px;border-radius:10px;transform:translateZ(-1px);opacity:0;backface-visibility:hidden;
  background:linear-gradient(180deg,rgba(255,255,255,.06),rgba(255,255,255,.02));
  box-shadow:0 0 0 1px rgba(255,255,255,.2),inset 0 0 0 5px rgba(255,255,255,.05);display:flex;flex-direction:column;overflow:hidden}
.cardout .tag{height:40px;background:linear-gradient(180deg,#f4f4f4,#d9d9d9);color:#111;display:grid;grid-template-columns:1fr auto;align-items:center;padding:0 9px;font-family:var(--mono);font-size:7px}
.cardout .tag .name{font-family:var(--body);font-weight:700;font-size:9px}
.cardout .tag .grade{font-family:var(--display);font-size:17px;font-weight:900}
.cardout .art{flex:1;margin:7px;border-radius:6px;background:linear-gradient(160deg,#2a1d0c,#0f1a2b 60%,#091321);display:grid;place-items:center;font-family:var(--display);font-size:44px;color:var(--vendor)}
.wrap{position:absolute;inset:0;backface-visibility:hidden;transform-style:preserve-3d}
.wrap.back{transform:rotateY(180deg) translateZ(2px)}
.foil{position:absolute;inset:0;border-radius:6px;overflow:hidden;
  background:
    linear-gradient(115deg,rgba(255,255,255,0) 30%,rgba(255,255,255,.35) 45%,rgba(255,255,255,0) 52%),
    repeating-linear-gradient(135deg,rgba(255,255,255,.05) 0 2px,transparent 2px 7px),
    linear-gradient(160deg,#2b3550 0%,#0e1530 35%,#1b2444 55%,#0a1024 100%);
  box-shadow:0 24px 50px rgba(0,0,0,.65),inset 0 0 0 1px color-mix(in srgb,var(--vendor) 45%,transparent),inset 0 0 40px rgba(0,0,0,.5);
  display:flex;flex-direction:column;align-items:center;justify-content:center;gap:8px}
.foil::before{content:"";position:absolute;inset:0;background:linear-gradient(100deg,transparent 20%,rgba(255,255,255,.18) 35%,transparent 42%,transparent 60%,color-mix(in srgb,var(--vendor) 30%,transparent) 72%,transparent 80%);mix-blend-mode:screen;animation:holo 3.4s ease-in-out infinite}
@keyframes holo{0%{transform:translateX(-40%) skewX(-12deg)}100%{transform:translateX(40%) skewX(-12deg)}}
.crimp{position:absolute;left:0;right:0;height:24px;background:repeating-linear-gradient(90deg,rgba(255,255,255,.16) 0 2px,rgba(0,0,0,.25) 2px 4px,transparent 4px 7px),linear-gradient(180deg,#3a4566,#1a2240)}
.crimp.t{top:0;border-radius:6px 6px 0 0;box-shadow:0 2px 0 rgba(0,0,0,.4)}
.crimp.b{bottom:0;border-radius:0 0 6px 6px;box-shadow:0 -2px 0 rgba(0,0,0,.4)}
.crimp::after{content:"";position:absolute;left:0;right:0;top:50%;height:1px;background:rgba(255,255,255,.18)}
.tear{position:absolute;left:-6px;right:-6px;top:23px;height:3px;z-index:3;background:repeating-linear-gradient(90deg,transparent 0 4px,rgba(255,255,255,.9) 4px 6px);opacity:0}
.foil .logo{width:58px;height:58px;border-radius:12px;background:#fff;overflow:hidden;display:grid;place-items:center;font-family:var(--display);font-weight:900;color:#111;box-shadow:0 6px 18px rgba(0,0,0,.5)}
.foil .logo img{width:100%;height:100%;object-fit:cover}
.foil .label{font-family:var(--display);font-size:14px;letter-spacing:.22em;color:var(--vendor);text-shadow:0 1px 0 rgba(0,0,0,.6)}
.foil .sub{font-family:var(--mono);font-size:8.5px;letter-spacing:.24em;color:var(--silver)}
.foil .dtseal{width:64px;height:64px;opacity:.9}
.foil .bm{font-family:var(--display);font-size:58px;font-weight:900;color:var(--vendor);line-height:1;text-shadow:0 2px 0 rgba(0,0,0,.6)}
.foil .bme{font-family:var(--mono);font-size:9px;letter-spacing:.2em;color:var(--teal);text-align:center}
.foil.half{clip-path:inset(0 50% 0 0)}
.foil.half.r{clip-path:inset(0 0 0 50%)}
.flash{position:absolute;inset:-200px;border-radius:50%;pointer-events:none;opacity:0;background:radial-gradient(circle,rgba(241,221,160,.95),color-mix(in srgb,var(--vendor) 45%,transparent) 35%,transparent 65%)}
.ring{position:absolute;left:50%;top:50%;width:40px;height:40px;border-radius:50%;border:2px solid var(--gold-hi);transform:translate(-50%,-50%) scale(0);opacity:0;pointer-events:none}
.rip-hint{position:absolute;bottom:-44px;left:0;right:0;text-align:center;font-family:var(--mono);font-size:11px;letter-spacing:.22em;color:var(--silver)}
.bits{position:absolute;inset:0;pointer-events:none}
.bit{position:absolute;width:6px;height:10px;background:linear-gradient(180deg,#fff,color-mix(in srgb,var(--vendor) 60%,#fff));opacity:0;border-radius:1px}
/* sequence */
.stage.ripping .spinner{animation:spinUp 1.9s cubic-bezier(.5,0,.15,1) forwards}
@keyframes spinUp{0%{transform:rotateY(-18deg) scale(1)}45%{transform:rotateY(900deg) scale(1.04)}75%{transform:rotateY(1800deg) scale(1.08)}100%{transform:rotateY(1800deg) scale(1)}}
.stage.ripping ~ .bgrays,.k-rip.live .bgrays{animation:rays 2.6s 1.6s ease-out forwards}
@keyframes rays{0%{opacity:0;transform:rotate(0) scale(.8)}30%{opacity:.9}100%{opacity:0;transform:rotate(40deg) scale(1.3)}}
.stage.ripping .tear{animation:tear .5s 1.85s steps(12) forwards}
@keyframes tear{from{opacity:1;clip-path:inset(0 100% 0 0)}to{opacity:1;clip-path:inset(0 0 0 0)}}
.stage.ripping .crimp.t{animation:crimpOff .7s 2.3s cubic-bezier(.5,0,.3,1) forwards}
@keyframes crimpOff{to{transform:translateY(-90px) rotateX(70deg) rotate(-8deg);opacity:0}}
.stage.ripping .foil.half.l{animation:splitL .9s 2.45s cubic-bezier(.6,0,.3,1) forwards}
.stage.ripping .foil.half.r{animation:splitR .9s 2.45s cubic-bezier(.6,0,.3,1) forwards}
@keyframes splitL{to{transform:translateX(-70px) rotateY(50deg) translateY(20px);opacity:0}}
@keyframes splitR{to{transform:translateX(70px) rotateY(-50deg) translateY(20px);opacity:0}}
.stage.ripping .cardout{animation:emerge 1.2s 2.5s cubic-bezier(.2,.9,.2,1) forwards}
@keyframes emerge{0%{opacity:1;transform:translateZ(-1px) translateY(0) scale(1)}60%{opacity:1;transform:translateZ(40px) translateY(-120px) scale(1.08)}100%{opacity:1;transform:translateZ(60px) translateY(-40px) scale(1.12)}}
.stage.ripping .flash{animation:flash .9s 2.5s ease-out forwards}
@keyframes flash{0%{opacity:0;transform:scale(.4)}25%{opacity:1}100%{opacity:0;transform:scale(1.4)}}
.stage.ripping .ring{animation:ring 1.1s 2.45s ease-out forwards}
.stage.ripping .ring.two{animation-delay:2.6s}
@keyframes ring{0%{transform:translate(-50%,-50%) scale(0);opacity:1}100%{transform:translate(-50%,-50%) scale(12);opacity:0}}
.stage.ripping .bit{animation:bit 1.3s 2.5s cubic-bezier(.2,.7,.3,1) forwards}
@keyframes bit{0%{opacity:0;transform:translate(0,0) rotate(0)}15%{opacity:1}100%{opacity:0;transform:translate(var(--dx),var(--dy)) rotate(var(--rz))}}
.bgseal{transition:opacity .6s}
.k-rip.live .bgseal{opacity:.3}
/* reveal */
.k-reveal{align-items:center;justify-content:space-between;padding-bottom:16px;text-align:center}
.slab-wrap{flex:1;display:grid;place-items:center;width:100%;position:relative}
/* SCOPED (2026-08-20). Was a bare `.slab`, which is also the type-pill modifier
   the ops page and the set list emit as <span class="tpill slab">. The reveal
   card's height:300px was landing on a 34px table row and stretching it to 317.
   The mockup has the same collision latent — it only shows once an ops page has
   a slab pull in it. The reveal card only ever lives inside .slab-wrap. */
.slab-wrap .slab{width:196px;height:300px;border-radius:12px;position:relative;background:linear-gradient(180deg,rgba(255,255,255,.06),rgba(255,255,255,.02));
  box-shadow:0 0 0 1px rgba(255,255,255,.18),inset 0 0 0 6px rgba(255,255,255,.04),0 30px 70px rgba(0,0,0,.7),0 0 60px color-mix(in srgb,var(--vendor) 25%,transparent);
  transform:translateY(60px) scale(.86);opacity:0;display:flex;flex-direction:column}
.k-reveal.active .slab{animation:rise 1s .15s cubic-bezier(.2,.9,.2,1) forwards}
@keyframes rise{to{transform:translateY(0) scale(1);opacity:1}}
.slab .tag{height:48px;border-radius:12px 12px 0 0;background:linear-gradient(180deg,#f4f4f4,#d9d9d9);color:#111;display:grid;grid-template-columns:1fr auto;align-items:center;padding:0 10px;font-family:var(--mono);font-size:8px;text-align:left}
.slab .tag .name{font-family:var(--body);font-weight:700;font-size:10px}
.slab .tag .grade{font-family:var(--display);font-size:20px;font-weight:900;line-height:1}
.slab .tag .score{font-size:7.5px;color:#555;text-align:right}
.slab .art{flex:1;margin:8px;border-radius:6px;position:relative;overflow:hidden;background:linear-gradient(160deg,#2a1d0c,#0f1a2b 60%,#091321);display:grid;place-items:center}
.slab .art .glyph{font-family:var(--display);font-size:56px;color:var(--vendor)}
.slab .art::after{content:"";position:absolute;inset:-50%;background:linear-gradient(115deg,transparent 40%,rgba(255,255,255,.22) 50%,transparent 60%);transform:translateX(-60%)}
.k-reveal.active .slab .art::after{animation:sheen 1.6s .9s ease-out forwards}
@keyframes sheen{to{transform:translateX(60%)}}
.slab .foot{height:24px;display:flex;align-items:center;justify-content:space-between;padding:0 10px;font-family:var(--mono);font-size:11px;letter-spacing:.12em;color:var(--silver)}
.reveal-copy{padding:0 22px}
.reveal-copy>*{opacity:0}
.reveal-copy h2{font-size:18px;margin:5px 0 3px}
.reveal-copy p{color:rgba(250,245,238,.8);font-size:13px;font-weight:300}
.k-reveal.active .reveal-copy>*{animation:fadeUp .6s ease forwards}
.k-reveal.active .reveal-copy .eyebrow{animation-delay:1.1s}.k-reveal.active .reveal-copy h2{animation-delay:1.25s}.k-reveal.active .reveal-copy p{animation-delay:1.4s}
@keyframes fadeUp{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}
.reveal-actions{display:flex;gap:8px;padding:12px 22px 0;width:100%}
.reveal-actions .btn{flex:1;padding:12px 8px;font-size:10px}
.spark{position:absolute;width:3px;height:3px;border-radius:50%;background:var(--gold-hi);opacity:0;pointer-events:none}
.k-reveal.active .spark{animation:spark 1.2s .2s ease-out forwards}
@keyframes spark{0%{opacity:0;transform:translate(0,0) scale(.4)}20%{opacity:1}100%{opacity:0;transform:translate(var(--dx),var(--dy)) scale(1.2)}}
/* share */
.k-share{padding:0 18px 14px;justify-content:center;gap:10px;text-align:center}
.sharecard{border-radius:12px;overflow:hidden;box-shadow:0 20px 50px rgba(0,0,0,.6);background:#000}
.sharecard canvas{width:100%;display:block}
.share-actions{display:grid;grid-template-columns:1fr 1fr;gap:8px}
.share-actions .btn{padding:12px 6px;font-size:10px}
.caption{font-family:var(--mono);font-size:11px;color:var(--silver);background:var(--cosmos-2);border:1px solid rgba(168,181,189,.2);border-radius:8px;padding:8px 10px;text-align:left;line-height:1.6;max-height:64px;overflow:auto}
/* Was a conic-gradient that LOOKED like a QR and encoded nothing. It is a real
   code now (ripvault-qr.js), so it just needs to be a white grid host. */
.qrmini{width:110px;height:110px;background:#fff;border-radius:8px;margin:0 auto;padding:5px}
.qrmini i{background:#111}
.toprize{display:inline-block;font-family:var(--display);font-size:10px;letter-spacing:.3em;color:var(--cosmos);background:linear-gradient(180deg,var(--gold-hi),var(--gold));padding:5px 10px;border-radius:4px}
/* handoff */
.k-hand{padding:0 22px 16px;justify-content:center;gap:12px;text-align:center}
.handcard{border-radius:12px;background:var(--ink);color:var(--cosmos);padding:16px;text-align:left;font-family:var(--mono);font-size:10px;letter-spacing:.06em}
.handcard .h{font-family:var(--display);font-size:12px;letter-spacing:.14em;display:flex;justify-content:space-between;margin-bottom:8px}
.handcard .big{font-family:var(--body);font-size:16px;font-weight:700;letter-spacing:0;margin:4px 0}
.handcard .row{display:flex;justify-content:space-between;border-top:1px dashed #b9b2a0;padding:5px 0}


/* ---------- EDIT 2 is GONE (2026-08-21) ----------
 * It blew .cabinet up to the full viewport under body.rv-kiosk — the standalone
 * kiosk page, which no longer exists. Every surface that mounts the game now
 * (the run screen, the builder preview, the landing demo) wants the 9:17 object
 * the mockup draws, which is what the unscoped .cabinet rule already gives. */

/* ---------- EDIT 4: mockup bug, founder-approved fix 2026-08-20 ----------
 * .k-reveal sets align-items:center, which shrinks .topbar to its content width
 * and leaves justify-content:space-between no free space — so the label and the
 * time render touching ("PULLED05:34 PM"). The mockup does the same; it is a bug
 * there, not intent. */
.k-reveal .topbar{width:100%}

/* ---------- EDIT 3 is GONE (2026-08-21) ----------
 * It mounted and positioned .oplock plus the .opsheet key box: the operator's
 * way out of an unattended kiosk. There is no kiosk and no unattended screen,
 * so there is nothing to escape from and nothing to authenticate to. Rules for
 * a control nothing renders are how a removed control comes back. */

/* ---------- the late-response hold (see ripvault-game.js::fire) ---------- */
/* The pack keeps turning while the draw is still in flight. Everything
   downstream of the spin is PAUSED rather than cancelled, so a slow network
   shows a pack that has not been opened yet — never a torn wrapper with nothing
   inside it. */
@keyframes spinHold{to{transform:rotateY(1800deg)}}
.stage.holding .spinner{animation:spinHold 1.4s linear infinite}
.stage.holding .tear,.stage.holding .crimp,.stage.holding .foil.half,
.stage.holding .cardout,.stage.holding .flash,.stage.holding .ring,.stage.holding .bit{animation-play-state:paused}

/* ---------- reduced motion ---------- */
/* The mockup's own rule, verbatim (its line 289). It flattens the rip entirely
   rather than shortening it. ripvault-game.js reads the same media query and
   shortens its 4000ms reveal wait to match — without that the flattened
   sequence finishes instantly and the customer stares at a finished animation
   for four seconds. See REVEAL_MS in that file. */
@media (prefers-reduced-motion:reduce){*{animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important}}

/* ---------- the even-odds promise on the set screen (0168) ----------
 * Sits between the stat header and the item list, because that is the moment a
 * customer is deciding — after the numbers, before the contents. */
.k-even{margin:2px 12px 8px;padding:8px 10px;border-radius:8px;background:rgba(0,184,169,.09);
  border:1px solid rgba(0,184,169,.22);font-family:var(--body);font-weight:300;
  font-size:10.5px;line-height:1.5;color:var(--ink);text-align:center}

/* ---------- kiosk: never let a section land on another ----------
 * .view is an absolutely-positioned flex column. When its content is taller
 * than the screen — a phone at 844px, or the landing page's preview cabinet —
 * space-between stops distributing and the children simply overlap: measured at
 * 2,560px² of "19" sitting on the RIP button.
 *
 * Scrolling the column and letting the seal shrink fixes it at every size
 * rather than at one breakpoint, which is why this is not in a media query. */
.k-idle,.k-set,.k-reveal,.k-share,.k-hand{overflow-y:auto;overflow-x:hidden}
.k-seal{flex:0 1 auto;min-height:0}
.k-copy,.stats,.k-cta,.k-foot{flex:none}
.slab-wrap{min-height:0}

/* ---------- [hidden] must actually hide ----------
 * The hidden attribute is a UA-stylesheet display:none, so ANY author rule that
 * sets display beats it. .pending (grid) and .quick (flex) both did, which is
 * why "Rendering your card…" stayed on screen underneath the loaded image and
 * the demo chips could show without ?demo=1. This is the general fix, not a
 * per-element patch. */
[hidden]{display:none !important}

/* ══════════════════════════════════════════════════════════════════════════
   ITEM PHOTOS (0170) — optional, per item
   ══════════════════════════════════════════════════════════════════════════
   A photo fills the slot the geometric mark occupied. Cover-fitted, because
   these are the hero of whichever surface they land on and letterboxing a card
   shot inside a card-shaped panel looks like a mistake. */
.row-card .g.has-photo{background:#0b1220;padding:0;overflow:hidden}
.row-card .g.has-photo img{width:100%;height:100%;object-fit:cover;display:block}
.cardout .art.has-photo{padding:0;overflow:hidden}
.cardout .art.has-photo img{width:100%;height:100%;object-fit:cover;display:block}
.slab .art .glyph.has-photo{width:100%;height:100%;display:block}
.slab .art .glyph.has-photo img{width:100%;height:100%;object-fit:cover;display:block}

/* ══════════════════════════════════════════════════════════════════════════
   PACK: VENDOR ACCENT FRONT, SACRED GOLD BACK  +  BRIGHTNESS PASS
   ══════════════════════════════════════════════════════════════════════════
   The two faces now say different things. The FRONT is the seller's — their
   accent, their logo, their name — and it is the face a customer looks at while
   deciding. The BACK is Digital Towns' — always Sacred Gold, never the vendor
   accent, because the seal is the platform's half of the co-brand and must not
   repaint itself per shop (the same rule .seal.mark follows).

   The brightness pass is not decoration: on a tablet on a show floor under
   fluorescent light the original surfaces read as flat dark grey. Every value
   here is lifted, and the three moving highlights — sheen, rays, flash — carry
   more opacity so the sequence still reads at arm's length. */

/* front — the vendor's face */
.wrap.front .foil{
  background:
    linear-gradient(115deg,rgba(255,255,255,0) 30%,rgba(255,255,255,.40) 45%,rgba(255,255,255,0) 55%),
    repeating-linear-gradient(135deg,rgba(255,255,255,.10) 0 2px,transparent 2px 7px),
    linear-gradient(160deg,
      color-mix(in srgb,var(--vendor) 72%,#101a30) 0%,
      color-mix(in srgb,var(--vendor) 34%,#0b1226) 38%,
      color-mix(in srgb,var(--vendor) 62%,#16224a) 58%,
      color-mix(in srgb,var(--vendor) 26%,#080e1e) 100%);
  box-shadow:0 24px 50px rgba(0,0,0,.6),
    inset 0 0 0 1.5px color-mix(in srgb,var(--vendor) 70%,transparent),
    inset 0 0 46px rgba(0,0,0,.34);
}
.wrap.front .crimp{
  background:
    repeating-linear-gradient(90deg,rgba(255,255,255,.24) 0 2px,rgba(0,0,0,.22) 2px 4px,transparent 4px 7px),
    linear-gradient(180deg,color-mix(in srgb,var(--vendor) 46%,#3a4566),color-mix(in srgb,var(--vendor) 24%,#1a2240));
}
.wrap.front .foil .label{color:#fff;text-shadow:0 1px 2px rgba(0,0,0,.55)}
.wrap.front .foil .sub{color:rgba(255,255,255,.86)}

/* back — Digital Towns, always Sacred Gold */
.wrap.back .foil{
  background:
    linear-gradient(115deg,rgba(255,255,255,0) 30%,rgba(255,255,255,.34) 45%,rgba(255,255,255,0) 55%),
    repeating-linear-gradient(135deg,rgba(201,168,76,.14) 0 2px,transparent 2px 7px),
    linear-gradient(160deg,#6b5824 0%,#171d33 40%,#54441c 62%,#0a1024 100%);
  box-shadow:0 24px 50px rgba(0,0,0,.6),
    inset 0 0 0 1.5px rgba(201,168,76,.72),
    inset 0 0 46px rgba(0,0,0,.34);
}
.wrap.back .crimp{
  background:
    repeating-linear-gradient(90deg,rgba(255,255,255,.24) 0 2px,rgba(0,0,0,.22) 2px 4px,transparent 4px 7px),
    linear-gradient(180deg,#6b5a2a,#2a2412);
}
.wrap.back .foil .dtseal{opacity:1}
.wrap.back .foil .dtseal circle{stroke:var(--gold);stroke-width:1.1;opacity:1;vector-effect:non-scaling-stroke}
.wrap.back .foil .dtseal .tick{stroke:var(--gold);stroke-width:1.1;vector-effect:non-scaling-stroke}
.wrap.back .foil .bm{color:var(--gold-hi);text-shadow:0 2px 0 rgba(0,0,0,.5)}
.wrap.back .foil .bme{color:var(--gold)}

/* the three moving highlights, lifted.
 * The travelling holo band is TINTED PER FACE: the vendor's colour on their
 * side, Sacred Gold on ours. A teal shimmer crossing the Digital Towns face
 * would be the seller's brand bleeding onto the platform's half of the
 * co-brand, which is the one thing the two-face split exists to prevent. */
.wrap.front .foil::before{
  background:linear-gradient(100deg,transparent 18%,rgba(255,255,255,.34) 35%,transparent 44%,
    transparent 58%,color-mix(in srgb,var(--vendor) 58%,transparent) 72%,transparent 82%);
}
.wrap.back .foil::before{
  background:linear-gradient(100deg,transparent 18%,rgba(255,255,255,.30) 35%,transparent 44%,
    transparent 58%,rgba(201,168,76,.55) 72%,transparent 82%);
}
.bgrays{opacity:0}
.stage.ripping ~ .bgrays,.k-rip.live .bgrays{animation:rays 2.6s 1.6s ease-out forwards}
@keyframes rays{0%{opacity:0;transform:rotate(0) scale(.8)}30%{opacity:1}100%{opacity:0;transform:rotate(40deg) scale(1.3)}}
.flash{background:radial-gradient(circle,rgba(255,250,235,1),color-mix(in srgb,var(--vendor) 62%,transparent) 36%,transparent 66%)}
.k-rip.live .bgseal{opacity:.42}

/* brighter surfaces, generally */
.cardout{background:linear-gradient(180deg,rgba(255,255,255,.12),rgba(255,255,255,.05));
  box-shadow:0 0 0 1px rgba(255,255,255,.30),inset 0 0 0 5px rgba(255,255,255,.09)}
.cardout .art{background:linear-gradient(160deg,#3a2a12,#16233a 60%,#0d1a2c)}
.slab-wrap .slab{background:linear-gradient(180deg,rgba(255,255,255,.11),rgba(255,255,255,.045));
  box-shadow:0 0 0 1px rgba(255,255,255,.26),inset 0 0 0 6px rgba(255,255,255,.07),
    0 30px 70px rgba(0,0,0,.66),0 0 74px color-mix(in srgb,var(--vendor) 34%,transparent)}
.slab .art{background:linear-gradient(160deg,#3a2a12,#16233a 60%,#0d1a2c)}
.row-card .g{background:linear-gradient(160deg,#3a2a12,#16233a)}
.set-stat{background:#141d33}
.stats{border-color:rgba(201,168,76,.34)}

/* ---------- the slab footer, at the 11px label floor ----------
 * The slab is a fixed 196px. At 11px with letter-spacing, "Graded · see label"
 * and the shop name wrapped to two lines and spilled past the slab edge. One
 * line each, truncating the shop name rather than the grade — the grade is the
 * fact, the shop name is already on the pack, the card and the share image. */
.slab .foot{gap:10px;letter-spacing:0;padding:0 12px}
.slab .foot span{min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.slab .foot span:first-child{flex:0 0 auto}
.slab .foot span:last-child{flex:1 1 auto;text-align:right}

/* ---------- the logo tile, doubled (staging walk) ----------
 * It was 58px on a ~230px pack — a stamp, not a brand. ~40% of the pack width
 * makes it the thing you see, which is the entire argument for co-branding the
 * wrapper at all. Percentage rather than pixels so it holds if the stage ever
 * changes size. The co-brand row's tile doubles to match.
 *
 * object-fit:cover was already here and was never the problem: the stored PNG
 * had transparent margins baked in by a contain-resize at upload, so cover was
 * faithfully covering the margins. Fixed in signup.js; this is the sizing half. */
.foil .logo{width:40%;height:auto;aspect-ratio:1;border-radius:16px}
.cobrand .logo{width:88px;height:88px;border-radius:18px;font-size:30px}
.cobrand .dt{width:88px;height:88px}
.cobrand{gap:18px}

/* ---------- the front door (2026-08-21) ----------
 * /rips is now the way into BOTH products, so the hero leads with two doors
 * rather than one CTA. Mint or Print was previously reachable only by typing
 * the URL. */
.doors{display:grid;grid-template-columns:1fr 1fr;gap:14px;margin:18px 0 4px}
@media (max-width:760px){.doors{grid-template-columns:1fr}}
.door{display:block;text-decoration:none;padding:18px;border-radius:14px;
  background:rgba(13,20,38,.7);border:1px solid rgba(201,168,76,.22);transition:border-color .15s,transform .15s}
.door:hover{border-color:var(--gold);transform:translateY(-2px)}
.door.on{border-color:var(--teal)}
.door b{display:block;font-family:var(--display);font-size:19px;color:var(--ink);letter-spacing:.02em}
.door span{display:block;font-weight:300;font-size:13.5px;color:var(--silver);line-height:1.6;margin-top:7px}
.door i{display:block;font-family:var(--mono);font-style:normal;font-size:10px;letter-spacing:.18em;
  text-transform:uppercase;color:var(--gold);margin-top:12px}
