/* The Private Asylum house style: a terminal, lightly.

   One monospaced face for everything, Geist Mono, self-hosted. A dark screen
   with a faint phosphor glow and a dot grid behind it; hairline borders and
   near-square corners; the product's own hue as the phosphor.

   A page loads Yeti, then this file, then the shared stylesheet for its kind
   of page (docs.css, media.css), then the site's own theme.css last. The
   site styles itself by overriding the variables in the theme contract
   below, in its theme.css, and nothing else: no shared file names a site's
   colours, and a site never restyles a rule.

   Everything here is a Yeti token or an element rule in the yeti.theme layer,
   apart from a few unlayered rules at the end for what Yeti exposes no token
   for. Nothing animates under prefers-reduced-motion. */

@layer yeti.reset, yeti.base, yeti.theme, yeti.layouts, yeti.components, yeti.utilities;

/* THE THEME CONTRACT: what a site's theme.css may set, with the house
   default. Override any of these in the site's own :root; leave the rest.
   Every other Yeti token (spacing, type, radii) can be overridden the same
   way, but these are the ones the house expects a site to choose. */
:root {
	/* Colour. The hues are Yeti's own tokens, with Yeti's defaults until a
	   site sets them, which every site should:
	     --yeti-hue-primary    the phosphor: links, the cursor, the current
	                           page, the eyebrow; the cursor in the brand mark
	     --yeti-hue-secondary  the second accent: strings in code
	     --yeti-hue-neutral    the tint in the greys (Yeti: the primary) */
	--yeti-chroma: 0.15;                               /* how saturated the accents are */
	--pa-neutral-chroma: 0.018;                        /* how much hue the greys keep */
	--pa-eyebrow-color: var(--yeti-color-primary-text); /* the lit segment of the eyebrow path */

	/* The screen behind every page: a glow of the phosphor from the top, over
	   a dot grid. */
	--pa-glow-strength: 11%;                           /* the glow's share of the phosphor */
	--pa-grid-strength: 7%;                            /* the dots' share of the text colour */
	--pa-grid-spacing: 22px;                           /* the distance between dots */
}

/* Geist Mono, variable weight 100 to 900. Each file covers one subset; the
   browser fetches only the subsets a page uses. */
@font-face {
	font-family: "Geist Mono";
	font-style: normal;
	font-display: swap;
	font-weight: 100 900;
	src: url("fonts/geist-mono-latin-wght-normal.woff2") format("woff2");
	unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
	font-family: "Geist Mono";
	font-style: normal;
	font-display: swap;
	font-weight: 100 900;
	src: url("fonts/geist-mono-latin-ext-wght-normal.woff2") format("woff2");
	unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
	font-family: "Geist Mono";
	font-style: italic;
	font-display: swap;
	font-weight: 100 900;
	src: url("fonts/geist-mono-latin-wght-italic.woff2") format("woff2");
	unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
	font-family: "Geist Mono";
	font-style: italic;
	font-display: swap;
	font-weight: 100 900;
	src: url("fonts/geist-mono-latin-ext-wght-italic.woff2") format("woff2");
	unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* Box drawing and block elements: the cursor, the markers. */
@font-face {
	font-family: "Geist Mono";
	font-style: normal;
	font-display: swap;
	font-weight: 100 900;
	src: url("fonts/geist-mono-symbols2-wght-normal.woff2") format("woff2");
	unicode-range: U+2000-2001, U+2004-2008, U+200A, U+23B8-23BD, U+2500-259F;
}

:root {
	/* Type. A monospace reads larger than a proportional face at the same
	   size, so the base sits a step lower and the scale climbs more gently. */
	--yeti-font-sans: "Geist Mono", ui-monospace, "SF Mono", "Cascadia Mono", Menlo, Consolas, monospace;
	--yeti-font-mono: var(--yeti-font-sans);
	--yeti-base-min: 0.9375rem;
	--yeti-base-max: 1rem;
	--yeti-ratio-min: 1.18;
	--yeti-ratio-max: 1.25;
	--yeti-weight-strong: 560;
	--yeti-weight-bold: 680;
	--yeti-tracking-heading: -0.03em;

	/* The screen. Deeper than Yeti's dark surfaces, so the raised and sunken
	   panes separate, and greys that keep a hint of the neutral hue (the
	   contract's --pa-neutral-chroma). */
	--yeti-color-surface: oklch(0.145 var(--pa-neutral-chroma) var(--yeti-hue-neutral));
	--yeti-color-surface-raised: oklch(0.18 var(--pa-neutral-chroma) var(--yeti-hue-neutral));
	--yeti-color-surface-sunken: oklch(0.115 var(--pa-neutral-chroma) var(--yeti-hue-neutral));
	--yeti-color-text: oklch(0.9 var(--pa-neutral-chroma) var(--yeti-hue-neutral));
	--yeti-color-text-muted: oklch(0.66 var(--pa-neutral-chroma) var(--yeti-hue-neutral));
	--yeti-color-border: oklch(0.27 var(--pa-neutral-chroma) var(--yeti-hue-neutral));
	--yeti-color-border-strong: oklch(0.38 var(--pa-neutral-chroma) var(--yeti-hue-neutral));

	/* Links glow in the phosphor and go white under the pointer. */
	--yeti-link-color: var(--yeti-color-primary-text);
	--yeti-link-color-hover: var(--yeti-color-text);

	/* Shape: near-square, hairline. Shadows become a dark drop with no blur
	   toward the light; a terminal has no sun. */
	--yeti-radius-sm: 2px;
	--yeti-radius-md: 4px;
	--yeti-radius-lg: 6px;
	--yeti-badge-radius: var(--yeti-radius-sm);
	--yeti-button-radius: var(--yeti-radius-sm);
	--yeti-shadow-sm: 0 1px 0 oklch(0 0 0 / 0.5);
	--yeti-shadow-md: 0 0 0 1px var(--yeti-color-border), 0 16px 40px -16px oklch(0 0 0 / 0.8);

	/* Components. */
	--yeti-card-surface: color-mix(in oklch, var(--yeti-color-surface-raised) 70%, transparent);
	--yeti-card-border: var(--yeti-color-border);
	--yeti-nav-surface: color-mix(in oklch, var(--yeti-color-surface) 80%, transparent);
	--yeti-nav-panel: var(--yeti-color-surface-raised);
	--yeti-nav-brand-weight: var(--yeti-weight-bold);
	--yeti-table-stripe: transparent;
	--yeti-breadcrumbs-separator: "/";
}

@layer yeti.theme {
	/* Always the dark screen: Yeti's colors are light-dark() pairs, and this
	   picks the dark half whatever the visitor's system prefers. */
	html {
		color-scheme: dark;
		scrollbar-color: var(--yeti-color-border-strong) transparent;
		scrollbar-width: thin;
		font-feature-settings: "calt" 1, "zero" 1;
	}

	/* A phosphor glow from the top of the screen over a faint dot grid. Fixed,
	   so it is the screen and not the page that carries it. */
	body {
		background-color: var(--yeti-color-surface);
		background-image:
			radial-gradient(70rem 32rem at 50% -12rem, color-mix(in oklch, var(--yeti-color-primary) var(--pa-glow-strength), transparent), transparent 70%),
			radial-gradient(color-mix(in oklch, var(--yeti-color-text) var(--pa-grid-strength), transparent) 1px, transparent 1.5px);
		background-size: auto, var(--pa-grid-spacing) var(--pa-grid-spacing);
		background-attachment: fixed;
	}

	::selection {
		background-color: var(--yeti-color-primary);
		color: var(--yeti-on-primary);
	}

	a {
		text-decoration-thickness: 1px;
		text-underline-offset: 0.22em;
	}

	h1, h2, h3, h4 {
		font-weight: var(--yeti-weight-bold);
		text-wrap: balance;
	}

	/* Inline code: a sunken cell with a hairline. Code inside pre is left to
	   the block. */
	:not(pre) > code {
		padding: 0.05em 0.35em;
		border: var(--yeti-border-width) solid var(--yeti-color-border);
		border-radius: var(--yeti-radius-sm);
		background-color: var(--yeti-color-surface-sunken);
		font-size: 0.9em;
	}

	pre {
		border: var(--yeti-border-width) solid var(--yeti-color-border);
		background-color: var(--yeti-color-surface-sunken);
	}

	kbd {
		padding: 0.05em 0.4em;
		border: var(--yeti-border-width) solid var(--yeti-color-border-strong);
		border-block-end-width: 2px;
		border-radius: var(--yeti-radius-sm);
		font-size: 0.85em;
	}

	hr {
		border: 0;
		border-block-start: var(--yeti-border-width) dashed var(--yeti-color-border-strong);
	}

	blockquote {
		border-inline-start-width: 2px;
	}

	th {
		font-size: var(--yeti-text-xs);
		font-weight: var(--yeti-weight-strong);
		text-transform: uppercase;
		letter-spacing: 0.08em;
		color: var(--yeti-color-text-muted);
	}
}

/* What Yeti exposes no token for. */

/* The bar frosts what scrolls under it. */
.nav {
	-webkit-backdrop-filter: blur(12px) saturate(1.2);
	backdrop-filter: blur(12px) saturate(1.2);
}

/* The brand is a prompt. The marker is decoration, hidden from assistive
   technology by the empty alternative text. */
.nav > [data-brand]::before {
	content: "▌" / "";
	margin-inline-end: 0.35em;
	color: var(--yeti-color-primary);
}

/* Badges are bracketed labels, not pills: an outline in the badge's own
   color, lowercase. */
.badge {
	border: var(--yeti-border-width) solid currentColor;
	background-color: transparent;
	text-transform: lowercase;
	letter-spacing: 0.02em;
}

.badge[data-variant="neutral"] {
	border-color: var(--yeti-color-border-strong);
	color: var(--yeti-color-text-muted);
}

/* Buttons: the high-emphasis one is a lit key, the rest are outlined. A
   pressed button sinks a pixel. */
.button {
	letter-spacing: 0.01em;
}

.button:active {
	translate: 0 1px;
}

/* Card titles share one size, linked or not. */
.card :is(h2, h3) {
	font-size: var(--yeti-text-lg);
}

/* Cards light their border on hover, in the phosphor. */
.card {
	transition: border-color var(--yeti-duration-fast) ease, background-color var(--yeti-duration-fast) ease;
}

a.card:hover {
	border-color: color-mix(in oklch, var(--yeti-color-primary) 60%, var(--yeti-color-border));
	background-color: color-mix(in oklch, var(--yeti-color-primary) 5%, var(--yeti-card-surface));
}

/* The footer is a status line. */
body > footer {
	border-block-start: var(--yeti-border-width) solid var(--yeti-color-border);
	font-size: var(--yeti-text-sm);
	color: var(--yeti-color-text-muted);
}

/* The house classes, beyond Yeti's own. The components in
   pvas-web-components emit them; a site's own markup may too.

   pa-prose    flowing text: Markdown output, an about section
   pa-eyebrow  a path-like label above a headline: private-asylum/gantry
   pa-card     a card that is a link as a whole
   pa-cursor   ends an element in the blinking block cursor */

/* Prose. Yeti zeroes block margins and spaces things with stacks, but
   flowing text (rendered Markdown above all) arrives as plain siblings, so
   prose spaces them itself. :where keeps all of it weaker than any heading or
   component rule. */
.pa-prose :where(h1, h2, h3, h4, p, ul, ol, dl, pre, blockquote, table, hr, details, div)
	+ :where(h1, h2, h3, h4, p, ul, ol, dl, pre, blockquote, table, hr, details, div) {
	margin-block-start: var(--yeti-space-md);
}

.pa-prose :where(h3, h4) {
	margin-block-start: var(--yeti-space-lg);
}

/* Lists keep their markers inside the column, lit in the phosphor. */
.pa-prose :where(ul, ol) {
	padding-inline-start: 3ch;
}

.pa-prose :where(li) + :where(li) {
	margin-block-start: calc(var(--yeti-space-xs) / 2);
}

.pa-prose :where(li)::marker {
	color: var(--yeti-color-primary-text);
}

/* Section headings carry their Markdown level, dimmed. Decoration: the
   empty alternative text keeps assistive technology to the words. */
.pa-prose h2::before {
	content: "## " / "";
}

.pa-prose h3::before {
	content: "### " / "";
}

.pa-prose :is(h2, h3)::before {
	color: var(--yeti-color-primary-text);
	opacity: 0.45;
	font-weight: var(--yeti-weight-normal);
}

/* A card set inside prose is still a card: it keeps its own spacing (its
   gap) and its titles carry no Markdown level. */
.pa-prose .card > * + * {
	margin-block-start: 0;
}

.pa-prose .card :is(h2, h3)::before {
	content: none;
}

.pa-eyebrow {
	margin: 0;
	font-size: var(--yeti-text-sm);
	color: var(--pa-eyebrow-color);
}

/* The house and parent segments dim; the last segment, where the page is,
   stays lit. */
.pa-eyebrow-parent {
	color: var(--yeti-color-text-muted);
}

/* A linked card reads as a command: its title ends in an arrow that steps
   forward under the pointer. */
a.pa-card {
	color: inherit;
	text-decoration: none;
}

a.pa-card :is(h2, h3)::after {
	content: "→" / "";
	display: inline-block;
	margin-inline-start: 0.5ch;
	color: var(--yeti-color-primary-text);
	transition: translate var(--yeti-duration-fast) ease;
}

a.pa-card:hover :is(h2, h3) {
	color: var(--yeti-color-primary-text);
}

a.pa-card:hover :is(h2, h3)::after {
	translate: 0.25em 0;
}

/* A block cursor, for whatever a site wants to end in one. */
.pa-cursor::after {
	content: "█" / "";
	margin-inline-start: 0.15ch;
	font-size: 0.8em;
	vertical-align: 0.06em;
	color: var(--yeti-color-primary);
	animation: pa-blink 1.1s steps(1, end) infinite;
}

@keyframes pa-blink {
	50% {
		opacity: 0;
	}
}

@media (prefers-reduced-motion: reduce) {
	.pa-cursor::after {
		animation: none;
	}
}
