/*
 * Brand colours and the two self-hosted faces now live in theme.css, which is
 * the single file a re-skin edits. Self-hosting keeps the critical path off
 * fonts.googleapis.com and fonts.gstatic.com and keeps both hosts out of the
 * CSP; both faces are SIL Open Font License 1.1.
 */
@import url("theme.css");

:root {
  /* Anything that sticks below the header has to clear it. */
  --header-h: 78px;

  /*
   * The landing page's own surfaces. Deliberately not in theme.css: this is a
   * near-black page by design of the template, not by choice of the brand.
   */
  --bg: #08070a;
  --bg-soft: #111014;
  --panel: #17151b;
  --paper: #f2efe9;
  --ink: #0c0b0e;
  --muted: #a7a1ab;
  --line: rgba(255, 255, 255, 0.13);
  --radius: 26px;
}

* { box-sizing: border-box; }
html { scroll-behavior: smooth; }
/* clip, not hidden: hidden makes the element a scroll container that touch
   gestures can still pan sideways on mobile (the decorative ticker, orbits,
   and carousel edges all poke past the viewport). clip forbids horizontal
   scrolling outright; the hidden line before it is the older-browser
   fallback. */
html {
  overflow-x: hidden;
  overflow-x: clip;
}
/* No pinch zoom over the 3D rack, and nowhere else. Zooming pushed the rack out
   of shape, which is the whole reason this exists -- so it is scoped to the one
   element that has that problem. `data-zoom-lock` is the single signal this
   rule and page-boot.mjs both read; the page itself, and every other page,
   zooms normally. Nothing sets it on <html>, and no meta viewport blocks scale.

   `pan-x pan-y` and not `manipulation`: manipulation still permits pinch. This
   allows scrolling in both directions and refuses the pinch and the double-tap
   zoom. Safari on iOS ignores this for page zoom, which is why page-boot.mjs
   also refuses the gesture events -- see the note there. */
[data-zoom-lock] { touch-action: pan-x pan-y; }
body {
  margin: 0;
  background: var(--bg);
  color: #fff;
  font-family: var(--font-body);
  overflow-x: hidden;
  overflow-x: clip;
}
body.locked { overflow: hidden; }
a { color: inherit; text-decoration: none; }
button, input, select, textarea { font: inherit; }
button, a { -webkit-tap-highlight-color: transparent; }
img { display: block; max-width: 100%; }

/*
 * Nothing here is selectable except form fields and the announcement banner --
 * the shop pages carry the same rule and the full reasoning; see the long note
 * in catalog.css.
 *
 * Short version: highlighting is not what screen readers use, so switching it
 * off costs far less than it looks like it does, and it buys a storefront that
 * stops highlighting a headline every time somebody double-clicks near one.
 *
 * No .admin-page guard in this file the way catalog.css has one -- the admin
 * never loads this stylesheet. Only index.html and one demo do.
 *
 * The wishlist share code is not allowlisted here either, for the same reason:
 * it lives on a shop page, so catalog.css is what covers it.
 */
body {
  -webkit-user-select: none;
  user-select: none;
}

input,
textarea,
select,
[contenteditable="true"],
.boom-announce-body {
  -webkit-user-select: text;
  user-select: text;
}

/*
 * No transition: an instant state change needs no reduced-motion guard, and a
 * press that eases is a press you feel late.
 *
 * The :hover twin is not redundant. `.btn:hover` lifts 2px further down this
 * file at equal specificity and later in source, so a mouse press -- which is
 * always also a hover -- would otherwise show nothing on the one control that
 * most wants the feedback. Landing on +1px from a -2px lift also makes that
 * press a 3px drop, which is about the right amount of give.
 */
:is(button, [role="button"], .btn, .footer-top-link, .find-map-toggle, .menu-toggle):active,
:is(button, [role="button"], .btn, .footer-top-link, .find-map-toggle, .menu-toggle):hover:active {
  transform: translateY(1px);
}

/*
 * Fixed, unlike the shop's, because this file has no per-theme accent to
 * follow. --brand-deep is the one value that stays legible against both
 * grounds this page uses: it reads as a block on the near-black body AND on
 * the paper panels in styles-content.css, where a light selection would
 * disappear. White on it measures 6.25:1, and the block itself
 * holds 3.22:1 against the dark ground and 5.44:1 against the paper.
 */
::selection {
  background-color: var(--brand-deep);
  color: #fff;
}

/*
 * The same ring the shop pages have had all along (catalog.css). The landing
 * page only ever had per-component focus rules -- the mascot, the footer links,
 * the map toggle, the comic controls -- so everything they missed fell back to
 * Chrome's 1px default, which on this near-black surface is drawn in near-black.
 *
 * Two rings, not one, and that is the point: white reads on the dark sections,
 * and the --ink halo outside it reads on the light ones. A single white ring
 * would vanish on the gold category panel (2.01:1) and on the paper cards.
 *
 * The bespoke rules above and below all carry at least two classes, so they
 * still win on `outline` where a component wants its own colour -- the comic's
 * gold, for instance. DESIGN.md:438 called focus the weakest point in this
 * system; this is the part of that which was a real failure.
 *
 * The halo does displace a component's own drop shadow for as long as it is
 * focused, because both are box-shadow and this rule is the more specific one.
 * Two controls hit that -- .find-map-toggle and .shop-map-event-marker, which
 * each carry a 3px offset shadow. Trading a decorative shadow for a ring you
 * can see, for the moment focus is on it, is the right way round.
 *
 * The halo's spread used to stop at 7px -- exactly the white ring's own outer
 * edge (3px offset + 4px width) -- so it never actually showed past the white,
 * only under it. On a light ground that left the white ring's outer edge
 * touching the page directly at 1.16:1. 9px puts a real 2px of --ink outside
 * the white on every ground; on a dark ground it was already fine either way.
 */
button:focus-visible,
a:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
summary:focus-visible {
  outline: 4px solid #fff;
  outline-offset: 3px;
  box-shadow: 0 0 0 9px var(--ink);
}

.site-header {
  position: sticky;
  top: 0;
  z-index: 30;
  height: var(--header-h);
  padding: 0 clamp(20px, 5vw, 76px);
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: 32px;
  border-bottom: 1px solid var(--line);
  background: rgba(8, 7, 10, 0.82);
  backdrop-filter: blur(18px);
}

.site-home-mascot {
  position: relative;
  width: 58px;
  height: 70px;
  display: grid;
  place-items: center;
  align-self: center;
  isolation: isolate;
}
.site-home-mascot::before {
  content: "";
  position: absolute;
  z-index: -1;
  width: 52px;
  height: 52px;
  left: 50%;
  top: 50%;
  background: var(--paper);
  border: 3px solid var(--brand);
  border-radius: 50%;
  transform: translate(-50%, -50%) rotate(-7deg);
}
.site-home-mascot img {
  width: 48px;
  height: 66px;
  object-fit: contain;
  object-position: center;
  filter:
    drop-shadow(1px 0 0 #fff)
    drop-shadow(-1px 0 0 #fff)
    drop-shadow(0 1px 0 #fff)
    drop-shadow(3px 3px 0 #000);
  transform: rotate(-3deg);
  transition: transform 160ms ease;
}
.site-home-mascot:hover img,
.site-home-mascot:focus-visible img {
  transform: translateY(2px) rotate(2deg) scale(1.06);
}
.site-home-mascot:focus-visible {
  outline: 3px solid #fff;
  outline-offset: 2px;
}

.wordmark {
  display: inline-flex;
  align-items: baseline;
  gap: 8px;
  font-family: var(--font-display);
  letter-spacing: 0.04em;
  white-space: nowrap;
}
.wordmark strong { color: var(--brand-soft); font-size: 1.9rem; font-weight: 400; }
.wordmark span { font-size: 0.72rem; letter-spacing: 0.24em; }

.site-header nav {
  justify-self: center;
  display: flex;
  align-items: center;
  gap: clamp(20px, 3vw, 44px);
  font-size: 0.82rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.1em;
}
.site-header nav a { opacity: 0.66; transition: opacity 180ms ease; }
.site-header nav a:hover { opacity: 1; }

.header-actions {
  display: flex;
  align-items: center;
  gap: 12px;
  justify-self: end;
}
.header-cart {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  gap: 8px;
  border: 1px solid rgba(255,255,255,.46);
  padding: 12px 16px;
  font-size: 0.72rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.11em;
}
/*
 * The count badge, and only the count.
 *
 * This used to name [data-cart-count] alone, so the wishlist's number sat
 * beside the cart's bubble as a bare digit -- at mobile width, where the words
 * are hidden, the header read "MENU 0 0" with one of the zeros circled and no
 * way to tell which control was which. catalog.css already badges both on the
 * shop pages; the landing page had been left behind.
 */
.header-cart [data-cart-count],
.header-cart [data-wishlist-count] {
  display: inline-grid;
  place-items: center;
  min-width: 20px;
  height: 20px;
  padding: 0 5px;
  background: var(--brand-soft);
  color: #0b0812;
  border-radius: 999px;
  font-size: 0.68rem;
}
/*
 * The icon stands in for the word below 1000px, where the word is hidden.
 *
 * Drawn rather than set in a font so it inherits the header's colour and needs
 * no second request, and marked aria-hidden because the link already carries a
 * full aria-label -- a screen reader should hear "View your cart", not "cart
 * image, View your cart".
 */
.cart-icon {
  display: none;
  width: 20px;
  height: 20px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.menu-toggle {
  display: none;
  justify-self: end;
  color: #fff;
  background: transparent;
  border: 1px solid var(--line);
  padding: 10px 12px;
  text-transform: uppercase;
  letter-spacing: .1em;
  font-size: .72rem;
}

.hero {
  position: relative;
  min-height: calc(100svh - 78px);
  overflow: hidden;
  background:
    radial-gradient(circle at 73% 43%, rgba(135, 126, 188,.26), transparent 27%),
    radial-gradient(circle at 92% 12%, rgba(200,175,217,.08), transparent 22%),
    linear-gradient(135deg, #08070a 52%, #121016);
}
.hero::before {
  content: "";
  position: absolute;
  inset: 0;
  opacity: .17;
  background-image:
    linear-gradient(rgba(255,255,255,.08) 1px, transparent 1px),
    linear-gradient(90deg, rgba(255,255,255,.08) 1px, transparent 1px);
  background-size: 52px 52px;
  mask-image: linear-gradient(to right, black, transparent 70%);
}
.hero-grid {
  position: relative;
  z-index: 2;
  min-height: calc(100svh - 78px);
  padding: clamp(58px, 8vw, 120px) clamp(20px, 5vw, 76px);
  display: grid;
  grid-template-columns: minmax(0, 1.05fr) minmax(360px, .95fr);
  align-items: center;
  gap: 42px;
}
.hero-copy { max-width: 760px; }
.kicker {
  margin: 0 0 18px;
  color: var(--brand-soft);
  font-size: .72rem;
  line-height: 1.4;
  text-transform: uppercase;
  letter-spacing: .24em;
  font-weight: 700;
}
.kicker-dark { color: #2a2030; }
.hero h1,
.section h2 {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 400;
  text-transform: uppercase;
  letter-spacing: 0;
  line-height: .88;
}
.hero h1 { font-size: clamp(4.6rem, 9.2vw, 9.2rem); }
.hero h1 span {
  color: transparent;
  -webkit-text-stroke: 2px var(--brand-soft);
  text-shadow: 0 0 60px rgba(135, 126, 188,.24);
}
.hero-lead {
  max-width: 620px;
  margin: 26px 0 0;
  color: #c9c4cc;
  font-size: clamp(1.05rem, 1.7vw, 1.35rem);
  line-height: 1.65;
}
.hero-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin: 34px 0 0;
}
.btn {
  min-height: 50px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 0;
  padding: 0 21px;
  cursor: pointer;
  font-size: .74rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: .12em;
  transition: transform 180ms ease, background 180ms ease;
}
.btn:hover { transform: translateY(-2px); }
/*
 * --brand was 4.09:1 against white at 11.8px/800 -- below the 4.5:1 AA floor
 * for normal text. Shifted one step down the same hue so both the resting and
 * hover fills clear AA (6.25:1 and 7.83:1). --brand stays the brand colour
 * everywhere it carries large text or no text at all.
 */
.btn-primary { color: #fff; background: var(--brand-deep); }
.btn-primary:hover { background: var(--brand-press); }
.btn-outline { border: 1px solid rgba(255,255,255,.44); background: transparent; color: #fff; }
.btn-wide { width: 100%; }

.hero-notes {
  margin-top: 46px;
  display: flex;
  flex-wrap: wrap;
  gap: 18px 28px;
  color: #8e8992;
  text-transform: uppercase;
  letter-spacing: .1em;
  font-size: .68rem;
}
.hero-notes span::before { content: "•"; color: var(--brand-soft); margin-right: 9px; }

.hero-art {
  position: relative;
  min-height: 680px;
  display: grid;
  place-items: center;
}
.hero-logo {
  position: relative;
  z-index: 4;
  width: min(600px, 95%);
  max-height: 710px;
  object-fit: contain;
  filter: drop-shadow(0 34px 42px rgba(0,0,0,.72));
}
.spin-wheel {
  position: absolute;
  z-index: 1;
  width: min(570px, 84vw);
  aspect-ratio: 1;
  border-radius: 50%;
  opacity: .3;
  background: repeating-conic-gradient(
    from 0deg,
    var(--brand-soft) 0 6deg,
    transparent 6deg 13deg
  );
  animation: spin 42s linear infinite;
  mask-image: radial-gradient(circle, transparent 0 22%, black 23% 70%, transparent 71%);
}
.orbit {
  position: absolute;
  border-radius: 50%;
  border: 1px solid rgba(200,175,217,.25);
}
.orbit-one { width: 66%; aspect-ratio: 1; animation: reverse-spin 32s linear infinite; }
.orbit-two { width: 82%; aspect-ratio: 1; border-style: dashed; opacity: .42; animation: spin 56s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }
@keyframes reverse-spin { to { transform: rotate(-360deg); } }

.scroll-cue {
  position: absolute;
  z-index: 5;
  display: inline-flex;
  align-items: center;
  /*
   * 44 tall from a 14px line, with `bottom` walked down by the same 15 the box
   * grew upward, so the words sit exactly where they always did.
   */
  min-height: 44px;
  left: clamp(20px, 5vw, 76px);
  bottom: 10px;
  color: #8d8791;
  font-size: .68rem;
  text-transform: uppercase;
  letter-spacing: .14em;
}
.scroll-cue-arrow { color: var(--brand-soft); margin-left: 9px; }

/*
 * The band and its control, stacked. The button used to be absolutely
 * positioned inside the strip, which meant it sat ON the marquee: a 123px
 * opaque pill over the right-hand tenth of a 1280px bar, with the phrases
 * sliding out of sight behind it. The fix is structural rather than a nudge --
 * the band is its own box and the control lives under it, so nothing overlaps
 * at any width and the strip is whole again.
 */
.ticker-bar {
  display: grid;
  justify-items: end;
}
.ticker {
  position: relative;
  width: 100%;
  overflow: hidden;
  background: var(--brand);
  color: #0c0b0e;
  border-block: 1px solid rgba(255,255,255,.16);
}
/* On the page ground now, not on brand, so it takes the header's outlined
   treatment: white on near-black rather than ink on purple. Set to the same
   gutter the sections use, so it lines up with the content edge below it. */
.ticker-pause {
  display: flex;
  align-items: center;
  gap: 7px;
  /* Tall enough to be a comfortable thumb target. */
  min-height: 44px;
  margin: 12px clamp(20px, 5vw, 76px) 0;
  padding: 0 15px;
  color: #fff;
  background: transparent;
  border: 1px solid rgba(255,255,255,.46);
  border-radius: 999px;
  cursor: pointer;
  font-family: var(--font-display);
  font-size: .68rem;
  letter-spacing: .1em;
  text-transform: uppercase;
}
.ticker-pause:hover { background: rgba(255,255,255,.09); border-color: rgba(255,255,255,.7); }
.ticker-pause-glyph { font-family: system-ui, sans-serif; font-size: .8em; }
.ticker-track {
  width: max-content;
  display: flex;
  align-items: center;
  gap: 28px;
  padding: 16px 0;
  animation: ticker 24s linear infinite;
  font-family: var(--font-display);
  font-size: 1.05rem;
  letter-spacing: .09em;
}
.ticker-track i { font-style: normal; }
@keyframes ticker { to { transform: translateX(-50%); } }

/*
 * Everything that moves forever, stopped on request -- WCAG 2.0 2.2.2.
 *
 * This is the complete inventory of `animation-iteration-count: infinite` on
 * the site: the banner, the hero's spin-wheel and its two orbits, the scroll
 * cue's nudge and the comic cover hint's pulse. Grep for `infinite` before
 * adding an animation that never ends, and add it here in the same commit --
 * a loop this list does not name is a loop the button silently fails to stop.
 *
 * Named one by one rather than as a blanket `*`. animation-play-state freezes
 * an animation exactly where it stands, so a blanket rule would catch the
 * one-shot animations mid-flight and leave, say, the sticker slam with half
 * its badges stopped in the air until the visitor pressed play again.
 *
 * `!important` for the same reason the reduced-motion block in styles-shell.css
 * uses it: several of these are declared with the `animation` shorthand, which
 * resets play-state to running, and `.hero.scroll-explosion .scroll-cue`
 * outranks anything this selector can reach without it.
 */
html.motion-paused .ticker-track,
html.motion-paused .spin-wheel,
html.motion-paused .orbit,
html.motion-paused .scroll-cue,
html.motion-paused .featured-3d-cover-hint {
  animation-play-state: paused !important;
}

.section { padding: clamp(78px, 9vw, 145px) clamp(20px, 5vw, 76px); }
.section-heading {
  display: grid;
  grid-template-columns: 1.1fr .9fr;
  align-items: end;
  gap: 70px;
  margin-bottom: 54px;
}
.section h2 { font-size: clamp(3.86rem, 7.36vw, 7.82rem); }
.section-copy {
  max-width: 590px;
  justify-self: end;
}
/* The visible featured headings are painted onto the rack's 3D sign. Keep the
   matching document heading available to assistive technology without leaving
   a second typographic billboard above the prop. */
.featured-sign-heading {
  position: relative;
  grid-template-columns: 1fr;
}
.featured-sign-heading .section-copy {
  justify-self: center;
  text-align: center;
}
/* Screen-reader-only text -- the landing page's three hidden spans share the
   one rule. catalog.css carries the same rule for the shop and admin pages. */
.featured-heading-a11y,
.featured-3d-status,
.featured-3d-book-controls button span {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  border: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}
.section-copy p {
  margin: 0;
  color: var(--muted);
  line-height: 1.75;
}
.concept-label {
  display: inline-block;
  margin-top: 18px;
  border: 1px solid var(--line);
  padding: 8px 10px;
  color: #817b85;
  text-transform: uppercase;
  letter-spacing: .12em;
  font-size: .62rem;
}

/* Skip link -- WCAG 2.0 2.4.1 Bypass Blocks.

   Placed inside the page header rather than before it. On the landing page that
   is what puts it under the age gate's `inert` sweep for free: the gate inerts
   .site-header, #top and the footer, so a skip link outside all three would stay
   tabbable while the gate was up and would land a keyboard user in inert
   content. Inside the header it is simply unreachable until the gate lifts, and
   is then the first thing Tab reaches.

   `position: absolute` while hidden, so it is out of the header's flex flow and
   cannot shift the layout; `fixed` once focused, so it appears at the top of the
   viewport regardless of where the header has scrolled to. */
.skip-link {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.skip-link:focus {
  position: fixed;
  top: 1rem;
  left: 1rem;
  z-index: 10000;
  width: auto;
  height: auto;
  margin: 0;
  padding: .75rem 1.25rem;
  overflow: visible;
  clip-path: none;
  border-radius: .5rem;
  background: #171219;
  color: #fff;              /* 16.6:1 on #171219 */
  font: 700 1rem/1 system-ui, sans-serif;
  text-decoration: none;
  outline: 3px solid #fff;
  outline-offset: 3px;
}

/* The skip destination is a landmark, not a control -- it takes focus so the
   next Tab continues from the content, but a ring drawn around the whole of
   <main> reads as a rendering fault rather than an indicator. */
main:focus { outline: none; }
