/* ==========================================================================
   GERMAN-LESSON-TEST.CSS — scoped Bauhaus retint + navbar redesign, same
   pattern as every other page in this family (tokens/navbar ported verbatim
   from german-a1-immersion-course.css). .card/.hub-tag-badge/.badge- variants
   are inherited from see-test.css.
   ========================================================================== */

html:root {
    --bg: #f7f2e7;
    --surface: #ffffff;
    --surface-2: #fbf7ee;
    --ink: #191726;
    --ink-soft: #5a5470;
    --ink-faint: #9089a3;
    --accent: #e0432b;
    --accent-2: #c23621;
    --accent-soft: rgba(224, 67, 43, 0.12);
    --gold: #b4870a;
    --gold-soft: rgba(239, 176, 0, 0.18);
    --line: #e7dec7;
    --line-strong: #d8cba8;

    --shadow-sm: 0 1px 2px rgba(25, 23, 38, 0.06), 0 1px 1px rgba(25, 23, 38, 0.04);
    --shadow-md: 0 10px 24px -8px rgba(25, 23, 38, 0.16), 0 2px 8px -2px rgba(25, 23, 38, 0.06);
    --shadow-lg: 0 0 0 1px rgba(25, 23, 38, 0.04), 0 16px 40px -16px rgba(224, 67, 43, 0.28);

    --serif: "Futura", "Avenir Next", Avenir, "Century Gothic", system-ui, sans-serif;

    --color-nom: #1d5fa6; --color-nom-bg: #e5eef8;
    --color-acc: #e0432b; --color-acc-bg: #fbe7e3;

    /* Irregular-verb / regular-verb / infinitive Functions (see
       IRREGULAR_CONJUGATED_FORMS etc. in the JS). */
    --color-vir: #2f8f52; --color-vir-bg: #e3f3e8;
    --color-vre: #8a5a2b; --color-vre-bg: #f5ece0;
    --color-inf: #4552b8; --color-inf-bg: #e6e8f8;

    /* Coordinating / subordinating conjunction Functions. */
    --color-ccj: #c2660c; --color-ccj-bg: #faecd9;
    --color-scj: #6b7a0f; --color-scj-bg: #eef2d9;

    /* Adverbs / adverbial phrases Function. */
    --color-adv: #a6236f; --color-adv-bg: #f6e2ef;

    /* Predicate adjectives Function. */
    --color-prd: #0e8a8a; --color-prd-bg: #dcf1f1;

    /* Accusative case Function — "akk" (Akkusativ), not "acc": that code
       is already Function 2's ("Es"). */
    --color-akk: #46596b; --color-akk-bg: #e2e8ec;

    /* Attributive adjectives Function. */
    --color-atr: #8034a8; --color-atr-bg: #f1e2f7;

    /* Negation Function. */
    --color-ngt: #8b2020; --color-ngt-bg: #f5e0e0;

    /* Prepositions Function. */
    --color-prp: #a8481f; --color-prp-bg: #f7e6da;

    /* Demonstrative pronoun Function — "dem" (Demonstrativpronomen), not
       "dpr": keeping it a real word-fragment like the other topic codes. */
    --color-dem: #2f6690; --color-dem-bg: #e1ecf3;

    /* Fixed-idiom Function — "idm", covers "Alles Gute" (a nominalized
       adjective after "alles"), and any other hand-placed set-phrase
       Function added later. */
    --color-idm: #a13d6b; --color-idm-bg: #f5e2ec;

    /* Comparative adjectives Function — "cmp", new in Chapter 3
       ("so groß wie", "älter"/"jünger"): the first Function genuinely new
       to a chapter past Chapter 1, hence its own "Chapter 3 Functions"
       section in that chapter's Functions panel. */
    --color-cmp: #4a5b8c; --color-cmp-bg: #e2e5f0;

    /* Superlative adjectives Function — "sup", new in Chapter 5
       ("die beste Suppe", "das allerbeste Bier") — related to but
       grammatically distinct from comparatives ("cmp"): der/die/das +
       adjective+st+e rather than a plain -er ending. */
    --color-sup: #5c7a4a; --color-sup-bg: #e6ecdf;
}

@media (prefers-color-scheme: dark) {
    html:root {
        --bg: #131220;
        --surface: #1c1a2c;
        --surface-2: #211f34;
        --ink: #f3eee1;
        --ink-soft: #b3abc9;
        --ink-faint: #867f9c;
        --accent: #ff5b41;
        --accent-2: #ff7b62;
        --accent-soft: rgba(255, 91, 65, 0.16);
        --gold: #ffcb3d;
        --gold-soft: rgba(255, 203, 61, 0.18);
        --line: #33304a;
        --line-strong: #413c5c;

        --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.3);
        --shadow-md: 0 10px 28px -10px rgba(0, 0, 0, 0.55);
        --shadow-lg: 0 0 0 1px rgba(255, 255, 255, 0.05), 0 16px 44px -16px rgba(255, 91, 65, 0.35);

        --color-nom: #5b98e8; --color-nom-bg: rgba(91, 152, 232, 0.16);
        --color-acc: #ff5b41; --color-acc-bg: rgba(255, 91, 65, 0.16);

        --color-vir: #4ade80; --color-vir-bg: rgba(74, 222, 128, 0.16);
        --color-vre: #d99b56; --color-vre-bg: rgba(217, 155, 86, 0.18);
        --color-inf: #8b94f0; --color-inf-bg: rgba(139, 148, 240, 0.18);

        --color-ccj: #ffa94d; --color-ccj-bg: rgba(255, 169, 77, 0.18);
        --color-scj: #c4d94f; --color-scj-bg: rgba(196, 217, 79, 0.18);

        --color-adv: #ec6bb5; --color-adv-bg: rgba(236, 107, 181, 0.18);

        --color-prd: #4dd9d9; --color-prd-bg: rgba(77, 217, 217, 0.18);

        --color-akk: #8fa8bd; --color-akk-bg: rgba(143, 168, 189, 0.18);

        --color-atr: #c98ae6; --color-atr-bg: rgba(201, 138, 230, 0.18);

        --color-ngt: #e57373; --color-ngt-bg: rgba(229, 115, 115, 0.18);

        --color-prp: #e8935e; --color-prp-bg: rgba(232, 147, 94, 0.18);

        --color-dem: #6fb3e0; --color-dem-bg: rgba(111, 179, 224, 0.18);

        --color-idm: #e587b3; --color-idm-bg: rgba(229, 135, 179, 0.18);

        --color-cmp: #8fa0e0; --color-cmp-bg: rgba(143, 160, 224, 0.18);

        --color-sup: #8fbf6e; --color-sup-bg: rgba(143, 191, 110, 0.18);
    }
}

:root {
    --good: #2f9e58;
    --good-soft: #e6f4ea;
    --bad: #d64545;
    --bad-soft: #fbe9e9;
}

@media (prefers-color-scheme: dark) {
    :root {
        --good: #6bc98a;
        --good-soft: rgba(107, 201, 138, 0.14);
        --bad: #e58080;
        --bad-soft: rgba(229, 128, 128, 0.14);
    }
}

/* ================= NAVBAR (redesigned, scoped to this page only) ================= */
.navbar {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    z-index: 999;
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 14px 28px;
    background: color-mix(in srgb, var(--bg) 92%, transparent);
    backdrop-filter: blur(14px);
    -webkit-backdrop-filter: blur(14px);
    border-bottom: 1px solid var(--line);
}

.brand {
    display: flex;
    align-items: center;
    gap: 10px;
    text-decoration: none;
}

.brand-mark {
    width: 34px;
    height: 34px;
    flex: 0 0 auto;
}

.brand-word {
    font-family: var(--serif);
    font-weight: 700;
    font-size: 1.05rem;
    letter-spacing: 0.01em;
    color: var(--ink);
}

.brand-word b {
    color: var(--accent);
}

.nav-links {
    display: flex;
    align-items: center;
    gap: 4px;
    margin-left: auto;
}

.nav-links > a {
    font-family: var(--mono);
    font-size: 0.76rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    text-decoration: none;
    padding: 9px 14px;
    border-radius: 8px;
    color: var(--ink-soft);
    transition: background 0.15s ease, color 0.15s ease;
}

.nav-links > a:hover {
    background: var(--surface-2);
    color: var(--ink);
}

.navbar .dropdown-item {
    position: relative;
}

.navbar .dropdown-trigger {
    display: flex;
    align-items: center;
    gap: 5px;
    cursor: pointer;
    font-family: var(--mono);
    font-size: 0.76rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    padding: 9px 14px;
    border-radius: 8px;
    color: var(--ink-soft);
    text-decoration: none;
    border: none;
    background: none;
    transition: background 0.15s ease, color 0.15s ease;
}

.navbar .dropdown-trigger:hover,
.navbar .dropdown-item.open .dropdown-trigger {
    background: var(--surface-2);
    color: var(--ink);
}

.navbar .dropdown-trigger.active {
    color: var(--accent);
}

.navbar .caret {
    transition: transform 0.18s ease;
    font-size: 0.7em;
}

.navbar .dropdown-item.open .caret {
    transform: rotate(180deg);
}

.navbar .dropdown-menu {
    position: absolute;
    top: calc(100% + 10px);
    left: 0;
    min-width: 230px;
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: 18px;
    box-shadow: var(--shadow-md);
    padding: 14px 10px 10px;
    display: flex;
    flex-direction: column;
    gap: 4px;
    opacity: 0;
    visibility: hidden;
    transform: translateY(-6px);
    transition: opacity 0.16s ease, transform 0.16s ease, visibility 0.16s;
    overflow: hidden;
}

.navbar .dropdown-menu::before {
    content: "";
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    height: 4px;
    background: linear-gradient(90deg, var(--accent), var(--gold), var(--color-nom));
}

.navbar .dropdown-item.open .dropdown-menu {
    opacity: 1;
    visibility: visible;
    transform: translateY(0);
}

.navbar .dropdown-menu a {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 12px;
    border-radius: 12px;
    font-size: 0.88rem;
    font-weight: 600;
    text-decoration: none;
    color: var(--ink-soft);
    transition: background 0.15s ease, color 0.15s ease, transform 0.15s ease;
}

.navbar .dropdown-menu a:hover {
    background: var(--surface-2);
    color: var(--ink);
    transform: translateX(2px);
}

.dropdown-flag {
    width: 22px;
    height: 22px;
    border-radius: 50%;
    flex-shrink: 0;
    box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.1);
    transition: box-shadow 0.15s ease;
}

.dropdown-flag-es {
    background: linear-gradient(to bottom, #c60b1e 0 25%, #ffc400 25% 75%, #c60b1e 75% 100%);
}

.dropdown-flag-fr {
    background: linear-gradient(to right, #0055a4 0 33.33%, #ffffff 33.33% 66.66%, #ef4135 66.66% 100%);
}

.navbar .dropdown-menu a:hover .dropdown-flag-es {
    box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.1), 0 0 0 3px var(--color-acc-bg);
}

.navbar .dropdown-menu a:hover .dropdown-flag-fr {
    box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.1), 0 0 0 3px var(--color-nom-bg);
}

.dropdown-lang-name {
    flex: 1;
}

.dropdown-soon-badge {
    font-family: var(--mono);
    font-size: 0.58rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--gold);
    background: var(--gold-soft);
    padding: 3px 7px;
    border-radius: 999px;
    flex-shrink: 0;
}

.nav-toggle {
    display: none;
    flex-direction: column;
    gap: 4px;
    background: none;
    border: none;
    cursor: pointer;
    padding: 8px;
}

.nav-toggle span {
    width: 22px;
    height: 2px;
    background: var(--ink);
    border-radius: 2px;
    transition: transform 0.2s ease, opacity 0.2s ease;
}

@media (max-width: 860px) {
    .nav-links {
        position: fixed;
        inset: 60px 0 auto 0;
        background: var(--surface);
        flex-direction: column;
        align-items: stretch;
        padding: 10px;
        border-bottom: 1px solid var(--line);
        box-shadow: var(--shadow-md);
        transform: translateY(-8px);
        opacity: 0;
        visibility: hidden;
        transition: opacity 0.18s ease, transform 0.18s ease, visibility 0.18s;
        gap: 2px;
    }

    .nav-links.open {
        transform: translateY(0);
        opacity: 1;
        visibility: visible;
    }

    .nav-links > a,
    .navbar .dropdown-trigger {
        width: 100%;
    }

    .navbar .dropdown-menu {
        position: static;
        box-shadow: none;
        border: none;
        padding-left: 14px;
        margin-top: 0;
        opacity: 1;
        visibility: visible;
        transform: none;
        display: none;
    }

    .navbar .dropdown-menu::before {
        display: none;
    }

    .navbar .dropdown-item.open .dropdown-menu {
        display: flex;
    }

    .nav-toggle {
        display: flex;
    }
}

/* ================= PAGE / BACK LINK ================= */
.lt-main {
    width: 100%;
    max-width: 1280px;
    margin: 0 auto;
    padding: 94px 16px 80px;
    display: flex;
    flex-direction: column;
    gap: 22px;
    min-height: 100vh;
    position: relative;
}

/* Soft ambient glow behind the whole page, sitting under everything else —
   pure decoration, built from the existing accent/gold tokens only. */
.lt-main::before {
    content: "";
    position: fixed;
    inset: 0;
    z-index: -1;
    background:
        radial-gradient(640px 420px at 14% 8%, var(--accent-soft), transparent 60%),
        radial-gradient(560px 380px at 92% 18%, var(--gold-soft), transparent 60%);
    opacity: 0.7;
    pointer-events: none;
}

/* Icon-only "back to course" link, sitting in the top bar to the left of
   the chapters dropdown — just the small red arrow, no pill/label, so it
   reads as a compact nav-bar back button rather than a separate element
   above the layout. Sized with the same padding recipe as the other
   topbar buttons (mode buttons, chapter trigger) instead of a fixed
   30x30 box, so its height lines up with them exactly instead of looking
   slightly off against their padding-driven height. */
.lt-back-link-icon-only {
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 9px;
    border-radius: 10px;
    color: var(--bad);
    flex-shrink: 0;
    transition: background 0.15s ease, transform 0.15s ease;
}

.lt-back-link-icon-only:hover {
    background: var(--bad-soft);
    transform: translateX(-2px);
}

/* ================= LAYOUT ================= */
/* Single column now: the top bar (chapters + mode + stats) sits above the
   content, which is free to use the page's full width instead of sharing
   it with a left sidebar. */
.lt-layout {
    display: flex;
    flex-direction: column;
    gap: 14px;
}

/* ================= TOP BAR: CHAPTERS + MODE + STATS =================
   One thin navbar-style strip above the sentence box, left to right:
   the chapters dropdown, then the German Text / Function / Vocab
   display-mode switch, then the two running lesson stats. Used to be a
   sticky left sidebar of three separate stacked cards; now everything
   shares a single flat row, thin dividers marking the three groups
   instead of card borders/shadows on each. Still sticky, so chapter
   jumping, mode switching, and the stats stay reachable while scrolling
   through a long passage. */
.lt-topbar {
    position: sticky;
    top: 78px;
    z-index: 15;
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 2px;
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: 14px;
    padding: 6px 10px;
    box-shadow: var(--shadow-md);
}

.lt-topbar-divider {
    align-self: stretch;
    width: 1px;
    min-height: 22px;
    margin: 0 6px;
    background: var(--line);
    flex-shrink: 0;
}

@media (max-width: 720px) {
    .lt-topbar {
        position: static;
    }

    .lt-topbar-divider {
        display: none;
    }
}

/* Small caption that used to live inside the Display Mode card; now sits
   just under the thin top bar instead, since there's no room left inside
   it for a hint line. */
.lt-mode-rail-hint {
    margin: 0;
    padding: 0 4px;
    font-size: 0.72rem;
    line-height: 1.4;
    color: var(--ink-faint);
}

/* ---- Chapters dropdown: trigger button + popover menu. The trigger
   shows the current chapter; clicking it reveals .lt-chapter-nav as a
   popover list of every chapter, one box per chapter. Each box turns
   green once THAT chapter's lesson (all blocks' reveal/cloze/vocab
   cycle) is fully done — see markChapterComplete()/CHAPTER_PROGRESS_KEY
   in the JS, which persists completion per chapter via localStorage so a
   box for a chapter you're not currently on can still show as done. The
   chapter you're currently reading is marked .is-current. Opens on
   click, stays open until you click away or press Escape (same "sticky
   popup" pattern used elsewhere on this page) — see
   wireChapterDropdown() in the JS. ---- */
.lt-chapter-dropdown {
    position: relative;
    flex-shrink: 0;
}

.lt-chapter-dropdown-trigger {
    display: flex;
    align-items: center;
    gap: 8px;
    font-family: inherit;
    text-align: left;
    background: transparent;
    border: 1px solid transparent;
    border-radius: 10px;
    padding: 8px 10px;
    cursor: pointer;
    transition: background 0.15s ease, border-color 0.15s ease;
}

.lt-chapter-dropdown-trigger:hover {
    background: var(--surface-2);
}

.lt-chapter-dropdown-trigger[aria-expanded="true"] {
    background: var(--accent-soft);
    border-color: var(--accent);
}

.lt-chapter-dropdown-trigger-label {
    font-family: var(--mono);
    font-size: 0.6rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--ink-faint);
    flex-shrink: 0;
}

.lt-chapter-dropdown-current {
    max-width: 170px;
    font-family: var(--serif);
    font-size: 0.86rem;
    font-weight: 700;
    color: var(--ink);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.lt-chapter-dropdown-caret {
    flex-shrink: 0;
    font-size: 0.7em;
    color: var(--ink-faint);
    transition: transform 0.15s ease;
}

.lt-chapter-dropdown-trigger[aria-expanded="true"] .lt-chapter-dropdown-caret {
    transform: rotate(180deg);
}

.lt-chapter-nav {
    position: absolute;
    top: calc(100% + 10px);
    left: 0;
    z-index: 20;
    flex-direction: column;
    gap: 6px;
    width: max(270px, 100%);
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: 18px;
    padding: 12px;
    box-shadow: var(--shadow-lg);
    max-height: min(420px, 70vh);
    overflow-y: auto;
    scrollbar-width: none; /* Firefox */
    -ms-overflow-style: none; /* legacy Edge/IE */
}

.lt-chapter-nav::-webkit-scrollbar {
    display: none; /* Chrome/Safari/Edge Chromium */
}

.lt-chapter-nav[hidden] {
    display: none;
}

.lt-chapter-nav:not([hidden]) {
    display: flex;
    animation: lt-chapter-nav-in 0.15s ease;
}

@keyframes lt-chapter-nav-in {
    from { opacity: 0; transform: translateY(-4px); }
    to { opacity: 1; transform: translateY(0); }
}

/* Chapter number now sits below the chapter name (HTML order: name span
   first, label span second) instead of beside it — with 10 chapters, a
   side-by-side "Chapter 1" vs "Chapter 10" pushed names to two different
   starting positions; stacked, every name lines up flush left the same
   way regardless of how wide its own number is. */
.lt-chapter-box {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 2px;
    text-decoration: none;
    background: var(--surface-2);
    border: 1px solid var(--line);
    border-radius: 12px;
    padding: 10px 14px;
    transition: transform 0.15s ease, box-shadow 0.15s ease, border-color 0.15s ease, background 0.15s ease;
}

.lt-chapter-box:hover {
    transform: translateY(-1px);
    box-shadow: var(--shadow-sm);
    border-color: var(--accent);
}

.lt-chapter-box-label {
    font-family: var(--mono);
    font-size: 0.6rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--ink-faint);
}

.lt-chapter-box-name {
    font-family: var(--serif);
    font-size: 0.92rem;
    font-weight: 700;
    color: var(--ink);
}

.lt-chapter-box.is-current {
    background: var(--accent-soft);
    border-color: var(--accent);
}

.lt-chapter-box.is-current .lt-chapter-box-label {
    color: var(--accent);
}

.lt-chapter-box.is-complete {
    background: var(--good-soft);
    border-color: var(--good);
}

.lt-chapter-box.is-complete .lt-chapter-box-label,
.lt-chapter-box.is-complete .lt-chapter-box-name {
    color: var(--good);
}

/* ---- Display-mode switch: German Text / Function / Vocab ---- */
.lt-mode-rail {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 2px;
    flex-shrink: 0;
}

.lt-mode-btn {
    display: flex;
    align-items: center;
    gap: 6px;
    font-family: var(--mono);
    font-size: 0.68rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.02em;
    color: var(--ink-soft);
    background: transparent;
    border: 1px solid transparent;
    border-radius: 10px;
    padding: 8px 10px;
    cursor: pointer;
    transition: background 0.15s ease, color 0.15s ease, opacity 0.15s ease, transform 0.1s ease;
}

.lt-mode-btn-icon {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 15px;
    height: 15px;
    color: inherit;
    flex-shrink: 0;
}

.lt-mode-btn:hover:not(:disabled) {
    background: var(--surface-2);
    color: var(--ink);
}

.lt-mode-btn.is-active {
    background: var(--accent-soft);
    color: var(--accent);
}

.lt-mode-btn:active:not(:disabled) {
    transform: scale(0.97);
}

.lt-mode-btn:disabled {
    opacity: 0.35;
    cursor: not-allowed;
}

/* ---- Lesson stats: Unique Root Words / Functions Known ---- */
.lt-stats-box {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 2px;
    flex-shrink: 0;
}

.lt-stats-item {
    position: relative;
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 8px 10px;
    border-radius: 10px;
}

.lt-stats-item-icon {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 15px;
    height: 15px;
    color: var(--ink-faint);
    flex-shrink: 0;
}

.lt-stats-item-text {
    display: flex;
    align-items: baseline;
    gap: 5px;
    min-width: 0;
}

.lt-stats-item-num {
    font-family: var(--serif);
    font-size: 1rem;
    font-weight: 800;
    color: var(--ink);
    line-height: 1.2;
    font-variant-numeric: tabular-nums;
}

.lt-stats-item-label {
    font-family: var(--mono);
    font-size: 0.58rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    color: var(--ink-faint);
    white-space: nowrap;
}

/* ================= RIGHT: CONTENT ================= */
.lt-content {
    display: flex;
    flex-direction: column;
    gap: 16px;
    min-width: 0;
}

/* Count of rows marked Unknown in the Functions panel, poking out of the
   top-right corner of the now-compact "Functions Known" stat item. */
.lt-fn-unknown-badge {
    position: absolute;
    top: -6px;
    right: -6px;
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 18px;
    height: 18px;
    padding: 0 4px;
    border-radius: 999px;
    background: var(--bad-soft);
    color: var(--bad);
    font-family: var(--mono);
    font-size: 0.62rem;
    font-weight: 800;
    font-variant-numeric: tabular-nums;
    border: 2px solid var(--surface);
}

.lt-fn-unknown-badge[hidden] {
    display: none;
}

/* ================= FUNCTIONS PANEL =================
   Styled to match german-coordinating-conjunctions-guide.html's content
   cards: a .hub-tag-badge sitting above a bold serif heading, and rows
   that read like its .cc-join-row — flat var(--surface-2) tint, no
   border, pill-badge label — instead of the bordered-card look this
   panel used before. A standalone, always-visible list of numbered rows
   (see LESSON_FUNCTIONS in the JS) — replaces the old click-Function/
   hover-a-word popup. Known turns a row green and counts once toward
   "Functions Known"; Unknown turns it red and never counts, the same
   desirable/undesirable coloring used for the adjective pairs on
   german-a1-adjective-opposites.html. */
.lt-functions-panel {
    padding: 32px 34px;
    border-radius: 22px;
}

.lt-functions-panel h2 {
    font-family: var(--serif);
    font-size: 1.35rem;
    font-weight: 800;
    color: var(--ink);
    margin: 0;
}

.lt-fn-list {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

/* Groups LESSON_FUNCTIONS by which chapter first introduced each one (see
   LESSON_FUNCTIONS_SECTION_BREAKS in the JS) — cumulative from chapter 2
   onward, so a later chapter's panel shows every earlier chapter's
   Functions too, not just its own. Unused on chapter 1 (single chapter,
   no grouping needed there), so this rule sits idle on that page. */
.lt-fn-section-header {
    font-family: var(--mono);
    font-size: 0.68rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--ink-faint);
    padding-bottom: 6px;
    margin-top: 6px;
    border-bottom: 1px dashed var(--line);
}

.lt-fn-section-header:first-child {
    margin-top: 0;
}

/* Each row's topic sets --fn-accent/--fn-accent-bg (see the [data-topic]
   blocks below) — a soft topic-tinted wash for the row itself, plus a
   matching left accent bar and a solid-fill number badge, mirroring the
   accusative case guide's tinted rule-band + solid transform-word
   treatment (german-accusative-case-guide.css). Rows with no matching
   topic just fall back to the neutral --surface-2 look. */
.lt-fn-row {
    display: flex;
    flex-direction: column;
    padding: 16px 18px;
    border-radius: 14px;
    background: var(--fn-accent-bg, var(--surface-2));
    border-left: 4px solid var(--fn-accent, transparent);
    transition: background 0.15s ease;
}

.lt-fn-row-main {
    display: flex;
    align-items: center;
    gap: 16px;
}

/* Extends the row downward in place of a popup when Unknown is clicked
   on a row that has quiz data (see LESSON_FUNCTIONS' `quizzes`). Rendered
   as its own white content card floating on the row's topic-tinted
   background — the same "white card nested in an accent-tinted band"
   motif as the accusative case guide's .acg-transform-row cards inside
   .acg-rule-band (german-accusative-case-guide.css). */
.lt-fn-row-expand {
    display: none;
}

.lt-fn-row.is-expanded .lt-fn-row-expand {
    display: block;
    margin-top: 16px;
    padding: 20px 22px;
    border-radius: 14px;
    background: var(--surface);
    box-shadow: var(--shadow-sm);
}

.lt-fn-row-number {
    flex-shrink: 0;
    font-family: var(--mono);
    font-size: 0.68rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    color: #ffffff;
    background: var(--fn-accent, var(--accent));
    padding: 4px 10px;
    border-radius: 999px;
    transition: background 0.15s ease, color 0.15s ease;
}

/* Ties a row back to its highlighted word in the passage (see
   .lt-topic-nom/.lt-topic-acc) — each topic sets the two
   custom properties .lt-fn-row/.lt-fn-row-number read above (soft tinted
   row + solid accent badge + matching left bar), so the connection reads
   at a glance. Known/Unknown state (below) still wins once you've marked
   the row either way. */
.lt-fn-row[data-topic="nom"] {
    --fn-accent: var(--color-nom);
    --fn-accent-bg: var(--color-nom-bg);
}

.lt-fn-row[data-topic="acc"] {
    --fn-accent: var(--color-acc);
    --fn-accent-bg: var(--color-acc-bg);
}

/* Irregular-verb / regular-verb / infinitive Functions — see
   IRREGULAR_CONJUGATED_FORMS etc. in the JS, and the --color-vir/vre/inf
   tokens above. */
.lt-fn-row[data-topic="vir"] {
    --fn-accent: var(--color-vir);
    --fn-accent-bg: var(--color-vir-bg);
}

.lt-fn-row[data-topic="vre"] {
    --fn-accent: var(--color-vre);
    --fn-accent-bg: var(--color-vre-bg);
}

.lt-fn-row[data-topic="inf"] {
    --fn-accent: var(--color-inf);
    --fn-accent-bg: var(--color-inf-bg);
}

/* Coordinating / subordinating conjunction Functions — see
   COORDINATING_CONJUNCTIONS/SUBORDINATING_CONJUNCTIONS in the JS. */
.lt-fn-row[data-topic="ccj"] {
    --fn-accent: var(--color-ccj);
    --fn-accent-bg: var(--color-ccj-bg);
}

.lt-fn-row[data-topic="scj"] {
    --fn-accent: var(--color-scj);
    --fn-accent-bg: var(--color-scj-bg);
}

/* Adverbs / adverbial phrases Function — see ADVERB_PHRASES in the JS. */
.lt-fn-row[data-topic="adv"] {
    --fn-accent: var(--color-adv);
    --fn-accent-bg: var(--color-adv-bg);
}

/* Predicate adjectives Function — see PREDICATE_ADJECTIVE_PHRASES/
   PREDICATE_ADJECTIVE_WORDS in the JS. */
.lt-fn-row[data-topic="prd"] {
    --fn-accent: var(--color-prd);
    --fn-accent-bg: var(--color-prd-bg);
}

/* Accusative case Function — see ACCUSATIVE_PHRASES in the JS. */
.lt-fn-row[data-topic="akk"] {
    --fn-accent: var(--color-akk);
    --fn-accent-bg: var(--color-akk-bg);
}

/* Attributive adjectives Function — see ATTRIBUTIVE_ADJECTIVE_PHRASES in
   the JS. */
.lt-fn-row[data-topic="atr"] {
    --fn-accent: var(--color-atr);
    --fn-accent-bg: var(--color-atr-bg);
}

/* Negation Function — see NEGATION_WORDS in the JS. */
.lt-fn-row[data-topic="ngt"] {
    --fn-accent: var(--color-ngt);
    --fn-accent-bg: var(--color-ngt-bg);
}

/* Prepositions Function — see PREPOSITION_PHRASES in the JS. */
.lt-fn-row[data-topic="prp"] {
    --fn-accent: var(--color-prp);
    --fn-accent-bg: var(--color-prp-bg);
}

/* Demonstrative pronoun Function — see DAS_HOVER_PHRASE in the JS. */
.lt-fn-row[data-topic="dem"] {
    --fn-accent: var(--color-dem);
    --fn-accent-bg: var(--color-dem-bg);
}

/* Fixed-idiom Function — see ALLES_GUTE_HOVER_PHRASE in the JS. */
.lt-fn-row[data-topic="idm"] {
    --fn-accent: var(--color-idm);
    --fn-accent-bg: var(--color-idm-bg);
}

/* Comparative adjectives Function — see COMPARATIVE_PHRASES/COMPARATIVE_WORDS
   in german-a1-part-3-personal-descriptions.js (Chapter 3, where this Function originates). */
.lt-fn-row[data-topic="cmp"] {
    --fn-accent: var(--color-cmp);
    --fn-accent-bg: var(--color-cmp-bg);
}

/* Superlative adjectives Function — see SUPERLATIVE_WORDS in
   german-a1-part-5-restaurant-food.js (Chapter 5, where this Function originates). */
.lt-fn-row[data-topic="sup"] {
    --fn-accent: var(--color-sup);
    --fn-accent-bg: var(--color-sup-bg);
}

.lt-fn-row-text {
    flex: 1 1 auto;
    font-family: var(--serif);
    font-size: 0.92rem;
    line-height: 1.55;
    color: var(--ink-soft);
}

.lt-fn-row .lt-popup-actions {
    flex-shrink: 0;
    margin-top: 0;
    width: 140px;
}

.lt-fn-row.is-known {
    background: var(--good-soft);
    border-left-color: var(--good);
}

.lt-fn-row.is-known .lt-fn-row-number {
    background: var(--good);
    color: #ffffff;
}

.lt-fn-row.is-known .lt-fn-row-text {
    color: var(--good);
}

/* Once a Function is marked Known, the Known/Unknown controls
   disappear — there's nothing left to decide. Covers both the
   Functions-panel row's own button pair (.lt-fn-row.is-known, set by
   setFunctionRowState()) and every grammar-trigger popup for that same
   Function (.lt-popup-actions.is-known, set directly on the popup's own
   actions element — see the "known" click handler and
   openGrammarPopupFor() in the JS, the latter syncing this on open so
   even a DIFFERENT instance of an already-known trigger word opens
   without the controls). */
.lt-fn-row.is-known .lt-popup-actions,
.lt-popup-actions.is-known {
    display: none;
}

.lt-fn-row.is-unknown {
    background: var(--bad-soft);
    border-left-color: var(--bad);
}

.lt-fn-row.is-unknown .lt-fn-row-number {
    background: var(--bad);
    color: #ffffff;
}

.lt-fn-row.is-unknown .lt-fn-row-text {
    color: var(--bad);
}

/* Brief flash when the grammar popup's Unknown button jumps here, so the
   row you were sent to is obvious even after the scroll settles. */
.lt-fn-row.lt-fn-highlight {
    animation: lt-fn-highlight-flash 1.6s ease;
}

@keyframes lt-fn-highlight-flash {
    0%, 100% { box-shadow: none; }
    25%, 70% { box-shadow: 0 0 0 4px var(--gold-soft); }
}

/* ================= TEXT CARD ================= */
.lt-text-card {
    position: relative;
    padding: 40px 46px;
    border: none;
    border-radius: 26px;
    min-height: 70vh;
    display: flex;
    flex-direction: column;
    gap: 20px;
    background: linear-gradient(175deg, var(--surface) 0%, var(--surface-2) 100%);
    box-shadow: var(--shadow-lg);
}

.lt-text-card-header {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    flex-wrap: wrap;
}

.lt-text-card-header-actions {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-shrink: 0;
}

.lt-text-card-title {
    margin: 0;
    font-family: var(--serif);
    font-size: clamp(1.3rem, 1.05rem + 1vw, 1.7rem);
    font-weight: 700;
    color: var(--ink);
}

/* Bypasses the reveal/cloze/vocab-pick activities entirely and shows the
   whole passage at once (see skipToFullText() in the JS) — for anyone who
   just wants to read the chapter instead of working through it block by
   block. */
.lt-skip-btn {
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-family: var(--mono);
    font-size: 0.64rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    color: var(--ink-soft);
    background: var(--surface-2);
    border: 1px solid var(--line);
    border-radius: 999px;
    padding: 7px 14px 7px 10px;
    cursor: pointer;
    transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease, transform 0.15s ease;
}

.lt-skip-btn:hover {
    background: var(--accent-soft);
    color: var(--accent);
    border-color: var(--accent);
    transform: translateY(-1px);
}

.lt-skip-btn-icon {
    display: flex;
    align-items: center;
    justify-content: center;
}

/* Only shown during the cloze (fill-in-the-blank) phase — see
   startClozePhase()/startVocabPhase()/skipToFullText() in the JS, which
   toggle this button's [hidden] alongside .lt-hint-popup's. Clicking it
   doesn't touch the blank inputs at all, it just shows the current
   block's plain German text (with the answers included) in the popup
   below, for anyone stuck. */
.lt-hint-btn {
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-family: var(--mono);
    font-size: 0.64rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    color: var(--gold);
    background: var(--gold-soft);
    border: 1px solid var(--gold);
    border-radius: 999px;
    padding: 7px 14px 7px 10px;
    cursor: pointer;
    transition: background 0.15s ease, transform 0.15s ease;
}

.lt-hint-btn:hover {
    transform: translateY(-1px);
}

.lt-hint-btn-icon {
    display: flex;
    align-items: center;
    justify-content: center;
}

.lt-hint-btn[hidden] {
    display: none;
}

.lt-hint-popup[hidden] {
    display: none;
}

.lt-hint-popup {
    position: absolute;
    z-index: 20;
    top: 100%;
    right: 0;
    margin-top: 8px;
    display: flex;
    flex-direction: column;
    gap: 4px;
    width: max-content;
    max-width: min(420px, calc(100vw - 48px));
    padding: 14px 18px;
    border-radius: 14px;
    background: var(--surface);
    border: 1px solid var(--gold);
    box-shadow: var(--shadow-lg);
    animation: lt-grammar-popup-in 0.15s ease;
}

.lt-hint-popup-label {
    font-family: var(--mono);
    font-size: 0.6rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--gold);
}

.lt-hint-popup-text {
    font-family: var(--serif);
    font-size: 0.94rem;
    line-height: 1.5;
    color: var(--ink);
}

.lt-text-card[hidden] {
    display: none;
}

/* Shown once a chapter's reveal/cloze/vocab cycle is fully done (see
   goToNextBlock()'s phase = "done" branch in the JS) — using "Show Full
   Text" to skip ahead doesn't trigger this, only actually finishing the
   chapter does. */
.lt-chapter-complete {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 12px;
    margin-top: 16px;
    padding: 14px 16px;
    border-radius: 12px;
    background: var(--good-soft);
    border: 1px solid var(--good);
}

.lt-chapter-complete[hidden] {
    display: none;
}

.lt-chapter-complete-badge {
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--good);
    flex-shrink: 0;
}

.lt-chapter-complete-text {
    font-family: var(--mono);
    font-size: 0.7rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    color: var(--good);
    flex: 1 1 auto;
}

.lt-continue-btn {
    display: inline-flex;
    align-items: center;
    font-family: var(--mono);
    font-size: 0.68rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    color: #ffffff;
    background: var(--accent);
    border: none;
    border-radius: 999px;
    padding: 9px 18px;
    text-decoration: none;
    cursor: pointer;
    transition: opacity 0.15s ease, transform 0.1s ease;
}

.lt-continue-btn:hover {
    opacity: 0.85;
}

.lt-continue-btn:active {
    transform: scale(0.96);
}

/* Countdown shown top-right before the cloze blanks pop up: a depleting
   ring driven by --pct (set from JS each tick), with the number in the
   center via an inset ::before circle. */
.lt-countdown[hidden] {
    display: none;
}

/* Lives in the top bar now (far right, pushed there by margin-left: auto)
   instead of floating over the text card's corner — sized down to fit
   the thin navbar-style bar. */
.lt-countdown {
    position: relative;
    margin-left: auto;
    flex-shrink: 0;
    width: 32px;
    height: 32px;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    background: conic-gradient(var(--gold) calc(var(--pct, 100) * 1%), var(--gold-soft) 0);
    box-shadow: var(--shadow-sm);
    animation: lt-countdown-pulse 1s ease infinite;
}

.lt-countdown::before {
    content: "";
    position: absolute;
    inset: 4px;
    border-radius: 50%;
    background: var(--surface);
}

.lt-countdown-num {
    position: relative;
    z-index: 1;
    font-family: var(--mono);
    font-size: 0.76rem;
    font-weight: 800;
    color: var(--gold);
    font-variant-numeric: tabular-nums;
}

@keyframes lt-countdown-pulse {
    0%, 100% { transform: scale(1); }
    50% { transform: scale(1.05); }
}

.lt-text {
    position: relative;
    z-index: 1;
    font-family: var(--serif);
    font-size: 1.3rem;
    line-height: 2.15;
    letter-spacing: 0.003em;
    color: var(--ink);
    max-width: 62ch;
}

/* EXPERIMENTAL (Chapter 1 only): applied by lockTextCardHeight() in the JS
   once the 3rd block divider appears — .lt-text-card gets a fixed height
   set inline at that moment, and this turns .lt-text into the scrollable
   pane that fills whatever space is left in the now-fixed card, so
   further sentences scroll into view internally instead of growing the
   page. min-height: 0 is required for a flex child to actually shrink
   and scroll rather than overflow its parent. */
.lt-text.is-height-locked {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    padding-right: 10px;
    scrollbar-width: none; /* Firefox */
    -ms-overflow-style: none; /* legacy Edge/IE */
}

.lt-text.is-height-locked::-webkit-scrollbar {
    display: none; /* Chrome/Safari/Edge Chromium */
}

.lt-sentence {
    position: relative;
    margin-right: 0.3em;
}

/* Separates each 5-sentence block from the next inside the passage — same
   dashed rule used above the mode rail's hint text. */
.lt-block-divider {
    display: block;
    width: 100%;
    border: none;
    border-top: 1px dashed var(--line);
    margin: 16px 0;
}

/* Highlight-to-translate: select any text in a sentence and everything
   else blurs, while a card popup (styled like the grammar popup) shows
   that sentence's English translation near the selection. */
.lt-text.lt-selecting .lt-sentence {
    filter: blur(4px);
    opacity: 0.4;
    transition: filter 0.2s ease, opacity 0.2s ease;
}

.lt-text.lt-selecting .lt-sentence.lt-select-active {
    filter: none;
    opacity: 1;
}

.lt-select-popup[hidden] {
    display: none;
}

.lt-select-popup {
    position: absolute;
    z-index: 20;
    display: flex;
    flex-direction: column;
    gap: 4px;
    width: max-content;
    max-width: 280px;
    padding: 14px 18px;
    border-radius: 14px;
    background: var(--surface);
    border: none;
    box-shadow: var(--shadow-lg);
    filter: none;
    animation: lt-grammar-popup-in 0.15s ease;
}

.lt-select-popup-label {
    font-family: var(--mono);
    font-size: 0.6rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--ink-faint);
}

.lt-select-popup-text {
    font-family: var(--serif);
    font-size: 0.94rem;
    line-height: 1.5;
    color: var(--ink);
}

/* Known/Unknown — shared by the Functions panel rows and the grammar
   popup (the translate/highlight popup has neither anymore — it's plain
   translation display only, not tied to any Function). "Known" bumps the
   Functions Known counter; "Unknown" opens the shared quiz popup (see
   .lt-quiz-popup below). */
.lt-popup-actions {
    display: flex;
    gap: 8px;
    margin-top: 4px;
}

.lt-known-btn,
.lt-unknown-btn {
    flex: 1;
    font-family: var(--mono);
    font-size: 0.64rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    border: none;
    border-radius: 999px;
    padding: 6px 10px;
    cursor: pointer;
    transition: opacity 0.15s ease, transform 0.1s ease;
}

.lt-known-btn:hover,
.lt-unknown-btn:hover {
    opacity: 0.85;
}

.lt-known-btn:active,
.lt-unknown-btn:active {
    transform: scale(0.96);
}

.lt-known-btn {
    background: var(--good);
    color: #ffffff;
}

.lt-unknown-btn {
    background: var(--bad);
    color: #ffffff;
}

/* Hoverable grammar callouts ("Es", "ist", "ein neuer Tag"): a muted
   topic-color background instead of an underline, using the same
   --color-* tokens as the site's bracket-highlight system elsewhere. Each
   trigger's color matches the accent on its corresponding row in the
   Functions panel (see .lt-fn-row[data-topic]) — .lt-topic-acc (es, an
   impersonal/dummy subject) and .lt-topic-nom (nominative-case adjective
   ending) each point at their own row; "ist" has no dedicated row of its
   own anymore — sein is just one entry in the generic .lt-topic-vir
   (irregular verb) bucket, same as every other irregular verb — so the
   highlight color is the visual thread connecting "this word in the
   story" to "its breakdown in the Functions panel". Independent of the
   German/Function toggle — works
   in any mode. Clicking it opens the popup (JS adds .lt-grammar-open),
   and it then stays open — via :has() targeting the sticky class — until
   a click lands outside it, blurring every other sentence the whole
   time. No position: relative here anymore: the popup is positioned by
   JS relative to .lt-text-card (like the highlight-to-translate popup
   below), not relative to the word itself. */
.lt-grammar-trigger {
    cursor: pointer;
    border-radius: 4px;
    padding: 0.05em 0.15em;
    margin: 0 -0.15em;
}

/* Underline a trigger word while its popup is open (JS toggles
   .lt-grammar-open on click — see openGrammarPopupFor()/
   closeGrammarPopup()) — layers on top of the trigger's normal
   topic-colored highlight, not a replacement for it, and disappears the
   moment the popup closes (click elsewhere). Excludes the "!"
   preview-marker badges (see below) — those are a small circle, not
   inline text, and already get their own open-state accent. */
.lt-grammar-trigger.lt-grammar-open:not(.lt-preview-marker) {
    text-decoration: underline;
    text-decoration-thickness: 1.5px;
    text-underline-offset: 2px;
}

/* Secondary-Function accent, for when two Functions' triggers land on
   the EXACT same span (e.g. "ist" is both the sein-showcase AND a
   generic irregular-verb trigger) — see groupOverlappingTriggers() in
   the JS. The primary Function still owns the span's background fill
   (.lt-topic-X, unchanged); this layers a colored underline for the
   second one on top, so both are visible and distinguishable without
   picking a winner. The color comes from a --dual-color custom property
   set per-instance in the JS (one generic rule instead of enumerating
   every topic-code pair). Repeated with .lt-grammar-open appended, at
   equal specificity but later in source order, so the colored accent
   keeps winning over the plain open-state underline above while the
   popup — which now shows BOTH Functions' explanations side by side
   (see .lt-grammar-popup-dual below), not stacked — is open. */
.lt-grammar-trigger.lt-dual-secondary,
.lt-grammar-trigger.lt-dual-secondary.lt-grammar-open {
    text-decoration-line: underline;
    text-decoration-thickness: 2px;
    text-underline-offset: 3px;
    text-decoration-color: var(--dual-color, currentColor);
}

/* Wider variant of .lt-grammar-popup for a dual/coincident trigger (see
   above): the two Functions' explanations sit in side-by-side columns
   instead of one stacked under the other, each with its own independent
   Known/Unknown controls. flex-wrap (rather than a separate narrow-
   viewport media query) lets the columns fall back to stacking on their
   own once the popup's max-width can't fit both side by side.

   max-width alone is safe to set unconditionally (it only matters once
   something makes the popup visible in the first place) — but it needs
   BOTH classes (.lt-grammar-popup.lt-grammar-popup-dual, not just
   .lt-grammar-popup-dual alone) to reliably beat the base
   .lt-grammar-popup's own max-width rule further down: a single-class
   selector here would be equal specificity to that base rule, so
   whichever comes later in source order would silently win regardless
   of intent (this WAS happening — dual popups were quietly capped at
   the single-popup width the whole time before this was two classes).

   display MUST stay scoped to the .lt-grammar-open state, in its own
   rule below, and never added to this same two-class selector — THIS
   selector's two classes genuinely do outrank the base
   ".lt-grammar-popup { display: none }" rule (0-2-0 beats 0-1-0,
   unlike max-width's situation above), so an unconditional
   "display: flex" here WOULD win even while CLOSED, leaving every dual
   popup permanently visible and stuck at its unpositioned top:0/left:0
   default (openGrammarPopupFor() never runs to place a popup nothing
   ever "opened") — exactly the "popups floating outside the box"
   regression this comment is here to prevent a repeat of. */
.lt-grammar-popup.lt-grammar-popup-dual {
    max-width: min(560px, calc(100vw - 32px));
}

.lt-grammar-trigger.lt-grammar-open > .lt-grammar-popup.lt-grammar-popup-dual {
    display: flex;
    flex-flow: row wrap;
    align-items: stretch;
    gap: 14px;
}

.lt-dual-popup-col {
    flex: 1 1 200px;
    min-width: 0;
}

.lt-dual-popup-divider {
    align-self: stretch;
    width: 1px;
    background: var(--line);
    flex-shrink: 0;
}

/* Dative-case / separable-verb preview marker — a small "!" badge to the
   LEFT of the phrase it's flagging, not a text-highlight. Deliberately
   not one of the --color-* topic tokens: this isn't a Function (no
   Functions-panel row, no goto link in its popup), just a quick note that
   the grammar there is covered properly at a later level. Higher
   specificity than the base .lt-grammar-trigger rule above so its own
   sizing (a small circle, not text padding) wins. */
.lt-grammar-trigger.lt-preview-marker {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.05em;
    height: 1.05em;
    margin: 0 0.2em 0 0;
    padding: 0;
    border-radius: 50%;
    background: var(--ink-faint);
    color: var(--surface);
    font-family: var(--mono);
    font-size: 0.72em;
    font-weight: 800;
    line-height: 1;
    vertical-align: middle;
    transition: background 0.15s ease;
}

.lt-grammar-trigger.lt-preview-marker:hover {
    background: var(--ink-soft);
}

.lt-grammar-trigger.lt-preview-marker.lt-grammar-open {
    background: var(--accent);
    color: #ffffff;
}

.lt-topic-nom {
    background: var(--color-nom-bg);
}

.lt-topic-acc {
    background: var(--color-acc-bg);
}

.lt-topic-vir {
    background: var(--color-vir-bg);
}

.lt-topic-vre {
    background: var(--color-vre-bg);
}

.lt-topic-inf {
    background: var(--color-inf-bg);
}

.lt-topic-ccj {
    background: var(--color-ccj-bg);
}

.lt-topic-scj {
    background: var(--color-scj-bg);
}

.lt-topic-adv {
    background: var(--color-adv-bg);
}

.lt-topic-prd {
    background: var(--color-prd-bg);
}

.lt-topic-akk {
    background: var(--color-akk-bg);
}

.lt-topic-atr {
    background: var(--color-atr-bg);
}

.lt-topic-ngt {
    background: var(--color-ngt-bg);
}

.lt-topic-prp {
    background: var(--color-prp-bg);
}

.lt-topic-dem {
    background: var(--color-dem-bg);
}

.lt-topic-idm {
    background: var(--color-idm-bg);
}

.lt-topic-cmp {
    background: var(--color-cmp-bg);
}

.lt-topic-sup {
    background: var(--color-sup-bg);
}

/* Plain reference text inside a hover popup (e.g. the "Es" note), as
   opposed to the grid-based grammar/conjugation popups. */
.lt-popup-text {
    font-family: var(--serif);
    font-size: 0.85rem;
    line-height: 1.5;
    color: var(--ink-soft);
    margin: 0 0 10px;
    max-width: 230px;
}

/* Same referenceHtml content reused inside the Functions panel's wider
   .lt-fn-row-expand card instead of the narrow hover popup — drop the
   popup's tight max-width and read a touch larger, matching the guide's
   body-copy scale (german-accusative-case-guide.css's .acg-card > p). */
.lt-fn-row-expand .lt-popup-text {
    font-size: 0.92rem;
    max-width: none;
}

.lt-text:has(.lt-grammar-trigger.lt-grammar-open) .lt-sentence:not(:has(.lt-grammar-trigger.lt-grammar-open)) {
    filter: blur(4px);
    opacity: 0.4;
    transition: filter 0.2s ease, opacity 0.2s ease;
}

.lt-grammar-popup {
    display: none;
    /* fixed, not absolute: this popup lives INSIDE #ltText (nested in its
       trigger span), and #ltText becomes a scrollable pane
       (overflow-y: auto, which per the CSS overflow spec also computes
       overflow-x as auto) once the EXPERIMENTAL height-lock kicks in after
       block 3 (see HEIGHT_LOCK_AFTER_BLOCKS in the JS) — an
       absolutely-positioned popup pinned outside #ltText's own width (see
       openGrammarPopupFor()) would silently get clipped by that ancestor
       overflow for every trigger from block 4 onward. position: fixed
       escapes ancestor overflow-clipping entirely (the standard fix for a
       tooltip trapped in a scroll container), which is why
       openGrammarPopupFor() sets left/top as plain viewport coordinates
       now instead of coordinates relative to .lt-text-card. */
    position: fixed;
    top: 0;
    left: 0;
    z-index: 20;
    width: max-content;
    /* Widened + heightened from the original 260px/480px caps — the
       longer, multi-line structured popup texts (predicate/attributive
       adjectives, prepositions, "es") were tall enough to trigger the
       overflow-y scrollbar below at the old size. openGrammarPopupFor()
       already clamps left/top against the popup's real rendered
       size/window bounds, so a bigger box here doesn't risk it running
       off-screen — it just repositions. Still viewport-relative (not a
       fixed size) so it stays safe on narrow/short screens. */
    max-width: min(380px, calc(100vw - 32px));
    max-height: min(85vh, 640px);
    overflow-y: auto;
    padding: 16px 20px;
    border-radius: 14px;
    background: var(--surface);
    border: none;
    box-shadow: var(--shadow-lg);
    filter: none;
    cursor: default;
}

/* Direct-child combinator, not a plain descendant selector: a trigger
   can now have another trigger NESTED inside it (see
   groupOverlappingTriggers()/renderTriggerNode() in the JS, for when two
   Functions' spans overlap without being identical) — a descendant
   selector here would also match the INNER trigger's own popup whenever
   the OUTER one opens, showing a stray unpositioned popup box. */
.lt-grammar-trigger.lt-grammar-open > .lt-grammar-popup {
    display: block;
    animation: lt-grammar-popup-in 0.15s ease;
}

@keyframes lt-grammar-popup-in {
    from { opacity: 0; transform: translateX(-4px); }
    to { opacity: 1; transform: translateX(0); }
}

.lt-gr-row {
    display: grid;
    grid-template-columns: repeat(4, auto);
    gap: 3px 10px;
    align-items: center;
    white-space: nowrap;
    font-family: var(--serif);
    font-size: 0.95rem;
    color: var(--ink);
}

.lt-gr-ending-row {
    margin-bottom: 10px;
}

.lt-gr-gender {
    color: var(--ink-faint);
    font-size: 0.82em;
}

.lt-gr-noun {
    font-weight: 700;
}

.lt-gr-ending {
    display: inline-block;
    color: var(--accent);
    font-weight: 700;
    font-family: var(--mono);
    font-size: 0.78rem;
}

.lt-gr-divider {
    display: block;
    height: 1px;
    background: var(--line);
    margin: 4px 0 10px;
}

/* .continuous-marquee-card (see-test.css) sets `display: flex` as an
   author-origin rule, which beats the browser's built-in
   `[hidden] { display: none }` UA rule regardless of selector specificity
   — so setMode() setting .hidden = true on the Vocab Marquee card had no
   visual effect, and it stayed visible on German Text mode. Same class of
   bug as documented elsewhere in this file (.ch1lab-quiz-active[hidden]
   etc.) — fixed the same way, but scoped to this lesson-page-only marker
   class (see wireVocabMarquee()'s HTML) rather than editing the shared
   .continuous-marquee-card class itself, since the letter-course pages
   that also use that class never toggle it hidden. */
.lt-vocab-marquee-card[hidden] {
    display: none;
}

/* Small mono-uppercase label sitting directly above a conjugation table
   in a hover popup (buildSeinPopupHtml()/irregularVerbPopupHtml()/
   REGULAR_VERB_POPUP_HTML in the JS), naming which of the two
   present-tense patterns it is. Deliberately neutral/ink-colored rather
   than tinted to the "irr"/"vir"/"vre" topic color it happens to be
   inside — "Irregular Verb" should look the same whether it's sitting
   above sein's own table (topic irr) or another irregular verb's (topic
   vir), not shift color depending on which specific verb was clicked. */
.lt-conj-label {
    display: block;
    font-family: var(--mono);
    font-size: 0.66rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--ink-faint);
    margin: 0 0 6px;
}

/* "sein" present-tense conjugation table — shown both in the "ist" hover
   popup and inline on Function 1 (same markup, see seinConjugationTableHtml
   in the JS). */
.lt-conj-table {
    display: grid;
    grid-template-columns: auto auto;
    gap: 5px 16px;
    white-space: nowrap;
    font-family: var(--serif);
    font-size: 0.95rem;
    color: var(--ink);
    margin-bottom: 10px;
}

.lt-conj-pronoun {
    color: var(--ink-faint);
    font-size: 0.82em;
}

.lt-conj-form {
    font-weight: 700;
}

/* ================= INLINE QUIZ CONTENT (Functions panel) =================
   Rendered inside a row's .lt-fn-row-expand instead of a separate popup —
   a single quiz "block" is an info paragraph + question + options; a row
   with multiple blocks (e.g. Function 3, which holds both the "ich" quiz
   and the grammar popup's quiz) stacks them with a divider between. */
.lt-quiz-divider-line {
    border: none;
    border-top: 1px solid var(--line);
    margin: 18px 0;
}

/* Gold-tinted callout box for the quiz's context sentence, same "Quick
   test" treatment as the guide's .acg-verb-test
   (german-accusative-case-guide.css) instead of a plain dashed rule. */
.lt-quiz-info {
    font-family: var(--serif);
    font-size: 0.9rem;
    line-height: 1.55;
    color: var(--ink);
    background: var(--gold-soft);
    border-radius: 12px;
    padding: 12px 16px;
    margin: 0 0 16px;
}

.lt-quiz-question {
    font-family: var(--serif);
    font-weight: 700;
    font-size: 0.98rem;
    color: var(--ink);
    margin: 0 0 12px;
}

.lt-quiz-options {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.lt-quiz-option {
    text-align: left;
    font-family: var(--serif);
    font-size: 0.88rem;
    color: var(--ink);
    background: var(--surface-2);
    border: 1.5px solid var(--line);
    border-radius: 12px;
    padding: 10px 16px;
    cursor: pointer;
    transition: border-color 0.15s ease, background 0.15s ease;
}

.lt-quiz-option:hover {
    border-color: var(--accent);
    background: var(--accent-soft);
}

.lt-quiz-options.is-answered .lt-quiz-option {
    cursor: default;
}

.lt-quiz-options.is-answered .lt-quiz-option:not(.is-correct):not(.is-wrong) {
    opacity: 0.5;
}

.lt-quiz-option.is-correct {
    border-color: var(--good);
    background: var(--good-soft);
    color: var(--good);
    font-weight: 700;
}

.lt-quiz-option.is-wrong {
    border-color: var(--bad);
    background: var(--bad-soft);
    color: var(--bad);
}

.lt-quiz-placeholder {
    font-family: var(--mono);
    font-size: 0.76rem;
    color: var(--ink-faint);
    font-style: italic;
    margin: 0;
}

/* Typewriter word-by-word reveal */
.lt-tw-word {
    display: inline-block;
    opacity: 0;
    transform: translateY(4px);
    animation: lt-tw-word-in 0.22s ease forwards;
}

@keyframes lt-tw-word-in {
    to {
        opacity: 1;
        transform: translateY(0);
    }
}

/* Cloze-phase blanks */
.lt-blank-wrap {
    display: inline-flex;
    align-items: baseline;
    margin: 0 2px;
}

.lt-blank-input {
    width: 5.5em;
    font-family: var(--serif);
    font-size: 1em;
    color: var(--ink);
    background: var(--surface);
    border: 1.5px solid var(--line-strong);
    border-radius: 8px;
    padding: 1px 8px;
    text-align: center;
    box-shadow: var(--shadow-sm);
    transition: border-color 0.15s ease, background 0.15s ease, box-shadow 0.15s ease;
}

.lt-blank-input:focus {
    outline: none;
    border-color: var(--accent);
    box-shadow: 0 0 0 3px var(--accent-soft);
}

.lt-blank-input.is-correct {
    border-color: var(--good);
    background: var(--good-soft);
    color: var(--good);
    font-weight: 700;
    box-shadow: none;
}

.lt-blank-input.is-wrong {
    border-color: var(--bad);
    background: var(--bad-soft);
    animation: lt-shake 0.3s ease;
}

@keyframes lt-shake {
    0%, 100% { transform: translateX(0); }
    25% { transform: translateX(-4px); }
    75% { transform: translateX(4px); }
}

/* ================= EXPERIMENTAL: CHAPTER 1 VOCAB LAB =================
   Flashcard deck + fill-in-the-blank drill, sitting below the vocab
   stream — Chapter 1 only, see CH1_FLASHCARD_DATA/wireVocabLab() in the
   JS. The flashcard box itself reuses see-test.css's shared
   .flashcard- / .card-face / .article-pill-placeholder classes verbatim
   (same markup as the "Flip & Learn" demo on the Letters A-Z page) — only
   the 2x2 grid, the drill box's own blank-fill mechanic, and the
   reserved placeholder boxes are new rules here. */
.ch1lab-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 20px;
    /* stretch (not start): the flashcard box and drill box end up exactly
       the same height regardless of small content differences (header
       text length, etc.) — see the flex-column + flex:1 treatment below,
       which lets each box's "middle" section absorb the shared row
       height instead of needing hand-tuned matching pixel values. */
    align-items: stretch;
}

@media (max-width: 720px) {
    .ch1lab-grid {
        grid-template-columns: 1fr;
    }
}

.ch1lab-flashcard-box,
.ch1lab-drill-box,
.ch1lab-quiz-box,
.ch1lab-builder-box {
    margin: 0 !important;
    display: flex;
    flex-direction: column;
}

/* The flip-card area is the one thing making the flashcard box taller
   than the drill box (that extra Known/Unknown button row has no drill
   equivalent) — shrinking it here, then letting flex:1 below fill
   whatever's left, is what makes the two boxes end up the same size. */
.ch1lab-flashcard-box .flashcard-stage-area {
    flex: 1;
    margin-bottom: 16px !important;
}

.ch1lab-flashcard-box .flashcard-perspective-wrapper {
    height: 200px !important;
}

/* ---- Sequential unlock: the Drill/Quiz/Builder boxes start locked and
   only reveal + begin processing their own queue once the box before
   them reaches its own empty/done terminal state — see
   unlockDrillBox()/unlockQuizBox()/unlockBuilderBox() in the JS. Items
   still accumulate into a locked box's queue in the background (so
   nothing is lost), just without rendering anything until unlock. */
.flashcard-dashboard-card.ch1lab-box-locked {
    opacity: 0.5;
    pointer-events: none;
}

.ch1lab-locked {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 8px;
    text-align: center;
}

/* Same [hidden]-vs-author-display-rule issue as .ch1lab-quiz-active
   below — without this, the locked message would stay visible even
   after the box unlocks and starts rendering real content. */
.ch1lab-locked[hidden] {
    display: none;
}

.ch1lab-locked-icon {
    font-size: 1.4rem;
    opacity: 0.6;
}

.ch1lab-locked p {
    font-size: 0.88rem;
    color: var(--ink-faint);
    line-height: 1.6;
    max-width: 28ch;
    margin: 0;
}

/* ---- Drill box: fill-in-the-blank, fed by flashcards marked Unknown ---- */
.ch1lab-drill-stage {
    flex: 1;
    min-height: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    text-align: center;
    gap: 10px;
}

.ch1lab-drill-empty {
    font-size: 0.88rem;
    color: var(--ink-faint);
    line-height: 1.6;
    max-width: 32ch;
    margin: 0;
}

.ch1lab-drill-sentence-wrap {
    width: 100%;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 14px;
}

/* Same [hidden]-vs-author-display-rule issue as .ch1lab-quiz-active
   above — without this, the fill-in-the-blank input/submit/skip controls
   would stay visible even in the empty/done states. */
.ch1lab-drill-sentence-wrap[hidden] {
    display: none;
}

.ch1lab-drill-sentence {
    font-family: var(--serif);
    font-size: 1.25rem;
    line-height: 1.7;
    color: var(--ink);
    margin: 0;
}

.ch1lab-drill-gloss {
    font-size: 0.8rem;
    font-style: italic;
    color: var(--ink-faint);
    margin: 0;
    min-height: 1.2em;
    opacity: 0;
    transition: opacity 0.2s ease;
}

.ch1lab-drill-gloss.is-visible {
    opacity: 1;
}

.ch1lab-drill-done {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 6px;
}

/* Same [hidden]-vs-author-display-rule issue as .ch1lab-quiz-active
   above, but on the "done" message this time. */
.ch1lab-drill-done[hidden] {
    display: none;
}

.ch1lab-drill-done p {
    margin: 0;
    font-size: 0.92rem;
    color: var(--good);
    font-weight: 700;
}

.ch1lab-drill-blank-wrap {
    display: inline-flex;
    align-items: baseline;
    gap: 6px;
    margin: 0 2px;
}

.ch1lab-drill-blank-input {
    width: 8ch;
    min-width: 8ch;
    font-family: var(--serif);
    font-size: 1em;
    color: var(--ink);
    background: transparent;
    border: none;
    border-bottom: 2px solid var(--accent);
    text-align: center;
    padding: 0 4px 2px;
    outline: none;
}

.ch1lab-drill-blank-input::placeholder {
    color: var(--ink-faint);
    opacity: 0.5;
}

.ch1lab-drill-blank-input:disabled {
    color: inherit;
    opacity: 1;
}

.ch1lab-drill-blank-input.is-correct {
    border-bottom-color: var(--good);
    color: var(--good);
    font-weight: 700;
}

.ch1lab-drill-blank-input.is-wrong {
    border-bottom-color: var(--bad);
    color: var(--bad);
    font-weight: 700;
}

.ch1lab-drill-blank-submit {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 24px;
    height: 24px;
    border-radius: 999px;
    border: none;
    background: var(--accent-soft);
    color: var(--accent);
    cursor: pointer;
    flex-shrink: 0;
    transition: background 0.15s ease, color 0.15s ease, transform 0.1s ease;
}

.ch1lab-drill-blank-submit:hover {
    background: var(--accent);
    color: #ffffff;
}

.ch1lab-drill-blank-submit:active {
    transform: scale(0.94);
}

.ch1lab-drill-blank-submit:disabled {
    display: none;
}

/* For when the learner isn't sure of a drill answer — reveals it instead
   of forcing a guess, without touching the Correct score. */
.ch1lab-drill-skip-btn {
    display: inline-flex;
    align-items: center;
    font-family: var(--mono);
    font-size: 0.6rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    color: var(--ink-faint);
    background: transparent;
    border: none;
    border-bottom: 1px dashed var(--ink-faint);
    padding: 0 0 1px;
    cursor: pointer;
    flex-shrink: 0;
    transition: color 0.15s ease, border-color 0.15s ease;
}

.ch1lab-drill-skip-btn:hover {
    color: var(--accent);
    border-color: var(--accent);
}

.ch1lab-drill-skip-btn:disabled {
    display: none;
}

.ch1lab-drill-blank-input.is-skipped {
    border-bottom-color: var(--ink-faint);
    color: var(--ink-faint);
    font-style: italic;
}

.ch1lab-drill-blank-correction {
    font-family: var(--mono);
    font-size: 0.7rem;
    font-weight: 700;
    color: var(--good);
    text-transform: uppercase;
    letter-spacing: 0.03em;
}

.ch1lab-drill-blank-correction.is-skip {
    color: var(--gold);
}

/* ---- Missed Word Check: 4-answer multiple-choice quiz, fed by drill
   answers that were wrong or skipped (never by correct drill answers) —
   see addToQuizPool()/wireVocabLab() in the JS. .choices-grid/.choice-box
   are see-test.css's shared quiz classes, the same ones
   german-a1-grammar-path.html uses; .choice-box.correct/.incorrect and
   the result-message styling aren't defined there (that reference page
   doesn't style them either), so they're added here. ---- */
.ch1lab-quiz-stage {
    flex: 1;
    min-height: 0;
    width: 100%;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    text-align: center;
    gap: 10px;
}

.ch1lab-quiz-empty {
    font-size: 0.88rem;
    color: var(--ink-faint);
    line-height: 1.6;
    max-width: 32ch;
    margin: 0;
}

.ch1lab-quiz-active {
    width: 100%;
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 10px;
}

/* Without this, the [hidden] attribute JS sets in showQuizEmpty()/
   showQuizDone() has no visual effect: this class's own `display: flex`
   above is an author-stylesheet rule, which beats the browser's built-in
   `[hidden] { display: none }` (a user-agent rule) regardless of
   selector specificity — so the prompt/choices/Check Answer button would
   stay visible with nothing loaded into them. Same fix already applied
   to every other [hidden]-toggled element in this file (.lt-text-card,
   .lt-select-popup, etc.). */
.ch1lab-quiz-active[hidden] {
    display: none;
}

.ch1lab-quiz-prompt {
    font-family: var(--serif);
    font-size: 1.1rem;
    font-weight: 700;
    color: var(--ink);
    text-align: center;
    margin: 0;
}

.ch1lab-quiz-active .choices-grid {
    margin-top: 0;
}

.ch1lab-quiz-result {
    font-family: var(--mono);
    font-size: 0.72rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    text-align: center;
    min-height: 1.2em;
    margin: 0;
    color: var(--ink-faint);
}

.ch1lab-quiz-result.is-success {
    color: var(--good);
}

.ch1lab-quiz-result.is-error {
    color: var(--bad);
}

.ch1lab-quiz-submit-btn {
    background-color: var(--accent) !important;
    align-self: center;
}

.ch1lab-quiz-done {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 6px;
}

/* Same [hidden]-vs-author-display-rule issue as .ch1lab-quiz-active
   above, but on the "done" message this time — without this, "All
   missed words cleared" stays on screen even after a new question loads
   into .ch1lab-quiz-active, since renderCurrentQuizItem() sets this
   element's hidden attribute but that alone has no visual effect. */
.ch1lab-quiz-done[hidden] {
    display: none;
}

.ch1lab-quiz-done p {
    margin: 0;
    font-size: 0.92rem;
    color: var(--good);
    font-weight: 700;
}

/* Not defined anywhere in see-test.css — german-a1-grammar-path.html's own
   quiz never gets this feedback either, but a filled-in color here reads
   much clearer for a quiz that's meant to reinforce a missed word. */
.choice-box.correct {
    background-color: var(--good-soft);
    border-color: var(--good);
}

.choice-box.correct .choice-number {
    background-color: var(--good);
    color: #ffffff;
}

.choice-box.correct .choice-text {
    color: var(--good);
}

.choice-box.incorrect {
    background-color: var(--bad-soft);
    border-color: var(--bad);
}

.choice-box.incorrect .choice-number {
    background-color: var(--bad);
    color: #ffffff;
}

.choice-box.incorrect .choice-text {
    color: var(--bad);
}

/* ---- Word Builder: the missed word gets split into 3 pieces and
   shuffled; click them in order to rebuild it. Fed only by wrong Missed
   Word Check answers — see addToBuilderPool() in the JS. Reuses
   @keyframes lt-shake (already defined above for the drill's wrong-blank
   feedback) for the wrong-attempt shake. ---- */
.ch1lab-builder-stage {
    flex: 1;
    min-height: 0;
    width: 100%;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    text-align: center;
    gap: 10px;
}

.ch1lab-builder-empty {
    font-size: 0.88rem;
    color: var(--ink-faint);
    line-height: 1.6;
    max-width: 32ch;
    margin: 0;
}

.ch1lab-builder-active {
    width: 100%;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 12px;
}

/* Same [hidden]-vs-author-display-rule issue as .ch1lab-quiz-active
   above — without this, the word-piece builder would stay visible even
   in the empty/done states. */
.ch1lab-builder-active[hidden] {
    display: none;
}

.ch1lab-builder-hint {
    font-size: 0.76rem;
    color: var(--ink-faint);
    margin: 0;
}

.ch1lab-builder-assembled {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 4px;
    font-family: var(--serif);
    font-size: 1.3rem;
    font-weight: 700;
    color: var(--ink);
    min-height: 1.6em;
    transition: color 0.15s ease;
}

.ch1lab-builder-slot {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 1.4em;
    padding: 2px 4px;
    border-bottom: 2px solid var(--line);
}

.ch1lab-builder-slot:empty::before {
    content: "\2026";
    color: var(--ink-faint);
    opacity: 0.4;
}

.ch1lab-builder-assembled.is-correct {
    color: var(--good);
}

.ch1lab-builder-assembled.is-correct .ch1lab-builder-slot {
    border-bottom-color: var(--good);
}

.ch1lab-builder-assembled.is-wrong {
    color: var(--bad);
    animation: lt-shake 0.3s ease;
}

.ch1lab-builder-assembled.is-wrong .ch1lab-builder-slot {
    border-bottom-color: var(--bad);
}

.ch1lab-builder-pieces {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: 8px;
}

.ch1lab-builder-piece {
    font-family: var(--serif);
    font-size: 1rem;
    font-weight: 700;
    color: var(--ink);
    background: var(--surface-2);
    border: 1.5px solid var(--line);
    border-radius: 10px;
    padding: 8px 14px;
    cursor: pointer;
    transition: transform 0.1s ease, border-color 0.15s ease, background 0.15s ease, opacity 0.15s ease;
}

.ch1lab-builder-piece:hover:not(:disabled) {
    border-color: var(--accent);
    background: var(--accent-soft);
}

.ch1lab-builder-piece:active:not(:disabled) {
    transform: scale(0.96);
}

.ch1lab-builder-piece:disabled {
    opacity: 0.3;
    cursor: default;
    pointer-events: none;
}

.ch1lab-builder-done {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 6px;
}

/* Same [hidden]-vs-author-display-rule issue as .ch1lab-quiz-active
   above, but on the "done" message this time. */
.ch1lab-builder-done[hidden] {
    display: none;
}

.ch1lab-builder-done p {
    margin: 0;
    font-size: 0.92rem;
    color: var(--good);
    font-weight: 700;
}

/* ================= RESPONSIVE ================= */
@media (max-width: 640px) {
    .lt-text-card {
        padding: 28px 24px;
        min-height: 50vh;
        border-radius: 20px;
    }

    .lt-text {
        font-size: 1.12rem;
        line-height: 1.95;
        max-width: none;
    }

}
