/* Pryanic's own layer, on top of uikit's theme variables.
   Every colour is a --mass-* token, so a theme switch restyles the whole site
   without touching this file.

   uikit's theme.css ends with a slice of Tailwind's Preflight, including:

       h1, h2, h3, h4, h5, h6 { font-size: inherit; font-weight: inherit; }
       h1, h2, h3, h4, h5, h6, p, figure, blockquote, dl, dd { margin: 0; }

   So every heading here must state its size, weight AND margin explicitly.
   Leaving any of them out is why headings render as plain body text. */

:root {
	/* One column for the whole site, set by the one thing with a right answer:
	   the reading measure of an article body. Lists, admin and the footer line
	   up with the prose instead of framing it, and the page is the measure plus
	   its own gutters so the text keeps exactly the width it had. The editor
	   opts out below — two panes side by side want the screen. */
	--pry-measure: 46rem;
	--pry-gutter: 24px;
	--pry-page: calc(var(--pry-measure) + var(--pry-gutter) * 2);
	/* One editor pane, sized so the prose inside it is exactly --pry-measure —
	   the preview then breaks its lines where the published page will, which is
	   the only reason to keep a preview at all. The addition is the pane's own
	   frame (14px padding and a 1px border each side) plus the 4px the preview
	   keeps clear for its scrollbar. Two of these need about 1600px of window;
	   under that both panes shrink together, so the preview stays narrower than
	   the article rather than wrong on one side only. */
	--pry-pane: calc(var(--pry-measure) + 34px);
	--pry-radius: 10px;
	--pry-radius-sm: 7px;
	--pry-border: 1px solid var(--mass-border);
}

body {
	margin: 0;
	color: var(--mass-text);
	font: 16px/1.65 ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
	-webkit-font-smoothing: antialiased;
}

a {
	color: var(--mass-accent);
	text-decoration: none;
}

a:hover {
	text-decoration: underline;
}

::selection {
	background: var(--mass-accent-soft);
}

/* ── Shell ─────────────────────────────────────────────────────────────── */

.pry-shell {
	display: flex;
	flex-direction: column;
	min-height: 100dvh;
}

.pry-wrap {
	width: 100%;
	max-width: var(--pry-page);
	margin-inline: auto;
	padding-inline: var(--pry-gutter);
}

/* main and its wrap are flex columns so a page that wants the leftover height
   can ask for it with flex: 1. For every other page this changes nothing —
   block children stack the same either way — but without the chain a full-height
   editor has no container height to resolve against. */
.pry-main {
	flex: 1;
	min-height: 0;
	display: flex;
	flex-direction: column;
	padding-block: 40px 72px;
}

.pry-main > .pry-wrap {
	flex: 1;
	min-height: 0;
	display: flex;
	flex-direction: column;
}

/* ── Header ────────────────────────────────────────────────────────────── */

.pry-header {
	position: sticky;
	top: 0;
	z-index: 10;
	/* A list is something you scan, so the way home follows you down it. */
	border-bottom: var(--pry-border);
	background: color-mix(in srgb, var(--mass-bg-base) 88%, transparent);
	backdrop-filter: blur(8px);
}

/* An article is something you read, and a bar tracking the top of the text for
   twenty screens is in the way. Unscripted it scrolls off with everything else,
   and the reader gets it back at the top of the page. */
.pry-loose {
	position: static;
}

/* Scripted, it does better than either: pinned everywhere, and out of the way
   going down. header.js adds this class, so the rules above stay what a page
   with no JavaScript gets. */
.pry-header-auto {
	position: sticky;
	top: 0;
	transition: transform 0.22s ease;
	will-change: transform;
}

.pry-header-auto.pry-header-away {
	transform: translateY(-100%);
}

/* A control inside it took focus from the keyboard, and a tab stop off screen is
   not usable at all. :focus-visible rather than :focus-within, because a pointer
   focuses what it clicks: the theme swatches prevent their own navigation, so a
   click left focus sitting in the bar and this rule pinned it open for the rest
   of the visit. */
.pry-header-auto:has(:focus-visible) {
	transform: none;
}

@media (prefers-reduced-motion: reduce) {
	.pry-header-auto {
		transition: none;
	}
}

/* Three columns so the title is centred on the page, not in the space the other
   two leave. Both edges are placed by line number: a site with no title leaves
   the middle empty rather than pulling the controls inward. */
.pry-header-inner {
	display: grid;
	grid-template-columns: 1fr auto 1fr;
	align-items: center;
	gap: 24px;
	min-height: 76px;
}

.pry-header-right {
	grid-column: 3;
	justify-self: end;
	display: flex;
	align-items: center;
	gap: 16px;
}

/* The site name, which is a reader's whole header: they have one page, so there
   is no nav — this is the way home from an article. MASS's brand mark: the
   monospace stack at 800 with wide tracking and a halo in the theme accent. Its
   two display faces cover digits only, so a title of letters falls through to
   exactly this stack — no font to ship. */
.pry-brand {
	grid-column: 2;
	justify-self: center;
	display: inline-block;
	color: var(--mass-text);
	font: 800 30px/1.1 ui-monospace, "JetBrains Mono", Menlo, Consolas, monospace;
	letter-spacing: 0.12em;
	/* Tracking is added after the last letter too, so pull it back and the centring
	   is optical rather than arithmetic. */
	margin-right: -0.12em;
	text-shadow: 0 0 18px var(--mass-accent-soft), 0 0 42px var(--mass-accent-soft);
	white-space: nowrap;
	/* A glitch, not an animation: still for seven seconds in eight, then two
	   frames of skew. Keyframes rather than a script, so it runs with JS off
	   and costs nothing to maintain. */
	animation: pry-glitch 8s infinite;
}

.pry-brand:hover {
	color: var(--mass-accent);
	text-decoration: none;
}

@keyframes pry-glitch {
	0%, 74.9% {
		opacity: 1;
		transform: none;
		text-shadow: none;
	}
	75% {
		opacity: 0.72;
		transform: skewX(-5deg) translateX(-1px);
		text-shadow: 1px 0 0 var(--mass-accent-soft), -1px 0 0 var(--mass-accent-soft);
	}
	76.2% {
		opacity: 1;
		transform: none;
		text-shadow: none;
	}
	77% {
		opacity: 0.82;
		transform: skewX(3deg) translateX(1px);
	}
	78%, 100% {
		opacity: 1;
		transform: none;
		text-shadow: none;
	}
}

/* A flicker is exactly what this setting is for. Below the rule it overrides,
   since both name .pry-brand and the later one wins. */
@media (prefers-reduced-motion: reduce) {
	.pry-brand {
		animation: none;
	}
}

/* Nav at the left edge, theme picker pushed to the right by the margin below.
   Admin only. */
.pry-nav {
	display: flex;
	align-items: center;
	gap: 20px;
	font-size: 14.5px;
}

.pry-nav a {
	color: var(--mass-text-muted);
	padding-block: 4px;
	border-bottom: 2px solid transparent;
}

.pry-nav a:hover {
	color: var(--mass-text);
	text-decoration: none;
}

.pry-nav a[aria-current="page"] {
	color: var(--mass-text);
	border-bottom-color: var(--mass-accent);
}

/* Theme picker: plain links, so it works with JS off. */

.pry-themes {
	display: flex;
	gap: 7px;
	align-items: center;
}

.pry-swatch {
	width: 18px;
	height: 18px;
	border-radius: 50%;
	background: var(--sw);
	border: var(--pry-border);
	display: block;
}

.pry-swatch:hover {
	border-color: var(--mass-text-muted);
}

.pry-swatch[aria-current="true"] {
	outline: 2px solid var(--mass-accent);
	outline-offset: 2px;
}

/* ── Buttons ───────────────────────────────────────────────────────────── */

.pry-btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 6px;
	padding: 8px 16px;
	border-radius: var(--pry-radius-sm);
	border: 1px solid transparent;
	font-size: 14.5px;
	font-weight: 600;
	line-height: 1.2;
	cursor: pointer;
	background: none;
	color: var(--mass-text);
	white-space: nowrap;
}

.pry-btn:hover {
	text-decoration: none;
}

/* A control the server has switched off. It has to read as unavailable before it
   is pressed, or the only feedback is a click that does nothing — which reads as
   a broken button rather than an unmet condition. The halo goes too: a glow is
   the loudest "press me" on the page. */
.pry-btn:disabled {
	opacity: 0.4;
	cursor: not-allowed;
	box-shadow: none;
}

/* Hover is where the reason arrives, via the control's title. Nothing about the
   button itself may move under the pointer, or it still reads as pressable. */
.pry-btn-primary:disabled:hover {
	background: var(--mass-accent-fill);
}

.pry-btn-ghost:disabled:hover {
	border-color: var(--mass-border);
	color: var(--mass-text-muted);
}

.pry-btn-sm {
	padding: 5px 11px;
	font-size: 13.5px;
}

/* A button that is only its mark. Square, so three of them beside the theme
   picker still fit inside half the header's leftover width — which is what keeps
   the brand between them optically centred rather than shoved left. */
.pry-btn-icon {
	padding: 0;
	width: 32px;
	height: 32px;
	flex: none;
}

/* Where the author is. The same fill the selected tag chip uses, so "this one is
   on" looks the same wherever it appears. */
.pry-btn-icon[aria-current] {
	background: var(--mass-accent);
	border-color: var(--mass-accent);
	color: var(--mass-bg-base);
	box-shadow: var(--mass-glow-primary, none);
}

.pry-btn-icon[aria-current]:hover {
	background: var(--mass-accent);
	color: var(--mass-bg-base);
}

/* The label follows the theme's own fill ink, not white: a theme whose fill is
   the light source (Carbon's accent is #daf0fd) puts dark ink on it. */
/* These are plain <a>/<button>, not sl-button, so uikit's component rules never
   reach them — the glow hook has to be repeated here. Themes that set no halo
   fall back to none. */
.pry-btn-primary {
	background: var(--mass-accent-fill);
	color: var(--mass-fill-text);
	box-shadow: var(--mass-glow-primary, none);
}

.pry-btn-primary:hover {
	background: color-mix(in srgb, var(--mass-accent-fill) 86%, #000);
}

.pry-btn-ghost {
	border-color: var(--mass-border);
	color: var(--mass-text-muted);
}

.pry-btn-ghost:hover {
	border-color: var(--mass-accent);
	color: var(--mass-text);
	background: var(--mass-bg-hover);
}

/* The same frame every other button has: a destructive action is still an
   action, and a borderless one reads as a link beside two buttons — which on the
   confirm page left Cancel looking like the button and Delete like the caption.
   The ink carries the warning at rest; the red frame arrives on hover, where the
   pointer already is. */
.pry-btn-danger {
	border-color: var(--mass-border);
	color: var(--mass-danger);
}

.pry-btn-danger:hover {
	border-color: var(--mass-danger);
	background: var(--mass-danger-soft);
}

.pry-inline-form {
	display: inline-flex;
}

/* ── Page headings ─────────────────────────────────────────────────────── */

/* Present to a screen reader, absent to everything else. Not display:none and
   not visibility:hidden — both take the element out of the accessibility tree
   too, which is the opposite of the point. */
.pry-offscreen {
	position: absolute;
	width: 1px;
	height: 1px;
	margin: -1px;
	padding: 0;
	border: 0;
	overflow: hidden;
	clip-path: inset(50%);
	white-space: nowrap;
}

.pry-title {
	font-size: 30px;
	font-weight: 700;
	line-height: 1.2;
	letter-spacing: -0.025em;
	margin: 0 0 20px;
	color: var(--mass-text);
}

.pry-lede {
	color: var(--mass-text-muted);
	font-size: 15px;
	margin: -12px 0 22px;
}

/* ── Post list ─────────────────────────────────────────────────────────── */

.pry-list {
	display: flex;
	flex-direction: column;
	gap: 12px;
	list-style: none;
	margin: 0;
	padding: 0;
}

/* The feed stacks the first page, every page loaded after it, and the button —
   at the same gap the cards inside a page use, so a page boundary is invisible. */
.pry-feed {
	display: flex;
	flex-direction: column;
	gap: 12px;
}

.pry-more {
	display: flex;
	justify-content: center;
	padding-block: 8px;
}

/* The button ends the list, so the space under it should read as the gap the
   list left above it — not that gap plus the page's own bottom padding, which
   put it three times closer to the last card than to the footer. Only when
   there is a button: a page that ends in an article still wants the room. */
.pry-main:has(.pry-more:not(:empty)) {
	padding-bottom: 24px;
}

/* Both stay in the document when there is nothing to show, because the server
   patches them by id and an id it cannot find is a patch that lands nowhere.
   Empty, they must not take a row of the feed's gap. */
#post-more:empty,
.pry-more:empty {
	display: none;
}

.pry-card {
	position: relative;
	background: var(--mass-bg-panel);
	border: var(--pry-border);
	border-radius: var(--pry-radius);
	padding: 20px 22px;
	transition: border-color 0.15s ease, transform 0.15s ease;
}

.pry-card:hover {
	border-color: color-mix(in srgb, var(--mass-accent) 55%, transparent);
	transform: translateY(-1px);
}

.pry-card-title {
	font-size: 20px;
	font-weight: 650;
	line-height: 1.3;
	letter-spacing: -0.015em;
	margin: 0 0 8px;
}

.pry-card-title a {
	color: var(--mass-text);
}

/* The whole card opens the post, empty space included, without a second link or
   a click handler: the title's own anchor grows an overlay over the card. One
   link in the accessibility tree, one tab stop, and the href still shows in the
   status bar. The cost is that text inside the card can no longer be selected by
   dragging — the overlay swallows it. */
.pry-card-title a::after {
	content: "";
	position: absolute;
	inset: 0;
	border-radius: inherit;
}

/* Tags sit inside the card and must stay reachable, so lift them out from under
   the overlay. */
/* In a card the tags are a label on the date line, not a control — quieter and
   smaller than the filter chips above, which are. z-index lifts them out of the
   title's click overlay so they stay clickable. */
.pry-card .pry-tag,
.pry-article-header .pry-tag {
	position: relative;
	z-index: 1;
	padding: 1px 8px;
	font-size: 11.5px;
	background: transparent;
	border-color: var(--mass-border);
	color: var(--mass-text-faint);
}

.pry-card .pry-tag:hover,
.pry-article-header .pry-tag:hover {
	border-color: var(--mass-accent);
	color: var(--mass-accent);
}

/* Highlight the title from anywhere on the card, so it is obvious what the click
   is going to open. */
.pry-card:hover .pry-card-title a,
.pry-card-title a:hover {
	color: var(--mass-accent);
	text-decoration: none;
}

/* The overlay is invisible, so focus has to be drawn on the card it covers. */
.pry-card:has(.pry-card-title a:focus-visible) {
	outline: 2px solid var(--mass-accent);
	outline-offset: 2px;
}

.pry-card-title a:focus-visible {
	outline: none;
}

.pry-card-summary {
	margin: 10px 0 0;
	color: var(--mass-text-muted);
	font-size: 14.5px;
	line-height: 1.6;
	/* Summaries are one flattened paragraph, so cap them and cards stay even. */
	display: -webkit-box;
	-webkit-line-clamp: 2;
	-webkit-box-orient: vertical;
	overflow: hidden;
}

.pry-meta {
	display: flex;
	align-items: center;
	gap: 10px;
	flex-wrap: wrap;
	color: var(--mass-text-faint);
	font-size: 13px;
}

.pry-meta .pry-sep {
	opacity: 0.5;
}

/* A date reads short and hovers long: the full instant with its zone lives in
   data-full and is drawn here, so it takes the theme like everything else.
   Dotted underline because nothing else on the site says "there is more here"
   without also saying "this is a link". */
.pry-time {
	position: relative;
	text-decoration: underline dotted currentColor;
	text-underline-offset: 3px;
	text-decoration-thickness: 1px;
	opacity: 0.85;
}

/* Only where a pointer can hover. A touch device has no hover to end, so the
   bubble would open on a tap and stay. */
@media (hover: hover) {
	.pry-time::after {
		content: attr(data-full);
		position: absolute;
		/* Left-aligned rather than centred: every meta line starts at the page's
		   left edge, which is the one side the bubble cannot be clipped against. */
		left: 0;
		/* Below, not above. Above the date on an article is the title, and a
		   bubble across a 42px headline reads as a rendering fault; below is the
		   gap before the rule. Everywhere else it lands on body text, where a
		   floating bubble is what a reader expects. */
		top: calc(100% + 7px);
		z-index: 3;
		padding: 5px 9px;
		border: var(--pry-border);
		border-radius: var(--pry-radius-sm);
		background: var(--mass-bg-panel);
		/* It floats over content, so it needs to look like it does. */
		box-shadow: 0 4px 14px rgb(0 0 0 / 0.28);
		color: var(--mass-text);
		font-size: 12.5px;
		line-height: 1.3;
		white-space: nowrap;
		/* Not display:none — a hidden box cannot be transitioned, and this one
		   should fade rather than blink. pointer-events keeps it from eating the
		   hover that summoned it. */
		opacity: 0;
		visibility: hidden;
		pointer-events: none;
		transition: opacity 120ms ease, visibility 120ms;
	}

	.pry-time:hover::after {
		opacity: 1;
		visibility: visible;
	}
}

/* ── Tags ──────────────────────────────────────────────────────────────── */

.pry-tags {
	display: flex;
	gap: 6px;
	flex-wrap: wrap;
	list-style: none;
	margin: 0;
	padding: 0;
}

.pry-tag {
	display: inline-flex;
	align-items: center;
	gap: 5px;
	padding: 2px 10px;
	border-radius: 999px;
	background: var(--mass-badge-bg);
	color: var(--mass-badge-text);
	font-size: 12.5px;
	border: 1px solid transparent;
}

.pry-tag:hover {
	border-color: var(--mass-accent);
	color: var(--mass-accent);
	text-decoration: none;
}

.pry-tag-count {
	color: var(--mass-text-faint);
	font-variant-numeric: tabular-nums;
}

/* The tag filter on the index. Bigger than the tags in a post's meta line,
   because here they are the control rather than a label. */
.pry-filter {
	display: flex;
	gap: 7px;
	flex-wrap: wrap;
	margin: 0 0 22px;
}

.pry-filter .pry-tag {
	font-size: 13.5px;
	padding: 4px 13px;
}

.pry-filter .pry-tag[aria-current] {
	background: var(--mass-accent);
	color: var(--mass-bg-base);
	box-shadow: var(--mass-glow-primary, none);
}

.pry-filter .pry-tag[aria-current] .pry-tag-count {
	color: inherit;
	opacity: 0.75;
}

/* The long tail, behind the platform's own disclosure — no script, and it keeps
   its state while the page is open.
   order sends the toggle to the end of the row: the tail chips come after it in
   the markup, but "Less" belongs after the thing it closes. */
.pry-filter-more {
	order: 1;
}

.pry-filter-more > summary {
	display: inline-flex;
	align-items: center;
	padding: 4px 13px;
	border-radius: 999px;
	border: 1px dashed var(--mass-border);
	color: var(--mass-text-faint);
	font-size: 13.5px;
	cursor: pointer;
	list-style: none;
}

/* Safari draws its own triangle through ::-webkit-details-marker, which
   list-style alone does not remove. */
.pry-filter-more > summary::-webkit-details-marker {
	display: none;
}

.pry-filter-more > summary:hover {
	border-color: var(--mass-accent);
	color: var(--mass-accent);
}

.pry-filter-more > summary:focus-visible {
	outline: 2px solid var(--mass-accent);
	outline-offset: 2px;
}

/* The tail's wrapper dissolves when the disclosure is open, so its chips become
   flex items of the filter row and carry on from the head's last one instead of
   starting a line of their own. */
.pry-filter-rest {
	display: none;
}

.pry-filter-more[open] ~ .pry-filter-rest {
	display: contents;
}

/* Both labels ship, exactly one is shown. */
.pry-filter-more > summary .pry-more-close,
.pry-filter-more[open] > summary .pry-more-open {
	display: none;
}

.pry-filter-more[open] > summary .pry-more-close {
	display: inline;
}

/* ── Article ───────────────────────────────────────────────────────────── */

.pry-article-header {
	margin-bottom: 32px;
	padding-bottom: 24px;
	border-bottom: var(--pry-border);
}

.pry-article-title {
	font-size: clamp(30px, 4.4vw, 42px);
	font-weight: 750;
	line-height: 1.12;
	letter-spacing: -0.03em;
	margin: 0 0 14px;
	color: var(--mass-text);
}

/* Prose. Every heading restates size + weight + margin, because the preflight
   above zeroes all three. */

.pry-prose {
	font-size: 17px;
	line-height: 1.72;
	color: var(--mass-text);
}

.pry-prose h1,
.pry-prose h2,
.pry-prose h3,
.pry-prose h4,
.pry-prose h5,
.pry-prose h6 {
	color: var(--mass-text);
	letter-spacing: -0.02em;
	line-height: 1.25;
	font-weight: 700;
	margin: 2em 0 0.6em;
}

.pry-prose > :first-child {
	margin-top: 0;
}

.pry-prose h1 { font-size: 28px; }
.pry-prose h2 { font-size: 24px; }
.pry-prose h3 { font-size: 20px; }
.pry-prose h4 { font-size: 17.5px; }
.pry-prose h5,
.pry-prose h6 { font-size: 16px; }

.pry-prose p {
	margin: 0 0 1.15em;
}

.pry-prose ul,
.pry-prose ol {
	margin: 0 0 1.15em;
	padding-left: 1.4em;
}

.pry-prose li {
	margin-bottom: 0.35em;
}

.pry-prose li::marker {
	color: var(--mass-text-faint);
}

.pry-prose strong {
	font-weight: 680;
	color: var(--mass-text);
}

.pry-prose img {
	max-width: 100%;
	height: auto;
	border-radius: var(--pry-radius);
	display: block;
	margin-block: 1.5em;
}

.pry-prose blockquote {
	margin: 1.5em 0;
	padding: 2px 0 2px 18px;
	border-left: 3px solid var(--mass-accent);
	color: var(--mass-text-muted);
	font-style: italic;
}

.pry-prose blockquote p:last-child {
	margin-bottom: 0;
}

.pry-prose hr {
	border: 0;
	border-top: var(--pry-border);
	margin-block: 2.5em;
}

.pry-prose a {
	text-decoration: underline;
	text-decoration-color: color-mix(in srgb, var(--mass-accent) 40%, transparent);
	text-underline-offset: 3px;
}

/* Code */

.pry-prose code {
	font-family: ui-monospace, "JetBrains Mono", SFMono-Regular, Menlo, Consolas, monospace;
	font-size: 0.88em;
	background: var(--mass-bg-active);
	padding: 0.15em 0.4em;
	border-radius: 5px;
}

.pry-prose pre {
	background: var(--mass-bg-panel);
	border: var(--pry-border);
	border-radius: var(--pry-radius);
	padding: 16px 18px;
	overflow-x: auto;
	margin: 0 0 1.4em;
	font-family: ui-monospace, "JetBrains Mono", SFMono-Regular, Menlo, Consolas, monospace;
	font-size: 13.5px;
	line-height: 1.7;
}

.pry-prose pre code {
	background: none;
	padding: 0;
	font-size: inherit;
	line-height: inherit;
}

/* The copy button and the block it belongs to. The wrapper carries the bottom
   margin the <pre> used to, because the <pre> is now inside it — and the button
   anchors to the wrapper rather than the <pre>, which scrolls horizontally and
   would carry it off the edge. Both are built by copy.js; without the script
   neither exists and the block is exactly what it was. */
.pry-code {
	position: relative;
	margin: 0 0 1.4em;
}

.pry-code pre {
	margin: 0;
}

.pry-copy {
	position: absolute;
	top: 8px;
	right: 8px;
	display: inline-flex;
	align-items: center;
	/* Square around a 14px glyph, and it grows on its own for the one state that
	   needs words. */
	padding: 5px;
	border: var(--pry-border);
	border-radius: var(--pry-radius-sm);
	background: var(--mass-bg-base);
	color: var(--mass-text-muted);
	font-size: 11.5px;
	font-family: inherit;
	line-height: 1.6;
	cursor: pointer;
	/* Out of the way until wanted, and never hidden from a keyboard: opacity
	   rather than display, so the button stays focusable and in the tab order. */
	opacity: 0;
	transition: opacity 120ms ease, color 120ms ease, border-color 120ms ease;
}

/* :focus, not :focus-visible, for the reveal: focus-visible is withheld from
   focus the browser judges non-keyboard, which would leave the button invisible
   while it holds focus. The outline below stays on focus-visible, where it
   belongs. */
.pry-code:hover .pry-copy,
.pry-copy:focus {
	opacity: 1;
}

/* A pointer is what the hover reveal assumes. On touch there is none, so the
   button simply stays. */
@media (hover: none) {
	.pry-copy {
		opacity: 1;
	}
}

.pry-copy:hover {
	color: var(--mass-accent);
	border-color: var(--mass-accent);
}

.pry-copy:focus-visible {
	outline: 2px solid var(--mass-accent);
	outline-offset: 2px;
}

.pry-copy[data-state="done"] {
	color: var(--mass-success);
	border-color: color-mix(in srgb, var(--mass-success) 45%, transparent);
}

.pry-copy[data-state="failed"] {
	color: var(--mass-warning);
	border-color: color-mix(in srgb, var(--mass-warning) 45%, transparent);
	/* The fallback is the one state that speaks in words. */
	padding: 3px 9px;
}

/* flex, not inline-flex: an inline-level box sits on a baseline and would give
   the button a descender's worth of padding under the glyph. */
.pry-copy-mark {
	display: flex;
}

/* Tables */

.pry-prose .pry-table-scroll,
.pry-prose table {
	margin: 0 0 1.4em;
}

.pry-prose table {
	width: 100%;
	border-collapse: collapse;
	font-size: 15px;
	border: var(--pry-border);
	border-radius: var(--pry-radius);
	overflow: hidden;
}

.pry-prose th,
.pry-prose td {
	border-bottom: var(--pry-border);
	padding: 9px 14px;
	text-align: left;
}

.pry-prose tr:last-child td {
	border-bottom: 0;
}

.pry-prose th {
	background: var(--mass-bg-panel);
	font-weight: 650;
	color: var(--mass-text);
}

/* Task lists */

.pry-prose input[type="checkbox"] {
	accent-color: var(--mass-accent);
	margin-right: 6px;
	vertical-align: -1px;
}

/* Footnotes */

.pry-prose .footnotes {
	margin-top: 3em;
	padding-top: 1.5em;
	border-top: var(--pry-border);
	font-size: 14.5px;
	color: var(--mass-text-muted);
}

.pry-prose .footnotes hr {
	display: none;
}

/* ── Search ────────────────────────────────────────────────────────────── */

/* No reading-measure cap here: the form is a control, not prose, and it sits
   directly above the result cards. Anything narrower than they are reads as a
   misalignment rather than as a deliberate column. */
.pry-search-form {
	display: flex;
	gap: 10px;
	margin-bottom: 16px;
}

.pry-search-form .pry-input {
	flex: 1;
	padding: 10px 13px;
	font-size: 15px;
}

/* WebKit paints its own clear button on type="search", which sits on the
   site's border colour and reads as a rendering fault. */
.pry-search-form .pry-input::-webkit-search-cancel-button {
	appearance: none;
}

.pry-snippet {
	color: var(--mass-text-muted);
	font-size: 14.5px;
	line-height: 1.6;
	margin: 10px 0 0;
}

.pry-snippet mark {
	background: var(--mass-accent-soft);
	color: var(--mass-accent);
	border-radius: 3px;
	padding: 0 3px;
	font-weight: 600;
}

/* ── Admin ─────────────────────────────────────────────────────────────── */

.pry-row-actions {
	display: flex;
	gap: 6px;
	align-items: center;
}

/* Metrics */

.pry-metrics {
	margin-bottom: 34px;
}

.pry-metrics-title {
	margin: 0 0 12px;
	font-size: 17px;
	font-weight: 650;
	color: var(--mass-text);
}

.pry-table {
	width: 100%;
	border-collapse: collapse;
	font-size: 15px;
	border: var(--pry-border);
	border-radius: var(--pry-radius);
	overflow: hidden;
}

.pry-table th,
.pry-table td {
	border-bottom: var(--pry-border);
	padding: 9px 14px;
	text-align: left;
}

.pry-table tr:last-child td {
	border-bottom: 0;
}

.pry-table th {
	background: var(--mass-bg-panel);
	font-weight: 650;
	color: var(--mass-text);
}

/* Counts are read down the column, so the digits line up: tabular figures and a
   width that holds the widest number this site will ever show. */
.pry-num {
	text-align: right;
	font-variant-numeric: tabular-nums;
	white-space: nowrap;
	width: 8ch;
}

/* The author's buttons. They sit in the header because they belong to no single
   post — everything that does is managed from the post itself. */
.pry-header-actions {
	display: flex;
	gap: 8px;
	align-items: center;
}

/* The controls for one post, on the post. Separated from the article by a rule
   rather than a panel: it is chrome the author sees and the reader never does,
   and boxing it would put a second frame inside the page's own header. */
.pry-post-actions {
	display: flex;
	gap: 6px;
	align-items: center;
	flex-wrap: wrap;
	margin-top: 16px;
	padding-top: 14px;
	border-top: var(--pry-border);
}

.pry-post-actions .pry-status {
	margin: 0 auto 0 0;
}

/* The Draft badge, on a card and in a post's own header. Warning colours, not
   the green badge pair: this is now the only state that is ever badged, and it
   means "not live yet" — green read as the opposite. */
.pry-state {
	font-size: 11px;
	font-weight: 650;
	text-transform: uppercase;
	letter-spacing: 0.07em;
	padding: 3px 9px;
	border-radius: 999px;
	background: var(--mass-warning-soft);
	color: var(--mass-warning);
}

/* A card's whole surface is a link to the post, so the badge must not swallow the
   click, and the action bar's buttons must stay clickable. */
.pry-card .pry-state,
.pry-post-actions {
	position: relative;
	z-index: 1;
}

/* Confirming a deletion: the two choices, side by side. */
.pry-confirm-actions {
	display: flex;
	gap: 8px;
	align-items: center;
	margin-top: 20px;
}

/* ── Editor ────────────────────────────────────────────────────────────── */

/* The editor is the only page that wants the window rather than the page
   measure. A reading column is right for prose and wrong for a writing surface:
   at 60rem the two panes are too narrow to hold a line of Markdown and its
   rendering side by side, and the box ends halfway down a tall screen with
   nothing under it. Widened and stretched to whatever the viewport has left. */
/* One scroll for both panes: the shell is only bounded below, so the panes grow
   to their content and the page's own scrollbar moves the pair together.

   It used to be pinned to exactly 100dvh, which made the remainder a definite
   number the two panes could divide and scroll inside. That gave them a
   scrollbar each: reading the preview left the source where it was, and the
   author scrolled twice to follow one document. */
.pry-shell:has(.pry-editor-page) {
	min-height: 100dvh;
}

/* The bottom pads to the same 19px the grid gap puts above the control bar, so
   the bar sits in its own even band rather than closer to the panes than to the
   footer. */
.pry-main:has(.pry-editor-page) {
	padding-block: 24px 19px;
}

/* The editor's own column widens. The header and footer do not.

   They used to, on the reasoning that chrome stopping short of the content it
   sits above reads as a broken grid — true when the brand was left-aligned and
   had a content edge to line up with. It is centred now, and both bars put their
   controls at the edges of their column: widening those columns flung the
   author's marks and the sign-out button out to the window edges on the way into
   the editor and back again on the way out. Chrome that moves when the page
   changes is worse than chrome that is narrower than the page. */
.pry-shell:has(.pry-editor-page) .pry-main > .pry-wrap {
	max-width: calc(var(--pry-pane) * 2 + 14px + var(--pry-gutter) * 2);
}

/* Rows: the form, then the control bar. Inside the form: the metadata strip,
   then the panes. Every row is auto, so each one asks for the height its content
   needs and the page carries the total — which is what leaves a single scrollbar
   governing both panes. */
.pry-editor-page {
	display: grid;
	grid-template-rows: auto auto;
	gap: 19px;
}

.pry-editor {
	display: grid;
	grid-template-rows: auto auto;
	gap: 14px;
}

/* Centred: the bar used to hold the title field and put its controls at the far
   edge to leave room for it. With the title in the source there is nothing to
   leave room for, and a lone cluster of buttons pinned to one corner of a
   two-pane layout belongs to neither pane.

   Stuck to the bottom, because the page scrolls now: under the panes it would
   sit past the end of the longer one, and Save would be reachable only after
   scrolling the whole post back. Sticky keeps it where the layout puts it, under
   the panes, and on screen the whole way down. */
.pry-editor-bar {
	display: flex;
	align-items: center;
	justify-content: center;
	gap: 16px;
	flex-wrap: wrap;
	position: sticky;
	bottom: 0;
	z-index: 10;
	padding-block: 10px;
	border-top: var(--pry-border);
	background: color-mix(in srgb, var(--mass-bg-base) 88%, transparent);
	backdrop-filter: blur(8px);
}

.pry-editor-bar-actions {
	display: flex;
	align-items: center;
	gap: 8px;
	flex-shrink: 0;
}

/* Summary takes the room, because it is the one field holding a sentence. Tags
   beside it hold a few words. */
.pry-editor-meta {
	display: grid;
	grid-template-columns: minmax(9rem, 1fr) minmax(15rem, 2fr);
	gap: 14px;
	align-items: end;
}

.pry-field {
	display: flex;
	flex-direction: column;
	gap: 5px;
	min-width: 0;
}

.pry-field-label {
	font-size: 11px;
	font-weight: 650;
	text-transform: uppercase;
	letter-spacing: 0.08em;
	color: var(--mass-text-faint);
}

.pry-input {
	width: 100%;
	background: var(--mass-bg-panel);
	color: var(--mass-text);
	border: var(--pry-border);
	border-radius: var(--pry-radius-sm);
	padding: 8px 11px;
	font: inherit;
	font-size: 14px;
}

.pry-input::placeholder {
	color: var(--mass-text-faint);
}

.pry-input:focus,
.pry-source:focus {
	outline: none;
	border-color: var(--mass-accent);
	box-shadow: 0 0 0 3px var(--mass-accent-soft);
}

/* The preview gets --pry-pane and the source takes what is left.

   Two full panes need about 1600px of window, which most screens do not have, so
   one of them has to absorb the shortfall. It is the source: that pane holds
   Markdown in a monospace face and its width means nothing, while the preview's
   width is the whole point — a preview at some other measure breaks its lines
   somewhere the published page will not. Past 1600px the wrap's own cap stops
   the source growing, so the two end up equal. */
.pry-editor-panes {
	display: grid;
	grid-template-columns: minmax(0, 1fr) minmax(0, var(--pry-pane));
	gap: 14px;
	min-height: 0;
}

.pry-pane {
	display: flex;
	flex-direction: column;
	min-width: 0;
	min-height: 0;
	background: var(--mass-bg-panel);
	border: var(--pry-border);
	border-radius: var(--pry-radius);
	padding: 12px 14px 14px;
}

.pry-pane-head {
	display: flex;
	align-items: center;
	gap: 10px;
	margin-bottom: 10px;
	flex-shrink: 0;
}

/* The title takes the slack, so every control after it groups at the right edge
   rather than spreading evenly across the head. */
.pry-pane-title {
	margin: 0;
	margin-right: auto;
	font-size: 11px;
	font-weight: 650;
	text-transform: uppercase;
	letter-spacing: 0.09em;
	color: var(--mass-text-faint);
}

/* The pane head's trailing controls: the Images link, and the Insert image
   button the upload script adds beside it. Both read as chrome, not as actions
   competing with Save. */
.pry-pane-link {
	background: none;
	border: 0;
	padding: 0;
	font: inherit;
	font-size: 11px;
	font-weight: 650;
	text-transform: uppercase;
	letter-spacing: 0.09em;
	color: var(--mass-text-faint);
	cursor: pointer;
}

.pry-pane-link:hover {
	color: var(--mass-accent);
	text-decoration: none;
}

/* Only while a file is over the textarea. */
.pry-source.pry-dropping {
	border-color: var(--mass-accent);
	box-shadow: 0 0 0 3px var(--mass-accent-soft);
}

/* The source grows to its own text rather than scrolling inside a fixed box,
   which is what puts both panes on the page's one scrollbar.

   field-sizing is what makes a textarea do that, and Chrome has it while Firefox
   does not (measured, not assumed). Where it is missing, grow.js sets the height
   instead; where JavaScript is off too, min-height is the whole box and the
   textarea keeps its own scrollbar — the preview still rides the page.

   flex-basis stays auto, not the 0 that `flex: 1` would set: the pane's height
   has to come from this element's content, and a zero basis hides it. Growing is
   still allowed, so the shorter pane stretches to the taller one and the pair
   stay the same height. */
.pry-source {
	flex: 1 1 auto;
	field-sizing: content;
	min-height: 24rem;
	width: 100%;
	resize: none;
	display: block;
	background: var(--mass-bg-base);
	color: var(--mass-text);
	border: var(--pry-border);
	border-radius: var(--pry-radius-sm);
	padding: 12px 14px;
	font-family: ui-monospace, "JetBrains Mono", SFMono-Regular, Menlo, Consolas, monospace;
	font-size: 13.5px;
	line-height: 1.7;
	tab-size: 4;
}

/* No font-size of its own. It carried 15.5px against the article's 17px, which
   put the preview's line breaks in different places from the published page's
   whatever the pane was wide — the one thing a preview must not do. */
.pry-preview-body {
	flex: 1 1 auto;
	padding-right: 4px;
}

/* The preview pane is server-rendered, this only marks a render in flight. */
.pry-busy {
	opacity: 0.5;
	transition: opacity 0.12s ease;
}

.pry-status {
	font-size: 13px;
	color: var(--mass-text-muted);
	white-space: nowrap;
}

/* Below the split, panes stack and size to content: two half-height boxes on a
   phone are worse than one of each you can scroll past.

   77rem, not the 62rem it was: the preview holds its measure and the source
   takes the rest, so the narrower the window the narrower the source, and by
   1100px it was a 208px column to write Markdown in. This is the width where the
   source still gets 400px. Under it, one truthful preview stacked under a usable
   editor beats two panes that are each wrong. */
@media (max-width: 77rem) {
	.pry-editor-meta {
		grid-template-columns: 1fr;
	}

	/* Stacked, but still capped and centred: the preview keeps the article's
	   measure here too, which is the only width at which it tells the truth. */
	.pry-editor-panes {
		grid-template-columns: minmax(0, var(--pry-pane));
		justify-content: center;
	}

	.pry-editor-bar-actions {
		width: 100%;
		justify-content: center;
	}

	/* Less of the window goes to the source when the panes are stacked: what is
	   under it is the preview of the same text, not empty page. */
	.pry-source {
		min-height: 20rem;
	}

	.pry-preview-body {
		min-height: 10rem;
	}
}

.pry-status[data-variant="error"] {
	color: var(--mass-danger);
}

.pry-status[data-variant="success"] {
	color: var(--mass-success);
}

/* Login */

.pry-login {
	max-width: 21rem;
	margin: 8vh auto 0;
	display: flex;
	flex-direction: column;
	gap: 16px;
	background: var(--mass-bg-panel);
	border: var(--pry-border);
	border-radius: var(--pry-radius);
	padding: 28px;
}

.pry-login .pry-input {
	padding: 10px 13px;
	font-size: 15px;
}

.pry-login .pry-title {
	margin-bottom: 0;
	font-size: 22px;
}

/* ── Images ────────────────────────────────────────────────────────────── */

.pry-upload-form {
	display: flex;
	gap: 10px;
	align-items: center;
	flex-wrap: wrap;
	margin-bottom: 12px;
}

.pry-upload-form .pry-input {
	width: auto;
	flex: 1;
	min-width: 14rem;
	padding: 6px 8px;
}

/* The browser's own file button is the only unthemed control on the site, and
   this is the one selector that reaches it. */
.pry-upload-form .pry-input::file-selector-button {
	margin-right: 10px;
	background: var(--mass-bg-base);
	color: var(--mass-text);
	border: var(--pry-border);
	border-radius: var(--pry-radius-sm);
	padding: 5px 12px;
	font: inherit;
	font-size: 13px;
	font-weight: 600;
	cursor: pointer;
}

.pry-upload-form .pry-input::file-selector-button:hover {
	border-color: var(--mass-accent);
	color: var(--mass-accent);
}

.pry-upload-list {
	display: flex;
	flex-direction: column;
	gap: 8px;
	list-style: none;
	margin: 0;
	padding: 0;
}

.pry-upload {
	display: flex;
	align-items: center;
	gap: 14px;
	flex-wrap: wrap;
	background: var(--mass-bg-panel);
	border: var(--pry-border);
	border-radius: var(--pry-radius);
	padding: 12px 16px;
}

/* A fixed box with a checkered backdrop: a transparent PNG on a panel-coloured
   card otherwise looks like a broken image. */
.pry-upload-thumb {
	flex-shrink: 0;
	width: 72px;
	height: 72px;
	display: grid;
	place-items: center;
	overflow: hidden;
	border-radius: var(--pry-radius-sm);
	border: var(--pry-border);
	background-color: var(--mass-bg-base);
	background-image:
		linear-gradient(45deg, var(--mass-border) 25%, transparent 25%),
		linear-gradient(-45deg, var(--mass-border) 25%, transparent 25%),
		linear-gradient(45deg, transparent 75%, var(--mass-border) 75%),
		linear-gradient(-45deg, transparent 75%, var(--mass-border) 75%);
	background-size: 12px 12px;
	background-position: 0 0, 0 6px, 6px -6px, -6px 0;
}

.pry-upload-thumb img {
	max-width: 100%;
	max-height: 100%;
	object-fit: contain;
}

.pry-upload-main {
	flex: 1;
	min-width: 0;
	display: flex;
	flex-direction: column;
	gap: 6px;
}

.pry-upload-name {
	margin: 0;
	font-weight: 620;
	font-size: 15px;
	color: var(--mass-text);
	overflow-wrap: anywhere;
}

/* user-select: all makes one click take the whole snippet, which is what a copy
   button would be for — and this needs no script. */
.pry-upload-snippet {
	user-select: all;
	display: inline-block;
	max-width: 100%;
	overflow-wrap: anywhere;
	background: var(--mass-bg-base);
	border: var(--pry-border);
	border-radius: var(--pry-radius-sm);
	padding: 5px 9px;
	font-family: ui-monospace, "JetBrains Mono", SFMono-Regular, Menlo, Consolas, monospace;
	font-size: 12.5px;
	color: var(--mass-text-muted);
}

.pry-upload-preview {
	max-width: 100%;
	max-height: 40vh;
	border-radius: var(--pry-radius);
	border: var(--pry-border);
}

/* ── Misc ──────────────────────────────────────────────────────────────── */

.pry-empty {
	color: var(--mass-text-faint);
	text-align: center;
	padding: 56px 16px;
	border: 1px dashed var(--mass-border);
	border-radius: var(--pry-radius);
	font-size: 15px;
}

.pry-error {
	text-align: center;
	padding: 8vh 0;
}

.pry-error-detail {
	margin: -4px 0 24px;
	color: var(--mass-text-faint);
	font-size: 15px;
}

.pry-error-code {
	font-size: 64px;
	font-weight: 750;
	letter-spacing: -0.03em;
	line-height: 1;
	margin: 0 0 12px;
	color: var(--mass-text-faint);
}

/* ── Footer ────────────────────────────────────────────────────────────── */

.pry-footer {
	border-top: var(--pry-border);
	color: var(--mass-text-faint);
	font-size: 13.5px;
	padding-block: 20px;
}

/* Grid, not flex: the credit sits in the middle column, so it is centred on the
   page rather than in whatever space the other two leave. The 1fr columns are
   what makes those two symmetric — space-between would push the middle right,
   because the owner and their links are wider than the auth button. */
.pry-footer-inner {
	display: grid;
	grid-template-columns: 1fr auto 1fr;
	align-items: center;
	gap: 16px;
}

.pry-footer-inner > :last-child {
	justify-self: end;
}

/* The credit, centred on the footer row. Quieter than everything beside it — it
   names the tool, and the reader came for the posts. */
.pry-colophon {
	color: var(--mass-text-faint);
	font-size: 12.5px;
}

/* Links elsewhere are marked by the accent colour, which is too loud for a
   credit. Muted instead — but then it needs an underline, or the only thing
   saying "link" is gone and it reads as the sentence it sits in. */
.pry-colophon a {
	color: inherit;
	text-decoration: underline;
	text-decoration-color: color-mix(in srgb, currentColor 50%, transparent);
	text-underline-offset: 2px;
}

.pry-colophon a:hover {
	color: var(--mass-accent);
	text-decoration-color: currentColor;
}

/* The owner's name and their links are one group, so the auth control keeps the
   far edge to itself however many links there are. */
.pry-footer-owner {
	display: flex;
	align-items: center;
	gap: 14px;
	flex-wrap: wrap;
}

.pry-social {
	display: flex;
	align-items: center;
	gap: 12px;
	list-style: none;
	margin: 0;
	padding: 0;
}

/* flex, not inline-flex: an inline-level box sits on a baseline, so the list item
   grew a descender's worth of space under the mark and the mark rode 3px above
   the name beside it. Block-level, and the item is exactly the icon. */
.pry-social-link {
	display: flex;
	color: var(--mass-text-faint);
	border-radius: var(--pry-radius-sm);
}

.pry-social-link:hover {
	color: var(--mass-accent);
	text-decoration: none;
}

.pry-social-link:focus-visible {
	outline: 2px solid var(--mass-accent);
	outline-offset: 3px;
}

@media (max-width: 40rem) {
	/* Nav and picker still fit one row without the brand mark, only the
	   breathing room needs to come down. */
	.pry-wrap {
		padding-inline: 16px;
	}

	/* A long title plus the picker doesn't fit a phone at 30px, so the title
	   comes down with the header whose height it sets. */
	.pry-header-inner {
		gap: 12px;
		min-height: 62px;
	}

	.pry-brand {
		font-size: 22px;
	}

	/* Signed in there are three buttons and the picker beside a centred brand,
	   which is more than a phone is wide — so that row splits in two. A reader
	   has only the picker there and keeps the single row. */
	.pry-header-inner:has(.pry-header-actions) {
		grid-template-columns: 1fr;
		justify-items: center;
		padding-block: 10px;
		min-height: 0;
	}

	/* Both children name a column of the three-column layout, which this one no
	   longer has — left alone they would be placed into implicit columns beside
	   it rather than stacked in it. */
	.pry-header-inner:has(.pry-header-actions) .pry-brand,
	.pry-header-inner:has(.pry-header-actions) .pry-header-right {
		grid-column: 1;
		justify-self: center;
		flex-wrap: wrap;
		justify-content: center;
	}

	.pry-nav {
		gap: 14px;
		font-size: 14px;
	}

	.pry-main {
		padding-block: 28px 48px;
	}

	/* Three columns can't hold their content this narrow — the owner's links
	   and the credit would both wrap mid-group. Stack instead, centred: the
	   brand above is centred at every width, so a left-aligned footer is the
	   one thing on the page that starts anywhere else. */
	.pry-footer-inner {
		grid-template-columns: 1fr;
		justify-items: center;
		gap: 12px;
	}

	.pry-footer-inner > :last-child {
		justify-self: center;
	}
}

html.sl-theme-dark {
/* Background */ .chroma-bg { color: #f8f8f2; background-color: #282a36; }
/* PreWrapper */ .chroma-chroma { color: #f8f8f2; background-color: #282a36; }
/* LineTableTD */ .chroma-chroma .chroma-lntd { vertical-align: top; padding: 0; margin: 0; border: 0; }
/* LineTable */ .chroma-chroma .chroma-lntable { border-spacing: 0; padding: 0; margin: 0; border: 0; }
/* LineHighlight */ .chroma-chroma .chroma-hl { background-color: #3d3f4a }
/* LineNumbersTable */ .chroma-chroma .chroma-lnt { white-space: pre; user-select: none; margin-right: 0.4em; padding: 0 0.4em 0 0.4em;color: #7f7f7f }
/* LineNumbers */ .chroma-chroma .chroma-ln { white-space: pre; user-select: none; margin-right: 0.4em; padding: 0 0.4em 0 0.4em;color: #7f7f7f }
/* Line */ .chroma-chroma .chroma-line { display: flex; }
/* Keyword */ .chroma-chroma .chroma-k { color: #ff79c6 }
/* KeywordConstant */ .chroma-chroma .chroma-kc { color: #ff79c6 }
/* KeywordDeclaration */ .chroma-chroma .chroma-kd { color: #8be9fd; font-style: italic }
/* KeywordNamespace */ .chroma-chroma .chroma-kn { color: #ff79c6 }
/* KeywordPseudo */ .chroma-chroma .chroma-kp { color: #ff79c6 }
/* KeywordReserved */ .chroma-chroma .chroma-kr { color: #ff79c6 }
/* KeywordType */ .chroma-chroma .chroma-kt { color: #8be9fd }
/* NameAttribute */ .chroma-chroma .chroma-na { color: #50fa7b }
/* NameBuiltin */ .chroma-chroma .chroma-nb { color: #8be9fd; font-style: italic }
/* NameClass */ .chroma-chroma .chroma-nc { color: #50fa7b }
/* NameFunction */ .chroma-chroma .chroma-nf { color: #50fa7b }
/* NameLabel */ .chroma-chroma .chroma-nl { color: #8be9fd; font-style: italic }
/* NameTag */ .chroma-chroma .chroma-nt { color: #ff79c6 }
/* NameVariable */ .chroma-chroma .chroma-nv { color: #8be9fd; font-style: italic }
/* NameVariableClass */ .chroma-chroma .chroma-vc { color: #8be9fd; font-style: italic }
/* NameVariableGlobal */ .chroma-chroma .chroma-vg { color: #8be9fd; font-style: italic }
/* NameVariableInstance */ .chroma-chroma .chroma-vi { color: #8be9fd; font-style: italic }
/* LiteralString */ .chroma-chroma .chroma-s { color: #f1fa8c }
/* LiteralStringAffix */ .chroma-chroma .chroma-sa { color: #f1fa8c }
/* LiteralStringBacktick */ .chroma-chroma .chroma-sb { color: #f1fa8c }
/* LiteralStringChar */ .chroma-chroma .chroma-sc { color: #f1fa8c }
/* LiteralStringDelimiter */ .chroma-chroma .chroma-dl { color: #f1fa8c }
/* LiteralStringDoc */ .chroma-chroma .chroma-sd { color: #f1fa8c }
/* LiteralStringDouble */ .chroma-chroma .chroma-s2 { color: #f1fa8c }
/* LiteralStringEscape */ .chroma-chroma .chroma-se { color: #f1fa8c }
/* LiteralStringHeredoc */ .chroma-chroma .chroma-sh { color: #f1fa8c }
/* LiteralStringInterpol */ .chroma-chroma .chroma-si { color: #f1fa8c }
/* LiteralStringOther */ .chroma-chroma .chroma-sx { color: #f1fa8c }
/* LiteralStringRegex */ .chroma-chroma .chroma-sr { color: #f1fa8c }
/* LiteralStringSingle */ .chroma-chroma .chroma-s1 { color: #f1fa8c }
/* LiteralStringSymbol */ .chroma-chroma .chroma-ss { color: #f1fa8c }
/* LiteralNumber */ .chroma-chroma .chroma-m { color: #bd93f9 }
/* LiteralNumberBin */ .chroma-chroma .chroma-mb { color: #bd93f9 }
/* LiteralNumberFloat */ .chroma-chroma .chroma-mf { color: #bd93f9 }
/* LiteralNumberHex */ .chroma-chroma .chroma-mh { color: #bd93f9 }
/* LiteralNumberInteger */ .chroma-chroma .chroma-mi { color: #bd93f9 }
/* LiteralNumberIntegerLong */ .chroma-chroma .chroma-il { color: #bd93f9 }
/* LiteralNumberOct */ .chroma-chroma .chroma-mo { color: #bd93f9 }
/* Operator */ .chroma-chroma .chroma-o { color: #ff79c6 }
/* OperatorWord */ .chroma-chroma .chroma-ow { color: #ff79c6 }
/* Comment */ .chroma-chroma .chroma-c { color: #6272a4 }
/* CommentHashbang */ .chroma-chroma .chroma-ch { color: #6272a4 }
/* CommentMultiline */ .chroma-chroma .chroma-cm { color: #6272a4 }
/* CommentSingle */ .chroma-chroma .chroma-c1 { color: #6272a4 }
/* CommentSpecial */ .chroma-chroma .chroma-cs { color: #6272a4 }
/* CommentPreproc */ .chroma-chroma .chroma-cp { color: #ff79c6 }
/* CommentPreprocFile */ .chroma-chroma .chroma-cpf { color: #ff79c6 }
/* GenericDeleted */ .chroma-chroma .chroma-gd { color: #ff5555 }
/* GenericEmph */ .chroma-chroma .chroma-ge { text-decoration: underline }
/* GenericHeading */ .chroma-chroma .chroma-gh { font-weight: bold }
/* GenericInserted */ .chroma-chroma .chroma-gi { color: #50fa7b; font-weight: bold }
/* GenericOutput */ .chroma-chroma .chroma-go { color: #44475a }
/* GenericSubheading */ .chroma-chroma .chroma-gu { font-weight: bold }
/* GenericUnderline */ .chroma-chroma .chroma-gl { text-decoration: underline }

.chroma-chroma { background: transparent; }

}
html.sl-theme-light {
/* Background */ .chroma-bg { background-color: #f8f8f8; }
/* PreWrapper */ .chroma-chroma { background-color: #f8f8f8; }
/* Other */ .chroma-chroma .chroma-x { color: #000000 }
/* Error */ .chroma-chroma .chroma-err { color: #a40000 }
/* LineTableTD */ .chroma-chroma .chroma-lntd { vertical-align: top; padding: 0; margin: 0; border: 0; }
/* LineTable */ .chroma-chroma .chroma-lntable { border-spacing: 0; padding: 0; margin: 0; border: 0; }
/* LineHighlight */ .chroma-chroma .chroma-hl { background-color: #dfdfdf }
/* LineNumbersTable */ .chroma-chroma .chroma-lnt { white-space: pre; user-select: none; margin-right: 0.4em; padding: 0 0.4em 0 0.4em;color: #7f7f7f }
/* LineNumbers */ .chroma-chroma .chroma-ln { white-space: pre; user-select: none; margin-right: 0.4em; padding: 0 0.4em 0 0.4em;color: #7f7f7f }
/* Line */ .chroma-chroma .chroma-line { display: flex; }
/* Keyword */ .chroma-chroma .chroma-k { color: #204a87; font-weight: bold }
/* KeywordConstant */ .chroma-chroma .chroma-kc { color: #204a87; font-weight: bold }
/* KeywordDeclaration */ .chroma-chroma .chroma-kd { color: #204a87; font-weight: bold }
/* KeywordNamespace */ .chroma-chroma .chroma-kn { color: #204a87; font-weight: bold }
/* KeywordPseudo */ .chroma-chroma .chroma-kp { color: #204a87; font-weight: bold }
/* KeywordReserved */ .chroma-chroma .chroma-kr { color: #204a87; font-weight: bold }
/* KeywordType */ .chroma-chroma .chroma-kt { color: #204a87; font-weight: bold }
/* Name */ .chroma-chroma .chroma-n { color: #000000 }
/* NameAttribute */ .chroma-chroma .chroma-na { color: #c4a000 }
/* NameBuiltin */ .chroma-chroma .chroma-nb { color: #204a87 }
/* NameBuiltinPseudo */ .chroma-chroma .chroma-bp { color: #3465a4 }
/* NameClass */ .chroma-chroma .chroma-nc { color: #000000 }
/* NameConstant */ .chroma-chroma .chroma-no { color: #000000 }
/* NameDecorator */ .chroma-chroma .chroma-nd { color: #5c35cc; font-weight: bold }
/* NameEntity */ .chroma-chroma .chroma-ni { color: #ce5c00 }
/* NameException */ .chroma-chroma .chroma-ne { color: #cc0000; font-weight: bold }
/* NameFunction */ .chroma-chroma .chroma-nf { color: #000000 }
/* NameFunctionMagic */ .chroma-chroma .chroma-fm { color: #000000 }
/* NameLabel */ .chroma-chroma .chroma-nl { color: #f57900 }
/* NameNamespace */ .chroma-chroma .chroma-nn { color: #000000 }
/* NameOther */ .chroma-chroma .chroma-nx { color: #000000 }
/* NameProperty */ .chroma-chroma .chroma-py { color: #000000 }
/* NameTag */ .chroma-chroma .chroma-nt { color: #204a87; font-weight: bold }
/* NameVariable */ .chroma-chroma .chroma-nv { color: #000000 }
/* NameVariableClass */ .chroma-chroma .chroma-vc { color: #000000 }
/* NameVariableGlobal */ .chroma-chroma .chroma-vg { color: #000000 }
/* NameVariableInstance */ .chroma-chroma .chroma-vi { color: #000000 }
/* NameVariableMagic */ .chroma-chroma .chroma-vm { color: #000000 }
/* Literal */ .chroma-chroma .chroma-l { color: #000000 }
/* LiteralDate */ .chroma-chroma .chroma-ld { color: #000000 }
/* LiteralString */ .chroma-chroma .chroma-s { color: #4e9a06 }
/* LiteralStringAffix */ .chroma-chroma .chroma-sa { color: #4e9a06 }
/* LiteralStringBacktick */ .chroma-chroma .chroma-sb { color: #4e9a06 }
/* LiteralStringChar */ .chroma-chroma .chroma-sc { color: #4e9a06 }
/* LiteralStringDelimiter */ .chroma-chroma .chroma-dl { color: #4e9a06 }
/* LiteralStringDoc */ .chroma-chroma .chroma-sd { color: #8f5902; font-style: italic }
/* LiteralStringDouble */ .chroma-chroma .chroma-s2 { color: #4e9a06 }
/* LiteralStringEscape */ .chroma-chroma .chroma-se { color: #4e9a06 }
/* LiteralStringHeredoc */ .chroma-chroma .chroma-sh { color: #4e9a06 }
/* LiteralStringInterpol */ .chroma-chroma .chroma-si { color: #4e9a06 }
/* LiteralStringOther */ .chroma-chroma .chroma-sx { color: #4e9a06 }
/* LiteralStringRegex */ .chroma-chroma .chroma-sr { color: #4e9a06 }
/* LiteralStringSingle */ .chroma-chroma .chroma-s1 { color: #4e9a06 }
/* LiteralStringSymbol */ .chroma-chroma .chroma-ss { color: #4e9a06 }
/* LiteralNumber */ .chroma-chroma .chroma-m { color: #0000cf; font-weight: bold }
/* LiteralNumberBin */ .chroma-chroma .chroma-mb { color: #0000cf; font-weight: bold }
/* LiteralNumberFloat */ .chroma-chroma .chroma-mf { color: #0000cf; font-weight: bold }
/* LiteralNumberHex */ .chroma-chroma .chroma-mh { color: #0000cf; font-weight: bold }
/* LiteralNumberInteger */ .chroma-chroma .chroma-mi { color: #0000cf; font-weight: bold }
/* LiteralNumberIntegerLong */ .chroma-chroma .chroma-il { color: #0000cf; font-weight: bold }
/* LiteralNumberOct */ .chroma-chroma .chroma-mo { color: #0000cf; font-weight: bold }
/* Operator */ .chroma-chroma .chroma-o { color: #ce5c00; font-weight: bold }
/* OperatorWord */ .chroma-chroma .chroma-ow { color: #204a87; font-weight: bold }
/* Punctuation */ .chroma-chroma .chroma-p { color: #000000; font-weight: bold }
/* Comment */ .chroma-chroma .chroma-c { color: #8f5902; font-style: italic }
/* CommentHashbang */ .chroma-chroma .chroma-ch { color: #8f5902; font-style: italic }
/* CommentMultiline */ .chroma-chroma .chroma-cm { color: #8f5902; font-style: italic }
/* CommentSingle */ .chroma-chroma .chroma-c1 { color: #8f5902; font-style: italic }
/* CommentSpecial */ .chroma-chroma .chroma-cs { color: #8f5902; font-style: italic }
/* CommentPreproc */ .chroma-chroma .chroma-cp { color: #8f5902; font-style: italic }
/* CommentPreprocFile */ .chroma-chroma .chroma-cpf { color: #8f5902; font-style: italic }
/* Generic */ .chroma-chroma .chroma-g { color: #000000 }
/* GenericDeleted */ .chroma-chroma .chroma-gd { color: #a40000 }
/* GenericEmph */ .chroma-chroma .chroma-ge { color: #000000; font-style: italic }
/* GenericError */ .chroma-chroma .chroma-gr { color: #ef2929 }
/* GenericHeading */ .chroma-chroma .chroma-gh { color: #000080; font-weight: bold }
/* GenericInserted */ .chroma-chroma .chroma-gi { color: #00a000 }
/* GenericOutput */ .chroma-chroma .chroma-go { color: #000000; font-style: italic }
/* GenericPrompt */ .chroma-chroma .chroma-gp { color: #8f5902 }
/* GenericStrong */ .chroma-chroma .chroma-gs { color: #000000; font-weight: bold }
/* GenericSubheading */ .chroma-chroma .chroma-gu { color: #800080; font-weight: bold }
/* GenericTraceback */ .chroma-chroma .chroma-gt { color: #a40000; font-weight: bold }
/* GenericUnderline */ .chroma-chroma .chroma-gl { color: #000000; text-decoration: underline }
/* TextWhitespace */ .chroma-chroma .chroma-w { color: #f8f8f8; text-decoration: underline }

.chroma-chroma { background: transparent; }

}
