/* core-typing.css — extracted from typing-test.php (static styles).
   Loaded by the main typing-test page AND the dynamic language pages. */

/* ===== block 1 (widget) ===== */
/* Landing content — scoped polish. Some utilities used below (space-y-*,
       divide-y, group-open:*) are not in the prebuilt Tailwind build, so the
       spacing, dividers, hover and the FAQ toggle are defined here instead.
       Colours come from the site's CSS variables, so this is theme-aware. */
        #tfLp .section-lead {
            margin-left: auto;
            margin-right: auto;
        }

        /* generic list spacing (space-y-* isn't compiled) */
        #tfLp ol>li+li,
        #tfLp ul>li+li {
            margin-top: .8rem;
        }

        /* numbered steps */
        #tfLp .tf-lp-steps {
            list-style: none;
            padding: 0;
            counter-reset: lpstep;
        }

        #tfLp .tf-lp-steps>li {
            position: relative;
            padding-left: 2.9rem;
        }

        #tfLp .tf-lp-steps>li+li {
            margin-top: 1rem;
        }

        #tfLp .tf-lp-steps>li::before {
            counter-increment: lpstep;
            content: counter(lpstep);
            position: absolute;
            left: 0;
            top: 0;
            width: 1.9rem;
            height: 1.9rem;
            border-radius: .65rem;
            display: grid;
            place-items: center;
            font-weight: 700;
            font-size: .8rem;
            color: #fff;
            background: var(--color-primary-500, #0f7cff);
        }

        /* benchmark table */
        #tfLp .tf-lp-table tbody tr {
            transition: background .15s ease;
        }

        #tfLp .tf-lp-table tbody tr:hover {
            background: var(--color-surface, #f3f7fd);
        }

        /* FAQ (divide-y / group-open aren't compiled) */
        #tfLp .tf-lp-faq {
            border-top: 1px solid var(--color-line, #dce5f2);
        }

        #tfLp .tf-lp-faq details {
            border-bottom: 1px solid var(--color-line, #dce5f2);
        }

        #tfLp .tf-lp-faq summary {
            list-style: none;
            display: flex;
            align-items: center;
            justify-content: space-between;
            gap: 1rem;
            padding: 1.1rem 0;
            cursor: pointer;
        }

        #tfLp .tf-lp-faq summary::-webkit-details-marker {
            display: none;
        }

        #tfLp .tf-lp-faq-ic {
            flex: none;
            transition: transform .2s ease;
            color: var(--color-body, #667085);
        }

        #tfLp .tf-lp-faq details[open] .tf-lp-faq-ic {
            transform: rotate(45deg);
            color: var(--color-primary-500, #0f7cff);
        }

        #tfLp .tf-lp-faq details[open] summary {
            color: var(--color-primary-600, #0f7cff);
        }

        #tfLp .tf-lp-faq-a {
            margin: 0;
            padding: 0 0 1.1rem;
        }

        @media (prefers-reduced-motion: reduce) {
            #tfLp .tf-lp-faq-ic {
                transition: none;
            }
        }

/* ===== block 2 (landing) ===== */
/* This page's CSS loads AFTER the compiled Tailwind sheet, so any local rule
       that sets `display` (e.g. .tf-pace-row{display:flex}, .tf-custom-control
       {display:grid}) silently beat Tailwind's `.hidden{display:none}` — a
       `hidden` element stayed visible (this is why the Pace-caret Fixed/Auto
       modes showed every field). Re-assert `.hidden` so every JS toggle works. */
    .hidden {
        display: none !important;
    }

    /* ── Page layout: test on the left, settings rail on the right ── */
    .tf-layout {
        display: grid;
        gap: 2rem;
        align-items: start;
    }

    @media (min-width: 1024px) {
        .tf-layout {
            grid-template-columns: minmax(0, 1fr) 280px;
        }
    }

    /* ── Toolbar checkboxes ── */
    .tf-check {
        display: inline-flex;
        align-items: center;
        gap: .4rem;
        font-size: .8125rem;
        color: var(--color-body);
        cursor: pointer;
        user-select: none;
    }

    .tf-check:hover {
        color: var(--color-ink);
    }

    .tf-check input {
        width: .9rem;
        height: .9rem;
        accent-color: var(--color-primary-500);
        cursor: pointer;
    }

    /* ── Dropdown (layout/numerals) ── */
    .tf-dropdown {
        position: relative;
    }

    .tf-language-select {
        width: 100%;
        padding: .58rem 2rem .58rem .75rem;
        border-radius: .5rem;
        border: 1px solid var(--color-line);
        background: var(--color-card);
        color: var(--color-ink);
        font-size: .8125rem;
        font-weight: 600;
        cursor: pointer;
    }

    .tf-language-select:focus {
        outline: 2px solid var(--color-primary-500);
        outline-offset: 1px;
    }

    .tf-dropdown-trigger {
        display: inline-flex;
        align-items: center;
        gap: .4rem;
        padding: .5rem .75rem;
        border-radius: .5rem;
        font-size: .8125rem;
        font-weight: 500;
        border: 1px solid var(--color-line);
        background: var(--color-card);
        color: var(--color-ink);
        cursor: pointer;
        transition: border-color .15s ease;
    }

    .tf-dropdown-trigger:hover {
        border-color: var(--color-primary-500);
    }

    .tf-dropdown-panel {
        position: absolute;
        top: calc(100% + .4rem);
        left: 0;
        right: 0;
        z-index: 30;
        max-height: 16rem;
        overflow-y: auto;
        border-radius: .75rem;
        border: 1px solid var(--color-line);
        background: var(--color-card);
        box-shadow: 0 8px 24px rgb(0 0 0 / .12);
        padding: .25rem 0;
    }

    .settings-option {
        display: flex;
        align-items: center;
        justify-content: space-between;
        gap: .5rem;
        width: 100%;
        text-align: left;
        padding: .55rem .9rem;
        font-size: .8125rem;
        color: var(--color-ink);
        cursor: pointer;
        user-select: none;
        transition: background-color .1s ease;
        background: none;
        border: none;
        border-radius: .5rem;
    }

    .settings-option:hover {
        background: var(--color-surface);
    }

    .settings-option.is-active {
        font-weight: 600;
        color: var(--color-primary-600);
    }

    .settings-option .check {
        opacity: 0;
        flex-shrink: 0;
    }

    .settings-option.is-active .check {
        opacity: 1;
    }

    /* ── Segmented (Words/Paragraph, Time/Words) ── */
    .tf-segmented {
        display: flex;
        border-radius: .5rem;
        border: 1px solid var(--color-line);
        overflow: hidden;
    }

    .tf-segmented .seg-btn {
        padding: .5rem .75rem;
        font-size: .8125rem;
        font-weight: 500;
        color: var(--color-body);
        background: var(--color-card);
        border: none;
        cursor: pointer;
        transition: color .15s ease;
    }

    .tf-segmented .seg-btn+.seg-btn {
        border-left: 1px solid var(--color-line);
    }

    .tf-segmented .seg-btn.is-active {
        background: var(--color-primary-50);
        color: var(--color-ink);
    }

    /* ── Rail grid buttons (duration / word-count / blind) ── */
    .tf-grid-btn {
        padding: .45rem .5rem;
        border-radius: .5rem;
        font-size: .8125rem;
        font-weight: 500;
        border: 1px solid var(--color-line);
        background: var(--color-card);
        color: var(--color-body);
        cursor: pointer;
        transition: all .12s ease;
        text-align: center;
    }

    .tf-grid-btn:hover {
        border-color: var(--color-primary-500);
        color: var(--color-ink);
    }

    .tf-grid-btn.is-active {
        background: var(--color-ink);
        color: var(--color-bg);
        border-color: var(--color-ink);
    }

    /* ── Option rows (blind mode) ──
       A secondary preference: a quiet tinted row, not a full-width filled
       button competing with the duration grid for attention. */
    .tf-opt-btn {
        display: block;
        width: 100%;
        padding: .4rem .55rem;
        border: none;
        border-radius: .4rem;
        background: none;
        color: var(--color-body);
        font-size: .8125rem;
        font-weight: 500;
        text-align: left;
        cursor: pointer;
        transition: background-color .12s ease, color .12s ease;
    }

    .tf-opt-btn:hover {
        background: var(--color-surface);
        color: var(--color-ink);
    }

    .tf-opt-btn.is-active {
        background: var(--color-primary-50);
        color: var(--color-primary-700);
        font-weight: 600;
    }

    /* ── Settings rail ──
       One panel with hairline dividers, rather than a stack of separate boxed
       cards: four nested borders next to a borderless test surface is what made
       the page read as cluttered. */
    .tf-rail {
        border: 1px solid var(--color-line);
        border-radius: .875rem;
        background: var(--color-card);
        overflow: hidden;
    }

    .tf-rail-section {
        padding: .95rem 1rem;
    }

    .tf-rail-section+.tf-rail-section {
        border-top: 1px solid var(--color-line);
    }

    .tf-rail-label {
        margin-bottom: .5rem;
        font-size: .6875rem;
        font-weight: 700;
        letter-spacing: .08em;
        text-transform: uppercase;
        color: var(--color-body);
    }

    .tf-custom-control:not(.hidden) {
        display: grid;
        grid-template-columns: 1fr;
        gap: .35rem;
        margin-top: .7rem;
        color: var(--color-body);
        font-size: .75rem;
        font-weight: 600;
    }

    .tf-custom-control input {
        min-width: 0;
        width: 100%;
        padding: .55rem .65rem;
        border: 1px solid var(--color-line);
        border-radius: .5rem;
        background: var(--color-card);
        color: var(--color-ink);
        font-weight: 400;
    }

    .tf-custom-control input:focus {
        outline: 2px solid var(--color-primary-500);
        outline-offset: 1px;
    }

    .tf-custom-text {
        width: 100%;
        resize: vertical;
        padding: .6rem .7rem;
        border: 1px solid var(--color-line);
        border-radius: .5rem;
        background: var(--color-surface);
        color: var(--color-ink);
        font-size: .85rem;
        line-height: 1.6;
    }

    .tf-custom-text:focus {
        outline: 2px solid var(--color-primary-500);
        outline-offset: 1px;
    }

    .tf-apply-btn {
        padding: .5rem 1.1rem;
        border-radius: .5rem;
        border: 1px solid var(--color-primary-600);
        background: var(--color-primary-600);
        color: #fff;
        font-size: .8125rem;
        font-weight: 600;
        cursor: pointer;
        transition: background-color .15s ease, transform .1s ease;
    }

    .tf-apply-btn:hover {
        background: var(--color-primary-500);
        border-color: var(--color-primary-500);
    }

    .tf-apply-btn:active {
        transform: translateY(1px);
    }

    /* ── Test controls (Restart / Pause) — sit under the typing box ── */
    .tf-ctl-btn {
        display: inline-flex;
        align-items: center;
        gap: .35rem;
        padding: .3rem .55rem;
        border-radius: .375rem;
        font-size: .75rem;
        font-weight: 500;
        color: var(--color-body);
        background: none;
        border: none;
        cursor: pointer;
        transition: color .15s ease, background-color .15s ease;
    }

    .tf-ctl-btn:hover {
        color: var(--color-ink);
        background: var(--color-surface);
    }

    .tf-ctl-sep {
        width: 1px;
        height: .9rem;
        background: var(--color-line);
        flex: none;
    }

    .tf-icon-btn {
        display: inline-flex;
        align-items: center;
        justify-content: center;
        width: 2.25rem;
        height: 2.25rem;
        border-radius: 9999px;
        border: 1px solid var(--color-line);
        background: var(--color-card);
        color: var(--color-body);
        cursor: pointer;
        transition: color .15s ease, border-color .15s ease;
    }

    .tf-icon-btn:hover {
        color: var(--color-ink);
        border-color: var(--color-primary-500);
    }

    /* ── Settings modal accordion ── */
    .tf-accordion {
        border-bottom: 1px solid var(--color-line);
    }

    .tf-accordion-summary {
        cursor: pointer;
        list-style: none;
        padding: 1rem 1.5rem;
        font-weight: 600;
        font-size: .875rem;
        color: var(--color-ink);
    }

    .tf-accordion-summary::-webkit-details-marker {
        display: none;
    }

    .tf-accordion-body {
        padding: 1.15rem 1.5rem 1.35rem;
    }

    /* Consistent modal sub-line (the one-line explainer under a modal header). */
    .tf-modal-sub {
        font-size: .8125rem;
        line-height: 1.5;
        color: var(--color-body);
        margin: 0 0 1rem;
    }

    /* ── Highlight-word toggle: when OFF, current word loses its accent
         block and falls back to a plain underline so there's still SOME
         positional feedback, just not a colored highlight. ── */
    /* ══════════════ Typing surface — the feedback layer ══════════════
       The engine renders .tf-word / .tf-char, but the global sheet only ever
       styled .t-word / .t-char (one letter off), so NOTHING here was styled:
       right, wrong, typed and untyped all painted the same grey and the test
       gave no feedback at all. These rules are that missing layer.

       Convention (Monkeytype/Keybr): untyped text is dim and lights up as you
       type it — progress reads at a glance, mistakes stay loud. */

    /* The current word's tint bleeds .18em past its text (padding + negative
       margin, so words never jitter when they become current). The viewport is
       overflow-hidden, so without this breathing room the FIRST word on a line
       gets its tint and caret clipped — at the left edge in LTR, the right in RTL. */
    #miniWordsViewport {
        padding-inline: .35rem;
    }

    #miniWords .tf-word {
        display: inline-block;
        margin-inline-end: .1rem;
        padding-inline: .18em;
        white-space: nowrap;
        border-radius: .3rem;
        color: var(--color-body);
        /* untyped: recedes */
        transition: color .1s ease;
        letter-spacing: .5px;
    }

    /* ── Finished words ── */
    #miniWords .tf-word.is-done-ok {
        color: var(--color-ink);
    }

    #miniWords .tf-word.is-done-err {
        color: var(--color-red, var(--red));
        text-decoration: underline;
        text-decoration-thickness: 2px;
        text-underline-offset: .22em;
        text-decoration-color: color-mix(in srgb, var(--color-red, var(--red)) 45%, transparent);
    }

    /* ── Race verdict banner (result panel) ── */
    #resultVerdict.is-win {
        color: var(--color-green, #16a34a);
    }

    #resultVerdict.is-lose {
        color: var(--color-red, var(--red));
    }

    /* ── Current word: a calm tint, not a filled orange block ── */
    #miniWords .tf-word.is-current {
        color: var(--color-ink);
        background: color-mix(in srgb, var(--color-primary-500) 12%, transparent);
        box-shadow: inset 0 -2px 0 0 var(--color-primary-500);
        /* margin-inline-start: -.18em; */
    }

    /* ── The caret ──
       ONE caret: the engine injects this inline element at the exact typing
       position (before the next untyped char / trailing after overflow), so it
       flows in the text and tracks the cursor letter-by-letter. It's its own
       element — independent of the current-word tint. The <input>'s native
       caret is hidden, so this is the only cursor on screen. */
    #miniInput {
        caret-color: transparent;
    }

    /* IME layouts type the composition in the field itself — show its native
       caret there so pinyin/romaji is easy to follow. */
    #miniInput.is-ime {
        caret-color: auto;
    }

    /* Current word while an IME composition is in progress — a soft underline so
       you know which word you're about to commit (the pinyin shows in the box). */
    #miniWords .tf-word.is-composing {
        text-decoration: underline dotted;
        text-underline-offset: .22em;
        text-decoration-color: color-mix(in srgb, var(--color-primary-500) 55%, transparent);
    }

    .tf-caret-el {
        position: absolute;
        left: 0;
        top: 0;
        width: 2px;
        border-radius: 1px;
        background: var(--color-accent);
        pointer-events: none;
        z-index: 1;
        /* ONLY left transitions: glide horizontally within a line, but SNAP
           vertically (top) so a wrap/scroll never leaves the caret on the wrong
           line or gliding diagonally. left/top, not transform (a global rule
           resets transform on this element). */
        transition: left .09s cubic-bezier(.4, 0, .2, 1);
        animation: tf-caret-blink 1.05s step-end infinite;
    }

    .tf-caret-el.is-typing {
        animation: none;
    }

    .tf-caret-el.is-hidden {
        display: none;
    }

    @keyframes tf-caret-blink {
        50% {
            opacity: 0;
        }
    }

    @media (prefers-reduced-motion: reduce) {
        .tf-caret-el {
            animation: none;
            transition: none;
        }
    }

    /* ── Pace / ghost caret ── (see pace-caret.js)
       A second, distinct caret you race against — glides on left/top. */
    .tf-ghost-caret {
        position: absolute;
        left: 0;
        top: 0;
        width: 3px;
        border-radius: 2px;
        background: var(--color-purple, #a855f7);
        opacity: .7;
        pointer-events: none;
        z-index: 2;
        box-shadow: 0 0 6px 0 color-mix(in srgb, var(--color-purple, #a855f7) 60%, transparent);
        transition: left .1s linear;
        /* glide within a line; snap on line change */
    }

    .tf-ghost-caret.is-hidden {
        display: none;
    }

    /* Small, quiet marker riding the ghost — sits just above the caret. */
    .tf-ghost-flag {
        position: absolute;
        bottom: calc(100% + 2px);
        left: -1px;
        font-size: .55rem;
        font-weight: 700;
        letter-spacing: .06em;
        text-transform: uppercase;
        color: #fff;
        background: var(--color-purple, #a855f7);
        padding: .02rem .28rem;
        border-radius: .2rem;
        white-space: nowrap;
        opacity: .9;
    }

    .tf-ghost-caret.is-ahead {
        background: var(--color-red, var(--red));
        box-shadow: 0 0 6px 0 color-mix(in srgb, var(--color-red, var(--red)) 60%, transparent);
    }

    .tf-ghost-caret.is-ahead .tf-ghost-flag {
        background: var(--color-red, var(--red));
    }

    /* ── Pace controls (settings modal) ── */
    .tf-switch {
        appearance: none;
        width: 2.2rem;
        height: 1.25rem;
        border-radius: 1rem;
        background: var(--color-line);
        position: relative;
        cursor: pointer;
        transition: background-color .15s ease;
        flex: none;
    }

    .tf-switch::after {
        content: '';
        position: absolute;
        top: 2px;
        left: 2px;
        width: 1rem;
        height: 1rem;
        border-radius: 50%;
        background: #fff;
        transition: transform .15s ease;
    }

    .tf-switch:checked {
        background: var(--color-primary-600);
    }

    .tf-switch:checked::after {
        transform: translateX(.95rem);
    }

    .tf-pace-row {
        display: flex;
        align-items: center;
        gap: .75rem;
    }

    .tf-pace-label {
        flex: 1;
        font-size: .8125rem;
        color: var(--color-body);
    }

    .tf-pace-unit {
        font-size: .75rem;
        color: var(--color-body);
        width: 2.5rem;
    }

    .tf-stepper {
        display: inline-flex;
        align-items: center;
        border: 1px solid var(--color-line);
        border-radius: .5rem;
        overflow: hidden;
    }

    .tf-stepper button {
        width: 2rem;
        height: 2rem;
        background: var(--color-surface);
        color: var(--color-ink);
        border: none;
        cursor: pointer;
        font-size: 1rem;
    }

    .tf-stepper button:hover {
        background: var(--color-surface2, var(--color-line));
    }

    .tf-stepper input {
        width: 3rem;
        height: 2rem;
        text-align: center;
        border: none;
        border-inline: 1px solid var(--color-line);
        background: var(--color-card);
        color: var(--color-ink);
        font-weight: 700;
        font-variant-numeric: tabular-nums;
        -moz-appearance: textfield;
    }

    .tf-stepper input::-webkit-outer-spin-button,
    .tf-stepper input::-webkit-inner-spin-button {
        -webkit-appearance: none;
        margin: 0;
    }

    /* ── Pace ramp preview (a wedge rising Start → End) ── */
    .tf-pace-preview {
        border: 1px solid var(--color-line);
        border-radius: .65rem;
        padding: .7rem .8rem .8rem;
        background: var(--color-surface);
    }

    .tf-pace-preview-head {
        display: flex;
        align-items: center;
        justify-content: space-between;
        font-size: .65rem;
        font-weight: 700;
        letter-spacing: .07em;
        text-transform: uppercase;
        color: var(--color-body);
        margin-bottom: .55rem;
    }

    #tfPacePreviewRange {
        color: var(--color-ink);
        font-variant-numeric: tabular-nums;
    }

    .tf-pace-preview-track {
        position: relative;
        height: 2.4rem;
        border-radius: .45rem;
        overflow: hidden;
        background: color-mix(in srgb, var(--color-ink) 7%, transparent);
    }

    .tf-pace-preview-fill {
        position: absolute;
        inset: 0;
        background: linear-gradient(90deg,
                color-mix(in srgb, var(--color-primary-500) 18%, transparent),
                var(--color-primary-500));
        clip-path: polygon(0 100%, 100% 15%, 100% 100%);
        opacity: .9;
        transition: clip-path .2s ease;
    }

    /* Exponential curve → a concave ramp (slow then steep). */
    .tf-pace-preview-track.is-exp .tf-pace-preview-fill {
        clip-path: polygon(0 100%, 55% 88%, 80% 60%, 100% 15%, 100% 100%);
    }

    .tf-pace-preview-start,
    .tf-pace-preview-end {
        position: absolute;
        font-size: .7rem;
        font-weight: 700;
        color: var(--color-ink);
    }

    .tf-pace-preview-start {
        left: .55rem;
        bottom: .3rem;
    }

    .tf-pace-preview-end {
        right: .55rem;
        top: .3rem;
    }

    .tf-pace-curve-label {
        font-size: .75rem;
        font-weight: 600;
        letter-spacing: .02em;
        color: var(--color-body);
        margin-top: .1rem;
    }

    /* ── Pace-caret panel (top-level modal) ── */
    .tf-pace-panel {
        display: flex;
        flex-direction: column;
        gap: 0;
        padding: 0 0 1.25rem;
    }

    .tf-pace-enable-row {
        display: flex;
        align-items: center;
        justify-content: space-between;
        gap: 1rem;
        padding: 1rem 1.5rem;
        border-bottom: 1px solid var(--color-line);
        cursor: pointer;
    }

    .tf-pace-enable-text {
        display: flex;
        flex-direction: column;
        gap: .15rem;
    }

    .tf-pace-enable-title {
        font-size: .9rem;
        font-weight: 600;
        color: var(--color-ink);
    }

    .tf-pace-enable-sub {
        font-size: .75rem;
        color: var(--color-body);
    }

    .tf-pace-fields {
        display: flex;
        flex-direction: column;
        gap: 1rem;
        padding: 1.25rem 1.5rem 0;
        transition: opacity .15s ease;
    }

    /* Pacer off → the controls stay visible but recede (still editable). */
    .tf-pace-fields.is-off {
        opacity: .55;
    }

    /* ── Error-behavior options (top-level modal) — clean left-aligned cards.
         Uses display:block (not the shared .settings-option flex, whose
         align-items:center was centering the description). ── */
    .tf-error-opt {
        display: block;
        width: 100%;
        text-align: left;
        padding: .7rem .85rem;
        border: 1px solid transparent;
        border-radius: .6rem;
        background: none;
        cursor: pointer;
        transition: background-color .12s ease, border-color .12s ease;
    }

    .tf-error-opt:hover {
        background: color-mix(in srgb, var(--color-ink) 5%, transparent);
    }

    .tf-error-opt.is-active {
        background: color-mix(in srgb, var(--color-primary-500) 12%, transparent);
        border-color: color-mix(in srgb, var(--color-primary-500) 55%, transparent);
    }

    .tf-error-opt-head {
        display: flex;
        align-items: center;
        justify-content: space-between;
        gap: .5rem;
    }

    .tf-error-opt-title {
        font-size: .875rem;
        font-weight: 600;
        color: var(--color-ink);
    }

    .tf-error-opt.is-active .tf-error-opt-title {
        color: var(--color-primary-600, #a855f7);
    }

    .tf-error-opt-check {
        flex: none;
        opacity: 0;
        color: var(--color-primary-600, #a855f7);
        transition: opacity .12s ease;
    }

    .tf-error-opt.is-active .tf-error-opt-check {
        opacity: 1;
    }

    .tf-error-opt-desc {
        display: block;
        margin-top: .2rem;
        font-size: .75rem;
        line-height: 1.45;
        color: var(--color-body);
    }

    /* ── Advanced result ── */
    .tf-adv-open {
        display: inline-flex;
        align-items: center;
        gap: .4rem;
        padding: .5rem .9rem;
        font-size: .85rem;
        font-weight: 600;
        color: var(--color-ink);
        background: none;
        border: 1px solid var(--color-line);
        border-radius: .6rem;
        cursor: pointer;
        transition: border-color .12s, background-color .12s;
    }

    .tf-adv-open:hover {
        border-color: color-mix(in srgb, var(--color-primary-500) 60%, transparent);
        background: color-mix(in srgb, var(--color-primary-500) 8%, transparent);
    }

    .tf-adv-stats {
        display: grid;
        grid-template-columns: repeat(auto-fit, minmax(96px, 1fr));
        gap: .6rem;
        margin-bottom: 1.5rem;
    }

    .tf-adv-tile {
        border: 1px solid var(--color-line);
        border-radius: .6rem;
        padding: .6rem .7rem;
        background: var(--color-surface);
    }

    .tf-adv-tile-val {
        font-family: ui-monospace, monospace;
        font-size: 1.35rem;
        font-weight: 700;
        color: var(--color-primary-600, #a855f7);
        line-height: 1.1;
    }

    .tf-adv-tile-label {
        font-size: .68rem;
        text-transform: uppercase;
        letter-spacing: .05em;
        color: var(--color-body);
        margin-top: .15rem;
    }

    .tf-adv-tile-sub {
        font-size: .62rem;
        color: var(--color-body);
        opacity: .8;
        margin-top: .1rem;
    }

    .tf-adv-section {
        margin-bottom: 1.5rem;
    }

    .tf-adv-section h3 {
        font-size: .8rem;
        font-weight: 700;
        text-transform: uppercase;
        letter-spacing: .05em;
        color: var(--color-body);
        margin: 0 0 .7rem;
    }

    /* "vs previous test" comparison tiles */
    .tf-adv-cmp {
        display: grid;
        grid-template-columns: repeat(3, 1fr);
        gap: .6rem;
    }
    .tf-adv-cmp-cell {
        border: 1px solid var(--color-line);
        border-radius: .6rem;
        padding: .6rem .7rem;
        text-align: center;
    }
    .tf-adv-cmp-label {
        font-size: .68rem;
        text-transform: uppercase;
        letter-spacing: .04em;
        color: var(--color-muted);
    }
    .tf-adv-cmp-now {
        font-family: ui-monospace, monospace;
        font-size: 1.3rem;
        font-weight: 700;
        color: var(--color-ink);
        line-height: 1.2;
    }
    .tf-adv-cmp-d {
        font-size: .78rem;
        font-weight: 600;
    }
    .tf-adv-cmp-d.up { color: #22c55e; }
    .tf-adv-cmp-d.down { color: #ef4444; }
    .tf-adv-cmp-d.flat, .tf-adv-cmp-na { color: var(--color-muted); }

    .tf-adv-grid2 {
        display: grid;
        grid-template-columns: 1fr 1fr;
        gap: 1.5rem;
    }

    @media (max-width: 640px) {
        .tf-adv-grid2 {
            grid-template-columns: 1fr;
        }
    }

    .tf-adv-chart {
        width: 100%;
        height: 180px;
        display: block;
    }

    .tf-adv-area {
        fill: color-mix(in srgb, var(--color-primary-500) 16%, transparent);
        stroke: none;
    }

    /* SOLID = this test, DASHED = previous test. Bright = Net WPM, muted = Raw. */
    .tf-adv-net {
        fill: none;
        stroke: var(--color-primary-500, #a855f7);
        stroke-width: 2.4;
        stroke-linejoin: round;
        stroke-linecap: round;
        vector-effect: non-scaling-stroke;
    }

    .tf-adv-raw {
        fill: none;
        stroke: color-mix(in srgb, var(--color-ink) 42%, transparent);
        stroke-width: 1.6;
        stroke-linejoin: round;
        vector-effect: non-scaling-stroke;
    }

    .tf-adv-net.prev {
        stroke-width: 1.8;
        stroke-dasharray: 5 4;
        opacity: .5;
    }

    .tf-adv-raw.prev {
        stroke-dasharray: 4 4;
        opacity: .32;
    }

    .tf-adv-grid {
        stroke: var(--color-line);
        stroke-width: 1;
        vector-effect: non-scaling-stroke;
    }

    .tf-adv-axis {
        fill: var(--color-body);
        font-size: 9px;
    }

    .tf-adv-errtick {
        stroke: var(--color-red, #ef4444);
        stroke-width: 2;
        stroke-linecap: round;
        vector-effect: non-scaling-stroke;
    }

    .tf-adv-errtick.prev {
        opacity: .38;
    }

    .tf-adv-errdot {
        fill: var(--color-red, #ef4444);
    }

    .tf-adv-legend {
        display: flex;
        gap: 1rem;
        margin-top: .4rem;
        font-size: .7rem;
        color: var(--color-body);
    }

    .tf-adv-k::before {
        content: "";
        display: inline-block;
        width: 12px;
        height: 3px;
        border-radius: 2px;
        margin-right: .3rem;
        vertical-align: middle;
    }

    .tf-adv-k.net::before {
        background: var(--color-primary-500, #a855f7);
    }

    .tf-adv-k.raw::before {
        background: color-mix(in srgb, var(--color-ink) 42%, transparent);
    }

    .tf-adv-k.prev::before {
        width: 14px;
        background: repeating-linear-gradient(90deg, var(--color-primary-500, #a855f7) 0 4px, transparent 4px 7px);
        opacity: .6;
    }

    .tf-adv-k.err::before {
        background: var(--color-red, #ef4444);
        border-radius: 1px;
        width: 3px;
        height: 9px;
    }

    .tf-adv-finger {
        display: grid;
        grid-template-columns: 84px 1fr 38px 42px;
        align-items: center;
        gap: .5rem;
        font-size: .78rem;
        color: var(--color-ink);
        margin-bottom: .45rem;
    }

    .tf-adv-finger-name {
        color: var(--color-body);
    }

    .tf-adv-bar {
        height: .5rem;
        border-radius: 1rem;
        background: color-mix(in srgb, var(--color-ink) 8%, transparent);
        overflow: hidden;
    }

    .tf-adv-bar-fill {
        display: block;
        height: 100%;
        border-radius: 1rem;
    }

    .tf-adv-bar-fill.good {
        background: var(--color-green, #16a34a);
    }

    .tf-adv-bar-fill.ok {
        background: #d4a017;
    }

    .tf-adv-bar-fill.bad {
        background: var(--color-red, #ef4444);
    }

    .tf-adv-finger-pct {
        font-family: ui-monospace, monospace;
        text-align: right;
    }

    .tf-adv-finger-n {
        font-size: .68rem;
        color: var(--color-body);
        text-align: right;
    }

    .tf-adv-keys {
        display: flex;
        flex-direction: column;
        gap: .45rem;
    }

    .tf-adv-key {
        display: grid;
        grid-template-columns: 34px 46px 1fr;
        align-items: center;
        gap: .5rem;
        font-size: .78rem;
    }

    .tf-adv-key kbd {
        display: inline-flex;
        align-items: center;
        justify-content: center;
        min-width: 28px;
        padding: .1rem .3rem;
        border: 1px solid var(--color-line);
        border-bottom-width: 2px;
        border-radius: .35rem;
        font-family: ui-monospace, monospace;
        color: var(--color-ink);
        background: var(--color-surface);
    }

    .tf-adv-key-acc {
        font-family: ui-monospace, monospace;
        color: var(--color-red, #ef4444);
    }

    .tf-adv-key-n {
        font-size: .68rem;
        color: var(--color-body);
    }

    .tf-adv-empty {
        font-size: .8rem;
        color: var(--color-body);
        padding: .5rem 0;
    }

    /* Keyboard heatmap — two side by side: this test vs previous. */
    .tf-adv-kb2 {
        display: grid;
        grid-template-columns: 1fr 1fr;
        gap: 1.25rem;
        align-items: start;
    }

    @media (max-width: 640px) {
        .tf-adv-kb2 {
            grid-template-columns: 1fr;
            gap: 1.5rem;
        }
    }

    .tf-adv-kb-cap {
        font-size: .68rem;
        text-transform: uppercase;
        letter-spacing: .06em;
        font-weight: 600;
        color: var(--color-body);
        text-align: center;
        margin-bottom: .55rem;
    }

    .tf-adv-kb-empty {
        display: flex;
        align-items: center;
        justify-content: center;
        min-height: 7rem;
        text-align: center;
    }

    .tf-adv-kb {
        display: flex;
        flex-direction: column;
        gap: .35rem;
        align-items: center;
    }

    .tf-adv-kb-row {
        display: flex;
        gap: .3rem;
    }

    /* Compact keys when two heatmaps share the row. */
    .tf-adv-kb2 .tf-adv-kb-key {
        width: 1.7rem;
        height: 1.7rem;
        font-size: .72rem;
    }

    .tf-adv-kb-key {
        width: 2rem;
        height: 2rem;
        display: inline-flex;
        align-items: center;
        justify-content: center;
        border-radius: .4rem;
        font-family: ui-monospace, monospace;
        font-size: .8rem;
        font-weight: 600;
        text-transform: uppercase;
        color: var(--color-body);
        background: color-mix(in srgb, var(--color-ink) 7%, transparent);
        border: 1px solid var(--color-line);
    }

    .tf-adv-kb-key.hit {
        color: #fff;
        background: var(--kbc);
        border-color: transparent;
    }

    .tf-adv-note {
        font-size: .78rem;
        line-height: 1.5;
        color: var(--color-body);
        background: color-mix(in srgb, var(--color-ink) 5%, transparent);
        border: 1px solid var(--color-line);
        border-radius: .55rem;
        padding: .6rem .8rem;
        margin-top: 1rem;
    }

    /* ── Realtime playback: a caret runs through the typed text at the recorded
         pace, with a WPM sparkline, scrubber timeline, live WPM+time + speed. ── */
    .tf-adv-pb {
        background: color-mix(in srgb, var(--color-ink) 4%, transparent);
        border: 1px solid var(--color-line);
        border-radius: .6rem;
        padding: .7rem .8rem;
    }
    .tf-adv-pb-head {
        display: flex;
        align-items: center;
        gap: .6rem;
        margin-bottom: .5rem;
    }
    .tf-adv-speed {
        display: inline-flex;
        border: 1px solid var(--color-line);
        border-radius: 999px;
        overflow: hidden;
    }
    .tf-adv-speed button {
        background: transparent;
        border: 0;
        color: var(--color-muted);
        font-size: .72rem;
        font-weight: 700;
        padding: .18rem .5rem;
        cursor: pointer;
    }
    .tf-adv-speed button.is-on {
        background: var(--color-primary-500);
        color: #fff;
    }
    .tf-adv-pb-play {
        border: 1px solid var(--color-primary-500);
        color: var(--color-primary-500);
        background: transparent;
        border-radius: 999px;
        padding: .18rem .7rem;
        font-size: .76rem;
        font-weight: 600;
        cursor: pointer;
    }
    .tf-adv-pb-read {
        font-weight: 700;
        color: var(--color-primary-500);
        font-variant-numeric: tabular-nums;
    }
    .tf-adv-pb-read small { color: var(--color-muted); font-weight: 500; }
    .tf-adv-pb-spark {
        width: 100%;
        height: 30px;
        display: block;
        margin-bottom: .4rem;
    }
    .tf-adv-pb-timeline {
        position: relative;
        height: 6px;
        border-radius: 999px;
        background: color-mix(in srgb, var(--color-ink) 10%, transparent);
        border: 1px solid var(--color-line);
        margin-bottom: .6rem;
        cursor: pointer;
    }
    .tf-adv-pb-fill {
        position: absolute;
        left: 0; top: 0; bottom: 0;
        border-radius: 999px;
        background: var(--color-primary-500);
        transition: width .13s linear;   /* smooth timer indicator */
    }
    .tf-adv-pb-headdot {
        position: absolute;
        top: 50%;
        width: 11px; height: 11px;
        margin-left: -5.5px;
        transform: translateY(-50%);
        border-radius: 50%;
        background: var(--color-primary-500);
        box-shadow: 0 0 0 2px var(--color-card, #0b141b);
        transition: left .13s linear;    /* smooth timer indicator */
    }
    .tf-adv-pb-keys {
        position: relative;   /* caret positioning context */
        max-height: 148px;
        overflow-y: auto;
    }
    .tf-adv-pb-text {
        display: flex;
        flex-wrap: wrap;
        align-items: center;
        align-content: flex-start;
        row-gap: .3rem;
        font-family: ui-monospace, "SF Mono", monospace;
        line-height: 1.3;
    }
    /* Each word is a speed-heatmap tile (bg set inline by WPM); error words get a
       red underline. Characters are plain text (mistyped ones tinted red). */
    .tf-adv-pb-word {
        display: inline-flex;
        margin: 0 .3rem .15rem 0;
        padding: 1px 3px;
        border-radius: 4px;
        cursor: default;
    }
    .tf-adv-pb-word.has-err {
        box-shadow: inset 0 -2px 0 color-mix(in srgb, var(--color-red, #ef4444) 55%, transparent);
    }
    .tf-adv-pb-key {
        font-size: .95rem;
        transition: background-color .12s ease;
    }
    .tf-adv-pb-key.is-ok  { color: var(--color-ink); background: transparent; }
    .tf-adv-pb-key.is-bad {
        color: var(--color-red, #ef4444);
        background: color-mix(in srgb, var(--color-red, #ef4444) 22%, transparent);
        border-radius: 2px;
    }
    /* Upcoming (not-yet-replayed) chars — dim, like the live test's future text. */
    .tf-adv-pb-key.is-dim { color: color-mix(in srgb, var(--color-muted, #94a3b8) 75%, transparent); background: transparent; }
    /* Standalone caret element (buffer-based replay), blinks at the write head. */
    /* Persistent caret: an absolute bar that SLIDES to the write head (moved by
       JS via transform), like the live test's caret — smooth, not re-created. */
    .tf-adv-pb-caret {
        position: absolute;
        top: 0; left: 0;
        width: 2px;
        height: 1.15em;
        border-radius: 1px;
        background: var(--color-primary-500);
        pointer-events: none;
        transition: transform .09s linear;
        animation: tf-adv-caret 1s ease-in-out infinite;
    }
    .tf-adv-pb-caretpos { display: inline-block; width: 0; }
    @keyframes tf-adv-caret { 0%, 100% { opacity: 1; } 50% { opacity: .2; } }

    .tf-adv-pb-titlerow {
        display: flex;
        align-items: center;
        justify-content: space-between;
        gap: .6rem;
    }
    .tf-adv-pb-titlerow h3 { margin: 0; }
    .tf-adv-pb-corr {
        font-size: .68rem;
        font-weight: 600;
        color: var(--color-red, #ef4444);
        background: color-mix(in srgb, var(--color-red, #ef4444) 12%, transparent);
        border: 1px solid color-mix(in srgb, var(--color-red, #ef4444) 40%, transparent);
        border-radius: 999px;
        padding: .1rem .5rem;
        white-space: nowrap;
    }

    /* Highlight Word toggle OFF: drop the block tint, caret stays. */
    #miniWords.tf-no-highlight .tf-word.is-current {
        background: none;
        box-shadow: none;
        padding-inline: 0;
        margin-inline-start: 0;
    }

    /* ── Per-character feedback. Every char in the current word is a <span>:
         .correct / .wrong (both show the TARGET letter — the word text never
         mutates), .extra (keys typed past the word), .tf-ch-pending (not yet
         typed). mark() keeps these after commit so finished words still show
         which letters were missed. ── */
    #miniWords .tf-char.correct {
        color: var(--color-ink);
    }

    #miniWords .tf-char.wrong {
        color: var(--color-red, var(--red));
        background: color-mix(in srgb, var(--color-red, var(--red)) 14%, transparent);
        border-radius: .15rem;
    }

    /* Extra keys past the end of the word — dim red, struck out. */
    #miniWords .tf-char.extra {
        color: color-mix(in srgb, var(--color-red, var(--red)) 80%, transparent);
        opacity: .8;
    }

    /* IME: the composing string isn't committed yet — neutral, not right/wrong. */
    #miniWords .tf-char.composing {
        color: var(--color-ink);
        text-decoration: underline dotted;
        text-underline-offset: .2em;
    }

    /* Mistype flash — the wrong KEY you pressed pops over the letter and shrinks
       away, so you see what you hit without the word text changing. */
    .tf-mistype-flash {
        position: absolute;
        z-index: 3;
        pointer-events: none;
        font-weight: 700;
        line-height: 1;
        color: var(--color-red, var(--red));
        text-shadow: 0 1px 8px color-mix(in srgb, var(--color-red, var(--red)) 45%, transparent);
        transform-origin: center bottom;
        animation: tf-mistype .45s cubic-bezier(.2, .6, .2, 1) forwards;
    }

    @keyframes tf-mistype {
        0% {
            opacity: 0;
            transform: scale(1.8) translateY(0);
        }

        20% {
            opacity: 1;
        }

        100% {
            opacity: 0;
            transform: scale(.55) translateY(-16px);
        }
    }

    /* ── Typing Box toggle: OFF visually hides the input but keeps it
         focusable/functional (see the widget-toggles plugin) — feedback then
         comes entirely from the current-word highlight. ── */
    [data-typing-box-target].tf-hidden-input {
        opacity: 0;
        height: 0;
        padding: 0;
        margin: 0;
        border: none;
        overflow: hidden;
        position: absolute;
    }

    #tfStatsBar.tf-stats-hidden {
        display: none;
    }

    .tf-stat-hidden {
        display: none !important;
    }

    .tf-setting-checks {
        display: grid;
        gap: .65rem;
        font-size: .8125rem;
        color: var(--color-ink);
    }

    .tf-setting-checks label {
        display: flex;
        align-items: center;
        gap: .45rem;
        cursor: pointer;
    }

    .tf-setting-checks input {
        accent-color: var(--color-primary-500);
    }

    @media (max-width: 420px) {
        .tf-stats-grid {
            overflow-x: auto;
        }

        .tf-stats-grid>div {
            min-width: 4.65rem;
        }

        .tf-rail-section {
            padding: .75rem;
        }
    }

    .tf-result-enter {
        opacity: 0;
        transform: translateY(6px);
        transition: opacity .25s ease, transform .25s ease;
    }

    .tf-result-enter.is-visible {
        opacity: 1;
        transform: translateY(0);
    }

    @media (prefers-reduced-motion: reduce) {

        .tf-result-enter,
        #miniProgressBar,
        #miniWords {
            transition: none !important;
        }
    }
