body {
	background-color: rgb(var(--zinc-950));
	color: rgb(var(--zinc-100));
}

/* Syntax Highlighting, tuned to sit low-chroma against the Nocturne ground */
.kw { color: rgb(var(--syn-kw)); } /* Keywords - official Go cyan, ties every code block back to the language's own brand */
.fn { color: rgb(var(--syn-fn)); }
.name { color: rgb(var(--syn-name)); font-weight: 600; } /* Functions */
.str { color: rgb(var(--syn-str)); } /* Strings */
.typ { color: rgb(var(--syn-typ)); } /* Types */
.cmt { color: rgb(var(--syn-cmt)); font-style: italic; } /* Comments */
.num { color: rgb(var(--syn-num)); } /* Numbers */

/* Inline code references in prose (e.g. `var a [5]int`). A color
   instead of a background chip — a pill box wraps badly on longer
   snippets like Sum([]int{...}), breaking mid-token across lines.
   Defaults to the "fn" blue, the common case for a prose <code>
   reference (a function, method, package.Identifier, or custom type
   name). Add class="kw" for a keyword or control-syntax reference
   (Go keywords, or a template action like {{define}}/{{range}}),
   class="typ" for a builtin type (string, int, bool), class="str"
   for a string literal, or class="num" for a numeric literal —
   these reuse the exact classes/colors already used inside code
   blocks (see .kw/.fn/.str/.typ/.cmt/.num above), so a reader learns
   one color language for both prose and code. */
code {
	font-family: 'RobotoMono Nerd Font', 'RobotoMono NF', 'Roboto Mono', ui-monospace, monospace;
	font-size: 1em;
	font-weight: 400;
	color: rgb(var(--code-inline));
}

/* A CodeBlock inside a Collapsible.
   CodeBlock is a self-contained panel: its own border, background, and
   rounded corners. Dropped inside the disclosure card that becomes a second
   frame a few pixels inside the first, with the corners fighting. Flattening
   it lets the card's own border be the only one, and the code sits flush
   under the filename header the way a file listing should. */
.collapsible-body [data-copy-wrap] {
	border: 0;
	border-radius: 0;
	background: transparent;
}
.collapsible-body [data-copy-wrap] > pre {
	padding: 1rem 1rem 1.25rem;
}

/* Spacing between blocks inside a prose column.
   The `prose` class on Segment, ProseBlock, and DiagramFigure comes from
   Tailwind Typography, which the Play CDN build does not include, so it
   carries no styles of its own. That left consecutive <p> elements, and a
   <p> after a list, sitting flush against each other. The class is still a
   useful hook, so the spacing is defined here instead. */
.prose > * + * {
	margin-top: 0.8em;
}

/* Links inside prose. A link in the middle of a sentence has no container
   to mark it as clickable, so it carries its own underline at rest rather
   than revealing one on hover the way the site's table rows and cards do.

   Scoped to paragraphs and list items inside a .prose block (Segment's
   explanation column, ProseBlock, DiagramFigure's caption). That keeps it
   off the "Related" pills, the nav, cards, and buttons, which carry their
   own styling and sit in containers that already read as interactive.

   The color stays close to the surrounding text on purpose: inline <code>
   already owns the .fn blue, so a blue prose link would be indistinguishable
   from a plain code reference. The underline is what marks it, which is also
   a non-color cue, so it holds up for a reader who cannot separate the two
   hues. */
.prose p a,
.prose li a {
	color: rgb(var(--zinc-300));
	text-decoration: underline;
	text-decoration-thickness: 1px;
	text-decoration-color: rgb(var(--zinc-600));
	text-underline-offset: 4px;
	transition: color 0.15s ease, text-decoration-color 0.15s ease;
}
.prose p a:hover,
.prose li a:hover {
	color: rgb(var(--brand-go));
	text-decoration-color: rgb(var(--brand-go));
}

/* A link wrapping an inline code reference keeps the code color, so the
   token still reads as code, with the underline marking it as a link. */
.prose p a code,
.prose li a code {
	color: inherit;
}

/* ...except inside highlighted code blocks/terminals, which style themselves */
pre code {
	color: inherit;
	background-color: transparent;
	padding: 0;
	border-radius: 0;
	font-size: inherit;
}

/* Hide scrollbar for sidebar */
.no-scrollbar::-webkit-scrollbar {
	display: none;
}
.no-scrollbar {
	-ms-overflow-style: none;
	scrollbar-width: none;
}

/* Prose container: 80% of its parent, capped to a readable line length,
   full-width with side padding on narrow screens */
.container-md {
	width: 80%;
	max-width: 65ch;
	margin-inline: auto;
}
@media (max-width: 640px) {
	.container-md {
		width: 100%;
		max-width: none;
		padding-inline: 1rem;
	}
}

/* Progress tracking states, driven by progress.js toggling
   these classes off localStorage — see [data-topic-check]
   and [data-mark-done] below. */
.nav-check { color: rgb(var(--zinc-700)); }
.nav-check.is-done { color: rgb(var(--brand-go)); } /* the active theme's chrome accent, not a fixed cyan */
.mark-done-btn.is-done {
	border-color: rgb(var(--brand-go));
	color: rgb(var(--accent-strong));
	background: rgb(var(--accent-surf));
}

/* Corner glow: three soft, fixed radial washes behind the content,
   in the site's three code-highlight accents (Go cyan, string
   green, index pink), so the page reads as one lit surface
   instead of a flat fill. Sits under everything (z-index -1)
   and never intercepts clicks. */
.corner-glow {
	position: fixed;
	inset: 0;
	z-index: -1;
	pointer-events: none;
	background:
		radial-gradient(55vw 55vh at 100% 0%, rgb(var(--brand-go) / 0.14), transparent 60%),
		radial-gradient(50vw 50vh at 0% 100%, rgb(var(--index-strong) / 0.10), transparent 60%),
		radial-gradient(45vw 45vh at 100% 100%, rgb(var(--ok-strong) / 0.08), transparent 60%);
}
/* Search page: the neon-pink "index" accent (see corner-glow above)
   carried into keyboard interaction. A matched substring gets a
   pink highlight, and summoning the page with ⌘K/"/" gets one
   restrained pulse. */
[data-search-row] mark {
	background: rgb(var(--index-strong) / 0.22);
	color: rgb(var(--index-soft));
	border-radius: 2px;
	padding: 0 1px;
}
@keyframes search-summon-pulse {
	0% { box-shadow: 0 0 0 0 rgb(var(--index-strong) / 0.45); }
	100% { box-shadow: 0 0 0 10px rgb(var(--index-strong) / 0); }
}
@media (prefers-reduced-motion: no-preference) {
	.search-summon-pulse {
		animation: search-summon-pulse 0.6s ease-out;
	}
}

/* ------------------------------------------------------------------
   Diagram colors. SVG presentation attributes (fill="#..." on an
   element) are not CSS declarations, so a var() inside one is not
   resolved by every browser. Diagram elements therefore carry a class
   and take their fill/stroke from here, where tokens do work, which is
   also what lets a diagram follow the active theme.
   ------------------------------------------------------------------ */
.dg-stroke  { stroke: rgb(var(--zinc-700)); }
.dg-fill    { fill:   rgb(var(--zinc-900)); }
.dg-inset   { fill:   rgb(var(--zinc-850)); }
.dg-label   { fill:   rgb(var(--zinc-400)); }
.dg-label-dim { fill: rgb(var(--zinc-500)); }
.dg-text    { fill:   rgb(var(--zinc-100)); }

.dg-ok       { stroke: rgb(var(--ok-strong)); }
.dg-ok-fill  { fill:   rgb(var(--ok-strong)); }
.dg-ok-soft  { fill:   rgb(var(--ok-soft)); }
.dg-ok-surf  { fill:   rgb(var(--ok-surf)); }

.dg-warn      { stroke: rgb(var(--warn-strong)); }
.dg-warn-fill { fill:   rgb(var(--warn-strong)); }
.dg-warn-soft { fill:   rgb(var(--warn-soft)); }
.dg-warn-surf { fill:   rgb(var(--warn-surf)); }

.dg-info      { stroke: rgb(var(--info-strong)); }
.dg-info-fill { fill:   rgb(var(--info-strong)); }
.dg-info-soft { fill:   rgb(var(--info-soft)); }
.dg-info-surf { fill:   rgb(var(--info-surf)); }

.dg-alt       { stroke: rgb(var(--alt-strong)); }
.dg-alt-fill  { fill:   rgb(var(--alt-strong)); }
.dg-alt-soft  { fill:   rgb(var(--alt-soft)); }
.dg-alt-surf  { fill:   rgb(var(--alt-surf)); }

.dg-danger-surf { fill: rgb(var(--danger-surf)); }
.dg-accent      { stroke: rgb(var(--brand-go)); }
.dg-accent-fill { fill:   rgb(var(--brand-go)); }

/* The home page gopher rides the ring on a transition, so it answers to a
   reduced-motion preference by landing on the new position directly. */
@media (prefers-reduced-motion: reduce) {
	#home-ring-gopher { transition: none !important; }
}

/* ============================================================
   On this page: the contents rail
   ------------------------------------------------------------
   static/js/site.js builds the list from the page's own <h2>
   headings and adds .has-toc to [data-toc-layout] when there
   are at least three of them. Everything here is keyed off that
   class, so a page with no contents list keeps the full column
   width and reserves no empty gutter.
   ============================================================ */
[data-page-toc] { display: none; }
[data-toc-layout].has-toc [data-page-toc] { display: block; margin: 1.5rem 0 0.5rem; }

/* The article keeps the width it had before the rail existed (max-w-6xl,
   72rem). A page with a rail widens the whole layout by the rail and its
   gap instead of narrowing the column, so the contents list is paid for out
   of the margins where the room actually is. */
.toc-shell {
	width: 100%;
	max-width: 72rem;
	margin-inline: auto;
}

.toc-card {
	width: fit-content;
	max-width: 100%;
	min-width: 13rem;
	border: 1px solid rgb(var(--zinc-800));
	border-radius: 0.5rem;
	background: rgb(var(--zinc-900) / 0.4);
}
.toc-summary {
	display: flex;
	align-items: center;
	gap: 0.5rem;
	padding: 0.35rem 0.7rem;
	cursor: pointer;
	font-size: 10px;
	font-weight: 600;
	text-transform: uppercase;
	letter-spacing: 0.06em;
	color: rgb(var(--zinc-500));
	user-select: none;
	list-style: none;
}
.toc-card:hover .toc-summary { color: rgb(var(--zinc-300)); }
.toc-summary::-webkit-details-marker { display: none; }
.toc-card[open] .toc-chevron { transform: rotate(180deg); }
.toc-chevron { transition: transform 0.2s; }
.toc-body { padding: 0 0.7rem 0.6rem; }
.toc-title { display: none; }

.toc-list { border-left: 1px solid rgb(var(--zinc-800)); }
.toc-list a {
	display: block;
	padding: 0.3rem 0 0.3rem 0.85rem;
	margin-left: -1px;
	border-left: 2px solid transparent;
	font-size: 12.5px;
	line-height: 1.45;
	color: rgb(var(--zinc-500));
	transition: color 0.15s, border-color 0.15s;
}
.toc-list a.is-sub { padding-left: 1.6rem; font-size: 12px; color: rgb(var(--zinc-600)); }
.toc-card:not([open]) { border-color: rgb(var(--zinc-800) / 0.7); }
.toc-card .toc-list a { padding-top: 0.2rem; padding-bottom: 0.2rem; }
.toc-list a:hover { color: rgb(var(--zinc-200)); border-left-color: rgb(var(--zinc-700)); }
.toc-list a.is-sub:hover { color: rgb(var(--zinc-300)); }
.toc-list a.is-current {
	color: rgb(var(--accent-strong));
	border-left-color: rgb(var(--brand-go));
	font-weight: 500;
}

/* A heading is the target of its own link, and <main> is the element that
   scrolls, so the offset has to clear the top of the viewport rather than
   the top of the document. */
.page-view h2,
.page-view h3 { scroll-margin-top: 2rem; }

/* ============================================================
   Collapsible sidebar
   ------------------------------------------------------------
   Driven by data-sidebar on <html>, set before first paint by the
   inline script in layout.templ and toggled by initSidebarCollapse
   in static/js/site.js. Only above md: below that the sidebar is
   already an off-canvas drawer with its own toggle, and collapsing
   a drawer means nothing.

   main carries the container this and the TOC rail both read.
   ============================================================ */

/* md and up only. container-type makes an element a containing block for
   position: fixed, and the mobile nav backdrop is a fixed child of main, so
   containing it below md would trap the backdrop inside the content area. */
@media (min-width: 768px) {
	main { container-type: inline-size; container-name: content; }
}

[data-sidebar-expand] { display: none; }

@media (min-width: 768px) {
	:root[data-sidebar="collapsed"] [data-mobile-nav] {
		width: 0;
		min-width: 0;
		border-right-width: 0;
		overflow: hidden;
	}

	/* The only way back, so it sits where the sidebar was rather than
	   floating over the article. */
	:root[data-sidebar="collapsed"] [data-sidebar-expand] {
		display: flex;
	}
}

/* The rail moves beside the article once the content column can hold both at
   full width: the article's own 72rem, the gap, the rail, and main's padding.
   Below that it stays the collapsible card above the article, because a
   contents list is not worth a fifth of the reading column.

   This is a container query, not a media query, so it measures the space the
   article actually has rather than the window. Collapsing the sidebar hands
   the content area another 16rem, and the rail appears on its own without
   the layout having to know the sidebar exists. */
@container content (min-width: 90rem) {
	[data-toc-layout].has-toc {
		display: grid;
		grid-template-columns: minmax(0, 72rem) 11rem;
		gap: 2rem;
		align-items: start;
		max-width: calc(72rem + 13rem);
	}
	[data-toc-layout].has-toc > [data-page-toc] {
		grid-column: 2;
		grid-row: 1;
		margin-bottom: 0;
		position: sticky;
		top: 2.5rem;
	}
	[data-toc-layout].has-toc > .toc-main { grid-column: 1; grid-row: 1; min-width: 0; }

	/* Beside the content the card frame is noise: the rule down the left of
	   the list is enough to hold it together. */
	.toc-card { border: 0; background: none; border-radius: 0; }
	.toc-summary { display: none; }
	.toc-body { padding: 0; }
	.toc-title {
		display: block;
		font-size: 10px;
		font-weight: 600;
		text-transform: uppercase;
		letter-spacing: 0.08em;
		color: rgb(var(--zinc-500));
		margin-bottom: 0.75rem;
	}
	.toc-list { max-height: calc(100vh - 9rem); overflow-y: auto; }
}

@media (prefers-reduced-motion: no-preference) {
	main { scroll-behavior: smooth; }
}

/* ============================================================
   The home page's go doc palette
   ------------------------------------------------------------
   Rows are built by initHomeSearch in static/js/site.js. The
   grid keeps the name, the kind, and the path in the same three
   places on every row, so a reader scanning five results reads
   down a column rather than across a sentence.
   ============================================================ */
.palette-key {
	border: 1px solid rgb(var(--zinc-800));
	border-radius: 4px;
	padding: 0.05rem 0.3rem;
	color: rgb(var(--zinc-500));
	line-height: 1.4;
}

.palette-row {
	display: grid;
	grid-template-columns: minmax(0, 1fr) auto auto auto;
	align-items: center;
	gap: 0.75rem;
	padding: 0.6rem 1rem;
	font-family: 'RobotoMono Nerd Font', 'RobotoMono NF', 'Roboto Mono', ui-monospace, monospace;
	font-size: 13px;
	transition: background-color 0.12s;
}
.palette-row:hover { background: rgb(var(--zinc-900) / 0.6); }
.palette-row.is-selected { background: rgb(var(--zinc-900)); box-shadow: inset 2px 0 0 rgb(var(--brand-go)); }

.palette-name { color: rgb(var(--zinc-100)); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.palette-pkg { color: rgb(var(--zinc-500)); }
.palette-note-word { color: rgb(var(--zinc-600)); font-size: 11.5px; }
.palette-path { color: rgb(var(--zinc-600)); font-size: 11.5px; text-align: right; }
.palette-row.is-selected .palette-path { color: rgb(var(--zinc-400)); }

.palette-badge {
	font-size: 9px;
	font-weight: 600;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	padding: 0.15rem 0.4rem;
	border-radius: 4px;
	border: 1px solid transparent;
	white-space: nowrap;
}
.palette-ref { color: rgb(var(--info-strong)); border-color: rgb(var(--info-strong) / 0.35); background: rgb(var(--info-surf) / 0.5); }
.palette-guide { color: rgb(var(--ok-strong)); border-color: rgb(var(--ok-strong) / 0.35); background: rgb(var(--ok-surf) / 0.5); }
.palette-tutorial { color: rgb(var(--warn-strong)); border-color: rgb(var(--warn-strong) / 0.35); background: rgb(var(--warn-surf) / 0.5); }
.palette-term { color: rgb(var(--index-strong)); border-color: rgb(var(--index-strong) / 0.35); background: rgb(var(--index-surf) / 0.5); }
.palette-note { color: rgb(var(--zinc-400)); border-color: rgb(var(--zinc-700)); }

.palette-empty {
	padding: 1.1rem 1rem;
	font-family: 'RobotoMono Nerd Font', 'RobotoMono NF', 'Roboto Mono', ui-monospace, monospace;
	font-size: 12.5px;
	color: rgb(var(--zinc-600));
}

/* The path is the first thing to go when the row runs out of room. */
@media (max-width: 640px) {
	.palette-path { display: none; }
	.palette-row { grid-template-columns: minmax(0, 1fr) auto; }
	.palette-row > .palette-path,
	.palette-row > .palette-note-word { display: none; }
	.palette-note-word { display: none; }
}

/* A key in prose that names a real control on the page. It is set as the
   button it refers to, so the eye joins the two without the sentence having
   to say "the button marked Step". */
.demo-key {
	display: inline-block;
	font-family: 'RobotoMono Nerd Font', 'RobotoMono NF', 'Roboto Mono', ui-monospace, monospace;
	font-size: 12px;
	line-height: 1.4;
	padding: 0.15rem 0.5rem;
	border: 1px solid rgb(var(--zinc-700));
	border-radius: 5px;
	background: rgb(var(--zinc-900));
	color: rgb(var(--zinc-100));
}

button.demo-key {
	cursor: pointer;
	transition: background-color .15s ease, border-color .15s ease;
}

button.demo-key:hover {
	background: rgb(var(--zinc-800));
	border-color: rgb(var(--zinc-600));
}
