/* ============================================================== PSYCHE FACTS
   Spike. Offplat's bones (one centred column, hairline rules, Switzer, the
   three-state theme pattern) carrying chadlewine's Psyche Facts label as the
   object being browsed.

   Three-state theming, same as offplat: bare :root is the complete light
   palette, prefers-color-scheme redefines TOKENS ONLY for the unstamped
   document, and the [data-theme] stamp wins in both directions. No colour is
   ever declared only inside a theme block.
   ========================================================================= */

@font-face {
  font-family: "Switzer";
  src: url("/assets/switzer.d1bf801ffb.woff2") format("woff2");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}

:root {
  /* Bone, not mauve. Offplat owns hue 330; a label is printed on paper, so
     this ground is a warm low-saturation neutral around hue 40. */
  --bg:         #e7e4dc;
  --bg-soft:    #ddd9cf;
  --paper:      #f7f6f2;
  --paper-2:    #efede7;
  --ink:        #191713;
  --ink-bright: #0d0c0a;
  --ink-dim:    #7a746a;
  --rule:       #c4bfb2;
  --rule-soft:  #d8d3c7;
  --scrim:      rgb(25 23 19 / 0.5);

  /* THE ONE CHROMA IS THE TIER. Five values, and they are data rather than
     decoration: the coloured rule is what you read while a card flips past.
     RC's hexes are tuned for a dark ground and three of the five give out on
     bone, so light mode takes a darkened pair, exactly the way offplat carries
     two azures. These are eyeballed for the spike, not measured. */
  --violet: #6b21d4;
  --blue:   #1f5fd0;
  --green:  #227f38;
  --orange: #9a6300;
  --red:    #c02020;
  --warn:   #8a5a00;

  --rail: 1080px;  /* the reading column: masthead, standfirst, now, meta, footer */
  --card-w: 268px;
  --card-h: 400px;
  /* The deck's footing. The rail sits --rail-lift above the stage's bottom edge
     and the deck reserves --deck-foot under it, so the button that stands on
     the rail can be placed from the same two numbers instead of a guess. */
  --deck-foot: 18px;
  --rail-lift: 22px;

  --t-card:  280ms;  /* a card travelling through the deck */
  --t-ui:    200ms;
  --t-theme: 300ms;
  /* The finder is the one control that moves at half the UI speed (2026-08-20,
     Chad). It is not a state change, it is a shape change: a button becoming a
     field is a bigger claim than a border lighting up, and at 200ms it read as
     a glitch rather than a gesture. Everything in that one move shares the
     duration, so the placeholder cannot arrive before the box that holds it. */
  --t-finder: 400ms;
  --t-wipe:  600ms;
  --d-wipe:  110ms;

  --f: "Switzer", "Segoe UI", system-ui, -apple-system, "Helvetica Neue", Arial, sans-serif;
  /* The label body is monospace because a drug-facts panel is. It is the one
     place the site stops being a website and starts being a printed artifact. */
  --f-mono: ui-monospace, "Cascadia Mono", "SF Mono", Menlo, Consolas, monospace;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg:         #12110f;
    --bg-soft:    #1b1a17;
    --paper:      #1e1d19;
    --paper-2:    #262420;
    --ink:        #e6e3da;
    --ink-bright: #f7f5ef;
    --ink-dim:    #948d80;
    --rule:       #45413a;
    --rule-soft:  #322f29;
    --scrim:      rgb(0 0 0 / 0.62);
    --violet: #9933ff;
    --blue:   #3388ff;
    --green:  #33cc55;
    --orange: #ffbb33;
    --red:    #ff3333;
    --warn:   #e8b04b;
  }
}
:root[data-theme="dark"] {
  --bg:         #12110f;
  --bg-soft:    #1b1a17;
  --paper:      #1e1d19;
  --paper-2:    #262420;
  --ink:        #e6e3da;
  --ink-bright: #f7f5ef;
  --ink-dim:    #948d80;
  --rule:       #45413a;
  --rule-soft:  #322f29;
  --scrim:      rgb(0 0 0 / 0.62);
  --violet: #9933ff;
  --blue:   #3388ff;
  --green:  #33cc55;
  --orange: #ffbb33;
  --red:    #ff3333;
  --warn:   #e8b04b;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--f);
  font-size: 16px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  transition: background-color var(--t-theme) ease, color var(--t-theme) ease;
}

a { color: inherit; }

:where(button, a, input):focus-visible {
  outline: 2px solid var(--ink-bright);
  outline-offset: 2px;
}

.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0;
}

/* ---------------------------------------------------------------- shell -- */

.page {
  position: relative;
  z-index: 1;
  max-width: 1416px;
  margin: 0 auto;
  padding: 0 28px 120px;
}

.masthead, .standfirst-row, .meta, .now, footer.site {
  max-width: var(--rail);
  margin-left: auto;
  margin-right: auto;
}

.masthead { padding: 74px 0 20px; }

.wordmark {
  margin: 0;
  font-size: clamp(48px, 8.4vw, 96px);
  font-weight: 500;
  letter-spacing: -0.05em;
  line-height: 1.02;
  color: var(--ink-bright);
  padding-block: 2px;
}

.standfirst-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 16px 24px;
  margin-bottom: 30px;
}
/* No prose cap. The lede is one sentence and it runs as one line: the 46ch
   measure was tuned against the old 900px column and broke it over two lines
   in the wider one. The flex row bounds it instead, so it takes what is left
   beside the button and wraps only when the column gets narrow. */
.standfirst { margin: 0; font-size: 17px; flex: 1 1 20rem; }

/* The two ways in, as a pair. */
.standfirst-actions { display: flex; align-items: center; gap: 12px; flex: 0 0 auto; }

/* Offplat's continuous sweep: the fill enters left and, on release, keeps
   going and exits right. Transform only. */
.buy {
  position: relative;
  z-index: 0;
  flex: 0 0 auto;
  display: inline-block;
  padding: 8px 18px;
  border: 1px solid var(--ink);
  background: transparent;
  color: inherit;
  font-family: var(--f);
  font-size: 14.5px;
  text-decoration: none;
  white-space: nowrap;
  overflow: hidden;
  cursor: pointer;
  transition: color var(--t-wipe) ease var(--d-wipe);
}
.buy::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: var(--ink);
  transform: scaleX(0);
  transform-origin: right;
  transition: transform var(--t-wipe) ease;
}
.buy:hover::before, .buy:focus-visible::before { transform: scaleX(1); transform-origin: left; }
.buy:hover, .buy:focus-visible { color: var(--bg); }
.buy[disabled] { color: var(--ink-dim); border-color: var(--rule); cursor: default; }
.buy[disabled]::before { transform: scaleX(0); }

/* --------------------------------------------------------------- search -- */

/* THE FINDER (2026-08-20, Chad). The button BECOMES the field. One bordered
   box, and the border itself is what grows, leftward, out of the button that
   was there. It opens left because the button is the rightmost thing on the
   row: there is nowhere else for it to go.

   HORIZONTAL ONLY. The toggle stays in normal flow when it is invisible, so it
   keeps setting the box height and the row can never change height on open. The
   input is taken out of flow and laid over it.

   How far it opens is measured, not guessed: it stops with air between its left
   edge and the end of the lede, so the sentence never has to reflow. See
   expandedWidth() in site.js. */
.finder {
  position: relative;
  z-index: 0;
  flex: 0 0 auto;
  border: 1px solid var(--ink);
  overflow: hidden;
  transition: width var(--t-finder) ease, border-color var(--t-finder) ease,
              background-color var(--t-finder) ease;
}

/* Offplat's continuous sweep, moved onto the box so the whole control wipes
   rather than a button inside it. It stops being a button once it is a field. */
.finder::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  background: var(--ink);
  transform: scaleX(0);
  transform-origin: right;
  transition: transform var(--t-wipe) ease;
}
/* NOT WHILE IT IS CLOSING. The pointer is usually still sitting where the box
   is shrinking back to, so without this the sweep fires under the cursor before
   the control has finished being a field again, and the two motions collide.
   The class comes off when the width transition actually ends. */
.finder:not(.on):not(.closing):hover::before { transform: scaleX(1); transform-origin: left; }
.finder.on::before, .finder.closing::before { transform: scaleX(0); }

.finder-toggle {
  position: relative;
  z-index: 1;
  display: block;
  width: 100%;
  padding: 8px 18px;
  border: 0;
  background: transparent;
  color: inherit;
  font-family: var(--f);
  font-size: 14.5px;
  white-space: nowrap;
  cursor: pointer;
  transition: color var(--t-wipe) ease var(--d-wipe), opacity var(--t-finder) ease;
}
.finder:not(.on):not(.closing):hover .finder-toggle { color: var(--bg); }
.finder-toggle:focus-visible { outline: none; }
.finder:has(.finder-toggle:focus-visible) { outline: 2px solid var(--ink-bright); outline-offset: 2px; }

.finder-input {
  position: absolute;
  inset: 0;
  z-index: 1;
  width: 100%;
  height: 100%;
  padding: 0 36px 0 18px;
  border: 0;
  background: transparent;
  color: var(--ink);
  font-family: var(--f);
  font-size: 14.5px;
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--t-finder) ease;
}
.finder-input::placeholder { color: var(--ink-dim); }
.finder-input:focus-visible, .finder-input:focus { outline: none; }

/* The way out, inside the box it made. */
.finder-clear {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  z-index: 2;
  display: none;
  place-items: center;
  width: 34px;
  padding: 0;
  border: 0;
  background: transparent;
  color: var(--ink-dim);
  font-family: var(--f-mono);
  font-size: 12px;
  line-height: 1;
  cursor: pointer;
  transition: color var(--t-ui) ease;
}
.finder-clear:hover { color: var(--ink-bright); }

.finder.on { border-color: var(--ink-dim); background: var(--bg-soft); }
.finder.on:focus-within { border-color: var(--ink-bright); }
.finder.on .finder-toggle { opacity: 0; pointer-events: none; }
.finder.on .finder-input { opacity: 1; pointer-events: auto; }
.finder.on .finder-clear { display: grid; }

/* Under the field: what the deck currently holds on the left, the way to
   redraw it on the right. No rule of its own, because it is the last band
   before the footer and the footer brings one. */
.meta {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px 20px;
  flex-wrap: wrap;
}
.count {
  font-family: var(--f-mono);
  font-size: 11px;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--ink-dim);
}
.count b { color: var(--ink); font-weight: 500; }

/* THE SHUFFLE, ported whole from Offplat (2026-08-20, Chad). Same control, same
   sweep, same arrow trip. What differs here is only where it stands: Offplat
   puts it beside the caption that names the field, and this one sits INSIDE THE
   STAGE, bottom right, right edge aligned with the next chevron's.

   The band it sits in: the outermost cards scale to 0.94 so their bottoms land
   about 64px above the stage floor, the rail is 22px up from it, and this rides
   14px above the rail in the gap between them.

   The sweep is the .buy gesture scaled down to the mono register of the caption
   it belongs to. Same gesture, quieter voice. */
.shuffle {
  position: absolute;
  bottom: calc(var(--deck-foot) + var(--rail-lift) + 14px);
  right: max(6px, calc(50% - var(--rail) / 2 - 21px));
  z-index: 60;              /* also the stacking context ::before sits behind */
  display: inline-flex;
  align-items: center;
  gap: 7px;
  flex: none;
  padding: 6px 11px;
  border: 1px solid var(--rule);
  background: transparent;
  color: var(--ink-dim);
  font-family: var(--f-mono);
  font-size: 10.5px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  line-height: 1;
  cursor: pointer;
  overflow: hidden;
  transition: color var(--t-wipe) ease var(--d-wipe),
              border-color var(--t-ui) ease;

  /* Local to the control. The sweep behind it is the house --t-wipe; the trip
     is a smaller gesture riding on top of it and needs its own clock. */
  --t-trip: 380ms;
  --d-trip: 90ms;
  /* Leaving accelerates away. Arriving decelerates in. Swapping the pair on
     mouseout is what makes the return read as a return rather than a rewind. */
  --e-leave: cubic-bezier(0.55, 0, 0.85, 0);
  --e-arrive: cubic-bezier(0.22, 0.61, 0.36, 1);
}
.shuffle::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: var(--ink);
  transform: scaleX(0);
  transform-origin: right;   /* leaving */
  transition: transform var(--t-wipe) ease;
}
/* Gated on a real pointer: on a touch screen the sweep would fire as a finger
   passed the control on its way down the page. */
@media (hover: hover) {
  .shuffle:hover::before { transform: scaleX(1); transform-origin: left; }
  .shuffle:hover { color: var(--bg); border-color: var(--ink); }
}
.shuffle:focus-visible::before { transform: scaleX(1); transform-origin: left; }
.shuffle:focus-visible {
  outline: none;
  color: var(--bg);
  border-color: var(--ink);
}

/* THE ARROWS TAKE A TRIP. Each arrow leaves in the direction it already points,
   off the button entirely, and an inverted twin arrives along the same diagonal
   from behind. Mouseout runs it backwards.

   Three things make it work, and removing any one breaks it:

   1. The travel is written in SVG USER UNITS, not CSS pixels. A CSS transform
      on an element inside an svg lands in that svg's coordinate system, so at a
      24-unit viewBox drawn 14px wide, one unit is well under a pixel. 34 units
      is the ~20px it takes to clear the button's edge.
   2. The svg carries overflow: visible. An svg root clips to its own viewBox by
      default, so without this the arrows would vanish at the edge of a 14px box
      instead of travelling across the button.
   3. The BUTTON's overflow: hidden is what actually cuts them off, and it is
      already there for the sweep. That is the "off canvas" the trip needs: the
      arrows are clipped by the control they are leaving. */
.shuffle-mark {
  position: relative;
  display: block;
  flex: none;
  width: 14px;
  height: 14px;
}
.shuffle-glyph {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
}

/* Explicit colours rather than currentColor. The button's own colour crosses to
   var(--bg) as the fill sweeps under it, and these two have to stay on opposite
   sides of that crossing for the whole gesture: the pair leaving keeps the
   resting ink, the pair arriving is already wearing the inverted one. */
.shuffle-glyph--out { color: var(--ink-dim); }
.shuffle-glyph--in  { color: var(--bg); }

/* Resting, which is also the return leg: the originals are home and the twins
   are parked off canvas, each one BEHIND its own exit, so it can arrive along
   the same line its counterpart leaves on. */
.shuffle-glyph--out .arm {
  transform: none;
  transition: transform var(--t-trip) var(--e-arrive) var(--d-trip);
}
.shuffle-glyph--in .arm {
  transition: transform var(--t-trip) var(--e-leave);
}
.shuffle-glyph--in .arm--ne { transform: translate(-34px, 34px); }
.shuffle-glyph--in .arm--se { transform: translate(-34px, -34px); }

/* Stated twice rather than shared: a hover selector inside the query cannot
   carry a focus one out of it. */
@media (hover: hover) {
  .shuffle:hover .shuffle-glyph--out .arm {
    transition: transform var(--t-trip) var(--e-leave);
  }
  .shuffle:hover .shuffle-glyph--out .arm--ne { transform: translate(34px, -34px); }
  .shuffle:hover .shuffle-glyph--out .arm--se { transform: translate(34px, 34px); }
  .shuffle:hover .shuffle-glyph--in .arm {
    transform: none;
    transition: transform var(--t-trip) var(--e-arrive) var(--d-trip);
  }
}
.shuffle:focus-visible .shuffle-glyph--out .arm {
  transition: transform var(--t-trip) var(--e-leave);
}
.shuffle:focus-visible .shuffle-glyph--out .arm--ne { transform: translate(34px, -34px); }
.shuffle:focus-visible .shuffle-glyph--out .arm--se { transform: translate(34px, 34px); }
.shuffle:focus-visible .shuffle-glyph--in .arm {
  transform: none;
  transition: transform var(--t-trip) var(--e-arrive) var(--d-trip);
}

/* Working. The button is already unpressable while a draw is in flight, so this
   only has to say why. A pulse on the mark rather than a spinner: the deck is
   animating at the same moment, and a second, faster motion beside it would be
   the loudest thing on a page whose whole argument is restraint. */
.shuffle[disabled] { cursor: default; color: var(--ink-dim); }
.shuffle[disabled] .shuffle-mark { animation: shuffle-busy 620ms ease-in-out infinite; }
@keyframes shuffle-busy {
  0%, 100% { opacity: 0.3; }
  50%      { opacity: 1; }
}

/* ----------------------------------------------------------------- deck -- */

.deck {
  position: relative;
  margin: 0 auto;
  padding: 46px 0 var(--deck-foot);
  /* The outermost cards sit around 700px off centre, which is wider than the
     page. Clipping here is what keeps the body from scrolling sideways, and it
     is also the right read: the deck carries on past the frame. */
  overflow: hidden;
  touch-action: pan-y;
}

.stage {
  position: relative;
  height: calc(var(--card-h) + 60px);
  perspective: 1500px;
  perspective-origin: 50% 46%;
}
.stage:focus-visible { outline: 2px solid var(--ink-bright); outline-offset: 6px; }

/* The rail the cards stand on. One hairline, the width of the reading column,
   fading out at both ends so it reads as a ground rather than a border. */
.rail {
  position: absolute;
  left: 50%;
  bottom: var(--rail-lift);
  width: min(var(--rail), 100%);
  height: 1px;
  transform: translateX(-50%);
  background: linear-gradient(90deg, transparent, var(--rule) 18%, var(--rule) 82%, transparent);
}

.card {
  position: absolute;
  top: 8px;
  left: 50%;
  width: var(--card-w);
  height: var(--card-h);
  margin-left: calc(var(--card-w) / -2);
  padding: 0;
  border: 1px solid var(--ink);
  background: var(--paper);
  color: var(--ink);
  font-family: var(--f-mono);
  text-align: left;
  cursor: pointer;
  overflow: hidden;
  backface-visibility: hidden;
  transition: transform var(--t-card) ease, opacity var(--t-card) ease;
}

/* Depth is painted, not faded. Dropping opacity on a text-dense card turns the
   type to mush; a scrim over the paper keeps the ink crisp and still puts the
   card behind the one in front of it. The gradient runs toward the outside
   edge, which is the edge angled away from the reader. */
.card::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(var(--scrim-dir, 90deg), transparent, var(--bg));
  opacity: var(--dim, 0);
  pointer-events: none;
  transition: opacity var(--t-card) ease;
}
.card--left  { --scrim-dir: 270deg; }
.card--right { --scrim-dir: 90deg; }

.card--active { cursor: zoom-in; }
.card--active::after { opacity: 0; }
.card--far { opacity: 0; pointer-events: none; }

/* A card whose label has not arrived yet. Same paper, same geometry, no ink.
   Only reachable by outrunning the prefetch, which takes a hard drag on a slow
   connection. Deliberately not a spinner: a deck that flickers with loaders
   while you flip is worse than a card that is briefly blank. */
.card--pending > * { visibility: hidden; }

.card:not(.card--active):hover { --dim: calc(var(--dim-base, 0) * 0.45); }

.card-head {
  padding: 13px 15px 11px;
  border-bottom: 1px solid var(--ink);
}
.kicker {
  display: block;
  font-family: var(--f);
  font-size: 15px;
  font-weight: 800;
  letter-spacing: 0.055em;
  text-transform: uppercase;
  line-height: 1.05;
  color: var(--ink-bright);
}
.card-title {
  margin: 7px 0 0;
  font-family: var(--f);
  font-size: 21px;
  font-weight: 500;
  letter-spacing: -0.03em;
  line-height: 1.12;
  color: var(--ink-bright);
  text-wrap: balance;
}
.card-by {
  display: block;
  margin-top: 4px;
  font-size: 10.5px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-dim);
}

/* THE TIER BAND. The only chroma on the page, and the thing you actually read
   while a card flips past. */
.band {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  padding: 8px 15px;
  border-bottom: 3px solid var(--tier);
  background: var(--paper-2);
  font-size: 11px;
  letter-spacing: 0.07em;
  text-transform: uppercase;
}
.band-tier { color: var(--tier); font-weight: 700; }
.band-charge { color: var(--ink-dim); font-variant-numeric: tabular-nums; }

.field { padding: 10px 15px; border-bottom: 1px solid var(--rule-soft); }
.field:last-child { border-bottom: 0; }
.field-label {
  display: block;
  font-weight: 700;
  font-size: 10px;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  margin-bottom: 4px;
}
.field-body { font-size: 12.5px; line-height: 1.45; }
.field-body p { margin: 0 0 8px; }
.field-body p:last-child { margin-bottom: 0; }
.field--warn .field-label { color: var(--warn); }

.chips { display: flex; flex-wrap: wrap; gap: 5px; margin: 0; padding: 0; list-style: none; }
.chips li {
  border: 1px solid var(--rule);
  padding: 1px 6px;
  font-size: 10.5px;
  line-height: 1.5;
  text-transform: lowercase;
  color: var(--ink-dim);
}
.chips li.shadow { border-color: color-mix(in srgb, var(--warn) 55%, transparent); color: var(--warn); }

/* The card is a slim panel and the label is longer than it. The clip is the
   point: a spine shows you enough to choose, and the full read is one move
   away. */
.card-clip { position: relative; overflow: hidden; height: 100%; }
.card-clip::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 64px;
  background: linear-gradient(transparent, var(--paper));
  pointer-events: none;
}
.card-open {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  padding: 9px 15px 11px;
  background: var(--paper);
  border-top: 1px solid var(--rule-soft);
  font-size: 10px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-dim);
  opacity: 0;
  transition: opacity var(--t-ui) ease, color var(--t-ui) ease;
}
.card--active .card-open { opacity: 1; }
.card--active:hover .card-open, .card--active:focus-visible .card-open { color: var(--ink-bright); }

/* Deck navigation. Square and hairline, flush to the reading column, because
   a round button is the one control this house style never uses. */
.nav {
  position: absolute;
  top: 50%;
  z-index: 60;
  display: grid;
  place-items: center;
  width: 42px;
  height: 42px;
  margin-top: -21px;
  border: 1px solid var(--rule);
  background: var(--bg);
  color: var(--ink-dim);
  font-family: var(--f);
  font-size: 15px;
  cursor: pointer;
  transition: color var(--t-ui) ease, border-color var(--t-ui) ease;
}
.nav:hover:not([disabled]) { color: var(--ink-bright); border-color: var(--ink-dim); }
.nav[disabled] { opacity: 0.35; cursor: default; }
.nav--prev { left: max(6px, calc(50% - var(--rail) / 2 - 21px)); }
.nav--next { right: max(6px, calc(50% - var(--rail) / 2 - 21px)); }

/* ----------------------------------------------------------------- now -- */

/* What is in the middle, said in the site's own voice rather than the label's.
   Sits under the deck on the reading column. */
.now {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: 14px 26px;
  /* No rule here. The deck's rail is the line that separates the two, and a
     second one 60px under it was a divider dividing nothing. Padding down 40
     percent (2026-08-20, Chad) now that there is no line to clear. */
  padding-top: 16px;
}
.now-title {
  margin: 0;
  font-size: clamp(26px, 3.6vw, 38px);
  font-weight: 500;
  letter-spacing: -0.035em;
  line-height: 1.08;
  color: var(--ink-bright);
  text-wrap: balance;
}
.now-by { margin: 6px 0 0; font-size: 15px; color: var(--ink); }
.now-deadpan {
  margin: 12px 0 0;
  max-width: 52ch;
  font-family: var(--f-mono);
  font-size: 12.5px;
  letter-spacing: 0.02em;
  color: var(--ink-dim);
}
.now-side { display: flex; flex-direction: column; align-items: flex-end; gap: 10px; }
.now-tier {
  font-family: var(--f-mono);
  font-size: 11px;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--tier);
}

.empty {
  max-width: var(--rail);
  margin: 0 auto;
  padding: 70px 0 10px;
  text-align: center;
}
.empty h2 {
  margin: 0;
  font-size: clamp(24px, 3.4vw, 34px);
  font-weight: 500;
  letter-spacing: -0.035em;
  color: var(--ink-bright);
}
.empty p {
  margin: 14px auto 0;
  max-width: 44ch;
  font-family: var(--f-mono);
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-dim);
}

/* ---------------------------------------------------------------- sheet -- */

.scrim {
  position: fixed;
  inset: 0;
  z-index: 80;
  background: var(--scrim);
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--t-ui) ease;
}
.scrim.on { opacity: 1; pointer-events: auto; }

.sheet {
  position: fixed;
  z-index: 90;
  inset: 0;
  display: grid;
  place-items: start center;
  padding: 40px 20px 60px;
  overflow-y: auto;
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--t-ui) ease;
}
.sheet.on { opacity: 1; pointer-events: auto; }

.sheet-inner {
  width: min(40rem, 100%);
  border: 1px solid var(--ink);
  background: var(--paper);
  font-family: var(--f-mono);
  transform: translateY(14px) scale(0.985);
  transition: transform var(--t-card) ease;
}
.sheet.on .sheet-inner { transform: none; }

.sheet-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
  padding: 18px 20px 15px;
  border-bottom: 3px solid var(--ink);
}
.sheet-title {
  margin: 8px 0 0;
  font-family: var(--f);
  font-size: clamp(24px, 3.6vw, 32px);
  font-weight: 500;
  letter-spacing: -0.035em;
  line-height: 1.08;
  color: var(--ink-bright);
}
.sheet-close {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 5px 9px;
  border: 1px solid var(--rule);
  background: transparent;
  color: var(--ink-dim);
  font-family: var(--f-mono);
  font-size: 10px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  cursor: pointer;
  transition: color var(--t-ui) ease, border-color var(--t-ui) ease;
}
.sheet-close:hover { color: var(--ink-bright); border-color: var(--ink-dim); }
/* The glyph sits a size up from the label so the two share an optical weight
   rather than a font size. */
.sheet-close__x { font-size: 12px; line-height: 1; }

.sheet .band { padding: 11px 20px; font-size: 12px; }
.sheet .field { padding: 13px 20px; }
.sheet .field-label { font-size: 11px; margin-bottom: 6px; }
.sheet .field-body { font-size: 13.5px; line-height: 1.55; }
.sheet .chips li { font-size: 11.5px; padding: 2px 7px; }

.rows { display: flex; flex-direction: column; }
.row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 16px;
  padding: 9px 20px;
  border-bottom: 1px solid var(--rule-soft);
  font-size: 12px;
}
.row-k { letter-spacing: 0.07em; text-transform: uppercase; color: var(--ink-dim); white-space: nowrap; }
.row-v { text-align: right; font-size: 13px; }

.sheet-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 12px 20px;
  border-top: 1px solid var(--ink);
  font-size: 10px;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--ink-dim);
}
.sheet-step {
  padding: 5px 9px;
  border: 1px solid var(--rule);
  background: transparent;
  color: var(--ink-dim);
  font-family: var(--f-mono);
  font-size: 10px;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  cursor: pointer;
  transition: color var(--t-ui) ease, border-color var(--t-ui) ease;
}
.sheet-step:hover:not([disabled]) { color: var(--ink-bright); border-color: var(--ink-dim); }
.sheet-step[disabled] { opacity: 0.35; cursor: default; }
.sheet-steps { display: flex; gap: 8px; }

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

footer.site {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 10px 24px;
  margin-top: 70px;
  padding-top: 22px;
  border-top: 1px solid var(--rule-soft);
  font-family: var(--f-mono);
  font-size: 10.5px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-dim);
}


/* The two names this site stands on. Underlined at a hairline, because a credit
   that does not look like a link is a credit nobody follows. */
footer.site a {
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
  text-decoration-color: var(--rule);
  transition: color var(--t-ui) ease, text-decoration-color var(--t-ui) ease;
}
footer.site a:hover,
footer.site a:focus-visible { color: var(--ink-bright); text-decoration-color: var(--ink-dim); }

/* --------------------------------------------------------------- theme -- */

.theme-toggle {
  position: fixed;
  top: 18px;
  right: 18px;
  /* UNDER THE SCRIM (80), not over it. While the sheet is open there is one
     thing to do, and a lit control floating above the dim says otherwise. */
  z-index: 40;
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  padding: 0;
  border: 1px solid var(--rule);
  background: var(--bg);
  color: var(--ink-dim);
  cursor: pointer;
  transition: color var(--t-ui) ease, border-color var(--t-ui) ease, background-color var(--t-theme) ease;
}
.theme-toggle:hover { color: var(--ink-bright); border-color: var(--ink-dim); }
.theme-toggle .i-sun { display: none; }
.theme-toggle .i-moon { display: block; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .theme-toggle .i-moon { display: none; }
  :root:not([data-theme="light"]) .theme-toggle .i-sun { display: block; }
}
:root[data-theme="dark"] .theme-toggle .i-moon { display: none; }
:root[data-theme="dark"] .theme-toggle .i-sun { display: block; }

/* ----------------------------------------------------------- responsive -- */

@media (max-width: 1080px) {
  .nav--prev { left: 6px; }
  .nav--next { right: 6px; }
}

@media (max-width: 680px) {
  :root { --card-w: 214px; --card-h: 330px; }
  .page { padding: 0 18px 90px; }
  .masthead { padding: 58px 0 16px; }
  .card-title { font-size: 18px; }
  .now { flex-direction: column; align-items: flex-start; }
  .now-side { align-items: flex-start; }
}

@media (prefers-reduced-motion: reduce) {
  * { transition-duration: 1ms !important; animation-duration: 1ms !important; }
}
