/* The product pages' shared layout: every VGraphics game and app (George, 22 Oct 2026: "the same layouts with different
   content and graphic"). tools/build-pages.mjs writes the pages from each product's page.json. Colours, fonts and
   shapes come from the product's theme pack (<product>/theme/theme.css, linked first), so nothing here names a
   product's colour: change a look in its pack, and the layout here, for every product at once. Tokens marked
   "optional" below have a fallback; tools/lib/theme.mjs lists the ones every pack must set. */

* { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
body {
  margin: 0;
  color: var(--ink);
  font: var(--body-weight) var(--body-size)/1.6 var(--font-body);
  background-color: var(--page);
  background-image: var(--page-pattern);
  background-size: var(--page-pattern-size);
  background-position: var(--page-pattern-position, 0 0); /* optional */
}
/* The ornaments reach past the screen's edges; clip, unlike hidden, makes no scroll box, so sticky pieces still stick. */
main { overflow-x: clip; }

/* Scrollbars in the product's own colour (George, 23 Oct 2026: "style the scrollbars to match the color of the
   project"): the thumb in --scrollbar (optional; the accent by default), a little lighter on hover and press, on a
   track of the page tinted with it. Chromium and Safari draw the ::-webkit-scrollbar parts, which can round and light
   up; Firefox, which has none, takes scrollbar-color. The page's own scrolling rows (the screenshot row) get the same,
   thinner. */
:root { --sb: var(--scrollbar, var(--accent)); --sb-track: color-mix(in srgb, var(--sb) 9%, var(--page)); }
::-webkit-scrollbar { width: 14px; height: 14px; }
::-webkit-scrollbar-track, ::-webkit-scrollbar-corner { background: var(--sb-track); }
::-webkit-scrollbar-thumb { min-height: 48px; border: 3px solid var(--sb-track); border-radius: 999px; background: var(--sb); }
::-webkit-scrollbar-thumb:hover { background: color-mix(in srgb, var(--sb) 80%, #FFFFFF); }
::-webkit-scrollbar-thumb:active { background: color-mix(in srgb, var(--sb) 64%, #FFFFFF); }
@supports not selector(::-webkit-scrollbar) {
  html { scrollbar-color: var(--sb) var(--sb-track); }
}
/* A picture keeps its own shape (George, 24 Oct 2026: "These are stretched."): a rule that sets only its width (the
   cards' 78%) or only its height gets the other side from the picture, never from its width and height attributes.
   A box that sets both sides crops with object-fit. As assets/vgraphics.css does for the company pages. */
img { max-width: 100%; height: auto; }
a { color: var(--link, var(--accent)); text-underline-offset: 3px; } /* --link: optional */
:focus-visible { outline: 3px solid var(--accent); outline-offset: 3px; }
.wrap { width: min(1120px, 100% - 40px); margin-inline: auto; }
[id] { scroll-margin-top: 92px; } /* clear of the sticky header */
.skip { position: absolute; left: 16px; top: -60px; z-index: 10; padding: 10px 16px; border-radius: var(--radius-sm); background: var(--surface); color: var(--ink); font-weight: 700; text-decoration: none; }
.skip:focus { top: 12px; }
.sr-only { position: absolute; width: 1px; height: 1px; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
h1, h2, h3 {
  margin: 0;
  font-family: var(--font-display);
  font-weight: var(--display-weight);
  text-transform: var(--display-case);
  letter-spacing: var(--display-tracking);
  line-height: var(--display-leading);
}
@keyframes rise { from { opacity: 0; transform: translateY(18px); } }

/* Header: only the product's own logo top left, its menu top right. It stays at the top of the screen (George, 22 Oct
   2026: "Make toolbar sticky and blurry when scrolling"): clear over the key art's sky at the very top, then, once the
   page scrolls (assets/product.js sets .scrolled), a frosted bar in the page's colour with a hairline at its foot, its
   words in the page's ink. Where backdrop-filter is missing, the bar is nearly opaque instead. */
.top {
  position: fixed;
  inset: 0 0 auto;
  z-index: 30;
  display: flex;
  flex-wrap: wrap;
  row-gap: 8px;
  justify-content: space-between;
  align-items: center;
  padding: calc(10px + env(safe-area-inset-top, 0px)) clamp(16px, 3vw, 40px) 10px;
  transition: background-color 200ms ease-out, box-shadow 200ms ease-out, -webkit-backdrop-filter 200ms ease-out, backdrop-filter 200ms ease-out;
}
.top a { color: var(--on-art); text-decoration: none; text-shadow: var(--on-art-shadow); transition: color 200ms ease-out, text-shadow 200ms ease-out; }
.top.scrolled {
  background-color: color-mix(in srgb, var(--page) 72%, transparent);
  -webkit-backdrop-filter: blur(14px) saturate(1.4);
  backdrop-filter: blur(14px) saturate(1.4);
  box-shadow: 0 1px 0 color-mix(in srgb, var(--ink) 12%, transparent), 0 10px 26px -18px rgb(0 0 0 / 0.45);
}
@supports not ((-webkit-backdrop-filter: blur(1px)) or (backdrop-filter: blur(1px))) {
  .top.scrolled { background-color: color-mix(in srgb, var(--page) 96%, transparent); }
}
.top.scrolled a { color: var(--ink); text-shadow: none; }
.product-name {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  min-height: 44px;
  margin-right: auto;
  font: var(--display-weight) 1.35rem/1 var(--font-display);
  text-transform: var(--display-case);
  letter-spacing: var(--display-tracking);
}
.product-name img { width: 36px; height: 36px; border-radius: 10px; }
/* A product's painted title logo (page.json site.logo) carries its name: shown at its own shape, a soft shadow so it
   reads on any sky and on the frosted bar. */
.product-name img.logo, .foot-brand img.logo { width: auto; border-radius: 0; box-shadow: none; filter: drop-shadow(0 2px 6px rgb(20 12 40 / 0.3)); }
.product-name img.logo { height: 42px; }
.foot-brand img.logo { height: 64px; }
.subnav { display: flex; gap: 4px; }
.subnav a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 0 15px;
  border-radius: 999px;
  font: var(--label-weight) 1rem/1 var(--label-font);
  text-transform: var(--label-case);
  letter-spacing: var(--label-tracking);
}
.subnav a:hover { background: rgba(255, 255, 255, 0.16); }
.subnav a[aria-current="page"] {
  background: var(--nav-current-bg);
  color: var(--nav-current-ink);
  box-shadow: var(--nav-current-line);
  border-radius: var(--nav-current-radius, 999px); /* optional */
  text-shadow: none;
}
.top.scrolled .subnav a:hover { background: color-mix(in srgb, var(--ink) 8%, transparent); }
.top.scrolled .subnav a[aria-current="page"] {
  background: var(--nav-current-bg-scrolled, var(--nav-current-bg)); /* optional */
  color: var(--nav-current-ink-scrolled, var(--nav-current-ink)); /* optional */
}

/* The hero of every product page, the landing page's, its other pages' and every wiki page's (George, 23 Oct 2026:
   "Heroes of all pages must have same height as hero in overview"; tools/lib/hero.mjs builds it for all of them).
   Key art: the product's welcome picture edge to edge from the very top (George's hero rules). Landscape screens get
   the wide picture (or the ultra-wide one past 2:1), cut to fill a 16:10 box no taller than the screen, so it fills
   the whole screen on most of them (George, 22 Oct: "Increase height of hero a bit", from 16:9). Portrait
   screens up to 4:5 get the whole tall 9:16 picture, never cut, so a tablet's lead line stays clear of the art's
   subject. The foot fades out into the page, and the lead line and store badges stand in its last fifth. The painted
   title stands in for the h1, which stays for screen readers and search. Per-picture settings come from page.json:
   --art-at (the crop's anchor), --art-fade and --art-fade-tall (where the fade starts). */
.key-art { position: relative; height: min(62.5vw, 100vh); height: min(62.5vw, 100svh); }
.key-art picture, .key-art picture img { display: block; width: 100%; height: 100%; }
.key-art picture img {
  object-fit: cover;
  object-position: var(--art-at, 50% 0);
  background: var(--art-placeholder, var(--surface-2));
  -webkit-mask-image: linear-gradient(#000 var(--art-fade, 76%), transparent);
  mask-image: linear-gradient(#000 var(--art-fade, 76%), transparent);
}
/* A soft shade under the header, so its words read on any sky. */
.key-art::before {
  content: "";
  position: absolute;
  inset: 0 0 auto;
  z-index: 1;
  height: 150px;
  background: linear-gradient(var(--art-shade), transparent);
  pointer-events: none;
}
.hero-foot { position: absolute; inset: auto 0 0; z-index: 2; padding-bottom: clamp(16px, 3.5vh, 40px); }
.hero-foot .wrap { display: grid; justify-items: center; gap: 12px; text-align: center; }
.foot-left .hero-foot .wrap { justify-items: start; text-align: left; }
.hero-foot .wrap > * { animation: rise 700ms 150ms cubic-bezier(.2, .8, .2, 1) both; }
.hero-foot .badges { animation-delay: 260ms; }
.lead {
  max-width: 14em;
  margin: 0;
  font: var(--lead-style) var(--display-weight) var(--lead-size)/1.02 var(--font-display);
  text-transform: var(--display-case);
  letter-spacing: var(--display-tracking);
  color: var(--lead-ink);
  text-shadow: var(--lead-shadow);
}
.lead em { font-style: inherit; color: var(--lead-em); }
@media (max-aspect-ratio: 4/5) {
  .key-art { height: 177.78vw; }
  .key-art picture img {
    object-position: 50% 0;
    -webkit-mask-image: linear-gradient(#000 var(--art-fade-tall, 62%), transparent);
    mask-image: linear-gradient(#000 var(--art-fade-tall, 62%), transparent);
  }
  .foot-left .hero-foot .wrap { justify-items: center; text-align: center; }
}

/* Store badges and buttons */
.badges { display: flex; flex-wrap: wrap; gap: 12px; align-items: center; justify-content: center; }
.foot-left .hero-foot .badges { justify-content: flex-start; }
/* Google's badge as supplied: its transparent margin is the clear space the brand guidelines ask for. */
.gp { display: inline-flex; margin: -14px -4px; border-radius: 18px; transition: transform 160ms ease-out; }
.gp img { display: block; height: 84px; width: auto; }
.gp:hover { transform: translateY(-2px); }
.gp:focus-visible { outline-offset: -12px; }
.pill {
  display: inline-flex;
  flex-direction: column;
  min-width: 150px;
  padding: 9px 18px 8px;
  border-radius: var(--radius-sm);
  border: var(--card-border);
  background: var(--surface);
  color: var(--ink);
  line-height: 1.25;
  text-align: left;
  text-decoration: none;
  box-shadow: var(--card-shadow);
  transition: transform 160ms ease-out, box-shadow 160ms ease-out;
}
.pill b { font-weight: 800; }
.pill small { color: var(--muted); font: var(--label-weight) 0.78rem/1.3 var(--label-font); text-transform: uppercase; letter-spacing: 0.08em; }
.pill:hover { transform: translateY(-2px); box-shadow: var(--card-lift); }
.btn {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  min-height: 56px;
  padding: 0 24px;
  border: 0;
  border-bottom: 4px solid var(--cta-edge);
  border-radius: var(--radius-sm);
  background: var(--cta);
  color: var(--cta-ink);
  font: var(--label-weight) 1.1rem/1 var(--label-font);
  text-transform: var(--label-case);
  letter-spacing: var(--label-tracking);
  text-decoration: none;
  cursor: var(--cursor-link, pointer);
  transition: transform 160ms ease-out, filter 160ms ease-out;
}
.btn:hover { filter: brightness(1.08); }
.btn:active { transform: translateY(2px); }
.btn svg { width: 20px; height: 20px; }

/* Scenes: a section's content on a stage of its own, as the gallery and the soundtrack have theirs: a picture from the
   key art's world (page.json stage) over --intro-bg, shaded at its top and foot (--stage-shade, optional) so the words
   on it, in --on-art, read. On phones it runs nearly edge to edge, like the gallery's. The intro's live demo (a
   playable board, a running gauge) stands on one. */
.intro .sec-head .badges { justify-content: flex-start; margin-top: 6px; }
.scene {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  display: grid;
  justify-items: center;
  gap: clamp(14px, 2vw, 22px);
  padding: clamp(18px, 3.5vw, 44px) clamp(10px, 3vw, 40px) clamp(20px, 3vw, 36px);
  border-radius: clamp(24px, 3vw, 44px);
  background: var(--intro-bg);
  color: var(--on-art);
  box-shadow: var(--card-shadow);
}
.scene-art, .scene-art img { position: absolute; inset: 0; z-index: -2; display: block; width: 100%; height: 100%; }
.scene-art img { object-fit: cover; object-position: var(--stage-at, 50% 50%); }
.scene::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: var(--stage-shade, linear-gradient(var(--art-shade), transparent 24%, transparent 72%, var(--art-shade))); /* optional */
  pointer-events: none;
}
.scene > :not(.scene-art) { width: 100%; }
.demo { width: 100%; animation: rise 800ms 200ms cubic-bezier(.2, .8, .2, 1) both; }
.demo-cap {
  max-width: 30em;
  margin: 0;
  padding: 10px 20px;
  border: var(--card-border);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--ink);
  box-shadow: var(--card-shadow);
  font: var(--label-weight) 1rem/1.4 var(--label-font);
  text-transform: var(--label-case);
  letter-spacing: var(--label-tracking);
  text-align: center;
  text-wrap: balance;
}

/* Sections */
.sec { padding-block: var(--section-pad); }
.sec-head { display: grid; gap: 12px; max-width: 46rem; margin-bottom: 32px; }
/* Blocks in one section stand apart (George, 24 Oct 2026: "Spaces needed here."): every block after the first, in the
   section or on its stage, keeps a gap above it, wider than the gaps inside a block, so two grids never read as one. */
.sec > .wrap > :not(.sec-head, .more) + :not(.more),
.sec:not(.intro) .scene > :not(.scene-art) + * { margin-top: var(--block-gap, clamp(28px, 4vw, 44px)); }
.eyebrow { font: var(--label-weight) 0.95rem/1 var(--label-font); text-transform: uppercase; letter-spacing: 0.2em; color: var(--accent); }
.sec h2 { font-size: var(--h2-size); }
.sec-intro { max-width: 40em; margin: 0; color: var(--muted); font-size: 1.1rem; }
/* A heading's link to itself: muted, shown on hover or focus (always on touch screens), in the heading's line. */
.anchor { display: inline-grid; place-items: center; width: 44px; height: 44px; margin: -10px -10px -10px 2px; vertical-align: middle; color: var(--muted); opacity: 0; transition: opacity 150ms ease-out; }
.anchor svg { width: 0.5em; max-width: 22px; height: auto; }
h2:hover .anchor, .anchor:focus-visible { opacity: 1; }
@media (hover: none) { .anchor { opacity: 0.7; } }
.more { display: inline-flex; align-items: center; min-height: 44px; margin-top: 18px; font-weight: 800; }

/* Gallery: the screenshots in a row that scrolls sideways, from the content's edge to the screen's. Its sides fade
   at the screen's edges while more lies that way (fade-edges.js, through its class fade-edges). */
.shots {
  --fade-size: 48px;
  display: flex;
  gap: 20px;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  margin-inline: calc(50% - 50vw);
  padding: 6px calc(50vw - 50%) 22px;
  scroll-padding-inline: calc(50vw - 50%);
}
.shots::-webkit-scrollbar { height: 10px; }
.shots::-webkit-scrollbar-track { background: transparent; }
.shots::-webkit-scrollbar-thumb { border-color: var(--page); }
@supports not selector(::-webkit-scrollbar) {
  .shots { scrollbar-width: thin; scrollbar-color: var(--sb) transparent; }
}
.shots figure { flex: none; margin: 0; scroll-snap-align: start; }
.shots img {
  display: block;
  width: auto;
  height: clamp(340px, 62vh, 540px);
  border: var(--shot-frame);
  border-radius: var(--radius);
  background: var(--surface-2);
  box-shadow: var(--card-shadow);
}
.shots figcaption { margin-top: 12px; text-align: center; color: var(--muted); font: var(--label-weight) 1rem/1 var(--label-font); text-transform: uppercase; letter-spacing: 0.12em; }

/* Cards: every product's panels share one shape; the pack sets their colour, edge, corner and shadow. A stripe
   (--card-stripe wide) runs down a card's left edge in the accent colour. */
.card, .steps li, .band, .panel {
  background: var(--card-bg);
  border: var(--card-border);
  border-radius: var(--radius);
  box-shadow: inset var(--card-stripe) 0 0 var(--accent), var(--card-shadow);
}

/* Steps */
.steps { list-style: none; padding: 0; margin: 0; display: grid; gap: 18px; counter-reset: step; }
.steps.n3 { grid-template-columns: repeat(3, 1fr); }
.steps.n4 { grid-template-columns: repeat(4, 1fr); }
.steps li {
  counter-increment: step;
  padding: 22px 20px 20px;
  color: var(--step-text, var(--ink)); /* optional */
  box-shadow: inset var(--step-stripe, var(--card-stripe)) 0 0 var(--accent), var(--card-shadow); /* optional */
}
.steps li::before {
  content: counter(step);
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  margin-bottom: 12px;
  border-radius: var(--radius-sm);
  font: var(--step-weight, 400) var(--step-size, 1.5rem)/1 var(--step-font); /* optional */
  color: var(--step-ink);
  background: var(--step-bg, var(--c)); /* optional: the item's swatch by default */
  text-shadow: var(--step-shadow, none); /* optional */
}
.steps b { color: var(--ink); }

/* Steps as the game's own cards (steps given as { title, text, board }), on a scene: the card the game shows its tips
   on, its level bubble standing on its top edge, a small still board drawing the step, then the words. */
/* The level bubble, as on the game's level map: a white disc with its number, on a lip. */
.bubble {
  display: inline-grid;
  place-items: center;
  flex: none;
  width: 46px;
  height: 46px;
  border-radius: 50%;
  border: 3px solid var(--surface-2);
  background: #FFFFFF;
  color: #2E2840;
  box-shadow: 0 4px 0 rgb(30 20 50 / 0.28);
  font: var(--display-weight) 1.15rem/1 var(--font-display);
  text-shadow: none;
}
.bubble.sm { width: 34px; height: 34px; border-width: 2px; font-size: 0.92rem; box-shadow: 0 3px 0 rgb(30 20 50 / 0.25); }
.steps.cards-game { gap: clamp(14px, 2vw, 22px); padding-top: 14px; }
.steps.cards-game li {
  position: relative;
  display: grid;
  align-content: start;
  justify-items: center;
  gap: 8px;
  padding: 34px 18px 22px;
  border: 0;
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--ink);
  text-align: center;
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--ink) 85%, transparent), 0 8px 0 color-mix(in srgb, var(--ink) 85%, transparent), 0 22px 34px -14px rgb(20 12 40 / 0.6);
}
.steps.cards-game li::before { content: none; }
.steps.cards-game .bubble { position: absolute; top: -20px; left: 50%; translate: -50% 0; background: var(--c); border-color: #FFFFFF; color: var(--step-ink); text-shadow: var(--step-shadow, none); font-size: 1.35rem; }
.steps.cards-game .miniboard { width: min(100%, 190px); height: auto; margin-bottom: 4px; filter: drop-shadow(0 6px 8px rgb(30 20 50 / 0.25)); }
.steps.cards-game h3 { font-size: 1.4rem; }
.steps.cards-game p { margin: 0; color: var(--muted); font-size: 0.98rem; line-height: 1.45; }

/* The journey: the level map's worlds as tiles in play order, each on its own world art with what it brings, linking
   to the wiki (tools/lib/journey.mjs). With detail, each piece has its line under its name. Tiles share a row and grow
   to fill it. */
.journey { list-style: none; padding: 0; margin: 0; display: grid; gap: 12px; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); }
.journey.detail { display: flex; flex-wrap: wrap; gap: 14px; }
.journey.detail > li { flex: 1 1 320px; }
.journey-world { position: relative; isolation: isolate; overflow: hidden; padding: 14px; border-radius: var(--radius); background: var(--w) var(--art) center / cover; box-shadow: var(--card-shadow); }
.journey-world::before { content: ""; position: absolute; inset: 0; z-index: -1; background: linear-gradient(180deg, rgb(20 12 40 / 0.5), rgb(20 12 40 / 0.08) 45%, rgb(20 12 40 / 0.25)); }
.journey-head { display: flex; justify-content: space-between; align-items: baseline; gap: 8px; margin: 0 0 10px; color: #FFFFFF; text-shadow: 0 2px 6px rgb(0 0 0 / 0.6); }
.journey-head b { font: var(--display-weight) 1.3rem/1 var(--font-display); }
.journey-head span { font-weight: 700; font-size: 0.82rem; }
.journey-world ul { list-style: none; padding: 0; margin: 0; display: grid; gap: 8px; }
.journey-world a { display: flex; align-items: center; gap: 10px; padding: 6px 10px 6px 6px; border-radius: var(--radius-sm); background: rgb(255 255 255 / 0.96); color: var(--ink); text-decoration: none; font: var(--display-weight) 1rem/1.1 var(--font-display); box-shadow: 0 4px 0 rgb(0 0 0 / 0.2); transition: transform 150ms ease-out; }
.journey-world a:hover { transform: translateY(-2px); }
.journey-piece { display: grid; place-items: center; flex: none; width: 30px; height: 30px; }
.journey-piece svg, .journey-piece img { width: 100%; height: 100%; }
.journey.detail .journey-world { padding: 16px; }
.journey.detail .journey-head b { font-size: 1.5rem; }
.journey.detail .journey-world a { align-items: flex-start; padding: 10px 12px 10px 8px; }
.journey.detail .journey-piece { width: 36px; height: 36px; }
.journey.detail .journey-world a > span:last-child { display: grid; gap: 3px; }
.journey.detail small { color: var(--muted); font: var(--body-weight) 0.9rem/1.35 var(--font-body); }

/* Card grids: "icon" cards link to a wiki entry, "media" ones show a picture on top, "side" ones beside the words. */
.cards { list-style: none; padding: 0; margin: 0; display: grid; gap: 16px; }
.cards.icon { grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); gap: 14px; }
.cards.media { grid-template-columns: repeat(3, 1fr); gap: 18px; }
.cards.side { grid-template-columns: repeat(2, 1fr); gap: 18px; }
.card { display: grid; align-content: start; gap: 12px; padding: 22px; color: var(--ink); }
.card h3 { font-size: 1.45rem; }
.card p { margin: 0; color: var(--muted); }
.card ul { margin: 0; padding-left: 1.1em; display: grid; gap: 8px; color: var(--muted); }
.card ul b { color: var(--ink); font-weight: 700; }
.cards.icon .card { padding: 0; }
.cards.icon .card > a {
  display: grid;
  grid-template-columns: 56px 1fr;
  gap: 14px;
  align-items: center;
  height: 100%;
  padding: 14px 16px;
  border-radius: inherit;
  color: var(--ink);
  text-decoration: none;
}
.cards.icon .card { transition: transform 150ms ease-out, box-shadow 150ms ease-out; }
.cards.icon .card:hover, .cards.icon .card:focus-within { transform: translateY(-3px) rotate(-0.4deg); box-shadow: inset var(--card-stripe) 0 0 var(--accent), var(--card-lift); }
.cards.icon .card > a:focus-visible { outline-offset: -3px; }
.cards.icon h3 { font-size: 1.2rem; line-height: 1.15; }
.cards.icon p { font-size: 0.95rem; line-height: 1.4; }
.pic { display: grid; place-items: center; width: 56px; height: 56px; border-radius: var(--radius-sm); background: var(--surface-2); }
.pic svg { width: 40px; height: 40px; }
.cards.media .card > img { width: 78%; margin: 4px auto 6px; filter: drop-shadow(0 18px 24px rgba(0, 0, 0, 0.45)); }
.cards.side .card { grid-template-columns: minmax(0, 0.8fr) minmax(0, 1.2fr); gap: 22px; }
.cards.side .card > img { border: var(--shot-frame); border-radius: calc(var(--radius) - 4px); box-shadow: var(--card-shadow); }
.cards.side .card > div { display: grid; align-content: start; gap: 12px; }
/* Tiles: a dense grid of small picture cards (a product's styles), each one a link when it has one. */
.cards.tile { grid-template-columns: repeat(auto-fill, minmax(min(168px, 42%), 1fr)); gap: 14px; }
.cards.tile .card { padding: 0; transition: transform 150ms ease-out, box-shadow 150ms ease-out; }
.cards.tile .card > a, .cards.tile .card:not(:has(> a)) { display: grid; align-content: start; gap: 8px; padding: 10px 10px 14px; color: inherit; text-decoration: none; }
.cards.tile .card:has(> a):hover, .cards.tile .card:focus-within { transform: translateY(-3px); box-shadow: var(--card-lift); }
.cards.tile .card > a:focus-visible { outline-offset: -3px; border-radius: inherit; }
.cards.tile img { display: block; width: 100%; border-radius: calc(var(--radius-sm) - 4px); background: #000; }
.cards.tile .tile-head { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: 2px 8px; }
.cards.tile h3 { font-size: 1.1rem; line-height: 1.1; }
.cards.tile .tag { font-size: 0.7rem; }
.cards.tile p { font-size: 0.86rem; line-height: 1.4; }
.tag {
  justify-self: start;
  display: inline-block;
  padding: var(--tag-pad, 2px 10px); /* optional */
  border-radius: 999px;
  background: var(--tag-bg);
  color: var(--tag-ink);
  font: var(--label-weight) 0.78rem/1.35 var(--label-font);
  text-transform: uppercase;
  letter-spacing: 0.1em;
}
.tag.alt { color: var(--accent-2); }
.cards.icon .tag { margin-bottom: 4px; font-size: 0.72rem; letter-spacing: 0.04em; }

/* Feature lists: a title and a line each, marked with the pack's own glyph in the item's swatch. */
.features { list-style: none; padding: 0; margin: 0; display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px 28px; }
.features.n4 { grid-template-columns: repeat(4, 1fr); gap: 16px; }
.features li {
  display: flex;
  gap: 14px;
  align-items: flex-start;
  padding: var(--feature-pad, 0); /* optional */
  border-radius: var(--radius);
  background: var(--feature-bg, none); /* optional */
  box-shadow: inset var(--feature-stripe, 0px) 0 0 var(--accent); /* optional */
  color: var(--feature-text, var(--ink)); /* optional */
}
.features .mark { flex: none; width: 30px; height: 30px; margin-top: 3px; color: var(--c); }
.features b {
  display: block;
  margin-bottom: 2px;
  color: var(--ink);
  font: var(--feature-title-weight, 800) var(--feature-title-size, 1em)/1.25 var(--feature-title-font, var(--font-body)); /* optional */
  text-transform: var(--feature-title-case, none); /* optional */
  letter-spacing: var(--feature-title-tracking, normal); /* optional */
}

/* A device frame, for products whose demo or tour shows a phone screen. */
.phone {
  position: relative;
  aspect-ratio: 1080 / 2400;
  padding: 10px;
  border-radius: 42px;
  background: linear-gradient(145deg, #55555c, #121214 38%, #2c2c31);
  box-shadow: 0 50px 90px -30px rgba(0, 0, 0, 0.95), 0 0 0 1px #000;
}
.phone img { display: block; width: 100%; height: 100%; object-fit: cover; border-radius: 32px; background: #111; }
.phone::after { content: ""; position: absolute; top: 20px; left: 50%; width: 12px; height: 12px; margin-left: -6px; border-radius: 50%; background: #050505; }

/* Tour: numbered spots on a screen, each opening its part of the list beside it. Without JavaScript every part stays
   open (assets/product.js keeps one open at a time). */
.tour { display: grid; grid-template-columns: 0.9fr 1.1fr; gap: 48px; align-items: start; }
.tour .stage { position: sticky; top: 24px; justify-self: center; width: min(380px, 86vw); }
.spot { position: absolute; display: grid; place-items: center; width: 44px; height: 44px; margin: -22px 0 0 -22px; padding: 0; border: 0; border-radius: 50%; background: transparent; cursor: var(--cursor-link, pointer); }
.spot::before { content: ""; width: 26px; height: 26px; border-radius: 50%; background: var(--accent); box-shadow: 0 0 0 4px color-mix(in srgb, var(--accent) 30%, transparent), 0 4px 10px rgba(0, 0, 0, 0.6); transition: transform 180ms ease-out; }
.spot::after { content: ""; position: absolute; inset: 6px; border-radius: 50%; border: 2px solid var(--accent); animation: ping 2.4s cubic-bezier(.2, .8, .2, 1) infinite; }
.spot span { position: absolute; color: #fff; font: 800 0.9rem/1 var(--label-font); }
.spot[aria-expanded="true"]::before { background: var(--accent-2); transform: scale(1.18); }
.spot[aria-expanded="true"] span { color: var(--cta-ink); }
@keyframes ping { 0% { transform: scale(0.8); opacity: 1; } 70%, 100% { transform: scale(1.7); opacity: 0; } }
.parts { list-style: none; margin: 0; padding: 0; display: grid; gap: 10px; }
.part { overflow: hidden; border: var(--card-border); border-radius: var(--radius-sm); background: var(--surface); }
.part > button {
  all: unset;
  box-sizing: border-box;
  display: flex;
  align-items: center;
  gap: 14px;
  width: 100%;
  min-height: 56px;
  padding: 12px 18px;
  cursor: var(--cursor-link, pointer);
  font: var(--display-weight) 1.3rem/1.1 var(--font-display);
  text-transform: var(--display-case);
  letter-spacing: 0.03em;
}
.part > button:focus-visible { outline: 3px solid var(--accent-2); outline-offset: -3px; border-radius: var(--radius-sm); }
.part .n { flex: none; display: grid; place-items: center; width: 30px; height: 30px; border-radius: 50%; background: var(--accent); color: #fff; font-size: 0.95rem; }
.part .chev { width: 20px; height: 20px; margin-left: auto; color: var(--muted); transition: transform 200ms ease-out; }
.part > button[aria-expanded="true"] .chev { transform: rotate(180deg); }
.part > button[aria-expanded="true"] .n { background: var(--accent-2); color: var(--cta-ink); }
.part .body { display: grid; gap: 8px; padding: 0 18px 18px 62px; color: var(--muted); }
.part .body[hidden] { display: none; }
.part .body p { margin: 0; }
.part .body ul { margin: 0; padding-left: 1.1em; display: grid; gap: 4px; }
.part .body b { color: var(--ink); font-weight: 600; }
.part .body .more { justify-self: start; margin-top: 0; color: var(--ink); font: var(--label-weight) 1rem/1 var(--label-font); text-transform: var(--label-case); letter-spacing: var(--label-tracking); text-decoration-color: var(--accent); text-underline-offset: 5px; }

/* Band: one promise in a wide panel, with a small picture, its words and a link. */
.band { display: grid; grid-template-columns: auto 1fr auto; gap: 26px; align-items: center; padding: 30px; }
.band h2 { margin-bottom: 6px; font-size: 1.8rem; }
.band p { margin: 0; color: var(--muted); }
.band .link { display: inline-flex; align-items: center; min-height: 44px; color: var(--ink); font: var(--label-weight) 1.05rem/1 var(--label-font); text-transform: var(--label-case); letter-spacing: var(--label-tracking); }

/* Documents: a policy another repo owns, set in the page as it is (the "document" block): its date and opening line,
   the short version as cards in the pack's swatches, then the contents beside the text on a card. */
.document .head { display: grid; gap: 10px; justify-items: start; margin-bottom: 26px; }
.document .updated { display: inline-block; margin: 0; padding: 5px 14px; border-radius: 999px; background: var(--tag-bg); color: var(--tag-ink); font: var(--label-weight) 0.85rem/1.3 var(--label-font); }
.document .intro { max-width: 46em; margin: 0; color: var(--muted); font-size: 1.1rem; }
.document .short-title { margin: 0 0 16px; font-size: clamp(1.7rem, 4vw, 2.2rem); }
.document .short { list-style: none; margin: 0 0 clamp(36px, 5vw, 56px); padding: 0; display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 14px; counter-reset: point; }
.document .short li {
  position: relative;
  counter-increment: point;
  padding: 18px 18px 18px 64px;
  border: var(--card-border);
  border-radius: var(--radius-sm);
  background: var(--card-bg);
  box-shadow: var(--card-shadow);
  font-size: 0.98rem;
  line-height: 1.5;
}
.document .short li::before {
  content: counter(point);
  position: absolute;
  left: 16px;
  top: 16px;
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  background: var(--dot);
  color: var(--step-ink);
  text-shadow: var(--step-shadow, none);
  font: var(--display-weight) 1rem/1 var(--step-font);
  box-shadow: 0 3px 0 rgb(30 20 50 / 0.25);
}
/* The swatches in turn; a pack with three (Speedometer's) starts again at the fourth. */
.document .short li { --dot: var(--swatch-1); }
.document .short li:nth-child(6n+2) { --dot: var(--swatch-2); }
.document .short li:nth-child(6n+3) { --dot: var(--swatch-3); }
.document .short li:nth-child(6n+4) { --dot: var(--swatch-4, var(--swatch-1)); }
.document .short li:nth-child(6n+5) { --dot: var(--swatch-5, var(--swatch-2)); }
.document .short li:nth-child(6n) { --dot: var(--swatch-6, var(--swatch-3)); }
/* A point that brings its own icon and title (Speedometer's policy): the icon, in the point's swatch on a tint of it,
   takes the number's place. */
.document .short li:has(> .ico)::before { content: none; }
.document .short .ico { position: absolute; left: 16px; top: 16px; display: grid; place-items: center; width: 34px; height: 34px; border-radius: 50%; background: color-mix(in srgb, var(--dot) 16%, transparent); color: var(--dot); }
.document .short .ico svg { width: 20px; height: 20px; }
.document .short li > b { display: block; margin-bottom: 4px; color: var(--ink); font: var(--display-weight) 1.15rem/1.15 var(--font-display); text-transform: var(--display-case); letter-spacing: var(--display-tracking); }
/* A date in the pack's step digits (Speedometer's LCD). */
.document .updated .lcd { font-family: var(--step-font); }
.document .layout { display: grid; grid-template-columns: 260px minmax(0, 1fr); gap: 32px; align-items: start; }
.document .toc { position: sticky; top: 84px; padding: 18px; border: var(--card-border); border-radius: var(--radius); background: var(--card-bg); box-shadow: var(--card-shadow); }
.document .toc p { margin: 0 0 8px; font: var(--label-weight) 0.78rem/1.2 var(--label-font); letter-spacing: 0.12em; text-transform: uppercase; color: var(--muted); }
.document .toc ol { margin: 0; padding: 0; list-style: none; display: grid; gap: 2px; }
.document .toc a { display: flex; align-items: center; gap: 10px; min-height: 36px; padding: 0 10px; border-radius: 12px; color: var(--ink); font-size: 0.95rem; text-decoration: none; }
.document .toc a::before { content: ""; flex: none; width: 9px; height: 9px; border-radius: 50%; background: var(--swatch-1); }
.document .toc li:nth-child(6n+2) a::before { background: var(--swatch-2); }
.document .toc li:nth-child(6n+3) a::before { background: var(--swatch-3); }
.document .toc li:nth-child(6n+4) a::before { background: var(--swatch-4, var(--swatch-1)); }
.document .toc li:nth-child(6n+5) a::before { background: var(--swatch-5, var(--swatch-2)); }
.document .toc li:nth-child(6n) a::before { background: var(--swatch-6, var(--swatch-3)); }
.document .toc a:hover { background: var(--surface-2); }
.document .doc { padding: clamp(22px, 4vw, 44px); border: var(--card-border); border-radius: calc(var(--radius) + 6px); background: var(--card-bg); box-shadow: var(--card-shadow); }
.document .doc section + section { margin-top: 28px; padding-top: 28px; border-top: var(--foot-rule); }
.document .doc h2 { margin-bottom: 12px; font-size: clamp(1.5rem, 3vw, 1.85rem); }
.document .doc h3 { margin: 18px 0 8px; font-size: 1.25rem; }
.document .doc p { max-width: 46em; margin: 0 0 12px; }
.document .doc ul, .document .doc ol { max-width: 46em; margin: 0 0 12px; padding-left: 1.2em; display: grid; gap: 8px; }
.document .doc .delete, .document .doc .key { padding: 22px 24px; border-top: 0; border-radius: var(--radius-sm); background: color-mix(in srgb, var(--accent) 10%, var(--surface)); }
.document .doc .delete + section, .document .doc .key + section { border-top: 0; }
.document .doc .contact { display: block; padding: 18px 20px; border-radius: var(--radius-sm); background: var(--surface-2); font-style: normal; line-height: 1.6; }
@media (max-width: 860px) {
  .document .layout { grid-template-columns: 1fr; }
  .document .toc { position: static; }
}

/* The last call to action, just above the horizon and the footer. Where the footer has a picture, the card stands half
   in it (George, 22 Oct 2026: "Move half of this inside the foot"): the footer rises by half the card's height,
   --cta-half, which assets/product.js measures (an estimate without JavaScript). */
.cta-band { padding-block: var(--section-pad); }
body:has(.foot.has-art) .cta-band { position: relative; z-index: 2; padding-bottom: 0; }
.panel {
  display: grid;
  justify-items: center;
  gap: 16px;
  padding: clamp(36px, 6vw, 64px) 24px clamp(30px, 5vw, 52px);
  border-radius: calc(var(--radius) + 8px);
  background: var(--band-bg, var(--card-bg)); /* optional */
  text-align: center;
}
.panel h2 { font-size: var(--h2-size); }
.panel p { max-width: 34em; margin: 0; color: var(--muted); font-size: 1.1rem; }

/* Footer, centred and compact (George picked layout B, 22 Oct 2026): the product's logo, one row of links with quiet
   dots between them, round buttons for its stores and the studio's channels, then the legal line. Styled like the
   hero: a picture generated from the key art fills the footer, fading in from the page, and the words stand straight
   on it in the pack's footer colours (--foot-ink and --foot-muted, optional) over a soft fade of --foot-veil
   (optional). Without a picture, the footer sits under the pack's rule. */
.foot .wrap {
  display: grid;
  justify-items: center;
  gap: 16px;
  padding-block: 30px 40px;
  border-top: var(--foot-rule);
  color: var(--foot-muted, var(--muted));
  text-align: center;
}
.foot a { color: var(--foot-ink, var(--ink)); text-decoration: none; }
.foot-brand { display: inline-flex; align-items: center; gap: 12px; font: var(--display-weight) 1.7rem/1 var(--font-display); text-transform: var(--display-case); letter-spacing: var(--display-tracking); }
.foot-brand img { width: 48px; height: 48px; border-radius: 13px; box-shadow: 0 6px 16px -8px rgb(0 0 0 / 0.5); }
.foot-links { display: flex; flex-wrap: wrap; justify-content: center; align-items: center; }
.foot-links a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 0 12px;
  font: var(--label-weight) 1rem/1.2 var(--label-font);
  text-transform: var(--label-case);
  letter-spacing: var(--label-tracking);
  text-underline-offset: 5px;
}
/* The dots sit between the links, not in them, so a link's hover underline stays under its own words. */
.foot-links .sep { color: color-mix(in srgb, var(--foot-ink, var(--ink)) 35%, transparent); }
.foot-links a:hover { text-decoration: underline; }
/* On phones the row wraps, and a dot would start the next line: spacing alone separates the links there. */
@media (max-width: 560px) {
  .foot-links { gap: 0 20px; }
  .foot-links a { padding: 0; }
  .foot-links .sep { display: none; }
  .foot-brand { flex-direction: column; gap: 10px; text-align: center; }
}
.foot-icons { display: flex; flex-wrap: wrap; justify-content: center; gap: 10px; }
.foot-icons a {
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  border: 1.5px solid color-mix(in srgb, var(--foot-ink, var(--ink)) 25%, transparent);
  transition: transform 150ms ease-out, background-color 150ms ease-out;
}
.foot-icons a:hover { transform: translateY(-2px); background: color-mix(in srgb, var(--foot-ink, var(--ink)) 10%, transparent); }
.foot-icons svg { width: 22px; height: 22px; }
.foot .legal { max-width: 60em; margin: 4px 0 0; font: 500 0.85rem/1.55 var(--font-body); }
.foot .legal a { color: inherit; text-decoration: underline; text-underline-offset: 2px; }
.foot.has-art {
  position: relative;
  isolation: isolate;
  overflow-x: clip;
  margin-top: calc(-1 * var(--cta-half, 150px));
  /* About 15% lower than it was (George, 23 Oct 2026: "Decrease height by 15%"); tools/lib/partials.mjs sizes the
     picture for this. */
  padding-top: calc(var(--cta-half, 150px) + clamp(170px, 21vw, 420px));
}
.foot-art { position: absolute; inset: 0; z-index: -1; }
.foot-art picture, .foot-art img { display: block; width: 100%; height: 100%; }
.foot-art img {
  object-fit: cover;
  object-position: var(--foot-at, 50% 50%);
  -webkit-mask-image: linear-gradient(transparent calc(var(--cta-half, 150px) * 0.4), #000 calc(var(--cta-half, 150px) + 120px));
  mask-image: linear-gradient(transparent calc(var(--cta-half, 150px) * 0.4), #000 calc(var(--cta-half, 150px) + 120px));
}
.foot.has-art .wrap { position: relative; border-top: 0; }
.foot.has-art .wrap::before {
  content: "";
  position: absolute;
  inset: -110px calc(50% - 50vw) 0;
  z-index: -1;
  background: linear-gradient(transparent, var(--foot-veil, color-mix(in srgb, var(--page) 80%, transparent)) 110px);
  pointer-events: none;
}

@media (max-width: 900px) {
  .tour { grid-template-columns: 1fr; }
  .tour .stage { position: relative; top: 0; }
  .steps.n4 { grid-template-columns: repeat(2, 1fr); }
  .steps.n3, .cards.media, .cards.side { grid-template-columns: 1fr; }
  .features, .features.n4 { grid-template-columns: 1fr 1fr; }
  .cards.media .card > img { width: 60%; }
  .band { grid-template-columns: 1fr; }
}
/* Below 1300px the menu keeps only its main links (the rest are in the footer), so it stays clear of a title painted
   across the top of the key art. */
@media (max-width: 1300px) {
  .subnav .wide-only:not([aria-current]) { display: none; }
}
@media (max-width: 560px) {
  body { font-size: calc(var(--body-size) - 1px); }
  .subnav a { padding: 0 12px; }
  .product-name span { display: none; }
  .product-name img.logo { height: 32px; }
  .gp img { height: 70px; }
  .scene { margin-inline: calc(50% - 50vw + 10px); border-radius: 24px; }
  .steps.n4, .features, .features.n4 { grid-template-columns: 1fr; }
  /* The game's cards go two by two, so the steps stay one screen tall. */
  .steps.cards-game.n4 { grid-template-columns: 1fr 1fr; gap: 26px 10px; }
  .steps.cards-game li { padding: 28px 10px 16px; gap: 6px; }
  .steps.cards-game .bubble { width: 38px; height: 38px; top: -17px; font-size: 1.1rem; }
  .steps.cards-game h3 { font-size: 1.12rem; }
  .steps.cards-game p { font-size: 0.86rem; line-height: 1.35; }
  .cards.side .card { grid-template-columns: 1fr; }
  .cards.side .card > img { width: 62%; margin-inline: auto; }
  .part .body { padding-left: 18px; }
}
/* The menu on phones (George, 23 Oct 2026: "At mobile the vgraphics.gr toolbar does not fit. It must be a burger
   menu."): below 561px, where the menu no longer fits beside the logo (Exitwise's needs about 390px for its three main
   links, 480 on its map rules page, so it broke onto a second row), it folds into a button at the right
   (tools/lib/partials.mjs) that opens it as a panel under the header (assets/menu.js): every link, the wide-only ones
   too, in the product's page colour and label face, the current page in the look its bar gives it once scrolled.
   Without JavaScript the row stays. */
.menu-toggle { display: none; }
@media (max-width: 560px) and (scripting: enabled) {
  .menu-toggle {
    display: inline-flex; align-items: center; justify-content: center; flex: none;
    width: 44px; height: 44px; margin-right: -10px; padding: 0; border: 0; border-radius: 50%;
    background: transparent; color: var(--on-art); filter: drop-shadow(var(--on-art-shadow)); cursor: var(--cursor-link, pointer);
    transition: color 200ms ease-out, background-color 200ms ease-out;
  }
  .top.scrolled .menu-toggle, .top.menu-open .menu-toggle { color: var(--ink); filter: none; }
  .menu-toggle:hover { background: color-mix(in srgb, var(--ink) 8%, transparent); }
  /* Three bars, which turn into a cross while the panel is open */
  .menu-toggle .bars { position: relative; }
  .menu-toggle .bars, .menu-toggle .bars::before, .menu-toggle .bars::after {
    display: block; width: 20px; height: 2px; border-radius: 2px; background: currentColor;
    transition: transform 180ms ease-out, background-color 180ms ease-out;
  }
  .menu-toggle .bars::before, .menu-toggle .bars::after { content: ""; position: absolute; left: 0; }
  .menu-toggle .bars::before { top: -6px; }
  .menu-toggle .bars::after { top: 6px; }
  .menu-open .menu-toggle .bars { background: transparent; }
  .menu-open .menu-toggle .bars::before { transform: translateY(6px) rotate(45deg); }
  .menu-open .menu-toggle .bars::after { transform: translateY(-6px) rotate(-45deg); }

  /* While it is open the header is a solid bar in the page's colour, the panel its continuation */
  .top.menu-open { background-color: var(--page); }
  .top.menu-open a { color: var(--ink); text-shadow: none; }
  .subnav {
    position: absolute; top: 100%; left: 0; right: 0; z-index: 1;
    display: grid; gap: 4px; max-height: calc(100dvh - 100%); overflow-y: auto; overscroll-behavior: contain;
    padding: 8px 16px 20px; background: var(--page); border-bottom: 1px solid var(--line);
    border-radius: 0 0 var(--radius) var(--radius); box-shadow: 0 18px 36px -24px rgb(0 0 0 / 0.55);
    visibility: hidden; opacity: 0; transform: translateY(-8px);
    transition: opacity 140ms ease-in, transform 140ms ease-in, visibility 0s linear 140ms;
  }
  .menu-open .subnav {
    visibility: visible; opacity: 1; transform: none;
    transition: opacity 200ms ease-out, transform 200ms ease-out;
  }
  /* Taller than a short screen, the panel scrolls (D:\Projects\Mine\CLAUDE.md, "Long lists scroll in their own box"):
     its bottom edge fades into the panel while more lies below. fade-edges.js keeps --fade-end current; the fade is
     drawn here in the panel's colour (--fade-mode: overlay), since a mask would fade the panel's own background too.
     It sticks to the visible bottom, over the padding, and takes no room (its row's gap aside). */
  .subnav { --fade-mode: overlay; }
  .subnav::after {
    content: ""; position: sticky; bottom: 0; z-index: 1; pointer-events: none;
    height: var(--fade-end, 0px); margin-top: calc(-4px - var(--fade-end, 0px));
    background: linear-gradient(transparent, var(--page));
  }
  @supports not selector(::-webkit-scrollbar) {
    .subnav { scrollbar-width: thin; scrollbar-color: var(--sb) transparent; }
  }
  .top .subnav a { min-height: 52px; padding: 0 16px; font-size: 1.15rem; border-radius: var(--radius-sm); color: var(--ink); text-shadow: none; }
  .top .subnav a.wide-only { display: inline-flex; }
  .top .subnav a:hover { background: color-mix(in srgb, var(--ink) 8%, transparent); }
  .top .subnav a[aria-current="page"] {
    background: var(--nav-current-bg-scrolled, var(--nav-current-bg));
    color: var(--nav-current-ink-scrolled, var(--nav-current-ink));
    border-radius: var(--nav-current-radius, var(--radius-sm)); /* optional */
  }
  /* The page under the panel, dimmed; a tap on it closes the panel */
  .top.menu-open::after {
    content: ""; position: absolute; top: 100%; left: 0; right: 0; height: 100dvh;
    background: rgb(8 6 14 / 0.55);
    animation: menu-dim 200ms ease-out;
  }
}
@keyframes menu-dim { from { opacity: 0; } }
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation: none !important; transition: none !important; }
}
