/* Undercover Comics — hand-written, one file.
 *
 * Direction: the shop after close, lit by two things. The cold blue is the
 * mascot's eyes and it is the site's key light; the ember is the little fire at
 * his feet and it is the only warm thing on the page. Everything else is ink
 * and bone. Nothing is grey-on-grey, because a comic shop is not a bank.
 *
 * Type is a film poster: Big Shoulders Display, condensed and set enormous, for
 * anything that shouts. Inter Tight carries the reading. JetBrains Mono carries
 * anything that is data rather than prose — times, prices, entry fees.
 *
 * The signature is the hero. It is `position: sticky`, so the page rises over
 * it like a shutter coming down; the title drops back, the room dims, and the
 * mascot sinks. On a pointer the three layers move by different amounts. All of
 * it degrades: no JavaScript is a static, complete hero, and
 * prefers-reduced-motion turns off every part of the movement.
 */

/* ---------------------------------------------------------------- tokens */

:root {
  --ink: #07080e;
  --ink2: #0c0e17;
  --ink3: #12151f;
  --ink4: #191d2a;
  --bone: #e9ecf5;
  --muted: #7f889f;
  --cold: #6fc3ff;
  --cold-deep: #2f6ea8;
  --ember: #ffab3d;
  --ember-deep: #b3630f;

  --line: rgb(233 236 245 / 9%);
  --line-strong: rgb(233 236 245 / 20%);

  --display: "Big Shoulders Display", "Haettenschweiler", "Arial Narrow", sans-serif;
  --body: "Inter Tight", system-ui, -apple-system, "Segoe UI", sans-serif;
  --mono: "JetBrains Mono", ui-monospace, "SF Mono", monospace;

  --gutter: clamp(20px, 5vw, 92px);
  /* Half the space between two sections, because both sides pay it. Setting it
   * as a full gap once produced a doubled 400px void wherever two padded
   * sections met. */
  --rhythm: clamp(56px, 6.6vw, 104px);
  --measure: 60ch;

  --ease: cubic-bezier(0.22, 0.61, 0.36, 1);
  --header: 74px;
}

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

/* ---------------------------------------------------------------- base */

html {
  scroll-behavior: smooth;
  /* The header is fixed, so an anchor would otherwise land under it. */
  scroll-padding-top: calc(var(--header) + 26px);
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  background: var(--ink);
  color: var(--bone);
  font-family: var(--body);
  font-size: 16.5px;
  line-height: 1.62;
  font-synthesis-weight: none;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

img {
  max-width: 100%;
  display: block;
}

a {
  color: inherit;
}

h1,
h2,
h3 {
  margin: 0;
  font-weight: 400;
}

p {
  margin: 0;
}

ul,
ol,
dl,
dd {
  margin: 0;
  padding: 0;
  list-style: none;
}

:focus-visible {
  outline: 2px solid var(--cold);
  outline-offset: 3px;
}

::selection {
  background: var(--cold);
  color: var(--ink);
}

.skip {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 300;
  padding: 14px 20px;
  background: var(--bone);
  color: var(--ink);
  font-family: var(--mono);
  font-size: 12px;
  text-decoration: none;
}

.skip:focus {
  left: 0;
}

/* Film grain. Fixed so it does not travel with the content, and blended rather
 * than laid on top, so it sits under the bone type instead of hazing it. */
.grain {
  position: fixed;
  inset: -50%;
  z-index: 150;
  pointer-events: none;
  opacity: 0.045;
  mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='200' height='200'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3' stitchTiles='stitch'/></filter><rect width='200' height='200' filter='url(%23n)'/></svg>");
  animation: drift 7s steps(6) infinite;
}

@keyframes drift {
  0% { transform: translate(0, 0); }
  20% { transform: translate(-3%, 2%); }
  40% { transform: translate(2%, -3%); }
  60% { transform: translate(-2%, -2%); }
  80% { transform: translate(3%, 1%); }
  100% { transform: translate(0, 0); }
}

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

.label {
  margin: 0;
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--muted);
}

.label a {
  color: var(--cold);
  text-decoration: none;
}

.label span {
  opacity: 0.4;
}

.display {
  font-family: var(--display);
  font-weight: 700;
  font-size: clamp(40px, 6.2vw, 82px);
  line-height: 0.92;
  letter-spacing: -0.015em;
  text-transform: uppercase;
}

.display.huge {
  font-size: clamp(52px, 9vw, 132px);
}

.display.small {
  font-size: clamp(26px, 3vw, 34px);
}

/* One word of a heading, lit. The CMS help text names this class, so an editor
 * chooses which word it lands on. */
.lit {
  color: var(--cold);
  font-style: normal;
}

.lede {
  color: rgb(233 236 245 / 74%);
  font-size: clamp(16px, 1.35vw, 19px);
  max-width: var(--measure);
}

.textlink {
  display: inline-block;
  color: var(--cold);
  text-decoration: none;
  font-family: var(--mono);
  font-size: 12.5px;
  letter-spacing: 0.06em;
  border-bottom: 1px solid rgb(111 195 255 / 30%);
  padding-bottom: 2px;
  transition: border-color 0.25s var(--ease), color 0.25s var(--ease);
}

.textlink:hover {
  border-color: var(--cold);
}

.button {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 15px 26px;
  background: var(--bone);
  color: var(--ink);
  border: 0;
  border-radius: 2px;
  font-family: var(--display);
  font-weight: 700;
  font-size: 18px;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  text-decoration: none;
  cursor: pointer;
  position: relative;
  overflow: hidden;
  transition: transform 0.3s var(--ease), box-shadow 0.3s var(--ease);
}

/* The light sweep. A single skewed highlight crossing the face of the button,
 * parked off to the left until it is asked for. */
.button::after {
  content: "";
  position: absolute;
  inset: -40% -10%;
  background: linear-gradient(100deg, transparent 38%, rgb(255 255 255 / 55%) 50%, transparent 62%);
  transform: translateX(-120%);
  transition: transform 0.6s var(--ease);
}

.button:hover {
  transform: translateY(-2px);
  box-shadow: 0 14px 40px rgb(111 195 255 / 22%);
}

.button:hover::after {
  transform: translateX(120%);
}

.button.small {
  padding: 10px 18px;
  font-size: 15px;
}

/* ---------------------------------------------------------------- chrome */

.announce {
  position: relative;
  z-index: 60;
  background: var(--ink2);
  border-bottom: 1px solid var(--line);
  text-align: center;
  padding: 9px 20px;
  font-size: 13px;
  color: rgb(233 236 245 / 72%);
}

.announce a {
  color: var(--cold);
  text-decoration: none;
  border-bottom: 1px solid rgb(111 195 255 / 35%);
  margin-left: 6px;
}

.pip {
  display: inline-block;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--ember);
  margin-right: 10px;
  vertical-align: 1px;
  box-shadow: 0 0 10px var(--ember);
  animation: breathe 2.6s ease-in-out infinite;
}

@keyframes breathe {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.35; }
}

.header {
  position: sticky;
  top: 0;
  z-index: 80;
  height: var(--header);
  display: flex;
  align-items: center;
  gap: 32px;
  padding: 0 var(--gutter);
  transition: background 0.35s var(--ease), border-color 0.35s var(--ease), backdrop-filter 0.35s var(--ease);
  border-bottom: 1px solid transparent;
}

.header.stuck {
  background: rgb(7 8 14 / 82%);
  backdrop-filter: blur(14px) saturate(140%);
  border-bottom-color: var(--line);
}

.wordmark {
  display: grid;
  gap: 1px;
  text-decoration: none;
  margin-right: auto;
}

.wordmarkname {
  font-family: var(--display);
  font-weight: 800;
  font-size: 23px;
  line-height: 1;
  letter-spacing: 0.005em;
  text-transform: uppercase;
}

.wordmarkkind {
  font-family: var(--mono);
  font-size: 8.5px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--muted);
}

.nav {
  display: flex;
  gap: 26px;
}

.nav a {
  font-size: 14px;
  text-decoration: none;
  color: rgb(233 236 245 / 76%);
  transition: color 0.25s var(--ease);
}

.nav a:hover {
  color: var(--cold);
}

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

.hero {
  --leave: 0;
  --px: 0;
  --py: 0;
  position: sticky;
  top: 0;
  height: 100svh;
  min-height: 620px;
  margin-top: calc(var(--header) * -1);
  overflow: hidden;
  isolation: isolate;
}

/* The room: a cold key light from above, a floor it falls on, and a warm pool
 * where the fire is. None of it moves except with the page. */
.stage {
  position: absolute;
  inset: 0;
  z-index: 0;
}

.beam {
  position: absolute;
  inset: 0;
  background:
    radial-gradient(110% 70% at 68% -12%, rgb(63 132 196 / 34%), transparent 62%),
    radial-gradient(80% 60% at 20% 0%, rgb(31 60 96 / 34%), transparent 70%),
    linear-gradient(180deg, var(--ink2) 0%, var(--ink) 58%, #04050a 100%);
}

.halo {
  position: absolute;
  left: 40%;
  right: -10%;
  top: 8%;
  height: 62%;
  background: radial-gradient(closest-side, rgb(84 168 235 / 26%), transparent 78%);
  filter: blur(30px);
  transform: translate3d(calc(var(--px) * -22px), calc(var(--py) * -12px), 0);
  transition: transform 0.5s var(--ease);
}

.ember {
  position: absolute;
  left: 52%;
  right: 6%;
  bottom: -8%;
  height: 34%;
  background: radial-gradient(closest-side, rgb(255 150 45 / 22%), transparent 74%);
  filter: blur(26px);
  animation: flicker 3.4s ease-in-out infinite;
}

@keyframes flicker {
  0%, 100% { opacity: 0.85; }
  35% { opacity: 1; }
  55% { opacity: 0.7; }
  70% { opacity: 0.95; }
}

.floor {
  position: absolute;
  inset: auto 0 0;
  height: 40%;
  background: linear-gradient(180deg, transparent, rgb(4 5 10 / 92%) 72%);
}

/* The title, behind him. This is the poster, so it is set as large as the
 * viewport allows and the mascot is allowed to stand in front of it. */
.heromark {
  position: absolute;
  z-index: 1;
  left: 0;
  right: 0;
  top: clamp(74px, 10vh, 128px);
  text-align: center;
  font-family: var(--display);
  font-weight: 800;
  font-size: clamp(88px, 19vw, 300px);
  line-height: 0.8;
  letter-spacing: -0.02em;
  text-transform: uppercase;
  background: linear-gradient(180deg, rgb(233 236 245 / 96%) 12%, rgb(140 165 200 / 42%) 78%, rgb(120 150 190 / 12%));
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  transform: translate3d(calc(var(--px) * -16px), calc(var(--py) * -8px + var(--leave) * -70px), 0)
    scale(calc(1 - var(--leave) * 0.05));
  opacity: calc(1 - var(--leave) * 1.15);
  transition: transform 0.5s var(--ease);
  user-select: none;
}

.herofigure {
  position: absolute;
  z-index: 2;
  right: 0;
  bottom: 0;
  width: min(88svh, 66vw);
  transform: translate3d(calc(var(--px) * 20px), calc(var(--py) * 11px + var(--leave) * 46px), 0);
  transition: transform 0.5s var(--ease);
  pointer-events: none;
}

/* The glow he casts, kept inside the figure so it travels with him rather than
 * with the room. */
.herofigure::before {
  content: "";
  position: absolute;
  inset: -18% -12% 6%;
  background: radial-gradient(ellipse at 50% 40%, rgb(78 158 228 / 30%), transparent 62%);
  filter: blur(18px);
  z-index: -1;
}

.herofigure img {
  width: 100%;
  height: auto;
  filter: drop-shadow(0 30px 60px rgb(0 0 0 / 65%));
}

/* Two small pools over the eyes in the artwork, screened on so they read as
 * emission rather than paint. The coordinates are fractions of the image, so
 * they hold at every size. */
.eyes {
  position: absolute;
  inset: 0;
  background:
    radial-gradient(circle at 42.2% 39%, rgb(168 230 255 / 95%), transparent 3.4%),
    radial-gradient(circle at 58.2% 39.2%, rgb(168 230 255 / 95%), transparent 3.4%);
  filter: blur(7px);
  mix-blend-mode: screen;
  animation: stare 5.2s ease-in-out infinite;
}

@keyframes stare {
  0%, 100% { opacity: 0.55; }
  50% { opacity: 1; }
}

.heroinner {
  position: absolute;
  z-index: 3;
  left: var(--gutter);
  bottom: clamp(150px, 26vh, 260px);
  max-width: min(44ch, 44vw);
  transform: translateY(calc(var(--leave) * -34px));
  opacity: calc(1 - var(--leave) * 1.4);
}

/* The copy sits in front of a title set large enough to run behind it, which is
 * the whole composition — so it carries its own pool of shadow rather than
 * asking the title to get out of the way. */
.heroinner::before {
  content: "";
  position: absolute;
  inset: -70px -140px -60px -120px;
  z-index: -1;
  background: radial-gradient(ellipse at 34% 52%, rgb(4 5 10 / 92%) 18%, rgb(4 5 10 / 62%) 46%, transparent 74%);
}

.herohead {
  font-family: var(--display);
  font-weight: 600;
  font-size: clamp(34px, 4.1vw, 58px);
  line-height: 0.96;
  letter-spacing: -0.01em;
  text-transform: uppercase;
  margin: 16px 0 18px;
  text-wrap: balance;
}

.heroactions {
  display: flex;
  align-items: center;
  gap: 26px;
  margin-top: 28px;
  flex-wrap: wrap;
}

.heronote {
  margin-top: 16px;
  font-family: var(--mono);
  font-size: 11.5px;
  letter-spacing: 0.06em;
  color: var(--muted);
}

.herostats {
  position: absolute;
  z-index: 3;
  left: var(--gutter);
  bottom: clamp(52px, 8vh, 84px);
  display: flex;
  gap: clamp(26px, 4vw, 56px);
  opacity: calc(1 - var(--leave) * 1.6);
}

.herostat dt {
  font-family: var(--display);
  font-weight: 700;
  font-size: clamp(28px, 3.2vw, 44px);
  line-height: 1;
  color: var(--bone);
}

.herostat dd {
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--muted);
  margin-top: 7px;
  max-width: 24ch;
}

.scrollcue {
  position: absolute;
  z-index: 3;
  right: 26px;
  bottom: clamp(52px, 8vh, 84px);
  transform-origin: 100% 100%;
  transform: rotate(-90deg) translateX(6px);
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: 0.32em;
  text-transform: uppercase;
  color: var(--muted);
  opacity: calc(1 - var(--leave) * 2);
}

.scrollcue::after {
  content: "";
  display: inline-block;
  width: 44px;
  height: 1px;
  background: currentcolor;
  margin-left: 14px;
  vertical-align: 3px;
  animation: reach 2.4s var(--ease) infinite;
  transform-origin: 0 50%;
}

@keyframes reach {
  0%, 100% { transform: scaleX(0.35); opacity: 0.5; }
  50% { transform: scaleX(1); opacity: 1; }
}

/* The shutter. Opaque, so the sticky hero disappears behind it rather than
 * showing through, and shadowed so the edge reads as a physical thing. */
.sheet {
  position: relative;
  z-index: 4;
  background: var(--ink);
  border-top: 1px solid var(--line-strong);
  box-shadow: 0 -70px 140px rgb(0 0 0 / 85%);
}

/* ---------------------------------------------------------------- ticker */

.ticker {
  overflow: hidden;
  border-bottom: 1px solid var(--line);
  padding: 17px 0;
  mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
}

.tickertrack {
  display: flex;
  gap: 46px;
  width: max-content;
  animation: roll 46s linear infinite;
}

.tickeritem {
  font-family: var(--mono);
  font-size: 11.5px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--muted);
  white-space: nowrap;
}

.tickeritem::before {
  content: "◆";
  color: var(--cold-deep);
  margin-right: 46px;
  font-size: 8px;
  vertical-align: 2px;
}

@keyframes roll {
  from { transform: translateX(0); }
  to { transform: translateX(-50%); }
}

/* ---------------------------------------------------------------- sections */

.sectionhead {
  max-width: 62ch;
}

.sectionhead.wide {
  max-width: 80ch;
}

.sectionhead .display,
.pullsay .display,
.storysay .display {
  margin: 14px 0 18px;
  text-wrap: balance;
}

.drop,
.inside,
.pull,
.events,
.regulars,
.story,
.visit {
  padding: var(--rhythm) var(--gutter);
}

.events + .events,
.inside {
  padding-top: 0;
}

/* ---------------------------------------------------------------- the rail */

.drop {
  padding-bottom: calc(var(--rhythm) * 0.7);
}

.drophead {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 40px;
  margin-bottom: 46px;
}

.railnav {
  display: flex;
  gap: 10px;
  flex-shrink: 0;
}

.railbutton {
  width: 46px;
  height: 46px;
  border: 1px solid var(--line-strong);
  background: transparent;
  color: var(--bone);
  border-radius: 50%;
  cursor: pointer;
  font-size: 16px;
  transition: background 0.25s var(--ease), border-color 0.25s var(--ease), opacity 0.25s var(--ease);
}

.railbutton:hover:not(:disabled) {
  background: var(--ink3);
  border-color: var(--cold);
  color: var(--cold);
}

.railbutton:disabled {
  opacity: 0.25;
  cursor: default;
}

/* No JavaScript means no arrows worth showing — the list still scrolls. */
html:not(.js) .railnav,
html:not(.js) .railbar,
.railstatic .railnav,
.railstatic .railbar {
  display: none;
}

.railtrack {
  display: flex;
  gap: 22px;
  overflow-x: auto;
  /* Explicit, because `overflow-x: auto` alone computes overflow-y to `auto`
   * as well — which makes the rail a vertical scroll container that swallows
   * the wheel, and a visitor scrolling with the cursor over it gets stuck on
   * this section. */
  overflow-y: hidden;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
  padding-bottom: 6px;
  margin: 0 calc(var(--gutter) * -1);
  padding-inline: var(--gutter);
}

.railtrack::-webkit-scrollbar {
  display: none;
}

.railtrack.dragging {
  scroll-snap-type: none;
  cursor: grabbing;
  user-select: none;
}

.railtrack.dragging * {
  pointer-events: none;
}

.pick {
  flex: 0 0 clamp(258px, 27vw, 340px);
  scroll-snap-align: start;
  display: flex;
  flex-direction: column;
  position: relative;
  background: linear-gradient(180deg, var(--ink3), var(--ink2));
  border: 1px solid var(--line);
  border-radius: 4px;
  overflow: hidden;
  transition: transform 0.4s var(--ease), border-color 0.4s var(--ease), box-shadow 0.4s var(--ease);
}

.pick:hover {
  transform: translateY(-8px);
  border-color: rgb(111 195 255 / 34%);
  box-shadow: 0 26px 60px rgb(0 0 0 / 55%), 0 0 40px rgb(111 195 255 / 8%);
}

.pickface {
  aspect-ratio: 2 / 3;
  position: relative;
  display: grid;
  place-items: center;
  overflow: hidden;
  border-bottom: 1px solid var(--line);
}

.pickface img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* A pick with no cover art. Setting the publisher large is a better answer
 * than an empty box, and most of what a shop wants to shout about on a
 * Wednesday arrives without a usable image. */
.pickblank {
  padding: 0 22px;
  font-family: var(--display);
  font-weight: 800;
  font-size: clamp(34px, 4vw, 52px);
  line-height: 0.9;
  text-align: center;
  text-transform: uppercase;
  text-wrap: balance;
  color: rgb(233 236 245 / 16%);
}

.pickflag {
  position: absolute;
  top: 14px;
  left: 14px;
  padding: 5px 10px;
  background: var(--ember);
  color: #1b0f00;
  font-family: var(--mono);
  font-size: 9.5px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  border-radius: 2px;
}

.pickbody {
  padding: 22px 22px 0;
  flex: 1;
}

.picktitle {
  font-family: var(--display);
  font-weight: 700;
  font-size: 27px;
  line-height: 1.02;
  text-transform: uppercase;
  margin: 10px 0 10px;
}

.picksummary {
  color: rgb(233 236 245 / 66%);
  font-size: 14.5px;
  line-height: 1.55;
}

.pickprice {
  padding: 18px 22px 22px;
  font-family: var(--mono);
  font-size: 13px;
  color: var(--ember);
}

/* Tints cycle by position so two adjacent cards never read as the same card. */
.tint-cold .pickface { background: radial-gradient(120% 90% at 50% 0%, rgb(47 110 168 / 40%), var(--ink2)); }
.tint-ember .pickface { background: radial-gradient(120% 90% at 50% 0%, rgb(179 99 15 / 34%), var(--ink2)); }
.tint-bone .pickface { background: radial-gradient(120% 90% at 50% 0%, rgb(233 236 245 / 14%), var(--ink2)); }
.tint-deep .pickface { background: radial-gradient(120% 90% at 50% 0%, rgb(25 29 42 / 90%), #06070c); }

.railbar {
  height: 2px;
  background: var(--line);
  margin-top: 30px;
  position: relative;
  overflow: hidden;
}

.railbar span {
  position: absolute;
  inset: 0 auto 0 0;
  width: 34%;
  background: var(--cold);
  transform: translateX(calc(var(--at, 0) * 194%));
  transition: transform 0.2s linear;
}

.dropnote {
  margin-top: 22px;
  font-family: var(--mono);
  font-size: 11.5px;
  letter-spacing: 0.06em;
  color: var(--muted);
}

/* ---------------------------------------------------------------- shelves */

.shelves {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(340px, 1fr));
  gap: 1px;
  margin-top: 54px;
  background: var(--line);
  border: 1px solid var(--line);
}

.shelf {
  position: relative;
  display: flex;
  flex-direction: column;
  padding: 40px 34px 42px;
  background: var(--ink);
  overflow: hidden;
  transition: background 0.4s var(--ease);
}

/* The torch: a pool of light that follows the pointer across the panel. The
 * coordinates come from ../src/client/spot.ts. */
.shelf::before,
.pull::before,
.visit::before {
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(340px circle at var(--mx, 50%) var(--my, 0%), rgb(111 195 255 / 9%), transparent 68%);
  opacity: 0;
  transition: opacity 0.4s var(--ease);
  pointer-events: none;
}

.shelf.torch::before,
.pull.torch::before,
.visit.torch::before {
  opacity: 1;
}

.shelf > * {
  position: relative;
}

.shelfnum {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.2em;
  color: var(--cold-deep);
}

.shelfname {
  font-family: var(--display);
  font-weight: 700;
  font-size: 34px;
  line-height: 1;
  text-transform: uppercase;
  margin: 16px 0 10px;
}

.shelfsummary {
  color: var(--bone);
  font-size: 16px;
  margin-bottom: 14px;
}

.shelfbody {
  color: rgb(233 236 245 / 62%);
  font-size: 14.5px;
  line-height: 1.6;
}

.shelfpoints {
  margin-top: 22px;
  display: grid;
  gap: 9px;
}

.shelfpoints li {
  position: relative;
  padding-left: 20px;
  font-size: 14px;
  color: rgb(233 236 245 / 78%);
}

.shelfpoints li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 9px;
  width: 8px;
  height: 1px;
  background: var(--cold);
}

.shelfnote {
  /* Pushed down so the notes line up along the bottom of a row of panels of
   * different lengths. */
  margin-top: auto;
  padding-top: 22px;
  padding-top: 18px;
  border-top: 1px solid var(--line);
  font-family: var(--mono);
  font-size: 11px;
  line-height: 1.6;
  color: var(--muted);
}

/* ---------------------------------------------------------------- pull list */

.pull {
  position: relative;
  background: linear-gradient(180deg, var(--ink2), var(--ink));
  border-block: 1px solid var(--line);
  overflow: hidden;
}

.pullinner {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 0.85fr);
  gap: clamp(40px, 6vw, 96px);
  align-items: start;
}

.pullsteps {
  margin-top: 44px;
  display: grid;
  gap: 26px;
}

.pullstep {
  display: grid;
  grid-template-columns: 46px 1fr;
  gap: 20px;
  align-items: start;
}

.stepnum {
  font-family: var(--display);
  font-weight: 700;
  font-size: 34px;
  line-height: 0.9;
  color: rgb(111 195 255 / 55%);
}

.stepname {
  font-family: var(--display);
  font-weight: 600;
  font-size: 22px;
  text-transform: uppercase;
  letter-spacing: 0.01em;
}

.pullstep p {
  color: rgb(233 236 245 / 64%);
  font-size: 14.5px;
  margin-top: 4px;
}

.pullform {
  background: var(--ink3);
  border: 1px solid var(--line-strong);
  border-radius: 4px;
  padding: clamp(26px, 3vw, 40px);
}

.field {
  display: grid;
  gap: 8px;
  margin-bottom: 18px;
}

.field label {
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted);
}

.field label span {
  opacity: 0.55;
  text-transform: none;
  letter-spacing: 0.06em;
}

.field input,
.field textarea {
  width: 100%;
  background: var(--ink);
  border: 1px solid var(--line-strong);
  border-radius: 2px;
  padding: 13px 14px;
  color: var(--bone);
  font-family: var(--body);
  font-size: 15px;
  transition: border-color 0.25s var(--ease), box-shadow 0.25s var(--ease);
}

.field textarea {
  resize: vertical;
  line-height: 1.55;
}

.field input:focus,
.field textarea:focus {
  outline: none;
  border-color: var(--cold);
  box-shadow: 0 0 0 3px rgb(111 195 255 / 14%);
}

.field ::placeholder {
  color: rgb(127 136 159 / 70%);
}

.trap {
  position: absolute;
  left: -9999px;
}

.formnote {
  margin-top: 16px;
  font-family: var(--mono);
  font-size: 11px;
  color: var(--muted);
}

.formerror {
  margin-bottom: 18px;
  padding: 12px 14px;
  border-left: 2px solid var(--ember);
  background: rgb(255 171 61 / 8%);
  font-size: 14px;
}

.pullsent .display {
  margin-bottom: 12px;
}

.pullsent p {
  color: rgb(233 236 245 / 70%);
  font-size: 15px;
}

/* ---------------------------------------------------------------- the board */

.board {
  margin-top: 48px;
  border-top: 1px solid var(--line);
}

.slot {
  display: grid;
  grid-template-columns: minmax(120px, 1.1fr) 96px minmax(0, 3fr) minmax(0, 1.6fr);
  gap: 24px;
  align-items: baseline;
  padding: 22px 4px;
  border-bottom: 1px solid var(--line);
  position: relative;
  transition: padding-left 0.35s var(--ease);
}

.slot::before {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(90deg, rgb(111 195 255 / 8%), transparent 55%);
  opacity: 0;
  transition: opacity 0.35s var(--ease);
}

.slot:hover {
  padding-left: 16px;
}

.slot:hover::before {
  opacity: 1;
}

.slot > * {
  position: relative;
}

.slotday {
  font-family: var(--display);
  font-weight: 700;
  font-size: clamp(22px, 2.4vw, 30px);
  text-transform: uppercase;
  line-height: 1;
}

.slottime {
  font-family: var(--mono);
  font-size: 13px;
  color: var(--cold);
}

.slottitle {
  font-size: 16.5px;
  color: var(--bone);
}

.slotnote {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
  text-align: right;
}

/* ---------------------------------------------------------------- events */

.nextup {
  margin-top: 68px;
}

.eventcards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(310px, 1fr));
  gap: 18px;
  margin: 24px 0 30px;
}

.eventcards.tall {
  grid-template-columns: 1fr;
  margin-top: 44px;
}

.eventcard {
  display: grid;
}

.eventcard a {
  display: grid;
  height: 100%;
  grid-template-columns: 74px 1fr auto;
  gap: 22px;
  align-items: center;
  padding: 22px 24px;
  background: var(--ink2);
  border: 1px solid var(--line);
  border-left: 2px solid var(--cold-deep);
  border-radius: 3px;
  text-decoration: none;
  transition: transform 0.35s var(--ease), border-color 0.35s var(--ease), background 0.35s var(--ease);
}

.eventcard a:hover {
  transform: translateX(4px);
  background: var(--ink3);
  border-left-color: var(--cold);
}

.kind-comics a { border-left-color: var(--ember-deep); }
.kind-comics a:hover { border-left-color: var(--ember); }
.kind-pokemon a { border-left-color: rgb(233 236 245 / 35%); }
.kind-pokemon a:hover { border-left-color: var(--bone); }
.kind-community a { border-left-color: var(--ember-deep); }
.kind-community a:hover { border-left-color: var(--ember); }

.eventdate {
  display: grid;
  place-items: center;
  gap: 2px;
  padding: 10px 0;
  background: var(--ink);
  border: 1px solid var(--line);
  border-radius: 2px;
}

.eventdate em {
  font-family: var(--mono);
  font-style: normal;
  font-size: 10px;
  letter-spacing: 0.16em;
  color: var(--muted);
}

.eventdate strong {
  font-family: var(--display);
  font-weight: 700;
  font-size: 30px;
  line-height: 1;
}

.eventbody {
  display: grid;
  gap: 6px;
  min-width: 0;
}

.eventtitle {
  font-family: var(--display);
  font-weight: 600;
  font-size: 25px;
  line-height: 1.02;
  text-transform: uppercase;
}

.eventsummary {
  color: rgb(233 236 245 / 60%);
  font-size: 14px;
  line-height: 1.5;
}

.eventtime {
  font-family: var(--mono);
  font-size: 12.5px;
  color: var(--cold);
  white-space: nowrap;
}

.empty {
  margin-top: 40px;
  padding: 34px;
  border: 1px dashed var(--line-strong);
  border-radius: 3px;
  color: rgb(233 236 245 / 66%);
  font-size: 15.5px;
}

.empty .textlink {
  margin-left: 10px;
}

.pastlist {
  margin-top: 40px;
  border-top: 1px solid var(--line);
}

.pastrow a {
  display: grid;
  grid-template-columns: minmax(0, 1.2fr) minmax(0, 2fr) auto;
  gap: 24px;
  align-items: baseline;
  padding: 18px 4px;
  border-bottom: 1px solid var(--line);
  text-decoration: none;
  color: rgb(233 236 245 / 62%);
  transition: color 0.3s var(--ease), padding-left 0.3s var(--ease);
}

.pastrow a:hover {
  color: var(--bone);
  padding-left: 14px;
}

.pastdate {
  font-family: var(--mono);
  font-size: 12px;
}

.pasttitle {
  font-family: var(--display);
  font-weight: 600;
  font-size: 22px;
  text-transform: uppercase;
}

/* ---------------------------------------------------------------- quotes */

.regulars {
  background: linear-gradient(180deg, var(--ink), var(--ink2));
  border-block: 1px solid var(--line);
}

.quotes {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
  gap: 26px;
  margin-top: 52px;
}

.quote {
  padding: 34px 32px;
  background: var(--ink3);
  border: 1px solid var(--line);
  border-radius: 3px;
  position: relative;
  display: flex;
  flex-direction: column;
}

.quote::before {
  content: "“";
  position: absolute;
  top: 6px;
  left: 22px;
  font-family: var(--display);
  font-size: 90px;
  line-height: 1;
  color: rgb(111 195 255 / 16%);
}

.quote blockquote {
  margin: 0;
  position: relative;
  font-size: 17px;
  line-height: 1.55;
  color: rgb(233 236 245 / 88%);
}

.quoteby {
  /* Pushed down so the names line up across a row of quotes of different
   * lengths. */
  margin-top: auto;
  padding-top: 22px;
  display: grid;
  gap: 5px;
}

.quotename {
  font-family: var(--display);
  font-weight: 700;
  font-size: 20px;
  text-transform: uppercase;
}

/* ---------------------------------------------------------------- story */

.story {
  display: grid;
  grid-template-columns: minmax(0, 0.72fr) minmax(0, 1fr);
  gap: clamp(40px, 6vw, 96px);
  align-items: center;
}

.storyart {
  position: relative;
  display: grid;
  place-items: center;
  aspect-ratio: 1;
  background: radial-gradient(circle at 50% 45%, rgb(47 110 168 / 26%), transparent 62%);
  border: 1px solid var(--line);
  border-radius: 3px;
  overflow: hidden;
}

.storyart img {
  width: 86%;
  height: auto;
  filter: drop-shadow(0 24px 46px rgb(0 0 0 / 70%));
}

.storyart::after {
  content: "";
  position: absolute;
  inset: auto 0 0;
  height: 46%;
  background: linear-gradient(180deg, transparent, var(--ink));
}

.storypara {
  margin-top: 18px;
  color: rgb(233 236 245 / 74%);
  font-size: 16.5px;
  max-width: 56ch;
}

.storypoints {
  margin-top: 36px;
  display: grid;
  gap: 12px;
  border-top: 1px solid var(--line);
  padding-top: 26px;
}

.storypoints li {
  position: relative;
  padding-left: 26px;
  font-size: 15px;
  color: rgb(233 236 245 / 82%);
}

.storypoints li::before {
  content: "◆";
  position: absolute;
  left: 0;
  top: 1px;
  font-size: 9px;
  color: var(--ember);
}

/* ---------------------------------------------------------------- visit */

.visit {
  position: relative;
  overflow: hidden;
  border-top: 1px solid var(--line);
}

.visitgrid {
  position: relative;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 22px;
  margin-top: 54px;
}

.visitcard {
  padding: 32px 30px;
  background: var(--ink2);
  border: 1px solid var(--line);
  border-radius: 3px;
  display: grid;
  align-content: start;
  justify-items: start;
  gap: 14px;
}

.visitaddress {
  font-family: var(--display);
  font-weight: 600;
  font-size: 28px;
  line-height: 1.08;
  text-transform: uppercase;
}

.visitnote {
  color: rgb(233 236 245 / 62%);
  font-size: 14.5px;
}

.hours {
  display: grid;
  gap: 2px;
}

.hourrow {
  display: flex;
  justify-content: space-between;
  gap: 18px;
  padding: 9px 10px;
  border-radius: 2px;
  font-size: 14.5px;
  color: rgb(233 236 245 / 74%);
}

.hourrow dd {
  font-family: var(--mono);
  font-size: 13px;
}

/* Today, so somebody checking at 6pm on a Tuesday finds the answer without
 * reading the whole table. Which row that is comes from ../src/present. */
.hourrow.today {
  background: rgb(255 171 61 / 10%);
  color: var(--bone);
}

.hourrow.today dd {
  color: var(--ember);
}

.visitbig {
  font-family: var(--display);
  font-weight: 700;
  font-size: 34px;
  text-transform: uppercase;
  text-decoration: none;
  line-height: 1;
}

.visitbig:hover {
  color: var(--cold);
}

.visitmail {
  font-family: var(--mono);
  font-size: 13px;
  color: rgb(233 236 245 / 74%);
  text-decoration: none;
  word-break: break-all;
}

.visitmail:hover {
  color: var(--cold);
}

/* ---------------------------------------------------------------- inner pages */

.page {
  position: relative;
  z-index: 4;
  background: var(--ink);
}

.pagehead {
  position: relative;
  padding: clamp(70px, 11vh, 130px) var(--gutter) clamp(50px, 7vh, 80px);
  overflow: hidden;
  border-bottom: 1px solid var(--line);
}

.pageglow {
  position: absolute;
  inset: -60% 22% auto -14%;
  height: 200%;
  background: radial-gradient(closest-side, rgb(66 140 208 / 46%), transparent 70%);
  filter: blur(24px);
}

/* Inner pages get no hero, so the mascot puts in an appearance here instead —
 * far enough right and faint enough to stay out of the reading. */
.pagemascot {
  position: absolute;
  right: clamp(-30px, -1vw, 0px);
  bottom: -18%;
  width: clamp(180px, 26vw, 380px);
  height: auto;
  opacity: 0.5;
  filter: drop-shadow(0 20px 50px rgb(0 0 0 / 70%));
  pointer-events: none;
}



/* `picture` is deliberately left static so the mascot inside it resolves
 * against the header rather than against an inline box with no height. */
.pagehead > *:not(picture) {
  position: relative;
}

.pagehead .display {
  max-width: 68%;
}

.pagehead .lede {
  max-width: min(52ch, 60%);
}

.pagehead .display {
  margin: 16px 0 20px;
  text-wrap: balance;
}

.eventmeta {
  padding: clamp(48px, 7vw, 84px) var(--gutter);
}

/* The page header already carries the air a hero would; the first section under
 * it does not need the full rhythm again. */
.page > section:first-of-type {
  padding-top: clamp(46px, 6vw, 78px);
}

.metagrid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: 1px;
  background: var(--line);
  border: 1px solid var(--line);
  margin-bottom: 48px;
}

.metaitem {
  background: var(--ink);
  padding: 24px 26px;
}

.metaitem dt {
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--muted);
}

.metaitem dd {
  font-family: var(--display);
  font-weight: 600;
  font-size: 24px;
  text-transform: uppercase;
  margin-top: 10px;
  line-height: 1.05;
}

.eventart {
  margin: 0 0 44px;
  border: 1px solid var(--line);
  border-radius: 3px;
  overflow: hidden;
}

.prose {
  max-width: var(--measure);
  display: grid;
  gap: 20px;
  color: rgb(233 236 245 / 78%);
  font-size: 17px;
}

.eventactions {
  display: flex;
  align-items: center;
  gap: 28px;
  margin-top: 44px;
  flex-wrap: wrap;
}

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

.footer {
  position: relative;
  z-index: 4;
  background: #04050a;
  border-top: 1px solid var(--line);
  padding: clamp(60px, 8vw, 100px) var(--gutter) 40px;
  overflow: hidden;
}

.footerstage {
  position: relative;
  display: grid;
  place-items: end center;
  margin-bottom: 40px;
}

.footermascot {
  width: clamp(150px, 18vw, 240px);
  height: auto;
  opacity: 0.72;
}

.footermark {
  position: absolute;
  inset: auto 0 -4%;
  text-align: center;
  font-family: var(--display);
  font-weight: 800;
  font-size: clamp(58px, 15vw, 220px);
  line-height: 0.78;
  letter-spacing: -0.02em;
  text-transform: uppercase;
  color: rgb(233 236 245 / 6%);
  z-index: -1;
  user-select: none;
}

.footercols {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: 34px;
  padding-top: 44px;
  border-top: 1px solid var(--line);
}

.footercol {
  display: grid;
  align-content: start;
  gap: 11px;
}

.footercol .label {
  margin-bottom: 4px;
}

.footerlink {
  font-size: 14.5px;
  color: rgb(233 236 245 / 70%);
  text-decoration: none;
  line-height: 1.5;
  transition: color 0.25s var(--ease);
}

.footerlink:hover {
  color: var(--cold);
}

.footerbase {
  display: flex;
  justify-content: space-between;
  gap: 24px;
  flex-wrap: wrap;
  margin-top: 54px;
  padding-top: 24px;
  border-top: 1px solid var(--line);
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.06em;
  color: var(--muted);
}

/* ---------------------------------------------------------------- reveal */

/* Nothing is hidden until the script has run: the class is added by
 * ../src/client/reveal.ts, so a bundle that failed to build leaves a complete
 * page rather than a blank one. */
html.js .reveal {
  opacity: 0;
  transform: translateY(24px);
  transition: opacity 0.7s var(--ease), transform 0.7s var(--ease);
}

html.js .reveal.shown {
  opacity: 1;
  transform: none;
}

/* ---------------------------------------------------------------- narrow */

@media (max-width: 1080px) {
  .pullinner {
    grid-template-columns: 1fr;
  }

  .story {
    grid-template-columns: 1fr;
  }

  .storyart {
    max-width: 380px;
  }

  .slot {
    grid-template-columns: minmax(96px, 1fr) 84px minmax(0, 2.4fr);
  }

  .slotnote {
    grid-column: 1 / -1;
    text-align: left;
    margin-top: -10px;
  }
}

@media (max-width: 880px) {
  .nav {
    display: none;
  }

  /* On a narrow screen the mascot cannot stand beside the copy, so he stands
   * behind it: pushed down, dimmed, and out of the way of the reading. */
  .hero {
    min-height: 560px;
  }

  .heromark {
    top: clamp(84px, 13vh, 120px);
    font-size: clamp(64px, 22vw, 150px);
  }

  .herofigure {
    right: 50%;
    width: min(150vw, 620px);
    transform: translateX(50%);
    opacity: 0.42;
  }

  .heroinner {
    bottom: clamp(120px, 22vh, 190px);
    max-width: none;
    right: var(--gutter);
  }

  .herostats {
    gap: 22px;
  }

  .herostat dd {
    max-width: 12ch;
  }

  .scrollcue {
    display: none;
  }

  .eventcard a {
    grid-template-columns: 62px 1fr;
  }

  .eventtime {
    grid-column: 2;
  }
}

@media (max-width: 560px) {
  .drophead {
    flex-direction: column;
    align-items: flex-start;
    gap: 26px;
  }

  .herostats {
    flex-wrap: wrap;
    gap: 18px 26px;
  }

  .footerbase {
    flex-direction: column;
    gap: 8px;
  }
}

/* ---------------------------------------------------------------- calm */

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }

  *,
  *::before,
  *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }

  /* The hero stops being a mechanism and becomes a picture. */
  .hero {
    position: relative;
  }

  .heromark,
  .herofigure,
  .heroinner,
  .halo {
    transform: none;
    opacity: 1;
  }

  .tickertrack {
    transform: none;
    flex-wrap: wrap;
  }

  html.js .reveal {
    opacity: 1;
    transform: none;
  }
}
