/* grammar-wiki.css — Grammar Wiki cluster chrome + content
 * ----------------------------------------------------------------
 * Established Sprint 6.15 (FINAL Phase 4 sub-cluster). Shared by 5
 * pages: grammar.html (landing) + grammar-roadmap / grammar-article /
 * grammar-search / grammar-compare (under /pages/).
 *
 * Foundation order: tokens.css → components.css → grammar-wiki.css.
 *   - admin-writing.css NOT linked (different cluster, at-cap)
 *   - writing-renderers.css NOT linked (Sprint 6.8 finding extends)
 *
 * Typography sub-system (DM Sans body + Lora display) preserved
 * intentionally per DESIGN_SYSTEM § 14.2 sub-system decision.
 * Grammar Wiki = long-form reading content; editorial typography
 * distinct from utilitarian dashboards (Plus Jakarta Sans elsewhere).
 *
 * Tailwind CDN + custom navy/teal palette config preserved per Phase A
 * finding — `frontend/js/grammar.js` renderer (1,034 lines) emits
 * `text-teal-light`, `bg-teal/15`, etc. utility classes that depend on
 * the palette. Dropping it would break runtime rendering. Removal can
 * happen in a future Tailwind utility-class refactor sprint analogous
 * to the deferred Sprint 6.14d-β.
 *
 * Class names emitted by `grammar.js` and inline HTML markup preserved
 * byte-identical (`.cat-card`, `.article-card`, `.search-input`,
 * `.btn-cta`, `.btn-primary`, `.btn-outline`, `.section-head`,
 * `.hero-title`, `.roadmap-card`, `.group-card`, `.article-body`,
 * `.toc-link`, `.toc-sidebar`, `.section-label`, `.skeleton`,
 * `.grammar-anchor-pulse`, `.compare-col`, `.group-article-row`).
 *
 * New gw-* namespace primitives reserved for future cross-page
 * grammar-wiki additions; none defined yet (token-only chrome
 * migration scope).
 */


/* ── Body surface + DM Sans + Lora sub-system override ─────────── */

body.av-page {
  /* DM Sans wins on cascade because grammar-wiki.css loads after
     components.css. Preserves the sub-system per § 14.2. */
  font-family: 'DM Sans', ui-sans-serif, system-ui;
  background: var(--av-surface-page);
  background-image: radial-gradient(
    color-mix(in srgb, var(--av-text-primary) 2.5%, transparent) 1px,
    transparent 1px
  );
  background-size: 28px 28px;
  color: var(--av-text-primary);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

/* Tailwind utility neutralizer (mirror 6.14d-α discipline) */
body.av-page .text-white { color: var(--av-text-primary); }

/* Font-stack discipline under Tailwind utility classes */
body.av-page .font-sans { font-family: 'DM Sans', ui-sans-serif, system-ui; }
body.av-page .font-mono { font-family: 'JetBrains Mono', ui-monospace, monospace; font-feature-settings: 'tnum'; }

/* Sprint 7.14 — Sprint 7.8-hotfix font-family scoping override retired.
   Chrome is now rendered by <aver-chrome> (Sprint 7.13) with styles
   encapsulated in its shadow root, so editorial pages' DM Sans body
   font can no longer leak into the chrome via cascade. The legacy
   `.topnav-wrap` / `.topnav` / `.brand` / `.nav-links` / `.topnav-right`
   selectors no longer match anything in the DOM on these pages. */


/* ── Sprint 6.15.4-hotfix — Tailwind white-utility opacity-variant coverage ─
 *
 * RED bug fix: light theme rendered all 5 Grammar Wiki pages illegible because
 * Sprint 6.15's cascade-winning override only neutralized plain `.text-white`
 * (line 54 above). Both the static markup AND `frontend/js/grammar.js`
 * renderer (1,034 lines) emit Tailwind opacity variants — `text-white/15`
 * through `text-white/90` — which compile to hardcoded `rgb(255 255 255 / X)`.
 * Against the light-theme `--av-surface-page` (#FAFAF9 warm off-white), white
 * text with any opacity is invisible.
 *
 * Map each variant to color-mix(--av-text-primary, X%) so the four-tier
 * semantic hierarchy (primary / secondary / muted / faint) survives in both
 * themes. Borders + backgrounds with white opacities follow the same pattern
 * via av-border-* / av-surface-* tokens.
 *
 * Why this slipped Sprint 6.15: cascade-winning override discipline correct
 * in principle, but the smoke test exercised dark theme only (white-on-dark
 * renders fine). Same blind-spot class as Sprint 6.10.1 icon rendering miss.
 * § 17 audit-gate methodology amendment ships with this hotfix.
 *
 * DO NOT add new hardcoded white utilities to grammar pages or grammar.js
 * renderer. When a variant outside this table is needed, extend this block
 * first, then use it.
 */

/* text color */
body.av-page .text-white\/90 { color: color-mix(in srgb, var(--av-text-primary) 90%, transparent); }
body.av-page .text-white\/85 { color: color-mix(in srgb, var(--av-text-primary) 85%, transparent); }
body.av-page .text-white\/80 { color: color-mix(in srgb, var(--av-text-primary) 80%, transparent); }
body.av-page .text-white\/70 { color: var(--av-text-secondary); }
body.av-page .text-white\/65 { color: var(--av-text-secondary); }
body.av-page .text-white\/60 { color: var(--av-text-secondary); }
body.av-page .text-white\/55 { color: var(--av-text-secondary); }
body.av-page .text-white\/50 { color: var(--av-text-muted); }
body.av-page .text-white\/40 { color: var(--av-text-muted); }
body.av-page .text-white\/35 { color: var(--av-text-muted); }
body.av-page .text-white\/30 { color: var(--av-text-faint); }
body.av-page .text-white\/28 { color: var(--av-text-faint); }
body.av-page .text-white\/25 { color: var(--av-text-faint); }
body.av-page .text-white\/20 { color: var(--av-text-faint); }
body.av-page .text-white\/15 { color: var(--av-text-faint); }

/* hover state — mirror the text-color hierarchy */
body.av-page .hover\:text-white:hover     { color: var(--av-text-primary); }
body.av-page .hover\:text-white\/90:hover { color: color-mix(in srgb, var(--av-text-primary) 90%, transparent); }
body.av-page .hover\:text-white\/85:hover { color: color-mix(in srgb, var(--av-text-primary) 85%, transparent); }
body.av-page .hover\:text-white\/70:hover { color: var(--av-text-secondary); }
body.av-page .hover\:text-white\/60:hover { color: var(--av-text-secondary); }

/* border color */
body.av-page .border-white\/10 { border-color: var(--av-border-default); }
body.av-page .border-white\/8  { border-color: var(--av-border-default); }
body.av-page .border-white\/6  { border-color: var(--av-border-subtle); }
body.av-page .border-white\/5  { border-color: var(--av-border-subtle); }

/* background color */
body.av-page .bg-white         { background-color: var(--av-surface-card); }
body.av-page .bg-white\/10     { background-color: var(--av-surface-elevated); }
body.av-page .bg-white\/8      { background-color: var(--av-surface-card); }
body.av-page .bg-white\/6      { background-color: var(--av-surface-card); }
body.av-page .bg-white\/5      { background-color: var(--av-surface-card); }


/* ── Sprint 6.15.5-hotfix — grammar-article cascade hardening for light theme ─
 *
 * RED bug: grammar-article.html article body still rendered invisible in
 * light theme after Sprint 6.15.4-hotfix shipped opacity-variant coverage.
 * Other 4 grammar pages (landing, roadmap, search, compare) rendered fine
 * because every text node sits inside an element with an explicit Tailwind
 * utility class — the Sprint 6.15.4 override block neutralizes them.
 *
 * grammar-article.html is structurally different: the article body comes
 * from the backend as markdown-converted HTML — bare semantic elements
 * (`<p>`, `<h2>`, `<table>`, `<li>`, `<td>`, `<strong>`) with NO classes.
 * Those elements inherit color from the nearest ancestor that has an
 * explicit `color` declaration.
 *
 * Two combined hardenings ship in this hotfix:
 *
 * 1. Body class drift fix — `<body>` previously carried `text-white` even
 *    on light theme. The descendant selector `body.av-page .text-white`
 *    cannot match the body element itself; the body therefore picked up
 *    Tailwind's plain `.text-white { color: rgb(255 255 255) }` and the
 *    bare semantic elements inside the article inherited that white. The
 *    `text-white` class was removed from `<body>` in grammar-article.html
 *    in the same hotfix.
 *
 * 2. Defensive explicit color on the article body container + every bare
 *    semantic descendant. Even if a future contributor re-adds `text-white`
 *    or some other inherited-white selector wins on a parent, these rules
 *    pin the article body content to the token-driven color hierarchy.
 *
 * Why Sprint 6.15.4-hotfix missed it: Gate 9 verified CSS cascade coverage
 * for class-bearing elements but didn't model inheritance into class-less
 * semantic HTML rendered at runtime by a markdown pipeline. Same blind-spot
 * family as Sprint 6.10.1 (icon rendering) and the 6.15.4 cascade miss.
 *
 * § 17.8 Gate 9.5 (renderer-inherited color audit) ships in a follow-up.
 */

/* Defensive: any time body still carries text-white (e.g. another grammar
 * page not yet de-classed), the body element itself must resolve to the
 * token color. body.av-page (0,0,1,1) already beats Tailwind's .text-white
 * (0,0,1,0) by specificity, but pairing the two classes on the same
 * compound selector (0,0,2,1) leaves zero ambiguity even if Tailwind CDN
 * later compiles to a higher-specificity utility. */
body.av-page.text-white { color: var(--av-text-primary); }

/* Article body container + every bare-semantic descendant a markdown
 * pipeline can emit. Specificity 0,0,2,1 (body+av-page+article-body+tag)
 * comfortably beats any Tailwind utility or inheritance chain. */
body.av-page .article-body,
body.av-page .article-body p,
body.av-page .article-body li,
body.av-page .article-body td,
body.av-page .article-body span,
body.av-page .article-body em,
body.av-page .article-body blockquote {
  color: var(--av-text-primary);
}

/* Article body bold + headings — preserve existing primary-color treatment.
 * Already declared earlier in this file but re-pinned here at higher
 * specificity for inherited-color robustness. */
body.av-page .article-body strong,
body.av-page .article-body h2,
body.av-page .article-body h3 {
  color: var(--av-text-primary);
}

/* Table headers preserve their teal accent (defined earlier in this file
 * as .article-body table th). Repeat at higher specificity so the
 * defensive paragraph rule above doesn't accidentally win on cascade
 * source-order ties. */
body.av-page .article-body table th {
  color: var(--av-primary);
}

/* Article header chrome — pinned at high specificity for the same reason
 * (bare H1 + meta div sit outside .article-body in grammar-article.html). */
body.av-page #article-title { color: var(--av-text-primary); }
body.av-page #article-meta  { color: var(--av-text-muted); }
body.av-page #breadcrumb    { color: var(--av-text-muted); }


/* ── Sprint 6.15.6-hotfix — comprehensive component class-hook coverage ─
 *
 * 4th Grammar Wiki light-theme RED regression. Andy reported cards (Học
 * tiếp theo, Bài liên quan) plus other component-level content invisible
 * across all 5 grammar pages in light theme. Prior 3 hotfixes each closed
 * ONE mechanism (Sprint 6.15.4 = cascade-winning Tailwind variants;
 * Sprint 6.15.5 = body inheritance into class-less HTML on grammar-
 * article.html). Each was scoped narrowly enough that the next mechanism
 * surfaced on the next test pass.
 *
 * This hotfix is the deliberate belt-and-suspenders pass — six combined
 * fixes mirrored across the Grammar Wiki cluster:
 *
 *   1. `text-white` removed from <body> on the remaining 4 grammar pages
 *      (grammar.html + grammar-{roadmap,search,compare}.html). Mirrors
 *      the Sprint 6.15.5 fix on grammar-article.html. The descendant
 *      override cannot match body itself, so Tailwind's raw white was
 *      still winning on body even after Sprint 6.15.4.
 *
 *   2. JS-emitted inline `style="color:rgba(255,255,255,X)"` sites in
 *      grammar.js refactored to class hooks. Inline styles bypass
 *      cascade overrides entirely — only direct refactor or !important
 *      can fix them. We took the refactor path: introduced
 *      `.gw-status-dot--planned`, `.gw-status-badge--planned`, and
 *      `.gw-save-btn` (+ `--saved` modifier).
 *
 *   3. Component class hooks (.cat-card, .article-card, .group-card,
 *      .group-article-row) get explicit `--av-text-*` color rules so
 *      cards no longer depend on Tailwind cascade winning — they always
 *      paint the token color regardless of source order.
 *
 *   4. Card surfaces switch from `bg-white/[0.03]` arbitrary-value
 *      Tailwind backgrounds (uncovered by the Sprint 6.15.4 neutralizer
 *      block) to `--av-surface-card` — visible pure-white surface on
 *      cream page in light theme, dark surface in dark theme. Card
 *      boundaries are no longer imperceptible.
 *
 *   5. `body.av-page.text-white` compound selector (no space) added as
 *      a defensive guard — if any future Grammar Wiki page (or future
 *      contributor) re-adds `text-white` to body, the body element
 *      itself resolves to the token color.
 *
 *   6. Sprint 6.15.6-hotfix marker comment (this block) + regression
 *      test pin file guard against future deletions.
 *
 * Why prior 3 hotfixes were incomplete (honest retrospection): each
 * hotfix's L3 single-root-cause discipline narrowed scope so much that
 * Phase A audit didn't enumerate every component class-hook and every
 * mechanism. § 17.8 Gate 9 + Gate 9.5 covered cascade + inheritance;
 * Gate 9.7 (deferred to its own sprint) is the per-component verification
 * lesson from this iteration.
 */


/* Item 5 — compound selector body-element guard (defensive). */
body.av-page.text-white { color: var(--av-text-primary); }


/* Item 3 — Component class hook text colors (cards). */

/* Landing category cards — h3 title + .text-xs meta + nested article list. */
body.av-page .cat-card               { color: var(--av-text-primary); }
body.av-page .cat-card h3            { color: var(--av-text-primary); }
body.av-page .cat-card p             { color: var(--av-text-muted); }
body.av-page .cat-card li,
body.av-page .cat-card li a         { color: var(--av-text-secondary); }
body.av-page .cat-card li:hover,
body.av-page .cat-card li:hover a   { color: var(--av-text-primary); }

/* Featured + article cards (article suggestion blocks on landing + sidebar). */
body.av-page .article-card           { color: var(--av-text-primary); }
body.av-page .article-card h3,
body.av-page .article-card h4        { color: var(--av-text-primary); }
body.av-page .article-card p         { color: var(--av-text-secondary); }
body.av-page .article-card .meta,
body.av-page .article-card .text-xs  { color: var(--av-text-muted); }

/* Group cards (grammar-roadmap.html clusters). */
body.av-page .group-card             { color: var(--av-text-primary); }
body.av-page .group-card h3,
body.av-page .group-card h4          { color: var(--av-text-primary); }
body.av-page .group-card p           { color: var(--av-text-muted); }

/* Group article rows (inside group-card, plus the renderer-emitted
 * "Sắp ra mắt" / "Đang cập nhật" status states). */
body.av-page .group-article-row             { color: var(--av-text-secondary); }
body.av-page .group-article-row a           { color: var(--av-text-secondary); }
body.av-page .group-article-row a:hover     { color: var(--av-text-primary); }


/* Item 4 — Card surface visibility (replace invisible bg-white/[0.03]).
 *
 * The arbitrary-value `bg-white/[0.03]` Tailwind class is uncovered by
 * the Sprint 6.15.4 bg-white neutralizer block (covers /5, /6, /8, /10
 * only, not /[0.03]). On cream surface in light theme,
 * `rgba(255,255,255,0.03)` is imperceptibly different from the page —
 * card boundaries disappear. Force a visible surface on cards even when
 * the renderer emits the arbitrary-value utility. */
body.av-page .cat-card,
body.av-page .article-card,
body.av-page .group-card,
body.av-page .group-article-row {
  background-color: var(--av-surface-card);
}

/* Also cover the arbitrary-value class name directly — Tailwind compiles
 * `bg-white/[0.03]` to `.bg-white\/\[0\.03\]`. Higher-specificity scoped
 * override beats it. Same for /[0.07] used on hover. */
body.av-page .bg-white\/\[0\.03\]  { background-color: var(--av-surface-card); }
body.av-page .bg-white\/\[0\.04\]  { background-color: var(--av-surface-card); }
body.av-page .bg-white\/\[0\.05\]  { background-color: var(--av-surface-card); }
body.av-page .hover\:bg-white\/\[0\.03\]:hover { background-color: var(--av-surface-elevated); }


/* Item 2 — Class hooks for grammar.js inline-color refactor sites.
 *
 * Renderer previously emitted `style="background:rgba(255,255,255,X);
 * color:rgba(255,255,255,Y)"` for the planned-status badge + save-article
 * button. Inline styles bypass cascade — the only fix is to migrate them
 * to class hooks. These rules define the token-driven base + state for
 * each. */

/* Planned-status dot (group-article-row, status === 'planned'). */
.gw-status-dot--planned {
  background-color: var(--av-text-faint);
}

/* Planned-status pill ("Sắp ra mắt"). Resolves to a muted-on-card surface
 * in both themes. */
.gw-status-badge--planned {
  background-color: var(--av-surface-sunken);
  color: var(--av-text-muted);
}

/* Save-article button (grammar-article.html header meta). Base state +
 * `--saved` modifier. */
.gw-save-btn {
  margin-left: auto;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 4px 12px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 600;
  cursor: pointer;
  border: 1px solid var(--av-border-default);
  background: var(--av-surface-sunken);
  color: var(--av-text-muted);
  transition: all 0.15s;
}
.gw-save-btn:hover {
  border-color: var(--av-primary-border);
  color: var(--av-text-primary);
}
.gw-save-btn--saved {
  border-color: var(--av-primary-border);
  background: var(--av-primary-soft);
  color: var(--av-primary);
}
.gw-save-btn--saved:hover {
  color: var(--av-primary-hover);
}

/* Progress-bar track (roadmap card category-level progress visual).
 * Was inline `style="background:rgba(255,255,255,0.06)"`. */
.gw-progress-track {
  background-color: var(--av-surface-sunken);
}


/* Lora-display headings — opt-in via .gw-display or class on element */
.gw-display,
.hero-title,
#article-title,
#search-heading {
  font-family: 'Lora', Georgia, serif;
}


/* ── Sprint 6.18 — secondary nav canonical bottom margin ───────── *
 * .gw-subnav is the Grammar Wiki editorial breadcrumb that lives
 * BELOW the canonical .topnav. Sticky `top:0` already keeps it
 * pinned during scroll; the margin-bottom restores the canonical
 * 64px chrome-to-content rhythm so the first body block lands at
 * the same vertical position as on canonical-chrome-only pages. */
.gw-subnav {
  margin-bottom: var(--av-chrome-bottom-margin);
}


/* ── Hero glow + section labels (shared across landing + sub-pages) ─ */

.hero-glow {
  position: absolute;
  top: -80px; left: 50%; transform: translateX(-50%);
  width: 600px; height: 400px;
  background: radial-gradient(
    ellipse at center,
    color-mix(in srgb, var(--av-primary) 18%, transparent) 0%,
    transparent 70%
  );
  pointer-events: none;
}

.section-head,
.section-label {
  display: flex; align-items: center; gap: 10px;
  font-size: 10.5px; font-weight: 700; letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--av-text-muted);
  margin-bottom: 18px;
}
.section-head::before,
.section-label::before {
  content: '';
  display: inline-block;
  width: 18px; height: 2px;
  background: linear-gradient(90deg, var(--av-primary), transparent);
  border-radius: 2px;
}

.section-label { font-size: 10px; }
.section-label::before { width: 14px; }


/* ── Category cards (grammar.html landing) ─────────────────────── */

.cat-card {
  cursor: pointer;
  position: relative;
  overflow: hidden;
  transition: transform 0.2s ease, box-shadow 0.2s ease, border-color 0.2s ease, background 0.2s ease;
}
.cat-card::after {
  content: '';
  position: absolute; inset: 0;
  background: linear-gradient(
    135deg,
    color-mix(in srgb, var(--av-primary) 4%, transparent) 0%,
    transparent 60%
  );
  opacity: 0; transition: opacity 0.2s;
}
.cat-card:hover {
  transform: translateY(-2px);
  box-shadow: 0 8px 32px color-mix(in srgb, var(--av-primary) 12%, transparent);
  border-color: color-mix(in srgb, var(--av-primary) 35%, transparent) !important;
  background: color-mix(in srgb, var(--av-primary) 6%, transparent) !important;
}
.cat-card:hover::after { opacity: 1; }


/* ── Article card + group card (landing) ─────────────────────── */

.article-card {
  position: relative;
  transition: transform 0.2s ease, box-shadow 0.2s ease, border-color 0.2s ease;
}
.article-card:hover {
  transform: translateY(-2px);
  box-shadow: 0 6px 24px color-mix(in srgb, var(--av-text-primary) 25%, transparent);
  border-color: color-mix(in srgb, var(--av-primary) 30%, transparent) !important;
}

.group-card {
  position: relative; overflow: hidden;
  transition: box-shadow 0.2s ease;
}
.group-card:hover {
  box-shadow: 0 4px 24px color-mix(in srgb, var(--av-text-primary) 30%, transparent);
}

.group-article-row { transition: background 0.15s; border-radius: 6px; }
.group-article-row:hover { background: var(--av-surface-card); }


/* ── Search input (landing + grammar-search.html) ──────────────── */

.search-input {
  background: var(--av-surface-card);
  border: 1px solid var(--av-border-default);
  border-radius: 999px;
  padding: 14px 20px 14px 48px;
  color: var(--av-text-primary);
  font-size: 15px;
  font-family: 'DM Sans', sans-serif;
  outline: none;
  transition: border-color 0.2s, box-shadow 0.2s, background 0.2s;
  width: 100%;
}
.search-input:focus {
  background: var(--av-surface-elevated);
  border-color: var(--av-primary-border);
  box-shadow: 0 0 0 4px var(--av-primary-soft);
}
.search-input::placeholder { color: var(--av-text-faint); }


/* ── Buttons / CTAs (landing) ─────────────────────────────────── */

.btn-cta {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 11px 22px; border-radius: 999px;
  font-weight: 600; font-size: 14px;
  font-family: 'DM Sans', sans-serif;
  transition: all 0.18s;
  cursor: pointer; border: none; text-decoration: none;
  letter-spacing: 0.01em;
}

.btn-primary {
  background: linear-gradient(135deg, var(--av-primary-hover), var(--av-primary));
  color: var(--av-text-on-primary);
  box-shadow: 0 2px 12px color-mix(in srgb, var(--av-primary) 40%, transparent);
}
.btn-primary:hover {
  background: linear-gradient(135deg, var(--av-primary-active), var(--av-primary-hover));
  transform: translateY(-1px);
  box-shadow: 0 4px 20px color-mix(in srgb, var(--av-primary) 50%, transparent);
}

.btn-outline {
  background: var(--av-surface-card);
  color: var(--av-text-secondary);
  border: 1px solid var(--av-border-default);
}
.btn-outline:hover {
  background: var(--av-surface-elevated);
  border-color: var(--av-primary-border);
  color: var(--av-primary);
  transform: translateY(-1px);
}


/* ── Roadmap CTA card (landing) ───────────────────────────────── */

.roadmap-card {
  background: linear-gradient(
    135deg,
    var(--av-primary-soft) 0%,
    var(--av-surface-card) 100%
  );
  border: 1px solid var(--av-primary-border);
  position: relative; overflow: hidden;
}
.roadmap-card::before {
  content: '';
  position: absolute; top: -40px; right: -40px;
  width: 160px; height: 160px;
  background: radial-gradient(
    circle,
    color-mix(in srgb, var(--av-primary) 8%, transparent) 0%,
    transparent 70%
  );
}


/* ── Skeleton shimmer + stagger fade-in (landing) ──────────────── */

@keyframes gw-shimmer {
  0%   { background-position: -400px 0; }
  100% { background-position:  400px 0; }
}
.skeleton {
  background: linear-gradient(
    90deg,
    var(--av-surface-card) 25%,
    var(--av-surface-elevated) 50%,
    var(--av-surface-card) 75%
  );
  background-size: 800px 100%;
  animation: gw-shimmer 1.4s infinite;
}

@keyframes gw-fadeUp {
  from { opacity: 0; transform: translateY(12px); }
  to   { opacity: 1; transform: translateY(0); }
}
#category-cards > *,
#featured-list > *,
#groups-list > * {
  animation: gw-fadeUp 0.35s ease both;
}
#category-cards > *:nth-child(2), #featured-list > *:nth-child(2), #groups-list > *:nth-child(2) { animation-delay: 0.06s; }
#category-cards > *:nth-child(3), #featured-list > *:nth-child(3), #groups-list > *:nth-child(3) { animation-delay: 0.12s; }
#category-cards > *:nth-child(4), #featured-list > *:nth-child(4), #groups-list > *:nth-child(4) { animation-delay: 0.18s; }
#category-cards > *:nth-child(5), #featured-list > *:nth-child(5), #groups-list > *:nth-child(5) { animation-delay: 0.24s; }
#category-cards > *:nth-child(6), #featured-list > *:nth-child(6), #groups-list > *:nth-child(6) { animation-delay: 0.30s; }
#groups-list > *:nth-child(7) { animation-delay: 0.35s; }
#groups-list > *:nth-child(8) { animation-delay: 0.40s; }


/* ── Reading progress bar (grammar-article.html) ─────────────── */

#reading-progress {
  position: fixed; top: 0; left: 0; z-index: 50;
  height: 2px; width: 0%;
  background: linear-gradient(90deg, var(--av-primary-hover), var(--av-primary));
  transition: width 0.1s linear;
  pointer-events: none;
}


/* ── Sticky TOC sidebar (grammar-article.html) ───────────────── */

.toc-sidebar {
  position: sticky;
  top: 72px;
  max-height: calc(100vh - 90px);
  overflow-y: auto;
}

.toc-link {
  transition: color 0.15s, border-color 0.15s, padding-left 0.15s;
}
.toc-link.text-teal-light {
  border-left: 2px solid var(--av-primary);
  padding-left: 10px;
  color: var(--av-primary) !important;
}


/* ── Article body typography (grammar-article + grammar-compare) ─ */

.article-body {
  color: var(--av-text-primary);
  line-height: 1.8;
  font-size: 15.5px;
}

.grammar-anchor-notice {
  margin: 0 0 1rem;
  padding: 0.9rem 1rem;
  border-radius: 0.9rem;
  border: 1px solid rgba(245, 158, 11, 0.22);
  background: rgba(245, 158, 11, 0.08);
  color: var(--av-text-primary);
  font-size: 0.92rem;
  line-height: 1.5;
}

/* Sprint 5 deep-link anchor scroll offset + pulse highlight */
.article-body .grammar-anchor { scroll-margin-top: 80px; }
.grammar-anchor-pulse {
  animation: gw-grammarAnchorPulse 3s ease-out;
  border-radius: 6px;
}
@keyframes gw-grammarAnchorPulse {
  0%   { background-color: transparent; }
  15%  { background-color: var(--av-primary-soft); }
  100% { background-color: transparent; }
}

.article-body h2 {
  font-family: 'Lora', serif;
  font-size: 1.3rem; font-weight: 700;
  color: var(--av-text-primary);
  margin-top: 2.5rem; margin-bottom: 0.85rem;
  padding-left: 12px;
  border-left: 3px solid var(--av-primary-hover);
  scroll-margin-top: 80px;
}
.article-body h3 {
  font-size: 1.05rem; font-weight: 600;
  color: var(--av-text-primary);
  margin-top: 1.75rem; margin-bottom: 0.6rem;
  scroll-margin-top: 80px;
  letter-spacing: 0.01em;
}
.article-body p { margin-bottom: 1.1rem; }
.article-body ul,
.article-body ol {
  padding-left: 1.5rem; margin-bottom: 1.1rem;
}
.article-body ul li { list-style: disc; margin-bottom: 0.4rem; }
.article-body ol li { list-style: decimal; margin-bottom: 0.4rem; }
.article-body strong { color: var(--av-text-primary); font-weight: 600; }
.article-body em {
  color: var(--av-primary);
  font-style: normal;
  font-weight: 500;
}

.article-body code {
  background: var(--av-primary-soft);
  border: 1px solid var(--av-primary-border);
  padding: 0.15em 0.45em; border-radius: 5px;
  font-size: 0.88em;
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  color: var(--av-primary);
}
.article-body pre {
  background: var(--av-surface-card);
  border: 1px solid var(--av-border-subtle);
  border-radius: 14px; padding: 18px 22px;
  overflow-x: auto; margin-bottom: 1.25rem;
}
.article-body pre code {
  background: none; border: none; padding: 0;
  font-size: 0.875rem;
  color: var(--av-text-primary);
}

.article-body table {
  width: 100%; border-collapse: collapse; margin-bottom: 1.5rem;
  font-size: 0.875rem; display: block; overflow-x: auto;
  border-radius: 10px;
}
.article-body table th {
  background: var(--av-primary-soft);
  color: var(--av-primary); font-weight: 600;
  padding: 10px 14px; text-align: left;
  border: 1px solid var(--av-primary-border);
  white-space: nowrap;
}
.article-body table td {
  padding: 9px 14px;
  border: 1px solid var(--av-border-subtle);
  color: var(--av-text-secondary);
}
.article-body table tr:nth-child(even) td { background: var(--av-surface-sunken); }
.article-body table tr:hover td { background: var(--av-primary-soft); }

.article-body blockquote {
  position: relative;
  padding: 18px 20px 14px 24px;
  margin: 1.5rem 0;
  background: var(--av-primary-soft);
  border: 1px solid var(--av-primary-border);
  border-radius: 12px;
  color: var(--av-text-secondary);
  font-style: italic;
}
.article-body blockquote::before {
  content: '\201C';
  font-family: 'Lora', serif;
  font-size: 3.5rem; line-height: 1;
  color: color-mix(in srgb, var(--av-primary) 25%, transparent);
  position: absolute; top: -4px; left: 12px;
  pointer-events: none;
}

.article-body a {
  color: var(--av-primary);
  text-decoration: underline;
  text-decoration-color: color-mix(in srgb, var(--av-primary) 35%, transparent);
  text-underline-offset: 3px;
  transition: text-decoration-color 0.15s;
}
.article-body a:hover { text-decoration-color: var(--av-primary); }


/* ── Compare column panels (grammar-compare.html) ─────────────── */

.compare-col {
  border: 1px solid var(--av-border-subtle);
  border-radius: 16px;
  padding: 24px;
  background: var(--av-surface-card);
}


/* ── Scrollbar polish (all pages) ─────────────────────────────── */

::-webkit-scrollbar { width: 5px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb {
  background: var(--av-border-default);
  border-radius: 9999px;
}
