/* The home site's shared layer: tokens, the page base, the Builder header, section labels, cards, chips and the
   footer. The home page and every generated update page link it. Page-specific rules stay in each page. */
/* THE SITE'S ROLES. Every colour, size and radius on the site is one of these names; a rule never spells a value
   (a tint is rgba(var(--<role>-rgb), alpha), so it follows its role). A reskin edits roles, never call sites.
   They come in three layers. */
:root {
  /* 1. THE SHARED CONTRACT. What every Monolith app shares comes from the workspace UI system's --m-ui-* tokens
     (assets/monolith-ui-contracts.css, a copy kept by scripts/sync_ui_contract.py and linked before this file).
     Change these in the contract (tools/ui_system/contract.json), never here. The ground is the Builder's own
     page ground where there is no 3D scene, and the header stands on it with no rule, as the Builder's does
     (maintainer, 2026-10-28 and 2026-10-31). */
  --bg: var(--m-ui-color-canvas);
  --panel: var(--m-ui-color-surface);
  --panel2: var(--m-ui-color-surface-raised);
  --code: var(--m-ui-color-control-well);   /* the Builder's name for the control well */
  --hover-face: var(--m-ui-state-hover);
  --line: var(--m-ui-color-border);
  --line-strong: var(--m-ui-color-border-strong);
  --primary: var(--m-ui-color-action);
  --accent: var(--m-ui-color-accent);
  --link: var(--m-ui-color-link);
  --elev: var(--m-ui-elevation-raised);
  --font: var(--m-ui-type-family);
  --fast: var(--m-ui-motion-fast) ease;
  /* The contract gives no channels, so these restate its colours as r, g, b for tints. Each must equal the role
     beside it, as Studio's core/tokens.css channels do. */
  --ink-rgb: 255, 255, 255;
  --accent-rgb: 169, 133, 221;            /* --accent */
  --accent-pale-rgb: 205, 185, 239;       /* --accent-pale */
  --primary-rgb: 116, 80, 182;            /* --primary */
  --link-rgb: 185, 154, 230;              /* --link */
  /* The inks keep the Builder's white-at-alpha steps, which the contract's solid greys do not match yet
     (Studio keeps them for the same reason). */
  --ink-strong: rgb(var(--ink-rgb));
  --txt: rgba(var(--ink-rgb), .87);
  --muted: rgba(var(--ink-rgb), .58);
  --low: rgba(var(--ink-rgb), .46);
  --accent-pale: rgb(var(--accent-pale-rgb));
  /* a select's chevron, drawn in --accent (a data URI cannot read a role, so it restates the accent's value) */
  --chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M3 4.5 6 7.5 9 4.5' fill='none' stroke='%23a985dd' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  --note-ink: rgba(var(--ink-rgb), .66);  /* running text a shade under --txt: a lead, an intro (Builder --note-ink) */

  /* 2. THE PILL SKIN: the Builder's pill restyle (Studio core/tokens.css body.builderdeploy), restated under the
     Builder's own role names until the contract carries it, so joining the two is deleting this block. Small
     things are pills and big things are 16px rounded rectangles, one 36px control size, a 42px standalone
     button. Roles that share a value are still separate names, as in the Builder (a chip is not a field). */
  --r-surface: 16px;                      /* cards, tiles */
  --r-segment: 999px;                     /* a tray */
  --r-control: 999px;                     /* buttons and icon buttons */
  --r-field: 999px;                       /* a select */
  --r-chip: 999px;                        /* a tag */
  --r-nested: 3px;                        /* a mark inside text or a control: a mention */
  --ctl-icon: 36px;                       /* the one control size */
  --ctl-btn-h: 42px;                      /* a standalone button */
  --header-h: 54px;                       /* the page header */
  --tile-foot-h: 44px;                    /* a project tile's flush foot */
  --pvnext-cover-w: 137px;                /* a tile turned on its side: the cover's track (the Builder's) */
  --tile-elev: 0 2px 10px rgba(0, 0, 0, .34);   /* a ready tile's lift (the Builder's), and its tint under it */
  --tile-tint: 0 12px 30px -12px rgba(0, 0, 0, .5);   /* neutral at rest: purple stays in the hero until hovered */
  --tile-tint-hover: 0 18px 40px -14px rgba(var(--primary-rgb), .5);
  --tray-pad: 3px;                        /* a tray holds its pills 3px in */
  --tray-gap: 2px;
  --tray-edge: rgba(var(--ink-rgb), .1);
  --tray-bg: var(--panel);                /* solid: nothing on the page is see-through (maintainer, 2026-10-28) */
  --tray-ink: rgba(var(--ink-rgb), .62);  /* an unchosen pill */
  --tray-on: rgba(var(--accent-rgb), .2); /* the chosen one */
  --tray-on-ink: var(--accent-pale);
  --tray-item-r: 999px;
  --cluster-btn-ink: rgba(var(--ink-rgb), .72);
  --cluster-on-bg: rgba(var(--accent-rgb), .2);
  --cluster-on-ink: var(--accent);
  --entry-act-bg: rgba(var(--accent-rgb), .14);   /* an entry row's action: a pill in the accent wash */
  --entry-act-ink: var(--accent-pale);
  --entry-act-r: 999px;
  --dlg-btn-bg: rgba(var(--ink-rgb), .06);        /* the plain button: the Builder's dialog secondary */
  --dlg-btn-bg-hover: rgba(var(--ink-rgb), .1);
  --dlg-btn-edge: rgba(var(--ink-rgb), .1);
  --dlg-btn-font: 600 13px/1 var(--font);
  /* Type. Sizes are the contract's scale (--m-ui-type-meta 12, -body 14, -section 16, -title 20) or one of the
     Builder's own beside it: a tray pill's or an entry action's 13px label, the Introduction's 15px text and
     28px title, and the 11px of a kicker, a tag or a count. Nothing else spells a size. */
  --tray-item-size: 13px;
  --entry-act-size: 13px;
  --intro-text-size: 15px;
  --intro-title-size: 28px;
  --label-size: 11px;

  /* 3. THE SITE'S OWN: the brand register (the hero), the grounds pictures sit on, and the shapes the Builder has
     no role for. (Its --r-thumb is a swatch's 8px, so a thumbnail's radius is named apart.) */
  --r-inset: 12px;                        /* a surface inside a surface: a product's stage, the latest photo, a box */
  --r-thumbnail: 10px;
  --hero-ground: #000;                    /* the hero's pitch black, which the ground turns from into --bg */
  --lockup: #9674cb;                      /* the MONOLITH wordmark, as in the Builder */
  --thumb-bg0: #f4f1f5; --thumb-bg1: #e9e5eb; --thumb-bg2: #d6d0db;   /* a project cover's studio ground (Studio's names) */
  --stage-0: #2c2833; --stage-1: #1f1e23; --stage-2: #18181b;        /* a render's lit stage */
  --photo-tray: #cfced3;                  /* the grey a white-ground photo is multiplied onto */
  --thumb-render: #232227;                /* a render's thumbnail */
  --cover-ground: #111;                   /* behind a full-bleed photo */
  --shade-rgb: 0, 0, 0;                   /* the black a cast shadow or a mark on a light ground is drawn in */
  --scrim: rgba(var(--shade-rgb), .96);            /* behind the photo viewer: the page all but gone */
  --page: 1240px;
  --gutter: clamp(16px, 3cqi, 28px);
}
* { box-sizing: border-box; }
[hidden] { display: none !important; }   /* hidden is hidden: no component's display rule may override it */
html { background: var(--bg); scroll-padding-top: calc(var(--header-h) + 8px); }   /* a focused or linked item clears the sticky header */
body {
  margin: 0;
  background: var(--bg);
  color: var(--txt);
  font: 400 var(--m-ui-type-body)/1.5 var(--font);
  -webkit-font-smoothing: antialiased;
}
a { color: var(--link); text-decoration: none; }
:focus-visible { outline: var(--m-ui-focus-width) solid var(--link); outline-offset: var(--m-ui-focus-offset); }
.card :focus-visible { outline-offset: -3px; }
.page { container-type: inline-size; }
.wrap { width: 100%; max-width: var(--page); margin: 0 auto; padding: 0 var(--gutter); }

/* Header: the Builder's page header (Studio core/studio.css .builder-page-top, with chrome.css's journey), copied
   rather than reinterpreted. A full-width 54px bar on the page ground with no rule under it, 22px in from each
   side: the MONOLITH wordmark left (the home page's taller wordmark, which the maintainer preferred to the
   Builder's 2026-10-31), the sections centred as the Builder's journey steps, and the socials right as the
   Builder's corner cluster. */
.hdr {
  position: sticky; top: 0; z-index: 20; height: var(--header-h); padding: 0 22px; display: grid;
  grid-template-columns: minmax(max-content, 1fr) auto minmax(max-content, 1fr); align-items: center;
  background: var(--bg);
}
.page > :not(.hdr) { position: relative; z-index: 1; }
.brand { grid-column: 1; justify-self: start; display: block; width: 105px; height: var(--ctl-icon); background: var(--lockup);
  -webkit-mask: url(brand/monolith-wordmark.svg) center / 105px 12.3px no-repeat; mask: url(brand/monolith-wordmark.svg) center / 105px 12.3px no-repeat; }
/* The sections as the Builder's journey steps: each label after an 18px badge with a hairline ring, which holds
   the section's icon where a Builder step holds its number. The section in view takes the Builder's active step,
   the badge filled with the primary and its icon white. The icons are masks drawn in the badge's ink, so one
   rule colours them; each link picks its own by its href, so the generated update pages need no markup of their
   own. */
.journey { grid-column: 2; display: flex; align-items: center; gap: 7px; }
.journey a {
  --jn-ink: var(--low); --jn-bg: transparent; --jn-edge: var(--line);
  position: relative; height: 32px; display: flex; align-items: center; gap: 6px; padding: 0 6px; margin: 0 -6px; border-radius: var(--r-control);
  color: var(--low); font-size: var(--m-ui-type-meta); white-space: nowrap; transition: color var(--fast);
}
.journey a::before {
  content: ""; flex: none; width: 18px; height: 18px; box-sizing: border-box; border-radius: 50%;
  border: 1px solid var(--jn-edge); background: var(--jn-bg); transition: background var(--fast), border-color var(--fast);
}
.journey a::after {
  content: ""; position: absolute; left: 10px; top: 50%; width: 10px; height: 10px; margin-top: -5px; background: var(--jn-ink);
  -webkit-mask: var(--jn-icon) center / 10px 10px no-repeat; mask: var(--jn-icon) center / 10px 10px no-repeat;
}
.journey a:hover { color: var(--txt); --jn-ink: var(--txt); }
.journey a.on { color: var(--txt); --jn-ink: var(--ink-strong); --jn-bg: var(--primary); --jn-edge: var(--primary); }
.journey a[href$="#projects"] { --jn-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' fill='none' stroke='black' stroke-width='1.4'%3E%3Crect x='1.2' y='1.2' width='3.8' height='3.8' rx='.8'/%3E%3Crect x='7' y='1.2' width='3.8' height='3.8' rx='.8'/%3E%3Crect x='1.2' y='7' width='3.8' height='3.8' rx='.8'/%3E%3Crect x='7' y='7' width='3.8' height='3.8' rx='.8'/%3E%3C/svg%3E"); }
.journey a[href$="#products"] { --jn-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' fill='none' stroke='black' stroke-width='1.4' stroke-linejoin='round'%3E%3Cpath d='M2.2 4.3h7.6l-.7 6.5H2.9z'/%3E%3Cpath d='M4.3 4.3V3.2a1.7 1.7 0 0 1 3.4 0v1.1'/%3E%3C/svg%3E"); }
.journey a[href$="#updates"] { --jn-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' fill='none' stroke='black' stroke-width='1.4' stroke-linecap='round'%3E%3Cpath d='M1.8 2.8h8.4M1.8 6h8.4M1.8 9.2h5'/%3E%3C/svg%3E"); }
.journey i { width: 18px; height: 1px; background: var(--line); }
/* GitHub, Discord and Patreon on the right as the Builder's corner cluster: one hairline pill tray holding 36px
   round buttons 3px in, with no face of their own until hovered, when they take the tray's accent wash. They
   are all links off the site, one kind of thing, so the tray has no divider; the Builder draws one only between
   groups that do different things. */
.elsewhere {
  grid-column: 3; justify-self: end; display: flex; align-items: center; gap: var(--tray-gap); padding: var(--tray-pad);
  border: 1px solid var(--tray-edge); border-radius: var(--r-segment); background: var(--tray-bg);
}
.elsewhere .ico { width: var(--ctl-icon); height: var(--ctl-icon); display: grid; place-items: center; border-radius: var(--r-control); color: var(--cluster-btn-ink); transition: background var(--fast), color var(--fast); }
.elsewhere .ico svg { width: 15px; height: 15px; fill: currentColor; }
.elsewhere .ico:hover { background: var(--cluster-on-bg); color: var(--cluster-on-ink); }
/* the segmented tray (Studio's .seg.fused): the one recipe for the topics and a product's versions */
.tray {
  display: flex; align-items: center; gap: var(--tray-gap); padding: var(--tray-pad); border-radius: var(--r-segment);
  border: 1px solid var(--tray-edge); background: var(--tray-bg);
}
/* a pill in a tray: the one control size, no face until it is hovered or chosen */
.tray > button {
  height: var(--ctl-icon); padding: 0 14px; display: flex; align-items: center; gap: 7px; flex: none; border: 0; border-radius: var(--tray-item-r);
  background: transparent; color: var(--tray-ink); font: 500 var(--tray-item-size)/1 var(--font); cursor: pointer; transition: background var(--fast), color var(--fast);
}
.tray > button:focus-visible { outline-offset: -2px; }   /* inside the tray's scrolling clip */
.tray > button:hover { background: var(--dlg-btn-bg); color: var(--txt); }
.tray > button[aria-pressed="true"] { background: var(--tray-on); color: var(--tray-on-ink); }
/* the plain button (Studio's dialog secondary): a 36px pill with a faint face and a hairline */
.plain {
  height: var(--ctl-icon); padding: 0 18px; border: 1px solid var(--dlg-btn-edge); border-radius: var(--r-control);
  background: var(--dlg-btn-bg); color: var(--txt); font: var(--dlg-btn-font); cursor: pointer; transition: background var(--fast);
}
.plain:hover { background: var(--dlg-btn-bg-hover); }

/* Section labels: the Builder's page kicker over a hairline that fades from the accent. */
section.block { scroll-margin-top: calc(16px - clamp(64px, 8cqi, 104px)); padding-top: clamp(64px, 8cqi, 104px); display: flex; flex-direction: column; gap: 14px; }
.kicker { display: flex; align-items: center; gap: 14px; }
/* the label: a kicker's word, the latest write-up's mark, the 404's code (the Builder's page kicker) */
:is(.kicker span:first-child, .label) { font-size: var(--label-size); font-weight: 600; line-height: 1; color: var(--accent); text-transform: uppercase; letter-spacing: .14em; }
.kicker span:last-child { flex: 1; height: 1px; background: linear-gradient(to right, rgba(var(--accent-rgb), .34), rgba(var(--ink-rgb), .06) 40%, rgba(var(--ink-rgb), .05)); }
/* the section's lead: one plain sentence 6px under the kicker, in the Introduction's text size */
.lead { margin: -8px 0 0; max-width: 90ch; color: var(--note-ink); font-size: var(--intro-text-size); line-height: 1.5; }
.card { background: var(--panel); border: 1px solid var(--line); border-radius: var(--r-surface); box-shadow: var(--elev); overflow: hidden; }

/* A credit: by the author, with the contributors, the names on the text's own ink (Discord's credit line). A
   mention in a post's text is Discord's chip in the site's accent. */
.by:has(+ .by)::after { content: "\00a0·"; color: var(--low); }
.by b { white-space: nowrap; color: var(--txt); font-weight: 500; }   /* a name never breaks, the line wraps between names */
.mention { padding: 0 3px; border-radius: var(--r-nested); background: var(--m-ui-color-selection); color: var(--accent-pale); font-weight: 500; }
/* read by a screen reader, not shown */
.sr-only { position: absolute; width: 1px; height: 1px; margin: -1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
.tag { padding: 2px 8px; border-radius: var(--r-chip); border: 1px solid var(--line-strong); color: var(--muted); font-size: var(--label-size); line-height: 1.3; white-space: nowrap; }

footer { padding-top: 56px; }
.foot { position: relative; padding-top: 16px; padding-bottom: 24px; display: flex; flex-wrap: wrap; align-items: center; gap: 4px 24px; justify-content: space-between; font-size: var(--m-ui-type-meta); color: var(--low); }
.foot::before { content: ""; position: absolute; top: 0; left: var(--gutter); right: var(--gutter); height: 1px; background: var(--line); }
.foot nav { display: flex; flex-wrap: wrap; gap: 4px 20px; }
.foot a { border-radius: var(--r-nested); min-height: 32px; display: inline-flex; align-items: center; color: var(--muted); }
.foot a:hover { color: var(--link); }

/* A development update's own page: one reading column on the page spine, its text and its media on one
   measure (about 75 characters of 16px text), the Builder's Introduction title, photos as 16px surfaces. */
.post { max-width: calc(640px + 2 * var(--gutter)); padding-top: 28px; padding-bottom: 8px; }
.post-back { display: inline-flex; align-items: center; height: var(--ctl-icon); margin-left: max(-14px, calc(var(--gutter) * -1 + 4px)); padding: 0 14px; border-radius: var(--r-control); color: var(--muted); font-size: var(--tray-item-size); font-weight: 500; transition: background var(--fast), color var(--fast); }
.post-back::before { content: ""; width: 7px; height: 7px; margin-right: 10px; border: solid currentColor; border-width: 0 0 1.6px 1.6px; transform: rotate(45deg); }
.post-back:hover { background: rgba(var(--ink-rgb), .06); color: var(--txt); }
.post article { margin-top: 22px; }
.post h1 { margin: 16px 0 0; color: var(--ink-strong); font-size: clamp(var(--m-ui-type-title), 4cqi + 12px, var(--intro-title-size)); line-height: 1.2; font-weight: 700; text-wrap: balance; }
.post-meta { margin: 10px 0 0; display: flex; flex-wrap: wrap; gap: 4px 14px; color: var(--low); font-size: var(--m-ui-type-meta); }
.post-meta > :not(.credit) { white-space: nowrap; }   /* a date or a credit never breaks inside, the line wraps between them */
.post-meta .members-first { flex-basis: 100%; }
.post-body { margin-top: 24px; color: var(--txt); font-size: var(--m-ui-type-section); line-height: 1.7; overflow-wrap: break-word; }
.post-body > * { margin: 0 0 18px; }
.post-body p:has(+ :is(ul, ol)) { margin-bottom: 6px; }   /* a line introducing a list stays with it */
.post-body :is(h2, h3, h4) { color: var(--ink-strong); line-height: 1.3; text-wrap: balance; }
.post-body h2 { margin: 40px 0 14px; padding-bottom: 10px; border-bottom: 1px solid var(--line); font-size: var(--m-ui-type-title); font-weight: 700; }
.post-body h3 { margin: 32px 0 10px; font-size: var(--m-ui-type-title); font-weight: 600; }
.post-body h4 { margin: 24px 0 8px; font-size: var(--m-ui-type-section); font-weight: 700; }
.post-body .spacer { height: 1em; }   /* Discord's ** ** blank line */
.post-body > :has(+ .spacer) { margin-bottom: 0; }
.post-body .spacer + :is(.mosaic, figure) { margin-top: 8px; }
.post-body a.mention, .post-body :is(h2, h3, h4) a, .post-body .shot { text-decoration: none; }
.post-body a { text-decoration: underline; text-decoration-color: rgba(var(--link-rgb), .4); text-underline-offset: 3px; }
.post-body a:hover { text-decoration-color: currentColor; }
.post-body strong { font-weight: 600; }
.post-body ul, .post-body ol { padding-left: 22px; }
.post-body li { line-height: 1.55; }
.post-body li + li { margin-top: 4px; }
.post-body blockquote > * { margin: 0; }
.post-body blockquote > * + * { margin-top: 8px; }
.post-body blockquote { margin-left: 0; padding: 2px 0 2px 16px; border-left: 2px solid rgba(var(--accent-rgb), .4); color: var(--muted); }
.post-body pre:focus-visible { outline-offset: -3px; }
.code-box { margin: 0 0 18px; border-radius: var(--r-inset); background: var(--code); border: 1px solid var(--line); overflow: hidden; }
.code-bar { display: flex; align-items: center; justify-content: flex-end; padding: 6px 6px 0 16px; }
.code-lang { margin-right: auto; color: var(--low); font-size: var(--m-ui-type-meta); }   /* Copy sits above the code, never over it */
.post-body pre { margin: 0; padding: 0 16px 14px; overflow-x: auto; font-size: var(--m-ui-type-body); line-height: 1.55; }   /* the frame is the box's, so a fade only fades the code */
.post-body pre code { padding: 0; background: none; font-size: inherit; }
code { font-family: var(--m-ui-type-mono); }
.post-body code { padding: 1px 5px; border-radius: var(--r-nested); background: rgba(var(--ink-rgb), .06); font-size: .92em; }
.post-body figure { margin: 24px 0; }
.post-body img, .post-body video, .post-body iframe { display: block; width: 100%; max-width: 100%; height: auto; border: 0; border-radius: var(--r-surface); background: var(--panel); box-shadow: var(--elev); }
.post-body iframe { aspect-ratio: 16 / 9; }
.post-body video { margin-inline: auto; background: var(--code); aspect-ratio: 16 / 9; }
/* a clip whose size the page carries (--ar) has its own box before it loads, no taller than most of the screen */
.post-body video[style] { width: min(100%, calc(min(80svh, 36rem) * var(--ar))); aspect-ratio: var(--ar); }   /* a clip at its own proportions (its size is written in the page), within the screen */
.media-missing::before { content: ""; display: inline-block; width: 16px; height: 16px; margin-right: 10px; vertical-align: -3px; background: var(--low);
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='black' stroke-width='1.4'%3E%3Crect x='1.5' y='3.5' width='9' height='9' rx='1.5'/%3E%3Cpath d='M10.5 7 14.5 4.8v6.4L10.5 9' stroke-linejoin='round'/%3E%3C/svg%3E") center / 16px no-repeat;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='black' stroke-width='1.4'%3E%3Crect x='1.5' y='3.5' width='9' height='9' rx='1.5'/%3E%3Cpath d='M10.5 7 14.5 4.8v6.4L10.5 9' stroke-linejoin='round'/%3E%3C/svg%3E") center / 16px no-repeat; }
.media-missing { padding: 14px 16px; border-radius: var(--r-inset); border: 1px solid var(--line); background: var(--code); color: var(--muted); font-size: var(--m-ui-type-body); }
.media-run { margin: 0 0 18px; padding: 14px 16px; border-radius: var(--r-inset); border: 1px solid var(--line); background: var(--code); }
.media-run .media-missing { margin: 0 0 8px; padding: 0; border: 0; background: none; }
.media-run :is(h2, h3, h4, h5) { margin: 0; padding: 0; border: 0; color: var(--muted); font-size: var(--m-ui-type-body); font-weight: 500; line-height: 1.6; }   /* the clips the run held, a list under its note */
.post-body .shot { display: block; cursor: zoom-in; }
:is(.post-body .shot, .thumb, .pstage) img { color: transparent; }   /* no alt text drawn while a photo loads */
.post-body .shot.broken { display: grid; place-items: center; min-height: 120px; background: var(--code); border: 1px solid var(--line); }
.post-body .shot.broken img { display: none; }
.mosaic .shot.broken { min-height: 0; }
.mosaic .shot.broken::after { content: "Not loaded. Open to retry."; font-size: var(--m-ui-type-meta); }
.post-body .shot.broken::after { content: "This photo could not be loaded. Open it to try again."; padding: 12px 16px; color: var(--muted); font-size: var(--m-ui-type-body); text-align: center; }
.post-body figure .shot { width: min(100%, var(--w, 100%), calc(min(80svh, 36rem) * var(--ar, 1))); aspect-ratio: var(--ar); margin-inline: auto; border-radius: var(--r-surface); }
.post-body figure .shot img { width: 100%; height: 100%; object-fit: contain; }
.mosaic { margin: 24px 0; display: flex; flex-direction: column; gap: 4px; border-radius: var(--r-surface); overflow: hidden; }
.mosaic-row { display: flex; gap: 4px; }
.mosaic-row .shot { flex: 1 1 0; min-width: 0; }
.mosaic .shot:focus-visible { outline-offset: -3px; }   /* inside the mosaic's rounded clip */
.mosaic-row .shot { aspect-ratio: 4 / 3; }
.mosaic-row[data-count="1"] .shot { aspect-ratio: 16 / 9; }
.mosaic-row[data-count="3"] .shot { aspect-ratio: 1; }
.mosaic-row img { height: 100%; object-fit: cover; border-radius: 0; box-shadow: none; }
/* the viewer: the photo full size over the page ground, closed by Esc, the backdrop or its button */
.viewer { overscroll-behavior: contain; width: 100vw; height: 100svh; max-width: none; max-height: none; margin: 0; padding: 0; border: 0; background: transparent; }
.viewer::backdrop { background: var(--scrim); }
.viewer:focus { outline: none; }
.viewer-caption { grid-column: 2; min-height: 1.5em; margin: 0; color: var(--muted); font-size: var(--m-ui-type-meta); text-align: center; }
.viewer[open] { display: grid; grid-template-rows: minmax(0, 1fr) auto; justify-items: center; gap: 10px; padding: calc(16px + var(--ctl-icon) + 10px) clamp(8px, 6vw, 64px) 14px; }
/* the photo's stage is row 1 whatever it holds (the photo, its error, nothing while loading), the bar row 2 */
.viewer-stage { grid-row: 1; position: relative; width: 100%; height: 100%; min-height: 0; display: grid; place-items: safe center; overflow: hidden; }
.viewer-stage.zoomed { overflow: auto; overscroll-behavior: contain; }
.viewer-stage.loading::after { content: "Loading"; position: absolute; inset: 0; display: grid; place-items: center; color: var(--muted); font-size: var(--m-ui-type-body); }
.viewer img { max-width: 100%; max-height: 100%; min-height: 0; object-fit: contain; border-radius: var(--r-inset); cursor: zoom-in; }
.viewer-stage.zoomed img { max-width: none; max-height: none; cursor: zoom-out; }
.viewer-stage.fits img { cursor: default; }   /* the photo at its own pixels, panned by scrolling */
.viewer :is(.viewer-close, .viewer-step) { position: absolute; width: var(--ctl-icon); height: var(--ctl-icon); display: grid; place-items: center; border: 1px solid var(--dlg-btn-edge); border-radius: var(--r-control);
  background: var(--panel); color: var(--txt); cursor: pointer; }
.viewer :is(.viewer-close, .viewer-step):hover { background: var(--hover-face); }
.viewer-close { top: 16px; right: 16px; }
.viewer-bar { grid-row: 2; width: min(100%, 720px); display: grid; grid-template-columns: var(--ctl-icon) minmax(0, 1fr) var(--ctl-icon); align-items: center; gap: 12px; }
/* Zoom and Open original beside Close, so the caption centres on the photo between the steps */
.viewer-tools { position: absolute; top: 16px; right: calc(16px + var(--ctl-icon) + 8px); display: flex; gap: 8px; }
.viewer-open { display: inline-flex; align-items: center; white-space: nowrap; }   /* the plain pill: one control height */
.viewer-stage:focus-visible { outline-offset: -3px; }
.viewer-bar .viewer-step { position: static; }
.viewer-step[data-step="-1"] { grid-column: 1; grid-row: 1; }
.viewer-step[data-step="1"] { grid-column: 3; grid-row: 1; }
@media (max-height: 520px) { .viewer[open] { padding-top: 14px; } }   /* the tools float over the stage's corner, as on the hero's short screens */
.viewer-step.off { visibility: hidden; }   /* a lone photo keeps the bar's columns */
.viewer-error { margin: 0; color: var(--muted); font-size: var(--m-ui-type-body); text-align: center; }
.viewer-error button { margin-left: 10px; vertical-align: middle; }
.post-body figcaption { margin-top: 8px; color: var(--low); font-size: var(--m-ui-type-meta); }
.post-body hr { border: 0; height: 1px; background: var(--line); }
.post-tags { margin-top: 12px; display: flex; flex-wrap: wrap; gap: 6px; }   /* in the header, where Discord shows a forum post's tags */
.post-tags:empty { display: none; }
.post-steps { margin-top: 40px; display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
.post-step { padding: 14px 16px; display: flex; flex-direction: column; gap: 4px; border-radius: var(--r-surface); background: var(--panel); border: 1px solid var(--line); color: var(--txt); font-size: var(--m-ui-type-body); font-weight: 600; line-height: 1.35; transition: border-color var(--fast), transform var(--fast); }
.post-step span { color: var(--low); font-size: var(--m-ui-type-meta); font-weight: 500; }
.post-step[rel="next"] { text-align: right; }
.post-step:hover { border-color: rgba(var(--accent-rgb), .42); transform: translateY(-2px); }
@media (prefers-reduced-motion: reduce) { .post-step:hover { transform: none; } }

/* A row wider than its box scrolls sideways (a tray, a code block): the side with more to see fades out, so a
   cut-off line reads as more to scroll to (data-more, kept by each page's script). */
[data-more="end"] { -webkit-mask: linear-gradient(90deg, #000 calc(100% - 36px), transparent); mask: linear-gradient(90deg, #000 calc(100% - 36px), transparent); }
[data-more="start"] { -webkit-mask: linear-gradient(270deg, #000 calc(100% - 36px), transparent); mask: linear-gradient(270deg, #000 calc(100% - 36px), transparent); }
[data-more="both"] { -webkit-mask: linear-gradient(90deg, transparent, #000 36px calc(100% - 36px), transparent); mask: linear-gradient(90deg, transparent, #000 36px calc(100% - 36px), transparent); }

/* A page narrower than the header's three parts: the mark and the icons stay and the sections are a scroll away,
   and an update's previous and next stack. It follows the page's width (the header is in the page's container),
   and it is last so it overrides the rules above. */
@container (max-width: 699px) {
  .hdr { padding: 0 16px; }
  .journey { display: none; }
  .post-steps { grid-template-columns: 1fr; }
  .post-step[rel="next"] { text-align: left; }
  .post-steps > span:empty { display: none; }
}
