/* Design tokens. Default is dark; [data-theme="light"] overrides. */

:root {
	/* Base Tokyo Night. The lighter "Storm" sibling was here first, on a
	   judgement that #1a1b26 read as too dark — made against nothing. The
	   editor this wiki is written in runs the base variant, and side by side
	   Storm is the one that looks washed out. fg/accent/border are identical
	   across the two; only bg and code-bg move. */
	--bg: #1a1b26;
	--fg: #c0caf5;
	--muted: #565f89;
	--accent: #7aa2f7;
	--border: #292e42;
	--code-bg: #16161e;
	/* Raised panels that sit on top of --bg rather than recede like code
	   blocks: the pin button's hover, landing cards, the floating TOC, the
	   mobile drawer toggle. Storm's bg_highlight. */
	--surface: #292e42;
	--strong: #e6e8f0;
	--header-bg: rgba(122, 162, 247, 0.10);
	--quote-bg: rgba(122, 162, 247, 0.05);

	/* Width of the ask column. The floating TOC clears it by this much, so
	   the two have to move together. */
	--right-w: 320px;
	/* Width of the category column. The drag handle rewrites this on the
	   root element and the value is restored before paint, so the bounds
	   below are repeated in main.js. */
	--left-w: 280px;
}

:root[data-theme="light"] {
	--bg: #eff1f5;
	--fg: #4c4f69;
	--muted: #6c6f85;
	--accent: #1e66f5;
	--border: #ccd0da;
	--code-bg: #e6e9ef;
	--surface: #e6e9ef;
	--strong: #1f2025;
	--header-bg: rgba(30, 102, 245, 0.08);
	--quote-bg: rgba(30, 102, 245, 0.05);
}

* { box-sizing: border-box; }

body {
	margin: 0;
	font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif;
	background: var(--bg);
	color: var(--fg);
	line-height: 1.6;
}

.layout {
	display: grid;
	grid-template-columns: var(--left-w) minmax(0, 1fr) var(--right-w);
	min-height: 100vh;
	background: var(--bg);
}

/* Landing: hide the body column, leaving left categories + right ask.
   The right area centers its content vertically and horizontally, with a
   max-width on the form so the textarea doesn't stretch full width. */
.layout.is-landing {
	grid-template-columns: var(--left-w) minmax(0, 1fr);
}

/* Sidebar modes — VSCode-style auto-hide vs pinned.
   - Default (no attribute set): pinned, full sidebar in the grid.
   - data-sidebar="auto": .left becomes a --left-w fixed element shifted off
     screen by all but 14px; hover slides it fully into view. .left-inner
     stays the visual container (background/padding/flex), no positioning
     gymnastics on it. .left is removed from the grid so columns collapse.
   - Toggle is driven by the in-sidebar pin button (#sidebar-pin). */
:root[data-sidebar="auto"] .layout {
	grid-template-columns: minmax(0, 1fr) var(--right-w);
}
:root[data-sidebar="auto"] .layout.is-landing {
	grid-template-columns: minmax(0, 1fr);
}
:root[data-sidebar="auto"] .left {
	position: fixed;
	top: 0;
	left: 0;
	width: var(--left-w);
	height: 100vh;
	transform: translateX(calc(-100% + 14px));
	transition: transform 0.18s ease, box-shadow 0.18s ease;
	z-index: 40;
	overflow: hidden;
}
:root[data-sidebar="auto"] .left:hover,
:root[data-sidebar="auto"] .left:focus-within {
	transform: translateX(0);
	box-shadow: 0 0 24px rgba(0, 0, 0, 0.35);
}
/* Strip visual cue — thin vertical line sits inside the visible 14px slice. */
:root[data-sidebar="auto"] .left::before {
	content: "";
	position: absolute;
	top: 50%;
	right: 4px;
	transform: translateY(-50%);
	width: 2px;
	height: 40px;
	background: var(--border);
	border-radius: 1px;
	pointer-events: none;
	transition: background 0.15s ease, height 0.15s ease;
	z-index: 1;
}
:root[data-sidebar="auto"] .left:hover::before {
	background: var(--accent);
	height: 56px;
}

/* Pin toggle button — sits in the sidebar header next to the brand. */
.left-head {
	display: flex;
	justify-content: space-between;
	align-items: flex-start;
	gap: 0.5rem;
	margin-bottom: 0.75rem;
}
.left-head .brand { margin: 0; }
.sidebar-pin {
	background: transparent;
	border: 1px solid transparent;
	color: var(--muted);
	font-size: 1.25rem;
	cursor: pointer;
	padding: 0.2rem 0.45rem;
	border-radius: 4px;
	line-height: 1;
	flex-shrink: 0;
	font-family: inherit;
	margin-top: 0.4rem;
}
.sidebar-pin:hover {
	background: var(--surface);
	border-color: var(--border);
}
.pin-icon-auto { display: none; }
:root[data-sidebar="auto"] .pin-icon-pinned { display: none; }
:root[data-sidebar="auto"] .pin-icon-auto { display: inline; }
.layout.is-landing .body { display: none; }
/* Landing: form vertically centered while the answer is empty; the layout
   reverts to flex-start once an answer arrives so a tall result list doesn't
   clip the heading above the viewport. */
.layout.is-landing .right {
	display: flex;
	flex-direction: column;
	justify-content: flex-start;
	align-items: center;
	padding: 3rem 2rem;
	gap: 1.5rem;
}
.layout.is-landing .right:has(#ai-result:empty) {
	justify-content: center;
}
.layout.is-landing .right h2 {
	text-align: center;
	font-size: 1.75rem;
	margin: 0;
	width: 100%;
	max-width: 560px;
}
.layout.is-landing .right form {
	width: 100%;
	max-width: 560px;
	display: flex;
	flex-direction: column;
	gap: 0.5rem;
}
.layout.is-landing .right textarea {
	font-size: 1rem;
	padding: 0.75rem 1rem;
	border-radius: 8px;
}
.layout.is-landing .right button {
	border-radius: 8px;
}
.layout.is-landing .right .ai-result {
	width: 100%;
	max-width: 560px;
	text-align: left;
}
.layout.is-landing .right .recent-section {
	width: 100%;
	max-width: 560px;
	margin-top: 1rem;
}

/* Primer: landing only, and only until something has been asked. It is
   onboarding, so it gets out of the way once the box has been used. */
.ask-help { display: none; }
.layout.is-landing .right:has(#ai-result:empty) .ask-help {
	display: block;
	width: 100%;
	max-width: 560px;
	text-align: left;
	font-size: 0.88rem;
	color: var(--muted);
}
.ask-help-lead { margin: 0 0 0.6rem; }
/* One attribute decides whether this is an ask box or a search box. It is set
   after the capability probe answers, so both halves start hidden and the
   right one is revealed — otherwise an Ask AI button flashes on a page that
   cannot ask. */
.ai-only, .search-only { display: none; }
:root[data-ai="on"] .ai-only { display: revert; }
:root[data-ai="off"] .search-only { display: revert; }
:root[data-ai="off"] #ask-ai-btn { display: none; }
.ask-modes {
	display: grid;
	grid-template-columns: auto 1fr;
	gap: 0.15rem 0.6rem;
	margin: 0 0 1rem;
}
.ask-modes dt {
	color: var(--accent);
	font-weight: 600;
}
.ask-modes dd { margin: 0; }
.ask-examples {
	list-style: none;
	margin: 0;
	padding: 0;
	display: flex;
	flex-direction: column;
	gap: 0.35rem;
}
.ask-example {
	width: 100%;
	text-align: left;
	font: inherit;
	color: var(--fg);
	background: var(--surface);
	border: 1px solid var(--border);
	border-radius: 6px;
	padding: 0.45rem 0.7rem;
	cursor: pointer;
}
.ask-example:hover {
	border-color: var(--accent);
	color: var(--accent);
}
/* Hide recent-updates on article pages — the sidebar tree already covers nav. */
.layout:not(.is-landing) .recent-section { display: none; }

.recent-section h3 {
	margin: 0 0 0.5rem;
	font-size: 0.85rem;
	font-weight: 500;
	color: var(--muted);
	text-transform: uppercase;
	letter-spacing: 0.04em;
}
.recent-list {
	list-style: none;
	margin: 0;
	padding: 0;
	display: flex;
	flex-direction: column;
	gap: 0.35rem;
}
.recent-list li {
	display: grid;
	grid-template-columns: 1fr auto auto;
	gap: 0.5rem;
	align-items: baseline;
	padding: 0.4rem 0.6rem;
	border: 1px solid var(--border);
	border-radius: 4px;
	background: var(--surface);
}
.recent-list a {
	color: var(--fg);
	text-decoration: none;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}
.recent-list a:hover { color: var(--accent); }
.recent-list .recent-cat {
	font-size: 0.75rem;
	color: var(--muted);
	padding: 0.05rem 0.4rem;
	background: var(--bg);
	border-radius: 3px;
}
.recent-list .recent-date {
	font-size: 0.75rem;
	color: var(--muted);
	font-variant-numeric: tabular-nums;
}

.right {
	/* Distinct tint + a hard edge from the center content area — the tint
	   alone is too subtle in light mode to read as a separate panel. */
	background: var(--code-bg);
	border-left: 1px solid var(--border);
	padding: 1.5rem;
	position: sticky;
	top: 0;
	height: 100vh;
	overflow-y: auto;
	display: flex;
	flex-direction: column;
}
.left {
	position: sticky;
	top: 0;
	height: 100vh;
	overflow: visible;
}
/* Drag handle straddling the sidebar's right edge. Invisible until pointed
   at, so the border stays the only line at rest. */
.left-resize {
	position: absolute;
	top: 0;
	right: -3px;
	width: 6px;
	height: 100%;
	cursor: col-resize;
	z-index: 41;
	touch-action: none;
	background: transparent;
	transition: background 0.15s ease;
}
.left-resize:hover,
.left-resize.is-dragging { background: var(--accent); }
/* Kill text selection everywhere while a drag is in flight. */
:root[data-resizing] { cursor: col-resize; user-select: none; }
.left-inner {
	/* Distinct tint + a hard edge from the center content area — the tint
	   alone is too subtle in light mode to read as a separate panel. */
	background: var(--code-bg);
	border-right: 1px solid var(--border);
	padding: 1.5rem;
	height: 100vh;
	overflow: hidden;
	display: flex;
	flex-direction: column;
}
.body {
	background: var(--bg);
	padding: 2rem 2.5rem;
	min-width: 0;
	max-width: 64rem;
	margin: 0 auto;
	width: 100%;
}

/* Prose styles for rendered wiki content */
.body h1 {
	font-size: 2rem;
	font-weight: 700;
	margin: 1.25rem 0 1rem;
	color: var(--accent);
	border-bottom: 1px solid var(--border);
	padding-bottom: 0.5rem;
	line-height: 1.25;
}
.body h2 {
	font-size: 1.5rem;
	font-weight: 700;
	margin: 2rem 0 0.75rem;
	color: var(--accent);
	line-height: 1.3;
}
.body h3 {
	font-size: 1.2rem;
	font-weight: 600;
	margin: 1.5rem 0 0.5rem;
	line-height: 1.3;
}
.body h4 { font-size: 1.05rem; font-weight: 600; margin: 1.25rem 0 0.5rem; }
.body p { margin: 0.75rem 0; }
.body ul, .body ol { padding-left: 1.5rem; margin: 0.75rem 0; }
.body li { margin: 0.25rem 0; }
.body li > ul, .body li > ol { margin: 0.25rem 0; }
.body blockquote {
	border-left: 3px solid var(--accent);
	padding: 0.5rem 1rem;
	margin: 1rem 0;
	color: var(--fg);
	background: var(--quote-bg);
}
.body code {
	background: var(--border);
	padding: 0.1rem 0.35rem;
	border-radius: 3px;
	font-family: ui-monospace, "SF Mono", "Cascadia Code", Menlo, monospace;
	font-size: 0.9em;
	/* long unbreakable inline code (registry sig hex, GUIDs, paths) wraps
	   instead of overflowing the column; block code (pre) keeps white-space:pre
	   so this only affects inline spans. */
	overflow-wrap: anywhere;
}
.body pre {
	background: var(--code-bg);
	padding: 1rem;
	border-radius: 6px;
	overflow-x: auto;
	margin: 1rem 0;
	border: 1px solid var(--border);
}
.body pre code {
	background: none;
	padding: 0;
	font-size: 0.875rem;
	line-height: 1.5;
}
/* Language title bar above fenced code blocks (renderer wraps every code
   block in .code-block; .code-block-title only exists when a fence
   language was given, e.g. ```bash). Higher specificity than `.body pre`
   above wins regardless of declaration order, so the box border/radius/
   margin live on the outer wrapper instead of double-stacking on both. */
.body .code-block {
	margin: 1rem 0;
	border: 1px solid var(--border);
	border-radius: 6px;
	overflow: hidden;
}
.body .code-block-title {
	padding: 0.4rem 1rem;
	font-size: 0.78rem;
	font-family: ui-monospace, "SF Mono", "Cascadia Code", Menlo, monospace;
	/* Fixed tones, not site theme vars: chroma's code body is hardcoded dark
	   (tokyonight-night, #1a1b26) regardless of light/dark site theme, so a
	   theme-linked title bg either barely differs from it (dark site) or
	   clashes outright (light site puts a pale bar over dark code). This is
	   Tokyo Night's own "terminal_black" highlight tone — distinctly lighter
	   than the code body in both cases. */
	color: #c0caf5;
	background: #414868;
	letter-spacing: 0.02em;
}
.body .code-block pre {
	margin: 0;
	border: none;
	border-radius: 0;
}
.body table {
	border-collapse: collapse;
	margin: 1rem 0;
	width: 100%;
	font-size: 0.95rem;
}
.body th, .body td {
	border: 1px solid var(--border);
	padding: 0.5rem 0.75rem;
	text-align: left;
	vertical-align: top;
	/* keep Korean words whole (목적 -> not 목/적); a narrow auto-layout column
	   would otherwise shrink to 1-char min-content and break mid-word.
	   overflow-wrap:break-word still splits a genuinely unbreakable token. */
	word-break: keep-all;
	overflow-wrap: break-word;
}
.body th {
	background: var(--header-bg);
	font-weight: 600;
	color: var(--accent);
}
.body a {
	color: var(--accent);
	text-decoration: underline;
	text-decoration-color: var(--muted);
	text-underline-offset: 2px;
}
.body a:hover { text-decoration-color: var(--accent); }
.body hr {
	border: none;
	border-top: 1px solid var(--border);
	margin: 2rem 0;
}
.body img {
	max-width: 100%;
	height: auto;
	border-radius: 4px;
	display: block;
	margin: 1.25rem auto 0.25rem;
}
/* Image caption: italic line right after an image (markdown pattern: ![](.) followed by _caption_) */
.body p > img + em,
.body p > img + br + em,
.body p > a > img + em {
	display: block;
	text-align: center;
	color: var(--muted);
	font-size: 0.85rem;
	margin: 0 auto 0.5rem;
	font-style: italic;
}

/* Mermaid diagram: center the SVG + style the caption line that follows */
.body .mermaid {
	display: flex;
	justify-content: center;
	margin: 1.25rem auto 0.25rem;
}
/* themeVariables.clusterBorder alone renders a thin 1px stroke that's easy
   to miss against the page background — thicken it so subgraph boxes read
   clearly as bordered containers, matching the node boxes' own border. */
.body .mermaid .cluster rect {
	stroke-width: 1.5px;
}
.body .mermaid + p {
	text-align: center;
	margin: 0 auto 0.75rem;
}
.body .mermaid + p > em:only-child {
	color: var(--muted);
	font-size: 0.85rem;
	font-style: italic;
}
.body strong { color: var(--strong); }

/* Table of contents — collapsible <details> auto-injected by the renderer.
   Default closed; click to expand. Indented per heading level (H2/H3/H4). */
/* Floated out of the flow to the bottom-right of the reading column, clearing
   the ask panel. It stays a <details>, so collapse/expand needs no JS, and
   collapsed it is just the summary chip. */
.body .toc {
	position: fixed;
	right: calc(var(--right-w) + 1.25rem);
	bottom: 1.25rem;
	z-index: 30;
	margin: 0;
	padding: 0.5rem 0.875rem;
	max-width: min(22rem, 30vw);
	background: var(--surface);
	border: 1px solid var(--border);
	border-radius: 6px;
	box-shadow: 0 4px 16px rgba(0, 0, 0, 0.28);
	font-size: 0.9rem;
}
/* A long article's list would otherwise run off the top of the screen. */
.body .toc[open] .toc-list {
	max-height: min(60vh, 30rem);
	overflow-y: auto;
	overscroll-behavior: contain;
}
.body .toc summary {
	cursor: pointer;
	color: var(--muted);
	font-weight: 500;
	user-select: none;
	list-style: none;
}
.body .toc summary::-webkit-details-marker { display: none; }
.body .toc summary::before {
	content: "▶";
	display: inline-block;
	width: 1em;
	margin-right: 0.25em;
	transition: transform 0.15s ease;
	font-size: 0.7em;
	color: var(--muted);
}
.body .toc[open] summary::before { transform: rotate(90deg); }
.body .toc-list {
	list-style: none;
	margin: 0.5rem 0 0;
	padding: 0;
}
.body .toc-list li { margin: 0.15rem 0; }
.body .toc-list a {
	color: var(--fg);
	text-decoration: none;
	border-bottom: 1px dashed transparent;
}
.body .toc-list a:hover { border-bottom-color: var(--muted); }
.body .toc-h2 { padding-left: 0; }
.body .toc-h3 { padding-left: 1.25rem; font-size: 0.95em; }
.body .toc-h4 { padding-left: 2.5rem; font-size: 0.9em; color: var(--muted); }

/* Theme toggle button (lives in the left sidebar footer) */
.left-footer { margin-top: auto; padding-top: 1rem; display: flex; flex-direction: column; gap: 0.5rem; }
.graph-link {
	display: block;
	color: var(--muted);
	text-decoration: none;
	font-size: 0.85rem;
	padding: 0.3rem 0;
	border-bottom: 1px dashed transparent;
	transition: color 0.15s ease, border-color 0.15s ease;
}
.graph-link:hover {
	color: var(--accent);
	border-bottom-color: var(--accent);
}
.theme-toggle {
	background: transparent;
	border: 1px solid var(--border);
	color: var(--fg);
	padding: 0.4rem 0.7rem;
	border-radius: 4px;
	cursor: pointer;
	font-size: 0.9rem;
	font-family: inherit;
	width: 100%;
	text-align: left;
}
.theme-toggle:hover {
	border-color: var(--accent);
	color: var(--accent);
}
.theme-toggle .icon { margin-right: 0.5rem; }
:root[data-theme="light"] .theme-toggle .icon-dark { display: none; }
:root:not([data-theme="light"]) .theme-toggle .icon-light { display: none; }
:root[data-theme="light"] .theme-label-dark { display: none; }
:root:not([data-theme="light"]) .theme-label-light { display: none; }
.body kbd {
	background: var(--border);
	padding: 0.1rem 0.4rem;
	border-radius: 3px;
	font-family: ui-monospace, monospace;
	font-size: 0.85em;
	border: 1px solid var(--muted);
}

.brand { font-size: 1.4rem; margin: 0 0 1.5rem; }
.brand a { color: var(--fg); text-decoration: none; display: inline-block; line-height: 0; }
.brand img {
	display: block;
	width: 180px;
	max-width: 100%;
	height: auto;
}

/* Middle region between brand and footer scrolls independently so the
   theme toggle stays visible no matter how long the catalog grows.
   The scrollbar itself is hidden — scrolling still works (wheel / drag),
   it just doesn't show a chrome bar that distracts from the tree. */
.categories {
	flex: 1;
	min-height: 0;
	overflow-y: auto;
	/* overflow-y:auto makes the spec compute overflow-x to auto as well, and
	   the scrollbars below are hidden — so anything that overflows sideways
	   becomes unreachable rather than scrollable. Titles wrap instead. */
	overflow-x: hidden;
	margin: 0 -0.5rem;
	padding: 0 0.5rem 0.5rem;
	scrollbar-width: none;       /* Firefox */
	-ms-overflow-style: none;    /* legacy Edge / IE */
}
.categories::-webkit-scrollbar { display: none; }  /* Chrome / Safari / Edge */
.left-inner, .right { scrollbar-width: none; -ms-overflow-style: none; }
.left-inner::-webkit-scrollbar,
.right::-webkit-scrollbar { display: none; }
.categories details {
	margin-bottom: 0.5rem;
}
.categories summary {
	cursor: pointer;
	padding: 0.25rem 0;
	color: var(--accent);
}
/* Subcategory groups (linux/ubuntu, cluster/kubernetes). Same markup one level
   down, indented to sit with the list beside it. The label takes --muted so the
   two levels read apart; the accent is reserved for the category above it. */
.categories details details {
	margin-left: 1rem;
	margin-bottom: 0.25rem;
}
.categories details details > summary {
	color: var(--muted);
	font-size: 0.9rem;
}
.categories details details > summary:hover { color: var(--accent); }
.categories ul {
	list-style: none;
	padding-left: 1rem;
	margin: 0.25rem 0;
}
.categories a {
	color: var(--fg);
	text-decoration: none;
	display: block;
	padding: 0.15rem 0;
	font-size: 0.9rem;
	/* Titles carry parentheticals like (taint·toleration·nodeSelector·PDB)
	   with no space to break on, which would otherwise run past the panel.
	   `anywhere` rather than `break-word` so the break counts toward the
	   intrinsic width too. */
	overflow-wrap: anywhere;
}
.categories a:hover { color: var(--accent); }
.categories a.active {
	color: var(--accent);
	background: var(--quote-bg);
	font-weight: 600;
	border-left: 2px solid var(--accent);
	padding-left: calc(0.5rem - 2px);
	margin-left: -0.5rem;
	border-radius: 0 3px 3px 0;
}
.loading { color: var(--muted); font-style: italic; }

/* Breadcrumb (lives at the top of the rendered body when a wiki page loads) */
.breadcrumb {
	display: flex;
	flex-wrap: wrap;
	align-items: baseline;
	/* No gap — .sep already carries the spacing, and the two would stack. */
	gap: 0;
	font-size: 0.85rem;
	color: var(--muted);
	margin: 0 0 1.5rem;
	padding-bottom: 0.75rem;
	border-bottom: 1px dashed var(--border);
}
/* Authored / updated dates ride the far end of the breadcrumb rather than
   taking a line of their own above the title. */
.bc-dates {
	margin-left: auto;
	display: flex;
	align-items: baseline;
	gap: 0;
	font-size: 0.78rem;
	font-variant-numeric: tabular-nums;
}
/* --border is a line colour and sits too close to --bg to read as text; the
   sheet's de-emphasised text colour is --muted. The date itself takes --fg so
   the label reads as the quieter half of the pair. */
.bc-dates .bc-label {
	color: var(--muted);
	margin-right: 0.3rem;
}
.bc-dates time { color: var(--fg); }
.breadcrumb a {
	color: var(--muted);
	text-decoration: none;
}
.breadcrumb a:hover {
	color: var(--accent);
	text-decoration: underline;
}
.breadcrumb .sep {
	margin: 0 0.4rem;
	color: var(--border);
}
.breadcrumb .bc-cat { color: var(--fg); }
.breadcrumb .bc-slug { color: var(--accent); font-weight: 500; }

.right h2, .body h2 { color: var(--accent); }
.right textarea {
	width: 100%;
	padding: 0.6rem 0.75rem;
	background: var(--border);
	color: var(--fg);
	border: 1px solid var(--muted);
	border-radius: 4px;
	font-family: inherit;
	font-size: 0.95rem;
	line-height: 1.5;
	resize: none;
	overflow-y: auto;
	min-height: 2.6rem;
	max-height: 14rem;
	/* Native auto-grow on Chrome 123+/Safari 17.4+/Firefox 추후. Falls back
	   to the JS autoGrowTextarea in main.js on older browsers. */
	field-sizing: content;
}
.right textarea:focus {
	outline: none;
	border-color: var(--accent);
}
.right .ask-actions {
	display: flex;
	gap: 0.5rem;
	margin-top: 0.5rem;
}
.right button {
	flex: 1;
	padding: 0.5rem;
	cursor: pointer;
	background: var(--accent);
	color: var(--bg);
	border: none;
	border-radius: 4px;
	font-weight: 600;
	font-family: inherit;
}
.right button[type="button"] {
	background: transparent;
	color: var(--accent);
	border: 1px solid var(--accent);
}
.right button:hover { opacity: 0.85; }
.ai-result { margin-top: 1rem; font-size: 0.9rem; color: var(--fg); }
.ai-placeholder, .ai-result .hint { color: var(--muted); font-style: italic; }

/* Search result cards */
.search-results {
	list-style: none;
	padding: 0;
	margin: 0.5rem 0 0;
	display: flex;
	flex-direction: column;
	gap: 0.5rem;
}
.search-results li a {
	display: block;
	padding: 0.6rem 0.75rem;
	background: var(--border);
	border-radius: 4px;
	text-decoration: none;
	color: var(--fg);
	border-left: 2px solid transparent;
}
.search-results li a:hover {
	border-left-color: var(--accent);
	background: var(--quote-bg);
}
.search-results .sr-cat {
	display: inline-block;
	font-size: 0.75rem;
	color: var(--accent);
	text-transform: uppercase;
	letter-spacing: 0.05em;
	margin-right: 0.5rem;
}
.search-results .sr-title {
	display: block;
	font-weight: 600;
	margin: 0.15rem 0;
	color: var(--fg);
	font-size: 0.9rem;
}
.search-results .sr-snippet {
	display: block;
	font-size: 0.8rem;
	color: var(--muted);
	line-height: 1.4;
}

/* ---- AI answer (RAG SSE) ---------------------------------------------
   Shell rendered into #ai-result. Three child slots receive named SSE
   events: answer / sources / meta. */
.ai-answer { display: flex; flex-direction: column; gap: 0.75rem; }
.ai-text-slot .ai-text {
	white-space: normal;
	line-height: 1.55;
	color: var(--fg);
	font-size: 0.95rem;
}
.ai-text-slot .hint { color: var(--muted); font-size: 0.85rem; }
.ai-meta-slot .ai-meta {
	color: var(--muted);
	font-size: 0.75rem;
	margin: 0.25rem 0 0;
	font-variant-numeric: tabular-nums;
}

/* Final rendered answer container. Standalone — Go handler emits
   class="ai-text ai-text-rendered" (no .body piggyback), so all prose rules
   the answer needs live in the dedicated .ai-text-rendered selectors below.
   Tuned for the narrow right panel: tighter margins, smaller headings,
   overflow-wrap so long URLs don't blow past the column. */
.ai-text-rendered {
	padding: 0;
	max-width: none;
	margin: 0;
	background: transparent;
	/* Long URLs in LLM answers break out of the narrow right panel
	   otherwise — break the line anywhere we have to. */
	overflow-wrap: anywhere;
	word-break: break-word;
}
.ai-text-rendered pre { overflow-x: auto; }
.ai-text-rendered h1 { font-size: 1.25rem; margin: 0.75rem 0 0.5rem; color: var(--accent); }
.ai-text-rendered h2 { font-size: 1.1rem; margin: 1rem 0 0.4rem; color: var(--accent); }
.ai-text-rendered h3 { font-size: 1rem; margin: 0.75rem 0 0.4rem; }
.ai-text-rendered p { margin: 0.6rem 0; line-height: 1.55; }
.ai-text-rendered ul, .ai-text-rendered ol {
	padding-left: 1.4rem;
	margin: 0.5rem 0;
}
.ai-text-rendered li { margin: 0.2rem 0; }
.ai-text-rendered li > ul,
.ai-text-rendered li > ol { margin: 0.2rem 0; }
.ai-text-rendered a { color: var(--accent); text-decoration: underline; }
.ai-text-rendered a:hover { text-decoration-color: var(--fg); }
.ai-text-rendered code {
	background: var(--code-bg);
	padding: 0.05rem 0.3rem;
	border-radius: 3px;
	font-size: 0.85em;
}
.ai-text-rendered pre {
	background: var(--code-bg);
	padding: 0.6rem 0.8rem;
	border-radius: 4px;
	margin: 0.5rem 0;
	overflow-x: auto;
	font-size: 0.82rem;
}
.ai-text-rendered pre code {
	background: transparent;
	padding: 0;
	font-size: inherit;
}
.ai-text-rendered blockquote {
	border-left: 3px solid var(--accent);
	padding: 0.3rem 0.8rem;
	margin: 0.6rem 0;
	color: var(--muted);
	background: var(--quote-bg);
}
.ai-text-rendered strong { color: var(--strong); }

/* Source cards — [N] cat title, grid keeps everything aligned. */
.ai-sources {
	list-style: none;
	margin: 0;
	padding: 0;
	display: flex;
	flex-direction: column;
	gap: 0.35rem;
}
.ai-sources li { margin: 0; }
.ai-sources a {
	display: grid;
	grid-template-columns: auto auto 1fr;
	gap: 0.5rem;
	align-items: baseline;
	padding: 0.45rem 0.6rem;
	border: 1px solid var(--border);
	border-radius: 4px;
	background: var(--quote-bg);
	color: var(--fg);
	text-decoration: none;
	min-width: 0;
}
.ai-sources a:hover { border-color: var(--accent); color: var(--accent); }
.ai-sources .src-num {
	color: var(--muted);
	font-size: 0.8rem;
	font-variant-numeric: tabular-nums;
}
.ai-sources .src-cat {
	font-size: 0.7rem;
	color: var(--muted);
	padding: 0.05rem 0.4rem;
	background: var(--bg);
	border-radius: 3px;
	letter-spacing: 0.02em;
}
.ai-sources .src-title {
	font-size: 0.85rem;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
	min-width: 0;
}

/* ============================================================
   Mobile / small tablet (≤900px): the 3-column grid can't fit.
   Collapse to a single column, turn the sidebar into a tap-driven
   off-canvas drawer (hover doesn't exist on touch — and the desktop
   data-sidebar="auto" fixed overlay would otherwise overlap content),
   and let the ask panel flow below the body instead of being a tall
   sticky column. Hamburger (#drawer-toggle) + backdrop hidden on desktop.
   ============================================================ */
.drawer-toggle,
.drawer-backdrop { display: none; }

@media (max-width: 900px) {
	/* No horizontal pan (keeps the fixed drawer from drifting on iOS), and
	   freeze background scroll while the drawer is open. */
	body { overflow-x: hidden; }
	:root[data-drawer="open"] body { overflow: hidden; }

	/* One column for every layout/sidebar mode. */
	.layout,
	.layout.is-landing,
	:root[data-sidebar="auto"] .layout,
	:root[data-sidebar="auto"] .layout.is-landing {
		grid-template-columns: 1fr;
	}

	/* Sidebar → off-canvas drawer, hidden until :root[data-drawer="open"]. */
	.left,
	:root[data-sidebar="auto"] .left {
		position: fixed;
		top: 0;
		left: 0;
		width: min(280px, 84vw);
		height: 100vh;
		height: 100dvh;   /* dynamic viewport — footer stays above iOS chrome */
		transform: translateX(-100%);
		transition: transform 0.2s ease;
		z-index: 50;
		overflow: hidden;
	}
	:root[data-drawer="open"] .left,
	:root[data-sidebar="auto"][data-drawer="open"] .left {
		transform: translateX(0);
		box-shadow: 0 0 24px rgba(0, 0, 0, 0.4);
	}
	/* Match inner to the visible viewport so .categories scrolls (flex:1) and
	   the footer stays pinned + on-screen. Base 100vh overshoots on iOS. */
	.left-inner { height: 100vh; height: 100dvh; }
	/* .categories sets overflow-y:auto, which makes the spec compute overflow-x
	   to auto too — so its slightly-wider content (negative margin) became
	   horizontally scrollable and panned, clipping item text on the left.
	   Pin it to vertical-only scroll. */
	.left-inner,
	.categories { overflow-x: hidden; }
	/* Touch has no hover — neutralize the desktop peek cue + hover slide. */
	.left::before,
	:root[data-sidebar="auto"] .left::before { display: none; }
	:root[data-sidebar="auto"] .left:hover,
	:root[data-sidebar="auto"] .left:focus-within { transform: translateX(-100%); }
	:root[data-drawer="open"] .left:hover { transform: translateX(0); }
	/* Pin (auto/pinned) toggle is meaningless on mobile — always a drawer. */
	.sidebar-pin { display: none; }
	/* So is dragging a drawer wider than the screen. */
	.left-resize { display: none; }

	/* Hamburger toggle — fixed top-left, hidden while the drawer is open. */
	.drawer-toggle {
		display: flex;
		position: fixed;
		top: 0.6rem;
		left: 0.6rem;
		z-index: 51;
		align-items: center;
		justify-content: center;
		width: 2.4rem;
		height: 2.4rem;
		background: var(--surface);
		color: var(--fg);
		border: 1px solid var(--border);
		border-radius: 6px;
		font-size: 1.2rem;
		line-height: 1;
		cursor: pointer;
	}
	:root[data-drawer="open"] .drawer-toggle { display: none; }

	/* Dim backdrop behind the open drawer; tap to close. */
	.drawer-backdrop {
		display: block;
		position: fixed;
		inset: 0;
		background: rgba(0, 0, 0, 0.5);
		z-index: 45;
		opacity: 0;
		pointer-events: none;
		transition: opacity 0.2s ease;
	}
	:root[data-drawer="open"] .drawer-backdrop {
		opacity: 1;
		pointer-events: auto;
	}

	/* Ask panel: stop being a tall sticky side column; flow in the stack. */
	.right,
	.layout.is-landing .right {
		position: static;
		height: auto;
		overflow: visible;
		padding: 3rem 1.25rem 1.5rem;
	}
	.layout.is-landing .right,
	.layout.is-landing .right:has(#ai-result:empty) {
		justify-content: flex-start;
	}

	/* Body: full width, top padding clears the fixed hamburger. */
	.body { padding: 3rem 1.1rem 1.5rem; }

	/* One column, so there is no ask panel to clear. */
	.body .toc {
		right: 1rem;
		bottom: 1rem;
		max-width: min(20rem, calc(100vw - 2rem));
	}

	/* The dates would be alone on a wrapped line at the far end; let them sit
	   directly after the title instead. */
	.bc-dates { margin-left: 0; }
}
