/* Shotcraft
   ---------
   Dark first. One variable family. Colour is a colour-temperature axis rather than a
   neutral plus an accent: tungsten 3200K for the human crafts, daylight 5600K for the
   machines. That mapping tells a reader which of the site's two subjects they are looking
   at before they read a word, which is why there is no third accent.

   The signature is the frame — a marked rectangle with corner crop marks, borrowed from a
   director's viewfinder. It appears where a page earns it, and its fullest expression is
   the safe-zone overlay, which is the best dataset on the site.

   Every value lives in :root. Nothing below :root hardcodes a colour or a duration. */

:root {
  --film-button-padding: .65rem 1rem;
  --film-focus: 2px;
  --film-inset: clamp(.5rem, 1.4vw, 1rem);
  --film-nav-gap: .25rem;
  --film-nav-padding: .3rem;
  --film-nav-radius: .9rem;
  --film-nav-surface: rgba(11, 12, 14, .92);
  --film-nav-shadow: 0 8px 24px rgba(0, 0, 0, .25);
  --film-nav-font: clamp(.75rem, 1vw, .875rem);
  --film-height: 52svh;
  --film-blur: 16px;
  /* Surfaces. Near-black and slightly cool, a darkened stage rather than pure black. */
  --black: #0b0c0e;
  --surface: #14161a;
  --surface-2: #1d2126;
  --surface-3: #262b32;

  /* Film white, not screen white. Pure #fff on near-black glares and reads cheap. */
  --paper: #f2efe9;
  --text: #e7e3db;
  --text-mid: #a7a29a;
  /* Raised from #7b766e, which measured 4.34:1 on --black, 4.02 on --surface and 3.59 on
     --surface-2 — all below the 4.5:1 WCAG AA threshold for body text, and it is the colour
     used by .meta, .row__meta, .unset, .tbl th, .keyfacts dt, .tile__foot and the search
     placeholder. #908a81 measures 5.72 / 5.29 / 4.73 and keeps the warm grey. It still misses 4.5:1
     on --surface-3 (4.16) — nothing puts dim text there today, and nothing should. */
  --text-dim: #908a81;

  /* Hairlines. Used sparingly; space does most of the separating. */
  --hair: rgba(242, 239, 233, 0.08);
  --hair-mid: rgba(242, 239, 233, 0.14);
  --hair-strong: rgba(242, 239, 233, 0.24);

  /* Form controls need a boundary a person can actually see, which a decorative hairline is
     not: --hair-mid composited over --surface is 1.46:1 against the field interior and 1.57:1
     against the page, both far below the 3:1 that 1.4.11 requires of a control's edge. The
     interior fill alone is 1.08:1 against the page, so without this the search field and the
     platform picker have no perceivable edge on either side. 3.38:1 on --surface, 3.65:1 on
     --black, same warm family as the text greys. */
  --control-edge: #6f6a63;

  /* The temperature axis. */
  --tungsten: #e8a33d;
  --tungsten-mid: #f0be76;
  --tungsten-wash: rgba(232, 163, 61, 0.12);
  --daylight: #7fa8d9;
  --daylight-mid: #a3c2e6;
  --daylight-wash: rgba(127, 168, 217, 0.12);

  /* --accent is re-pointed per section. Components only ever read --accent. */
  --accent: var(--daylight);
  --accent-mid: var(--daylight-mid);
  --accent-wash: var(--daylight-wash);

  /* One family, four registers, differing by variable axis rather than by weight alone. */
  --family: "Fraunces", "Iowan Old Style", "Palatino Linotype", Georgia, serif;
  --ax-display: "opsz" 144, "wght" 400, "SOFT" 0, "WONK" 1;
  --ax-heading: "opsz" 72, "wght" 500, "SOFT" 20, "WONK" 1;
  --ax-body: "opsz" 14, "wght" 400, "SOFT" 0, "WONK" 0;
  --ax-meta: "opsz" 14, "wght" 500, "SOFT" 0, "WONK" 0;

  --wrap: 1160px;
  --read: 40rem; /* long-form measure, roughly 70 characters at body size */
  --r: 4px;
  --r-lg: 8px;

  /* Motion: slow and confident. 300-500ms, ease-out, small distances. */
  --dur: 380ms;
  --dur-fast: 200ms;
  --ease: cubic-bezier(0.16, 0.84, 0.44, 1);

  /* Entry pages: readable prompt examples and clear routes. */
  --entry-space: clamp(2rem, 5vw, 4rem);
  --entry-band: clamp(3rem, 7vw, 6rem);
  --entry-title: clamp(2.9rem, 5.2vw, 4.5rem);
  --entry-example-title: clamp(1.35rem, 2vw, 1.65rem);
  --entry-small: 0.9375rem;
  --entry-body: 1.0625rem;
  --entry-control-height: 2.75rem;
  --entry-third: 18rem;
  --entry-half: 24rem;
  --gap: 1.5rem;
  --band: clamp(4rem, 9vw, 8rem); /* vertical rhythm between major sections */
}

/* Required. A display:grid class beats the user agent [hidden] rule on specificity, and
   without this both a filtered-out card and its replacement render at once. */
[hidden] {
  display: none !important;
}

*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  /* The sticky header is about 65px and 88% opaque with a blur, so anything scrolled flush to
     y=0 lands underneath it and cannot be read — including wherever the skip link sends you.
     WCAG 2.2 added 2.4.11 for exactly this. */
  scroll-padding-top: 5rem;
}

body {
  margin: 0;
  background: var(--black);
  color: var(--text);
  font-family: var(--family);
  font-variation-settings: var(--ax-body);
  font-size: 1.125rem;
  line-height: 1.62;
  font-optical-sizing: auto;
  text-rendering: optimizeLegibility;
}

/* ---------- structure ---------- */

.wrap {
  width: 100%;
  max-width: var(--wrap);
  margin-inline: auto;
  padding-inline: clamp(1.25rem, 5vw, 3rem);
}

.read {
  max-width: var(--read);
}

section {
  margin-block: var(--band);
}

/* Reset first-child heading margins only inside real panels. Including `section` in this
   selector zeroes nearly every heading on the site; that regressed twice on MCPHunt. */
.panel > :first-child,
.tile > :first-child,
.callout > :first-child,
.figure > :first-child {
  margin-top: 0;
}

.skip {
  position: absolute;
  left: -9999px;
  top: 0;
  background: var(--surface-2);
  color: var(--paper);
  padding: 0.75rem 1.25rem;
  z-index: 100;
}
.skip:focus {
  left: 1rem;
  top: 1rem;
}

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

h1,
h2,
h3,
h4 {
  font-variation-settings: var(--ax-heading);
  line-height: 1.14;
  letter-spacing: -0.012em;
  color: var(--paper);
  text-wrap: balance;
}

h1 {
  font-variation-settings: var(--ax-display);
  font-size: clamp(2.9rem, 6.4vw, 5.6rem);
  line-height: 1.02;
  letter-spacing: -0.028em;
  margin: 0 0 1.25rem;
}

h2 {
  font-size: clamp(1.75rem, 3vw, 2.5rem);
  margin: 0 0 1rem;
}

h3 {
  font-size: 1.3rem;
  margin: 2.25rem 0 0.6rem;
}

h4 {
  font-size: 1.075rem;
  margin: 1.75rem 0 0.4rem;
}

p {
  margin: 0 0 1.15rem;
}

.lede {
  font-size: clamp(1.25rem, 2vw, 1.5rem);
  line-height: 1.45;
  color: var(--paper);
  font-variation-settings: "opsz" 48, "wght" 400, "SOFT" 10, "WONK" 0;
  max-width: 34ch;
}

.lede--wide {
  max-width: 46ch;
}

.eyebrow {
  font-variation-settings: var(--ax-meta);
  font-size: 0.8125rem;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--accent);
  margin: 0 0 1.1rem;
  display: block;
}

.meta {
  font-variation-settings: var(--ax-meta);
  font-size: 0.875rem;
  color: var(--text-dim);
  letter-spacing: 0.01em;
}

.dim {
  color: var(--text-mid);
}

a {
  color: var(--accent-mid);
  text-decoration-color: color-mix(in srgb, var(--accent) 45%, transparent);
  text-decoration-thickness: 1px;
  text-underline-offset: 0.22em;
  transition: color var(--dur-fast) var(--ease),
    text-decoration-color var(--dur-fast) var(--ease);
}
a:hover {
  color: var(--paper);
  text-decoration-color: var(--accent);
}

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
  /* No border-radius here. It applied to the focused *element*, snapping a pill-shaped .chip or
     .btn to a near-square on focus. The outline already follows the element's own radius. */
}

/* ---------- temperature: the two halves of the site ---------- */

.warm {
  --accent: var(--tungsten);
  --accent-mid: var(--tungsten-mid);
  --accent-wash: var(--tungsten-wash);
}

.cool {
  --accent: var(--daylight);
  --accent-mid: var(--daylight-mid);
  --accent-wash: var(--daylight-wash);
}

/* ---------- the frame: the signature element ---------- */

/* Corner crop marks drawn as eight one-pixel gradients, so the marks stay crisp at any
   size and nothing is nested inside the frame to draw them. */
.frame {
  position: relative;
  padding: clamp(1.5rem, 4vw, 3rem);
  background-image: linear-gradient(var(--accent), var(--accent)),
    linear-gradient(var(--accent), var(--accent)),
    linear-gradient(var(--accent), var(--accent)),
    linear-gradient(var(--accent), var(--accent)),
    linear-gradient(var(--accent), var(--accent)),
    linear-gradient(var(--accent), var(--accent)),
    linear-gradient(var(--accent), var(--accent)),
    linear-gradient(var(--accent), var(--accent));
  background-size: 22px 1px, 1px 22px, 22px 1px, 1px 22px, 22px 1px, 1px 22px, 22px 1px,
    1px 22px;
  background-position: left top, left top, right top, right top, left bottom, left bottom,
    right bottom, right bottom;
  background-repeat: no-repeat;
}

.frame--quiet {
  --accent: var(--hair-strong);
}

/* ---------- header and footer ---------- */

.site-head {
  position: sticky;
  top: 0;
  z-index: 40;
  background: color-mix(in srgb, var(--black) 88%, transparent);
  backdrop-filter: saturate(140%) blur(14px);
  border-bottom: 1px solid var(--hair);
}

.site-head__in {
  display: flex;
  align-items: baseline;
  gap: clamp(1rem, 3vw, 2.5rem);
  padding-block: 1.05rem;
}

.brand {
  font-variation-settings: "opsz" 72, "wght" 600, "SOFT" 0, "WONK" 1;
  font-size: 1.3rem;
  color: var(--paper);
  text-decoration: none;
  letter-spacing: -0.02em;
  flex: none;
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  line-height: 1;
}
.brand:hover {
  color: var(--paper);
}

/* The mark carries the temperature gradient itself, so it needs no colour here. The lift on
   hover is the only motion in the header. */
.brand__mark {
  display: block;
  width: 30px;
  height: 30px;
  transition: transform var(--dur) var(--ease);
}
.brand:hover .brand__mark {
  transform: rotate(-30deg);
}
.brand--foot {
  font-size: 1.15rem;
}

.nav {
  display: flex;
  gap: clamp(0.85rem, 2vw, 1.75rem);
  flex-wrap: wrap;
  margin-left: auto;
}

.nav a {
  font-variation-settings: var(--ax-meta);
  font-size: 0.9375rem;
  color: var(--text-mid);
  text-decoration: none;
}
.nav a:hover,
.nav a[aria-current="page"] {
  color: var(--paper);
}

.site-foot {
  margin-top: var(--band);
  border-top: 1px solid var(--hair);
  padding-block: 3rem 4rem;
  color: var(--text-dim);
  font-size: 0.9375rem;
}

.site-foot a {
  color: var(--text-mid);
}

.foot-cols {
  display: grid;
  gap: 2rem;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
}

.foot-cols h2 {
  font-size: 0.8125rem;
  font-variation-settings: var(--ax-meta);
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--text-mid);
  margin-bottom: 0.75rem;
}

.foot-cols ul {
  list-style: none;
  margin: 0;
  padding: 0;
}
.foot-cols li {
  margin-bottom: 0.35rem;
}

/* ---------- hero ---------- */

.hero {
  padding-block: clamp(4rem, 11vh, 9rem) clamp(3rem, 7vh, 6rem);
}

.hero h1 {
  max-width: 22ch;
}

.hero__sub {
  max-width: 44ch;
  color: var(--text-mid);
  font-size: clamp(1.125rem, 1.6vw, 1.3rem);
}

/* Page-load reveal. Small distance, slow ease, and removed entirely under reduced motion. */
.rise {
  animation: rise var(--dur) var(--ease) both;
}
.rise-2 {
  animation-delay: 90ms;
}
.rise-3 {
  animation-delay: 180ms;
}

@keyframes rise {
  from {
    opacity: 0;
    transform: translateY(14px);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

/* ---------- listings ---------- */

.tiles {
  display: grid;
  gap: 1px;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 21rem), 1fr));
  background: var(--hair);
  border-block: 1px solid var(--hair);
}

.tile {
  background: var(--black);
  padding: 1.6rem clamp(1rem, 2vw, 1.6rem) 1.75rem;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  text-decoration: none;
  color: inherit;
  transition: background var(--dur) var(--ease);
}

a.tile:hover {
  background: var(--surface);
  color: inherit;
}

.tile__name {
  font-variation-settings: var(--ax-heading);
  font-size: 1.2rem;
  color: var(--paper);
  line-height: 1.2;
  margin: 0;
}

a.tile:hover .tile__name {
  color: var(--accent-mid);
}

.tile__desc {
  color: var(--text-mid);
  font-size: 0.9375rem;
  line-height: 1.5;
  margin: 0;
}

.tile__foot {
  margin-top: auto;
  padding-top: 0.9rem;
  font-variation-settings: var(--ax-meta);
  font-size: 0.8125rem;
  color: var(--text-dim);
  letter-spacing: 0.02em;
}

/* A quieter list for long inventories, where a tile grid would be exhausting. */
.rows {
  list-style: none;
  margin: 0;
  padding: 0;
  /* The row layout depends on how much room the list actually has, not on the viewport: the
     same component is used full width and inside the three narrow columns on /learn/. */
  container-type: inline-size;
}

/* Stacked by default. The two-column form only appears when there is room for it.

   This was a real overlap bug: the grid was `minmax(0,1fr) auto` with a `nowrap` meta column,
   so inside a ~340px column on /learn/ a role name that wrapped to two lines collided with its
   own alias list — "Matte Painter" and "Second Assistant Camera" were printed through by the
   text beside them. Nothing clipped it because nowrap made the meta wider than its track. */
.row {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 0.2rem;
  padding: 1.05rem 0;
  border-bottom: 1px solid var(--hair);
}

.row__name {
  font-variation-settings: "opsz" 32, "wght" 500, "SOFT" 0, "WONK" 0;
  font-size: 1.0625rem;
  color: var(--paper);
  text-decoration: none;
}
.row__name:hover {
  color: var(--accent-mid);
}

.row__desc {
  grid-column: 1 / -1;
  color: var(--text-mid);
  font-size: 0.9375rem;
  margin: 0;
  max-width: 68ch;
}

.row__meta {
  font-variation-settings: var(--ax-meta);
  font-size: 0.8125rem;
  color: var(--text-dim);
  /* Never nowrap. An alias list can be longer than the name it belongs to, and a track that
     refuses to wrap simply overflows into its neighbour. */
  white-space: normal;
  overflow-wrap: anywhere;
}

.row__name {
  overflow-wrap: anywhere;
}

/* Side by side only once the list is wide enough for two tracks. The meta column is capped so
   a long alias list narrows itself rather than squeezing the name. */
@container (min-width: 34rem) {
  .row {
    /* min-content, not 0. A track with a 0 minimum can be sized below its item, and the item's
       own min-width:auto then makes it overflow rightward across the next track instead of
       shrinking — which is what painted names over their own alias lists. */
    grid-template-columns: minmax(min-content, 1fr) minmax(0, 38%);
    gap: 0.35rem 1.5rem;
    align-items: baseline;
  }

  .row__meta {
    text-align: right;
  }
}

/* Containers are widely supported, but if they are not the stacked form is the fallback and
   nothing overlaps — the degradation is a slightly taller list, not a broken one. */

/* ---------- specs, without a boxed-in table ---------- */

.specs {
  margin: 0;
  display: grid;
  /* Was minmax(9rem, 14rem). A 9rem floor is 144px, which inside a narrow panel left about
     108px for the value and wrapped every value one word per line. */
  grid-template-columns: minmax(7rem, 12rem) minmax(0, 1fr);
  gap: 0;
}

.specs dt {
  font-variation-settings: var(--ax-meta);
  font-size: 0.8125rem;
  letter-spacing: 0.11em;
  text-transform: uppercase;
  color: var(--text-dim);
  padding: 0.95rem 1.5rem 0.95rem 0;
  border-top: 1px solid var(--hair);
}

.specs dd {
  margin: 0;
  padding: 0.95rem 0;
  border-top: 1px solid var(--hair);
  color: var(--text);
  /* A grid item keeps its min-content width unless told otherwise, so without these a long
     value pushes out past its track and out of the card. */
  min-width: 0;
  overflow-wrap: anywhere;
}

.specs dt {
  min-width: 0;
  overflow-wrap: anywhere;
}

/* Stack when the *container* is narrow, not when the viewport is.
   The direction matters: this is a max-width query, so where no query container exists — a
   spec list sitting directly in .wrap on a model page — it simply never matches and the
   two-column form is kept. A min-width query would have stacked those instead. */
@container (max-width: 30rem) {
  .specs {
    grid-template-columns: 1fr;
  }

  .specs dt {
    padding: 0.8rem 0 0;
    border-bottom: 0;
  }

  .specs dd {
    border-top: 0;
    padding: 0.1rem 0 0.15rem;
  }
}

.specs dd:last-of-type,
.specs dt:last-of-type {
  border-bottom: 1px solid var(--hair);
}

@media (max-width: 34rem) {
  .specs {
    grid-template-columns: 1fr;
  }

  .specs dt {
    padding-bottom: 0;
    border-bottom: 0;
  }

  .specs dd {
    border-top: 0;
    padding-top: 0.2rem;
  }
}

/* "not established" is a real value on this site, and it must never look like an omission
   or an error. It looks like a deliberate, quiet statement of fact. */
.unset {
  color: var(--text-dim);
  font-variation-settings: var(--ax-meta);
  font-size: 0.9375rem;
  letter-spacing: 0.02em;
}

/* ---------- callouts ---------- */

.callout {
  border-left: 2px solid var(--accent);
  background: var(--accent-wash);
  padding: 1.15rem 1.35rem;
  margin: 1.75rem 0;
  border-radius: 0 var(--r) var(--r) 0;
  font-size: 1rem;
}

.callout p:last-child {
  margin-bottom: 0;
}

.callout__label {
  display: block;
  font-variation-settings: var(--ax-meta);
  font-size: 0.75rem;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--accent);
  margin-bottom: 0.4rem;
}

.callout--warn {
  --accent: var(--tungsten);
  --accent-wash: var(--tungsten-wash);
}

.callout--quiet {
  /* The label used to inherit --accent, which was set to --hair-strong here: composited over
     --surface that is rgb(73,74,76), a contrast ratio of 2.04:1. The "MODEL-BOUND" label was
     effectively invisible. The rule stays quiet; the label does not. */
  --accent: var(--text-mid);
  --accent-wash: transparent;
  background: var(--surface);
  color: var(--text-mid);
  border-left-color: var(--hair-strong);
}

/* ---------- lists in prose ---------- */

.stack {
  list-style: none;
  padding: 0;
  margin: 0 0 1.5rem;
}

.stack > li {
  padding: 0.7rem 0 0.7rem 1.6rem;
  position: relative;
  border-bottom: 1px solid var(--hair);
}

.stack > li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 1.35rem;
  width: 8px;
  height: 1px;
  background: var(--accent);
}

.stack--plain > li {
  border-bottom: 0;
  padding-block: 0.3rem;
}

.terms {
  margin: 0;
}
.terms dt {
  font-variation-settings: "opsz" 32, "wght" 600, "SOFT" 0, "WONK" 0;
  color: var(--paper);
  margin-top: 1.4rem;
}
.terms dd {
  margin: 0.3rem 0 0;
  color: var(--text-mid);
}

/* ---------- sources ---------- */

.sources {
  list-style: none;
  padding: 0;
  margin: 0;
  font-size: 0.9375rem;
  columns: 2;
  column-gap: 2.5rem;
}

.sources li {
  margin-bottom: 0.5rem;
  break-inside: avoid;
}

.sources a {
  color: var(--text-mid);
  word-break: break-word;
}

@media (max-width: 40rem) {
  .sources {
    columns: 1;
  }
}

/* ---------- filters ---------- */

.filters {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-bottom: 2rem;
}

.chip {
  font-family: inherit;
  font-variation-settings: var(--ax-meta);
  font-size: 0.875rem;
  color: var(--text-mid);
  background: transparent;
  border: 1px solid var(--control-edge);
  border-radius: 100px;
  padding: 0.45rem 1rem;
  cursor: pointer;
  transition: color var(--dur-fast) var(--ease),
    border-color var(--dur-fast) var(--ease), background var(--dur-fast) var(--ease);
}

.chip:hover {
  color: var(--paper);
  border-color: var(--hair-strong);
}

.chip[aria-pressed="true"] {
  color: var(--black);
  background: var(--accent);
  border-color: var(--accent);
}

.search {
  font-family: inherit;
  font-variation-settings: var(--ax-body);
  font-size: 1rem;
  width: 100%;
  max-width: 26rem;
  padding: 0.7rem 1rem;
  color: var(--paper);
  background: var(--surface);
  border: 1px solid var(--control-edge);
  border-radius: var(--r);
  margin-bottom: 1.25rem;
}

.search::placeholder {
  color: var(--text-dim);
}

.count {
  font-variation-settings: var(--ax-meta);
  font-size: 0.875rem;
  color: var(--text-dim);
  margin-bottom: 1rem;
}

/* A row of pill links used as in-page jump navigation. This had no rule at all, so the pills
   were inline anchors: vertical padding did not contribute to the line box and wrapped rows
   overlapped each other, and .chip never reset the link underline. */
.chips {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-bottom: 2rem;
}

a.chip {
  text-decoration: none;
}

/* ---------- the safe-zone overlay ---------- */

.sz {
  display: grid;
  grid-template-columns: minmax(0, 320px) minmax(0, 1fr);
  gap: clamp(1.5rem, 4vw, 3.5rem);
  align-items: start;
}

@media (max-width: 54rem) {
  .sz {
    grid-template-columns: 1fr;
  }
}

/* The phone frame is 9:16 and its overlay bands are percentages of it, so the whole tool
   scales with the container and the numbers stay honest at any size. */
.sz__stage {
  position: relative;
  width: 100%;
  max-width: 320px;
  aspect-ratio: 9 / 16;
  margin-inline: auto;
  background: linear-gradient(
    170deg,
    var(--surface-3),
    var(--surface) 45%,
    var(--surface-2)
  );
  border-radius: 14px;
  overflow: hidden;
  box-shadow: 0 0 0 1px var(--hair-mid), 0 30px 60px -25px rgba(0, 0, 0, 0.9);
}

.sz__band {
  position: absolute;
  background: rgba(232, 163, 61, 0.17);
  /* The fill alone measured 1.39:1 against the stage. Raising its alpha to reach 3:1 would need
     about 0.72 and would obliterate the phone underneath, so the edge carries the contrast
     instead: --tungsten is 6.61-7.50:1 across the stage gradient. */
  border: 1px solid var(--tungsten);
  transition: all var(--dur) var(--ease);
}

.sz__band--top {
  top: 0;
  left: 0;
  right: 0;
}
.sz__band--bottom {
  bottom: 0;
  left: 0;
  right: 0;
}
.sz__band--left {
  top: 0;
  bottom: 0;
  left: 0;
}
.sz__band--right {
  top: 0;
  bottom: 0;
  right: 0;
}

.sz__safe {
  position: absolute;
  border: 1px dashed var(--daylight);
  background: rgba(127, 168, 217, 0.07);
  transition: all var(--dur) var(--ease);
}

/* The centre line, and the fact that the safe box is not centred on it, is the single most
   useful thing this tool shows. */
.sz__centre {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 50%;
  width: 1px;
  /* Was --hair-strong at 2.06:1. This is the true centre of the frame, which is the single most
     useful thing the tool shows, so it is not decoration. 5.20:1 composited. */
  background: repeating-linear-gradient(
    to bottom,
    rgba(242, 239, 233, 0.55) 0 6px,
    transparent 6px 12px
  );
}

.sz__label {
  position: absolute;
  font-variation-settings: var(--ax-meta);
  font-size: 0.6875rem;
  letter-spacing: 0.08em;
  color: var(--paper);
  background: rgba(11, 12, 14, 0.72);
  padding: 0.1rem 0.35rem;
  border-radius: 2px;
  pointer-events: none;
}

.sz__readout {
  font-variation-settings: var(--ax-meta);
  font-size: 0.9375rem;
}

.sz__readout dt {
  color: var(--text-dim);
  font-size: 0.75rem;
  letter-spacing: 0.11em;
  text-transform: uppercase;
  margin-top: 1rem;
}

.sz__readout dd {
  margin: 0.15rem 0 0;
  color: var(--paper);
  font-size: 1.05rem;
}

.conf {
  font-variation-settings: var(--ax-meta);
  font-size: 0.75rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-dim);
}

.conf--official {
  color: var(--daylight);
}
.conf--measured,
.conf--official-template-measured {
  color: var(--tungsten);
}
.conf--disputed {
  color: var(--tungsten);
}

select.picker {
  font-family: inherit;
  font-variation-settings: var(--ax-meta);
  font-size: 1rem;
  width: 100%;
  padding: 0.7rem 0.9rem;
  color: var(--paper);
  background: var(--surface);
  border: 1px solid var(--control-edge);
  border-radius: var(--r);
  margin-bottom: 1.5rem;
}

/* ---------- misc ---------- */

.grid-2 {
  display: grid;
  gap: clamp(1.5rem, 4vw, 3rem);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 18rem), 1fr));
}

.panel {
  background: var(--surface);
  border-radius: var(--r-lg);
  padding: clamp(1.25rem, 3vw, 2rem);
  /* A panel in a three-column grid is about 276px wide inside its padding, which is narrower
     than plenty of full-width components assume. Making it a query container lets those
     components respond to the panel rather than to the viewport. */
  container-type: inline-size;
}

.crumbs {
  font-variation-settings: var(--ax-meta);
  font-size: 0.875rem;
  color: var(--text-dim);
  padding-top: 2rem;
}

.crumbs a {
  color: var(--text-mid);
  text-decoration: none;
}
.crumbs a:hover {
  color: var(--paper);
}

.pills {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem 0.5rem;
  list-style: none;
  margin: 0 0 1.5rem;
  padding: 0;
}

.pills li {
  font-variation-settings: var(--ax-meta);
  font-size: 0.8125rem;
  color: var(--text-mid);
  border: 1px solid var(--hair-mid);
  border-radius: 100px;
  padding: 0.25rem 0.7rem;
}

.big {
  font-variation-settings: var(--ax-display);
  font-size: clamp(2.5rem, 5vw, 4rem);
  line-height: 1;
  color: var(--paper);
  display: block;
  letter-spacing: -0.03em;
}

hr {
  border: 0;
  border-top: 1px solid var(--hair);
  margin-block: var(--band);
}

/* ---------- structured prose ---------- */

/* A numbered sequence where the number carries meaning: these are the shapes a prompt takes,
   and there are two of them, so the count is information rather than decoration. */
.numbered {
  list-style: none;
  counter-reset: step;
  margin: 1.5rem 0;
  padding: 0;
}

.numbered > li {
  counter-increment: step;
  position: relative;
  padding: 0 0 1.5rem 3.25rem;
}

.numbered > li::before {
  content: counter(step);
  position: absolute;
  left: 0;
  top: 0.05em;
  width: 2.15rem;
  height: 2.15rem;
  display: grid;
  place-items: center;
  border-radius: 50%;
  border: 1px solid var(--accent);
  color: var(--accent);
  font-variation-settings: var(--ax-meta);
  font-size: 0.9375rem;
}

.numbered h3,
.numbered h4,
.numbered h5,
.numbered h6 {
  margin: 0.15rem 0 0.5rem;
  font-size: 1.0625rem;
  color: var(--paper);
}

.numbered p:last-child {
  margin-bottom: 0;
}

/* Tables with no box. One hairline per row, and space doing the rest, per §4. */
.tbl {
  width: 100%;
  border-collapse: collapse;
  margin: 1.25rem 0 1.75rem;
  font-size: 0.9375rem;
  text-align: left;
}

.tbl th {
  font-variation-settings: var(--ax-meta);
  font-size: 0.75rem;
  letter-spacing: 0.11em;
  text-transform: uppercase;
  color: var(--text-dim);
  font-weight: 400;
  padding: 0 1.25rem 0.6rem 0;
  border-bottom: 1px solid var(--hair-mid);
}

.tbl td {
  padding: 0.7rem 1.25rem 0.7rem 0;
  border-bottom: 1px solid var(--hair);
  vertical-align: top;
  color: var(--text);
}

.tbl td:first-child {
  color: var(--paper);
  /* Not nowrap. The safe-zone table's first column holds names like "Snapchat (Spotlight,
     Stories, Commercials - one shared spec)", and refusing to wrap them pushed the table wider
     than its container and put the whole page into horizontal scroll — a 1.4.10 reflow failure
     rather than a cosmetic one. */
  white-space: normal;
  min-width: 0;
}

/* ---------- download call to action ---------- */

.dl {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 1rem 1.25rem;
  margin: 1.75rem 0;
  padding: 1.15rem 1.35rem;
  background: var(--surface);
  border-radius: var(--r-lg);
  border-left: 2px solid var(--accent);
}

.dl__text {
  flex: 1 1 16rem;
  margin: 0;
  font-size: 0.9375rem;
  color: var(--text-mid);
}

.dl__text strong {
  display: block;
  color: var(--paper);
  font-variation-settings: "opsz" 32, "wght" 600, "SOFT" 0, "WONK" 0;
  margin-bottom: 0.2rem;
}

.btn {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  font-variation-settings: var(--ax-meta);
  font-size: 0.9375rem;
  color: var(--black);
  background: var(--accent);
  border: 1px solid var(--accent);
  border-radius: 100px;
  padding: 0.55rem 1.15rem;
  text-decoration: none;
  white-space: nowrap;
  transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}

.btn:hover {
  background: transparent;
  color: var(--accent);
}

.btn--ghost {
  background: transparent;
  color: var(--accent);
}

.btn--ghost:hover {
  background: var(--accent);
  color: var(--black);
}

/* ---------- footer legal ---------- */

/* Long-form legal copy in four columns at desk width, so it is present and readable without
   dominating the page. It is set smaller than body copy but not smaller than 14px. */
.foot-legal {
  margin-top: 3.5rem;
  padding-top: 2.5rem;
  border-top: 1px solid var(--hair);
  display: grid;
  gap: 2rem clamp(1.5rem, 3vw, 3rem);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 17rem), 1fr));
  font-size: 0.875rem;
  line-height: 1.55;
}

.foot-legal h2 {
  font-size: 0.75rem;
  font-variation-settings: var(--ax-meta);
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--text-mid);
  margin: 0 0 0.6rem;
}

.foot-legal p {
  margin: 0 0 0.75rem;
  color: var(--text-dim);
}

.foot-legal p:last-child {
  margin-bottom: 0;
}

/* Not monospace: §4 rules out monospace as decoration, and an obfuscated address does not
   need to look like code to be uncopyable by a scraper. */
.contact {
  color: var(--text-mid);
  /* Allowed to wrap: at 320px the obfuscated address is close to the full line width, and it
     is more useful broken over two lines than pushing the footer sideways. */
  overflow-wrap: anywhere;
}

.foot-tail {
  margin-top: 2.5rem;
  max-width: 62ch;
}

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }
  *,
  *::before,
  *::after {
    animation: none !important;
    transition: none !important;
  }
  .rise {
    opacity: 1;
    transform: none;
  }
}

/* ---------- freshness and info tooltips ----------
   Time sensitive facts collected from a vendor site are marked with a clock, not with a
   paragraph. The text stays in the DOM so screen readers and crawlers still get it, and is
   revealed on hover and on keyboard focus. Never put a fact only a sighted mouse user can
   reach in here: this carries provenance and caveats, never the value itself. */

.tt {
  position: relative;
  display: inline-flex;
  align-items: center;
  vertical-align: middle;
  margin-left: 0.35em;
  line-height: 0;
}

/* The trigger is a real button now. 24px square minimum for 2.5.8 Target Size, with the icon
   centred inside it: the old span measured 13.3px, and the touch-only escape hatch only reached
   21.3px. */
.tt__btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 24px;
  min-height: 24px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: none;
  color: var(--text-mid);
  cursor: help;
  line-height: 0;
}

.tt__btn:hover,
.tt__btn[aria-expanded="true"] {
  color: var(--accent);
}

/* Bridges the gap between the button and the bubble, so a pointer moving up to read the bubble
   does not cross dead space and dismiss it. 1.4.13 "Hoverable". */
.tt__btn::after {
  content: "";
  position: absolute;
  bottom: 100%;
  left: 0;
  right: 0;
  height: 0.6rem;
}

.tt svg {
  width: 0.95em;
  height: 0.95em;
  display: block;
}

.tt__body {
  position: absolute;
  bottom: calc(100% + 0.5rem);
  left: 50%;
  transform: translateX(-50%) translateY(0.25rem);
  z-index: 40;
  width: max-content;
  max-width: min(22rem, 78vw);
  padding: 0.7rem 0.85rem;
  border: 1px solid var(--hair-strong);
  border-radius: var(--r-sm, 8px);
  background: var(--surface);
  box-shadow: 0 8px 28px rgba(0, 0, 0, 0.45);
  color: var(--text-mid);
  font-size: 0.8125rem;
  line-height: 1.5;
  text-align: left;
  text-transform: none;
  letter-spacing: 0;
  white-space: normal;
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.14s ease, transform 0.14s ease, visibility 0.14s;
}

.tt:hover .tt__body,
.tt:focus-within .tt__body,
.tt__btn[aria-expanded="true"] + .tt__body {
  opacity: 1;
  visibility: visible;
  transform: translateX(-50%) translateY(0);
}

/* Hover and focus-within are kept deliberately: they mean the bubble still opens with
   JavaScript disabled, where the aria-expanded toggle cannot run. */

.tt__body strong {
  display: block;
  margin-bottom: 0.3rem;
  color: var(--text);
  font-size: 0.75rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.tt__body a {
  overflow-wrap: anywhere;
}

/* Near the right edge a centred bubble overflows the viewport. */
.tt--end .tt__body {
  left: auto;
  right: 0;
  transform: translateY(0.25rem);
}

.tt--end:hover .tt__body,
.tt--end:focus-within .tt__body,
.tt--end .tt__btn[aria-expanded="true"] + .tt__body {
  transform: translateY(0);
}

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

/* Touch has no hover, so the bubble opens on tap via :focus. Keep it comfortably tappable. */
@media (hover: none) {
  .tt { padding: 0.25rem; margin-left: 0.15em; }
}

/* ---------- key facts strip ---------- */

/* Sits directly under the hero lede. The two questions a model page is searched for — how long
   and how big — used to be a quarter of the way down the page behind the licence caveat. */
.keyfacts {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem 2.25rem;
  margin: 2rem 0 0;
  padding-top: 1.35rem;
  border-top: 1px solid var(--hair);
}

.keyfacts > div {
  min-width: 6rem;
}

.keyfacts dt {
  font-variation-settings: var(--ax-meta);
  font-size: 0.6875rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-dim);
  margin-bottom: 0.15rem;
}

.keyfacts dd {
  margin: 0;
  font-variation-settings: "opsz" 32, "wght" 500, "SOFT" 0, "WONK" 0;
  font-size: 1.05rem;
  color: var(--paper);
}

/* ---------- the answer block ---------- */

/* Used where a page exists to deliver a specific figure. It carries the h2 that states the
   question and the table that answers it, above anything interactive. */
.answer {
  margin-top: 2.5rem;
  padding-top: 1.75rem;
  border-top: 1px solid var(--hair-mid);
}

.answer h2 {
  font-size: clamp(1.35rem, 2.2vw, 1.85rem);
  margin-bottom: 1rem;
}

/* Both download formats sit side by side, so the actions need their own group. */
.dl__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem;
}

/* Footer column labels are labels, not document structure. They were <h2>, which put eight
   boilerplate headings in every page's outline — as many as a model page has real ones. */
.foot-head {
  font-size: 0.8125rem;
  font-variation-settings: var(--ax-meta);
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--text-mid);
  margin: 0 0 0.75rem;
}

.foot-legal h3 {
  font-size: 0.75rem;
  font-variation-settings: var(--ax-meta);
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--text-mid);
  margin: 0 0 0.6rem;
}

/* Visible to assistive technology, absent from the visual design. */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

.spec-note {
  max-width: 60ch;
  margin-top: -0.35rem;
}

/* Capability matrix: yes and no need to differ by more than the word, but the word stays,
   because colour alone is not an accessible distinction. */
.data td.yes { color: var(--text); font-variation-settings: var(--ax-meta); }
.data td.no  { color: var(--text-mid); }

/* ---------- scrollable table region ---------- */

/* A wide data table is exempt from reflow, but making it usable means a scroll container, and a
   scroll container that cannot be reached by keyboard is a 2.1.1 failure. render.table() wraps
   tables over four columns in a labelled, focusable region; this is what makes that visible. */
.tbl-scroll {
  overflow-x: auto;
  /* Room for the focus ring, which would otherwise be clipped by the scroll container. */
  padding: 3px;
  margin: 0 -3px;
}

.tbl-scroll:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.tbl-scroll .tbl {
  min-width: 34rem;
}

/* ---------- a worked prompt set ---------- */

/* Eleven full prompts on one page is a wall unless each is collapsed. The summary carries the
   two things you scan for — where it is set and what the drawing comes out of. */
.scene {
  border-bottom: 1px solid var(--hair);
  padding: 0.35rem 0;
}

.scene > summary {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.3rem 1rem;
  padding: 0.85rem 0;
  cursor: pointer;
  list-style: none;
}

.scene > summary::-webkit-details-marker {
  display: none;
}

/* A disclosure triangle drawn in CSS, so the row has an affordance without an icon font. */
.scene > summary::before {
  content: "";
  flex: none;
  width: 0.5rem;
  height: 0.5rem;
  border-right: 1.5px solid var(--accent);
  border-bottom: 1.5px solid var(--accent);
  transform: rotate(-45deg);
  transition: transform var(--dur-fast) var(--ease);
}

.scene[open] > summary::before {
  transform: rotate(45deg);
}

.scene > summary:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
}

.scene__name {
  font-variation-settings: "opsz" 32, "wght" 500, "SOFT" 0, "WONK" 0;
  font-size: 1.0625rem;
  color: var(--paper);
}

.scene__from {
  font-variation-settings: var(--ax-meta);
  font-size: 0.8125rem;
  color: var(--text-dim);
  margin-left: auto;
}

/* Prompt text is quoted material, not the site's own prose: set narrower and cooler so it
   reads as something being shown rather than something being said. */
.scene__prompt {
  max-width: var(--read);
  padding: 0.9rem 1.1rem;
  background: var(--surface);
  border-left: 2px solid var(--hair-strong);
  border-radius: 0 var(--r) var(--r) 0;
  font-size: 0.9375rem;
  line-height: 1.6;
  color: var(--text);
}

.scene h3 {
  font-size: 0.75rem;
  font-variation-settings: var(--ax-meta);
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--text-mid);
  margin: 1.5rem 0 0.5rem;
}

/* ---------- citations ---------- */

/* A citation is evidence, so it is set apart from the prose that leans on it rather than
   trailing off the end of a paragraph. */
.cite {
  margin: 0 0 1.15rem;
  padding: 0.7rem 0 0.7rem 1rem;
  border-left: 2px solid var(--hair-strong);
  font-size: 0.9375rem;
}

.cite__label {
  display: block;
  font-variation-settings: var(--ax-meta);
  font-size: 0.6875rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-dim);
  margin-bottom: 0.2rem;
}

/* ---------- list pages ---------- */

/* The whole point of a list page is that nothing sits between the reader and the words, so a
   phrase gets a background chip and no border, no bullet and no icon. Space separates them,
   which is the same rule the rest of the site follows. */

.grid-2--tight {
  gap: clamp(1.25rem, 3vw, 2.5rem);
  margin-top: 2rem;
}

.h-sm {
  font-variation-settings: "opsz" 32, "wght" 500, "SOFT" 12, "WONK" 0;
  font-size: 0.9375rem;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--text-dim);
  margin: 0 0 0.45rem;
}

.listing {
  padding-top: 2.4rem;
}

.listing__head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.35rem 0.9rem;
  margin-bottom: 1rem;
  padding-bottom: 0.55rem;
  border-bottom: 1px solid var(--hair);
}

.listing__head h2 {
  margin: 0;
}

.listing__head .meta {
  margin: 0;
}

.phrases {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}

.phrases li {
  margin: 0;
}

.phrase {
  display: inline-block;
  /* A phrase is meant to be selected and copied, so it gets a text cursor rather than the
     default arrow: it looks like a chip but it is not a control, and nothing happens on click. */
  cursor: text;
  padding: 0.34rem 0.7rem;
  border-radius: var(--r-sm);
  background: var(--surface);
  color: var(--paper);
  font-size: 1rem;
  line-height: 1.4;
}

/* An annotated list is one phrase per line, because the entries are whole prompts rather than
   single terms and a wrapping flex row would leave them impossible to tell apart. */
.phrases--annotated {
  display: block;
}

.phrases--annotated li {
  padding: 0.9rem 0;
  border-bottom: 1px solid var(--hair);
}

.phrases--annotated .phrase {
  display: block;
  background: none;
  padding: 0;
  max-width: 62ch;
}

.phrase__note {
  display: block;
  margin-top: 0.3rem;
  font-variation-settings: var(--ax-meta);
  font-size: 0.8125rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--daylight);
}

.example {
  max-width: 62ch;
  margin: 0.9rem 0 0;
  padding-left: 1rem;
  border-left: 2px solid var(--hair-strong);
  color: var(--text-mid);
  font-size: 1rem;
}

/* The download offer. Warmer than a plain panel because it is the one thing on the page being
   offered rather than stated, but no badge and no urgency copy. */
.panel--offer {
  background: linear-gradient(180deg, var(--tungsten-wash), transparent 70%), var(--surface);
  border: 1px solid var(--hair-strong);
  margin-top: 3rem;
}

.panel--offer .eyebrow {
  color: var(--tungsten-mid);
}

/* ---------- the featured strip ---------- */

/* A scrolling strip is decorative motion, so it is built to be ignorable. It stops on hover, it
   stops when anything inside it takes keyboard focus, and it does not move at all when the
   system asks for reduced motion — in which case it becomes an ordinary horizontally
   scrollable list, which is also what it is with no CSS animation support. */

.strip {
  display: flex;
  gap: 1rem;
  overflow: hidden;
  /* Fade the edges rather than cutting hard, so it reads as continuing rather than clipped. */
  mask-image: linear-gradient(90deg, transparent, #000 3rem, #000 calc(100% - 3rem), transparent);
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 3rem, #000 calc(100% - 3rem), transparent);
}

.strip__track {
  display: flex;
  flex: 0 0 auto;
  gap: 1rem;
  margin: 0;
  padding: 0;
  list-style: none;
  animation: strip-scroll 90s linear infinite;
}

/* Two tracks make the loop seamless: the second is a copy, and translating by exactly its own
   width lands the first copy where the second began. The duration is long on purpose — 90s for
   twenty cards is a slow drift rather than a carousel, which is the register §4 asks for. */
@keyframes strip-scroll {
  from { transform: translateX(0); }
  to   { transform: translateX(calc(-100% - 1rem)); }
}

.strip:hover .strip__track,
.strip:focus-within .strip__track {
  animation-play-state: paused;
}

.strip__item {
  flex: 0 0 clamp(15rem, 22vw, 19rem);
  padding: 1.1rem 1.25rem;
  border-radius: var(--r-lg);
  background: var(--surface);
  border: 1px solid var(--hair);
}

.strip__cat {
  font-variation-settings: var(--ax-meta);
  font-size: 0.75rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--daylight);
  text-decoration: none;
}
.strip__cat:hover { text-decoration: underline; }

.strip__name {
  font-variation-settings: "opsz" 32, "wght" 500, "SOFT" 0, "WONK" 0;
  font-size: 1.0625rem;
  margin: 0.4rem 0 0.35rem;
  color: var(--paper);
}
.strip__name a { color: inherit; text-decoration: none; }
.strip__name a:hover { text-decoration: underline; }

.strip__desc {
  margin: 0 0 0.55rem;
  font-size: 0.9375rem;
  color: var(--text-mid);
}

.strip__meta {
  margin: 0;
  font-variation-settings: var(--ax-meta);
  font-size: 0.75rem;
  letter-spacing: 0.04em;
  color: var(--text-dim);
}

@media (prefers-reduced-motion: reduce) {
  .strip {
    overflow-x: auto;
    mask-image: none;
    -webkit-mask-image: none;
  }
  .strip__track { animation: none; }
  /* The duplicate exists only to close the loop. With no loop it is 20 redundant cards. */
  .strip__track[aria-hidden="true"] { display: none; }
}

/* Entry pages retain the shared Shotcraft palette and type axes. */
.entry-hero { display: grid; grid-template-columns: minmax(0, 1.08fr) minmax(0, 1fr); gap: var(--entry-space); align-items: center; margin-block: var(--entry-band); }
.entry-hero h1 { font-size: var(--entry-title); max-width: 14ch; }
.entry-hero .lede { font-size: var(--entry-body); max-width: var(--read); }
.entry-actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--gap); margin-block: var(--gap); }
.entry-actions .btn { white-space: normal; text-align: center; }
.entry-example { padding: var(--gap); background: var(--surface); border-radius: var(--r-lg); border-top: 1px solid var(--tungsten); }
.entry-example h2 { font-size: var(--entry-example-title); }
.entry-example .prompt-copy__text { font-size: var(--entry-small); }
.entry-example .meta { margin-bottom: 0; }
.prompt-copy__text { font-size: var(--entry-body); line-height: 1.7; max-width: var(--read); user-select: text; }
.prompt-copy__text:focus-visible { outline: 2px solid var(--accent); outline-offset: var(--r); }
.entry-route-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--entry-third)), 1fr)); gap: var(--entry-space); }
.entry-route-grid h3 { margin-top: var(--gap); }
.entry-route-grid p { color: var(--text-mid); font-size: var(--entry-body); }
.entry-luxury { display: grid; grid-template-columns: minmax(0, 1.3fr) minmax(0, 1fr); gap: var(--entry-space); padding-block: var(--entry-space); border-block: 1px solid var(--hair-mid); }
.entry-examples { padding: 0; list-style: none; margin: 0; }
.entry-examples li + li { margin-top: var(--gap); }
.entry-examples p { margin-block: var(--r) 0; }
.entry-destinations { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--entry-half)), 1fr)); gap: var(--gap) var(--entry-space); }
.entry-destination { color: inherit; text-decoration: none; padding-block: var(--gap); border-bottom: 1px solid var(--hair-mid); }
.entry-destination h3 { margin-top: 0; }
.entry-destination p { color: var(--text-mid); font-size: var(--entry-body); }
.entry-destination:hover h3 { color: var(--accent); }
.entry-destinations.entry-examples li + li { margin-top: 0; }
.entry-promotion { padding-block: var(--gap); padding-inline-start: var(--gap); border-inline-start: 1px solid var(--tungsten); }
.luxury-hero { margin-block: var(--entry-band); }
.luxury-hero h1 { max-width: 18ch; font-size: var(--entry-title); }
.prompt-jumps { display: flex; flex-wrap: wrap; gap: var(--gap); margin-block: var(--entry-space); }
.luxury-shot { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 2fr); gap: var(--entry-space); padding-block: var(--entry-space); border-top: 1px solid var(--hair-mid); scroll-margin-top: var(--entry-space); }
.luxury-shot h3 { margin-top: 0; }
.luxury-shot h4 { margin-block: var(--gap); }
.luxury-shot header p { color: var(--text-mid); }
.shot-decisions { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--gap); margin: 0; }
.shot-decisions dt { font-size: var(--entry-small); color: var(--text-mid); }
.shot-decisions dd { margin: 0; font-size: var(--entry-body); }
.shot-notes { margin-block: var(--gap); }
.shot-notes summary { cursor: pointer; color: var(--accent); padding-block: var(--r-lg); }
.shot-notes[open] summary { margin-bottom: var(--gap); }
.entry-steps { padding-inline-start: var(--gap); margin-block: var(--entry-space); }
.budget-form { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--entry-half)), 1fr)); gap: var(--gap) var(--entry-space); margin-block: var(--entry-space); }
.budget-form label { display: block; margin-bottom: var(--r-lg); font-size: var(--entry-body); }
.budget-form input { width: 100%; min-height: var(--entry-control-height); border: 1px solid var(--control-edge); border-radius: var(--r); background: var(--surface); color: var(--text); padding: var(--r-lg); font: inherit; }
.budget-form input:focus-visible { outline: 2px solid var(--accent); outline-offset: var(--r); }
.budget-form .meta { margin-block: var(--r-lg); }
.budget-submit, .budget-result { grid-column: 1 / -1; }
.budget-result { padding: var(--gap); background: var(--surface); border-radius: var(--r-lg); }
.budget-result p:last-child { margin-bottom: 0; }
@media (max-width: 54rem) {
  .entry-hero, .entry-luxury { grid-template-columns: minmax(0, 1fr); }
  .entry-hero h1 { max-width: 18ch; }
  .luxury-shot { grid-template-columns: minmax(0, 1fr); gap: var(--gap); }
}

/* Course: the existing warm reading palette, one working frame at a time. */
.course-page { padding-block: var(--entry-space); }
.course-intro, .course-overview { max-width: var(--read); margin-bottom: var(--entry-space); }
.course-intro h1 { font-size: var(--entry-title); }
.course-page section { margin-block: var(--entry-space); }
.course-workspace { border-top: solid thin var(--accent); padding-top: var(--gap); }
.course-actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--gap); margin-block: var(--gap); }
.course-card { max-width: var(--read); padding: var(--gap); background: var(--surface); border-radius: var(--r-lg); }
.course-card h3 { margin-top: 0; }
.course-card textarea { display: block; width: 100%; font: inherit; background: var(--black); color: var(--text); border: solid thin var(--control-edge); border-radius: var(--r); margin-block: var(--gap); padding: var(--gap); }
.course-card fieldset { border: 0; padding: 0; min-width: 0; }
.course-option { display: flex; align-items: baseline; gap: var(--gap); padding-block: var(--gap); cursor: pointer; border-bottom: solid thin var(--hair-mid); }
.course-option input { accent-color: var(--accent); flex-shrink: 0; }
.course-feedback { border-left: solid thin var(--accent); padding-left: var(--gap); margin-block: var(--gap); }
.course-levels { list-style: none; padding: 0; display: grid; grid-template-columns: repeat(auto-fit,minmax(min(100%,var(--entry-half)),1fr)); gap: var(--entry-space); }
.course-levels li { border-top: solid thin var(--hair-mid); padding-top: var(--gap); }
.course-reading { max-width: var(--read); border-top: solid thin var(--hair-mid); padding-block: var(--gap); overflow-wrap: anywhere; }
.course-reading summary { cursor: pointer; }
.course-page input[type=file] { max-width: 100%; font: inherit; }
.course-page button:disabled { opacity: .65; cursor: wait; }

/* Homepage cinema: a contained screen, with choices floating above the image. */
.entry-hero--films { grid-template-columns: minmax(0, .9fr) minmax(0, 1.2fr); align-items: start; }
.entry-hero--films > * { min-width: 0; }
.entry-hero--films h1 { max-width: 14ch; }
.hero-films { min-width: 0; width: 100%; }
.hero-films > h2 { font-size: var(--entry-example-title); margin-top: 0; margin-bottom: var(--gap); }
.hero-film-stage { position: relative; min-width: 0; }
.hero-film-choices { position: absolute; z-index: 1; inset: var(--film-inset) var(--film-inset) auto; display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--film-nav-gap); padding: var(--film-nav-padding); background: var(--film-nav-surface); border: thin solid var(--hair-strong); border-radius: var(--film-nav-radius); box-shadow: var(--film-nav-shadow); backdrop-filter: blur(var(--film-blur)); }
.hero-film-choice { appearance: none; min-width: 0; min-height: var(--entry-control-height); font-family: var(--family); font-variation-settings: var(--ax-meta); font-size: var(--film-nav-font); line-height: 1.35; color: var(--paper); border: 0; border-radius: var(--r-lg); background: transparent; padding: var(--film-button-padding); cursor: pointer; transition: background var(--dur) var(--ease), color var(--dur) var(--ease); }
.hero-film-choice:hover { background: var(--surface-3); }
.hero-film-choice[aria-pressed="true"] { color: var(--black); background: var(--daylight-mid); }
.hero-film-choice:focus-visible { outline: var(--film-focus) solid var(--paper); outline-offset: var(--film-focus); }
.hero-films article { min-width: 0; }
.hero-films video { display: block; width: 100%; max-width: 100%; height: auto; max-height: var(--film-height); aspect-ratio: 16 / 9; object-fit: contain; background: var(--surface); border-radius: var(--r-lg); }
.hero-film-caption { padding-block: var(--gap); max-width: var(--read); }
.hero-film-caption h3 { margin-top: 0; font-size: var(--entry-example-title); }
.hero-film-caption p { font-size: var(--entry-small); }
.hero-film-steps { display: flex; flex-wrap: wrap; gap: var(--gap); padding-left: var(--gap); color: var(--daylight-mid); font-size: var(--entry-small); }
.hero-film-steps li { padding-right: var(--gap); }
.hero-films details, .hero-films > .meta { font-size: var(--entry-small); color: var(--text-mid); }
@media (max-width: 900px) {
  .entry-hero--films { grid-template-columns: minmax(0, 1fr); }
  .hero-films { max-width: var(--read); margin-inline: auto; }
}
@media (max-width: 480px) {
  .hero-film-choices { position: relative; inset: auto; margin-bottom: var(--film-inset); box-shadow: none; }
  .hero-film-choice { padding: var(--film-inset); }
}
@media (prefers-reduced-motion: reduce) { .hero-film-choice { transition: none; } }
