
/**
 * TYPOGRAPHY
 *
 * Full architecture + philosophy: docs/architecture/typography.md
 *
 * Layered architecture (top is what you write, bottom is what feeds it):
 *
 *   Voice classes        .calm-voice, .attention-voice, ...
 *        ↑               (semantic — names a role, not a size)
 *   Per-voice tokens     --calm-voice-font-size, --calm-voice-font-family, ...
 *        ↑               (the swap surface — themes / white-label override here)
 *   Type scale           --scale-up-1, --scale-up-2, --scale-down-1, ...
 *        ↑               (modular steps generated from a single ratio)
 *   Scale ratio          --scale-ratio
 *                        (named scale — Major Third / Perfect Fourth / Golden Ratio)
 *
 * Modes (data-attrs on <html>):
 *   data-typography  default | classic                            — flips heading/body families
 *   data-type-scale  major-third | perfect-fourth | golden-ratio  — swaps the ratio
 *
 * Philosophy:
 *   Voices are roles, not renderings. "Attention voice" means "this needs to get
 *   noticed," not "this is 1.875rem." The same voice can render any number of
 *   ways across themes.
 *
 *   Type sizes are mostly fixed per scale — the page is a fine-art book; the
 *   grid moves around the text. The exception is `loud-voice`, which is fluid
 *   (clamp). Display moments earn fluidity; body type does not.
 *
 *   Voices carry font, size, rhythm — NOT color. Color is a scope/tone concern
 *   (data-emphasis, data-tone) applied in context. If you find yourself wanting
 *   to add `color:` to a voice, stop — reach for a scope/tone instead.
 */

/* ===== FONT PRIMITIVES ===== */

:root {
	--font-sans: 'PP Neue Montreal', sans-serif;
	--font-serif: 'Georgia', serif;
	--font-mono: 'Monaspace Neon', monospace;

	/* Per-typeface calibration: the face's left side bearing, measured as the
	   gap before a capital H's stem, as a negative em. Every face gets one,
	   declared right here beside it, so swapping a font swaps its inset too.
	   Consumed via the role pointer --font-heading-inset below. */
	--font-sans-inset: -0.05em; /* tuned by eye on "Programming exercises" */
	--font-serif-inset: 0em; /* $todo: Georgia not yet eyeballed */
}

/* ===== SEMANTIC FONT TOKENS ===== */

:root {
	--font-heading: var(--font-sans);
	--font-body: var(--font-serif);
	--font-ui: var(--font-sans);
	--font-code: var(--font-mono);

	/* Optical left edge. Pulls large headings left so the first glyph's stem
	   sits on the column edge instead of its side bearing — at display sizes
	   that built-in gap reads as an indent against the body text.

	   Three questions, three owners:
	   - HOW MUCH is the font's — the --font-*-inset primitives above. This
	     is only a pointer; re-point it wherever --font-heading changes.
	   - WHETHER IT SHOWS is the voice's — attention, loud, welcome consume
	     it. Not strong: at that size it's sub-pixel, and strong-voice lands
	     on spans, legends, summaries and ✓-led lines where a nudge is wrong.
	   - WHETHER IT APPLIES is the scope's — a centered or edge-flush scope
	     sets this to 0, the same way a scope repaints ink. See welcome.css.

	   Mechanics:
	   - em, so one value holds at every size. Never px.
	   - margin-inline-start, not text-indent (headings wrap; indent moves
	     only the first line) and not transform (checked in the browser
	     2026-09: no rendering difference; margin keeps layout honest and
	     leaves transform free for animation).
	   - Margins on one element never add — the cascade picks one. A
	     component's `margin: 0` on a voiced heading silently cancels this
	     (use margin-block there); a second margin nudge replaces, not
	     doubles. It DOES double when mechanisms mix (translateX on top) or a
	     nudged ancestor wraps a nudged heading. One nudge, one mechanism.
	   - A compromise per face: flat stems (P, H) want the most, A/T/W less.

	   No native CSS does this yet (csswg-drafts #5466, open since 2020;
	   text-box-trim is block-axis only). If one ships, an @supports block
	   zeroes the primitives and turns it on — consumption stays here. */
	--font-heading-inset: var(--font-sans-inset);
}

/* Classic mode: flip heading/body */
[data-typography='classic'] {
	--font-heading: var(--font-serif);
	--font-body: var(--font-sans);
	--font-heading-inset: var(--font-serif-inset);
}

/* ===== TYPE SCALE =====
 *
 * Two knobs generate the whole scale:
 *
 *   --type-anchor  the document's optical baseline (typically 1rem). Themes
 *                  override this when a different body font reads visibly
 *                  larger or smaller — keeps perceived size constant across
 *                  font swaps. The ratio handles relationships; the anchor
 *                  handles absolute size.
 *
 *   --scale-ratio  the geometric ratio between consecutive steps.
 *
 * Steps are computed from --step-0 (which reads from --type-anchor) via calc()
 * so the math is visible — change either knob and watch every step recompute.
 *
 * Naming combines the modern --step-0 convention (base = step zero) with
 * readable up/down direction:
 *   --step-0       = base (= --type-anchor)
 *   --step-up-1    = one rung up
 *   --step-down-1  = one rung down
 *
 * Default: Perfect Fourth (1.333). UI/display classic — more presence than
 * a tight book scale, still controlled.
 */

:root {
	--type-anchor: 1.1rem;
	--scale-ratio: 1.25; /* major-second  for now - */

	--step-down-2: calc(var(--step-down-1) / var(--scale-ratio));
	--step-down-1: calc(var(--step-0) / var(--scale-ratio));
	--step-0: var(--type-anchor);
	--step-up-1: calc(var(--step-0) * var(--scale-ratio));
	--step-up-2: calc(var(--step-up-1) * var(--scale-ratio));
	--step-up-3: calc(var(--step-up-2) * var(--scale-ratio));
	--step-up-4: calc(var(--step-up-3) * var(--scale-ratio));
	--step-up-5: calc(var(--step-up-4) * var(--scale-ratio));
}

/* The canonical musical-interval set. Pick one and the whole document re-tunes. */
[data-type-scale='minor-second'] { --scale-ratio: 1.067; }
[data-type-scale='major-second'] { --scale-ratio: 1.125; }
[data-type-scale='minor-third'] { --scale-ratio: 1.2; }
[data-type-scale='major-third'] { --scale-ratio: 1.25; }  /* default */
[data-type-scale='perfect-fourth'] { --scale-ratio: 1.333; }
[data-type-scale='augmented-fourth'] { --scale-ratio: 1.414; }  /* paper sizes (1:√2) */
[data-type-scale='perfect-fifth'] { --scale-ratio: 1.5; }
[data-type-scale='golden-ratio'] { --scale-ratio: 1.618; }
[data-type-scale='major-sixth'] { --scale-ratio: 1.667; }
[data-type-scale='minor-seventh'] { --scale-ratio: 1.778; }
[data-type-scale='major-seventh'] { --scale-ratio: 1.875; }
[data-type-scale='octave'] { --scale-ratio: 2; }

/* ===== PER-VOICE TOKENS =====
 *
 * Each voice resolves to a small token set. Voice classes consume these tokens.
 * Themes / white-label / mode swaps override at this layer — never inside the
 * voice class itself.
 */

:root {
	/* quiet — recedes; UI labels, footnotes, microcopy */
	--quiet-voice-font-family: var(--font-ui);
	--quiet-voice-font-size: var(--step-down-1);
	--quiet-voice-line-height: 1.3;

	/* data — boring data: dates, IDs, counts, version tags. tnum keeps digits aligned */
	--data-voice-font-family: var(--font-code);
	--data-voice-font-size: calc( var(--step-0) * 0.8 );
	--data-voice-line-height: 1.4;
	--data-voice-letter-spacing: 0.01em;

	/* label — control labels: form labels, switch labels, option labels next to inputs */
	--label-voice-font-family: var(--font-ui);
	--label-voice-font-size: var(--step-down-1);
	--label-voice-line-height: 1.3;
	--label-voice-font-weight: 500;

	/* calm — body. Default for <p>. No class needed on paragraphs.
	   Sits at the anchor itself: body literally = the document's optical baseline. */
	--calm-voice-font-family: var(--font-body);
	--calm-voice-font-size: var(--step-0);
	--calm-voice-line-height: 1.5;
	--calm-voice-max-width: 72ch;

	/* strong — sub-display; section openers, pull quotes */
	--strong-voice-font-family: var(--font-heading);
	--strong-voice-font-size: var(--step-up-1);
	--strong-voice-line-height: 1.2;
	--strong-voice-font-weight: 430;

	/* attention — section-level grab; default for text-content h2 */
	--attention-voice-font-family: var(--font-heading);
	--attention-voice-font-size: var(--step-up-3);
	--attention-voice-line-height: 1.2;
	--attention-voice-max-width: 32ch;

	/* loud — display, the documented fluid exception */
	--loud-voice-font-family: var(--font-heading);
	--loud-voice-font-size: clamp(var(--step-up-3), 5vw, var(--step-up-5));
	--loud-voice-font-weight: 500;
	--loud-voice-line-height: 1.2;
	--loud-voice-max-width: 28ch;

	/* ===== APP VOICES =====
	   Parallel voice family for app/chrome surfaces. Locked to mono and
	   fixed sizes so chrome stays stable regardless of the user's
	   typography / scale preferences. Used inside [data-ui='app']. */

	/* app-data — chrome default: small, mono, stable. Section labels,
	   button labels, microcopy in panels. */
	--app-data-voice-font-family:    var(--font-mono);
	--app-data-voice-font-size:      0.825rem;
	--app-data-voice-line-height:    1.4;
	--app-data-voice-letter-spacing: 0.01em;
}

/* ===== ELEMENT DEFAULTS ===== */

p {
	text-wrap: pretty;
}

h1, h2, h3, h4, h5, h6 {
	color: var(--ink-primary);
	text-wrap: pretty;
	text-wrap: balance;

}

/* ===== VOICE CLASSES =====
 *
 * Each class is a token consumer. Don't hardcode values here — set them in
 * the per-voice tokens block above. That's how themes override.
 */

.quiet-voice {
	font-family: var(--quiet-voice-font-family);
	font-size:   var(--quiet-voice-font-size);
	line-height: var(--quiet-voice-line-height);

	&.mono {
		font-family: var(--font-code);
	}
}

.data-voice {
	font-family:           var(--data-voice-font-family);
	font-size:             var(--data-voice-font-size);
	font-feature-settings: 'tnum' 1;
	letter-spacing:        var(--data-voice-letter-spacing);
	line-height:           var(--data-voice-line-height);
}

.app-data-voice {
	font-family:    var(--app-data-voice-font-family);
	font-size:      var(--app-data-voice-font-size);
	line-height:    var(--app-data-voice-line-height);
	letter-spacing: var(--app-data-voice-letter-spacing);
}

.label-voice {
	font-family: var(--label-voice-font-family);
	font-size:   var(--label-voice-font-size);
	line-height: var(--label-voice-line-height);
	font-weight: var(--label-voice-font-weight);
}

/* high-voice — parked, under review. Still in use (header skip-link).
   Not yet tokenized; revisit alongside focus / stout / huge. */
.high-voice {
	font-family: var(--font-ui);
	font-size: 0.83rem;
	text-transform: uppercase;
	letter-spacing: 0.15em;
	font-variation-settings: "wght" 540, "ital" 0;
}

.calm-voice, p { /* all paragraphs default to calm */
	font-family: var(--calm-voice-font-family);
	font-size:   var(--calm-voice-font-size);
	line-height: var(--calm-voice-line-height);
	max-width:   var(--calm-voice-max-width);
	text-wrap:   pretty;

	em {
		/* real italic — assumes the variable font carries an italic axis or face */
		font-style: italic;
	}

	strong, &.strong {
		font-weight: 700;
	}
}

.strong-voice,
text-content h3 {
	font-family: var(--strong-voice-font-family);
	font-size:   var(--strong-voice-font-size);
	line-height: var(--strong-voice-line-height);
	font-weight: var(--strong-voice-font-weight);
}

.attention-voice,
text-content h2 {
	font-family: var(--attention-voice-font-family);
	font-size:   var(--attention-voice-font-size);
	line-height: var(--attention-voice-line-height);
	max-width:   var(--attention-voice-max-width);
	margin-inline-start: var(--font-heading-inset);
}

.loud-voice {
	font-family: var(--loud-voice-font-family);
	font-size:   var(--loud-voice-font-size);
	font-weight: var(--loud-voice-font-weight);
	line-height: var(--loud-voice-line-height);
	max-width:   var(--loud-voice-max-width);
	margin-inline-start: var(--font-heading-inset);
}

.welcome-voice {
	font-family: var(--loud-voice-font-family);
	font-size:   var(--loud-voice-font-size);
	font-weight: var(--loud-voice-font-weight);
	line-height: var(--loud-voice-line-height);
	max-width:  100%;
	margin-inline-start: var(--font-heading-inset);
}

/* ===== ARTICLE / TEXT-CONTENT FLOW =====
 *
 * Article-scope rules — about relationships between siblings, not about voice.
 * Voice handles per-element rendering; this handles rhythm.
 */

:where(article, text-content) {

	/* $todo: Donnie of mise-en-mode lets margins collapse naturally. Worth
	   revisiting whether explicit p+p gives us enough to justify the verbosity. */
	p + p {
		margin-top: 1em;
	}

	h1 + p {
		margin-top: 1.6em;
	}

	/* some headings are implied visually */
	h2:not(.visually-hidden) + p {
		margin-top: 1em;
	}

	h3 + p {
		margin-top: 1em;
	}

	p + h2 {
		margin-top: 1.3em;
	}

	p + h3 {
		margin-top: 1.3em;
	}

	blockquote + p {
		margin-top: 1.7em;
	}

	/* WYSIWYG auto-embeds: a bare YouTube/Vimeo URL on its own line becomes
	   a raw iframe with fixed pixel attributes, wrapped in its own <p> —
	   expand it to the reading band instead. The p sheds the prose measure
	   so the video isn't clamped to text width. Scoped to video-provider
	   srcs: other embeds in prose (CodePen, Substack) carry their own
	   intended geometry. Deliberate video placements use the video module. */
	p:has(> iframe) {
		max-width: none;
	}

	p > iframe[src*='youtube.com'],
	p > iframe[src*='youtube-nocookie.com'],
	p > iframe[src*='player.vimeo.com'] {
		display: block;
		width: 100%;
		height: auto;
		aspect-ratio: 16 / 9;
		background: var(--ink-primary);
	}

	:where(ul, ol):not([role='list']) {
		padding-left: 1.5em;
		margin-top: 1em;
		max-width: 86ch;
	}

	/* how can we target these... without all the ones inbetween! @scope is now - but for example, exercise-list is a list inside article too - */

	> ul, > ol {
		> li + li {
			margin-top: 0.4em;
		}

		> li {
			font-family: var(--calm-voice-font-family);
			font-size:   var(--calm-voice-font-size);
			line-height: var(--calm-voice-line-height);
			max-width:   var(--calm-voice-max-width);
			text-wrap:   pretty;

			em {
				/* real italic — assumes the variable font carries an italic axis or face */
				font-style: italic;
			}

			strong, &.strong {
				font-weight: 700;
			}
		}

		+ p {
			margin-top: 1.7em;
		}
	}

	/* how can we target these... without all the ones inbetween! @scope is now - but for example, exercise-list is a list inside article too - */

	ul { list-style: disc; }
	ol { list-style: decimal; }

	li + li {
		/* margin-top: 0.4em; */
	}

	figcaption a {
		color: inherit;
	}

	blockquote {
		background-color: var(--fill-secondary);
		margin-block: 1em;
		padding: 1em;
		max-width: 90ch;
		border-left: 1px solid var(--accent);
		p {
			color: var(--accent);
		}
	}

	/* Inner-thought bubble.
	 *
	 * Authored as <p class='thinking'><i>...</i></p>. The class is the visual
	 * hook; the <i> is the semantic mood shift (HTML5's spec example for <i>
	 * is "a thought") and carries the italic natively — we don't style it.
	 * Registered as a TinyMCE toolbar button in functions/acf-customization.php
	 * and scripts/tinymce-thinking.js.
	 *
	 * $todo: --bubble is --fill-primary, which collides when the surrounding
	 * section is also --fill-primary (bubble disappears into the page). Right
	 * fix is probably a "fill on top of fill" token, or scoping the bubble
	 * value off the section's own fill. For now, authors place these inside
	 * --fill-secondary sections.
	 */
	p.thinking {
		--bubble: var(--fill-primary);
		--bubble-stroke: var(--stroke-primary);

		position: relative;
		max-width: 36em;
		margin-block: 1.6em 2.2em;
		padding: 1.1em 1.4em;
		color: var(--ink-primary);
		background-color: var(--bubble);
		border-radius: 1.4em;
		filter:
			drop-shadow( 1px  0   0 var(--bubble-stroke))
			drop-shadow(-1px  0   0 var(--bubble-stroke))
			drop-shadow( 0    1px 0 var(--bubble-stroke))
			drop-shadow( 0   -1px 0 var(--bubble-stroke));

		&::before,
		&::after {
			content: '';
			position: absolute;
			left: 1.6em;
			background-color: var(--bubble);
			border-radius: 50%;
		}

		&::before {
			width: 0.7em;
			height: 0.7em;
			bottom: -0.55em;
		}

		&::after {
			width: 0.4em;
			height: 0.4em;
			bottom: -1.1em;
			left: 1.2em;
		}
	}

	p code {
		/* Derive from currentColor so the chip is always a soft tint of the text.
		   Auto-contrasts with whatever section background is behind it (any emphasis). */
		--thing: color-mix(in oklab, currentColor 12%, transparent);

		display: inline-block;
		margin-inline: 0.2em;
		background-color: var(--thing);
		box-shadow: 0.2em 0 0 var(--thing), -0.2em 0 0 var(--thing);
	}
}



/* color shouldn't be in the ^ type-patterns */
p {
	color: var(--ink-secondary);
}

/* ===== CODE ===== */

code {
	font-family: var(--font-code);
	font-size: 0.9em;
}

/* ===== MARKS ===== */

mark {
	display: inline-block;
	background-color: var(--highlighter);
	color: var(--highlighter-ink);
}

/* <q>: intentionally bare. reset.css strips browser-default quotation marks
   and we keep them stripped — authors type the curly marks into the prose
   directly so they survive style-stripping (RSS, Reader View, plain-text
   conversion, copy-paste). The <q> tag still carries the semantic "this is
   a quotation" signal; the visible marks travel with the text. */

/* ===== INLINE SEMANTIC SET =====
 *
 * Starter defaults — specimen at templates/components/style-guide/semantic-inlines.php.
 * Refine alongside the design-system foundations page for inline elements.
 *
 * Convention map:
 *   <code>  inline code, filenames, identifiers      (mono)
 *   <kbd>   keys the reader presses                  (mono, key-cap)
 *   <samp>  literal program output                   (mono)
 *   <var>   placeholder / user-supplied value        (mono italic)
 *   <dfn>   the term being defined (first mention)   (italic)
 *   <abbr>  abbreviation/acronym, with title=""      (dotted underline)
 *   <cite>  title of a referenced work               (italic)
 *   <mark>  highlighted text                         (yellow background, above)
 */

kbd {
	font-family: var(--font-code);
	font-size: 0.85em;
	padding: 0.1em 0.4em;
	border: 1px solid var(--stroke-primary);
	border-radius: 0.25em;
	background-color: var(--fill-secondary);
	box-shadow: 0 1px 0 var(--stroke-primary);
	white-space: nowrap;
}

samp {
	font-family: var(--font-code);
	font-size: 0.9em;
}

var {
	font-family: var(--font-code);
	font-size: 0.9em;
	font-style: italic;
}

dfn {
	font-style: italic;
	font-weight: 500;
}

abbr[title] {
	text-decoration: underline dotted;
	text-underline-offset: 0.2em;
	cursor: help;
}

cite {
	font-style: italic;
}

/* ===== EXTERNAL LINK SIGNIFIER ===== */
/* Chill arrow appended to off-site / target links.
   Glyph candidates from our display font:
     U+2B0F (\2B0F, 681)  — current pick (heavier triangle-headed arrow)
     U+2197 (\2197, 671)  — alt (lighter north-east arrow)
   Internal /relative/#anchor links are excluded by the http(s) check. */

/* Scoped to <p> so the arrow doesn't intrude on headings, nav, cards, etc.
   $todo revisit scoping. <p> alone misses <li>, <blockquote>, <figcaption>.
   Options to weigh next time:
     - :is(p, li, blockquote, figcaption) a[...]   (explicit list of prose containers)
     - text-content a[...] / .prose a[...]         (opt-in by container — likely best fit
                                                    since <text-content> already wraps body copy)
     - global + opt-outs on header/nav/.card       (fragile; exclusions grow forever) */
/* External (off-site) → rightwards arrow.
   Active: \2192  → (rightwards arrow)
   Alts:   \2BA1  ⮡  (down-right arrow)
           \2197  ↗  (north-east arrow, angled up-right)
   The `/ ""` is CSS-generated-content alt text — modern screen readers
   announce the glyph as "right arrow" otherwise. Empty alt silences it,
   since the arrow is a visual signifier and the link text already carries
   the meaning. */
p a[href^="http"]:not([href*="perpetual.education"]):not([href*="pe:8888"])::after {
	/* Leading no-break space (\00A0) glues the arrow to the link's last word.
	   The old `display: inline-block` made the arrow an atomic inline — which
	   is a soft-wrap opportunity, so the arrow could break onto its own line.
	   Staying inline means the link's underline runs under the arrow too;
	   that's the tradeoff for never orphaning it. */
	content: "\00A0\2192" / "";
	font-family: var(--font-ui);
}

/* New-tab → up-right arrow with hook (overrides external when both apply).
   Active: \2B0F  ⬏  (up-right, hooked from below)
   Alts (hooked / curved arrow family — pick by feel):
     \2B0E ⬎   \2B10 ⬐   \2B11 ⬑
     \2BA0 ⮠   \2BA1 ⮡   \2BA2 ⮢   \2BA3 ⮣
     \2BA4 ⮤   \2BA5 ⮥   \2BA6 ⮦   \2BA7 ⮧

   Matches any link whose target opens a different browsing context:
   `target="_blank"` (always new) and any named target like
   `target="docs"` (opens in the named tab — new on first use). The three
   :not()s exclude same-context keywords; everything else qualifies.

   Unlike the external arrow (purely decorative), target≠self carries real
   semantic weight — opening elsewhere is unexpected behavior AT users
   should know about (WCAG 3.2.5). The alt text becomes part of the link's
   accessible name, so AT announces "assertions (new tab), visited, link"
   instead of the glyph. */
p a[target]:not([target="_self"]):not([target="_parent"]):not([target="_top"])::after {
	/* Same no-break-space glue as the external arrow above. */
	content: "\00A0\2B0F" / " (new tab)";
	font-family: var(--font-ui);
}


/* ===== HIGHLIGHTS =====
 *
 * The CSS Highlight family — selection, scroll-to-text-fragment target,
 * and browser find-in-page. Themes override the tokens; structure stays.
 *
 *   ::selection             user-dragged selection (universal)
 *   ::target-text           the fragment a #:~:text= URL landed on
 *   ::search-text           every match for browser find (Chromium 138+)
 *   ::search-text:current   the active find match
 *
 * EVERY token below must be defined — never let a highlight fall through
 * to system colors (Mark, MarkText, Highlight, HighlightText).
 *
 * Why (learned the hard way, 2026-07): system colors are per-browser-build
 * answers, not colors. A build resolves them by its own platform + reported
 * color scheme, and builds disagree. Real case: ::target-text had no tokens,
 * so it fell back to Mark/MarkText — macOS Chrome resolved MarkText black,
 * a student's dark-preference Windows Chrome resolved it WHITE on our light
 * yellow, unreadable. Nothing on the student's machine was misconfigured,
 * and no amount of testing on ours could see it. The failure shape is a
 * SPLIT PAIR: background from one authority (our CSS), ink from another
 * (the browser). Fill and ink must always come from the same authority —
 * which is why reading highlights consume the --highlighter /
 * --highlighter-ink pair (styles/themes/theme-setup.css) instead of
 * raw values.
 *
 * Related, distinct: Chrome's Auto Dark Mode (chrome://flags force-dark)
 * rewrites computed colors at paint time. Explicit tokens don't opt out of
 * that — but it transforms fill and ink TOGETHER, one authority, so pairs
 * stay readable. It's the split, not the transform, that breaks reading.
 *
 * $todo write this up for pssst-css (the "system colors are per-build
 * answers / never split a fill-ink pair" chapter).
 *
 * Notes:
 *   - Highlight pseudos accept a narrow property set (color, background-color,
 *     text-decoration, text-shadow). No padding, border, box-shadow.
 *   - ::search-text is Chromium-only as of 2026; other browsers fall back to
 *     their built-in find UI. That's fine — defaults are usable.
 *   - The "stop selection" / "exclude from copy" pattern is `.no-select` below,
 *     not a highlight-color trick.
 */

:root {
	--selection-background: #fffab5;
	--selection-color: var(--highlighter-ink);

	/* Explicit pairs — never fall through to Mark/MarkText system colors.
	   System-color resolution varies by browser build, OS, and reported
	   color scheme (dark-preference Windows machines resolved MarkText
	   to white on our light content). Ink comes from the highlighter pair
	   in theme-setup.css — repainted per scope alongside the fill. */
	--target-text-background: var(--highlighter);
	--target-text-color: var(--highlighter-ink);

	/* Find-in-page: every match gets a soft accent tint; the current match
	   gets the full accent with white ink so it stands apart. */
	--search-text-background: color-mix(in oklch, var(--accent) 25%, transparent);
	--search-text-current-background: var(--accent);
	--search-text-current-color: white;

/* 	--selection-background: color-mix(in oklch, var(--accent) 35%, transparent);
	--selection-color: var(--ink-primary);

	--target-text-background: color-mix(in oklch, var(--accent) 50%, transparent);
	--target-text-color: var(--ink-primary); */
}

::selection {
	background: var(--selection-background, Highlight);
	color: var(--selection-color, HighlightText);
}

::target-text {
	background: var(--target-text-background, Mark);
	color: var(--target-text-color, MarkText);
}

::search-text {
	background: var(--search-text-background, Mark);
}

::search-text:current {
	background: var(--search-text-current-background, Highlight);
	color: var(--search-text-current-color, HighlightText);
}


/* ===== SELECTION CONTROL =====
 *
 * `.no-select` blocks cursor selection. Two effects in one switch:
 *   1. Double-click and drag don't paint a selection rectangle on the element.
 *   2. When the user Cmd-A's the page and copies, browsers skip
 *      user-select:none regions. Header, footer, copyright, sidebar drop out
 *      of the clipboard automatically — paste contains only content.
 *
 * `.allow-select` opts an inner element back in. Useful inside a `.no-select`
 * footer where the email address, mailing address, or copyright line should
 * still be copyable.
 *
 * Rule of thumb: content gets selected, chrome doesn't. Apply `.no-select` to
 * site header, site footer, nav, breadcrumbs, pagination, admin chrome, tags,
 * badges, status pills. Apply `.allow-select` to anything inside that a user
 * might legitimately want in their clipboard.
 *
 * Not bulletproof "uncopyable": this is cursor-selection-based copy only.
 * View-source, DevTools, and a11y tools still see the text.
 */

.no-select {
	user-select: none;
	-webkit-user-select: none;
}

.allow-select {
	user-select: text;
	-webkit-user-select: text;
}
