/*  ╔══════════════════════════════════════════════════════════════════╗
    ║  Lattice — Direction H · Cube Lattice                            ║
    ║                                                                  ║
    ║  Shared design system. Imported by every voice/static/*.html     ║
    ║  page so the visual language stays consistent across surfaces.   ║
    ║                                                                  ║
    ║  Brand identity: a unit cell of a cubic lattice (3 visible       ║
    ║  colored faces forming an isometric cube). Words are nodes,      ║
    ║  meaning is connectivity, the lattice is the math.               ║
    ╚══════════════════════════════════════════════════════════════════╝ */

/* Web fonts are loaded via <link> tags injected by theme-loader.js so
   they fetch in PARALLEL with this stylesheet rather than serially after
   it (which is what @import url(...) does, blocking text rendering by
   ~200-500ms on cold loads). The injected tags include preconnects to
   fonts.googleapis.com / fonts.gstatic.com plus the stylesheet itself
   with display=swap so fallback text shows immediately if the web font
   is slow. See theme-loader.js: ensureFonts(). */

/* ─── THEME TOKENS ────────────────────────────────────────────────────
   :root holds the AMETHYST defaults (current production theme). The
   html[data-theme="cool"] block below overrides individual tokens for
   the legacy cool palette. Both blocks live in design.css so themes
   ship with the single render-blocking stylesheet - no async race
   between design.css applying and the theme file arriving. Switching
   themes at runtime is just a data-theme attribute change.
   ─────────────────────────────────────────────────────────────────── */
:root {
    /* Brand mark - rendered via CSS background-image on .cube-mark. */
    --brand-mark: url("/static/brand-amethyst/mark.svg");

    /* Surfaces - cream paper */
    --canvas:      #FFFCF6;
    --surface:     #FFFFFF;
    --surface-2:   #FBF6EE;
    --surface-3:   #F4E6D2;
    --border:      #E8C9A8;
    --border-strong:#C9A578;

    /* Ink - deep brown family */
    --ink:       #2D1A10;
    --ink-soft:  #4D3625;
    --muted:     #8C7864;
    --muted-2:   #B8A88C;

    /* Accent - amethyst purple */
    --accent:        #6B3FA0;
    --accent-deep:   #4A2475;
    --accent-soft:   #EFE4FB;
    --accent-subtle: #F7EFFC;

    /* Cube faces - tri-tone amethyst.
       Light-from-above convention: top brightest, left darkest. */
    --face-top:    #B894E0;
    --face-top-2:  #9B6FCC;
    --face-right:  #6B3FA0;
    --face-right-2:#5A3286;
    --face-left:   #4A2475;
    --face-left-2: #2D1A10;

    /* Grade semantics - good shifts to moss to avoid amethyst clash */
    --bad:       #B54040;
    --bad-soft:  #FBEFE0;
    --hard:      #B87A14;
    --hard-soft: #FBF2E0;
    --good:      #5C7A4A;
    --good-soft: #EAEFE0;

    /* Typography */
    --serif: 'Source Serif 4', 'Iowan Old Style', 'Lyon Text', Georgia, serif;
    --jp:    'Klee One', 'Hiragino Mincho ProN', 'Yu Mincho', 'Noto Serif JP', serif;
    --jp-sans: 'Hiragino Kaku Gothic ProN', 'Yu Gothic', 'Noto Sans JP', sans-serif;
    --sans:  'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;

    /* Motion */
    --ease:     cubic-bezier(0.32, 0.72, 0.24, 1);
    --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
    --spring:   cubic-bezier(0.34, 1.56, 0.64, 1);

    /* Patterns - accent dot uses amethyst rgb */
    --hex-dot-pattern:
        radial-gradient(circle at 1px 1px, rgba(45, 26, 16, 0.08) 1px, transparent 0);
    --hex-dot-pattern-soft:
        radial-gradient(circle at 1px 1px, rgba(45, 26, 16, 0.05) 1px, transparent 0);
    --hex-dot-pattern-accent:
        radial-gradient(circle at 1px 1px, rgba(107, 63, 160, 0.18) 1px, transparent 0);

    /* Shadows - warm shadow color matches the brown ink */
    --shadow-card:
        0 1px 0 white inset,
        0 0 0 1px var(--border),
        0 2px 4px rgba(45, 26, 16, 0.05),
        0 12px 24px -8px rgba(45, 26, 16, 0.10),
        0 28px 56px -16px rgba(45, 26, 16, 0.14);
    --shadow-key:
        inset 0 1px 0 white,
        0 1px 0 rgba(45, 26, 16, 0.05),
        0 4px 8px -2px rgba(45, 26, 16, 0.07);
    --shadow-key-hover:
        inset 0 1px 0 white,
        0 1px 0 rgba(45, 26, 16, 0.05),
        0 12px 22px -6px rgba(45, 26, 16, 0.18);
    --shadow-key-active:
        inset 0 1px 2px rgba(45, 26, 16, 0.07);
}

/* Cool theme - opt-in via html[data-theme="cool"]. Specificity (0,1,1)
   beats :root (0,0,1) regardless of source order. */
html[data-theme="cool"] {
    --brand-mark: url("/static/brand/mark.svg");

    --canvas:      #fbfaf6;
    --surface:     #ffffff;
    --surface-2:   #f5f3ec;
    --surface-3:   #efece2;
    --border:      #e5e1d4;
    --border-strong: #d2cebf;

    --ink:       #16151a;
    --ink-soft:  #2a2829;
    --muted:     #6b6864;
    --muted-2:   #97938b;

    --accent:        #0e7c66;
    --accent-deep:   #095a4a;
    --accent-soft:   #d3ebe3;
    --accent-subtle: #ecf5f1;

    --face-top:    #f4a01a;
    --face-top-2:  #d97706;
    --face-right:  #0e7c66;
    --face-right-2:#0a604f;
    --face-left:   #4f46e5;
    --face-left-2: #3730a3;

    --bad:       #b54040;
    --bad-soft:  #fbe9e9;
    --hard:      #b87a14;
    --hard-soft: #fbf2e0;
    --good:      #0e7c66;
    --good-soft: #ecf5f1;

    --hex-dot-pattern:
        radial-gradient(circle at 1px 1px, rgba(22, 21, 26, 0.08) 1px, transparent 0);
    --hex-dot-pattern-soft:
        radial-gradient(circle at 1px 1px, rgba(22, 21, 26, 0.05) 1px, transparent 0);
    --hex-dot-pattern-accent:
        radial-gradient(circle at 1px 1px, rgba(14, 124, 102, 0.16) 1px, transparent 0);

    --shadow-card:
        0 1px 0 white inset,
        0 0 0 1px var(--border),
        0 2px 4px rgba(22, 21, 26, 0.04),
        0 12px 24px -8px rgba(22, 21, 26, 0.08),
        0 28px 56px -16px rgba(22, 21, 26, 0.12);
    --shadow-key:
        inset 0 1px 0 white,
        0 1px 0 rgba(22, 21, 26, 0.04),
        0 4px 8px -2px rgba(22, 21, 26, 0.06);
    --shadow-key-hover:
        inset 0 1px 0 white,
        0 1px 0 rgba(22, 21, 26, 0.04),
        0 12px 22px -6px rgba(22, 21, 26, 0.16);
    --shadow-key-active:
        inset 0 1px 2px rgba(22, 21, 26, 0.06);
}

/* ─── Cross-document view transitions ────────────────────────────────
   Tells the browser to animate same-origin navigations as a smooth
   cross-fade (Chrome 126+, Edge 126+, Safari 18.2+). Older browsers
   ignore the at-rule and fall back to the default instant nav. The
   transition is BROWSER-NATIVE, runs on the compositor (60fps), and
   doesn't block JS or interfere with the page load. The animation is
   short enough to mask the brief paint races (font swap, settings
   pill mount, etc.) without feeling sluggish. */
@view-transition { navigation: auto; }
::view-transition-old(root),
::view-transition-new(root) {
    animation-duration: 220ms;
    animation-timing-function: cubic-bezier(0.32, 0.72, 0.24, 1);
}

/* ── Base ─────────────────────────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; }
html, body { height: 100%; }
/* Always reserve scrollbar gutter so the viewport width is stable across
   pages with different content lengths. Without this, navigating between
   a long page (scrollbar present) and a short one (no scrollbar) shifts
   centered content horizontally by ~7-8px - visible as the header
   "flicking right" on click. scrollbar-gutter is the modern API
   (Chromium/Firefox); the fallback overflow-y:scroll covers older Safari. */
html { scrollbar-gutter: stable; overflow-y: scroll; }
body {
    margin: 0;
    background: var(--canvas);
    color: var(--ink);
    font-family: var(--sans);
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    text-rendering: optimizeLegibility;
    min-height: 100vh;
    position: relative;
}

/* The canvas lattice pattern - present but receding. Apply to body
   automatically; pages can opt out by setting body.no-lattice class. */
body:not(.no-lattice)::before {
    content: '';
    position: fixed; inset: 0;
    background-image: var(--hex-dot-pattern);
    background-size: 24px 24px;
    pointer-events: none;
    z-index: 0;
    mask-image: radial-gradient(ellipse at center, black 30%, transparent 100%);
    -webkit-mask-image: radial-gradient(ellipse at center, black 30%, transparent 100%);
}

/* All app content sits above the canvas pattern */
.app-header, main, header, footer { position: relative; z-index: 1; }

/* ── Cube mark (brand glyph) ─────────────────────────────────────────────
   The mark is rendered as a CSS background-image driven by the
   --brand-mark token, which each theme declares pointing at its own
   /static/brand-<theme>/mark.svg. CSS-driven (not JS-driven) means the
   correct geometry appears on first paint with zero timing window for a
   visible cube-then-hex morph. Pages just emit <span class="cube-mark
   spinning"></span> with no inner SVG. */
.cube-mark {
    position: relative;
    display: inline-block;
    background-image: var(--brand-mark);
    background-position: center;
    background-repeat: no-repeat;
    background-size: contain;
}
/* The cube-mark stays static at rest. The big brand-hero mark on the
   Hub is grab-draggable via JS (rotates while held, snaps back on
   release). The auto-spin animation was removed per "don't spin on its
   own" — kept the .spinning class as a no-op so existing markup keeps
   working without churn. */
.cube-mark.spinning { animation: none; }

/* ── App header ──────────────────────────────────────────────────────── */
.app-header {
    /* width:100% + align-self:stretch defend against pages that make
       <body> a flex container with align-items:center (index.html does
       this). Without these, the header shrinks to content-width on those
       pages and is full-width elsewhere - clicking between produces a
       visible "header flicks to the right" shift on every nav. */
    width: 100%;
    align-self: stretch;
    border-bottom: 1px solid var(--border);
    background: rgba(251, 250, 246, 0.86);
    backdrop-filter: saturate(180%) blur(20px);
    -webkit-backdrop-filter: saturate(180%) blur(20px);
    position: sticky;
    top: 0;
    z-index: 50;
}
.app-header .inner {
    max-width: 1200px;
    margin: 0 auto;
    padding: 14px 32px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 32px;
}
.app-header .brand {
    font-family: var(--serif);
    font-size: 22px;
    font-weight: 600;
    letter-spacing: -0.02em;
    color: var(--ink);
    display: flex;
    align-items: center;
    gap: 12px;
    text-decoration: none;
}
.app-header .brand .cube-mark {
    width: 32px; height: 32px;
    flex-shrink: 0;
}
.app-header nav {
    display: flex;
    gap: 2px;
}
.app-header nav a {
    padding: 8px 14px;
    border-radius: 8px;
    font-family: var(--sans);
    font-size: 14px;
    font-weight: 500;
    color: var(--muted);
    text-decoration: none;
    transition: all 0.18s var(--ease);
}
.app-header nav a:hover { color: var(--ink); background: var(--surface-2); }
.app-header nav a.active {
    color: var(--accent);
    background: var(--accent-subtle);
    box-shadow: inset 0 0 0 1px var(--accent-soft);
}
.app-header .meta {
    font-family: var(--serif);
    font-style: italic;
    font-size: 14px;
    color: var(--muted);
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 14px;
    /* Reserve space for the settings pill so the header doesn't reflow
       when settings-anchor.js mounts the pill async after its API load.
       Sized comfortably above the pill's typical footprint (~210px for
       a 6-char tutor name; longer names would still grow the slot but
       240 covers the common case). flex-shrink:0 prevents flexbox from
       collapsing the slot when content gets crowded. */
    min-width: 240px;
    min-height: 32px;
    flex-shrink: 0;
}
.app-header .meta .level {
    font-style: normal;
    font-weight: 600;
    color: var(--ink);
    background: var(--surface);
    border: 1px solid var(--border);
    padding: 2px 10px;
    border-radius: 999px;
    font-size: 13px;
    box-shadow:
        inset 0 1px 0 white,
        0 1px 2px rgba(22,21,26,0.04);
}

/* ── Global settings pill (anchor in header) ────────────────────────────
   Shows current tutor + language + level. Clickable, opens settings drawer. */
.settings-pill {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 5px 12px 5px 6px;
    border-radius: 999px;
    background: var(--surface);
    border: 1px solid var(--border);
    cursor: pointer;
    font-family: var(--sans);
    font-size: 13px;
    font-weight: 500;
    color: var(--ink);
    box-shadow:
        inset 0 1px 0 white,
        0 1px 2px rgba(22,21,26,0.04);
    transition: all 0.18s var(--ease);
}
.settings-pill:hover {
    border-color: var(--border-strong);
    box-shadow:
        inset 0 1px 0 white,
        0 4px 10px -2px rgba(22,21,26,0.08);
    transform: translateY(-1px);
}
.settings-pill .tutor-dot {
    width: 22px;
    height: 22px;
    border-radius: 50%;
    background: var(--accent-subtle);
    border: 1.5px solid var(--accent);
    display: flex;
    align-items: center;
    justify-content: center;
    font-family: var(--serif);
    font-style: italic;
    font-weight: 600;
    color: var(--accent-deep);
    font-size: 12px;
    flex-shrink: 0;
}
.settings-pill .sep {
    color: var(--muted-2);
    font-weight: 400;
    margin: 0 2px;
}
.settings-pill .lang {
    color: var(--ink-soft);
}
.settings-pill .lvl {
    color: var(--accent-deep);
    font-weight: 600;
}
.settings-pill .gear {
    color: var(--muted-2);
    margin-left: 2px;
    transition: transform 0.3s var(--ease);
}
.settings-pill:hover .gear { color: var(--ink-soft); transform: rotate(45deg); }

/* ── Settings drawer ──────────────────────────────────────────────────── */
.settings-overlay {
    position: fixed;
    inset: 0;
    z-index: 100;
    background: rgba(22, 21, 26, 0);
    pointer-events: none;
    transition: background 0.25s ease;
}
.settings-overlay.open {
    background: rgba(22, 21, 26, 0.18);
    pointer-events: auto;
    backdrop-filter: blur(2px);
    -webkit-backdrop-filter: blur(2px);
}

.settings-drawer {
    position: fixed;
    top: 0;
    right: 0;
    width: 460px;
    max-width: 100vw;
    height: 100vh;
    background: var(--canvas);
    background-image: var(--hex-dot-pattern-soft);
    background-size: 24px 24px;
    z-index: 101;
    transform: translateX(100%);
    transition: transform 0.32s cubic-bezier(0.32, 0.72, 0.24, 1);
    overflow-y: auto;
    border-left: 1px solid var(--border);
    box-shadow: -16px 0 48px -16px rgba(22, 21, 26, 0.18);
    display: flex;
    flex-direction: column;
}
.settings-drawer.open { transform: translateX(0); }

.settings-drawer .drawer-head {
    padding: 20px 28px;
    display: flex;
    justify-content: space-between;
    align-items: center;
    border-bottom: 1px solid var(--border);
    background: rgba(255, 255, 255, 0.6);
    backdrop-filter: blur(8px);
}
.settings-drawer .drawer-head h2 {
    margin: 0;
    font-family: var(--serif);
    font-size: 22px;
    font-weight: 600;
    letter-spacing: -0.02em;
    color: var(--ink);
}
.settings-drawer .drawer-close {
    background: none;
    border: none;
    padding: 6px 10px;
    border-radius: 6px;
    cursor: pointer;
    font-family: var(--serif);
    font-style: italic;
    font-size: 14px;
    color: var(--muted);
}
.settings-drawer .drawer-close:hover { color: var(--ink); background: var(--surface-2); }

.settings-section {
    padding: 24px 28px 12px;
}
.settings-section + .settings-section {
    border-top: 1px solid var(--border);
}
.settings-section .section-label {
    font-family: var(--serif);
    font-style: italic;
    font-size: 13px;
    color: var(--muted);
    letter-spacing: 0.01em;
    margin-bottom: 12px;
    display: block;
}

/* Tutor cards */
.tutor-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 10px;
    margin-bottom: 12px;
}
.tutor-card {
    background: var(--surface);
    border: 1.5px solid var(--border);
    border-radius: 14px;
    padding: 14px;
    cursor: pointer;
    text-align: left;
    transition: all 0.18s var(--ease);
    box-shadow: var(--shadow-key);
    font-family: var(--sans);
    color: var(--ink);
    display: flex;
    flex-direction: column;
    gap: 4px;
}
.tutor-card:hover {
    transform: translateY(-2px);
    border-color: var(--border-strong);
    box-shadow: var(--shadow-key-hover);
}
.tutor-card.selected {
    border-color: var(--accent);
    background: var(--accent-subtle);
    box-shadow:
        inset 0 1px 0 white,
        0 0 0 1px var(--accent),
        0 8px 18px -8px rgba(14, 124, 102, 0.2);
}
.tutor-card .name {
    font-family: var(--serif);
    font-size: 18px;
    font-weight: 600;
    letter-spacing: -0.01em;
    color: var(--ink);
    margin-bottom: 2px;
}
.tutor-card.selected .name { color: var(--accent-deep); }
.tutor-card .voice-tag {
    font-family: var(--serif);
    font-style: italic;
    font-size: 11px;
    color: var(--muted);
    margin-bottom: 6px;
}
.tutor-card .bio {
    font-family: var(--serif);
    font-size: 13px;
    line-height: 1.4;
    color: var(--ink-soft);
}
.tutor-card-pick {
    background: none;
    border: none;
    padding: 0;
    width: 100%;
    text-align: left;
    cursor: pointer;
    display: flex;
    flex-direction: column;
    gap: 4px;
    color: inherit;
    font-family: inherit;
}
.voice-override-row {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-top: 10px;
    padding-top: 10px;
    border-top: 1px dashed var(--border);
    font-family: var(--serif);
    font-size: 12px;
    color: var(--muted);
    font-style: italic;
}
.voice-override-row label {
    flex-shrink: 0;
    font-style: italic;
}
.voice-override-select {
    flex: 1;
    padding: 4px 8px;
    border: 1px solid var(--border);
    border-radius: 6px;
    background: var(--surface);
    font-size: 12px;
    font-family: var(--sans);
    color: var(--ink);
    cursor: pointer;
}
.voice-override-select:focus { outline: none; border-color: var(--accent); }

/* Form rows */
.settings-row {
    display: flex;
    flex-direction: column;
    margin-bottom: 14px;
}
.settings-row label {
    font-size: 13px;
    font-weight: 500;
    color: var(--ink-soft);
    margin-bottom: 6px;
}
.settings-row select {
    padding: 10px 12px;
    border: 1px solid var(--border);
    border-radius: 8px;
    font-size: 14px;
    background: var(--surface);
    appearance: none;
    background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'%3e%3cpath d='M1 1l4 4 4-4' stroke='%236b6864' fill='none' stroke-width='1.5'/%3e%3c/svg%3e");
    background-repeat: no-repeat;
    background-position: right 12px center;
    padding-right: 32px;
    color: var(--ink);
    font-family: var(--sans);
}
.settings-row select:focus { outline: none; border-color: var(--accent); }

.settings-saved {
    padding: 8px 14px;
    background: var(--accent-subtle);
    color: var(--accent-deep);
    border-radius: 8px;
    font-family: var(--serif);
    font-style: italic;
    font-size: 13px;
    text-align: center;
    margin: 0 28px 20px;
    opacity: 0;
    transition: opacity 0.2s ease;
}
.settings-saved.show { opacity: 1; }

/* ── Card primitive ──────────────────────────────────────────────────── */
.lattice-card {
    background: var(--surface);
    border-radius: 24px;
    overflow: hidden;
    position: relative;
    box-shadow: var(--shadow-card);
    animation: cardIn 0.5s var(--ease-out);
}
@keyframes cardIn {
    from { opacity: 0; transform: translateY(14px); }
    to   { opacity: 1; transform: translateY(0); }
}
/* Lattice dust at top of card */
.lattice-card::before {
    content: '';
    position: absolute;
    top: 0; left: 0; right: 0;
    height: 60px;
    background-image: var(--hex-dot-pattern-soft);
    background-size: 14px 14px;
    pointer-events: none;
    mask-image: linear-gradient(180deg, black 0%, transparent 100%);
    -webkit-mask-image: linear-gradient(180deg, black 0%, transparent 100%);
    opacity: 0.7;
    z-index: 0;
}
.lattice-card > * { position: relative; z-index: 2; }

/* ── Pill / tag ──────────────────────────────────────────────────────── */
.pill {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    padding: 4px 12px 4px 9px;
    border-radius: 999px;
    font-family: var(--sans);
    font-size: 13px;
    font-weight: 500;
    background: var(--surface);
    color: var(--accent-deep);
    box-shadow:
        inset 0 0 0 1px var(--accent-soft),
        0 1px 2px rgba(14, 124, 102, 0.08);
}
.pill .dot {
    width: 7px; height: 7px;
    border-radius: 50%;
    background: var(--accent);
    box-shadow: 0 0 6px var(--accent), inset 0 0 0 1px rgba(255,255,255,0.5);
}

/* ── Typewriter button (key-cap + stamp-bar) ─────────────────────────── */
.typewriter-btn {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 14px;
    padding: 18px 12px 16px;
    cursor: pointer;
    transition:
        transform 0.18s var(--ease),
        border-color 0.18s var(--ease),
        box-shadow 0.18s var(--ease),
        background 0.18s var(--ease);
    position: relative;
    text-align: center;
    font-family: var(--sans);
    box-shadow: var(--shadow-key);
}
.typewriter-btn:hover {
    transform: translateY(-3px);
    border-color: var(--border-strong);
    box-shadow: var(--shadow-key-hover);
}
.typewriter-btn:active {
    transform: translateY(0) scale(0.99);
    box-shadow: var(--shadow-key-active);
    transition-duration: 0.06s;
}
.typewriter-btn .label {
    font-family: var(--serif);
    font-size: 18px;
    font-weight: 600;
    line-height: 1;
    margin-bottom: 5px;
    color: var(--ink);
}
.typewriter-btn .desc {
    font-family: var(--serif);
    font-style: italic;
    font-size: 13px;
    color: var(--muted);
    line-height: 1.3;
}
.typewriter-btn .key-cap {
    position: absolute;
    top: 9px;
    right: 9px;
    width: 22px;
    height: 22px;
    border-radius: 6px;
    background: var(--surface-2);
    border: 1px solid var(--border);
    display: flex;
    align-items: center;
    justify-content: center;
    font-family: var(--serif);
    font-style: italic;
    font-size: 13px;
    font-weight: 600;
    color: var(--muted);
    transition: all 0.18s var(--ease);
    box-shadow:
        inset 0 1px 0 rgba(255, 255, 255, 0.8),
        0 1px 1px rgba(22, 21, 26, 0.04);
}
.typewriter-btn:hover .key-cap {
    background: var(--surface);
    transform: translateY(-1px);
    box-shadow: inset 0 1px 0 white, 0 2px 3px rgba(22, 21, 26, 0.08);
}
.typewriter-btn .stamp-bar {
    position: absolute;
    left: 14px; right: 14px; bottom: 8px;
    height: 3px;
    border-radius: 999px;
    background: var(--border);
    overflow: hidden;
    transform-origin: center left;
    transform: scaleX(0.3);
    opacity: 0.4;
    transition: all 0.32s var(--ease-out);
}
.typewriter-btn .stamp-bar::after {
    content: '';
    position: absolute;
    inset: 0;
    background: currentColor;
    border-radius: 999px;
    transform-origin: center left;
    transform: scaleX(0);
    transition: transform 0.32s var(--ease-out);
}
.typewriter-btn:hover .stamp-bar { opacity: 1; transform: scaleX(1); }
.typewriter-btn:hover .stamp-bar::after { transform: scaleX(1); }

/* Outcome colors */
.typewriter-btn.miss { color: var(--bad); }
.typewriter-btn.miss:hover { background: var(--bad-soft); border-color: var(--bad); }
.typewriter-btn.miss:hover .label { color: var(--bad); }
.typewriter-btn.miss:hover .key-cap { color: var(--bad); border-color: var(--bad); }

.typewriter-btn.hard { color: var(--hard); }
.typewriter-btn.hard:hover { background: var(--hard-soft); border-color: var(--hard); }
.typewriter-btn.hard:hover .label { color: var(--hard); }
.typewriter-btn.hard:hover .key-cap { color: var(--hard); border-color: var(--hard); }

.typewriter-btn.easy { color: var(--good); }
.typewriter-btn.easy:hover { background: var(--good-soft); border-color: var(--good); }
.typewriter-btn.easy:hover .label { color: var(--good); }
.typewriter-btn.easy:hover .key-cap { color: var(--good); border-color: var(--good); }

/* ── Lattice progress bar (3-color cube-face gradient) ───────────────── */
.lattice-progress {
    height: 14px;
    background: var(--surface-2);
    background-image: var(--hex-dot-pattern-soft);
    background-size: 14px 14px;
    border-radius: 7px;
    overflow: hidden;
    position: relative;
    box-shadow: inset 0 1px 2px rgba(22,21,26,0.04);
    border: 1px solid var(--border);
}
.lattice-progress > .fill {
    position: absolute;
    inset: 0;
    width: 0%;
    background: linear-gradient(90deg,
        var(--face-left) 0%,
        var(--face-right) 50%,
        var(--face-top) 100%);
    border-right: 1px solid rgba(255,255,255,0.4);
    transition: width 0.5s var(--ease-out);
}

/* Slim variant for small contexts */
.lattice-progress.slim {
    height: 4px;
    border-radius: 999px;
}

/* ── Definition block (recessed inner panel) ─────────────────────────── */
.def-block {
    background: var(--surface-2);
    background-image: var(--hex-dot-pattern-soft);
    background-size: 14px 14px;
    border-radius: 16px;
    padding: 22px 26px;
    box-shadow:
        inset 0 1px 2px rgba(22,21,26,0.04),
        inset 0 0 0 1px var(--border);
}
.def-line {
    display: grid;
    grid-template-columns: 60px 1fr;
    gap: 16px;
    align-items: baseline;
    padding: 9px 10px;
    margin: 0 -10px;
    font-family: var(--serif);
    font-size: 18px;
    color: var(--ink);
    line-height: 1.45;
    background: rgba(255, 255, 255, 0.55);
    border-radius: 6px;
}
.def-line + .def-line { margin-top: 4px; }
.def-line .pos {
    font-family: var(--serif);
    font-style: italic;
    font-size: 14px;
    font-weight: 500;
    color: var(--muted);
    text-align: right;
    padding-top: 3px;
}

/* ── Hint pattern (footer keyboard prompts in serif italic prose) ────── */
.hint {
    text-align: center;
    font-family: var(--serif);
    font-style: italic;
    font-size: 14px;
    color: var(--muted);
}
.hint .key {
    font-style: normal;
    font-weight: 600;
    color: var(--ink-soft);
}

/* ── Section heading typography ──────────────────────────────────────── */
.section-h1 {
    font-family: var(--serif);
    font-size: 32px;
    font-weight: 600;
    letter-spacing: -0.025em;
    color: var(--ink);
}
.section-position {
    font-family: var(--serif);
    font-style: italic;
    font-size: 16px;
    color: var(--muted);
    font-variant-numeric: oldstyle-nums;
}
.section-position .now {
    color: var(--ink);
    font-style: normal;
    font-weight: 600;
}

/* ── Native font on Japanese text ────────────────────────────────────── */
.jp, .jp-text { font-family: var(--jp); }
.jp-sans     { font-family: var(--jp-sans); }

/* ── Mobile header (2026-07-05, device-QA + on-device CDP diagnosis) ──
   The desktop header row's MIN-CONTENT width is ~655-836px depending on
   the page (brand + 5-6 unbreakable nav links + level/settings pills +
   gaps/padding). Flex items refuse to shrink below min-content, so on
   real phones Android Chrome inflates the initial layout viewport to
   fit it (the whole app renders zoomed-out and side-scrollable - the
   S23U bug) and WebKit overflows the viewport by the same amount.
   Below 900px the header becomes: row 1 = brand + pills, row 2 = nav
   as an edge-to-edge swipeable strip with >=40px tap targets. */
@media (max-width: 900px) {
    .app-header .inner {
        flex-wrap: wrap;
        gap: 6px 12px;
        padding: 10px 16px;
    }
    .app-header .brand { order: 1; min-width: 0; }
    .app-header .meta {
        order: 2;
        margin-left: auto;
        gap: 8px;
        min-width: 0;
    }
    /* Standalone level chip duplicates the settings pill's level. */
    .app-header .meta > .level { display: none; }

    .app-header nav {
        order: 3;
        flex-basis: 100%;
        min-width: 0;
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
        scrollbar-width: none;
        margin: 0 -16px -10px;
        padding: 0 12px 6px;
    }
    .app-header nav::-webkit-scrollbar { display: none; }
    /* Edge fades: the strip scrolls, and hidden scrollbars need an
       affordance - without this, links past the fold simply "don't
       exist" to the user (the reported can't-see-menu-icons feel). */
    .app-header nav {
        -webkit-mask-image: linear-gradient(to right,
            transparent 0, black 14px, black calc(100% - 22px), transparent 100%);
        mask-image: linear-gradient(to right,
            transparent 0, black 14px, black calc(100% - 22px), transparent 100%);
    }
    .app-header nav a {
        padding: 10px 14px;   /* >=40px tap height on the strip */
        white-space: nowrap;
        flex-shrink: 0;
    }

    /* Slim the settings pill: the tutor's colored dot already encodes
       the tutor - drop the name + its separator, keep lang · level. */
    .settings-pill { max-width: 60vw; }
    .settings-pill > span:not([class]) { display: none; }
    .settings-pill > span:not([class]) + .sep { display: none; }
    .settings-pill .lang {
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
        min-width: 0;
    }
}
