.products { background: #0b0a0d; }
/* One link under the grid, for whoever has read seven panels and still does
   not know. The button is the hero's outline button; only the spacing is new. */
.pick-cta { margin: 34px 0 0; }
.pick-cta .btn { gap: 12px; }
.tilt-target {
  --tilt-x: 0deg;
  --tilt-y: 0deg;
  transform-style: preserve-3d;
  will-change: transform;
}
.product-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 10px;
}
.category-panel {
  position: relative;
  min-height: 330px;
  overflow: hidden;
  isolation: isolate;
  border: 3px solid #070608;
  color: #fff;
  background: var(--brand-deep);
}
.category-panel::before {
  content: "";
  position: absolute;
  z-index: -2;
  inset: 0;
  opacity: .34;
  background:
    linear-gradient(135deg, transparent 48%, rgba(255,255,255,.15) 49%, transparent 51%) 0 0 / 34px 34px;
}
.category-panel::after {
  content: "";
  position: absolute;
  z-index: -1;
  inset: 0;
  background: linear-gradient(to top, rgba(7,6,8,.82), transparent 58%);
}
.category-panel.category-feature {
  grid-column: span 2;
  min-height: 470px;
}
.category-panel.category-wide {
  grid-column: span 2;
  min-height: 350px;
}
/*
 * The `.category-panel img` block that used to live here positioned seven
 * copies of assets/brand/mascot.png -- one per panel, the same drawing every
 * time, individually rotated and mirrored to disguise the repetition.
 *
 * There is one of him now, and he walks between the panels rather than being
 * copied into all of them -- so the panels hold no <img> at all, and the tiles
 * are colour, stripes and a wordmark. He is drawn onto per-panel canvases
 * instead, styled in category-mascot.css.
 */
.category-arrow {
  position: absolute;
  z-index: 3;
  top: 18px;
  right: 18px;
  width: 44px;
  height: 44px;
  display: grid;
  place-items: center;
  border: 2px solid currentColor;
  border-radius: 50%;
  font-size: 1.25rem;
}
.category-copy {
  position: absolute;
  z-index: 3;
  left: clamp(20px, 3vw, 46px);
  right: 20px;
  bottom: clamp(20px, 3vw, 42px);
}
.category-copy small {
  display: block;
  margin-bottom: 9px;
  color: #fff;
  font-size: .66rem;
  font-weight: 800;
  letter-spacing: .13em;
  text-transform: uppercase;
}
.category-copy strong {
  display: block;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(2.76rem, 6.44vw, 5.98rem);
  line-height: .86;
  text-transform: uppercase;
}
.category-feature .category-copy strong { font-size: clamp(3.86rem, 8.28vw, 7.36rem); }
.category-flower {
  background:
    radial-gradient(circle at 76% 32%, rgba(224,204,236,.44), transparent 24%),
    #76518f;
}
.category-edibles { background: #a83a39; }
.category-prerolls { background: #17151b; }
.category-concentrates {
  color: #161218;
  background: #d4b344;
}
.category-concentrates .category-copy small,
.category-merch .category-copy small { color: #161218; }
.category-concentrates::after,
.category-merch::after {
  background: linear-gradient(to top, rgba(241,234,224,.82), transparent 58%);
}
.category-vapes { background: #496d8f; }
.category-merch {
  color: #161218;
  background: #ece5dc;
}

.sticker-story {
  position: relative;
  min-height: clamp(690px, 78vw, 920px);
  display: grid;
  grid-template-columns: minmax(300px, .72fr) minmax(520px, 1.28fr);
  align-items: stretch;
  overflow: hidden;
  isolation: isolate;
  background:
    radial-gradient(circle at 18% 18%, rgba(186,145,214,.35), transparent 27%),
    repeating-linear-gradient(31deg, transparent 0 40px, rgba(8,7,10,.09) 41px 44px),
    #69348d;
}
.sticker-story::before {
  content: "";
  position: absolute;
  z-index: -1;
  inset: 0;
  opacity: .35;
  background:
    linear-gradient(135deg, transparent 48%, rgba(255,255,255,.15) 49%, transparent 51%) 0 0 / 45px 45px;
}
.sticker-story-copy {
  position: relative;
  z-index: 10;
  align-self: center;
  padding: clamp(70px, 9vw, 140px) 0 clamp(70px, 9vw, 140px) clamp(20px, 7vw, 116px);
}
.sticker-story-copy .kicker { color: #f4dff7; }
.sticker-story-copy h2 {
  margin: 0;
  font-family: var(--font-display);
  font-size: clamp(4.6rem, 9.2vw, 9.2rem);
  font-weight: 400;
  line-height: .78;
  letter-spacing: 0;
  text-transform: uppercase;
  text-shadow: clamp(4px, .55vw, 9px) clamp(4px, .55vw, 9px) 0 #171219;
  transform: rotate(-3deg);
}
.sticker-story-copy h2 span { color: #efb526; }
/* Named rather than positional. It was `> p:last-child`, and mounting the
   sound board under this paragraph made the board the last child -- so the
   paragraph stopped matching and lost its width, margins, colour and type
   scale at once, on the landing page, for every browser with Web Audio. */
.sticker-story-lede {
  max-width: 490px;
  margin: 40px 0 0;
  color: #eee4f2;
  font-size: clamp(1rem, 1.7vw, 1.3rem);
  line-height: 1.65;
}
.sticker-stage {
  position: relative;
  min-width: 0;
  transform: none;
}
.sticker-stage > img {
  position: absolute;
  z-index: 5;
  width: min(61%, 590px);
  height: 102%;
  right: 4%;
  bottom: -17%;
  object-fit: contain;
  filter: drop-shadow(-10px 12px 0 rgba(15,8,18,.5));
}
.mascot-sticker {
  position: absolute;
  z-index: 2;
  min-width: 76px;
  min-height: 76px;
  display: grid;
  place-items: center;
  padding: 13px;
  border: 3px solid #171219;
  background: #eee4cf;
  color: #171219;
  box-shadow:
    0 0 0 5px #faf4e7,
    7px 8px 0 rgba(14,8,17,.38);
  font-family: var(--font-body);
  font-size: clamp(.68rem, 1vw, .85rem);
  font-weight: 900;
  line-height: .86;
  text-align: center;
  text-transform: uppercase;
  letter-spacing: .04em;
}
.mascot-sticker b {
  display: block;
  font-family: var(--font-display);
  font-size: clamp(1.24rem, 1.84vw, 1.93rem);
  font-weight: 400;
  line-height: .82;
}
.mascot-sticker small {
  display: block;
  margin-top: 5px;
  font-size: .54rem;
  letter-spacing: .12em;
}
.sticker-eight {
  width: 94px;
  height: 94px;
  left: 5%;
  top: 27%;
  border-radius: 50%;
  background: #efb526;
  transform: rotate(-12deg);
}
.sticker-eight b { font-size: 3.2rem; }
.sticker-fuse {
  right: 7%;
  top: 8%;
  color: #fff;
  background: #c83a42;
  transform: rotate(10deg);
}
.sticker-boom {
  right: -2%;
  top: 30%;
  color: #efb526;
  background: #171219;
  transform: rotate(17deg);
}
.sticker-boom b { font-size: clamp(1.61rem, 2.39vw, 2.48rem); }
.sticker-leaf {
  left: 3%;
  top: 51%;
  border-radius: 50%;
  color: #2f6841;
  transform: rotate(8deg);
}
.sticker-roll {
  left: 25%;
  top: 38%;
  background: #efb526;
  transform: rotate(-8deg);
}
.sticker-torch {
  right: 13%;
  top: 47%;
  border-radius: 50%;
  transform: rotate(13deg);
}
.sticker-mass {
  z-index: 7;
  left: 2%;
  bottom: 14%;
  color: #416d99;
  background: #e3eff5;
  transform: rotate(-13deg);
}
.sticker-rig {
  z-index: 7;
  right: 3%;
  bottom: 17%;
  color: #fff;
  background: #c83a42;
  border-radius: 50%;
  transform: rotate(11deg);
}
.sticker-key {
  left: 32%;
  top: 8%;
  color: #efb526;
  background: #171219;
  transform: rotate(-8deg);
}
.sticker-star {
  min-width: 58px;
  min-height: 58px;
  width: 58px;
  height: 58px;
  padding: 0;
  border-radius: 50%;
  color: #fff;
  background: #c83a42;
  font-size: 2rem;
}
.sticker-star-one {
  left: 40%;
  bottom: 8%;
  transform: rotate(-7deg);
}
.sticker-star-two {
  right: 31%;
  top: 21%;
  color: #171219;
  background: #efb526;
  transform: rotate(7deg);
}
.sticker-xtracts {
  z-index: 7;
  right: 27%;
  bottom: 4%;
  background: #efb526;
  transform: rotate(-5deg);
}

/*
 * The stickers land.
 *
 * Driven entirely by `.visible`, which site-interactions.js already puts on
 * .sticker-stage the first time it scrolls into view -- so this needs no
 * JavaScript of its own and runs on a phone, with the 3D mascot module never
 * loaded. That is the point: the mascot LISTENS for these animations ending
 * (they bubble) and leans at whichever sticker just landed. The timing lives
 * here, in one place, and there is no shared constant for the two to drift on.
 *
 * Why the rotations move to `rotate:`
 * -----------------------------------
 * Each sticker's base rule ends in `transform: rotate(Ndeg)`, and an animation
 * touching `transform` overrides that rule for its whole run -- with
 * `fill-mode: both`, afterwards too. All twelve would snap upright. The used
 * transform is `translate -> rotate -> scale -> transform`, so moving the tilt
 * onto the `rotate` property puts it on a channel the keyframes never touch.
 *
 * Declaring BOTH would rotate them twice, which is why `transform: none` is in
 * here as well. A browser without individual transform properties skips this
 * whole block, keeps its `transform: rotate()`, and gets correctly-tilted
 * stickers with no slam -- and the mascot, hearing no animationend, simply
 * idles. Nothing is broken by being old.
 */
@supports (rotate: 1deg) {
  .sticker-eight,
  .sticker-fuse,
  .sticker-boom,
  .sticker-leaf,
  .sticker-roll,
  .sticker-torch,
  .sticker-mass,
  .sticker-rig,
  .sticker-key,
  .sticker-star-one,
  .sticker-star-two,
  .sticker-xtracts { transform: none; }

  .sticker-eight    { rotate: -12deg; }
  .sticker-fuse     { rotate: 10deg; }
  .sticker-boom     { rotate: 17deg; }
  .sticker-leaf     { rotate: 8deg; }
  .sticker-roll     { rotate: -8deg; }
  .sticker-torch    { rotate: 13deg; }
  .sticker-mass     { rotate: -13deg; }
  .sticker-rig      { rotate: 11deg; }
  .sticker-key      { rotate: -8deg; }
  .sticker-star-one { rotate: -7deg; }
  .sticker-star-two { rotate: 7deg; }
  .sticker-xtracts  { rotate: -5deg; }

  /*
   * Overshoot and settle: in fast and oversized, past the mark, back onto it.
   * `both` is load-bearing -- without it every sticker sits fully drawn through
   * its own delay and only the last one appears to move at all.
   */
  @keyframes sticker-slam {
    0%   { opacity: 0; scale: 1.9;  translate: 0 -22px; }
    55%  { opacity: 1; scale: .88;  translate: 0 3px; }
    78%  {             scale: 1.06; translate: 0 -2px; }
    100% { opacity: 1; scale: 1;    translate: 0 0; }
  }

  .sticker-stage .mascot-sticker { opacity: 0; }
  .sticker-stage.visible .mascot-sticker {
    animation: sticker-slam 420ms cubic-bezier(.2, .9, .25, 1) both;
  }

  /*
   * The order is a beat, not the DOM's -- which is why these are written per
   * class rather than with :nth-child. The z-indices already say what the beat
   * is: the nine BEHIND him land first and bury him, then the three at
   * z-index 7 land on top of him last.
   *
   * The 260ms lead-in is the stage's own .reveal fade (750ms) getting far
   * enough off zero that the first sticker is visible when it arrives.
   */
  .sticker-stage.visible .sticker-eight    { animation-delay: 260ms; }
  .sticker-stage.visible .sticker-key      { animation-delay: 350ms; }
  .sticker-stage.visible .sticker-fuse     { animation-delay: 440ms; }
  .sticker-stage.visible .sticker-star-two { animation-delay: 530ms; }
  .sticker-stage.visible .sticker-boom     { animation-delay: 620ms; }
  .sticker-stage.visible .sticker-roll     { animation-delay: 710ms; }
  .sticker-stage.visible .sticker-leaf     { animation-delay: 800ms; }
  .sticker-stage.visible .sticker-torch    { animation-delay: 890ms; }
  .sticker-stage.visible .sticker-star-one { animation-delay: 980ms; }
  .sticker-stage.visible .sticker-mass     { animation-delay: 1070ms; }
  .sticker-stage.visible .sticker-rig      { animation-delay: 1160ms; }
  .sticker-stage.visible .sticker-xtracts  { animation-delay: 1250ms; }
}

.find-section { background: #0b0a0d; }
.find-panel {
  min-height: 700px;
  border: 1px solid var(--line);
  padding: clamp(38px, 6vw, 84px);
  display: grid;
  grid-template-columns: .9fr 1.1fr;
  gap: 80px;
  align-items: center;
  background:
    radial-gradient(circle at 12% 80%, rgba(135, 126, 188,.25), transparent 28%),
    #131116;
}
.find-panel h2 { font-size: clamp(3.68rem, 7.36vw, 7.36rem); }
.find-panel > div:first-child > p:last-child {
  max-width: 540px;
  color: #aaa4ae;
  line-height: 1.75;
}
.find-map-stage { min-width: 0; }
.find-map-shell {
  position: relative;
  /* Tall enough to contain an open event popup — the shell clips overflow,
     so anything the popup can't fit inside simply disappears. */
  min-height: 500px;
  overflow: hidden;
  border: 3px solid #09070d;
  background:
    linear-gradient(rgba(200,175,217,.09) 1px, transparent 1px) 0 0 / 34px 34px,
    linear-gradient(90deg, rgba(200,175,217,.09) 1px, transparent 1px) 0 0 / 34px 34px,
    #21182a;
  box-shadow: 8px 9px 0 rgba(0,0,0,.45);
}
.find-map,
.find-map.maplibregl-map {
  position: absolute;
  inset: 0;
}
.find-map .maplibregl-canvas { outline: none; }
.find-map-shell::after {
  /* Not "NORTHEAST" — the map reaches every state, and a coast-to-coast frame
     with a regional caption on it reads as a bug. */
  content: "NATIONWIDE / DROP RADAR";
  position: absolute;
  right: 12px;
  bottom: 10px;
  color: rgba(244,231,250,.5);
  font-size: .56rem;
  font-weight: 900;
  letter-spacing: .13em;
  pointer-events: none;
}
.map-coming-soon {
  position: absolute;
  z-index: 2;
  top: 16px;
  left: 16px;
  max-width: 245px;
  padding: 14px 16px 13px 47px;
  border: 2px solid var(--ink);
  background: var(--paper);
  color: var(--ink);
  box-shadow: 4px 5px 0 var(--ink);
  transform: rotate(-2deg);
  pointer-events: none;
}
.map-coming-soon strong {
  display: block;
  font-family: var(--font-display);
  font-size: 1.32rem;
  font-weight: 400;
  line-height: .9;
  letter-spacing: .025em;
  text-transform: uppercase;
}
.map-coming-soon small {
  display: block;
  margin-top: 7px;
  color: #655d68;
  font-size: .61rem;
  font-weight: 800;
  line-height: 1.35;
  letter-spacing: .04em;
}
.map-status-spark {
  position: absolute;
  left: 13px;
  top: 18px;
  color: var(--brand-deep);
  font-size: 1.45rem;
}
/* The phone's "load the map" button: the map's own frame, until it is asked
   for. Centred in the shell so it reads as the map's poster, not a form. */
.find-map-load {
  position: absolute;
  z-index: 2;
  /* Centred with auto margins, not a translate: the site's press effect
     rewrites transform on buttons, and a translate-centred button jumps half
     its own size on touchstart -- out from under the finger, so the click
     that follows lands on the map frame instead. Measured, not guessed. */
  inset: 0;
  margin: auto;
  width: fit-content;
  height: fit-content;
  min-height: 44px;
  padding: 12px 22px;
  border: 2px solid var(--ink);
  border-radius: 0;
  background: var(--paper);
  color: var(--ink);
  font: inherit;
  font-size: .78rem;
  font-weight: 800;
  letter-spacing: .1em;
  text-transform: uppercase;
  box-shadow: 3px 4px 0 rgba(0,0,0,.46);
  cursor: pointer;
}
.find-map-load:focus-visible { outline: 3px solid var(--brand-soft); outline-offset: 2px; }
.map-cooperative-note {
  position: absolute;
  z-index: 2;
  left: 17px;
  bottom: 12px;
  margin: 0;
  color: #e8ddea;
  font-size: .57rem;
  font-weight: 800;
  letter-spacing: .1em;
  text-transform: uppercase;
  text-shadow: 0 1px 4px #100b16;
  pointer-events: none;
}
.find-map-shell .maplibregl-ctrl-top-right { top: 12px; right: 12px; }
.find-map-shell .maplibregl-ctrl-group {
  overflow: hidden;
  border: 2px solid var(--ink);
  border-radius: 0;
  box-shadow: 3px 4px 0 rgba(0,0,0,.46);
}
.find-map-shell .maplibregl-ctrl-group button {
  width: 44px;
  height: 44px;
  background-color: var(--paper);
}
.find-map-shell .maplibregl-ctrl-group button + button { border-top: 2px solid var(--ink); }
.find-map-toggle {
  position: absolute;
  z-index: 3;
  top: 12px;
  right: 57px;
  min-height: 44px;
  padding: 0 10px;
  border: 2px solid var(--ink);
  background: var(--paper);
  color: var(--ink);
  box-shadow: 3px 4px 0 rgba(0,0,0,.46);
  cursor: pointer;
  font-size: .61rem;
  font-weight: 900;
  letter-spacing: .08em;
  text-transform: uppercase;
}
.find-map-toggle-spark { color: var(--brand-deep); font-size: 1rem; margin-right: 3px; }
.find-map-toggle b { color: var(--brand-deep); margin-left: 4px; }
.find-map-toggle[aria-pressed="false"] { opacity: .64; }
.find-map-toggle:focus-visible { outline: 3px solid #fff; outline-offset: 3px; }
/* --- the pins ------------------------------------------------------------
 *
 * Explosion bursts, not teardrops. See the comment above markerElement in
 * find-map.mjs for why the shape matters and why the edge is a filter rather
 * than a border -- clip-path cuts a border off with everything else, so the
 * outline is a drop-shadow that follows the clipped silhouette, exactly as
 * drop-stamp.css does for the torn strip.
 *
 * Every polygon's last-listed lower vertex is 50% 100%. MapLibre anchors these
 * markers to "bottom", so that point is what stands on the coordinate; move it
 * and every pin on the map drifts off its address.
 */
.shop-map-marker,
.shop-map-event-marker {
  /* A plain 44px box, and the burst is the span inside it.
     That split is not tidiness. clip-path clips the element's own painted
     decoration AND its hit-testing, so with the clip on the button the focus
     ring below was cut away entirely -- as was the global
     button:focus-visible halo -- and no pin on this map showed anything at all
     when it was tabbed to. The same clip left the 34px shop pin with only the
     star's own inner ~19px to press, so a thumb landing on the visible corner
     did nothing.
     The burst is seated at the BOTTOM, centred. MapLibre anchors these to
     "bottom", so the box's bottom centre is what stands on the coordinate --
     and that is exactly the burst's own lowest vertex, 50% 100%. Centre it
     instead and every pin on the map drifts north of its address. */
  display: grid;
  place-items: end center;
  width: 44px;
  height: 44px;
  padding: 0;
  border: 0;
  background: none;
  color: var(--ink);
  cursor: pointer;
}
.shop-map-marker span,
.shop-map-event-marker span {
  display: grid;
  place-items: center;
  line-height: 1;
  /* The ink edge, and a shadow to lift it off the basemap. Two drop-shadows
     rather than a border and a box-shadow, because both have to follow the
     burst rather than its bounding box. */
  filter:
    drop-shadow(0 -2px 0 var(--ink)) drop-shadow(0 2px 0 var(--ink))
    drop-shadow(-2px 0 0 var(--ink)) drop-shadow(2px 0 0 var(--ink))
    drop-shadow(3px 4px 0 rgba(0, 0, 0, .5));
}

/* An appearance: the spikier burst, and gold. Boom turns up, bangs, leaves. */
.shop-map-event-marker span {
  width: 38px;
  height: 38px;
  background: #efb526;
  font-size: 1rem;
  clip-path: polygon(
    50% 0%, 61% 18%, 79% 10%, 75% 31%, 96% 34%, 81% 50%,
    98% 66%, 77% 68%, 82% 89%, 63% 81%, 50% 100%, 37% 81%,
    18% 89%, 23% 68%, 2% 66%, 19% 50%, 4% 34%, 25% 31%,
    21% 10%, 39% 18%
  );
}

/* A shop: the rounder burst, and paper. It is a place that stays put, so it
   gets the calmer silhouette -- the shape carries the difference, not just the
   colour, for anybody who cannot use colour to tell the two apart. */
.shop-map-marker span {
  width: 34px;
  height: 34px;
  background: var(--paper);
  font-size: .82rem;
  clip-path: polygon(
    50% 2%, 66% 12%, 82% 9%, 84% 26%, 97% 38%, 88% 52%,
    95% 68%, 79% 73%, 74% 88%, 59% 85%, 50% 100%, 41% 85%,
    26% 88%, 21% 73%, 5% 68%, 12% 52%, 3% 38%, 16% 26%,
    18% 9%, 34% 12%
  );
}

/* Focus lands on the bounding box, which is the honest thing here: an outline
   clipped to a twenty-point star is not a focus ring anybody can follow. The
   box is unclipped now, so there is a ring to land on. */
.shop-map-marker:focus-visible,
.shop-map-event-marker:focus-visible {
  outline: 3px solid #fff;
  outline-offset: 3px;
}
.shop-map-popup-shell .maplibregl-popup-content {
  padding: 0;
  overflow: hidden;
  border: 3px solid var(--ink);
  border-radius: 0;
  background: var(--paper);
  color: var(--ink);
  box-shadow: 5px 6px 0 var(--ink);
}
.shop-map-popup-shell .maplibregl-popup-close-button {
  z-index: 1;
  top: 2px;
  right: 3px;
  color: var(--ink);
  font-size: 1.35rem;
  font-weight: 900;
}
.shop-map-popup-shell .maplibregl-popup-tip { border-top-color: var(--ink); }
/* The retail card and the appearance card are the same panel: a caption, a
   name in the display face, an address. They are the same kind of thing -- a
   place on the map with a comic panel hanging off it -- so they are set the
   same way, and only the flyer and the two actions belong to an event. */
.shop-map-popup,
.shop-map-event-popup { display: grid; gap: 6px; padding: 17px; }
.shop-map-popup span,
.shop-map-event-popup span {
  color: var(--brand-deep);
  font-size: .58rem;
  font-weight: 900;
  letter-spacing: .12em;
  text-transform: uppercase;
}
.shop-map-popup strong,
.shop-map-event-popup strong {
  font-family: var(--font-display);
  font-size: 1.7rem;
  font-weight: 400;
  line-height: .9;
  text-transform: uppercase;
}
.shop-map-popup p,
.shop-map-event-popup p { margin: 0; font-size: .72rem; line-height: 1.25; }
.shop-map-event-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 14px; }
.shop-map-event-popup .shop-map-event-calendar,
.shop-map-event-popup .shop-map-event-going {
  color: var(--brand-deep);
  font-size: .62rem;
  font-weight: 900;
  letter-spacing: .08em;
  text-transform: uppercase;
  text-decoration: underline;
  text-underline-offset: 2px;
}
.shop-map-event-popup .shop-map-event-going {
  padding: 0;
  border: 0;
  background: none;
  font-family: inherit;
  cursor: pointer;
}
.shop-map-event-popup .shop-map-event-calendar:hover,
.shop-map-event-popup .shop-map-event-calendar:focus-visible,
.shop-map-event-popup .shop-map-event-going:hover,
.shop-map-event-popup .shop-map-event-going:focus-visible { color: var(--ink); }
/* Pressed reads as a settled fact, not a dead control. */
.shop-map-event-popup .shop-map-event-going.is-going {
  color: var(--ink);
  text-decoration: none;
  cursor: default;
}
.shop-map-event-popup .shop-map-event-going.is-going::before { content: "\2713\00a0"; }
.shop-map-event-popup img {
  width: 100%;
  height: auto;
  max-height: 170px;
  object-fit: contain;
  background: #09070d;
  border: 2px solid var(--ink);
}
/* Last line of defence: a flyer with unusual proportions can still never
   push the address out of reach. */
.shop-map-popup-shell .maplibregl-popup-content {
  max-height: 360px;
  overflow-y: auto;
}
.map-placeholders {
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 8px;
  margin-top: 15px;
}
.map-placeholders article {
  min-width: 0;
  grid-template-columns: 1fr;
  gap: 5px;
  padding: 14px;
}
.map-placeholders.location-stack strong {
  grid-row: auto;
  align-self: auto;
  font-size: 1.15rem;
  line-height: .88;
}
.location-stack { display: grid; gap: 12px; }
.location-stack article {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 7px 20px;
  padding: 24px;
  border: 1px solid var(--line);
  background: rgba(255,255,255,.025);
}
.location-stack span {
  color: #8c8690;
  font-size: .67rem;
  text-transform: uppercase;
  letter-spacing: .12em;
}
.location-stack strong {
  grid-row: span 2;
  align-self: center;
  color: var(--brand-soft);
  font-family: var(--font-display);
  font-size: 1.7rem;
  font-weight: 400;
  text-transform: uppercase;
}
.location-stack small { color: #fff; }

@media (max-width: 900px) {
  .find-panel { grid-template-columns: 1fr; gap: 42px; }
  .find-copy { max-width: 620px; }
}
@media (max-width: 680px) {
  .find-panel { min-height: 0; padding: 42px 20px; }
  /* The event card needs its full vertical field on a phone too. The map is
     bounds-clamped there, so it cannot always pan a pin upward far enough to
     compensate for a shorter shell. */
  .find-map-shell { min-height: 500px; }

  /* On a phone the rotated status card covered ~40% of the map and collided
     with the events toggle. It becomes a slim strip along the bottom edge so
     the map itself is what fills the frame. */
  .map-coming-soon {
    top: auto;
    right: 0;
    bottom: 0;
    left: 0;
    display: flex;
    align-items: center;
    gap: 10px;
    max-width: none;
    padding: 7px 12px;
    border-width: 2px 0 0;
    box-shadow: none;
    transform: none;
  }
  /* The <br> stays — without it the two phrases run together, since the
     markup has no whitespace between them. */
  .map-coming-soon strong { flex: none; font-size: .8rem; line-height: 1.04; letter-spacing: .02em; }
  .map-coming-soon small { margin-top: 0; font-size: .53rem; line-height: 1.2; }
  .map-status-spark { display: none; }
  /* Both would sit underneath the strip. MapLibre still raises its own
     cooperative-gesture overlay the moment a one-finger drag is attempted. */
  .map-cooperative-note,
  .find-map-shell::after { display: none; }

  /* Shrinks the type to clear the map controls, but not the box: this is the
     narrow screen, which is exactly where the 32px version was hardest to hit. */
  .find-map-toggle { right: 55px; padding: 0 7px; font-size: .53rem; }

  /* The flyer made the popup taller than the map, so the address was cut off
     with no way to reach it. Shrink it to fit, and keep a scroll as a floor. */
  .shop-map-event-popup { gap: 4px; padding: 13px; }
  .shop-map-event-popup strong { font-size: 1.28rem; }
  .shop-map-event-popup p { font-size: .78rem; line-height: 1.3; }
  .shop-map-event-popup img { max-height: 124px; }
  .shop-map-popup-shell .maplibregl-popup-content { max-height: 290px; }

  .map-placeholders { grid-template-columns: 1fr; gap: 6px; margin-top: 12px; }
  .map-placeholders article {
    grid-template-columns: 1fr auto;
    align-items: center;
    gap: 2px 14px;
    padding: 10px 14px;
  }
  .map-placeholders.location-stack strong {
    grid-row: span 2;
    align-self: center;
    font-size: 1rem;
  }
  .map-placeholders span { font-size: .58rem; }
  .map-placeholders small { font-size: .73rem; }
}

.faq {
  display: grid;
  grid-template-columns: .65fr 1.35fr;
  gap: clamp(55px, 8vw, 120px);
  background: #0b0a0d;
}
.faq h2 { font-size: clamp(4.6rem, 8.28vw, 8.28rem); }
.faq h2 span { color: var(--brand); }
.faq-list { border-top: 2px solid #44394a; }
.faq-list details { border-bottom: 2px solid #44394a; }
.faq-list summary {
  cursor: pointer;
  list-style: none;
  padding: 27px 50px 27px 0;
  position: relative;
  font-size: clamp(1.05rem, 1.6vw, 1.3rem);
  font-weight: 700;
}
.faq-list summary::-webkit-details-marker { display: none; }
.faq-list summary::after {
  content: "+";
  position: absolute;
  top: 50%;
  right: 2px;
  width: 31px;
  height: 31px;
  display: grid;
  place-items: center;
  border: 2px solid var(--brand);
  border-radius: 50%;
  color: var(--brand-soft);
  font-size: 1.25rem;
  line-height: 1;
  transform: translateY(-50%);
}
.faq-list details[open] summary::after { content: "–"; }
.faq-list details p {
  margin: 0;
  max-width: 720px;
  padding: 0 35px 25px 0;
  color: #99939d;
  line-height: 1.7;
}

.loud-footer {
  padding: 0;
  border-top: 0;
  background: #070609;
}
.footer-sendoff {
  position: relative;
  min-height: clamp(570px, 67vw, 810px);
  overflow: hidden;
  isolation: isolate;
  background:
    radial-gradient(circle at 78% 30%, rgba(200,175,217,.32), transparent 25%),
    repeating-linear-gradient(31deg, transparent 0 40px, rgba(8,7,10,.09) 41px 44px),
    #69348d;
}
.footer-sendoff::before {
  content: "";
  position: absolute;
  z-index: -1;
  inset: 0;
  opacity: .32;
  background:
    linear-gradient(135deg, transparent 48%, rgba(255,255,255,.15) 49%, transparent 51%) 0 0 / 45px 45px;
}
.footer-sendoff-copy {
  position: relative;
  z-index: 3;
  padding: clamp(75px, 9vw, 135px) clamp(20px, 7vw, 116px);
}
.footer-sendoff-copy .kicker { color: #f3e8f6; }
.footer-sendoff h2 {
  margin: 0;
  font-family: var(--font-display);
  font-size: clamp(2.21rem, 4.6vw, 4.78rem);
  font-weight: 400;
  line-height: .84;
  letter-spacing: 0;
  text-transform: uppercase;
  text-shadow: clamp(3px, .3vw, 5px) clamp(3px, .3vw, 5px) 0 #171219;
}
.footer-sendoff h2 span { color: #efb526; }
.footer-mascot {
  position: absolute;
  z-index: 2;
  width: min(42vw, 560px);
  height: 110%;
  right: 3%;
  bottom: -24%;
  object-fit: contain;
  filter: drop-shadow(-10px 12px 0 rgba(15,8,18,.5));
}
.footer-top-link {
  min-height: 48px;
  display: inline-flex;
  align-items: center;
  gap: 12px;
  margin-top: 40px;
  padding: 0 17px;
  border: 3px solid #171219;
  background: #efb526;
  color: #171219;
  box-shadow: 5px 6px 0 #171219;
  font-size: .72rem;
  font-weight: 900;
  letter-spacing: .1em;
  text-transform: uppercase;
  transition: transform 180ms ease, box-shadow 180ms ease;
}
.footer-top-link:hover,
.footer-top-link:focus-visible {
  box-shadow: 2px 3px 0 #171219;
  transform: translate(3px, 3px);
}
.footer-top-link:focus-visible {
  outline: 3px solid #fff;
  outline-offset: 3px;
}
.footer-utility {
  padding: clamp(42px, 5vw, 72px) clamp(20px, 5vw, 76px) 28px;
}
.footer-utility nav {
  display: flex;
  flex-wrap: wrap;
  gap: 0 clamp(24px, 4vw, 58px);
  padding-bottom: 35px;
  border-bottom: 1px solid var(--line);
  font-size: .72rem;
  font-weight: 800;
  letter-spacing: .11em;
  text-transform: uppercase;
}
.footer-utility nav a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  color: #d7d1d9;
  transition: color 180ms ease;
}
.footer-utility nav a:hover,
.footer-utility nav a:focus-visible { color: var(--brand-soft); }
.footer-utility nav a:focus-visible {
  outline: 2px solid var(--brand-soft);
  outline-offset: 5px;
}
.footer-social {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 14px clamp(14px, 2vw, 22px);
  margin-top: 30px;
}
.footer-social-label {
  color: #85808a;
  font-size: .68rem;
  font-weight: 800;
  letter-spacing: .14em;
  text-transform: uppercase;
}
.social-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 44px;
  min-height: 44px;
  color: var(--brand-soft);
  transition: transform 180ms ease, color 180ms ease;
}
/* Admin clearing a social link sets [hidden] on the anchor, and a bare
   `display: inline-flex` outranks the attribute's own display: none -- the
   icon stayed on the page, full size and still clickable, pointing at the
   profile that had just been taken down. */
.social-icon[hidden] { display: none; }
.social-icon:hover,
.social-icon:focus-visible {
  transform: translateY(-2px);
  color: var(--brand-tint);
}
.social-icon:focus-visible {
  outline: 2px solid var(--brand-soft);
  outline-offset: 3px;
}
.warning-box {
  margin-top: 35px;
  border: 1px solid var(--line);
  padding: 22px;
}
.warning-box strong {
  color: var(--brand-soft);
  font-size: .75rem;
  letter-spacing: .12em;
}
.warning-box p {
  margin: 9px 0 0;
  color: #85808a;
  font-size: .72rem;
  line-height: 1.65;
}
.footer-bottom {
  margin-top: 28px;
  padding-top: 20px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  border-top: 1px solid var(--line);
  color: #8d8791;
  font-size: .68rem;
  text-transform: uppercase;
  letter-spacing: .08em;
}
/* The studio credit sits between the copyright and the compliance line. Giving
 * the two outer spans equal flex basis is what centres it on the page — with
 * plain space-between it would only be centred in the leftover gap, which
 * shifts as the copyright year and compliance text change width. Scoped above
 * the 720px breakpoint, since the row stacks into a column below it. */
@media (min-width: 721px) {
  .footer-bottom > span { flex: 1 1 0; }
  .footer-bottom > span:last-child { text-align: right; }
  .footer-bottom > .rv-credit { flex: 0 0 auto; }
}
/* Stock-footage credit. Quieter than the compliance copy around it, but the
 * Vecteezy Free License requires it stay visible and linked. */
.footer-credits {
  margin-top: 14px;
  color: #8d8791;
  font-size: .66rem;
  letter-spacing: .04em;
}
.footer-credits a {
  color: var(--muted);
  text-decoration: underline;
  text-decoration-color: rgba(255, 255, 255, .22);
  text-underline-offset: 3px;
}
.footer-credits a:hover,
.footer-credits a:focus-visible {
  color: var(--brand-soft);
  text-decoration-color: currentColor;
}

/* Studio credit. Inherits the footer-bottom row's uppercase and letter-spacing
 * on purpose, so the three items read as one line rather than three. */
.rv-credit {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  gap: 7px;
  color: inherit; /* Match the row rather than sit dimmer than the text beside it. */
  text-decoration: none;
  transition: color .2s ease;
}
.rv-credit-mark {
  display: block;
  width: 31px;
  height: 15px;
  opacity: .72;
  transition: opacity .2s ease;
}
.rv-credit-name {
  text-decoration: underline;
  text-decoration-color: rgba(255, 255, 255, .18);
  text-underline-offset: 3px;
  transition: text-decoration-color .2s ease;
}
.rv-credit:hover,
.rv-credit:focus-visible {
  color: #d9c9a3; /* Warm, to match the eclipse mark rather than the Boom purple. */
}
.rv-credit:hover .rv-credit-mark,
.rv-credit:focus-visible .rv-credit-mark { opacity: 1; }
.rv-credit:hover .rv-credit-name,
.rv-credit:focus-visible .rv-credit-name { text-decoration-color: currentColor; }

/* The hover preview card. Built by rv-peek.mjs and parked on <body>, so it is
 * positioned fixed and cannot be clipped by the footer. */
.rv-peek {
  position: fixed;
  z-index: 60;
  width: 260px;
  padding: 3px;
  border-radius: 10px;
  background: #14121a;
  border: 1px solid rgba(255, 255, 255, .12);
  box-shadow: 0 18px 44px rgba(0, 0, 0, .55);
  opacity: 0;
  pointer-events: none; /* Never steal the click that was meant for the link. */
  transform: translate(var(--rv-peek-drift, 0), 6px) scale(.97);
  transition: opacity .18s ease, transform .18s ease;
}
.rv-peek.is-open {
  opacity: 1;
  transform: translate(var(--rv-peek-drift, 0), 0) scale(1);
}
.rv-peek-image {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 7px;
}
@media (prefers-reduced-motion: reduce) {
  .rv-peek,
  .rv-peek.is-open {
    transform: none;
    transition: opacity .12s ease;
  }
}

.category-cbd { background: var(--green); }
.category-cbd img { left: -8%; }

/* Featured drops — the fanned card stack. The landing page's own version of it
   is gone: featured-3d.mjs took that section over and featured-cards.mjs, which
   computed the fan per card, went with it. These rules are still live because
   new-issues.css and drop-archive.css both build their racks out of
   .featured-card; the inner -tilt layer carries the pointer tilt so a fan
   transform and the tilt never fight over one transform property. */
.featured-section { padding-bottom: clamp(30px, 4vw, 60px); }
.featured-stage {
  position: relative;
  height: clamp(420px, 46vw, 500px);
  margin-top: clamp(24px, 4vw, 56px);
  perspective: 1100px;
  /* The carousel is its own clipped 3D viewport: edge cards slide off inside
     it, so the page never gains a horizontal scroll on mobile. pan-y leaves
     vertical page scrolling alone while horizontal drags rotate the ring. */
  overflow: hidden;
  touch-action: pan-y;
}
.featured-card {
  position: absolute;
  inset-inline: 0;
  top: 4%;
  margin-inline: auto;
  width: min(330px, 76vw);
  cursor: pointer;
  transition: transform .55s cubic-bezier(.34, 1.35, .4, 1);
}
/* Same seven category themes catalog.css maps to --accent, drawn from the same
   values in theme.css. Kept as tokens rather than hexes so a re-skin does not
   have to find this block as well as that one. */
.featured-card[data-theme="purple"] { --card-accent: var(--brand); }
.featured-card[data-theme="red"] { --card-accent: var(--red); }
.featured-card[data-theme="ink"] { --card-accent: #343139; }
.featured-card[data-theme="gold"] { --card-accent: var(--gold); }
.featured-card[data-theme="blue"] { --card-accent: var(--blue); }
.featured-card[data-theme="green"] { --card-accent: var(--green); }
.featured-card[data-theme="paper"] { --card-accent: var(--brand-tint); }
.featured-card-tilt {
  transform-style: preserve-3d;
  transition: transform .5s cubic-bezier(.22, 1.4, .36, 1);
  color: var(--ink);
  background: var(--paper);
  border: 3px solid var(--ink);
  border-top: 9px solid var(--card-accent, var(--brand));
  box-shadow: 11px 13px 0 rgba(0, 0, 0, .5);
}
.featured-card.is-tilting .featured-card-tilt { transition: none; }
.featured-card.is-center:hover .featured-card-tilt { box-shadow: 15px 18px 0 rgba(0, 0, 0, .55); }
.featured-card-depth {
  display: grid;
  gap: 13px;
  padding: 20px 20px 22px;
  transform: translateZ(24px);
}
.featured-card-brand {
  display: flex;
  align-items: center;
  gap: 11px;
  font-size: .68rem;
  font-weight: 900;
  letter-spacing: .14em;
  text-transform: uppercase;
}
.featured-card-thumb {
  width: 36px;
  height: 36px;
  object-fit: cover;
  border: 2px solid var(--ink);
  flex-shrink: 0;
}
.featured-card-chip {
  display: grid;
  place-items: center;
  color: #fff;
  background: var(--ink);
  font-family: var(--font-display);
  font-size: 1rem;
  letter-spacing: 0;
}
.featured-card-depth h3 {
  margin: 0;
  font-family: var(--font-display);
  font-size: 1.85rem;
  font-weight: 400;
  line-height: .95;
  text-transform: uppercase;
}
.featured-card-price {
  margin: 0;
  color: var(--brand-deep);
  font-size: .95rem;
  font-weight: 900;
}
.featured-card-blurb {
  margin: 0;
  font-size: .82rem;
  line-height: 1.5;
  color: #46404d;
}
.featured-card-tags { display: flex; flex-wrap: wrap; gap: 7px; }
.featured-card-tags span {
  padding: 4px 10px;
  border: 2px solid var(--ink);
  background: #fff;
  font-size: .56rem;
  font-weight: 900;
  letter-spacing: .1em;
  text-transform: uppercase;
}
.featured-card-open {
  justify-self: start;
  padding-bottom: 3px;
  border-bottom: 2px solid currentColor;
  font-size: .68rem;
  font-weight: 900;
  letter-spacing: .1em;
  text-transform: uppercase;
}
@media (max-width: 680px) {
  .featured-stage { height: 470px; }
}
@media (prefers-reduced-motion: reduce) {
  .featured-card, .featured-card-tilt { transition: none; }
}

/* Featured Drops — a fixed, upright four-row comic shelf. The real 3D books
   take pointer input; this aligned button grid gives the same physical books
   durable keyboard focus and a usable fallback if WebGL is unavailable. */
.featured-section { padding-bottom: clamp(30px, 4vw, 60px); }
/* The rack is taller than it is wide, so it gets a scroll track of its own:
   the stage sticks to the viewport while the track scrolls past it, and
   featured-3d.mjs walks the camera down the rack over that distance. */
.featured-3d-track {
  position: relative;
  /* The stage, a window in which it parks below the header, and then however
     much scrolling the camera's descent down the rack is worth — both of the
     latter measured by featured-3d.mjs, which also sets the stage height.
     The parking window is not optional: without a track taller than the stage
     the sticky never engages at all, and the top row of comics ends up behind
     the site header. */
  height: calc(
    var(--featured-stage-height, calc(100dvh - var(--header-h, 78px))) + 30vh +
    var(--featured-scroll, 0px)
  );
  margin-top: clamp(24px, 4vw, 56px);
}
.featured-3d-stage {
  position: sticky;
  top: var(--header-h, 78px);
  /* featured-3d.mjs measures the rack and sets the height, capped at a
     viewport. The fallback covers the frames before the GLB has loaded. */
  height: var(--featured-stage-height, calc(100dvh - var(--header-h, 78px)));
  overflow: clip;
  isolation: isolate;
  /* The rack belongs to the page, not a framed diorama. Its transparent WebGL
     canvas shows the site background straight through at every scroll stop. */
  background: transparent;
}
.featured-3d-stage::after {
  content: none;
}
.featured-3d-stage canvas {
  position: absolute;
  inset: 0;
  z-index: 0;
  width: 100%;
  height: 100%;
  cursor: pointer;
  touch-action: pan-y;
}
.featured-3d-stage.is-panning-book canvas { cursor: grabbing; }
.featured-3d-pan-hint {
  position: absolute;
  z-index: 4;
  bottom: 13px;
  left: 50%;
  margin: 0;
  padding: 5px 9px;
  color: #f7f0df;
  background: rgba(12, 11, 14, .78);
  border: 1px solid rgba(247, 240, 223, .6);
  font-size: .62rem;
  font-weight: 900;
  letter-spacing: .1em;
  pointer-events: none;
  text-transform: uppercase;
  transform: translateX(-50%);
}
/* The prompt for the second tap. Sits under the held-up comic in the same band
   the pan hint uses -- the two are never on screen together, since one belongs
   to a shut book and the other to an open one. Louder than the pan hint on
   purpose: a reader who does not find this one is looking at a comic that will
   not open. */
.featured-3d-cover-hint {
  position: absolute;
  z-index: 4;
  bottom: 13px;
  left: 50%;
  padding: 9px 15px;
  color: #0c0b0e;
  background: #e1a925;
  border: 2px solid #0c0b0e;
  box-shadow: 3px 3px 0 rgba(12, 11, 14, .55);
  cursor: pointer;
  font: inherit;
  font-size: .72rem;
  font-weight: 900;
  letter-spacing: .1em;
  text-transform: uppercase;
  transform: translateX(-50%);
  animation: featured-cover-hint-pulse 1.6s ease-in-out infinite;
}
/* The beat is in the halo, not in the box. Scaling the button would move a tap
   target under a thumb that is already on its way down, and it makes the
   element permanently unstable to anything driving the page. */
@keyframes featured-cover-hint-pulse {
  50% { box-shadow: 3px 3px 0 rgba(12, 11, 14, .55), 0 0 0 6px rgba(225, 169, 37, .32); }
}
/* Prev and next issue, sat on the book's bottom edge and left there.
   featured-3d.mjs projects that edge from the reading pose only, so unlike
   every other control on this stage these do not travel with the paper — see
   placeIssueNav. Hung by its bottom on that point so the row sits above the
   edge rather than across it. */
.featured-3d-issue-nav {
  position: absolute;
  z-index: 4;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  /* Lifted clear of the edge by enough that the open-the-cover prompt below it
     still reads as a separate control on a phone, where the book's bottom edge
     and the bottom of the stage are only a few dozen pixels apart. */
  transform: translate(-50%, -26px);
}
.featured-3d-issue-nav[hidden] { display: none; }
.featured-3d-issue-nav-label {
  padding: 2px 7px;
  color: #e1a925;
  background: rgba(12, 11, 14, .86);
  font: 900 .52rem / 1 var(--font-body);
  letter-spacing: .16em;
  text-transform: uppercase;
}
.featured-3d-issue-nav-actions {
  display: flex;
  gap: 11px;
}
.featured-3d-issue-nav button {
  padding: 7px 12px;
  color: #f7f0df;
  background: rgba(12, 11, 14, .86);
  border: 2px solid #e1a925;
  box-shadow: 3px 3px 0 rgba(12, 11, 14, .5);
  cursor: pointer;
  font: 900 .64rem / 1 var(--font-body);
  letter-spacing: .1em;
  text-transform: uppercase;
  white-space: nowrap;
}
.featured-3d-issue-nav button:hover { color: #0c0b0e; background: #e1a925; }
.featured-3d-issue-nav button[data-issue-cover] { color: #0c0b0e; background: #e1a925; }
.featured-3d-issue-nav button:disabled { cursor: default; opacity: .48; }
.featured-3d-stage canvas:focus-visible,
.featured-3d-book-controls button:focus-visible,
.featured-sheet :focus-visible { outline: 3px solid #e1a925; outline-offset: 4px; }
/* Each button is placed over its cover by projecting the 3D position every
   frame, so this layer only has to be a full-stage positioning context. */
.featured-3d-book-controls {
  position: absolute;
  z-index: 2;
  inset: 0;
  pointer-events: none;
}
.featured-3d-book-controls button {
  position: absolute;
  min-width: 0;
  padding: 0;
  border: 0;
  background: transparent;
  cursor: pointer;
  pointer-events: auto;
}
.featured-3d-book-controls button[aria-pressed="true"] { background: rgba(225,169,37,.11); }
/* The controls printed on an open comic. Add-to-cart and a page turn have to be
   real buttons, so featured-3d.mjs projects each band onto its page every frame
   using the same fractions the page painters leave blank for them. This layer is
   only a positioning context; the bands inside it take the pointer. */
.featured-3d-page-controls {
  position: absolute;
  z-index: 3;
  inset: 0;
  pointer-events: none;
}
/* The page texture supplies the visible controls so they are physically carried
   by the turning sheet. These remain real controls, but only their focus ring
   appears above the printed art. */
.featured-3d-page-controls.has-baked-page-controls .featured-page-close,
.featured-3d-page-controls.has-baked-page-controls .featured-page-turn {
  opacity: 0;
}
/* A shut cover has no printed page chip. Keep the same semantic close button
   visible while the reader is holding that cover, then return to the invisible
   hit area exactly over the ink once the pages are open. */
.featured-3d-page-controls.is-cover .featured-page-close { opacity: 1; }
.featured-3d-page-controls.has-baked-page-controls :focus-visible {
  opacity: 1;
  outline: 3px solid var(--gold);
  outline-offset: 4px;
}
/* Only a grouping, so one `hidden` can take the whole readable page's controls
   away at once. It holds no layout and takes no pointer: the bands inside it are
   each projected onto their own printed rectangle by featured-3d.mjs.

   They used to be laid out as percentages of this box, with the values mirrored
   from drawBakedControls(). The values were right and the box was wrong — it is
   the axis-aligned rectangle bounding a leaning, bending trapezium, so it is
   wider than the page region it stands for and off-centre from it, and a
   percentage of it lands somewhere the artwork never went. Worse, an `auto`
   pointer here made the whole of that box swallow clicks that had missed every
   control in it. */
.featured-page-zone {
  position: absolute;
  inset: 0;
  display: block;
  pointer-events: none;
}
.featured-page-zone[hidden] { display: none; }
.featured-page-cart,
.featured-page-turn {
  position: absolute;
  margin: 0;
  min-height: 0;
  transform: none;
  pointer-events: auto;
}
/* The block fills the blank the coupon is printed around; the button inside it
   takes only the room it needs, because the sizes above it need the rest. */
.featured-page-cart .cart-controls { height: 100%; }
.featured-page-turn,
.featured-page-close,
.featured-page-cart .featured-sheet-add {
  display: block;
  border: 3px solid #0c0b0e;
  box-shadow: none;
  filter: drop-shadow(6px 7px 0 rgba(12, 11, 14, .68));
  font-family: var(--font-body);
  font-weight: 900;
  letter-spacing: .07em;
  text-transform: uppercase;
  cursor: pointer;
}
/* No min-height, no clip and no rotation: the element is the projection of the
   printed band, and anything that resizes, reshapes or turns it here moves the
   hit area off the ink. The band's own slant and lean are in the artwork and in
   the page it is projected onto. */
.featured-page-turn {
  padding: 10px 14px 9px;
  color: #0c0b0e;
  background: var(--gold);
  font-size: clamp(10px, 1vw, 13px);
  line-height: 1.1;
  text-align: center;
}
.featured-page-cart .featured-sheet-add {
  display: flex;
  align-items: center;
  justify-content: space-between;
  /* Sized in em, not pixels: this button is projected onto a page that is a
     third of the width on a phone, and 61 fixed pixels of it left no room for
     the sizes above -- which are the reason the page exists. */
  min-height: 3em;
  gap: .8em;
  width: 100%;
  padding: .5em 1.1em .5em 1.2em;
  color: #f7f0df;
  background: #0c0b0e;
  border: 3px solid #0c0b0e;
  clip-path: polygon(7% 0, 100% 0, 93% 100%, 0 100%, 0 19%);
  text-align: left;
}
/* The shipping hint goes, and only here. It is one line of small type on a
   button that has to share a coupon with the sizes; the sheet and the product
   page both still carry it, and "Add to cart" is not ambiguous without it. */
.featured-page-cart .featured-sheet-add small { display: none; }
/* em and not rem, all through here.

   rem is the root font size, which knows nothing about this coupon -- so the
   label and the diamond stayed one fixed size while the paper around them grew
   and shrank with the stage. At the small end the 23px diamond was most of the
   height of a 24px button; at the large end it was a speck on a poster. The
   whole block is measured against the coupon, and these were the two pieces
   opting out of it. */
.featured-page-cart .featured-sheet-add strong {
  margin-top: .2em;
  font-size: .82em;
  letter-spacing: .09em;
}
.featured-page-cart .featured-sheet-add b {
  display: grid;
  width: 1.9em;
  height: 1.9em;
  place-items: center;
  flex: 0 0 auto;
  color: #0c0b0e;
  background: var(--gold);
  clip-path: polygon(50% 0, 100% 50%, 50% 100%, 0 50%);
  font-size: 1.1em;
  line-height: 1;
}
.featured-page-turn:hover { background: #f7f0df; }
.featured-page-cart .featured-sheet-add:hover { background: #342d3d; }
/* `display: block` above outranks the browser's own [hidden] rule, so a button
   the script hides would otherwise stay on screen — which is how the page-turn
   control survived onto the last page, where it had nowhere to turn. */
.featured-page-turn[hidden],
.featured-page-close[hidden] { display: none; }
/* The same rule again, for the add button and the stepper it trades places
   with. bindCartControls shows one by hiding the other, so every display given
   to either of them below has to lose to `hidden` or both are on screen at
   once — and on the comic, both are on screen *on top of each other*: the add
   band is projected across the whole printed strip and the stepper is a short
   row of type laid over it. An add button that would not go away made every
   pixel around the minus into "add one more" — a 631x104 target for adding
   sitting under a 22x30 one for removing, and ten pixels wide on a phone — so
   a miss did the opposite of the press.

   Written as the catalog's own rule rather than one narrowed to the stepper,
   because that narrower version is what was here, and it is why the add button
   was left out. catalog.css carries the identical line for the shop pages;
   index.html does not load catalog.css, which is the whole reason this one
   has to exist. */
.cart-controls [hidden] { display: none !important; }
/* The cart block ships from catalog-render, so it is scaled to the page rather
   than restyled — the comic must not fork the store's buy controls. */
/* A fallback only, for the first frame of a turn.

   The size that counts is set inline by fitCoupon() in featured-3d.mjs, which
   measures the form against the coupon it is projected onto. It used to be
   `clamp(11px, 1.05vw, 14px)` -- a reasonable guess for an element in the page
   flow and wrong for this one, since the coupon tracks the stage rather than
   the window, and capped at 14px it left a small form marooned in a large
   coupon. See the note on fitCoupon for why no fixed ratio works either. */
.featured-page-cart { font-size: 13px; }
.featured-page-cart .cart-inline-stepper { filter: drop-shadow(4px 5px 0 rgba(12, 11, 14, .45)); }
/* The picker coupon's live form.

   Every other control on a comic page is invisible: the ink is in the page
   texture and the DOM is only a hit area over it. This one cannot be. Which
   size is chosen is state that changes while the page is on screen, and the
   texture is painted once and cached — paper can never show it. So the coupon
   is printed empty and the real form shows through the blank, which is what a
   mail-in coupon on a comic's back page has always looked like.

   Its own colours rather than the catalog's: this sits on cream newsprint
   inside a printed frame, not on a white card, and the shop's --ink/--paper
   tokens do not exist on the landing page. */
.featured-page-cart .cart-controls {
  display: flex;
  /* Scrolls rather than clips. On a phone the coupon projects to about a
     hundred pixels tall, and a size somebody cannot reach is worse than a
     scrollbar on a comic page. */
  overflow-y: auto;
  flex-direction: column;
  /* Centred, so a product with nothing to pick -- no sizes, no colours, just a
     buy button -- sits on the middle of the coupon rather than clinging to its
     top edge with a hand's width of blank paper underneath. `safe` keeps
     overflow starting at the top, where it can still be scrolled to. */
  justify-content: safe center;
  gap: .5em;
  color: #0c0b0e;
}
/* No `min-height: 0` here, and that is load-bearing. It was, to let the block
   scroll -- and a column flex item with a zero minimum shrinks below its own
   content instead of pushing the container, so the size grid collapsed to two
   rows' worth of box while still drawing three rows of chips. They spilled out
   the bottom and landed on top of the colour row. `flex: none` below is the
   half that keeps them honest. */
.featured-page-cart fieldset {
  display: grid;
  gap: .4em;
  margin: 0;
  padding: 0;
  border: 0;
}
.featured-page-cart .cart-controls > * { flex: none; }
.featured-page-cart legend {
  padding: 0;
  font-size: .72em;
  font-weight: 900;
  letter-spacing: .1em;
  text-transform: uppercase;
}
.featured-page-cart legend > span {
  margin-left: .6em;
  font-family: var(--font-display);
  font-size: 1.2em;
  font-weight: 400;
  letter-spacing: .02em;
  text-transform: none;
}
/* Three across, whatever they are called.

   `auto-fit` with a minimum was the wrong tool: a grid item will not shrink
   below its own min-content width, so "XS $20.00" set the track wider than the
   minimum asked for, three of those overflowed the coupon, and the row grew a
   sideways scrollbar that clipped every price. An apparel run is eight sizes
   and a THC run is four, so a fixed three reads as a size chart either way.

   minmax(0, …) rather than (auto, …) is the half of the fix that matters: it is
   what lets a column be narrower than the words in it, so the label below can
   wrap instead of pushing the track. */
.featured-page-cart .product-price-options > div {
  display: grid;
  grid-template-columns: repeat(var(--pick-cols, 3), minmax(0, 1fr));
  gap: .35em;
}
.featured-page-cart .product-color-options > div {
  display: flex;
  flex-wrap: wrap;
  gap: .35em;
}
.featured-page-cart .product-price-options label,
.featured-page-cart .product-color-options label {
  display: flex;
  align-items: center;
  gap: .4em;
  padding: .35em .5em;
  border: 2px solid #0c0b0e;
  background: #fffdf6;
  font-size: .82em;
  font-weight: 900;
  cursor: pointer;
}
/* The price goes under the size rather than beside it. Side by side needs the
   width of both plus the radio, which is more than a third of the coupon; the
   size over the price is also how a printed order form has always set it. */
.featured-page-cart .product-price-options label {
  display: grid;
  grid-template-columns: auto 1fr;
  align-items: center;
  gap: 0 .35em;
  min-width: 0;
  padding: .3em .4em;
}
.featured-page-cart .product-price-options label strong { grid-column: 2; }
.featured-page-cart .product-price-options label span { min-width: 0; }
.featured-page-cart .product-price-options input,
.featured-page-cart .product-color-options input { accent-color: var(--gold); }
.featured-page-cart .product-price-options label strong {
  font-family: var(--font-display);
  font-size: 1.25em;
  font-weight: 400;
}
.featured-page-cart .product-color-swatch {
  flex: none;
  width: 1.4em;
  height: 1.4em;
  border: 2px solid #0c0b0e;
}
/* Selected has to survive a glance at a page that is leaning away from you, so
   it is a filled chip and not only the radio dot. */
.featured-page-cart label:has(input:checked) {
  color: #f7f0df;
  background: #0c0b0e;
  box-shadow: 3px 3px 0 var(--gold);
}
.featured-page-cart label:has(input:checked) .product-color-swatch { border-color: #f7f0df; }
.featured-page-cart label.is-unavailable {
  border-color: #b3aeb6;
  color: #8b8590;
  cursor: not-allowed;
}
.featured-page-cart label.is-unavailable span { text-decoration: line-through; }
.featured-page-cart .product-price-options p { margin: 0; font-size: .7em; }
/* What is about to be added and what it costs, immediately above the button
   that adds it — and gone entirely when there is neither, since an empty bar
   over the button reads as a rendering fault. */
.featured-page-cart .product-pick {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: .6em;
  margin: 0;
  font-size: .76em;
  font-weight: 900;
  letter-spacing: .07em;
  text-transform: uppercase;
}
.featured-page-cart .product-pick strong {
  font-family: var(--font-display);
  font-size: 1.6em;
  font-weight: 400;
  letter-spacing: 0;
}
.featured-page-cart .product-pick:not(:has(span:not(:empty), strong:not(:empty))) { display: none; }
/* The action follows the form, and then sticks.

   It follows so that a product with four sizes reads as a form that has ended
   rather than one with a hand's width of blank paper punched out of the middle
   of it. It sticks because a tee is eight sizes and three colours, and on a
   laptop that does not fit the coupon even at the smallest type worth setting
   -- so the column scrolls, and the one thing that must never scroll out of
   reach is the button you came here to press.

   Both share the slot and both are sized alike, so swapping one for the other
   when the item lands in the cart moves nothing. That matters more than it
   looks: the type is measured against the form once, and a swap that changed
   the height would invalidate the measurement and cut the action off the
   bottom -- which is exactly what it did. */
.featured-page-cart .featured-sheet-add,
.featured-page-cart .cart-inline-stepper {
  position: sticky;
  z-index: 1;
  bottom: 0;
  margin-top: .1em;
  min-height: 3em;
}
.featured-page-cart .cart-inline-stepper {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .5em;
  padding: .5em .8em;
  color: #f7f0df;
  border: 3px solid #0c0b0e;
  background: #0c0b0e;
}
.featured-page-cart .cart-inline-stepper button {
  min-width: 2em;
  padding: .1em .3em;
  color: #0c0b0e;
  border: 0;
  background: var(--gold);
  font: 900 1.1em/1 var(--font-body);
  cursor: pointer;
}
.featured-page-cart .cart-inline-stepper span { font-weight: 900; }

/* Placed on the comic's own top-right corner by featured-3d.mjs, which projects
   the four corners of the square the close glyph is printed in and gives this
   the box that bounds them — so no size, no offset and no clip here. All three
   used to be, and all three were wrong: a fixed 32px is 32 *screen* pixels
   while the printed chip is 32 *page* pixels, which is a different size at
   every viewport and every angle the page leans at; the translate then hung
   that mis-sized box off an anchor that missed the chip's edge; and the clip
   took a further bite out of what was left. The reader saw ink they could not
   press about nine pixels left of where the button actually was. */
.featured-page-close {
  position: absolute;
  z-index: 1;
  display: grid;
  place-items: center;
  padding: 0;
  color: #f7f0df;
  background: #0c0b0e;
  border-color: #f7f0df;
  font-size: 1.5rem;
  line-height: 1;
  pointer-events: auto;
}
.featured-page-close:hover { color: #0c0b0e; background: var(--gold); border-color: #0c0b0e; }
.featured-page-controls :focus-visible { outline: 3px solid #e1a925; outline-offset: 4px; }

/* No body-level scroll lock here on purpose. The stage is `position: sticky`
   and the camera is driven by scroll, so both of the usual locks break this
   section: `overflow: hidden` clamps scrollY to zero and throws the camera to
   the top of the rack, and `position: fixed` stops the stage being sticky.
   featured-3d.mjs refuses the scroll gestures instead, which leaves the layout
   untouched. */

/* Hidden by the shared screen-reader rule in styles-core.css; only what that
   rule does not say lives here. */
.featured-3d-status { z-index: 2; pointer-events: none; }
/* The sheet is pinned to the middle of the screen, not to the tall stage, so
   it is reachable wherever you are in the track. It is sized to fit the
   viewport outright: no nested scroll region, which is what made the opened
   comic feel like a second page to scroll through. */
/* [hidden] is a UA display:none, which a display:grid here would silently
   beat and leave the scrim covering the page for good. */
#featuredSheetMount[hidden] { display: none; }
#featuredSheetMount {
  position: fixed;
  z-index: 40;
  inset: 0;
  display: grid;
  place-items: center;
  padding: 16px;
  background: rgba(12, 11, 14, .58);
  animation: featured-scrim-in .2s ease both;
}
.featured-sheet {
  position: relative;
  z-index: 4;
  display: grid;
  grid-template-columns: .85fr 1.15fr;
  width: min(600px, 100%);
  max-height: 100%;
  overflow: hidden;
  color: #0c0b0e;
  border: 3px solid #0c0b0e;
  background: #f7f0df;
  box-shadow: 11px 13px 0 #0c0b0e;
  transform: rotate(-.8deg);
  animation: featured-sheet-open .3s cubic-bezier(.2,1.35,.4,1) both;
}
.featured-sheet-art,
.featured-sheet-copy { display: grid; align-content: space-between; gap: 17px; padding: clamp(17px, 2.6vw, 29px); }
.featured-sheet-art {
  position: relative;
  overflow: hidden;
  background: var(--flat-brand);
  border-right: 3px solid #0c0b0e;
  box-shadow: inset -10px 0 12px rgba(0,0,0,.18);
  background-image: radial-gradient(circle, rgba(12,11,14,.25) 1px, transparent 1.7px);
  background-size: 8px 8px;
}
/*
 * The flats, matching the painted comic's own — this panel is the 2D stand-in
 * for its cover, and the product photo sits on it. These used to be the accents
 * at full strength, written out as literals for a third time.
 *
 * The ink and green rows dropped their cream text with the saturation: both
 * flats are light enough that the dark type wins, and cream on #7f7a78 is
 * 3.7:1 against 4.6:1 for ink.
 */
.featured-sheet-art[data-theme="red"] { background-color: var(--flat-red); }
.featured-sheet-art[data-theme="ink"] { background-color: var(--flat-ink); }
.featured-sheet-art[data-theme="gold"] { background-color: var(--flat-gold); }
.featured-sheet-art[data-theme="blue"] { background-color: var(--flat-blue); }
.featured-sheet-art[data-theme="green"] { background-color: var(--flat-green); }
.featured-sheet-art[data-theme="paper"] { background-color: var(--flat-paper); }
.featured-sheet-issue,
.featured-sheet-copy > small {
  position: relative;
  z-index: 2;
  font-size: .62rem;
  font-weight: 900;
  letter-spacing: .14em;
  text-transform: uppercase;
}
.featured-sheet-art .catalog-pack {
  z-index: 1;
  width: min(73%, 210px);
  min-height: 210px;
  margin: auto;
}
.featured-sheet-photo,
.featured-sheet-mascot {
  z-index: 1;
  width: 100%;
  min-height: 0;
  height: 100%;
  object-fit: cover;
  /*
   * Was saturate(.87) contrast(1.1) — the photo pushed back to stop it fighting
   * a full-chroma ground. The ground is a flat now, so the photo no longer has
   * to lose to win; this is a touch of newsprint, not a retreat.
   */
  filter: saturate(.95) contrast(1.04);
}
.featured-sheet-mascot { object-fit: contain; }
.featured-sheet-copy h3 {
  margin: 0;
  font-family: var(--font-display);
  font-size: clamp(2.16rem, 4.6vw, 4.23rem);
  font-weight: 400;
  line-height: .76;
  text-transform: uppercase;
}
.featured-sheet-copy { background: linear-gradient(90deg, #e3d8c2, #f7f0df 10%); }
.featured-sheet-copy h3 { font-size: clamp(1.75rem, 3.4vw, 2.99rem); }
.featured-sheet-copy > p { margin: 0; color: #45404a; font-size: .85rem; line-height: 1.45; }
.featured-sheet-price { color: var(--brand-deep, #6158a6) !important; font-weight: 900; }
.featured-sheet-build { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; margin: 0; }
.featured-sheet-build div { padding-top: 6px; border-top: 1px solid rgba(12,11,14,.22); }
.featured-sheet-build dt { font-size: .52rem; font-weight: 900; letter-spacing: .1em; text-transform: uppercase; }
.featured-sheet-build dd { margin: 3px 0 0; font-size: .66rem; font-weight: 800; line-height: 1.2; }
.featured-sheet .cart-controls { display: grid; gap: 7px; }
/* The 2D sheet a browser with no WebGL gets carries the same picker the comic's
   coupon does, so it needs the same chips — index.html does not load
   catalog.css, and without these the radios render as bare browser defaults on
   a page that has none anywhere else. Scoped rather than lifted from
   catalog.css: the shop's chips are white cards on paper and these are printed
   ones on newsprint. */
.featured-sheet fieldset { display: grid; gap: 5px; margin: 0; padding: 0; border: 0; }
.featured-sheet legend { padding: 0; font-size: .52rem; font-weight: 900; letter-spacing: .1em; text-transform: uppercase; }
.featured-sheet legend > span { margin-left: 8px; font-family: var(--font-display); font-size: .9rem; font-weight: 400; text-transform: none; }
.featured-sheet .product-price-options > div { display: grid; grid-template-columns: repeat(auto-fit, minmax(96px, 1fr)); gap: 5px; }
.featured-sheet .product-color-options > div { display: flex; flex-wrap: wrap; gap: 5px; }
.featured-sheet .product-price-options label,
.featured-sheet .product-color-options label { display: flex; align-items: center; justify-content: space-between; gap: 6px; padding: 6px 8px; border: 2px solid #0c0b0e; background: #fffdf6; font-size: .64rem; font-weight: 900; cursor: pointer; }
.featured-sheet .product-price-options input, .featured-sheet .product-color-options input { accent-color: var(--gold); }
.featured-sheet .product-price-options label strong { font-family: var(--font-display); font-size: 1rem; font-weight: 400; }
.featured-sheet .product-color-swatch { flex: none; width: 18px; height: 18px; border: 2px solid #0c0b0e; }
.featured-sheet label:has(input:checked) { color: #f7f0df; background: #0c0b0e; box-shadow: 3px 3px 0 var(--gold); }
.featured-sheet label:has(input:checked) .product-color-swatch { border-color: #f7f0df; }
.featured-sheet label.is-unavailable { border-color: #b3aeb6; color: #8b8590; cursor: not-allowed; }
.featured-sheet label.is-unavailable span { text-decoration: line-through; }
.featured-sheet .product-price-options p { margin: 0; font-size: .55rem; font-weight: 900; letter-spacing: .07em; text-transform: uppercase; }
.featured-sheet .product-pick { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; margin: 0; font-size: .58rem; font-weight: 900; letter-spacing: .07em; text-transform: uppercase; }
.featured-sheet .product-pick strong { font-family: var(--font-display); font-size: 1.15rem; font-weight: 400; letter-spacing: 0; }
.featured-sheet .product-pick:not(:has(span:not(:empty), strong:not(:empty))) { display: none; }
.featured-sheet-add { display: flex; align-items: center; justify-content: space-between; gap: 10px; width: 100%; padding: 9px 10px; color: #f7f0df; border: 0; background: #0c0b0e; cursor: pointer; font: inherit; }
.featured-sheet-add small, .featured-sheet-add strong { display: block; text-align: left; font-size: .6rem; letter-spacing: .08em; text-transform: uppercase; }
.featured-sheet-add strong { margin-top: 2px; font-size: .72rem; }
.featured-sheet-add b { font-size: 1.25rem; }
.featured-sheet .quantity-control { justify-self: start; }
.featured-sheet-product-link { justify-self: start; padding: 8px 10px; color: #f7f0df; background: #0c0b0e; font-size: .64rem; font-weight: 900; letter-spacing: .11em; text-transform: uppercase; }
.featured-sheet-close { position: absolute; z-index: 5; top: 9px; right: 9px; width: 30px; height: 30px; color: #f7f0df; border: 2px solid currentColor; background: #0c0b0e; cursor: pointer; font-size: 1.35rem; line-height: 1; }
.featured-sheet-tag { position: absolute; z-index: 3; right: 8%; bottom: 5%; --pop-size: clamp(1.3rem, 2.5vw, 2rem); }
.featured-pop-video { position: absolute; z-index: 2; right: -8%; bottom: -7%; width: 72%; opacity: .42; mix-blend-mode: screen; pointer-events: none; }
.featured-3d-fallback { position: absolute; z-index: 3; inset: auto 18px 18px; margin: 0; padding: 12px; color: #0c0b0e; background: #f7f0df; font-weight: 800; }
@keyframes featured-scrim-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes featured-sheet-open { from { opacity: 0; transform: rotate(-7deg) scale(.7); } to { opacity: 1; transform: rotate(-.8deg) scale(1); } }
@media (max-width: 680px) {
  .featured-section .section-heading { grid-template-columns: 1fr; gap: 20px; }
  .featured-section .section-copy { max-width: 34rem; }
  /* This is the only way back from the product-detail spread on a phone. Give
     its short instruction a larger, tighter-set treatment than the longer
     forward label, without changing the projected page zone beneath it. */
  .featured-page-zone[data-zone="left"] .featured-page-turn {
    font-size: clamp(13px, 3.7vw, 16px);
    letter-spacing: .055em;
  }
  .featured-sheet { grid-template-columns: .72fr 1.28fr; }
  .featured-sheet-art,
  .featured-sheet-copy { padding: 17px; }
}
@media (min-width: 681px) {
  .featured-3d-pan-hint { display: none; }
}
@media (max-width: 430px) {
  .featured-sheet { grid-template-columns: 1fr; }
  .featured-sheet-art { min-height: 130px; max-height: 168px; }
  .featured-sheet-photo,
  .featured-sheet-mascot { max-height: 168px; }
}
/* Landscape phones and short windows: drop the art and tighten the copy so the
   sheet still fits the screen whole rather than growing a scrollbar. */
@media (max-height: 560px) {
  .featured-sheet { grid-template-columns: 1fr; }
  .featured-sheet-art { display: none; }
  .featured-sheet-copy { gap: 10px; padding: 15px; }
  .featured-sheet-copy h3 { font-size: clamp(1.38rem, 3.68vh, 1.93rem); }
  /* The blurb is the only line worth losing here. Targeted by id so it cannot
     take the price paragraph, which is also a direct p, down with it. */
  #featuredSheetDescription { display: none; }
}
@media (prefers-reduced-motion: reduce) {
  .featured-sheet,
  #featuredSheetMount { animation: none; }
  .featured-pop-video { display: none; }
  /* The prompt still has to be found, so it keeps its colour and loses only the
     beat. */
  .featured-3d-cover-hint { animation: none; }
  /* The stage is deliberately left alone here. featured-3d.mjs already frames
     the whole rack and reports no travel under reduced motion, which collapses
     the track above; overriding the stage height as well would desync it from
     the size the renderer was given and stretch the render. */
}
