/*
  The design system every page of brickworks.diy shares (docs/DESIGN_SYSTEM.md):
  its tokens, then its components. The app is a canvas and has its own
  look; this follows it: near-black by default, warm yellow for the way
  in, and the mark from web/icon.svg.

  Its controls are here and nowhere else: a field (text box, dropdown,
  text area, file picker), a checkbox, the buttons, the dialog, the card,
  the badge, the callout, a plan's card. A page lays them out; it does not
  restyle them. Each unit used to copy the styles it needed, and what a
  copy missed was drawn by the browser: the age question's month was a
  bare dropdown beside a full-size year box. tools/web/design_flow.mjs
  keeps it so.

  Contrast is measured, not eyeballed: every text colour here is at least
  4.5:1 on each surface it sits on, and an edge that marks a state 3:1, in
  both themes (WCAG AA; tests/test_site_contrast.py).

  Two themes, the person's choice (System, Light or Dark: web/theme.js
  sets data-theme on <html> before the page is drawn). Dark is the set
  below; the light set is chosen, or the system's when nothing was.

  site356 (2026-10-29, the owner: "next level UI/UX"): a deeper ground, a
  line that is quieter and one that is firmer, three steps of elevation
  (--shadow-1, --shadow-2, --shadow), a top-edge highlight on every raised
  surface, the yellow as a soft tint (--accent-soft) and as words
  (--accent-ink), and a fifth corner for the largest surfaces.
*/
:root {
	--bg: #0b0c0e;
	--bg-soft: #101215;
	--panel: #15171b;
	--panel-hi: #1c1f24;
	--line: rgba(255, 255, 255, 0.08);
	/* A firmer edge: a control's at rest, a card under the pointer. */
	--line-strong: rgba(255, 255, 255, 0.16);
	--ink: #f3f4f6;
	--ink-soft: #b4b9c2;
	--ink-faint: #8b929d;
	--red: #d0332f;
	--yellow: #f2cd37;
	--blue: #2a6fc4;
	--green: #57c97e;
	--accent: var(--yellow);
	/* The top of a primary button: the yellow lit from above. */
	--accent-hi: #ffdc55;
	--on-accent: #17130a;
	/* An edge in the accent that marks a state (a pressed toggle, the New
	   pill, the older-version box): the yellow is 1.33:1 on the light
	   pages, so the light set darkens it to 3:1. A yellow button keeps
	   the yellow. */
	--accent-edge: var(--yellow);
	/* The accent as words (an eyebrow, a plan's saving): 4.5:1 on every
	   surface, so darker again in light. */
	--accent-ink: var(--yellow);
	/* The accent as a ground: a badge, an icon's tile, the chosen plan. */
	--accent-soft: rgba(242, 205, 55, 0.12);
	--focus: #7cb8ff;
	--bad: #ef7a72;
	/* The 404's wall: four bricks, the same in both themes. */
	--brick-red: #b40000;
	--brick-yellow: var(--yellow);
	--brick-blue: #1e5aa8;
	--brick-green: #00852b;
	/* A brick's shading (the 404's wall, a colour's dot): its lower edge in
	   shadow, its top in light. And the dim behind an open dialog. */
	--shade: rgba(0, 0, 0, 0.3);
	--shine: rgba(255, 255, 255, 0.18);
	--scrim: rgba(0, 0, 0, 0.6);
	/* What a model's picture stands on (a card's frame, its page's picture):
	   the app draws it with nothing behind the model since 2026-10-24
	   (docs/SOCIAL.md U15), so the ground is the theme's, lighter at the top
	   as a studio's is. A dark one lit enough that a black model still
	   shows against it; the light one the ground the app drew before, so a
	   picture published before then and a new one look alike there. */
	--picture-ground: linear-gradient(180deg, #333a45, #1d222a);
	/* The ground a picture published before then carries, in either theme:
	   carried on above and below one drawn smaller than its frame
	   (web/model-page.js fitPicture). */
	--render-top: #edeff4;
	--render-foot: #ccd3dd;
	/* An avatar made from a handle (web/kit.js avatarHtml): one of eight
	   tiles, its letter in white, 4.5:1 or more on each, in both themes. */
	--avatar-1: #b42318; --avatar-2: #1f5fbf; --avatar-3: #1f7a3d; --avatar-4: #7a3fb0;
	--avatar-5: #9a4a00; --avatar-6: #0e6f8a; --avatar-7: #a3175a; --avatar-8: #4b5563;
	--on-avatar: #ffffff;
	/* A set's own picture (Rebrickable's) stands on the white it was
	   photographed on, in both themes (web/directory.css .set-page). */
	--photo-ground: #ffffff;
	/* Controls: a field and a button side by side are the same height,
	   with the same corners; every field has the same fill. */
	--field: var(--bg-soft);
	--control-h: 44px;
	/* Five corners: small (a chip, a code box), a control's, a card's or a
	   panel's, a large surface's (a plan, the app's picture, a band), and a
	   pill's; a circle is 50%. */
	--r-1: 6px;
	--r-2: 10px;
	--r-3: 14px;
	--r-4: 20px;
	--r-pill: 999px;
	--control-radius: var(--r-2);
	--radius: var(--r-3);
	/* A page's width: a page of words keeps --page; a page of cards and
	   pictures (.wrap.wide: the gallery, a person, a collection, a model,
	   the feed, the landing page's row of models) and the header and
	   footer on every page use the window up to --page-wide. Nothing was
	   wider than 1,140 px, 59% of a 1920 window (site273). */
	--page: 1140px;
	--page-wide: 1600px;
	/* One type scale for every page (docs/DESIGN_SYSTEM.md): the landing
	   page's one line, a page's title, a section's, a card's; the lede;
	   then the words, small print, the smallest, and a count's. Each page
	   used to size its own titles, from 26 to 74 px. */
	--t-display: clamp(42px, 7vw, 76px);
	--t-h1: clamp(32px, 4.6vw, 48px);
	--t-h2: clamp(22px, 2.4vw, 26px);
	--t-h3: 18px;
	--t-lede: clamp(17px, 1.9vw, 19px);
	--t-body: 16px;
	--t-small: 14.5px;
	--t-tiny: 13px;
	--t-micro: 12px;
	/* A section's title on the landing pages (home, plans, download): the
	   step between a page's title and a section's. */
	--t-section: clamp(28px, 3.6vw, 40px);
	/* Code in a line of words: a monospace face looks larger at one size. */
	--t-code: 0.92em;
	/* And one rhythm: the space above a page's title, between its sections,
	   and the steps between. */
	--s-1: 4px; --s-2: 8px; --s-3: 12px; --s-4: 16px; --s-5: 24px; --s-6: 32px; --s-7: 48px; --s-8: 64px;
	--page-top: clamp(40px, 6vw, 72px);
	--section: clamp(64px, 9vw, 112px);
	/* Elevation, three steps: resting on the page (a card, a ghost
	   button), raised (a card under the pointer, a menu), and floating (a
	   dialog, the app's picture). And the light along a raised surface's
	   top edge, and a primary button's. */
	--shadow-1: 0 1px 2px rgba(0, 0, 0, 0.35);
	--shadow-2: 0 1px 2px rgba(0, 0, 0, 0.3), 0 12px 32px -12px rgba(0, 0, 0, 0.7);
	--shadow: 0 30px 70px -30px rgba(0, 0, 0, 0.8);
	--highlight: inset 0 1px 0 rgba(255, 255, 255, 0.05);
	--shine-btn: inset 0 1px 0 rgba(255, 255, 255, 0.5), inset 0 -1px 0 rgba(0, 0, 0, 0.12);
	/* The warm light over a landing page's opening and its last offer. */
	--glow: radial-gradient(60% 55% at 50% 0%, rgba(242, 205, 55, 0.14), transparent 70%);
	/* The baseplate under it: a grid of studs, faint. */
	--studs: radial-gradient(circle at 1px 1px, rgba(255, 255, 255, 0.07) 1px, transparent 1.5px);
	/* Motion (docs/DESIGN_SYSTEM.md "Motion"): how long a control takes to
	   answer the pointer, and an opening's; one easing for both. None of it
	   under reduced motion. */
	--motion: 150ms;
	--motion-open: 180ms;
	--ease: cubic-bezier(0.2, 0.7, 0.2, 1);
	/* The header's height (.bar's 60 px and its line), which main fills the
	   window under. */
	--head-h: 61px;
	color-scheme: dark;
}
/* The light set, twice: chosen (data-theme="light"), and the system's
   when nothing was chosen. CSS cannot say "this attribute or this media
   query" in one rule; tests/test_site_contrast.py fails if they differ. */
:root[data-theme="light"] {
	--bg: #fbfbfa;
	--bg-soft: #f3f3f1;
	--panel: #ffffff;
	--panel-hi: #f7f7f5;
	--line: rgba(17, 19, 23, 0.1);
	--line-strong: rgba(17, 19, 23, 0.2);
	--ink: #111317;
	--ink-soft: #454a54;
	--ink-faint: #5b616b;
	--green: #1f7a3d;
	--accent-edge: #a67c00;
	--accent-ink: #7a5b00;
	--accent-soft: rgba(242, 205, 55, 0.22);
	--focus: #1f5fbf;
	--bad: #b42318;
	--scrim: rgba(17, 19, 23, 0.45);
	--shadow-1: 0 1px 2px rgba(16, 24, 40, 0.07);
	--shadow-2: 0 1px 2px rgba(16, 24, 40, 0.06), 0 12px 32px -12px rgba(16, 24, 40, 0.2);
	--shadow: 0 30px 60px -32px rgba(20, 30, 50, 0.35);
	--highlight: inset 0 1px 0 rgba(255, 255, 255, 0.9);
	--glow: radial-gradient(60% 55% at 50% 0%, rgba(242, 205, 55, 0.3), transparent 70%);
	--studs: radial-gradient(circle at 1px 1px, rgba(17, 19, 23, 0.08) 1px, transparent 1.5px);
	--picture-ground: linear-gradient(180deg, #edeff5, #ccd4de);
	color-scheme: light;
}
@media (prefers-color-scheme: light) {
	:root:not([data-theme]) {
		--bg: #fbfbfa;
		--bg-soft: #f3f3f1;
		--panel: #ffffff;
		--panel-hi: #f7f7f5;
		--line: rgba(17, 19, 23, 0.1);
		--line-strong: rgba(17, 19, 23, 0.2);
		--ink: #111317;
		--ink-soft: #454a54;
		--ink-faint: #5b616b;
		--green: #1f7a3d;
		--accent-edge: #a67c00;
		--accent-ink: #7a5b00;
		--accent-soft: rgba(242, 205, 55, 0.22);
		--focus: #1f5fbf;
		--bad: #b42318;
		--scrim: rgba(17, 19, 23, 0.45);
		--shadow-1: 0 1px 2px rgba(16, 24, 40, 0.07);
		--shadow-2: 0 1px 2px rgba(16, 24, 40, 0.06), 0 12px 32px -12px rgba(16, 24, 40, 0.2);
		--shadow: 0 30px 60px -32px rgba(20, 30, 50, 0.35);
		--highlight: inset 0 1px 0 rgba(255, 255, 255, 0.9);
		--glow: radial-gradient(60% 55% at 50% 0%, rgba(242, 205, 55, 0.3), transparent 70%);
		--studs: radial-gradient(circle at 1px 1px, rgba(17, 19, 23, 0.08) 1px, transparent 1.5px);
		--picture-ground: linear-gradient(180deg, #edeff5, #ccd4de);
		color-scheme: light;
	}
}

*, *::before, *::after { box-sizing: border-box; }
html { scroll-behavior: smooth; scroll-padding-top: 76px; -webkit-text-size-adjust: 100%; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }
body {
	margin: 0;
	background: var(--bg);
	color: var(--ink);
	font: 400 var(--t-body)/1.65 ui-sans-serif, system-ui, -apple-system, "Segoe UI",
		Roboto, Helvetica, Arial, sans-serif;
	-webkit-font-smoothing: antialiased;
	text-rendering: optimizeLegibility;
	font-optical-sizing: auto;
}
::selection { background: var(--accent); color: var(--on-accent); }
img { max-width: 100%; height: auto; display: block; }
a { color: inherit; text-underline-offset: 0.18em; text-decoration-thickness: 1px; }
a:hover { text-decoration-thickness: 2px; }
code { font: var(--t-code)/1.4 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }
/* A command to type: a box of its own that wraps, so a long one never
   pushes the page sideways or hides its end past the edge of a phone. */
code.cmd {
	display: block; margin: 6px 0; padding: 8px 10px; border-radius: var(--r-1);
	background: var(--bg-soft); border: 1px solid var(--line); color: var(--ink);
	font-size: var(--t-tiny); white-space: pre-wrap; overflow-wrap: anywhere;
}
[hidden] { display: none !important; }

/* Keyboard focus, visible on every control in both schemes. The ring
   follows a control's own corners; it does not change them. */
:focus-visible { outline: 3px solid var(--focus); outline-offset: 3px; }
a:focus-visible { border-radius: var(--r-1); }

.wrap { width: min(100% - 32px, var(--page)); margin-inline: auto; }
.wrap.wide, .site-head > .wrap, .site-foot > .wrap { width: min(100% - 32px, var(--page-wide)); }
.skip {
	position: absolute; left: 12px; top: -60px; z-index: 50;
	background: var(--accent); color: var(--on-accent);
	padding: 10px 14px; border-radius: var(--r-2); font-weight: 650; text-decoration: none;
}
.skip:focus { top: 12px; }

/* -- the bar --------------------------------------------------------- */

.site-head {
	position: sticky; top: 0; z-index: 20;
	backdrop-filter: saturate(1.6) blur(16px);
	-webkit-backdrop-filter: saturate(1.6) blur(16px);
	background: color-mix(in srgb, var(--bg) 78%, transparent);
	border-bottom: 1px solid var(--line);
}
.bar { display: flex; align-items: center; gap: 12px; min-height: 60px; }
.mark {
	display: inline-flex; align-items: center; gap: 10px;
	font-weight: 700; letter-spacing: -0.025em; font-size: var(--t-h3);
	text-decoration: none; padding: 6px 4px;
}
/* The mark (web/icon.svg): a cube with a corner cut away. The .chip every
   page's header has, so a page shows it with no markup of its own. */
.chip { width: 26px; height: 26px; flex: none; background: url(/icon.svg) center / contain no-repeat; }
/* In the bar everything is a finger's 44 px: the mark, the links, Open the
   app (the regular .cta, not a size of its own: it was 42 px at 14.5),
   Menu and your avatar's button. Where the bar has no room for the word
   (a phone under about 390 px), the word wraps onto a second line the
   mark's height hides, and the mark is the cube alone, its name still
   "Brickworks": no breakpoint of its own, only the room the rest leaves. */
.site-head .mark {
	flex: 0 1 auto; min-width: 44px; height: var(--control-h); padding: 0 4px; overflow: hidden;
	flex-wrap: wrap; align-content: flex-start; row-gap: 0; line-height: var(--control-h);
}
.site-head .mark .chip { margin-block: 9px; }
/* The nav fills the bar after the mark: its four links in the middle of
   what is left, Open the app and your account at the far right (the
   first link and Open the app each take half the room that is over). */
.nav { flex: 1; display: flex; align-items: center; gap: 2px; }
.nav > a:not(.cta) {
	display: inline-flex; align-items: center; min-height: var(--control-h);
	text-decoration: none; color: var(--ink-soft); font-size: var(--t-small); font-weight: 520;
	padding: 0 14px; border-radius: var(--r-pill); white-space: nowrap;
}
.nav > a:not(.cta):first-child { margin-left: auto; }
.nav > a:not(.cta):hover { color: var(--ink); background: var(--panel); }
.nav > a:not(.cta)[aria-current="page"] { color: var(--ink); background: var(--panel); box-shadow: inset 0 0 0 1px var(--line); }
.nav > .cta { margin-left: 8px; }
.nav > .cta:not(.ghost) { margin-left: auto; }

/* On a phone: the mark, the way in, and a menu for the rest. A <details>
   so it opens with no script, which the site's security policy would
   not run inline anyway. */
.menu { display: none; position: relative; }
.menu summary {
	list-style: none; cursor: pointer; display: inline-flex; align-items: center; min-height: var(--control-h);
	padding: 0 14px; border-radius: var(--control-radius);
	border: 1px solid var(--line-strong); font-size: var(--t-body); color: var(--ink); background: var(--panel);
	box-shadow: var(--highlight);
}
.menu summary::-webkit-details-marker { display: none; }
.menu[open] summary { background: var(--panel); }
.menu-list {
	position: absolute; right: 0; top: calc(100% + 8px); min-width: 220px;
	display: grid; padding: 6px; border-radius: var(--r-3);
	background: var(--panel); border: 1px solid var(--line-strong); box-shadow: var(--highlight), var(--shadow);
}
.menu-list nav { display: grid; }
.menu-list a { text-decoration: none; padding: 10px 12px; border-radius: var(--r-1); color: var(--ink-soft); }
.menu-list a:hover { background: var(--panel-hi); color: var(--ink); }
/* The theme on Menu, under the links: the whole width, a button a third. */
.menu-list .theme-choice { display: grid; gap: var(--s-2); margin: 6px 0 0; padding: 12px 6px 6px; border-top: 1px solid var(--line); }
.menu-list .segmented { display: grid; grid-template-columns: repeat(3, 1fr); }
/* What came into your feed since you opened it (web/follow.js): a small
   count on Account, and on Menu where Account is behind it. */
.site-head .count {
	display: inline-block; min-width: 18px; padding: 0 5px; border-radius: var(--r-pill);
	background: var(--accent); color: var(--on-accent); font-size: var(--t-micro); font-weight: 700;
	line-height: 18px; text-align: center; font-variant-numeric: tabular-nums;
}
/* On Menu, over its corner: the header has no room at 390 px for more. */
.site-head .menu summary { position: relative; }
.site-head .menu summary .count { position: absolute; top: -7px; right: -7px; }
/* Your account, signed in (web/follow.js, docs/SOCIAL.md U7): your avatar
   where Sign in was, last at the far right after Open the app, what is
   new for you over its corner, opening the account menu (a .more-menu
   with the header Menu's panel): who you are, your places with their
   counts, the theme, Sign out. On a phone Menu is the avatar and holds
   the same, under the site's links. 12 px from Open the app with the
   nav's gap, as Menu is on a phone (.bar's gap). */
.account-menu { margin-left: 10px; }
.site-head .account-btn {
	position: relative; display: inline-grid; place-items: center; min-width: var(--control-h); min-height: var(--control-h);
	padding: 0; border: 0; border-radius: 50%; background: none; list-style: none; cursor: pointer;
}
.site-head .account-btn::-webkit-details-marker { display: none; }
.site-head .account-btn .avatar { width: 36px; height: 36px; font-size: var(--t-body); }
.account-menu[open] .account-btn .avatar, .menu[open] .account-btn .avatar { box-shadow: 0 0 0 2px var(--bg), 0 0 0 4px var(--accent-edge); }
.site-head .account-btn .count { position: absolute; top: -1px; right: -3px; }
.account-menu .menu-list { min-width: 240px; }
.menu-who { display: flex; align-items: center; gap: var(--s-3); margin: 0; padding: 8px 12px 10px; }
.menu-who span { display: grid; min-width: 0; }
.menu-who b { font-weight: 650; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.menu-who small { color: var(--ink-faint); font-size: var(--t-tiny); overflow-wrap: anywhere; }
/* Your name and handle before the server has said them: a line's height each. */
.menu-who .bone { height: 0.95em; }
.menu-who .bone.wide { width: 128px; }
.menu-who .bone.short { width: 88px; }
.account-part nav { display: grid; }
.account-part nav a { display: flex; align-items: center; justify-content: space-between; gap: var(--s-3); }
.account-part nav a[aria-current="page"] { color: var(--ink); background: var(--panel-hi); }
.menu .account-part { margin-top: 6px; padding-top: 6px; border-top: 1px solid var(--line); }
/* Sign out last, a menu's button as any other, under a line. */
.menu-list > :has(+ .sign-out) { padding-bottom: 12px; border-bottom: 1px solid var(--line); }
.menu-list > .sign-out { margin-top: 6px; }
/* Under 900 px the mark, Open the app and Menu fill the bar (the four
   links and Sign in are on Menu), and the last keeps the page's 16 px
   gutter (design_flow.mjs fails it closer). On a phone the bar's gaps
   close to 8 px, and Open the app and Menu give a little a side, so the
   word still fits at 390. Open the app is laid out for the longest of the
   site's four languages: a label longer than "Open the app" with room to
   spare ("Ouvrir l'application", "Abrir la aplicación") takes two
   balanced lines in the same 44 px, never a shorter word, so the word
   fits at 390 in each. The whole bar fits from 900 px (site356: four
   links and two buttons, where it was two and two from 600). */
@media (width < 900px) {
	.nav > a:not(.cta), .nav > a[data-account], .nav .account-menu { display: none; }
	.menu { display: block; }
}
@media (width < 600px) {
	.site-head .bar { gap: var(--s-2); }
	.site-head .nav .cta {
		margin-left: auto; padding: 3px 10px; max-width: calc(8.5em + 20px);
		white-space: normal; text-wrap: balance; text-align: center; line-height: 1.1;
	}
	.site-head .menu summary:not(.account-btn) { padding-inline: 10px; }
}

/* -- buttons ------------------------------------------------------- */

/* Primary (.cta, yellow: the way in), secondary (.cta.ghost, and any
   button with no class of its own) and quiet (.link, words underlined);
   .small for a row of actions on a card or a list, .big for a page's
   opening offer. A toggle that is on (aria-pressed) has the accent edge. */
.cta, :where(button) {
	display: inline-flex; align-items: center; justify-content: center; gap: 8px;
	min-height: var(--control-h); padding: 9px 20px; border-radius: var(--control-radius);
	font: inherit; font-weight: 640; font-size: var(--t-body); line-height: 24px; white-space: nowrap;
	text-decoration: none; cursor: pointer;
	background: var(--accent); color: var(--on-accent); border: 1px solid transparent;
}
/* The primary one lit from above, with its own edge of light and a
   shadow under it: it is the way in, and looks pressable. */
.cta:not(.ghost) {
	background: linear-gradient(180deg, var(--accent-hi), var(--accent));
	box-shadow: var(--shine-btn), var(--shadow-1);
}
.cta:hover { filter: brightness(1.06); }
.cta.ghost, :where(button) { background: transparent; color: var(--ink); border-color: var(--line-strong); }
/* A secondary button that stands on the page as a primary one does: on
   the panel's ground, with an edge of light and a shadow. */
.cta.ghost { background: var(--panel); box-shadow: var(--highlight), var(--shadow-1); }
/* Not a primary button's: :where(button):hover weighs as much as .cta, and
   came after it, so a yellow button went white under the pointer. */
.cta.ghost:hover, :where(button:not(.cta)):hover { background: var(--panel-hi); filter: none; }
.cta.ghost[aria-pressed="true"] { border-color: var(--accent-edge); }
.cta.small { min-height: 36px; padding: 5px 12px; font-size: var(--t-small); }
.cta.big { min-height: 52px; padding: 13px 26px; font-size: var(--t-h3); border-radius: var(--control-radius); }
/* orangecheck's button says its name in the visitor's language, and the
   French one ran out of the sign-in dialog on a phone: it wraps instead. */
[data-oc-sign-in] { white-space: normal; max-inline-size: 100%; }
/* A way on, its arrow after the words, nudged under the pointer. */
.cta .arrow { display: inline-block; transition: transform var(--motion) var(--ease); }
.cta:hover .arrow { transform: translateX(3px); }
summary.cta { width: fit-content; list-style: none; }
summary.cta::-webkit-details-marker { display: none; }
button.link, a.link {
	display: inline; min-height: 0; padding: 0; border: 0; border-radius: 0; white-space: normal;
	font: inherit; color: var(--ink-soft); background: none;
	text-decoration: underline; text-underline-offset: 0.18em; cursor: pointer;
}
button.link:hover, a.link:hover { color: var(--ink); background: none; }
.actions { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; }
.actions.center { justify-content: center; }

/* A choice of a few, side by side: buttons in a row, the one chosen
   pressed (aria-pressed) and edged in the accent. The theme (System,
   Light, Dark: web/theme.js) in the footer, on Menu and in Settings.
   As tall as a field, with its buttons inside. */
.segmented {
	/* A long one (/admin's six "where it stands") wraps inside its frame
	   rather than push a phone's page sideways. */
	display: inline-flex; flex-wrap: wrap; max-width: 100%; gap: 2px; padding: 3px; margin: 0;
	border: 1px solid var(--line); border-radius: var(--r-2); background: var(--bg-soft);
}
.segmented button {
	min-height: 36px; padding: 5px 12px; border-radius: var(--r-1); border: 1px solid transparent;
	font-size: var(--t-small); font-weight: 600; line-height: 24px; color: var(--ink-soft); background: transparent; box-shadow: none;
}
.segmented button:hover { color: var(--ink); background: var(--panel); }
.segmented button[aria-pressed="true"] { color: var(--ink); background: var(--panel); border-color: var(--accent-edge); box-shadow: var(--shadow-1); }
/* On a phone its buttons are a finger's 44 px (the footer's theme too). */
@media (width < 600px) { .segmented button { min-height: var(--control-h); } }
/* Its words beside it: what is being chosen. */
.theme-choice { display: inline-flex; flex-wrap: wrap; align-items: center; gap: var(--s-3); font-size: var(--t-small); color: var(--ink-soft); }

/* -- fields ---------------------------------------------------------
   A text box, a dropdown, a text area and a file picker are one box. By
   element at zero specificity (:where), so no field is ever left to the
   browser, and a page can still size one (flex: 1, a width). */

:where(input:not([type="checkbox"], [type="radio"], [type="hidden"]), select, textarea) {
	min-width: 0; max-width: 100%; min-height: var(--control-h); margin: 0; padding: 9px 12px;
	font: inherit; font-size: var(--t-body); line-height: 24px; color: var(--ink);
	background-color: var(--field); border: 1px solid var(--line-strong); border-radius: var(--control-radius);
}
:where(input:not([type="checkbox"], [type="radio"], [type="hidden"]), select, textarea):hover { border-color: var(--ink-faint); }
/* A field being typed in is ringed in the accent's edge as well as the
   keyboard's ring, so a mouse's click shows where the words go too. */
:where(input:not([type="checkbox"], [type="radio"], [type="hidden"], [type="file"]), select, textarea):focus {
	border-color: var(--accent-edge); box-shadow: 0 0 0 3px var(--accent-soft);
}
:where(input, textarea)::placeholder { color: var(--ink-faint); }
/* A dropdown is the text box with an arrow in the page's ink; its first,
   hidden choice ("Month") in the quieter ink until one is made. */
:where(select) {
	appearance: none; -webkit-appearance: none; padding-right: 36px; cursor: pointer;
	background-image: linear-gradient(45deg, transparent 50%, var(--ink-soft) 50%),
		linear-gradient(135deg, var(--ink-soft) 50%, transparent 50%);
	background-position: right 18px center, right 13px center;
	background-size: 5px 5px; background-repeat: no-repeat;
}
:where(select:invalid) { color: var(--ink-soft); }
:where(textarea) { line-height: 1.5; resize: vertical; }
/* A file picker: the box, its button the secondary one. */
:where(input[type="file"]) { height: var(--control-h); padding: 5px 12px 5px 5px; line-height: 32px; color: var(--ink-soft); cursor: pointer; }
:where(input[type="file"])::file-selector-button {
	box-sizing: border-box; height: 32px; margin: 0 12px 0 0; padding: 0 12px; cursor: pointer;
	font: inherit; font-size: var(--t-small); font-weight: 640; color: var(--ink);
	background: var(--panel); border: 1px solid var(--line); border-radius: var(--r-1);
}
/* A checkbox or radio: the browser's own, which every keyboard and screen
   reader knows, at one size and in the accent. With its words, a
   label.choice (or .tick): the box on the first line, then the words. */
:where(input[type="checkbox"], input[type="radio"]) {
	width: 18px; height: 18px; margin: 0; flex: none; accent-color: var(--accent-edge); cursor: pointer;
}
.choice, .tick {
	display: flex; gap: 10px; align-items: flex-start; margin: 0; padding: 6px 0;
	font-size: var(--t-small); line-height: 24px; color: var(--ink); cursor: pointer;
}
.choice > input, .tick > input { margin-top: 3px; }
/* In a form, a field's words above it. */
:where(form) label { display: grid; gap: 6px; font-size: var(--t-small); color: var(--ink-soft); }
:where(form) label small { font-size: var(--t-tiny); font-weight: 400; color: var(--ink-faint); }
/* A date: day, month and year, three dropdowns side by side under its
   words (fieldset.date, its legend the words). Never the browser's own date
   box, which draws itself, and differently in every browser. */
fieldset.date { min-width: 0; margin: 0; padding: 0; border: 0; }
fieldset.date legend { padding: 0; margin: 0 0 6px; font-size: var(--t-small); color: var(--ink-soft); }
fieldset.date .dropdowns {
	display: grid; gap: 8px; grid-template-columns: minmax(76px, 2fr) minmax(0, 4fr) minmax(88px, 3fr);
}

/* -- dialogs --------------------------------------------------------
   What a page opens over itself: sign in and the age question
   (account.js), report it (report.js). */

dialog {
	width: min(420px, calc(100vw - 32px)); border: 1px solid var(--line-strong); border-radius: var(--r-4);
	background: var(--panel); color: var(--ink); padding: 24px; box-shadow: var(--highlight), var(--shadow);
}
dialog::backdrop { background: var(--scrim); backdrop-filter: blur(4px); -webkit-backdrop-filter: blur(4px); }
dialog h2 { margin: 0 0 6px; }
dialog p { color: var(--ink-soft); margin: 0 0 14px; }
dialog form label { margin-bottom: 14px; }
dialog .said { margin: 10px 0 0; color: var(--ink); min-height: 1em; }
/* Sign in's other way, orangecheck, under the email and apart from it. */
dialog .elsewhere { margin-top: 18px; padding-top: 18px; border-top: 1px solid var(--line); }
dialog .elsewhere .note { margin: 8px 0 0; }
/* Under it, orangecheck Connect's box: the box and its words, then
   orangecheck's line under the words. */
dialog .consent { margin-top: 10px; }
dialog .consent .note { margin: 0 0 0 28px; }
/* The age question's month and year, side by side. */
dialog .when { display: grid; grid-template-columns: 3fr 2fr; gap: 12px; }
/* Send feedback (feedback.js): wider, its three kinds in a row, and what
   goes with it under them, the picture shown small with its Remove. */
dialog.feedback { width: min(520px, calc(100vw - 32px)); }
dialog.feedback fieldset { min-width: 0; margin: 0 0 14px; padding: 0; border: 0; }
dialog.feedback legend { padding: 0; margin: 0 0 6px; font-size: var(--t-small); color: var(--ink-soft); }
dialog.feedback .kinds { display: flex; flex-wrap: wrap; column-gap: var(--s-4); }
dialog.feedback .attach .actions { margin: 0 0 6px; }
dialog.feedback figure.attached { display: grid; grid-template-columns: 120px 1fr; gap: 6px 12px; align-items: center; margin: 0 0 8px; }
dialog.feedback figure.attached canvas { grid-row: span 2; width: 120px; height: auto; border: 1px solid var(--line); border-radius: var(--r-1); }
dialog.feedback figcaption { font-size: var(--t-small); color: var(--ink-soft); overflow-wrap: anywhere; }
dialog.feedback .tick span { overflow-wrap: anywhere; }
/* First steps after a first sign-in (first-steps.js): wider, for a row of
   pills and a grid of cards, its steps counted in the eyebrow. */
dialog.first-steps { width: min(640px, calc(100vw - 32px)); }
dialog.first-steps .eyebrow { margin-bottom: var(--s-2); }
dialog.first-steps h3 { margin: var(--s-5) 0 var(--s-2); }
dialog.first-steps .face-row { display: flex; align-items: center; gap: var(--s-4); margin: 0 0 var(--s-4); }
dialog.first-steps .face-row p { margin: 0; overflow-wrap: anywhere; }
dialog.first-steps .face-row b { color: var(--ink); font-weight: 650; }
dialog.first-steps .kinds { margin: 0 0 var(--s-5); }
/* Six cards: three to a row in its width, two on a phone. */
dialog.first-steps .models { margin: 0 0 var(--s-2); grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--s-3); }
@media (width < 600px) { dialog.first-steps .models { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
dialog.first-steps .actions { margin-top: var(--s-5); }

/* A person to follow (the feed's designers, First steps): their avatar,
   their name and best models, and Follow. A list of them is .people-list. */
.people-list { list-style: none; margin: 0; padding: 0; display: grid; }
.person-row {
	display: grid; grid-template-columns: auto minmax(0, 1fr) auto; align-items: center; gap: var(--s-1) var(--s-3);
	padding: var(--s-2) 0;
}
.person-row + .person-row { border-top: 1px solid var(--line); }
.person-row .face { flex: none; text-decoration: none; }
.person-row .names { display: grid; min-width: 0; line-height: 1.35; }
.person-row .names a { color: var(--ink); text-decoration: none; }
.person-row .names a:hover { text-decoration: underline; text-decoration-thickness: 1px; }
.person-row .names b, .person-row .names small { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.person-row .names b { font-weight: 650; }
.person-row .names small { color: var(--ink-soft); font-size: var(--t-small); }
.person-row .said { grid-column: 2 / -1; color: var(--ink-soft); font-size: var(--t-small); }
.person-row .said:empty { display: none; }

/* -- type ---------------------------------------------------------- */

h1, h2, h3 { text-wrap: balance; }
h1 {
	margin: 0 0 var(--s-3); font-size: var(--t-h1); line-height: 1.06;
	letter-spacing: -0.035em; font-weight: 740;
}
/* The landing page's one line, and nowhere else. */
.display { font-size: var(--t-display); line-height: 1; letter-spacing: -0.045em; font-weight: 760; }
/* Words in a title that are the point, in the accent's ink. */
.display em, h1 em, .title em { font-style: normal; color: var(--accent-ink); }
h2 {
	margin: 0 0 var(--s-2); font-size: var(--t-h2); line-height: 1.15;
	letter-spacing: -0.025em; font-weight: 690;
}
h3 { margin: 0 0 6px; font-size: var(--t-h3); line-height: 1.3; letter-spacing: -0.01em; font-weight: 650; }
.eyebrow {
	display: inline-block; margin: 0 0 14px; font-size: var(--t-tiny); font-weight: 680;
	letter-spacing: 0.08em; text-transform: uppercase; color: var(--accent-ink);
}
.lede { margin: 0 0 var(--s-5); font-size: var(--t-lede); color: var(--ink-soft); max-width: 60ch; text-wrap: pretty; }
.sub { margin: 0 0 var(--s-5); color: var(--ink-soft); max-width: 66ch; font-size: var(--t-lede); text-wrap: pretty; }
.note { margin: 14px 0 0; font-size: var(--t-small); color: var(--ink-faint); }
.center { text-align: center; }
.center .lede, .center .sub { margin-inline: auto; }

/* -- targets -------------------------------------------------------
   A link on a line of its own is a finger's target, 30-32 px (WCAG 2.5.8
   asks 24; they were 16-22): padding above and below that an inline
   link's line makes no room for, so its words stay where they were, or,
   on a block, given back by a negative margin. A crumb, Older versions,
   Version 1, a card's designer, a person to follow. */
.crumbs a, .note a, .eyebrow a, .state a, .earlier a { padding-block: 6px; }
.model a.who, .person-row .names a { padding-block: 4px; margin-block: -4px; }

/* -- blocks -------------------------------------------------------- */

/* A page's main fills the window under the header, so the footer starts
   at the window's foot however short the page is or however late its
   script draws: on a short page it stopped two-thirds of the way down,
   and on every page it jumped as the script's parts came in (site273). */
.site-head ~ main { display: block; min-height: calc(100vh - var(--head-h)); }
main > section, .band { padding: var(--section) 0; }
main > section + section { border-top: 1px solid var(--line); }

/* A page: every page but the landing one is this. Its head (an eyebrow,
   the title, a lede), then what it has; .prose for the pages that are
   words (questions, the legal pages), narrower and quieter. */
.page { padding: var(--page-top) 0 var(--section); }
.page-head { margin-bottom: var(--s-6); }
/* A page made of wraps side by side under <main>, its head the first. */
main > .wrap.page-head:first-child { padding-top: var(--page-top); }
.page-head .lede { margin-bottom: 0; }
.page-head .eyebrow { margin-bottom: var(--s-3); }
.page section { margin-top: var(--s-7); }
.page section > h2:first-child { margin-top: 0; }
.prose { max-width: 760px; }
.prose h2 { margin: var(--s-6) 0 var(--s-2); }
.prose p { color: var(--ink-soft); margin: 0 0 var(--s-3); }
.prose p b { color: var(--ink); font-weight: 620; }

/* Something that has nothing to show yet, or is on its way. */
.state { margin: 0; padding: 22px; border: 1px dashed var(--line); border-radius: var(--radius); color: var(--ink-soft); }
.state .link { color: var(--ink); }

/* A skeleton: what a script draws, in its place and at its size before
   its data comes, so nothing moves when it does. A card's (.model.skeleton,
   web/card.js skeletonHtml), a row's or a panel's (.skeleton); its words
   are .bone bars in the panel's lighter tone, breathing slowly. Taken out
   whole for what came, never filled in, so what came is drawn new rather
   than moved. Read out as one status, not as its bones. */
.skeleton { pointer-events: none; }
.bone {
	display: block; height: 0.8em; width: 70%; margin: 0.35em 0; border-radius: var(--r-1);
	background: var(--panel-hi); animation: breathe 1.6s ease-in-out infinite;
}
.bone.short { width: 45%; }
.bone.wide { width: 92%; }
.bone.button { width: 132px; height: var(--control-h); margin: 0; border-radius: var(--control-radius); }
.bone.round { width: 40px; height: 40px; margin: 0; border-radius: 50%; }
.bone.round.huge { width: 112px; height: 112px; }
@media (width < 600px) { .bone.round.huge { width: 80px; height: 80px; } }
.tabs .bone { width: 240px; margin: 14px var(--s-3); }
.skeleton-card {
	display: flex; flex-direction: column; min-width: 0; border-radius: var(--radius); overflow: hidden;
	border: 1px solid var(--line); background: var(--panel); container-type: inline-size;
}
.skeleton-card .frame { aspect-ratio: 4 / 3; background: var(--picture-ground); animation: breathe 1.6s ease-in-out infinite; }
/* As tall as a row of cards' words: a name of two lines (16 px at every
   width), the designer's line (24 px, two lines on a card narrower than
   190 px, where their name and its size wrap), and one line of what it has
   (Moves, the most common), each bar drawn in the middle of its line's box.
   The card has no row of numbers since site277: they are on the
   designer's line. */
.skeleton-card .words { display: flex; flex-direction: column; gap: 2px; padding: 10px 12px 12px; font-size: var(--t-body); }
.skeleton-card .bone { height: calc(1.35em); margin: 0; padding: 0.3em 0; background-clip: content-box; }
.skeleton-card .bone:nth-child(3) { height: 24px; padding: 6px 0; }
.skeleton-card .bone:nth-child(4) { height: calc(var(--t-tiny) * 1.65); padding: 6px 0; }
.bone.tiny { width: 30%; }
/* A bar as tall as a line of the words it stands for (a comment list's
   "Nobody has commented yet"), drawn in the line's middle. */
.bone.line { height: 1lh; margin: 0; padding: 0.3lh 0; background-clip: content-box; }
/* The card's width decides the wrap, not the window's: a phone's card two
   a row is 171 px, but a row that scrolls holds 200 px cards on a phone
   too, and the landing strip's skeletons stood 24 px taller than its cards
   there (site277). */
@container (width < 190px) {
	.skeleton-card .bone:nth-child(3) { height: calc(24px + 2px + var(--t-tiny) * 1.5); padding: 6px 0 calc(var(--t-tiny) * 1.5 + 8px); }
}
@media (width >= 900px) { .skeleton-card .words { padding: 10px 14px 12px; } }
@keyframes breathe { 50% { opacity: 0.55; } }

.card {
	background: var(--panel); border: 1px solid var(--line);
	border-radius: var(--radius); padding: 24px; box-shadow: var(--highlight), var(--shadow-1);
}
.card p { margin: 0; color: var(--ink-soft); font-size: var(--t-small); }

/* A table of facts, in a .table: a scroller (below) where it is wider
   than the page, and a named region the keyboard can reach and scroll
   (role="region", aria-label, tabindex="0"). Each row's name is its
   th[scope="row"]; a number is .n. In .table.wide, many columns, the
   row's name stays in view as the rest scrolls past it. */
.table table { width: 100%; border-collapse: separate; border-spacing: 0; font-size: var(--t-small); }
.table th, .table td { padding: 9px 10px; border-bottom: 1px solid var(--line); text-align: left; vertical-align: top; }
.table thead th { color: var(--ink-faint); font-weight: 500; font-size: var(--t-tiny); vertical-align: bottom; }
.table tbody th { font-weight: 600; }
.table td { color: var(--ink-soft); }
.table .n { text-align: right; font-variant-numeric: tabular-nums; }
.table.wide table { min-width: 860px; }
.table.wide td, .table.wide thead th { min-width: 130px; }
.table.wide thead th { color: var(--ink); font-size: var(--t-small); font-weight: 650; }
.table.wide tr > :first-child { position: sticky; left: 0; z-index: 1; min-width: 120px; max-width: 150px; background: var(--bg); }

/* A model: the one card for a shared model, wherever one is listed (the
   gallery, the landing page, a profile, a collection, a model's remixes,
   your account), drawn by web/card.js on the server and in the browser.
   Its picture 4:3, the middle of the 1200 x 630 one a share is published
   with (docs/SOCIAL.md D3): a model shows 1.43 times larger at the same
   width, rows line up, and the space is held before the picture comes.
   Its name is the link, stretched over the whole card; the designer's
   name and a like button sit above it, links and buttons of their own.
   .models lays them out: two to a row on a phone, three from 600 px and
   four from 900 px up (the owner, 2026-10-29: four a row on a desktop), so
   a page of 24 is whole rows at every width and a model is shown up to
   380 px wide. .models.scroller is one row of them that scrolls (the
   scroller, below), a card 180-300 px wide: as many as a grid has at that
   width less a half, so the next one always shows in part. */
.models { display: grid; gap: var(--s-4); grid-template-columns: repeat(2, minmax(0, 1fr)); }
@media (width >= 600px) { .models { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (width >= 900px) { .models { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--s-5); } }
.models.scroller {
	grid-template-columns: none; grid-auto-flow: column; padding-block: 2px 10px;
	grid-auto-columns: clamp(180px, (100% - var(--s-4)) / 1.5, 300px);
}
@media (width >= 600px) { .models.scroller { grid-auto-columns: clamp(180px, (100% - 2 * var(--s-4)) / 2.5, 300px); } }
@media (width >= 900px) { .models.scroller { grid-auto-columns: clamp(180px, (100% - 4 * var(--s-5)) / 4.5, 300px); } }
/* Beside a rail or in a narrower column: more to a row. Cards that each
   carry a button under them (a challenge's entries): fewer, one to a row
   on a phone, so the button's words fit. */
.models.compact { grid-template-columns: repeat(auto-fill, minmax(min(100%, 200px), 1fr)); }
.models.wide { grid-template-columns: repeat(auto-fill, minmax(min(100%, 280px), 1fr)); }

/* A list's pages (web/pager.js; one markup, pagerHtml, for the server's
   pages and the browser's): Show earlier over a page opened by its
   address; under the list the count, Show more (the way on, a secondary
   button) and the numbered links, each a 40 px target, the pages shown
   on the accent's soft ground and the last of them edged in the accent.
   Under 600 px only the numbers next to it, the first and the last are
   left, and Previous and Next are their arrows. While a page comes, Show
   more is aria-busy and its cards' skeletons hold their places. */
.pager-earlier { display: flex; justify-content: center; margin: 0 0 var(--s-5); }
.pager { display: flex; flex-direction: column; align-items: center; gap: var(--s-3); margin: var(--s-6) 0 0; text-align: center; }
.pager-earlier[hidden], .pager[hidden], .pager [hidden] { display: none; }
.pager-count { margin: 0; color: var(--ink-soft); font-size: var(--t-small); font-variant-numeric: tabular-nums; }
.pager-more { min-width: min(100%, 220px); }
.pager-more[aria-busy="true"] { cursor: progress; opacity: 0.7; }
.pager-pages { display: flex; flex-wrap: wrap; justify-content: center; align-items: center; gap: 4px; margin: var(--s-1) 0 0; padding: 0; list-style: none; }
.pager-pages a {
	display: inline-flex; align-items: center; justify-content: center; gap: 6px; min-width: 40px; height: 40px; padding: 0 10px;
	border-radius: var(--r-2); color: var(--ink-soft); font-size: var(--t-small); font-variant-numeric: tabular-nums; text-decoration: none;
}
.pager-pages a:hover { background: var(--panel-hi); color: var(--ink); }
.pager-pages a[data-shown] { background: var(--accent-soft); color: var(--ink); }
.pager-pages a[aria-current="page"] { box-shadow: inset 0 0 0 1px var(--accent-edge); color: var(--ink); font-weight: 650; }
.pager-pages .gap { min-width: 16px; color: var(--ink-faint); }
@media (width < 600px) {
	.pager-pages [data-far] { display: none; }
	.pager-pages .step .words {
		position: absolute; width: 1px; height: 1px; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap;
	}
}
.model {
	position: relative; display: flex; flex-direction: column; color: inherit; min-width: 0;
	border-radius: var(--radius); overflow: hidden; border: 1px solid var(--line);
	background: var(--panel); box-shadow: var(--highlight), var(--shadow-1);
}
.model:hover { border-color: var(--line-strong); box-shadow: var(--highlight), var(--shadow-2); }
.model:hover b { text-decoration: underline; text-decoration-thickness: 1px; }
.model .frame { position: relative; aspect-ratio: 4 / 3; background: var(--picture-ground); overflow: hidden; }
.model .frame img { width: 100%; height: 100%; object-fit: cover; }
.model .frame.none {
	display: grid; place-items: center; color: var(--ink-faint); font-size: var(--t-small);
	background: linear-gradient(180deg, var(--panel-hi), var(--bg-soft));
}
/* Its marks over the picture's top corner: Tested, 3D. One
   row of them: a mark that does not fit is left off whole, never cut (the
   row is one pill tall, its 3 px edge holding their shadows). They stacked
   two and three rows deep on a phone, 30% of the picture (site273). A
   mark nearly every card on the page carries is not said at all
   (web/card.js quietMarks, <body data-quiet>). */
.model .marks {
	position: absolute; top: 5px; left: 5px; right: 5px; max-height: 30px; padding: 3px; overflow: hidden;
	display: flex; flex-wrap: wrap; gap: var(--s-1);
}
.model .marks .pill { box-shadow: 0 1px 3px var(--shade); }
[data-quiet~="tested"] .model .marks .tested { display: none; }
/* The gallery's like, over the picture's other corner, on a ground of its
   own over any picture; the marks keep clear of it. */
.model .frame > .icon-btn {
	position: absolute; top: var(--s-2); right: var(--s-2); z-index: 1;
	background: var(--panel); box-shadow: 0 1px 3px var(--shade);
}
.model .frame > .icon-btn:hover { background: var(--panel-hi); }
.model .frame:has(> .icon-btn) .marks { right: 49px; }
/* On a phone the marks keep to the picture's left 60%: one, mostly, never
   more than 12% of it (two side by side on a pinned row's wider card were
   12.7%, site277). */
@media (width < 600px) { .model .marks, .model .frame:has(> .icon-btn) .marks { right: 40%; } }
.model .words { flex: 1; padding: 10px 12px 12px; display: flex; flex-direction: column; gap: 2px; min-width: 0; }
@media (width >= 900px) { .model .words { padding: 10px 14px 12px; } }
/* The name: the card's one link to the model, stretched over all of it,
   and a finger's target of its own too (24 px at least, WCAG 2.5.8): a
   one-line name on a phone is 20 px, a hair from the designer's link. */
.model .open { color: inherit; text-decoration: none; min-height: 24px; }
.model .open::after { content: ""; position: absolute; inset: 0; border-radius: var(--radius); }
.model .open:focus-visible { outline: none; }
.model .open:focus-visible::after { outline: 2px solid var(--focus); outline-offset: -2px; }
/* A name is at most 80 characters (api/share.js); two lines of it here. */
.model b {
	display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
	color: var(--ink); font-size: var(--t-body); font-weight: 640; line-height: 1.35; overflow-wrap: anywhere;
}
/* Who made it, with their avatar, its size and its numbers, one line that
   wraps on a phone. */
.model .by {
	display: flex; flex-wrap: wrap; align-items: center; gap: 2px var(--s-2); min-width: 0;
	color: var(--ink-soft); font-size: var(--t-small); line-height: 1.5;
}
/* Clear of the name by more than the designer's link reaches above its line
   (4 px, "targets"): a one-line name's 24 px target was left 22 under it,
   on a build card whose line wraps (axe target-size, /builds at 390). */
.model .open + .by { margin-top: 3px; }
.model .who { display: inline-flex; align-items: center; gap: 6px; min-width: 0; max-width: 100%; color: var(--ink-soft); }
.model .who span:not(.avatar) { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.model a.who { position: relative; z-index: 1; text-decoration: none; }
.model a.who:hover { color: var(--ink); text-decoration: underline; }
.model .parts { color: var(--ink-faint); font-size: var(--t-tiny); white-space: nowrap; }
.model small:not(.pill) { color: var(--ink-faint); font-size: var(--t-tiny); font-variant-numeric: tabular-nums; }
/* How much of it the signed-in person's collection holds, and what moves. */
.model small.moves, .model small.owned.all { color: var(--ink); font-weight: 600; }
.model small.owned { color: var(--ink-soft); }
/* Its numbers on that line, after its size: likes (where the like is not
   a button), builds and comments, each an icon and a count. The card used
   to end in a row of them, which held only an empty heart on every card. */
.model .by .acts { display: inline-flex; flex-wrap: wrap; align-items: center; gap: 0 var(--s-3); font-size: inherit; }
.model .tally { display: inline-flex; align-items: center; gap: var(--s-1); color: var(--ink-soft); }
.model .tally .icon { width: 16px; height: 16px; }
/* A photo of a real build as a card (web/card.js buildCardHtml), the
   gallery's Builds tab: the model card's shape, the photo cut to its 4:3;
   who built it and when on one line, and what they said of it, two lines
   at most, its quote marks the browser's. */
.model .when { color: var(--ink-faint); font-size: var(--t-tiny); white-space: nowrap; font-variant-numeric: tabular-nums; }
/* Who built it takes a second line before the name is cut: "Gebaut von
   Robin Castell" is wider than a phone's card, where the English fits. */
.build-card .who span:not(.avatar) {
	display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; white-space: normal; overflow-wrap: anywhere;
}
.build-card .said {
	display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; margin-top: 2px;
	color: var(--ink-soft); font-size: var(--t-small); line-height: 1.4; overflow-wrap: anywhere;
}
/* A collection's cover: up to four of its models' pictures (web/card.js
   collectionCardHtml, api/_lists.js mosaicHtml), on its card and at the
   head of its page. */
/* Its shape holds whatever its pictures' own: a wide picture across both
   columns would make its row taller than the cover's half. */
.mosaic {
	aspect-ratio: 4 / 3; min-height: 0; overflow: hidden; display: grid; gap: 2px; background: var(--bg-soft);
	grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); grid-template-rows: minmax(0, 1fr) minmax(0, 1fr);
}
.mosaic img { width: 100%; height: 100%; min-height: 0; object-fit: cover; background: var(--picture-ground); }
.mosaic.n1 img { grid-column: 1 / -1; grid-row: 1 / -1; }
/* Kept wide, as the pictures are: two one above the other, three a wide
   one over two. */
.mosaic.n2 img, .mosaic.n3 img:first-child { grid-column: 1 / -1; }
.mosaic.n0 { place-items: center; grid-template-columns: 1fr; grid-template-rows: 1fr; color: var(--ink-faint); font-size: var(--t-small); }
/* A public collection as a card (web/card.js collectionCardHtml), the
   gallery's Collections tab: the model card's shape, its cover filling the
   frame; whose, how many models and followers on its line, and Follow at
   its foot (web/follow.js), over the card's link as the designer's is,
   level across a row; nothing there when there is no Follow (your own)
   and nothing said. */
.collection-card .frame > .mosaic { aspect-ratio: auto; width: 100%; height: 100%; }
.collection-card .follow-line {
	position: relative; z-index: 1; display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-2);
	margin: auto 0 0; padding-top: var(--s-2);
}
.collection-card .follow-line:not(:has(> .follow:not([hidden]), > .said:not(:empty))) { display: none; }
.collection-card .follow-line .said { flex-basis: 100%; color: var(--ink-soft); font-size: var(--t-small); }
.collection-card .follow-line .said:empty { display: none; }
/* A card 180-280 px wide: the designer's line a step smaller, so their
   name, its size and its numbers fit. The name stays 16 px at every width. */
@media (width < 900px) {
	.model .by { font-size: var(--t-tiny); }
	.model .by .acts { gap: 0 var(--s-2); }
}
.grid { display: grid; gap: 14px; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); }

/* -- the kit --------------------------------------------------------
   What a social page is made of (docs/DESIGN_SYSTEM.md, web/kit.js): the
   pill, tabs, an avatar, an icon and an icon button with its count, the
   toast, the "more" menu. web/_kit.html shows each, in both themes. */

/* A pill: a fact, a tag, a mark. One that is a link or a button is taller,
   a finger's width, and takes the pointer's edge. .good is green (Tested),
   .new is edged in the accent, .tag says "#" first. A row of them is
   .pills. */
.pill {
	display: inline-flex; align-items: center; gap: var(--s-1); min-height: 24px; padding: 1px 10px;
	border: 1px solid var(--line-strong); border-radius: var(--r-pill); background: var(--panel);
	font: inherit; font-size: var(--t-tiny); font-weight: 500; line-height: 20px; white-space: nowrap;
	color: var(--ink-soft); text-decoration: none;
}
a.pill, button.pill, summary.pill { min-height: 32px; padding: 5px 12px; font-size: var(--t-small); color: var(--ink); cursor: pointer; }
a.pill:hover, button.pill:hover, summary.pill:hover { border-color: var(--ink-faint); background: var(--panel); }
summary.pill { width: fit-content; list-style: none; }
summary.pill::-webkit-details-marker { display: none; }
.pill.good { color: var(--green); border-color: var(--green); font-weight: 600; }
.pill.new { color: var(--ink); border-color: var(--accent-edge); }
.pill.tag { gap: 0; }
.pill.tag::before { content: "#"; color: var(--ink-faint); }
/* Its quieter part: a handle after a name. */
.pill small { color: var(--ink-faint); font-size: inherit; }
/* A person's achievements (web/card.js awardsHtml): pills, each the award
   icon at its words' height before its name. */
.pills.awards .icon { width: 16px; height: 16px; margin-left: -2px; }
.pills { display: flex; flex-wrap: wrap; gap: var(--s-2); margin: 0; padding: 0; list-style: none; }
/* .pills.scroller: one row of them that scrolls (the gallery's kinds,
   the library's themes). A pressed one is chosen, edged in the accent. */
.pills.scroller { flex-wrap: nowrap; padding-block: 2px; }
button.pill[aria-pressed="true"], a.pill[aria-current="true"] { border-color: var(--accent-edge); background: var(--panel-hi); }

/* Tabs: a row of links or buttons, the one shown aria-current (or
   aria-selected in a tablist) underlined in the accent's edge. A
   scroller by its own class (below): on a phone the row scrolls inside
   itself. A count in .n. */
.tabs {
	display: flex; gap: var(--s-1); margin: 0 0 var(--s-5); padding: 0; list-style: none;
	border-bottom: 1px solid var(--line);
}
.tabs a, .tabs button {
	flex: none; display: inline-flex; align-items: center; gap: var(--s-2); min-height: var(--control-h);
	margin: 0 0 -1px; padding: 0 var(--s-3); border: 0; border-bottom: 2px solid transparent; border-radius: 0;
	background: none; color: var(--ink-soft); font-size: var(--t-small); font-weight: 600; text-decoration: none; white-space: nowrap;
}
.tabs a:hover, .tabs button:hover { color: var(--ink); background: none; }
.tabs [aria-current="page"], .tabs [aria-current="true"], .tabs [aria-selected="true"] { color: var(--ink); border-bottom-color: var(--accent-edge); }
.tabs .n { color: var(--ink-faint); font-weight: 500; font-variant-numeric: tabular-nums; }

/* The scroller: the one way anything on the site scrolls sideways
   (docs/DESIGN_SYSTEM.md "Scroller", web/scroller.js). It scrolls inside
   itself, never the page, and a swipe past its end never takes the
   browser back a page. A row of items is its component's class and
   .scroller (.models, .pills, .media-strip, .build-strip); .tabs is one
   by its own class. A box wider than its room scrolls the same way, but
   freely, with no snapping, gutter or buttons: a .table, the docs'
   .code, /admin's .card.scroller.

   Where it has more, its edge fades (scroller.js says which, data-more:
   "start", "end" or both), over the item cut there: its start as far as
   an item comes to rest (16 px), its end wider, where a row of pills or
   tabs may be cut between two and the fade is all that says so. Its
   scrollbar is thin
   and drawn while the pointer or the focus is in it, its room kept the
   while, so nothing moves when it is. Positioned, so a .visually-hidden
   heading inside it scrolls with it rather than push the page sideways. */
:where(.scroller, .tabs, .table, .code > pre) {
	position: relative; overflow-x: auto; overflow-y: hidden; overscroll-behavior-x: contain; scroll-behavior: smooth;
	scrollbar-width: thin; scrollbar-color: transparent transparent;
}
:where(.scroller, .tabs, .table, .code > pre):is(:hover, :focus-within) { scrollbar-color: var(--line-strong) transparent; }
:where(.scroller, .tabs, .table, .code > pre)[data-more="start"] { mask-image: linear-gradient(to right, transparent, var(--ink) 16px); }
:where(.scroller, .tabs, .table, .code > pre)[data-more="end"] { mask-image: linear-gradient(to left, transparent, var(--ink) 40px); }
:where(.scroller, .tabs, .table, .code > pre)[data-more="start end"] {
	mask-image: linear-gradient(to right, transparent, var(--ink) 16px, var(--ink) calc(100% - 40px), transparent);
}
@media (prefers-reduced-motion: reduce) { :where(.scroller, .tabs, .table, .code > pre) { scroll-behavior: auto; } }
/* A row of items: each comes to rest with its start at the row's, clear
   of the fade (scroll-padding), as does one the keyboard focuses, whose
   ring is drawn inside it so the row does not cut it off. A .scroller
   row reaches into the page's 16 px gutter: its first item starts at the
   page's edge, under the words over it, and a phone's runs to the edge
   of the screen. */
:where(.scroller:not(.card), .tabs) { scroll-snap-type: x mandatory; scroll-padding-inline: 16px; }
:where(.scroller:not(.card), .tabs) > * { flex: none; scroll-snap-align: start; }
:where(.scroller:not(.card), .tabs) :focus-visible { outline-offset: -3px; }
.scroller:not(.card) { margin-inline: -16px; padding-inline: 16px; }
/* .inset: a row that does not start at the page's edge (after a control,
   inside a panel) keeps to its own box. */
.scroller.inset { margin-inline: 0; padding-inline: 0; }
/* A row's head: its name, and where the row is the start of a longer
   list, See all to it at the far end. */
.scroller-head { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: 0 var(--s-4); margin: 0 0 var(--s-3); }
.scroller-head > h2 { margin: 0; }
.scroller-head > a { padding-block: 6px; color: var(--ink-soft); font-size: var(--t-small); }
.scroller-head > a:hover { color: var(--ink); }
/* Previous and Next (scroller.js), for a mouse: a finger swipes. Beside
   the row's two ends, over its fade, each hidden at its end; a page of
   items a press, and what comes to rest is clear of them. Drawn where
   the browser can tie them to the row (anchor positioning); elsewhere the
   row scrolls as it does under a finger. */
.icon-btn.scroller-go { display: none; }
@media (hover: hover) and (pointer: fine) {
	@supports (anchor-name: --row) {
		.icon-btn.scroller-go {
			display: inline-flex; position: absolute; z-index: 1; top: anchor(center); translate: 0 -50%;
			background: var(--panel); box-shadow: var(--highlight), var(--shadow-1);
		}
		.icon-btn.scroller-go:hover { background: var(--panel-hi); }
		.scroller-go.scroller-back { left: anchor(left); }
		.scroller-go.scroller-next { right: anchor(right); }
		.scroller:not(.card) { scroll-padding-inline: 44px; }
		.scroller:not(.card)[data-more="start"] { mask-image: linear-gradient(to right, transparent, var(--ink) 44px); }
		.scroller:not(.card)[data-more="end"] { mask-image: linear-gradient(to left, transparent, var(--ink) 44px); }
		.scroller:not(.card)[data-more="start end"] {
			mask-image: linear-gradient(to right, transparent, var(--ink) 44px, var(--ink) calc(100% - 44px), transparent);
		}
	}
}

/* An avatar: a person's picture, or one made from their handle (web/kit.js
   avatarHtml): a round tile in one of eight colours and its first letter,
   never a figure's likeness (docs/TRADEMARKS.md). Four sizes: .small 24
   (a byline), 40, .big 64 (your account), .huge 112 (a profile). */
.avatar {
	display: inline-grid; place-items: center; flex: none; width: 40px; height: 40px; overflow: hidden;
	border-radius: 50%; background: var(--avatar-8); color: var(--on-avatar);
	font-size: var(--t-h3); font-weight: 700; line-height: 1; text-transform: uppercase; user-select: none;
}
.avatar img { width: 100%; height: 100%; object-fit: cover; }
.avatar.small { width: 24px; height: 24px; font-size: var(--t-micro); }
.avatar.big { width: 64px; height: 64px; font-size: var(--t-h2); }
.avatar.huge { width: 112px; height: 112px; font-size: var(--t-h1); }
.avatar.c1 { background: var(--avatar-1); } .avatar.c2 { background: var(--avatar-2); }
.avatar.c3 { background: var(--avatar-3); } .avatar.c4 { background: var(--avatar-4); }
.avatar.c5 { background: var(--avatar-5); } .avatar.c6 { background: var(--avatar-6); }
.avatar.c7 { background: var(--avatar-7); } .avatar.c8 { background: var(--avatar-8); }
/* Somebody not known yet (your own in the header before the server has
   said who you are): the same circle, blank, on the neutral ground. */
.avatar.unknown { background: var(--panel-hi); box-shadow: inset 0 0 0 1px var(--line-strong); }

/* A picture of your own cropped to a circle (web/picture.js, Edit
   profile's Choose a picture): the picture on a square canvas, the circle
   it is cut to drawn on it, as wide as the dialog lets it be, the zoom's
   two icon buttons under it. Dragged with a finger, so the page does not
   scroll under it. */
.crop-dialog { width: min(440px, calc(100vw - 32px)); }
.cropper { display: grid; gap: var(--s-3); justify-items: center; margin: 0 0 var(--s-4); }
.cropper canvas { display: block; width: 100%; max-width: 360px; aspect-ratio: 1; border-radius: var(--radius);
	background: var(--field); touch-action: none; cursor: grab; }
.cropper canvas:active { cursor: grabbing; }
.cropper .zoom { display: flex; gap: var(--s-2); }

/* An icon from the sprite (web/icons.svg, web/kit.js iconHtml), in the
   words' colour; filled when its button is pressed. */
.icon { width: 20px; height: 20px; flex: none; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
/* An icon button: a round button with an icon, and its count beside it
   once there is one (never "0"). Its name and count are its label for a
   screen reader ("Like, 12 likes"); a toggle is aria-pressed, and pressed
   it is edged in the accent and its icon filled. .small for a card's row. */
.icon-btn {
	display: inline-flex; align-items: center; justify-content: center; gap: 6px;
	min-width: var(--control-h); min-height: var(--control-h); padding: 0 12px;
	border: 1px solid var(--line); border-radius: var(--r-pill); background: transparent; color: var(--ink);
	font: inherit; font-size: var(--t-small); font-weight: 600; line-height: 1; font-variant-numeric: tabular-nums;
	text-decoration: none; cursor: pointer; list-style: none;
}
.icon-btn::-webkit-details-marker { display: none; }
.icon-btn:hover { background: var(--panel); }
/* data-on: on, for a button that opens something rather than toggling
   (Save, when the model is in one of your lists). */
.icon-btn[aria-pressed="true"], .icon-btn[data-on] { border-color: var(--accent-edge); }
.icon-btn[aria-pressed="true"] .icon, .icon-btn[data-on] .icon { fill: currentColor; }
.icon-btn.small { min-width: 36px; min-height: 36px; padding: 0 10px; }
.icon-btn.small .icon { width: 18px; height: 18px; }
/* .labelled says a word for it too, between its icon and its count (a
   model's Like and I built it), a little closer set; on a phone the row of
   six has room for icons and counts alone, and the name stays its label. */
.icon-btn.labelled { gap: 4px; padding: 0 10px; }
@media (width < 600px) { .icon-btn.labelled .word { display: none; } .icon-btn.labelled { gap: 6px; padding: 0 12px; } }

/* The toast (web/kit.js toast): a line that says what just happened
   ("Link copied") at the foot of the screen, read out, gone in a moment. */
.toast {
	position: fixed; left: 50%; bottom: var(--s-5); z-index: 60; max-width: calc(100vw - 32px);
	padding: 10px 18px; border-radius: var(--r-pill); background: var(--ink); color: var(--bg);
	font-size: var(--t-small); font-weight: 600; box-shadow: var(--shadow);
	transform: translate(-50%, 12px); opacity: 0; pointer-events: none; transition: opacity 0.2s, transform 0.2s;
}
.toast.shown { transform: translate(-50%, 0); opacity: 1; }
@media (prefers-reduced-motion: reduce) { .toast { transition: none; } }

/* The "more" menu: an icon button that opens a short list of what else
   can be done (Report it, Takedown requests), the header Menu's panel.
   A <details>, so it opens with no script; web/kit.js closes it on a click
   elsewhere or Escape. */
.more-menu { position: relative; display: inline-block; }
/* It opens from its button's start, along the row; .end at a row's end
   opens back from the button's end, so it never runs off the page. */
.more-menu .menu-list { z-index: 30; left: 0; right: auto; }
.more-menu.end .menu-list { left: auto; right: 0; }
.menu-list > button {
	justify-content: flex-start; min-height: 0; padding: 10px 12px; border: 0; border-radius: var(--r-1);
	background: none; color: var(--ink-soft); font-size: var(--t-body); font-weight: 400; text-align: left;
}
.menu-list > button:hover { background: var(--panel-hi); color: var(--ink); }

/* Settings: a panel of rows, each what a setting is and its control
   beside it (under it on a phone). .wide takes the whole row. A row that
   cannot be undone is .danger, and so is its button. */
.settings { border: 1px solid var(--line); border-radius: var(--radius); background: var(--panel); }
.setting {
	display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: var(--s-3) var(--s-5);
	align-items: start; padding: 18px 20px; margin: 0;
}
.setting + .setting { border-top: 1px solid var(--line); }
.setting .wide { grid-column: 1 / -1; }
.setting h2 { margin: 0 0 var(--s-1); }
.setting p { margin: 0 0 6px; color: var(--ink-soft); font-size: var(--t-small); max-width: 70ch; }
.setting .actions .said { margin: 0; }
@media (width < 600px) { .setting { grid-template-columns: minmax(0, 1fr); } }
/* Settings, Feedback: each report sent, its marks (what, where it stands,
   when), its words as written, and our answers under it. */
.reports { display: grid; gap: var(--s-3); margin: var(--s-3) 0 0; padding: 0; list-style: none; }
.reports .report { padding: var(--s-3) var(--s-4); border: 1px solid var(--line); border-radius: var(--r-2); background: var(--panel); }
.reports .marks { display: flex; flex-wrap: wrap; gap: var(--s-2); align-items: center; margin: 0 0 var(--s-2); }
.reports .marks small { color: var(--ink-faint); font-size: var(--t-tiny); }
.reports .words { white-space: pre-line; overflow-wrap: anywhere; color: var(--ink); }
.reports .answer { margin-top: var(--s-3); padding: var(--s-2) var(--s-3); border-left: 3px solid var(--accent-edge); background: var(--panel-hi); border-radius: 0 var(--r-1) var(--r-1) 0; }
.reports .answer .who { margin: 0 0 4px; font-size: var(--t-tiny); color: var(--ink-faint); }
.setting.danger summary { color: var(--bad); }
.cta.danger, .cta.danger:hover { color: var(--bad); border-color: var(--bad); }
.dot {
	display: inline-block; width: 12px; height: 12px; border-radius: var(--r-1); flex: none;
	box-shadow: inset 0 -2px 0 var(--shade); margin-right: 9px; vertical-align: -1px;
}

.shot {
	margin: 0; border-radius: var(--radius); overflow: hidden;
	border: 1px solid var(--line); background: var(--bg-soft); box-shadow: var(--highlight), var(--shadow);
}
/* A window's bar over a picture of the app, with its address in it: the
   point that it runs in a browser, made without a word. */
.window { display: flex; align-items: center; gap: 7px; height: 34px; padding: 0 14px;
	background: var(--panel-hi); border-bottom: 1px solid var(--line); }
.window i { width: 10px; height: 10px; border-radius: 50%; background: var(--line-strong); flex: none; }
.window span { flex: 0 1 340px; margin-inline: auto; padding: 3px 12px; border-radius: var(--r-1);
	background: var(--bg-soft); font-size: var(--t-micro); color: var(--ink-faint); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.shot img { width: 100%; }
figcaption { padding: 12px 16px 14px; font-size: var(--t-small); color: var(--ink-soft); }
figcaption b { display: block; color: var(--ink); font-size: var(--t-small); font-weight: 640; }

.stats { display: grid; gap: 12px; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); list-style: none; margin: 0; padding: 0; }
.stat { background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius); padding: 18px 18px 16px; box-shadow: var(--highlight); }
.stat b { display: block; font-size: var(--t-h2); letter-spacing: -0.03em; font-variant-numeric: tabular-nums; line-height: 1.15; }
.stat span { font-size: var(--t-small); color: var(--ink-soft); }

details.qa {
	border: 1px solid var(--line); border-radius: var(--r-3); background: var(--panel);
	padding: 0 20px; box-shadow: var(--highlight);
}
details.qa:hover { border-color: var(--line-strong); }
details.qa + details.qa { margin-top: 10px; }
details.qa summary {
	cursor: pointer; padding: 16px 0; font-weight: 620; font-size: var(--t-body);
	list-style: none; display: flex; justify-content: space-between; gap: 16px;
}
details.qa summary::-webkit-details-marker { display: none; }
details.qa summary::after { content: "+"; color: var(--ink-faint); font-weight: 500; font-size: var(--t-h3); line-height: 1; }
details.qa[open] summary::after { content: "–"; }
details.qa > div { padding: 0 0 18px; color: var(--ink-soft); }
details.qa > div p { margin: 0 0 10px; }

/* -- the foot ------------------------------------------------------
   One footer on every page (web/_shell.html): the mark, a line of what
   Brickworks is and the theme, beside four columns of links (Product,
   Community, Help, Legal); then the notices, quiet but whole
   (docs/TRADEMARKS.md). site356: the row of eleven links read as one
   long line nobody scanned. A link is 32 px tall under a mouse and a
   finger's 44 on a phone, four to a column at most, so the footer is no
   taller than the row was by more than a column's height (a profile at
   1280 px stays under 2,000 px, account_page_flow). */

.site-foot { border-top: 1px solid var(--line); padding: var(--s-7) 0 var(--s-6); color: var(--ink-faint); background: var(--bg-soft); }
.foot-top { display: grid; gap: var(--s-5) var(--s-7); margin-bottom: var(--s-5); }
@media (width >= 900px) { .foot-top { grid-template-columns: minmax(220px, 1fr) minmax(0, 2.4fr); } }
.foot-brand { display: grid; align-content: start; justify-items: start; gap: var(--s-2); }
.foot-brand .mark { font-size: var(--t-body); min-height: var(--control-h); margin-left: -4px; }
.foot-brand .chip { width: 22px; height: 22px; }
.foot-brand p { margin: 0; max-width: 34ch; color: var(--ink-soft); font-size: var(--t-small); }
.foot-brand .theme-choice { margin-top: var(--s-1); }
.foot-links { display: grid; gap: var(--s-4); grid-template-columns: repeat(2, minmax(0, 1fr)); }
@media (width >= 600px) { .foot-links { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
.foot-h { margin: 0 0 var(--s-1); color: var(--ink); font-size: var(--t-small); font-weight: 650; }
.foot-links ul { display: grid; margin: 0; padding: 0; list-style: none; }
.foot-links a {
	display: inline-flex; align-items: center; min-height: var(--control-h); color: var(--ink-soft);
	text-decoration: none; font-size: var(--t-small);
}
@media (width >= 600px) { .foot-links a { min-height: 32px; } }
.foot-links a:hover { color: var(--ink); text-decoration: underline; }
.legal { padding-top: var(--s-4); border-top: 1px solid var(--line); }
.legal p { margin: 0 0 6px; max-width: 150ch; font-size: var(--t-micro); line-height: 1.55; }
.legal a { color: var(--ink-soft); }

/* -- the landing kit --------------------------------------------------
   What the landing pages (home, plans, download) are made of, and any
   page may use: a section's head, a badge, a callout, a row of features
   each with its icon, three steps, a pair of pictures before and after, a
   plan's card and its ticks, a table of what each plan has, and the last
   offer (.closing; .offer is the download page's own). site356, 2026-10-29. */

/* A section on a landing page: more room above and below than a page's
   section, its title the larger --t-section (h2.title), a line under it,
   and a way to more of it at the right. */
.section { padding: var(--section) 0; }
/* .defer: a section under the first screen laid out only as it nears the
   window. The rebuilt home page laid out 2.6 times what the old one did
   before its first paint (79 ms to 30 under SwiftShader, site356), and
   painted 40 ms later. Its height is kept once drawn ("auto"), so nothing
   above the window moves as a reader scrolls back. Not for a page whose
   words a check reads with innerText: a section not yet laid out has
   none (the plans flow failed on /plans with it). */
.defer { content-visibility: auto; contain-intrinsic-size: auto 900px; }
.section + .section { border-top: 1px solid var(--line); }
.title { font-size: var(--t-section); line-height: 1.08; letter-spacing: -0.035em; font-weight: 740; }
.section-head { display: flex; flex-wrap: wrap; align-items: flex-end; justify-content: space-between; gap: var(--s-3) var(--s-5); margin: 0 0 var(--s-6); }
.section-head > div { max-width: 62ch; }
.section-head h2 { margin: 0; }
.section-head p:not(.eyebrow) { margin: var(--s-3) 0 0; color: var(--ink-soft); font-size: var(--t-lede); text-wrap: pretty; }
.section-head .eyebrow { margin-bottom: var(--s-3); }
.section-head > a { color: var(--ink-soft); font-size: var(--t-small); font-weight: 600; text-decoration: none; padding-block: 6px; }
.section-head > a:hover { color: var(--ink); text-decoration: underline; }
.section-head.center { flex-direction: column; align-items: center; text-align: center; }
.section-head.center > div { margin-inline: auto; }

/* A badge: a short label beside a title or on a card (Two months free,
   Recommended). A pill is a fact or a filter; a badge says what kind. */
.badge {
	display: inline-flex; align-items: center; gap: var(--s-1); min-height: 22px; padding: 0 8px;
	border: 1px solid var(--line-strong); border-radius: var(--r-pill); background: var(--panel-hi);
	color: var(--ink-soft); font-size: var(--t-micro); font-weight: 650; line-height: 20px; white-space: nowrap;
}
.badge.accent { color: var(--ink); background: var(--accent-soft); border-color: var(--accent-edge); }
.badge.good { color: var(--green); border-color: var(--green); background: transparent; }
/* A badge that goes somewhere (the landing page's news): a pointer's
   target of 30 px, its edge firming under the pointer. */
a.badge { min-height: 30px; padding: 0 12px; font-size: var(--t-tiny); text-decoration: none; }
a.badge:hover { border-color: var(--ink-faint); }
a.badge.accent:hover { border-color: var(--accent-edge); background: var(--panel-hi); }

/* A callout: a note, a tip or a warning, its edge the kind's colour (the
   docs' and any page's; it was docs.css's alone). */
.callout {
	margin: 0 0 var(--s-5); padding: var(--s-3) var(--s-4); border: 1px solid var(--line);
	border-left: 4px solid var(--focus); border-radius: var(--r-2); background: var(--panel);
}
.callout.tip { border-left-color: var(--green); }
.callout.warning { border-left-color: var(--bad); }
.callout.accent { border-left-color: var(--accent-edge); }
.callout p { margin: 0 0 var(--s-2); }
.callout p:last-child { margin-bottom: 0; }
.callout .callout-title { color: var(--ink); font-weight: 650; font-size: var(--t-small); }

/* An icon on a tile of the accent's soft ground (a feature's). */
.glyph {
	display: inline-grid; place-items: center; flex: none; width: 40px; height: 40px; border-radius: var(--r-2);
	border: 1px solid var(--line); background: var(--accent-soft); color: var(--accent-ink);
}
.glyph .icon { width: 22px; height: 22px; }

/* Features: a grid of panels, each its icon, a title and a line; as
   many to a row as fit at 300 px (three on a laptop). */
.features { display: grid; gap: var(--s-4); grid-template-columns: repeat(auto-fill, minmax(min(100%, 300px), 1fr)); margin: 0; padding: 0; list-style: none; }
.feature {
	padding: var(--s-5); border: 1px solid var(--line); border-radius: var(--radius);
	background: var(--panel); box-shadow: var(--highlight);
}
.feature h3 { margin: var(--s-4) 0 var(--s-1); }
.feature p { margin: 0; color: var(--ink-soft); font-size: var(--t-small); }

/* Steps: three panels in order, each numbered in the accent. */
.steps { counter-reset: step; display: grid; gap: var(--s-4); grid-template-columns: minmax(0, 1fr); margin: 0; padding: 0; list-style: none; }
@media (width >= 900px) { .steps { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
.steps > li {
	counter-increment: step; display: flex; flex-direction: column; padding: var(--s-5);
	border: 1px solid var(--line); border-radius: var(--radius); background: var(--panel); box-shadow: var(--highlight);
}
.steps > li::before {
	content: counter(step); display: inline-grid; place-items: center; width: 32px; height: 32px; margin-bottom: var(--s-4);
	border-radius: 50%; background: linear-gradient(180deg, var(--accent-hi), var(--accent)); color: var(--on-accent);
	font-size: var(--t-small); font-weight: 760; box-shadow: var(--shine-btn);
}
.steps h3 { margin: 0 0 var(--s-1); }
.steps p { margin: 0; color: var(--ink-soft); font-size: var(--t-small); }
.steps .shot { margin-top: auto; }
.steps p + .shot { margin-top: var(--s-4); }

/* Two pictures of one thing, before and after, side by side, each named
   by a badge over its corner; what they show under them. */
.ba { margin: 0; }
.ba .pair { display: grid; gap: var(--s-3); grid-template-columns: repeat(2, minmax(0, 1fr)); }
.ba .side { position: relative; margin: 0; overflow: hidden; border: 1px solid var(--line); border-radius: var(--radius); background: var(--picture-ground); }
.ba .side img { width: 100%; height: auto; aspect-ratio: 1; object-fit: cover; }
.ba .side .badge { position: absolute; top: var(--s-2); left: var(--s-2); background: var(--panel); box-shadow: var(--shadow-1); }
/* Over a picture a badge stands on a ground of its own: the accent's is
   the yellow itself, as a primary button's. */
.ba .side .badge.accent { border-color: transparent; background: var(--accent); color: var(--on-accent); }
.ba > figcaption { padding: var(--s-3) 0 0; }

/* Text beside a picture: the text first, the picture the larger; one over
   the other under 900 px. .flip puts the picture first on a laptop. */
.split { display: grid; gap: var(--s-6) clamp(24px, 5vw, 72px); align-items: center; }
@media (width >= 900px) {
	.split { grid-template-columns: minmax(0, 5fr) minmax(0, 6fr); }
	.split.flip { grid-template-columns: minmax(0, 6fr) minmax(0, 5fr); }
	.split.flip > :first-child { order: 2; }
}
.split p:not(.eyebrow) { color: var(--ink-soft); max-width: 56ch; }

/* A plan's card (/plans, the landing page's teaser): its name and badge,
   who it is for, its price, the way in, and its ticks. .featured, the
   one to choose, edged and lit in the accent. */
.tier {
	position: relative; display: flex; flex-direction: column; gap: var(--s-3); min-width: 0; padding: var(--s-6) var(--s-5);
	border: 1px solid var(--line); border-radius: var(--r-4); background: var(--panel); box-shadow: var(--highlight), var(--shadow-1);
}
.tier.featured { border-color: var(--accent-edge); background-image: var(--glow); box-shadow: var(--highlight), var(--shadow-2); }
.tier .name { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-2) var(--s-3); }
.tier .name h2, .tier .name h3 { margin: 0; }
.tier p:not(.eyebrow) { margin: 0; color: var(--ink-soft); }
.tier .cta { width: 100%; }
.price { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0 var(--s-2); margin: 0; color: var(--ink-soft); font-size: var(--t-body); }
.price b { color: var(--ink); font-size: var(--t-h1); font-weight: 760; line-height: 1.1; letter-spacing: -0.04em; font-variant-numeric: tabular-nums; }
.price small { flex-basis: 100%; color: var(--ink-faint); font-size: var(--t-small); }
/* A list of what something has, each with a tick in green. */
.ticks { display: grid; align-content: start; gap: var(--s-2); margin: 0; padding: 0; list-style: none; color: var(--ink-soft); font-size: var(--t-small); }
.ticks li { position: relative; padding-left: 28px; line-height: 1.55; }
.ticks li::before {
	content: ""; position: absolute; left: 6px; top: 0.25em; width: 6px; height: 11px;
	border: solid var(--green); border-width: 0 2px 2px 0; transform: rotate(45deg);
}
.ticks b { color: var(--ink); font-weight: 620; }

/* What each plan has, side by side (.table.matrix): the plans' columns
   centred, a row of a group's name across them, and a tick or a dash. */
.table.matrix { border: 1px solid var(--line); border-radius: var(--radius); background: var(--panel); box-shadow: var(--highlight); }
.table.matrix th, .table.matrix td { padding: 12px 16px; }
.table.matrix thead th { color: var(--ink); font-size: var(--t-small); font-weight: 650; }
.table.matrix td, .table.matrix thead th + th { text-align: center; }
.table.matrix tbody th { color: var(--ink); font-weight: 520; }
.table.matrix tr.group th { padding-top: var(--s-5); color: var(--accent-ink); font-size: var(--t-tiny); font-weight: 680; letter-spacing: 0.08em; text-transform: uppercase; }
.table.matrix tbody tr:last-child > * { border-bottom: 0; }
.has, .hasnt { position: relative; display: inline-block; width: 18px; height: 18px; vertical-align: middle; }
.has::before {
	content: ""; position: absolute; left: 6px; top: 1px; width: 6px; height: 12px;
	border: solid var(--green); border-width: 0 2px 2px 0; transform: rotate(45deg);
}
.hasnt::before { content: ""; position: absolute; left: 3px; top: 8px; width: 12px; height: 2px; border-radius: var(--r-1); background: var(--ink-faint); }

/* The last offer on a landing page: a panel lit from above on a faint
   baseplate of studs, its words and its ways in at the middle. */
.closing {
	padding: clamp(40px, 7vw, 80px) var(--s-5); border: 1px solid var(--line); border-radius: var(--r-4); text-align: center;
	background-color: var(--panel); background-image: var(--glow), var(--studs); background-size: auto, 24px 24px;
	box-shadow: var(--highlight), var(--shadow-1);
}
.closing .lede { margin-inline: auto; }
/* The opening of a landing page, lit the same way. */
.halo { background-image: var(--glow), var(--studs); background-size: auto, 24px 24px; background-repeat: no-repeat, repeat; }

/* -- motion ---------------------------------------------------------
   Every control and card answers the pointer in --motion (150 ms): its
   colour, ground, edge and shadow ease rather than snap, a press sinks it
   a little (:active, for a finger as much as a mouse), a card lifts 2 px
   under a mouse, and a dialog or a menu fades in as it opens. Nothing
   moves under reduced motion, as the toast did not (site273: two
   transitions on the whole site, both the toast's). */
.cta, :where(button), .icon-btn, .pill, .tabs a, .tabs button, .segmented button, .nav a, .menu summary,
.menu-list a, .menu-list > button, .foot-links a, .model, .list-card, details.qa, .media-strip .thumb, .feature, .tier,
:where(input:not([type="checkbox"], [type="radio"], [type="hidden"]), select, textarea) {
	transition: color var(--motion) var(--ease), background-color var(--motion) var(--ease),
		border-color var(--motion) var(--ease), box-shadow var(--motion) var(--ease),
		transform var(--motion) var(--ease), filter var(--motion) var(--ease);
}
.cta:active, :where(button:not(.link)):active, .icon-btn:active, a.pill:active, button.pill:active,
summary.pill:active, .segmented button:active, .menu summary:active { transform: scale(0.97); }
.cta:active { filter: brightness(0.95); }
.tabs a:active, .tabs button:active { color: var(--ink); background: var(--panel); }
.nav a:active, .menu-list a:active, .menu-list > button:active { background: var(--panel-hi); }
.model:active, .list-card:active { transform: scale(0.99); }
@media (hover: hover) {
	.model:hover, .list-card:hover { transform: translateY(-2px); }
	.feature:hover { border-color: var(--line-strong); }
	.model:active, .list-card:active { transform: translateY(-1px) scale(0.99); }
}
dialog[open] { animation: rise var(--motion-open) var(--ease); }
dialog[open]::backdrop { animation: fade var(--motion-open) ease-out; }
details[open] > .menu-list { animation: drop var(--motion-open) var(--ease); }
@keyframes fade { from { opacity: 0; } }
@keyframes rise { from { opacity: 0; transform: translateY(8px) scale(0.98); } }
@keyframes drop { from { opacity: 0; transform: translateY(-4px); } }
@media (prefers-reduced-motion: reduce) {
	*, *::before, *::after, ::backdrop {
		transition-duration: 0s !important; animation-duration: 0s !important; animation-iteration-count: 1 !important;
	}
	.cta:active, :where(button):active, .icon-btn:active, .pill:active, .segmented button:active, .menu summary:active,
	.model:hover, .model:active, .list-card:hover, .list-card:active { transform: none; }
}

/* Read aloud, not shown. */
.visually-hidden {
	position: absolute !important; width: 1px; height: 1px; padding: 0; margin: -1px;
	overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* -- an inner page ----------------------------------------------------
   site359, 2026-10-29, for site356's system to keep: every page that is
   not a landing page (the docs, settings, the FAQ, the legal pages,
   /compare, /changelog, /feed, /notifications, /admin, the 404) opens on
   the same head, lit as the landing pages' opening is (.halo), and a page
   of parts keeps what is on it in view beside them.

   .page-hero: the head, the whole width: the yellow's light from above
   over the baseplate of studs, which fade into the ground under the words
   (a gradient over them, not a mask: one layer to paint). Its .wrap
   holds the .eyebrow, the h1, the .lede and, under them, .hero-meta (a
   date, a count) or .actions. */
.page-hero {
	padding: var(--page-top) 0 var(--s-7); border-bottom: 1px solid var(--line);
	background-image: var(--glow), linear-gradient(180deg, transparent 10%, var(--bg) 90%), var(--studs);
	background-size: auto, auto, 24px 24px; background-repeat: no-repeat, no-repeat, repeat;
}
.page-hero h1 { max-width: 22ch; }
.page-hero .lede { margin-bottom: 0; }
.page-hero .actions { margin-top: var(--s-5); }
/* A rule page's copy in another language: one line under its heading,
   that the English text binds (tools/site_lang.py BOUND). */
.page-hero .binding { margin: 0 0 var(--s-3); color: var(--ink-faint); font-size: var(--t-small); }
/* A head that ends in .tabs (the legal pages, /feed and /notifications):
   the tabs sit on the head's line, the one shown underlined on it. */
.page-hero:has(> .wrap > .tabs:last-child) { padding-bottom: 0; }
.page-hero > .wrap > .tabs:last-child { margin-block: var(--s-5) -1px; border-bottom: 0; }
.hero-meta {
	display: flex; flex-wrap: wrap; gap: var(--s-2) var(--s-4); margin: var(--s-4) 0 0; padding: 0;
	list-style: none; color: var(--ink-faint); font-size: var(--t-small);
}
.hero-meta b { color: var(--ink-soft); font-weight: 600; }
/* Under the head, the page's own parts. */
.page-body { padding: var(--s-7) 0 var(--section); }

/* .page-grid: what is on the page (.page-toc) down the left from 900 px,
   sticky under the header, and the parts beside it; over them, in one
   row of pills that scrolls (ul.scroller), on a phone and a tablet. */
.page-grid { display: grid; gap: var(--s-5) var(--s-8); grid-template-columns: minmax(0, 1fr); align-items: start; }
@media (width >= 900px) { .page-grid { grid-template-columns: 220px minmax(0, 1fr); } }
.page-toc { min-width: 0; }
.page-toc-title {
	margin: 0 0 var(--s-2); color: var(--ink-faint); font-size: var(--t-tiny); font-weight: 650;
	letter-spacing: 0.06em; text-transform: uppercase;
}
.page-toc ul { margin: 0; padding: 0; list-style: none; }
.page-toc a { color: var(--ink-soft); text-decoration: none; font-size: var(--t-small); }
.page-toc a:hover { color: var(--ink); }
@media (width < 900px) {
	.page-toc-title { display: none; }
	.page-toc ul { display: flex; gap: var(--s-2); padding-block: 2px; }
	.page-toc a {
		display: inline-flex; align-items: center; min-height: 36px; padding: 0 var(--s-3);
		border: 1px solid var(--line); border-radius: var(--r-pill); background: var(--panel);
	}
}
@media (width >= 900px) {
	.page-toc { position: sticky; top: calc(var(--head-h) + var(--s-5)); }
	.page-toc ul { border-left: 1px solid var(--line); }
	/* A list down the side, not a row: nothing to scroll. */
	.page-toc ul.scroller { overflow: visible; margin-inline: 0; padding-inline: 0; }
	.page-toc a {
		display: block; margin-left: -1px; padding: 6px 0 6px var(--s-3); border-left: 2px solid transparent; line-height: 1.4;
	}
	.page-toc a:hover { border-left-color: var(--line-strong); }
	.page-toc a[aria-current="true"] { color: var(--ink); border-left-color: var(--accent-edge); }
}
