/* ════════════════════════════════════════════════════════════════════════
   journey-onboarding.css — first-run THE UNFOLD flow (port of
   design-mockups/onboarding/onb-polished3.html into the real app).

   Scoped under #kjOnb (a full-screen overlay inside the .kj root). The mockup's
   phone bezel (.screen / .stage / .phone) is dropped — #reel fills the viewport.
   c-kit tokens the mockup relied on are redeclared LOCALLY on #kjOnb so this is
   self-contained (and consistent with css/journey.css's c-kit values).

   Beats: 0 opener (word-snow) · 1 bloom (glyphs→pictures) · 2 unfold (one word,
   a whole world) · 3 picker (starter decks → Begin). "Build your own" hands off
   to the real composer (js/journey-composer.js), so the mockup's inline
   constructor CSS is intentionally omitted.

   和の感性 floor — the LOCKED three-gold contract: gold (--gold #C9A96E, on dark
   surfaces lifted to --gold-bright for legibility) appears at EXACTLY three earned
   moments, pixel-identical material each time, so its recurrence tells the reward
   story: (1) the payoff accent ("A whole world."), (2) the おすすめ pin (the dot +
   ring on the recommended door), (3) the 道 handoff seal (ring + 道 kanji). Nowhere
   else. Selection is moss; romaji rides under every Japanese token.
   ════════════════════════════════════════════════════════════════════════ */

#kjOnb{
  /* c-kit tokens (local, self-contained) */
  --font-jp:'Klee One','Noto Sans JP',serif;
  --font-ui:'Inter','Noto Sans JP',sans-serif;
  --bg:var(--color-paper); --paper:var(--color-card); --ink:var(--color-ink); --stone:var(--color-stone); --faint:#6E6860;
  --accent:var(--color-accent); --gold:var(--color-gold); --moss:var(--color-moss);
  /* --gold-bright (the ONE bright tint of --gold for use on near-black) comes from
     the app's css/tokens.css (always loaded), so the three earned gold moments
     (payoff accent · おすすめ pin · 道 seal) use the SAME material as the rest of the
     app, never a one-off hex. Fallback hex matches the token in case tokens.css is
     absent in an isolated render. */
  --gold-bright:var(--color-gold-bright, #D4B87C);
  --divider:rgba(44,40,32,.12); --image-base:#cdc4b4;
  --radius:10px; --radius-lg:16px; --radius-xl:22px; --radius-full:999px;
  --shadow-rest:0 1px 2px rgba(20,16,10,.05), 0 6px 18px rgba(20,16,10,.06);
  --shadow-card:0 2px 6px rgba(20,16,10,.07), 0 14px 34px rgba(18,16,10,.11);
  --ease:cubic-bezier(.16,1,.3,1);
  /* the bloom wavefront's reveal ease — slow-out, a water surface relaxing */
  --wave-ease:cubic-bezier(.22,.61,.27,1);

  position:fixed; inset:0; z-index:120; background:#14100a; color:var(--ink); font-family:var(--font-ui);
  opacity:0; pointer-events:none; transition:opacity .4s var(--ease);
  -webkit-font-smoothing:antialiased;
}
#kjOnb.on{opacity:1; pointer-events:auto;}
/* Defensive (mirrors #kjStudy): off = fully inert. On iOS Safari an opacity:0
   composited overlay still hit-tests — pointer-events:none on the root alone is
   NOT honored reliably during/after the opacity transition, so the leftover
   full-screen layer traps every tap on the dashboard beneath until reload. Force
   the whole subtree inert; journey-onboarding.js close() also removes the node
   post-fade so nothing survives to hit-test. */
#kjOnb:not(.on), #kjOnb:not(.on) *{pointer-events:none !important;}

/* the onboarding owns the whole screen — one dark room, the watercolor IS the surface */
#kjOnb #reel{position:absolute; inset:0; overflow:hidden; background:#14100a; font-family:var(--font-ui);}

/* ── the shared dark room every beat lives inside ── */
#kjOnb .room{position:absolute; inset:0; overflow:hidden;}
/* 夜明け pre-dawn grade: the light gets a DIRECTION. A warm horizon pools LOW in
   the frame (where a sun will rise — the bloom is about to deliver 太陽) and a
   cool crown sits above, the temperature axis the sun completes. The dark reads
   as anticipation, not gloom. v2: the first pass buried the horizon under the
   claim band — the ellipse now rides higher (96%) and warmer (.55) so the glow
   is VISIBLE in the lower-mid field, not hidden under the lockup. */
#kjOnb .room::before{content:""; position:absolute; inset:0; pointer-events:none; z-index:0;
  background:
    radial-gradient(140% 70% at 50% -8%, rgba(44,58,94,.36) 0%, rgba(14,19,32,0) 58%),
    radial-gradient(150% 75% at 50% 96%, rgba(150,104,52,.55) 0%, rgba(96,72,40,.26) 38%, rgba(20,16,10,0) 70%);}

/* ════ THE CASCADE (beat 0 ambient) — a quiet snowfall of words ════ */
#kjOnb .flow{position:absolute; inset:0; z-index:2; overflow:hidden; pointer-events:none;
  transition:opacity 1.1s var(--ease), filter 1.1s var(--ease);}
/* bottom vignette dropped entirely — the claim band already protects the lockup,
   and any extra scrim here just re-buries the horizon glow */
#kjOnb .flow::before{content:""; position:absolute; inset:0; pointer-events:none;
  background:linear-gradient(to bottom, rgba(20,16,10,.55) 0%, rgba(20,16,10,0) 16%, rgba(20,16,10,0) 100%);}
#kjOnb .flow .w{position:absolute; top:0; left:0; white-space:nowrap; color:rgba(178,170,156,.5);
  font-weight:400; letter-spacing:.3px; line-height:1; text-shadow:0 1px 8px rgba(8,5,3,.45);
  will-change:transform,opacity; transform:translate3d(0,-14vh,0);
  animation-name:kjo-fall; animation-timing-function:linear; animation-iteration-count:infinite;
  transition:color 1.2s var(--ease);}
/* JP out-weights romaji/EN — it carries more presence (brighter, heavier) */
#kjOnb .flow .w.jp{font-family:var(--font-jp); font-weight:500; color:rgba(198,190,176,.70);}
#kjOnb .flow .w.kana{font-family:var(--font-jp); font-weight:400; color:rgba(180,172,158,.54);}
#kjOnb .flow .w.rom{font-family:var(--font-ui); font-weight:500; color:rgba(166,159,146,.50); letter-spacing:.5px;}
#kjOnb .flow .w.en{font-family:var(--font-ui); font-weight:400; color:rgba(170,163,150,.50); letter-spacing:.2px;}
/* depth planes — near is crisper/brighter, far recedes into haze */
#kjOnb .flow .w.near{filter:none; text-shadow:0 1px 9px rgba(8,5,3,.5);}
#kjOnb .flow .w.near.jp{color:rgba(222,214,198,.88);}
#kjOnb .flow .w.far{filter:blur(.6px); text-shadow:0 1px 6px rgba(8,5,3,.4);}
#kjOnb .flow .w.far.jp{color:rgba(176,168,154,.50);}
#kjOnb .flow .w.far.kana,#kjOnb .flow .w.far.rom,#kjOnb .flow .w.far.en{color:rgba(150,143,131,.32);}
/* a few tokens warm toward paper-cream (NOT gold) so the eye has somewhere warm
   to land amid the cool grays — concentrated on the near/hero plane */
#kjOnb .flow .w.warm{color:rgba(238,228,210,.68); text-shadow:0 1px 10px rgba(40,30,16,.45);}
#kjOnb .flow .w.warm.near{color:rgba(245,237,221,.95);}
@keyframes kjo-fall{
  0%   {transform:translate3d(0,-14vh,0); opacity:0;}
  10%  {opacity:1;}
  86%  {opacity:1;}
  100% {transform:translate3d(0,101vh,0); opacity:0;}
}
#kjOnb .flow.slowing .w{animation-timing-function:cubic-bezier(.33,0,.15,1) !important;}
#kjOnb .flow.gone{opacity:0; filter:blur(3px);}
#kjOnb .flow.gone .w{animation-play-state:paused;}
#kjOnb .wall.under-flow{opacity:.24; filter:saturate(0) brightness(.9);
  transition:opacity 1.1s var(--ease), filter 1.1s var(--ease);}

/* ════ THE BLOOM STAGE — one grid, two beats (list → bloom) ════ */
#kjOnb .wall{position:absolute; inset:0; z-index:1; display:grid; gap:5px; padding:5px;
  grid-template-columns:repeat(4,1fr); grid-template-rows:repeat(6,1fr);
  grid-auto-flow:row dense; align-content:stretch;
  transition:opacity .9s var(--ease), transform 1.05s var(--ease), filter 1.05s var(--ease);}
#kjOnb .cell{position:relative; border-radius:9px; overflow:hidden; background:#1d1710;
  box-shadow:inset 0 0 0 1px rgba(120,108,90,.10);
  opacity:0; transform:translateY(14px); will-change:transform,opacity;}
#kjOnb .cell.big{grid-column:span 2; grid-row:span 2;}
/* bloom-state children ride --wd, the per-cell wavefront delay set inline by
   beatBloom(). It MUST live on the children: the bloom transitions are theirs,
   and a transition-delay on .cell itself delays nothing they animate (the old
   "ripple" set exactly that, so the stagger never actually fired). Durations
   are SHORT relative to the 1.05s wave window (ratio ~3:1) — that ratio is what
   makes the front readable instead of 17 overlapping fades. */
#kjOnb .cell .dead{position:absolute; inset:0; z-index:2; display:flex; align-items:center; justify-content:center;
  font-family:var(--font-jp); font-weight:400; color:rgba(176,168,154,.40); letter-spacing:.5px;
  font-size:18px; line-height:1; text-align:center; padding:4px;
  transition:opacity .30s var(--wave-ease), transform .38s var(--wave-ease), color .30s var(--wave-ease);
  /* the glyph lifts a breath BEFORE the crest lands on its cell — the front
     "touches" the word, then the painting rises through it */
  transition-delay:calc(var(--wd, 0s) - .06s);}
#kjOnb .cell.big .dead{font-size:30px;}
/* no blur() in either state: the pic is opacity:0 while "blurred" (invisible),
   and keeping blur out of the tween means filter work is saturate/brightness
   only — no animated blur radius (the #292/#299 iOS concern). */
#kjOnb .cell .pic{position:absolute; inset:0; z-index:1; background-size:cover; background-position:center;
  filter:saturate(.5) brightness(.5); opacity:0;
  transform:scale(1.08);}
#kjOnb .cell .shade{position:absolute; left:0; right:0; bottom:0; z-index:2; height:60%; pointer-events:none;
  opacity:0; transition:opacity .36s var(--wave-ease); transition-delay:var(--wd, 0s);
  background:linear-gradient(to top, rgba(11,7,3,.88) 0%, rgba(11,7,3,.34) 54%, rgba(11,7,3,0) 100%);}
#kjOnb .cell .lab{position:absolute; left:7px; right:7px; bottom:6px; z-index:3; color:#fdfaf3;
  font-family:var(--font-ui); opacity:0; transform:translateY(4px);
  /* the caption settles just AFTER the crest passes — water first, name after */
  transition:opacity .34s var(--wave-ease), transform .34s var(--wave-ease);
  transition-delay:calc(var(--wd, 0s) + .10s);}
#kjOnb .cell .lab .lj{display:block; font-family:var(--font-jp); font-size:11.5px; font-weight:600; line-height:1.1;
  letter-spacing:.02em; color:#fdfaf3; text-shadow:0 1px 3px rgba(0,0,0,.85);
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap;}
#kjOnb .cell .lab .le{display:block; font-size:9.5px; font-weight:500; line-height:1.12; letter-spacing:.1px; margin-top:1px;
  color:rgba(243,234,217,.82); text-shadow:0 1px 3px rgba(0,0,0,.8);
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap;}
#kjOnb .cell.big .lab .lj{font-size:15px;} #kjOnb .cell.big .lab .le{font-size:11px;}
#kjOnb .cell.big .lab{bottom:9px; left:10px; right:10px;}
#kjOnb .wall.listed .cell{opacity:1; transform:none; transition:opacity .5s var(--ease), transform .55s var(--ease);}
/* THE WAVEFRONT — one decelerating ripple out of 太陽 (the stone's impact at
   delay 0); every cell reveals after its --wd. No separate hero pre-state: the
   old bloom-hero/bloom two-step is what split the reveal into "sun, then
   everything at once". The pic rides a CREST keyframe instead of a flat fade —
   it surfaces a touch over-bright and over-scaled, then settles, like water
   lifting and relaxing. That traveling bright edge is what the eye locks onto;
   v1's plain fades swept but didn't read as a wave. */
#kjOnb .wall.bloom .cell .dead{opacity:0; transform:translateY(-7px) scale(.82); color:rgba(253,250,243,.7);}
#kjOnb .wall.bloom .cell .pic{opacity:1; filter:saturate(.98) brightness(.94); transform:scale(1);
  animation:kjo-crest .60s var(--wave-ease) both; animation-delay:var(--wd, 0s);}
#kjOnb .wall.bloom .cell .shade{opacity:1;}
#kjOnb .wall.bloom .cell .lab{opacity:1; transform:none;}
@keyframes kjo-crest{
  0%   {opacity:0; transform:scale(1.08); filter:saturate(.5) brightness(.5);}
  60%  {opacity:1; transform:scale(1.014); filter:saturate(1.04) brightness(1.10);}
  100% {opacity:1; transform:scale(1);     filter:saturate(.98) brightness(.94);}
}
/* 夜明け payoff — as the wave travels, the sun's light floods the room: a single
   static warm gradient anchored at the hero corner, opacity-only, one composited
   layer. It is LIGHT (α≤.18), never a gold shape; retireIntro() disposes it with
   the room. If it ever reads as generic glow on device, cut it. */
#kjOnb .dawn{position:absolute; inset:0; z-index:2; pointer-events:none; opacity:0;
  background:radial-gradient(95% 75% at 18% 18%, rgba(214,150,70,.18) 0%, rgba(214,150,70,0) 72%);
  transition:opacity 1.2s var(--ease);}
#kjOnb .room.dawned .dawn{opacity:1;}

/* ── the claim band: razor copy in its OWN protected zone. ── */
/* bottom padding reserves the cue zone: the 28px ring sits at +34px, so a 96px
   zone centres it optically — even air above (to the text) and below (to the
   screen edge), never hugging the border */
#kjOnb .claim{position:absolute; left:0; right:0; bottom:0; z-index:6; pointer-events:none;
  padding:92px 24px calc(96px + env(safe-area-inset-bottom,0px));
  background:linear-gradient(to top, #0d0904 0%, #0d0904 40%, rgba(13,9,4,.88) 60%, rgba(13,9,4,.42) 82%, rgba(13,9,4,0) 100%);
  opacity:0; transform:translateY(10px); transition:opacity .6s var(--ease), transform .6s var(--ease);}
#kjOnb .claim.show{opacity:1; transform:none;}
/* beat 0's cue also carries the one-time "tap to begin" label — a touch more room */
/* solid floor pulled down (62%→54%) + a gentler climb: the band reads as warm
   shadow holding the lockup, not a black floor sealing off the horizon glow */
#kjOnb .claim.solid{padding-bottom:calc(110px + env(safe-area-inset-bottom,0px));
  background:linear-gradient(to top, #0d0904 0%, #0d0904 54%, rgba(13,9,4,.86) 74%, rgba(13,9,4,0) 100%);}
/* quiet brand lockup — seal + the locked tracked-caps wordmark (brand.css §8) */
#kjOnb .eyebrow-brand{display:inline-flex; align-items:center; gap:9px; margin-bottom:16px;}
#kjOnb .eyebrow-brand .ebhanko{width:28px; height:28px; border-radius:50%; object-fit:cover; flex:0 0 auto; box-shadow:0 2px 8px rgba(20,16,10,.35);}
/* the ONE wordmark component, lifted to cream for the dark room (color only —
   face/tracking/case stay the locked brand.css spec, so the mark cannot drift) */
#kjOnb .kotoba-wordmark{color:rgba(253,250,243,.9);}
#kjOnb .kotoba-motto{display:block; margin-top:10px; font-size:12px; color:rgba(243,234,217,.58); text-shadow:0 1px 8px rgba(8,5,3,.5);}
#kjOnb .claim h1.en{font-family:var(--font-ui); font-size:30px; font-weight:600; line-height:1.18; color:#f6f1e6;
  letter-spacing:-.014em; text-shadow:0 2px 18px rgba(0,0,0,.6); max-width:300px; text-wrap:balance;}
#kjOnb .claim .en-lead{font-family:var(--font-ui); font-size:29px; font-weight:600; line-height:1.2;
  color:#f6f1e6; letter-spacing:-.014em; text-shadow:0 2px 18px rgba(0,0,0,.6); max-width:320px; text-wrap:balance;}
#kjOnb .claim .en-lead.big{font-size:31px;}

/* ════ SWIPE CUE — a soft "swipe to continue" hint (non-interactive) ════
   ONE gesture only: the hairline ring drifts gently down (the swipe invitation);
   the glyph rides it passively. No halo, no inner nudge — restraint over
   decoration (和の感性). Full voice on beat 0 (with a one-time "tap to begin"
   label); after the first advance the cue has taught the gesture and drops to a
   whisper (.quiet). */
#kjOnb .tapcue{position:absolute; left:50%; transform:translateX(-50%);
  bottom:calc(env(safe-area-inset-bottom,0px) + 34px); z-index:20; pointer-events:none;
  display:inline-flex; flex-direction:column; align-items:center;
  opacity:0; transition:opacity .55s var(--ease);}
#kjOnb .tapcue.show{opacity:1;}
#kjOnb .tapcue.show.quiet{opacity:.55;}
/* at the payoff the cue dies INSTANTLY (no .55s fade lingering under the crest) */
#kjOnb .tapcue.cut{transition:none !important; opacity:0 !important;}
#kjOnb .tapcue .chev{position:relative; width:28px; height:28px; border-radius:50%;
  border:1.25px solid rgba(253,250,243,.4);
  display:flex; align-items:center; justify-content:center;
  animation:kjo-cueBob 3.6s var(--ease) infinite;}
/* the chevron glyph — two strokes meeting at a point, pointing down, at rest */
#kjOnb .tapcue .chev::after{content:""; width:8px; height:8px;
  border-right:1.5px solid rgba(253,250,243,.88); border-bottom:1.5px solid rgba(253,250,243,.88);
  border-radius:0 0 2px 0; transform:translateY(-2px) rotate(45deg);}
@keyframes kjo-cueBob{0%,100%{transform:translateY(0);} 55%{transform:translateY(3px);}}
/* one-time first-gesture label — beat 0 only, removed forever on the first advance */
#kjOnb .tapcue .cuelab{margin-top:10px; font-family:var(--font-ui); font-size:11px; font-weight:500;
  letter-spacing:.04em; color:rgba(253,250,243,.55); text-shadow:0 1px 6px rgba(8,5,3,.5);}

/* ════ THE FOLD — the showcase tile pulls FORWARD into the scene ════ */
#kjOnb .flyer{position:absolute; z-index:14; border-radius:11px; overflow:hidden; background:var(--image-base);
  box-shadow:0 18px 50px rgba(8,5,3,.55); opacity:0; pointer-events:none;
  transition:left 1.1s cubic-bezier(.33,0,.2,1), top 1.1s cubic-bezier(.33,0,.2,1),
             width 1.1s cubic-bezier(.33,0,.2,1), height 1.1s cubic-bezier(.33,0,.2,1),
             border-radius .9s var(--ease), box-shadow .9s var(--ease), opacity .45s var(--ease);}
#kjOnb .flyer .fpic{position:absolute; inset:0; background-size:cover; background-position:center; filter:saturate(.96) brightness(.92);}

/* ════ THE UNFOLD ════ */
#kjOnb .unfold{position:absolute; inset:0; z-index:12; display:flex; flex-direction:column; background:#14100a;
  opacity:0; pointer-events:none; transition:opacity .6s var(--ease);}
#kjOnb .unfold.live{opacity:1; pointer-events:auto;}
#kjOnb .uscene{position:absolute; inset:0; z-index:0;}
#kjOnb .uscene .uphoto{position:absolute; inset:0; background-size:cover; background-position:center;
  filter:brightness(.84) saturate(1.02); transform:scale(1.02);
  animation:kjo-u-kb 26s var(--ease) infinite alternate;}
@keyframes kjo-u-kb{0%{transform:scale(1.02);} 100%{transform:scale(1.1);}}
#kjOnb .uscene .uscrim{position:absolute; inset:0;
  background:linear-gradient(to top, rgba(13,9,4,.97) 0%, rgba(13,9,4,.9) 26%, rgba(13,9,4,.62) 48%, rgba(13,9,4,.2) 72%, rgba(13,9,4,.04) 100%);}
#kjOnb .uscene .uphoto.reduced{animation:none; transform:none;}
@keyframes kjo-audioPulse{0%{transform:scale(1); opacity:.65;} 100%{transform:scale(2); opacity:0;}}

#kjOnb .ustack{position:relative; z-index:10; flex:1; min-height:0; overflow-y:auto; overflow-x:hidden;
  -webkit-overflow-scrolling:touch; display:flex; flex-direction:column; justify-content:flex-end;}
#kjOnb .ustack::-webkit-scrollbar{display:none;}
#kjOnb .ustack .uspacer{flex:1 0 30vh; min-height:120px;}
#kjOnb .ustack .ubody{position:relative; padding:0 24px calc(env(safe-area-inset-bottom,0px) + 124px);}

#kjOnb .ulayer{display:none; opacity:0; transform:translateY(16px);
  transition:opacity .55s var(--ease), transform .55s var(--ease); will-change:opacity,transform;}
#kjOnb .ulayer.armed{display:block;}
#kjOnb .ulayer.in{opacity:1; transform:none;}

#kjOnb .usec{display:inline-flex; align-items:center; gap:9px; margin-bottom:11px;}
#kjOnb .usec::before{content:""; width:15px; height:1.5px; border-radius:2px; background:rgba(253,250,243,.4);}
#kjOnb .usec .sj{font-family:var(--font-jp); font-size:13px; font-weight:600; color:rgba(253,250,243,.86); letter-spacing:.06em; text-shadow:0 1px 6px rgba(8,5,3,.6);}
#kjOnb .usec .se{font-family:var(--font-ui); font-size:9.5px; font-weight:700; letter-spacing:.14em; text-transform:uppercase; color:rgba(253,250,243,.62); text-shadow:0 1px 6px rgba(8,5,3,.6);}
#kjOnb .ulayer .usec{opacity:0; transform:translateY(8px); transition:opacity .45s var(--ease), transform .45s var(--ease);}
#kjOnb .ulayer .ustory .stxt, #kjOnb .ulayer .usent .ex{opacity:0; transform:translateY(10px);
  transition:opacity .5s var(--ease) .08s, transform .5s var(--ease) .08s;}
#kjOnb .ulayer.in .usec{opacity:1; transform:none;}
#kjOnb .ulayer.in .ustory .stxt, #kjOnb .ulayer.in .usent .ex{opacity:1; transform:none;}

/* LAYER 0 · word identity */
#kjOnb .uword{margin-bottom:6px;}
#kjOnb .uword .wjp{font-family:var(--font-jp); font-size:56px; font-weight:600; line-height:1; color:#fdfaf3;
  font-feature-settings:'palt' 1; text-shadow:0 2px 16px rgba(8,5,3,.7);}
#kjOnb .uword .wread{display:flex; align-items:center; gap:11px; margin-top:11px;}
#kjOnb .uword .wread .wk{font-family:var(--font-jp); font-size:19px; font-weight:600; color:rgba(251,247,238,.88); letter-spacing:.02em; text-shadow:0 1px 8px rgba(8,5,3,.6);}
#kjOnb .uword .wread .wr{font-family:var(--font-ui); font-size:16px; font-weight:500; color:rgba(250,244,233,.84); letter-spacing:.4px;}
#kjOnb .uword .wread .uaud{position:relative; flex:0 0 auto; width:34px; height:34px; margin-left:2px; border-radius:50%;
  display:inline-flex; align-items:center; justify-content:center; cursor:pointer;
  background:rgba(20,15,10,.62); -webkit-backdrop-filter:blur(6px); backdrop-filter:blur(6px);
  box-shadow:inset 0 0 0 1.5px rgba(255,255,255,.28), 0 2px 8px rgba(8,5,3,.55); -webkit-user-select:none; user-select:none; -webkit-touch-callout:none;
  transition:transform .2s var(--ease);}
/* invisible hit-area expander — the visible ring stays 34px, the tappable circle
   grows to 46px (the proven .dcheck::before pattern; audio is the most-tapped
   control on the most important intro card). The .hint breathe rides the same
   pseudo, so its ring simply breathes from the true (expanded) touch edge. */
#kjOnb .uword .wread .uaud::before{content:""; position:absolute; inset:-6px; border-radius:50%;}
#kjOnb .uword .wread .uaud:active{transform:scale(.9);}
#kjOnb .uword .wread .uaud svg{width:15px; height:15px; fill:#fdfaf3;}
/* soft expanding-ring breath — the audio "tap me" hint (one-shot, 2 cycles) */
@keyframes kjo-tapBreathe{0%,100%{box-shadow:0 0 0 0 rgba(253,250,243,0);} 50%{box-shadow:0 0 0 5px rgba(253,250,243,.14);}}
#kjOnb .uword .wread .uaud.hint::before{inset:0; pointer-events:none;
  animation:kjo-tapBreathe 2.2s var(--ease) 2;}
#kjOnb .uword .wread .uaud.playing::after{content:""; position:absolute; inset:-1px; border-radius:50%;
  border:1.5px solid rgba(253,250,243,.7); pointer-events:none; animation:kjo-audioPulse .72s var(--ease) forwards;}
#kjOnb .uword .wen{font-family:var(--font-ui); font-size:17px; font-weight:500; color:#f3ead9; margin-top:9px; letter-spacing:.005em; text-shadow:0 1px 8px rgba(8,5,3,.55);}

#kjOnb .ulayer.div{margin-top:18px; padding-top:18px; border-top:1px solid rgba(253,250,243,.13);}

/* LAYER 1 · story */
#kjOnb .ustory .stxt{font-family:var(--font-ui); font-size:14.5px; font-weight:500; line-height:1.62; color:rgba(248,242,231,.92);
  letter-spacing:.005em; text-shadow:0 1px 7px rgba(8,5,3,.5); max-width:330px;}
#kjOnb .ustory .stxt b{font-family:var(--font-jp); font-weight:600; color:#fdfaf3;}

/* LAYER 2 · sentence */
/* plain JP — no furigana here (too small to read on a photo; the romaji line
   below is the taught pronunciation channel), so the line-height relaxes too */
#kjOnb .usent .ex .ejp{font-family:var(--font-jp); font-size:21px; font-weight:600; line-height:1.6; color:#fdfaf3;
  font-feature-settings:'palt' 1; text-shadow:0 1px 9px rgba(8,5,3,.6);}
#kjOnb .usent .ex .erm{font-family:var(--font-ui); font-size:12.5px; font-weight:500; color:rgba(248,241,230,.66); letter-spacing:.3px; margin-top:8px;}
#kjOnb .usent .ex .een{font-family:var(--font-ui); font-size:13.5px; font-weight:500; color:rgba(243,234,217,.86); margin-top:6px; line-height:1.4;}

/* LAYER 3 · family */
#kjOnb .ufam .fam{display:flex; justify-content:center; gap:16px; margin-top:2px; flex-wrap:wrap; align-items:flex-start;}
#kjOnb .ufam .fc{position:relative; display:flex; flex-direction:column; align-items:stretch; text-align:center;
  flex:0 1 132px; max-width:148px;
  opacity:0; transform:translateY(10px); transition:opacity .5s var(--ease) .08s, transform .5s var(--ease) .08s;}
#kjOnb .ufam.in .fc{opacity:1; transform:none;}
#kjOnb .ufam .fc:nth-child(2){transition-delay:.17s;}
#kjOnb .ufam .fc .frel{display:inline-flex; align-self:center; align-items:baseline; gap:7px; margin-bottom:9px;}
#kjOnb .ufam .fc .frel .frj{font-family:var(--font-jp); font-size:12px; font-weight:600; color:rgba(253,250,243,.86); line-height:1; letter-spacing:.04em; text-shadow:0 1px 6px rgba(8,5,3,.6);}
/* the EN tag is the relation's only gloss now (romaji culled) — load-bearing, so
   it sits above the legibility floor, not at 8.5px */
#kjOnb .ufam .fc .frel .fre{font-family:var(--font-ui); font-size:10px; font-weight:700; letter-spacing:.14em; text-transform:uppercase; color:rgba(253,250,243,.66); line-height:1;}
#kjOnb .ufam .fc .ph{position:relative; width:100%; aspect-ratio:1/1; border-radius:13px; overflow:hidden;
  background-size:cover; background-position:center; background-color:var(--image-base);
  box-shadow:0 4px 14px rgba(8,5,3,.46), inset 0 0 0 1px rgba(255,255,255,.07);}
#kjOnb .ufam .fc .ph::after{content:""; position:absolute; inset:0;
  background:linear-gradient(to top, rgba(11,7,3,.34) 0%, rgba(11,7,3,0) 55%);}
#kjOnb .ufam .fc .fjp{font-family:var(--font-jp); font-size:14px; font-weight:600; color:#fdfaf3; margin-top:8px; line-height:1.15;
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap; text-shadow:0 1px 5px rgba(8,5,3,.6);}
#kjOnb .ufam .fc .frm{font-family:var(--font-ui); font-size:10px; font-weight:500; color:rgba(248,241,230,.64); margin-top:2px; letter-spacing:.2px;
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap;}
#kjOnb .ufam .fc .fen{font-family:var(--font-ui); font-size:10.5px; font-weight:500; color:rgba(243,234,217,.78); margin-top:2px; line-height:1.25;}

/* THE PAYOFF — gold lives in EXACTLY ONE element */
#kjOnb .upay{position:relative; margin-top:24px; padding-top:22px; border-top:1px solid rgba(253,250,243,.13);}
#kjOnb .upay::before{content:""; position:absolute; left:-24px; right:-24px; top:-6px; bottom:-30px; z-index:-1; pointer-events:none;
  background:radial-gradient(120% 90% at 50% 60%, rgba(13,9,4,.6) 0%, rgba(13,9,4,.3) 55%, rgba(13,9,4,0) 100%);}
#kjOnb .upay .ph1{font-family:var(--font-ui); font-size:26px; font-weight:700; line-height:1.2; color:#f7f2e7;
  letter-spacing:-.012em; text-shadow:0 2px 16px rgba(8,5,3,.6); text-wrap:balance;}
/* the gold clause ("A whole world.") lands a half-beat after "One word." so the
   peak reads as two thoughts; gold fades up last, the earned spark of the crest. */
#kjOnb .upay .ph1 .gold{color:var(--gold-bright); letter-spacing:.004em; text-shadow:0 1px 12px rgba(8,5,3,.7);
  opacity:0; transition:opacity .6s var(--ease) .34s;}
#kjOnb .ulayer.upay.in .ph1 .gold{opacity:1;}
/* the climax gets a slower, more deliberate ease + scale-from-.97 — distinct from
   the supporting layers' quicker translateY(16px). It is the peak, paced as one. */
#kjOnb .ulayer.upay{transform:translateY(20px) scale(.97); transition:opacity .9s cubic-bezier(.2,.7,.2,1), transform .9s cubic-bezier(.2,.7,.2,1);}
#kjOnb .ulayer.upay.in{transform:none;}

/* PAYOFF HELD BREATH — when the payoff lands, the supporting layers recede so only
   the sun scene + the crest own the frame (the scrim deepens beneath the peak). */
#kjOnb .unfold.pay-focus #uL0,
#kjOnb .unfold.pay-focus #uL1,
#kjOnb .unfold.pay-focus #uL2,
#kjOnb .unfold.pay-focus #uL3{opacity:.26; filter:saturate(.92); transition:opacity .8s var(--ease) .25s, filter .8s var(--ease) .25s;}
#kjOnb .unfold.pay-focus .uscene .uscrim{background:linear-gradient(to top, rgba(13,9,4,.98) 0%, rgba(13,9,4,.94) 30%, rgba(13,9,4,.74) 54%, rgba(13,9,4,.34) 76%, rgba(13,9,4,.08) 100%); transition:background .8s var(--ease) .25s;}
/* …and the bottom reserve collapses. The unfold's 124px ubody padding exists so
   the EARLIER layers' text clears the floating cue — but the cue HIDES at the
   crest (held breath: no chrome under the final word), so the gold line anchors
   the bottom of the frame the way it does on a tall desktop window, instead of
   floating over a dead black band on a 6.1" phone. The pay-focus class lands
   BEFORE the payoff's scroll-to-bottom, so the reflow is absorbed by the same
   smooth scroll that delivers the crest. */
#kjOnb .unfold.pay-focus .ustack .ubody{padding-bottom:calc(env(safe-area-inset-bottom,0px) + 36px);}

/* (BEAT 3 — the old starter-deck picker .close{...} was removed in the tiered
   graft. The TIERED-picker rules are appended at the END of this file, namespaced
   to #kjoTflow / #kjoTwall so they never touch the beats 0-2 .wall/.flow.) */

/* ════ reduced-motion: still TAP-GATED; the metaphor is a two-state SNAP ════ */
@media (prefers-reduced-motion: reduce){
  #kjOnb .flow{display:none !important;}
  #kjOnb .cell{opacity:1 !important; transform:none !important;}
  #kjOnb .cell .dead{transition:none !important;}
  #kjOnb .cell .pic{transition:none !important; animation:none !important;}
  #kjOnb .wall.bloom .cell .dead{display:none !important;}
  #kjOnb .wall.bloom .cell .pic{opacity:1 !important; filter:saturate(.98) brightness(.94) !important; transform:none !important; animation:none !important;}
  #kjOnb .cell .shade, #kjOnb .cell .lab{transition:none !important;}
  #kjOnb .wall, #kjOnb .claim, #kjOnb .tapcue, #kjOnb .unfold, #kjOnb .uscene .uphoto, #kjOnb .ulayer, #kjOnb .flyer, #kjOnb .uaud{transition-duration:.001s !important; animation:none !important;}
  #kjOnb .ulayer.armed{opacity:1; transform:none;}
  #kjOnb .ulayer.upay{transform:none;}
  /* PAYOFF parity — the gold peak lands typographically emphasized; the staggered
     fade collapses to an instant visible end-state. */
  #kjOnb .upay .ph1 .gold{opacity:1 !important; transition:none !important;}
  /* DAYBREAK parity — no spreading light under reduce; the wall presents its
     static end-state (the .bloom rules above) with no veil animation. */
  #kjOnb .dawn{display:none !important;}
  #kjOnb .uword .wread .uaud.hint::before{animation:none !important;}
  /* animation:none on .uaud cannot reach its pseudo — cover the playing pulse too */
  #kjOnb .uword .wread .uaud.playing::after{animation:none !important;}
  /* pay-focus now applies under reduce too (it owns the payoff LAYOUT) — its dim
     is covered by the .ulayer rule above; zero the scrim's transition as well */
  #kjOnb .unfold.pay-focus .uscene .uscrim{transition:none !important;}
  #kjOnb .tapcue .chev,
  #kjOnb .tapcue .chev::after{animation:none !important;}
}

/* ════════════════════════════════════════════════════════════════════════
   BEAT 3 — the TIERED-door picker (grafted from onb-tiered-flow.html).
   Appended after beats 0-2; namespaced to #kjoTflow (router stage) and
   #kjoTwall (topic wall) so it never clobbers the bloom .wall / snow .flow.
   The master #kjOnb base/overlay/token block above is NOT redeclared; the
   tiered-only tokens it needs (--image-base dark, --radius-md/-sm, the
   tiered ease) are scoped to #kjoTflow + the seal below.
   和の感性 floor: gold only on the おすすめ tag + the 道 seal. Selection = moss.
   ════════════════════════════════════════════════════════════════════════ */

/* tiered-only tokens, scoped so they never touch beats 0-2 */
#kjOnb #kjoTflow, #kjOnb .seal-veil{
  --ease:cubic-bezier(.22,1,.36,1);
  --image-base:#1c150d; --radius-md:12px; --radius-sm:9px; --radius-lg:16px;
}

/* ── the router stage: every screen is absolutely stacked, slid by class ── */
/* tiered router stage — hidden until the unfold payoff tap reveals it (toClose adds .live) */
#kjOnb #kjoTflow{position:absolute; inset:0; z-index:18; overflow:hidden; background:#0d0904; font-family:var(--font-ui);
  opacity:0; pointer-events:none; transition:opacity .7s var(--ease);}
#kjOnb #kjoTflow.live{opacity:1; pointer-events:auto;}
/* The picker stage is invisible (opacity:0) during beats 0-2, but its children
   (e.g. #scr-doors) set pointer-events:auto, which re-enables hit-testing even
   through the invisible parent — an invisible full-screen doors layer would then
   swallow the intro taps so the opener never advances. Force the whole tiered
   subtree inert until the stage is .live (mirrors the #kjOnb:not(.on) guard). */
#kjOnb #kjoTflow:not(.live), #kjOnb #kjoTflow:not(.live) * { pointer-events: none !important; }
#kjOnb .scr{position:absolute; inset:0; display:flex; flex-direction:column; background:#0d0904;
  transform:translateX(100%); opacity:0; pointer-events:none;
  visibility:hidden;
  transition:transform .4s var(--ease), opacity .4s var(--ease), visibility 0s linear .45s;}
#kjOnb .scr.active{transform:none; opacity:1; pointer-events:auto;
  visibility:visible; transition:transform .4s var(--ease), opacity .4s var(--ease), visibility 0s linear 0s;}
#kjOnb .scr.behind{transform:translateX(-14%) scale(.96); opacity:.0;}
#kjOnb #scr-doors{transform:translateX(0); opacity:1; pointer-events:auto;}
#kjOnb #scr-doors:not(.behind){visibility:visible;}
#kjOnb #scr-doors.behind{transform:translateX(-14%) scale(.96); opacity:0; pointer-events:none;}
/* ── iOS memory: PARK every screen that isn't on stage ──────────────────────
   Screens are never display:none'd (the slide transitions need boxes), so all
   9 of them — each with a full-screen .cbg running an INFINITE Ken Burns
   transform animation, plus a full-screen .cscrim stacked above it — stayed
   permanently composited at iPhone DPR 3 (~12MB of backing per full-screen
   layer, plus overlap promotion of everything painted above an animating
   layer). That idle baseline alone ran to hundreds of MB and WebKit jetsammed
   the tab the moment a heavy screen (Browse everything) mounted on top.
   visibility:hidden (delayed past the .45s slide so exits still animate)
   drops a parked screen out of paint + compositing entirely, and pausing its
   animations stops the per-frame style ticks. Both lift the instant a screen
   returns to .active; geometry is unaffected (IntersectionObserver preloading
   on a not-yet-revealed grid keeps working). */
#kjOnb .scr:not(.active) *{animation-play-state:paused;}
#kjOnb #scr-doors:not(.behind) *{animation-play-state:running;}

#kjOnb .cbg{position:absolute; inset:0; background-size:cover; background-position:center;
  filter:brightness(.3) saturate(.88); animation:kjo-cb-kb 32s var(--ease) infinite alternate;}
/* SEAM — the doors' bg is born from the SAME 太陽 photo the unfold held (painted by
   toClose for frame 1), then dissolves to 海 once the doors land. A brief opacity
   dip cross-fades the image swap so the room re-furnishes itself, never a black cut. */
#kjOnb #scr-doors .cbg.seam{animation:kjo-cb-seam .9s var(--ease) both; transition:opacity .55s var(--ease), filter .9s var(--ease);}
@keyframes kjo-cb-seam{0%{transform:scale(1.03); filter:brightness(.42) saturate(1);} 100%{transform:scale(1.07); filter:brightness(.34) saturate(.9);}}
@keyframes kjo-cb-kb{0%{transform:scale(1.04);} 100%{transform:scale(1.12);}}
#kjOnb .cscrim{position:absolute; inset:0; background:linear-gradient(to top,
  rgba(13,9,4,.97) 0%, rgba(13,9,4,.93) 32%, rgba(13,9,4,.86) 66%, rgba(13,9,4,.82) 100%);}
#kjOnb .cbody{position:relative; z-index:2; display:flex; flex-direction:column; height:100%; min-height:0;}

#kjOnb .skip{position:absolute; top:calc(env(safe-area-inset-top,0px) + 14px); right:16px; z-index:30;
  font-family:var(--font-ui); font-size:12.5px; font-weight:600; color:rgba(238,231,219,.55);
  padding:6px 12px; border-radius:var(--radius-full); cursor:pointer;
  -webkit-user-select:none; user-select:none;
  background:rgba(20,15,10,.32); -webkit-backdrop-filter:blur(5px); backdrop-filter:blur(5px);
  box-shadow:inset 0 0 0 1px rgba(255,253,248,.12);}

/* express-mode (returning-user create) dismiss — a ✕ in the top-right where first-run
   shows "Choose for me". A deliberate returning user picks a path (or backs out); the
   auto-pick escape is a first-run convenience, so express swaps it for the exit. Brand
   + heading keep their first-run positions. Injected by open({express}); lives inside
   #scr-doors so it hides under any drilled-in sub-screen (those carry their own back). */
#kjOnb #kjoTflow.express #skipBtn{display:none !important;}
#kjOnb .kjo-x{position:absolute; top:calc(env(safe-area-inset-top,0px) + 12px); right:14px; z-index:30;
  width:34px; height:34px; display:flex; align-items:center; justify-content:center; cursor:pointer;
  color:rgba(243,234,217,.9); background:rgba(20,15,10,.4); border-radius:var(--radius-full);
  -webkit-backdrop-filter:blur(6px); backdrop-filter:blur(6px);
  box-shadow:inset 0 0 0 1px rgba(255,253,248,.16);
  -webkit-user-select:none; user-select:none; -webkit-touch-callout:none;
  transition:transform .15s var(--ease), background .2s var(--ease);}
#kjOnb .kjo-x:active{transform:scale(.92);}

#kjOnb .back{flex:0 0 auto; width:38px; height:38px; border-radius:var(--radius-full);
  display:flex; align-items:center; justify-content:center; cursor:pointer;
  color:rgba(243,234,217,.82); background:rgba(20,15,10,.4);
  -webkit-backdrop-filter:blur(6px); backdrop-filter:blur(6px);
  box-shadow:inset 0 0 0 1px rgba(255,253,248,.16);
  -webkit-user-select:none; user-select:none; -webkit-touch-callout:none;
  transition:transform .15s var(--ease), background .2s var(--ease);}
#kjOnb .back:active{transform:scale(.92);}
#kjOnb .back svg{width:18px; height:18px; fill:none; stroke:currentColor; stroke-width:2.2; stroke-linecap:round; stroke-linejoin:round;}

#kjOnb .cbrand{display:flex; align-items:center; gap:8px; min-width:0;}
#kjOnb .cbrand .hanko{width:24px; height:24px; border-radius:50%; object-fit:cover; flex:0 0 auto;
  box-shadow:0 2px 8px rgba(20,16,10,.35);}
/* .bk = the BREADCRUMB slot (dynamic drill context, JP-capable → Klee). The brand
   itself never rides .bk anymore — literal "Kotoba" spans use .kotoba-wordmark. */
#kjOnb .cbrand .bk{font-family:var(--font-jp); font-size:13px; font-weight:600; color:rgba(253,250,243,.9); letter-spacing:.03em; white-space:nowrap;}

#kjOnb .chl{font-family:var(--font-ui); font-size:22px; font-weight:600; line-height:1.18; color:#f7f2e7;
  letter-spacing:-.012em; text-shadow:0 2px 16px rgba(0,0,0,.55);}
#kjOnb .chl .cjp{font-family:var(--font-jp); font-size:14px; font-weight:600; color:rgba(238,231,219,.7); margin-left:9px;}
#kjOnb .chl .csub{display:block; margin-top:6px; font-size:12.5px; font-weight:500; color:rgba(238,231,219,.62);
  letter-spacing:.1px; text-shadow:none;}

#kjOnb .cscroll{flex:1 1 auto; min-height:0; overflow-y:auto; -webkit-overflow-scrolling:touch;
  -webkit-mask-image:linear-gradient(to bottom, transparent 0, #000 10px, #000 calc(100% - 10px), transparent 100%);
          mask-image:linear-gradient(to bottom, transparent 0, #000 10px, #000 calc(100% - 10px), transparent 100%);}
#kjOnb .cscroll::-webkit-scrollbar{display:none;}

#kjOnb .cfoot{flex:0 0 auto; position:relative; z-index:3;
  padding:12px 20px calc(env(safe-area-inset-bottom,0px) + 16px);
  background:linear-gradient(to top, #0d0904 0%, #0d0904 62%, rgba(13,9,4,0) 100%);}
#kjOnb .cta{width:100%; display:flex; align-items:center; justify-content:center; gap:11px;
  padding:16px; border-radius:var(--radius-full); background:transparent; color:rgba(243,234,217,.5);
  box-shadow:inset 0 0 0 1.5px rgba(243,234,217,.22); -webkit-user-select:none; user-select:none;
  pointer-events:none; transition:background .3s var(--ease), color .3s var(--ease), box-shadow .3s var(--ease), transform .15s var(--ease);}
#kjOnb .cta.on{background:var(--accent); color:#fff; box-shadow:0 3px 10px rgba(61,90,128,.28); pointer-events:auto;}
#kjOnb .cta:active{transform:scale(.97);}
#kjOnb .cta b{font-family:var(--font-jp); font-size:17px; font-weight:600;}
#kjOnb .cta .cen,#kjOnb .cta .cwords{font-family:var(--font-ui); font-size:12px; font-weight:500; opacity:.74; letter-spacing:.3px; font-variant-numeric:tabular-nums;}
#kjOnb .cta .ar{font-size:17px; line-height:1; margin-left:1px;}

/* ════════════════════════════════ SCREEN 0 — door picker ═══════════════════ */
#kjOnb #scr-doors .cbg{filter:brightness(.34) saturate(.9); animation-duration:30s;}
#kjOnb #scr-doors .cbody{padding:calc(env(safe-area-inset-top,0px) + 24px) 0 0;}
#kjOnb .chead{flex:0 0 auto; padding:0 20px 12px;}
#kjOnb .dbrand{display:flex; flex-wrap:wrap; align-items:center; gap:6px 9px; margin-bottom:13px;}
#kjOnb .dbrand .hanko{width:28px; height:28px; border-radius:50%; object-fit:cover; flex:0 0 auto; box-shadow:0 2px 8px rgba(20,16,10,.35);}
/* copy bridge — carries the intro's warm voice into the picker (same author). */
#kjOnb #scr-doors .chl{font-size:23px; max-width:300px; text-wrap:balance;}
#kjOnb #scr-doors .chl .csub{font-size:12.5px; margin-top:5px;}
#kjOnb #scr-doors .cscroll{padding:6px 20px calc(env(safe-area-inset-bottom,0px) + 26px);
  -webkit-mask-image:linear-gradient(to bottom, transparent 0, #000 9px, #000 calc(100% - 9px), transparent 100%);
          mask-image:linear-gradient(to bottom, transparent 0, #000 9px, #000 calc(100% - 9px), transparent 100%);}

/* ── door-assemble cascade — ONE motion grammar matching the intro's timing
   personality: brand → eyebrow → headline → おすすめ hero → textbook hero →
   tier-seam → the three explore rows. Same translateY the doors already use. ── */
/* Entrance = a staggered FADE only. The earlier version also slid every element
   up from translateY(14-16px); stacked across brand → headline → heroes → rows
   plus the container's .7s opacity fade, that upward slide read as the gate
   "jumping up" after load. Materialise in place instead — calm, no vertical jump. */
#kjOnb .dbrand, #kjOnb #scr-doors .chl,
#kjOnb .tier-seam{opacity:0; transition:opacity .55s var(--ease);}
#kjOnb .door{opacity:0; transition:opacity .55s var(--ease);}

#kjOnb #kjoTflow.assemble .dbrand{opacity:1; transform:none; transition-delay:.04s;}
#kjOnb #kjoTflow.assemble #scr-doors .chl{opacity:1; transform:none; transition-delay:.12s;}
#kjOnb #kjoTflow.assemble .tier-lead .door:nth-of-type(1){opacity:1; transform:none; transition-delay:.18s;}
#kjOnb #kjoTflow.assemble .tier-lead .door:nth-of-type(2){opacity:1; transform:none; transition-delay:.26s;}
#kjOnb #kjoTflow.assemble .tier-seam{opacity:1; transform:none; transition-delay:.32s;}
#kjOnb #kjoTflow.assemble .tier-explore .door:nth-of-type(1){opacity:1; transform:none; transition-delay:.36s;}
#kjOnb #kjoTflow.assemble .tier-explore .door:nth-of-type(2){opacity:1; transform:none; transition-delay:.40s;}
#kjOnb #kjoTflow.assemble .tier-explore .door:nth-of-type(3){opacity:1; transform:none; transition-delay:.44s;}

#kjOnb .tier-lead{display:flex; flex-direction:column; gap:12px; margin-bottom:18px;}
#kjOnb .hero{position:relative; border-radius:var(--radius-lg); overflow:hidden; cursor:pointer;
  aspect-ratio:16/8.4; background-color:var(--image-base);
  box-shadow:0 7px 22px rgba(8,5,3,.5), inset 0 0 0 1px rgba(255,255,255,.06);
  -webkit-user-select:none; user-select:none; -webkit-touch-callout:none;
  transition:transform .25s var(--ease), box-shadow .25s var(--ease);}
#kjOnb .hero:active{transform:scale(.985);}
#kjOnb .hero .hpic{position:absolute; inset:0; background-size:cover; background-position:center;
  filter:saturate(1.02) brightness(.98); transition:filter .25s var(--ease);}
/* the hero photos hold still — the room bg (.cbg) is this beat's ONE ambient
   drift; the おすすめ gold pin alone carries the recommendation (motion budget). */
@keyframes kjo-hero-kb{0%{transform:scale(1.03);} 100%{transform:scale(1.1);}}
#kjOnb .hero .htint{position:absolute; inset:0;
  background:linear-gradient(105deg, rgba(11,7,3,.94) 0%, rgba(11,7,3,.72) 34%, rgba(11,7,3,.3) 64%, rgba(11,7,3,.06) 100%);}
#kjOnb .hero .hbody{position:absolute; left:18px; right:16px; bottom:16px; z-index:2; max-width:74%;}
/* hkick + hseal text are warm paper-cream, NOT gold — gold lives ONLY in the
   pin dot below, so the おすすめ accent is a single earned spark, not a wash. */
#kjOnb .hero .hkick{display:inline-flex; align-items:center; gap:7px; margin-bottom:9px;
  font-family:var(--font-ui); font-size:10px; font-weight:700; letter-spacing:.14em; text-transform:uppercase; color:rgba(243,234,217,.85);}
#kjOnb .hero .hseal{display:inline-flex; align-items:center; gap:6px;
  font-family:var(--font-jp); font-size:11px; font-weight:600; letter-spacing:.05em; color:rgba(243,234,217,.85);
  padding:3px 10px 3px 9px; border-radius:var(--radius-full);
  background:rgba(20,15,8,.36); box-shadow:inset 0 0 0 1px rgba(201,169,110,.7);
  -webkit-backdrop-filter:blur(4px); backdrop-filter:blur(4px);}
/* matte gold dot — the same material as the payoff word and the 道 seal (the
   three-gold contract promises pixel-identical material; no glow anywhere) */
#kjOnb .hero .hseal::before{content:""; width:6px; height:6px; border-radius:50%; background:var(--gold);}
#kjOnb .hero .hen{font-family:var(--font-ui); font-size:21px; font-weight:700; line-height:1.1; color:#fdfaf3;
  letter-spacing:-.01em; text-shadow:0 1px 3px rgba(0,0,0,.9), 0 0 14px rgba(0,0,0,.5);}
#kjOnb .hero .hjp{font-family:var(--font-jp); font-size:14px; font-weight:600; color:rgba(251,247,238,.94);
  margin-top:6px; line-height:1.1; text-shadow:0 1px 5px rgba(8,5,3,.95);}
#kjOnb .hero .hsub{font-family:var(--font-ui); font-size:12px; font-weight:500; color:rgba(243,234,217,.82);
  margin-top:8px; line-height:1.3; text-shadow:0 1px 4px rgba(8,5,3,.9); max-width:240px;}

/* ════════════════ the ONE moss hanko (判子) selection seal — reused everywhere ════════════════
   ONE pressed-seal mark stands in for every former green tick. The wrapper element
   (.dcheck / .cbox / .wcheck / .bck / .tck / .lck / .sabox …) owns position + outer
   size; the .kjhk svg owns the seal itself, so the look is identical on every surface.
   Idle  = a faint hollow moss ring + no tick (a seal not yet pressed).
   Pressed (selected) = ring inks to full moss + the carved tick appears, STAMPED in
   (scale 1.15 → 1 with a ~2° settle + an ink-soft edge). Moss only, never vermilion. */
#kjOnb .kjhk{width:100%; height:100%; display:block; overflow:visible;}
#kjOnb .kjhk .kjhk-ring{fill:none; stroke:var(--moss); stroke-width:2; opacity:.42; transition:stroke .2s var(--ease), opacity .2s var(--ease), stroke-width .2s var(--ease);}
#kjOnb .kjhk .kjhk-tick{fill:none; stroke:var(--moss); stroke-width:2.6; stroke-linecap:round; stroke-linejoin:round;
  opacity:0; transition:opacity .16s var(--ease), stroke .2s var(--ease);}
/* selected state + the stamp motion are driven per-surface by an .on/.sel ancestor
   (rules below), so the seal positions correctly in each context. */
@keyframes kjo-stamp{0%{transform:scale(1.15) rotate(2deg);} 60%{transform:scale(.985) rotate(-.6deg);} 100%{transform:scale(1) rotate(0);}}

/* corner-badge seals (doors / feat / world / lessons): hollow ring sits dormant on the
   card, inks + stamps when the card is selected. */
#kjOnb .dcheck{position:absolute; top:11px; right:11px; z-index:4; width:26px; height:26px; border-radius:50%;
  display:flex; align-items:center; justify-content:center; padding:5px;
  opacity:0; transform:scale(.72); transition:opacity .22s var(--ease), transform .22s var(--ease);
  background:rgba(18,13,8,.32); -webkit-backdrop-filter:blur(3px); backdrop-filter:blur(3px);
  box-shadow:inset 0 0 0 1px rgba(255,253,248,.2);}
/* (.dinto chevron badges removed — a tappable poster needs no inset arrow; the
   whole card is role=button with :active feedback, and the sub says what's inside) */

#kjOnb .tier-seam{display:flex; align-items:center; gap:11px; margin:2px 2px 14px;}
#kjOnb .tier-seam .line{flex:1 1 auto; height:1px; background:rgba(243,234,217,.15);}
#kjOnb .tier-seam .lab{flex:0 0 auto; font-family:var(--font-ui); font-size:10.5px; font-weight:600;
  letter-spacing:.12em; text-transform:uppercase; color:rgba(238,231,219,.5);}

#kjOnb .tier-explore{display:flex; flex-direction:column; gap:10px;}
#kjOnb .row{position:relative; display:flex; align-items:center; cursor:pointer;
  border-radius:var(--radius-lg); overflow:hidden; background-color:#16110a;
  min-height:78px; box-shadow:0 4px 14px rgba(8,5,3,.4), inset 0 0 0 1px rgba(255,255,255,.05);
  -webkit-user-select:none; user-select:none; -webkit-touch-callout:none;
  transition:transform .22s var(--ease), box-shadow .22s var(--ease);}
#kjOnb .row:active{transform:scale(.985);}
#kjOnb .row .rthumb{position:relative; flex:0 0 auto; width:96px; align-self:stretch; overflow:hidden; background-color:var(--image-base);}
#kjOnb .row .rthumb .rpic{position:absolute; inset:0; background-size:cover; background-position:center; filter:saturate(.98) brightness(.82);}
#kjOnb .row .rthumb::after{content:""; position:absolute; inset:0; background:linear-gradient(90deg, rgba(22,17,10,0) 40%, rgba(22,17,10,.96) 100%);}
#kjOnb .row .rmosaic{position:absolute; inset:0; display:grid; grid-template-columns:1fr 1fr; grid-template-rows:1fr 1fr; gap:1.5px; background:rgba(11,7,3,.5);}
#kjOnb .row .rmosaic .mq{background-size:cover; background-position:center; filter:saturate(.95) brightness(.8);}
#kjOnb .row .rbody{flex:1 1 auto; min-width:0; padding:12px 44px 12px 15px;}
#kjOnb .row .ren{font-family:var(--font-ui); font-size:15px; font-weight:700; line-height:1.12; color:#fdfaf3; letter-spacing:-.005em;}
#kjOnb .row .rjp{font-family:var(--font-jp); font-size:12px; font-weight:600; color:rgba(251,247,238,.88); margin-top:3px; line-height:1.1;}
#kjOnb .row .rsub{font-family:var(--font-ui); font-size:11px; font-weight:500; color:rgba(238,231,219,.62); margin-top:5px; line-height:1.25;}
#kjOnb .row .rmark{position:absolute; top:8px; left:8px; z-index:3; width:26px; height:26px; border-radius:50%;
  display:flex; align-items:center; justify-content:center; pointer-events:none;
  background:rgba(20,15,10,.44); -webkit-backdrop-filter:blur(5px); backdrop-filter:blur(5px);
  box-shadow:inset 0 0 0 1px rgba(255,253,248,.3), 0 1px 5px rgba(8,5,3,.4);}
#kjOnb .row .rmark span{font-family:var(--font-jp); font-size:14px; font-weight:600; color:#fdfaf3; line-height:1; text-shadow:0 1px 3px rgba(8,5,3,.6);}


/* ════════════════ shared substep header bar (back + brand) ════════════════ */
#kjOnb .subhead{flex:0 0 auto; padding:calc(env(safe-area-inset-top,0px) + 16px) 20px 10px;}
#kjOnb .cbar{display:flex; align-items:center; gap:10px; margin-bottom:13px;}
#kjOnb .subhead .chl{font-size:22px; max-width:300px; padding-right:8px;}
#kjOnb .subhead .chl .cjp{white-space:nowrap; display:inline-block;}

/* ════════════════ TEXTBOOK · book picker ════════════════ */
#kjOnb #scr-book .cscroll{padding:8px 20px 24px;}
#kjOnb .bkgrid{display:flex; flex-direction:column; gap:12px;}
#kjOnb .bcard{position:relative; display:flex; align-items:stretch; cursor:pointer; min-height:96px;
  border-radius:var(--radius-lg); overflow:hidden; background-color:#16110a;
  box-shadow:0 5px 16px rgba(8,5,3,.44), inset 0 0 0 1px rgba(255,255,255,.05);
  -webkit-user-select:none; user-select:none; -webkit-touch-callout:none;
  transition:transform .22s var(--ease), box-shadow .22s var(--ease);}
#kjOnb .bcard:active{transform:scale(.985);}
#kjOnb .bcard .bcpic{position:relative; flex:0 0 auto; width:108px; align-self:stretch; overflow:hidden; background-color:var(--image-base);}
#kjOnb .bcard .bcpic .bcimg{position:absolute; inset:0; background-size:cover; background-position:center; filter:saturate(1) brightness(.86);}
#kjOnb .bcard .bcpic::after{content:""; position:absolute; inset:0; background:linear-gradient(90deg, rgba(22,17,10,0) 46%, rgba(22,17,10,.95) 100%);}
#kjOnb .bcard .bcbody{flex:1 1 auto; min-width:0; padding:15px 46px 15px 16px; display:flex; flex-direction:column; justify-content:center;}
#kjOnb .bcard .bcen{font-family:var(--font-ui); font-size:17px; font-weight:700; color:#fdfaf3; line-height:1.1; letter-spacing:-.01em;}
#kjOnb .bcard .bcjp{font-family:var(--font-jp); font-size:12.5px; font-weight:600; color:rgba(251,247,238,.86); margin-top:4px; line-height:1.1;}
#kjOnb .bcard .bcmeta{font-family:var(--font-ui); font-size:11.5px; font-weight:500; color:rgba(238,231,219,.6); margin-top:7px; letter-spacing:.1px;}
#kjOnb .bcard .bcmeta .bcdot{display:inline-block; width:3px; height:3px; border-radius:50%; background:rgba(238,231,219,.4); margin:0 6px; vertical-align:middle;}

/* ════════════════ TEXTBOOK · lessons ════════════════ */
#kjOnb #scr-lessons .cscroll{padding:8px 20px 24px;}
#kjOnb #scr-spoken .cscroll{padding:8px 20px 24px;}
#kjOnb .lnote{font-family:var(--font-ui); font-size:11.5px; font-weight:500; color:rgba(238,231,219,.58);
  margin:0 2px 12px; line-height:1.35;}
#kjOnb .lgrid{display:flex; flex-direction:column; gap:9px;}
#kjOnb .lcard{position:relative; display:flex; align-items:center; cursor:pointer; min-height:74px;
  border-radius:var(--radius-lg); overflow:hidden; background-color:#16110a;
  box-shadow:0 4px 13px rgba(8,5,3,.4), inset 0 0 0 1px rgba(255,255,255,.05);
  -webkit-user-select:none; user-select:none; -webkit-touch-callout:none;
  transition:transform .2s var(--ease), box-shadow .2s var(--ease);}
#kjOnb .lcard:active{transform:scale(.985);}
#kjOnb .lcard .lpic{position:relative; flex:0 0 auto; width:86px; align-self:stretch; overflow:hidden; background-color:var(--image-base);}
#kjOnb .lcard .lpic .lpimg{position:absolute; inset:0; background-size:cover; background-position:center; filter:saturate(.98) brightness(.84);}
#kjOnb .lcard .lpic::after{content:""; position:absolute; inset:0; background:linear-gradient(90deg, rgba(22,17,10,0) 36%, rgba(22,17,10,.94) 100%);}
#kjOnb .lcard .lbody{flex:1 1 auto; min-width:0; padding:11px 46px 11px 14px;}
#kjOnb .lcard .lnum{font-family:var(--font-ui); font-size:10px; font-weight:700; letter-spacing:.12em; text-transform:uppercase; color:rgba(238,231,219,.55);}
#kjOnb .lcard .lname{font-family:var(--font-ui); font-size:14.5px; font-weight:700; color:#fdfaf3; line-height:1.14; margin-top:3px; letter-spacing:-.005em;}
#kjOnb .lcard .lct{font-family:var(--font-ui); font-size:11px; font-weight:500; color:rgba(238,231,219,.58); margin-top:5px; letter-spacing:.1px;}
#kjOnb .lcard.sel{box-shadow:0 7px 20px rgba(8,5,3,.5), 0 0 0 3px var(--moss), 0 0 0 4.5px rgba(11,7,3,.6) !important;}
#kjOnb .lcard .dcheck{top:50%; transform:translateY(-50%) scale(.72); right:12px;}
#kjOnb .lcard.sel .dcheck{opacity:1; transform:translateY(-50%) scale(1); background:var(--moss); box-shadow:0 2px 7px rgba(8,5,3,.5), 0 0 0 1.5px rgba(48,38,28,.6);}
#kjOnb .lcard.sel .dcheck .kjhk{animation:kjo-stamp .34s var(--ease) both;}
#kjOnb .lcard.sel .dcheck .kjhk .kjhk-ring{stroke:#fff; opacity:1; stroke-width:0;}
#kjOnb .lcard.sel .dcheck .kjhk .kjhk-tick{stroke:#fff; opacity:1;}

/* ════════════════ PICK A TOPIC · the wall ════════════════ */
#kjOnb #scr-topic .cscroll{padding:8px 20px 24px;}
#kjOnb .feat{position:relative; border-radius:var(--radius-lg); overflow:hidden; cursor:pointer;
  aspect-ratio:16/8; margin-bottom:14px; background-color:var(--image-base);
  box-shadow:0 7px 22px rgba(8,5,3,.5), inset 0 0 0 1px rgba(255,255,255,.06);
  -webkit-user-select:none; user-select:none;}
#kjOnb .feat:active{transform:scale(.985);}
#kjOnb .feat .fpic{position:absolute; inset:0; background-size:cover; background-position:center;
  filter:saturate(1.02) brightness(.96); animation:kjo-hero-kb 26s var(--ease) infinite alternate;}
#kjOnb .feat .ftint{position:absolute; inset:0; background:linear-gradient(105deg,
  rgba(11,7,3,.9) 0%, rgba(11,7,3,.6) 38%, rgba(11,7,3,.2) 70%, rgba(11,7,3,.04) 100%);}
#kjOnb .feat .fbody{position:absolute; left:16px; right:14px; bottom:14px; z-index:2;}
/* (the "Featured topic" eyebrow is gone — the poster's size already says featured) */
#kjOnb .feat .fen{font-family:var(--font-ui); font-size:19px; font-weight:700; color:#fdfaf3; line-height:1.08; margin-top:6px; letter-spacing:-.01em; text-shadow:0 1px 3px rgba(0,0,0,.85);}
#kjOnb .feat .fjp{font-family:var(--font-jp); font-size:12.5px; font-weight:600; color:rgba(251,247,238,.9); margin-top:4px; text-shadow:0 1px 4px rgba(8,5,3,.9);}

/* in-flow: the topic grid carries the .wall class (shared with the bloom wall,
   which is position:absolute; inset:0) — reset it so the grid flows inside the
   scroll area (else it overlays the featured poster and the list can't scroll). */
#kjOnb #kjoTwall{position:static; inset:auto; z-index:auto; padding:0; display:grid; grid-template-columns:1fr 1fr; gap:11px;}
#kjOnb .world{position:relative; opacity:0; transform:translateY(14px); transition:opacity .5s var(--ease), transform .55s var(--ease);}
#kjOnb #scr-topic.tin .world{opacity:1; transform:none;}
#kjOnb .wcard{position:relative; border-radius:var(--radius-lg); overflow:hidden; cursor:pointer;
  aspect-ratio:1/1; background-color:var(--image-base);
  box-shadow:0 5px 16px rgba(8,5,3,.46), inset 0 0 0 1px rgba(255,255,255,.05);
  -webkit-user-select:none; user-select:none; -webkit-touch-callout:none;
  transition:transform .22s var(--ease), box-shadow .22s var(--ease);}
#kjOnb .wcard:active{transform:scale(.975);}
#kjOnb .wcard .wpic{position:absolute; inset:0; background-size:cover; background-position:center;
  filter:saturate(1) brightness(.92); transition:filter .25s var(--ease);}
#kjOnb .wcard .wtint{position:absolute; inset:0; background:linear-gradient(to top, rgba(11,7,3,.92) 0%, rgba(11,7,3,.6) 28%, rgba(11,7,3,.14) 56%, rgba(11,7,3,0) 80%);}
#kjOnb .wcard .wbody{position:absolute; left:12px; right:12px; bottom:11px; z-index:2;}
#kjOnb .wcard .wen{font-family:var(--font-ui); font-size:14px; font-weight:700; line-height:1.12; color:#fdfaf3; letter-spacing:-.006em; text-shadow:0 1px 3px rgba(0,0,0,.85);}
#kjOnb .wcard .wjp{font-family:var(--font-jp); font-size:12px; font-weight:600; color:rgba(251,247,238,.9); margin-top:3px; line-height:1.1; text-shadow:0 1px 4px rgba(8,5,3,.9);}
#kjOnb .wcard .wcount{display:block; margin-top:5px; font-family:var(--font-ui); font-size:10.5px; font-weight:600; color:rgba(238,231,219,.66); letter-spacing:.2px; text-shadow:0 1px 3px rgba(8,5,3,.85);}
#kjOnb .world.sel .wcard{box-shadow:0 8px 22px rgba(8,5,3,.52), 0 0 0 3px var(--moss), 0 0 0 4.5px rgba(11,7,3,.55) !important;}
#kjOnb .world.sel .wcard .wpic{filter:saturate(1.05) brightness(.98);}
/* partial = a softer ring + a hollow (ring-only, no tick) seal so a pruned topic reads as a
   SUBSET at a glance, not the full solid stamp (mirrors the inside-drill .lcard.some grammar) */
#kjOnb .world.partial .wcard{box-shadow:0 8px 22px rgba(8,5,3,.52), 0 0 0 2px var(--moss), 0 0 0 3.5px rgba(11,7,3,.5) !important;}
#kjOnb .wcheck{position:absolute; top:9px; left:9px; z-index:4; width:24px; height:24px; border-radius:50%;
  display:flex; align-items:center; justify-content:center; padding:5px;
  opacity:0; transform:scale(.62); transition:opacity .2s var(--ease), transform .2s var(--ease);
  background:rgba(18,13,8,.32); -webkit-backdrop-filter:blur(3px); backdrop-filter:blur(3px);
  box-shadow:inset 0 0 0 1px rgba(255,253,248,.2);}
#kjOnb .world.sel .wcheck, #kjOnb .world.partial .wcheck{opacity:1; transform:scale(1);}
#kjOnb .world.sel .wcheck .kjhk, #kjOnb .world.partial .wcheck .kjhk{animation:kjo-stamp .34s var(--ease) both;}
/* FULL: solid moss disc + white tick */
#kjOnb .world.sel .wcheck{background:var(--moss); box-shadow:0 2px 7px rgba(8,5,3,.5), 0 0 0 1.5px rgba(48,38,28,.6);}
#kjOnb .world.sel .wcheck .kjhk .kjhk-ring{stroke:#fff; opacity:1; stroke-width:0;}
#kjOnb .world.sel .wcheck .kjhk .kjhk-tick{stroke:#fff; opacity:1;}
/* PARTIAL: washed moss disc + hollow white ring, no tick */
#kjOnb .world.partial .wcheck{background:rgba(107,127,92,.34); box-shadow:0 2px 7px rgba(8,5,3,.4), 0 0 0 1.5px rgba(48,38,28,.55);}
#kjOnb .world.partial .wcheck .kjhk .kjhk-ring{stroke:#fff; opacity:.92; stroke-width:2; fill:none;}
#kjOnb .world.partial .wcheck .kjhk .kjhk-tick{opacity:0;}
#kjOnb .wpeek{position:absolute; bottom:9px; right:9px; z-index:5; display:flex; align-items:center; gap:5px;
  padding:5px 9px 5px 10px; border-radius:var(--radius-full); cursor:pointer;
  font-family:var(--font-ui); font-size:9.5px; font-weight:600; letter-spacing:.02em; color:rgba(253,250,243,.9);
  background:rgba(18,13,8,.5); -webkit-backdrop-filter:blur(6px); backdrop-filter:blur(6px);
  box-shadow:inset 0 0 0 1px rgba(255,253,248,.22); transition:transform .15s var(--ease), background .2s var(--ease);}
#kjOnb .wpeek:active{transform:scale(.93);}
#kjOnb .wpeek svg{width:11px; height:11px; fill:none; stroke:currentColor; stroke-width:2.2; stroke-linecap:round; stroke-linejoin:round;}

/* ── Pick-a-topic MULTI-SELECT: the featured poster becomes a selectable
      participant (moss 判子 seal + Refine pill + ring), and the wall gains a
      contextual Clear toggle + a 始める footer count-tick. The grid .world cards
      reuse the existing .world.sel / .world.partial / .wcheck seals above. ── */
#kjOnb .feat .wcheck{top:11px; left:11px;}
/* the full-cover select button; the seal + title are decorative so taps fall through to it.
   The Refine pill (z 5) sits above it and stays independently tappable. */
#kjOnb .feat .feat-hit{position:absolute; inset:0; z-index:3; cursor:pointer; -webkit-tap-highlight-color:transparent; border-radius:inherit;}
#kjOnb .feat .wcheck, #kjOnb .feat .fbody{pointer-events:none;}
#kjOnb .feat.sel{box-shadow:0 9px 26px rgba(8,5,3,.56), 0 0 0 3px var(--moss), 0 0 0 4.5px rgba(11,7,3,.55);}
#kjOnb .feat.partial{box-shadow:0 9px 26px rgba(8,5,3,.56), 0 0 0 2px var(--moss), 0 0 0 3.5px rgba(11,7,3,.5);}
#kjOnb .feat.sel .fpic, #kjOnb .feat.partial .fpic{filter:saturate(1.05) brightness(1);}
#kjOnb .feat.sel .wcheck, #kjOnb .feat.partial .wcheck{opacity:1; transform:scale(1);}
#kjOnb .feat.sel .wcheck .kjhk, #kjOnb .feat.partial .wcheck .kjhk{animation:kjo-stamp .34s var(--ease) both;}
#kjOnb .feat.sel .wcheck{background:var(--moss); box-shadow:0 2px 7px rgba(8,5,3,.5), 0 0 0 1.5px rgba(48,38,28,.6);}
#kjOnb .feat.sel .wcheck .kjhk .kjhk-ring{stroke:#fff; opacity:1; stroke-width:0;}
#kjOnb .feat.sel .wcheck .kjhk .kjhk-tick{stroke:#fff; opacity:1;}
#kjOnb .feat.partial .wcheck{background:rgba(107,127,92,.34); box-shadow:0 2px 7px rgba(8,5,3,.4), 0 0 0 1.5px rgba(48,38,28,.55);}
#kjOnb .feat.partial .wcheck .kjhk .kjhk-ring{stroke:#fff; opacity:.92; stroke-width:2; fill:none;}
#kjOnb .feat.partial .wcheck .kjhk .kjhk-tick{opacity:0;}
#kjOnb .feat .wpeek{bottom:12px; right:12px;}
#kjOnb .feat .fbody{right:108px;}   /* clear the bottom-right Refine pill so a long title never runs under it */
/* iOS: the poster + Refine pill are tap targets — suppress the long-press text/Copy callout */
#kjOnb .feat{-webkit-touch-callout:none;}
#kjOnb .wpeek{-webkit-user-select:none; user-select:none; -webkit-touch-callout:none;}

/* contextual Clear toggle, top-right of the wall subhead (reuses the .wtgl grammar) */
#kjOnb #scr-topic .cbar .wtgl{margin-left:auto; flex:0 0 auto; display:inline-flex; align-items:center; cursor:pointer;
  padding:7px 13px; border-radius:var(--radius-full); box-shadow:inset 0 0 0 1px rgba(238,231,219,.2);
  -webkit-user-select:none; user-select:none; transition:transform .15s var(--ease);}
#kjOnb #scr-topic .cbar .wtgl .clab{font-family:var(--font-ui); font-size:12px; font-weight:600; color:rgba(243,234,217,.9); line-height:1;}
#kjOnb #scr-topic .cbar .wtgl:active{transform:scale(.95);}
#kjOnb #scr-topic .cbar .wtgl[hidden]{display:none;}

/* wall footer count micro-tick (scr-topic is not .kjo-drill → its own rule) */
#kjOnb #scr-topic .cta .cwords.tick{display:inline-block; animation:kjoNumTick .34s var(--ease);}



/* ════════════════ BUILD YOUR OWN · the composer ════════════════ */
#kjOnb .shoji{position:absolute; inset:0; z-index:7; background:#0d0904; pointer-events:none;
  opacity:1; transition:opacity .5s var(--ease);}
#kjOnb #scr-byo.shoji-on .shoji{opacity:0;}
#kjOnb .csheet{position:relative; z-index:5; flex:1 1 auto; min-height:0; margin-top:6px; display:flex; flex-direction:column;
  background:#1a140c; border-radius:24px 24px 0 0;
  box-shadow:0 -10px 34px rgba(8,5,3,.6), inset 0 1px 0 rgba(255,253,248,.06); overflow:hidden;}
#kjOnb .csheet .grab{flex:0 0 auto; display:flex; justify-content:center; padding:9px 0 4px;}
#kjOnb .csheet .grab span{width:38px; height:4px; border-radius:2px; background:rgba(243,234,217,.22);}
#kjOnb .sbody{flex:1 1 auto; min-height:0; overflow-y:auto; -webkit-overflow-scrolling:touch; padding:6px 20px 22px;
  -webkit-mask-image:linear-gradient(to bottom, transparent 0, #000 10px, #000 calc(100% - 10px), transparent 100%);
          mask-image:linear-gradient(to bottom, transparent 0, #000 10px, #000 calc(100% - 10px), transparent 100%);}
#kjOnb .sbody::-webkit-scrollbar{display:none;}

#kjOnb .count{position:relative; border-radius:var(--radius-lg); overflow:hidden; margin:4px 0 18px; aspect-ratio:16/8.2;
  background-color:var(--image-base); box-shadow:inset 0 0 0 1px rgba(255,255,255,.06);}
#kjOnb .count .cpic{position:absolute; inset:0; background-size:cover; background-position:center;
  filter:saturate(1) brightness(.96); transition:opacity .4s var(--ease); animation:kjo-count-kb 26s var(--ease) infinite alternate;}
@keyframes kjo-count-kb{0%{transform:scale(1.03);} 100%{transform:scale(1.1);}}
#kjOnb .count .ctint{position:absolute; inset:0; background:linear-gradient(105deg, rgba(11,7,3,.93) 0%, rgba(11,7,3,.78) 38%, rgba(11,7,3,.4) 70%, rgba(11,7,3,.12) 100%);}
#kjOnb .count .cbody2{position:absolute; left:18px; right:16px; bottom:15px; z-index:2;}
#kjOnb .count .clab{font-family:var(--font-ui); font-size:10.5px; font-weight:700; letter-spacing:.14em; text-transform:uppercase; color:rgba(238,231,219,.55); display:flex; align-items:baseline; gap:8px; flex-wrap:wrap;}
#kjOnb .count .cnum{display:flex; align-items:baseline; gap:9px; margin-top:3px;}
#kjOnb .count .cn{font-family:var(--font-ui); font-size:52px; font-weight:700; line-height:.96; color:#fdfaf3; letter-spacing:-.025em; text-shadow:0 2px 12px rgba(0,0,0,.5); font-variant-numeric:tabular-nums;}
#kjOnb .count .cu{font-family:var(--font-ui); font-size:13px; font-weight:600; color:rgba(243,234,217,.74); letter-spacing:.2px; padding-bottom:6px;}
#kjOnb .count .cn.tick{animation:kjo-numtick .42s var(--ease);}
@keyframes kjo-numtick{0%{transform:translateY(4px); opacity:.4;} 100%{transform:none; opacity:1;}}
#kjOnb .count .cwater{position:relative; margin-top:11px; height:4px; border-radius:2px; background:rgba(243,234,217,.13); overflow:hidden;}
#kjOnb .count .cwater i{position:absolute; left:0; top:0; bottom:0; border-radius:2px; background:var(--accent); width:0%; transition:width .5s var(--ease);}
#kjOnb .count.narrow .cpic{filter:brightness(.5) saturate(.55) grayscale(.3);}
#kjOnb .count .cledger{margin-top:9px; font-family:var(--font-ui); font-size:11px; font-weight:500; color:rgba(238,231,219,.7); line-height:1.35; text-shadow:0 1px 3px rgba(8,5,3,.7);}

/* ════════════════ live word-preview carousel ("pick inside") — borrowed from
   the dashboard composer's .cmp-peek-rail, re-skinned for the dark overlay. The
   ACTUAL words a query resolves to, curated picture-first, ~24 max, long-press →
   audio. Used in scr-byo (required), scr-lessons + scr-topic (peeks). ════════════════ */

#kjOnb .sect-h{display:flex; align-items:baseline; gap:9px; margin:2px 2px 9px;}
#kjOnb .sect-h b{font-family:var(--font-ui); font-size:13px; font-weight:700; color:#fdfaf3; letter-spacing:-.005em;}
#kjOnb .sect-h .sjp{font-family:var(--font-jp); font-size:11px; font-weight:600; color:rgba(243,234,217,.6);}
#kjOnb .sect-h .sjp .srm{font-family:var(--font-ui); font-size:9px; font-weight:500; color:rgba(243,234,217,.5); margin-left:5px; letter-spacing:.2px;}
#kjOnb .sect-note{font-family:var(--font-ui); font-size:11px; font-weight:500; color:rgba(238,231,219,.54); margin:-4px 2px 11px; line-height:1.3;}

#kjOnb .bases{display:grid; grid-template-columns:repeat(3,1fr); gap:9px; margin-bottom:10px;}
#kjOnb .base{position:relative; border-radius:var(--radius-md); overflow:hidden; cursor:pointer; aspect-ratio:1/1.05;
  background-color:var(--image-base); box-shadow:0 3px 11px rgba(8,5,3,.4), inset 0 0 0 1px rgba(255,255,255,.05);
  -webkit-user-select:none; user-select:none; -webkit-touch-callout:none; transition:transform .2s var(--ease), box-shadow .2s var(--ease);}
#kjOnb .base:active{transform:scale(.97);}
#kjOnb .base .bpic{position:absolute; inset:0; background-size:cover; background-position:center; filter:saturate(.92) brightness(.62); transition:filter .25s var(--ease);}
#kjOnb .base .btint{position:absolute; inset:0; background:linear-gradient(to top, rgba(11,7,3,.92) 0%, rgba(11,7,3,.5) 48%, rgba(11,7,3,.18) 100%);}
#kjOnb .base .bbody{position:absolute; left:10px; right:9px; bottom:9px; z-index:2;}
#kjOnb .base .ben{font-family:var(--font-ui); font-size:13px; font-weight:700; color:#fdfaf3; line-height:1.08; letter-spacing:-.01em; text-shadow:0 1px 3px rgba(0,0,0,.8);}
#kjOnb .base .bjp{display:block; font-family:var(--font-jp); font-size:11px; font-weight:600; color:rgba(251,247,238,.86); margin-top:3px; line-height:1;}
#kjOnb .base .brm{display:block; font-family:var(--font-ui); font-size:9px; font-weight:500; color:rgba(243,234,217,.66); margin-top:2px; letter-spacing:.2px;}
#kjOnb .base .bwhy{display:-webkit-box; -webkit-line-clamp:1; -webkit-box-orient:vertical; overflow:hidden; font-family:var(--font-ui); font-size:9px; font-weight:500; color:rgba(243,234,217,.58); margin-top:4px; line-height:1.25; text-shadow:0 1px 3px rgba(0,0,0,.8);}
#kjOnb .base.sel{box-shadow:0 6px 16px rgba(8,5,3,.5), 0 0 0 2.5px var(--moss), 0 0 0 4px rgba(11,7,3,.55) !important;}
#kjOnb .base.sel .bpic{filter:saturate(1) brightness(.72);}
#kjOnb .base .bck{position:absolute; top:8px; right:8px; z-index:3; width:22px; height:22px; border-radius:50%;
  display:flex; align-items:center; justify-content:center; opacity:0; transform:scale(.7); padding:4px;
  background:rgba(18,13,8,.32); -webkit-backdrop-filter:blur(3px); backdrop-filter:blur(3px);
  box-shadow:inset 0 0 0 1px rgba(255,253,248,.2); transition:opacity .2s var(--ease), transform .2s var(--ease);}
#kjOnb .base.sel .bck{opacity:1; transform:scale(1); background:var(--moss); box-shadow:0 1px 5px rgba(8,5,3,.5), 0 0 0 1.5px rgba(48,38,28,.6);}
#kjOnb .base.sel .bck .kjhk{animation:kjo-stamp .34s var(--ease) both;}
#kjOnb .base.sel .bck .kjhk .kjhk-ring{stroke:#fff; opacity:1; stroke-width:0;}
#kjOnb .base.sel .bck .kjhk .kjhk-tick{stroke:#fff; opacity:1;}

#kjOnb .facets{display:flex; flex-direction:column; gap:10px;}
#kjOnb .facet{border-radius:var(--radius-md); overflow:hidden; background:#1d160d; box-shadow:inset 0 0 0 1px rgba(255,255,255,.05);}
#kjOnb .fhd{display:flex; align-items:center; gap:11px; padding:14px 14px; cursor:pointer; -webkit-user-select:none; user-select:none; transition:background .2s var(--ease);}
#kjOnb .facet.open .fhd{background:rgba(255,253,248,.03);}
#kjOnb .fhd:active{background:rgba(255,253,248,.04);}
#kjOnb .fname{flex:0 0 auto; min-width:0;}
#kjOnb .fname .fn-en{font-family:var(--font-ui); font-size:14px; font-weight:700; color:#fdfaf3; line-height:1.1; letter-spacing:-.005em;}
#kjOnb .fname .fn-jp{font-family:var(--font-jp); font-size:10.5px; font-weight:600; color:rgba(243,234,217,.56); margin-left:7px; line-height:1;}
#kjOnb .fname .fn-jp .fn-rm{font-family:var(--font-ui); font-size:8.5px; font-weight:500; color:rgba(243,234,217,.46); margin-left:4px; letter-spacing:.2px;}
#kjOnb .fsum{flex:1 1 auto; min-width:0; text-align:right; font-family:var(--font-ui); font-size:12px; font-weight:500; color:rgba(238,231,219,.5); line-height:1.25; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;}
#kjOnb .fsum.on{color:#a9c39b; font-weight:600;}
#kjOnb .fchev{flex:0 0 auto; width:24px; height:24px; display:flex; align-items:center; justify-content:center; color:rgba(243,234,217,.5); transition:transform .25s var(--ease);}
#kjOnb .facet.open .fchev{transform:rotate(90deg);}
#kjOnb .fchev svg{width:17px; height:17px; fill:none; stroke:currentColor; stroke-width:2.2; stroke-linecap:round; stroke-linejoin:round;}
#kjOnb .fclear{flex:0 0 auto; width:24px; height:24px; border-radius:50%; display:none; align-items:center; justify-content:center; cursor:pointer; margin-right:-2px;
  color:rgba(238,231,219,.62); background:rgba(20,15,10,.5); box-shadow:inset 0 0 0 1px rgba(255,253,248,.12);}
#kjOnb .facet.has .fclear{display:flex;}
#kjOnb .fclear svg{width:12px; height:12px; fill:none; stroke:currentColor; stroke-width:2.4; stroke-linecap:round;}
#kjOnb .fbody{display:none; padding:0 13px 14px;}
#kjOnb .facet.open .fbody{display:block;}

#kjOnb .tgrid{display:grid; grid-template-columns:repeat(3,1fr); gap:8px;}
#kjOnb .tcell{position:relative; border-radius:var(--radius-sm); overflow:hidden; cursor:pointer; background:none; border:0; padding:0; text-align:left; -webkit-user-select:none; user-select:none;}
#kjOnb .tcell .tart{position:relative; aspect-ratio:1/.82; border-radius:var(--radius-sm); overflow:hidden; background-size:cover; background-position:center; background-color:var(--image-base); box-shadow:inset 0 0 0 1px rgba(255,255,255,.05); transition:box-shadow .2s var(--ease);}
#kjOnb .tcell .tart::after{content:""; position:absolute; inset:0; background:linear-gradient(to top, rgba(11,7,3,.72) 0%, rgba(11,7,3,.1) 60%);}
#kjOnb .tcell.on .tart{box-shadow:0 0 0 2.5px var(--moss), 0 0 0 4px rgba(22,17,10,.7);}
#kjOnb .tcell .tck{position:absolute; top:5px; right:5px; z-index:2; width:20px; height:20px; border-radius:50%; display:flex; align-items:center; justify-content:center; padding:4px; opacity:0; transform:scale(.55); background:rgba(18,13,8,.36); -webkit-backdrop-filter:blur(3px); backdrop-filter:blur(3px); box-shadow:inset 0 0 0 1px rgba(255,253,248,.22); transition:opacity .18s var(--ease), transform .18s var(--ease);}
#kjOnb .tcell.on .tck{opacity:1; transform:scale(1); background:var(--moss); box-shadow:0 1px 4px rgba(8,5,3,.5);}
#kjOnb .tcell.on .tck .kjhk{animation:kjo-stamp .34s var(--ease) both;}
#kjOnb .tcell.on .tck .kjhk .kjhk-ring{stroke:#fff; opacity:1; stroke-width:0;}
#kjOnb .tcell.on .tck .kjhk .kjhk-tick{stroke:#fff; opacity:1;}
#kjOnb .tcap{padding:5px 2px 1px;}
#kjOnb .tcap .tl{font-family:var(--font-ui); font-size:10.5px; font-weight:600; color:rgba(253,250,243,.92); line-height:1.15; letter-spacing:-.005em;}
#kjOnb .tcap .tj{font-family:var(--font-jp); font-size:9.5px; font-weight:500; color:rgba(243,234,217,.56); margin-top:1px; line-height:1.1; display:flex; align-items:baseline; gap:4px; flex-wrap:wrap;}
#kjOnb .tcap .tj .trm{font-family:var(--font-ui); font-size:8.5px; font-weight:500; color:rgba(243,234,217,.46); letter-spacing:.2px;}
#kjOnb .tcap .tc{display:block; margin-top:2px; font-family:var(--font-ui); font-size:9px; font-weight:600; color:rgba(243,234,217,.42); letter-spacing:.2px;}
#kjOnb .tmore{margin-top:10px; width:100%; padding:9px; border-radius:var(--radius-full); cursor:pointer; background:rgba(255,253,248,.04); color:rgba(243,234,217,.66); border:0; font-family:var(--font-ui); font-size:11.5px; font-weight:600; letter-spacing:.2px; box-shadow:inset 0 0 0 1px rgba(255,253,248,.1); -webkit-user-select:none; user-select:none;}
#kjOnb .tmore:active{background:rgba(255,253,248,.07);}

#kjOnb .chips{display:flex; flex-direction:column; gap:8px;}

/* ── "Most spoken words" frequency bands: image cards ALIGNED with BYO → Frequency.
   Same .lcard shell; multi-select tiers (no drill chevron). Filled moss dot = chosen,
   hollow ring = not — the same seal treatment as the BYO list cards. ── */
#kjOnb #scr-spoken .chips{gap:9px;}
#kjOnb #scr-spoken .lcard .dcheck{opacity:1; background:transparent !important; -webkit-backdrop-filter:none !important; backdrop-filter:none !important; box-shadow:none !important;}
#kjOnb #scr-spoken .lcard .dcheck .kjhk .kjhk-tick{opacity:0 !important; stroke-width:0 !important;}
#kjOnb #scr-spoken .lcard.sel{box-shadow:0 4px 13px rgba(8,5,3,.4), inset 0 0 0 1px rgba(255,255,255,.05) !important;}
#kjOnb #scr-spoken .lcard.sel .dcheck .kjhk .kjhk-ring{fill:var(--moss) !important; stroke:var(--moss) !important; opacity:1 !important; stroke-width:0 !important;}
#kjOnb #scr-spoken .lcard.off .dcheck .kjhk .kjhk-ring{fill:none !important; stroke:rgba(243,234,217,.5) !important; opacity:.7 !important; stroke-width:1.6 !important;}
#kjOnb #scr-spoken .lcard.off .lpimg{filter:none !important;}

#kjOnb .bklist{display:flex; flex-direction:column; gap:8px;}
#kjOnb .bkblock{border-radius:var(--radius-sm); overflow:hidden; background:rgba(255,253,248,.022); box-shadow:inset 0 0 0 1px rgba(255,253,248,.07);}
#kjOnb .bkrow{display:flex; align-items:center; gap:10px; padding:11px 12px; cursor:pointer; -webkit-user-select:none; user-select:none;}
#kjOnb .bkck{flex:0 0 auto; width:21px; height:21px; border-radius:50%; cursor:pointer; padding:3px; display:flex; align-items:center; justify-content:center; background:none; border:0; transition:background .18s var(--ease), box-shadow .18s var(--ease);}
#kjOnb .bkrow.on .bkck{background:var(--moss); padding:4px;}
#kjOnb .bkrow.on .bkck .kjhk{animation:kjo-stamp .34s var(--ease) both;}
#kjOnb .bkrow.on .bkck .kjhk .kjhk-ring{stroke:#fff; opacity:1; stroke-width:0;}
#kjOnb .bkrow.on .bkck .kjhk .kjhk-tick{stroke:#fff; opacity:1;}
#kjOnb .bknm{flex:1 1 auto; min-width:0; background:none; border:0; text-align:left; cursor:pointer; padding:0;}
#kjOnb .bknm .be{font-family:var(--font-ui); font-size:13px; font-weight:600; color:#fdfaf3; line-height:1.1;}
#kjOnb .bknm .bj{display:block; font-family:var(--font-jp); font-size:9.5px; font-weight:500; color:rgba(243,234,217,.52); margin-top:2px;}
#kjOnb .bknm .bj .bjrm{font-family:var(--font-ui); font-size:8.5px; font-weight:500; color:rgba(243,234,217,.46); margin-left:5px; letter-spacing:.2px;}
#kjOnb .bkct{flex:0 0 auto; font-family:var(--font-ui); font-size:11.5px; font-weight:700; color:rgba(243,234,217,.6); font-variant-numeric:tabular-nums;}
#kjOnb .bkexp{flex:0 0 auto; width:24px; height:24px; display:flex; align-items:center; justify-content:center; color:rgba(243,234,217,.5); background:none; border:0; cursor:pointer; transition:transform .22s var(--ease);}
#kjOnb .bkblock.exp .bkexp{transform:rotate(90deg);}
#kjOnb .bkexp svg{width:16px; height:16px; fill:none; stroke:currentColor; stroke-width:2.2; stroke-linecap:round; stroke-linejoin:round;}
#kjOnb .bklessons{display:none; padding:0 12px 11px; flex-direction:column; gap:5px;}
#kjOnb .bkblock.exp .bklessons{display:flex;}
/* volume divider inside a multi-volume series' lesson list (BYO composer) */
#kjOnb .bkvol{font-family:var(--font-ui); font-size:9.5px; font-weight:700; letter-spacing:.14em; text-transform:uppercase; color:rgba(243,234,217,.52); padding:7px 2px 1px;}
#kjOnb .bklessons .bkvol:first-child{padding-top:2px;}
/* partial: some-but-not-all volumes of a series picked → dimmed seal */
#kjOnb .bkrow.part .bkck{background:rgba(107,127,92,.34); padding:4px;}
#kjOnb .bkrow.part .bkck .kjhk .kjhk-ring{stroke:#fff; opacity:.7; stroke-width:0;}
#kjOnb .bkrow.part .bkck .kjhk .kjhk-tick{stroke:#fff; opacity:.7;}
#kjOnb .lchip{display:flex; align-items:center; gap:9px; padding:9px 11px; cursor:pointer; border-radius:var(--radius-sm); background:rgba(255,253,248,.03); border:0; text-align:left; box-shadow:inset 0 0 0 1px rgba(255,253,248,.06); -webkit-user-select:none; user-select:none;}
#kjOnb .lchip.on{background:rgba(107,127,92,.16); box-shadow:inset 0 0 0 1.5px var(--moss);}
#kjOnb .lchip .lck{flex:0 0 auto; width:18px; height:18px; border-radius:50%; padding:2.5px; display:flex; align-items:center; justify-content:center; transition:background .18s var(--ease);}
#kjOnb .lchip.on .lck{background:var(--moss); padding:3.5px;}
#kjOnb .lchip.on .lck .kjhk{animation:kjo-stamp .34s var(--ease) both;}
#kjOnb .lchip.on .lck .kjhk .kjhk-ring{stroke:#fff; opacity:1; stroke-width:0;}
#kjOnb .lchip.on .lck .kjhk .kjhk-tick{stroke:#fff; opacity:1;}
#kjOnb .lchip .ll{flex:1 1 auto; min-width:0;}
#kjOnb .lchip .ll .ln{font-family:var(--font-ui); font-size:11.5px; font-weight:600; color:rgba(253,250,243,.9); line-height:1.1;}
#kjOnb .lchip .ll .lnn{display:block; font-family:var(--font-ui); font-size:9.5px; font-weight:500; color:rgba(238,231,219,.5); margin-top:2px;}
#kjOnb .lchip .lct{flex:0 0 auto; font-family:var(--font-ui); font-size:10px; font-weight:600; color:rgba(243,234,217,.46); font-variant-numeric:tabular-nums;}

#kjOnb .fhint{margin-top:10px; font-family:var(--font-ui); font-size:10.5px; font-weight:500; color:rgba(238,231,219,.46); line-height:1.35; letter-spacing:.1px;}
#kjOnb .cross{margin:16px 2px 2px; padding:11px 13px; border-radius:var(--radius-sm); background:rgba(255,253,248,.025); box-shadow:inset 0 0 0 1px rgba(255,253,248,.06); font-family:var(--font-ui); font-size:11px; font-weight:500; color:rgba(238,231,219,.6); line-height:1.4;}
#kjOnb .cross b{color:#a9c39b; font-weight:700;}
#kjOnb .cross .ar{color:rgba(243,234,217,.4); margin:0 4px;}
#kjOnb .guard{margin:14px 2px 2px; padding:14px; border-radius:var(--radius-sm); background:rgba(180,120,90,.1); box-shadow:inset 0 0 0 1px rgba(201,140,110,.3);}
#kjOnb .guard .gt{font-family:var(--font-ui); font-size:12.5px; font-weight:700; color:#e8c4ac;}
#kjOnb .guard .gb{font-family:var(--font-ui); font-size:11px; font-weight:500; color:rgba(238,224,217,.72); margin-top:5px; line-height:1.4;}

#kjOnb .sfoot{flex:0 0 auto; position:relative; z-index:6; padding:13px 18px calc(env(safe-area-inset-bottom,0px) + 16px);
  background:linear-gradient(to top, #1a140c 0%, #1a140c 70%, rgba(26,20,12,0) 100%);}

/* ════════════════ the HANDOFF seal — the THIRD earned gold moment (ring + 道) ════════════════
   Matte, still, pressed — an inkan (印鑑, personal seal), not a spotlight: ONE thin
   flat gold ring, a flat gold 道, an even scrim, a motionless photo. The only
   motion is the press itself (the same kjo-stamp grammar every selection seal in
   the flow has been teaching), then the character resolves inside it. */
#kjOnb .seal-veil{position:absolute; inset:0; z-index:60; display:flex; align-items:center; justify-content:center;
  background:#0d0904; opacity:0; pointer-events:none; transition:opacity .45s var(--ease); overflow:hidden;}
#kjOnb .seal-veil.open{opacity:1; pointer-events:auto;}
#kjOnb .seal-bg{position:absolute; inset:0; background-size:cover; background-position:center; filter:brightness(.4) saturate(.95);}
#kjOnb .seal-scrim{position:absolute; inset:0; background:linear-gradient(rgba(11,7,3,.88), rgba(11,7,3,.93));}
#kjOnb .seal-back{position:absolute; top:calc(env(safe-area-inset-top,0px) + 14px); left:16px; z-index:5;}
#kjOnb .seal-card{position:relative; z-index:2; text-align:center; padding:0 34px; transform:translateY(14px) scale(.97); opacity:0;
  transition:transform .55s var(--ease), opacity .55s var(--ease);}
#kjOnb .seal-veil.open .seal-card{transform:none; opacity:1; transition-delay:.12s;}
#kjOnb .seal-ring{width:84px; height:84px; margin:0 auto 20px; border-radius:50%; position:relative; display:flex; align-items:center; justify-content:center;
  box-shadow:inset 0 0 0 1.5px var(--gold-bright);}
#kjOnb .seal-veil.open .seal-ring{animation:kjo-stamp .5s var(--ease) .45s both;}
#kjOnb .seal-ring .skanji{font-family:var(--font-jp); font-size:34px; font-weight:600; color:var(--gold-bright); line-height:1;
  opacity:0; transition:opacity .45s var(--ease) 1.05s;}
#kjOnb .seal-veil.open .seal-ring .skanji{opacity:1;}
#kjOnb .seal-card .sttl{font-family:var(--font-ui); font-size:21px; font-weight:700; color:#f7f2e7; letter-spacing:-.01em;}
#kjOnb .seal-card .stwhat{font-family:var(--font-ui); font-size:13px; font-weight:500; color:rgba(238,231,219,.74); margin-top:12px; line-height:1.5; max-width:290px;}
/* seal body copy is paper-cream, not gold — gold stays on the ring + 道 only */
#kjOnb .seal-card .stwhat b{color:#f3ead9; font-weight:700;}
#kjOnb .seal-card .stbless{font-family:var(--font-jp); font-size:12.5px; font-weight:600; color:rgba(243,234,217,.7); margin-top:16px;}
#kjOnb .seal-card .stbless .strm{font-family:var(--font-ui); font-size:10px; font-weight:500; color:rgba(243,234,217,.5); margin-left:6px;}
/* the blessing's quiet gloss — doubles as its translation + the one pace reassurance */
#kjOnb .seal-card .stgloss{font-family:var(--font-ui); font-size:11px; font-weight:500; color:rgba(238,231,219,.56); margin-top:5px; letter-spacing:.1px;}
/* ghost button — hairline ring, no fill, no shadow (cards rest; the seal above is the event) */
#kjOnb .seal-enter{margin-top:22px; display:inline-flex; align-items:center; gap:10px; cursor:pointer; padding:14px 30px; border-radius:var(--radius-full);
  background:transparent; color:#f3ead9; box-shadow:inset 0 0 0 1.5px rgba(243,234,217,.45); -webkit-user-select:none; user-select:none; transition:transform .15s var(--ease), box-shadow .2s var(--ease);}
#kjOnb .seal-enter:active{transform:scale(.97);}
#kjOnb .seal-enter b{font-family:var(--font-jp); font-size:16px; font-weight:600;}
#kjOnb .seal-enter .erm{font-family:var(--font-ui); font-size:12px; font-weight:500; opacity:.82; letter-spacing:.3px;}
#kjOnb .seal-enter .ar{font-size:16px; line-height:1;}

@media (prefers-reduced-motion: reduce){
  #kjOnb .cbg, #kjOnb #scr-doors .cbg.seam, #kjOnb .feat .fpic, #kjOnb .count .cpic, #kjOnb .wcard .wpic{animation:none !important;}
  #kjOnb .scr, #kjOnb .door, #kjOnb .dbrand, #kjOnb .chl, #kjOnb .tier-seam, #kjOnb .cta, #kjOnb .dcheck, #kjOnb .world, #kjOnb .wcheck,
  #kjOnb .seal-veil, #kjOnb .seal-card, #kjOnb .count .cn, #kjOnb .shoji{transition-duration:.001s !important; transition-delay:0s !important;}
  /* the doors-assemble cascade is delay-driven — zero the delays too, or the
     seven elements still pop in one-by-one (an animation by another name) */
  #kjOnb #kjoTflow.assemble .dbrand, #kjOnb #kjoTflow.assemble #scr-doors .chl,
  #kjOnb #kjoTflow.assemble .tier-seam, #kjOnb #kjoTflow.assemble .door{transition-delay:0s !important;}
  /* hanko: keep the pressed STATE, drop the stamp motion */
  #kjOnb .kjhk{animation:none !important;}
  #kjOnb .kjhk .kjhk-ring, #kjOnb .kjhk .kjhk-tick{transition-duration:.001s !important;}
  /* seal ceremony: no press, the 道 is simply present */
  #kjOnb .seal-veil.open .seal-ring{animation:none !important;}
  #kjOnb .seal-ring .skanji{transition:none !important; opacity:1 !important;}
}
/* short viewports (≤680px: SE-class phones, landscape) — protect the two surfaces
   that genuinely overflow: the unfold's taught audio/gloss line and the seal card */
@media (max-height:680px){
  #kjOnb .ustack .uspacer{flex:1 0 14vh; min-height:64px;}
  #kjOnb .uword .wjp{font-size:44px;}
  #kjOnb .seal-ring{width:64px; height:64px; margin-bottom:14px;}
  #kjOnb .seal-ring .skanji{font-size:26px;}
  #kjOnb .seal-card .sttl{font-size:19px;}
  #kjOnb .seal-card .stwhat{margin-top:9px;}
  #kjOnb .seal-card .stbless{margin-top:11px;}
  #kjOnb .seal-enter{margin-top:16px; padding:12px 26px;}
}

/* ════════════════════════════════════════════════════════════════════════
   UNIFIED ONBOARDING DRILL (topic + textbook + byo) — ported from
   design-mockups/onboarding-unified/. Scoped to #scr-topic-inside /
   #scr-topic-words / .kjo-drill so nothing bleeds into the wall or the
   legacy lessons screen. Reuses prod .lcard / .world / .wcard / .kjhk.
   ════════════════════════════════════════════════════════════════════════ */

/* ── inside screen · subtopic/lesson cards (seal + drill chevron) ── */
#kjOnb #scr-topic-inside .cscroll { padding: 8px 20px 24px; }
#kjOnb #scr-topic-words .cscroll { padding: 8px 20px 24px; }
/* breadcrumb font split: JP rides Klee (.bk default), English rides Inter so the
   "Topics / Textbook" tokens match the door + card titles instead of the JP face. */
#kjOnb .cbrand .bk .ebe { font-family: var(--font-ui); font-weight: 600; }
#kjOnb #scr-topic-inside .lgrid { gap: 11px; }
#kjOnb #scr-topic-inside .lcard .dcheck { opacity: 1; }
#kjOnb #scr-topic-inside .lcard .lbody { padding-right: 92px; }
#kjOnb #scr-topic-inside .lcard .lct { font-variant-numeric: tabular-nums; font-size: 12px; color: rgba(238,231,219,.62); margin-top: 2px; }
#kjOnb #scr-topic-inside .lcard .ldrill { position: absolute; right: 54px; top: 50%; transform: translateY(-50%); width: 40px; height: 40px; padding: 9px; box-sizing: content-box; display: flex; align-items: center; justify-content: center; color: rgba(238,231,219,.42); }
#kjOnb #scr-topic-inside .lcard .ldrill svg { width: 18px; height: 18px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
#kjOnb #scr-topic-inside .lcard.some .lct { color: rgba(238,231,219,.72); font-weight: 600; }
#kjOnb #scr-topic-inside .lcard.off .lpimg { filter: none; }
#kjOnb #scr-topic-inside .lcard.off .lname { color: rgba(238,231,219,.62); }
#kjOnb #scr-topic-inside .lcard.off .lct { color: rgba(238,231,219,.58); font-weight: 600; }
#kjOnb #scr-topic-inside .lcard.off .lnum, #kjOnb #scr-topic-inside .lcard.off .ldrill { opacity: .4; }
#kjOnb #scr-topic-inside .lcard .lname, #kjOnb #scr-topic-inside .lcard .lct { transition: color .2s var(--ease); }
#kjOnb #scr-topic-inside .lcard .lpic .lpimg { transition: filter .25s var(--ease); }
#kjOnb #scr-topic-inside .lcard .dcheck:active { transform: translateY(-50%) scale(.88); }

/* ── Keep all / Drop all toggle, top-right corner (both drill screens) ── */
#kjOnb #scr-topic-inside .wtgl, #kjOnb #scr-topic-words .wtgl { margin-left: auto; flex: 0 0 auto; display: inline-flex; align-items: center; gap: 7px; cursor: pointer; padding: 7px 12px 7px 10px; border-radius: var(--radius-full); box-shadow: inset 0 0 0 1px rgba(238,231,219,.2); -webkit-user-select: none; user-select: none; }
#kjOnb .kjo-drill .wtgl .cdot { width: 7px; height: 7px; border-radius: 50%; background: var(--moss); flex: 0 0 auto; }
#kjOnb .kjo-drill .wtgl .clab { font-family: var(--font-ui); font-size: 12px; font-weight: 600; color: rgba(243,234,217,.9); line-height: 1; }

/* ── word image grid (2-col), shared by all three pillars ── */
#kjOnb #scr-topic-words .wgrid { display: grid; grid-template-columns: 1fr 1fr; gap: 11px; }
#kjOnb #scr-topic-words .wgrid .world { opacity: 0; transform: translateY(14px); transition: opacity .34s var(--ease), transform .34s var(--ease); }
#kjOnb #scr-topic-words.reveal .wgrid .world { opacity: 1; transform: none; }
/* Tiles beyond the first screenful skip the entrance transition (.instant, set in JS).
   "Browse everything" mounts ~1,100 tiles; running 1,100 simultaneous opacity/transform
   transitions promotes 1,100 compositor layers on iOS → memory jetsam → the whole app
   silently reloads. Below-the-fold tiles render in place; only the first dozen animate. */
#kjOnb #scr-topic-words .wgrid .world.instant { opacity: 1; transform: none; transition: none; }
/* .instant tiles also skip the seal-stamp animation: "Browse everything" mounts
   ~1,100 tiles ALL .sel, and kjo-stamp is an accelerated transform animation —
   firing 1,100 of them in the same frame promotes 1,100 compositor layers
   (fill:both keeps them composited after they finish) → the same iOS jetsam
   class the .instant entrance fix above addressed. Only the first screenful
   stamps on mount; a per-tile TAP still stamps every tile, because toggleTile
   re-fires the animation via element.style (inline beats this rule). */
#kjOnb #scr-topic-words .wgrid .world.instant .wcheck .kjhk { animation: none; }
/* And let WebKit skip layout/paint for far-offscreen tiles outright: ~1,100
   1:1 tiles in a 2-col phone grid is a ~106,000px scroll surface; with
   content-visibility only the rows near the viewport render (iOS 18+;
   harmless no-op below). `auto` in contain-intrinsic-size memoizes each
   tile's real rendered height so scroll geometry stays honest. */
#kjOnb #scr-topic-words .wgrid .world { content-visibility: auto; contain-intrinsic-size: auto 170px; }
#kjOnb #scr-topic-words .wgrid .world .wcheck { opacity: 1; transform: scale(1); width: 26px; height: 26px; }
#kjOnb #scr-topic-words .wgrid .world .wbody { display: flex; flex-direction: column; }
#kjOnb #scr-topic-words .wgrid .world .wjp { font-size: 15px; font-weight: 600; }
#kjOnb #scr-topic-words .wgrid .world .wen { font-size: 11px; font-weight: 500; color: rgba(243,234,217,.78); margin-top: 3px; }
#kjOnb #scr-topic-words .wgrid .world.playing .wcard::after { content: ''; position: absolute; inset: 3px; border-radius: var(--radius-lg); border: 1.5px solid rgba(253,250,243,.7); pointer-events: none; opacity: 0; animation: kjoPulseFade .72s var(--ease) forwards; }
@keyframes kjoPulseFade { 0% { opacity: .9 } 100% { opacity: 0 } }
#kjOnb #scr-topic-words .chl { font-size: 19px; }
@keyframes kjoNumTick { 0% { transform: translateY(0) } 30% { transform: translateY(-2px) } 100% { transform: translateY(0) } }
#kjOnb .kjo-drill .cta .cwords.tick { display: inline-block; animation: kjoNumTick .34s var(--ease); }

/* ── FILLED-DOT selection: kept = solid moss maru, not-kept = hollow ring.
   !important + id-scope beats prod's .kjhk faint-ring + .world.partial loud-ring. ── */
#kjOnb #scr-topic-inside .lcard.sel { box-shadow: 0 4px 13px rgba(8,5,3,.4), inset 0 0 0 1px rgba(255,255,255,.05) !important; }
#kjOnb #scr-topic-words .wgrid .world.sel .wcard { box-shadow: 0 5px 16px rgba(8,5,3,.46), inset 0 0 0 1px rgba(255,255,255,.05) !important; }
#kjOnb #scr-topic-inside .lcard .dcheck, #kjOnb #scr-topic-words .wgrid .world .wcheck { background: transparent !important; -webkit-backdrop-filter: none !important; backdrop-filter: none !important; box-shadow: none !important; }
#kjOnb #scr-topic-inside .lcard .dcheck .kjhk .kjhk-tick, #kjOnb #scr-topic-words .wgrid .world .wcheck .kjhk .kjhk-tick { opacity: 0 !important; stroke-width: 0 !important; }
#kjOnb #scr-topic-inside .lcard.sel .dcheck .kjhk .kjhk-ring, #kjOnb #scr-topic-words .wgrid .world.sel .wcheck .kjhk .kjhk-ring { fill: var(--moss) !important; stroke: var(--moss) !important; opacity: 1 !important; stroke-width: 0 !important; }
/* partial keep ('some'): a faint moss wash + visible ring — glanceably different from the full solid dot (mirrors the .lvolsel.some treatment). */
#kjOnb #scr-topic-inside .lcard.some .dcheck .kjhk .kjhk-ring { fill: rgba(106,127,92,.24) !important; stroke: var(--moss) !important; opacity: 1 !important; stroke-width: 2 !important; }
#kjOnb #scr-topic-inside .lcard.off .dcheck .kjhk .kjhk-ring, #kjOnb #scr-topic-words .wgrid .world:not(.sel) .wcheck .kjhk .kjhk-ring { fill: none !important; stroke: rgba(243,234,217,.5) !important; opacity: .7 !important; stroke-width: 1.6 !important; }
/* topic/textbook dropped part: pristine cover (label carries state). word grid dropped: whisper recede. */
#kjOnb #scr-topic-inside .lcard.off .lpimg { filter: none !important; }
#kjOnb #scr-topic-words .wgrid .world:not(.sel) .wcard .wpic { filter: saturate(.3) brightness(.86) !important; }
#kjOnb #scr-topic-words .wgrid .world:not(.sel) .wcard .wtint { opacity: 1 !important; }

@media (prefers-reduced-motion: reduce) {
  #kjOnb #scr-topic-words .wgrid .world { transition: none !important; transform: none !important; transition-delay: 0ms !important; opacity: 1 !important; }
  #kjOnb #scr-topic-words .wgrid .world.playing .wcard::after { animation: none !important; }
  #kjOnb .kjo-drill .cta .cwords.tick, #kjOnb #scr-topic .cta .cwords.tick { animation: none !important; }
}

/* ════════════════════════════════════════════════════════════════════════
   BUILD YOUR OWN — root facet chooser + recursive list. Word grid is the
   shared #scr-topic-words (styled above). Scoped to #scr-byo / #scr-byo-list.
   ════════════════════════════════════════════════════════════════════════ */
#kjOnb #scr-byo .cscroll { padding: 8px 20px 24px; }
#kjOnb #scr-byo .fcard { position: relative; display: block; height: 148px; border-radius: var(--radius-lg); overflow: hidden; margin-bottom: 13px; cursor: pointer; box-shadow: 0 6px 20px rgba(8,5,3,.5), inset 0 0 0 1px rgba(255,255,255,.05); }
#kjOnb #scr-byo .fcard .fimg { position: absolute; inset: 0; background-size: cover; background-position: center; transition: transform .5s var(--ease); }
#kjOnb #scr-byo .fcard:active .fimg { transform: scale(1.03); }
#kjOnb #scr-byo .fcard .fsc { position: absolute; inset: 0; background: linear-gradient(180deg, rgba(11,7,3,.15) 0%, rgba(11,7,3,.78) 100%); }
#kjOnb #scr-byo .fcard .ft { position: absolute; left: 16px; right: 16px; bottom: 14px; }
#kjOnb #scr-byo .fcard .ftjp { font-family: var(--font-jp); font-size: 22px; font-weight: 600; color: #faf7f2; line-height: 1.1; }
/* English token ("Topics"/"Textbook"/"Frequency") rides Inter, matching the door
   hero titles; the JP head + separator keep the Klee face. */
#kjOnb #scr-byo .fcard .ftjp .fte { font-family: var(--font-ui); font-weight: 700; }
#kjOnb #scr-byo .fcard .ften { font-family: var(--font-ui); font-size: 12.5px; font-weight: 600; letter-spacing: .04em; color: rgba(243,234,217,.86); margin-top: 3px; }
#kjOnb #scr-byo .fcard .fmeta { position: absolute; right: 14px; top: 13px; display: flex; align-items: center; gap: 7px; font-family: var(--font-ui); font-size: 11.5px; font-weight: 600; color: rgba(243,234,217,.92); padding: 5px 11px; border-radius: var(--radius-full); background: rgba(11,7,3,.42); -webkit-backdrop-filter: blur(3px); backdrop-filter: blur(3px); font-variant-numeric: tabular-nums; }
#kjOnb #scr-byo .fcard .fmeta .bd { width: 7px; height: 7px; border-radius: 50%; background: var(--moss); }

/* basket pill (root only) */
#kjOnb #scr-byo .bsk { margin-left: auto; flex: 0 0 auto; display: inline-flex; align-items: center; gap: 7px; padding: 7px 13px; border-radius: var(--radius-full); box-shadow: inset 0 0 0 1px rgba(238,231,219,.2); -webkit-user-select: none; user-select: none; }
#kjOnb #scr-byo .bsk .bd { width: 7px; height: 7px; border-radius: 50%; background: rgba(238,231,219,.35); flex: 0 0 auto; transition: background .2s var(--ease); }
#kjOnb #scr-byo .bsk.has .bd { background: var(--moss); }
#kjOnb #scr-byo .bsk .bl { font-family: var(--font-ui); font-size: 12px; font-weight: 600; color: rgba(243,234,217,.9); line-height: 1; font-variant-numeric: tabular-nums; }

/* active-filter chips tray (root only) */
#kjOnb #scr-byo .byoTray { display: flex; gap: 8px; overflow-x: auto; padding: 0 20px 11px; -webkit-overflow-scrolling: touch; scrollbar-width: none; }
#kjOnb #scr-byo .byoTray::-webkit-scrollbar { display: none; }
#kjOnb #scr-byo .byoTray:empty { display: none; }
#kjOnb #scr-byo .byoTray .ftag { flex: 0 0 auto; display: inline-flex; align-items: center; gap: 6px; padding: 6px 8px 6px 12px; border-radius: var(--radius-full); background: rgba(107,127,92,.2); box-shadow: inset 0 0 0 1px rgba(107,127,92,.55); font-family: var(--font-ui); font-size: 12px; font-weight: 600; color: rgba(243,234,217,.94); white-space: nowrap; cursor: pointer; }
#kjOnb #scr-byo .byoTray .ftag .fn { font-variant-numeric: tabular-nums; color: rgba(243,234,217,.62); }
#kjOnb #scr-byo .byoTray .ftag .fx { display: inline-flex; width: 17px; height: 17px; border-radius: 50%; align-items: center; justify-content: center; color: rgba(243,234,217,.78); background: rgba(11,7,3,.22); }
#kjOnb #scr-byo .byoTray .ftag .fx svg { width: 10px; height: 10px; stroke: currentColor; stroke-width: 2.3; fill: none; stroke-linecap: round; }
#kjOnb #scr-byo .byoTray .ftag.clear { background: transparent; box-shadow: none; color: rgba(238,231,219,.6); padding: 6px 6px; }

/* ── BYO list (reuses .lcard + the top-right toggle) ── */
#kjOnb #scr-byo-list .cscroll { padding: 8px 20px 24px; }
#kjOnb #scr-byo-list .lgrid { gap: 11px; }
#kjOnb #scr-byo-list .lcard .dcheck { opacity: 1; }
#kjOnb #scr-byo-list .lcard .lbody { padding-right: 92px; }
#kjOnb #scr-byo-list .lcard .lct { font-variant-numeric: tabular-nums; font-size: 12px; color: rgba(238,231,219,.62); margin-top: 2px; }
/* bilingual leaf name (Word-type buckets): JP headword on the Klee face, English in
   the card's Inter — keeps "名詞 · Nouns" consistent with the font split elsewhere. */
#kjOnb #scr-byo-list .lcard .lname .ljp { font-family: var(--font-jp); font-weight: 600; color: rgba(243,234,217,.86); margin-right: 1px; }
#kjOnb #scr-byo-list .lcard .ldrill { position: absolute; right: 54px; top: 50%; transform: translateY(-50%); width: 40px; height: 40px; padding: 9px; box-sizing: content-box; display: flex; align-items: center; justify-content: center; color: rgba(238,231,219,.42); }
#kjOnb #scr-byo-list .lcard .ldrill svg { width: 18px; height: 18px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
#kjOnb #scr-byo-list .lcard.some .lct { color: rgba(238,231,219,.72); font-weight: 600; }
#kjOnb #scr-byo-list .lcard.off .lpimg { filter: none !important; }
#kjOnb #scr-byo-list .lcard.off .lname { color: rgba(243,234,217,.95) !important; }
#kjOnb #scr-byo-list .lcard.off .lct { color: rgba(238,231,219,.55) !important; }
#kjOnb #scr-byo-list .lcard .dcheck:active { transform: translateY(-50%) scale(.88); }
#kjOnb #scr-byo-list .wtgl { margin-left: auto; flex: 0 0 auto; display: inline-flex; align-items: center; gap: 7px; cursor: pointer; padding: 7px 12px 7px 10px; border-radius: var(--radius-full); box-shadow: inset 0 0 0 1px rgba(238,231,219,.2); -webkit-user-select: none; user-select: none; }
#kjOnb #scr-byo-list .wtgl .cdot { width: 7px; height: 7px; border-radius: 50%; background: var(--moss); flex: 0 0 auto; }
#kjOnb #scr-byo-list .wtgl .clab { font-family: var(--font-ui); font-size: 12px; font-weight: 600; color: rgba(243,234,217,.9); line-height: 1; }
/* filled-dot for BYO list cards */
#kjOnb #scr-byo-list .lcard.sel { box-shadow: 0 4px 13px rgba(8,5,3,.4), inset 0 0 0 1px rgba(255,255,255,.05) !important; }
#kjOnb #scr-byo-list .lcard .dcheck { background: transparent !important; -webkit-backdrop-filter: none !important; backdrop-filter: none !important; box-shadow: none !important; }
#kjOnb #scr-byo-list .lcard .dcheck .kjhk .kjhk-tick { opacity: 0 !important; stroke-width: 0 !important; }
#kjOnb #scr-byo-list .lcard.sel .dcheck .kjhk .kjhk-ring { fill: var(--moss) !important; stroke: var(--moss) !important; opacity: 1 !important; stroke-width: 0 !important; }
#kjOnb #scr-byo-list .lcard.some .dcheck .kjhk .kjhk-ring { fill: rgba(106,127,92,.24) !important; stroke: var(--moss) !important; opacity: 1 !important; stroke-width: 2 !important; }
/* seal hit-target: grow the tappable box to ~44px without enlarging the 26px moss ring
   (the drill seal is independently tappable; the visible mark stays put). */
#kjOnb #scr-topic-inside .lcard .dcheck, #kjOnb #scr-byo-list .lcard .dcheck { position: absolute; }
#kjOnb #scr-topic-inside .lcard .dcheck::before, #kjOnb #scr-byo-list .lcard .dcheck::before { content: ''; position: absolute; inset: -9px; border-radius: 50%; }
#kjOnb #scr-byo-list .lcard.off .dcheck .kjhk .kjhk-ring { fill: none !important; stroke: rgba(243,234,217,.5) !important; opacity: .7 !important; stroke-width: 1.6 !important; }
