.bstory {
	--bstory-bg: #FAF8F4;
	--bstory-text: #262320;
	--bstory-text-strong: #2b2721;
	--bstory-muted: #857f74;
	--bstory-muted-2: #5c574f;
	--bstory-border: #e4ddd2;
	--bstory-border-light: #eee9de;
	--bstory-accent: #2f6f6a;
	--bstory-accent-hover: #265854;
	--bstory-accent-bg: #e7f0ee;
	--bstory-accent-text: #1f4f4b;
	--bstory-badge-bg: #efe9df;
	--bstory-badge-text: #423e37;
	--bstory-placeholder: #a39c8f;
	--bstory-surface: #fff;

	/* KHỔ NGANG DÙNG CHUNG cho MỌI khối của trang truyện — hero, thanh chuyển ngôn ngữ,
	   đoạn truyện, từ vựng, ý nghĩa, câu hỏi, footer. Mọi khối phải canh đúng một mép trái
	   và một mép phải; lệch một khối là nhìn ra ngay như lỗi dựng trang.
	   Đặt thành biến vì trang từng trôi mất bất biến này: có lúc tồn tại song song 3 khổ
	   (1040 cho hero/switcher/footer, 880 cho nội dung, 980 cho ảnh phá khung). Sửa ở đây
	   là cả trang đổi theo, không phải đi sửa 8 chỗ rời rạc.
	   Đổi số này cũng chính là đổi CHIỀU CAO ảnh đoạn truyện: ảnh khoá tỉ lệ 3:2 nên cao
	   = rộng x 0.5625 (1040px -> 585px). */
	--bstory-measure: 1040px;
	/* Độ dài dòng tối đa cho văn xuôi đọc liên tục ("Ý nghĩa & bài học", câu hỏi thảo
	   luận). Khổ ngang ở trên là cho KHUNG, không phải cho chữ: thả cho văn xuôi chạy hết
	   1040px thì mỗi dòng ~106 ký tự, quá dài.
	   90ch ~ 810px, tức giữ gần đúng bề rộng các mục này vốn có khi khổ nội dung còn là
	   880px. Từng thử 68ch cho "chuẩn sách" nhưng hẹp hơn hiện trạng tới 200px, đặt cạnh
	   bảng từ vựng chạy hết khổ thì lộ ra như hụt lề — chỉnh độ dài dòng phải nhìn cả khối
	   bên cạnh chứ không chỉ nhìn con số lý thuyết. */
	--bstory-prose: 90ch;

	font-family: 'Source Serif 4', Georgia, serif;
	font-size: 16px;
	color: var(--bstory-text);
	background: var(--bstory-bg);
	line-height: 1.5;
}

/* ===== Dark reading theme =====
   Custom properties scoped to .bstory — almost everything below reads color through
   these, so overriding them here is enough for the story content itself; no rule
   duplication needed. The site header/footer chrome lives outside .bstory (separate
   stylesheet, site-chrome.css) and can't see this attribute, so story.js also toggles
   Theme của TOÀN SITE do một class duy nhất trên <html> quyết định (`html.bstory-dark`,
   server in sẵn — xem bstory_html_dark_class). Mọi stylesheet đều thấy thẻ <html> nên
   không còn phải gắn cờ ở 2 nơi như trước. */
html.bstory-dark .bstory {
	--bstory-bg: #1c1a17;
	--bstory-text: #e8e3d9;
	--bstory-text-strong: #f2ede2;
	--bstory-muted: #a39a8c;
	--bstory-muted-2: #b9b0a1;
	--bstory-border: #3a352d;
	--bstory-border-light: #2e2a24;
	--bstory-accent: #6fb3ac;
	--bstory-accent-hover: #8cc5bf;
	--bstory-accent-bg: #24413f;
	--bstory-accent-text: #bfe6e1;
	--bstory-badge-bg: #2c2822;
	--bstory-badge-text: #d8d0c2;
	--bstory-placeholder: #8a8175;
	--bstory-surface: #2a2620;
}

.bstory a { color: var(--bstory-accent); }
.bstory a:hover { color: var(--bstory-accent-hover); }

/* ===== Hero ===== */
.bstory__hero {
	max-width: var(--bstory-measure);
	margin: 0 auto;
	padding: 48px 24px 32px;
	display: flex;
	gap: 40px;
	flex-wrap: wrap;
	align-items: center;
	border-bottom: 1px solid var(--bstory-border);
}
.bstory__hero-text { flex: 1 1 320px; min-width: 280px; }
.bstory__title-vi {
	font-family: 'Source Serif 4', Georgia, serif;
	font-size: 40px;
	line-height: 1.15;
	margin: 0 0 6px;
	font-weight: 600;
}
.bstory__title-en {
	font-family: 'Source Serif 4', Georgia, serif;
	font-size: 22px;
	line-height: 1.25;
	margin: 0 0 20px;
	font-weight: 400;
	font-style: italic;
	color: var(--bstory-muted-2);
}
.bstory__badges { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 22px; }
.bstory__badge {
	font-size: 13px;
	font-weight: 500;
	padding: 6px 12px;
	border-radius: 100px;
	text-decoration: none;
	display: inline-block;
}
.bstory__badge--neutral { background: var(--bstory-badge-bg); color: var(--bstory-badge-text); }
.bstory__badge--accent { background: var(--bstory-accent-bg); color: var(--bstory-accent-text); font-weight: 600; }
.bstory__badge--plain { background: transparent; color: var(--bstory-muted); padding: 6px 4px; }
a.bstory__badge--neutral:hover { color: var(--bstory-badge-text); background: var(--bstory-border); }

.bstory__hero-media { flex: 1 1 400px; min-width: 320px; max-width: 560px; }
.bstory__hero-media img {
	/* TỈ LỆ ẢNH = 2:1, và BA CHỖ PHẢI KHỚP NHAU: `STYLE_SUFFIX` trong prompt
	   ("2:1 wide landscape composition"), `size: 1536x768` gửi cho API, và mọi
	   `aspect-ratio` ở đây. Lệch một chỗ là object-fit:cover xén ngầm — đã dính ở
	   3.12.0 (prompt nói 16:9, khung vẽ thật 3:2, CSS ép lại 16:9 → mất 15,6% chiều cao).

	   3:2 → 2:1 ở 4.7.0 vì lý do đọc chứ không phải lý do ảnh: bố cục là TRANH TRÊN,
	   CHỮ DƯỚI, nên ảnh cao là mỗi đoạn một bức tường phải cuộn qua. Đo ở khổ 1040px,
	   truyện 40 đoạn: 3:2 cho trang cao 38.840px, 2:1 còn 31.920px (−18%).

	   Không đi dẹt hơn (16:7 / 3:1) vì luật đóng khung là FULL-LENGTH — nhân vật phải
	   thấy trọn từ đầu tới chân. Ở 2:1 ảnh còn cao 520px, đủ rõ mặt và tay; xuống 3:1
	   còn 347px thì nhân vật thành vệt nhỏ giữa hai bên trống, tức phải bỏ luôn luật
	   toàn thân — một quyết định khác hẳn, không phải chỉnh một con số.

	   MỌI khung hiện ảnh AI đều 2:1 (hero, đoạn, ý-nghĩa, thumb truyện liên quan, thẻ
	   lưới archive, thẻ demo trang chủ, thẻ lưới trang chủ). Ngoại lệ DUY NHẤT (trừ
	   `.bstory__media-embed` 16:9 — khung nhúng video, không phải ảnh sinh) là truyện
	   có `data-image-ratio="16:9"` — xem khối override ngay dưới CHUNG cho cả 7 khung,
	   dành cho truyện vẽ bằng Google Flow (không hỗ trợ 2:1, xem docs/decisions.md).
	   Truyện thường KHÔNG có attribute đó nên luật 2:1 gốc không đổi gì. */
	width: 100%;
	aspect-ratio: 2 / 1;
	object-fit: cover;
	border-radius: 12px;
	display: block;
}

/* ===== Audio controls ===== */
.bstory__audio-controls { display: flex; gap: 10px; flex-wrap: wrap; }
.bstory__audio-btn {
	display: flex;
	align-items: center;
	gap: 8px;
	border: none;
	padding: 12px 20px;
	border-radius: 8px;
	font-size: 14px;
	font-weight: 600;
	cursor: pointer;
	font-family: inherit;
	text-decoration: none; /* the "Xem video" control is an <a>, not a <button> */
}
.bstory__audio-btn--primary { background: var(--bstory-accent); color: #fff; }
.bstory__audio-btn--primary:hover { background: var(--bstory-accent-hover); }
.bstory__audio-btn--secondary { background: var(--bstory-surface); color: var(--bstory-accent); border: 1.5px solid var(--bstory-accent); }
.bstory__audio-btn--secondary:hover { background: var(--bstory-accent-bg); }
.bstory__audio-btn--youtube { background: var(--bstory-surface); color: var(--bstory-text); border: 1.5px solid var(--bstory-border); }
.bstory__audio-btn--youtube:hover { border-color: #ff0000; }

.bstory__audio-flag { display: inline-flex; flex: none; }
.bstory__audio-flag svg { display: block; border-radius: 2px; box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.08); }

/* Play icon shows while idle; swaps for an animated waveform once audio starts. */
.bstory__audio-icon { display: inline-flex; }
.bstory__audio-btn.is-playing .bstory__audio-icon { display: none; }
.bstory__audio-wave { display: none; align-items: flex-end; gap: 2.5px; height: 14px; }
.bstory__audio-btn.is-playing .bstory__audio-wave { display: flex; }
.bstory__audio-wave span {
	width: 3px;
	background: currentColor;
	border-radius: 1px;
	animation: bstory-wave 0.9s ease-in-out infinite;
}
.bstory__audio-wave span:nth-child(1) { height: 40%; animation-delay: 0s; }
.bstory__audio-wave span:nth-child(2) { height: 100%; animation-delay: 0.15s; }
.bstory__audio-wave span:nth-child(3) { height: 65%; animation-delay: 0.3s; }
.bstory__audio-wave span:nth-child(4) { height: 85%; animation-delay: 0.45s; }
@keyframes bstory-wave {
	0%, 100% { transform: scaleY(0.35); }
	50% { transform: scaleY(1); }
}
@media (prefers-reduced-motion: reduce) {
	.bstory__audio-wave span { animation: none; height: 70%; }
}

/* The underlying <audio> elements are controlled entirely via JS (play/pause/seek from
   the buttons + .bstory__audio-player below) — without `controls` they have no native UI
   of their own, but leaving them unstyled left an empty rendered box in some browsers. */
.bstory__audio-el { display: none; }

/* Real playback UI (seek bar + elapsed/duration) shown once a track starts, so listening
   isn't limited to "no scrubbing, no idea how long is left" — the language buttons above
   stay as the play/pause + language switch, this bar is purely transport controls.
   Waveform-bar texture (repeating-linear-gradient) + a gradient fill + a thumb dot dress
   up what would otherwise be a flat progress rectangle — a plain single-color bar read as
   "hơi đơn điệu" (too plain) when this first shipped. */
.bstory__audio-player {
	display: flex;
	align-items: center;
	gap: 16px;
	margin-top: 14px;
	padding: 0;
	background: transparent;
	border: none;
	max-width: 480px;
}
.bstory__audio-player[hidden] { display: none; }
.bstory__audio-player-toggle {
	flex: none;
	width: 44px;
	height: 44px;
	border-radius: 50%;
	border: none;
	background: linear-gradient(155deg, var(--bstory-accent), var(--bstory-accent-hover));
	color: #fff;
	display: flex;
	align-items: center;
	justify-content: center;
	cursor: pointer;
	font-size: 12px;
	padding: 0;
	box-shadow: 0 3px 10px rgba(47, 111, 106, 0.4);
	transition: transform 0.15s ease, box-shadow 0.15s ease;
}
.bstory__audio-player-toggle:hover { transform: scale(1.08); box-shadow: 0 4px 14px rgba(47, 111, 106, 0.5); }
.bstory__audio-player-toggle:active { transform: scale(0.94); }
.bstory__audio-player-toggle svg { width: 16px; height: 16px; }
.bstory__audio-player-icon-play,
.bstory__audio-player-icon-pause { display: inline-flex; }
.bstory__audio-player-icon-pause { display: none; }
.bstory__audio-player.is-playing .bstory__audio-player-icon-play { display: none; }
.bstory__audio-player.is-playing .bstory__audio-player-icon-pause { display: inline-flex; }
.bstory__audio-player-time {
	flex: none;
	font-variant-numeric: tabular-nums;
	font-size: 12.5px;
	font-weight: 700;
	color: var(--bstory-muted-2);
	min-width: 34px;
}
.bstory__audio-player.is-playing .bstory__audio-player-current { color: var(--bstory-accent); }
.bstory__audio-player-duration { text-align: right; color: var(--bstory-muted); font-weight: 600; }

/* Podcast-style waveform scrubber instead of a flat bar: a repeating tile of bars (see
   --bstory-waveform-tile below) is used as a CSS mask so the SAME svg shape can be
   recolored per theme via background-color (a masked background-image can't be
   recolored with currentColor/CSS vars the way an svg <rect fill> can). -bg is the full
   muted waveform; -fill is an identical masked layer clipped to width:pct% (set by JS,
   same technique the old flat bar used) so the played portion reads as solid accent
   bars against the muted unplayed ones — the two masks share the same px-based tile
   size/position so bars line up exactly at the fill's clip edge. */
.bstory {
	--bstory-waveform-tile: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2054%2024'%3E%3Cg%20fill='black'%3E%3Crect%20x='0'%20y='7'%20width='3'%20height='10'%20rx='1.5'/%3E%3Crect%20x='6'%20y='3'%20width='3'%20height='18'%20rx='1.5'/%3E%3Crect%20x='12'%20y='8'%20width='3'%20height='8'%20rx='1.5'/%3E%3Crect%20x='18'%20y='1'%20width='3'%20height='22'%20rx='1.5'/%3E%3Crect%20x='24'%20y='5'%20width='3'%20height='14'%20rx='1.5'/%3E%3Crect%20x='30'%20y='2'%20width='3'%20height='20'%20rx='1.5'/%3E%3Crect%20x='36'%20y='7.5'%20width='3'%20height='9'%20rx='1.5'/%3E%3Crect%20x='42'%20y='4'%20width='3'%20height='16'%20rx='1.5'/%3E%3Crect%20x='48'%20y='6'%20width='3'%20height='12'%20rx='1.5'/%3E%3C/g%3E%3C/svg%3E");
}
.bstory__audio-player-track {
	flex: 1;
	height: 24px;
	position: relative;
	cursor: pointer;
}
.bstory__audio-player-track::before {
	/* Invisible hit area taller than the 24px bars, so scrubbing doesn't require
	   pixel-precise clicks. */
	content: '';
	position: absolute;
	top: 50%;
	left: 0;
	right: 0;
	height: 32px;
	transform: translateY(-50%);
}
.bstory__audio-player-track-bg,
.bstory__audio-player-fill {
	position: absolute;
	top: 0;
	left: 0;
	height: 100%;
	mask-image: var(--bstory-waveform-tile);
	-webkit-mask-image: var(--bstory-waveform-tile);
	mask-repeat: repeat-x;
	-webkit-mask-repeat: repeat-x;
	mask-position: left center;
	-webkit-mask-position: left center;
	mask-size: 54px 24px;
	-webkit-mask-size: 54px 24px;
}
.bstory__audio-player-track-bg {
	width: 100%;
	background: var(--bstory-border);
	pointer-events: none;
}
.bstory__audio-player-fill {
	width: 0%;
	pointer-events: none;
	background: linear-gradient(90deg, var(--bstory-accent), var(--bstory-accent-hover));
	transition: width 0.1s linear;
}
.bstory__audio-player-thumb {
	position: absolute;
	top: 50%;
	left: 0%;
	width: 10px;
	height: 10px;
	border-radius: 50%;
	pointer-events: none;
	background: var(--bstory-accent-hover);
	border: 2px solid var(--bstory-surface);
	box-shadow: 0 1px 4px rgba(0, 0, 0, 0.35);
	transform: translate(-50%, -50%) scale(0.85);
	transition: left 0.1s linear, transform 0.15s ease;
}
.bstory__audio-player-track:hover .bstory__audio-player-thumb,
.bstory__audio-player.is-playing .bstory__audio-player-thumb {
	transform: translate(-50%, -50%) scale(1);
}

/* ===== Switcher =====
   The bar background is deliberately full-bleed (sticky nav convention), but the
   divider line is scoped to .bstory__switcher-inner — same max-width/centering as
   every other section — so it doesn't read as a stray full-width rule against the
   centered content below it. */
.bstory__switcher {
	position: sticky;
	top: 0;
	z-index: 10;
	background: var(--bstory-bg);
	box-shadow: 0 1px 0 rgba(0, 0, 0, 0.02);
	transition: transform 0.25s ease;
}
/* Hidden while scrolling down, slides back in on scroll up (story.js toggles this). */
.bstory__switcher.bstory__switcher--hidden { transform: translateY(-100%); }
@media (prefers-reduced-motion: reduce) {
	.bstory__switcher { transition: none; }
}
.bstory__switcher-inner {
	max-width: var(--bstory-measure);
	margin: 0 auto;
	padding: 14px 24px;
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 10px;
	flex-wrap: wrap;
	border-bottom: 1px solid var(--bstory-border);
}
.bstory__switcher-label { font-size: 13px; color: var(--bstory-muted); font-weight: 500; margin-right: 4px; }
.bstory__switcher-tabs { display: flex; background: var(--bstory-badge-bg); border-radius: 8px; padding: 3px; gap: 2px; }
.bstory__tab {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	height: 32px;
	border: none;
	border-radius: 6px;
	padding: 0 16px;
	font-size: 13px;
	font-weight: 600;
	font-family: inherit;
	line-height: 1;
	cursor: pointer;
	background: transparent;
	color: var(--bstory-muted-2);
}
.bstory__tab-label-short { display: none; }

.bstory__tab--active {
	background: var(--bstory-bg);
	color: var(--bstory-accent);
	box-shadow: inset 0 0 0 1.5px var(--bstory-accent);
}

/* ===== Reading controls (font size / dark / focus) =====
   Icon-only by design — a visible text label here would duplicate "Ngôn ngữ:" next
   to it; aria-label/aria-pressed carry the a11y meaning instead. */
.bstory__reading-controls { display: flex; align-items: center; gap: 8px; margin-left: auto; }
.bstory__font-size-group { display: flex; background: var(--bstory-badge-bg); border-radius: 8px; padding: 3px; gap: 2px; }
.bstory__font-btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	height: 32px;
	border: none;
	border-radius: 6px;
	padding: 0 10px;
	font-family: inherit;
	font-weight: 600;
	cursor: pointer;
	background: transparent;
	color: var(--bstory-muted-2);
	line-height: 1;
}
.bstory__font-btn--sm { font-size: 12px; }
.bstory__font-btn--md { font-size: 15px; }
.bstory__font-btn--lg { font-size: 18px; }
.bstory__font-btn--active { background: var(--bstory-accent); color: #fff; }
.bstory__control-btn {
	display: flex;
	align-items: center;
	justify-content: center;
	width: 32px;
	height: 32px;
	border: none;
	border-radius: 8px;
	background: var(--bstory-badge-bg);
	color: var(--bstory-muted-2);
	cursor: pointer;
	padding: 0;
}
.bstory__control-btn:hover { background: var(--bstory-border); }
.bstory__control-btn[aria-pressed="true"] { background: var(--bstory-accent); color: #fff; }

/* Theme button shows a sun icon in light mode, a moon icon once dark is active. */
.bstory__icon-moon { display: none; }
.bstory__control-btn[aria-pressed="true"] .bstory__icon-sun { display: none; }
.bstory__control-btn[aria-pressed="true"] .bstory__icon-moon { display: block; }

/* ===== Font-size presets =====
   Only the continuous-reading copy scales (story text + analysis) — headings and
   reference material (glossary table, discussion list) stay put. */
.bstory[data-font-size="sm"] .bstory__seg-text,
.bstory[data-font-size="sm"] .bstory__analysis-body,
.bstory[data-font-size="sm"] .bstory__discussion-item { font-size: 16px; line-height: 1.7; }
.bstory[data-font-size="lg"] .bstory__seg-text,
.bstory[data-font-size="lg"] .bstory__analysis-body,
.bstory[data-font-size="lg"] .bstory__discussion-item { font-size: 20px; line-height: 1.8; }

/* ===== Focus mode =====
   Hides everything but the hero title, the switcher (still needed to change language
   or exit focus), and the story text itself. */
.bstory[data-focus="on"] .bstory__hero-media,
.bstory[data-focus="on"] .bstory__badges,
.bstory[data-focus="on"] .bstory__audio-controls,
.bstory[data-focus="on"] .bstory__glossary,
.bstory[data-focus="on"] .bstory__analysis,
.bstory[data-focus="on"] .bstory__discussion,
.bstory[data-focus="on"] .bstory__media,
.bstory[data-focus="on"] .bstory__footer { display: none; }

/* ===== Story segments ===== */
.bstory__story { max-width: var(--bstory-measure); margin: 0 auto; padding: 40px 24px 8px; }
.bstory__segment { margin-bottom: 20px; padding-bottom: 20px; border-bottom: 1px solid var(--bstory-border-light); }
/* TRANH TRÊN, CHỮ DƯỚI, xếp chồng — mỗi đoạn là một khối: ảnh chạy hết khổ rồi tới đoạn
   văn. Đây là kiểu thứ BA của khối này; hai kiểu trước đều bị bỏ vì lý do rõ ràng:
   - 2 cột 60:40 xen kẽ trái/phải: ảnh chỉ còn ~40% bề ngang (385px ở khổ 992) nên chi tiết
     tranh nhỏ hẳn, mà tranh là thứ đáng xem nhất trên trang này.
   - "immersive" (ảnh tràn khổ, chữ đè lên đáy trên lớp scrim, tới 2.0.1): scrim che mất
     38-48% chiều cao tranh — đo trên chính trang Tấm Cám. Rút scrim ngắn lại vẫn không đủ.
   Xếp chồng thì trang dài hơn hẳn (Tấm Cám 49 đoạn ≈ 15.500px), đó là cái giá đã biết và
   chấp nhận: đổi lại tranh được xem trọn vẹn ở khổ lớn nhất có thể.
   Thứ tự ảnh-trước-chữ đặt thẳng trong HTML (xem class-story-renderer.php), KHÔNG dùng
   `order` — thứ tự nhìn thấy khớp thứ tự DOM. */
.bstory__segment-body { display: block; }
.bstory__seg-image-wrap {
	display: block;
	position: relative;
	width: 100%;
	/* 3:2 — ĐÚNG bằng khung 1536×1024 mà API sinh ra, và đúng tỉ lệ ghi trong
	   STYLE_SUFFIX. Trước đây khung là 16:9 nên `object-fit: cover` xén mất 15,6%
	   chiều cao (khoảng 8% trên + 8% dưới) — nhân vật đã vẽ tới đầu gối lại còn bị
	   cắt thêm hai đầu. Đổi số này là phải đổi CẢ hai chỗ kia, nếu không lại lệch. */
	aspect-ratio: 2 / 1;
	/* margin-BOTTOM: ảnh đứng TRƯỚC chữ nên khoảng cách nằm ở phía dưới. */
	margin: 0 0 18px;
	border-radius: 14px;
	overflow: hidden;
	box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05), 0 6px 20px rgba(0, 0, 0, 0.10);
	cursor: zoom-in;
}
.bstory__seg-image { display: block; width: 100%; height: 100%; object-fit: cover; transition: transform 0.3s ease; }
.bstory__seg-image-wrap:hover .bstory__seg-image,
.bstory__seg-image-wrap:focus-visible .bstory__seg-image { transform: scale(1.06); }
.bstory__seg-image-zoom {
	position: absolute;
	right: 10px;
	bottom: 10px;
	display: flex;
	align-items: center;
	justify-content: center;
	width: 30px;
	height: 30px;
	border-radius: 50%;
	background: rgba(0, 0, 0, 0.55);
	color: #fff;
	opacity: 0;
	transform: scale(0.85);
	transition: opacity 0.2s ease, transform 0.2s ease;
}
.bstory__seg-image-wrap:hover .bstory__seg-image-zoom,
.bstory__seg-image-wrap:focus-visible .bstory__seg-image-zoom { opacity: 1; transform: scale(1); }
.bstory__seg-image-wrap:focus-visible { outline: 2px solid var(--bstory-accent); outline-offset: 2px; }
/* Lightbox: single shared overlay appended once to <body> by initSegImageLightbox()
   in story.js, reused for every segment image instead of building one modal per
   image — click/tap opens it at a larger size (the 'large' attachment URL already
   generated for the thumbnail, no separate full-size request). */
.bstory__lightbox {
	position: fixed;
	inset: 0;
	z-index: 9999;
	display: flex;
	align-items: center;
	justify-content: center;
	padding: 32px;
	background: rgba(20, 18, 14, 0.88);
	opacity: 0;
	pointer-events: none;
	transition: opacity 0.2s ease;
}
.bstory__lightbox.is-open { opacity: 1; pointer-events: auto; }
.bstory__lightbox img {
	max-width: 100%;
	max-height: 100%;
	border-radius: 10px;
	box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5);
}
.bstory__lightbox-close {
	position: absolute;
	top: 20px;
	right: 20px;
	display: flex;
	align-items: center;
	justify-content: center;
	width: 40px;
	height: 40px;
	border-radius: 50%;
	border: none;
	background: rgba(255, 255, 255, 0.12);
	color: #fff;
	cursor: pointer;
}
.bstory__lightbox-close:hover { background: rgba(255, 255, 255, 0.22); }
/* Song song (VI/EN side by side) already narrows each column to fit two languages —
   a per-segment illustration on top of that would squeeze the columns further and add
   little since the same image doesn't carry separate VI/EN meaning anyway. */
.bstory[data-mode="parallel"] .bstory__seg-image-wrap { display: none; }
.bstory__segment-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); gap: 28px; }
.bstory__seg-text {
	font-family: 'Source Serif 4', Georgia, serif;
	font-size: 18px;
	line-height: 1.75;
	color: var(--bstory-text-strong);
	margin: 0;
}
.bstory__seg-lang-tag {
	font-size: 11px;
	font-weight: 700;
	letter-spacing: 0.06em;
	color: var(--bstory-placeholder);
	display: block;
	margin-bottom: 6px;
}

/* Reading mode: VI/EN both stay in the DOM always; only display toggles. */
.bstory[data-mode="vi"] .bstory__segment-grid,
.bstory[data-mode="en"] .bstory__segment-grid { grid-template-columns: 1fr; }
.bstory[data-mode="vi"] .bstory__seg-text--en,
.bstory[data-mode="en"] .bstory__seg-text--vi { display: none; }

/* The VI/EN lang tag only earns its keep when both columns are visible side by side. */
.bstory[data-mode="vi"] .bstory__seg-lang-tag,
.bstory[data-mode="en"] .bstory__seg-lang-tag { display: none; }

/* ===== Glossary ===== */
.bstory__glossary { max-width: var(--bstory-measure); margin: 0 auto; padding: 24px 24px 36px; }
.bstory__section-title { font-family: 'Source Serif 4', Georgia, serif; font-size: 24px; font-weight: 600; margin: 0 0 6px; }
/* Lưới thẻ thay cho <table> 5 cột (Phiên 11). Bảng cũ nhồi 5 cột vào khổ 992px nên ô nào
   cũng gãy chữ, và cột "Loại từ" còn HẸP HƠN CHÍNH TIÊU ĐỀ của nó (nội dung chỉ "n."/
   "adj." — bảng auto-layout chia cột theo nội dung chứ không theo tiêu đề). Thẻ thì mỗi
   mục tự do xuống dòng, không cột nào bóp cột nào.
   Bỏ luôn được `overflow-x: auto` + `min-width: 560px` của bảng cũ: mobile giờ về 1 cột
   chứ không phải cuộn ngang.
   Dùng CHUNG quy cách với .bstory__discussion-list ngay dưới (cùng gap, cùng ngưỡng 820px,
   cùng nền/viền/bo góc) — hai lưới thẻ cạnh nhau mà lệch nhau vài px thì lộ ngay. */
.bstory__glossary-list {
	/* 24px khớp đúng .bstory__discussion-list và .bstory__analysis-panel — cả ba mục dùng
	   chung một khoảng cách tiêu đề→nội dung (section-title margin-bottom 6 + 24 = 30). */
	margin: 24px 0 0;
	padding: 0;
	display: grid;
	gap: 14px;
}
@media (min-width: 820px) {
	.bstory__glossary-list { grid-template-columns: 1fr 1fr; }
}
/* Thân thẻ dùng --bstory-surface (trắng) + viền, KHÔNG phải một bậc teal nhạt nữa.
   Từng thử thân thẻ #f2f7f5 trên nền trang #FAF8F4: lệch đúng 8 điểm ở kênh đỏ và 1 điểm
   ở hai kênh còn lại — thẻ gần như vô hình, dải trên lệch tiếp 11/7/7 cũng mờ nốt. Ba tông
   gần trùng nhau xếp chồng thì mắt phải căng ra tìm mép thẻ.
   Nguyên tắc rút ra: MỘT bước phân định rõ ăn đứt hai bước mờ. Giờ nền trang → thẻ tách
   bằng viền (dứt khoát, không phụ thuộc chênh lệch màu), thẻ → dải trên tách bằng cả một
   bậc teal đầy (#fff so với #e7f0ee).
   Dải teal vẫn là thứ phân biệt lưới này với lưới thẻ Câu hỏi thảo luận phía dưới — nửa
   dưới trang có 16 thẻ, phải khác nhau ở đâu đó thì mới không thành một biển thẻ giống hệt.
   overflow:hidden để dải nền của <dt> bị bo góc cắt theo thẻ. */
.bstory__glossary-card {
	background: var(--bstory-surface);
	border: 1px solid var(--bstory-border);
	border-radius: 14px;
	overflow: hidden;
	font-family: 'Source Serif 4', Georgia, serif;
}
/* Chia đôi kiểu thẻ học từ: <dt> là "mặt trước" (từ tiếng Anh) trên nền teal đậm hơn một
   bậc, <dd> là "mặt sau" (nghĩa). Hai vùng phân định bằng CHÊNH LỆCH NỀN chứ không bằng
   đường kẻ — đã bỏ viền thẻ thì thêm kẻ ngang bên trong là mâu thuẫn.
   Đây là cấu trúc thật chứ không phải trang trí: nội dung vốn có đúng hai phần.
   baseline (không phải center): từ 17px, loại từ 13px và IPA 13.5px cao khác nhau — canh
   giữa thì ba thứ nổi lềnh bềnh, canh baseline thì chúng ngồi chung một đường chân chữ. */
.bstory__glossary-term {
	display: flex;
	align-items: baseline;
	gap: 8px;
	margin: 0;
	padding: 13px 18px;
	background: var(--bstory-accent-bg);
}
/* Chữ nằm trong MỘT ô flex riêng (không phải 3 ô anh em với nút): ở khổ hẹp, từ dài kèm
   IPA phải tự xuống dòng bên trong ô của nó. Để cả 4 thứ làm ô ngang hàng thì nút lật bị
   đẩy hẳn xuống một dòng trống riêng — thẻ "poisoned needle" cao 90px trong khi 9 thẻ còn
   lại 57px. `flex: 1` cũng thay luôn `margin-left: auto` để đẩy nút về sát mép phải. */
.bstory__glossary-term-text {
	flex: 1;
	min-width: 0;
	display: flex;
	flex-wrap: wrap;
	align-items: baseline;
	gap: 8px;
}
.bstory__glossary-en { font-weight: 600; font-size: 17px; color: var(--bstory-accent-text); }
/* Loại từ + IPA dùng CÙNG --bstory-accent-text với từ chính, phân cấp bằng cỡ chữ và
   dáng nghiêng chứ không bằng độ nhạt. Từng để --bstory-accent: chỉ 5.02:1 trên nền teal,
   đủ AA nhưng với chữ nghiêng 13px nét mảnh thì vẫn đọc ra là mờ. Biến này cho 7.94:1. */
.bstory__glossary-pos { font-style: italic; font-size: 13px; color: var(--bstory-accent-text); }
/* IPA dùng chính Source Serif nghiêng, KHÔNG dùng monospace: máy không có SF Mono/Roboto
   Mono sẽ rơi về monospace hệ thống (DejaVu/Courier tuỳ máy), nét và bề rộng khác hẳn chữ
   xung quanh nên khối chữ trông vá víu — mà cũng chẳng được gì, phiên âm không cần các ký
   tự thẳng cột như code. */
.bstory__glossary-ipa { font-size: 13.5px; font-style: italic; color: var(--bstory-accent-text); }

/* Nút nghe phát âm. Đặt NGAY SAU từ trong cùng ô chữ (không phải mép phải cạnh "Xem
   nghĩa"): mắt phải nối được nút với từ nó đọc. Nền trong suốt, chỉ là một icon nhỏ —
   nó là công cụ phụ, không được tranh vai với từ vựng. */
.bstory__glossary-say {
	flex: none;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 26px;
	height: 26px;
	padding: 0;
	border: 0;
	border-radius: 50%;
	background: transparent;
	color: var(--bstory-accent-text);
	opacity: 0.75;
	cursor: pointer;
	/* Icon canh theo dòng chữ chứ không theo baseline: ô chữ là flex baseline, để mặc thì
	   loa bị đẩy tụt xuống dưới chân chữ. */
	align-self: center;
	transition: opacity 0.18s ease, background-color 0.18s ease, transform 0.18s ease;
}
.bstory__glossary-say:hover { opacity: 1; background: rgba(255, 255, 255, 0.1); }
.bstory__glossary-say:focus-visible { outline: 2px solid var(--bstory-accent-text); outline-offset: 2px; }
/* Đang phát: sáng hẳn lên và nhích to một chút. Đủ để biết máy đã nhận lệnh, mà không
   nhấp nháy — từ chỉ dài một hai giây, hiệu ứng lặp sẽ giật. */
.bstory__glossary-say.is-playing {
	opacity: 1;
	background: rgba(255, 255, 255, 0.16);
	transform: scale(1.12);
}
/* <dd> mặc định thụt vào 40px — phải reset, không thì nghĩa lệch hẳn so với từ. */
.bstory__glossary-def { margin: 0; padding: 14px 18px 16px; }
/* Nghĩa để màu chữ THƯỜNG, không teal: từ tiếng Anh ở dải trên đã là teal rồi, hai dòng
   cùng màu nhấn thì không còn dòng nào được nhấn. */
.bstory__glossary-vi { display: block; font-size: 16.5px; font-weight: 600; color: var(--bstory-text-strong); }
.bstory__glossary-note { display: block; margin-top: 6px; font-size: 14.5px; line-height: 1.55; color: var(--bstory-muted-2); }

/* ===== Chế độ đố (flashcard thật) =====
   Cùng cơ chế với switcher VI/EN, dark mode và chế độ tập trung: JS chỉ đặt data-quiz
   trên .bstory, CSS lo ẩn/hiện. Phần nghĩa LUÔN nằm trong DOM, chỉ bị CSS giấu — không
   bao giờ được xoá node, y như quy tắc của switcher (Google phải crawl được).
   Googlebot có localStorage rỗng nên luôn nhận trạng thái mặc định TẮT, thấy đủ nội dung. */
.bstory__glossary-head {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 16px;
	flex-wrap: wrap;
}
.bstory__glossary-head .bstory__section-title { margin-bottom: 0; }
.bstory__quiz-toggle {
	display: inline-flex;
	align-items: center;
	gap: 7px;
	font-family: 'Source Sans 3', 'Segoe UI', system-ui, sans-serif;
	font-size: 13px;
	font-weight: 600;
	color: var(--bstory-accent-text);
	background: none;
	border: 1px solid var(--bstory-border);
	border-radius: 99px;
	padding: 6px 14px;
	cursor: pointer;
}
.bstory__quiz-toggle:hover { border-color: var(--bstory-accent); }
.bstory__quiz-toggle[aria-pressed="true"] {
	background: var(--bstory-accent-bg);
	border-color: transparent;
}
/* Chỉ trong chế độ đố mới bỏ giãn đều chiều cao: thẻ đã lật cao lên mà thẻ chưa lật cùng
   hàng bị kéo theo thì nó thành một hộp trắng RỖNG, nhìn như lỗi. Ngoài chế độ đố vẫn giữ
   stretch mặc định vì lúc đó thẻ nào cũng có nội dung, cao đều mới gọn. */
.bstory[data-quiz="on"] .bstory__glossary-list { align-items: start; }
/* Nút lật: chỉ tồn tại về mặt thị giác khi đang bật chế độ đố VÀ thẻ chưa lật. */
.bstory__glossary-reveal { display: none; }
.bstory[data-quiz="on"] .bstory__glossary-card:not([data-revealed]) .bstory__glossary-reveal {
	display: inline-block;
	flex: none;
	font-family: 'Source Sans 3', 'Segoe UI', system-ui, sans-serif;
	font-size: 12px;
	font-weight: 600;
	color: var(--bstory-accent-text);
	background: var(--bstory-surface);
	border: 1px solid var(--bstory-border);
	border-radius: 99px;
	padding: 4px 12px;
	cursor: pointer;
}
.bstory[data-quiz="on"] .bstory__glossary-card:not([data-revealed]) .bstory__glossary-reveal:hover {
	border-color: var(--bstory-accent);
}
.bstory[data-quiz="on"] .bstory__glossary-card:not([data-revealed]) .bstory__glossary-def { display: none; }

/* ===== Analysis =====
   Same max-width/margin as glossary/story above so every section's left AND
   right edge lines up when the page is centered. */
.bstory__analysis { max-width: var(--bstory-measure); margin: 0 auto; padding: 24px 24px 36px; }
/* Mục này viết CHO NGƯỜI LỚN đọc cùng bé, không phải phần tiếp của truyện — trước đây nó
   được trình bày y hệt văn truyện nên chìm nghỉm.
   Từ Phiên 11 KHÔNG còn tấm nền màu. Tấm nền cũ ôm gần 400px: callout to bằng cả một
   section thì thôi không còn là callout, chỉ còn là mảng màu. Thay vào đó khối tự tách
   bằng 2 thứ nhẹ hơn — câu bài học rút gọn cỡ lớn màu accent, và một cột ảnh bên phải.
   Nhãn "Dành cho người lớn đọc cùng bé" đã BỎ HẲN (từng là chip, rồi hạ xuống làm dòng
   phụ dưới h3, rồi bỏ). Nó nói về NGƯỜI ĐỌC chứ không nói gì về nội dung, mà cả site vốn
   đã là truyện cho bé và ba mẹ — nhắc riêng ở mục này là nhắc lại điều đúng với toàn
   trang. Nó chỉ có nghĩa hồi còn tấm nền màu, khi khối này trông như một callout tách
   biệt cần chú thích. Giờ h3 đi thẳng vào câu bài học: ba tầng nhãn còn một.
   margin-top 24px khớp đúng khoảng cách tiêu đề→nội dung của mục Câu hỏi thảo luận
   (title margin-bottom 6 + list margin-top 24), để hai mục liền nhau cùng nhịp. */
.bstory__analysis-panel { margin-top: 24px; }
/* Ảnh THẢ NỔI bên phải, KHÔNG phải lưới 2 cột. Đã thử lưới 2 cột và hỏng: đoạn phân tích
   ~700 ký tự nhét vào cột hẹp thì cao hơn ảnh 3:2 cả trăm px, đẻ ra một lỗ hình chữ L cố
   định; tệ hơn là độ dài đoạn khác nhau theo từng truyện nên lỗ đó lúc to lúc nhỏ — bố
   cục phụ thuộc độ dài chữ là bố cục hỏng. Float thì chữ chạy vòng qua ảnh rồi tiếp tục
   xuống dưới nó, dài ngắn bao nhiêu cũng lấp kín, không bao giờ có lỗ.
   flow-root để khối chứa ôm trọn chiều cao float — thiếu nó, truyện có đoạn phân tích
   ngắn hơn ảnh sẽ bị ảnh tràn xuống đè lên phần Câu hỏi thảo luận. */
.bstory__analysis-panel--with-image { display: flow-root; }
/* Ảnh CỐ Ý nhỏ hơn khổ chung và có bo góc, KHÔNG tràn khổ như ảnh đoạn truyện: tới đây
   người đọc vừa cuộn qua vài chục ảnh tràn khổ, một tấm nữa cùng kiểu sẽ đọc ra như đoạn
   truyện tiếp theo chứ không như phần đúc kết. Khác cỡ + khác lề = khác vai trò.
   3:2 = ĐÚNG tỉ lệ gốc ảnh do module sinh ảnh trả về (1536x1024), nên ở đây ảnh không bị
   cắt chút nào — giống ảnh đoạn truyện, cả hai đều 3:2 từ 3.12.0. */
.bstory__analysis-image {
	display: block;
	width: 100%;
	aspect-ratio: 2 / 1;
	object-fit: cover;
	border-radius: 14px;
	/* Bố cục dọc (màn hẹp): ảnh nằm TRÊN chữ, nên chừa lề dưới. */
	margin: 0 0 22px;
}
/* PHẢI đứng SAU rule gốc ở trên: cùng độ đặc hiệu nên rule viết sau mới thắng — đặt media
   query lên trước thì `width: 100%` đè mất `width: 340px` và ảnh float chiếm trọn khổ. */
@media (min-width: 940px) {
	.bstory__analysis-image {
		float: right;
		/* 340px (không phải 420): float càng rộng thì phần dòng chữ chạy cạnh nó càng ngắn,
		   và bậc nhảy độ dài dòng khi chữ thoát khỏi ảnh càng lộ. 340 để dòng cạnh ảnh còn
		   ~620px, tức vẫn là một khổ đọc bình thường chứ không phải cột báo. */
		width: 340px;
		margin: 6px 0 20px 32px;
	}
}
/* 20px, PHẢI nhỏ hơn rõ rệt .bstory__section-title (24px) ngay trên nó. Từng để 25px —
   tức phụ đề to hơn chính tiêu đề mục nó nằm dưới, lại cùng font serif cùng weight 600 —
   thành ra hai dòng như hai tiêu đề tranh nhau, mắt không biết cái nào là chính. Lý do
   đặt 25px lúc đó là để câu này gánh việc tách khối thay tấm nền màu vừa gỡ; nay ảnh
   float đã tách khối nên nó không cần to nữa. Thứ bậc giờ rõ: 24 đậm sẫm → 20 teal → 17.5
   văn xuôi.
   --bstory-accent-text vốn được đặt ra cho chữ trên nền --bstory-accent-bg, nhưng cả hai
   giá trị của nó cũng ăn đúng nền TRANG: #1f4f4b trên cream sáng và #bfe6e1 trên nền tối,
   đều thừa tương phản — nên giữ biến này, không cần thêm biến mới cho dark. */
.bstory__analysis-lead {
	font-family: 'Source Serif 4', Georgia, serif;
	font-size: 20px;
	line-height: 1.4;
	font-weight: 600;
	color: var(--bstory-accent-text);
	margin: 0 0 16px;
	max-width: var(--bstory-prose);
}
.bstory__analysis-body {
	font-family: 'Source Serif 4', Georgia, serif;
	font-size: 17.5px;
	line-height: 1.75;
	color: var(--bstory-muted-2);
	/* Ở bố cục 2 cột thì cột chữ (~530px) đã hẹp hơn mức này nên nó không có tác dụng;
	   giữ lại cho trường hợp truyện chưa có ảnh nào, khối về một cột chạy hết khổ. */
	max-width: var(--bstory-prose);
}
.bstory__analysis-body p:first-child { margin-top: 0; }
.bstory__analysis-body p:last-child { margin-bottom: 0; }

/* ===== Discussion ===== */
.bstory__discussion { max-width: var(--bstory-measure); margin: 0 auto; padding: 24px 24px 36px; }
/* Lưới 2 cột thay cho danh sách dọc: 5 câu hỏi xếp dọc thành một khối chữ đều đều dài
   ngoẵng; tách thành thẻ thì mỗi câu là một "vật thể" riêng, phụ huynh liếc chọn câu để
   hỏi dễ hơn hẳn — đây là kịch bản cho một cuộc trò chuyện, không phải văn bản để đọc. */
.bstory__discussion-list {
	margin: 24px 0 0;
	padding: 0;
	list-style: none;
	display: grid;
	gap: 14px;
}
@media (min-width: 820px) {
	.bstory__discussion-list { grid-template-columns: 1fr 1fr; }
}
.bstory__discussion-item {
	background: var(--bstory-surface);
	border: 1px solid var(--bstory-border);
	border-radius: 14px;
	padding: 18px 20px;
}
.bstory__discussion-tag {
	/* inline-flex (không phải inline-block) để icon canh giữa theo chiều dọc với chữ:
	   `vertical-align` trên <svg> canh theo đường baseline, luôn lệch xuống vài px vì icon
	   là hình vuông còn chữ có phần dưới baseline. */
	display: inline-flex;
	align-items: center;
	gap: 6px;
	font-family: 'Source Sans 3', 'Segoe UI', system-ui, sans-serif;
	/* KHÔNG in hoa: cụm tiếng Việt dài viết hoa vừa nặng vừa dễ chồng dấu (dấu thanh và dấu
	   mũ đều nằm trên chiều cao chữ hoa). */
	font-size: 12px;
	font-weight: 600;
	letter-spacing: 0.01em;
	/* --bstory-accent-text (KHÔNG phải --bstory-accent): đây đúng là biến dành cho chữ đặt
	   trên nền --bstory-accent-bg. Dùng --bstory-accent cho tương phản 5.02:1 ở nền sáng và
	   4.58:1 ở nền tối — đạt AA nhưng sát ngưỡng 4.5 một cách khó chịu với chữ 11px in hoa,
	   cỡ nhỏ nhất trang. Đổi biến đưa lên 7.94:1 và 8.21:1. */
	color: var(--bstory-accent-text);
	background: var(--bstory-accent-bg);
	border-radius: 99px;
	padding: 5px 12px;
	margin: 0 0 10px;
}
.bstory__discussion-text {
	margin: 0;
	font-size: 16.5px;
	line-height: 1.55;
	color: var(--bstory-text-strong);
}
/* Nét icon mảnh hơn nét chữ một chút (1.8 so với 2 thường dùng): icon ở đây chỉ 14px,
   nhỏ nhất trong plugin, và nằm cạnh chữ 12px — cùng độ đậm thì icon "nặng" hơn chữ,
   đọc ra như một nút bấm chứ không phải một nhãn. */
.bstory__discussion-icon { flex: none; }

/* ===== Media ===== */
.bstory__media { max-width: var(--bstory-measure); margin: 0 auto; padding: 24px 24px 36px; }
.bstory__media-embed { margin-top: 28px; aspect-ratio: 16 / 9; border-radius: 10px; overflow: hidden; background: #262320; }
.bstory__media-embed iframe { width: 100%; height: 100%; border: 0; display: block; }

/* ===== Footer / attribution / related ===== */
.bstory__footer { max-width: var(--bstory-measure); margin: 0 auto; padding: 32px 24px 64px; border-top: 1px solid var(--bstory-border); }
.bstory__attribution { font-size: 13px; color: var(--bstory-muted); margin: 0 0 40px; }
/* auto-FILL, không phải auto-fit — giống hệt .bstory-archive__grid và .bstory-home__grid.
   auto-fit gộp các track trống lại rồi kéo giãn phần còn lại, nên khi truyện chỉ có MỘT
   truyện liên quan (rất thường, kho còn nhỏ và related lọc theo chủ đề) thì card đó rộng
   hết cả khổ 1152px và cái thumb 4:3 cao thành 864px — một tấm ảnh khổng lồ nằm dưới chân
   trang. auto-fill giữ nguyên số track nên card luôn cỡ ~273px dù có 1 hay 3 cái. */
.bstory__related-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 20px; margin-top: 28px; }
.bstory__related-card { display: block; text-decoration: none; color: inherit; }
.bstory__related-thumb {
	aspect-ratio: 2 / 1;
	border-radius: 10px;
	overflow: hidden;
	background: var(--bstory-badge-bg);
	margin-bottom: 10px;
}
.bstory__related-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.bstory__related-title-vi { font-family: 'Source Serif 4', Georgia, serif; font-size: 16px; font-weight: 600; margin-bottom: 2px; }
.bstory__related-title-en { font-family: 'Source Serif 4', Georgia, serif; font-size: 13px; color: var(--bstory-muted); font-style: italic; }

/* ===== Listing pages (front page / /truyen/ archive / /chu-de/ taxonomy) =====
   Shared template (templates/archive-story.php) — see class-story-archive.php.
   Cards deliberately mirror .bstory__related-card's proportions/type scale (that's
   the "story teaser" pattern already established at the bottom of a single story
   page) rather than inventing a second visual language for the same kind of tile. */
.bstory-archive__intro { max-width: 720px; margin: 0 auto; padding: 56px 24px 8px; text-align: center; }
.bstory-archive__title {
	font-family: 'Source Serif 4', Georgia, serif;
	font-size: 36px;
	font-weight: 600;
	line-height: 1.2;
	margin: 0 0 12px;
}
.bstory-archive__lede { font-size: 16px; color: var(--bstory-muted-2); margin: 0; line-height: 1.6; }

.bstory-archive__grid {
	max-width: var(--bstory-measure);
	margin: 0 auto;
	padding: 40px 24px 24px;
	display: grid;
	grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
	gap: 28px;
}
.bstory-archive__card {
	display: block;
	text-decoration: none;
	color: inherit;
	background: var(--bstory-surface);
	border: 1px solid var(--bstory-border);
	border-radius: 14px;
	overflow: hidden;
	transition: transform 0.15s ease, box-shadow 0.15s ease, border-color 0.15s ease;
}
.bstory-archive__card:hover {
	transform: translateY(-3px);
	box-shadow: 0 10px 24px rgba(0, 0, 0, 0.08);
	border-color: var(--bstory-accent);
}
.bstory-archive__card-thumb { aspect-ratio: 2 / 1; background: var(--bstory-badge-bg); }
.bstory-archive__card-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.bstory-archive__card-body { padding: 16px; }
.bstory-archive__card-badge {
	display: inline-block;
	font-size: 12px;
	font-weight: 500;
	padding: 4px 10px;
	border-radius: 100px;
	background: var(--bstory-badge-bg);
	color: var(--bstory-badge-text);
	margin-bottom: 8px;
}
.bstory-archive__card-title-vi { font-family: 'Source Serif 4', Georgia, serif; font-size: 18px; font-weight: 600; margin-bottom: 2px; }
.bstory-archive__card-title-en { font-family: 'Source Serif 4', Georgia, serif; font-size: 13px; color: var(--bstory-muted); font-style: italic; }

/*
 * ===== Ảnh 16:9 (truyện vẽ bằng Google Flow, 18/08) =====
 *
 * Flow không hỗ trợ 2:1 (đã kiểm dứt điểm bảng "Agent settings" của Flow — chỉ có
 * 16:9/4:3/1:1/3:4/9:16), nên truyện nào vẽ bằng Flow được đánh dấu `_bstory_image_ratio
 * = '16:9'` (mặc định RỖNG = 2:1, không đụng truyện cũ). PHP đưa cờ đó ra HTML bằng
 * `data-image-ratio` — CHỈ đổi `aspect-ratio`, mọi thứ khác (bo góc, object-fit, margin,
 * box-shadow) giữ nguyên từ rule 2:1 gốc phía trên, không lặp lại ở đây.
 *
 * HAI CÁCH NEO KHÁC NHAU, đừng nhầm — chỗ nào đọc theo cách nào tuỳ khung đó có phải
 * hiện MỘT truyện khác trong đó không:
 * 1. Ảnh CỦA CHÍNH truyện đang xem (hero/đoạn/ý-nghĩa) → attribute nằm trên `.bstory`
 *    (gốc trang), đọc `data-image-ratio` của MODEL truyện này.
 * 2. Ảnh đại diện cho MỘT TRUYỆN KHÁC (thumb truyện liên quan, thẻ lưới archive) → mỗi
 *    thẻ tự mang `data-image-ratio` CỦA RIÊNG truyện nó đại diện — related-grid/archive
 *    -grid có thể trộn lẫn truyện 2:1 và 16:9 cùng lúc, page-level attribute sẽ SAI cho
 *    những thẻ không khớp truyện đang xem.
 */
.bstory[data-image-ratio="16:9"] .bstory__hero-media img,
.bstory[data-image-ratio="16:9"] .bstory__seg-image-wrap,
.bstory[data-image-ratio="16:9"] .bstory__analysis-image {
	aspect-ratio: 16 / 9;
}
.bstory__related-thumb[data-image-ratio="16:9"],
.bstory-archive__card-thumb[data-image-ratio="16:9"] {
	aspect-ratio: 16 / 9;
}

.bstory-archive__empty { max-width: var(--bstory-measure); margin: 0 auto; padding: 24px; text-align: center; color: var(--bstory-muted); }

.bstory-archive__pagination { max-width: var(--bstory-measure); margin: 0 auto; padding: 8px 24px 56px; display: flex; justify-content: center; }
.bstory-archive__pagination .page-numbers {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-width: 36px;
	height: 36px;
	padding: 0 10px;
	margin: 0 3px;
	border-radius: 8px;
	background: var(--bstory-surface);
	border: 1px solid var(--bstory-border);
	color: var(--bstory-text);
	text-decoration: none;
	font-size: 14px;
}
.bstory-archive__pagination .page-numbers.current { background: var(--bstory-accent); border-color: var(--bstory-accent); color: #fff; }
.bstory-archive__pagination .page-numbers:hover:not(.current) { border-color: var(--bstory-accent); color: var(--bstory-accent); }

@media (max-width: 600px) {
	.bstory-archive__title { font-size: 28px; }
	.bstory-archive__intro { padding: 40px 16px 8px; }
	.bstory-archive__grid { padding: 28px 16px 16px; gap: 20px; }
	/* Vùng bấm 44px cho nút nghe — cùng luật đã áp cho tab ngôn ngữ / nút cỡ chữ. Nới bằng
	   khung ngoài chứ không phóng to icon: icon to lên sẽ tranh chỗ với chính từ vựng. */
	.bstory__glossary-say { width: 44px; height: 44px; margin: -9px -9px -9px -4px; }

}

@media (max-width: 600px) {
	.bstory__title-vi { font-size: 30px; }
	.bstory__hero { padding: 32px 16px 24px; gap: 24px; text-align: center; }
	.bstory__hero-text { display: flex; flex-direction: column; align-items: center; }
	.bstory__badges,
	.bstory__audio-controls { justify-content: center; }
	.bstory__audio-btn--secondary,
	.bstory__audio-btn--primary { display: none; }
	/* Only the YouTube link is left in .bstory__audio-controls at this width — put it
	   on the same row as the player bar instead of stacking, since neither is full-width
	   on its own anymore. */
	.bstory__audio-row { display: flex; align-items: stretch; flex-wrap: wrap; justify-content: center; gap: 10px; }
	.bstory__audio-row .bstory__audio-controls { width: auto; order: 2; }
	.bstory__audio-player { max-width: 100%; margin-top: 0; order: 1; }
	.bstory__audio-row .bstory__audio-btn--youtube { border-radius: 12px; }
	/* Bố cục đoạn truyện KHÔNG cần override riêng cho điện thoại nữa: bản desktop đã là
	   xếp chồng ảnh-trên-chữ-dưới chạy hết khổ, đúng thứ cần trên màn hẹp. Trước đây chỗ
	   này phải lật flex-direction để phá bố cục 2 cột. */
	/* One scrollable line instead of wrapping to 2 rows — there just isn't enough
	   width on a phone for "Ngôn ngữ:" + 3 tabs + 3 font-size buttons + theme/focus
	   all visible at once without shrinking tap targets below a usable size. */
	.bstory__switcher-inner {
		padding: 12px 16px;
		flex-wrap: nowrap;
		overflow-x: auto;
		-webkit-overflow-scrolling: touch;
		scrollbar-width: none;
		justify-content: flex-start;
	}
	.bstory__switcher-inner::-webkit-scrollbar { display: none; }
	.bstory__switcher-label { display: none; }
	.bstory__tab-label-full { display: none; }
	.bstory__tab-label-short { display: inline; }
	.bstory__switcher-tabs { flex: none; }
	.bstory__reading-controls { margin-left: 12px; flex: none; }
	/* Vùng bấm 44px trên điện thoại (chuẩn Apple HIG; Material đề 48). Ở desktop 32px là
	   đủ vì chuột trỏ chính xác tới từng pixel, nhưng đầu ngón tay thì không — 32px là cỡ
	   hay bấm trượt sang nút bên cạnh, mà ở đây các nút lại xếp sát nhau.
	   Nới được vì thanh này VỐN ĐÃ là dải cuộn ngang (nowrap + overflow-x ở trên), nên
	   thêm bề ngang không đẩy gì xuống dòng — chỉ là cuộn thêm một chút. */
	.bstory__tab,
	.bstory__font-btn { height: 44px; }
	.bstory__tab { padding: 0 18px; }
	.bstory__font-btn { padding: 0 14px; }
	.bstory__control-btn { width: 44px; height: 44px; }
	.bstory__story,
	.bstory__glossary,
	.bstory__analysis,
	.bstory__discussion,
	.bstory__media,
	.bstory__footer { padding-left: 16px; padding-right: 16px; }
	.bstory__segment-grid { gap: 20px; }
}

/* =====================================================================
   GeneratePress integration: flatten the theme's default boxed-card
   layout on story templates (body.bstory-flat-layout, set by the plugin).
   GP's "Separate Containers" style wraps the article in a white card
   with padding on a grey page background — that competes with .bstory's
   own full-bleed cream background and reads as a design regression
   against the clean/flat/modern direction. !important is needed because
   GP prints its own container rules as inline <style> in wp_head, whose
   position relative to this stylesheet isn't guaranteed.
   ===================================================================== */
body.bstory-flat-layout {
	background: #FAF8F4;
}
/* Phải đủ nặng để thắng `body.bstory-flat-layout` ngay phía trên (nền cream) bất kể thứ tự
   nạp file — nên viết đủ cả html lẫn body. */
html.bstory-dark body.bstory-flat-layout {
	background: #1c1a17;
}
body.bstory-flat-layout .inside-article,
body.bstory-flat-layout .content-area,
body.bstory-flat-layout .site-content,
body.bstory-flat-layout .paging-navigation {
	background: transparent !important;
	box-shadow: none !important;
	padding: 0 !important;
	margin: 0 !important;
}
body.bstory-flat-layout #primary,
body.bstory-flat-layout .content-area {
	width: 100% !important;
}
body.bstory-flat-layout article.type-story {
	border: none !important;
}
