/* =============================================================================
 * duo.css — Design tokens + CSS primitives for the Duolingo-style English app
 * -----------------------------------------------------------------------------
 * Hand-written plain CSS port of the React 19 + Tailwind 4 reference app that
 * lives (READ-ONLY) in `duolingual/`. No Tailwind, no SCSS, no build step.
 *
 * Reference files this was ported from:
 *   duolingual/src/index.css                      -> tokens, keyframes
 *   duolingual/src/App.tsx                        -> shell, header, hero, nav, toast
 *   duolingual/src/components/GrammarPractice.tsx -> exercise card, bubble, word blocks
 *   duolingual/src/components/DictionarySection.tsx -> search, chips, result card
 *   duolingual/src/components/LeaderboardSection.tsx -> rank medals, rows
 *   duolingual/src/components/ProgressCharts.tsx  -> stat cards
 *
 * CONVENTIONS (please keep these when extending)
 * -----------------------------------------------------------------------------
 * 1. Every class is prefixed `duo-`. No bare element selectors (`button {}`,
 *    `input {}`) — they would break the Bricks theme and other plugins.
 * 2. Primitives that map onto NATIVE FORM/INTERACTIVE elements
 *    (.duo-btn, .duo-nav-btn, .duo-input, .duo-textarea, .duo-box,
 *     .duo-word-block, .duo-chip, .duo-select-card) are written as
 *    `.duo-app .duo-x` — specificity (0,2,0).
 *    WHY: themes ship rules like `input[type="text"] {}` or
 *    `button[type="submit"] {}` with specificity (0,1,1), which would beat a
 *    single class (0,1,0) regardless of load order. The extra `.duo-app`
 *    ancestor wins without needing a single `!important`.
 *    => THE APP ROOT ELEMENT MUST CARRY `class="duo-app"`.
 *    Purely decorative primitives (cards, badges, alerts, ranks…) stay
 *    single-class because no theme element selector can target them.
 * 3. State classes are `.is-*` (`.is-active`, `.is-done`, `.is-error`).
 * 4. Tailwind mappings are noted per block as `[tw: …]` so a reviewer can
 *    diff 1-1 against the React source.
 *
 * FONTS — deliberately NOT loaded here.
 * The reference app used `@import url(fonts.googleapis.com…)` at the top of
 * index.css, which is render-blocking and serialised after the stylesheet
 * itself. Load them from PHP instead (see report / README notes):
 *   wp_enqueue_style('duo-fonts',
 *     'https://fonts.googleapis.com/css2?family=Nunito:ital,wght@0,300..900;1,300..900&family=JetBrains+Mono:wght@400;500&display=swap',
 *     [], null);
 * duo.css degrades gracefully to system sans / system mono without them.
 * ========================================================================== */


/* =============================================================================
 * 1. TOKENS
 * ========================================================================== */

:root {
    /* ---------------------------------------------------------------------
     * 1.1 Type families   [tw: @theme --font-sans / --font-mono]
     * ------------------------------------------------------------------ */
    --duo-font-sans: "Nunito", ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
    /* JetBrains Mono is already part of the reference app (IPA transcription in
     * the dictionary). Reused for .duo-box so `1ch` is exact — see §7. */
    --duo-font-mono: "JetBrains Mono", ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;

    /* ---------------------------------------------------------------------
     * 1.2 Brand palette — ported verbatim from duolingual/src/index.css @theme
     * ------------------------------------------------------------------ */
    --duo-ecto-green: #58cc02;
    --duo-lingot-lime: #a5ed6e;
    --duo-eel-light: #d7ffb8;
    --duo-macaw-blue: #1cb0f6;
    --duo-eel-dark-blue: #042c60;
    --duo-midnight: #000437;
    --duo-graphite: #e5e5e5;
    --duo-ash: #777777;
    --duo-charcoal: #4b4b4b;
    --duo-paper: #ffffff;

    /* NEW — for the word-box feature (does not exist in the React app) */
    --duo-error: #ff4b4b;
    --duo-error-bg: #fff1f1;
    --duo-error-border: #ffb3b3;

    /* ---------------------------------------------------------------------
     * 1.3 3D "lip" colours — the darker bottom border of pressable elements
     * Hex values lifted straight out of the JSX.
     * ------------------------------------------------------------------ */
    --duo-green-lip: #46a302;        /* [tw: border-b-[#46a302]]  check-answer button */
    --duo-green-lip-nav: #4cae02;    /* [tw: border-b-[#4cae02]]  active practice nav */
    --duo-blue-lip: #0388c3;         /* [tw: border-b-[#0388c3]]  next / search button */

    /* ---------------------------------------------------------------------
     * 1.4 Accent surfaces — ports of the Tailwind default palette swatches the
     * React app used for amber / purple / rose / medal / feedback states.
     * These are NOT new brand colours: they are the literal values behind
     * `bg-amber-100`, `text-purple-700`, `border-red-300`, … in the JSX and are
     * required by the component list (btn--amber, btn--purple, badge--medium,
     * badge--hard, rank--gold/silver/bronze, toast variants).
     * Values are the Tailwind v4 defaults converted from oklch to hex.
     * ------------------------------------------------------------------ */
    --duo-gray-50: #f9fafb;
    --duo-gray-100: #f3f4f6;
    --duo-gray-200: #e5e7eb;
    --duo-gray-500: #6a7282;
    --duo-slate-50: #f8fafc;
    --duo-slate-100: #f1f5f9;
    --duo-slate-300: #cad5e2;
    --duo-slate-700: #314158;

    --duo-green-100: #dcfce7;
    --duo-green-300: #7bf1a8;
    --duo-green-700: #008236;
    --duo-green-800: #016630;
    --duo-green-900: #0d542b;

    --duo-blue-100: #dbeafe;
    --duo-blue-200: #bedbff;
    --duo-sky-50: #f0f9ff;
    --duo-sky-600: #0084d1;
    --duo-sky-900: #052f4a;

    --duo-orange-50: #fff7ed;
    --duo-orange-100: #ffedd4;
    --duo-orange-200: #ffd6a8;
    --duo-orange-500: #ff6900;
    --duo-orange-600: #f54a00;

    --duo-amber-50: #fffbeb;
    --duo-amber-100: #fef3c6;
    --duo-amber-200: #fee685;
    --duo-amber-300: #ffd230;
    --duo-amber-500: #fe9a00;        /* nav / btn amber base   [tw: amber-500] */
    --duo-amber-600: #e17100;        /* nav / btn amber lip    [tw: amber-600] */
    --duo-amber-700: #bb4d00;
    --duo-amber-800: #973c00;
    --duo-amber-900: #7b3306;

    --duo-yellow-100: #fef9c2;
    --duo-yellow-300: #ffdf20;
    --duo-yellow-800: #894b00;

    --duo-purple-50: #faf5ff;
    --duo-purple-100: #f3e8ff;
    --duo-purple-200: #e9d4ff;
    --duo-purple-300: #dab2ff;
    --duo-purple-500: #ad46ff;
    --duo-purple-600: #9810fa;       /* nav / btn purple base  [tw: purple-600] */
    --duo-purple-700: #8200db;       /* nav / btn purple lip   [tw: purple-700] */
    --duo-purple-900: #59168b;

    --duo-rose-50: #fff1f2;
    --duo-rose-100: #ffe4e6;
    --duo-rose-200: #ffccd3;
    --duo-rose-500: #ff2056;
    --duo-rose-800: #a3004c;

    --duo-red-50: #fef2f2;
    --duo-red-100: #ffe2e2;
    --duo-red-200: #ffc9c9;
    --duo-red-300: #ffa2a2;
    --duo-red-500: #fb2c36;
    --duo-red-600: #e7000b;
    --duo-red-700: #c10007;
    --duo-red-800: #9f0712;
    --duo-red-900: #82181a;

    /* ---------------------------------------------------------------------
     * 1.5 Translucent surfaces — ports of Tailwind's `/opacity` modifiers
     * ------------------------------------------------------------------ */
    --duo-eel-light-50: rgba(215, 255, 184, .5);     /* [tw: bg-eel-light/50, bg-[#d7ffb8]/50] */
    --duo-eel-light-30: rgba(215, 255, 184, .3);     /* [tw: bg-eel-light/30] */
    --duo-eel-light-soft: rgba(215, 255, 184, .45);  /* NEW — .duo-box.is-done fill */
    --duo-lime-40: rgba(165, 237, 110, .4);          /* [tw: border-lingot-lime/40] */
    --duo-macaw-05: rgba(28, 176, 246, .05);         /* [tw: bg-macaw-blue/5]  hero banner */
    --duo-macaw-10: rgba(28, 176, 246, .1);          /* [tw: bg-macaw-blue/10] hero mascot */
    --duo-macaw-20: rgba(28, 176, 246, .2);          /* [tw: border-macaw-blue/20] */
    --duo-macaw-30: rgba(28, 176, 246, .3);          /* [tw: border-macaw-blue/30] */
    --duo-paper-60: rgba(255, 255, 255, .6);         /* [tw: bg-white/60] */
    --duo-paper-75: rgba(255, 255, 255, .75);        /* [tw: bg-white/75] */
    --duo-hairline: rgba(0, 0, 0, .05);              /* [tw: border-black/5] */

    /* ---------------------------------------------------------------------
     * 1.6 Radii   [tw: rounded-* scale]
     * ------------------------------------------------------------------ */
    --duo-radius-xs: 4px;      /* [tw: rounded] */
    --duo-radius-sm: 8px;      /* [tw: rounded-lg] */
    --duo-radius-md: 12px;     /* [tw: rounded-xl]  — the app's default */
    --duo-radius-lg: 16px;     /* [tw: rounded-2xl] */
    --duo-radius-pill: 9999px; /* [tw: rounded-full] */

    /* ---------------------------------------------------------------------
     * 1.7 Border / "lip" widths — the Duolingo 3D signature
     * ------------------------------------------------------------------ */
    --duo-border: 2px;         /* [tw: border-2]       — everywhere */
    --duo-hairline-w: 1px;     /* [tw: border]         — inner panels */
    --duo-lip-sm: 3px;         /* [tw: border-b-[3px]] — draft word block, small btn */
    --duo-lip: 4px;            /* [tw: border-b-[4px]] — pool word block, buttons, nav idle */
    --duo-lip-md: 5px;         /* [tw: border-b-[5px]] — nav active, toast, alert */
    --duo-lip-lg: 6px;         /* [tw: border-b-[6px]] — cards */
    --duo-lip-pressed: 2px;    /* [tw: active:border-b-[2px]] */
    --duo-press-shift: 2px;    /* [tw: active:translate-y-[2px]] */

    /* ---------------------------------------------------------------------
     * 1.8 Spacing scale — Tailwind's 0.25rem step
     * ------------------------------------------------------------------ */
    --duo-space-0-5: .125rem;  /* 2px  */
    --duo-space-1: .25rem;     /* 4px  */
    --duo-space-1-5: .375rem;  /* 6px  */
    --duo-space-2: .5rem;      /* 8px  */
    --duo-space-2-5: .625rem;  /* 10px */
    --duo-space-3: .75rem;     /* 12px */
    --duo-space-3-5: .875rem;  /* 14px */
    --duo-space-4: 1rem;       /* 16px */
    --duo-space-5: 1.25rem;    /* 20px */
    --duo-space-6: 1.5rem;     /* 24px */
    --duo-space-8: 2rem;       /* 32px */
    --duo-space-10: 2.5rem;    /* 40px */
    --duo-space-16: 4rem;      /* 64px */

    /* ---------------------------------------------------------------------
     * 1.9 Font sizes   [tw: text-* scale]
     * ------------------------------------------------------------------ */
    --duo-text-3xs: .625rem;   /* 10px  [tw: text-[10px]] */
    --duo-text-xs: .75rem;     /* 12px  [tw: text-xs]     */
    --duo-text-sm: .875rem;    /* 14px  [tw: text-sm]     */
    --duo-text-base: 1rem;     /* 16px  [tw: text-base]   */
    --duo-text-lg: 1.125rem;   /* 18px  [tw: text-lg]     */
    --duo-text-xl: 1.25rem;    /* 20px  [tw: text-xl]     */
    --duo-text-2xl: 1.5rem;    /* 24px  [tw: text-2xl]    */
    --duo-text-3xl: 1.875rem;  /* 30px  [tw: text-3xl]    */
    --duo-text-4xl: 2.25rem;   /* 36px  [tw: text-4xl]    */

    /* Line heights */
    --duo-leading-none: 1;
    --duo-leading-snug: 1.375;
    --duo-leading-normal: 1.5;
    --duo-leading-relaxed: 1.625;

    /* ---------------------------------------------------------------------
     * 1.10 Weights + tracking
     * ------------------------------------------------------------------ */
    --duo-weight-normal: 400;
    --duo-weight-bold: 700;        /* [tw: font-bold]      */
    --duo-weight-extrabold: 800;   /* [tw: font-extrabold] */
    --duo-weight-black: 900;       /* [tw: font-black]     */

    --duo-tracking-tight: -.025em; /* [tw: tracking-tight]  */
    --duo-tracking-base: .05em;    /* body letter-spacing from index.css */
    --duo-tracking-wide: .025em;   /* [tw: tracking-wide]   */
    --duo-tracking-wider: .05em;   /* [tw: tracking-wider]  */
    --duo-tracking-widest: .1em;   /* [tw: tracking-widest] */

    /* ---------------------------------------------------------------------
     * 1.11 Shadows   [tw: shadow-sm / shadow-lg]
     * ------------------------------------------------------------------ */
    --duo-shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, .05);
    --duo-shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, .1), 0 4px 6px -4px rgba(0, 0, 0, .1);

    /* ---------------------------------------------------------------------
     * 1.12 Motion — easings copied verbatim from index.css
     * ------------------------------------------------------------------ */
    --duo-ease-expo: cubic-bezier(0.16, 1, 0.3, 1);      /* fadeIn / slideIn / btn-tactile */
    --duo-ease-back: cubic-bezier(0.34, 1.56, 0.64, 1);  /* scaleIn (overshoot) */
    --duo-ease-shake: cubic-bezier(.36, .07, .19, .97);  /* NEW — duo-shake */
    --duo-dur-press: .15s;   /* .btn-tactile transition */
    --duo-dur-fade: .3s;     /* animate-fadeIn  */
    --duo-dur-slide: .4s;    /* animate-slideIn */
    --duo-dur-scale: .2s;    /* animate-scaleIn */
    --duo-dur-shake: .32s;   /* NEW */
    --duo-dur-bar: .5s;      /* [tw: duration-500] progress fill */

    /* ---------------------------------------------------------------------
     * 1.13 z-index
     * ------------------------------------------------------------------ */
    --duo-z-base: 1;
    --duo-z-raised: 10;
    --duo-z-drawer: 40;
    --duo-z-header: 50;   /* [tw: sticky top-0 z-50] */
    --duo-z-toast: 60;    /* above header on purpose */

    /* ---------------------------------------------------------------------
     * 1.14 Layout
     * ------------------------------------------------------------------ */
    --duo-shell-max: 72rem;      /* [tw: max-w-6xl] = 1152px */
    --duo-shell-pad: 1rem;       /* [tw: px-4] */
    --duo-grid-gap: 2rem;        /* [tw: gap-8] */
    --duo-header-h: 4rem;        /* [tw: h-16] */
}


/* =============================================================================
 * 2. APP SHELL
 * ========================================================================== */

/* [tw: min-h-screen bg-white text-charcoal font-sans pb-16 flex flex-col
 *      selection:bg-eel-light  + body{} rules from index.css] */
.duo-app {
    display: flex;
    flex-direction: column;
    min-height: 100vh;
    padding-bottom: var(--duo-space-16);
    font-family: var(--duo-font-sans);
    font-size: var(--duo-text-base);
    line-height: var(--duo-leading-normal);
    letter-spacing: var(--duo-tracking-base);
    color: var(--duo-charcoal);
    background-color: var(--duo-paper);
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}

/* Scoped box-sizing reset (replaces Tailwind preflight) — never leaks out of
 * the app because it is anchored on .duo-app. */
.duo-app *,
.duo-app *::before,
.duo-app *::after {
    box-sizing: border-box;
}

.duo-app ::selection {
    background-color: var(--duo-eel-light);
}

/* Headings inside the app must not inherit the theme's huge margins. */
.duo-app h1,
.duo-app h2,
.duo-app h3,
.duo-app h4,
.duo-app h5,
.duo-app p {
    margin: 0;
}

/* --- Sticky header -------------------------------------------------------- */
/* [tw: sticky top-0 z-50 bg-white border-b-2 border-graphite h-16 shrink-0 shadow-sm] */
.duo-header {
    position: sticky;
    top: 0;
    z-index: var(--duo-z-header);
    flex-shrink: 0;
    height: var(--duo-header-h);
    background-color: var(--duo-paper);
    border-bottom: var(--duo-border) solid var(--duo-graphite);
    box-shadow: var(--duo-shadow-sm);
}

/* [tw: max-w-6xl mx-auto h-full px-4 flex items-center justify-between] */
.duo-header__inner {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--duo-space-4);
    height: 100%;
    max-width: var(--duo-shell-max);
    margin-inline: auto;
    padding-inline: var(--duo-shell-pad);
}

/* [tw: flex items-center space-x-3] */
.duo-brand {
    display: flex;
    align-items: center;
    gap: var(--duo-space-3);
}

/* [tw: text-3xl filter drop-shadow animate-bounce] */
.duo-brand__owl {
    font-size: var(--duo-text-3xl);
    line-height: var(--duo-leading-none);
    filter: drop-shadow(0 1px 1px rgba(0, 0, 0, .1));
}

/* [tw: text-lg font-black text-ecto-green tracking-wider uppercase leading-none] */
.duo-brand__title {
    display: flex;
    align-items: center;
    gap: .375rem;
    font-size: var(--duo-text-lg);
    font-weight: var(--duo-weight-black);
    line-height: var(--duo-leading-none);
    text-transform: uppercase;
    letter-spacing: var(--duo-tracking-wider);
    color: var(--duo-ecto-green);
}

.duo-brand__title-accent {
    color: var(--duo-eel-dark-blue);
}

/* [tw: text-[10px] text-ash tracking-widest uppercase font-black mt-1] */
.duo-brand__tagline {
    margin-top: var(--duo-space-1);
    font-size: var(--duo-text-3xs);
    font-weight: var(--duo-weight-black);
    text-transform: uppercase;
    letter-spacing: var(--duo-tracking-widest);
    color: var(--duo-ash);
}

/* --- Header metric pills -------------------------------------------------- */
/* [tw: flex items-center space-x-1.5 border-2 px-3 py-1 rounded-xl] */
.duo-metrics {
    display: flex;
    align-items: center;
    gap: var(--duo-space-4);
}

.duo-pill {
    display: inline-flex;
    align-items: center;
    gap: var(--duo-space-1-5);
    padding: var(--duo-space-1) var(--duo-space-3);
    border: var(--duo-border) solid var(--duo-graphite);
    border-radius: var(--duo-radius-md);
    font-size: var(--duo-text-sm);
    font-weight: var(--duo-weight-black);
}

/* [tw: bg-orange-50 border-orange-200 text-orange-600] */
.duo-pill--streak {
    background-color: var(--duo-orange-50);
    border-color: var(--duo-orange-200);
    color: var(--duo-orange-600);
}

/* [tw: bg-eel-light/50 border-lingot-lime text-ecto-green] */
.duo-pill--xp {
    background-color: var(--duo-eel-light-50);
    border-color: var(--duo-lingot-lime);
    color: var(--duo-ecto-green);
}

/* [tw: text-[10px] text-gray-500 font-normal] — the "XP" suffix */
.duo-pill__unit {
    font-size: var(--duo-text-3xs);
    font-weight: var(--duo-weight-normal);
    color: var(--duo-gray-500);
}

/* --- Hero banner --------------------------------------------------------- */
/* [tw: bg-macaw-blue/5 border-2 border-macaw-blue rounded-2xl p-5
 *      flex flex-col md:flex-row items-center justify-between gap-4] */
.duo-hero {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: space-between;
    gap: var(--duo-space-4);
    padding: var(--duo-space-5);
    background-color: var(--duo-macaw-05);
    border: var(--duo-border) solid var(--duo-macaw-blue);
    border-radius: var(--duo-radius-lg);
}

/* [tw: flex items-start space-x-4] */
.duo-hero__body {
    display: flex;
    align-items: flex-start;
    gap: var(--duo-space-4);
}

/* [tw: text-lg font-black text-eel-dark-blue tracking-tight uppercase] */
.duo-hero__title {
    font-size: var(--duo-text-lg);
    font-weight: var(--duo-weight-black);
    text-transform: uppercase;
    letter-spacing: var(--duo-tracking-tight);
    color: var(--duo-eel-dark-blue);
}

/* [tw: text-xs text-charcoal mt-1 leading-relaxed max-w-2xl font-bold] */
.duo-hero__text {
    max-width: 42rem;
    margin-top: var(--duo-space-1);
    font-size: var(--duo-text-xs);
    font-weight: var(--duo-weight-bold);
    line-height: var(--duo-leading-relaxed);
    color: var(--duo-charcoal);
}

/* [tw: bg-white border-2 border-graphite px-4 py-2.5 rounded-xl text-xs
 *      text-ash shadow-sm flex items-center space-x-2 shrink-0] */
.duo-quote {
    display: flex;
    flex-shrink: 0;
    align-items: center;
    gap: var(--duo-space-2);
    max-width: 100%;
    padding: var(--duo-space-2-5) var(--duo-space-4);
    font-size: var(--duo-text-xs);
    color: var(--duo-ash);
    background-color: var(--duo-paper);
    border: var(--duo-border) solid var(--duo-graphite);
    border-radius: var(--duo-radius-md);
    box-shadow: var(--duo-shadow-sm);
}

.duo-quote__text {
    font-weight: var(--duo-weight-bold);
    font-style: italic;
}

@media (min-width: 768px) {
    .duo-hero {
        flex-direction: row;
    }
}


/* =============================================================================
 * 3. LAYOUT — CSS Grid port of `max-w-6xl mx-auto` + `md:grid-cols-12`
 * Breakpoints: 640px (sm) / 768px (md) / 1024px (lg) — same as Tailwind.
 * ========================================================================== */

/* [tw: max-w-6xl mx-auto w-full px-4] */
.duo-shell {
    width: 100%;
    max-width: var(--duo-shell-max);
    margin-inline: auto;
    padding-inline: var(--duo-shell-pad);
}

.duo-shell--flush-top {
    padding-top: var(--duo-space-8);   /* [tw: pt-8] */
}

.duo-shell--main {
    flex: 1 1 auto;                    /* [tw: flex-1] */
    margin-top: var(--duo-space-8);    /* [tw: mt-8]   */
}

/* [tw: grid grid-cols-1 md:grid-cols-12 gap-8] */
.duo-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--duo-grid-gap);
}

.duo-col-sidebar,
.duo-col-main {
    min-width: 0;   /* prevents grid blowout from long words / charts */
}

@media (min-width: 768px) {
    .duo-grid {
        grid-template-columns: repeat(12, minmax(0, 1fr));
    }

    /* [tw: md:col-span-3] */
    .duo-col-sidebar {
        grid-column: span 3 / span 3;
    }

    /* [tw: md:col-span-9] */
    .duo-col-main {
        grid-column: span 9 / span 9;
    }

    /* `.duo-grid--practice` là grid 1 cột dưới 1024px, nhưng 2 rule span 3/9 ở
     * trên KHÔNG scope theo grid cha nên con của nó vẫn ăn → `span 3` sinh cột
     * ẩn, layout lệch ở dải 768–1023px. Reset về `auto`; khối 1024px bên dưới
     * (cùng specificity, source order sau) vẫn thắng ở ≥1024px. */
    .duo-grid--practice > .duo-col-sidebar,
    .duo-grid--practice > .duo-col-main {
        grid-column: auto;
    }
}

/* Practice pane uses `lg:grid-cols-12` + 4/8 split, i.e. it stays a single
 * column until 1024px. Declared AFTER the md block so it wins there.
 * [tw: grid grid-cols-1 lg:grid-cols-12 gap-8 / lg:col-span-4 / lg:col-span-8] */
.duo-grid--practice {
    grid-template-columns: 1fr;
}

@media (min-width: 1024px) {
    .duo-grid--practice {
        grid-template-columns: repeat(12, minmax(0, 1fr));
    }

    .duo-grid--practice > .duo-col-sidebar {
        grid-column: span 4 / span 4;
    }

    .duo-grid--practice > .duo-col-main {
        grid-column: span 8 / span 8;
    }
}

/* --- Top bar: 3 tab nằm ngang + card mục tiêu bên phải (hàng 1 của shell) - */
.duo-topbar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--duo-grid-gap);
}

.duo-navrow {
    display: flex;
    flex: 1 1 auto;
    flex-wrap: wrap;
    gap: var(--duo-space-3);
}

/* Thắng `.duo-app .duo-nav-btn { width: 100% }` (0,2,0) bằng specificity
 * (0,3,0) — KHÔNG dùng !important. */
.duo-app .duo-navrow .duo-nav-btn {
    width: auto;
    flex: 1 1 auto;
    justify-content: center;
}

.duo-topbar__goal {
    flex: 0 1 20rem;
}

/* --- Secondary grids ----------------------------------------------------- */
/* [tw: grid grid-cols-1 md:grid-cols-3 gap-4] — stat cards */
.duo-stat-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--duo-space-4);
}

/* [tw: grid grid-cols-1 lg:grid-cols-2 gap-6] — chart cards */
.duo-chart-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--duo-space-6);
}

/* [tw: grid grid-cols-2 gap-4] — synonyms / antonyms */
.duo-split-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--duo-space-4);
}

/* Grid ngữ pháp ở TRANG GỐC của practice panel (danh sách tất cả cấu trúc).
 * 1 cột → 2 cột ≥640px → 3 cột ≥1024px.
 * `.duo-select-card` bên trong KHÔNG cần rule chiều cao: nó là grid item và
 * `align-self` mặc định là stretch, nên các thẻ cùng hàng tự bằng nhau. */
.duo-grammar-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--duo-space-4);
}

@media (min-width: 640px) {
    .duo-split-grid {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    .duo-grammar-grid {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

@media (min-width: 768px) {
    .duo-stat-grid {
        grid-template-columns: repeat(3, minmax(0, 1fr));
    }
}

@media (min-width: 1024px) {
    .duo-chart-grid {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    .duo-grammar-grid {
        grid-template-columns: repeat(3, minmax(0, 1fr));
    }
}

/* --- Vertical rhythm helpers (ports of `space-y-*`) ---------------------- */
.duo-stack {
    display: flex;
    flex-direction: column;
    gap: var(--duo-space-4);
}

.duo-stack--xs { gap: var(--duo-space-2); }        /* [tw: space-y-2]   */
.duo-stack--sm { gap: var(--duo-space-2-5); }      /* [tw: space-y-2.5] */
.duo-stack--md { gap: var(--duo-space-3); }        /* [tw: space-y-3]   */
.duo-stack--lg { gap: var(--duo-space-6); }        /* [tw: space-y-6]   */

/* [tw: flex items-start space-x-4] — mascot + bubble row, alert row … */
.duo-row {
    display: flex;
    align-items: flex-start;
    gap: var(--duo-space-4);
}

.duo-row--center { align-items: center; }
.duo-row--between { justify-content: space-between; }
.duo-row--end { justify-content: flex-end; }
.duo-row--wrap { flex-wrap: wrap; }   /* [tw: flex-wrap] — tiêu đề + tóm tắt phân trang */

/* [tw: hidden md:block] — target card, hero mascot */
.duo-hide-sm { display: none; }
.duo-hide-md { display: none; }

@media (min-width: 640px) {
    .duo-hide-sm { display: block; }
}

@media (min-width: 768px) {
    .duo-hide-md { display: block; }
}

/* Screen-reader-only label (word boxes need an accessible name) */
.duo-sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}


/* =============================================================================
 * 4. SURFACES — cards & panels
 * ========================================================================== */

/* THE signature card.
 * [tw: bg-white border-2 border-graphite border-b-[6px] rounded-xl p-6] */
.duo-card {
    padding: var(--duo-space-6);
    background-color: var(--duo-paper);
    border: var(--duo-border) solid var(--duo-graphite);
    border-bottom-width: var(--duo-lip-lg);
    border-radius: var(--duo-radius-md);
}

.duo-card--flush {
    padding: 0;
    overflow: hidden;              /* [tw: overflow-hidden] dictionary result card */
    border-bottom-width: var(--duo-border);
}

.duo-card--pad-sm { padding: var(--duo-space-4); }   /* [tw: p-4] */
.duo-card--pad-md { padding: var(--duo-space-5); }   /* [tw: p-5] */
.duo-card--pad-lg { padding: var(--duo-space-8); }   /* [tw: p-8] */

/* [tw: bg-slate-50 border-2 border-graphite rounded-2xl p-4 mt-6] — target card */
.duo-panel {
    padding: var(--duo-space-4);
    background-color: var(--duo-slate-50);
    border: var(--duo-border) solid var(--duo-graphite);
    border-radius: var(--duo-radius-lg);
}

/* [tw: flex items-center space-x-2 mb-2] + [tw: text-xs font-black uppercase
 *      text-eel-dark-blue tracking-wide] — "Mục tiêu hôm nay" heading */
.duo-panel__head {
    display: flex;
    align-items: center;
    gap: var(--duo-space-2);
    margin-bottom: var(--duo-space-2);
}

.duo-panel__title {
    font-size: var(--duo-text-xs);
    font-weight: var(--duo-weight-black);
    text-transform: uppercase;
    letter-spacing: var(--duo-tracking-wide);
    color: var(--duo-eel-dark-blue);
}

/* [tw: w-4 h-4 text-rose-500] — the 🎯 Target icon */
.duo-panel__icon {
    flex-shrink: 0;
    width: 1rem;
    height: 1rem;
    color: var(--duo-rose-500);
}

/* [tw: bg-slate-50 border border-dashed border-graphite p-3.5 rounded-xl
 *      text-xs text-charcoal leading-relaxed] — grammar explanation */
.duo-note {
    padding: var(--duo-space-3-5);
    font-size: var(--duo-text-xs);
    line-height: var(--duo-leading-relaxed);
    color: var(--duo-charcoal);
    background-color: var(--duo-slate-50);
    border: var(--duo-hairline-w) dashed var(--duo-graphite);
    border-radius: var(--duo-radius-md);
}

.duo-note__lead {
    font-weight: var(--duo-weight-extrabold);
    color: var(--duo-eel-dark-blue);
}

/* [tw: border-t border-graphite pt-4] — action bar divider */
.duo-divider-top {
    padding-top: var(--duo-space-4);
    border-top: var(--duo-hairline-w) solid var(--duo-graphite);
}

/* --- Typographic helpers used by every section header -------------------- */
/* [tw: text-sm font-black text-ash uppercase tracking-wider] */
.duo-eyebrow {
    font-size: var(--duo-text-sm);
    font-weight: var(--duo-weight-black);
    text-transform: uppercase;
    letter-spacing: var(--duo-tracking-wider);
    color: var(--duo-ash);
}

/* [tw: text-xs uppercase text-ash font-black tracking-widest] */
.duo-eyebrow--xs {
    font-size: var(--duo-text-xs);
    letter-spacing: var(--duo-tracking-widest);
}

/* [tw: text-xl font-black text-eel-dark-blue tracking-tight uppercase] */
.duo-title {
    font-size: var(--duo-text-xl);
    font-weight: var(--duo-weight-black);
    text-transform: uppercase;
    letter-spacing: var(--duo-tracking-tight);
    color: var(--duo-eel-dark-blue);
}

.duo-title--lg { font-size: var(--duo-text-2xl); }   /* [tw: text-2xl] */
.duo-title--md { font-size: var(--duo-text-lg); }    /* [tw: text-lg]  */

/* [tw: text-xs text-ash] */
.duo-subtitle {
    font-size: var(--duo-text-xs);
    color: var(--duo-ash);
}

.duo-muted { color: var(--duo-ash); }
.duo-strong { font-weight: var(--duo-weight-black); }
.duo-italic { font-style: italic; }


/* =============================================================================
 * 5. BUTTONS — port of `.btn-tactile` + every inline button in the JSX
 * Base = shape/typography; variants = colour + lip colour.
 * ========================================================================== */

/* [tw: px-6 py-2.5 rounded-xl border-2 border-b-[4px] font-black uppercase
 *      tracking-wider flex items-center space-x-1.5 transition-all
 *      disabled:opacity-50 active:translate-y-[2px] active:border-b-[2px]] */
.duo-app .duo-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--duo-space-1-5);
    padding: var(--duo-space-2-5) var(--duo-space-6);
    font-family: var(--duo-font-sans);
    font-size: var(--duo-text-sm);
    font-weight: var(--duo-weight-black);
    line-height: 1.25;
    text-align: center;
    text-decoration: none;
    text-transform: uppercase;
    letter-spacing: var(--duo-tracking-wider);
    color: var(--duo-charcoal);
    background-color: var(--duo-paper);
    border: var(--duo-border) solid var(--duo-graphite);
    border-bottom-width: var(--duo-lip);
    border-radius: var(--duo-radius-md);
    cursor: pointer;
    -webkit-appearance: none;
    appearance: none;
    transition: all var(--duo-dur-press) var(--duo-ease-expo);
}

/* [tw: active:translate-y-[2px] active:border-b-[2px]] */
.duo-app .duo-btn:active:not(:disabled):not(.is-disabled) {
    transform: translateY(var(--duo-press-shift));
    border-bottom-width: var(--duo-lip-pressed);
}

/* [tw: disabled:opacity-50 disabled:pointer-events-none] */
.duo-app .duo-btn:disabled,
.duo-app .duo-btn[aria-disabled="true"],
.duo-app .duo-btn.is-disabled {
    opacity: .5;
    pointer-events: none;
}

.duo-app .duo-btn:focus-visible {
    outline: var(--duo-border) solid var(--duo-macaw-blue);
    outline-offset: var(--duo-border);
}

/* [tw: hover:brightness-105] */
.duo-app .duo-btn--green,
.duo-app .duo-btn--blue,
.duo-app .duo-btn--amber,
.duo-app .duo-btn--purple {
    color: var(--duo-paper);
}

.duo-app .duo-btn--green:hover:not(:disabled),
.duo-app .duo-btn--blue:hover:not(:disabled),
.duo-app .duo-btn--amber:hover:not(:disabled),
.duo-app .duo-btn--purple:hover:not(:disabled) {
    filter: brightness(1.05);
}

/* [tw: bg-ecto-green border-ecto-green border-b-[#46a302]] */
.duo-app .duo-btn--green {
    background-color: var(--duo-ecto-green);
    border-color: var(--duo-ecto-green);
    border-bottom-color: var(--duo-green-lip);
}

/* [tw: bg-macaw-blue border-macaw-blue border-b-[#0388c3]] */
.duo-app .duo-btn--blue {
    background-color: var(--duo-macaw-blue);
    border-color: var(--duo-macaw-blue);
    border-bottom-color: var(--duo-blue-lip);
}

/* [tw: bg-amber-500 border-amber-500 border-b-amber-600] */
.duo-app .duo-btn--amber {
    background-color: var(--duo-amber-500);
    border-color: var(--duo-amber-500);
    border-bottom-color: var(--duo-amber-600);
}

/* [tw: bg-purple-600 border-purple-600 border-b-purple-700] */
.duo-app .duo-btn--purple {
    background-color: var(--duo-purple-600);
    border-color: var(--duo-purple-600);
    border-bottom-color: var(--duo-purple-700);
}

/* [tw: bg-white text-charcoal border-graphite hover:bg-gray-50 hover:border-charcoal] */
.duo-app .duo-btn--ghost {
    color: var(--duo-charcoal);
    background-color: var(--duo-paper);
    border-color: var(--duo-graphite);
}

.duo-app .duo-btn--ghost:hover:not(:disabled) {
    background-color: var(--duo-gray-50);
    border-color: var(--duo-charcoal);
}

/* AI generator button — a tinted "soft purple" button, not the solid one.
 * [tw: bg-purple-50 hover:bg-purple-100 text-purple-700 px-3.5 py-2 rounded-xl
 *      border-2 border-purple-200 hover:border-purple-300 border-b-[3px]] */
.duo-app .duo-btn--purple-soft {
    color: var(--duo-purple-700);
    background-color: var(--duo-purple-50);
    border-color: var(--duo-purple-200);
    border-bottom-width: var(--duo-lip-sm);
}

.duo-app .duo-btn--purple-soft:hover:not(:disabled) {
    background-color: var(--duo-purple-100);
    border-color: var(--duo-purple-300);
}

/* [tw: text-xs font-bold uppercase tracking-wider px-3.5 py-2] — small pill */
.duo-app .duo-btn--sm {
    gap: var(--duo-space-1-5);
    padding: var(--duo-space-2) var(--duo-space-3-5);
    font-size: var(--duo-text-xs);
    font-weight: var(--duo-weight-extrabold);
    border-bottom-width: var(--duo-lip-sm);
}

.duo-app .duo-btn--xs {
    padding: var(--duo-space-1) var(--duo-space-2-5);
    font-size: var(--duo-text-3xs);
    border-bottom-width: var(--duo-lip-sm);
}

/* [tw: p-1.5 rounded-lg border-2 border-graphite hover:border-macaw-blue
 *      text-ash hover:text-macaw-blue bg-white hover:bg-sky-50
 *      active:translate-y-[1px]] — leaderboard "challenge" icon button */
.duo-app .duo-btn--icon {
    gap: 0;
    padding: var(--duo-space-1-5);
    color: var(--duo-ash);
    border-bottom-width: var(--duo-border);
    border-radius: var(--duo-radius-sm);
}

.duo-app .duo-btn--icon:hover:not(:disabled) {
    color: var(--duo-macaw-blue);
    background-color: var(--duo-sky-50);
    border-color: var(--duo-macaw-blue);
}

/* `:not(.is-disabled)` is repeated here only to match the specificity of the
 * base `.duo-btn:active` rule — without it that rule (one class heavier) would
 * keep the 2px shift. Same reason on --link below and in the reduced-motion block. */
.duo-app .duo-btn--icon:active:not(:disabled):not(.is-disabled) {
    transform: translateY(1px);
    border-bottom-width: var(--duo-border);
}

/* [tw: text-xs font-black uppercase tracking-wider text-macaw-blue
 *      hover:text-sky-600 flex items-center space-x-1] — mode toggle link */
.duo-app .duo-btn--link {
    gap: var(--duo-space-1);
    padding: 0;
    font-size: var(--duo-text-xs);
    color: var(--duo-macaw-blue);
    background: none;
    border: 0;
    border-radius: 0;
}

.duo-app .duo-btn--link:hover:not(:disabled) {
    color: var(--duo-sky-600);
}

.duo-app .duo-btn--link:active:not(:disabled):not(.is-disabled) {
    transform: none;
    border-bottom-width: 0;
}

/* [tw: w-full] */
.duo-app .duo-btn--block {
    width: 100%;
}

/* Icon sizing inside buttons — [tw: w-4 h-4 / w-3.5 h-3.5 / w-5 h-5] */
.duo-btn__icon {
    flex-shrink: 0;
    width: 1rem;
    height: 1rem;
}

.duo-btn__icon--sm { width: .875rem; height: .875rem; }
.duo-btn__icon--lg { width: 1.25rem; height: 1.25rem; }


/* =============================================================================
 * 6. NAVIGATION — 4 sidebar tabs, one accent colour each
 * ========================================================================== */

/* [tw: w-full flex items-center space-x-3.5 px-4 py-3.5 rounded-xl border-2
 *      transition-all font-black uppercase tracking-wider text-sm
 *      + idle: bg-white text-charcoal border-graphite border-b-[4px]] */
.duo-app .duo-nav-btn {
    display: flex;
    align-items: center;
    gap: var(--duo-space-3-5);
    width: 100%;
    padding: var(--duo-space-3-5) var(--duo-space-4);
    font-family: var(--duo-font-sans);
    font-size: var(--duo-text-sm);
    font-weight: var(--duo-weight-black);
    line-height: 1.25;
    text-align: left;
    text-decoration: none;
    text-transform: uppercase;
    letter-spacing: var(--duo-tracking-wider);
    color: var(--duo-charcoal);
    background-color: var(--duo-paper);
    border: var(--duo-border) solid var(--duo-graphite);
    border-bottom-width: var(--duo-lip);
    border-radius: var(--duo-radius-md);
    cursor: pointer;
    -webkit-appearance: none;
    appearance: none;
    transition: all var(--duo-dur-press) var(--duo-ease-expo);
}

/* [tw: hover:bg-gray-50 hover:border-charcoal] */
.duo-app .duo-nav-btn:hover:not(.is-active) {
    background-color: var(--duo-gray-50);
    border-color: var(--duo-charcoal);
}

.duo-app .duo-nav-btn:focus-visible {
    outline: var(--duo-border) solid var(--duo-macaw-blue);
    outline-offset: var(--duo-border);
}

/* [tw: active tab -> text-white border-b-[5px]] */
.duo-app .duo-nav-btn.is-active {
    color: var(--duo-paper);
    border-bottom-width: var(--duo-lip-md);
}

/* [tw: bg-ecto-green border-ecto-green border-b-[#4cae02]] */
.duo-app .duo-nav-btn--practice.is-active {
    background-color: var(--duo-ecto-green);
    border-color: var(--duo-ecto-green);
    border-bottom-color: var(--duo-green-lip-nav);
}

/* [tw: bg-amber-500 border-amber-500 border-b-amber-600] */
.duo-app .duo-nav-btn--leaderboard.is-active {
    background-color: var(--duo-amber-500);
    border-color: var(--duo-amber-500);
    border-bottom-color: var(--duo-amber-600);
}

/* [tw: bg-purple-600 border-purple-600 border-b-purple-700] */
.duo-app .duo-nav-btn--progress.is-active {
    background-color: var(--duo-purple-600);
    border-color: var(--duo-purple-600);
    border-bottom-color: var(--duo-purple-700);
}

/* [tw: w-5 h-5 shrink-0] */
.duo-nav-btn__icon {
    flex-shrink: 0;
    width: 1.25rem;
    height: 1.25rem;
}

/* --- Selectable list card (grammar structure picker) --------------------- */
/* [tw: w-full text-left p-4 rounded-xl border-2 transition-all relative
 *      idle: border-graphite bg-white hover:border-charcoal border-b-[4px]] */
.duo-app .duo-select-card {
    position: relative;
    display: block;
    width: 100%;
    padding: var(--duo-space-4);
    font-family: var(--duo-font-sans);
    text-align: left;
    /* Thẻ này là <a> (link thật tới /cau-truc-ngu-phap/{id}/), không còn là
     * <button>: phải tắt gạch chân mặc định của link, kể cả ở :hover của theme.
     * `display: block` ở trên đã lo phần <a> mặc định là inline. */
    text-decoration: none;
    background-color: var(--duo-paper);
    border: var(--duo-border) solid var(--duo-graphite);
    border-bottom-width: var(--duo-lip);
    border-radius: var(--duo-radius-md);
    cursor: pointer;
    -webkit-appearance: none;
    appearance: none;
    transition: all var(--duo-dur-press) var(--duo-ease-expo);
}

.duo-app .duo-select-card:hover:not(.is-active) {
    border-color: var(--duo-charcoal);
}

/* [tw: border-ecto-green bg-eel-light/30 border-b-[5px]] */
.duo-app .duo-select-card.is-active {
    background-color: var(--duo-eel-light-30);
    border-color: var(--duo-ecto-green);
    border-bottom-width: var(--duo-lip-md);
}

.duo-app .duo-select-card:focus-visible {
    outline: var(--duo-border) solid var(--duo-macaw-blue);
    outline-offset: var(--duo-border);
}

/* [tw: font-extrabold text-sm text-eel-dark-blue tracking-wide] */
.duo-select-card__title {
    font-size: var(--duo-text-sm);
    font-weight: var(--duo-weight-extrabold);
    letter-spacing: var(--duo-tracking-wide);
    color: var(--duo-eel-dark-blue);
}

/* [tw: text-xs text-ash mt-0.5] */
.duo-select-card__meta {
    margin-top: var(--duo-space-0-5);
    font-size: var(--duo-text-xs);
    color: var(--duo-ash);
}

/* [tw: text-xl] emoji */
.duo-select-card__emoji {
    font-size: var(--duo-text-xl);
    line-height: var(--duo-leading-none);
}

/* [tw: max-h-[500px] overflow-y-auto pr-1] */
.duo-scroll-list {
    max-height: 500px;
    padding-right: var(--duo-space-1);
    overflow-y: auto;
}


/* =============================================================================
 * 7. `.duo-box` — WORD-BOX INPUT (new feature, not present in the React app)
 * -----------------------------------------------------------------------------
 * One <input> per English word. Wrong keystroke => the box shakes and turns red.
 *
 * WIDTH CONTRACT (Alpine sets the custom property, CSS does the maths):
 *     <input class="duo-box" style="--duo-box-len: 7">
 *     width: calc(var(--duo-box-len) * 1ch + 1.5rem)
 *
 * Why the geometry works out EXACTLY:
 *   - `box-sizing: border-box` (from the .duo-app reset) means `width` covers
 *     content + padding + border.
 *   - padding-inline is `calc(.75rem - var(--duo-border))` per side, so
 *       2 * (.75rem - 2px)  +  2 * 2px  ==  1.5rem
 *     exactly — the border width cancels out, which keeps the sum correct even
 *     if a theme changes the root font-size (a flat 10px padding would not).
 *   - …so the `+ 1.5rem` in the calc() is consumed precisely by the box chrome
 *     and the content box ends up exactly `--duo-box-len * 1ch` wide.
 *     Do NOT change padding-inline or --duo-border without re-deriving this.
 *
 * Why a MONOSPACE font here (and only here):
 *   `1ch` is defined as the advance width of the "0" glyph. In Nunito
 *   (proportional) "0" is ~0.6em but "i" is ~0.28em and "m" ~0.9em, so
 *   `len * 1ch` would be far too narrow for "mm" and far too wide for "il".
 *   JetBrains Mono — already loaded by the app for IPA transcription, so no
 *   extra network cost — has a uniform 0.6em advance for every glyph, making
 *   `len * 1ch` mathematically exact for any word.
 *   Ligatures MUST be off: JetBrains Mono ships coding ligatures ("->", "!=")
 *   that fuse two glyphs into one advance and would break the fit.
 *   letter-spacing MUST be 0: .duo-app sets .05em globally, which would add
 *   len * 0.8px of untracked width and overflow the box.
 * ========================================================================== */

/* Container — [flex wrap, gap, baseline] */
.duo-box-row {
    display: flex;
    flex-wrap: wrap;
    gap: var(--duo-space-2-5) var(--duo-space-2);
    align-items: baseline;
}

.duo-box-row--center {
    justify-content: center;
}

/* Punctuation rendered between boxes (".", ",", "?") — not editable */
.duo-box-row__punct {
    align-self: flex-end;
    padding-bottom: var(--duo-space-1);
    font-family: var(--duo-font-mono);
    font-size: var(--duo-text-lg);
    font-weight: var(--duo-weight-bold);
    color: var(--duo-ash);
    user-select: none;
}

.duo-app .duo-box {
    /* Fallback so the box is usable even if Alpine has not set the property */
    --duo-box-len: 8;

    box-sizing: border-box;
    width: calc(var(--duo-box-len) * 1ch + 1.5rem);
    min-width: calc(3ch + 1.5rem);   /* keeps 1-2 letter words tappable */
    max-width: 100%;
    padding-block: var(--duo-space-2);
    /* inline padding + border must total exactly 1.5rem — see width contract */
    padding-inline: calc(.75rem - var(--duo-border));

    font-family: var(--duo-font-mono);
    font-size: var(--duo-text-base);
    font-weight: var(--duo-weight-bold);
    line-height: 1.5;
    letter-spacing: 0;               /* MUST stay 0 — see comment above */
    text-align: center;
    text-transform: none;            /* never auto-capitalise visually */
    font-variant-ligatures: none;
    font-feature-settings: "liga" 0, "clig" 0, "calt" 0;
    font-variant-numeric: tabular-nums;

    color: var(--duo-charcoal);
    caret-color: var(--duo-macaw-blue);
    background-color: var(--duo-paper);
    border: var(--duo-border) solid var(--duo-graphite);
    border-bottom-width: var(--duo-lip-sm);
    border-radius: var(--duo-radius-sm);

    -webkit-appearance: none;
    appearance: none;
    outline: none;
    /* transform is intentionally NOT transitioned: the shake keyframes own it */
    transition:
        border-color var(--duo-dur-press) var(--duo-ease-expo),
        background-color var(--duo-dur-press) var(--duo-ease-expo),
        color var(--duo-dur-press) var(--duo-ease-expo);
}

/* idle -> focused. `.is-active` is the Alpine-driven state; `:focus` covers
 * plain keyboard/mouse focus so both look identical. */
.duo-app .duo-box.is-active,
.duo-app .duo-box:focus {
    border-color: var(--duo-macaw-blue);
    box-shadow: 0 0 0 1px var(--duo-macaw-blue);
}

/* whole word typed correctly */
.duo-app .duo-box.is-done {
    color: var(--duo-ecto-green);
    background-color: var(--duo-eel-light-soft);
    border-color: var(--duo-ecto-green);
    box-shadow: none;
}

/* wrong character — shake + red. Wins over .is-active/.is-done by being last. */
.duo-app .duo-box.is-error {
    color: var(--duo-error);
    caret-color: var(--duo-error);
    background-color: var(--duo-error-bg);
    border-color: var(--duo-error);
    box-shadow: 0 0 0 1px var(--duo-error-border);
    animation: duo-shake var(--duo-dur-shake) var(--duo-ease-shake) both;
}

.duo-app .duo-box:disabled,
.duo-app .duo-box[readonly] {
    color: var(--duo-ash);
    background-color: var(--duo-gray-50);
    cursor: default;
}

.duo-app .duo-box::placeholder {
    color: var(--duo-graphite);
    opacity: 1;
}

/* Optional per-box hint (the target word length / first letter) */
.duo-box-hint {
    display: block;
    margin-top: var(--duo-space-0-5);
    font-size: var(--duo-text-3xs);
    font-weight: var(--duo-weight-black);
    text-align: center;
    letter-spacing: var(--duo-tracking-widest);
    color: var(--duo-ash);
}


/* =============================================================================
 * 8. WORD BLOCKS — tap-to-build sentence (GrammarPractice mode B)
 * ========================================================================== */

/* Pool block.
 * [tw: bg-white text-charcoal px-3.5 py-2 rounded-xl border-2 border-graphite
 *      border-b-[4px] hover:border-charcoal hover:bg-slate-50 font-extrabold
 *      text-sm active:translate-y-[2px] active:border-b-[2px] transition-all] */
.duo-app .duo-word-block {
    display: inline-flex;
    align-items: center;
    padding: var(--duo-space-2) var(--duo-space-3-5);
    font-family: var(--duo-font-sans);
    font-size: var(--duo-text-sm);
    font-weight: var(--duo-weight-extrabold);
    line-height: 1.25;
    color: var(--duo-charcoal);
    background-color: var(--duo-paper);
    border: var(--duo-border) solid var(--duo-graphite);
    border-bottom-width: var(--duo-lip);
    border-radius: var(--duo-radius-md);
    cursor: pointer;
    -webkit-appearance: none;
    appearance: none;
    transition: all var(--duo-dur-press) var(--duo-ease-expo);
}

.duo-app .duo-word-block:hover:not(:disabled) {
    background-color: var(--duo-slate-50);
    border-color: var(--duo-charcoal);
}

.duo-app .duo-word-block:active:not(:disabled) {
    transform: translateY(var(--duo-press-shift));
    border-bottom-width: var(--duo-lip-pressed);
}

.duo-app .duo-word-block:disabled {
    opacity: .5;
    pointer-events: none;
}

.duo-app .duo-word-block:focus-visible {
    outline: var(--duo-border) solid var(--duo-macaw-blue);
    outline-offset: var(--duo-border);
}

/* Draft (already-picked) block — slightly smaller, thinner lip.
 * [tw: px-3 py-1.5 border-b-[3px] font-bold hover:bg-gray-100 animate-scaleIn] */
.duo-app .duo-word-block--draft {
    padding: var(--duo-space-1-5) var(--duo-space-3);
    font-weight: var(--duo-weight-bold);
    border-bottom-width: var(--duo-lip-sm);
}

.duo-app .duo-word-block--draft:hover:not(:disabled) {
    background-color: var(--duo-gray-100);
    border-color: var(--duo-graphite);
}

/* Draft drop zone.
 * [tw: min-h-16 w-full p-3 border-2 border-graphite border-dashed rounded-xl
 *      bg-gray-50 flex flex-wrap gap-2 items-center] */
.duo-draft-zone {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--duo-space-2);
    width: 100%;
    min-height: var(--duo-space-16);
    padding: var(--duo-space-3);
    background-color: var(--duo-gray-50);
    border: var(--duo-border) dashed var(--duo-graphite);
    border-radius: var(--duo-radius-md);
}

/* [tw: text-xs text-ash italic w-full text-center] */
.duo-draft-zone__empty {
    width: 100%;
    font-size: var(--duo-text-xs);
    font-style: italic;
    text-align: center;
    color: var(--duo-ash);
}

/* [tw: flex flex-wrap gap-2.5 justify-center py-2] */
.duo-word-pool {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: var(--duo-space-2-5);
    padding-block: var(--duo-space-2);
}


/* =============================================================================
 * 9. BADGES, CHIPS, RANKS
 * ========================================================================== */

/* [tw: text-[10px] font-black px-2 py-0.5 rounded-full uppercase border-2] */
.duo-badge {
    display: inline-flex;
    align-items: center;
    gap: var(--duo-space-1);
    padding: var(--duo-space-0-5) var(--duo-space-2);
    font-size: var(--duo-text-3xs);
    font-weight: var(--duo-weight-black);
    line-height: 1.4;
    text-transform: uppercase;
    letter-spacing: var(--duo-tracking-wider);
    color: var(--duo-charcoal);
    background-color: var(--duo-gray-100);
    border: var(--duo-border) solid var(--duo-graphite);
    border-radius: var(--duo-radius-pill);
    white-space: nowrap;
}

/* [tw: bg-green-100 text-green-700 border-green-300] */
.duo-badge--easy {
    color: var(--duo-green-700);
    background-color: var(--duo-green-100);
    border-color: var(--duo-green-300);
}

/* [tw: bg-amber-100 text-amber-700 border-amber-300] */
.duo-badge--medium {
    color: var(--duo-amber-700);
    background-color: var(--duo-amber-100);
    border-color: var(--duo-amber-300);
}

/* [tw: bg-red-100 text-red-700 border-red-300] */
.duo-badge--hard {
    color: var(--duo-red-700);
    background-color: var(--duo-red-100);
    border-color: var(--duo-red-300);
}

/* [tw: bg-ecto-green text-white px-2 py-0.5 rounded-full uppercase font-black
 *      tracking-wide] — the "Bạn" tag on the leaderboard */
.duo-badge--me {
    color: var(--duo-paper);
    background-color: var(--duo-ecto-green);
    border-color: var(--duo-ecto-green);
}

/* [tw: bg-amber-100 text-amber-800 border-amber-300 text-xs px-2.5 py-1] */
.duo-badge--league {
    padding: var(--duo-space-1) var(--duo-space-2-5);
    font-size: var(--duo-text-xs);
    color: var(--duo-amber-800);
    background-color: var(--duo-amber-100);
    border-color: var(--duo-amber-300);
}

/* --- Chips (suggestions / synonyms / antonyms) --------------------------- */
/* [tw: text-xs font-bold bg-gray-50 border-2 border-graphite px-3 py-1
 *      rounded-full text-charcoal hover:bg-gray-100 hover:border-charcoal
 *      transition-all] */
.duo-app .duo-chip {
    display: inline-flex;
    align-items: center;
    gap: var(--duo-space-1);
    padding: var(--duo-space-1) var(--duo-space-3);
    font-family: var(--duo-font-sans);
    font-size: var(--duo-text-xs);
    font-weight: var(--duo-weight-bold);
    line-height: 1.4;
    color: var(--duo-charcoal);
    background-color: var(--duo-gray-50);
    border: var(--duo-border) solid var(--duo-graphite);
    border-radius: var(--duo-radius-pill);
    cursor: pointer;
    -webkit-appearance: none;
    appearance: none;
    transition: all var(--duo-dur-press) var(--duo-ease-expo);
}

.duo-app .duo-chip:hover {
    background-color: var(--duo-gray-100);
    border-color: var(--duo-charcoal);
}

.duo-app .duo-chip:focus-visible {
    outline: var(--duo-border) solid var(--duo-macaw-blue);
    outline-offset: var(--duo-border);
}

/* [tw: bg-eel-light hover:bg-lingot-lime text-charcoal px-2.5 py-1 rounded-lg
 *      border-2 border-lingot-lime/40] */
.duo-app .duo-chip--synonym {
    padding: var(--duo-space-1) var(--duo-space-2-5);
    background-color: var(--duo-eel-light);
    border-color: var(--duo-lime-40);
    border-radius: var(--duo-radius-sm);
}

.duo-app .duo-chip--synonym:hover {
    background-color: var(--duo-lingot-lime);
    border-color: var(--duo-lime-40);
}

/* [tw: bg-rose-50 hover:bg-rose-100 text-rose-800 px-2.5 py-1 rounded-lg
 *      border-2 border-rose-200] */
.duo-app .duo-chip--antonym {
    padding: var(--duo-space-1) var(--duo-space-2-5);
    color: var(--duo-rose-800);
    background-color: var(--duo-rose-50);
    border-color: var(--duo-rose-200);
    border-radius: var(--duo-radius-sm);
}

.duo-app .duo-chip--antonym:hover {
    background-color: var(--duo-rose-100);
    border-color: var(--duo-rose-200);
}

/* [tw: text-xs bg-white border border-graphite px-2 py-0.5 rounded-lg
 *      text-charcoal italic] — non-interactive "other phrasings" pill */
.duo-chip--static {
    display: inline-flex;
    align-items: center;
    padding: var(--duo-space-0-5) var(--duo-space-2);
    font-size: var(--duo-text-xs);
    font-style: italic;
    color: var(--duo-charcoal);
    background-color: var(--duo-paper);
    border: var(--duo-hairline-w) solid var(--duo-graphite);
    border-radius: var(--duo-radius-sm);
}

/* [tw: flex flex-wrap items-center gap-1.5] */
.duo-chip-row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--duo-space-1-5);
}

.duo-chip-row--tight {
    gap: var(--duo-space-1);
}

/* --- Rank medals --------------------------------------------------------- */
/* [tw: w-8 h-8 rounded-full flex items-center justify-center font-black
 *      text-sm bg-gray-100 text-[#4b4b4b] border-2 border-graphite] */
.duo-rank {
    display: inline-flex;
    flex-shrink: 0;
    align-items: center;
    justify-content: center;
    width: 2rem;
    height: 2rem;
    font-size: var(--duo-text-sm);
    font-weight: var(--duo-weight-black);
    line-height: var(--duo-leading-none);
    color: var(--duo-charcoal);
    background-color: var(--duo-gray-100);
    border: var(--duo-border) solid var(--duo-graphite);
    border-radius: var(--duo-radius-pill);
}

/* [tw: bg-yellow-100 text-yellow-800 border-yellow-300] */
.duo-rank--gold {
    color: var(--duo-yellow-800);
    background-color: var(--duo-yellow-100);
    border-color: var(--duo-yellow-300);
}

/* [tw: bg-slate-100 text-slate-700 border-slate-300] */
.duo-rank--silver {
    color: var(--duo-slate-700);
    background-color: var(--duo-slate-100);
    border-color: var(--duo-slate-300);
}

/* [tw: bg-amber-50 text-amber-700 border-amber-200] */
.duo-rank--bronze {
    color: var(--duo-amber-700);
    background-color: var(--duo-amber-50);
    border-color: var(--duo-amber-200);
}

/* [tw: text-base leading-none] — the 👑 / 🥈 / 🥉 glyph */
.duo-rank__medal {
    font-size: var(--duo-text-base);
    line-height: var(--duo-leading-none);
}

/* --- Leaderboard row ----------------------------------------------------- */
/* [tw: flex items-center justify-between p-3 rounded-xl border-2
 *      transition-all duration-300 border-graphite bg-white
 *      hover:border-charcoal] */
.duo-rank-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--duo-space-3);
    padding: var(--duo-space-3);
    background-color: var(--duo-paper);
    border: var(--duo-border) solid var(--duo-graphite);
    border-radius: var(--duo-radius-md);
    transition: all .3s var(--duo-ease-expo);
}

.duo-rank-row:hover {
    border-color: var(--duo-charcoal);
}

/* [tw: border-ecto-green bg-eel-light/30 font-bold] */
.duo-rank-row.is-me {
    font-weight: var(--duo-weight-bold);
    background-color: var(--duo-eel-light-30);
    border-color: var(--duo-ecto-green);
}

.duo-rank-row.is-me:hover {
    border-color: var(--duo-ecto-green);
}

/* [tw: w-10 h-10 rounded-xl bg-gray-50 border-2 border-graphite flex
 *      items-center justify-center text-2xl select-none] */
.duo-avatar {
    display: inline-flex;
    flex-shrink: 0;
    align-items: center;
    justify-content: center;
    width: 2.5rem;
    height: 2.5rem;
    font-size: var(--duo-text-2xl);
    line-height: var(--duo-leading-none);
    background-color: var(--duo-gray-50);
    border: var(--duo-border) solid var(--duo-graphite);
    border-radius: var(--duo-radius-md);
    user-select: none;
}

/* [tw: text-sm font-black text-charcoal flex items-center gap-1.5] */
.duo-rank-row__name {
    display: flex;
    align-items: center;
    gap: var(--duo-space-1-5);
    font-size: var(--duo-text-sm);
    font-weight: var(--duo-weight-black);
    color: var(--duo-charcoal);
}

/* [tw: flex items-center space-x-0.5 text-orange-500 font-bold text-xs] */
.duo-rank-row__streak {
    display: inline-flex;
    align-items: center;
    gap: var(--duo-space-0-5);
    margin-top: var(--duo-space-0-5);
    font-size: var(--duo-text-xs);
    font-weight: var(--duo-weight-bold);
    color: var(--duo-orange-500);
}

/* [tw: text-sm font-black text-ecto-green] */
.duo-rank-row__score {
    font-size: var(--duo-text-sm);
    font-weight: var(--duo-weight-black);
    text-align: right;
    color: var(--duo-ecto-green);
}


/* =============================================================================
 * 10. FORM CONTROLS (non-word-box)
 * ========================================================================== */

/* [tw: w-full px-4 py-3 rounded-xl border-2 border-graphite bg-white
 *      text-charcoal focus:outline-none focus:border-macaw-blue font-bold
 *      text-sm] */
.duo-app .duo-input {
    display: block;
    width: 100%;
    padding: var(--duo-space-3) var(--duo-space-4);
    font-family: var(--duo-font-sans);
    font-size: var(--duo-text-sm);
    font-weight: var(--duo-weight-bold);
    line-height: var(--duo-leading-normal);
    letter-spacing: var(--duo-tracking-base);
    color: var(--duo-charcoal);
    background-color: var(--duo-paper);
    border: var(--duo-border) solid var(--duo-graphite);
    border-radius: var(--duo-radius-md);
    -webkit-appearance: none;
    appearance: none;
    outline: none;
    box-shadow: none;
    transition: border-color var(--duo-dur-press) var(--duo-ease-expo);
}

/* Dictionary search box focuses blue [tw: focus:border-macaw-blue] */
.duo-app .duo-input:focus {
    border-color: var(--duo-macaw-blue);
    box-shadow: none;
}

.duo-app .duo-input::placeholder {
    font-weight: var(--duo-weight-bold);
    color: var(--duo-ash);
    opacity: 1;
}

/* Green focus variant (answer fields) */
.duo-app .duo-input--green:focus {
    border-color: var(--duo-ecto-green);
}

/* [tw: pl-10] — leaves room for the search icon */
.duo-app .duo-input--search {
    padding-left: var(--duo-space-10);
}

/* [tw: relative flex-1] + [tw: absolute left-3.5 top-3.5 w-5 h-5 text-ash] */
.duo-input-wrap {
    position: relative;
    flex: 1 1 auto;
    min-width: 0;
}

.duo-input-wrap__icon {
    position: absolute;
    top: 50%;
    left: var(--duo-space-3-5);
    width: 1.25rem;
    height: 1.25rem;
    color: var(--duo-ash);
    transform: translateY(-50%);
    pointer-events: none;
}

/* [tw: w-full h-24 p-4 border-2 border-graphite bg-white text-charcoal
 *      rounded-xl focus:outline-none focus:border-ecto-green text-sm
 *      leading-relaxed] */
.duo-app .duo-textarea {
    display: block;
    width: 100%;
    height: 6rem;
    min-height: 4rem;
    padding: var(--duo-space-4);
    font-family: var(--duo-font-sans);
    font-size: var(--duo-text-sm);
    font-weight: var(--duo-weight-normal);
    line-height: var(--duo-leading-relaxed);
    letter-spacing: var(--duo-tracking-base);
    color: var(--duo-charcoal);
    background-color: var(--duo-paper);
    border: var(--duo-border) solid var(--duo-graphite);
    border-radius: var(--duo-radius-md);
    resize: vertical;
    -webkit-appearance: none;
    appearance: none;
    outline: none;
    box-shadow: none;
    transition: border-color var(--duo-dur-press) var(--duo-ease-expo);
}

/* Practice textarea focuses green [tw: focus:border-ecto-green] */
.duo-app .duo-textarea:focus {
    border-color: var(--duo-ecto-green);
    box-shadow: none;
}

.duo-app .duo-textarea::placeholder {
    color: var(--duo-ash);
    opacity: 1;
}

.duo-app .duo-textarea:disabled,
.duo-app .duo-input:disabled {
    color: var(--duo-ash);
    background-color: var(--duo-gray-50);
    cursor: default;
}

/* [tw: flex gap-2] — search form row */
.duo-form-row {
    display: flex;
    gap: var(--duo-space-2);
    align-items: stretch;
}


/* =============================================================================
 * 11. MASCOT + SPEECH BUBBLE
 * ========================================================================== */

/* [tw: w-16 h-16 rounded-2xl bg-eel-light border-2 border-ecto-green
 *      flex items-center justify-center text-4xl select-none shrink-0
 *      border-b-[4px]] */
.duo-mascot {
    display: flex;
    flex-shrink: 0;
    align-items: center;
    justify-content: center;
    width: var(--duo-space-16);
    height: var(--duo-space-16);
    font-size: var(--duo-text-4xl);
    line-height: var(--duo-leading-none);
    background-color: var(--duo-eel-light);
    border: var(--duo-border) solid var(--duo-ecto-green);
    border-bottom-width: var(--duo-lip);
    border-radius: var(--duo-radius-lg);
    user-select: none;
}

/* Hero variant — [tw: text-4xl p-3 bg-macaw-blue/10 rounded-2xl border-2
 *                     border-macaw-blue/20] */
.duo-mascot--blue {
    background-color: var(--duo-macaw-10);
    border-color: var(--duo-macaw-20);
    border-bottom-width: var(--duo-border);
}

/* [tw: relative bg-white border-2 border-graphite rounded-xl p-4 flex-1]
 * + tail [tw: absolute top-5 -left-2.5 w-3 h-3 bg-white border-l-2 border-b-2
 *              border-graphite rotate-45] */
.duo-bubble {
    position: relative;
    flex: 1 1 auto;
    min-width: 0;
    padding: var(--duo-space-4);
    background-color: var(--duo-paper);
    border: var(--duo-border) solid var(--duo-graphite);
    border-radius: var(--duo-radius-md);
}

.duo-bubble::before {
    content: "";
    position: absolute;
    top: var(--duo-space-5);
    left: calc(-1 * var(--duo-space-2-5));
    width: var(--duo-space-3);
    height: var(--duo-space-3);
    background-color: var(--duo-paper);
    border-left: var(--duo-border) solid var(--duo-graphite);
    border-bottom: var(--duo-border) solid var(--duo-graphite);
    transform: rotate(45deg);
}

/* [tw: text-xs font-black text-macaw-blue uppercase tracking-widest] */
.duo-bubble__label {
    font-size: var(--duo-text-xs);
    font-weight: var(--duo-weight-black);
    text-transform: uppercase;
    letter-spacing: var(--duo-tracking-widest);
    color: var(--duo-macaw-blue);
}

/* [tw: text-lg font-black text-eel-dark-blue mt-1 leading-snug] */
.duo-bubble__text {
    margin-top: var(--duo-space-1);
    font-size: var(--duo-text-lg);
    font-weight: var(--duo-weight-black);
    line-height: var(--duo-leading-snug);
    color: var(--duo-eel-dark-blue);
}


/* =============================================================================
 * 12. PROGRESS BAR — "Mục tiêu hôm nay"
 * ========================================================================== */

/* [tw: w-full bg-gray-200 rounded-full h-3 overflow-hidden border border-graphite] */
.duo-progress-track {
    width: 100%;
    height: var(--duo-space-3);
    overflow: hidden;
    background-color: var(--duo-gray-200);
    border: var(--duo-hairline-w) solid var(--duo-graphite);
    border-radius: var(--duo-radius-pill);
}

/* [tw: bg-ecto-green h-full rounded-full transition-all duration-500] */
.duo-progress-fill {
    width: 0;
    height: 100%;
    background-color: var(--duo-ecto-green);
    border-radius: var(--duo-radius-pill);
    transition: width var(--duo-dur-bar) var(--duo-ease-expo);
}

.duo-progress-fill--blue { background-color: var(--duo-macaw-blue); }
.duo-progress-fill--amber { background-color: var(--duo-amber-500); }

/* [tw: text-[10px] text-ash mt-2 font-bold leading-relaxed] */
.duo-progress-note {
    margin-top: var(--duo-space-2);
    font-size: var(--duo-text-3xs);
    font-weight: var(--duo-weight-bold);
    line-height: var(--duo-leading-relaxed);
    color: var(--duo-ash);
}


/* =============================================================================
 * 13. ALERTS — the feedback drawer after grading
 * ========================================================================== */

/* [tw: mt-6 p-5 rounded-xl border-2 border-b-[5px] animate-slideIn] */
.duo-alert {
    display: flex;
    align-items: flex-start;
    gap: var(--duo-space-3);
    padding: var(--duo-space-5);
    font-size: var(--duo-text-xs);
    line-height: var(--duo-leading-relaxed);
    border: var(--duo-border) solid var(--duo-graphite);
    border-bottom-width: var(--duo-lip-md);
    border-radius: var(--duo-radius-md);
}

/* [tw: bg-[#d7ffb8]/50 border-ecto-green] */
.duo-alert--success {
    background-color: var(--duo-eel-light-50);
    border-color: var(--duo-ecto-green);
}

/* [tw: bg-red-50 border-red-500] */
.duo-alert--error {
    background-color: var(--duo-red-50);
    border-color: var(--duo-red-500);
}

/* Neutral/info variant for dictionary lookup failures
 * [tw: bg-red-50 border-2 border-red-200 text-red-600 p-4 rounded-xl text-sm] */
.duo-alert--soft-error {
    padding: var(--duo-space-4);
    font-size: var(--duo-text-sm);
    color: var(--duo-red-600);
    background-color: var(--duo-red-50);
    border-color: var(--duo-red-200);
    border-bottom-width: var(--duo-border);
}

.duo-alert__icon {
    flex-shrink: 0;
    width: 1.5rem;
    height: 1.5rem;
    margin-top: var(--duo-space-0-5);
}

.duo-alert__body {
    flex: 1 1 auto;
    min-width: 0;
}

/* [tw: text-sm font-black uppercase tracking-wide] */
.duo-alert__title {
    font-size: var(--duo-text-sm);
    font-weight: var(--duo-weight-black);
    text-transform: uppercase;
    letter-spacing: var(--duo-tracking-wide);
}

/* [tw: text-xs mt-1 leading-relaxed] */
.duo-alert__text {
    margin-top: var(--duo-space-1);
    font-size: var(--duo-text-xs);
    line-height: var(--duo-leading-relaxed);
}

/* [tw: text-green-800 / text-green-900] */
.duo-alert--success .duo-alert__title { color: var(--duo-green-800); }
.duo-alert--success .duo-alert__text { color: var(--duo-green-900); }
.duo-alert--success .duo-alert__icon { color: var(--duo-ecto-green); }

/* [tw: text-red-800 / text-red-900] */
.duo-alert--error .duo-alert__title { color: var(--duo-red-800); }
.duo-alert--error .duo-alert__text { color: var(--duo-red-900); }
.duo-alert--error .duo-alert__icon { color: var(--duo-red-500); }

/* [tw: mt-2.5 bg-white/60 p-2.5 rounded-lg border border-black/5 text-xs
 *      text-charcoal] — "reference translation" panel */
.duo-alert__panel {
    margin-top: var(--duo-space-2-5);
    padding: var(--duo-space-2-5);
    font-size: var(--duo-text-xs);
    color: var(--duo-charcoal);
    background-color: var(--duo-paper-60);
    border: var(--duo-hairline-w) solid var(--duo-hairline);
    border-radius: var(--duo-radius-sm);
}

/* [tw: mt-3 bg-white/75 p-3 rounded-xl border border-dashed border-graphite
 *      text-xs text-charcoal leading-relaxed] — grammar notes panel */
.duo-alert__panel--dashed {
    margin-top: var(--duo-space-3);
    padding: var(--duo-space-3);
    line-height: var(--duo-leading-relaxed);
    background-color: var(--duo-paper-75);
    border-style: dashed;
    border-color: var(--duo-graphite);
    border-radius: var(--duo-radius-md);
}

/* [tw: whitespace-pre-line] */
.duo-prewrap {
    white-space: pre-line;
}

/* [tw: mt-5 p-4 bg-purple-50 border-2 border-purple-200 rounded-xl
 *      flex items-start space-x-3] — league quest card */
.duo-alert--quest {
    background-color: var(--duo-purple-50);
    border-color: var(--duo-purple-200);
    border-bottom-width: var(--duo-border);
    padding: var(--duo-space-4);
}

.duo-alert--quest .duo-alert__title { color: var(--duo-purple-900); }

.duo-alert--quest .duo-alert__text {
    font-weight: var(--duo-weight-bold);
    color: var(--duo-purple-700);
}

/* [tw: bg-amber-50 border-2 border-amber-200 p-3.5 rounded-xl flex items-start
 *      space-x-3] — dictionary mnemonic box */
.duo-alert--mnemonic {
    padding: var(--duo-space-3-5);
    background-color: var(--duo-amber-50);
    border-color: var(--duo-amber-200);
    border-bottom-width: var(--duo-border);
}

.duo-alert--mnemonic .duo-alert__title {
    font-size: var(--duo-text-xs);
    letter-spacing: var(--duo-tracking-wider);
    color: var(--duo-amber-800);
}

.duo-alert--mnemonic .duo-alert__text {
    font-style: italic;
    color: var(--duo-amber-900);
}

/* [tw: bg-amber-100 p-1.5 rounded-lg border border-amber-300] — icon tile */
.duo-alert__icon-tile {
    display: inline-flex;
    flex-shrink: 0;
    align-items: center;
    justify-content: center;
    padding: var(--duo-space-1-5);
    margin-top: var(--duo-space-0-5);
    color: var(--duo-amber-600);
    background-color: var(--duo-amber-100);
    border: var(--duo-hairline-w) solid var(--duo-amber-300);
    border-radius: var(--duo-radius-sm);
}


/* =============================================================================
 * 14. TOASTS — bottom-right stack
 * ========================================================================== */

/* [tw: fixed bottom-4 right-4 z-50 space-y-2 pointer-events-none max-w-sm w-full] */
.duo-toast-stack {
    position: fixed;
    right: var(--duo-space-4);
    bottom: var(--duo-space-4);
    z-index: var(--duo-z-toast);
    display: flex;
    flex-direction: column;
    gap: var(--duo-space-2);
    width: calc(100% - 2 * var(--duo-space-4));
    max-width: 24rem;   /* [tw: max-w-sm] */
    pointer-events: none;
}

/* [tw: p-4 rounded-xl border-2 border-b-[5px] shadow-lg flex items-center
 *      justify-between pointer-events-auto animate-scaleIn
 *      + default: bg-white border-ecto-green text-charcoal] */
.duo-toast {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--duo-space-3);
    padding: var(--duo-space-4);
    font-size: var(--duo-text-xs);
    font-weight: var(--duo-weight-black);
    color: var(--duo-charcoal);
    background-color: var(--duo-paper);
    border: var(--duo-border) solid var(--duo-ecto-green);
    border-bottom-width: var(--duo-lip-md);
    border-radius: var(--duo-radius-md);
    box-shadow: var(--duo-shadow-lg);
    pointer-events: auto;
}

.duo-toast--success {
    color: var(--duo-charcoal);
    background-color: var(--duo-paper);
    border-color: var(--duo-ecto-green);
}

/* [tw: bg-sky-50 border-macaw-blue text-sky-900] */
.duo-toast--info {
    color: var(--duo-sky-900);
    background-color: var(--duo-sky-50);
    border-color: var(--duo-macaw-blue);
}

/* [tw: bg-purple-50 border-purple-500 text-purple-900] */
.duo-toast--purple {
    color: var(--duo-purple-900);
    background-color: var(--duo-purple-50);
    border-color: var(--duo-purple-500);
}

/* NEW — error toast (word-box feature may need it) */
.duo-toast--error {
    color: var(--duo-red-900);
    background-color: var(--duo-error-bg);
    border-color: var(--duo-error);
}

.duo-toast__text {
    flex: 1 1 auto;
    min-width: 0;
    font-size: var(--duo-text-xs);
    font-weight: var(--duo-weight-black);
}

/* [tw: ml-3 hover:opacity-75 transition-all] */
.duo-app .duo-toast__close {
    display: inline-flex;
    flex-shrink: 0;
    align-items: center;
    justify-content: center;
    padding: 0;
    color: var(--duo-ash);
    background: none;
    border: 0;
    cursor: pointer;
    transition: opacity var(--duo-dur-press) var(--duo-ease-expo);
}

.duo-app .duo-toast__close:hover {
    opacity: .75;
}

.duo-toast__close-icon {
    width: .875rem;
    height: .875rem;
}


/* =============================================================================
 * 15. STAT CARDS + ICON TILES
 * ========================================================================== */

/* [tw: bg-white border-2 border-graphite border-b-[6px] rounded-xl p-4
 *      flex items-center space-x-4] */
.duo-stat-card {
    display: flex;
    align-items: center;
    gap: var(--duo-space-4);
    padding: var(--duo-space-4);
    background-color: var(--duo-paper);
    border: var(--duo-border) solid var(--duo-graphite);
    border-bottom-width: var(--duo-lip-lg);
    border-radius: var(--duo-radius-md);
}

/* [tw: p-3 rounded-xl border] */
.duo-stat-card__icon {
    display: inline-flex;
    flex-shrink: 0;
    align-items: center;
    justify-content: center;
    padding: var(--duo-space-3);
    border: var(--duo-hairline-w) solid var(--duo-graphite);
    border-radius: var(--duo-radius-md);
}

.duo-stat-card__icon > svg,
.duo-stat-card__icon > .duo-icon {
    width: 2rem;    /* [tw: w-8 h-8] */
    height: 2rem;
}

/* [tw: bg-orange-100 border-orange-200 text-orange-500] */
.duo-stat-card__icon--streak {
    color: var(--duo-orange-500);
    background-color: var(--duo-orange-100);
    border-color: var(--duo-orange-200);
}

/* [tw: bg-eel-light border-lingot-lime text-ecto-green] */
.duo-stat-card__icon--xp {
    color: var(--duo-ecto-green);
    background-color: var(--duo-eel-light);
    border-color: var(--duo-lingot-lime);
}

/* [tw: bg-blue-100 border-blue-200 text-macaw-blue] */
.duo-stat-card__icon--done {
    color: var(--duo-macaw-blue);
    background-color: var(--duo-blue-100);
    border-color: var(--duo-blue-200);
}

/* [tw: text-2xl font-black text-charcoal tracking-tight] */
.duo-stat-card__value {
    font-size: var(--duo-text-2xl);
    font-weight: var(--duo-weight-black);
    line-height: 1.15;
    letter-spacing: var(--duo-tracking-tight);
    color: var(--duo-charcoal);
}

/* [tw: text-xs text-ash uppercase font-black tracking-wide mt-0.5] */
.duo-stat-card__label {
    margin-top: var(--duo-space-0-5);
    font-size: var(--duo-text-xs);
    font-weight: var(--duo-weight-black);
    text-transform: uppercase;
    letter-spacing: var(--duo-tracking-wide);
    color: var(--duo-ash);
}

/* [tw: bg-blue-100 p-2 rounded-xl border border-blue-200] — section icon tile */
.duo-icon-tile {
    display: inline-flex;
    flex-shrink: 0;
    align-items: center;
    justify-content: center;
    padding: var(--duo-space-2);
    border: var(--duo-hairline-w) solid var(--duo-graphite);
    border-radius: var(--duo-radius-md);
}

.duo-icon-tile--blue {
    color: var(--duo-macaw-blue);
    background-color: var(--duo-blue-100);
    border-color: var(--duo-blue-200);
}

.duo-icon-tile--orange {
    color: var(--duo-orange-500);
    background-color: var(--duo-orange-100);
    border-color: var(--duo-orange-200);
}

.duo-icon-tile--green {
    color: var(--duo-ecto-green);
    background-color: var(--duo-eel-light);
    border-color: var(--duo-lingot-lime);
}

/* Loading placeholder [tw: mt-8 flex flex-col items-center py-10 space-y-3] */
.duo-loading {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: var(--duo-space-3);
    padding-block: var(--duo-space-10);
    font-size: var(--duo-text-sm);
    color: var(--duo-ash);
    text-align: center;
}

.duo-loading__spinner {
    width: 3rem;    /* [tw: w-12 h-12] */
    height: 3rem;
    color: var(--duo-macaw-blue);
}


/* =============================================================================
 * 16. ANIMATIONS — ported verbatim from duolingual/src/index.css
 * ========================================================================== */

@keyframes duo-fadeIn {
    from { opacity: 0; transform: translateY(5px); }
    to { opacity: 1; transform: translateY(0); }
}

@keyframes duo-slideIn {
    from { opacity: 0; transform: translateY(12px); }
    to { opacity: 1; transform: translateY(0); }
}

@keyframes duo-scaleIn {
    from { opacity: 0; transform: scale(.95); }
    to { opacity: 1; transform: scale(1); }
}

/* NEW — wrong keystroke feedback for .duo-box */
@keyframes duo-shake {
    0%, 100% { transform: translateX(0); }
    20%, 60% { transform: translateX(-4px); }
    40%, 80% { transform: translateX(4px); }
}

/* [tw: animate-spin] */
@keyframes duo-spin {
    to { transform: rotate(360deg); }
}

/* [tw: animate-bounce] — the header owl */
@keyframes duo-bounce {
    0%, 100% { transform: translateY(-25%); animation-timing-function: cubic-bezier(.8, 0, 1, 1); }
    50% { transform: none; animation-timing-function: cubic-bezier(0, 0, .2, 1); }
}

/* [tw: animate-pulse] */
@keyframes duo-pulse {
    50% { opacity: .5; }
}

/* [tw: .animate-fadeIn] */
.duo-animate-fadeIn {
    animation: duo-fadeIn var(--duo-dur-fade) var(--duo-ease-expo) forwards;
}

/* [tw: .animate-slideIn] */
.duo-animate-slideIn {
    animation: duo-slideIn var(--duo-dur-slide) var(--duo-ease-expo) forwards;
}

/* [tw: .animate-scaleIn] */
.duo-animate-scaleIn {
    animation: duo-scaleIn var(--duo-dur-scale) var(--duo-ease-back) forwards;
}

.duo-animate-spin {
    animation: duo-spin 1s linear infinite;
}

.duo-animate-bounce {
    animation: duo-bounce 1s infinite;
}

.duo-animate-pulse {
    animation: duo-pulse 2s cubic-bezier(.4, 0, .6, 1) infinite;
}


/* =============================================================================
 * 17. REDUCED MOTION
 * Colour feedback is preserved; only movement is removed.
 * ========================================================================== */

@media (prefers-reduced-motion: reduce) {
    /* The shake conveys "wrong" — keep the red, drop the movement. */
    .duo-app .duo-box.is-error {
        animation: none;
    }

    .duo-animate-fadeIn,
    .duo-animate-slideIn,
    .duo-animate-scaleIn {
        animation-duration: 1ms;
    }

    .duo-animate-bounce,
    .duo-animate-pulse {
        animation: none;
    }

    /* Spinners still need to spin (they signal "busy"), just slower. */
    .duo-animate-spin {
        animation-duration: 2s;
    }

    /* No tactile press displacement, but keep the border-width change so the
     * button still reads as "pressed". */
    .duo-app .duo-btn:active:not(:disabled):not(.is-disabled),
    .duo-app .duo-word-block:active:not(:disabled):not(.is-disabled),
    .duo-app .duo-btn--icon:active:not(:disabled):not(.is-disabled) {
        transform: none;
    }

    .duo-app .duo-btn,
    .duo-app .duo-nav-btn,
    .duo-app .duo-select-card,
    .duo-app .duo-word-block,
    .duo-app .duo-chip,
    .duo-app .duo-box,
    .duo-progress-fill,
    .duo-rank-row {
        transition-duration: 1ms;
    }
}


/* =============================================================================
 * 18. PAGINATION — trang danh sách cấu trúc ngữ pháp
 *
 * Bộ đề mặc định đã hơn 1500 cấu trúc nên `.duo-grammar-grid` phải cắt trang
 * (PracticePanel::PER_PAGE). Nút mang cùng ngôn ngữ 3D "lip" của `.duo-btn`
 * nhưng KHÔNG tái dùng class đó: `.duo-btn` là padding cỡ nút hành động, một
 * hàng chữ số cỡ ấy sẽ nặng hơn cả lưới thẻ nó đang điều khiển.
 * ========================================================================== */

.duo-app .duo-pager {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: var(--duo-space-2);
    margin-top: var(--duo-space-2);
}

/* Dãy số co lại trước, hai nút Trước/Sau luôn giữ nguyên cỡ: ở màn hẹp thà
 * xuống dòng dãy số còn hơn bóp mất chữ của hai nút điều hướng chính. */
.duo-app .duo-pager__numbers {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: var(--duo-space-1);
    min-width: 0;
}

.duo-app .duo-pager__page,
.duo-app .duo-pager__step {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-family: var(--duo-font-sans);
    font-size: var(--duo-text-sm);
    font-weight: var(--duo-weight-bold);
    line-height: 1;
    color: var(--duo-charcoal);
    background-color: var(--duo-paper);
    border: var(--duo-border) solid var(--duo-graphite);
    border-bottom-width: var(--duo-lip);
    border-radius: var(--duo-radius-sm);
    cursor: pointer;
    -webkit-appearance: none;
    appearance: none;
    transition: all var(--duo-dur-press) var(--duo-ease-expo);
}

/* Ô vuông: `min-width` = `height` để 1 chữ số và 2 chữ số cùng cỡ ô, hàng nút
 * không giật khi nhảy từ trang 9 sang 10. */
.duo-app .duo-pager__page {
    min-width: var(--duo-space-10);
    height: var(--duo-space-10);
    padding: 0 var(--duo-space-2);
    font-variant-numeric: tabular-nums;
}

.duo-app .duo-pager__step {
    height: var(--duo-space-10);
    padding: 0 var(--duo-space-4);
    white-space: nowrap;
}

.duo-app .duo-pager__page:hover:not(:disabled),
.duo-app .duo-pager__step:hover:not(:disabled) {
    background-color: var(--duo-gray-50);
}

.duo-app .duo-pager__page:active:not(:disabled),
.duo-app .duo-pager__step:active:not(:disabled) {
    transform: translateY(var(--duo-press-shift));
    border-bottom-width: var(--duo-lip-pressed);
}

.duo-app .duo-pager__page:focus-visible,
.duo-app .duo-pager__step:focus-visible {
    outline: var(--duo-border) solid var(--duo-macaw-blue);
    outline-offset: var(--duo-border);
}

.duo-app .duo-pager__step:disabled {
    opacity: .5;
    cursor: default;
}

/* Trang hiện tại: tô nền xanh thương hiệu. KHÔNG dùng `pointer-events: none` —
 * nút vẫn phải nhận được focus bàn phím, `aria-current="page"` mới là thứ báo
 * cho screen reader biết đang ở đâu. */
.duo-app .duo-pager__page.is-active {
    color: var(--duo-paper);
    background-color: var(--duo-macaw-blue);
    border-color: var(--duo-macaw-blue);
}

.duo-app .duo-pager__gap {
    padding: 0 var(--duo-space-1);
    font-family: var(--duo-font-sans);
    font-size: var(--duo-text-sm);
    font-weight: var(--duo-weight-bold);
    color: var(--duo-ash);
    user-select: none;
}

/* "25–48 trong 1.551 cấu trúc" cạnh tiêu đề danh sách. */
.duo-app .duo-pager__summary {
    flex-shrink: 0;
    font-family: var(--duo-font-sans);
    font-size: var(--duo-text-xs);
    font-weight: var(--duo-weight-bold);
    color: var(--duo-ash);
    font-variant-numeric: tabular-nums;
}

@media (prefers-reduced-motion: reduce) {
    .duo-app .duo-pager__page,
    .duo-app .duo-pager__step {
        transition: none;
    }

    .duo-app .duo-pager__page:active:not(:disabled),
    .duo-app .duo-pager__step:active:not(:disabled) {
        transform: none;
    }
}

/* =============================================================================
 * 19. PRINT (cheap win — students print exercise sheets)
 * ========================================================================== */

@media print {
    .duo-header,
    .duo-toast-stack,
    .duo-topbar,
    .duo-col-sidebar,
    .duo-pager {
        display: none;
    }

    .duo-app {
        padding-bottom: 0;
    }

    .duo-card,
    .duo-stat-card {
        border-bottom-width: var(--duo-border);
    }
}
