/* ==========================================================================
   Kanji Page — 漢字 the character's own room (kanji layer, second dress)
   The SECOND ROOM OF THE SAME MUSEUM: a right-anchored washi sheet soaked
   in the origin word's pigment (--kjp-tone, set per open by kanji-page.js),
   opened by a painting band — a close crop of the very painting the reader
   was just inside. Sections sit as ink on the washi (the word page's
   grammar); the watch-out keeps its earned gold card, the twin pair keeps
   its specimen tray. Slides in as a fusuma, like every door in the house.
   Palette = 和の感性 tokens: washi #FAF7EF · ink #2C2C2C (warmed in-panel to
   --kjp-ink #3A3633) · warm stone #57534e · indigo #3D5A80 · kintsugi gold #C9A96E.
   ========================================================================== */

/* the --kjp palette is hosted on BOTH roots that carry kanji content: the
   kanji page/drawer overlay itself, and the word panel's embedded full glance
   (.wpn-kbody — universal tap 2b), whose subtree renders the same spine via
   KanjiPage.embedBody. One palette, two hosts; --kjp-tone is set per-open by
   kanji-page.js on the overlay and per-render by word-panel.js on the kbody. */
.kjp-overlay,
.wpn-kbody,
.kw-brush-host,  /* the walk's borrowed writing block (KR2) shares the palette */
.kjp-parts,      /* the ONE parts row (js/kanji-parts.js) self-hosts, so the
                    walk sheet / 字 panel / first meeting resolve the same
                    tokens the page does — one truth, one dress */
.kjp-type-tag {  /* and so does the TYPE TAG the same builder renders */
    /* Warm sumi for the panel's STRUCTURAL ink — the named things the eye lands
       on first (hero glyph, reading names, word lemmas, section labels, the
       kun'yomi/on'yomi term). A hair deeper than the prose #44403c so headings
       still outweigh body, and warm (R>G>B) so it sits on the washi instead of
       the cold neutral #2C2C2C that read as "plastic" beside the word page. */
    --kjp-ink: #3A3633;
    /* Warm hairline for the dividers/borders — re-tinted off the cold neutral so a
       "warm" panel doesn't still read clinical (fleet restraint watch-out). */
    --kjp-rule: rgba(64, 53, 40, 0.11);
    /* one group-break rhythm shared by the readings list + the sound family, so the
       three lists (readings / 声符 / 意符) pulse the same (owner consistency ask,
       2026-06-29). Tight, in the direction the owner already trended the gaps. */
    --kjw-grp-gap: 12px;

    /* integrate-hero-v2 palette (the won design). Warm sumi only — NEVER #000.
       Indigo reserved for meaning (readings / prove-the-reading), gold scarcity-
       gated. The sheet tone (--kjp-tone) is set per-open by kanji-page.js. */
    --kjp-ink-wet: #2f2b28;       /* the brush's wet tip — a momentary deepening */
    --kjp-prose: #44403c;         /* body prose */
    --kjp-stone: var(--color-stone);         /* secondary text */
    --kjp-ghost: #8c857b;         /* faint / operators (clears AA on the sheet) */
    --kjp-ghost-soft: #b3aca3;    /* hairline-weight accents only */
    --kjp-indigo: var(--color-accent);        /* teaching accent · prove-the-reading · the key */
    --kjp-gold: var(--color-gold);          /* kintsugi — earned only */
    --kjp-gold-deep: #8a6e35;     /* gold legible AS small type on washi */
    --kjp-paper: #FAF7EF;         /* the raw drawer washi */
    /* the drawer sheet = paper soaked 7% in the painting's tone (the app formula);
       used by the step-mode recede mix + the band fade-to-sheet. */
    --kjp-sheet: color-mix(in srgb, #FAF7EF 93%, var(--kjp-tone, #b0a090) 7%);
    --kjp-jp: 'Klee One', 'Noto Sans JP', serif;
    --kjp-ui: 'Inter', 'Noto Sans JP', system-ui, sans-serif;
    /* the scholar note's ONE earned non-sumi accent: a hand-pressed hanko red.
       Spent exactly once, on the 由来 cue seal (scarcity = "this is precious"). */
    --kjp-seal: #9e3b2c;
    --kjp-seal-deep: #76271c;
}
.kjp-overlay {
    position: fixed;
    inset: 0;
    z-index: 9100; /* above the 図録 word page overlay (word-page.css: 9000) */
    display: none;
    /* the whole page fades in/out (driven by .kjp-in on the root, added on rAF by
       open() and removed on close) — the word-page frame's own wpArrive is killed
       below so the two entrances never double up. */
    opacity: 0;
    transition: opacity 0.32s ease;
}
body.kanji-page-open .kjp-overlay { display: block; }
/* full-screen page: lock the surface underneath (word page / wall) the way the
   word page does (body.wp-open), so only the kanji page scrolls. */
body.kanji-page-open { overflow: hidden; }
/* the slide-OUT close: the overlay must stay painted one beat longer than the
   kanji-page-open class (which would display:none it in the same frame, so the
   sheet used to teleport away). .kjp-out keeps it visible + click-through (the room
   beneath is live) until the sheet finishes its exit transition, then JS clears it. */
.kjp-overlay.kjp-out { display: block; pointer-events: none; }

/* THE PILL/LIFT MUST DIE HERE — same trap word-page.css fights (lines 49-67):
   components.css paints every bare <button> as a floating white pill with a
   12px radius, a drop shadow, and a translateY(-2px) hover lift + glow
   (components.css:390). That lift is the "buttons shake on hover" the owner
   saw — the kanji overlay's buttons (.kjw-row, .kjr-more, .kjp-back,
   .kjp-part--door, .kjt-cell--twin) inherited it because this sheet, unlike
   the word page, had no scoped reset. Buttons in this room REST. Each button
   class re-states its intended look AFTER this reset in the cascade below. */
.kjp-overlay button {
    appearance: none;
    background: none;
    border: none;
    border-radius: 0;
    box-shadow: none;
    font: inherit;
    color: inherit;
    cursor: pointer;
    padding: 0;
    margin: 0;
}
.kjp-overlay button:hover,
.kjp-overlay button:active {
    transform: none;
    box-shadow: none;
}

/* the dimming behind the panel — the scrim drinks the tone. Kept TRANSLUCENT so
   the room the panel rose from (the word page, or the wall) stays visible beside
   it: a room next to the room, never a blackout. Only the .kjp-* drawer + the
   family side panel use this now; the full page dims with its own .wp-scrim.
   A click on the field's margins closes the panel, like clicking outside it. */
.kjp-scrim {
    position: absolute;
    inset: 0;
    background: color-mix(in srgb, rgba(44, 44, 44, 0.42) 88%, var(--kjp-tone, #b0a090) 12%);
    opacity: 0;
    transition: opacity 0.28s ease;
}
.kjp-overlay.kjp-in .kjp-scrim { opacity: 1; }

/* the panel: a right-anchored washi sheet soaked in the origin word's pigment,
   sliding in as a fusuma from the edge. The room it rose from stays visible at
   the left through the translucent scrim — a room beside the room, not a modal
   blackout. The washi is the app's formula: paper soaked 7% in the tone. */
.kjp-sheet {
    position: absolute;
    top: 0;
    bottom: 0;
    right: 0;
    left: auto;
    width: min(760px, 64vw);
    display: flex;
    flex-direction: column;
    background: color-mix(in srgb, #FAF7EF 93%, var(--kjp-tone, #b0a090) 7%);
    border-left: 1px solid var(--kjp-rule);
    box-shadow: -14px 0 40px rgba(15, 11, 7, 0.25);
    opacity: 0;
    transform: translateX(40px);
    transition: opacity 0.32s ease, transform 0.42s cubic-bezier(0.33, 0, 0.2, 1);
}
.kjp-overlay.kjp-in .kjp-sheet { opacity: 1; transform: translateX(0); }

/* the 声符/意符 family SIDE PANEL rides one layer up (above the full page at
   z 9100), so it stacks over the very page whose pill was tapped. It reuses this
   whole .kjp-* drawer dress; only its stacking order differs. */
.kjp-overlay.kjp-aside { z-index: 9200; }

/* 和紙 — the same paper as the word page / gallery / journey: one faint
   fractalNoise wash so the reading area reads as washi, not flat plastic. Copied
   verbatim from the app's shared grain (grid-mode.css). The painting band
   full-bleeds OVER it (content sits at z-index 1), so grain shows only where the
   eye actually rests — the reading lists, not the picture. */
.kjp-sheet::before {
    content: '';
    position: absolute;
    inset: 0;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
    opacity: 0.05;
    mix-blend-mode: multiply;
    pointer-events: none;
    z-index: 0;
}
/* the bar + scrolling body ride above the grain */
.kjp-bar, .kjp-body { position: relative; z-index: 1; }

/* ── top bar ──────────────────────────────────────────────────────────── */

/* the bar is no longer a toolbar strip — just a single quiet back-chevron
   floating at the top-left over the washi, so nothing competes with the glyph
   (no hairline, no stroke-count pill, no destination label). */
/* the bar reserves NO row (owner ruling 2026-07-30 — the reserved strip
   also read as a pale band, because the body's tone wash began below it):
   the chevron floats pinned at the sheet's top-left, the washi runs one
   uninterrupted surface to the top edge. Level with the 陽 seal — exit
   on the left, room door on the right. */
.kjp-bar {
    position: absolute;
    top: 14px;
    left: 14px;
    z-index: 3;
    padding: 0;
}
/* ONE CLOSE (desktop polish round 4, 14 October 2026, finding 6): the
   round-3 door the filter panel, the rail and the palette wear
   (css/browse-sidebar.css .sidebar-close-btn): a 34px seat, 8px corners, the
   16px chevron at a 2px stroke, quiet warm ink at rest, ink on a 5 per cent
   sumi wash under the pointer, no shadow, the one ring (below, with the
   sheet's other rings). It keeps its faint paper plate, so scrolled content
   sliding beneath never tangles with the stroke, and the wash is laid OVER
   the plate. Scoped under .kjp-overlay: the overlay's button reset (0,1,1)
   outranked the bare class, so the plate, the round corner and the ink never
   rendered (measured: a transparent 36px square, the chevron in black). */
.kjp-overlay .kjp-back {
    appearance: none;
    background: rgba(250, 247, 239, 0.82);
    border: 0;
    width: 34px;
    height: 34px;
    border-radius: 8px;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    color: var(--color-faint-warm, #6E6860);
    transition: color 0.2s ease, background-color 0.2s ease;
}
/* 95 per cent plate, 5 per cent sumi: a premultiplied srgb mix IS the wash
   rgba(44,44,44,.05) laid over the plate, and it still animates */
.kjp-overlay .kjp-back:hover {
    color: var(--color-ink, #2C2C2C);
    background-color: color-mix(in srgb, rgba(250, 247, 239, 0.82) 95%, rgb(44, 44, 44));
}
/* the chevron's stroke lives in its markup (js/kanji-page.js): a 16px box over
   the 16-unit view box draws the 2px stroke at exactly 2px */
.kjp-back svg {
    width: 16px;
    min-width: 16px;
    height: 16px;
    flex-shrink: 0;
}
.kjp-sheet:focus { outline: none; }
.kjp-sheet:focus-visible { outline: none; }
/* (.kjp-bar-label + .kjp-bar-seal rules removed 2026-06-27 — the bar is intentionally
   a bare back-chevron (see .kjp-bar above); neither element was ever in the markup.) */

/* ── scrolling body ───────────────────────────────────────────────────── */

.kjp-body {
    flex: 1 1 auto;
    overflow-y: auto;
    overscroll-behavior: contain;
    -webkit-overflow-scrolling: touch;
    padding: 0 28px 64px;
    color: var(--kjp-ink);
    font-family: 'Inter', 'Noto Sans JP', sans-serif;
}

/* 字を照らす — the word page's inline-JP law, shared: Japanese in prose
   is display Klee (spans minted by kanji-page.js wrapJP, text runs only) */
.kjp-body .wp-jp,
.wpn-kbody .wp-jp {
    font-family: 'Klee One', 'Noto Sans JP', sans-serif;
    font-size: 1.25em;
    color: var(--kjp-ink);
}

/* a faint tone wash bridges the top glyph zone and the painting's mount halo so
   the page reads as one continuously-toned washi surface (mockup O10).
   ⛔ Both hosts of this body wear it (2026-08-07) — the word panel's embedded
   glance renders the same glyph zone over the same mount, and without the wash
   the two surfaces part company on the one thing this rule exists to give
   them: reading as ONE toned sheet rather than two stacked blocks. */
.kjp-body::before,
.wpn-kbody::before {
    content: '';
    position: absolute;
    inset: 0 0 auto 0;
    height: 680px;
    z-index: 0;
    pointer-events: none;
    background:
        radial-gradient(120% 64% at 56% -4%,
            color-mix(in srgb, var(--kjp-tone, #b0a090) 16%, transparent) 0%,
            color-mix(in srgb, var(--kjp-tone, #b0a090) 6%, transparent) 34%,
            transparent 64%),
        radial-gradient(90% 30% at 50% 56%,
            color-mix(in srgb, var(--kjp-tone, #b0a090) 5%, transparent) 0%,
            transparent 70%);
}
/* …and the blocks stand above that wash, in either host */
.kjp-body > *,
.wpn-kbody > * { position: relative; z-index: 1; }

/* ── 陽 room seal — the IN-BODY housing ───
   The same door the page placard carries (js roomSealHTML, one builder),
   pinned over the hero's quiet top-right corner; positioned in the scroll
   flow, so it leaves with the content — a door, not chrome. Sumi tile on
   washi: this housing never wears the page's dark-regime rakkan dress.

   ⛔ TWO HOSTS, one list — the drawer and the word panel's embedded glance
   (2026-08-07). Anything that renders the drawer's BODY renders this seal;
   a host list, not an ID, is what keeps them identical. `:is()` takes its
   widest argument's specificity, so both branches sit at the drawer's old
   (1,1,0) — deliberately, since word-page.css's unscoped `.wp-rakkan .kg` /
   `.kc` / `.go` (0,2,0) reach the panel and must keep losing here. */
:is(#kanjiPage[data-shell="drawer"], .wpn-kbody) .kjp-room-seal {
    position: absolute;
    top: 14px;
    z-index: 2;
    display: inline-flex;
    flex-direction: column;
    align-items: center;
    gap: 5px;
    padding: 0;
    background: none;
    border: none;
    cursor: pointer;
    color: var(--kjp-ink);
}
/* ink at rest, light on intent (owner ruling — never pastel-at-rest): the
   resting tile is quiet ink, its one identity note the wall seal's #6F5524
   warm-brown 陽 (the SAME door on the gallery wall writes its sun in this
   ink). Hover floods the tile with the room's own light — the seed-halo
   hue from css/constellation.css — the word page's "gold only on intent"
   law, spoken in sunlight. */
:is(#kanjiPage[data-shell="drawer"], .wpn-kbody) .kjp-room-seal .kg {
    width: 38px;
    height: 38px;
    display: flex;
    align-items: center;
    justify-content: center;
    border: 1.5px solid color-mix(in srgb, var(--kjp-ink) 45%, transparent);
    border-radius: 10px;
    color: #6F5524;
    font-family: 'Klee One', 'Noto Sans JP', sans-serif;
    font-weight: 600;
    font-size: 20px;
    transition: border-color 0.18s ease, background-color 0.18s ease;
}
:is(#kanjiPage[data-shell="drawer"], .wpn-kbody) .kjp-room-seal .kc {
    font-size: 9px;
    font-weight: 600;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--kjp-stone);
    white-space: nowrap;
    /* the unscoped .wp-rakkan .kc keyword cap (88px + ellipsis) leaks in
       from word-page.css — a count is never ellipsized */
    max-width: none;
}
:is(#kanjiPage[data-shell="drawer"], .wpn-kbody) .kjp-room-seal .go { display: none; }
/* the one measurement the two hosts cannot share: the drawer's scroller IS the
   28px-guttered column, so the seal anchors to it directly; the panel's embedded
   body sits INSIDE that gutter, so its seal reaches back out over it. Both land
   on the same pixel column (x 694 at a 525px sheet — measured, not guessed).
   Stated per host rather than in the shared block above: neither selector can
   match the other's tree, so there is no cascade fight to lose. */
#kanjiPage[data-shell="drawer"] .kjp-room-seal { right: 24px; }
.wpn-kbody .kjp-room-seal { right: -4px; }
:is(#kanjiPage[data-shell="drawer"], .wpn-kbody) .kjp-room-seal:hover .kg,
:is(#kanjiPage[data-shell="drawer"], .wpn-kbody) .kjp-room-seal:focus-visible .kg {
    border-color: rgba(163, 122, 51, 0.75);
    background: rgba(255, 236, 170, 0.62);
}
/* page shell: the seal's count caption ("2 connections") outgrows the rakkan
   dress's 88px keyword cap — let it breathe, never ellipsize a number */
.wp-root.kjp-overlay .wp-plright .kjp-room-seal .kc { max-width: none; }
/* page shell rests in the plain rakkan regime ink; on intent the same
   sunlight, tuned for the dark hero veil */
.wp-root.kjp-overlay .wp-plright .kjp-room-seal:hover .kg,
.wp-root.kjp-overlay .wp-plright .kjp-room-seal:focus-visible .kg {
    background: rgba(255, 240, 188, 0.30);
    border-color: rgba(255, 244, 205, 0.85);
}
/* the one ring on the door (desktop polish round 4, finding 6), in every
   host: drawn with the seal tile's own 10px corner, 2px off. The page shell
   wore the word page's 3px rectangle round seal and caption, 3px off. */
:is(#kanjiPage[data-shell="drawer"], .wpn-kbody) .kjp-room-seal:focus-visible,
.wp-root.kjp-overlay .wp-plright .kjp-room-seal:focus-visible {
    outline: 2px solid var(--color-accent, #3D5A80);
    outline-offset: 2px;
    border-radius: 10px;
    box-shadow: none;
}

/* ── the painting band — you are still inside the picture (band-on only) ──
   In v2 the band is a thin crop ABOVE the writing hero (the hero glyph no longer
   sits inside it). When window._wpKanjiBand === false the band is simply absent
   and the hero opens straight onto the bare-washi axis. */
.kjp-band--withhero {
    position: relative;
    height: 150px;
    margin: 0 -28px 6px;        /* full-bleed across the sheet */
    background-color: var(--kjp-tone, #b0a090);   /* load guard */
    background-size: 200%;
    background-repeat: no-repeat;
}
.kjp-band--withhero::after {
    content: '';
    position: absolute;
    inset: 0;
    background: linear-gradient(to bottom,
        transparent 0%,
        color-mix(in srgb, var(--kjp-sheet, #FAF7EF) 88%, var(--kjp-tone, #b0a090) 12%) 92%);
}

/* ════════════════════════════════════════════════════════════════════════
   THE WRITING HERO — integrate-hero-v2 (the glyph IS the control).
   ════════════════════════════════════════════════════════════════════════ */
/* the hero is a COLUMN that centres each child on one meditative spine:
   glyph, keyword, hint each sit as their own centred block. */
.hero {
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    padding: 16px 0 0;
}

/* THE GLYPH STAGE — the resting debossed Klee glyph and the stroke SVG share
   ONE fixed box, stacked, at the same scale; a tap cross-fades them IN PLACE so
   the page never reflows and the writing reads as the SAME character re-inking. */
.glyph-stage {
    position: relative;
    display: flex; align-items: center; justify-content: center;
    margin-inline: auto;
    width: clamp(138px, 18.5vw, 184px);
    height: clamp(138px, 18.5vw, 184px);
    cursor: pointer; border-radius: 14px;
    background: none; border: 0; padding: 0; margin: 0; font: inherit; color: inherit;
    -webkit-tap-highlight-color: transparent;
    /* pressed INTO the sheet — a directional deboss pair + a soft ink-bloom; the
       drop-shadow FILTER lets the same pressed-in light wrap the inked strokes. */
    filter:
        drop-shadow(0 1.5px 0 rgba(255, 251, 243, 0.85))
        drop-shadow(0 -1px 0 rgba(58, 40, 20, 0.08))
        drop-shadow(0 2px 26px rgba(58, 54, 51, 0.07));
}
.glyph-stage--static { cursor: default; }
.glyph-stage:focus-visible { outline: 2px solid var(--kjp-indigo); outline-offset: 6px; }
.glyph-stage:focus { outline: none; }

/* the resting text glyph — scaled to FILL the shared box so it lines up with the
   SVG it cross-fades to. On hover/focus at rest it warms a hair (colour only). */
.glyph-rest {
    position: absolute; inset: 0;
    display: flex; align-items: center; justify-content: center;
    font-family: var(--kjp-jp); font-size: clamp(138px, 19.4vw, 192px); line-height: 1;
    color: var(--kjp-ink); font-weight: 400; user-select: none;
    transition: opacity 0.4s ease, color 0.3s ease;
}
.glyph-stage:not(.glyph-stage--static):not(.is-writing):hover .glyph-rest,
.glyph-stage:not(.glyph-stage--static):not(.is-writing):focus-visible .glyph-rest { color: var(--kjp-ink-wet); }

/* the writing surface — the SVG of strokes, same box, hidden at rest. An under-
   bloom so wet ink reads as set INTO the sheet, matching the rest glyph's bloom. */
.glyph-ink {
    position: absolute; inset: 0; opacity: 0; pointer-events: none;
    transition: opacity 0.25s ease;
    filter: drop-shadow(0 2px 14px rgba(58, 54, 51, 0.06));
}
.glyph-ink.is-finishing { animation: kjpInkSettle 0.5s ease both; }
@keyframes kjpInkSettle {
    0%   { filter: drop-shadow(0 2px 14px rgba(58, 54, 51, 0.06)); }
    42%  { filter: drop-shadow(0 3px 20px rgba(58, 54, 51, 0.12)); }
    100% { filter: drop-shadow(0 2px 14px rgba(58, 54, 51, 0.06)); }
}
.glyph-ink svg { width: 100%; height: 100%; display: block; overflow: visible; }
/* when writing: the text glyph dissolves slowly + a touch late, lingering under
   the first wet strokes; the ink layer's own fade-in is short (crisp over it). */
.glyph-stage.is-writing .glyph-rest { opacity: 0; transition: opacity 0.8s ease 0.08s; }
.glyph-stage.is-writing .glyph-ink { opacity: 1; pointer-events: auto; }

/* the ghost of the finished glyph, very faint — step / reduced-motion only */
.glyph-ink .ghost path {
    fill: none; stroke: rgba(58, 54, 51, 0.16);
    stroke-width: 5.8; stroke-linecap: round; stroke-linejoin: round;
    opacity: 0; transition: opacity 0.35s ease;
}
.glyph-ink.show-ghost .ghost path { opacity: 1; }
/* the LIVE strokes — warm sumi; scaling stroke-width (viewBox units) reads as the
   same heavy Klee ink the rest glyph carries, so the cross-fade is the SAME glyph. */
.glyph-ink .live path {
    fill: none; stroke: var(--kjp-ink);
    stroke-width: 5.8; stroke-linecap: round; stroke-linejoin: round;
    transition: stroke 0.42s ease, stroke-width 0.5s cubic-bezier(.2, .7, .2, 1);
}
/* the ACTIVE stroke — wet warm sumi + a touch heavier (brush pressure), eased
   back to settled sumi on land. NEVER indigo (reserved for the readings). */
.glyph-ink .live path.is-wet { stroke: var(--kjp-ink-wet); stroke-width: 7.4; transition: none; }
/* step-mode three-tier depth: TAUGHT strokes recede so the current one leads */
.glyph-ink.is-stepping .live path.is-done {
    stroke: color-mix(in srgb, var(--kjp-ink) 60%, var(--kjp-sheet, #FAF7EF));
    stroke-width: 5.4;
}
.glyph-ink .live path.is-current { stroke: var(--kjp-ink-wet); stroke-width: 6.8; }

/* the keyword line — its own centred block on the hero spine, held by framing
   rules that are dense at the words and fade to the margin. */
.hero .kw {
    display: flex; width: fit-content; margin-inline: auto;
    align-items: center; gap: 13px; margin-top: 15px;
    /* the meaning is the headline answer to "what is this kanji" — lift it a hair
       above the coloured reading glance below it (was 13.5px/stone). */
    font: 500 15px var(--kjp-ui); color: var(--kjp-prose); letter-spacing: 0.05em;
}
.hero .kw .kw-words { display: inline; }
.hero .kw .sep { font-style: normal; color: var(--kjp-ghost-soft); margin: 0 0.42em; }
.hero .kw::before, .hero .kw::after {
    content: ''; width: 26px; height: 1px;
    background: linear-gradient(90deg, transparent, color-mix(in srgb, var(--kjp-tone, #b0a090) 46%, transparent));
}
.hero .kw::after { background: linear-gradient(90deg, color-mix(in srgb, var(--kjp-tone, #b0a090) 46%, transparent), transparent); }

/* THE WHISPER + AFTER-LINE — the only new affordance, hide-until-intent. ONE
   reserved row beneath the keyword so nothing ever reflows.

   ⛔ HOSTED ON EVERY ROOT THAT CARRIES KANJI CONTENT — the same list the
   --kjp palette block at the top of this file already keeps, and for the same
   reason. Scoped to #kanjiPage alone (until 2026-08-07) this whole dress
   silently vanished wherever the writing block was BORROWED: in the word
   panel's full glance the 24×24 brush icon rendered at 504px (a black spike
   down the sheet), the whisper lost its hide-until-intent and sat there as
   raw 16px run-on prose, and the stepper lost its row. The walk's sheet hit
   the same cliff earlier and answered it by writing a second dress of its own
   (study-walk.css .kw-brush-host) — that host is deliberately NOT in this
   list; every other borrower belongs here. Pinned by tests/desktop/verify_panel_brush.py. */
:where(#kanjiPage, .wpn-kbody) .hint {
    height: 26px; margin-top: 8px;
    display: flex; align-items: center; justify-content: center;
}
:where(#kanjiPage, .wpn-kbody) .hint .rest {
    display: inline-flex; align-items: center; gap: 8px;
    font: 600 10.5px var(--kjp-ui); letter-spacing: 0.14em; text-transform: uppercase;
    /* hover-only (owner): hidden at rest, revealed on hero hover / glyph focus. */
    color: var(--kjp-stone); opacity: 0; transition: opacity 0.26s ease; pointer-events: none;
}
:where(#kanjiPage, .wpn-kbody) .hint .rest [lang="ja"] {
    font-family: var(--kjp-jp); font-size: 13px; letter-spacing: 0.02em;
    color: var(--kjp-ink); text-transform: none; opacity: 0.82;
}
:where(#kanjiPage, .wpn-kbody) .hint .rest .brush { width: 13px; height: 13px; flex: 0 0 auto; display: block; }
:where(#kanjiPage, .wpn-kbody) .hint .rest .brush svg {
    width: 13px; height: 13px; fill: none; stroke: var(--kjp-gold-deep);
    stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round;
}
.hero:hover .hint .rest, .glyph-stage:focus-visible ~ .hint .rest { opacity: 1; }
/* on touch the giant glyph is the control but there's no hover — rest the whisper
   softly visible (a calm cue), suppressed once the glyph is open. */
@media (hover: none) {
    :where(#kanjiPage, .wpn-kbody) .hint .rest { opacity: 0.7; }
    .glyph-stage.is-writing ~ .hint .rest { opacity: 0; }
}
:where(#kanjiPage, .wpn-kbody) .hint .after {
    display: none; align-items: center; justify-content: center; gap: 18px;
    opacity: 0; transition: opacity 0.4s ease; pointer-events: none;
}
.glyph-stage.is-writing ~ .hint .rest { display: none; }
.glyph-stage.is-writing ~ .hint .after { display: inline-flex; }
:where(#kanjiPage, .wpn-kbody) .hint .after.show { opacity: 1; pointer-events: auto; }
.hero:hover .glyph-stage.is-writing ~ .hint .after,
.glyph-stage.is-writing:focus-visible ~ .hint .after { opacity: 1; pointer-events: auto; }
.ink-link {
    appearance: none; background: none; border: 0; cursor: pointer; font: inherit;
    padding: 12px 2px;
    display: inline-flex; align-items: baseline; gap: 7px;
    color: var(--kjp-stone); transition: color 0.18s ease;
}
.ink-link [lang="ja"] { font-family: var(--kjp-jp); font-size: 13px; color: var(--kjp-ink); transition: color 0.18s ease; }
.ink-link .en { font: 400 11px var(--kjp-ui); letter-spacing: 0.04em; }
.ink-link:hover, .ink-link:hover [lang="ja"] { color: var(--kjp-indigo); }
.ink-link:focus-visible { outline: 2px solid var(--kjp-indigo); outline-offset: 3px; border-radius: 4px; }
.ink-link.on [lang="ja"], .ink-link.on .en { color: var(--kjp-indigo); }
:where(#kanjiPage, .wpn-kbody) .hint .stepper {
    display: inline-flex; align-items: center; gap: 8px;
    opacity: 0; transition: opacity 0.26s ease; pointer-events: none;
}
:where(#kanjiPage, .wpn-kbody) .hint.stepping .stepper { opacity: 1; pointer-events: auto; }
.step-arrow {
    appearance: none; background: none; border: 0; cursor: pointer; font: inherit;
    position: relative; width: 44px; height: 44px; line-height: 1; padding: 0;
    display: inline-flex; align-items: center; justify-content: center;
    color: var(--kjp-ink); transition: color 0.18s ease;
}
.step-arrow::before {
    content: ''; position: absolute; left: 50%; top: 50%; width: 26px; height: 26px;
    transform: translate(-50%, -50%); border-radius: 50%;
    background: transparent; transition: background-color 0.18s ease;
}
.step-arrow svg {
    position: relative; width: 13px; height: 13px; fill: none; stroke: currentColor;
    stroke-width: 2.2; stroke-linecap: round; stroke-linejoin: round; display: block;
}
.step-arrow:hover { color: var(--kjp-indigo); }
.step-arrow:hover::before { background: rgba(61, 90, 128, 0.06); }
.step-arrow:focus-visible { outline: none; }
.step-arrow:focus-visible::before { outline: 2px solid var(--kjp-indigo); outline-offset: 2px; }
.step-arrow[disabled] { color: var(--kjp-ghost-soft); opacity: 0.45; cursor: default; pointer-events: none; }
:where(#kanjiPage, .wpn-kbody) .hint .ord {
    display: inline-flex; align-items: baseline; gap: 3px;
    min-width: 42px; justify-content: center;
    font: 600 12px var(--kjp-ui); letter-spacing: 0.04em;
    color: var(--kjp-stone); font-variant-numeric: tabular-nums lining-nums;
}
:where(#kanjiPage, .wpn-kbody) .hint .ord .now { color: var(--kjp-indigo); }
:where(#kanjiPage, .wpn-kbody) .hint .ord .tot { color: var(--kjp-ghost); }

.sr-only {
    position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
    overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* ── THE MOUNTED PRINT — the etymology painting set into a passe-partout ── */
.story { display: flex; flex-direction: column; align-items: center; padding: 22px 0 4px; }
.story .mount-wrap { position: relative; width: min(486px, 94%); }
.story .mount-wrap::before {
    content: ''; position: absolute; inset: -32px -26px -28px -26px; z-index: 0;
    pointer-events: none; border-radius: 26px;
    background: radial-gradient(62% 78% at 40% 28%,
        color-mix(in srgb, var(--kjp-tone, #b0a090) 27%, transparent) 0%, transparent 72%);
    opacity: 0.52; filter: blur(9px);
}
.story .mount {
    position: relative; z-index: 1; padding: 26px; border-radius: 4px; margin: 0;
    background: linear-gradient(150deg,
        color-mix(in srgb, var(--kjp-paper) 96%, #fff) 0%,
        var(--kjp-paper) 42%,
        color-mix(in srgb, var(--kjp-paper) 92%, var(--kjp-tone, #b0a090) 8%) 100%);
    box-shadow:
        inset 0 1px 0 rgba(255, 251, 243, 0.85),
        inset 0 0 0 1px rgba(120, 90, 60, 0.10),
        0 1px 2px rgba(58, 40, 20, 0.04),
        0 6px 18px rgba(58, 40, 20, 0.05);
}
.story .plate {
    position: relative; z-index: 1; width: 100%; aspect-ratio: 3 / 2;
    border-radius: 2px; overflow: hidden;
    background:
        radial-gradient(120% 90% at 28% 22%, color-mix(in srgb, var(--kjp-tone, #b0a090) 24%, var(--kjp-paper)) 0%, transparent 56%),
        radial-gradient(110% 100% at 78% 84%, color-mix(in srgb, var(--kjp-tone, #b0a090) 16%, var(--kjp-paper)) 0%, transparent 60%),
        color-mix(in srgb, var(--kjp-tone, #b0a090) 11%, var(--kjp-paper));
    box-shadow:
        inset 1px 1px 0 rgba(255, 251, 243, 0.55),
        inset -1px -1px 0 rgba(58, 40, 20, 0.10),
        /* gold inner edge dropped — the .bevel warm-brown ring already frames the
           plate, and gold is reserved for the earned watch-out (scarcity). */
        inset 0 2px 10px rgba(58, 40, 20, 0.10),
        inset 0 0 50px rgba(120, 90, 60, 0.05);
}
.story .plate .fallback { position: absolute; inset: 0; pointer-events: none; }
.story .plate .fallback .g {
    position: absolute; font-family: var(--kjp-jp); font-weight: 400;
    line-height: 1; filter: blur(0.3px); user-select: none; color: rgba(120, 90, 60, 0.16);
}
.story .plate .fallback .g.g-a { font-size: clamp(46px, 11vw, 80px); top: 13%; left: 21%; }
.story .plate .fallback .g.g-b { font-size: clamp(92px, 20vw, 150px); bottom: 5%; right: 11%; }
/* one-part / no-part fallback: centre one calm glyph instead of jamming it into the
   bottom-right corner (a position tuned for the two-component evocation). */
.story .plate .fallback--solo .g-b {
    top: 50%; left: 50%; right: auto; bottom: auto;
    transform: translate(-50%, -50%);
    font-size: clamp(72px, 16vw, 110px);
}
.story .plate .fallback .disc {
    position: absolute; top: 18%; left: 27%;
    width: clamp(34px, 7vw, 56px); height: clamp(34px, 7vw, 56px); border-radius: 50%;
    /* a soft tone disc (the "sun" reads by its shape, not by gold) — gold is reserved
       for the earned watch-out, so the image-less fallback no longer spends it. */
    background: radial-gradient(circle at 42% 40%, color-mix(in srgb, var(--kjp-tone, #b0a090) 38%, transparent), color-mix(in srgb, var(--kjp-tone, #b0a090) 10%, transparent) 70%, transparent);
}
.story .plate .art {
    position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; display: block;
    opacity: 0; transition: opacity 0.5s ease;
}
.story .plate .art.loaded { opacity: 1; }
.story .plate .art.art-b { z-index: 2; }
.story .plate .bevel {
    position: absolute; inset: 0; pointer-events: none; z-index: 3; border-radius: 2px;
    box-shadow:
        inset 1px 1px 0 rgba(255, 251, 243, 0.40),
        inset -1px -1px 0 rgba(58, 40, 20, 0.18),
        inset 0 0 0 1px rgba(120, 90, 60, 0.14);
}
.story .plate .tag {
    position: absolute; top: 12px; left: 12px; z-index: 4;
    font: 600 9px var(--kjp-ui); letter-spacing: 0.15em; text-transform: uppercase;
    color: var(--kjp-stone);
    background: rgba(250, 247, 239, 0.80); border: 1px solid var(--kjp-rule);
    border-radius: 2px; padding: 3px 9px;
    display: inline-flex; align-items: center; gap: 7px; backdrop-filter: blur(2px);
}
.story .plate .tag .nib { width: 5px; height: 5px; border-radius: 50%; background: var(--kjp-indigo); opacity: 0.55; }

/* the component caption under the print — the etymology named through its parts:
   the two component glyphs flank, the part names sit between (demo parity). */
.story .mount .caption {
    margin-top: 16px;
    text-align: center;
    font: 400 10px 'Inter', 'Noto Sans JP', sans-serif;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: var(--kjp-stone);
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 9px;
    flex-wrap: wrap;
}
.story .mount .caption [lang="ja"] {
    font-family: 'Klee One', 'Noto Sans JP', sans-serif;
    font-size: 13px;
    letter-spacing: 0.04em;
    text-transform: none;
    color: var(--kjp-ink);
}
.story .mount .caption .dot { width: 3px; height: 3px; border-radius: 50%; background: var(--kjp-ghost-soft); opacity: 0.8; }   /* neutral mote, not earned gold */

/* the TYPE TAG's housing on the kanji surfaces (the row's own voice lives in
   css/kanji-parts.css, with the builder that renders it — one dress for the
   page, the drawer, the word panel and the walk sheet). Here: only where it
   sits. Under the mount's print wherever the print is in the body — the
   drawer AND the word panel's embedded glance, which since 2026-08-07 renders
   that same mount instead of printing its own painting above and floating
   this caption to the top of the sheet; and on the PAGE, where the print is
   pinned overhead, heading the shape act it classifies. */
.story .mount .kjp-type-cap {
    margin-top: 14px;
}
.kjp-body > .kjp-type-cap {
    margin: 4px auto 0; max-width: 460px;
}

/* ── the shape story (prose) + the part-doors (borrowed-light component tie-in) ── */
.shape { text-align: center; padding: 28px 0 2px; }
.shape .prose {
    font-family: var(--kjp-jp); font-size: 18px; line-height: 1.92;
    color: var(--kjp-prose); max-width: 444px; margin: 0 auto; text-wrap: pretty;
}
.shape .prose b { color: var(--kjp-ink); font-weight: 600; font-style: normal; }
.shape .prose i { color: var(--kjp-indigo); font-style: normal; font-weight: 600; }
.shape .prose .wp-jp { color: var(--kjp-ink); }
/* the parts row — v2 doors. The existing door physics (button[data-kanji]) are
   preserved; this is the dress + the writing-led warm (borrowed light). */
.kjp-parts.parts {
    display: flex; justify-content: center; gap: 16px; margin-top: 24px;
    flex-wrap: wrap; align-items: center;
}
.parts .door {
    display: inline-flex; align-items: center; gap: 10px;
    background: none; border: 1px solid var(--kjp-rule); border-radius: 6px;
    padding: 7px 14px 7px 12px; text-decoration: none; cursor: pointer; font: inherit;
    transition: transform 0.2s ease, border-color 0.42s ease, background 0.42s ease;
}
/* an ungated part is not interactive — rest it without hover affordances */
.parts span.door { cursor: default; }
/* a tappable door (button) carries a quiet indigo edge AT REST so it reads as
   openable without waiting for hover — material, not an always-on arrow. The dead
   chips (span.door) keep the plain rule hairline, so the two are distinct at a glance. */
.parts button.door { border-color: rgba(61, 90, 128, 0.22); background: rgba(61, 90, 128, 0.02); }
button.parts, .parts button.door:hover {
    border-color: rgba(61, 90, 128, 0.32); background: rgba(61, 90, 128, 0.025);
}
.parts span.door:hover { transform: none; border-color: var(--kjp-rule); background: none; }
.parts .door:focus-visible { outline: 2px solid var(--kjp-indigo); outline-offset: 2px; }
.parts .door .g { font-family: var(--kjp-jp); font-size: 30px; color: var(--kjp-ink); line-height: 1; transition: color 0.35s ease; }
.parts .door .n { font: 400 11px var(--kjp-ui); color: var(--kjp-stone); letter-spacing: 0.02em; }
/* the hop arrow is navigation, so it wears the indigo teaching accent (matching the
   glyph's own hover colour), never the earned gold. */
.parts .door .go { font: 400 13px var(--kjp-ui); color: var(--kjp-indigo); opacity: 0; transition: opacity 0.2s ease; margin-left: -3px; }
button.parts.door:hover .g, button.parts.door:focus-visible .g,
.parts button.door:hover .g, .parts button.door:focus-visible .g { color: var(--kjp-indigo); }
.parts button.door:hover .go, .parts button.door:focus-visible .go { opacity: 1; }
/* the writing-led warm: while a component's strokes draw, its door glows the same
   indigo a hover gives — borrowed light, calm and brief. */
.parts .door.writing .g { color: var(--kjp-indigo); }
.parts .door.writing { border-color: rgba(61, 90, 128, 0.22); background: rgba(61, 90, 128, 0.02); }
/* touch has no hover: keep the hop arrow softly present so a door still signals it
   opens a kanji page (mirrors the hero whisper's touch treatment). */
@media (hover: none) { .parts button.door .go { opacity: 0.4; } }

/* ── THE THRESHOLD — 間 (ma): a band of breath, the gear-change ── */
.threshold {
    position: relative; height: 108px; margin-top: 12px;
    display: flex; align-items: center; justify-content: center;
}
.threshold::before {
    content: ''; position: absolute; left: 50%; top: 50%;
    width: 78%; height: 58px; transform: translate(-50%, -50%);
    background: radial-gradient(60% 50% at 50% 50%,
        color-mix(in srgb, var(--kjp-tone, #b0a090) 16%, transparent) 0%, transparent 72%);
    opacity: 0.85; pointer-events: none;
}
.threshold .mark { position: relative; z-index: 1; display: flex; align-items: center; gap: 13px; }
.threshold .mark .ln {
    width: clamp(34px, 9vw, 64px); height: 1px;
    background: linear-gradient(90deg, transparent, color-mix(in srgb, var(--kjp-tone, #b0a090) 40%, transparent));
}
.threshold .mark .ln.r { background: linear-gradient(90deg, color-mix(in srgb, var(--kjp-tone, #b0a090) 40%, transparent), transparent); }
.threshold .mark .ch { font-family: var(--kjp-jp); font-size: 18px; color: var(--kjp-ink); opacity: 0.62; line-height: 1; }
.threshold .mark .lbl { font: 600 9.5px var(--kjp-ui); letter-spacing: 0.24em; text-transform: uppercase; color: var(--kjp-stone); }

/* ── sections: ink on the washi (the word page's grammar) ─────────────── */

.kjp-sec { padding: 30px 0 0; }
.kjp-sec + .kjp-sec,
.kjp-sec + .kjp-card,
.kjp-sec ~ .kjp-card { margin-top: 30px; }
/* the labels are gone (なりたち / あなたのことばの中で were self-explanatory),
   so the scenes must read apart on whitespace + the band + the READ AS group
   eyebrows alone. The shape story opens just under the band as its own scene
   (a touch more air than a labelled section once gave); the words section then
   sits a full scene-gap below, its first group eyebrow doing the framing. */
.kjp-story { padding-top: 34px; }
.kjp-story + .kjp-words { margin-top: 34px; }

/* ── 例文 examples — the kanji met in real sentences, reusing the example set
   the words already carry. Calm stacked rows; the page kanji (and its reading)
   light indigo inside each sentence so the eye finds the character it came for. */
/* Each example is its OWN unit, and reads like one (owner 2026-08-05, comparing
   this list against the word page's). An 18px gap and nothing else stacked three
   sentences into one grey block — and once the 訳 offer joined each row, the
   sentence, its offer and the NEXT sentence were all the same distance apart, so
   nothing said which offer belonged to which line. The word page had already
   solved it: air on the row itself, and a hairline to say "that one has ended".
   The structure ports; the dress does not — this is the page's OWN --kjp-rule,
   the same hairline its reading groups already use, not the word page's. */
.kje-list { display: flex; flex-direction: column; }
.kje-ex { padding: 17px 2px; }
.kje-ex + .kje-ex { border-top: 1px solid var(--kjp-rule); }
/* the first row sits directly under the 例文 label, which carries its own space */
.kje-ex:first-child { padding-top: 4px; }
.kje-jp {
    margin: 0 0 6px;
    font-family: 'Klee One', 'Noto Sans JP', serif;
    font-size: 20px;
    line-height: 2.15;                 /* headroom for the ruby */
    color: var(--kjp-ink);
}
.kje-jp ruby rt {
    font: 400 10px 'Inter', 'Noto Sans JP', sans-serif;
    color: var(--kjp-stone);
    letter-spacing: 0.02em;
}
/* the studied kanji, lit inside the sentence — warm indigo ink (the panel's
   teaching accent) + a little more weight (Klee One 600), no box, no underline:
   the glyph the reader came for reads a different COLOUR from the sentence around
   it, calmly (和の感性 restraint). Its reading above matches ONLY when the ruby
   group is exactly this one kanji (word-level furigana can't be split per char). */
.kje-jp .kje-hl { color: var(--kjp-indigo); font-weight: 600; }
.kje-jp ruby.kje-rb-hl rt { color: var(--kjp-indigo); font-weight: 600; }
/* every OTHER gated kanji in the sentence is a door deeper into the trail
   (universal tap). The affordance is hover-only: a resting tint on every
   live glyph would patchwork the sentence and bury the studied character's
   own highlight — the sentence's one point. Pointer users discover it the
   way they discover the word page's example doors. */
@media (hover: hover) {
    .kje-jp .kje-kt { cursor: pointer; transition: color 0.15s ease; }
    .kje-jp .kje-kt:hover { color: var(--kjp-indigo); }
}
.kje-ro {
    display: block;
    font: 400 12.5px 'Inter', 'Noto Sans JP', sans-serif;
    font-style: italic;
    color: var(--kjp-ghost);
}
.kje-en {
    display: block;
    margin-top: 2px;
    font: 400 14px 'Inter', 'Noto Sans JP', sans-serif;
    line-height: 1.5;
    color: var(--kjp-prose);
}
/* 訳 — the reader ASKS for the romaji + meaning (owner 2026-08-05). The BEHAVIOUR
   is the word page's; the DRESS is this page's own. It borrows .kje-more's exact
   control voice (12px Inter 500, ghost ink, the same padding and hover) because a
   surface with two different quiet-button species reads as two surfaces — and for
   the same specificity reason: it MUST be scoped under both hosts the kanji spine
   mounts in, or the `.kjp-overlay button` / `.wpn-kbody button` resets (0,1,1)
   leave it as plain 16px body text. The 訳 sits in the panel's teaching indigo so
   the offer reads as the section's own hand, not a stray word of prose. */
.kjp-overlay .kje-ask,
.wpn-kbody .kje-ask {
    appearance: none;
    background: none;
    border: 0;
    margin: 2px 0 0;
    padding: 5px 8px 5px 2px;
    display: inline-flex;
    align-items: baseline;
    gap: 8px;
    border-radius: 6px;
    font: 500 12px 'Inter', 'Noto Sans JP', sans-serif;
    color: var(--kjp-ghost);
    cursor: pointer;
    transition: color 0.18s ease;
}
/* THE [hidden] RESET (tests/css/hidden_reset_test.js). The `display` above is
   author origin and beats the UA's `[hidden] { display: none }` outright, so
   without this the spent offer stays painted — and stays clickable, and stays a
   tab stop — directly above the answer it just revealed, captioning it. Seventh
   strike on this law; the guard names the fix. */
.kjp-overlay .kje-ask[hidden],
.wpn-kbody .kje-ask[hidden] { display: none; }
.kjp-overlay .kje-ask:hover,
.wpn-kbody .kje-ask:hover { color: var(--kjp-stone); }
.kjp-overlay .kje-ask:active,
.wpn-kbody .kje-ask:active { color: var(--kjp-ink); }
.kjp-overlay .kje-ask:focus-visible,
.wpn-kbody .kje-ask:focus-visible { outline: 2px solid var(--kjp-indigo); outline-offset: 2px; }
.kje-ask-ink {
    font-family: 'Klee One', 'Noto Sans JP', serif;
    font-size: 14px;
    color: var(--kjp-indigo);
}
/* held-back examples wait behind the "Show N more" tap, then grow in calmly
   (same transform-only reveal the reading groups use — safe under reduced-motion) */
.kje-ex--hid { display: none; }
.kje-ex--reveal { animation: kjwReveal 0.24s ease both; }
/* the "Show N more" disclosure. MUST be scoped under .kjp-overlay so it out-
   specifies the `.kjp-overlay button` reset (which otherwise leaves it as plain
   16px ink body text — the un-native look) and reads as a small tracked ghost
   affordance with the panel's caret: a quiet "there's more", not a line of prose. */
.kjp-overlay .kje-more,
.wpn-kbody .kje-more {
    appearance: none;
    background: none;
    border: 0;
    margin: 8px 0 0;
    padding: 6px 8px 6px 2px;
    display: inline-flex;
    align-items: center;
    gap: 8px;
    border-radius: 6px;
    font: 500 12px 'Inter', 'Noto Sans JP', sans-serif;
    color: var(--kjp-ghost);
    cursor: pointer;
    transition: color 0.18s ease;
}
.kjp-overlay .kje-more:hover,
.wpn-kbody .kje-more:hover { color: var(--kjp-stone); }
.kjp-overlay .kje-more:active,
.wpn-kbody .kje-more:active { color: var(--kjp-ink); }
.kjp-overlay .kje-more:focus-visible,
.wpn-kbody .kje-more:focus-visible { outline: 2px solid var(--kjp-indigo); outline-offset: 2px; }
/* (the .kjp-howto / 読み方 orientation rules were removed 2026-06-27 with the dead
   howtoHTML() that emitted them — never rendered; the reading standfirsts teach it.) */
.kjp-slabel {
    display: flex;
    align-items: baseline;
    gap: 10px;
    margin-bottom: 12px;
    color: var(--color-stone);
}
.kjp-slabel [lang="ja"] {
    font: 600 15px 'Klee One', 'Noto Sans JP', sans-serif;
    color: var(--kjp-ink);
}
.kjp-slabel span:not([lang]) {
    font: 600 10.5px 'Inter', 'Noto Sans JP', sans-serif;
    letter-spacing: 0.17em;
    text-transform: uppercase;
    color: var(--color-stone);
}
/* (INERT since 12 October 2026: SentenceTokens.inviteHTML prints nothing, the
   invitation retired for good; kept so a revival is one line in the js.)
   the 例文 block's invitation — the words in these sentences answer, said once
   and retired on the first tap. It sits INSIDE .kjp-slabel, whose
   `span:not([lang])` rule would otherwise dress it as a second section label —
   so this must out-specify it: `span.kje-tap` ties at (0,2,1) and wins on
   source order, which is why it lives directly beneath. A label names; this
   asks for a gesture, so it takes the whisper voice instead. */
.kjp-slabel span.kje-tap {
    font: italic 400 11.5px 'Inter', 'Noto Sans JP', sans-serif;
    letter-spacing: 0.02em;
    text-transform: none;
    color: var(--color-stone);
}

/* the one box that remains earned: the gold watch-out card (and the twin
   specimen tray below) — everything else reads as ink on the paper */
.kjp-card {
    background: var(--color-card);
    border: 1px solid var(--kjp-rule);
    border-radius: 3px;
    box-shadow: 0 1px 3px rgba(58, 40, 20, 0.05);   /* warm sumi shadow, not cold neutral */
    padding: 20px 22px;
    margin: 30px 0 0;
}
.kjp-card .kjp-slabel [lang="ja"] { font-size: 13px; }

/* prose <b>/<i> + the shared Klee-bold for prose/watch/twin emphasis. (The shape
   prose itself is styled in the v2 hero block above as .shape .prose; this keeps
   the shared bold rule for the watch-out / twin lines that also carry <b>.) */
.kjp-story b, .kjp-watch b, .kjt-note b {
    font-family: 'Klee One', 'Noto Sans JP', sans-serif;
    font-weight: 600;
}
/* the v2 part-doors are styled in the hero block above (.parts .door .g/.n/.go +
   the borrowed-light .writing warm). The renderer now emits .kjp-part-name as
   .n and the glyph as .g, so the old flat-typography part rules are retired. */

/* ── reading groups + word rows ───────────────────────────────────────── */

.kjr-group { margin-top: var(--kjw-grp-gap); }   /* shared group rhythm (was 14px; owner consistency 2026-06-29) */
.kjr-group:first-of-type { margin-top: 0; }
.kjr-eyebrow {
    /* a shelf's teaching title (まるごと · read as · usually written in kana) —
       lifted out of the 9.5px basement so it reads as a real heading, still
       distinct from the 10px band-metadata caption. (The kun/on eyebrows left
       with B3, 11 October 2026: the rows device names the ways now.) */
    font: 600 12px 'Inter', 'Noto Sans JP', sans-serif;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: #78716c;
    margin-bottom: 16px;
    line-height: 1.5;
    text-wrap: pretty;
}
/* (the .kjr-eb-note standfirst retired 2026-08-11 — the rule joined the
   history behind the term's whisper; owner ruling, supersedes 08-07) */
/* ── the term's resting history (owner 2026-08-07) ─────────────────────────
   The standfirst keeps the RULE; WHY the two channels exist rests behind the
   訓読み / 音読み term it belongs to. Three ways in, because this panel is read
   on all three: hover where hover is real, focus for the keyboard, TAP on
   touch (iPad is a primary device — a hover-only note is a DELETED note there).
   Same whisper law as the walk's kanji sheet (.kw-tip, css/study-walk.css). */
.kjr-tiphost {
    position: relative;
    display: inline-block;
    cursor: help;
}
/* the only chrome the note gets: a hairline under the term saying something
   rests here. Rides the .jp itself so it stops at the word, not at its gutter. */
.kjr-tiphost > .jp {
    border-bottom: 1px dotted var(--kjp-ghost-soft);
    padding-bottom: 1px;
}
/* the hit area a finger needs, without moving a pixel of the line */
.kjr-tiphost::after { content: ""; position: absolute; inset: -11px -6px -8px; }
/* the whisper's two lines: the RULE first, the history under it */
.kjr-tip-line { display: block; }
.kjr-tip-line + .kjr-tip-line { margin-top: 6px; color: var(--color-stone); }
/* the neu "read as" label as host wears the same hairline the JP term does */
.kjr-tiphost--en > .kjr-eb-en {
    border-bottom: 1px dotted var(--kjp-ghost-soft);
    padding-bottom: 1px;
}
.kjr-tip {
    position: absolute; left: -4px; top: calc(100% + 9px); z-index: 40;
    width: 244px;
    background: var(--kjp-paper);
    border: 1px solid var(--color-divider);
    border-radius: 9px;
    box-shadow: 0 10px 26px -12px rgba(67, 50, 30, 0.35);
    padding: 9px 12px;
    font: italic 400 11.5px/1.55 'Inter', 'Noto Sans JP', sans-serif;
    color: var(--color-stone);
    text-align: left; text-transform: none; letter-spacing: 0.01em;
    white-space: normal; opacity: 0; visibility: hidden;
    transition: opacity 0.18s; pointer-events: none;
}
.kjr-tip [lang="ja"] {
    font-family: 'Klee One', 'Noto Sans JP', sans-serif;
    font-style: normal; color: var(--kjp-ink);
}
/* hover only where hover is REAL — on touch, iOS sticky-hover would open the
   whisper on the first tap and desync the tap toggle's own class state */
@media (hover: hover) and (pointer: fine) {
    .kjr-tiphost:hover > .kjr-tip { opacity: 1; visibility: visible; }
}
.kjr-tiphost:focus-visible > .kjr-tip { opacity: 1; visibility: visible; }
/* touch: .kjr-tip-on is set only by the tap handler, so mouse keeps pure hover */
.kjr-tiphost.kjr-tip-on > .kjr-tip { opacity: 1; visibility: visible; }
/* (.kjr-eb-rom, the romaji kun'yomi / on'yomi beside 訓読み / 音読み, and its house
   middot left with those eyebrows: B3, 11 October 2026; since Round C the same day the
   kinds' names print nowhere on the page.) */
/* the kanji term before the English (まるごと / かな) — Klee, ink, no
   tracking, a hair faded, so it reads as the native label leading the heading. */
.kjr-eyebrow .jp {
    font-family: 'Klee One', 'Noto Sans JP', sans-serif;
    font-size: 16px;
    letter-spacing: 0;
    color: var(--kjp-ink);
    text-transform: none;
    margin-right: 7px;
    opacity: 1;
}
/* a hairline under the reading header anchors the reading name to its word list
   (so とき / じ / とけい don't float orphaned); the lines BETWEEN rows and BETWEEN
   sections are gone — only this header rule remains. */
.kjr-head {
    display: flex;
    align-items: baseline;
    gap: 11px;
    /* match the word rows' 5px side padding so the reading name sits on the tile
       column and "N words" lines up over the rank rail (was flush, 5px adrift). */
    padding: 0 5px 8px;
    border-bottom: 1px solid var(--kjp-rule);
    margin-bottom: 12px;
}
/* glance jump landing: a brief accent wash on the reading head you jumped to confirms
   the tap took you to the right reading (added in JS after the scroll settles). */
@keyframes kjrArrive {
    0%   { background-color: transparent; }
    25%  { background-color: color-mix(in srgb, var(--rd-accent, var(--kjp-indigo)) 13%, transparent); }
    100% { background-color: transparent; }
}
.kjr-head--arrive { animation: kjrArrive 0.7s ease; }
/* the reading-family head (とき / じ) — indigo because the readings ARE the lesson
   (the teaching accent, matching the won v2 .gname). Sumi is reserved for the glyph,
   labels, and word rows; here the kun/on name carries the indigo teaching signal. */
.kjr-name { font: 600 22px 'Klee One', 'Noto Sans JP', sans-serif; color: var(--rd-accent, var(--color-accent)); }
.kjr-name--whole { font-size: 14px; color: var(--color-stone); }
.kjr-sub { font: 400 11.5px 'Inter', 'Noto Sans JP', sans-serif; color: var(--color-stone); }
.kjr-head .kjr-sub { margin-left: auto; }       /* the word count rests at the right */

/* reading FAMILIES — native (kun) · borrowed (on) · まるごと. The eyebrow names the
   family in plain English; the def teaches the term + when the reading fires. Ink
   on the washi: the family is typography + the head's hairline, never a box.
   v2: a soft vertical rule to the left — gold-tipped fading to tone for kun/on,
   indigo for まるごと — gives each family its own quiet spine. */
.kjr-family { position: relative; margin-top: 22px; padding-left: 22px; --rd-accent: var(--color-accent); }   /* tightened (owner 2026-06-29; was 36px) */
/* reading-type accent — one variable drives every per-type colour:
   native (kun'yomi) = indigo (default), borrowed (on'yomi) = terracotta,
   fused combo (まるごと) = bronze. */
.kjr-family--on { --rd-accent: #9E5E43; }
.kjr-family--whole { --rd-accent: #8A6A33; }
/* unclassified readings ("read as" / "in your words") must NOT borrow kun-indigo —
   colour means a real classification. Warm stone reads as honestly unclaimed. */
.kjr-family--neu { --rd-accent: var(--kjp-stone); }
.kjr-family:first-of-type { margin-top: 0; }
.kjr-family .kjr-group:first-of-type { margin-top: 0; }
/* the family spine echoes the locked reading accent (kun indigo / on terracotta /
   まるごと bronze / neu stone) instead of a decorative gold tip — so a glance down
   the spine reads the kun/on structure, and gold stays earned (watch-out only). */
.kjr-family::before {
    content: ''; position: absolute; left: 0; top: 3px; bottom: 6px;
    width: 2px; border-radius: 2px;
    background: linear-gradient(180deg,
        color-mix(in srgb, var(--rd-accent) 38%, transparent),
        color-mix(in srgb, var(--rd-accent) 8%, transparent));
}
.kjr-def {
    margin: 2px 0 13px;
    max-width: 66ch;                            /* fits each one-line def on a single row */
    font: 400 12.5px/1.55 'Inter', 'Noto Sans JP', sans-serif;
    color: var(--color-stone);
    text-wrap: pretty;                          /* clean wrap on narrow viewports */
}
.kjr-def b { font-weight: 600; color: var(--kjp-ink); }
.kjr-def [lang="ja"] {
    font-family: 'Klee One', 'Noto Sans JP', sans-serif;
    font-size: 1.05em;
    color: var(--kjp-ink);
}
/* the reading's romaji — a quiet companion beside the kana name. #6b6358 matches the
   row romaji + clears AA (was #78716c, which read lighter than the smaller row romaji). */
.kjr-romaji { font: 400 13px 'Inter', 'Noto Sans JP', sans-serif; color: #6b6358; }
/* rendaku: this reading is the family's base with a voiced first sound, not new */
.kjr-voiced { font: 400 11.5px 'Inter', 'Noto Sans JP', sans-serif; color: #6b6358; }
.kjr-voiced [lang="ja"] {
    font-family: 'Klee One', 'Noto Sans JP', sans-serif;
    font-size: 1.15em;
    color: var(--color-stone);
}

/* まるごと block: the fused unit named before its words — "時 + 計 → とけい · clock".
   The kanji combine (the current one tinted indigo like a row highlight), arrow to
   the fused reading, then the plain meaning. One header per distinct block, so
   different jukujikun units never read as a single pooled reading. */
.kjr-group--juku { margin-top: 12px; }   /* tightened (owner 2026-06-29; was 18px) */
.kjr-juku-head {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: 4px 7px;
    padding: 0 5px 8px;     /* on the row grid, like .kjr-head */
    margin-bottom: 4px;
    border-bottom: 1px solid var(--kjp-rule);
}
/* the fused pair → its sound, as one indigo "equation" on the washi. BOTH kanji
   carry the same indigo (together they make the reading — neither is "the source"),
   and the fused READING is the larger indigo result the eye lands on. No black: the
   formula reads as a calm label, distinct from the warm word rows it heads. */
.kjr-juku-k { font: 600 18px 'Klee One', 'Noto Sans JP', sans-serif; color: var(--rd-accent, var(--color-accent)); }
.kjr-juku-op { font: 400 13px 'Inter', sans-serif; color: #b3aca3; align-self: center; }
.kjr-juku-read {
    font: 600 20px 'Klee One', 'Noto Sans JP', sans-serif;
    color: var(--rd-accent, var(--color-accent));           /* the fused sound — the result, no black */
    margin-left: 2px;
}
.kjr-juku-mean { font: 400 13px 'Inter', 'Noto Sans JP', sans-serif; color: var(--color-stone); }

/* ── ⭐ THE PLACE ON A GROUP'S HEAD (the owner, 20 October 2026: `習 has two ways.` and its rows "duplicates the readings we
   have below"; js/kanji-page.js placesOf, placeHTML; shelf review item B). The course's rows device (Round B, B3, 11 October
   2026: `日 has two ways.` and one row a way over the lists) left the page; the one fact it carried that the groups do not, how
   the reading is placed in its word, follows the head's kana in the head's quiet sans: `なら · on its own`, `しゅう · with other
   kanji` (the kana is content, the phrase English chrome). A group with no place keeps its head as it was. ── */
.kjr-place { font: 400 12.5px 'Inter', 'Noto Sans JP', sans-serif; color: var(--color-stone); letter-spacing: 0.01em; }
.kjr-place-dot { margin-right: 0.5em; color: #b3aca3; }

.kjw-row {
    appearance: none;
    background: none;
    border: 0;
    border-radius: 0;
    width: 100%;
    display: flex;
    align-items: center;
    gap: 18px;
    padding: 11px 5px;
    cursor: pointer;
    text-align: left;
    font-family: inherit;
    color: inherit;
    transition: background-color 0.18s ease;
}
/* The overlay button-reset (.kjp-overlay button, 0,1,1) zeroes padding and
   outranks .kjw-row (0,1,0) — but only the BUTTON rows match it, so image rows
   lost their padding while the no-card DIV rows kept it. That was the entire
   cross-section height drift. Re-assert at matching specificity so every row
   (button or div) carries the same vertical padding. */
.kjp-overlay .kjw-row,
.wpn-kbody .kjw-row { padding: 11px 5px; }
/* rows tint only on hover/press (warm sumi) — the 4px slide is dropped so every
   tappable surface shares one calm vocabulary (like the twin cell). */
.kjw-row:hover { background: rgba(58, 54, 51, 0.03); }
.kjw-row:active { background: rgba(58, 54, 51, 0.05); }
.kjw-row:last-of-type { border-bottom: none; }
.kjw-row--hid { display: none; }

/* live mastery dot — which of these words the learner already holds. Off the
   thumbnail (never deface the art), at the row's right edge beside the rank
   chip; the placard's own status colours (amber Saved · moss Resting · bright
   Coming back). New rows — most of any list — stay unmarked: the mark must
   earn its place. */
.kjw-dot {
    flex: 0 0 auto;
    width: 7px;
    height: 7px;
    border-radius: 50%;
}
.kjw-dot--learning { background: var(--color-amber, #A07850); }
.kjw-dot--learned { background: var(--color-moss, #6B7F5C); }
.kjw-dot--comeback { background: var(--color-moss-bright, #5B8C5A); }

/* the row placard — a solid muted tone tile (the word's own img_tone via --rowtone),
   not a photo thumbnail: the calm reading-room look (demo parity). A faint washi
   grain + a top-left sheen sit it on the same paper as the sheet. */
.kjw-tile {
    width: 94px;
    height: 67px;
    border-radius: 8px;
    flex: 0 0 auto;
    position: relative;
    overflow: hidden;
    background: var(--rowtone, #b0a090);
    box-shadow:
        inset 0 0 0 1px rgba(120, 90, 60, 0.10),
        0 1px 4px rgba(58, 40, 20, 0.07);
}
.kjw-tile::after {
    content: '';
    position: absolute;
    inset: 0;
    mix-blend-mode: multiply;
    opacity: 0.06;
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='40' height='40'><filter id='kjt'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='1'/></filter><rect width='100%25' height='100%25' filter='url(%23kjt)'/></svg>");
}
.kjw-tile::before {
    content: '';
    position: absolute;
    inset: 0;
    z-index: 1;
    background: radial-gradient(120% 100% at 26% 18%, rgba(250, 247, 239, 0.30), transparent 62%);
}
/* the real word painting fills the tile (the tone swatch behind is the load
   guard); fades in on load, hidden on error so the swatch shows instead. */
.kjw-thumb {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
    z-index: 2;
    opacity: 0;
    transition: opacity 0.4s ease;
}
.kjw-thumb.loaded { opacity: 1; }
.kjw-main { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 4px; }
/* word rows read at a calm medium weight (matches the まるごと no-card examples) —
   the per-type highlight carries the emphasis, not a heavy stroke. */
.kjw-jp { font: 500 27px 'Klee One', 'Noto Sans JP', sans-serif; line-height: 1.5; }
.kjw-hl { color: var(--rd-accent, var(--color-accent)); }
/* alt-spelling rows (the かな shelf): the kanji dress the word would wear,
   quiet beside the kana headword — the page kanji lit inside it is the row's
   teaching point. */
.kjw-alt {
    font: 400 17px 'Klee One', 'Noto Sans JP', sans-serif;
    color: var(--kjp-ghost-soft, #a8a299);
    margin-left: 9px;
}
.kjw-alt .kjw-hl { color: var(--rd-accent, var(--color-accent)); }
/* the reading, one quiet line under the word (kana furigana removed 2026-06-26).
   It CARRIES the whole pronunciation, so it must clear AA — #6b6358 is ~5.5:1 on
   the washi (the old ghost #8c857b was ~3.4:1, a fail), still quieter than the lemma.
   Since 2026-08-06 the line is KANA and the romaji rides behind the ローマ字 control
   beside it; both wear the same weight, because they are the same line. */
.kjw-ro,
.kjw-rd-kana {
    font: 500 12.5px 'Inter', 'Noto Sans JP', sans-serif;
    color: #6b6358;
    letter-spacing: 0.04em;
}
.kjw-rd-kana {
    font-family: 'Klee One', 'Noto Sans JP', sans-serif;
    font-size: 13.5px;
    letter-spacing: 0.02em;
}
/* ONE line for the pair: .kjw-main is a flex COLUMN, so bare siblings each took
   a row and the list grew taller the moment romaji was asked for. Answering an
   ask must never move the page the reader is reading. */
.kjw-rdline { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
.kjw-ro-note { letter-spacing: 0; color: var(--kjp-ghost-soft, #a8a299); }
.kjw-ro-note [lang="ja"] { font-family: 'Klee One', 'Noto Sans JP', sans-serif; }
.kjw-kana {
    font: 400 14px 'Klee One', 'Noto Sans JP', sans-serif;
    color: var(--color-stone);
    margin-left: 9px;
}
/* prove the reading: the kana this kanji contributes, lit to match the kanji in
   the lemma above it (時 indigo → じ indigo) so the sound↔shape link is visible.
   v2: a hand-laid sumi stitch under the kana (indigo underline) rather than a bare
   colour swap — it reads as the teacher tracing where the sound sits. */
.kjw-kana-hl {
    color: var(--rd-accent, var(--color-accent));
    background-image: linear-gradient(
        color-mix(in srgb, var(--rd-accent, var(--color-accent)) 78%, transparent),
        color-mix(in srgb, var(--rd-accent, var(--color-accent)) 78%, transparent));
    background-repeat: no-repeat;
    background-position: 0 calc(100% - 1px);
    background-size: 100% 1.6px;
    padding-bottom: 2.5px;
}
.kjw-en {
    font: 400 13px 'Inter', 'Noto Sans JP', sans-serif;
    color: var(--color-stone);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
/* the BAND WORD at a word row's right edge (polish round 1, 12 October 2026, the
   owner's pick 8): core · everyday · occasional · rare, never the raw "#9883", and
   in the word page's own dress, copied value for value from css/word-page.css
   .wp-dict-rank so the two housings print one word one way: a quiet lowercase
   word, orientation and never the thing the eye lands on. No band, no chip. */
.kjw-row .rank {
    flex: 0 0 auto;
    align-self: center;
    font: 600 10.5px 'Inter', 'Noto Sans JP', sans-serif;
    letter-spacing: 0.04em;
    color: #a49c94;
    text-align: right;
    white-space: nowrap;
    min-width: 42px;
}
/* RARE in caps: a quiet warning past the five-digit cliff (deliberate, the word
   page's own: css/word-page.css .wp-dict-rank.is-rare) */
.kjw-row .rank.is-rare {
    font-size: 10px;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: #8a827b;
}

/* "Show N more" — a considered disclosure, not orphan text in the tile gutter.
   Indented to the lemma column (row pad 5 + tile 94 + gap 18 = 117px) so it reads as
   the list continuing; a caret + plain English + the same faint warm hover the rows
   carry make it legibly pressable at rest. Caret/ink stay ghost→stone (never gold).
   MUST be scoped under both hosts (same reason as .kje-more below): the
   `.kjp-overlay button` / `.wpn-kbody button` resets are (0,1,1) and a bare
   .kjr-more (0,1,0) loses to them — it shipped as 16px ink body text. */
.kjp-overlay .kjr-more,
.wpn-kbody .kjr-more {
    appearance: none;
    background: none;
    border: 0;
    margin-left: 112px;
    padding: 9px 5px 5px;
    display: inline-flex;
    align-items: center;
    gap: 7px;
    border-radius: 6px;
    font: 500 12px 'Inter', 'Noto Sans JP', sans-serif;
    color: var(--kjp-ghost);
    cursor: pointer;
    transition: color 0.18s ease, background-color 0.18s ease;
}
.kjp-overlay .kjr-more:hover,
.wpn-kbody .kjr-more:hover { color: var(--kjp-stone); background: rgba(58, 54, 51, 0.03); }
.kjp-overlay .kjr-more:active,
.wpn-kbody .kjr-more:active { color: var(--kjp-ink); }
.kjp-overlay .kjr-more:focus-visible,
.wpn-kbody .kjr-more:focus-visible { outline: 2px solid var(--kjp-indigo); outline-offset: 2px; }
.kjr-more-caret {
    width: 12px; height: 12px; flex: 0 0 auto; display: block;
    fill: none; stroke: currentColor; stroke-width: 2.2;
    stroke-linecap: round; stroke-linejoin: round;
    transition: transform 0.18s ease;
}
/* open folds point their caret back up — the same line now offers the way closed */
.kjr-more.is-open .kjr-more-caret,
.kje-more.is-open .kjr-more-caret { transform: rotate(180deg); }
/* the revealed rows fade up rather than snapping in (wired in render(), reduced-motion-guarded) */
/* transform-only (same safe-degrade reason as kjp-reg-rise): a frozen "Show N more"
   reveal stays legible — at worst the new rows sit 4px low, never invisible. */
@keyframes kjwReveal { from { transform: translateY(4px); } to { transform: none; } }
.kjw-row--reveal { animation: kjwReveal 0.24s ease both; }

/* rarer readings rest behind one quiet line at the family's tail (K4) — same
   voice as "Show N more" but flush left (it discloses whole reading groups,
   not rows in the lemma column). The folded readings' names ride on the line
   so completeness is visible before the tap (and label the "Hide" line once open). */

/* ── watch-out (earned gold) ──────────────────────────────────────────── */

/* the watch-out dissolves to gold-marked ink on the washi — the earned gold rule
   stays, the frame/fill/shadow go (the twin tray keeps its frame: a side-by-side
   specimen genuinely earns one). Mirrors how the word page dissolved its cards. */
.kjp-watch {
    background: none;
    border: 0;
    border-left: 3px solid var(--color-gold);
    border-radius: 0;
    box-shadow: none;
    padding: 2px 0 2px 18px;
}
.kjp-watch .kjp-slabel { color: var(--color-gold); }
.kjp-watch .kjp-slabel span:not([lang]) { opacity: 1; }
/* the leading gold seal dot (demo parity) */
.kjp-watch .kjp-slabel .seal {
    align-self: center;
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--kjp-gold);
    flex: 0 0 auto;
}
.kjp-watch p { font-size: 15px; line-height: 1.7; color: #44403c; margin: 0; }

/* ── the closing colophon — one gold dot + the KanjiVG credit, a whisper ── */
.foot {
    min-height: 90px;
    padding: 8px 0 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 13px;
}
.foot .dot { width: 4px; height: 4px; border-radius: 50%; background: var(--kjp-ghost-soft); opacity: 0.6; }   /* a neutral mote — gold is reserved for the earned watch-out */
.foot .colophon {
    font: 400 9px 'Inter', 'Noto Sans JP', sans-serif;
    letter-spacing: 0.1em;
    color: var(--kjp-ghost);
    opacity: 0.7;
    text-align: center;
}

/* ── the scholar note (由来) — real etymology, behind a tap ────────────── */
/* NATIVE rework: one uninterrupted washi column. Each register is free prose
   under a readings-row-echo label, parted only by air + a single hairline — no
   coloured callout cards, no spine, no ochre ground, no ALL-CAPS eyebrows. The
   honesty signal is a ghost-ink scholar's mark (scarcity-gated); the lineage is
   a faded older form, never a ＋/→ flowchart. */
.kjp-scholar { margin-top: 22px; }
.kjp-story + .kjp-scholar { margin-top: 20px; }

/* the cue: a CENTERED ornament flanked by two short rules (the hero keyword's own
   "— year —" language), so it reads as part of the panel, never a full-width UI
   accordion bar. No top hairline; the flanking rules carry the separation. */
/* 朱筆 the vermilion margin-note (redesign 2026-06-29). A left-anchored annotation
   row on the panel's OWN running hairline, no filled shape: the maroon chip read as
   a pasted sticker (the one solid block on an ink-on-washi panel), so the red now
   lives only as ink. 由来 in cinnabar, a fine dotted vermilion baseline (the footnote
   tell), the plain words + a right-edge caret carrying the tap. Touch-first: the ink,
   the words, and the caret already invite at rest with no hover. */
.kjp-scholar-cue {
    display: flex;
    align-items: center;
    justify-content: flex-start;
    gap: 11px;
    padding: 13px 2px;
    border-top: 1px solid var(--kjp-rule);   /* the page's own running rule */
    min-height: 44px;
    cursor: pointer;
    list-style: none;
    user-select: none;
    -webkit-tap-highlight-color: transparent;
}
.kjp-scholar-cue::-webkit-details-marker { display: none; }
.kjp-scholar-cue::marker { content: ""; }
.kjp-scholar > .kjp-scholar-cue:focus-visible {
    outline: 2px solid var(--kjp-indigo);
    outline-offset: 3px;
    border-radius: 2px;
}
/* 由来 as vermilion brush-ink — the glyphs ARE the red, no box. */
.kjp-sc-mark {
    position: relative; align-self: center;
    font: 600 15.5px 'Klee One', 'Noto Sans JP', sans-serif;
    letter-spacing: 0.14em; line-height: 1;
    color: var(--kjp-seal);
    transition: color 0.2s ease, transform 0.12s ease;
}
/* the footnote tell: one fine dotted vermilion baseline under 由来 only (same hue,
   so glyph + line read as ONE mark, not two reds) */
.kjp-sc-mark::after {
    content: ""; position: absolute; left: 0; right: 0.04em; bottom: -4px; height: 0;
    border-bottom: 1px dotted color-mix(in srgb, var(--kjp-seal) 52%, transparent);
    transition: border-color 0.2s ease;
}
.kjp-sc-where { font: 400 13px 'Inter', 'Noto Sans JP', sans-serif; color: var(--kjp-stone); letter-spacing: 0.01em; }
/* lightest open affordance: a hairline caret pushed to the right edge */
.kjp-sc-turn {
    margin-left: auto; align-self: center; flex: none;
    width: 6px; height: 6px;
    border-right: 1.4px solid var(--kjp-ghost);
    border-bottom: 1.4px solid var(--kjp-ghost);
    transform: rotate(45deg) translateY(-1px);
    transition: transform 0.28s cubic-bezier(0.22,1,0.36,1), border-color 0.2s ease;
}
.kjp-scholar[open] > .kjp-scholar-cue .kjp-sc-turn { transform: rotate(-135deg) translateY(1px); }
.kjp-scholar-cue:active .kjp-sc-mark { transform: translateY(0.5px); }
/* hover = additive only (desktop); touch already fully invites */
@media (hover: hover) {
    .kjp-scholar-cue:hover .kjp-sc-mark { color: var(--kjp-seal-deep); }
    .kjp-scholar-cue:hover .kjp-sc-mark::after { border-bottom-color: color-mix(in srgb, var(--kjp-seal-deep) 70%, transparent); }
    .kjp-scholar-cue:hover .kjp-sc-turn { border-color: var(--kjp-stone); }
}

/* the opened note is an aged-washi LEAF laid into the sheet: a hair warmer/lighter
   paper with a soft inset top-shadow (paper lifting off), so it reads as a special
   page, not a coloured callout box. No border ring. */
.kjp-scholar-body {
    margin-top: 4px;
    padding: 16px 20px 10px;
    background: color-mix(in srgb, var(--kjp-paper) 72%, var(--kjp-sheet));
    border-radius: 3px;
    box-shadow:
        inset 0 1px 0 rgba(255, 255, 255, 0.5),
        inset 0 18px 26px -24px rgba(58, 40, 20, 0.20);
}

/* a register: free prose on the leaf. The two are parted by a brushed sumi rule. */
.kjp-reg { position: relative; margin: 0; }
.kjp-reg + .kjp-reg { margin-top: 24px; padding-top: 22px; }
/* the brushed divider — a tapered sumi stroke, not a flat hairline */
.kjp-reg + .kjp-reg::before {
    content: ""; position: absolute; top: 0; left: 50%; transform: translateX(-50%);
    width: 88px; height: 2px; border-radius: 2px;
    background: linear-gradient(90deg, transparent,
        color-mix(in srgb, var(--kjp-ink) 32%, transparent) 24%,
        color-mix(in srgb, var(--kjp-ink) 48%, transparent) 50%,
        color-mix(in srgb, var(--kjp-ink) 32%, transparent) 76%, transparent);
}
.kjp-reg-label {
    display: flex; align-items: baseline; gap: 7px;
    margin: 0 0 12px; font-weight: 400;
}
.kjp-reg-label .jp {
    position: relative;
    font: 600 14.5px 'Klee One', 'Noto Sans JP', sans-serif; color: var(--kjp-ink); line-height: 1; letter-spacing: 0.03em;
}
/* a faint brush-tapered underline gives the JP headword ink character */
.kjp-reg-label .jp::after {
    content: ""; position: absolute; left: 1px; right: -2px; bottom: -5px; height: 1.5px;
    background: linear-gradient(90deg,
        color-mix(in srgb, var(--kjp-ink) 44%, transparent),
        color-mix(in srgb, var(--kjp-ink) 14%, transparent) 70%, transparent);
}
.kjp-reg-label .rom { font: 400 11.5px 'Inter', sans-serif; color: var(--kjp-stone); }
.kjp-reg-label .sep { color: var(--kjp-ghost-soft); }
.kjp-reg-label .en { font: 400 12px 'Inter', 'Noto Sans JP', sans-serif; color: var(--kjp-stone); }

/* a story BEAT's evocative header (story-wave corpus, 2026-08-05): quiet ink,
   the same measure as the register labels, no underline flourish — the words
   themselves are the hook ("A recipe you can still read"). */
.kjp-beat-head {
    margin: 0 0 8px;
    font: 600 13px/1.4 'Inter', 'Noto Sans JP', sans-serif;
    color: var(--kjp-ink); letter-spacing: 0.02em;
}

/* the reading measure (~62ch), generous leading to absorb the taller inline JP. */
.kjp-reg-prose {
    font: 400 14.5px/1.78 'Inter', 'Noto Sans JP', sans-serif;
    color: var(--kjp-prose);
    margin: 0; max-width: min(100%, 62ch);
    text-wrap: pretty; hyphens: none; -webkit-hyphens: none;
    hanging-punctuation: first last;
    font-feature-settings: "liga" 1, "calt" 1, "onum" 1;
}
.kjp-reg-prose .wp-jp {
    font-family: 'Klee One', 'Noto Sans JP', sans-serif;
    font-weight: 500; color: var(--kjp-ink);
    font-size: 1.04em; letter-spacing: 0.015em;
}

/* the honesty mark — ghost-ink, scarcity-gated, no bordered badge. */
.kjp-cert {
    margin: 13px 0 0;
    font: 400 12.5px/1.6 'Inter', sans-serif; color: var(--kjp-stone);
    display: flex; align-items: baseline; gap: 8px; text-wrap: balance;
}
.kjp-cert .mark { flex: none; color: var(--kjp-ghost); }
.kjp-cert .mark .jp { font-family: 'Klee One', 'Noto Sans JP', sans-serif; }
.kjp-cert .mark .rom { font-size: 11px; }
.kjp-cert .t { font-style: italic; }

/* the ancient-form IMPRESSION — the real older glyph stands large + very faint in
   the journey's right margin, captioned. Says "old and deep" AND teaches; sumi
   ink only, no colour cost. Rendered only where a single older form exists
   (JS gates on strip.from.length === 1); the journey reserves a right gutter. */
.kjp-reg--impressed .kjp-reg-prose { padding-right: 118px; }
.kjp-impression {
    position: absolute; top: 26px; right: -2px; width: 108px;
    display: flex; flex-direction: column; align-items: center; text-align: center; gap: 9px;
    pointer-events: none;
}
.kjp-impression .g {
    font-family: 'Klee One', 'Noto Sans JP', sans-serif;
    font-size: 96px; line-height: 0.88; color: var(--kjp-ink); opacity: 0.07;
}
.kjp-impression .cap { font: 400 11px 'Inter', 'Noto Sans JP', sans-serif; color: var(--kjp-stone); line-height: 1.4; }
.kjp-impression .cap .og { font-family: 'Klee One', 'Noto Sans JP', sans-serif; color: var(--kjp-prose); font-size: 13px; }

/* the open gesture — one quiet upward rise. */
@media (prefers-reduced-motion: no-preference) {
    .kjp-scholar[open] .kjp-reg--journey .kjp-reg-prose  { animation: kjp-reg-rise 0.4s cubic-bezier(0.16,1,0.3,1) both; }
    .kjp-scholar[open] .kjp-reg--journey .kjp-impression { animation: kjp-reg-rise 0.5s cubic-bezier(0.16,1,0.3,1) 0.08s both; }
    .kjp-scholar[open] .kjp-reg--journey .kjp-cert       { animation: kjp-reg-rise 0.4s cubic-bezier(0.16,1,0.3,1) 0.12s both; }
    .kjp-scholar[open] .kjp-reg--world                   { animation: kjp-reg-rise 0.4s cubic-bezier(0.16,1,0.3,1) 0.14s both; }
}
/* TRANSFORM-ONLY rise (no opacity fade) so the note is legible EVEN IF the animation
   never completes: the battery-saver (html.app-backgrounded *{animation-play-state:
   paused}) freezes animations, and with an opacity keyframe + `both` fill a tab
   backgrounded mid-open used to hold the `from` state (opacity:0) — the scholar
   note's first half rendered invisible and didn't recover on return. Animating only
   the transform means a frozen reveal is at worst 6px low, always readable. */
@keyframes kjp-reg-rise {
    from { transform: translateY(6px); }
    to { transform: translateY(0); }
}
@media (pointer: coarse) { .kjp-scholar-cue { min-height: 44px; } }
@media (max-width: 560px) {
    .kjp-reg--impressed .kjp-reg-prose { padding-right: 0; }
    .kjp-impression { display: none; }
}
@media (max-width: 440px) { .kjp-reg-prose { max-width: none; } }

/* ── look-alikes (似ている字) — the TWIN SEAT (S4, 2026-09-06) ─────────── */
/* The course's one component for a pair, in this page's tokens: two glyphs
   side by side — this character LEFT in the brush's own brown, the twin RIGHT
   in sumi and a silent door (ink to indigo on hover, nothing at rest) — under
   each its one-word name, under the name the differing part as a small mark
   with its plain name. One shared clause in the quiet ink, then two per-side
   lines, each opening with its glyph in that glyph's ink. No seam, no wash, no
   arrow, no captions: position and ink say which is which. */
.kjt-head { margin: 0 0 2px; }
.kjt-pair {
    display: flex;
    justify-content: center;
    gap: clamp(28px, 7vw, 56px);
    margin: 6px 0 0;
}
.kjt-side {
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    gap: 4px;
    min-width: 7em;
    padding: 12px 6px 8px;
    background: none;
    border: 0;
    font-family: inherit;
    color: inherit;
}
.kjt-g {
    font: 400 clamp(50px, 11vw, 68px)/1 'Klee One', 'Noto Sans JP', serif;
    color: var(--kjp-ink);
    transition: color 0.18s ease;
}
.kjt-side--here .kjt-g { color: var(--color-jp-text, #523E1E); }
.kjt-kw { margin-top: 7px; font: 600 13px 'Inter', 'Noto Sans JP', sans-serif; color: var(--kjp-ink); max-width: 11em; }
.kjt-part {
    display: inline-flex;
    align-items: baseline;
    justify-content: center;
    gap: 5px;
    max-width: 12em;
    font: 400 11.5px 'Inter', 'Noto Sans JP', sans-serif;
    color: var(--kjp-stone);
    line-height: 1.4;
}
.kjt-part-g { font: 400 18px/1 'Klee One', 'Noto Sans JP', serif; color: var(--color-jp-text, #523E1E); }
/* the twin is a silent door: nothing at rest, the glyph to indigo under the pointer */
.kjt-side--twin { cursor: pointer; border-radius: 8px; }
.kjt-side--twin:hover .kjt-g,
.kjt-side--twin:focus-visible .kjt-g { color: var(--kjp-indigo); }
.kjt-side--twin:active .kjt-g { color: var(--kjp-ink-wet); }
.kjt-note {
    font-size: 14px;
    line-height: 1.7;
    color: var(--kjp-stone);
    margin: 14px 0 0;
    max-width: min(100%, 62ch);
}
.kjt-line {
    font-size: 14px;
    line-height: 1.7;
    color: var(--kjp-prose);
    margin: 8px 0 0;
    max-width: min(100%, 62ch);
}
.kjt-line-g { font: 400 19px/1 'Klee One', 'Noto Sans JP', serif; color: var(--kjp-ink); margin-right: 0.35em; }
.kjt-line-g--here { color: var(--color-jp-text, #523E1E); }

/* (the .kjc-chip pill kit is retired — the hero entry is the word page's
   落款 rakkan marks in word-page.css; paper stickers never reached the art) */

/* ── gallery seam glyph → kanji page affordance ───────────────────────── */

button.grid-seam-kanji {
    appearance: none;
    background: none;
    border: 0;
    padding: 0;
    cursor: pointer;
    transition: color 0.18s ease;
}
button.grid-seam-kanji:hover { color: var(--color-accent); }

/* ── focus + reduced motion + small screens ───────────────────────────── */

.kjp-back:focus-visible,
.kjw-row:focus-visible,
.kjr-more:focus-visible,
.kjt-side--twin:focus-visible,
button.kjp-part--door:focus-visible,
button.grid-seam-kanji:focus-visible {
    outline: 2px solid var(--color-accent);
    outline-offset: 2px;
}

@media (max-width: 768px) {
    /* full-bleed page on small screens — no side gutters, hairlines or float shadow */
    .kjp-sheet { width: 100%; border-left: 0; border-right: 0; box-shadow: none; }
    .kjp-body { padding: 0 16px 56px; }
    .kjp-band { height: 170px; margin: 0 -16px; }
    .kjp-band .kjp-glyph, .kjp-inkhead .kjp-glyph { font-size: 88px; }
    /* the versus tray stays side-by-side on mobile — comparing the two shapes is the point */
    .kjp-overlay .kjp-back { width: 44px; height: 44px; }   /* the primary exit clears the 44px touch min */
}

/* narrow phones: tighten the rows + drop the rank column (demo parity) */
@media (max-width: 560px) {
    .kjw-row { gap: 11px; }
    .kjw-tile { width: 62px; height: 41px; }
    .kjw-jp { font-size: 20px; }
    .kjw-row .rank { display: none; }
    .kjr-head .kjr-sub { display: none; }    /* no rank rail for rows to echo → drop the head count */
    .kjr-more { margin-left: 73px; }         /* re-align to the shrunk lemma column (5+62+11) */
}

@media (prefers-reduced-motion: reduce) {
    /* a scoped blanket reset — the old enumerated allow-list had drifted (the glyph
       cross-fade, image fades, glance pills, reveal + the smooth-scroll still moved).
       Neutralize everything inside the overlay; the JS smooth-scroll is guarded too. */
    .kjp-overlay *, .kjp-overlay *::before, .kjp-overlay *::after {
        transition-duration: 0.01ms !important;
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        scroll-behavior: auto !important;
    }
    .kjp-sheet { transform: none; }
    button.grid-seam-kanji { transition: none; }
}

/* ── TYPE signal — what KIND of kanji + what to DO (owner: the valuable part) ──
   A calm centred line at the head of the shape scene: a quiet mark, the plain
   bucket name, the 六書 term whispered, then a plain-English action line. The
   mark vocabulary is always paired with its word, never decoded alone. */
.kjp-type {
    display: flex; flex-wrap: wrap; align-items: baseline; justify-content: center;
    column-gap: 8px; row-gap: 2px; margin: 0 0 16px;
}
/* the boxy mark is retired — the name carries the type signal now (de-badge) */
.kjp-tmark { display: none; }
.kjp-type--picture .kjp-tmark { border: 1.5px solid var(--kjp-indigo);
    background: color-mix(in srgb, var(--kjp-indigo) 42%, transparent); }
.kjp-type--combine .kjp-tmark::before { content: "+"; position: absolute; inset: -2px 0 0;
    display: flex; align-items: center; justify-content: center; font: 700 16px var(--kjp-ui); color: var(--kjp-indigo); }
.kjp-type--sound .kjp-tmark { border: 1.5px solid var(--kjp-indigo);
    background: linear-gradient(90deg, color-mix(in srgb, var(--kjp-indigo) 50%, transparent) 0 50%, transparent 50%); }
.kjp-type--fused .kjp-tmark { border: 1.5px dashed var(--kjp-ghost);
    background: color-mix(in srgb, var(--kjp-ghost) 20%, transparent); }
/* ("Nothing to take apart" — the line that stood where a parts row would be on
   a picture or a sign — retired 2026-08-03 with the scattered type deliveries.
   The TYPE TAG answers that question for all six buckets now, not three.) */
/* The 六書 romaji, riding the eyebrow's JP term (2026-08-01). A beginner meets
   象形 with no way to read it; the house rule is that every Japanese token a
   learner sees carries romaji. It sits QUIETER than the term it glosses and
   drops the eyebrow's uppercase tracking — it is a pronunciation, not a label. */
.kjp-hero .wp-eyebrow .pr,
.wp-eyebrow .pr {
  margin-left: -4px;
  font-family: 'Inter', system-ui, sans-serif;
  font-size: 10.5px;
  font-weight: 400;
  letter-spacing: 0.04em;
  text-transform: none;
  color: var(--inkdim);
  opacity: 0.72;
}
/* the English bucket name LEADS the eyebrow — for a beginner 象形/会意 is unreadable
   jargon, so the plain word is the lesson (the reading eyebrow leads with 訓読み because
   THERE the JP term is the lesson; kinship is shared voice, not identical lead-order). */
.kjp-tname { font: 600 14px var(--kjp-ui); color: var(--kjp-ink); letter-spacing: 0.01em; }
.kjp-type--fused .kjp-tname { color: #7a6a52; }
/* the 六書 term is a quiet Klee companion, not a basement whisper */
.kjp-tjp { font: 400 12.5px var(--kjp-jp); color: var(--kjp-stone); opacity: 0.85; letter-spacing: 0.04em; }
/* the action is the standfirst/deck — colour-matched to .kjr-eb-note so the type
   eyebrow and the reading eyebrows share one note voice */
.kjp-tact { flex-basis: 100%; text-align: center; font: 400 12px var(--kjp-ui);
    color: var(--color-stone); line-height: 1.5; margin-top: 3px; }

/* the two role badges wear the app's two locked inks (owner contract B,
   2026-08-03): 音 sound in the on'yomi terracotta the reading rows paint
   readings with — amber IS sound, app-wide — and 意 meaning in the teaching
   indigo the app spends on meaning. Chip and badge tell one story, so the
   eye reads "this side means, that side only sounds" from the colour alone. */
.kjp-snd { font: 700 9px var(--kjp-ui); letter-spacing: 0.08em; text-transform: uppercase;
    color: var(--color-kanji-on, #9E5E43); background: rgba(158, 94, 67, 0.08); border-radius: 4px;
    padding: 2px 5px; margin-left: 1px; }
.parts .door.kjp-part--sound { border-color: rgba(158, 94, 67, 0.28); }
.kjp-mng { font: 700 9px var(--kjp-ui); letter-spacing: 0.08em; text-transform: uppercase;
    color: var(--kjp-indigo); background: rgba(61, 90, 128, 0.08); border-radius: 4px;
    padding: 2px 5px; margin-left: 1px; }
.parts .door.kjp-part--meaning { border-color: rgba(61, 90, 128, 0.24); }

/* the quiet line that frames the meaning/sound pills now that the 形声 header is
   gone — a beginner reads what the two pills mean before scanning the chips. The
   two words tint to echo their pills: meaning = sumi, sound = the indigo accent. */
.kjp-parts-cap {
    text-align: center; margin: 0 0 14px;
    font: 400 12.5px var(--kjp-ui); color: var(--kjp-stone); letter-spacing: 0.01em;
}
.kjp-parts-cap b { font-weight: 600; }
.kjp-parts-cap .kjp-cap-m { color: var(--kjp-ink); }
.kjp-parts-cap .kjp-cap-s { color: var(--kjp-indigo); }

/* a fused part is a worn-down leftover, not a meaning piece: dashed + faded, no door */
.parts .door.kjp-part--ghost { border-style: dashed; border-color: rgba(64, 53, 40, 0.26); }
.parts .door.kjp-part--ghost .g,
.parts .door.kjp-part--ghost .n { color: var(--kjp-ghost); }

/* the sum token: two meanings visibly add up to the kanji (日 + 月 → 明) */
.kjp-plus { font: 600 17px var(--kjp-jp); color: var(--kjp-ghost-soft); }
.kjp-eq { font: 400 15px var(--kjp-ui); color: var(--kjp-ghost); }
.kjp-sum-k { font-family: var(--kjp-jp); font-size: 30px; color: var(--kjp-ink); line-height: 1; }

/* a reading's un-activated example: a real word with no card yet, rendered as a
   TEXT FRAME — reading + gloss + rank, no thumbnail slot (K4: the reserved grey
   plate read as a broken image; the word page's meet-later frames are the
   precedent). Flush left, quieter ink — a lighter entry in the same list. */
.kjw-row--nocard { cursor: default; }
/* rendaku note on a まるごと top-up row (voiced from とけい) — a quiet third line
   under the gloss, same register as the kun/on voiced note. */
.kjw-voiced {
    display: block;
    margin-top: 1px;
    font: 400 11px 'Inter', 'Noto Sans JP', sans-serif;
    color: #8a847b;
}
.kjw-voiced [lang="ja"] {
    font-family: 'Klee One', 'Noto Sans JP', sans-serif;
    font-size: 1.1em;
    color: var(--color-stone);
}
.kjw-row--nocard:hover { background: none; padding-left: 5px; }
.kjw-row--nocard .kjw-jp { font-weight: 500; color: var(--kjp-prose); }

/* the homograph note — one quiet line under the gloss on a same-spelling twin
   (何時 なんどき names なんじ as the usual reading). The word page's 同 "written
   the same" lesson, inlined; kana in Klee, romaji italic (romaji-only rule). */
.kjw-note {
    display: block;
    margin-top: 2px;
    font: 400 12px 'Inter', 'Noto Sans JP', sans-serif;
    color: #8a847b;
}
.kjw-note b[lang="ja"] {
    font-family: 'Klee One', 'Noto Sans JP', sans-serif;
    font-weight: 500;
    font-size: 1.15em;
    color: var(--color-stone);
}
.kjw-note i { font-style: italic; }
/* no painting yet → a PRIMED PLATE (owner pick C): the frame is reserved and washed
   faint warm in the room's pigment, reading as a blank canvas waiting for its painting
   (the word just isn't activated yet) — never a broken/loading box, never an empty void.
   Same soft frame + top-left sheen as a real tile; grain off so the plate stays clean.
   (Owner 2026-06-29: kept as the no-painting frame for word rows AND kanji-family rows —
   a reserved frame reads as "a picture goes here", more useful than empty space.) */
.kjw-tile--empty {
    background: color-mix(in srgb, var(--kjp-tone, #b0a090) 13%, var(--kjp-paper));
    /* inset hairline only — no outer drop shadow: a primed plate is a recess pressed
       INTO the washi, not a floating card. */
    box-shadow: inset 0 0 0 1px rgba(120, 90, 60, 0.10);
}
.kjw-tile--empty::after { display: none; }   /* grain off — the sheen (::before) stays */
/* (.rank.is-nocard removed 2026-06-27 — dead: no JS ever emitted it; bandChip
   emits .rank and .rank.is-rare only.) */

/* readings at a glance — the helicopter view of all readings, under the keyword */
.kjp-glance { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: center;
    column-gap: 18px; row-gap: 8px; margin-top: 11px; }   /* wider gap separates kun vs on families */
/* the group is now just a colour-scoped container (no 訓/音 label, no tap); each reading
   inside is its own tap button. kun = indigo, on = terracotta — the colour carries the
   kun/on distinction the labels used to. */
.kjg-grp { display: inline-flex; align-items: baseline; gap: 6px; --rd-accent: var(--color-accent); }
.kjg-grp--on { --rd-accent: #9E5E43; }
/* each reading is its own tap target → jumps to that reading's word list */
.kjg-pair { display: inline-flex; align-items: baseline; gap: 4px;
    appearance: none; border: 0; background: none; font: inherit; color: inherit;
    cursor: pointer; padding: 4px 6px; margin: -4px 0; border-radius: 7px;
    transition: background-color 0.18s ease; }
.kjg-pair.kjg-tap:hover { background: rgba(58, 54, 51, 0.05); }
.kjg-pair.kjg-tap:active { background: rgba(58, 54, 51, 0.08); }
.kjg-pair:focus-visible { outline: 2px solid var(--kjp-indigo); outline-offset: 2px; }
.kjg-r { font: 400 16px var(--kjp-jp); color: var(--rd-accent, var(--kjp-ink)); }
/* (no under-rule on the glance readings — owner: the per-reading colour + the hover
   wash carry the tappable tell; the underline read as clutter.) */
.kjg-ro { font: 400 11px var(--kjp-ui); color: #6b6358; letter-spacing: 0.02em; }
.kjg-dot { color: var(--kjp-ghost-soft); }
/* (.kjg-gap divider removed — kun/on now separate by colour + the wider column-gap, so
   nothing orphans when the glance line wraps.) */

/* ════════════════════════════════════════════════════════════════════════════
   声符 SOUND FAMILY — kanji that share this kanji's phonetic component, grouped
   by reading. Opened by tapping the SOUND pill in the shape story; rows reuse the
   reading-list .kjw-* look. Indigo = the selection/eyebrow accent, terracotta
   (#9E5E43, the on'yomi colour) = readings, NO gold. Design locked 2026-06-28.
   ════════════════════════════════════════════════════════════════════════════ */
/* Tier-2: the SOUND pill is a DOOR into the sound family room. Its cue is a static
   forward chevron ("step in"), echoing the component-door go-arrow. */
.kjp-snd.kjsf-pill { display: inline-flex; align-items: baseline; gap: 3px; }
.kjp-snd.kjsf-pill::after {
    content: '\203A'; font-weight: 700; font-size: 10px; color: var(--kjp-ghost);
}
/* the sound chip, now a family door, gets a quiet indigo ring on hover (scoped past
   the overlay button-reset so it is not zeroed) */
.kjp-overlay .kjp-part--sound.kjsf-door:hover,
.wpn-kbody .kjp-part--sound.kjsf-door:hover {
    box-shadow: inset 0 0 0 1px rgba(61, 90, 128, 0.5);
}

/* ══════════════════════════════════════════════════════════════════════════════
   THE FAMILY ROOM (Tier-2 view-swap) — the panel body becomes one focused family,
   entered from a story pill and left by the sheet's back chevron. A compact header
   anchors WHOSE family this is (時 › 寺) so the reader keeps the thread; the family's
   own eyebrow + note + roster render below (the .kjsf / .kjmf inner, reused verbatim).
   ══════════════════════════════════════════════════════════════════════════════ */
.kjfam-room { animation: kjfamRoomIn 0.28s cubic-bezier(0.16, 1, 0.3, 1); }
@keyframes kjfamRoomIn { from { transform: translateY(5px); } to { transform: none; } }
@media (prefers-reduced-motion: reduce) { .kjfam-room { animation: none; } }
.kjfam-head {
    display: flex; align-items: center; gap: 9px;
    padding: 2px 0 14px; margin-bottom: 4px;
    border-bottom: 1px solid var(--kjp-rule);
}
.kjfam-glyph {
    font-family: var(--kjp-jp); font-size: 30px; line-height: 1; color: var(--kjp-ink);
}
.kjfam-arrow { font: 400 16px var(--kjp-ui); color: var(--kjp-ghost-soft); }
/* the shared piece, tinted by family: terracotta = the sound key, indigo = meaning */
.kjfam-piece { font-family: var(--kjp-jp); font-size: 26px; line-height: 1; }
.kjfam-room--sound   .kjfam-piece { color: #9E5E43; }
.kjfam-room--meaning .kjfam-piece { color: var(--kjp-indigo); }

/* the sound family renders inside the family room (familyRoomHTML); no standalone
   section margin or hidden state any more (it is summoned, never resting in the spine) */
.kjsf { margin-top: 0; }
.kjsf[hidden] { display: none; }
/* NEVER overflow:hidden here — it clips the picture-less rows and eats the rank chip */
.kjsf-inner { padding-top: 4px; }

/* the eyebrow names the sound piece (the 寺 family) as a door to its own page */
.kjsf-eb {
    /* shares the reading section's teaching-title spec (.kjr-eyebrow): same colour
       #78716c + 0.12em tracking, so 訓読み / 音読み / 声符 / なかま read as one family
       of section titles instead of four slightly-different eyebrows. */
    font: 600 11px var(--kjp-ui); letter-spacing: 0.12em; text-transform: uppercase;
    color: #78716c; margin-bottom: 10px;
    display: flex; align-items: baseline; gap: 7px; flex-wrap: wrap;
}
.kjsf-eb .jp {
    font-family: 'Klee One', 'Noto Sans JP', sans-serif; font-size: 15px;
    letter-spacing: 0; color: var(--kjp-ink); text-transform: none;
}
.kjsf-ebpiece {
    font-family: 'Klee One', 'Noto Sans JP', sans-serif; font-size: 16px;
    color: var(--kjp-ink); text-transform: none; letter-spacing: 0;
}
/* the eyebrow piece is a button → re-assert past the overlay reset. Underlined in the
   sound family's own colour (terracotta = the on'yomi/sound side), so the 声符 eyebrow
   reads as the SOUND room and the 意符 eyebrow (indigo) as the MEANING room. */
.kjp-overlay button.kjsf-ebpiece,
.wpn-kbody button.kjsf-ebpiece {
    cursor: pointer; text-decoration: underline;
    text-decoration-color: rgba(158, 94, 67, 0.40); text-underline-offset: 3px;
}
.kjp-overlay button.kjsf-ebpiece:hover,
.wpn-kbody button.kjsf-ebpiece:hover { text-decoration-color: #9E5E43; }
.kjp-overlay button.kjsf-ebpiece:focus-visible,
.wpn-kbody button.kjsf-ebpiece:focus-visible { outline: 2px solid #9E5E43; outline-offset: 2px; border-radius: 3px; }

/* the honesty heads-up (look-alike / worn-down / hidden marker) */
.kjsf-honest { margin: 10px 0 0; font: 400 12.5px/1.6 var(--kjp-ui); color: var(--kjp-stone); }
.kjsf-honest .wp-jp { font-family: 'Klee One', 'Noto Sans JP', sans-serif; color: var(--kjp-prose); }

/* reading groups — each echoes the panel's reading groups: a terracotta on'yomi
   header + romaji, with one full-width hairline under it (NOT a line per row) */
.kjsf-grp { margin-top: var(--kjw-grp-gap); }   /* shared group rhythm (was 10px; owner consistency 2026-06-29) */
.kjsf-ghead {
    display: flex; align-items: baseline; gap: 9px; margin: 0 0 4px; padding: 0 2px 9px;
    border-bottom: 1px solid var(--kjp-rule);
}
.kjsf-ghead .rd { font: 400 19px 'Klee One', 'Noto Sans JP', sans-serif; color: #9E5E43; }
.kjsf-ghead .ro { font: 400 12px var(--kjp-ui); color: var(--kjp-stone); }
.kjsf-ghead .cnt { font: 400 11px var(--kjp-ui); color: var(--kjp-ghost); margin-left: auto; }
.kjsf-foot { margin: 16px 0 0; font: 400 12.5px/1.5 var(--kjp-ui); font-style: italic; color: var(--kjp-stone); }

/* ── ONE shared kanji-family member row (声符 sound family + 意符 meaning family) ──
   The panel's word-row look, tuned for a single glyph: a painting placard (the
   kanji's story image, or a primed-plate frame when it has none) · glyph · reading ·
   meaning (no rank chip since 12 October 2026: a member's number was its KANJI
   rank, and a kanji rank has no band). Both families share this one row grammar so
   a learner meets it once; the only structural delta is the SEPARATION — the sound family leans on its
   reading-group hairline (no per-row border), the meaning family is a flat list
   (a faint per-row rule). The reading chip (.kjw-rd) + the current-kanji wash
   (.kjw-here) were byte-identical kjsf- / kjmf- twins — collapsed here.
   ⛔ THE SPACES IN THAT LAST LINE ARE LOAD-BEARING. It was written with a
   glob-then-slash between the two prefixes,
   and the `*` + `/` in the middle of that shorthand CLOSED THIS COMMENT — so
   the rest of the sentence stood as raw CSS and the browser discarded tokens
   through the next block, eating `.kjw-row--kanji`'s own layout rule beneath.
   Found 2026-08-10 by tests/css/stylesheet_integrity_test.js on its first run;
   nothing else in the repo could see it, because every other CSS law reads
   this file as text. Never write a glob with a slash after it in a comment. */
.kjw-row--kanji {
    align-items: center; overflow: visible;
    width: 100%; box-sizing: border-box; border-bottom: none;
}
.kjw-row--kanji .kjw-jp { font-size: 26px; line-height: 1.2; }
.kjw-row--kanji .kjw-main { gap: 2px; }
.kjw-gl-row { display: flex; align-items: baseline; gap: 9px; flex-wrap: wrap; }
/* the member's reading: on'yomi romaji beside the glyph, in the on'yomi terracotta —
   colour carries the reading type, shared by both families. */
.kjw-rd { font: 400 13px var(--kjp-ui); color: #9E5E43; letter-spacing: 0.01em; }
/* (the family rows' 4-digit rank chip left with the raw ranks, 12 October 2026) */
/* a "meet later" member (not in the app yet) rests a hair quieter */
.kjsf .kjw-row--nocard, .kjmf .kjw-row--nocard { opacity: 0.92; }
/* the current kanji, marked silently: a soft WARM rest-wash, fully rounded, no bar
   (owner 2026-06-29). The [data-here] selector also catches the meet-later DIV rows,
   which carried the attribute but had no matching CSS — so the current kanji could
   render unmarked on a picture-less row. */
.kjw-row--kanji.kjw-here,
.kjw-row--kanji.kjw-here:hover,
.kjw-row--kanji[data-here] {
    background: color-mix(in srgb, var(--kjp-tone, #b0a090) 16%, transparent);
    border-radius: 10px;
}
/* sound family: rows sit under the group's reading hairline — no per-row border */
.kjsf .kjw-row--kanji { border-top: none; }

/* ════════════════════════════════════════════════════════════════════════════
   意符 MEANING FAMILY (なかま nakama) — kanji that share this kanji's MEANING
   piece, a flat neighbourhood. The DELIBERATELY weaker sibling of the sound
   family: indigo accent (the calm meaning-side colour, echoing the kun reading)
   and NO terracotta reading headers — that flat shape is the honest signal it is
   a different kind of tool. Opened by tapping the MEANING pill.
   ════════════════════════════════════════════════════════════════════════════ */
/* the MEANING pill is a DOOR into the meaning family room: a static forward chevron
   ("step in"), matching the SOUND pill so both families open the same way. */
.kjp-mng.kjmf-pill { display: inline-flex; align-items: baseline; gap: 3px; }
.kjp-mng.kjmf-pill::after {
    content: '\203A'; font-weight: 700; font-size: 10px; color: var(--kjp-ghost);
}
/* the meaning chip, now a family door, gets a quiet indigo ring on hover (scoped
   past the overlay button-reset so it is not zeroed) */
.kjp-overlay .kjp-part--meaning.kjmf-door:hover,
.wpn-kbody .kjp-part--meaning.kjmf-door:hover {
    box-shadow: inset 0 0 0 1px rgba(61, 90, 128, 0.45);
}

/* the family, revealed below the sound family */
.kjmf { margin-top: 0; }
.kjmf[hidden] { display: none; }
.kjmf-inner { padding-top: 4px; }   /* never overflow:hidden — it clips rank chips */

/* the eyebrow: なかま nakama · the 日 family, with the plain-English concept */
.kjmf-eb {
    /* same shared teaching-title spec as .kjsf-eb / .kjr-eyebrow */
    font: 600 11px var(--kjp-ui); letter-spacing: 0.12em; text-transform: uppercase;
    color: #78716c; margin-bottom: 4px;
    display: flex; align-items: baseline; gap: 7px; flex-wrap: wrap;
}
.kjmf-eb .jp {
    font-family: 'Klee One', 'Noto Sans JP', sans-serif; font-size: 15px;
    letter-spacing: 0; color: var(--kjp-ink); text-transform: none;
}
.kjmf-ebpiece {
    font-family: 'Klee One', 'Noto Sans JP', sans-serif; font-size: 16px;
    color: var(--kjp-ink); text-transform: none; letter-spacing: 0;
}
.kjmf-concept {
    text-transform: none; letter-spacing: 0; font-weight: 400; font-style: italic;
    color: var(--kjp-indigo); margin-left: 2px;   /* the meaning-side accent (kun colour) */
}
/* the eyebrow piece is a button → re-assert past the overlay reset */
.kjp-overlay button.kjmf-ebpiece,
.wpn-kbody button.kjmf-ebpiece {
    cursor: pointer; text-decoration: underline;
    text-decoration-color: rgba(61, 90, 128, 0.35); text-underline-offset: 3px;
}
.kjp-overlay button.kjmf-ebpiece:hover,
.wpn-kbody button.kjmf-ebpiece:hover { text-decoration-color: var(--kjp-indigo); }
.kjp-overlay button.kjmf-ebpiece:focus-visible,
.wpn-kbody button.kjmf-ebpiece:focus-visible { outline: 2px solid var(--kjp-indigo); outline-offset: 2px; border-radius: 3px; }

/* the honest asymmetry line (and the "looks like the moon" heads-up) */
.kjmf-honest { margin: 10px 0 0; font: 400 12.5px/1.6 var(--kjp-ui); color: var(--kjp-stone); }
.kjmf-honest .wp-jp { font-family: 'Klee One', 'Noto Sans JP', sans-serif; color: var(--kjp-prose); }
/* the nikuzuki / funazuki note earns a faint indigo left-rail — a real heads-up */
.kjmf-lookalike {
    padding: 8px 0 8px 12px; margin-top: 12px;
    box-shadow: inset 2px 0 0 rgba(61, 90, 128, 0.30);
}

/* ── 意符 MEANING family PERSONA (owner 2026-06-29: the two families read identical;
   give each its own honest voice). The sound family predicts a reading (terracotta,
   grouped). The meaning family only gathers a topic, so it leads with the MEANING and
   makes NO reading claim. Two subtractive moves carry it:
   1. DROP the per-row hairline — it was the real cause of the "tighter than the others"
      feeling (a dense ledger). The flat run now breathes on the same row pitch as the
      sound family's grouped rows; nothing fences every neighbour.
   2. The English gloss LEADS (inked, a touch larger/heavier) and the per-row reading
      falls to a neutral grey whisper — never terracotta, because terracotta means
      "a reading you can predict" and this family predicts none. The visible grey
      variety (ji / sei / sho ...) is itself the honest proof the meaning piece does
      not fix the reading. */
.kjmf .kjw-row--kanji { border-top: none; }
.kjmf .kjw-en { color: var(--kjp-prose); font-size: 13.5px; font-weight: 500; }
.kjmf .kjw-rd { color: var(--kjp-ghost); font-size: 11.5px; }
/* a faded member: a quiet uppercase tag by the glyph + its one-line truth note
   under the gloss. The kanji is a real member; only the meaning LINK is faded, so
   the row stays fully legible — the tag and note do the honest work. */
.kjmf-tag {
    font: 700 9px var(--kjp-ui); letter-spacing: 0.08em; text-transform: uppercase;
    color: var(--kjp-stone); background: rgba(64, 53, 40, 0.07);
    border-radius: 4px; padding: 2px 5px; align-self: center;
}
.kjmf-note {
    display: block; margin-top: 2px;
    font: 400 11.5px/1.5 var(--kjp-ui); font-style: italic; color: var(--kjp-stone);
}
/* (the current-kanji wash + the reading chip are now the shared .kjw-here /
   .kjw-rd rules in the sound-family block above — kjmf-here / kjmf-rd were
   byte-identical twins, collapsed.) */

/* =============================================================================
   FULL-PAGE FRAME (revision #2) — the kanji page IS the word page, kanji content
   -----------------------------------------------------------------------------
   The root carries BOTH .wp-root (the word-page frame from css/word-page.css:
   the fixed scroller, the pinned .wp-stage hero, the rising .wp-sheet catalog
   and its cue↔running-head lip) AND .kjp-overlay (so every kanji-content rule
   scoped `.kjp-overlay …` plus the CSS-var block keep matching). These few rules
   reconcile the two frames and dress the kanji hero variant. The former drawer
   rules (.kjp-scrim / .kjp-sheet / .kjp-bar / .kjp-back) are now inert — no
   element carries those classes.
   ============================================================================= */

/* sit above the word page (z 9000); kill wp-root's wpArrive so only the .kjp-in
   opacity fade runs the entrance. */
.wp-root.kjp-overlay { z-index: 9100; animation: none; }
.kjp-overlay.kjp-in { opacity: 1; }

/* the content column: .wp-entry (from word-page.css) owns the centred width +
   padding; .kjp-body keeps only the content typography and its tone-wash
   ::before, so shed the old drawer role (its own scroll + drawer padding). */
.wp-root .kjp-body {
    position: relative;   /* the .kjp-body::before tone wash anchors to the column */
    flex: none;
    overflow: visible;
    padding: 0;
}

/* ── the pinned hero, kanji variant ──────────────────────────────────────── */
/* one big glyph inscribed top-right like a gasan — no multi-column ruby machine */
.kjp-hero .wp-gasan { top: 44px; right: 60px; }
.kjp-hero .wp-word {
    font-size: clamp(140px, 25vh, 300px);
    line-height: 0.86;
    writing-mode: horizontal-tb;   /* a single character needs no vertical column */
}
/* the keyword sits in the placard's gloss slot; quiet its · separators */
.kjp-hero .kjp-kw-sep { opacity: 0.5; }
/* a gated kanji always ships art, but guard the empty case with a toned plate */
.kjp-paint--empty { position: absolute; inset: 0; background: var(--kjp-tone, #b0a090); }

@media (max-width: 768px) {
    .kjp-hero .wp-gasan { top: 24px; right: 24px; }
    .kjp-hero .wp-word { font-size: clamp(96px, 20vh, 200px); }
}

/* ── ローマ字 — this page's romaji, on the reader's ask ────────────────────────
   Owner ruling 2026-08-06: the reading MODE decides what is PRINTED; romaji is
   never printed and is always one press away, in every mode.

   ⛔ THE ONE THING THIS PAGE COULD NOT AFFORD TO LOSE. On the reading list the
   romaji was not a crutch BESIDE the reading — it WAS the reading, because ruby
   here was ruled clutter in June: a row read 時計 · tokei · "clock" with no kana
   anywhere. So the word rows keep their line and change SCRIPT (時計 · とけい ·
   "clock", see rowReadingHTML in js/kanji-page.js) rather than losing it, and
   only the romaji goes behind the control.

   Everything else on this page had its kana already sitting beside it — the
   group heads (.kjr-name), the readings glance (.kjg-r), the rarer-reading fold
   names, the homograph note — so for those the control costs the reader nothing.

   FOUR HOSTS, one state: the page, the drawer and the family aside are all
   .kjp-overlay; embedded in the word panel the spine hangs under .wpn-overlay,
   which carries the state the panel's own control already writes.

   NOT gated, each by ruling or by construction:
   · 例文 romaji — its own 訳 ask, per sentence, never remembered (law 10)
   · 声符 / 意符 family member rows (.kjw-rd) — the family blocks only ever render
     BEHIND their door, so they are already one gesture away; and their records
     carry no kana at all, so gating them would leave a row with no reading
   · the terms this page NAMES — the 六書 type tag, seifu / nakama / naritachi /
     mukashi / setsu. Those spell a Japanese WORD THE UI JUST USED so a
     non-Japanese-reading learner can say it. That is the app's standing rule for
     its own chrome, and it is the opposite of a reading crutch. (The kun'yomi /
     on'yomi eyebrows were one until B3, 11 October 2026.)
   · the place on a group's head (.kjr-place) — English chrome, nothing to spell
     (the course's rows, .kjp-ways, left the page on 20 October 2026). */
.kjp-overlay:not(.is-ro) .kjw-ro,
.wpn-overlay:not(.is-ro) .kjw-ro,
.kjp-overlay:not(.is-ro) .kjr-romaji,
.wpn-overlay:not(.is-ro) .kjr-romaji,
.kjp-overlay:not(.is-ro) .kjg-ro,
.wpn-overlay:not(.is-ro) .kjg-ro,
.kjp-overlay:not(.is-ro) .kjw-note-ro,
.wpn-overlay:not(.is-ro) .kjw-note-ro { display: none; }

/* the control's seat: one quiet line at the head of the reading list, sitting
   at its right edge the way the 活用 fold sits in a section head */
.kjr-rohead {
    display: flex;
    justify-content: flex-end;
    margin: 0 0 2px;
}
.kjp-overlay .ro-fold,
.wpn-overlay .kjr-rofold {
    appearance: none;
    background: none;
    border: 0;
    padding: 3px 2px;
    display: inline-flex;
    align-items: center;
    gap: 5px;
    font: 500 11.5px 'Inter', 'Noto Sans JP', sans-serif;
    letter-spacing: 0.02em;
    color: var(--kjp-ghost, #8c857b);
    cursor: pointer;
    transition: color 0.18s ease, opacity 0.18s ease;
}
.kjp-overlay .ro-fold:hover,
.kjp-overlay .ro-fold:focus-visible,
.wpn-overlay .kjr-rofold:hover,
.wpn-overlay .kjr-rofold:focus-visible { color: var(--color-ink, #2C2C2C); }
.kjp-overlay .ro-fold .ro-fold-caret,
.wpn-overlay .kjr-rofold .ro-fold-caret {
    width: 11px;
    height: 11px;
    flex: 0 0 auto;
    display: block;
    fill: none;
    stroke: currentColor;
    stroke-width: 2.2;
    stroke-linecap: round;
    stroke-linejoin: round;
    transition: transform 0.18s ease;
}
.kjp-overlay .ro-fold.is-open .ro-fold-caret,
.wpn-overlay .kjr-rofold.is-open .ro-fold-caret { transform: rotate(180deg); }
/* said its piece: it steps behind what it revealed, and comes back on hover */
.kjp-overlay.is-ro .ro-fold,
.wpn-overlay.is-ro .kjr-rofold { opacity: 0.5; }
.kjp-overlay.is-ro .ro-fold:hover,
.kjp-overlay.is-ro .ro-fold:focus-visible,
.wpn-overlay.is-ro .kjr-rofold:hover,
.wpn-overlay.is-ro .kjr-rofold:focus-visible { opacity: 1; }

/* ── ⭐ 単語帳 THE COURSE PROFILE (the owner, 20 October 2026, shelf review item E: "drill down works for words but not
   kanjis"; js/kanji-page.js courseHeroHTML, courseBodyHTML). The app's full page over a kanji the course's flashcards hold:
   the kanji teacher's painting is a square drawn on bare paper, so the stage is the course's paper and the painting rests
   whole between the way home and the placard, never cropped (the course's word page, css/word-page.css .wp-course); the
   placard and the gasan take the sumi ink of the light regime. The teacher's story and the look-alike block wear the course
   book's own dress (css/course-book.css .cb-tell-parts, .cb-tell-punch, .cb-tell-story, .cb-alike: .cb-embed carries its
   tokens), seated in this page's column; the readings keep this page's groups, the taught words only. ── */
.wp-root.kjp-course { background: #FCFAF2; }
.kjp-course .wp-paint {
    inset: 64px 0 188px 0;
    width: 100%;
    height: calc(100% - 252px);
    object-fit: contain;
    object-position: center;
}
/* ⭐ THE DESIGN ELEVATION, STEPS 1 AND 2 (1 November 2026) ON THE COURSE'S KANJI PAGE (the word page's block,
   css/word-page.css .wp-course, says the paper, the lift and the inks it shares): the page's own palette in the course's
   inks, the sumi #2A231F for the glyph, the reading names and the lemmas, the ink #38322D for the prose, the stone and
   the one quiet ink #69625A for what was faint, the slip 胡粉 #FFFFFB for its washi; the native way's readings leave the
   static indigo for the sumi (the owner's call 5: #313 restored, indigo answers the hand), the borrowed way and the
   whole word keep theirs. 木 STANDS CLEAR OF ITS PAINTING: the painting's box steps 128 px in from the right, so the tree's
   branches end before the glyph (they ran 40 px under it, GROUND.md §7.3). The app's own kanji page keeps its palette. */
.wp-root.kjp-course {
    --kjp-ink: #2A231F;
    --kjp-ink-wet: #1E1916;
    --kjp-prose: #38322D;
    --kjp-stone: #514A44;
    --kjp-ghost: #69625A;
    --kjp-paper: #FFFFFB;
    --kjp-sheet: #FFFFFB;
    --kjp-rule: rgba(42, 35, 31, 0.11);
    --kjp-hit: #9A4A16;
}
.wp-root.kjp-course .kjr-family--kun { --rd-accent: #2A231F; }
.wp-root.kjp-course .wp-paint { width: calc(100% - 128px); }
/* ⭐ THE REVIEW ROUND (1 November 2026). (1) THE KANJI'S MARK INSIDE ITS WORDS (the two marks, the same day: the owner's
   call 12 of the direction of record, "the persimmon ink = this word, now": today's word, the asked word, this kanji). In
   every family, the native way, the borrowed way and the words said as one, the character the row's sound sits on prints
   in the persimmon ink #9A4A16 (the pinned hex, tests/course/hit_ink_test.js), the rest of the word in the sumi, so a
   beginner finds at a glance which 日 of 日曜日 is read び and which にち; a word said as one (今日 きょう) marks its whole
   pair, as the app has always marked it, its reading no one character's. The family's ink stays on its head (the native
   way's kana in the sumi, the borrowed way's in its terracotta): the reading tells the family, the persimmon tells this
   kanji. Never the vermilion, the step forward's and the seal's. (The round's first answer, the word's other characters
   stepped back to the stone around a kanji in the sumi, left with it: at reading size a depth of ink did not find the
   kanji, a hue does.) (2) The reading kana under a word in the one quiet ink (was #6b6358) at the weight the
   card's small readings wear (600: at 400 and 13.5 px it printed 3.4:1 on a 1x glass), and the 読 threshold's
   mark opaque in it (it faded to 62 per cent of the sumi, 4.45:1). (3) THE TAUGHT WORDS' PORTRAITS MELT INTO THE SHEET: the
   tile's tone swatch, its ring, its grain and its sheen stand down and the painting sits on the one lift and multiply, as
   every course painting does (its own tan paper showed as a square 7.9 L* under the slip). */
.wp-root.kjp-course .kjw-hl { color: var(--kjp-hit); }
.wp-root.kjp-course .kjw-rd-kana { color: var(--kjp-ghost); font-weight: 600; }
.wp-root.kjp-course .threshold .mark .ch { color: var(--kjp-ghost); opacity: 1; }
.wp-root.kjp-course .kjw-row--course .kjw-tile { background: transparent; box-shadow: none; }
.wp-root.kjp-course .kjw-row--course .kjw-tile::before,
.wp-root.kjp-course .kjw-row--course .kjw-tile::after { content: none; }
.wp-root.kjp-course .kjw-row--course .kjw-thumb { filter: url(#cl-washi); mix-blend-mode: multiply; }
/* ⭐ D59 (the owner, 22 October 2026: "Everything should come from the kanji teacher and not be picked programmatically").
   A COURSE ROW on the app's own page (the bundle entry's `crs`: a kanji the course has taught; js/kanji-page.js
   isCourseRow) wears the course's paper as the course profile above does: the kanji teacher's painting is a square drawn
   on bare paper, so it rests whole between the way home and the placard, never cropped to the scene frame, and the
   drawer's 3:2 plate shows it whole on the same paper. The punch line leads the story in the prose's own bold. */
.wp-root.kjp-crow { background: #EFE9DD; }
.kjp-crow .wp-paint {
    inset: 64px 0 188px 0;
    width: 100%;
    height: calc(100% - 252px);
    object-fit: contain;
    object-position: center;
}
.story .plate.plate--course { background: #EFE9DD; }
.story .plate.plate--course .art { object-fit: contain; }
.shape.kjp-story--course .prose.kjp-punch { font-weight: 600; color: var(--kjp-ink); margin-bottom: 0.7em; }
.kjp-overlay .kjp-cstory { --cl-u: 19px; padding-top: 34px; }
.kjp-overlay .kjp-cstory .cb-tell-parts { margin: 0 0 1.1rem; }
.kjp-overlay .kjp-cstory .cb-tell-punch { margin: 0.4rem 0 1rem; }
.kjp-overlay .kjp-cstory .cb-tell-story { margin: 0; }
.kjp-overlay .kjp-cstory .cb-alike { margin-top: 1.6rem; }
/* a part the flashcards hold is a door to its own page, as every kanji glyph in a card is (the accent under the pointer) */
.kjp-overlay .kjp-cpart { cursor: pointer; transition: color 160ms ease; }
.kjp-overlay .kjp-cpart:hover { color: var(--color-accent, #3D5A80); }
.kjp-overlay .kjp-cpart:focus-visible { outline: 2px solid var(--color-accent, #3D5A80); outline-offset: 2px; border-radius: 2px; }
.kjp-cstory + .threshold { margin-top: 18px; }
/* the readings of the taught words: the course's portraits sit on the course's paper (no rank rail: the course prints none) */
.kjp-overlay .kjw-row--course .kjw-thumb { object-fit: cover; }
.kjp-overlay .kjw-row--here .kjw-jp { color: var(--color-jp-text, #523E1E); }
/* the look-alike's partner, a press: the page's own button reset would shrink it, so it takes the block's glyph again */
.kjp-overlay .kjp-cstory button.cb-alike-k {
    appearance: none;
    background: none;
    border: 0;
    padding: 0;
    margin: 0;
    font-family: 'Klee One', 'Noto Sans JP', serif;
    font-size: calc(1.9 * var(--cb-u));
    font-weight: 400;
    line-height: 1;
    color: var(--cb-jp);
    cursor: pointer;
    transition: color 160ms ease;
}
.kjp-overlay .kjp-cstory button.cb-alike-k:hover { color: var(--color-accent, #3D5A80); }
.kjp-overlay .kjp-cstory button.cb-alike-k:disabled { cursor: default; color: var(--cb-jp); }
