/* ============================================================
   ZuzuKids — kids English. Light, soft-3D, phone-first.
   ============================================================ */
:root{
  --ink:#2B2A38; --ink2:#6B6880;
  --sun:#FFD84D; --mint:#7FD1B9; --sky:#8FB8F5; --rose:#FF9FC0;
  --lilac:#C9B6F5; --peach:#FFB86B;
  --surf:#FFFFFF; --surf2:#F7F4FF;
  --glass:rgba(255,255,255,.85); --glass2:rgba(255,255,255,.65);
  --rim:#EDE9F7; --rim2:#E4E0F0; --line:rgba(43,42,56,.10);
  --page1:#FFF9F0; --page2:#EAF4FF; --scrim:transparent;
  --ok:#4FBF8B; --soft:#FFE9A8;
  --r:26px; --r2:18px;
  --sh:0 10px 24px rgba(43,42,56,.10), 0 2px 6px rgba(43,42,56,.06);
  --shb:0 16px 34px rgba(43,42,56,.14);
  --font:"Nunito","Baloo 2",system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;
}
*{box-sizing:border-box;-webkit-tap-highlight-color:transparent}
html{height:100%}
html,body{margin:0;font-family:var(--font);color:var(--ink);
  overscroll-behavior:none;user-select:none;-webkit-text-size-adjust:100%}
body{background:#EDE7F6;display:grid;place-items:center;
  height:100vh;height:100dvh;width:100vw;overflow:hidden}

/* ---------- phone frame ---------- */
#frame{position:relative;width:100vw;width:100dvw;height:100vh;height:100dvh;
  background:linear-gradient(180deg,var(--page1),var(--page2));overflow:hidden;border-radius:0;
  --safe-t:env(safe-area-inset-top,0px); --safe-b:env(safe-area-inset-bottom,0px)}
/* Desktop / tablet: show it as a phone so the design still reads correctly */
@media(min-width:560px) and (min-height:720px){
  #frame{width:min(430px,94vw);height:min(880px,92dvh);border-radius:44px;
    border:10px solid #1B1A24;box-shadow:0 30px 70px rgba(43,42,56,.28)}
  body{background:radial-gradient(circle at 50% 20%,#F3EEFF,#DCD5F0)}
}
/* ---------- typing: the frame shrinks to what is still visible ----------
   Measured by js/kb.js, because in-app browsers cover the page instead of
   resizing it and 100dvh then hides its own bottom under the keyboard. */
body.kbon #frame,body.typing #frame{height:var(--vvh,100dvh)}
/* The room that makes lifting possible. Without a screenful of slack under
   the last field, a scroller asked to raise it simply runs out of content
   and stops with the field still under the keyboard. */
body.typing .scroll{padding-bottom:78vh}
/* nothing decorative competes for the little room that is left */
body.kbon #bg,body.kbon #fxLayer{display:none}
#stage{position:absolute;inset:0;overflow:hidden}
.scr{position:absolute;inset:0;display:flex;flex-direction:column;
  padding:calc(14px + var(--safe-t)) clamp(12px,4.2vw,20px) calc(10px + var(--safe-b));
  opacity:0;pointer-events:none;transform:translateX(24px);
  transition:opacity .3s ease, transform .34s cubic-bezier(.22,1,.36,1)}
.scr.on{opacity:1;pointer-events:auto;transform:none}
.scr.back{transform:translateX(-24px)}

/* backdrop: quiet by design, never competes with the word card */
#bg{position:absolute;inset:0;z-index:0;isolation:isolate;transition:background .6s ease}
#bg::after{content:"";position:absolute;inset:0;z-index:1;
  background:radial-gradient(120% 60% at 50% 0%,rgba(255,255,255,.55),transparent 70%)}
.hills{position:absolute;bottom:0;left:0;width:100%;height:34%;opacity:.5;z-index:2}

/* ---------- fx layer ---------- */
#fxLayer{position:absolute;inset:0;pointer-events:none;z-index:90;overflow:hidden}
.pt{position:absolute;border-radius:50%;pointer-events:none;
  animation:pt .62s cubic-bezier(.2,.7,.3,1) forwards}
@keyframes pt{0%{transform:translate(-50%,-50%) scale(.4);opacity:1}
  100%{transform:translate(calc(-50% + var(--dx)),calc(-50% + var(--dy))) scale(0);opacity:0}}
.cf{position:absolute;width:9px;height:14px;border-radius:3px;
  animation:cf 1.8s linear forwards}
@keyframes cf{0%{transform:translateY(0) rotate(0);opacity:1}
  100%{transform:translate(var(--x),900px) rotate(var(--r));opacity:.9}}

/* ---------- generic press feedback ---------- */
.tap{cursor:pointer;transition:transform .16s cubic-bezier(.34,1.56,.64,1),box-shadow .16s}
.tap:active{transform:scale(.96)}
.pressed{animation:sp .19s cubic-bezier(.34,1.56,.64,1)}
@keyframes sp{0%{transform:scale(1)}40%{transform:scale(.94)}100%{transform:scale(1)}}
.shk{animation:shk .4s ease}
@keyframes shk{0%,100%{transform:translateX(0)}20%{transform:translateX(-7px)}
  40%{transform:translateX(6px)}60%{transform:translateX(-4px)}80%{transform:translateX(3px)}}
.pop{animation:pop .42s cubic-bezier(.34,1.56,.64,1)}
@keyframes pop{0%{transform:scale(.7);opacity:0}100%{transform:scale(1);opacity:1}}
.rise{animation:rise .45s cubic-bezier(.22,1,.36,1) both}
@keyframes rise{from{opacity:0;transform:translateY(14px)}to{opacity:1;transform:none}}
.d1{animation-delay:.06s}.d2{animation-delay:.12s}.d3{animation-delay:.18s}
.d4{animation-delay:.24s}.d5{animation-delay:.3s}.d6{animation-delay:.36s}
.d7{animation-delay:.42s}.d8{animation-delay:.48s}

/* calm mode: kill decorative motion, keep essential transitions */
body.calm .float,body.calm .char,body.calm .glow,body.calm .breathe{animation:none!important}
body.calm .pop,body.calm .rise{animation-duration:.001s}

/* ---------- typography ---------- */
h1,h2,h3{margin:0;line-height:1.15;font-weight:800}
h1{font-size:clamp(24px,7.2vw,31px);letter-spacing:-.4px}
h2{font-size:clamp(18px,5.4vw,22px)}
.sub{color:var(--ink2);font-size:14px;font-weight:700;margin-top:5px}
.kicker{font-size:11px;font-weight:800;letter-spacing:1.4px;text-transform:uppercase;color:var(--ink2)}

/* ---------- buttons ---------- */
/* ONE button. Variants change colour and nothing else: height, radius,
   font size, icon gap and label layout all live here, so two buttons
   stacked on top of each other can never read as different species.
   Height comes from min-height rather than vertical padding — padding
   varies with the label's line count, min-height does not. */
.btn{
  display:flex;align-items:center;justify-content:center;gap:9px;
  box-sizing:border-box;width:100%;min-height:56px;padding:8px 18px;
  border:0;border-radius:19px;
  font-family:var(--font);font-weight:800;font-size:clamp(15px,4.4vw,17px);
  line-height:1.15;text-align:center;color:#fff;
  background:linear-gradient(180deg,#8FB8F5,#5E90E0);
  box-shadow:0 5px 0 #4A79C4, var(--sh);
  cursor:pointer;transition:transform .12s,box-shadow .12s;
  -webkit-tap-highlight-color:transparent}
.btn:active{transform:translateY(4px);box-shadow:0 1px 0 #4A79C4}
.btn>.ic{flex:0 0 auto}
.btn.sun{background:linear-gradient(180deg,#FFE07A,#FFC22E);color:#5A4200;
  box-shadow:0 5px 0 #E0A310,var(--sh)}
.btn.sun:active{box-shadow:0 1px 0 #E0A310}
.btn.mint{background:linear-gradient(180deg,#93DEC8,#4FBF9F);box-shadow:0 5px 0 #35997C,var(--sh)}
.btn.mint:active{box-shadow:0 1px 0 #35997C}
/* neutral weight — same button, no colour claim */
.btn.plain{background:var(--surf);color:var(--ink);box-shadow:0 5px 0 var(--rim2),var(--sh)}
.btn.plain:active{box-shadow:0 1px 0 var(--rim2)}
/* the quiet one: for a step backwards, not an action. Same size as
   every other button — only the colour steps down. */
.btn.flat{background:var(--glass);color:var(--ink2);box-shadow:none;
  border:2px solid var(--line)}
.btn.flat:active{transform:scale(.99);box-shadow:none}
.btn.wide{width:100%}
.btn[disabled]{opacity:.45;pointer-events:none}
/* a column of buttons: even gaps, no per-button margins */
.bstack{display:grid;gap:10px;margin-top:12px}
.bstack .btn{margin:0}
/* two buttons side by side, always exactly equal width */
.brow{display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-top:12px}

/* small icon affordance inside a settings row — not a stacked action */
.ghost{background:var(--glass);color:var(--ink);border:2px solid rgba(43,42,56,.1);
  box-shadow:var(--sh);font-weight:800;border-radius:18px;padding:12px 18px;font-size:15px;cursor:pointer}

/* ---------- cards ---------- */
.card{background:var(--surf);border-radius:var(--r);box-shadow:var(--sh);padding:16px}
.row{display:flex;align-items:center;gap:12px}
.sp{flex:1}
.center{display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center}

/* ---------- characters ---------- */
.char{width:100%;height:100%;overflow:visible}
.char .cbl{animation:bl 4.6s infinite}
@keyframes bl{0%,94%,100%{transform:scaleY(1)}97%{transform:scaleY(.08)}}
.avatar{width:clamp(76px,22vw,98px);height:clamp(76px,22vw,98px);flex:0 0 auto}
.avatar.sm{width:clamp(44px,13vw,58px);height:clamp(44px,13vw,58px)}
.avatar.lg{width:clamp(112px,34vw,152px);height:clamp(112px,34vw,152px)}
.float{animation:fl 3.4s ease-in-out infinite}
@keyframes fl{0%,100%{transform:translateY(0)}50%{transform:translateY(-9px)}}
.cheer{animation:ch .55s cubic-bezier(.34,1.56,.64,1)}
@keyframes ch{0%{transform:scale(1) rotate(0)}30%{transform:scale(1.18) rotate(-7deg)}
  60%{transform:scale(1.08) rotate(6deg)}100%{transform:scale(1) rotate(0)}}

/* ---------- speech bubble ---------- */
.bub{position:relative;background:var(--surf);border-radius:18px;padding:11px 14px;
  box-shadow:var(--sh);font-weight:800;font-size:15px;max-width:210px}
.bub::after{content:"";position:absolute;left:-8px;bottom:14px;width:0;height:0;
  border:8px solid transparent;border-right-color:#fff}

/* ---------- Zuzu's task instruction ----------
   Anchored under the mascot in the session header, above the task but below
   the feedback bar, and it never takes pointer events: the child can tap
   straight through it at the task underneath. */
.zsay{position:absolute;z-index:60;right:clamp(10px,3.6vw,18px);
  top:calc(var(--safe-t,0px) + 64px);max-width:min(78%,300px);
  background:var(--surf);border-radius:16px;border-bottom-right-radius:5px;
  box-shadow:var(--shb);padding:10px 13px;pointer-events:none;
  transition:opacity .3s ease,transform .3s ease}
.zsay .zsaytx{font-weight:800;font-size:clamp(13px,3.9vw,15px);line-height:1.35;color:var(--ink)}
.zsay.out{opacity:0;transform:translateY(-6px) scale(.97)}
body.calm .zsay{animation:none}


/* ---------- language select ---------- */
.pairs{display:grid;gap:14px;width:100%}
.pair{display:flex;align-items:center;gap:14px;background:var(--surf);border-radius:22px;padding:16px;
  box-shadow:var(--sh);cursor:pointer;border:3px solid transparent}
.pair.sel{border-color:var(--mint);background:#F2FFFB}
.flag{font-size:30px}
.pname{font-weight:800;font-size:17px}
.pnote{font-size:12px;color:var(--ink2);font-weight:700}
.ages{display:grid;grid-template-columns:repeat(3,1fr);gap:12px;width:100%}
.age{background:var(--surf);border-radius:20px;padding:16px 8px;text-align:center;box-shadow:var(--sh);
  cursor:pointer;border:3px solid transparent}
.age.sel{border-color:var(--sun);background:#FFFDF0}
.age b{display:block;font-size:20px}
.age span{font-size:11px;color:var(--ink2);font-weight:700}

/* ---------- home ---------- */
/* A top bar that overflows draws its last button over the frame edge, so the
   row is clipped and the only elastic item (the child's name) is the one that
   gives way. */
.topbar{display:flex;align-items:center;gap:10px;margin-bottom:12px;
  min-width:0;overflow:hidden}
.topbar>*{flex:0 0 auto}
.topbar>.mechip{flex:0 1 auto;min-width:52px}
.topbar>.sp{flex:1 1 auto}
.chip{background:var(--surf);border-radius:14px;padding:7px 12px;box-shadow:var(--sh);
  font-weight:800;font-size:13px;display:flex;align-items:center;gap:5px}
.scroll{flex:1;overflow-y:auto;overflow-x:hidden;-webkit-overflow-scrolling:touch;
  margin:0 clamp(-20px,-4.2vw,-12px);padding:0 clamp(12px,4.2vw,20px) 14px;
  scrollbar-width:none}
.scroll::-webkit-scrollbar{display:none}
.slist{display:grid;gap:12px}
.sitem{display:flex;align-items:center;gap:13px;background:var(--surf);border-radius:22px;
  padding:13px;box-shadow:var(--sh);cursor:pointer;position:relative;overflow:hidden}
.sitem.lock{opacity:.55}
.sitem .ico{width:clamp(44px,12.5vw,54px);height:clamp(44px,12.5vw,54px);border-radius:17px;
  display:grid;place-items:center;font-size:clamp(22px,6.4vw,27px);flex:0 0 auto}
.sitem .nm{font-weight:800;font-size:16px;line-height:1.2}
.sitem .mt{font-size:12px;color:var(--ink2);font-weight:700;margin-top:3px}
.bar{height:7px;border-radius:99px;background:#EFECF7;overflow:hidden;margin-top:7px;width:112px}
.bar i{display:block;height:100%;border-radius:99px;
  background:linear-gradient(90deg,var(--mint),var(--sky));transition:width .6s cubic-bezier(.22,1,.36,1)}
.stars{font-size:13px;letter-spacing:1px}

/* my town */
.town{background:linear-gradient(180deg,#E6F2FF,#FFF3DE);border-radius:22px;padding:12px;
  box-shadow:var(--sh);margin-bottom:14px;position:relative;overflow:hidden}
.townrow{display:grid;grid-template-columns:repeat(4,1fr);gap:8px}
.bld{font-size:clamp(24px,7vw,32px);animation:pop .5s cubic-bezier(.34,1.56,.64,1) both}
.bld.ph{opacity:.2;filter:grayscale(1)}

/* ---------- session ---------- */
.shead{display:flex;align-items:center;gap:10px;margin-bottom:10px}
.pbar{flex:1;height:11px;border-radius:99px;background:var(--glass2);
  box-shadow:inset 0 1px 3px rgba(43,42,56,.12);overflow:hidden}
.pbar i{display:block;height:100%;border-radius:99px;
  background:linear-gradient(90deg,var(--sun),var(--peach));transition:width .5s cubic-bezier(.22,1,.36,1)}
.qwrap{flex:1;display:flex;flex-direction:column;justify-content:center;gap:14px;min-height:0}
.prompt{display:flex;align-items:center;justify-content:center;gap:8px;font-weight:800;
  font-size:clamp(14px,4.3vw,17px);color:var(--ink2);text-align:center}
.prompt .ic{flex:0 0 auto}

/* word card — the hero element, always high contrast */
.wcard{background:var(--surf);border-radius:30px;box-shadow:var(--shb);padding:18px;
  display:flex;flex-direction:column;align-items:center;gap:8px;cursor:pointer;position:relative}
.dome{width:clamp(112px,34vw,158px);height:clamp(112px,34vw,158px);border-radius:50%;
  display:grid;place-items:center;font-size:clamp(58px,17vw,80px);position:relative;
  background:radial-gradient(circle at 34% 26%,#fff,rgba(255,255,255,.2) 46%,rgba(0,0,0,.05));
  box-shadow:inset 0 -8px 18px rgba(43,42,56,.08),0 8px 20px rgba(43,42,56,.12)}
.dome.sm{width:clamp(74px,21vw,100px);height:clamp(74px,21vw,100px);font-size:clamp(38px,11vw,50px)}
.dome.xs{width:clamp(54px,15vw,72px);height:clamp(54px,15vw,72px);font-size:clamp(26px,8vw,36px)}
.glow{position:absolute;inset:-16px;border-radius:50%;z-index:0;pointer-events:none;
  animation:gl 3s ease-in-out infinite}
.dome>.emo{position:relative;z-index:1;line-height:1;transition:opacity .35s;
  display:grid;place-items:center;width:66%;height:66%}
.dome>.emo>svg.ic{width:100%;height:100%;filter:drop-shadow(0 3px 5px rgba(43,42,56,.18))}
@keyframes gl{0%,100%{opacity:.4;transform:scale(1)}50%{opacity:.75;transform:scale(1.06)}}
.wen{font-size:31px;font-weight:900;letter-spacing:-.5px}
.wtr{font-size:16px;font-weight:800;color:var(--ink2)}
.cefr{position:absolute;top:12px;right:14px;font-size:10px;font-weight:900;color:var(--ink2);
  background:var(--surf2);padding:3px 7px;border-radius:8px}
/* the two language buttons are a matched pair: equal width via the
   grid, equal height via min-height, so neither looks like the
   more important one */
.spk{display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-top:2px;width:100%}
.spkb{border:0;border-radius:14px;padding:0 10px;min-height:42px;box-sizing:border-box;
  font-family:var(--font);font-weight:800;font-size:13px;cursor:pointer;line-height:1.1;
  box-shadow:var(--sh);display:flex;align-items:center;justify-content:center;gap:7px}
.spkb>.fl{flex:0 0 auto}
.spkb.en{background:linear-gradient(180deg,#FFE07A,#FFC22E);color:#5A4200}
.spkb.nat{background:var(--surf);color:var(--ink2);border:2px solid rgba(43,42,56,.08)}

/* option grids */
.opts{display:grid;grid-template-columns:1fr 1fr;gap:clamp(8px,2.8vw,12px)}
.opt{background:var(--surf);border-radius:22px;box-shadow:var(--sh);padding:12px 8px;cursor:pointer;
  display:flex;flex-direction:column;align-items:center;gap:6px;border:3px solid transparent;
  transition:transform .16s cubic-bezier(.34,1.56,.64,1),border-color .2s,background .2s}
.opt .lbl{font-weight:800;font-size:14px;text-align:center;line-height:1.2}
.opt.good{border-color:var(--ok);background:#F1FFF8}
.opt.bad{border-color:#FFC9A8;background:#FFF7F2}
.opt.dim{opacity:.4}
.opts.text .opt{padding:16px 10px;font-size:16px}

/* memory */

/* ---------- connect: join each picture to its word ----------
   The wires are an SVG layer sitting under the two columns, drawn in board
   coordinates. The columns keep a wide centre gutter so a line has somewhere
   to travel and never crosses a label. */
.cboard{position:relative;margin-top:4px}
.cwire{position:absolute;inset:0;z-index:0;pointer-events:none;overflow:visible}
.cwire .wire{fill:none;stroke-width:5;stroke-linecap:round;pointer-events:stroke;
  cursor:pointer;stroke-dasharray:1000;stroke-dashoffset:1000;
  animation:wdraw .34s ease-out forwards}
@keyframes wdraw{to{stroke-dashoffset:0}}
.cwire .wire.ok{stroke:var(--ok)!important;stroke-width:6}
.cwire .wire.bad{stroke:#EF4444!important;stroke-dasharray:8 7;animation:none;
  stroke-dashoffset:0}
.ccols{position:relative;z-index:1;display:grid;grid-template-columns:1fr 1.25fr;
  gap:clamp(26px,10vw,54px)}
.ccol{display:flex;flex-direction:column;gap:clamp(8px,2.6vw,12px)}
.cnode{background:var(--surf);border-radius:20px;box-shadow:var(--sh);cursor:pointer;
  border:3px solid transparent;transition:transform .16s cubic-bezier(.34,1.56,.64,1),
  border-color .18s,box-shadow .18s}
.cnode.pic{aspect-ratio:1;padding:5px;display:grid;place-items:center}
.cnode.word{padding:9px 10px;display:flex;flex-direction:column;align-items:flex-start;gap:2px;
  min-height:56px;justify-content:center}
.cnode .cw{font-size:clamp(15px,4.6vw,19px);font-weight:900;letter-spacing:-.2px}
.cnode.sel{border-color:var(--mint);transform:scale(1.03);box-shadow:var(--shb)}
.cnode.linked{border-color:var(--wire,var(--mint))}
.cnode.ok{border-color:var(--ok);background:#F2FBF6}
.wnat.tiny{font-size:13px;animation:none;filter:none}

/* ---------- fill: the word inside a sentence ---------- */
.fsent{margin-top:10px;font-size:clamp(19px,5.6vw,24px);font-weight:900;line-height:1.5;
  display:flex;flex-wrap:wrap;align-items:center;justify-content:center;gap:5px}
.fsent .ft{white-space:pre-wrap}
.fgap{display:inline-grid;place-items:center;min-width:78px;padding:2px 12px;
  border-radius:12px;border:3px dashed var(--rim2);color:var(--ink2);background:var(--surf2)}
.fgap.on{border-style:solid;border-color:var(--ok);background:#F2FBF6;color:var(--ink);
  animation:pop .34s cubic-bezier(.34,1.56,.64,1)}
.wen.sm{font-size:clamp(17px,5vw,21px)}

/* ---------- weekly report preview ---------- */
.prview{margin:10px 0 14px;border-radius:22px;overflow:hidden;background:#fff;
  box-shadow:var(--sh)}
.prview canvas{display:block;width:100%;height:auto}

/* ---------- act it out: the countdown ring ---------- */
.acring{margin:14px auto 0;position:relative;display:grid;place-items:center;
  width:clamp(88px,26vw,112px);height:clamp(88px,26vw,112px);border-radius:50%;
  background:conic-gradient(var(--mint) 0turn,#EDEFF5 0turn);
  box-shadow:var(--sh);border:6px solid #fff}
.acring .acfill{position:absolute;inset:-6px;border-radius:50%;border:6px solid var(--mint);
  animation:acdrain 4s linear forwards;clip-path:inset(0 0 0 0)}
.acring .acnum{font-weight:900;font-size:clamp(30px,9vw,40px);color:var(--ink);
  position:relative;z-index:1}
.acring.done{background:#EAFBF2;border-color:#fff}
.acring>svg.ic{width:52%;height:52%}
@keyframes acdrain{
  0%{opacity:1;transform:scale(1)}
  100%{opacity:.15;transform:scale(.9)}
}
body.calm .acring .acfill{animation:none;opacity:.5}

/* ---- story reader (teaching through stories) --------------------------
   The line is the biggest thing on the page and the word being taught is
   the only coloured word in it, so a seven-year-old's eye lands on the
   right place without being told where to look. */
.sdots{display:flex;gap:6px;justify-content:center;margin:9px 0 2px}
.sdot{width:8px;height:8px;border-radius:50%;background:#DDE2EC;transition:transform .18s,background .18s}
.sdot.done{background:var(--mint)}
.sdot.now{background:var(--sun);transform:scale(1.4)}
.sline{font-size:clamp(20px,6.2vw,27px);font-weight:800;line-height:1.32;
  color:var(--ink);margin-top:10px;letter-spacing:-.2px}
.sline .sfoc{color:#1B4FCC;font-weight:900;
  text-decoration:underline;text-decoration-color:var(--sun);
  text-decoration-thickness:4px;text-underline-offset:3px}
.snat{margin-top:7px;font-size:clamp(15px,4.4vw,18px);font-weight:700;color:var(--ink2)}
.gapline{margin-top:4px}

/* ---------- say it: the microphone card ---------- */
.micb{margin:12px auto 0;display:grid;place-items:center;position:relative;
  width:clamp(96px,30vw,124px);height:clamp(96px,30vw,124px);border:0;cursor:pointer;
  border-radius:50%;background:linear-gradient(160deg,#FFE79A,#FFC93C);
  box-shadow:0 8px 0 #D9A21B,var(--sh);transition:transform .16s cubic-bezier(.34,1.56,.64,1)}
.micb:active{transform:translateY(3px) scale(.97);box-shadow:0 5px 0 #D9A21B,var(--sh)}
.micb .mring{position:absolute;inset:-10px;border-radius:50%;pointer-events:none;
  border:4px solid rgba(255,201,60,.55);opacity:0}
.micb.live{background:linear-gradient(160deg,#B6EBD8,#5FC9A9);box-shadow:0 8px 0 #2E9C74,var(--sh)}
.micb.live .mring{opacity:1;animation:mpulse 1.25s ease-out infinite}
.micb.won{background:linear-gradient(160deg,#B6EBD8,#4FBF9F);box-shadow:0 8px 0 #2E9C74,var(--sh)}
.micb.off{filter:grayscale(1);opacity:.45;box-shadow:0 5px 0 var(--rim2)}
@keyframes mpulse{0%{transform:scale(.94);opacity:.85}100%{transform:scale(1.28);opacity:0}}
body.calm .micb.live .mring{animation:none;opacity:.7}
.saynote{margin-top:12px;text-align:center;font-weight:800;color:var(--ink2);
  font-size:clamp(14px,4.2vw,16px);min-height:22px;line-height:1.35}
.saynote.live{color:#2E9C74}
.saynote.good{color:var(--ok)}
.saynote.bad{color:#C2410C}

.mgrid{display:grid;grid-template-columns:repeat(4,1fr);gap:clamp(6px,2.2vw,10px)}
.mc{aspect-ratio:1;border-radius:18px;box-shadow:var(--sh);cursor:pointer;position:relative;
  transform-style:preserve-3d;transition:transform .38s cubic-bezier(.22,1,.36,1)}
.mc.flip{transform:rotateY(180deg)}
.mc .f,.mc .b{position:absolute;inset:0;border-radius:18px;display:grid;place-items:center;
  backface-visibility:hidden;font-weight:800}
.mc .f{background:linear-gradient(160deg,#A9C8F7,#7FA8E8);color:#fff;font-size:24px}
.mc .b{background:var(--surf);transform:rotateY(180deg);padding:4px;text-align:center;
  font-size:13px;line-height:1.1;word-break:break-word}
.mc .b.emo{font-size:30px}
.mc .b .dome>.emo>svg.ic{width:86%;height:86%}
.mc.gone{opacity:0;pointer-events:none;transition:opacity .4s}

/* phrase builder */
.slot{min-height:60px;background:var(--glass2);border:3px dashed rgba(43,42,56,.14);
  border-radius:20px;display:flex;flex-wrap:wrap;gap:7px;padding:10px;align-content:flex-start}
.tokbank{display:flex;flex-wrap:wrap;gap:8px;justify-content:center}
.tok{background:var(--surf);border-radius:14px;padding:10px 13px;font-weight:800;font-size:15px;
  box-shadow:var(--sh);cursor:pointer;border:2px solid rgba(43,42,56,.06)}
.tok.used{opacity:.25;pointer-events:none}
.tok.inslot{background:linear-gradient(180deg,#FFF3C4,#FFE07A)}

/* spell */
.spellbox{display:flex;gap:6px;justify-content:center;flex-wrap:wrap}
.sl{width:clamp(28px,8vw,36px);height:clamp(38px,11vw,46px);border-radius:12px;background:var(--surf);
  box-shadow:var(--sh);display:grid;place-items:center;font-weight:900;font-size:clamp(17px,5vw,21px);color:var(--ink)}
.sl.empty{background:var(--glass2);box-shadow:inset 0 2px 5px rgba(43,42,56,.08)}
.sl.gap{width:14px;background:none;box-shadow:none}
.spacer{height:12px}
.keys{display:flex;flex-wrap:wrap;gap:6px;justify-content:center}
.key{width:clamp(31px,9vw,40px);height:clamp(37px,10.5vw,44px);border-radius:12px;background:var(--surf);
  box-shadow:var(--sh);border:0;font-weight:900;font-size:clamp(15px,4.4vw,18px);cursor:pointer;font-family:var(--font)}

/* say-it */
.mic{width:104px;height:104px;border-radius:50%;border:0;cursor:pointer;
  background:linear-gradient(180deg,#FF9FC0,#F2739E);color:#fff;font-size:42px;
  box-shadow:0 8px 0 #D45580,var(--shb)}
.mic.rec{animation:breathe 1.1s ease-in-out infinite}
@keyframes breathe{0%,100%{transform:scale(1)}50%{transform:scale(1.08)}}

/* feedback banner */
.fb{position:absolute;left:0;right:0;bottom:0;
  padding:16px clamp(12px,4.2vw,20px) calc(18px + var(--safe-b));
  background:linear-gradient(180deg,rgba(255,255,255,0),#fff 40%);
  transform:translateY(110%);transition:transform .34s cubic-bezier(.22,1,.36,1);z-index:60}
.fb.on{transform:none}
.fb .msg{font-weight:900;font-size:19px}
.fb .cor{font-weight:800;font-size:14px;color:var(--ink2);margin-top:2px}

/* reward screen */
.rewardbig{font-size:clamp(58px,18vw,82px)}
.coinfly{position:absolute;font-size:24px;z-index:95;pointer-events:none;
  animation:cfly .8s cubic-bezier(.4,0,.6,1) forwards}
@keyframes cfly{0%{transform:translate(0,0) scale(1);opacity:1}
  100%{transform:translate(var(--tx),var(--ty)) scale(.5);opacity:0}}
.plist{display:grid;gap:9px;width:100%}
.pchip{background:var(--surf);border-radius:18px;padding:12px 14px;box-shadow:var(--sh);
  display:flex;align-items:center;gap:10px;cursor:pointer}
.pchip .pe{font-size:15px;font-weight:900}
.pchip .pt2{font-size:12.5px;color:var(--ink2);font-weight:700}

/* parent task */
.ptask{background:linear-gradient(160deg,#E7F7EE,#D6F0E4);border-radius:22px;padding:15px;
  box-shadow:var(--sh);border:2px solid rgba(79,191,139,.28)}

/* settings */
.setrow{display:flex;align-items:center;gap:12px;background:var(--surf);border-radius:18px;
  padding:14px;box-shadow:var(--sh);margin-bottom:10px}
.sw{width:52px;height:30px;border-radius:99px;background:#DFDCEA;position:relative;cursor:pointer;
  transition:background .22s;flex:0 0 auto}
.sw::after{content:"";position:absolute;top:3px;left:3px;width:24px;height:24px;border-radius:50%;
  background:var(--surf);box-shadow:0 2px 5px rgba(0,0,0,.2);transition:transform .22s}
.sw.on{background:var(--ok)}
.sw.on::after{transform:translateX(22px)}
.note{font-size:12px;color:var(--ink2);font-weight:700;line-height:1.45}
/* A caption directly under a raised button was landing inside that button's
   drop shadow, which reads as the button cutting the text in half. Elevated
   controls need clearance, not just document order. */
.bstack + .note, .btn + .note{margin-top:14px}
/* introduction card: the way back sits beside the way on, never under it */
.nrow{display:flex;gap:10px;align-items:stretch;margin-top:10px}
.nrow .nprev{flex:0 0 auto;width:66px;padding:0;min-height:56px}
.nrow .btn.wide{flex:1 1 auto;width:auto}

/* ============================================================
   v2 — real photos, 3D motion, trilingual cards, richer feedback
   ============================================================ */

/* ---------- living background canvas ---------- */
#bgcv{position:absolute;inset:0;pointer-events:none;z-index:3}
#stage{z-index:1}

/* ---------- real photographs inside the dome ---------- */
.dome{overflow:hidden;isolation:isolate}
.dome .photo{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
  border-radius:50%;opacity:0;transform:scale(1.08);z-index:2;
  transition:opacity .45s ease, transform .6s cubic-bezier(.22,1,.36,1)}
.dome.hasphoto .photo{opacity:1;transform:scale(1)}
.dome.hasphoto .emo{opacity:0}
.dome.hasphoto{box-shadow:inset 0 -8px 18px rgba(43,42,56,.10),0 10px 24px rgba(43,42,56,.18)}
/* Curated artwork is a single object on a plain background, so it is fitted
   whole and inset rather than cropped to fill the circle: cropping a photo
   loses background, cropping a drawing loses the word. The pastel dome stays
   visible behind it and does the work the photo's own background used to. */
.dome .photo.art{object-fit:contain;padding:11%;box-sizing:border-box}
.dome.sm .photo.art,.dome.xs .photo.art{padding:8%}
.dome.hasart{box-shadow:inset 0 -8px 18px rgba(43,42,56,.06),0 8px 20px rgba(43,42,56,.12)}
.dome::after{content:"";position:absolute;inset:0;border-radius:50%;z-index:3;pointer-events:none;
  background:linear-gradient(155deg,rgba(255,255,255,.45),transparent 42%)}
.dome .ring{position:absolute;inset:-6px;border-radius:50%;z-index:4;pointer-events:none;
  border:5px solid rgba(255,255,255,.85);box-shadow:0 6px 16px rgba(43,42,56,.18)}

/* ---------- trilingual word block ---------- */
.wen{font-size:clamp(26px,8.2vw,34px);font-weight:900;letter-spacing:-.5px;line-height:1.05}
.wnat{font-size:clamp(23px,7.4vw,30px);font-weight:900;line-height:1.1;letter-spacing:-.2px;
  background:linear-gradient(180deg,#FF7A3D,#E0451C);-webkit-background-clip:text;
  background-clip:text;color:transparent;
  filter:drop-shadow(0 2px 0 rgba(224,69,28,.18));
  animation:natpop .52s cubic-bezier(.34,1.56,.64,1) both}
@keyframes natpop{0%{opacity:0;transform:scale(.55) translateY(10px) rotate(-4deg)}
  70%{transform:scale(1.09) translateY(0) rotate(1deg)}100%{opacity:1;transform:none}}
.wnat.ru{background:linear-gradient(180deg,#3D8BFF,#1B4FCC);
  filter:drop-shadow(0 2px 0 rgba(27,79,204,.18))}
.wnat.pulse{animation:natpulse .5s cubic-bezier(.34,1.56,.64,1)}
@keyframes natpulse{0%{transform:scale(1)}45%{transform:scale(1.14)}100%{transform:scale(1)}}
.wother{font-size:clamp(13px,3.8vw,16px);font-weight:800;color:var(--ink2);opacity:.85}
/* Settings > one language only: the third line goes, nothing else moves */
body.onelang .wother{display:none}
.langtag{font-size:10px;font-weight:900;letter-spacing:1px;color:var(--ink2);opacity:.65;
  text-transform:uppercase}
.trirow{display:flex;flex-direction:column;align-items:center;gap:2px}

/* ---------- 3D press physics ---------- */
.d3{transform-style:preserve-3d;transition:transform .2s cubic-bezier(.34,1.56,.64,1),
  box-shadow .2s ease}
.d3:active{transform:perspective(760px) rotateX(7deg) translateY(2px) scale(.975)}
.wcard{perspective:900px}
.wcard.tilt{animation:tilt .5s cubic-bezier(.22,1,.36,1)}
@keyframes tilt{0%{transform:perspective(900px) rotateX(0) rotateY(0)}
  35%{transform:perspective(900px) rotateX(8deg) rotateY(-6deg) scale(.98)}
  100%{transform:perspective(900px) rotateX(0) rotateY(0) scale(1)}}
.flip3d{animation:flip3d .6s cubic-bezier(.22,1,.36,1) both}
@keyframes flip3d{0%{opacity:0;transform:perspective(800px) rotateX(-38deg) translateY(18px)}
  100%{opacity:1;transform:none}}
.opt{transform-style:preserve-3d}
.opt:active{transform:perspective(700px) rotateX(9deg) scale(.955)}

/* ---------- button colour family (one per context) ---------- */
.btn.sky{background:linear-gradient(180deg,#9FC6FF,#5E90E0);box-shadow:0 6px 0 #4A79C4,var(--sh)}
.btn.sky:active{box-shadow:0 2px 0 #4A79C4}
/* Leaving a lesson is an exit, not a reward: red says so, and it is the
   only red button in the app so it cannot be confused with anything. */
.btn.exit{background:linear-gradient(180deg,#FF8A7A,#E23B2E);color:#fff;
  box-shadow:0 6px 0 #B32418,var(--sh)}
.btn.exit:active{box-shadow:0 2px 0 #B32418}
.btn.rose{background:linear-gradient(180deg,#FFAFC9,#F2739E);box-shadow:0 6px 0 #D45580,var(--sh)}
.btn.rose:active{box-shadow:0 2px 0 #D45580}
.btn.lilac{background:linear-gradient(180deg,#D6C7FF,#A48CE8);box-shadow:0 6px 0 #7F63C9,var(--sh)}
.btn.lilac:active{box-shadow:0 2px 0 #7F63C9}
.btn.peach{background:linear-gradient(180deg,#FFCE9B,#FFA24D);color:#6A3B00;
  box-shadow:0 6px 0 #DE8226,var(--sh)}
.btn.peach:active{box-shadow:0 2px 0 #DE8226}
.btn.grass{background:linear-gradient(180deg,#B6E88F,#79C94B);color:#274D0E;
  box-shadow:0 6px 0 #5AA332,var(--sh)}
.btn.grass:active{box-shadow:0 2px 0 #5AA332}
.btn .bi{font-size:19px;line-height:1}
.btn{display:inline-flex;align-items:center;justify-content:center;gap:9px}
.btn.wide{display:flex}
.btn:disabled{filter:grayscale(.4) opacity(.55);cursor:default}

/* section accent bars so each area reads as its own place */
/* renamed from .accbar: the teacher panel's accent buttons carry .accbar too,
   and both stylesheets load on both pages */
.accbar{height:5px;border-radius:99px;margin:2px 0 10px;width:56px}
.accbar.a{background:linear-gradient(90deg,#FFD84D,#FFB020)}
.accbar.b{background:linear-gradient(90deg,#7FD1B9,#3FA98D)}
.accbar.c{background:linear-gradient(90deg,#8FB8F5,#4D82D8)}
.accbar.d{background:linear-gradient(90deg,#C9B6F5,#9188C6)}

/* ---------- success feedback: green wash ---------- */
.flash{position:absolute;inset:0;z-index:70;pointer-events:none;opacity:0}
.flash.go{animation:flash .62s ease-out}
@keyframes flash{0%{opacity:0}18%{opacity:1}100%{opacity:0}}
.flash.ok{background:radial-gradient(circle at 50% 62%,rgba(79,191,139,.42),rgba(79,191,139,0) 68%)}
.flash.big{background:radial-gradient(circle at 50% 50%,rgba(79,191,139,.55),rgba(255,216,77,.28) 45%,transparent 72%)}
.fb.ok{background:linear-gradient(180deg,rgba(232,255,243,0),#E9FBF1 38%)}
.fb.ok .msg{color:#1F7A50}
.fb.no{background:linear-gradient(180deg,rgba(255,247,242,0),#FFF6EF 38%)}
.opt.good{border-color:var(--ok);background:#EAFBF2;
  box-shadow:0 0 0 5px rgba(79,191,139,.18),var(--sh);animation:goodpop .45s cubic-bezier(.34,1.56,.64,1)}
@keyframes goodpop{0%{transform:scale(1)}45%{transform:scale(1.07)}100%{transform:scale(1)}}
.tick{position:absolute;top:-8px;right:-8px;width:30px;height:30px;border-radius:50%;
  background:var(--ok);color:#fff;display:grid;place-items:center;font-weight:900;font-size:16px;
  box-shadow:0 4px 10px rgba(31,122,80,.35);animation:pop .38s cubic-bezier(.34,1.56,.64,1) both;z-index:5}
.opt{position:relative}

/* ---------- Zuzu jumping ---------- */
.jump{animation:jump .72s cubic-bezier(.28,.9,.36,1)}
@keyframes jump{0%{transform:translateY(0) scaleY(1) scaleX(1)}
  14%{transform:translateY(0) scaleY(.82) scaleX(1.14)}
  40%{transform:translateY(-46px) scaleY(1.12) scaleX(.92) rotate(-6deg)}
  62%{transform:translateY(-30px) scaleY(1.04) scaleX(.98) rotate(5deg)}
  84%{transform:translateY(0) scaleY(.88) scaleX(1.1)}
  100%{transform:translateY(0) scaleY(1) scaleX(1)}}
.mascotbtn{border:0;background:transparent;padding:0;cursor:pointer}

/* ---------- top bar age chip ---------- */
.chip.age{background:linear-gradient(180deg,#FFF4D6,#FFE7A6);cursor:pointer}
.chip.tap:active{transform:scale(.93)}
.chip{transition:transform .15s}

/* ---------- town card ---------- */
.town .tdesc{font-size:12px;font-weight:700;color:#5A5670;line-height:1.5;margin-top:8px;
  background:var(--glass2);border-radius:12px;padding:9px 11px}
.bld{cursor:default;transition:transform .2s cubic-bezier(.34,1.56,.64,1)}
.bld:not(.ph):active{transform:scale(1.25) translateY(-4px)}

/* ---------- dictionary ---------- */
.dgroup{margin-bottom:16px}
.dhead{display:flex;align-items:center;gap:9px;margin:0 0 8px}
.dhead .di{width:34px;height:34px;border-radius:12px;display:grid;place-items:center;font-size:18px}
.dhead .dn{font-weight:900;font-size:15px}
.drow{display:flex;align-items:center;gap:11px;background:var(--surf);border-radius:18px;padding:9px 11px;
  box-shadow:var(--sh);margin-bottom:8px;cursor:pointer}
.drow .dome{flex:0 0 auto}
.drow .den{font-weight:900;font-size:16px;line-height:1.15}
.drow .dnat{font-weight:900;font-size:15px;line-height:1.2;
  background:linear-gradient(180deg,#FF7A3D,#E0451C);-webkit-background-clip:text;
  background-clip:text;color:transparent}
.drow .dnat.ru{background:linear-gradient(180deg,#3D8BFF,#1B4FCC);
  -webkit-background-clip:text;background-clip:text}
.drow .doth{font-size:11.5px;font-weight:700;color:var(--ink2)}
.drow .dsp{margin-left:auto;font-size:19px;opacity:.5}
.dknown{width:8px;height:8px;border-radius:50%;background:var(--ok);flex:0 0 auto}

/* progress ring for phrase list etc */
.pchip{transition:transform .16s cubic-bezier(.34,1.56,.64,1)}
.pchip:active{transform:perspective(600px) rotateX(8deg) scale(.97)}

/* calm mode also silences the background field */
body.calm #bgcv{display:none}


/* ---------- very short viewports: keep everything reachable ---------- */
@media(max-height:680px){
  .dome{width:clamp(92px,26vh,120px);height:clamp(92px,26vh,120px);font-size:clamp(46px,13vh,62px)}
  .avatar.lg{width:clamp(90px,24vh,120px);height:clamp(90px,24vh,120px)}
  .qwrap{gap:10px}
  .wcard{padding:13px;gap:5px}
  .rewardbig{font-size:clamp(44px,12vh,62px)}
  h1{font-size:clamp(21px,5vh,26px)}
}
@media(max-height:560px){
  .wother{display:none}          /* third language hides before anything important */
  .spk{margin-top:0}
  .prompt{font-size:13px}
}

/* ============================================================
   v3 — attention effects, running spark borders, timer
   ============================================================ */

/* ---------- translation: unmistakably different from English ---------- */
.wnat{
  position:relative;display:inline-block;padding:4px 14px 6px;border-radius:16px;
  background:linear-gradient(180deg,#FFF6D9,#FFE9A8);
  -webkit-background-clip:border-box;background-clip:border-box;
  color:#D2400F;
  text-shadow:0 2px 0 rgba(255,255,255,.85), 0 -1px 0 rgba(210,64,15,.18);
  box-shadow:0 5px 0 #F0C64B, 0 10px 18px rgba(210,64,15,.16);
  animation:natland .58s cubic-bezier(.34,1.56,.64,1) both;
  filter:none}
.wnat.ru{background:linear-gradient(180deg,#E4F0FF,#BFD9FF);color:#123C9E;
  text-shadow:0 2px 0 rgba(255,255,255,.9), 0 -1px 0 rgba(18,60,158,.18);
  box-shadow:0 5px 0 #8FB2E8, 0 10px 18px rgba(18,60,158,.16)}
/* arrives with a real jump, then breathes so the eye keeps returning to it */
@keyframes natland{
  0%{opacity:0;transform:translateY(-30px) scale(.6) rotate(-7deg)}
  55%{opacity:1;transform:translateY(6px) scale(1.12) rotate(2deg)}
  75%{transform:translateY(-4px) scale(.98) rotate(-1deg)}
  100%{opacity:1;transform:none}}
@keyframes natbob{
  0%,100%{transform:translateY(0) rotate(0)}
  50%{transform:translateY(-5px) rotate(-1.2deg)}}
/* the sheen runs once when the child asks to hear the word, never on a loop:
   looping motion next to the text being memorised competes with recall */
.wnat::after{content:"";position:absolute;inset:0;border-radius:16px;pointer-events:none;
  background:linear-gradient(115deg,transparent 32%,rgba(255,255,255,.75) 47%,transparent 62%);
  background-size:250% 100%;background-position:130% 0;opacity:0}
.wnat.pulse::after{opacity:1;animation:shine 1.1s ease-out 1}
@keyframes shine{0%{background-position:130% 0}55%,100%{background-position:-60% 0}}
.wnat.pulse{animation:natjump .62s cubic-bezier(.28,.9,.36,1)}
@keyframes natjump{
  0%{transform:translateY(0) scaleY(1) scaleX(1)}
  16%{transform:translateY(0) scaleY(.8) scaleX(1.16)}
  44%{transform:translateY(-26px) scaleY(1.14) scaleX(.9) rotate(-4deg)}
  70%{transform:translateY(-8px) scaleY(1.02) scaleX(1) rotate(3deg)}
  86%{transform:translateY(0) scaleY(.9) scaleX(1.08)}
  100%{transform:translateY(0) scaleY(1) scaleX(1)}}
body.calm .wnat{animation:natland .35s ease both}
body.calm .wnat::after{display:none}

/* ---------- running spark border ----------------------------------
   The wrapper paints a rotating conic gradient; its child sits on top
   with an opaque background, so only the 3px rim shows. No masks -
   masks silently fail on some engines and leak the gradient inward. */
.sparkbox{position:relative;border-radius:26px;padding:3px;overflow:hidden;
  background:var(--rim);isolation:isolate}
.sparkbox::before{content:"";position:absolute;left:-50%;top:-50%;width:200%;height:200%;
  z-index:0;
  background:conic-gradient(from 0deg,
    rgba(255,216,77,0) 0deg, #FFD84D 18deg, #FFFFFF 30deg, #FF9FC0 42deg,
    rgba(255,159,192,0) 62deg,
    rgba(127,209,185,0) 178deg, #7FD1B9 196deg, #FFFFFF 208deg, #8FB8F5 220deg,
    rgba(143,184,245,0) 240deg,
    rgba(255,216,77,0) 360deg);
  animation:orbit 3.2s linear infinite}
@keyframes orbit{to{transform:rotate(360deg)}}
/* The moving light must only ever show as a 3px rim. This inner plate is
   painted by the frame itself, so even a single-element sparkbox cannot
   leak the gradient across its middle. */
.sparkbox::after{content:"";position:absolute;inset:3px;border-radius:23px;
  z-index:0;background:var(--surf)}
.sparkbox.thin::after{inset:2px;border-radius:24px}
.sparkbox>*{position:relative;z-index:1;border-radius:23px;background:transparent}
.sparkbox.warm::before{background:conic-gradient(from 0deg,
  rgba(255,216,77,0) 0deg,#FFD84D 18deg,#FFFFFF 30deg,#FFB020 42deg,
  rgba(255,176,32,0) 62deg,rgba(255,201,168,0) 178deg,#FFC9A8 196deg,
  #FFFFFF 208deg,#FF9FC0 220deg,rgba(255,159,192,0) 240deg,rgba(255,216,77,0) 360deg)}
.sparkbox.cool::before{background:conic-gradient(from 0deg,
  rgba(127,209,185,0) 0deg,#7FD1B9 18deg,#FFFFFF 30deg,#8FB8F5 42deg,
  rgba(143,184,245,0) 62deg,rgba(201,182,245,0) 178deg,#C9B6F5 196deg,
  #FFFFFF 208deg,#A7E8D8 220deg,rgba(167,232,216,0) 240deg,rgba(127,209,185,0) 360deg)}
.sparkbox.gold::before{animation-duration:2.2s}
.sparkbox.thin{padding:2px}
.sparkbox.thin>*{border-radius:24px}
body.calm .sparkbox::before{animation:none}
body.calm .sparkbox{background:var(--rim2)}

/* running light on ordinary buttons: a bright band sweeping the rim */
.btn.edge{position:relative;overflow:hidden}
.btn.edge::after{content:"";position:absolute;inset:0;border-radius:inherit;
  pointer-events:none;
  background:linear-gradient(105deg,transparent 38%,rgba(255,255,255,.85) 50%,transparent 62%);
  background-size:230% 100%;background-repeat:no-repeat;
  animation:bandsweep 2.8s ease-in-out infinite}
@keyframes bandsweep{0%{background-position:150% 0}55%,100%{background-position:-70% 0}}
body.calm .btn.edge::after{display:none}

/* section header underline that sweeps */
.accbar{position:relative;overflow:hidden}
.accbar::after{content:"";position:absolute;inset:0;border-radius:99px;
  background:linear-gradient(90deg,transparent,rgba(255,255,255,.95),transparent);
  background-size:55% 100%;background-repeat:no-repeat;
  animation:sweep 2.6s ease-in-out infinite}
@keyframes sweep{0%{background-position:-60% 0}60%,100%{background-position:160% 0}}
body.calm .accbar::after{display:none}

/* ---------- stopwatch chip ---------- */
.chip.time{background:linear-gradient(180deg,#E9F6FF,#C9E6FB);font-variant-numeric:tabular-nums}
.tbig{font-size:clamp(30px,9vw,40px);font-weight:900;font-variant-numeric:tabular-nums;
  letter-spacing:-.5px;color:#1F6C8F}
.tunit{font-size:13px;font-weight:800;color:var(--ink2)}
.statgrid{display:grid;grid-template-columns:1fr 1fr;gap:10px;width:100%}
/* ---------- the home menu ----------
   Everything that is not today's lesson lives here: two columns of small
   tiles, tall enough for a child's thumb and short enough that four of them
   never push the lesson button off the screen. */
.mgrid{display:grid;grid-template-columns:1fr 1fr;gap:10px;width:100%;margin-bottom:8px}
.mtile{background:var(--surf);border-radius:20px;box-shadow:var(--sh);
  padding:13px 11px;text-align:center;cursor:pointer;
  display:flex;flex-direction:column;align-items:center;gap:5px;
  color:var(--ink)}
.mtile .mico{width:44px;height:44px;display:grid;place-items:center}
.mtile .mlab{font-weight:800;font-size:clamp(14px,4.2vw,16px);line-height:1.15}
.mtile .mnote{font-size:11.5px;font-weight:700;color:var(--ink2);line-height:1.2}
.stat{background:var(--surf);border-radius:20px;padding:13px;box-shadow:var(--sh);text-align:center}
.stat .sv{font-size:clamp(19px,5.6vw,23px);font-weight:900;font-variant-numeric:tabular-nums}
.stat .sl2{font-size:11px;font-weight:800;color:var(--ink2);margin-top:2px;line-height:1.25}
.stat.ok .sv{color:#1F7A50}
.stat.time .sv{color:#1F6C8F}
.stat.coin .sv{color:#B8860B}

/* ---------- text inputs (join / teacher panel) ---------- */
.tinput{width:100%;font-family:var(--font);font-weight:800;font-size:16px;color:var(--ink);
  background:#FFFDF5;border:2px solid #E4DFF2;border-radius:14px;padding:11px 13px;margin-top:7px;
  outline:none;-webkit-user-select:text;user-select:text}
.tinput:focus{border-color:var(--mint);background:var(--surf)}
.tinput.ta{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:11.5px;
  font-weight:600;line-height:1.45;resize:vertical}
.selseg{font-weight:900}

/* ============================================================
   v4 — big titles, 3D icons, balloons, dictionary search
   ============================================================ */

/* ---------- section titles: unmistakably bigger than body ---------- */
.stitle{display:flex;align-items:center;gap:11px;margin:2px 0 4px}
.stitle .icw{flex:0 0 auto;filter:drop-shadow(0 3px 5px rgba(43,42,56,.22))}
.stitle .st{font-size:clamp(20px,6.2vw,26px);font-weight:900;letter-spacing:-.5px;
  line-height:1.08;color:#2B2A38}
.stitle .st.hero{font-size:clamp(23px,7.2vw,30px)}
/* gradient-filled headline for the two flagship sections */
.st.grad{background:linear-gradient(180deg,#F59E1B,#D2400F);-webkit-background-clip:text;
  background-clip:text;color:transparent;
  filter:drop-shadow(0 2px 0 rgba(210,64,15,.16))}
.st.grad.cool{background:linear-gradient(180deg,#3D8BFF,#1B4FCC);
  -webkit-background-clip:text;background-clip:text;
  filter:drop-shadow(0 2px 0 rgba(27,79,204,.16))}
.st.pop{animation:titlepop .6s cubic-bezier(.34,1.56,.64,1) both}
@keyframes titlepop{0%{opacity:0;transform:translateY(-14px) scale(.82)}
  60%{transform:translateY(3px) scale(1.05)}100%{opacity:1;transform:none}}
h1,h2{letter-spacing:-.6px}
h2{font-size:clamp(21px,6.4vw,27px);font-weight:900}
/* the small all-caps kicker is gone from the main sections; keep for minor ones */
.kicker{font-size:11px;letter-spacing:1.4px}

/* ---------- 3D icon wrapper ---------- */
.icw{display:inline-flex;align-items:center;justify-content:center;line-height:0}
.ic{display:block;overflow:visible}
/* Chrome icons draw in currentColor. A <button> takes its colour from the
   user agent, not from the page, and on a phone in system dark mode that
   colour is white - which turned the back and settings buttons into blank
   white squares. Buttons follow the page unless they say otherwise. */
button{color:var(--ink)}
.icbtn{width:clamp(42px,12vw,48px);height:clamp(42px,12vw,48px);border-radius:16px;border:0;
  background:var(--glass);box-shadow:var(--sh);cursor:pointer;color:var(--ink);
  display:grid;place-items:center;padding:0;
  transition:transform .16s cubic-bezier(.34,1.56,.64,1)}
.icbtn:active{transform:scale(.9) rotate(-6deg)}
.chip .icw{margin-right:1px}
.chip{gap:6px;font-size:clamp(12px,3.6vw,14px)}
.sitem .ico3{width:clamp(46px,13vw,56px);height:clamp(46px,13vw,56px);border-radius:17px;
  display:grid;place-items:center;flex:0 0 auto;
  filter:drop-shadow(0 4px 6px rgba(43,42,56,.18))}
.bld3{filter:drop-shadow(0 3px 4px rgba(43,42,56,.2));
  transition:transform .2s cubic-bezier(.34,1.56,.64,1);cursor:default}
.bld3.ph{opacity:.22;filter:grayscale(1)}
.bld3:not(.ph):active{transform:scale(1.22) translateY(-4px)}
.btn .icw{filter:drop-shadow(0 2px 3px rgba(0,0,0,.22))}

/* ---------- rating rows: big, few words ---------- */
.rrow{display:flex;align-items:center;gap:12px;background:var(--surf);border-radius:20px;
  padding:12px 14px;box-shadow:var(--sh);margin-bottom:9px}
.rrow .rk{font-size:clamp(20px,6vw,25px);font-weight:900;width:38px;text-align:center;
  font-variant-numeric:tabular-nums;color:var(--ink2)}
.rrow .rn{font-size:clamp(17px,5.2vw,21px);font-weight:900;line-height:1.15;flex:1;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.rrow .rc{font-size:clamp(19px,5.8vw,24px);font-weight:900;color:#B8860B;
  font-variant-numeric:tabular-nums;display:flex;align-items:center;gap:5px}
.rrow.me{background:#FFFDF0}
.rbig{font-size:clamp(34px,11vw,46px);font-weight:900;line-height:1;
  font-variant-numeric:tabular-nums}
.rlab{font-size:clamp(13px,4vw,16px);font-weight:800;color:var(--ink2);margin-top:3px}
.segrow{display:flex;gap:8px;margin:6px 0 12px}
.seg{flex:1;border:0;border-radius:16px;padding:12px 6px;font-family:var(--font);
  font-weight:900;font-size:clamp(14px,4.4vw,17px);background:var(--surf);color:var(--ink2);
  box-shadow:var(--sh);cursor:pointer}
.seg.on{background:linear-gradient(180deg,#FFE07A,#FFC22E);color:#5A4200;
  box-shadow:0 4px 0 #E0A310,var(--sh)}

/* ---------- balloons drifting up ---------- */
#balloons{position:absolute;inset:0;pointer-events:none;z-index:4;overflow:hidden}
.bal{position:absolute;bottom:-90px;animation:rise-bal linear forwards;
  filter:drop-shadow(0 6px 10px rgba(43,42,56,.16))}
@keyframes rise-bal{
  0%{transform:translateY(0) translateX(0) rotate(0);opacity:0}
  8%{opacity:.95}
  100%{transform:translateY(calc(-100dvh - 140px)) translateX(var(--drift,20px))
    rotate(var(--spin,8deg));opacity:.95}}
body.calm #balloons{display:none}
/* burst: the skin snaps outward and vanishes; particles come from fx.js */
.bal.pop{animation:none;transition:transform .18s cubic-bezier(.2,1.6,.4,1),opacity .22s}
.bal.pop{transform:scale(1.45);opacity:0}

/* ---------- dictionary search ---------- */
.dsearch{position:sticky;top:0;z-index:5;padding:4px 0 10px;
  background:linear-gradient(180deg,rgba(255,249,240,.97) 70%,rgba(255,249,240,0))}
.dsbox{display:flex;align-items:center;gap:9px;background:var(--surf);border-radius:18px;
  padding:10px 13px;box-shadow:var(--sh);border:2.5px solid #EDE7F6}
.dsbox:focus-within{border-color:var(--mint)}
.dsi{flex:1;border:0;outline:none;background:transparent;font-family:var(--font);
  font-weight:800;font-size:clamp(15px,4.6vw,18px);color:var(--ink);min-width:0;
  -webkit-user-select:text;user-select:text}
.dsi::placeholder{color:#B9B4C8}
.dsx{border:0;background:#F1EEF9;border-radius:50%;width:26px;height:26px;cursor:pointer;
  font-weight:900;color:var(--ink2);flex:0 0 auto}
.dhint{font-size:12.5px;font-weight:800;color:var(--ink2);margin:2px 0 8px;text-align:center}
.dcount{font-size:12px;font-weight:800;color:var(--ink2);margin:0 0 8px}
mark.hl{background:#FFE9A8;color:inherit;border-radius:4px;padding:0 2px}
.dnear{background:#FFFBEA;border:1.5px dashed #F0D68A}

/* ============================================================
   DARK MODE
   Evening homework is the normal case, so dark is a first-class
   theme rather than an inverted filter: surfaces darken, the word
   itself stays the brightest thing on screen, and the photographs
   are dimmed slightly so they stop glaring in a dark room.
   ============================================================ */
body.dark{
  color-scheme:dark;
  --ink:#F4F2FB; --ink2:#A9A4C0;
  --surf:#2A2839; --surf2:#211F2E;
  --glass:rgba(58,55,80,.86); --glass2:rgba(58,55,80,.60);
  --rim:#3A3750; --rim2:#332F46; --line:rgba(255,255,255,.12);
  --page1:#1A1826; --page2:#14121F;
  --soft:#4A3F1E;
  --sh:0 10px 24px rgba(0,0,0,.45), 0 2px 6px rgba(0,0,0,.35);
  --shb:0 16px 34px rgba(0,0,0,.55);
  background:#12111C;
}
@media(min-width:560px) and (min-height:720px){
  body.dark{background:radial-gradient(circle at 50% 20%,#241F33,#100E19)}
}
/* the per-screen pastel wash would glow in the dark; scrim it back */
body.dark #bg{filter:saturate(.7) brightness(.42)}
body.dark #bg::after{background:radial-gradient(120% 60% at 50% 0%,rgba(0,0,0,.35),transparent 70%)}
body.dark .hills{opacity:.30}
body.dark .card,body.dark .town,body.dark .wcard,body.dark .drow,body.dark .setrow,
body.dark .stat,body.dark .pchip,body.dark .rrow{border:1px solid var(--line)}
body.dark .dome{background:radial-gradient(circle at 34% 26%,#4A4660,rgba(255,255,255,.10) 46%,rgba(0,0,0,.25))}
body.dark .dome .photo{filter:brightness(.86) saturate(.95)}
/* artwork is already flat and light; dimming it only makes it muddy */
body.dark .dome .photo.art{filter:none}
body.dark .dome{border:1px solid rgba(255,255,255,.10)}
body.dark .wen{color:#FFFFFF}
body.dark .wnat{background:linear-gradient(180deg,#4A3410,#3A2708);color:#FFD98E;
  text-shadow:0 1px 0 rgba(0,0,0,.45)}
body.dark .wnat.ru{background:linear-gradient(180deg,#16304F,#0F2540);color:#A9CDFF}
body.dark .doth,body.dark .pnote,body.dark .note,body.dark .rlab,body.dark .sl2{color:var(--ink2)}
body.dark .opt,body.dark .key,body.dark .sl,body.dark .mc .b{background:var(--surf)}
body.dark .ghost{border-color:var(--line)}
body.dark .seg.on{background:var(--sky);color:#12111C}
body.dark .bld3.ph{background:rgba(255,255,255,.05)}
body.dark mark.hl{background:#5A4A12;color:#FFE9A8}
body.dark .icbtn{background:var(--glass)}
body.dark .ic-line{stroke:#EDEAF7}

/* ---------- My Town: one visible plot per story ---------- */
.plot{position:relative;border-radius:16px;padding:8px 4px 6px;text-align:center;
  background:var(--surf);box-shadow:var(--sh);
  transition:transform .2s cubic-bezier(.34,1.56,.64,1)}
.plot .pico{display:grid;place-items:center;height:38px}
.plot .pico svg{filter:drop-shadow(0 3px 4px rgba(43,42,56,.22))}
.plot .plab{font-size:10.5px;font-weight:800;color:var(--ink2);margin-top:3px;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.plot.built{background:linear-gradient(180deg,var(--surf),#FFFBEE);
  border:2px solid #FFD84D}
.plot.built .plab{color:var(--ink)}
.plot.built:active{transform:scale(1.08) translateY(-3px)}
.plot.ph{background:var(--glass2);border:2px dashed rgba(43,42,56,.18);box-shadow:none}
.plot.ph .pico{opacity:.42;filter:grayscale(.65)}
.plot.ph .plab{opacity:.6}
.ptick{position:absolute;top:-6px;right:-4px;width:22px;height:22px;border-radius:50%;
  background:#4FBF8B;display:grid;place-items:center;box-shadow:0 2px 6px rgba(43,42,56,.25)}
.ptick svg{width:14px;height:14px}
body.dark .town{background:linear-gradient(180deg,#242233,#2C2536)}
body.dark .plot.built{background:linear-gradient(180deg,#33304A,#3A3020);border-color:#C99A18}
body.dark .plot.ph{border-color:rgba(255,255,255,.16)}

/* dark-mode corrections for the remaining light-only surfaces */
body.dark .pair.sel{background:#1E3A31}
body.dark .age.sel{background:#3A3320}
body.dark .bar{background:rgba(255,255,255,.12)}
body.dark .opt.good{background:#1D3B2C}
body.dark .opt.bad{background:#3B2622;border-color:#8A5544}
body.dark .tok.inslot{background:linear-gradient(180deg,#4A3F1E,#3A3010)}
body.dark .sw{background:#4A4660}
body.dark .chip.age{background:linear-gradient(180deg,#3A3320,#2E2718)}
body.dark .tinput{background:#211F2E;border-color:#443F5C;color:var(--ink)}
body.dark .rrow.me{background:#3A3320}
body.dark .dsx{background:#3A3750}
body.dark .dnear{background:#2E2A22;border-color:#6B5A2A}
body.dark .dsearch{background:linear-gradient(180deg,rgba(20,18,31,.97) 70%,rgba(20,18,31,0))}
body.dark .dsbox{border-color:#3A3750}
body.dark .slot{border-color:rgba(255,255,255,.18)}
body.dark .cefr{background:var(--glass);color:var(--ink2)}
body.dark .spkb.nat{background:linear-gradient(180deg,#3A3750,#2C2A3D);color:var(--ink)}
body.dark .plab,body.dark .langtag{color:var(--ink2)}

/* ============================================================
   CURRENT STORY
   One story is "yours now". Green, framed, labelled, and nudged with a
   small repeating pop so the eye lands on it before anything else. The
   nudge is a scale pulse rather than travel, so it cannot be mistaken
   for something moving away, and it stops in calm mode.
   ============================================================ */
.sitem.now{background:linear-gradient(160deg,#EAFBF1,#D6F5E4);
  border:2.5px solid #4FBF8B;
  box-shadow:0 0 0 5px rgba(79,191,139,.16),0 12px 26px rgba(31,122,80,.20);
  animation:nowpulse 2.6s ease-in-out infinite}
@keyframes nowpulse{
  0%,100%{box-shadow:0 0 0 5px rgba(79,191,139,.16),0 12px 26px rgba(31,122,80,.20)}
  50%{box-shadow:0 0 0 11px rgba(79,191,139,.05),0 14px 30px rgba(31,122,80,.26)}}
.sitem.now .nm{color:#166B44}
.sitem.now .ico3 svg{filter:drop-shadow(0 3px 5px rgba(22,107,68,.30))}
.nowtag{display:inline-flex;align-items:center;gap:5px;margin-top:5px;
  background:#4FBF8B;color:#fff;border-radius:99px;padding:3px 10px 4px;
  font-size:11px;font-weight:900;letter-spacing:.2px;
  box-shadow:0 3px 8px rgba(31,122,80,.30);
  animation:tagpop 2.6s ease-in-out infinite}
.nowtag svg{width:13px;height:13px}
@keyframes tagpop{0%,100%{transform:scale(1)}46%{transform:scale(1.09)}}
.sitem.now .bar{background:rgba(22,107,68,.14)}
.sitem.now .bar i{background:linear-gradient(90deg,#4FBF8B,#2F9E70)}
body.calm .sitem.now,body.calm .nowtag{animation:none}
body.dark .sitem.now{background:linear-gradient(160deg,#1E3B2C,#1A3327);border-color:#4FBF8B}
body.dark .sitem.now .nm{color:#8FE6BB}

/* ---------- My Town, folded away ---------- */
.trowhead{display:flex;align-items:center;gap:8px;cursor:pointer}
.trowhead .stitle{margin:0;flex:1}
.tcount{font-size:13px;font-weight:900;color:var(--ink2);
  background:var(--glass2);border-radius:99px;padding:3px 10px}
.tcaret{display:grid;place-items:center;opacity:.7}
.tcaret svg{transform:rotate(-90deg)}

/* ---------- confirm sheet ---------- */
.sheet{position:absolute;inset:0;z-index:120;display:grid;place-items:center;
  padding:22px;background:rgba(28,26,40,.42);backdrop-filter:blur(3px);
  animation:fadein .18s ease both}
@keyframes fadein{from{opacity:0}to{opacity:1}}
.sheetcard{width:100%;max-width:330px;background:var(--surf);border-radius:26px;
  padding:20px 18px;text-align:center;box-shadow:var(--shb);
  animation:sheetin .3s cubic-bezier(.2,1.3,.4,1) both}
@keyframes sheetin{from{opacity:0;transform:translateY(22px) scale(.94)}
  to{opacity:1;transform:none}}
.shico{display:grid;place-items:center;margin-bottom:6px}
.sheetcard .btn{width:100%}
.langtag2{display:inline-grid;place-items:center;min-width:26px;height:20px;padding:0 5px;
  border-radius:7px;background:var(--ink);color:var(--surf);
  font-size:11px;font-weight:900;letter-spacing:.5px}
body.dark .langtag2{background:var(--ink);color:#1A1826}

/* ============================================================
   PROFILE, BADGES, DISCUSSION
   ============================================================ */
.pav{width:56px;height:56px;border-radius:50%;display:grid;place-items:center;
  background:linear-gradient(180deg,#FFF6D9,#FFE9A8);box-shadow:var(--sh);flex:0 0 auto}
body.dark .pav{background:linear-gradient(180deg,#3A3320,#2E2718)}
.mechip{display:inline-flex;align-items:center;gap:5px;background:var(--glass);
  border-radius:99px;padding:5px 11px 5px 7px;font-size:12.5px;font-weight:900;
  box-shadow:var(--sh);cursor:pointer;max-width:112px}
.mechip span:last-child{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.mechip:active{transform:scale(.94)}

.bdg{display:grid;place-items:center;width:46px;height:46px;border-radius:50%;
  background:linear-gradient(180deg,#FFF6D9,#FFE07A);
  box-shadow:0 4px 0 #E8B420,0 8px 16px rgba(184,134,11,.25);flex:0 0 auto}
.bdg.lg{width:58px;height:58px}
.bdg.sm{width:34px;height:34px}
.bdg.xs{width:22px;height:22px;box-shadow:none;background:none}
body.dark .bdg{background:linear-gradient(180deg,#4A3F1E,#3A3010);box-shadow:0 4px 0 #6B5A2A}
body.dark .bdg.xs{background:none;box-shadow:none}

.bgrid{display:grid;grid-template-columns:repeat(3,1fr);gap:9px;margin:8px 0 2px}
.bcard{background:var(--surf);border-radius:18px;padding:11px 6px 9px;text-align:center;
  box-shadow:var(--sh);display:grid;justify-items:center;gap:6px}
.bcard .bnm{font-size:10.5px;font-weight:900;color:var(--ink2);line-height:1.2}
body.dark .bcard{border:1px solid var(--line)}

/* discussion */
.msg{max-width:82%;align-self:flex-start;background:var(--surf);border-radius:18px 18px 18px 6px;
  padding:9px 12px 10px;box-shadow:var(--sh);margin-bottom:9px}
.msg.me{align-self:flex-end;background:linear-gradient(180deg,#EAFBF1,#D6F5E4);
  border-radius:18px 18px 6px 18px}
body.dark .msg{border:1px solid var(--line)}
body.dark .msg.me{background:linear-gradient(180deg,#1E3B2C,#1A3327)}
.mhead{display:flex;align-items:center;gap:5px;font-size:11.5px;font-weight:900;
  color:var(--ink2);margin-bottom:3px}
.mtext{font-size:15px;font-weight:800;line-height:1.35;word-break:break-word}
#chatscroll{display:flex;flex-direction:column}
.qrow{display:flex;gap:7px;overflow-x:auto;padding:6px 0 8px;scrollbar-width:none}
.qrow::-webkit-scrollbar{display:none}
.qchip{flex:0 0 auto;background:var(--glass);border-radius:99px;padding:8px 13px;
  font-size:13px;font-weight:800;box-shadow:var(--sh);white-space:nowrap;cursor:pointer}
.qchip:active{transform:scale(.94)}
.cbar{display:flex;gap:8px;align-items:center;padding-top:2px}
.cbar .tinput{margin-top:0;flex:1}
.tinput.pin{letter-spacing:10px;font-size:22px;text-align:center;font-weight:900}
.pchip.on{border:2.5px solid var(--mint);background:#F2FFFB}
body.dark .pchip.on{background:#1E3A31}

/* ---------- teacher entry, deliberately quiet ---------- */
/* No fill, no border, no icon: it reads as a footnote rather than a
   button, which is exactly how a child skims past it. */
.adminlink{
  display:block; width:100%; margin:26px 0 10px; padding:10px 0;
  background:none; border:0; font:inherit;
  font-size:12.5px; letter-spacing:.02em;
  color:var(--ink); opacity:.34; text-align:center;
  text-decoration:underline; text-underline-offset:3px;
  cursor:pointer;
}
.adminlink:active{ opacity:.7 }

/* adult-facing error: a flat line, no shake and no sound */
.aderr{
  margin-top:10px; padding:8px 12px; border-radius:10px;
  background:#FDECEC; color:#A32020;
  font-size:13.5px; line-height:1.35; font-weight:600;
}
body.dark .aderr{ background:#3A2226; color:#FFB4B4 }

/* no aliases: every stacked action uses .btn, so there is exactly one
   place that decides how a button looks */

/* flags line up with the text baseline and never squash */
.fl{display:block;border-radius:5px;flex:0 0 auto}
.pair .fl{width:auto;height:26px}

body.dark .btn.plain{background:linear-gradient(180deg,#3A3750,#2C2A3D);color:var(--ink);
  box-shadow:0 5px 0 #191728,var(--sh)}
body.dark .btn.plain:active{box-shadow:0 1px 0 #191728}
body.dark .btn.flat{border-color:var(--rim2);color:var(--ink)}
.flagpair{display:flex;gap:5px;align-items:center;flex:0 0 auto;margin-right:2px}
.seg .fl{display:block}

/* was .empty — the teacher panel styles that name too */
.kempty{text-align:center;padding:22px 12px;color:var(--ink2);font-weight:800;font-size:13.5px}

/* ---------- teacher's brief + written answers ---------- */
.bcard2{background:var(--surf);border-radius:22px;box-shadow:var(--sh);
  padding:14px;display:flex;flex-direction:column;gap:10px}
.bimg{border-radius:16px;overflow:hidden;background:var(--surf2);cursor:pointer;
  max-height:44dvh;display:grid;place-items:center}
.bimg img{width:100%;height:auto;display:block;max-height:44dvh;object-fit:contain}
.bnote{font-size:15px;font-weight:700;line-height:1.45;color:var(--ink)}
.bfile{display:flex;align-items:center;gap:9px;text-decoration:none;
  background:var(--glass);border:1px solid var(--line);border-radius:14px;
  padding:11px 13px;color:var(--ink);font-weight:800;font-size:14px}
.bfile:active{transform:scale(.99)}
/* full-size picture viewer */
.shot{position:absolute;inset:0;z-index:200;background:rgba(16,14,26,.92);
  display:grid;place-items:center;padding:14px;animation:fadein .16s ease both}
.shot img{max-width:100%;max-height:100%;border-radius:12px}
.wq{font-size:clamp(17px,5vw,21px);font-weight:900;line-height:1.3}
.wans{min-height:120px;resize:vertical;font-size:15px;line-height:1.5;font-weight:700}
.wcount{align-self:flex-end;font-size:11px;font-weight:800;color:var(--ink2)}

/* ---------- did you like it? ---------- */
.funrow{display:grid;grid-template-columns:1fr 1fr 1fr;gap:10px;margin-top:8px}
.funb{border:2px solid var(--line,#E7E1F5);background:#fff;border-radius:18px;
  min-height:64px;display:grid;place-items:center;cursor:pointer;transition:transform .12s}
.funb:active{transform:scale(.94)}

/* ---------- Zuzu points: the first-run guide ----------
   The card being pointed at stays fully lit and fully tappable; everything
   else dims. A child can finish the guide by doing the thing, which is the
   whole point of it. */
.coachlayer{position:absolute;inset:0;z-index:200;pointer-events:none}
.coachshade{position:absolute;inset:0;pointer-events:auto}
.coachring{position:absolute;border-radius:26px;pointer-events:auto;cursor:pointer;
  box-shadow:0 0 0 9999px rgba(24,22,40,.52),0 0 0 3px #FFD84D,0 0 26px 6px rgba(255,216,77,.55);
  animation:cring 1.5s ease-in-out infinite}
@keyframes cring{50%{box-shadow:0 0 0 9999px rgba(24,22,40,.52),0 0 0 5px #FFE9A0,
  0 0 34px 10px rgba(255,216,77,.75)}}
.coachtoy{position:absolute;width:104px;height:104px;pointer-events:none;
  filter:drop-shadow(0 8px 14px rgba(0,0,0,.3))}
.coachtoy svg{width:100%;height:100%;display:block}
.coachtoy.leap{animation:cleapb .5s cubic-bezier(.2,1.5,.4,1) both}
.coachtoy[data-from="tl"].leap{animation-name:cleapt}
@keyframes cleapb{0%{transform:translate(-70px,90px) scale(.35) rotate(-14deg);opacity:0}
  60%{transform:translate(4px,-14px) scale(1.08) rotate(4deg);opacity:1}
  100%{transform:none;opacity:1}}
@keyframes cleapt{0%{transform:translate(-70px,-90px) scale(.35) rotate(14deg);opacity:0}
  60%{transform:translate(4px,12px) scale(1.08) rotate(-4deg);opacity:1}
  100%{transform:none;opacity:1}}
.coachtoy.hop{animation:chop 1s ease-in-out .1s infinite}
@keyframes chop{0%,100%{transform:translateY(0) rotate(0)}
  30%{transform:translateY(-15px) rotate(-5deg)}
  55%{transform:translateY(0) rotate(0)}
  70%{transform:translateY(-7px)}}
.coachhand{position:absolute;width:46px;height:46px;pointer-events:none;
  filter:drop-shadow(0 4px 8px rgba(0,0,0,.32))}
.coachhand svg{width:100%;height:100%;display:block}
/* the drawn hand points up, so it only turns over when the toy stands
   above the card and has to reach down onto it */
.coachhand[data-dir="down"]{transform:rotate(180deg)}
.coachhand.tapping{animation:chandu .85s ease-in-out infinite}
.coachhand[data-dir="down"].tapping{animation-name:chandd}
@keyframes chandu{0%,100%{transform:translateY(0)}50%{transform:translateY(-13px)}}
@keyframes chandd{0%,100%{transform:rotate(180deg) translateY(0)}
  50%{transform:rotate(180deg) translateY(-13px)}}
.coachbub{position:absolute;width:190px;pointer-events:auto;background:var(--surf);
  border-radius:20px;padding:11px 13px 9px;box-shadow:0 10px 26px rgba(0,0,0,.28);
  border:2.5px solid #FFD84D}
.cbt{font-weight:900;font-size:15px;display:flex;align-items:center;gap:6px;
  color:var(--ink);line-height:1.15}
.cbn{font-size:12.5px;color:var(--ink2);font-weight:700;margin:5px 0 8px;line-height:1.3}
.cbr{display:flex;align-items:center;gap:8px}
.cbskip{flex:0 0 auto;background:none;border:0;font:inherit;font-size:11.5px;
  font-weight:800;color:var(--ink2);padding:5px 2px;cursor:pointer}
.cbnext{flex:1;background:linear-gradient(180deg,#FFE9A0,#FFC93C);border:0;
  border-radius:12px;padding:8px 10px;font:inherit;font-size:13px;font-weight:900;
  color:#5A4200;box-shadow:0 3px 0 #E0A800;cursor:pointer}
.cbnext:active{transform:translateY(2px);box-shadow:0 1px 0 #E0A800}
body.dark .coachbub{background:#241F2E}
body.calm .coachring,body.calm .coachtoy.hop,body.calm .coachhand.tapping{animation:none}
