/**
 * ============================================================================
 * style-ck-content.css — Unified Content Design System
 * ============================================================================
 *
 * File DUY NHẤT, dùng ở CẢ HAI nơi — backend (camtest, Laravel + CKEditor 4)
 * VÀ frontend (camtestfe, Next.js + CKEditor 5). Không phải 2 hệ thống style
 * khác nhau đồng bộ tay — đây là 1 file, copy y hệt sang 2 nơi:
 *
 *   - Backend (camtest)  : `public/ckeditor/style-ck-content.css`
 *                           dùng cho contentsCss của CKEditor 4 (bodyClass
 *                           "ck-content") VÀ khung "Xem trước" trên trang admin
 *                           (bọc `<div class="ck-content">`).
 *   - Frontend (camtestfe): `styles/style-ck-content.css` (copy nguyên văn từ
 *                           file backend, không sửa) dùng cho `.article-content`
 *                           (trang web đã publish) và `.ck-content` (CKEditor 5).
 *
 * Selector luôn viết cặp `.article-content X, .ck-content X` — ở backend chỉ
 * `.ck-content` có hiệu lực (không có `.article-content` trong DOM), ở frontend
 * cả hai đều dùng. Token ở SECTION 1 dùng `var(--x, fallback)` nên tự hoạt động
 * độc lập dù dự án có hay không có biến shadcn/ui (--background, --primary...)
 * — backend (không có shadcn) sẽ tự dùng giá trị fallback, frontend (có shadcn)
 * sẽ tự ăn theo theme thật của site.
 *
 * KHI SỬA: chỉ sửa 1 bản (khuyến nghị sửa ở backend vì đây là nơi tạo/kiểm tra
 * nội dung), rồi copy đè sang bản còn lại — không sửa riêng lẻ từng bên vì sẽ
 * làm mất đúng mục tiêu "soạn sao, hiển thị vậy".
 *
 * ---------------------------------------------------------------------------
 * QUY ƯỚC KỸ THUẬT
 * ---------------------------------------------------------------------------
 * - Mọi selector đều viết CẶP tường minh `.article-content X, .ck-content X`
 *   (không dùng CSS Nesting) — một số kiểu nesting (bare type selector, nested
 *   rule bắt đầu bằng combinator `>`/`+`) tuy hợp lệ theo spec mới nhất nhưng
 *   CHƯA được hỗ trợ đồng nhất trên toàn bộ hệ sinh thái công cụ CSS hiện nay;
 *   viết phẳng đảm bảo tương thích tuyệt đối với mọi trình duyệt/bundler.
 * - KHÔNG dùng !important — mọi override dựa vào thứ tự khai báo & specificity
 *   tự nhiên (selector luôn ở dạng lớp đơn giản, dễ override từ ngoài nếu cần).
 *   Ngoại lệ DUY NHẤT: khối reduced-motion (SECTION 18) — bắt buộc theo WCAG.
 * - KHÔNG hardcode màu — 100% dùng CSS custom properties. Ưu tiên tái sử dụng
 *   biến shadcn/ui có sẵn (--background, --foreground, --primary, --border,
 *   --muted, --muted-foreground, --accent, --destructive, --radius...). Phần
 *   token riêng cho nội dung bài viết (callout, code, TOC...) định nghĩa thêm
 *   ở SECTION 1, tự động đổi màu theo `.dark` nhờ cascade — không cần viết lại
 *   style trong media query hay class .dark riêng cho từng thành phần.
 * - Markup giả định KHỚP với HTML thực tế CKEditor 5 xuất ra (`figure.image`,
 *   `figure.table`, `figure.media`, `ul.todo-list`, `pre > code.language-*`...)
 *   — ghi chú markup mẫu ở đầu mỗi section liên quan để đối chiếu.
 * - `.callout-*`, `.alert-*`, `.badge-*`, `.toc-*` là các class do trình soạn
 *   thảo chèn qua plugin/GHS (General HTML Support) tuỳ chỉnh riêng của dự án
 *   — không phải tính năng lõi CKEditor 5 — file này chỉ style phần hiển thị.
 * ============================================================================
 */

/* ============================================================================
 * SECTION 1 — DESIGN TOKENS
 * ============================================================================
 * Token riêng cho nội dung bài viết, nằm CẠNH (không thay thế) biến shadcn/ui.
 * Mọi màu dùng oklch() để đảm bảo độ tương phản đồng đều giữa các tông màu.
 * ============================================================================
 */
:root {
  /* --- Layout & đo lường đọc (reading measure) --- */
  --article-max-width: 44rem; /* ≈ 720px, đúng "measure" đọc thoải mái (60-75 ký tự/dòng) */
  --article-gutter: 1.25rem;
  --article-scroll-offset: 5rem; /* trừ hao header sticky khi nhảy tới heading từ TOC */

  /* --- Font stack (đổi tại đây nếu dùng web font riêng, vd Inter) --- */
  --article-font-sans:
    'Public Sans', -apple-system, BlinkMacSystemFont, 'Inter', 'Segoe UI', Roboto,
    'Helvetica Neue', Arial, 'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji';
  --article-font-mono:
    ui-monospace, 'SF Mono', 'Cascadia Code', 'JetBrains Mono', Consolas, 'Roboto Mono', monospace;

  /* --- Nhịp dọc (vertical rhythm) mặc định giữa các block liên tiếp --- */
  --article-flow-space: 1.25em;

  /* --- Bo góc & bóng đổ dùng chung, ăn theo --radius của shadcn nếu có --- */
  --article-radius-sm: calc(var(--radius, 0.625rem) - 4px);
  --article-radius: var(--radius, 0.625rem);
  --article-radius-lg: calc(var(--radius, 0.625rem) + 4px);
  --article-shadow-sm: 0 1px 2px 0 oklch(0% 0 0 / 0.04), 0 1px 1px 0 oklch(0% 0 0 / 0.03);
  --article-shadow: 0 2px 8px -2px oklch(0% 0 0 / 0.08), 0 1px 2px -1px oklch(0% 0 0 / 0.06);
  --article-shadow-lg: 0 12px 32px -8px oklch(0% 0 0 / 0.14), 0 4px 8px -4px oklch(0% 0 0 / 0.08);

  /* --- Transition ngắn, không rối mắt --- */
  --article-ease: cubic-bezier(0.16, 1, 0.3, 1);
  --article-duration-fast: 120ms;
  --article-duration: 180ms;

  /* --- Code / Pre --- */
  --article-code-bg: var(--muted, oklch(96% 0.003 264));
  --article-code-fg: var(--foreground, oklch(21% 0.006 264));
  --article-code-border: var(--border, oklch(90% 0.005 264));
  --article-code-inline-bg: oklch(96% 0.01 290 / 0.55);
  --article-code-inline-fg: oklch(40% 0.16 300);

  /* --- Blockquote --- */
  --article-quote-bg: color-mix(in oklch, var(--primary, oklch(55% 0.18 265)) 6%, var(--background, white));
  --article-quote-border: var(--primary, oklch(55% 0.18 265));
  --article-quote-fg: var(--foreground, oklch(21% 0.006 264));

  /* --- Table --- */
  --article-table-header-bg: var(--muted, oklch(96% 0.003 264));
  --article-table-header-fg: var(--foreground, oklch(21% 0.006 264));
  --article-table-border: var(--border, oklch(90% 0.005 264));
  --article-table-zebra-bg: color-mix(in oklch, var(--muted, oklch(96% 0.003 264)) 45%, transparent);
  --article-table-hover-bg: color-mix(in oklch, var(--primary, oklch(55% 0.18 265)) 6%, transparent);

  /* --- Callout — 10 loại, mỗi loại 3 token: bg / border / icon (fg suy ra từ --foreground) --- */
  --callout-info-bg: oklch(96% 0.03 250);
  --callout-info-border: oklch(62% 0.16 250);
  --callout-info-icon: oklch(45% 0.17 250);

  --callout-warning-bg: oklch(96.5% 0.05 85);
  --callout-warning-border: oklch(68% 0.16 80);
  --callout-warning-icon: oklch(48% 0.15 75);

  --callout-success-bg: oklch(96% 0.04 150);
  --callout-success-border: oklch(62% 0.15 150);
  --callout-success-icon: oklch(45% 0.14 150);

  --callout-danger-bg: oklch(96% 0.03 25);
  --callout-danger-border: oklch(58% 0.19 25);
  --callout-danger-icon: oklch(48% 0.19 25);

  --callout-tip-bg: oklch(96% 0.03 305);
  --callout-tip-border: oklch(58% 0.17 305);
  --callout-tip-icon: oklch(46% 0.17 305);

  --callout-note-bg: oklch(96.5% 0.004 264);
  --callout-note-border: oklch(65% 0.01 264);
  --callout-note-icon: oklch(42% 0.01 264);

  /* hue 275 (indigo) — cố tình tách khỏi --primary (teal, hue ~184, dùng cho rất nhiều chi
     tiết cấu trúc chính: link/heading/step-badge/timeline/.problem-type) và khỏi mọi hue callout
     khác (info 250, tip 305) để khối "Ví dụ" không hòa lẫn vào phần còn lại của bài. */
  --callout-example-bg: oklch(96.5% 0.025 275);
  --callout-example-border: oklch(58% 0.19 275);
  --callout-example-icon: oklch(46% 0.19 275);

  --callout-question-bg: oklch(96% 0.03 320);
  --callout-question-border: oklch(58% 0.15 320);
  --callout-question-icon: oklch(46% 0.15 320);

  --callout-homework-bg: oklch(96.5% 0.045 55);
  --callout-homework-border: oklch(62% 0.15 50);
  --callout-homework-icon: oklch(47% 0.14 48);

  --callout-summary-bg: oklch(96% 0.03 175);
  --callout-summary-border: oklch(58% 0.11 175);
  --callout-summary-icon: oklch(42% 0.1 175);
}

/* --- Dark mode: chỉ override token nào KHÔNG tự đủ tương phản khi nền tối đi --- */
.dark {
  --article-code-inline-bg: oklch(30% 0.05 300 / 0.35);
  --article-code-inline-fg: oklch(85% 0.1 300);

  --article-quote-bg: color-mix(in oklch, var(--primary, oklch(70% 0.16 265)) 12%, var(--background, black));

  --article-table-zebra-bg: color-mix(in oklch, var(--muted, oklch(27% 0.006 264)) 60%, transparent);
  --article-table-hover-bg: color-mix(in oklch, var(--primary, oklch(70% 0.16 265)) 10%, transparent);

  --callout-info-bg: oklch(28% 0.06 250);
  --callout-info-border: oklch(55% 0.17 250);
  --callout-info-icon: oklch(80% 0.1 250);

  --callout-warning-bg: oklch(28% 0.06 80);
  --callout-warning-border: oklch(62% 0.15 78);
  --callout-warning-icon: oklch(82% 0.12 80);

  --callout-success-bg: oklch(28% 0.055 150);
  --callout-success-border: oklch(56% 0.14 150);
  --callout-success-icon: oklch(80% 0.13 150);

  --callout-danger-bg: oklch(28% 0.06 25);
  --callout-danger-border: oklch(55% 0.18 25);
  --callout-danger-icon: oklch(82% 0.13 25);

  --callout-tip-bg: oklch(28% 0.06 305);
  --callout-tip-border: oklch(55% 0.16 305);
  --callout-tip-icon: oklch(82% 0.11 305);

  --callout-note-bg: oklch(27% 0.006 264);
  --callout-note-border: oklch(50% 0.01 264);
  --callout-note-icon: oklch(82% 0.006 264);

  --callout-example-bg: oklch(28% 0.07 275);
  --callout-example-border: oklch(58% 0.2 275);
  --callout-example-icon: oklch(80% 0.14 275);

  --callout-question-bg: oklch(28% 0.06 320);
  --callout-question-border: oklch(55% 0.14 320);
  --callout-question-icon: oklch(82% 0.12 320);

  --callout-homework-bg: oklch(28% 0.06 52);
  --callout-homework-border: oklch(58% 0.14 50);
  --callout-homework-icon: oklch(82% 0.12 50);

  --callout-summary-bg: oklch(27% 0.045 175);
  --callout-summary-border: oklch(52% 0.1 175);
  --callout-summary-icon: oklch(80% 0.1 175);
}

/* ============================================================================
 * SECTION 2 — CONTAINER & BASE
 * ============================================================================
 */
.article-content,
.ck-content {
  color: var(--foreground, oklch(21% 0.006 264));
  background: transparent;
  font-family: var(--article-font-sans);
  font-size: 1.0625rem; /* 17px — vùng "sweet spot" đọc dài trên desktop */
  line-height: 1.75;
  letter-spacing: -0.011em;
  font-feature-settings: 'kern' 1, 'liga' 1, 'calt' 1;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  word-wrap: break-word;
  overflow-wrap: break-word;
}

/* Giới hạn bề rộng "cột đọc" (measure) + căn giữa + padding-inline CHỈ áp dụng
   cho trang web đã publish (.article-content) — KHÔNG áp dụng cho khung soạn
   thảo (.ck-content), vì khung soạn thảo đã có bề rộng đúng theo modal/container
   chứa nó rồi; nếu co hẹp + căn giữa + đệm thêm lần nữa sẽ tạo 1 cột chữ hẹp
   nằm giữa 1 khung rộng, để lại khoảng trắng lớn 2 bên trông như bị lệch padding
   và con trỏ/text không bao giờ chạm được mép khung thật (đặc biệt rõ với
   CKEditor 4 — vùng soạn thảo CHÍNH LÀ <body class="ck-content"> của iframe,
   nên bất kỳ padding-inline nào ở đây cũng đẩy thẳng điểm bắt đầu gõ chữ, không
   qua lớp bọc nào khác để bù trừ). CKEditor 5 có padding riêng qua rule
   `.ck.ck-editor__editable.ck-content` bên dưới, không phụ thuộc vào đây. */
.article-content {
  max-width: var(--article-max-width);
  margin-inline: auto;
  padding-inline: var(--article-gutter);
}

/* Biến thể "wide" — mở rộng cột đọc cho bài dùng nhiều component dạng lưới
   (concept-grid-3/4, intro-grid, stat-grid ở SECTION 22-23) — 44rem mặc định
   (biến --article-max-width ở SECTION 1) đủ cho văn bản thuần nhưng quá hẹp
   khi ép 3-4 cột vào, khiến lưới bị bóp méo. KHÔNG đổi giá trị mặc định của
   --article-max-width vì đó là lựa chọn có chủ đích cho bài lý thuyết 1 mạch
   văn bản dài (đo đọc 60-75 ký tự/dòng) — chỉ override khi tác giả CHỦ ĐỘNG
   thêm class phụ này cho trang có nội dung dạng lưới nhiều cột.
   var(--container-app) là token layout đã có sẵn ở frontend (app/globals.css,
   80rem); fallback 80rem dùng khi hiển thị ở nơi không có token đó (vd trang
   "Xem trước" trong admin Laravel không có Tailwind/shadcn).
   Markup: <article class="article-content article-content--wide">...</article> */
.article-content.article-content--wide {
  --article-max-width: var(--container-app, 80rem);
}

/* Biến thể "in-app" — bỏ padding-inline riêng của .article-content khi nó đã nằm trong 1
   container Tailwind có sẵn padding (vd `p-4 sm:p-6` ở TheoryDetailClient/TheoryBlogDetailClient/
   BlogDetailClient) — tránh cộng dồn 2 lớp padding khiến nội dung thụt sâu hơn hẳn so với các
   phần tử khác cùng trang (hero, banner CTA, "Bài viết liên quan") không đi qua `.article-content`.
   KHÔNG đổi rule `.article-content` gốc vì trang "Xem trước" CKEditor bên admin Laravel không có
   wrapper Tailwind, vẫn cần padding-inline riêng để không dính sát mép khung.
   Markup: <div className="article-content article-content--in-app">...</div> */
.article-content.article-content--in-app {
  padding-inline: 0;
}

/* Nhịp dọc: mọi phần tử con trực tiếp (trừ phần tử đầu) cách nhau đều nhau —
   tránh phải khai margin-top thủ công lặp lại ở từng loại thẻ bên dưới. */
.article-content > * + *,
.ck-content > * + * {
  margin-top: var(--article-flow-space);
}
.article-content > *:first-child,
.ck-content > *:first-child {
  margin-top: 0;
}
.article-content > *:last-child,
.ck-content > *:last-child {
  margin-bottom: 0;
}

/* CKEditor 5 tự thêm padding/outline riêng cho vùng soạn thảo (class
   .ck.ck-editor__editable trên chính editable root) — đồng bộ lại để không
   lệch so với .article-content khi hiển thị preview. Selector này chỉ có
   nghĩa ở frontend (CKEditor 5) — ở backend (CKEditor 4) không có class
   "ck-editor__editable" nên rule này không match gì cả (vô hại, không cần
   xoá vì file này dùng chung 2 nơi). CKEditor 4 chỉ có 1 class duy nhất trên
   <body> của iframe (khai báo qua bodyClass: 'ck-content'), nên đã được style
   đầy đủ bởi rule .ck-content dùng chung ở trên — không cần thêm gì riêng. */
.ck.ck-editor__editable.ck-content {
  padding: 1.5rem var(--article-gutter);
  border-radius: var(--article-radius);
}
.ck.ck-editor__editable.ck-content:not(.ck-focused) {
  border-color: var(--border, oklch(90% 0.005 264));
}

/* ============================================================================
 * SECTION 3 — TYPOGRAPHY: HEADINGS
 * ============================================================================
 * scroll-margin-top để khi bấm link trong TOC nhảy tới heading không bị che
 * bởi header sticky (chỉnh --article-scroll-offset ở SECTION 1 nếu cần).
 */
.article-content h1,
.article-content h2,
.article-content h3,
.article-content h4,
.article-content h5,
.article-content h6,
.ck-content h1,
.ck-content h2,
.ck-content h3,
.ck-content h4,
.ck-content h5,
.ck-content h6 {
  scroll-margin-top: var(--article-scroll-offset);
  font-weight: 700;
  color: var(--foreground, oklch(21% 0.006 264));
  text-wrap: balance;
  letter-spacing: -0.02em;
}

/* Heading theo SAU 1 heading khác (2 heading liền nhau) không cần khoảng cách
   lớn phía trên — chỉ heading đứng sau nội dung thường mới cần nhịp lớn. */
.article-content h2 + h3,
.article-content h3 + h4,
.article-content h4 + h5,
.article-content h5 + h6,
.ck-content h2 + h3,
.ck-content h3 + h4,
.ck-content h4 + h5,
.ck-content h5 + h6 {
  margin-top: 0.5em;
}

.article-content h1,
.ck-content h1 {
  margin-top: 0;
  font-size: 2.375rem;
  line-height: 1.2;
  font-weight: 800;
  letter-spacing: -0.03em;
}

.article-content h2,
.ck-content h2 {
  margin-top: 2.5em;
  font-size: 1.75rem;
  line-height: 1.3;
  padding-bottom: 0.5rem;
  border-bottom: 1px solid var(--border, oklch(90% 0.005 264));
}

.article-content h3,
.ck-content h3 {
  margin-top: 2em;
  font-size: 1.375rem;
  line-height: 1.4;
  font-weight: 700;
}

.article-content h4,
.ck-content h4 {
  margin-top: 1.75em;
  font-size: 1.125rem;
  line-height: 1.5;
  font-weight: 600;
}

.article-content h5,
.ck-content h5 {
  margin-top: 1.5em;
  font-size: 1rem;
  line-height: 1.5;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--muted-foreground, oklch(50% 0.01 264));
}

.article-content h6,
.ck-content h6 {
  margin-top: 1.5em;
  font-size: 0.875rem;
  line-height: 1.5;
  font-weight: 600;
  color: var(--muted-foreground, oklch(50% 0.01 264));
}

/* Khoảng cách giữa heading và nội dung ngay sau nó hẹp hơn nhịp chung */
.article-content h1 + *,
.article-content h2 + *,
.article-content h3 + *,
.article-content h4 + *,
.article-content h5 + *,
.article-content h6 + *,
.ck-content h1 + *,
.ck-content h2 + *,
.ck-content h3 + *,
.ck-content h4 + *,
.ck-content h5 + *,
.ck-content h6 + * {
  margin-top: 0.75em;
}

/* ============================================================================
 * SECTION 4 — TYPOGRAPHY: PARAGRAPH & INLINE ELEMENTS
 * ============================================================================
 */
.article-content p,
.ck-content p {
  margin: 0;
  color: var(--foreground, oklch(21% 0.006 264));
}

.article-content strong,
.article-content b,
.ck-content strong,
.ck-content b {
  /* KHÔNG set color ở đây — in đậm chỉ nên đổi font-weight, còn màu chữ để KẾ THỪA
     tự nhiên từ ngữ cảnh xung quanh (đoạn văn thường, hoặc span màu tùy biến do
     tác giả tự chọn, vd <span style="color:#27ae60"><strong>...</strong></span>).
     Nếu set color trực tiếp ở đây, nó sẽ đè lên màu kế thừa từ span cha — dù span
     cha có inline style specificity cao đến đâu, vì color trên chính thẻ <strong>
     luôn thắng giá trị kế thừa (inherited) từ tổ tiên. */
  font-weight: 700;
}

.article-content em,
.article-content i,
.ck-content em,
.ck-content i {
  font-style: italic;
}

.article-content del,
.article-content s,
.ck-content del,
.ck-content s {
  text-decoration: line-through;
  text-decoration-color: var(--muted-foreground, oklch(50% 0.01 264));
  color: var(--muted-foreground, oklch(50% 0.01 264));
}

.article-content u,
.ck-content u {
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 2px;
}

.article-content small,
.ck-content small {
  font-size: 0.8125em;
  color: var(--muted-foreground, oklch(50% 0.01 264));
}

.article-content sup,
.article-content sub,
.ck-content sup,
.ck-content sub {
  font-size: 0.7em;
  line-height: 0;
  position: relative;
  vertical-align: baseline;
}
.article-content sup,
.ck-content sup {
  top: -0.5em;
}
.article-content sub,
.ck-content sub {
  bottom: -0.25em;
}

.article-content mark,
.ck-content mark {
  background: linear-gradient(to bottom, transparent 55%, oklch(85% 0.14 95 / 0.65) 55%);
  color: inherit;
  border-radius: 2px;
  padding-inline: 0.05em;
}
.dark .article-content mark,
.dark .ck-content mark {
  background: linear-gradient(to bottom, transparent 55%, oklch(55% 0.14 95 / 0.4) 55%);
}

.article-content kbd,
.ck-content kbd {
  display: inline-block;
  font-family: var(--article-font-mono);
  font-size: 0.8125em;
  line-height: 1.4;
  padding: 0.1em 0.5em;
  border-radius: var(--article-radius-sm);
  border: 1px solid var(--border, oklch(90% 0.005 264));
  border-bottom-width: 2px;
  background: var(--card, var(--background, oklch(100% 0 0)));
  box-shadow: var(--article-shadow-sm);
  color: var(--foreground, oklch(21% 0.006 264));
}

.article-content abbr[title],
.ck-content abbr[title] {
  text-decoration: underline dotted;
  text-decoration-color: var(--muted-foreground, oklch(50% 0.01 264));
  cursor: help;
}

/* ============================================================================
 * SECTION 5 — LINKS
 * ============================================================================
 * Underline animation kiểu "gạch chân trượt vào" — tinh tế, không giật.
 */
.article-content a,
.ck-content a {
  color: var(--primary, oklch(55% 0.18 265));
  font-weight: 500;
  text-decoration: none;
  background-image: linear-gradient(currentColor, currentColor);
  background-position: 0% 100%;
  background-repeat: no-repeat;
  background-size: 0% 1px;
  padding-bottom: 1px;
  transition:
    background-size var(--article-duration) var(--article-ease),
    color var(--article-duration-fast) var(--article-ease);
}

.article-content a:hover,
.ck-content a:hover {
  background-size: 100% 1px;
}

.article-content a:visited,
.ck-content a:visited {
  color: color-mix(in oklch, var(--primary, oklch(55% 0.18 265)) 75%, var(--muted-foreground, oklch(50% 0.01 264)));
}

.article-content a:active,
.ck-content a:active {
  color: color-mix(in oklch, var(--primary, oklch(55% 0.18 265)) 85%, black);
}

/* Link bọc quanh ảnh/figure không cần gạch chân */
.article-content a:has(img),
.article-content a:has(figure),
.ck-content a:has(img),
.ck-content a:has(figure) {
  background-image: none;
  padding-bottom: 0;
}

/* ============================================================================
 * SECTION 6 — LISTS (ul, ol, nested, task list / checklist)
 * ============================================================================
 * Markup task list của CKEditor 5:
 *   <ul class="todo-list">
 *     <li class="todo-list__item">
 *       <label class="todo-list__label">
 *         <input type="checkbox" disabled>
 *         <span class="todo-list__label__description">Nội dung</span>
 *       </label>
 *     </li>
 *   </ul>
 */
.article-content ul,
.article-content ol,
.ck-content ul,
.ck-content ol {
  margin: 0;
  padding-left: 1.5rem;
}

.article-content ul,
.ck-content ul {
  list-style-type: disc;
}
.article-content ol,
.ck-content ol {
  list-style-type: decimal;
}

.article-content li,
.ck-content li {
  padding-left: 0.25rem;
  margin-top: 0.5em;
}
.article-content li:first-child,
.ck-content li:first-child {
  margin-top: 0;
}
.article-content li::marker,
.ck-content li::marker {
  color: var(--muted-foreground, oklch(50% 0.01 264));
  font-weight: 600;
}

.article-content li > p,
.ck-content li > p {
  margin: 0;
}

/* Nested list: giảm khoảng cách dọc, đổi kiểu marker theo cấp */
.article-content li > ul,
.article-content li > ol,
.ck-content li > ul,
.ck-content li > ol {
  margin-top: 0.4em;
  padding-left: 1.375rem;
}
.article-content ul ul,
.ck-content ul ul {
  list-style-type: circle;
}
.article-content ul ul ul,
.ck-content ul ul ul {
  list-style-type: square;
}
.article-content ol ol,
.ck-content ol ol {
  list-style-type: lower-alpha;
}
.article-content ol ol ol,
.ck-content ol ol ol {
  list-style-type: lower-roman;
}

/* --- Task list / checklist --- */
.article-content ul.todo-list,
.ck-content ul.todo-list {
  list-style: none;
  padding-left: 0;
}

.article-content .todo-list__item,
.ck-content .todo-list__item {
  padding-left: 0;
}

.article-content .todo-list__label,
.ck-content .todo-list__label {
  display: flex;
  align-items: flex-start;
  gap: 0.625rem;
  cursor: default;
}

.article-content .todo-list__label > input[type='checkbox'],
.ck-content .todo-list__label > input[type='checkbox'] {
  appearance: none;
  flex: none;
  width: 1.125rem;
  height: 1.125rem;
  margin-top: 0.2em;
  border-radius: 0.3125rem;
  border: 1.5px solid var(--border, oklch(90% 0.005 264));
  background: var(--background, oklch(100% 0 0));
  cursor: pointer;
  transition:
    background-color var(--article-duration-fast) var(--article-ease),
    border-color var(--article-duration-fast) var(--article-ease);
}

.article-content .todo-list__label > input[type='checkbox']:checked,
.ck-content .todo-list__label > input[type='checkbox']:checked {
  background-color: var(--primary, oklch(55% 0.18 265));
  border-color: var(--primary, oklch(55% 0.18 265));
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='white' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3.5 8.5L6.5 11.5L12.5 4.5'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: center;
  background-size: 68%;
}

.article-content .todo-list__label__description,
.ck-content .todo-list__label__description {
  line-height: 1.6;
}

.article-content li:has(> .todo-list__label input:checked) > .todo-list__label .todo-list__label__description,
.ck-content li:has(> .todo-list__label input:checked) > .todo-list__label .todo-list__label__description {
  color: var(--muted-foreground, oklch(50% 0.01 264));
  text-decoration: line-through;
  text-decoration-color: var(--border, oklch(90% 0.005 264));
}

/* ============================================================================
 * SECTION 7 — BLOCKQUOTE
 * ============================================================================
 */
.article-content blockquote,
.ck-content blockquote {
  position: relative;
  margin: 0;
  padding: 1.125rem 1.375rem 1.125rem 3.25rem;
  background: var(--article-quote-bg);
  border-left: 3px solid var(--article-quote-border);
  border-radius: 0 var(--article-radius) var(--article-radius) 0;
  color: var(--article-quote-fg);
  font-size: 1.0625em;
  font-style: italic;
  line-height: 1.65;
}

.article-content blockquote::before,
.ck-content blockquote::before {
  content: '\201C';
  position: absolute;
  left: 0.9rem;
  top: 0.5rem;
  font-family: Georgia, 'Times New Roman', serif;
  font-style: normal;
  font-size: 2.25rem;
  line-height: 1;
  color: var(--article-quote-border);
  opacity: 0.55;
}

.article-content blockquote > p,
.ck-content blockquote > p {
  margin: 0;
}
.article-content blockquote > * + *,
.ck-content blockquote > * + * {
  margin-top: 0.75em;
}

.article-content blockquote cite,
.ck-content blockquote cite {
  display: block;
  margin-top: 0.75em;
  font-style: normal;
  font-size: 0.8125em;
  font-weight: 600;
  color: var(--muted-foreground, oklch(50% 0.01 264));
}
.article-content blockquote cite::before,
.ck-content blockquote cite::before {
  content: '— ';
}

/* Blockquote lồng trong blockquote */
.article-content blockquote blockquote,
.ck-content blockquote blockquote {
  border-left-color: var(--border, oklch(90% 0.005 264));
  background: transparent;
  padding-left: 1.25rem;
}
.article-content blockquote blockquote::before,
.ck-content blockquote blockquote::before {
  display: none;
}

/* ============================================================================
 * SECTION 8 — IMAGE & FIGURE
 * ============================================================================
 * Markup CKEditor 5:
 *   <figure class="image"><img src=".."><figcaption>...</figcaption></figure>
 *   <figure class="image image_resized" style="width:60%">...</figure>
 *   variant căn lề: .image-style-side / .image-style-align-left / -align-right
 */
.article-content img,
.ck-content img {
  max-width: 100%;
  height: auto;
  border-radius: var(--article-radius);
  display: block;
}

.article-content figure,
.ck-content figure {
  margin: 0;
}

.article-content figure.image,
.article-content .image,
.ck-content figure.image,
.ck-content .image {
  display: block;
  text-align: center;
}

.article-content figure.image > img,
.article-content .image > img,
.ck-content figure.image > img,
.ck-content .image > img {
  margin-inline: auto;
  border-radius: var(--article-radius);
  box-shadow: var(--article-shadow);
  border: 1px solid var(--border, oklch(90% 0.005 264));
}

/* Ảnh không có caption/border đặc thù (icon, logo nhỏ...) dùng .image--plain
   để tắt khung/shadow nếu cần — class tuỳ chọn, opt-in */
.article-content .image--plain > img,
.ck-content .image--plain > img {
  box-shadow: none;
  border: none;
}

.article-content figcaption,
.ck-content figcaption {
  margin-top: 0.625rem;
  font-size: 0.8125rem;
  line-height: 1.5;
  color: var(--muted-foreground, oklch(50% 0.01 264));
  text-align: center;
}

.article-content figure.table > figcaption,
.article-content .table > figcaption,
.ck-content figure.table > figcaption,
.ck-content .table > figcaption {
  text-align: left;
  margin-top: 0.5rem;
}

/* Căn lề ảnh: trái/phải cho chữ chạy quanh (desktop) */
.article-content .image-style-align-left,
.article-content .image-style-side,
.ck-content .image-style-align-left,
.ck-content .image-style-side {
  float: left;
  margin-right: 1.5rem;
  max-width: min(45%, 22rem);
}
.article-content .image-style-align-right,
.ck-content .image-style-align-right {
  float: right;
  margin-left: 1.5rem;
  max-width: min(45%, 22rem);
}
.article-content .image-style-align-center,
.ck-content .image-style-align-center {
  margin-inline: auto;
}

/* Ảnh resize thủ công trong CKEditor giữ nguyên % width đã set */
.article-content .image.image_resized,
.ck-content .image.image_resized {
  max-width: 100%;
}
.article-content .image.image_resized > img,
.ck-content .image.image_resized > img {
  width: 100%;
}

/* ============================================================================
 * SECTION 9 — TABLE
 * ============================================================================
 * Markup CKEditor 5: <figure class="table"><table>...</table></figure>
 * Bọc thêm 1 lớp scroll ngang cho mobile mà không phá layout card/shadow.
 */
.article-content figure.table,
.article-content .table,
.ck-content figure.table,
.ck-content .table {
  margin: 0;
  width: 100%;
  overflow-x: auto;
  border-radius: var(--article-radius);
  border: 1px solid var(--article-table-border);
  box-shadow: var(--article-shadow-sm);
  -webkit-overflow-scrolling: touch;
}

.article-content table,
.ck-content table {
  width: 100%;
  min-width: 100%;
  border-collapse: separate;
  border-spacing: 0;
  font-size: 0.9375rem;
  line-height: 1.5;
}

.article-content caption,
.ck-content caption {
  caption-side: top;
  padding: 0.75rem 1rem 0;
  font-size: 0.8125rem;
  color: var(--muted-foreground, oklch(50% 0.01 264));
  text-align: left;
}

.article-content thead,
.ck-content thead {
  position: sticky;
  top: 0;
  z-index: 1;
}

.article-content th,
.ck-content th {
  background: var(--article-table-header-bg);
  color: var(--article-table-header-fg);
  font-weight: 600;
  font-size: 0.8125rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  text-align: left;
  white-space: nowrap;
}

.article-content th,
.article-content td,
.ck-content th,
.ck-content td {
  padding: 0.75rem 1rem;
  border-bottom: 1px solid var(--article-table-border);
}

.article-content th:not(:last-child),
.article-content td:not(:last-child),
.ck-content th:not(:last-child),
.ck-content td:not(:last-child) {
  border-right: 1px solid var(--article-table-border);
}

.article-content tbody tr:last-child td,
.ck-content tbody tr:last-child td {
  border-bottom: none;
}

/* Zebra striping */
.article-content tbody tr:nth-child(even),
.ck-content tbody tr:nth-child(even) {
  background: var(--article-table-zebra-bg);
}

/* Hover row */
.article-content tbody tr,
.ck-content tbody tr {
  transition: background-color var(--article-duration-fast) var(--article-ease);
}
.article-content tbody tr:hover,
.ck-content tbody tr:hover {
  background: var(--article-table-hover-bg);
}

/* Bo góc đúng theo khung ngoài figure.table */
.article-content table tr:first-child th:first-child,
.ck-content table tr:first-child th:first-child {
  border-top-left-radius: var(--article-radius);
}
.article-content table tr:first-child th:last-child,
.ck-content table tr:first-child th:last-child {
  border-top-right-radius: var(--article-radius);
}

/* --- 9.1 Table group header — hàng tiêu đề nhóm span hết cột, tô màu theo nhóm ---
   Chia 1 bảng tra cứu dài (lộ trình học, bảng so sánh nhiều nhóm) thành từng
   đoạn có tiêu đề. Đặt trực tiếp trong <tbody>.
   Markup:
     <tr class="table-group table-group--2">
       <td colspan="5"><span class="table-group__badge">GĐ 2</span> Phân số &amp; bước chuyển</td>
     </tr>
   .table-group--1..8 tô nền/viền/badge theo --article-topic-N; không gắn modifier
   thì dùng --primary. Đúc rút từ "lo-trinh-chinh-phuc-toan.css" (ltt-table-phase-head). */
.article-content tr.table-group > td,
.ck-content tr.table-group > td {
  --tg-color: var(--primary, oklch(55% 0.18 265));
  padding: 0.625rem 1rem;
  font-weight: 700;
  font-size: 0.875rem;
  color: var(--tg-color);
  background: color-mix(in oklch, var(--tg-color) 12%, var(--background, white));
  border-top: 2px solid var(--tg-color);
  border-bottom: 1px solid var(--article-table-border);
}
/* Huỷ hover-row + zebra của SECTION 9 cho hàng nhóm */
.article-content tr.table-group:hover > td,
.ck-content tr.table-group:hover > td {
  background: color-mix(in oklch, var(--tg-color) 12%, var(--background, white));
}
.article-content .table-group__badge,
.ck-content .table-group__badge {
  display: inline-block;
  margin-right: 0.5rem;
  padding: 0.0625rem 0.5rem;
  border-radius: var(--article-radius-sm);
  font-size: 0.75rem;
  font-weight: 800;
  letter-spacing: 0.02em;
  color: white;
  background: var(--tg-color);
}
.article-content tr.table-group--1 > td, .ck-content tr.table-group--1 > td { --tg-color: var(--article-topic-1); }
.article-content tr.table-group--2 > td, .ck-content tr.table-group--2 > td { --tg-color: var(--article-topic-2); }
.article-content tr.table-group--3 > td, .ck-content tr.table-group--3 > td { --tg-color: var(--article-topic-3); }
.article-content tr.table-group--4 > td, .ck-content tr.table-group--4 > td { --tg-color: var(--article-topic-4); }
.article-content tr.table-group--5 > td, .ck-content tr.table-group--5 > td { --tg-color: var(--article-topic-5); }
.article-content tr.table-group--6 > td, .ck-content tr.table-group--6 > td { --tg-color: var(--article-topic-6); }
.article-content tr.table-group--7 > td, .ck-content tr.table-group--7 > td { --tg-color: var(--article-topic-7); }
.article-content tr.table-group--8 > td, .ck-content tr.table-group--8 > td { --tg-color: var(--article-topic-8); }

/* ============================================================================
 * SECTION 10 — CODE (inline & block)
 * ============================================================================
 * Markup code block CKEditor 5: <pre><code class="language-js">...</code></pre>
 * Nhãn ngôn ngữ hiển thị qua attr(data-language) nếu BE render kèm thuộc tính
 * đó (khuyến nghị), hoặc attr(class) làm phương án dự phòng (SECTION dưới).
 */
.article-content code,
.ck-content code {
  font-family: var(--article-font-mono);
  font-size: 0.875em;
  font-variant-ligatures: none;
}

/* Inline code — không nằm trong <pre> */
.article-content :not(pre) > code,
.ck-content :not(pre) > code {
  background: var(--article-code-inline-bg);
  color: var(--article-code-inline-fg);
  padding: 0.15em 0.4em;
  border-radius: 0.3125rem;
  font-weight: 500;
  word-break: break-word;
}

.article-content pre,
.ck-content pre {
  position: relative;
  margin: 0;
  padding: 1.125rem 1.25rem;
  background: var(--article-code-bg);
  color: var(--article-code-fg);
  border: 1px solid var(--article-code-border);
  border-radius: var(--article-radius);
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  tab-size: 2;
}

.article-content pre > code,
.ck-content pre > code {
  display: block;
  background: transparent;
  padding: 0;
  font-size: 0.875rem;
  line-height: 1.65;
  white-space: pre;
}

/* Nhãn ngôn ngữ góc phải trên — ưu tiên data-language, dự phòng bằng class
   "language-xxx" (sẽ hiện nguyên cả class nếu không có data-language, do CSS
   thuần không cắt được tiền tố "language-" khỏi attr()). */
.article-content pre > code[class*='language-']::before,
.ck-content pre > code[class*='language-']::before {
  content: attr(class);
  position: absolute;
  top: 0.625rem;
  right: 0.875rem;
  font-family: var(--article-font-sans);
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--muted-foreground, oklch(50% 0.01 264));
  opacity: 0.7;
  pointer-events: none;
}
.article-content pre[data-language]::before,
.article-content pre > code[data-language]::before,
.ck-content pre[data-language]::before,
.ck-content pre > code[data-language]::before {
  content: attr(data-language);
}

/* Optional: tương thích sẵn với token class của Prism.js / Shiki nếu sau này
   tích hợp syntax highlighting theo màu — không bắt buộc phải dùng. */
.article-content .token.comment,
.article-content .token.prolog,
.article-content .token.doctype,
.article-content .token.cdata,
.ck-content .token.comment,
.ck-content .token.prolog,
.ck-content .token.doctype,
.ck-content .token.cdata {
  color: var(--muted-foreground, oklch(50% 0.01 264));
  font-style: italic;
}
.article-content .token.string,
.article-content .token.attr-value,
.ck-content .token.string,
.ck-content .token.attr-value {
  color: oklch(58% 0.14 150);
}
.article-content .token.keyword,
.article-content .token.selector,
.ck-content .token.keyword,
.ck-content .token.selector {
  color: oklch(56% 0.19 305);
}
.article-content .token.function,
.article-content .token.class-name,
.ck-content .token.function,
.ck-content .token.class-name {
  color: oklch(55% 0.17 260);
}
.article-content .token.number,
.article-content .token.boolean,
.ck-content .token.number,
.ck-content .token.boolean {
  color: oklch(60% 0.16 55);
}

/* ============================================================================
 * SECTION 11 — HORIZONTAL RULE
 * ============================================================================
 */
.article-content hr,
.ck-content hr {
  border: none;
  height: 1px;
  margin: 2.5em auto;
  width: 100%;
  background: linear-gradient(to right, transparent, var(--border, oklch(90% 0.005 264)) 20%, var(--border, oklch(90% 0.005 264)) 80%, transparent);
}

/* ============================================================================
 * SECTION 12 — CALLOUT
 * ============================================================================
 * Markup mong đợi (do plugin GHS tuỳ chỉnh chèn vào nội dung):
 *   <div class="callout callout-info">
 *     <p class="callout-title">Tiêu đề</p>
 *     <div class="callout-body"><p>Nội dung...</p></div>
 *   </div>
 * Icon hiển thị qua ::before trên .callout-title (glyph Unicode, không phụ
 * thuộc icon font/thư viện ngoài — giữ file hoàn toàn tự chứa).
 */
.article-content .callout,
.ck-content .callout {
  padding: 1rem 1.25rem;
  border-radius: var(--article-radius);
  border: 1px solid;
  border-left-width: 4px;
}

.article-content .callout > * + *,
.ck-content .callout > * + * {
  margin-top: 0.5em;
}

.article-content .callout-title,
.ck-content .callout-title {
  margin: 0;
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-weight: 700;
  font-size: 0.9375rem;
}

.article-content .callout-title::before,
.ck-content .callout-title::before {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: 1.375rem;
  height: 1.375rem;
  border-radius: 9999px;
  font-size: 0.75rem;
  font-weight: 800;
  line-height: 1;
}

.article-content .callout-body,
.ck-content .callout-body {
  font-size: 0.9375rem;
  line-height: 1.65;
}
.article-content .callout-body > p,
.ck-content .callout-body > p {
  margin: 0;
}
.article-content .callout-body > * + *,
.ck-content .callout-body > * + * {
  margin-top: 0.6em;
}

/* --- 10 biến thể màu, dùng chung khung ở trên --- */
.article-content .callout-info,
.ck-content .callout-info {
  background: var(--callout-info-bg);
  border-color: var(--callout-info-border);
}
.article-content .callout-info .callout-title::before,
.ck-content .callout-info .callout-title::before {
  content: 'i';
  background: var(--callout-info-icon);
  color: var(--callout-info-bg);
  font-style: italic;
  font-family: Georgia, serif;
}

.article-content .callout-warning,
.ck-content .callout-warning {
  background: var(--callout-warning-bg);
  border-color: var(--callout-warning-border);
}
.article-content .callout-warning .callout-title::before,
.ck-content .callout-warning .callout-title::before {
  content: '!';
  background: var(--callout-warning-icon);
  color: var(--callout-warning-bg);
}

.article-content .callout-success,
.ck-content .callout-success {
  background: var(--callout-success-bg);
  border-color: var(--callout-success-border);
  border-style: dashed;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.375rem 0.5rem;
}
.article-content .callout-success > .callout-title,
.article-content .callout-success > .callout-body,
.ck-content .callout-success > .callout-title,
.ck-content .callout-success > .callout-body {
  margin-top: 0;
}
.article-content .callout-success > .callout-body,
.ck-content .callout-success > .callout-body {
  flex: 1 1 auto;
  min-width: 0;
}
.article-content .callout-success .callout-title::before,
.ck-content .callout-success .callout-title::before {
  content: '\2713';
  background: var(--callout-success-icon);
  color: var(--callout-success-bg);
}

.article-content .callout-danger,
.ck-content .callout-danger {
  background: var(--callout-danger-bg);
  border-color: var(--callout-danger-border);
}
.article-content .callout-danger .callout-title::before,
.ck-content .callout-danger .callout-title::before {
  content: '\2715';
  background: var(--callout-danger-icon);
  color: var(--callout-danger-bg);
}

.article-content .callout-tip,
.ck-content .callout-tip {
  background: var(--callout-tip-bg);
  border-color: var(--callout-tip-border);
}
.article-content .callout-tip .callout-title::before,
.ck-content .callout-tip .callout-title::before {
  content: '\2726';
  background: var(--callout-tip-icon);
  color: var(--callout-tip-bg);
  font-size: 0.6875rem;
}

.article-content .callout-note,
.ck-content .callout-note {
  background: var(--callout-note-bg);
  border-color: var(--callout-note-border);
}
.article-content .callout-note .callout-title::before,
.ck-content .callout-note .callout-title::before {
  content: '\270E';
  background: var(--callout-note-icon);
  color: var(--callout-note-bg);
  font-size: 0.6875rem;
}

/* callout-example dùng cho khối "Ví dụ" bọc quanh .steps + nội dung dài — viền trái 4px
   đậm (kế thừa từ .callout dùng chung cho mọi loại callout/alert) khiến khối ví dụ nổi bật
   hơn cả khối nội dung chính bao ngoài nó, phản tác dụng (ví dụ chỉ nên là 1 khối phụ minh
   hoạ). Trả về viền đều 1px như 3 cạnh còn lại — riêng cho callout-example, các loại callout
   khác (success/warning/note/definition...) vẫn giữ nguyên viền trái 4px làm dấu hiệu phân
   loại nhanh theo màu. */
.article-content .callout-example,
.ck-content .callout-example {
  border-color: var(--callout-example-border);
  border-left-width: 1px;
}
/* Icon "sổ tay + cây bút" (Lucide notebook-pen) đứng trần, không khung/nền tròn bọc ngoài
   như 6 biến thể callout còn lại — cùng kỹ thuật CSS mask với .problem-type__title::before
   (SECTION 21.6): background-color chính là màu ICON qua mask, không phải khung nền phía sau. */
.article-content .callout-example .callout-title::before,
.ck-content .callout-example .callout-title::before {
  content: '';
  border-radius: 0;
  background: var(--callout-example-icon);
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M13.4 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-7.4'/%3E%3Cpath d='M2 6h4'/%3E%3Cpath d='M2 10h4'/%3E%3Cpath d='M2 14h4'/%3E%3Cpath d='M2 18h4'/%3E%3Cpath d='M21.378 5.626a1 1 0 1 0-3.004-3.004l-5.01 5.012a2 2 0 0 0-.506.854l-.837 2.87a.5.5 0 0 0 .62.62l2.87-.837a2 2 0 0 0 .854-.506z'/%3E%3C/svg%3E");
  mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M13.4 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-7.4'/%3E%3Cpath d='M2 6h4'/%3E%3Cpath d='M2 10h4'/%3E%3Cpath d='M2 14h4'/%3E%3Cpath d='M2 18h4'/%3E%3Cpath d='M21.378 5.626a1 1 0 1 0-3.004-3.004l-5.01 5.012a2 2 0 0 0-.506.854l-.837 2.87a.5.5 0 0 0 .62.62l2.87-.837a2 2 0 0 0 .854-.506z'/%3E%3C/svg%3E");
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  -webkit-mask-position: center;
  mask-position: center;
  -webkit-mask-size: contain;
  mask-size: contain;
}

/* Ảnh trong callout-example (ảnh chụp phép tính đặt cột dọc, sơ đồ minh hoạ...) canh trái thay
   vì canh giữa mặc định của SECTION 8 — ảnh loại này thường cần đọc liền mạch với đoạn văn phía
   trên/dưới (hay bắt đầu bằng "a)"/"b)" ở lề trái), canh giữa làm ảnh trôi nổi lệch khỏi mạch đọc.
   padding-inline đặt trên figure (không đặt trên chính img) để không phá box viền/shadow của
   img ở SECTION 8 — img vẫn giữ margin-inline:0 để bám sát mép trái của vùng padding này. */
.article-content .callout-example figure.image,
.article-content .callout-example .image,
.ck-content .callout-example figure.image,
.ck-content .callout-example .image {
  text-align: left;
  padding-inline: 2rem;
}
.article-content .callout-example figure.image > img,
.article-content .callout-example .image > img,
.ck-content .callout-example figure.image > img,
.ck-content .callout-example .image > img {
  margin-inline: 0;
}

/* --- Cấu trúc nội bộ callout-example: câu hỏi / lời giải / đáp số ---
   Mặc định .callout-body chỉ có <p> trơn nên đề bài, các bước giải và đáp số
   trộn lẫn thị giác, chỉ phân biệt bằng vài chữ đậm "Lời giải:"/"Đáp số:" lẫn
   trong dòng — học sinh phải đọc hết mới biết đang ở phần nào. 3 lớp dưới đây
   tách rõ 3 vai trò, tái dùng đúng token --callout-example-* đã có sẵn để
   không lệch tông với khung "Ex" bao ngoài.
   Markup:
     <div class="callout-example__prompt"><p>Đề bài...</p></div>
     <p class="callout-solution-label">Lời giải:</p>  (hoặc "Hướng giải:")
     ...các bước giải (giữ <p> thường, "Cách 1:"/"Cách 2:" vẫn chỉ cần <strong>)...
     <p class="callout-answer">Đáp số: <strong>...</strong></p> */

/* Đề bài — đóng khung nền trắng/card nổi lên trên nền teal nhạt của
   callout-example, viền trái đậm màu icon để nhận ra ngay "đây là câu hỏi",
   tách bạch khỏi phần lời giải chảy tự do ngay bên dưới. */
.article-content .callout-example__prompt,
.ck-content .callout-example__prompt {
  padding: 0.75rem 1rem;
  background: var(--card, var(--background, oklch(100% 0 0)));
  border-left: 3px solid var(--callout-example-icon);
  border-radius: 0 var(--article-radius) var(--article-radius) 0;
  font-weight: 600;
}
.article-content .callout-example__prompt > * + *,
.ck-content .callout-example__prompt > * + * {
  margin-top: 0.5em;
}

/* Nhãn "Lời giải:"/"Hướng giải:" — vạch chia cùng ngôn ngữ thị giác với
   .callout-subhead (21.3b/21.6b: uppercase + letter-spacing + viền nét đứt
   phía trên) nhưng tô theo --callout-example-icon để khớp tông teal của
   khối Ví dụ thay vì màu primary/definition. Selector cố tình có ".callout-body"
   (không chỉ ".callout-solution-label") để chắc chắn thắng ".callout-body > * + *"
   (SECTION 12, cùng 2 class) bất kể thứ tự khai báo — tái dùng đúng kỹ thuật
   đã ghi chú ở .callout-subhead phía trên. */
.article-content .callout-body .callout-solution-label,
.ck-content .callout-body .callout-solution-label {
  margin-top: 1rem;
  padding-top: 0.75rem;
  border-top: 1px dashed var(--callout-example-border);
  font-size: 0.75rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--callout-example-icon);
}

/* Đáp số — khung viền nét đứt cuối ví dụ (KHÔNG tô nền đặc, chỉ outline —
   để nhẹ mắt hơn kiểu chip nền đặc, vẫn nổi nhờ viền + dấu tích tròn đặc).
   Dùng token --callout-success-* (xanh lá, KHÔNG dùng --callout-example-icon
   như trước) — đáp số là 1 tín hiệu "kết quả đúng" riêng biệt, cần tách khỏi
   tông indigo của khung "Ví dụ" bao ngoài để không bị hiểu nhầm là cùng 1
   loại nhấn mạnh (phản hồi người dùng thật: đổi --callout-example-icon sang
   indigo trước đó vô tình kéo theo màu Đáp số đổi theo). Dấu tích tái dùng
   đúng glyph đã có ở .callout-success. */
.article-content .callout-body .callout-answer,
.ck-content .callout-body .callout-answer {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-top: 1rem;
  padding: 0.625rem 1rem;
  background: none;
  border: 1px dashed var(--callout-success-icon);
  border-radius: var(--article-radius);
  color: var(--callout-success-icon);
  font-weight: 700;
}
.article-content .callout-answer::before,
.ck-content .callout-answer::before {
  content: '\2713';
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: 1.25rem;
  height: 1.25rem;
  border-radius: 9999px;
  background: var(--callout-success-icon);
  color: var(--callout-success-bg);
  font-size: 0.6875rem;
  font-weight: 800;
}

.article-content .callout-question,
.ck-content .callout-question {
  background: var(--callout-question-bg);
  border-color: var(--callout-question-border);
}
.article-content .callout-question .callout-title::before,
.ck-content .callout-question .callout-title::before {
  content: '?';
  background: var(--callout-question-icon);
  color: var(--callout-question-bg);
}

.article-content .callout-homework,
.ck-content .callout-homework {
  background: var(--callout-homework-bg);
  border-color: var(--callout-homework-border);
}
.article-content .callout-homework .callout-title::before,
.ck-content .callout-homework .callout-title::before {
  content: '\25A4';
  background: var(--callout-homework-icon);
  color: var(--callout-homework-bg);
  font-size: 0.6875rem;
}

.article-content .callout-summary,
.ck-content .callout-summary {
  background: var(--callout-summary-bg);
  border-color: var(--callout-summary-border);
}
.article-content .callout-summary .callout-title::before,
.ck-content .callout-summary .callout-title::before {
  content: '\2261';
  background: var(--callout-summary-icon);
  color: var(--callout-summary-bg);
}

/* ============================================================================
 * SECTION 13 — ALERT (đồng bộ ngôn ngữ thị giác với shadcn/ui Alert)
 * ============================================================================
 * Markup: <div class="alert" role="alert"><p class="alert-title">..</p>
 *           <div class="alert-description">..</div></div>
 *         <div class="alert alert-destructive" role="alert">...</div>
 * Dùng đúng token --destructive/--border/--foreground của shadcn — khác
 * callout ở chỗ trung tính hơn (dành cho cảnh báo hệ thống, không phải chú
 * thích sư phạm) và chỉ có 2 biến thể mặc định/destructive giống component
 * gốc của shadcn/ui.
 */
.article-content .alert,
.ck-content .alert {
  display: flex;
  /* flex-wrap/overflow-x — lưới an toàn giống bảng (SECTION bảng ở trên): markup chuẩn chỉ có
   * đúng 2 con (.alert-title + .alert-description), nhưng nội dung lý thuyết CŨ (trước khi có
   * convention GHS .alert này) từng dùng lại đúng class "alert alert-primary" cho mục đích khác
   * hẳn (tô nền Bootstrap, khối chứa TỰ DO nhiều thẻ con — h/p/ul...). Với nội dung cũ đó,
   * flex-wrap:nowrap mặc định ép toàn bộ chục thẻ con vào 1 hàng ngang duy nhất, đẩy tràn ngang
   * cả trang (bug thật gặp ở bài lý thuyết "Bài Toán Liên Quan Tới Tỉ Số Phần Trăm"). Không đổi
   * gì với alert 2-con đúng chuẩn (không có gì để wrap/scroll).
   */
  flex-wrap: wrap;
  overflow-x: auto;
  gap: 0.75rem;
  padding: 1rem;
  border: 1px solid var(--border, oklch(90% 0.005 264));
  border-radius: var(--article-radius);
  background: var(--card, var(--background, oklch(100% 0 0)));
  font-size: 0.9375rem;
}

.article-content .alert-title,
.ck-content .alert-title {
  margin: 0;
  font-weight: 600;
  color: var(--foreground, oklch(21% 0.006 264));
}

.article-content .alert-description,
.ck-content .alert-description {
  margin-top: 0.25rem;
  color: var(--muted-foreground, oklch(50% 0.01 264));
  line-height: 1.6;
}
.article-content .alert-description > p,
.ck-content .alert-description > p {
  margin: 0;
}

.article-content .alert-destructive,
.ck-content .alert-destructive {
  border-color: color-mix(in oklch, var(--destructive, oklch(58% 0.22 27)) 40%, var(--border, oklch(90% 0.005 264)));
  background: color-mix(in oklch, var(--destructive, oklch(58% 0.22 27)) 8%, var(--background, oklch(100% 0 0)));
  color: var(--destructive, oklch(58% 0.22 27));
}
.article-content .alert-destructive .alert-title,
.ck-content .alert-destructive .alert-title {
  color: var(--destructive, oklch(58% 0.22 27));
}
.article-content .alert-destructive .alert-description,
.ck-content .alert-destructive .alert-description {
  color: color-mix(in oklch, var(--destructive, oklch(58% 0.22 27)) 70%, var(--foreground, oklch(21% 0.006 264)));
}

/* ============================================================================
 * SECTION 14 — BADGE
 * ============================================================================
 */
.article-content .badge,
.ck-content .badge {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  padding: 0.125rem 0.625rem;
  border-radius: 9999px;
  font-size: 0.75rem;
  font-weight: 600;
  line-height: 1.6;
  letter-spacing: 0.01em;
  border: 1px solid transparent;
  background: var(--secondary, var(--muted, oklch(96% 0.003 264)));
  color: var(--secondary-foreground, var(--foreground, oklch(21% 0.006 264)));
  vertical-align: middle;
}

.article-content .badge-outline,
.ck-content .badge-outline {
  background: transparent;
  border-color: var(--border, oklch(90% 0.005 264));
  color: var(--foreground, oklch(21% 0.006 264));
}

.article-content .badge-primary,
.ck-content .badge-primary {
  background: var(--primary, oklch(55% 0.18 265));
  color: var(--primary-foreground, oklch(98% 0.01 265));
}

.article-content .badge-success,
.ck-content .badge-success {
  background: var(--callout-success-bg);
  color: var(--callout-success-icon);
  border-color: var(--callout-success-border);
}

.article-content .badge-warning,
.ck-content .badge-warning {
  background: var(--callout-warning-bg);
  color: var(--callout-warning-icon);
  border-color: var(--callout-warning-border);
}

.article-content .badge-danger,
.ck-content .badge-danger {
  background: var(--callout-danger-bg);
  color: var(--callout-danger-icon);
  border-color: var(--callout-danger-border);
}

/* ============================================================================
 * SECTION 15 — TABLE OF CONTENTS
 * ============================================================================
 * Markup gợi ý:
 *   <nav class="toc">
 *     <p class="toc-title">Mục lục</p>
 *     <ol class="toc-list">
 *       <li class="toc-item toc-level-2"><a href="#slug">Tiêu đề</a></li>
 *     </ol>
 *   </nav>
 * `.toc-item.is-active` dùng cho scroll-spy (đánh dấu mục đang xem, xử lý ở JS).
 */
.article-content .toc,
.ck-content .toc {
  font-size: 0.875rem;
  padding: 1.125rem 1.25rem;
  border: 1px solid var(--border, oklch(90% 0.005 264));
  border-radius: var(--article-radius);
  background: var(--card, var(--muted, oklch(96% 0.003 264)));
}

.article-content .toc-title,
.ck-content .toc-title {
  margin: 0 0 0.625rem;
  font-size: 0.75rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--muted-foreground, oklch(50% 0.01 264));
}

.article-content .toc-list,
.ck-content .toc-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  border-left: 1px solid var(--border, oklch(90% 0.005 264));
}

.article-content .toc-item,
.ck-content .toc-item {
  padding: 0;
  margin: 0;
}

.article-content .toc-item a,
.ck-content .toc-item a {
  display: block;
  padding-left: 0.875rem;
  margin-left: -1px;
  border-left: 2px solid transparent;
  color: var(--muted-foreground, oklch(50% 0.01 264));
  background-image: none;
  font-weight: 500;
  line-height: 1.5;
  transition:
    color var(--article-duration-fast) var(--article-ease),
    border-color var(--article-duration-fast) var(--article-ease);
}

.article-content .toc-item a:hover,
.ck-content .toc-item a:hover {
  color: var(--foreground, oklch(21% 0.006 264));
}

.article-content .toc-item.is-active > a,
.article-content .toc-item a.is-active,
.ck-content .toc-item.is-active > a,
.ck-content .toc-item a.is-active {
  color: var(--primary, oklch(55% 0.18 265));
  border-left-color: var(--primary, oklch(55% 0.18 265));
  font-weight: 600;
}

.article-content .toc-level-3 a,
.ck-content .toc-level-3 a {
  padding-left: 1.75rem;
  font-size: 0.8125rem;
}
.article-content .toc-level-4 a,
.ck-content .toc-level-4 a {
  padding-left: 2.625rem;
  font-size: 0.8125rem;
}

/* TOC dính khi dùng làm sidebar (opt-in — chỉ có hiệu lực nếu component cha
   có đủ chiều cao để sticky hoạt động) */
.article-content .toc--sticky,
.ck-content .toc--sticky {
  position: sticky;
  top: var(--article-scroll-offset);
  max-height: calc(100vh - var(--article-scroll-offset) - 2rem);
  overflow-y: auto;
}

/* ============================================================================
 * SECTION 16 — EMBED / IFRAME / YOUTUBE / VIDEO
 * ============================================================================
 * Markup CKEditor 5 MediaEmbed: <figure class="media"><div data-oembed-url="...">
 *   <iframe ...></iframe></div></figure>
 */
.article-content figure.media,
.article-content .media,
.ck-content figure.media,
.ck-content .media {
  margin: 0;
}

.article-content figure.media > div,
.article-content .media > div,
.article-content .video-wrapper,
.ck-content figure.media > div,
.ck-content .media > div,
.ck-content .video-wrapper {
  position: relative;
  aspect-ratio: 16 / 9;
  border-radius: var(--article-radius);
  overflow: hidden;
  background: var(--muted, oklch(96% 0.003 264));
  box-shadow: var(--article-shadow);
}

.article-content figure.media iframe,
.article-content .media iframe,
.article-content .video-wrapper iframe,
.ck-content figure.media iframe,
.ck-content .media iframe,
.ck-content .video-wrapper iframe {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
}

.article-content video,
.ck-content video {
  display: block;
  max-width: 100%;
  border-radius: var(--article-radius);
  box-shadow: var(--article-shadow);
  background: black;
}

.article-content audio,
.ck-content audio {
  display: block;
  width: 100%;
}

.article-content video,
.article-content audio,
.ck-content video,
.ck-content audio {
  accent-color: var(--primary, oklch(55% 0.18 265));
}

/* ============================================================================
 * SECTION 17 — SELECTION & ACCESSIBILITY
 * ============================================================================
 * Contrast tối thiểu AA đã đảm bảo qua lựa chọn L/C ở SECTION 1 (fg luôn
 * ≥ 4.5:1 so với bg tương ứng của từng callout/alert) — mọi callout đều có
 * icon + tiêu đề chữ đi kèm màu, không chỉ dựa vào màu làm tín hiệu duy nhất.
 */
.article-content ::selection,
.ck-content ::selection {
  background: color-mix(in oklch, var(--primary, oklch(55% 0.18 265)) 25%, transparent);
  color: var(--foreground, oklch(21% 0.006 264));
}

.article-content a:focus-visible,
.article-content button:focus-visible,
.article-content [tabindex]:focus-visible,
.article-content input:focus-visible,
.ck-content a:focus-visible,
.ck-content button:focus-visible,
.ck-content [tabindex]:focus-visible,
.ck-content input:focus-visible {
  outline: 2px solid var(--ring, var(--primary, oklch(55% 0.18 265)));
  outline-offset: 2px;
  border-radius: 2px;
}

/* ============================================================================
 * SECTION 18 — REDUCED MOTION
 * ============================================================================
 */
@media (prefers-reduced-motion: reduce) {
  .article-content *,
  .ck-content * {
    transition-duration: 0.01ms !important;
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
  }
}
/* Ngoại lệ hợp lệ duy nhất cho !important trong toàn bộ file: tắt animation
   là yêu cầu accessibility bắt buộc (WCAG 2.3.3), phải thắng mọi transition
   khác bất kể specificity. */

/* ============================================================================
 * SECTION 19 — RESPONSIVE (Tablet & Mobile)
 * ============================================================================
 */
@media (max-width: 768px) {
  .article-content,
  .ck-content {
    --article-gutter: 1rem;
    font-size: 1rem;
    line-height: 1.7;
  }

  .article-content h1,
  .ck-content h1 {
    font-size: 1.875rem;
  }
  .article-content h2,
  .ck-content h2 {
    font-size: 1.5rem;
  }
  .article-content h3,
  .ck-content h3 {
    font-size: 1.25rem;
  }
  .article-content h4,
  .ck-content h4 {
    font-size: 1.0625rem;
  }

  .article-content blockquote,
  .ck-content blockquote {
    padding: 1rem 1rem 1rem 2.5rem;
  }
  .article-content blockquote::before,
  .ck-content blockquote::before {
    left: 0.6rem;
    font-size: 1.75rem;
  }

  /* Ảnh căn lề trái/phải không còn đủ chỗ để chữ chạy quanh trên mobile */
  .article-content .image-style-align-left,
  .article-content .image-style-align-right,
  .article-content .image-style-side,
  .ck-content .image-style-align-left,
  .ck-content .image-style-align-right,
  .ck-content .image-style-side {
    float: none;
    margin-inline: auto;
    max-width: 100%;
  }

  .article-content pre,
  .ck-content pre {
    padding: 1rem;
    font-size: 0.8125rem;
  }

  .article-content table,
  .ck-content table {
    font-size: 0.875rem;
  }
  .article-content th,
  .article-content td,
  .ck-content th,
  .ck-content td {
    padding: 0.625rem 0.75rem;
  }
}

@media (max-width: 480px) {
  .article-content h1,
  .ck-content h1 {
    font-size: 1.625rem;
  }
  .article-content h2,
  .ck-content h2 {
    font-size: 1.3125rem;
  }

  .article-content .callout,
  .article-content .alert,
  .article-content .toc,
  .ck-content .callout,
  .ck-content .alert,
  .ck-content .toc {
    padding: 0.875rem 1rem;
  }
}

/* ============================================================================
 * SECTION 20 — PRINT
 * ============================================================================
 */
@media print {
  .article-content,
  .ck-content {
    max-width: 100%;
    color: black;
    background: white;
    font-size: 12pt;
    line-height: 1.5;
  }

  .article-content a,
  .ck-content a {
    color: black;
    background-image: none;
  }
  .article-content a[href^='http']::after,
  .ck-content a[href^='http']::after {
    content: ' (' attr(href) ')';
    font-size: 0.75em;
    color: #555;
  }

  .article-content pre,
  .ck-content pre,
  .article-content .callout,
  .ck-content .callout,
  .article-content .alert,
  .ck-content .alert,
  .article-content figure.table,
  .ck-content figure.table {
    border: 1px solid #999;
    box-shadow: none;
    break-inside: avoid;
  }

  .article-content h1,
  .article-content h2,
  .article-content h3,
  .ck-content h1,
  .ck-content h2,
  .ck-content h3 {
    break-after: avoid;
  }

  .article-content img,
  .ck-content img,
  .article-content figure,
  .ck-content figure,
  .article-content table,
  .ck-content table {
    break-inside: avoid;
  }

  .article-content .toc--sticky,
  .ck-content .toc--sticky {
    position: static;
  }

  /* Media nhúng (video/iframe) không in được nội dung động — ẩn đi */
  .article-content figure.media,
  .article-content .media,
  .ck-content figure.media,
  .ck-content .media {
    display: none;
  }
}

/* ============================================================================
 * SECTION 21 — LESSON / THEORY EXTENSIONS (bài giảng dạng SGK)
 * ============================================================================
 * Bổ sung cho nội dung dạng "bài giảng lý thuyết" (theory page) — ngoài phạm
 * vi bài viết/blog thông thường đã đủ ở SECTION 1-20: banner tiêu đề đầu bài,
 * tiêu đề mục lớn đánh số, khung định nghĩa, khung công thức, danh sách các
 * bước giải, khối "Dạng bài" bọc ví dụ minh hoạ bên trong.
 *
 * Toàn bộ tái sử dụng token & cơ chế .callout/.badge/.table đã có ở SECTION
 * 1/12/14 — KHÔNG tạo hệ thống màu hay khung riêng song song. Class ở đây là
 * lớp phủ THÊM lên trên các class gốc (vd <div class="callout callout-definition">),
 * không phải class thay thế.
 * ============================================================================
 */
:root {
  /* Accent phụ (hồng/magenta) dùng cho số thứ tự mục lớn & lesson-hero — tách
     khỏi --primary (xanh, dùng cho link/badge/button) để số mục điều hướng có
     nhịp thị giác riêng, không bị lẫn với các yếu tố hành động trên trang. */
  --article-accent: oklch(58% 0.19 350);

  /* Callout biến thể thứ 11: "Định nghĩa" — dùng riêng cho phát biểu định
     nghĩa/định lý chính thức (khác .callout-note là ghi chú phụ, và khác
     .callout-info là thông tin chung). CỐ Ý bám đúng --primary/--chart-4
     (teal thương hiệu, xem app/globals.css) thay vì tự đặt hue riêng — đây là
     khối xuất hiện tần suất cao nhất trong mọi bài học nên cần nhất quán màu
     thương hiệu với CTA/formula/.problem-type thay vì lệch tông. border dùng
     --primary (đậm hơn ở light, nhạt hơn ở dark — vừa đủ nổi làm viền), icon
     dùng --chart-4 (đảo ngược độ đậm/nhạt giữa 2 theme) để chữ luôn đủ tương
     phản đọc trên nền thân (--card, trung tính — xem lý do ở rule
     .callout-definition bên dưới, KHÔNG dùng riêng 1 token bg tint teal như
     10 callout khác vì khối này thường rất dài, tô tint teal cả thân sẽ ngập
     màu). */
  --callout-definition-border: var(--primary, oklch(60% 0.118 185));
  --callout-definition-icon: var(--chart-4, oklch(51% 0.096 186));

  /* Accent vàng/hổ phách riêng cho formula-box — CỐ Ý khác --primary (teal):
     formula-box thường nằm LỒNG bên trong .callout-definition/.problem-type
     (đều đã dùng teal), viền cùng tông sẽ chìm vào nền xung quanh. Ấm (vàng)
     đối lập lạnh (teal) tạo tương phản mạnh, đúng vai trò "công thức cần nổi
     bật nhất trong khối", không lấn màu với bất kỳ callout nào khác (warning
     hue 80, homework hue 50 — chọn 65 nằm giữa, tách biệt cả hai). */
  --article-formula-accent: oklch(64% 0.15 65);
}
.dark {
  --article-accent: oklch(75% 0.14 350);
  --callout-definition-border: var(--chart-4, oklch(60% 0.118 185));
  --callout-definition-icon: var(--primary, oklch(78% 0.152 182));
  --article-formula-accent: oklch(80% 0.13 68);
}

/* --- 21.1 Lesson hero — banner tiêu đề đầu bài giảng ---
   Markup:
     <header class="lesson-hero">
       <p class="lesson-hero__eyebrow">Toán 5 · Chuyển động đều</p>
       <h1>Vận tốc, quãng đường và thời gian</h1>
       <p class="lesson-hero__desc">Mô tả ngắn về bài học...</p>
     </header>
   Là *:first-child của .article-content nên tự ăn rule margin-top:0 ở SECTION 2. */
.article-content .lesson-hero,
.ck-content .lesson-hero {
  padding: 2rem 2rem 1.75rem;
  border-radius: var(--article-radius-lg);
  background: linear-gradient(
    135deg,
    var(--primary, oklch(55% 0.18 265)),
    color-mix(in oklch, var(--primary, oklch(55% 0.18 265)) 65%, var(--article-accent))
  );
  color: var(--primary-foreground, oklch(98% 0.01 265));
  box-shadow: var(--article-shadow-lg);
}
.article-content .lesson-hero > * + *,
.ck-content .lesson-hero > * + * {
  margin-top: 0.5rem;
}
.article-content .lesson-hero__eyebrow,
.ck-content .lesson-hero__eyebrow {
  display: inline-block;
  padding: 0.2rem 0.75rem;
  border-radius: 9999px;
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  background: oklch(100% 0 0 / 0.16);
}
.article-content .lesson-hero h1,
.ck-content .lesson-hero h1 {
  margin: 0;
  color: inherit;
  font-size: 2rem;
  text-wrap: balance;
}
.article-content .lesson-hero__desc,
.ck-content .lesson-hero__desc {
  color: oklch(100% 0 0 / 0.85);
  font-size: 1.0625rem;
  max-width: 42rem;
}

/* --- 21.2 Section heading — mục lớn đánh số kiểu SGK ("1", "2" trong vòng tròn) ---
   Markup: <h2 class="section-heading"><span class="section-num">1</span>Tiêu đề</h2>
   Số KHÔNG dùng CSS counter tự động — nội dung soạn tay trong CKEditor và
   không phải H2 nào cũng thuộc chuỗi đánh số (vd "Bài tập", "Tổng kết" không
   đánh số), counter tự động sẽ đếm lệch trong trường hợp đó. */
.article-content h2.section-heading,
.ck-content h2.section-heading {
  display: flex;
  align-items: center;
  gap: 0.625rem;
  border-bottom-color: var(--article-accent);
}
.article-content .section-num,
.ck-content .section-num {
  display: inline-flex;
  flex: none;
  align-items: center;
  justify-content: center;
  width: 1.75rem;
  height: 1.75rem;
  border-radius: 9999px;
  background: var(--article-accent);
  color: white;
  font-size: 0.9375rem;
  font-weight: 800;
}

/* --- 21.3 Callout "Định nghĩa" — biến thể thứ 11, dùng chung khung
   .callout/.callout-title/.callout-body của SECTION 12 nhưng phủ thêm bố cục
   "thẻ có header" (header dải màu riêng + icon nổi khối) để tách hẳn khỏi
   10 callout phẳng còn lại — dành riêng cho phát biểu định nghĩa/lý thuyết
   chính thức, đặt đầu mỗi khối kiến thức nên cần trọng lượng thị giác cao hơn. */
.article-content .callout-definition,
.ck-content .callout-definition {
  padding: 0;
  border-width: 1.5px;
  border-color: var(--callout-definition-border);
  border-radius: var(--article-radius-lg);
  /* Nền THÂN dùng trắng/card trung tính, KHÔNG dùng --callout-definition-bg
     (tint teal) — khối này thường rất dài (B1-B4, Chú ý, Ghi chú...), cùng 1
     mức bão hoà như callout ngắn khác nhưng trải trên diện tích lớn sẽ tạo
     cảm giác "ngập màu primary". Teal chỉ tập trung ở header (dải cố định,
     không phình theo nội dung) + viền + icon là đủ nhận diện thương hiệu. */
  background: var(--card, var(--background, oklch(100% 0 0)));
  box-shadow: var(--article-shadow);
  overflow: hidden;
}
.article-content .callout-definition > * + *,
.ck-content .callout-definition > * + * {
  margin-top: 0;
}

/* Header: dải nền riêng, bo góc trên khớp khung ngoài, có viền dưới phân
   tách rõ với phần nội dung — thay cho hàng tiêu đề phẳng dùng chung. */
.article-content .callout-definition .callout-title,
.ck-content .callout-definition .callout-title {
  gap: 0.75rem;
  padding: 1rem 1.375rem;
  border-bottom: 1.5px solid var(--callout-definition-border);
  background: linear-gradient(135deg, color-mix(in oklch, var(--callout-definition-icon) 14%, transparent), color-mix(in oklch, var(--callout-definition-icon) 5%, transparent));
  font-size: 1.0625rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--callout-definition-icon);
}
.article-content .callout-definition .callout-body,
.ck-content .callout-definition .callout-body {
  padding: 1.125rem 1.375rem 1.375rem;
}

/* Icon: glyph sách mở đứng trần (không khung/nền bọc ngoài) — tô màu qua kỹ
   thuật CSS mask (background-color đổ vào phần alpha của SVG) nên to, sắc nét
   và nổi bật ngay trên nền header, không cần hộp màu phía sau. SVG inline tự
   chứa, không phụ thuộc icon font ngoài, gợi đúng ngữ cảnh "lý thuyết/định nghĩa". */
.article-content .callout-definition .callout-title::before,
.ck-content .callout-definition .callout-title::before {
  content: '';
  width: 1.875rem;
  height: 1.875rem;
  border-radius: 0;
  background-color: var(--callout-definition-icon);
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z'/%3E%3Cpath d='M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z'/%3E%3C/svg%3E");
  mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z'/%3E%3Cpath d='M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z'/%3E%3C/svg%3E");
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  -webkit-mask-position: center;
  mask-position: center;
  -webkit-mask-size: contain;
  mask-size: contain;
}

/* --- 21.3b Callout subhead — nhãn mục con bên trong 1 callout dài (vd "Chú
   ý", "Ghi chú" nằm chung khối .callout-definition với "Cách giải tổng quát")
   --- Markup: <p class="callout-subhead">Chú ý</p> đặt ngay trước nội dung
   mục con. Viền trên phân tách rõ với mục phía trước; mục ĐẦU TIÊN trong body
   không cần viền/khoảng đệm riêng vì đã có border-bottom của header lo việc
   đó rồi. Hiện chỉ định nghĩa màu cho ngữ cảnh .callout-definition — cần dùng
   trong callout khác thì bổ sung thêm rule màu tương ứng khi phát sinh. */
.article-content .callout-body .callout-subhead,
.ck-content .callout-body .callout-subhead {
  /* Selector cố tình thêm ".callout-body" (không chỉ ".callout-subhead") để đủ
     specificity (3 class) thắng ".callout-body > p" (SECTION 12, 2 class + 1
     type = specificity cao hơn 2 class suông) — subhead luôn là 1 thẻ <p>, nên
     nếu chỉ viết ".callout-subhead" (2 class) thì rule margin:0 dành cho <p>
     thường trong callout-body sẽ thắng, xoá mất margin-top khai báo ở đây dù
     khai báo sau (bug thật đã gặp — margin-top tưởng đã set 1.5rem nhưng
     getComputedStyle vẫn trả 0px, viền nét đứt dính sát dòng cuối đoạn trước). */
  margin: 1.5rem 0 0;
  padding-top: 1rem;
  border-top: 1px dashed var(--callout-definition-border);
  font-size: 0.8125rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--callout-definition-icon);
}
.article-content .callout-definition .callout-body > .callout-subhead:first-child,
.ck-content .callout-definition .callout-body > .callout-subhead:first-child {
  margin-top: 0;
  padding-top: 0;
  border-top: none;
}

/* --- 21.4 Formula box — khung công thức nổi bật, căn giữa ---
   Markup:
     <div class="formula-box">
       <p class="formula">v&nbsp;=&nbsp;s&nbsp;:&nbsp;t</p>
       <p class="formula-legend">v: vận tốc — s: quãng đường — t: thời gian</p>
     </div> */
.article-content .formula-box,
.ck-content .formula-box {
  position: relative;
  width: fit-content;
  max-width: 100%;
  margin-inline: auto;
  padding: 1.5rem 2.25rem;
  text-align: center;
  /* Nền trắng/card THUẦN (không pha gradient tint vàng) — pha màu càng nhiều
     càng ngả xỉn/tối, ngược với mục tiêu "sáng, nổi bật". Độ nổi bật đến từ
     viền đậm + shadow, không phải từ nhuộm nền. */
  background: var(--card, var(--background, oklch(100% 0 0)));
  border: 2px solid var(--article-formula-accent);
  border-radius: var(--article-radius-lg);
  box-shadow: var(--article-shadow);
  overflow: hidden;
}
/* Ký hiệu ∑ mờ nhạt, đặt góc trên-phải làm hoạ tiết nền — báo hiệu "đây là
   công thức" bằng thị giác thay vì nhãn chữ (đã bỏ nhãn "Công thức" theo yêu
   cầu vì trùng lặp với chính công thức) — độ mờ thấp để không cạnh tranh với
   nội dung, overflow:hidden của box cha cắt gọn phần tràn ra ngoài bo góc. */
.article-content .formula-box::before,
.ck-content .formula-box::before {
  content: '\2211';
  position: absolute;
  top: -0.5rem;
  right: 0.5rem;
  font-family: var(--article-font-mono);
  font-size: 4rem;
  font-weight: 700;
  line-height: 1;
  color: color-mix(in oklch, var(--article-formula-accent) 12%, transparent);
  pointer-events: none;
}
.article-content .formula,
.ck-content .formula {
  position: relative;
  margin: 0;
  font-family: var(--article-font-mono);
  font-size: 1.5rem;
  font-weight: 700;
  color: var(--primary, oklch(55% 0.18 265));
  letter-spacing: 0.02em;
}
.article-content .formula-legend,
.ck-content .formula-legend {
  position: relative;
  margin-top: 0.5rem;
  font-size: 0.875rem;
  color: var(--muted-foreground, oklch(50% 0.01 264));
}

/* --- 21.5 Steps — danh sách các bước giải có nhãn "Bước N" ---
   Markup:
     <ol class="steps">
       <li><span class="step-badge">Bước 1</span><div class="step-body"><p>...</p></div></li>
     </ol>
   list-style:none + số viết tay trong span (không dùng ::marker) vì cần bo
   tròn + nền màu cho nhãn — ::marker không style được background/padding.
   Xếp CHỒNG DỌC (badge trên, nội dung full-width dưới) ở MỌI kích thước màn
   hình — trước đây dùng flex-row 2 cột (badge trái, nội dung phải), nhưng vì
   .step-body thường dài hơn nhiều dòng so với badge 1 dòng, hàng flex cao
   bằng .step-body khiến toàn bộ phần còn lại của cột badge bị bỏ trống suốt
   chiều cao khối — 1 dải trắng chạy dọc bên trái rất dễ nhận ra (phản hồi
   người dùng thật, kèm ảnh chụp khoanh đỏ đúng dải trống này). Trên mobile,
   cột badge còn ăn bớt bề rộng cột đọc vốn đã hẹp, đẩy chữ dồn sang phải.
   Xếp chồng loại bỏ hẳn cột trống này ở mọi bề rộng màn hình.

   Đường timeline: mỗi <li> thụt trái 1.25rem (padding-left) — .step-body thừa
   hưởng khoảng thụt này để nội dung tách khỏi mép trái, .step-badge kéo
   ngược lại bằng margin-left âm để vẫn đứng ở mép trái (trên "trục" của
   đường kẻ). Đường đứt nét (::before) đặt trong khoảng thụt đó, bắt đầu từ
   NGAY DƯỚI badge (top: 1.75rem) chạy tới hết <li> — áp dụng cho MỌI <li> kể
   cả bước cuối (line-height của <li> cha là 1.75 — "leading-7" trong
   richContentClassName — nên .step-badge PHẢI tự reset line-height riêng,
   nếu không chiều cao thật của badge ăn theo 1.75rem đó (≈2.375rem) sẽ cao
   hơn mốc top: 1.75rem, khiến đường kẻ cắt ngang qua badge thay vì nằm dưới
   nó — bug thật đã gặp, ảnh chụp cho thấy đường đứt xuyên qua chữ "Bước 1").
   Bước không phải cuối: gap giữa các <li> = 0 (đổi thành padding-bottom trên
   chính <li>) nên line của <li> này CHẠY LIỀN sang tới sát mép trên badge kế
   tiếp — cảm giác 1 đường liền mạch bị các badge "ngắt quãng" tại mỗi bước.
   Bước cuối: padding-bottom = 0 nên line dừng khớp đúng đáy nội dung của
   chính nó — mỗi bước (kể cả bước cuối) đều có 1 đoạn line riêng, không bước
   nào "trơ trọi" thiếu line. */
.article-content ol.steps,
.ck-content ol.steps {
  list-style: none;
  padding-left: 0;
  display: flex;
  flex-direction: column;
  gap: 0;
}
.article-content ol.steps > li,
.ck-content ol.steps > li {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.5rem;
  position: relative;
  padding: 0 0 1.25rem 1.25rem;
  margin-top: 0;
}
.article-content ol.steps > li:last-child,
.ck-content ol.steps > li:last-child {
  padding-bottom: 0;
}
.article-content ol.steps > li::before,
.ck-content ol.steps > li::before {
  content: '';
  position: absolute;
  left: 0.625rem;
  top: 1.75rem;
  bottom: 0;
  border-left: 2px dashed color-mix(in oklch, var(--primary, oklch(55% 0.18 265)) 35%, var(--border, oklch(90% 0.005 264)));
}
.article-content .step-badge,
.ck-content .step-badge {
  flex: none;
  margin-left: -1.25rem;
  padding: 0.25rem 0.75rem;
  border-radius: var(--article-radius-sm);
  background: transparent;
  border: 1px solid var(--primary, oklch(55% 0.18 265));
  color: var(--primary, oklch(55% 0.18 265));
  font-size: 0.8125rem;
  line-height: 1.2;
  font-weight: 700;
  white-space: nowrap;
}
.article-content .step-body,
.ck-content .step-body {
  width: 100%;
}
.article-content .step-body > p,
.ck-content .step-body > p {
  margin: 0;
}

/* .steps lồng trong .callout-example (khối "Ví dụ", xem 21.5b bên dưới) đổi badge + đường
   timeline từ --primary (teal) sang đúng tông indigo của callout-example — tránh 1 thẻ "Ví dụ"
   có 2 màu nhấn cạnh tranh nhau (viền/icon indigo nhưng badge bước lại teal). .steps đứng ĐỘC
   LẬP ngoài callout-example (lý thuyết thường) không bị ảnh hưởng, vẫn giữ teal như cũ — cùng
   tiền lệ đổi màu theo ngữ cảnh đã có ở .flow__step (qua các class .flow--topic-1..8). */
.article-content .callout-example ol.steps > li::before,
.ck-content .callout-example ol.steps > li::before {
  border-left-color: color-mix(in oklch, var(--callout-example-icon) 35%, var(--border, oklch(90% 0.005 264)));
}
.article-content .callout-example .step-badge,
.ck-content .callout-example .step-badge {
  border-color: var(--callout-example-icon);
  color: var(--callout-example-icon);
}

/* --- 21.6 Problem type — khối "Dạng N. ..." bọc ví dụ minh hoạ bên trong ---
   Markup:
     <section class="problem-type">
       <p class="problem-type__title">Dạng 1. Tính vận tốc</p>
       <div class="problem-type__body"><!-- callout-example, steps, formula-box... --></div>
     </section> */
.article-content .problem-type,
.ck-content .problem-type {
  border-radius: var(--article-radius-lg);
  overflow: hidden;
  border: 1px solid color-mix(in oklch, var(--primary, oklch(55% 0.18 265)) 22%, var(--border, oklch(90% 0.005 264)));
  box-shadow: var(--article-shadow-sm);
}
.article-content .problem-type__title,
.ck-content .problem-type__title {
  margin: 0;
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.875rem 1.25rem;
  background: linear-gradient(
    135deg,
    color-mix(in oklch, var(--primary, oklch(55% 0.18 265)) 12%, var(--card, var(--background, oklch(100% 0 0)))),
    color-mix(in oklch, var(--primary, oklch(55% 0.18 265)) 4%, var(--card, var(--background, oklch(100% 0 0))))
  );
  border-bottom: 1px solid color-mix(in oklch, var(--primary, oklch(55% 0.18 265)) 22%, var(--border, oklch(90% 0.005 264)));
  color: var(--primary, oklch(55% 0.18 265));
  font-weight: 700;
  font-size: 1.0625rem;
}
/* Icon: glyph "clipboard danh sách" đứng trần (không khung/nền bọc ngoài) —
   cùng kỹ thuật CSS mask như .callout-definition ở trên — khớp với nội dung
   bên trong thường là các bước giải (B1, B2...) của một ví dụ minh hoạ. */
.article-content .problem-type__title::before,
.ck-content .problem-type__title::before {
  content: '';
  flex: none;
  width: 1.625rem;
  height: 1.625rem;
  border-radius: 0;
  background-color: var(--primary, oklch(55% 0.18 265));
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='8' height='4' x='8' y='2' rx='1' ry='1'/%3E%3Cpath d='M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2'/%3E%3Cpath d='M12 11h4'/%3E%3Cpath d='M12 16h4'/%3E%3Cpath d='M8 11h.01'/%3E%3Cpath d='M8 16h.01'/%3E%3C/svg%3E");
  mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='8' height='4' x='8' y='2' rx='1' ry='1'/%3E%3Cpath d='M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2'/%3E%3Cpath d='M12 11h4'/%3E%3Cpath d='M12 16h4'/%3E%3Cpath d='M8 11h.01'/%3E%3Cpath d='M8 16h.01'/%3E%3C/svg%3E");
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  -webkit-mask-position: center;
  mask-position: center;
  -webkit-mask-size: contain;
  mask-size: contain;
}

.article-content .problem-type__body,
.ck-content .problem-type__body {
  padding: 1.25rem;
  background: var(--card, var(--background, oklch(100% 0 0)));
  display: flex;
  flex-direction: column;
  gap: 1rem;
}
.article-content .problem-type__body > * + *,
.ck-content .problem-type__body > * + * {
  margin-top: 0;
}

/* --- 21.6b Callout subhead dùng trong problem-type__body — cùng markup/mục
   đích với 21.3b (mốc chia mục con trong 1 khối lý thuyết dài, vd "Dãy số
   cách đều:" / "Dãy số có quy luật nhân:" gộp chung 1 "Dạng N") nhưng đổi màu
   theo tông --primary của problem-type thay vì --callout-definition-icon để
   khớp với tiêu đề "Dạng N"/viền card đang toàn xanh dương, và bỏ margin-top
   riêng vì problem-type__body dùng gap làm nguồn khoảng cách duy nhất giữa
   các con (xem "> * + *" ở trên) — nếu giữ margin-top như 21.3b sẽ cộng dồn
   với gap, thừa khoảng trắng. Subhead ở đây chỉ còn lo padding-top+border-top
   để tạo hiệu ứng gạch chia. */
.article-content .problem-type__body .callout-subhead,
.ck-content .problem-type__body .callout-subhead {
  margin-top: 0;
  padding-top: 1rem;
  border-top: 1px dashed color-mix(in oklch, var(--primary, oklch(55% 0.18 265)) 22%, var(--border, oklch(90% 0.005 264)));
  font-size: 0.8125rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--primary, oklch(55% 0.18 265));
}
.article-content .problem-type__body > .callout-subhead:first-child,
.ck-content .problem-type__body > .callout-subhead:first-child {
  padding-top: 0;
  border-top: none;
}

/* --- 21.7 Section divider — đường phân cách có nhãn giữa 2 khối lớn của bài
   (vd Lý thuyết → chuỗi Ví dụ minh hoạ), báo hiệu chuyển từ "học" sang "luyện" ---
   Markup:
     <div class="section-divider"><span class="section-divider__label">Ví dụ minh hoạ</span></div>
   Dùng --article-accent (cùng tông với .section-num) vì đây cũng là mốc phân
   ranh cấp "major section", không phải màu callout thông thường. */
.article-content .section-divider,
.ck-content .section-divider {
  display: flex;
  align-items: center;
  gap: 1rem;
  margin: 0.5rem 0;
}
.article-content .section-divider::before,
.article-content .section-divider::after,
.ck-content .section-divider::before,
.ck-content .section-divider::after {
  content: '';
  flex: 1 1 auto;
  height: 1px;
  background: var(--border, oklch(90% 0.005 264));
}
.article-content .section-divider__label,
.ck-content .section-divider__label {
  flex: none;
  padding: 0.25rem 0.875rem;
  border: 1px solid var(--article-accent);
  border-radius: 9999px;
  color: var(--article-accent);
  font-size: 0.75rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

@media (max-width: 768px) {
  .article-content .lesson-hero,
  .ck-content .lesson-hero {
    padding: 1.5rem 1.25rem;
  }
  .article-content .lesson-hero h1,
  .ck-content .lesson-hero h1 {
    font-size: 1.625rem;
  }
  .article-content .formula,
  .ck-content .formula {
    font-size: 1.125rem;
  }
}

@media print {
  /* Gradient nền tối tốn mực in — thay bằng khung viền đơn giản khi in */
  .article-content .lesson-hero,
  .ck-content .lesson-hero {
    background: none;
    color: black;
    border: 1px solid #999;
    box-shadow: none;
  }
  .article-content .lesson-hero__eyebrow,
  .ck-content .lesson-hero__eyebrow {
    background: none;
    border: 1px solid #999;
  }
  .article-content .problem-type__title,
  .ck-content .problem-type__title {
    background: none;
    color: black;
    border-bottom: 1px solid #999;
  }
}

/* ============================================================================
 * SECTION 22 — RICH CONTENT COMPONENTS (bài giảng nhiều chủ đề con)
 * ============================================================================
 * Đúc rút từ hệ thiết kế "khoa-hoc-chat.css" (dự án tdntest) — dành cho bài
 * giảng có NHIỀU chủ đề con, mỗi chủ đề nhiều thẻ khái niệm (vd "Khoa học về
 * Chất": 7 chủ đề × nhiều thẻ), khác SECTION 21 (dành cho 1 mạch lý thuyết
 * Toán tuyến tính). Tái dùng tối đa token/callout/badge đã có ở SECTION 1/12/14
 * — chỉ thêm 8 màu topic-N cho nhu cầu duy nhất còn thiếu: mã màu theo CHỦ ĐỀ
 * CON (khác mục đích với màu callout, vốn mã hoá theo LOẠI ghi chú).
 * ============================================================================
 */
:root {
  /* 8 màu mã hoá chủ đề con — dùng cho .topic-block__title (nền, chữ trắng)
     và viền trên .concept-card. Độc lập với hệ màu callout ở SECTION 1. */
  --article-topic-1: oklch(52% 0.17 250); /* xanh dương */
  --article-topic-2: oklch(55% 0.13 200); /* cyan */
  --article-topic-3: oklch(55% 0.12 165); /* xanh lá - teal */
  --article-topic-4: oklch(58% 0.15 135); /* xanh lá */
  --article-topic-5: oklch(60% 0.15 70); /* cam */
  --article-topic-6: oklch(55% 0.19 25); /* đỏ */
  --article-topic-7: oklch(50% 0.19 305); /* tím */
  --article-topic-8: oklch(48% 0.13 85); /* nâu vàng, đậm hơn để chữ trắng đủ tương phản */
}

/* --- 22.1 Button — CTA trong nội dung bài viết ---
   Markup: <a class="btn btn-primary" href="#">Nhãn</a>
   Đặc biệt cần override hệ gạch chân slide-in của thẻ <a> ở SECTION 5 — làm
   bằng cách tăng specificity qua 2 class (.article-content .btn-primary) thay
   vì !important: (.article-content a) = (0,1,1) trong khi (.article-content
   .btn-primary) = (0,2,0), tự thắng theo thứ tự specificity chuẩn. */
.article-content .btn,
.ck-content .btn {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.5rem 1.125rem;
  border-radius: var(--article-radius-sm);
  font-weight: 700;
  font-size: 0.9375rem;
  text-decoration: none;
  background-image: none;
  border: 1px solid transparent;
  transition:
    transform var(--article-duration-fast) var(--article-ease),
    background-color var(--article-duration) var(--article-ease),
    border-color var(--article-duration) var(--article-ease);
}
.article-content .btn:hover,
.ck-content .btn:hover {
  background-image: none;
  transform: translateY(-1px);
}
.article-content .btn-primary,
.ck-content .btn-primary {
  background: var(--primary, oklch(55% 0.18 265));
  color: var(--primary-foreground, oklch(98% 0.01 265));
}
.article-content .btn-primary:hover,
.ck-content .btn-primary:hover {
  background: color-mix(in oklch, var(--primary, oklch(55% 0.18 265)) 85%, white);
  color: var(--primary-foreground, oklch(98% 0.01 265));
}
.article-content .btn-secondary,
.ck-content .btn-secondary {
  background: var(--card, var(--background, oklch(100% 0 0)));
  border-color: var(--border, oklch(90% 0.005 264));
  color: var(--foreground, oklch(21% 0.006 264));
  box-shadow: var(--article-shadow-sm);
}
.article-content .btn-secondary:hover,
.ck-content .btn-secondary:hover {
  border-color: var(--primary, oklch(55% 0.18 265));
  color: var(--primary, oklch(55% 0.18 265));
}
/* Biến thể dùng trên nền tối (vd bên trong .cta-banner) */
.article-content .btn-light,
.ck-content .btn-light {
  background: white;
  color: var(--primary, oklch(55% 0.18 265));
}
.article-content .btn-ghost,
.ck-content .btn-ghost {
  background: oklch(100% 0 0 / 0.14);
  border-color: oklch(100% 0 0 / 0.4);
  color: white;
}
.article-content .btn-ghost:hover,
.ck-content .btn-ghost:hover {
  background: oklch(100% 0 0 / 0.22);
  color: white;
}

/* Đã từng bấm nút này (browser đánh dấu :visited) → phải giữ nguyên màu chữ
   như chưa bấm. Không đủ nếu chỉ dựa vào specificity 2 class như comment đầu
   SECTION 22.1 nói — đó là mẹo thắng RULE `.article-content a` (SECTION 5,
   (0,1,1)), còn `.article-content a:visited` (SECTION 5, ngay dưới rule `a`)
   có thêm 1 pseudo-class nên specificity là (0,2,1) — NGANG bằng
   `.article-content .btn-primary` (0,2,0) ở cột class nhưng HƠN ở cột type,
   tức `a:visited` vẫn thắng. Bug thật đã gặp: nút CTA dạng <a> sau khi bấm 1
   lần (browser nhớ lịch sử) đổi màu chữ sang color-mix(primary, muted-
   foreground) xám mờ khó đọc, trong khi Ctrl+Shift+N (incognito, chưa có lịch
   sử duyệt web) vẫn hiện đúng màu trắng — dễ nhầm là lỗi extension/trình
   duyệt nếu không kiểm tra DevTools. Cần thêm 1 class nữa (:visited) để đạt
   (0,3,0), thắng chắc chắn a:visited (0,2,1) bất kể thứ tự khai báo. */
.article-content .btn-primary:visited,
.ck-content .btn-primary:visited {
  color: var(--primary-foreground, oklch(98% 0.01 265));
}
.article-content .btn-secondary:visited,
.ck-content .btn-secondary:visited {
  color: var(--foreground, oklch(21% 0.006 264));
}
.article-content .btn-light:visited,
.ck-content .btn-light:visited {
  color: var(--primary, oklch(55% 0.18 265));
}
.article-content .btn-ghost:visited,
.ck-content .btn-ghost:visited {
  color: white;
}

/* --- 22.2 Concept grid & card — nhiều thẻ khái niệm dưới 1 chủ đề con ---
   Markup:
     <div class="concept-grid concept-grid-3">
       <div class="concept-card topic-1">
         <div class="concept-card__top">
           <h4>Tiêu đề</h4>
           <span class="badge badge-info">Khái niệm</span>
         </div>
         <p>Nội dung...</p>
         <div class="note-inline">...</div>
       </div>
     </div>
   Modifier .topic-1..topic-8 tô viền trên bằng --article-topic-N tương ứng.

   Track tối thiểu 24rem (384px, nâng từ 260px cũ — xem lesson-content-migration
   skill "concept-grid min-width" để biết lý do: 260px chỉ còn ~25 ký tự/dòng sau
   khi trừ padding card, dưới xa ngưỡng đọc thoải mái ~40-45 ký tự/dòng, khiến
   chữ xuống dòng liên tục → card bị kéo cao bất thường → cả hàng grid bị kéo
   theo ô cao nhất → cuộn trang nhiều hơn cần thiết) BỌC trong `max(24rem, ...)`
   để tự chặn trần tối đa 3 cột dù KHÔNG gắn `.concept-grid-3` — vế thứ 2 của
   max() tính đúng 1/3 bề rộng khả dụng (trừ 2 khoảng gap giữa 3 cột); khi màn
   hình đủ rộng để 1/3 đó vượt 24rem, track tối thiểu tự nâng lên đúng bằng 1/3
   bề rộng, khiến 1 cột thứ 4 không bao giờ đủ chỗ để auto-fill sinh thêm — nhờ
   vậy quên gắn `.concept-grid-3` cũng không thể vô tình ra 4+ cột trên màn hình
   rất rộng. Khi màn hình hẹp hơn ngưỡng đó, max() trả về 24rem như bình thường,
   auto-fill tự co xuống 2 rồi 1 cột — không cần dựa vào media query 700px/900px
   bên dưới nữa (những rule đó vẫn giữ nguyên, vô hại vì trùng kết quả).
   24rem (không phải 25rem/400px như thử đầu tiên) vì `.article-content` thực tế
   trên trang bị chặn cứng ở 1232px (kiểm chứng: không đổi dù resize viewport từ
   1600px lên 2200px — có `max-width` Tailwind cố định ở tầng trang, không phải
   biến --article-max-width của riêng file này) — 3 cột × 400px + 2×18px gap =
   1236px đã VƯỢT 1232px nên vẫn bị rớt xuống 2 cột; 384px + 36px = 1188px, dư
   44px an toàn. */
.article-content .concept-grid,
.ck-content .concept-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(max(24rem, (100% - 2 * 1.125rem) / 3), 1fr));
  gap: 1.125rem;
}
.article-content .concept-grid-1,
.ck-content .concept-grid-1 {
  grid-template-columns: 1fr;
}
.article-content .concept-grid-2,
.ck-content .concept-grid-2 {
  grid-template-columns: repeat(2, minmax(0, 1fr));
}
/* auto-fill + max(sàn 24rem, 1/N bề rộng khả dụng) — cùng cơ chế với `.concept-grid` ở trên,
   chỉ khác trần số cột (3 và 4). Trước đây ép cứng `repeat(3|4, minmax(0, 1fr))`: ở dải
   ~900-1200px vẫn nhồi đủ 3|4 cột dù mỗi cột tụt dưới 24rem (~40 ký tự/dòng), chữ trong card
   vỡ dòng liên tục làm card cao bất thường. auto-fill tự rớt 3→2→1 (hoặc 4→3→2→1) khi không
   đủ chỗ cho sàn 24rem; vế `(100% - (N-1)*gap) / N` chặn trần đúng N cột khi container đủ rộng.
   Vì công thức đã tự lo mọi bề rộng nên 2 media query 900px/700px cho `-3`/`-4` đã bỏ bên dưới. */
.article-content .concept-grid-3,
.ck-content .concept-grid-3 {
  grid-template-columns: repeat(auto-fill, minmax(max(24rem, (100% - 2 * 1.125rem) / 3), 1fr));
}
.article-content .concept-grid-4,
.ck-content .concept-grid-4 {
  grid-template-columns: repeat(auto-fill, minmax(max(24rem, (100% - 3 * 1.125rem) / 4), 1fr));
}

.article-content .concept-card,
.ck-content .concept-card {
  padding: 1.25rem 1.375rem;
  border-radius: var(--article-radius);
  border: 1px solid var(--border, oklch(90% 0.005 264));
  border-top: 3px solid var(--border, oklch(90% 0.005 264));
  background: var(--card, var(--background, oklch(100% 0 0)));
  box-shadow: var(--article-shadow-sm);
  transition: transform var(--article-duration) var(--article-ease), box-shadow var(--article-duration) var(--article-ease);
}
.article-content .concept-card:hover,
.ck-content .concept-card:hover {
  transform: translateY(-2px);
  box-shadow: var(--article-shadow);
}
.article-content .concept-card > * + *,
.ck-content .concept-card > * + * {
  margin-top: 0.625rem;
}
.article-content .concept-card__top,
.ck-content .concept-card__top {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 0.75rem;
}
.article-content .concept-card__top h3,
.article-content .concept-card__top h4,
.ck-content .concept-card__top h3,
.ck-content .concept-card__top h4 {
  margin: 0;
}

.article-content .concept-card.topic-1, .ck-content .concept-card.topic-1 { border-top-color: var(--article-topic-1); }
.article-content .concept-card.topic-2, .ck-content .concept-card.topic-2 { border-top-color: var(--article-topic-2); }
.article-content .concept-card.topic-3, .ck-content .concept-card.topic-3 { border-top-color: var(--article-topic-3); }
.article-content .concept-card.topic-4, .ck-content .concept-card.topic-4 { border-top-color: var(--article-topic-4); }
.article-content .concept-card.topic-5, .ck-content .concept-card.topic-5 { border-top-color: var(--article-topic-5); }
.article-content .concept-card.topic-6, .ck-content .concept-card.topic-6 { border-top-color: var(--article-topic-6); }
.article-content .concept-card.topic-7, .ck-content .concept-card.topic-7 { border-top-color: var(--article-topic-7); }
.article-content .concept-card.topic-8, .ck-content .concept-card.topic-8 { border-top-color: var(--article-topic-8); }

/* --- 22.3 Topic block — khối chủ đề con lớn, bọc nhiều concept-card ---
   Markup:
     <section class="topic-block">
       <p class="topic-block__title topic-1">Ba thể của chất</p>
       <div class="concept-grid concept-grid-3">...</div>
     </section> */
.article-content .topic-block,
.ck-content .topic-block {
  border-radius: var(--article-radius-lg);
  overflow: hidden;
  border: 1px solid var(--border, oklch(90% 0.005 264));
  box-shadow: var(--article-shadow-sm);
}
.article-content .topic-block__title,
.ck-content .topic-block__title {
  margin: 0;
  padding: 0.875rem 1.25rem;
  font-weight: 800;
  font-size: 1.0625rem;
  color: white;
  background: var(--primary, oklch(55% 0.18 265));
}
.article-content .topic-block .concept-grid,
.ck-content .topic-block .concept-grid {
  padding: 1.125rem 1.25rem;
  margin-top: 0;
}

.article-content .topic-block__title.topic-1, .ck-content .topic-block__title.topic-1 { background: var(--article-topic-1); }
.article-content .topic-block__title.topic-2, .ck-content .topic-block__title.topic-2 { background: var(--article-topic-2); }
.article-content .topic-block__title.topic-3, .ck-content .topic-block__title.topic-3 { background: var(--article-topic-3); }
.article-content .topic-block__title.topic-4, .ck-content .topic-block__title.topic-4 { background: var(--article-topic-4); }
.article-content .topic-block__title.topic-5, .ck-content .topic-block__title.topic-5 { background: var(--article-topic-5); }
.article-content .topic-block__title.topic-6, .ck-content .topic-block__title.topic-6 { background: var(--article-topic-6); }
.article-content .topic-block__title.topic-7, .ck-content .topic-block__title.topic-7 { background: var(--article-topic-7); }
.article-content .topic-block__title.topic-8, .ck-content .topic-block__title.topic-8 { background: var(--article-topic-8); }

/* --- 22.4 Badge — 3 biến thể còn thiếu so với SECTION 14, cùng tái dùng
   token callout tương ứng (đúng quy ước badge-success/warning/danger đã có) --- */
.article-content .badge-info,
.ck-content .badge-info {
  background: var(--callout-info-bg);
  color: var(--callout-info-icon);
  border-color: var(--callout-info-border);
}
.article-content .badge-tip,
.ck-content .badge-tip {
  background: var(--callout-tip-bg);
  color: var(--callout-tip-icon);
  border-color: var(--callout-tip-border);
}
.article-content .badge-example,
.ck-content .badge-example {
  background: var(--callout-example-bg);
  color: var(--callout-example-icon);
  border-color: var(--callout-example-border);
}

/* --- 22.5 Note inline — ghi chú nhỏ lồng BÊN TRONG 1 card ---
   Khác .callout (SECTION 12) ở chỗ gọn hơn, không icon tròn — dùng khi cần 1
   dòng "Ghi nhớ" ngắn nằm trong .concept-card thay vì đứng độc lập cả bài.
   Markup: <div class="note-inline"><p class="note-inline__label">Ghi nhớ</p><p>...</p></div> */
.article-content .note-inline,
.ck-content .note-inline {
  padding: 0.75rem 1rem;
  border-radius: var(--article-radius-sm);
  border-left: 3px solid var(--callout-info-border);
  background: linear-gradient(135deg, var(--callout-info-bg), transparent);
}
.article-content .note-inline__label,
.ck-content .note-inline__label {
  margin: 0 0 0.25rem;
  font-size: 0.6875rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--callout-info-icon);
}
.article-content .note-inline p,
.ck-content .note-inline p {
  margin: 0;
  font-size: 0.875rem;
}
.article-content .note-inline p + p,
.ck-content .note-inline p + p {
  margin-top: 0.4em;
}

/* --- 22.6 Stat grid — dãy số liệu nổi bật đầu bài ---
   Markup: <div class="stat-grid"><div class="stat-card"><p class="stat-card__number">7</p><p class="stat-card__label">Chủ đề</p></div>...</div> */
.article-content .stat-grid,
.ck-content .stat-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 0.875rem;
}
.article-content .stat-card,
.ck-content .stat-card {
  padding: 1.125rem 0.875rem;
  text-align: center;
  border-radius: var(--article-radius);
  border: 1px solid var(--border, oklch(90% 0.005 264));
  background: var(--card, var(--background, oklch(100% 0 0)));
  box-shadow: var(--article-shadow-sm);
}
.article-content .stat-card__number,
.ck-content .stat-card__number {
  margin: 0;
  font-size: 1.75rem;
  font-weight: 800;
  color: var(--primary, oklch(55% 0.18 265));
  line-height: 1;
  font-variant-numeric: tabular-nums;
}
.article-content .stat-card__label,
.ck-content .stat-card__label {
  margin: 0.375rem 0 0;
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--muted-foreground, oklch(50% 0.01 264));
}

/* --- 22.7 Memory box — mẹo ghi nhớ trang trí, nổi bật hơn callout-tip ---
   Dùng cho 1 chuỗi ghi nhớ nhiều dòng + danh sách ví dụ ngắn, đặt ngay sau
   phần lý thuyết dài, cần nổi bật hơn mức callout thông thường.
   Markup:
     <div class="memory-box">
       <span class="memory-box__icon">💡</span>
       <div>
         <p class="memory-box__label">Mẹo ghi nhớ nhanh</p>
         <p class="memory-box__seq">RẮN → LỎNG → KHÍ</p>
         <ul class="memory-box__list"><li>...</li></ul>
       </div>
     </div> */
.article-content .memory-box,
.ck-content .memory-box {
  display: flex;
  align-items: flex-start;
  gap: 1rem;
  padding: 1.125rem 1.375rem;
  border-radius: var(--article-radius);
  border: 1px solid var(--callout-homework-border);
  border-left: 4px solid var(--callout-homework-icon);
  background: linear-gradient(135deg, var(--callout-homework-bg), color-mix(in oklch, var(--callout-homework-bg) 55%, transparent));
}
.article-content .memory-box > * + *,
.ck-content .memory-box > * + * {
  margin-top: 0;
}
.article-content .memory-box__icon,
.ck-content .memory-box__icon {
  flex: none;
  font-size: 1.5rem;
  line-height: 1;
  margin-top: 0.125rem;
}
.article-content .memory-box__label,
.ck-content .memory-box__label {
  margin: 0 0 0.25rem;
  font-size: 0.6875rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--callout-homework-icon);
}
.article-content .memory-box__seq,
.ck-content .memory-box__seq {
  margin: 0 0 0.25rem;
  font-weight: 800;
  font-size: 1rem;
  color: var(--callout-homework-icon);
}
.article-content .memory-box__list,
.ck-content .memory-box__list {
  list-style: none;
  padding: 0;
  margin: 0.375rem 0 0;
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem 1rem;
  font-size: 0.8125rem;
  color: var(--callout-homework-icon);
}
.article-content .memory-box__list li,
.ck-content .memory-box__list li {
  margin: 0;
  padding: 0;
}
.article-content .memory-box__list li::before,
.ck-content .memory-box__list li::before {
  content: '\2022';
  margin-right: 0.375rem;
  color: var(--callout-homework-border);
}

/* --- 22.8 Table section — bảng có tiêu đề riêng, nổi bật hơn figure.table trơn ---
   Markup:
     <section class="table-section">
       <p class="table-section__title">So sánh 3 thể của chất</p>
       <div class="table-section__body"><figure class="table"><table>...</table></figure></div>
     </section> */
.article-content .table-section,
.ck-content .table-section {
  border-radius: var(--article-radius-lg);
  overflow: hidden;
  border: 1px solid var(--border, oklch(90% 0.005 264));
  border-top: 3px solid var(--primary, oklch(55% 0.18 265));
}
.article-content .table-section__title,
.ck-content .table-section__title {
  margin: 0;
  padding: 0.875rem 1.25rem;
  font-weight: 800;
  font-size: 1rem;
  color: var(--primary, oklch(55% 0.18 265));
  background: color-mix(in oklch, var(--primary, oklch(55% 0.18 265)) 8%, var(--background, white));
  border-bottom: 1px solid var(--border, oklch(90% 0.005 264));
}
.article-content .table-section__body,
.ck-content .table-section__body {
  padding: 1.125rem 1.25rem;
}
.article-content .table-section__body figure.table,
.ck-content .table-section__body figure.table {
  border: none;
  box-shadow: none;
}

/* --- 22.9 CTA banner — băng gradient kêu gọi hành động, thường đặt cuối bài ---
   Markup:
     <div class="cta-banner">
       <div>
         <p class="cta-banner__title">Tiêu đề</p>
         <p class="cta-banner__desc">Mô tả...</p>
       </div>
       <div class="cta-banner__actions">
         <a class="btn btn-light" href="#">Nút 1</a>
         <a class="btn btn-ghost" href="#">Nút 2</a>
       </div>
     </div> */
.article-content .cta-banner,
.ck-content .cta-banner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 1.5rem;
  padding: 2rem 2.25rem;
  border-radius: var(--article-radius-lg);
  background: linear-gradient(
    135deg,
    var(--primary, oklch(55% 0.18 265)),
    color-mix(in oklch, var(--primary, oklch(55% 0.18 265)) 65%, var(--article-accent))
  );
  color: white;
}
.article-content .cta-banner > * + *,
.ck-content .cta-banner > * + * {
  margin-top: 0;
}
.article-content .cta-banner__title,
.ck-content .cta-banner__title {
  margin: 0 0 0.375rem;
  color: inherit;
  font-size: 1.25rem;
}
.article-content .cta-banner__desc,
.ck-content .cta-banner__desc {
  margin: 0;
  color: oklch(100% 0 0 / 0.85);
  max-width: 34rem;
}
.article-content .cta-banner__actions,
.ck-content .cta-banner__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  flex: none;
}

/* --- 22.10 FAQ accordion KHÔNG JS — dùng <details>/<summary> gốc trình duyệt ---
   Ưu tiên hơn xếp chồng nhiều .callout-question khi danh sách FAQ dài: gọn
   hơn, người đọc tự mở câu mình cần. Không phụ thuộc Bootstrap JS vì trang
   blog publish chỉ chèn HTML thô từ CKEditor, không chắc có JS accordion đi
   kèm theo mọi nơi hiển thị (preview admin, AMP, RSS...).
   Markup:
     <details class="qa">
       <summary class="qa__q">Câu hỏi?</summary>
       <div class="qa__a"><p>Câu trả lời...</p></div>
     </details> */
.article-content details.qa,
.ck-content details.qa {
  counter-increment: qa;
  border: 1px solid var(--border, oklch(90% 0.005 264));
  border-radius: var(--article-radius);
  background: var(--card, var(--background, oklch(100% 0 0)));
  box-shadow: 0 1px 2px oklch(0% 0 0 / 0.04);
  overflow: hidden;
  transition: border-color var(--article-duration) var(--article-ease),
    box-shadow var(--article-duration) var(--article-ease);
}
/* Đánh số lại từ 1 ở câu đầu mỗi nhóm FAQ liền nhau (1 bài có thể có nhiều nhóm). */
.article-content details.qa:not(.qa + .qa),
.ck-content details.qa:not(.qa + .qa) {
  counter-reset: qa;
}
.article-content details.qa + details.qa,
.ck-content details.qa + details.qa {
  margin-top: 0.75rem;
}
.article-content details.qa:hover,
.ck-content details.qa:hover,
.article-content details.qa[open],
.ck-content details.qa[open] {
  border-color: color-mix(in oklch, var(--primary, oklch(55% 0.18 265)) 40%, transparent);
}
.article-content details.qa[open],
.ck-content details.qa[open] {
  box-shadow: 0 2px 8px oklch(0% 0 0 / 0.06);
}
.article-content .qa__q,
.ck-content .qa__q {
  cursor: pointer;
  list-style: none;
  padding: 0.875rem 1.25rem;
  font-weight: 600;
  font-size: 0.9375rem;
  line-height: 1.5;
  color: var(--foreground, oklch(21% 0.006 264));
  display: flex;
  align-items: center;
  gap: 0.75rem;
}
.article-content .qa__q::-webkit-details-marker,
.ck-content .qa__q::-webkit-details-marker {
  display: none;
}
/* Ô số thứ tự đầu câu hỏi — tô đặc khi đang mở. */
.article-content .qa__q::before,
.ck-content .qa__q::before {
  content: counter(qa);
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.75rem;
  height: 1.75rem;
  border-radius: 999px;
  font-size: 0.75rem;
  font-weight: 700;
  background: color-mix(in oklch, var(--primary, oklch(55% 0.18 265)) 10%, transparent);
  color: var(--primary, oklch(55% 0.18 265));
  transition: background-color var(--article-duration) var(--article-ease),
    color var(--article-duration) var(--article-ease);
}
.article-content details.qa[open] .qa__q::before,
.ck-content details.qa[open] .qa__q::before {
  background: var(--primary, oklch(55% 0.18 265));
  color: var(--primary-foreground, oklch(100% 0 0));
}
/* Mũi tên (chevron) cuối dòng — xoay lên khi mở. */
.article-content .qa__q::after,
.ck-content .qa__q::after {
  content: '';
  flex: none;
  margin-left: auto;
  width: 0.5rem;
  height: 0.5rem;
  border-right: 2px solid var(--muted-foreground, oklch(50% 0.01 264));
  border-bottom: 2px solid var(--muted-foreground, oklch(50% 0.01 264));
  transform: translateY(-25%) rotate(45deg);
  transition: transform var(--article-duration) var(--article-ease);
}
.article-content details.qa[open] .qa__q::after,
.ck-content details.qa[open] .qa__q::after {
  transform: translateY(25%) rotate(-135deg);
}
/* Câu trả lời: chữ nhạt trong khối nền mờ, thụt thẳng hàng chữ câu hỏi (1.75rem ô số + 0.75rem gap). */
.article-content .qa__a,
.ck-content .qa__a {
  margin: 0 1.25rem 1rem 3.75rem;
  padding: 0.625rem 0.875rem;
  border-radius: calc(var(--article-radius) * 0.6);
  background: color-mix(in oklch, var(--muted, oklch(96% 0.003 264)) 50%, transparent);
  font-size: 0.9375rem;
  line-height: 1.7;
  color: var(--muted-foreground, oklch(50% 0.01 264));
}
.article-content .qa__a > p,
.ck-content .qa__a > p {
  margin: 0;
}
.article-content .qa__a > * + *,
.ck-content .qa__a > * + * {
  margin-top: 0.5em;
}
@media (max-width: 640px) {
  .article-content .qa__a,
  .ck-content .qa__a {
    margin-left: 1.25rem;
  }
}

@media (max-width: 700px) {
  .article-content .concept-grid,
  .ck-content .concept-grid,
  .article-content .concept-grid-2,
  .ck-content .concept-grid-2 {
    grid-template-columns: 1fr;
  }
  .article-content .stat-grid,
  .ck-content .stat-grid {
    grid-template-columns: repeat(2, 1fr);
  }
  .article-content .cta-banner,
  .ck-content .cta-banner {
    flex-direction: column;
    align-items: flex-start;
    padding: 1.5rem;
  }
  .article-content .memory-box,
  .ck-content .memory-box {
    flex-direction: column;
  }
}

@media (max-width: 480px) {
  .article-content .stat-grid,
  .ck-content .stat-grid {
    grid-template-columns: 1fr;
  }
}

@media print {
  .article-content .cta-banner,
  .ck-content .cta-banner {
    background: none;
    color: black;
    border: 1px solid #999;
  }
  .article-content .topic-block__title,
  .ck-content .topic-block__title {
    background: none;
    color: black;
    border-bottom: 1px solid #999;
  }
  .article-content details.qa,
  .ck-content details.qa {
    border: 1px solid #999;
  }
}

/* ============================================================================
 * SECTION 23 — MEDIA GALLERY / LIGHTBOX (KHÔNG JS) + TAG PHÂN LOẠI + DIVIDER
 * ============================================================================
 * Đúc rút tiếp từ hệ "photo-single"/"photo-gallery" (dự án tdntest) — nhưng bản
 * gốc dùng <script> tự chạy (đăng ký click handler, render lightbox bằng JS).
 * Cách đó KHÔNG dùng được ở đây: nội dung CKEditor render qua
 * dangerouslySetInnerHTML ở frontend React — trình duyệt **không bao giờ thực
 * thi** thẻ <script> được chèn bằng innerHTML/dangerouslySetInnerHTML (hành vi
 * bảo mật chuẩn của DOM, không phải giới hạn riêng của React), nên toàn bộ
 * script gắn kèm nội dung sẽ im lặng không chạy.
 *
 * Giải pháp: lightbox CSS thuần dùng kỹ thuật `:target` — mở bằng đúng 1 thẻ
 * <a href="#id">, đóng bằng <a href="#_"> (id "_" không tồn tại nên không có
 * phần tử nào khớp :target nữa), điều hướng ảnh trước/sau cũng chỉ là <a>
 * nhảy sang id khác. Không cần JavaScript ở bất kỳ đâu — hoạt động y hệt dù
 * nội dung được chèn bằng innerHTML, dangerouslySetInnerHTML, hay SSR thường.
 * Đánh đổi chấp nhận được: không khoá focus (focus trap) trong lightbox và
 * không có phím Esc để đóng (cả hai đều cần JS) — đóng bằng cách bấm nền mờ,
 * nút ✕, hoặc nút Back của trình duyệt (đổi hash cũng đẩy 1 mục lịch sử).
 * ============================================================================
 */
:root {
  --article-overlay-bg: oklch(0% 0 0 / 0.86);
}

/* --- 23.1 Zoomable — 1 ảnh đơn bấm vào để phóng to ---
   Markup:
     <figure class="image zoomable">
       <a href="#lb-vi-du-1" class="zoomable__trigger">
         <img src="thumb.jpg" alt="...">
         <span class="zoomable__hint">🔍</span>
       </a>
       <figcaption>Chú thích ảnh</figcaption>
     </figure>

     <div class="lightbox" id="lb-vi-du-1">
       <a href="#_" class="lightbox__backdrop" aria-label="Đóng">&nbsp;</a>
       <figure class="lightbox__frame">
         <a href="#_" class="lightbox__close" aria-label="Đóng">&times;</a>
         <img src="full.jpg" alt="...">
         <figcaption>Chú thích ảnh</figcaption>
       </figure>
     </div>
   id trong href và trong lightbox phải khớp nhau, mỗi ảnh 1 id duy nhất trong
   toàn trang.
   QUAN TRỌNG: `.lightbox__backdrop` PHẢI có nội dung (`&nbsp;` như trên) dù nó vô
   hình về mặt thị giác — CKEditor 4 (`public/ckeditor/config.js`, camtest) tự
   xoá mất bất kỳ thẻ <a> nào hoàn toàn rỗng (không có text/con) mỗi khi nội dung
   đi qua vùng soạn thảo WYSIWYG hoặc được lưu lại, dù `config.allowedContent =
   true` đã tắt hẳn ACF — đây là hành vi dọn "thẻ inline rỗng vô nghĩa" ở tầng
   thấp hơn ACF, không tắt được qua config. Thiếu `&nbsp;` này, backdrop biến mất
   khỏi nội dung đã lưu (kiểm chứng qua API response thực tế), lightbox vẫn mở
   được (nhờ `.lightbox__close` còn nguyên do có chữ "×") nhưng mất nền mờ + mất
   cách bấm ra ngoài để đóng. */
.article-content .zoomable__trigger,
.ck-content .zoomable__trigger {
  position: relative;
  display: block;
  cursor: zoom-in;
  background-image: none;
}
/* Ảnh lồng trong .zoomable__trigger nằm sâu hơn 1 cấp so với `figure.image > img`
   (SECTION 8) nên KHÔNG tự nhận viền/bóng/bo góc từ rule đó — bổ sung riêng ở đây
   để ảnh zoomable trông giống hệt ảnh thường, chỉ khác ở chỗ bấm được để phóng to. */
.article-content .zoomable__trigger > img,
.ck-content .zoomable__trigger > img {
  margin-inline: auto;
  border-radius: var(--article-radius);
  box-shadow: var(--article-shadow);
  border: 1px solid var(--border, oklch(90% 0.005 264));
}
.article-content .zoomable__hint,
.ck-content .zoomable__hint {
  position: absolute;
  right: 0.625rem;
  bottom: 0.625rem;
  width: 2rem;
  height: 2rem;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 9999px;
  background: oklch(100% 0 0 / 0.85);
  font-size: 1rem;
  opacity: 0;
  transform: scale(0.85);
  transition:
    opacity var(--article-duration) var(--article-ease),
    transform var(--article-duration) var(--article-ease);
  pointer-events: none;
}
.article-content .zoomable__trigger:hover .zoomable__hint,
.article-content .zoomable__trigger:focus-visible .zoomable__hint,
.ck-content .zoomable__trigger:hover .zoomable__hint,
.ck-content .zoomable__trigger:focus-visible .zoomable__hint {
  opacity: 1;
  transform: scale(1);
}

/* --- 23.2 Gallery — dải thumbnail cuộn ngang, mỗi ảnh mở lightbox riêng ---
   Markup:
     <div class="gallery">
       <p class="gallery__label">📸 Hình ảnh tham khảo — nhấn để phóng to</p>
       <div class="gallery__track">
         <a href="#lb-g1-1" class="gallery__thumb"><img src="thumb1.jpg" alt="Ảnh 1"><span class="zoomable__hint">🔍</span></a>
         <a href="#lb-g1-2" class="gallery__thumb"><img src="thumb2.jpg" alt="Ảnh 2"><span class="zoomable__hint">🔍</span></a>
       </div>
     </div>
     <!-- 1 <div class="lightbox" id="lb-g1-N"> cho mỗi ảnh, xem 23.3 để thêm nút prev/next --> */
.article-content .gallery,
.ck-content .gallery {
  padding: 1rem;
  border: 1px solid var(--border, oklch(90% 0.005 264));
  border-radius: var(--article-radius);
  background: var(--muted, oklch(96% 0.003 264));
}
.article-content .gallery__label,
.ck-content .gallery__label {
  margin: 0 0 0.75rem;
  font-size: 0.8125rem;
  font-weight: 700;
  color: var(--muted-foreground, oklch(50% 0.01 264));
}
.article-content .gallery__track,
.ck-content .gallery__track {
  display: flex;
  gap: 0.75rem;
  overflow-x: auto;
  padding-bottom: 0.25rem;
  scroll-snap-type: x proximity;
  -webkit-overflow-scrolling: touch;
}
.article-content .gallery__thumb,
.ck-content .gallery__thumb {
  position: relative;
  flex: none;
  width: 9rem;
  height: 6.75rem;
  border-radius: var(--article-radius-sm);
  overflow: hidden;
  scroll-snap-align: start;
  cursor: zoom-in;
  background-image: none;
  box-shadow: var(--article-shadow-sm);
}
.article-content .gallery__thumb img,
.ck-content .gallery__thumb img {
  width: 100%;
  height: 100%;
  border-radius: 0;
  object-fit: cover;
  transition: transform var(--article-duration) var(--article-ease);
}
.article-content .gallery__thumb:hover img,
.ck-content .gallery__thumb:hover img {
  transform: scale(1.06);
}
.article-content .gallery__thumb:hover .zoomable__hint,
.article-content .gallery__thumb:focus-visible .zoomable__hint,
.ck-content .gallery__thumb:hover .zoomable__hint,
.ck-content .gallery__thumb:focus-visible .zoomable__hint {
  opacity: 1;
  transform: scale(1);
}

/* Thiết bị cảm ứng KHÔNG có hover — icon 🔍 ẩn chờ hover sẽ không bao giờ hiện
   trước khi học sinh chạm vào, khiến ảnh trông như ảnh thường (mất tín hiệu
   "bấm để phóng to"). `(hover: none)` phát hiện đúng nhóm thiết bị này (khác
   max-width — 1 máy tính bảng màn hình hẹp vẫn có hover qua chuột/bút, không
   nên ẩn icon của nó) — hiện icon thường trực, mờ nhẹ hơn 100% để đỡ rối mắt. */
@media (hover: none) {
  .article-content .zoomable__hint,
  .ck-content .zoomable__hint {
    opacity: 0.85;
    transform: scale(1);
  }
}

/* --- 23.3 Lightbox overlay — hiện/ẩn bằng :target, KHÔNG JS ---
   Markup nút điều hướng bên trong .lightbox__frame (tuỳ chọn, chỉ cần khi ảnh
   nằm trong 1 gallery nhiều ảnh):
     <a href="#lb-g1-3" class="lightbox__nav lightbox__prev" aria-label="Ảnh trước">&lsaquo;</a>
     <a href="#lb-g1-2" class="lightbox__nav lightbox__next" aria-label="Ảnh sau">&rsaquo;</a>
   href trỏ vòng tròn qua id ảnh trước/sau trong cùng gallery. */
.article-content .lightbox,
.ck-content .lightbox {
  position: fixed;
  inset: 0;
  z-index: 200;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1.25rem;
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity var(--article-duration) var(--article-ease);
}
.article-content .lightbox:target,
.ck-content .lightbox:target {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
}
.article-content .lightbox__backdrop,
.ck-content .lightbox__backdrop {
  position: absolute;
  inset: 0;
  background: var(--article-overlay-bg);
  background-image: none;
}
.article-content .lightbox__frame,
.ck-content .lightbox__frame {
  position: relative;
  z-index: 1;
  max-width: min(96vw, 90rem);
  max-height: 94vh;
  margin: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
}
.article-content .lightbox__frame img,
.ck-content .lightbox__frame img {
  max-width: 100%;
  max-height: 86vh;
  width: auto;
  border: none;
  border-radius: var(--article-radius);
  box-shadow: var(--article-shadow-lg);
}
.article-content .lightbox__frame figcaption,
.ck-content .lightbox__frame figcaption {
  margin-top: 0.75rem;
  color: white;
  font-size: 0.875rem;
  text-align: center;
}
.article-content .lightbox__close,
.article-content .lightbox__nav,
.ck-content .lightbox__close,
.ck-content .lightbox__nav {
  position: absolute;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 9999px;
  background: oklch(100% 0 0 / 0.15);
  color: white;
  background-image: none;
  text-decoration: none;
  transition: background-color var(--article-duration-fast) var(--article-ease);
}
.article-content .lightbox__close:hover,
.article-content .lightbox__nav:hover,
.ck-content .lightbox__close:hover,
.ck-content .lightbox__nav:hover {
  background: oklch(100% 0 0 / 0.28);
}
.article-content .lightbox__close,
.ck-content .lightbox__close {
  top: -2.5rem;
  right: 0;
  width: 2.25rem;
  height: 2.25rem;
  font-size: 1.125rem;
}
.article-content .lightbox__nav,
.ck-content .lightbox__nav {
  top: 50%;
  translate: 0 -50%;
  width: 2.75rem;
  height: 2.75rem;
  font-size: 1.5rem;
}
.article-content .lightbox__prev,
.ck-content .lightbox__prev {
  left: -3.5rem;
}
.article-content .lightbox__next,
.ck-content .lightbox__next {
  right: -3.5rem;
}

/* --- 23.4 Tag phân loại nội dung — KHÁC .badge (SECTION 14, trạng thái UI) ---
   Dùng để gắn nhãn LOẠI nội dung của 1 thẻ khái niệm (khái niệm/thực hành/
   chuyển thể/tự nhiên/lịch sử/vật liệu/ứng dụng) — tái dùng token callout đã
   có, không tạo màu mới. Markup: <span class="tag tag-concept">Khái niệm</span> */
.article-content .tag,
.ck-content .tag {
  display: inline-block;
  padding: 0.125rem 0.625rem;
  border-radius: var(--article-radius-sm);
  font-size: 0.75rem;
  font-weight: 700;
  border: 1px solid transparent;
}
.article-content .tag-concept,
.ck-content .tag-concept {
  background: var(--callout-info-bg);
  color: var(--callout-info-icon);
  border-color: var(--callout-info-border);
}
.article-content .tag-practice,
.ck-content .tag-practice {
  background: var(--callout-success-bg);
  color: var(--callout-success-icon);
  border-color: var(--callout-success-border);
}
.article-content .tag-transition,
.ck-content .tag-transition {
  background: var(--callout-example-bg);
  color: var(--callout-example-icon);
  border-color: var(--callout-example-border);
}
.article-content .tag-nature,
.ck-content .tag-nature {
  background: var(--callout-summary-bg);
  color: var(--callout-summary-icon);
  border-color: var(--callout-summary-border);
}
.article-content .tag-history,
.ck-content .tag-history {
  background: var(--callout-warning-bg);
  color: var(--callout-warning-icon);
  border-color: var(--callout-warning-border);
}
.article-content .tag-material,
.ck-content .tag-material {
  background: var(--callout-tip-bg);
  color: var(--callout-tip-icon);
  border-color: var(--callout-tip-border);
}
.article-content .tag-application,
.ck-content .tag-application {
  background: var(--callout-danger-bg);
  color: var(--callout-danger-icon);
  border-color: var(--callout-danger-border);
}

/* --- 23.5 Divider label — nhãn chia nhóm nhẹ, KHÔNG phải heading thật ---
   Dùng để chia nhỏ 1 khối flashcard/danh sách dài thành từng nhóm mà không
   cần thêm 1 cấp heading mới (h5/h6 ở SECTION 3 dùng cho heading thật, có
   scroll-margin + xuất hiện trong mục lục nếu TOC tự sinh theo heading).
   Markup: <p class="divider-label">Nhóm 1: Ba thể</p> */
.article-content .divider-label,
.ck-content .divider-label {
  margin: 0;
  padding: 0.5rem 1.25rem;
  font-size: 0.875rem;
  font-weight: 700;
  color: var(--primary, oklch(55% 0.18 265));
  background: color-mix(in oklch, var(--primary, oklch(55% 0.18 265)) 8%, var(--background, white));
  border-left: 3px solid var(--primary, oklch(55% 0.18 265));
  border-radius: 0 var(--article-radius-sm) var(--article-radius-sm) 0;
}

/* --- 23.6 Topic index — danh sách chủ đề đánh số "01, 02..." tô màu topic-N ---
   Biến thể giàu thông tin hơn .toc (SECTION 15) — dùng trong .intro-panel
   (SECTION 23.7) ở đầu bài tổng hợp nhiều chủ đề con: mỗi dòng có số thứ tự +
   nhãn viết tắt (màu theo topic-N) + tiêu đề + mô tả ngắn. Màu số khớp với
   .topic-block__title/.concept-card cùng topic-N để người đọc nối được dòng
   nào dẫn tới khối màu nào bên dưới trong bài.
   Markup:
     <div class="topic-index">
       <a href="#chu-de-1" class="topic-index__row">
         <span class="topic-index__num topic-1">01<small>Thể</small></span>
         <span class="topic-index__text">
           <strong>Ba thể của chất — Rắn, Lỏng, Khí</strong>
           <small>Hình dạng, thể tích, sự chuyển thể</small>
         </span>
       </a>
     </div> */
.article-content .topic-index,
.ck-content .topic-index {
  display: flex;
  flex-direction: column;
  gap: 0.625rem;
}
.article-content .topic-index__row,
.ck-content .topic-index__row {
  display: grid;
  grid-template-columns: 3.25rem 1fr;
  gap: 0.875rem;
  align-items: start;
  padding: 0.75rem 1rem;
  border-radius: var(--article-radius-sm);
  border: 1px solid var(--border, oklch(90% 0.005 264));
  background: var(--card, var(--background, oklch(100% 0 0)));
  background-image: none;
  transition:
    border-color var(--article-duration-fast) var(--article-ease),
    background-color var(--article-duration-fast) var(--article-ease);
}
.article-content .topic-index__row:hover,
.ck-content .topic-index__row:hover {
  border-color: var(--article-accent);
  background: var(--muted, oklch(96% 0.003 264));
}
.article-content .topic-index__num,
.ck-content .topic-index__num {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  line-height: 1.25;
  font-weight: 800;
  font-size: 1.0625rem;
}
.article-content .topic-index__num small,
.ck-content .topic-index__num small {
  font-weight: 500;
  font-size: 0.6875rem;
  color: var(--muted-foreground, oklch(50% 0.01 264));
}
.article-content .topic-index__num.topic-1, .ck-content .topic-index__num.topic-1 { color: var(--article-topic-1); }
.article-content .topic-index__num.topic-2, .ck-content .topic-index__num.topic-2 { color: var(--article-topic-2); }
.article-content .topic-index__num.topic-3, .ck-content .topic-index__num.topic-3 { color: var(--article-topic-3); }
.article-content .topic-index__num.topic-4, .ck-content .topic-index__num.topic-4 { color: var(--article-topic-4); }
.article-content .topic-index__num.topic-5, .ck-content .topic-index__num.topic-5 { color: var(--article-topic-5); }
.article-content .topic-index__num.topic-6, .ck-content .topic-index__num.topic-6 { color: var(--article-topic-6); }
.article-content .topic-index__num.topic-7, .ck-content .topic-index__num.topic-7 { color: var(--article-topic-7); }
.article-content .topic-index__num.topic-8, .ck-content .topic-index__num.topic-8 { color: var(--article-topic-8); }
.article-content .topic-index__text,
.ck-content .topic-index__text {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
}
.article-content .topic-index__text strong,
.ck-content .topic-index__text strong {
  font-size: 0.9375rem;
  font-weight: 700;
  color: var(--foreground, oklch(21% 0.006 264));
}
.article-content .topic-index__text small,
.ck-content .topic-index__text small {
  color: var(--muted-foreground, oklch(50% 0.01 264));
}

/* --- 23.7 Intro grid — mở bài 2 cột: giới thiệu chung + bảng mục lục chủ đề ---
   Biến thể "hero" thứ 2, dùng cho bài TỔNG HỢP nhiều chủ đề con (khác
   .lesson-hero ở SECTION 21 — banner gradient 1 cột, hợp bài 1 mạch lý
   thuyết). Nền trắng/trung tính, nghiêng về biên tập (editorial) hơn quảng
   cáo, vì đây là trang tra cứu học nhiều lần chứ không phải trang đích 1 lần.
   Markup:
     <div class="intro-grid">
       <div>
         <p class="eyebrow">🔬 Khoa học tự nhiên · Lớp 4–5</p>
         <h1>Khoa học về Chất</h1>
         <p>Đoạn giới thiệu chung...</p>
         <div class="intro-grid__actions">
           <a class="btn btn-primary" href="#chu-de-1">Ba thể của chất</a>
           <a class="btn btn-secondary" href="#chu-de-7">Khám phá vật liệu</a>
         </div>
       </div>
       <div class="intro-panel">
         <div class="intro-panel__head">
           <p class="intro-panel__title">7 Chủ đề kiến thức</p>
           <span class="badge badge-outline">Lớp 4–5 · Khoa học</span>
         </div>
         <div class="topic-index"> ... 23.6 ... </div>
       </div>
     </div>
   h1/p bên trong cột trái KHÔNG bọc thêm .lesson-hero nên vẫn ăn nhịp margin
   mặc định của SECTION 2/3 như nội dung thường — chỉ .intro-grid tự thêm gap
   giữa 2 cột, không đụng margin-top dọc vốn có của heading/paragraph. */
.article-content .eyebrow,
.ck-content .eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  margin: 0;
  padding: 0.375rem 1rem;
  border-radius: 9999px;
  border: 1px solid color-mix(in oklch, var(--primary, oklch(55% 0.18 265)) 35%, var(--border, oklch(90% 0.005 264)));
  background: color-mix(in oklch, var(--primary, oklch(55% 0.18 265)) 8%, var(--background, white));
  color: var(--primary, oklch(55% 0.18 265));
  font-weight: 700;
  font-size: 0.875rem;
}
.article-content .intro-grid,
.ck-content .intro-grid {
  display: grid;
  grid-template-columns: 1.1fr 0.9fr;
  gap: 2rem;
  align-items: start;
}
.article-content .intro-grid > * + *,
.ck-content .intro-grid > * + * {
  margin-top: 0;
}
.article-content .intro-grid__actions,
.ck-content .intro-grid__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  margin-top: 1.25rem;
}
.article-content .intro-panel,
.ck-content .intro-panel {
  padding: 1.5rem;
  border-radius: var(--article-radius-lg);
  border: 1px solid var(--border, oklch(90% 0.005 264));
  background: var(--card, var(--background, oklch(100% 0 0)));
  box-shadow: var(--article-shadow);
}
.article-content .intro-panel__head,
.ck-content .intro-panel__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  padding-bottom: 0.875rem;
  margin-bottom: 0.875rem;
  border-bottom: 1px solid var(--border, oklch(90% 0.005 264));
}
.article-content .intro-panel__title,
.ck-content .intro-panel__title {
  margin: 0;
  font-weight: 800;
  font-size: 1.0625rem;
  color: var(--primary, oklch(55% 0.18 265));
}

@media (max-width: 900px) {
  .article-content .intro-grid,
  .ck-content .intro-grid {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 700px) {
  .article-content .lightbox,
  .ck-content .lightbox {
    padding: 1rem;
  }
  .article-content .lightbox__prev,
  .ck-content .lightbox__prev {
    left: 0.5rem;
  }
  .article-content .lightbox__next,
  .ck-content .lightbox__next {
    right: 0.5rem;
  }
  .article-content .lightbox__close,
  .ck-content .lightbox__close {
    top: 0.5rem;
    right: 0.5rem;
    /* Đủ 44×44px (kích thước chạm tối thiểu khuyến nghị) thay vì 36px mặc định */
    width: 2.75rem;
    height: 2.75rem;
    font-size: 1.375rem;
  }
  .article-content .gallery__thumb,
  .ck-content .gallery__thumb {
    width: 7rem;
    height: 5.25rem;
  }
  .article-content .topic-index__row,
  .ck-content .topic-index__row {
    grid-template-columns: 2.5rem 1fr;
  }
}

@media print {
  /* Lightbox/gallery zoom là tương tác chỉ có nghĩa trên màn hình — ẩn khi in,
     giữ lại ảnh gốc trong luồng nội dung (figure.image ở SECTION 8 đã lo việc đó) */
  .article-content .lightbox,
  .ck-content .lightbox,
  .article-content .zoomable__hint,
  .ck-content .zoomable__hint,
  .article-content .gallery__label,
  .ck-content .gallery__label {
    display: none;
  }
}

/* ============================================================================
 * SECTION 24 — TIMELINE, RESOURCE LIST, PERSON CARD (bài lịch sử/mốc sự kiện)
 * ============================================================================
 * Đúc rút từ hệ "lich-su-cac-trieu-dai-phong-kien.css" (dự án tdntest) — dành
 * cho nội dung dạng CHUỖI SỰ KIỆN THEO THỜI GIAN (không riêng môn Lịch sử, áp
 * dụng được cho bất kỳ bài nào cần dòng thời gian: tiểu sử, quá trình phát
 * triển, các mốc của 1 dự án...). Tiếp tục tái dùng --article-topic-1..8 ở
 * SECTION 22 làm màu mã hoá giai đoạn — không tạo thêm bộ màu "giai đoạn"
 * riêng như bản gốc (--lsd-gd1..6) vì trùng đúng mục đích với topic-N đã có.
 * ============================================================================
 */

/* --- 24.1 Timeline dọc — 2 cột xen kẽ trái/phải quanh 1 trục giữa ---
   Markup:
     <div class="timeline">
       <div class="timeline__item">
         <div class="timeline__side timeline__side--left">
           <div class="timeline__card topic-1"><h4>Nhà nước Văn Lang</h4><p>...</p></div>
         </div>
         <div class="timeline__center">
           <span class="timeline__dot topic-1">🏹</span>
           <span class="timeline__year">2879 TCN</span>
         </div>
         <div class="timeline__side timeline__side--right"></div>
       </div>
       <div class="timeline__item">
         <div class="timeline__side timeline__side--left"></div>
         <div class="timeline__center"><span class="timeline__dot topic-2">⚔️</span><span class="timeline__year">179 TCN</span></div>
         <div class="timeline__side timeline__side--right">
           <div class="timeline__card topic-2"><h4>Bắc thuộc lần 1</h4><p>...</p></div>
         </div>
       </div>
     </div>
   Mốc lẻ đặt card ở side--left, mốc chẵn đặt ở side--right (tự xen kẽ theo
   thứ tự tác giả viết) — bên còn lại để trống (div rỗng) để giữ đúng cột lưới. */
.article-content .timeline,
.ck-content .timeline {
  position: relative;
  padding: 0.625rem 0;
}
/* Trục dọc — dày hơn (2px→3px), bo tròn 2 đầu. Màu tô qua biến --timeline-track (có
   fallback mặc định = accent đặc 88% + tàn dần cuối, y hệt hành vi trước đây) thay vì
   hard-code thẳng var(--article-accent) — mục đích: 1 bài dòng thời gian CỤ THỂ (như
   Lịch sử các triều đại) có thể khai --timeline-track cục bộ ngay trên thẻ
   <div class="timeline" style="--timeline-track: linear-gradient(...)"> để trục tự
   chuyển màu khớp từng giai đoạn (--article-topic-N) đang đi qua, mà KHÔNG phải sửa
   cứng component dùng chung này — các bài timeline khác (tiểu sử, tiến độ dự án...)
   không khai biến thì vẫn nhận đúng trục 1 màu accent như cũ, không ảnh hưởng.
   box-shadow đổi sang glow trung tính (không buộc theo 1 màu accent) vì trục giờ có
   thể mang nhiều màu cùng lúc — 1 glow đơn sắc sẽ lệch tông với đoạn trục không phải
   màu đó. */
.article-content .timeline::before,
.ck-content .timeline::before {
  content: '';
  position: absolute;
  left: 50%;
  top: 0;
  bottom: 0;
  width: 3px;
  border-radius: 9999px;
  translate: -50% 0;
  background: var(--timeline-track, linear-gradient(180deg, var(--article-accent) 0%, var(--article-accent) 88%, transparent 100%));
  box-shadow: 0 0 0.5rem oklch(0% 0 0 / 0.12);
}
/* Cột giữa dùng max-content thay vì 1 trị số rem cố định — mỗi HÀNG tự lấy đúng bề
   rộng cần thiết cho .timeline__year của chính nó (dot 3rem hay pill dài hơn, lấy
   max). Đây là cách duy nhất vừa giữ 2 cột thẻ TO tối đa (1fr chiếm hết phần còn lại,
   không bị trừ bớt cho 1 trị số cố định) vừa đảm bảo pill năm KHÔNG BAO GIỜ tràn ra
   ngoài track của nó dù dài ngắn khác nhau — khác hẳn cách cũ (trị số rem cố định +
   pill được phép overflow qua max-width/wrap) từng gây đè lên thẻ vì pill render RỘNG
   HƠN track chứa nó mà CSS không tự clip phần tràn. */
.article-content .timeline__item,
.ck-content .timeline__item {
  position: relative;
  display: grid;
  grid-template-columns: 1fr max-content 1fr;
  gap: 0 1.25rem;
  align-items: start;
  margin-top: 2rem;
}
.article-content .timeline > .timeline__item:first-child,
.ck-content .timeline > .timeline__item:first-child {
  margin-top: 0;
}
.article-content .timeline__side--left,
.ck-content .timeline__side--left {
  text-align: right;
}
.article-content .timeline__center,
.ck-content .timeline__center {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.375rem;
}
.article-content .timeline__dot,
.ck-content .timeline__dot {
  flex: none;
  width: 3rem;
  height: 3rem;
  border-radius: 9999px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.25rem;
  background: var(--card, var(--background, oklch(100% 0 0)));
  border: 3px solid var(--article-accent);
  box-shadow: var(--article-shadow-sm);
}
.article-content .timeline__dot.topic-1, .ck-content .timeline__dot.topic-1 { border-color: var(--article-topic-1); }
.article-content .timeline__dot.topic-2, .ck-content .timeline__dot.topic-2 { border-color: var(--article-topic-2); }
.article-content .timeline__dot.topic-3, .ck-content .timeline__dot.topic-3 { border-color: var(--article-topic-3); }
.article-content .timeline__dot.topic-4, .ck-content .timeline__dot.topic-4 { border-color: var(--article-topic-4); }
.article-content .timeline__dot.topic-5, .ck-content .timeline__dot.topic-5 { border-color: var(--article-topic-5); }
.article-content .timeline__dot.topic-6, .ck-content .timeline__dot.topic-6 { border-color: var(--article-topic-6); }
.article-content .timeline__dot.topic-7, .ck-content .timeline__dot.topic-7 { border-color: var(--article-topic-7); }
.article-content .timeline__dot.topic-8, .ck-content .timeline__dot.topic-8 { border-color: var(--article-topic-8); }
/* Nhãn năm dưới mỗi chấm mốc — dạng pill LUÔN 1 DÒNG (nowrap), không giới hạn
   max-width — vì cột giữa giờ đã "max-content" (xem .timeline__item ở trên), track
   tự nới đúng bằng bề rộng thật của pill nên không còn lý do phải cho xuống dòng hay
   ép hẹp lại nữa. VẪN giữ viền + box-shadow (khung pill rõ ràng) — chỉ nền đổi sang
   trắng/trung tính phẳng (--card) thay vì nền tint màu như trước, để không cạnh tranh
   với màu CHỮ (đổi theo topic-N khi có modifier, khớp giai đoạn) — màu giờ nằm ở chữ
   + viền, nền chỉ đóng vai trò khung nền trung tính cho dễ đọc. */
.article-content .timeline__year,
.ck-content .timeline__year {
  display: inline-block;
  white-space: nowrap;
  padding: 0.3125rem 0.875rem;
  border-radius: 0.75rem;
  font-size: 0.875rem;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.01em;
  color: var(--muted-foreground, oklch(50% 0.01 264));
  background: var(--card, var(--background, oklch(100% 0 0)));
  border: 1px solid var(--border, oklch(90% 0.005 264));
  box-shadow: var(--article-shadow-sm);
}
.article-content .timeline__year.topic-1, .ck-content .timeline__year.topic-1 { color: var(--article-topic-1); border-color: color-mix(in oklch, var(--article-topic-1) 55%, transparent); }
.article-content .timeline__year.topic-2, .ck-content .timeline__year.topic-2 { color: var(--article-topic-2); border-color: color-mix(in oklch, var(--article-topic-2) 55%, transparent); }
.article-content .timeline__year.topic-3, .ck-content .timeline__year.topic-3 { color: var(--article-topic-3); border-color: color-mix(in oklch, var(--article-topic-3) 55%, transparent); }
.article-content .timeline__year.topic-4, .ck-content .timeline__year.topic-4 { color: var(--article-topic-4); border-color: color-mix(in oklch, var(--article-topic-4) 55%, transparent); }
.article-content .timeline__year.topic-5, .ck-content .timeline__year.topic-5 { color: var(--article-topic-5); border-color: color-mix(in oklch, var(--article-topic-5) 55%, transparent); }
.article-content .timeline__year.topic-6, .ck-content .timeline__year.topic-6 { color: var(--article-topic-6); border-color: color-mix(in oklch, var(--article-topic-6) 55%, transparent); }
.article-content .timeline__year.topic-7, .ck-content .timeline__year.topic-7 { color: var(--article-topic-7); border-color: color-mix(in oklch, var(--article-topic-7) 55%, transparent); }
.article-content .timeline__year.topic-8, .ck-content .timeline__year.topic-8 { color: var(--article-topic-8); border-color: color-mix(in oklch, var(--article-topic-8) 55%, transparent); }
.article-content .timeline__card,
.ck-content .timeline__card {
  padding: 1rem 1.125rem;
  border-radius: var(--article-radius);
  border: 1px solid var(--border, oklch(90% 0.005 264));
  background: var(--card, var(--background, oklch(100% 0 0)));
  box-shadow: var(--article-shadow-sm);
  text-align: left;
  display: inline-block;
  width: 100%;
  transition: transform var(--article-duration) var(--article-ease), box-shadow var(--article-duration) var(--article-ease);
}
/* Hover lift — cùng token thời lượng/easing với .concept-card, .stat-card... (SECTION
   22) để cả hệ thống chuyển động đồng nhất; trước đây .timeline__card là card DUY
   NHẤT thiếu trạng thái hover trong khi mọi card khác đều có, tạo cảm giác "tĩnh, kém
   hoàn thiện" hơn phần còn lại của bài. */
.article-content .timeline__card:hover,
.ck-content .timeline__card:hover {
  transform: translateY(-2px);
  box-shadow: var(--article-shadow);
}
.article-content .timeline__card h4,
.ck-content .timeline__card h4 {
  margin: 0 0 0.375rem;
}
.article-content .timeline__card p,
.ck-content .timeline__card p {
  margin: 0;
}
/* Viền hông màu tăng 3px→4px, khớp độ dày trục dọc (SECTION 24.1 ::before, cũng 3px+)
   — cùng "trọng lượng nét vẽ" giữa các thành phần liên quan thay vì để viền thẻ mảnh
   hơn hẳn trục chính. */
.article-content .timeline__side--left .timeline__card,
.ck-content .timeline__side--left .timeline__card {
  border-right: 4px solid var(--article-accent);
}
.article-content .timeline__side--right .timeline__card,
.ck-content .timeline__side--right .timeline__card {
  border-left: 4px solid var(--article-accent);
}
.article-content .timeline__side--left .timeline__card.topic-1, .ck-content .timeline__side--left .timeline__card.topic-1,
.article-content .timeline__side--right .timeline__card.topic-1, .ck-content .timeline__side--right .timeline__card.topic-1 { border-color: var(--article-topic-1); }
.article-content .timeline__side--left .timeline__card.topic-2, .ck-content .timeline__side--left .timeline__card.topic-2,
.article-content .timeline__side--right .timeline__card.topic-2, .ck-content .timeline__side--right .timeline__card.topic-2 { border-color: var(--article-topic-2); }
.article-content .timeline__side--left .timeline__card.topic-3, .ck-content .timeline__side--left .timeline__card.topic-3,
.article-content .timeline__side--right .timeline__card.topic-3, .ck-content .timeline__side--right .timeline__card.topic-3 { border-color: var(--article-topic-3); }
.article-content .timeline__side--left .timeline__card.topic-4, .ck-content .timeline__side--left .timeline__card.topic-4,
.article-content .timeline__side--right .timeline__card.topic-4, .ck-content .timeline__side--right .timeline__card.topic-4 { border-color: var(--article-topic-4); }
.article-content .timeline__side--left .timeline__card.topic-5, .ck-content .timeline__side--left .timeline__card.topic-5,
.article-content .timeline__side--right .timeline__card.topic-5, .ck-content .timeline__side--right .timeline__card.topic-5 { border-color: var(--article-topic-5); }
.article-content .timeline__side--left .timeline__card.topic-6, .ck-content .timeline__side--left .timeline__card.topic-6,
.article-content .timeline__side--right .timeline__card.topic-6, .ck-content .timeline__side--right .timeline__card.topic-6 { border-color: var(--article-topic-6); }
.article-content .timeline__side--left .timeline__card.topic-7, .ck-content .timeline__side--left .timeline__card.topic-7,
.article-content .timeline__side--right .timeline__card.topic-7, .ck-content .timeline__side--right .timeline__card.topic-7 { border-color: var(--article-topic-7); }
.article-content .timeline__side--left .timeline__card.topic-8, .ck-content .timeline__side--left .timeline__card.topic-8,
.article-content .timeline__side--right .timeline__card.topic-8, .ck-content .timeline__side--right .timeline__card.topic-8 { border-color: var(--article-topic-8); }

@media (max-width: 700px) {
  /* Trục dồn về sát mép trái, mỗi mốc chỉ còn 1 cột nội dung bên phải —
     tránh nhồi 2 cột hẹp trên màn hình điện thoại. */
  .article-content .timeline::before,
  .ck-content .timeline::before {
    left: 1.375rem;
  }
  .article-content .timeline__item,
  .ck-content .timeline__item {
    grid-template-columns: max-content 1fr;
  }
  .article-content .timeline__side--left,
  .ck-content .timeline__side--left {
    display: none;
  }
  .article-content .timeline__side--right,
  .ck-content .timeline__side--right {
    text-align: left;
  }
  .article-content .timeline__side--right .timeline__card,
  .ck-content .timeline__side--right .timeline__card {
    border-left: 4px solid var(--article-accent);
  }
}

/* --- 24.2 Resource list — nhóm liên kết tài liệu/video có icon loại file ---
   Markup:
     <div class="resource-group">
       <div class="resource-group__header resource-group__header--doc">
         <span aria-hidden="true">📄</span>
         <h3>Tài liệu</h3>
         <span class="badge badge-outline">3 file</span>
       </div>
       <ul class="resource-list">
         <li>
           <a class="resource-link" href="/files/vi-du.pdf" download>
             <span class="resource-link__icon resource-link__icon--pdf">PDF</span>
             <span class="resource-link__info"><strong>Tên tài liệu</strong><small>Mô tả ngắn</small></span>
             <span class="resource-link__action">⬇</span>
           </a>
         </li>
       </ul>
     </div>
   Biến thể header: --doc (xanh lá), --video (đỏ). Biến thể icon: --pdf, --rar, --yt. */
.article-content .resource-group,
.ck-content .resource-group {
  border-radius: var(--article-radius);
  overflow: hidden;
  border: 1px solid var(--border, oklch(90% 0.005 264));
}
.article-content .resource-group__header,
.ck-content .resource-group__header {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.875rem 1.25rem;
  border-bottom: 1px solid var(--border, oklch(90% 0.005 264));
}
.article-content .resource-group__header h3,
.ck-content .resource-group__header h3 {
  flex: 1;
  margin: 0;
  font-size: 1.0625rem;
}
.article-content .resource-group__header--doc,
.ck-content .resource-group__header--doc {
  background: linear-gradient(135deg, var(--callout-success-icon), var(--callout-success-border));
  border-bottom-color: transparent;
}
.article-content .resource-group__header--doc h3,
.ck-content .resource-group__header--doc h3 {
  color: white;
}
.article-content .resource-group__header--video,
.ck-content .resource-group__header--video {
  background: linear-gradient(135deg, var(--callout-danger-icon), var(--callout-danger-border));
  border-bottom-color: transparent;
}
.article-content .resource-group__header--video h3,
.ck-content .resource-group__header--video h3 {
  color: white;
}
.article-content .resource-list,
.ck-content .resource-list {
  list-style: none;
  margin: 0;
  padding: 0.875rem 1rem;
  display: flex;
  flex-direction: column;
  gap: 0.625rem;
}
.article-content .resource-list li,
.ck-content .resource-list li {
  margin: 0;
  padding: 0;
}
.article-content .resource-link,
.ck-content .resource-link {
  display: flex;
  align-items: center;
  gap: 0.875rem;
  padding: 0.875rem 1rem;
  border-radius: var(--article-radius-sm);
  border: 1px solid var(--border, oklch(90% 0.005 264));
  background: var(--muted, oklch(96% 0.003 264));
  background-image: none;
  transition: border-color var(--article-duration) var(--article-ease), transform var(--article-duration-fast) var(--article-ease), background-color var(--article-duration) var(--article-ease);
}
.article-content .resource-link:hover,
.ck-content .resource-link:hover {
  border-color: var(--callout-success-border);
  background: var(--callout-success-bg);
  transform: translateY(-1px);
}
.article-content .resource-link--video:hover,
.ck-content .resource-link--video:hover {
  border-color: var(--callout-danger-border);
  background: var(--callout-danger-bg);
}
.article-content .resource-link__icon,
.ck-content .resource-link__icon {
  flex: none;
  width: 3rem;
  height: 3rem;
  border-radius: var(--article-radius-sm);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.6875rem;
  font-weight: 800;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  border: 1px solid transparent;
}
.article-content .resource-link__icon--pdf,
.ck-content .resource-link__icon--pdf {
  background: var(--callout-danger-bg);
  color: var(--callout-danger-icon);
  border-color: var(--callout-danger-border);
}
.article-content .resource-link__icon--rar,
.ck-content .resource-link__icon--rar {
  background: var(--callout-homework-bg);
  color: var(--callout-homework-icon);
  border-color: var(--callout-homework-border);
}
.article-content .resource-link__icon--yt,
.ck-content .resource-link__icon--yt {
  background: var(--callout-danger-bg);
  color: var(--callout-danger-icon);
  border-color: var(--callout-danger-border);
  font-size: 1.125rem;
}
.article-content .resource-link__info,
.ck-content .resource-link__info {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
}
.article-content .resource-link__info strong,
.ck-content .resource-link__info strong {
  font-size: 0.9375rem;
}
.article-content .resource-link__info small,
.ck-content .resource-link__info small {
  color: var(--muted-foreground, oklch(50% 0.01 264));
}
.article-content .resource-link__action,
.ck-content .resource-link__action {
  flex: none;
  width: 2.25rem;
  height: 2.25rem;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--article-radius-sm);
  background: var(--card, var(--background, oklch(100% 0 0)));
  border: 1px solid var(--border, oklch(90% 0.005 264));
  transition: background-color var(--article-duration) var(--article-ease), color var(--article-duration) var(--article-ease);
}
.article-content .resource-link:hover .resource-link__action,
.ck-content .resource-link:hover .resource-link__action {
  background: var(--callout-success-icon);
  color: white;
}
.article-content .resource-link--video:hover .resource-link__action,
.ck-content .resource-link--video:hover .resource-link__action {
  background: var(--callout-danger-icon);
}

/* --- 24.3 Person grid — thẻ nhân vật/tiểu sử (khung ảnh viền màu + mô tả dưới) ---
   Markup:
     <div class="person-grid">
       <div class="person-card topic-1">
         <div class="person-card__avatar"><img src="..." alt="Tên nhân vật"></div>
         <h4>Tên nhân vật</h4>
         <p class="person-card__years">2879 – 2524 TCN</p>
         <p>Mô tả ngắn 1-2 câu.</p>
       </div>
     </div>
   Không có ảnh thật: thay .person-card__avatar bằng
   <div class="person-card__avatar person-card__avatar--placeholder">👤</div>
   Port 1:1 từ CSS thật của hệ thống gốc (.lsd-person-card + .lsd-person-avatar +
   .lsd-avatar-img, dự án tdntest — lấy đúng từ DevTools computed styles, không suy
   luận): khung cố định 160×200px, radius 12px, shadow 0 2px 8px đen 10%, ảnh
   width/height 100% + object-fit:cover + object-position:top center. Chỉ đổi 2 chỗ
   bắt buộc để khớp hệ token dùng chung: nền --muted (thay --lsd-bg-warm) và viền
   3px màu topic-N (thay 1 màu cố định --lsd-border-accent) — giữ đúng vai trò "viền
   màu theo giai đoạn" đã có trong .lsd-person-avatar.gd1..6 gốc.
   Cần app/globals.css có 1 override RIÊNG cho `.person-card__avatar img` (đã thêm) để
   !important của `.rc-compact/.rc-spacious img` không ép lại width/height auto +
   margin, phá mất hiệu lực của width/height:100% ở đây.
   ĐÃ XÁC MINH TRỰC TIẾP (2026-08-27, chrome-devtools MCP mở thật
   https://tdntest.vn/blog-details/lich-su-cac-trieu-dai-phong-kien, ảnh "Lê Hoàn"):
   object-position:top center render đúng, nhân vật hiện rõ ngay từ đỉnh khung, không
   để hở khoảng trống — từng nghi ngờ sai (đổi thử sang "center") dựa trên ảnh crop
   giả lập bằng PIL tự dựng, hoá ra đọc lố tỉ lệ phần trang trí ở đỉnh ảnh gốc. Kết
   luận: khi có cách xác minh trên trang thật (MCP), ưu tiên hơn hẳn giả lập offline. */
.article-content .person-grid,
.ck-content .person-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 1rem;
}
.article-content .person-card,
.ck-content .person-card {
  padding: 1.25rem 1.125rem 1.125rem;
  border-radius: var(--article-radius);
  border: 1px solid var(--border, oklch(90% 0.005 264));
  background: var(--card, var(--background, oklch(100% 0 0)));
  box-shadow: var(--article-shadow-sm);
  text-align: center;
  transition: transform var(--article-duration) var(--article-ease), box-shadow var(--article-duration) var(--article-ease);
}
.article-content .person-card:hover,
.ck-content .person-card:hover {
  transform: translateY(-3px);
  box-shadow: var(--article-shadow);
}
.article-content .person-card > * + *,
.ck-content .person-card > * + * {
  margin-top: 0.625rem;
}
.article-content .person-card__avatar,
.ck-content .person-card__avatar {
  width: 10rem;
  height: 12.5rem;
  margin: 0 auto;
  border-radius: 0.75rem;
  overflow: hidden;
  background: var(--muted, oklch(96% 0.003 264));
  border: 3px solid var(--article-accent);
  box-shadow: 0 2px 8px oklch(0% 0 0 / 0.1);
}
.article-content .person-card__avatar img,
.ck-content .person-card__avatar img {
  width: 100%;
  height: 100%;
  display: block;
  object-fit: cover;
  object-position: top center;
}
.article-content .person-card__avatar--placeholder,
.ck-content .person-card__avatar--placeholder {
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 3rem;
}
.article-content .person-card__avatar.topic-1, .ck-content .person-card__avatar.topic-1 { border-color: var(--article-topic-1); }
.article-content .person-card__avatar.topic-2, .ck-content .person-card__avatar.topic-2 { border-color: var(--article-topic-2); }
.article-content .person-card__avatar.topic-3, .ck-content .person-card__avatar.topic-3 { border-color: var(--article-topic-3); }
.article-content .person-card__avatar.topic-4, .ck-content .person-card__avatar.topic-4 { border-color: var(--article-topic-4); }
.article-content .person-card__avatar.topic-5, .ck-content .person-card__avatar.topic-5 { border-color: var(--article-topic-5); }
.article-content .person-card__avatar.topic-6, .ck-content .person-card__avatar.topic-6 { border-color: var(--article-topic-6); }
.article-content .person-card__avatar.topic-7, .ck-content .person-card__avatar.topic-7 { border-color: var(--article-topic-7); }
.article-content .person-card__avatar.topic-8, .ck-content .person-card__avatar.topic-8 { border-color: var(--article-topic-8); }
/* Markup-contract đặt `topic-N` trên `.person-card` (xem comment 24.3 ở trên) — chấp
   nhận cả 2 chỗ: cascade màu viền xuống `.person-card__avatar` khi modifier nằm trên
   thẻ. (2 file lịch sử migrate trước đặt topic-N trên .person-card mà chưa có rule
   này nên avatar chỉ hiện màu accent mặc định.) */
.article-content .person-card.topic-1 .person-card__avatar, .ck-content .person-card.topic-1 .person-card__avatar { border-color: var(--article-topic-1); }
.article-content .person-card.topic-2 .person-card__avatar, .ck-content .person-card.topic-2 .person-card__avatar { border-color: var(--article-topic-2); }
.article-content .person-card.topic-3 .person-card__avatar, .ck-content .person-card.topic-3 .person-card__avatar { border-color: var(--article-topic-3); }
.article-content .person-card.topic-4 .person-card__avatar, .ck-content .person-card.topic-4 .person-card__avatar { border-color: var(--article-topic-4); }
.article-content .person-card.topic-5 .person-card__avatar, .ck-content .person-card.topic-5 .person-card__avatar { border-color: var(--article-topic-5); }
.article-content .person-card.topic-6 .person-card__avatar, .ck-content .person-card.topic-6 .person-card__avatar { border-color: var(--article-topic-6); }
.article-content .person-card.topic-7 .person-card__avatar, .ck-content .person-card.topic-7 .person-card__avatar { border-color: var(--article-topic-7); }
.article-content .person-card.topic-8 .person-card__avatar, .ck-content .person-card.topic-8 .person-card__avatar { border-color: var(--article-topic-8); }
.article-content .person-card h4,
.ck-content .person-card h4 {
  margin: 0;
}
.article-content .person-card__years,
.ck-content .person-card__years {
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--muted-foreground, oklch(50% 0.01 264));
}
.article-content .person-card p:not(.person-card__years),
.ck-content .person-card p:not(.person-card__years) {
  text-align: left;
  font-size: 0.875rem;
}

/* --- 24.4 Year badge — nhãn năm/khoảng năm nhỏ, tô màu theo topic-N ---
   Markup: <span class="year-badge topic-2">179 TCN – 905</span> */
.article-content .year-badge,
.ck-content .year-badge {
  display: inline-block;
  padding: 0.2rem 0.625rem;
  border-radius: var(--article-radius-sm);
  font-size: 0.8125rem;
  font-weight: 700;
  white-space: nowrap;
  background: transparent;
  border: 1.5px solid var(--border, oklch(90% 0.005 264));
  color: var(--muted-foreground, oklch(50% 0.01 264));
}
.article-content .year-badge.topic-1, .ck-content .year-badge.topic-1 { border-color: var(--article-topic-1); color: var(--article-topic-1); }
.article-content .year-badge.topic-2, .ck-content .year-badge.topic-2 { border-color: var(--article-topic-2); color: var(--article-topic-2); }
.article-content .year-badge.topic-3, .ck-content .year-badge.topic-3 { border-color: var(--article-topic-3); color: var(--article-topic-3); }
.article-content .year-badge.topic-4, .ck-content .year-badge.topic-4 { border-color: var(--article-topic-4); color: var(--article-topic-4); }
.article-content .year-badge.topic-5, .ck-content .year-badge.topic-5 { border-color: var(--article-topic-5); color: var(--article-topic-5); }
.article-content .year-badge.topic-6, .ck-content .year-badge.topic-6 { border-color: var(--article-topic-6); color: var(--article-topic-6); }
.article-content .year-badge.topic-7, .ck-content .year-badge.topic-7 { border-color: var(--article-topic-7); color: var(--article-topic-7); }
.article-content .year-badge.topic-8, .ck-content .year-badge.topic-8 { border-color: var(--article-topic-8); color: var(--article-topic-8); }

/* --- 24.5 Gloss — chú thích dịch/thuật ngữ chêm ngay trong câu văn ---
   Markup: Trận <strong>Bạch Đằng</strong> <em class="gloss">(Battle of Bạch Đằng)</em> năm 938... */
.article-content .gloss,
.ck-content .gloss {
  font-style: italic;
  font-size: 0.9em;
  color: var(--muted-foreground, oklch(50% 0.01 264));
}

/* --- 24.6 Note inline — 3 biến thể màu bổ sung + dạng gấp gọn (collapsible) ---
   .note-inline mặc định (SECTION 22.5) màu info/xanh dương — thêm 3 biến thể
   dùng chung khung. Dạng gấp gọn dùng thẳng <details>/<summary> (không JS,
   cùng kỹ thuật với FAQ accordion SECTION 22.10) khi ghi chú dài, không cần
   hiện ngay: <details class="note-inline note-inline--warning">
   <summary class="note-inline__label">Nhãn</summary><p>...</p></details> */
.article-content .note-inline--warning,
.ck-content .note-inline--warning {
  border-left-color: var(--callout-warning-border);
  background: linear-gradient(135deg, var(--callout-warning-bg), transparent);
}
.article-content .note-inline--warning .note-inline__label,
.ck-content .note-inline--warning .note-inline__label {
  color: var(--callout-warning-icon);
}
.article-content .note-inline--success,
.ck-content .note-inline--success {
  border-left-color: var(--callout-success-border);
  background: linear-gradient(135deg, var(--callout-success-bg), transparent);
}
.article-content .note-inline--success .note-inline__label,
.ck-content .note-inline--success .note-inline__label {
  color: var(--callout-success-icon);
}
.article-content .note-inline--tip,
.ck-content .note-inline--tip {
  border-left-color: var(--callout-tip-border);
  background: linear-gradient(135deg, var(--callout-tip-bg), transparent);
}
.article-content .note-inline--tip .note-inline__label,
.ck-content .note-inline--tip .note-inline__label {
  color: var(--callout-tip-icon);
}
.article-content details.note-inline,
.ck-content details.note-inline {
  cursor: default;
}
.article-content details.note-inline > .note-inline__label,
.ck-content details.note-inline > .note-inline__label {
  cursor: pointer;
  list-style: none;
  user-select: none;
}
.article-content details.note-inline > .note-inline__label::-webkit-details-marker,
.ck-content details.note-inline > .note-inline__label::-webkit-details-marker {
  display: none;
}
.article-content details.note-inline > .note-inline__label::before,
.ck-content details.note-inline > .note-inline__label::before {
  content: '\25B6';
  display: inline-block;
  margin-right: 0.25rem;
  font-size: 0.625rem;
  transition: transform var(--article-duration) var(--article-ease);
}
.article-content details.note-inline[open] > .note-inline__label::before,
.ck-content details.note-inline[open] > .note-inline__label::before {
  transform: rotate(90deg);
}

@media (max-width: 900px) {
  .article-content .person-grid,
  .ck-content .person-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}
@media (max-width: 700px) {
  .article-content .resource-list,
  .ck-content .resource-list {
    padding: 0.75rem;
  }
  /* Icon/nút thu nhỏ + gap hẹp lại một chút để đủ chỗ cho tiêu đề tài liệu
     trên điện thoại (≤ 375px) mà không phải cắt chữ giữa dòng. */
  .article-content .resource-link,
  .ck-content .resource-link {
    gap: 0.625rem;
    padding: 0.75rem;
  }
  .article-content .resource-link__icon,
  .ck-content .resource-link__icon {
    width: 2.5rem;
    height: 2.5rem;
  }
}
@media (max-width: 480px) {
  .article-content .person-grid,
  .ck-content .person-grid {
    grid-template-columns: 1fr;
  }
}

@media print {
  .article-content .timeline::before,
  .ck-content .timeline::before {
    display: none;
  }
  .article-content .resource-group__header--doc,
  .article-content .resource-group__header--video,
  .ck-content .resource-group__header--doc,
  .ck-content .resource-group__header--video {
    background: none;
    border-bottom: 1px solid #999;
  }
  .article-content .resource-group__header--doc h3,
  .article-content .resource-group__header--video h3,
  .ck-content .resource-group__header--doc h3,
  .ck-content .resource-group__header--video h3 {
    color: black;
  }
}

/* ============================================================================
 * SECTION 25 — FUN FACT, QUICK CHIP, GRADE BADGE
 * ============================================================================
 * Đúc rút từ "dia-li-viet-nam.css" (dự án tdntest). Cả 3 thành phần đều nhẹ,
 * bổ sung cho nhu cầu chưa có component riêng dù đã xuất hiện lặp lại ở nhiều
 * bài tham khảo (khoa-hoc-chat, lich-su, dia-li-viet-nam đều có biến thể của
 * "hộp mẹo/em có biết" và "chip liên kết nhanh" trong hero).
 * ============================================================================
 */

/* --- 25.1 Fun fact — hộp "Em có biết?" / "Mẹo nhớ nhanh" dùng LINH HOẠT ---
   Khác .memory-box (SECTION 22.7, cố định 1 cấu trúc icon+sequence+list) và
   .note-inline (SECTION 22.5, nhỏ gọn lồng trong card) — .fun-fact là 1 khối
   ĐỘC LẬP đứng giữa bài, LUÔN cùng 1 kiểu hiển thị nhưng nhãn tự do (tác giả
   tự đổi icon + text trong .fun-fact__label tuỳ ngữ cảnh: "🌟 Em có biết?",
   "🧠 Mẹo nhớ nhanh", "💡 Cần nhớ"...).
   Markup:
     <div class="fun-fact">
       <p class="fun-fact__label">🌟 Em có biết?</p>
       <p>Nội dung thú vị...</p>
     </div> */
.article-content .fun-fact,
.ck-content .fun-fact {
  padding: 0.875rem 1.125rem;
  border-radius: var(--article-radius);
  border: 1px solid var(--callout-tip-border);
  background: linear-gradient(135deg, var(--callout-tip-bg), transparent);
}
.article-content .fun-fact > * + *,
.ck-content .fun-fact > * + * {
  margin-top: 0.375rem;
}
.article-content .fun-fact__label,
.ck-content .fun-fact__label {
  margin: 0;
  font-weight: 700;
  font-size: 0.9375rem;
  color: var(--callout-tip-icon);
}
.article-content .fun-fact p,
.ck-content .fun-fact p {
  margin: 0;
  font-size: 0.9375rem;
}

/* --- 25.2 Quick chip — chip liên kết nhanh dạng viên thuốc (đầu bài/hero) ---
   Nhẹ hơn .resource-link (SECTION 24.2, cả khối card) — dùng khi chỉ cần 1
   hàng chip ngắn dẫn sang tài liệu/video mà không cần cả danh sách.
   Markup: <a class="quick-chip quick-chip--doc" href="#">📄 Tài liệu</a> */
.article-content .quick-chip,
.ck-content .quick-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  padding: 0.25rem 0.75rem;
  border-radius: 9999px;
  font-size: 0.8125rem;
  font-weight: 700;
  text-decoration: none;
  background-image: none;
  border: 1px solid transparent;
  transition: background-color var(--article-duration) var(--article-ease), color var(--article-duration) var(--article-ease), transform var(--article-duration-fast) var(--article-ease);
}
.article-content .quick-chip:hover,
.ck-content .quick-chip:hover {
  transform: translateY(-1px);
  background-image: none;
}
.article-content .quick-chip--doc,
.ck-content .quick-chip--doc {
  background: var(--callout-success-bg);
  color: var(--callout-success-icon);
  border-color: var(--callout-success-border);
}
.article-content .quick-chip--doc:hover,
.ck-content .quick-chip--doc:hover {
  background: var(--callout-success-icon);
  color: white;
}
.article-content .quick-chip--yt,
.ck-content .quick-chip--yt {
  background: var(--callout-danger-bg);
  color: var(--callout-danger-icon);
  border-color: var(--callout-danger-border);
}
.article-content .quick-chip--yt:hover,
.ck-content .quick-chip--yt:hover {
  background: var(--callout-danger-icon);
  color: white;
}

/* --- 25.3 Grade badge — nhãn khối lớp nhỏ, đặt cạnh heading/thẻ nội dung ---
   Markup: <h3>Địa hình đồi núi <span class="grade-badge grade-badge--l4">L4</span></h3> */
.article-content .grade-badge,
.ck-content .grade-badge {
  display: inline-flex;
  align-items: center;
  padding: 0.125rem 0.5rem;
  margin-left: 0.5rem;
  border-radius: var(--article-radius-sm);
  font-size: 0.6875rem;
  font-weight: 800;
  letter-spacing: 0.03em;
  vertical-align: middle;
  border: 1px solid transparent;
}
.article-content .grade-badge--l4,
.ck-content .grade-badge--l4 {
  background: var(--callout-info-bg);
  color: var(--callout-info-icon);
  border-color: var(--callout-info-border);
}
.article-content .grade-badge--l5,
.ck-content .grade-badge--l5 {
  background: var(--callout-warning-bg);
  color: var(--callout-warning-icon);
  border-color: var(--callout-warning-border);
}

/* ============================================================================
 * SECTION 26 — EXTRA TEACHING PATTERNS (đúc rút từ tvtl / ltt)
 * ============================================================================
 * Các khối trang trí nhỏ lặp nhiều trong bài luyện tập nhưng chưa có ở SECTION
 * 22–25: hộp đối chiếu Sai/Đúng, thẻ Hỏi→Đáp không gập, chuỗi bước dạng pill,
 * kho từ (chip), trích đoạn đọc hiểu đánh số dòng, dòng thời gian nhãn-trái.
 * Đúc rút từ 2 hệ thiết kế tdntest: "tieng-viet-noi-dung-on-luyen" (.tvtl-*) và
 * "lo-trinh-chinh-phuc-toan" (.ltt-*). Tái dùng token callout / --article-topic-N
 * / --primary đã có — KHÔNG thêm bảng màu mới.
 * ============================================================================
 */

/* --- 26.1 Compare — hộp đối chiếu "làm sai vs. làm đúng" ---
   Cho phần "lỗi thường gặp / cách sửa" ở mọi môn — thay vì xếp 2 .note-inline
   (--warning + --success) rời, gộp thành 1 khung viền chung, 2 cột.
   Markup:
     <div class="compare">
       <div class="compare__bad">
         <span class="compare__tag">✗ Sai</span>
         <p>"Biện pháp so sánh." — quá ngắn, thiếu dẫn câu.</p>
       </div>
       <div class="compare__good">
         <span class="compare__tag">✓ Đúng</span>
         <p>"Tác giả dùng biện pháp so sánh qua '…'. Biện pháp này giúp …".</p>
       </div>
     </div>
   2 cột trên màn rộng, xếp chồng ở ≤ 640px. Lặp nhiều .compare liền nhau được. */
.article-content .compare,
.ck-content .compare {
  display: grid;
  grid-template-columns: 1fr 1fr;
  border-radius: var(--article-radius);
  border: 1px solid var(--border, oklch(90% 0.005 264));
  overflow: hidden;
}
.article-content .compare + .compare,
.ck-content .compare + .compare {
  margin-top: 0.625rem;
}
.article-content .compare__bad,
.article-content .compare__good,
.ck-content .compare__bad,
.ck-content .compare__good {
  padding: 0.875rem 1rem;
  font-size: 0.875rem;
  line-height: 1.6;
}
.article-content .compare__bad,
.ck-content .compare__bad {
  background: linear-gradient(135deg, var(--callout-danger-bg), transparent);
  border-right: 1px solid var(--border, oklch(90% 0.005 264));
}
.article-content .compare__good,
.ck-content .compare__good {
  background: linear-gradient(135deg, var(--callout-success-bg), transparent);
}
.article-content .compare__bad > * + *,
.article-content .compare__good > * + *,
.ck-content .compare__bad > * + *,
.ck-content .compare__good > * + * {
  margin-top: 0.375rem;
}
.article-content .compare__bad > p:last-child,
.article-content .compare__good > p:last-child,
.ck-content .compare__bad > p:last-child,
.ck-content .compare__good > p:last-child {
  margin-bottom: 0;
}
.article-content .compare__tag,
.ck-content .compare__tag {
  display: inline-block;
  padding: 0.0625rem 0.5rem;
  border-radius: var(--article-radius-sm);
  font-size: 0.6875rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  background: var(--card, var(--background, white));
}
.article-content .compare__bad .compare__tag,
.ck-content .compare__bad .compare__tag {
  color: var(--callout-danger-icon);
  border: 1px solid var(--callout-danger-border);
}
.article-content .compare__good .compare__tag,
.ck-content .compare__good .compare__tag {
  color: var(--callout-success-icon);
  border: 1px solid var(--callout-success-border);
}

/* --- 26.2 QA card — cặp "câu hỏi → mẫu trả lời", KHÔNG gập ---
   Khác details.qa (SECTION 22.10, FAQ gập được): qa-card luôn hiện, dùng khi
   liệt kê "các dạng câu hỏi hay gặp + mẫu trả lời", "phân tích ví dụ"… Xếp
   chồng nhiều .qa-card thành 1 danh sách. Chip phân loại tuỳ chọn ở dòng câu hỏi.
   Markup:
     <div class="qa-card">
       <p class="qa-card__q">Đoạn văn nói về điều gì? <span class="badge badge-outline">Nội dung chính</span></p>
       <div class="qa-card__a">→ "Đoạn văn / bài thơ nói về …."</div>
     </div> */
.article-content .qa-card,
.ck-content .qa-card {
  border-radius: var(--article-radius-sm);
  border: 1px solid var(--border, oklch(90% 0.005 264));
  overflow: hidden;
}
.article-content .qa-card + .qa-card,
.ck-content .qa-card + .qa-card {
  margin-top: 0.5rem;
}
.article-content .qa-card__q,
.ck-content .qa-card__q {
  margin: 0;
  padding: 0.625rem 0.875rem;
  font-weight: 600;
  font-size: 0.9375rem;
  color: var(--foreground, oklch(21% 0.006 264));
  background: color-mix(in oklch, var(--primary, oklch(55% 0.18 265)) 7%, var(--card, var(--background, white)));
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
}
.article-content .qa-card__a,
.ck-content .qa-card__a {
  padding: 0.625rem 0.875rem;
  font-size: 0.9375rem;
  line-height: 1.65;
  color: var(--muted-foreground, oklch(50% 0.01 264));
  border-top: 1px solid var(--border, oklch(90% 0.005 264));
}
.article-content .qa-card__a > p,
.ck-content .qa-card__a > p {
  margin: 0;
}
.article-content .qa-card__a > * + *,
.ck-content .qa-card__a > * + * {
  margin-top: 0.4em;
}

/* --- 26.3 Flow — chuỗi bước dạng "viên thuốc" có mũi tên, tự xuống dòng ---
   Bản nâng cấp của .memory-box__seq (SECTION 22.7, chỉ là text "A → B → C"):
   mỗi bước là 1 pill tô màu. Dấu mũi tên là 1 <span class="flow__sep"> tường
   minh giữa các pill (giữ nguyên cách của tdntest — chắc chắn khi wrap dòng).
   Markup:
     <div class="flow">
       <span class="flow__step">Đọc đề</span>
       <span class="flow__sep">→</span>
       <span class="flow__step">Gạch từ khóa</span>
       <span class="flow__sep">→</span>
       <span class="flow__step">Viết đáp án</span>
     </div>
   Thêm .flow--topic-1..8 để đổi màu pill theo chủ đề con (mặc định --primary). */
.article-content .flow,
.ck-content .flow {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.375rem 0.25rem;
  --flow-color: var(--primary, oklch(55% 0.18 265));
}
.article-content .flow__step,
.ck-content .flow__step {
  display: inline-block;
  padding: 0.25rem 0.75rem;
  border-radius: 9999px;
  font-size: 0.8125rem;
  font-weight: 700;
  color: white;
  background: var(--flow-color);
}
.article-content .flow__sep,
.ck-content .flow__sep {
  color: var(--muted-foreground, oklch(50% 0.01 264));
  font-weight: 400;
}
.article-content .flow--topic-1, .ck-content .flow--topic-1 { --flow-color: var(--article-topic-1); }
.article-content .flow--topic-2, .ck-content .flow--topic-2 { --flow-color: var(--article-topic-2); }
.article-content .flow--topic-3, .ck-content .flow--topic-3 { --flow-color: var(--article-topic-3); }
.article-content .flow--topic-4, .ck-content .flow--topic-4 { --flow-color: var(--article-topic-4); }
.article-content .flow--topic-5, .ck-content .flow--topic-5 { --flow-color: var(--article-topic-5); }
.article-content .flow--topic-6, .ck-content .flow--topic-6 { --flow-color: var(--article-topic-6); }
.article-content .flow--topic-7, .ck-content .flow--topic-7 { --flow-color: var(--article-topic-7); }
.article-content .flow--topic-8, .ck-content .flow--topic-8 { --flow-color: var(--article-topic-8); }

/* --- 26.4 Chip list — kho từ / danh sách thuật ngữ ngắn dạng "viên thuốc" ---
   Cho "vốn từ theo chủ đề", danh sách công thức/thuật ngữ/từ khoá. Thêm 1
   <p class="chip-list__label"> phía trên để đặt tên nhóm.
   Markup:
     <p class="chip-list__label">🌿 Thiên nhiên</p>
     <div class="chip-list">
       <span class="chip">bầu trời</span>
       <span class="chip">mây trắng</span>
       <span class="chip">nắng vàng</span>
     </div> */
.article-content .chip-list,
.ck-content .chip-list {
  display: flex;
  flex-wrap: wrap;
  gap: 0.375rem;
}
.article-content .chip-list__label,
.ck-content .chip-list__label {
  margin: 0 0 0.375rem;
  font-size: 0.75rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--primary, oklch(55% 0.18 265));
}
.article-content .chip,
.ck-content .chip {
  display: inline-block;
  padding: 0.1875rem 0.625rem;
  border-radius: var(--article-radius-sm);
  font-size: 0.8125rem;
  background: var(--muted, oklch(96% 0.003 264));
  color: var(--foreground, oklch(21% 0.006 264));
  border: 1px solid var(--border, oklch(90% 0.005 264));
}

/* --- 26.5 Passage — trích đoạn đọc hiểu, tự đánh số dòng ---
   Cho bài luyện đọc hiểu (thơ / văn xuôi). Mỗi <p class="passage__line"> được
   đánh số "1." "2." … tự động; <p> thường (không có class) giữ lề bình thường;
   <cite> ở cuối để ghi nguồn.
   Markup:
     <div class="passage">
       <p class="passage__line">Quê hương là chùm khế ngọt,</p>
       <p class="passage__line">Cho con trèo hái mỗi ngày.</p>
       <cite>Đỗ Trung Quân</cite>
     </div> */
.article-content .passage,
.ck-content .passage {
  counter-reset: passage-line;
  padding: 0.875rem 1.125rem;
  border-radius: var(--article-radius);
  border: 1px solid var(--callout-example-border);
  background: linear-gradient(135deg, var(--callout-example-bg), transparent);
}
.article-content .passage__line,
.ck-content .passage__line {
  margin: 0;
  padding-left: 1.75rem;
  text-indent: -1.75rem;
  line-height: 1.9;
}
.article-content .passage__line::before,
.ck-content .passage__line::before {
  counter-increment: passage-line;
  content: counter(passage-line) ".";
  display: inline-block;
  width: 1.5rem;
  margin-right: 0.25rem;
  text-indent: 0;
  color: var(--muted-foreground, oklch(50% 0.01 264));
  font-size: 0.8125rem;
  font-weight: 600;
}
.article-content .passage cite,
.ck-content .passage cite {
  display: block;
  margin-top: 0.5rem;
  font-size: 0.8125rem;
  color: var(--muted-foreground, oklch(50% 0.01 264));
  text-align: right;
}
.article-content .passage cite::before,
.ck-content .passage cite::before {
  content: "— ";
}

/* --- 26.6 Roadmap — dòng thời gian đơn giản: nhãn giai đoạn trái | nội dung phải ---
   Nhẹ hơn .timeline (SECTION 24.1 — trục giữa, xen kẽ 2 bên). Cho lộ trình học,
   kế hoạch nhiều giai đoạn. Đúc rút từ "lo-trinh-chinh-phuc-toan.css" (ltt-timeline).
   Markup:
     <div class="roadmap">
       <div class="roadmap__row">
         <div class="roadmap__label topic-1">GĐ 1<small>Tuần 1–15</small></div>
         <div class="roadmap__body">
           <h4>Nền tảng số học</h4>
           <p>Xây nền lớp 4: số, phép tính, chia hết…</p>
         </div>
       </div>
     </div>
   .roadmap__label.topic-1..8 tô màu nhãn + viền trái của row (qua :has()). */
.article-content .roadmap,
.ck-content .roadmap {
  display: flex;
  flex-direction: column;
  gap: 0.875rem;
}
.article-content .roadmap__row,
.ck-content .roadmap__row {
  --roadmap-color: var(--primary, oklch(55% 0.18 265));
  display: grid;
  grid-template-columns: 6rem 1fr;
  gap: 1rem;
  align-items: start;
  padding: 1rem 1.125rem;
  border-radius: var(--article-radius);
  border: 1px solid var(--border, oklch(90% 0.005 264));
  border-left: 3px solid var(--roadmap-color);
  background: var(--card, var(--background, white));
  box-shadow: var(--article-shadow-sm);
}
.article-content .roadmap__label,
.ck-content .roadmap__label {
  display: flex;
  flex-direction: column;
  font-weight: 800;
  font-size: 1rem;
  color: var(--roadmap-color);
}
.article-content .roadmap__label small,
.ck-content .roadmap__label small {
  font-weight: 500;
  font-size: 0.6875rem;
  color: var(--muted-foreground, oklch(50% 0.01 264));
}
.article-content .roadmap__body > h4,
.ck-content .roadmap__body > h4 {
  margin: 0 0 0.25rem;
}
.article-content .roadmap__body > * + *,
.ck-content .roadmap__body > * + * {
  margin-top: 0.375rem;
}
.article-content .roadmap__row:has(.roadmap__label.topic-1), .ck-content .roadmap__row:has(.roadmap__label.topic-1) { --roadmap-color: var(--article-topic-1); }
.article-content .roadmap__row:has(.roadmap__label.topic-2), .ck-content .roadmap__row:has(.roadmap__label.topic-2) { --roadmap-color: var(--article-topic-2); }
.article-content .roadmap__row:has(.roadmap__label.topic-3), .ck-content .roadmap__row:has(.roadmap__label.topic-3) { --roadmap-color: var(--article-topic-3); }
.article-content .roadmap__row:has(.roadmap__label.topic-4), .ck-content .roadmap__row:has(.roadmap__label.topic-4) { --roadmap-color: var(--article-topic-4); }
.article-content .roadmap__row:has(.roadmap__label.topic-5), .ck-content .roadmap__row:has(.roadmap__label.topic-5) { --roadmap-color: var(--article-topic-5); }
.article-content .roadmap__row:has(.roadmap__label.topic-6), .ck-content .roadmap__row:has(.roadmap__label.topic-6) { --roadmap-color: var(--article-topic-6); }
.article-content .roadmap__row:has(.roadmap__label.topic-7), .ck-content .roadmap__row:has(.roadmap__label.topic-7) { --roadmap-color: var(--article-topic-7); }
.article-content .roadmap__row:has(.roadmap__label.topic-8), .ck-content .roadmap__row:has(.roadmap__label.topic-8) { --roadmap-color: var(--article-topic-8); }

@media (max-width: 640px) {
  .article-content .compare,
  .ck-content .compare {
    grid-template-columns: 1fr;
  }
  .article-content .compare__bad,
  .ck-content .compare__bad {
    border-right: none;
    border-bottom: 1px solid var(--border, oklch(90% 0.005 264));
  }
  .article-content .roadmap__row,
  .ck-content .roadmap__row {
    grid-template-columns: 1fr;
    gap: 0.5rem;
  }
}

@media print {
  .article-content .flow__step,
  .ck-content .flow__step,
  .article-content .table-group__badge,
  .ck-content .table-group__badge {
    background: none;
    color: black;
    border: 1px solid #999;
  }
  .article-content tr.table-group > td,
  .ck-content tr.table-group > td {
    background: none;
    border-top: 1px solid #999;
  }
}
