/* KLINK — card payment terminal for ages 2–5
   Two worlds: cream paper (child) and slate (grown-up).
   Payment moment implements handoff option 4b. */

:root{
  /* ---- colour ---- */
  --ink:#2A2318;
  --ink-62:rgba(42,35,24,.62);
  --ink-45:rgba(42,35,24,.45);
  --ink-42:rgba(42,35,24,.42);
  --cream:#FBF6EA;
  --cream-warm:#FDF7E6;
  --paper:#F1EAD8;
  --panel:#F6E9CF;
  --green:#1F6F4A;
  --green-deep:#16543A;
  --success:#3E9B57;
  --blue:#2E7DD1;
  --blue-deep:#1B5AA0;
  --blue-line:rgba(46,125,209,.55);
  /* tap target — monochrome warm grey, drawn from the ink */
  --target-line:rgba(42,35,24,.34);
  --target-glow:rgba(42,35,24,.13);
  /* shortfall — the poppy red already in the card themes */
  --short:#B93A22;
  --short-soft:rgba(185,58,34,.10);
  --amber-band:#F3E1BB;
  --amber:#C98A1E;
  --amber-badge:#D98324;
  --amber-badge-deep:#A56013;
  --mint-band:#CFE9D6;
  --mint:#2E8B57;
  --mint-deep:#1E6B40;
  --mint-bg:#F3FAF3;
  --slate:#171A21;
  --slate-panel:#21252E;
  --slate-ink:#E8E4DA;
  --slate-mute:#7E8B9C;

  /* ---- golden spacing scale ----
     φ ≈ 1.618, Fibonacci-rounded so every step is the sum of the two before it.
     All padding, gaps and vertical rhythm come from this ladder — nothing
     in between. Sizes the handoff pins exactly (55px digit, 186×118 card,
     34px badge coin) stay as specified; the scale governs the space around them. */
  --s0:3px;
  --s1:5px;
  --s2:8px;
  --s3:13px;
  --s4:21px;
  --s5:34px;
  --s6:55px;
  --s7:89px;

  /* golden sections of a full screen height */
  --minor:38.2%;
  --major:61.8%;

  /* ---- radii ---- */
  --r-screen:34px;
  --r-card:16px;
  --r-lg:21px;
  --r-md:13px;
  --r-sm:8px;
  --r-chip:6px;

  --mono:'IBM Plex Mono',ui-monospace,SFMono-Regular,Menlo,monospace;
  --round:'Baloo 2',system-ui,sans-serif;
  --body:Nunito,system-ui,-apple-system,sans-serif;
}

*{box-sizing:border-box;-webkit-tap-highlight-color:transparent}

html,body{height:100%}
body{
  margin:0;
  font-family:var(--body);
  color:var(--ink);
  background:#DDD6C8;
  display:flex;
  align-items:center;
  justify-content:center;
  overflow:hidden;
}

/* ---------- device shell ---------- */
.device{
  width:380px;
  height:min(824px,96vh);
  padding:var(--s2);
  border-radius:44px;
  background:#1A1E25;
  box-shadow:0 var(--s4) 44px rgba(30,20,5,.3);
  flex:none;
}
.screen{
  position:relative;
  height:100%;
  border-radius:var(--r-screen);
  overflow:hidden;
  background:var(--cream);
  display:flex;
  flex-direction:column;
  isolation:isolate;
}
@media (max-width:520px),(max-height:700px){
  body{background:#1A1E25}
  .device{width:100vw;height:100dvh;padding:0;border-radius:0;box-shadow:none}
  .screen{border-radius:0}
}

.fade{animation:klFade .26s ease both}
@keyframes klFade{from{opacity:0;transform:translateY(var(--s1))}to{opacity:1;transform:none}}

/* ---------- status bar ---------- */
.status{
  display:flex;align-items:center;justify-content:space-between;
  padding:var(--s3) var(--s4) 0;
  font:600 10px var(--mono);
  letter-spacing:.16em;
  color:var(--ink-42);
  flex:none;
}
.status.on-dark{color:rgba(232,228,218,.45)}
.status.on-theme{color:rgba(255,255,255,.6)}

/* ---------- navigation ----------
   One slot, one place, every screen: the Material navigation position at the
   start of the top bar. 44px minimum target, muted so a child won't aim for
   it, and never anywhere else on the screen. */
.navbar{
  display:flex;align-items:center;gap:var(--s2);
  padding:var(--s2) var(--s3) 0;min-height:var(--s6);flex:none;
}
.navbtn{
  width:44px;height:44px;flex:none;border:0;background:none;padding:0;cursor:pointer;
  display:flex;align-items:center;justify-content:center;border-radius:50%;
}
.navbtn:active{background:rgba(42,35,24,.07)}
.navbtn .chev{
  display:block;width:12px;height:12px;margin-left:4px;
  border-left:3px solid var(--ink-45);border-bottom:3px solid var(--ink-45);
  transform:rotate(45deg);
}
.navbtn .x{position:relative;display:block;width:18px;height:18px}
.navbtn .x::before,.navbtn .x::after{
  content:'';position:absolute;left:0;top:8px;width:18px;height:3px;border-radius:2px;
  background:var(--ink-45);
}
.navbtn .x::before{transform:rotate(45deg)}
.navbtn .x::after{transform:rotate(-45deg)}
.navbar .title{font:600 10px var(--mono);letter-spacing:.16em;text-transform:uppercase;color:var(--ink-42)}

.dark .navbtn:active{background:rgba(232,228,218,.08)}
.dark .navbtn .chev{border-color:rgba(232,228,218,.5)}
.dark .navbtn .x::before,.dark .navbtn .x::after{background:rgba(232,228,218,.5)}
.dark .navbar .title{color:var(--slate-mute)}

/* ---------- shared type ---------- */
.mono{font:600 10px var(--mono);letter-spacing:.18em;text-transform:uppercase}
.mute{color:var(--ink-42)}
.wordmark{font:800 22px var(--round);letter-spacing:-.01em}

/* ---------- the coin ---------- */
.coin{
  position:relative;flex:none;border-radius:50%;
  background:radial-gradient(circle at 34% 26%,#fff7d6 0%,#f9d35d 34%,#e6a924 66%,#b8781a 100%);
}
.coin .rim{position:absolute;border-radius:50%;border:2px solid rgba(255,248,214,.6)}
.coin .face{position:absolute;left:50%;top:50%;transform:rotate(45deg);background:linear-gradient(140deg,#fffbea,#e9b53a);box-shadow:inset 0 0 0 1px rgba(140,90,10,.25)}
.coin .spec{position:absolute;left:22%;top:13%;border-radius:50%;background:rgba(255,255,255,.7)}

.coin.ghost{background:rgba(165,130,60,.09);border:2px dashed rgba(150,115,45,.55);box-shadow:none!important}
.coin.ghost .rim,.coin.ghost .spec{display:none}
.coin.ghost .face{background:none;border:2px dashed rgba(150,115,45,.45);box-shadow:none}

/* coin + numeral pair — the amount format everywhere in the app */
.cc{display:inline-flex;align-items:center;flex:none}
.cc .num{font-family:var(--round);font-weight:800;line-height:.9;letter-spacing:-.02em;font-variant-numeric:tabular-nums}

/* ---------- buttons ---------- */
.btn{border:0;font-family:inherit;cursor:pointer;display:flex;align-items:center;justify-content:center;user-select:none}
.btn:active{transform:translateY(2px)}
.btn-go{
  height:var(--s7);border-radius:26px;background:var(--green);
  box-shadow:0 7px 0 var(--green-deep);gap:var(--s3);width:100%;
}
.btn-go:active{box-shadow:0 var(--s0) 0 var(--green-deep)}
.btn-go span{font:800 30px var(--round);color:#fff}
.btn-ready{
  height:var(--s6)+15px;height:70px;border-radius:var(--r-lg);background:var(--green);
  box-shadow:0 var(--s1) 0 var(--green-deep);width:100%;
}
.btn-ready:active{box-shadow:0 2px 0 var(--green-deep)}
.btn-ready span{font:800 24px var(--round);color:#fff}
.btn-ready[disabled]{background:#C9C2B4;box-shadow:0 var(--s1) 0 #ABA495;cursor:default}
.btn-ready[disabled]:active{transform:none;box-shadow:0 var(--s1) 0 #ABA495}
.pill-adult{
  display:flex;align-items:center;gap:var(--s2);padding:var(--s2) var(--s4);border-radius:999px;
  border:1.5px solid rgba(42,35,24,.16);background:none;
  font:600 10px var(--mono);letter-spacing:.14em;color:var(--ink-45);
}
.pill-adult i{display:block;width:11px;height:9px;border-radius:2px;background:rgba(42,35,24,.4)}

.plus-glyph{position:relative;flex:none}
.plus-glyph span{position:absolute;border-radius:var(--s0);background:#fff}

/* ---------- keypads ---------- */
.pad{display:grid;grid-template-columns:repeat(3,1fr);gap:var(--s2)}
.key{
  height:var(--s6);border-radius:var(--r-card);background:#fff;
  box-shadow:0 var(--s0) 0 rgba(42,35,24,.1);
  font:700 26px var(--round);color:var(--ink);
}
.key:active{box-shadow:0 1px 0 rgba(42,35,24,.1)}
.key.util{background:rgba(42,35,24,.06);box-shadow:none;font:600 11px var(--mono);letter-spacing:.1em;color:var(--ink-45)}
.key.blank{background:rgba(42,35,24,.03);box-shadow:none;cursor:default}
.key.blank:active{transform:none}

.pad-dark .key{
  height:52px;border-radius:var(--r-md);background:var(--slate-panel);
  border:1px solid rgba(232,228,218,.08);box-shadow:none;
  font:500 19px var(--mono);color:var(--slate-ink);
}
.pad-dark .key.util{background:none;border:0;font:500 10px var(--mono);color:rgba(232,228,218,.4)}

/* ================================================================
   PAYMENT MOMENT — handoff option 4b
   ================================================================ */

.pay{position:relative;flex:1;display:flex;flex-direction:column}

/* tap target: the minor golden section of the screen */
.tapzone{position:relative;height:var(--minor);flex:none}
.tapzone-in{
  position:absolute;left:0;right:0;top:50%;transform:translateY(-50%);
  display:flex;flex-direction:column;align-items:center;gap:var(--s5);
}
/* The same target, laid out in flow instead of pinned to the middle of a
   tap zone — idle, registration and card-linking each place it themselves.
   It stays positioned so the note underneath can hang off it. */
.tapzone-in.inflow{position:relative;top:0;transform:none}

/* A single breathing glow behind the card glyph, in warm grey — the target
   says "a card goes here" without borrowing any child's colour. The glyph
   itself never changes: the light lives strictly behind it. */
.glowwrap{position:relative;width:62px;height:39px;display:flex;align-items:center;justify-content:center}
.glow{
  position:absolute;left:-14px;top:-11px;right:-14px;bottom:-11px;border-radius:var(--r-md);
  background:var(--target-glow);
  filter:blur(11px);
  animation:klBreathe 1.4s ease-in-out infinite alternate;
}

/* Card glyph — one third of the handoff's 186×118 footprint.
   It marks the centre of the landing zone rather than tracing its outline. */
.cardglyph{
  position:relative;width:62px;height:39px;border-radius:var(--r-chip);
  border:2px solid var(--target-line);
  background:var(--cream);
}
.cardglyph .chip{position:absolute;left:var(--s1);top:var(--s1);width:10px;height:8px;border-radius:2px;border:1.5px solid rgba(42,35,24,.3)}
.cardglyph .b1{position:absolute;left:var(--s1);bottom:7px;width:26px;height:3px;border-radius:2px;background:rgba(42,35,24,.22)}
.cardglyph .b2{position:absolute;left:var(--s1);bottom:13px;width:17px;height:3px;border-radius:2px;background:rgba(42,35,24,.14)}

.prompt{font:800 19px var(--round);color:var(--ink-45);animation:klBobSm 1.8s ease-in-out infinite}

/* the same target, inverted for the slate world */
.on-slate .glow{background:rgba(232,228,218,.16)}
.on-slate .cardglyph{border-color:rgba(232,228,218,.32);background:var(--slate)}
.on-slate .cardglyph .chip{border-color:rgba(232,228,218,.3)}
.on-slate .cardglyph .b1{background:rgba(232,228,218,.24)}
.on-slate .cardglyph .b2{background:rgba(232,228,218,.15)}
.on-slate .prompt{color:rgba(232,228,218,.55)}

.target-out{animation:klTargetOut .12s ease both}
@keyframes klTargetOut{to{opacity:0;transform:scale(.86)}}
@keyframes klBreathe{from{transform:scale(.9);opacity:.45}to{transform:scale(1.08);opacity:.9}}
@keyframes klPulseRing{0%{transform:scale(.55);opacity:0}12%{opacity:.75}45%{transform:scale(1.5);opacity:0}100%{transform:scale(1.5);opacity:0}}
@keyframes klBobSm{0%,100%{transform:translateY(0)}50%{transform:translateY(-4px)}}

/* the real card, landing on the glyph's centre */
.paycard{
  position:absolute;left:50%;top:50%;width:186px;height:118px;margin:-59px 0 0 -93px;
  border-radius:var(--r-card);
  background:linear-gradient(135deg,var(--blue),var(--blue-deep));
  box-shadow:0 9px 0 rgba(0,0,0,.18),0 var(--r-card) 26px rgba(20,45,85,.26);
  opacity:0;
}
.paycard .chip{position:absolute;left:var(--r-card);top:14px;width:30px;height:23px;border-radius:var(--r-chip);background:linear-gradient(140deg,#fff3c0,#e0ab2c)}
.paycard .who{position:absolute;right:15px;top:15px;font:800 15px var(--round);color:rgba(255,255,255,.85)}
.paycard .badge{position:absolute;left:18px;bottom:var(--r-card);display:flex;align-items:center;gap:10px}
/* a slot window too, and it reserves the width of the starting balance so
   the badge does not shift as the count crosses 10 */
.paycard .badge .num{
  position:relative;overflow:hidden;display:block;
  width:calc(var(--digits,2) * 1ch);height:30px;
  font:800 27px/1.1 var(--round);color:#fff;
  text-align:left;font-variant-numeric:tabular-nums;
}
.dashring{position:absolute;left:0;top:0;width:34px;height:34px;border-radius:50%;border:2px dashed rgba(255,255,255,.5)}

/* Amount — the price keeps its place on the golden section and never moves.
   The coins gathered so far appear in a matching row directly above it, so the
   two read as the same kind of thing and "are they equal yet?" is the question
   the block asks. */
.amountzone{position:relative;flex:1}
.amount{
  position:absolute;left:0;right:0;top:calc(var(--major) - 29px);
  display:flex;flex-direction:column;align-items:center;
}
.amount-row{display:flex;align-items:center;justify-content:center;gap:var(--s3);height:58px}
/* anchored to the price row's top edge, so gathering coins never shifts it */
.amount-acc{position:absolute;left:0;right:0;bottom:calc(100% + var(--s3));opacity:0}
.amount-goal{position:relative;width:100%}
.goal-wrap{display:flex;align-items:center;justify-content:center;gap:var(--s3);height:58px}
.amount-coin{position:relative;width:40px;height:40px;flex:none}
/* Both rows reserve the width of the longest number and right-align into it,
   so the digits line up under each other and the coin never moves as the
   count grows past 9 or 99. */
.amount-digit{
  position:relative;overflow:hidden;
  width:calc(var(--digits,1) * 1ch);height:58px;flex:none;
  font:800 55px/1.05 var(--round);letter-spacing:-.02em;color:var(--ink);
  text-align:right;font-variant-numeric:tabular-nums;
}
/* dense counts hold a standing blur like a spinning reel and settle once */
.amount-digit.rolling,.paycard .num.rolling{filter:blur(1.9px);transform:scaleY(1.16)}
.amount-digit.short{color:var(--short)}

/* The slot-machine window. Every number that changes is a stack of `.roll`
   layers inside a box with `overflow:hidden`: the one leaving climbs out
   of the top while the one arriving climbs in from the bottom, and the
   clip is what makes it read as a reel turning over rather than two
   numbers sharing a space. Driven by rollTo() in app/app.js. */
.roll{
  display:block;position:absolute;left:0;right:0;top:0;
  will-change:transform,filter;
}

/* "Paid ✓" lands in the price row's place once the two numbers agree */
.paid{
  position:absolute;left:0;right:0;top:0;height:58px;
  display:flex;align-items:center;justify-content:center;gap:var(--s2);
  font:800 34px/1 var(--round);color:var(--success);opacity:0;
}
.checkmark{
  display:block;width:30px;height:16px;flex:none;
  border-left:7px solid var(--success);border-bottom:7px solid var(--success);
  border-radius:0 0 0 var(--s0);
  transform:rotate(-45deg) translate(2px,-4px);
}
.checkmark.sm{
  width:22px;height:12px;margin-left:var(--s2);
  border-left-width:5px;border-bottom-width:5px;
  transform:rotate(-45deg) translate(2px,-3px);
}

.flying{position:absolute;z-index:5;pointer-events:none}

/* ---- price entry ----
   The panel is scaffolding for typing; the amount inside it is the real
   thing, drawn at exactly the size the payment screen will draw it, so
   that on "Ready to tap" it can simply travel there. `.bare` dissolves the
   panel out from under it without touching the amount. */
.pricepanel{
  margin:0 var(--s4);padding:var(--s4);border-radius:var(--r-lg);
  background:#fff;box-shadow:0 2px 0 rgba(42,35,24,.06),inset 0 0 0 1px rgba(42,35,24,.06);
  display:flex;align-items:center;justify-content:center;flex:1;min-height:var(--s7);
  transition:background .2s ease,box-shadow .2s ease;
}
.pricepanel.bare{background:transparent;box-shadow:none}
/* the amount out of the payment screen's absolute placement */
.amount.inline{position:static;left:auto;right:auto;top:auto}

/* ---- the balance check ----
   The card arrives full width with its coins on it, so there is nothing
   left to repeat underneath. What goes there instead is the one decision
   in the app that belongs to the child. */
.pay.peek .paycard{
  left:var(--s4);right:var(--s4);width:auto;height:auto;
  aspect-ratio:186 / 118;
  margin:0;top:50%;
  /* `translate` is its own property, so it composes with the drop
     animation's `transform` instead of being overwritten by it */
  translate:0 -50%;
}
.pay.peek .paycard .chip{width:42px;height:32px;left:var(--s4);top:var(--s4)}
.pay.peek .paycard .who{right:var(--s4);top:var(--s4);font-size:22px}
.pay.peek .paycard .badge{left:var(--s4);bottom:var(--s4);gap:var(--s3)}
.pay.peek .paycard .badge .num{font-size:38px;height:42px}

/* The colours centre in what is left below the card; SAVE sits on the
   bottom edge where every other screen puts its one big green action, and
   the padding keeps the two from ever meeting. */
.peekzone{
  display:flex;flex-direction:column;align-items:center;justify-content:center;
  padding:0 var(--s4) calc(var(--s7) + var(--s4));opacity:0;
}
.peekzone.in{opacity:1}

/* Seven, in the order a rainbow has them, and one more that chooses for
   you. Four across so every target clears 44px on a phone — these are a
   child's controls, not an adult's. */
.swatches{display:grid;grid-template-columns:repeat(4,1fr);gap:var(--s3);width:100%}
.chip-swatch{
  position:relative;width:100%;aspect-ratio:1;border:0;padding:0;border-radius:50%;
  cursor:pointer;box-shadow:inset 0 -4px 0 rgba(0,0,0,.16);
}
.chip-swatch:active{transform:translateY(2px)}
.chip-swatch.sel{box-shadow:inset 0 -4px 0 rgba(0,0,0,.16),0 0 0 4px var(--cream),0 0 0 7px var(--ink)}
/* the whole rainbow at once reads as "any of these", without a word on it */
.chip-swatch.surprise{
  background:conic-gradient(
    #E4402C 0turn .143turn,#EA7A1E .143turn .286turn,#D69C10 .286turn .429turn,
    #3E9B57 .429turn .571turn,#2E7DD1 .571turn .714turn,#464FB4 .714turn .857turn,
    #8348C0 .857turn 1turn);
}

/* Nothing is written to the card until this is pressed, so it only exists
   once there is something to write. It holds its space while hidden, so
   the colours never jump when it appears. */
.savebtn{
  position:absolute;left:var(--s4);right:var(--s4);bottom:var(--s5);
  height:70px;border-radius:var(--r-lg);background:var(--green);
  box-shadow:0 var(--s1) 0 var(--green-deep);
  opacity:0;pointer-events:none;transform:translateY(var(--s2));
  transition:opacity .2s ease,transform .2s ease;
}
.savebtn.on{opacity:1;pointer-events:auto;transform:none}
.savebtn.on:active{transform:translateY(2px);box-shadow:0 2px 0 var(--green-deep)}
.savebtn span{font:800 24px var(--round);color:#fff}

/* ---- shortfall: the same moment, stopped short ---- */
.paybottom{
  position:absolute;left:0;right:0;bottom:var(--s5);padding:0 var(--s4);
  display:none;flex-direction:column;align-items:center;gap:var(--s3);opacity:0;
}
/* Once the shortfall lands the amount stops floating on the golden section
   and the whole group centres, so the message can never collide with it. */
.pay.short-mode .amountzone{
  display:flex;flex-direction:column;align-items:center;justify-content:center;
  gap:var(--s4);padding:var(--s4) var(--s4) var(--s5);
}
/* the gathered row rejoins the flow here, so the group can stack and centre */
.pay.short-mode .amount{position:relative;top:auto;left:auto;right:auto;gap:var(--s3)}
.pay.short-mode .amount-acc{position:static;bottom:auto}
.pay.short-mode .paybottom{position:static;display:flex;padding:0}
.paybottom .need{
  display:flex;align-items:center;gap:var(--s3);
  padding:var(--s2) var(--s4);border-radius:999px;background:var(--short-soft);
}
.paybottom .need .num{font:800 34px/1 var(--round);color:var(--short);font-variant-numeric:tabular-nums}
.paybottom .say{font:800 19px var(--round);color:var(--short);text-align:center}
.paybottom .note{font:600 9px var(--mono);letter-spacing:.16em;color:var(--ink-42);text-transform:uppercase}
.coin.short-ghost{background:var(--short-soft);border:2px dashed rgba(185,58,34,.5);box-shadow:none!important}
.coin.short-ghost .rim,.coin.short-ghost .spec{display:none}
.coin.short-ghost .face{background:none;border:2px dashed rgba(185,58,34,.45);box-shadow:none}

/* ---------- tap invitation (kept for the register step) ---------- */
.invite{
  position:relative;border-radius:var(--r-lg);overflow:hidden;width:100%;
  border:2px solid rgba(60,50,35,.16);background:#E9E5DA;padding:0;cursor:pointer;
}
.invite:active{transform:scale(.985)}
.invite .stage{position:absolute;inset:0;display:flex;align-items:center;justify-content:center}
.ti-phone{
  position:relative;flex:none;width:74px;height:118px;border-radius:var(--r-card);
  background:#161A21;border:3px solid #2E353F;box-shadow:0 var(--s1) 0 #0B0E13;
  animation:klBobSm 2.2s ease-in-out infinite;
}
.ti-phone .glass{position:absolute;inset:7px;border-radius:11px;background:linear-gradient(165deg,#3B4453,#1C2129)}
.ti-phone .notch{position:absolute;left:50%;top:11px;width:22px;height:4px;margin-left:-11px;border-radius:2px;background:rgba(255,255,255,.22)}
.ti-phone .pad-dot{position:absolute;right:-7px;top:50%;width:14px;height:14px;margin-top:-7px;border-radius:50%;background:#F9D35D;box-shadow:0 0 0 3px rgba(249,211,93,.28)}
.ti-ring{position:absolute;left:50%;top:50%;width:22px;height:22px;margin:-11px 0 0 var(--s1);border-radius:50%;border:3px solid rgba(120,110,95,.6);animation:tiRing 2.2s ease-out infinite}
.ti-card{
  position:relative;flex:none;width:114px;height:74px;margin-left:-6px;border-radius:var(--r-md);
  box-shadow:0 7px 0 rgba(0,0,0,.22),0 12px 20px rgba(30,20,0,.2);
  animation:tiApproach 2.2s ease-in-out infinite;
}
.ti-card .chip{position:absolute;left:11px;top:var(--s3);width:26px;height:20px;border-radius:var(--s1);background:linear-gradient(140deg,#fff3c0,#e0ab2c)}
.ti-card .l1{position:absolute;left:11px;bottom:12px;width:62px;height:7px;border-radius:4px;background:rgba(255,255,255,.72)}
.ti-card .l2{position:absolute;left:11px;bottom:25px;width:40px;height:7px;border-radius:4px;background:rgba(255,255,255,.4)}
.ti-card .dot{position:absolute;right:10px;top:11px;width:20px;height:20px;border-radius:50%;background:rgba(255,255,255,.9)}
.ti-hint{position:absolute;right:14px;bottom:var(--r-card);font:600 9px var(--mono);letter-spacing:.14em;color:rgba(42,35,24,.34)}

@keyframes tiApproach{0%,100%{transform:translateX(30px) rotate(-7deg)}44%,62%{transform:translateX(-10px) rotate(0)}}
@keyframes tiRing{0%{transform:scale(.35);opacity:0}26%{opacity:.85}100%{transform:scale(2.9);opacity:0}}
@keyframes klBob{0%,100%{transform:translateY(0)}50%{transform:translateY(-7px)}}
@keyframes klPulse{0%,100%{transform:scale(1);opacity:.6}50%{transform:scale(1.09);opacity:1}}
@keyframes klRead{0%,100%{opacity:.25}50%{opacity:1}}
@keyframes klRise{from{transform:translateY(26px);opacity:0}to{transform:none;opacity:1}}

.bob{animation:klBob 3s ease-in-out infinite}
.rise{animation:klRise .45s .25s ease-out both}

/* ---------- grown-up world ---------- */
.dark{background:var(--slate);color:var(--slate-ink)}
.dark .mono{color:var(--slate-mute)}
.row{
  display:flex;align-items:center;gap:var(--s3);padding:var(--r-card);border-radius:var(--r-md);
  background:var(--slate-panel);border:1px solid rgba(232,228,218,.08);
  font:600 12px var(--mono);color:var(--slate-ink);width:100%;text-align:left;
}
.row.green{background:var(--mint);border-color:transparent;color:#fff;font-weight:700;font-size:13px;letter-spacing:.06em}
.row.ghost{background:none;border:1px solid rgba(232,228,218,.12);color:rgba(232,228,218,.5)}
.row .caret{margin-left:auto;width:10px;height:10px;border-top:2px solid rgba(255,255,255,.8);border-right:2px solid rgba(255,255,255,.8);transform:rotate(45deg)}
.row .val{margin-left:auto;font:500 11px var(--mono);color:rgba(232,228,218,.4)}
.cardtile{
  position:relative;height:112px;border-radius:var(--r-card);padding:14px var(--r-card);width:100%;
  display:flex;flex-direction:column;align-items:flex-start;justify-content:space-between;
  box-shadow:0 4px 0 rgba(0,0,0,.35);border:0;text-align:left;
}
.cardtile .nm{font:800 24px var(--round);color:#fff}
.cardtile .chip{width:26px;height:20px;border-radius:4px;background:linear-gradient(140deg,#fff3c0,#e0ab2c)}
.cardtile .caret{position:absolute;right:14px;bottom:var(--r-card);width:11px;height:11px;border-top:2.5px solid rgba(255,255,255,.8);border-right:2.5px solid rgba(255,255,255,.8);transform:rotate(45deg)}
.dashed-row{
  padding:14px var(--r-card);border-radius:var(--r-md);border:1px dashed rgba(232,228,218,.2);
  display:flex;align-items:center;gap:var(--s3);background:none;width:100%;
  font:600 11px var(--mono);letter-spacing:.1em;color:rgba(232,228,218,.5);
}
.pin-dots{display:flex;justify-content:center;gap:var(--r-card);padding:var(--s6) 0 var(--s5)}
.pin-dots i{display:block;width:var(--r-card);height:var(--r-card);border-radius:50%;border:2px solid rgba(232,228,218,.3)}
.pin-dots i.on{background:var(--slate-ink);border-color:var(--slate-ink)}
.pin-dots.bad{animation:klShake .4s}
@keyframes klShake{0%,100%{transform:translateX(0)}20%{transform:translateX(-8px)}40%{transform:translateX(8px)}60%{transform:translateX(-5px)}80%{transform:translateX(5px)}}
.nameinput{
  width:100%;padding:14px var(--r-card);border-radius:var(--r-md);background:var(--slate-panel);
  border:1px solid rgba(232,228,218,.18);font:700 18px var(--body);color:var(--slate-ink);
}
.nameinput:focus{outline:0;border-color:#7FCBA0}
/* seven across, so the row is the rainbow at a glance and every swatch
   stays square as it divides the width */
.swatchrow{display:grid;grid-template-columns:repeat(7,1fr);gap:var(--s2)}
.swatch{width:auto;aspect-ratio:1;border-radius:var(--r-md);border:0;padding:0;cursor:pointer}
.swatch.sel{box-shadow:0 0 0 3px var(--slate-ink)}

/* ---------- card picker sheet (prototype affordance) ---------- */
.sheet-wrap{position:absolute;inset:0;z-index:20;display:flex;align-items:flex-end;background:rgba(20,14,0,.42);animation:klFade .18s ease both}
.sheet{
  width:100%;background:var(--cream-warm);border-radius:var(--s5) var(--s5) 0 0;padding:var(--s4) var(--s4) var(--s5);
  display:flex;flex-direction:column;gap:var(--s3);animation:klRise .28s ease-out both;
}
.sheet .hd{font:600 10px var(--mono);letter-spacing:.16em;color:var(--ink-42);text-align:center}
.sheet .pick{
  display:flex;align-items:center;gap:var(--s3);padding:var(--s3) var(--s3);border-radius:var(--r-card);border:0;width:100%;
  background:rgba(42,35,24,.05);cursor:pointer;
}
.sheet .pick .nm{font:800 20px var(--round)}
.sheet .cancel{background:none;border:0;font:600 10px var(--mono);letter-spacing:.14em;color:var(--ink-42);padding:var(--s2)}
.mini-card{width:34px;height:22px;border-radius:var(--s1);flex:none}

.center{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center}
.pad-x{padding-left:var(--s4);padding-right:var(--s4)}
.stack{display:flex;flex-direction:column}
.scroll{overflow-y:auto;-webkit-overflow-scrolling:touch}

@media (prefers-reduced-motion:reduce){
  .glow,.pulse,.prompt,.bob,.rise{animation:none!important}
}

/* ---------- the reader's own voice ----------
   A quiet mono line under a tap prompt, for the things the card glyph
   cannot say: that there is no reader on this phone, or that the card
   which touched it was not the one this screen was waiting for. It is
   absolutely positioned so appearing and disappearing never moves the
   glyph — the target sits on the golden minor section and stays there.
   When the reader is simply working, this says nothing at all. */
.readnote{
  position:absolute;left:0;right:0;top:100%;margin-top:var(--s3);
  font:600 9px/1.6 var(--mono);letter-spacing:.16em;text-transform:uppercase;
  text-align:center;color:var(--ink-42);
}
.readnote.warn{color:var(--short)}
.on-slate .readnote{color:rgba(232,228,218,.38)}
.on-slate .readnote.warn{color:#E5906F}

/* ---------- installed as an app ----------
   Standing on a counter for hours with a small child's hands on it: no
   pull-to-refresh, no text selection, no magnifier on a long press. */
body{overscroll-behavior:none}
.screen{user-select:none;-webkit-user-select:none;-webkit-touch-callout:none}
.screen input{user-select:text;-webkit-user-select:text}

/* Android draws its own status bar above an installed app, so the
   prototype's drawn clock would be the second one on the phone. The row
   stays — the vertical rhythm is built on it — but the clock goes. */
@media (display-mode:standalone){
  .status span:first-child{visibility:hidden}
}
