/* ========================================
   Vocabulary Lookup — shared skeleton + mobile bottom sheet.
   The desktop housing (quiet centered palette) lives in
   css/vocab-palette.css; this file keeps the structure both
   presentations share and the mobile (≤768px) sheet skin.
   Stacking: the lookup rides the z tokens in tokens.css — above
   every page surface (docs/SEARCH_ARCHITECTURE.md §5.4).
   ======================================== */

.vocab-panel-backdrop {
    /* display declared explicitly: index.html's critical FOUC style holds
       both lookup elements at display:none until this sheet loads */
    display: block;
    position: fixed;
    inset: 0;
    background: rgba(44, 44, 44, 0.15);
    z-index: var(--z-lookup-scrim, 9800);
    opacity: 0;
    visibility: hidden;
    transition: opacity 0.35s ease, visibility 0.35s ease;
}

.vocab-panel-backdrop.active {
    opacity: 1;
    visibility: visible;
}

.vocab-panel {
    position: fixed;
    z-index: var(--z-lookup-palette, 9900);
    display: flex;
    flex-direction: column;
    color: var(--color-ink);
    /* Force visibility so the panel escapes any inherited `visibility: hidden`
       from ancestors — notably `body.mobile-home #app` on the mobile landing,
       which would otherwise leave only the backdrop visible when the
       search button is tapped. The panel is hidden via its own skin's
       closed state (opacity on desktop, transform on mobile). */
    visibility: visible;
}

/* ========================================
   Panel Header with Search
   ======================================== */
.panel-header {
    padding: 20px;
    border-bottom: 1px solid rgba(44, 44, 44, 0.06);
    flex-shrink: 0;
    background: rgba(255, 255, 255, 0.4);
}

.panel-header-row {
    display: flex;
    align-items: center;
    gap: 0;
}

.panel-header-row .panel-search {
    flex: 1;
    min-width: 0;
}

/* Cancel button — hidden on desktop (desktop has keyboard Esc).
   NOTE: components.css has a global `button { box-shadow: 0 4px 15px ...;
   background: white }` rule. We explicitly null out background, shadow,
   border-radius, and hover transform or the Cancel text looks like a
   floating pill with a drop shadow. */
.panel-cancel {
    display: none;
    flex-shrink: 0;
    background: transparent;
    border: none;
    border-radius: 0;
    outline: none;
    box-shadow: none;
    color: var(--color-accent, #3D5A80);
    font-family: var(--font-ui, 'Inter', -apple-system, sans-serif);
    font-size: 17px;
    font-weight: 500;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
    -webkit-appearance: none;
    appearance: none;
}
.panel-cancel:hover,
.panel-cancel:active {
    background: transparent;
    box-shadow: none;
    transform: none;
}
.panel-cancel:focus { outline: none; }
.panel-cancel:focus-visible {
    outline: 2px solid var(--color-accent, #3D5A80);
    outline-offset: 2px;
    border-radius: 4px;
}

.panel-search {
    display: flex;
    align-items: center;
    gap: 12px;
    background: rgba(255, 255, 255, 0.7);
    border-radius: 10px;
    padding: 12px 16px;
    border: 1px solid rgba(44, 44, 44, 0.08);
    transition: border-color 0.2s ease, background 0.2s ease, box-shadow 0.2s ease;
    box-shadow: 0 1px 3px rgba(44, 44, 44, 0.02);
}

.panel-search:focus-within {
    border-color: var(--color-accent);
    background: rgba(255, 255, 255, 0.95);
    box-shadow: 0 0 0 3px rgba(61, 90, 128, 0.06);
}

.panel-search-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: var(--color-faint);
    line-height: 1;
}

.panel-search-input {
    flex: 1;
    background: transparent;
    border: none;
    color: var(--color-ink);
    font-size: 1.1rem;
    font-weight: 500;
    font-family: inherit;
}

.panel-search-input:focus {
    outline: none;
}

.panel-search-input::placeholder {
    color: var(--color-stone);
}

/* Typeahead ghost text — Google-style inline completion */
.search-typeahead-wrapper {
    flex: 1;
    min-width: 0;
    position: relative;
    display: flex;
    align-items: center;
}

.search-ghost {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    display: flex;
    align-items: center;
    pointer-events: none;
    overflow: hidden;
    white-space: nowrap;
    font-size: 1.1rem;
    font-weight: 500;
    font-family: inherit;
    color: transparent;
}

.search-ghost-typed {
    visibility: hidden;
    white-space: pre;
}

.search-ghost-completion {
    color: var(--color-faint);
    opacity: 0.45;
    white-space: pre;
}

/* Result count — hidden on desktop by default */
.panel-result-count {
    display: none;
}

.panel-close {
    width: 32px;
    height: 32px;
    border-radius: 8px;
    background: rgba(44, 44, 44, 0.05);
    border: none;
    color: var(--color-faint);
    font-size: 1rem;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: background-color 0.2s ease, color 0.2s ease;
}

.panel-close:hover {
    background: rgba(239, 68, 68, 0.1);
    color: var(--color-terracotta);
}

/* The ✕ glyph needs explicit CSS size: as a flex item, the attribute-sized
   svg resolves to width 0 in Chrome (height honors the attribute, width
   does not) — the button shipped as a blank box. */
.panel-close svg {
    width: 12px;
    height: 12px;
    flex: none;
}

/* ========================================
   Panel Content (Scrollable Results)
   ======================================== */
.panel-content {
    flex: 1;
    overflow-y: auto;
    padding: 12px;
    scrollbar-width: thin;
    scrollbar-color: rgba(44,44,44,0.15) transparent;
    overscroll-behavior: contain;
}

.panel-content::-webkit-scrollbar {
    width: 6px;
}

.panel-content::-webkit-scrollbar-thumb {
    background: rgba(44, 44, 44, 0.15);
    border-radius: 3px;
}

.panel-content::-webkit-scrollbar-thumb:hover {
    background: rgba(44, 44, 44, 0.25);
}

/* ========================================
   Result Items - Refined Light Theme
   ======================================== */
.vocab-panel .vocab-search-result,
.panel-result {
    padding: 14px 16px;
    border-radius: 10px;
    background: rgba(44, 44, 44, 0.025);
    border: 1px solid rgba(44, 44, 44, 0.03);
    margin-bottom: 8px;
    cursor: pointer;
    transition: background-color 0.18s ease, border-color 0.18s ease, box-shadow 0.18s ease, transform 0.18s ease;
    display: flex;
    align-items: center;
    gap: 14px;
    opacity: 0;
    animation: panelResultFadeIn 0.25s ease forwards;
}

/* Thumbnail — mobile-only. Hidden on desktop (hover mini-preview handles it) */
.result-thumb {
    display: none;
}

@keyframes panelResultFadeIn {
    from {
        opacity: 0;
        transform: translateX(-12px);
    }
    to {
        opacity: 1;
        transform: translateX(0);
    }
}

/* (The unscoped row stagger retired in desktop polish round 3: it beat the
   desktop palette's own rule and re-ran on every keystroke. The phone keeps
   its stagger, scoped in the mobile block below.) */

.vocab-panel .vocab-search-result:hover,
.vocab-panel .vocab-search-result.selected {
    background: rgba(44, 44, 44, 0.045);
    border-color: rgba(44, 44, 44, 0.06);
    transform: translateX(3px);
}

/* Previewing (hover) reads as selection — same treatment as .selected,
   defined per-skin (vocab-palette.css desktop; mobile neutralizes it). */

.vocab-panel .vocab-search-result:active {
    transform: scale(0.99) translateX(3px);
    background: rgba(44, 44, 44, 0.06);
}

/* Text Hierarchy - Refined Light Theme
   Japanese: Primary (black) - the word to learn
   Romanization: Accent (indigo) - pronunciation aid
   English: Secondary (dark gray) - the meaning
   Meta: Tertiary (medium gray) - supplementary info
*/
.vocab-panel .result-japanese {
    font-family: 'Klee One', 'Noto Sans JP', sans-serif;
    font-size: 1.4em;
    font-weight: 600;
    color: #000000;
    margin-bottom: 5px;
    letter-spacing: 0.01em;
}

.vocab-panel .result-details {
    font-family: 'Inter', -apple-system, sans-serif;
    font-size: 0.88em;
    color: var(--color-stone);
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
}

.vocab-panel .result-romanization {
    font-style: italic;
    color: var(--color-accent);
    font-weight: 500;
    letter-spacing: 0.02em;
}

.vocab-panel .result-separator {
    color: var(--color-faint);
    font-weight: 300;
}

.vocab-panel .result-english {
    color: var(--color-ink);
    font-weight: 450;
}

/* Highlight matches - subtle indigo underline effect */
.vocab-panel .result-japanese mark,
.vocab-panel .result-romanization mark,
.vocab-panel .result-english mark,
.vocab-panel .result-altw mark {
    background: rgba(61, 90, 128, 0.12);
    color: inherit;
    border-radius: 3px;
    padding: 1px 4px;
    margin: 0 -1px;
}

/* Part of speech badge - refined pill */
.vocab-panel .result-badge {
    padding: 2px 8px;
    background: rgba(61, 90, 128, 0.08);
    border: none;
    border-radius: 6px;
    font-size: 0.72em;
    font-weight: 600;
    color: var(--color-accent);
    text-transform: lowercase;
    white-space: nowrap;
    letter-spacing: 0.02em;
}

/* Category tag - muted neutral */
.vocab-panel .result-category {
    padding: 2px 8px;
    background: rgba(44, 44, 44, 0.035);
    border-radius: 6px;
    font-size: 0.68em;
    font-weight: 500;
    color: var(--color-faint);
    white-space: nowrap;
    max-width: 120px;
    overflow: hidden;
    text-overflow: ellipsis;
    letter-spacing: 0.01em;
}

/* Progress dots */
.vocab-panel .progress-dot {
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: rgba(44, 44, 44, 0.12);
}

.vocab-panel .progress-dot.known {
    background: rgba(163, 177, 138, 0.9);
    box-shadow: 0 0 4px rgba(163, 177, 138, 0.24);
}

.vocab-panel .progress-dot.learning {
    background: rgba(194, 130, 114, 0.9);
    box-shadow: 0 0 4px rgba(194, 130, 114, 0.24);
}

/* ========================================
   Empty & Loading States
   ======================================== */
.vocab-panel .vocab-search-empty,
.vocab-panel .vocab-search-loading {
    padding: 40px 20px;
    text-align: center;
}

.vocab-panel .vocab-search-empty-icon {
    font-size: 3em;
    margin-bottom: 12px;
    opacity: 0.4;
}

.vocab-panel .vocab-search-empty-text {
    font-family: 'Inter', sans-serif;
    font-size: 0.95em;
    color: var(--color-faint);
    line-height: 1.5;
}

.vocab-panel .vocab-search-empty-text strong {
    color: var(--color-ink);
}

.vocab-panel .vocab-search-spinner {
    width: 28px;
    height: 28px;
    border: 2.5px solid rgba(61, 90, 128, 0.12);
    border-top-color: var(--color-accent);
    border-radius: 50%;
    animation: panelSpin 0.8s linear infinite;
    margin: 0 auto 12px;
}

@keyframes panelSpin {
    to { transform: rotate(360deg); }
}

/* ========================================
   Panel Footer (Keyboard Hints)
   ======================================== */
/* (The keyboard-hints footer was retired 2026-07-12 — owner: chrome filler.
   The ? sheet teaches the palette keys.) */

/* ========================================
   Card Preview Mode Styling
   Clean preview - no border or badge, just smooth content swap
   ======================================== */
.flashcard.preview-mode {
    /* No visual indicators - seamless preview */
    transition: none;
}

/* ========================================
   Desktop Wide: Constrain text line length
   ======================================== */
@media (min-width: 1200px) {
    .vocab-panel .result-details {
        max-width: 70ch;
    }
}

/* ========================================
   Mobile: Full-screen overlay, Kotoba 和の感性 aesthetic
   Matches mobile-landing + learn-mode warm paper language.
   Design principles (in order of importance):
     1. Subtraction before addition (one textured surface max)
     2. Content IS the decoration (images + JP type carry the warmth)
     3. Scarcity gives meaning (gold earned, not sprayed)
     4. Cards rest, not float
   ======================================== */
@media (max-width: 768px) {
    .vocab-panel {
        top: 0;
        left: 0;
        right: 0;
        bottom: 0;
        width: 100%;
        max-width: none;
        height: 100%;
        max-height: 100%;
        border-radius: 0;
        border-right: none;
        border-top: none;
        transform: translateY(100%);
        box-shadow: none;
        /* Warm paper ground + seasonal tint — matches mobile-grid-container */
        background:
            radial-gradient(ellipse 90% 70% at 50% 15%, var(--seasonal-tint, rgba(201, 169, 110, 0.04)) 0%, transparent 70%),
            var(--color-paper);
        backdrop-filter: none;
        -webkit-backdrop-filter: none;
        color: var(--color-ink);
        /* iOS sheet curve — expo-out, calm shoji-slide, not springy */
        transition: transform 0.42s cubic-bezier(0.22, 1, 0.36, 1);
        /* Safe area padding for notched phones */
        padding-top: env(safe-area-inset-top, 0);
    }

    .vocab-panel.open {
        transform: translateY(0);
    }

    /* Washi paper grain — matches mobile-grid + landing */
    .vocab-panel::before {
        content: '';
        position: fixed;
        inset: 0;
        pointer-events: none;
        z-index: 0;
        opacity: 0.025;
        background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='300' height='300'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.75' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='300' height='300' filter='url(%23n)' opacity='1'/%3E%3C/svg%3E");
        background-size: 300px 300px;
    }

    /* Header — transparent over paper, frosted on scroll.
       Right gutter (20px) is slightly wider than left (20px as well) so the
       Cancel button has air against the viewport edge. */
    .vocab-panel .panel-header {
        padding: 10px 20px 8px;
        padding-top: calc(10px + env(safe-area-inset-top, 0));
        background: transparent;
        border-bottom: none;
        transition: background 0.3s ease, box-shadow 0.3s ease, backdrop-filter 0.3s ease;
    }

    /* Frosted header — activated on scroll via JS, matches mg-header--solid */
    .vocab-panel .panel-header.panel-header--frosted {
        background: rgba(240, 237, 232, 0.88);
        backdrop-filter: blur(12px);
        -webkit-backdrop-filter: blur(12px);
        box-shadow: 0 1px 0 rgba(216, 210, 200, 0.4);
    }

    /* Mobile header row: search field + Cancel text button */
    .vocab-panel .panel-header-row {
        gap: 8px;
    }

    /* BARE-LINE SEARCH (one surface rule)
       Strip the pill. Hairline underline replaces it.
       Icon, input, and inline ✕ sit on the paper directly. */
    .vocab-panel .panel-search {
        background: transparent;
        border: none;
        border-bottom: 1px solid var(--color-divider);
        border-radius: 0;
        padding: 10px 2px 10px 0;
        gap: 12px;
        box-shadow: none;
        transition: border-color 0.3s ease;
    }

    .vocab-panel .panel-search:focus-within {
        background: transparent;
        border-color: var(--color-ink);
        box-shadow: none;
    }

    .vocab-panel .panel-search-icon {
        display: inline-flex;
        align-items: center;
        justify-content: center;
        color: var(--color-faint);
        font-size: 0;
        transition: color 0.3s ease;
    }

    .vocab-panel .panel-search:focus-within .panel-search-icon {
        color: var(--color-ink);
    }

    .vocab-panel .panel-search-input {
        font-size: 17px; /* Native iOS size, still no zoom */
        font-family: var(--font-ui);
        font-weight: 400;
        color: var(--color-ink);
        caret-color: var(--color-accent);
    }

    .vocab-panel .panel-search-input::placeholder {
        color: var(--color-faint);
        font-weight: 400;
        font-family: var(--font-jp), var(--font-ui);
        letter-spacing: 0.02em;
    }

    /* Ghost typeahead — match mobile input metrics exactly */
    .vocab-panel .search-ghost {
        font-size: 17px;
        font-weight: 400;
        font-family: var(--font-ui);
    }
    .vocab-panel .search-ghost-completion {
        color: var(--color-faint);
        opacity: 0.4;
    }

    /* Unified close button (✕).
       One control, dual role: tap once to clear text, tap again (empty)
       to close the panel. handleClearButton() in vocab-search.js handles
       the state machine. Always visible — a close affordance shouldn't
       hide and seek. The Cancel text button is redundant and dropped
       on mobile. */
    .vocab-panel .panel-close {
        display: flex;
        align-items: center;
        justify-content: center;
        width: 30px;
        height: 30px;
        background: rgba(44, 44, 44, 0.07);
        color: var(--color-ink);
        border: none;
        border-radius: var(--radius-full);
        font-size: 15px;
        line-height: 1;
        padding: 0;
        position: relative;
        flex-shrink: 0;
        box-shadow: none;
        transition: background 0.18s ease, color 0.18s ease, transform 0.18s ease;
    }
    /* Expanded hit area (44pt) without visual bloat */
    .vocab-panel .panel-close::before {
        content: "";
        position: absolute;
        inset: -7px;
    }
    .vocab-panel .panel-close:hover,
    .vocab-panel .panel-close:active {
        background: rgba(44, 44, 44, 0.14);
        color: var(--color-ink);
        transform: scale(0.94);
    }

    /* Cancel text button — dropped on mobile. The ✕ close button above
       is self-explanatory. Leaving markup in place for desktop/accessibility
       tooling but hiding it on mobile. */
    .vocab-panel .panel-cancel {
        display: none !important;
    }

    /* No drag handle needed for full-screen */
    .panel-header::before {
        display: none;
    }

    /* Content area — calmer gutter; safe-area bottom so last row escapes
       the home indicator when keyboard dismisses */
    .vocab-panel .panel-content {
        padding: 6px 20px calc(32px + env(safe-area-inset-bottom, 0));
        scroll-padding-bottom: env(safe-area-inset-bottom, 0);
    }

    /* ========================================
       RESULT COUNT — quiet tally above results
       ======================================== */
    .vocab-panel .panel-result-count {
        display: none;
        font-family: var(--font-ui);
        font-size: 11px;
        font-weight: 500;
        color: var(--color-faint);
        letter-spacing: 0.06em;
        padding: 12px 0 2px;
    }
    .vocab-panel .panel-result-count.visible {
        display: block;
    }

    /* ========================================
       EMPTY STATE — recent chips + example hints
       Calmer than a list. Teaches what's searchable.
       ======================================== */
    .vocab-panel .vocab-search-recent-label {
        display: block;
        font-family: var(--font-ui);
        font-size: 11px;
        font-weight: 500;
        color: var(--color-faint);
        letter-spacing: 0.08em;
        text-transform: uppercase;
        padding: 18px 0 10px;
    }
    /* the recents label speaks the house pattern — 最近 saikin · recent
       (M3): embedded JP sheds the tracked caps, romaji goes italic */
    .vocab-panel .vocab-search-recent-label [lang="ja"] {
        font-family: var(--font-jp);
        font-size: 13px;
        letter-spacing: 0;
        text-transform: none;
        color: var(--color-stone);
    }
    .vocab-panel .vocab-search-recent-label i {
        font-style: italic;
        text-transform: none;
        letter-spacing: 0.02em;
    }

    .vocab-panel .vocab-search-recent-empty {
        font-family: var(--font-ui);
        color: var(--color-faint);
        font-size: 14px;
        padding: 20px 0 8px;
        letter-spacing: 0.01em;
    }

    /* Horizontal chip rail — recent or example starters */
    .vocab-panel .vocab-search-chip-row {
        display: flex;
        gap: 8px;
        overflow-x: auto;
        scroll-snap-type: x proximity;
        padding: 4px 0 8px;
        margin: 0 -20px 8px;
        padding-left: 20px;
        padding-right: 20px;
        scrollbar-width: none;
        -webkit-overflow-scrolling: touch;
    }
    .vocab-panel .vocab-search-chip-row::-webkit-scrollbar { display: none; }

    .vocab-panel .vocab-search-chip {
        flex-shrink: 0;
        scroll-snap-align: start;
        display: inline-flex;
        align-items: center;
        height: 38px;
        padding: 0 16px;
        border-radius: var(--radius-full);
        background: rgba(250, 250, 247, 0.75);
        border: 1px solid rgba(44, 44, 44, 0.07);
        box-shadow: none;
        color: var(--color-ink);
        font-family: var(--font-jp);
        font-size: 16px;
        font-weight: 400;
        letter-spacing: 0.01em;
        cursor: pointer;
        -webkit-tap-highlight-color: transparent;
        -webkit-user-select: none;
        user-select: none;
        -webkit-touch-callout: none;
        transition: background 0.18s ease, transform 0.18s ease;
    }
    .vocab-panel .vocab-search-chip:hover,
    .vocab-panel .vocab-search-chip:active {
        background: rgba(201, 169, 110, 0.12);
        transform: scale(0.97);
        box-shadow: none;
    }

    .vocab-panel .vocab-search-chip .chip-roma {
        font-family: var(--font-ui);
        font-style: italic;
        font-weight: 400;
        font-size: 12px;
        color: var(--color-faint);
        margin-left: 8px;
        letter-spacing: 0.01em;
    }

    /* Example hint copy under the chip row. Named `vocab-search-tip`
       (not `-hint`) to dodge a legacy collision with an absolute-
       positioned desktop keyboard-shortcut pill styled in
       vocab-search.css. Explicit display:block keeps the rule clear. */
    .vocab-panel .vocab-search-tip {
        display: block;
        font-family: var(--font-ui);
        font-size: 13px;
        font-weight: 400;
        color: var(--color-faint);
        line-height: 1.55;
        padding: 18px 0 4px;
        letter-spacing: 0.01em;
    }
    .vocab-panel .vocab-search-tip em {
        font-style: normal;
        color: var(--color-stone);
    }

    /* ========================================
       RESULT ROWS — image + text, one hairline
       ======================================== */
    .vocab-panel .vocab-search-result {
        display: grid;
        grid-template-columns: 58px 1fr;
        gap: 18px;
        align-items: center;
        padding: 18px 0;
        background: transparent;
        border: none;
        border-bottom: none;
        border-radius: 0;
        margin-bottom: 0;
        /* Ultra-subtle stagger — micro-breathe, items settle into place */
        animation: mobileResultEnter 160ms ease-out both;
        position: relative;
        /* Long-press delighter conflict: iOS Safari's default behavior for
           long-press on text is to open the selection callout (Copy / Look
           Up / Share). That fires BEFORE our 320ms audio timer, hijacking
           the gesture. Disable text selection + iOS callout on the row so
           the long-press reaches our handler cleanly. */
        -webkit-user-select: none;
        user-select: none;
        -webkit-touch-callout: none;
    }

    .vocab-panel .vocab-search-recent-item {
        padding: 18px 0;
        background: transparent;
        border: none;
        border-bottom: none;
        border-radius: 0;
        margin-bottom: 0;
        position: relative;
    }
    /* Gradient fade divider for recent items */
    .vocab-panel .vocab-search-recent-item::before {
        content: '';
        position: absolute;
        bottom: 0;
        left: 0;
        right: 24px;
        height: 0.5px;
        background: linear-gradient(90deg, transparent, var(--color-divider) 10%, var(--color-divider) 90%, transparent);
        pointer-events: none;
    }
    .vocab-panel .vocab-search-recent-item:last-child::before {
        display: none;
    }

    /* Gradient fade divider — starts after thumbnail, fades at edges.
       Uses ::before to keep ::after free for audio-playing gold sweep. */
    .vocab-panel .vocab-search-result::before {
        content: '';
        position: absolute;
        bottom: 0;
        left: 76px;
        right: 24px;
        height: 0.5px;
        background: linear-gradient(90deg, transparent, var(--color-divider) 10%, var(--color-divider) 90%, transparent);
        pointer-events: none;
    }
    .vocab-panel .vocab-search-result:last-child::before {
        display: none;
    }

    /* Mobile stagger timing — the phone's own; the desktop palette has no
       row entrance (css/vocab-palette.css) */
    @keyframes mobileResultEnter {
        from { opacity: 0; transform: translateY(4px); }
        to   { opacity: 1; transform: translateY(0); }
    }
    .vocab-panel .vocab-search-result:nth-child(1) { animation-delay: 0ms; }
    .vocab-panel .vocab-search-result:nth-child(2) { animation-delay: 20ms; }
    .vocab-panel .vocab-search-result:nth-child(3) { animation-delay: 40ms; }
    .vocab-panel .vocab-search-result:nth-child(4) { animation-delay: 60ms; }
    .vocab-panel .vocab-search-result:nth-child(5) { animation-delay: 80ms; }
    .vocab-panel .vocab-search-result:nth-child(6) { animation-delay: 100ms; }
    .vocab-panel .vocab-search-result:nth-child(7) { animation-delay: 115ms; }
    .vocab-panel .vocab-search-result:nth-child(n+8) { animation-delay: 130ms; }

    /* Active tap feedback — warm amber wash, not gray. 160ms release. */
    .vocab-panel .vocab-search-result:active {
        background: rgba(201, 169, 110, 0.08);
        transform: none;
        border-color: var(--color-divider);
    }

    /* Kill hover/selected states on mobile — no keyboard, no cursor */
    .vocab-panel .vocab-search-result:hover,
    .vocab-panel .vocab-search-result.selected,
    .vocab-panel .vocab-search-result.previewing,
    .vocab-panel .vocab-search-result.preview-expanded {
        background: transparent;
        border-color: var(--color-divider);
        transform: none;
        padding-left: 0;
        flex-direction: row;
        align-items: center;
    }
    .vocab-panel .vocab-search-result.previewing .result-compact,
    .vocab-panel .vocab-search-result.preview-expanded .result-compact {
        display: flex;
    }
    .vocab-panel .vocab-search-result .mini-preview {
        display: none !important;
    }

    /* Thumbnail — 58×58 rounded warm paper tile, matches mg-thumb.
       This IS the decoration. Muji would be proud. */
    .vocab-panel .result-thumb {
        display: block;
        width: 58px;
        height: 58px;
        border-radius: var(--radius-lg);
        background: var(--color-card);
        overflow: hidden;
        flex-shrink: 0;
        position: relative;
        box-shadow:
            0 2px 6px rgba(44, 28, 10, 0.06),
            0 0 0 0.5px rgba(216, 210, 200, 0.6);
    }
    .vocab-panel .result-thumb img {
        width: 100%;
        height: 100%;
        object-fit: cover;
        display: block;
        opacity: 0;
        transition: opacity 0.25s ease;
    }
    .vocab-panel .result-thumb img.loaded {
        opacity: 1;
    }
    /* Placeholder — a single ink stroke for words without images */
    .vocab-panel .result-thumb.no-image::before {
        content: "言";
        position: absolute;
        inset: 0;
        display: flex;
        align-items: center;
        justify-content: center;
        font-family: var(--font-jp);
        font-size: 22px;
        color: var(--color-divider);
    }

    /* Learning status dot — thumbnail corner, scarcity-compliant.
       Only learning (amber) and known (sage) get a dot. New = nothing. */
    .vocab-panel .result-thumb .status-dot {
        position: absolute;
        top: -2px;
        right: -2px;
        width: 8px;
        height: 8px;
        border-radius: 50%;
        border: 1.5px solid var(--color-paper);
        z-index: 1;
        opacity: 0;
        animation: statusDotAppear 250ms ease-out 200ms forwards;
    }
    .vocab-panel .result-thumb .status-dot--learning {
        background: var(--color-gold);
    }
    .vocab-panel .result-thumb .status-dot--known {
        background: var(--color-moss);
    }
    @keyframes statusDotAppear {
        from { opacity: 0; transform: scale(0.4); }
        to   { opacity: 1; transform: scale(1); }
    }

    /* Right-side status dot — vertically centered, right edge.
       Only rendered for known (sage) and learning (gold). New = absent. */
    .vocab-panel .result-status-dot {
        position: absolute;
        right: 12px;
        top: 50%;
        transform: translateY(-50%);
        width: 8px;
        height: 8px;
        border-radius: 50%;
        opacity: 0;
        animation: statusDotAppear 250ms ease-out 200ms forwards;
    }
    .vocab-panel .result-status-dot--known {
        background: #5a7a3e;
    }
    .vocab-panel .result-status-dot--learning {
        background: #b8860b;
    }

    /* Accent line — left-edge ribbon, matches mg-accent-line.
       Replaces dots as primary status signal on mobile. */
    .vocab-panel .result-accent-line {
        position: absolute;
        left: 0;
        top: 50%;
        transform: translateY(-50%);
        width: 2.5px;
        height: 55%;
        border-radius: 0 2px 2px 0;
        opacity: 0;
        animation: statusDotAppear 250ms ease-out 200ms forwards;
    }
    .vocab-panel .result-accent-line--known {
        background: var(--color-moss);
    }
    .vocab-panel .result-accent-line--learning {
        background: var(--color-gold);
    }

    /* Hide part-of-speech badge + status dot entirely on mobile.
       The learn-mode card surfaces this; the scan list doesn't need it. */
    .vocab-panel .result-meta {
        display: none !important;
    }

    /* Text column — stacked, generous ma */
    .vocab-panel .result-compact {
        display: block;
        min-width: 0;
    }
    .vocab-panel .result-main {
        min-width: 0;
    }

    /* Japanese word — warm sumi ink, matches mg-japanese */
    .vocab-panel .result-japanese {
        font-family: var(--font-jp);
        font-size: 22px;
        font-weight: 400;
        color: var(--color-jp-text);
        margin-bottom: 4px;
        line-height: 1.4;
        letter-spacing: 0.03em;
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
    }

    /* Romaji · English row — tertiary rhythm */
    .vocab-panel .result-details {
        font-family: var(--font-ui);
        font-size: 13px;
        color: var(--color-romaji);
        line-height: 1.45;
        display: block;
    }
    .vocab-panel .result-romanization {
        color: var(--color-romaji);
        font-style: italic;
        font-weight: 400;
    }
    .vocab-panel .result-separator {
        color: var(--color-divider);
        margin: 0 6px;
        font-weight: 300;
    }
    .vocab-panel .result-english {
        color: var(--color-stone);
        font-weight: 400;
    }

    /* SUMI-BRUSH highlight — ink underline stroke, not a pill
       The match looks like paper-and-ink, not a tag.
       The gold sits in the same 62%/38% ratio as a sumi brush stroke. */
    .vocab-panel .result-japanese mark,
    .vocab-panel .result-romanization mark,
    .vocab-panel .result-english mark,
    .vocab-panel .result-altw mark {
        background: linear-gradient(
            transparent 62%,
            rgba(201, 169, 110, 0.28) 62%,
            rgba(201, 169, 110, 0.28) 92%,
            transparent 92%
        );
        color: inherit;
        padding: 0 1px;
        margin: 0;
        border-radius: 0;
    }
    .vocab-panel .result-japanese mark {
        background: linear-gradient(
            transparent 70%,
            rgba(201, 169, 110, 0.32) 70%,
            rgba(201, 169, 110, 0.32) 96%,
            transparent 96%
        );
    }

    /* Long-press audio state — kintsugi gold hairline beneath the word.
       The ONLY place gold appears on mobile search — earned by holding.
       This is the transcendent moment: "this app treats Japanese as a sound." */
    .vocab-panel .vocab-search-result.audio-playing {
        background: transparent;
    }
    .vocab-panel .vocab-search-result.audio-playing .result-japanese {
        color: var(--color-jp-text);
    }
    .vocab-panel .vocab-search-result.audio-playing::after {
        content: "";
        position: absolute;
        left: 76px;
        right: 0;
        bottom: 0;
        height: 1.5px;
        background: var(--color-gold);
        opacity: 0.6;
        transform-origin: left center;
        animation: audioWaveSweep 1.1s cubic-bezier(0.22, 1, 0.36, 1) forwards;
    }
    @keyframes audioWaveSweep {
        0%   { transform: scaleX(0); opacity: 0.8; }
        60%  { transform: scaleX(1); opacity: 0.6; }
        100% { transform: scaleX(1); opacity: 0; }
    }

    /* Audio pulse on thumbnail — kintsugi ring breathes outward.
       Pairs with the gold hairline sweep for a cohesive audio moment. */
    .vocab-panel .vocab-search-result.audio-playing .result-thumb {
        animation: thumbAudioPulse 0.6s ease-in-out 2;
    }
    @keyframes thumbAudioPulse {
        0%, 100% {
            box-shadow:
                0 2px 6px rgba(44, 28, 10, 0.06),
                0 0 0 0.5px rgba(216, 210, 200, 0.6);
        }
        50% {
            box-shadow:
                0 0 0 3px rgba(201, 169, 110, 0.2),
                0 2px 6px rgba(44, 28, 10, 0.06),
                0 0 0 0.5px rgba(201, 169, 110, 0.15);
        }
    }

    /* ========================================
       NO-RESULTS STATE — calm Japanese phrase
       Not an error, not an illustration. Just breath.
       ======================================== */
    .vocab-panel .vocab-search-empty {
        padding: 72px 20px 48px;
        text-align: center;
    }
    .vocab-panel .vocab-search-empty-icon {
        display: none; /* the SVG magnifying glass is chrome, drop it */
    }
    .vocab-panel .vocab-search-empty-text {
        font-family: var(--font-ui);
        color: var(--color-faint);
        font-size: 14px;
        line-height: 1.7;
    }
    .vocab-panel .vocab-search-empty-text::before {
        content: "見つかりません";
        display: block;
        font-family: var(--font-jp);
        font-size: 20px;
        color: var(--color-stone);
        letter-spacing: 0.04em;
        margin-bottom: 12px;
        font-weight: 400;
    }
    .vocab-panel .vocab-search-empty-text strong {
        color: var(--color-ink);
        font-weight: 500;
    }

    /* Loading spinner — gold ink, smaller */
    .vocab-panel .vocab-search-loading {
        padding: 40px 20px;
    }
    .vocab-panel .vocab-search-spinner {
        width: 22px;
        height: 22px;
        border-width: 2px;
        border-color: rgba(201, 169, 110, 0.15);
        border-top-color: var(--color-gold);
    }

    /* Branding slide-out — slightly faster than panel entrance */
    body.vocab-panel-open .app-branding-topleft {
        transition: transform 0.28s cubic-bezier(0.22, 1, 0.36, 1), opacity 0.2s ease;
    }
}

/* Vocab panel available in all modes (video learn, revision, focus, standard) */

/* ========================================
   Slide Branding Out When Panel Opens (mobile sheet only — the desktop
   palette is centered on a scrim, so the branding just rests beneath it)
   ======================================== */
@media (max-width: 768px) {
    body.vocab-panel-open .app-branding-topleft {
        transform: translateX(-120%);
        opacity: 0;
        transition: transform 0.35s cubic-bezier(0.32, 0.72, 0, 1), opacity 0.25s ease;
    }
}

/* Hide old search modal elements when panel is active */
body:has(.vocab-panel) .search-modal,
body:has(.vocab-panel) .search-modal-overlay {
    display: none !important;
}

/* ========================================
   Result row layout (shared)
   (The hover mini-preview card was retired with the centered palette —
   result rows now carry the thumbnail directly; see vocab-palette.css.)
   ======================================== */

/* Compact result row - default view */
.result-compact {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    gap: 12px;
}

/* (The revision-mode preview-only styling left with the mini-preview —
   result rows commit through the one lookup path in every mode.) */
