/* ═══════════════════════════════════════════════════════════════════════
   SWIFT ARCHIVE
   Twelve eras, twelve colour worlds, and as much glitter as CSS allows.

   Everything colour-related runs through the six era tokens below. JS swaps
   them as you scroll and the entire page follows — background, text, glow,
   sparkle, borders. Nothing else hardcodes a colour.
   ═══════════════════════════════════════════════════════════════════════ */

/* Registered so gradient angles can actually animate. A plain custom property
   is just a string to the interpolator; this is what makes the holographic
   sweep possible without a canvas. */
@property --spin {
  syntax: '<angle>';
  initial-value: 0deg;
  inherits: false;
}

:root {
  /* Era tokens — overwritten at runtime. These are the Midnights defaults. */
  --bg:      #12172E;
  --surface: #1C2240;
  --ink:     #ECEDFB;
  --dim:     #A9AEDA;
  --accent:  #7B7FD4;
  --glow:    #A8ADFF;

  /* The rainbow. Fixed, era-independent — it's the site's own signature. */
  --r1: #FF6B9D;
  --r2: #FFB03A;
  --r3: #FFE66D;
  --r4: #7FE7A4;
  --r5: #7FD8FF;
  --r6: #C79BFF;

  --line:      color-mix(in oklab, var(--ink) 16%, transparent);
  --line-soft: color-mix(in oklab, var(--ink) 8%, transparent);

  --display: 'Playfair Display', Georgia, serif;
  --body: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  --mono: 'Space Grotesk', ui-monospace, monospace;

  --gut: clamp(1.25rem, 4vw, 4.5rem);
  --section-y: clamp(4.5rem, 11vw, 10rem);
  --maxw: 1500px;

  --ease: cubic-bezier(0.22, 1, 0.36, 1);
  --ease-io: cubic-bezier(0.65, 0, 0.35, 1);

  /* How long the whole page takes to become a different era. */
  --era-fade: 900ms;
}

/* ─── reset ──────────────────────────────────────────────────────────── */

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

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  color-scheme: dark;
  scroll-padding-top: 5.5rem;
  /* `clip` rather than `hidden`: hidden on the root makes the element a scroll
     container, which quietly breaks `position: fixed` children and anchor
     scrolling. clip just clips. Belt and braces against a stray wide child. */
  overflow-x: clip;
}

body {
  background: var(--bg);
  color: var(--ink);
  font-family: var(--body);
  font-size: clamp(0.95rem, 0.9rem + 0.2vw, 1.0625rem);
  line-height: 1.65;
  font-weight: 300;
  overflow-x: hidden;
  -webkit-font-smoothing: antialiased;
  touch-action: manipulation;
  -webkit-tap-highlight-color: color-mix(in oklab, var(--accent) 30%, transparent);
  transition: background var(--era-fade) var(--ease), color var(--era-fade) var(--ease);
}

img, svg { display: block; max-width: 100%; }
img { height: auto; }

/* A component's own `display` beats the UA `[hidden]` rule, so settle it once. */
[hidden] { display: none !important; }

a { color: inherit; text-decoration: none; }

button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }

::selection { background: var(--accent); color: var(--bg); }

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

.skip {
  position: absolute; left: -9999px; top: 0; z-index: 999;
  padding: 0.75rem 1.25rem; background: var(--accent); color: var(--bg);
  font: 700 0.75rem var(--mono);
}
.skip:focus { left: 0; }

/* ═══════════════════════════════════════════════════════════════════════
   GLITTER
   ═══════════════════════════════════════════════════════════════════════ */

/* 1. Holographic text — the signature move.
      A conic gradient through the full rainbow, clipped to the glyphs, with
      the angle animated. Because --spin is registered it interpolates
      smoothly instead of snapping. */
/* Started as a conic gradient, which was wrong: a conic sweeps around a centre
   point, so its 0°/360° seam cuts through whichever letter it lands on — the R
   in TAYLOR came out visibly out of step with its neighbours. A linear gradient
   has no seam of its own.

   It does still tile, though, and that was a second bug: the list ran r1…r6
   twice and stopped, so the image ended on purple and the next copy began on
   pink. Those met with no interpolation — a 99/255 hard edge that the
   animation then dragged across the letters every 6s. Ending on a repeated
   --r1 makes the last pixel match the first, so the tiling is invisible.
   Listing the rainbow twice is what keeps the -200% shift a whole number of
   image widths; the trailing stop is what makes the tile seamless. Both are
   needed — they fix different things. */
.holo {
  background: linear-gradient(100deg,
    var(--r1), var(--r2), var(--r3), var(--r4), var(--r5), var(--r6),
    var(--r1), var(--r2), var(--r3), var(--r4), var(--r5), var(--r6),
    var(--r1));
  background-size: 200% 100%;
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  animation: holo 6s linear infinite;
  /* Without this the clipped text has no weight against a dark background. */
  filter: drop-shadow(0 0 18px color-mix(in oklab, var(--glow) 45%, transparent));
}

@keyframes holo { to { background-position: -200% 0; } }

/* 2. Sparkle field — drifting specks, brighter near the cursor. Drawn in JS. */
.sparkle {
  position: fixed;
  inset: 0;
  z-index: 6; /* above content — glitter in front of you, not behind */
  width: 100%;
  height: 100%;
  pointer-events: none;
}

/* 3. Glitter dust — the same feTurbulence trick the monochrome sibling site
      uses for film grain, retuned to throw off coloured specks instead. */
/* Sized to just over the viewport rather than 4x it, and the blend mode is
   gone. `mix-blend-mode` on a fixed full-screen layer forces the browser to
   re-composite the entire stacking context every frame, which was the single
   biggest cause of the fans spinning. A plain low-opacity overlay looks
   near-identical here because the page underneath is already dark. */
.dust {
  position: fixed;
  inset: -8%;
  z-index: 3;
  pointer-events: none;
  opacity: 0.5;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='260' height='260'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='matrix' values='3 0 0 0 -1.1  0 2 0 0 -1.0  0 0 4 0 -1.3  0 0 0 1.6 -0.75'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23g)'/%3E%3C/svg%3E");
  animation: shimmer 6s steps(3) infinite;
  will-change: transform;
  transform: translateZ(0);
}

@keyframes shimmer {
  0%   { transform: translate3d(0, 0, 0) }
  33%  { transform: translate3d(-1%, 0.8%, 0) }
  66%  { transform: translate3d(0.8%, -1%, 0) }
  100% { transform: translate3d(0, 0, 0) }
}

/* 4. Era wash — a soft bloom of the current era's colour, top and bottom. */
.wash {
  position: fixed;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background:
    radial-gradient(120% 60% at 50% -10%, color-mix(in oklab, var(--glow) 20%, transparent), transparent 70%),
    radial-gradient(100% 50% at 50% 110%, color-mix(in oklab, var(--accent) 16%, transparent), transparent 70%);
  transition: background var(--era-fade) var(--ease);
}

/* Everything real sits above the atmosphere layers. */
.nav, main, .footer { position: relative; z-index: 5; }

/* ─── nav ────────────────────────────────────────────────────────────── */

.nav {
  position: fixed;
  inset: 0 0 auto;
  z-index: 800;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.5rem;
  padding: 0.9rem max(var(--gut), env(safe-area-inset-left)) 0.9rem max(var(--gut), env(safe-area-inset-right));
  background: color-mix(in oklab, var(--bg) 72%, transparent);
  /* A backdrop blur is recomputed on every scroll frame and the cost scales
     with the radius, so this is as small as it can be while still reading as
     frosted. */
  backdrop-filter: blur(8px) saturate(1.3);
  -webkit-backdrop-filter: blur(8px) saturate(1.3);
  border-bottom: 1px solid var(--line-soft);
  transition: transform 500ms var(--ease), background var(--era-fade) var(--ease);
}
.nav--hidden { transform: translateY(-105%); }

.nav__mark {
  display: flex;
  gap: 0.45em;
  align-items: baseline;
  font-family: var(--mono);
  font-weight: 700;
  font-size: 0.9rem;
  letter-spacing: 0.16em;
  white-space: nowrap;
}
.nav__mark-b { color: var(--dim); font-weight: 400; }

.nav__links {
  display: flex;
  gap: clamp(0.8rem, 1.8vw, 1.9rem);
  font-family: var(--mono);
  font-size: 0.7rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}
.nav__links a { position: relative; opacity: 0.7; transition: opacity 250ms, color 250ms; }
.nav__links a::after {
  content: '';
  position: absolute; left: 0; bottom: -4px;
  width: 100%; height: 2px; border-radius: 2px;
  background: linear-gradient(90deg, var(--r1), var(--r3), var(--r5));
  transform: scaleX(0); transform-origin: right;
  transition: transform 380ms var(--ease);
}
.nav__links a:hover, .nav__links a.is-active { opacity: 1; }
.nav__links a:hover::after, .nav__links a.is-active::after { transform: scaleX(1); transform-origin: left; }

.nav__live {
  display: flex; align-items: center; gap: 0.5rem;
  font-family: var(--mono); font-size: 0.63rem;
  letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--dim); white-space: nowrap;
}

.dot {
  width: 7px; height: 7px; border-radius: 50%;
  background: var(--glow);
  animation: pulse 2.4s var(--ease-io) infinite;
}
@keyframes pulse {
  0%, 100% { opacity: 1; box-shadow: 0 0 0 0 color-mix(in oklab, var(--glow) 60%, transparent); }
  50%      { opacity: 0.5; box-shadow: 0 0 0 7px transparent; }
}

@media (max-width: 1000px) { .nav__links { display: none; } }

/* ─── hero ───────────────────────────────────────────────────────────── */

.hero {
  position: relative;
  min-height: 100svh;
  display: grid;
  align-items: center;
  padding: 7rem max(var(--gut), env(safe-area-inset-right)) clamp(3rem, 8vw, 6rem) max(var(--gut), env(safe-area-inset-left));
  overflow: hidden;
  isolation: isolate;
}

.hero__art { position: absolute; inset: 0; z-index: -2; }
.hero__art img {
  width: 100%; height: 100%; object-fit: cover;
  opacity: 0; transform: scale(1.15);
  filter: blur(46px) saturate(1.7) brightness(0.62);
  transition: opacity 1.6s var(--ease);
}
.hero__art img.is-in { opacity: 0.75; }

.hero::after {
  content: '';
  position: absolute; inset: 0; z-index: -1; pointer-events: none;
  background: linear-gradient(to bottom,
    color-mix(in oklab, var(--bg) 55%, transparent),
    color-mix(in oklab, var(--bg) 78%, transparent));
}

.hero__inner { width: 100%; max-width: var(--maxw); margin-inline: auto; }

.hero__kicker {
  display: flex; align-items: center; gap: 0.9rem;
  font-family: var(--mono); font-size: 0.72rem;
  letter-spacing: 0.2em; text-transform: uppercase;
  color: var(--dim);
  margin-bottom: clamp(1rem, 3vw, 1.75rem);
}
.rule { flex: 1 1 auto; max-width: 220px; height: 1px; background: linear-gradient(90deg, var(--line), transparent); }
.sparkles { color: var(--glow); animation: twinkle 2.2s var(--ease-io) infinite; }
@keyframes twinkle { 0%,100% { opacity: 1; transform: scale(1) } 50% { opacity: 0.35; transform: scale(0.8) } }

.wordmark {
  font-family: var(--display);
  font-weight: 900;
  font-size: clamp(3.2rem, 15vw, 13rem);
  line-height: 0.86;
  letter-spacing: -0.03em;
  margin-bottom: clamp(1.25rem, 3vw, 2rem);
}
.wordmark__line { display: block; }
.wordmark__line--2 {
  font-style: italic;
  font-weight: 700;
  padding-left: 0.08em;
  color: var(--ink);
}

.hero__sub {
  max-width: 40ch;
  color: var(--dim);
  font-size: clamp(1rem, 1.2vw, 1.2rem);
  margin-bottom: clamp(2rem, 4vw, 3rem);
}

.hero__stats {
  display: flex; flex-wrap: wrap;
  gap: clamp(1.5rem, 5vw, 4rem);
  padding-top: 1.75rem;
  border-top: 1px solid var(--line);
  margin-bottom: 2.5rem;
}
.hero__stats div { display: flex; flex-direction: column-reverse; gap: 0.3rem; }
.hero__stats dt {
  font-family: var(--mono); font-size: 0.63rem;
  letter-spacing: 0.16em; text-transform: uppercase; color: var(--dim);
}
.hero__stats dd {
  font-family: var(--display); font-weight: 700;
  font-size: clamp(1.9rem, 4vw, 3rem); line-height: 1;
  font-variant-numeric: tabular-nums;
}

.hero__cue {
  display: inline-flex; align-items: center; gap: 0.6rem;
  font-family: var(--mono); font-size: 0.68rem;
  letter-spacing: 0.18em; text-transform: uppercase; color: var(--dim);
  transition: color 250ms, gap 350ms var(--ease);
}
.hero__cue:hover { color: var(--ink); gap: 1rem; }
.hero__cue svg { animation: bob 2.6s var(--ease-io) infinite; }
@keyframes bob { 0%,100% { transform: translateY(0) } 50% { transform: translateY(4px) } }

/* ─── shared furniture ───────────────────────────────────────────────── */

.section {
  max-width: var(--maxw);
  margin-inline: auto;
  padding: var(--section-y) max(var(--gut), env(safe-area-inset-right)) var(--section-y) max(var(--gut), env(safe-area-inset-left));
  /* Skip layout and paint for sections that are off screen. The page is ~19
     screens tall with 120-odd album covers, and without this the browser was
     doing that work on every frame the glitter animated. `contain-intrinsic-size`
     keeps the scrollbar from jumping as they get skipped and unskipped. */
  content-visibility: auto;
  contain-intrinsic-size: auto 900px;
}

.section__head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 1.5rem; padding-bottom: 1.1rem;
  margin-bottom: clamp(2rem, 5vw, 3.25rem);
  border-bottom: 1px solid var(--line);
}
.section__head--wide {
  max-width: var(--maxw);
  margin-inline: auto;
  padding-inline: max(var(--gut), env(safe-area-inset-left)) max(var(--gut), env(safe-area-inset-right));
}

.section__title {
  font-family: var(--display);
  font-weight: 700;
  font-size: clamp(2rem, 6vw, 4.75rem);
  line-height: 1;
  letter-spacing: -0.02em;
  text-wrap: balance;
}

.section__meta, .mono {
  font-family: var(--mono); font-size: 0.68rem;
  letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--dim); white-space: nowrap;
}

/* `nowrap` is right for short labels like a date, but "Scroll — the whole page
   follows along" is 285px wide and pushed the document to 393px on a 375px
   phone. Below the fold that's a horizontal scrollbar on every page. */
@media (max-width: 560px) {
  .section__head { flex-wrap: wrap; gap: 0.4rem; }
  .section__meta { white-space: normal; }
}

.eyebrow {
  font-family: var(--mono); font-size: 0.7rem;
  letter-spacing: 0.2em; text-transform: uppercase;
  color: var(--dim); margin-bottom: 1.25rem;
}

[data-reveal] {
  opacity: 0; transform: translateY(26px);
  transition: opacity 900ms var(--ease), transform 900ms var(--ease);
}
[data-reveal].is-in { opacity: 1; transform: none; }

/* ═══════════════════════════════════════════════════════════════════════
   THE ERAS — the centrepiece
   ═══════════════════════════════════════════════════════════════════════ */

.eras { padding-block: var(--section-y); }

.eras__rail { display: grid; gap: clamp(3rem, 9vw, 7rem); }

.era {
  --era-accent: var(--accent);
  --era-glow: var(--glow);
  max-width: var(--maxw);
  margin-inline: auto;
  padding-inline: max(var(--gut), env(safe-area-inset-left)) max(var(--gut), env(safe-area-inset-right));
  display: grid;
  grid-template-columns: minmax(0, 0.85fr) minmax(0, 1.15fr);
  gap: clamp(1.5rem, 5vw, 4.5rem);
  align-items: center;
  scroll-margin-top: 6rem;
}
.era:nth-child(even) { direction: rtl; }
.era:nth-child(even) > * { direction: ltr; }

@media (max-width: 900px) {
  .era, .era:nth-child(even) { grid-template-columns: 1fr; direction: ltr; }
}

/* Stacked, twelve eras ran to 10.4 screens on a phone — half the entire page
   before you reach anything else. The cover doesn't need to be full-bleed
   square to do its job, so it gets cropped and the gaps come in. */
/* Scoped with `.eras` on purpose: these sit above the base .era__art rule in
   the file, so at equal specificity source order would win and the override
   would silently do nothing. */
@media (max-width: 560px) {
  .eras__rail { gap: 2.5rem; }
  .era { gap: 1rem; }
  .eras .era__art { aspect-ratio: 16 / 10; }
  .eras .era__art img { object-position: center 32%; }
  .era__blurb {
    font-size: 0.92rem;
    display: -webkit-box;
    -webkit-line-clamp: 4;
    -webkit-box-orient: vertical;
    overflow: hidden;
  }
}

/* The "Show all" bar lives as a rail *child* (a grid item, not a sibling after
   the grid), so the rail's own `gap` spaces it consistently with the era
   cards. That means it needs the era cards' own side padding and max-width —
   .more's base margin-top would otherwise stack on top of that gap, so it's
   zeroed here. Hidden by default; JS only reveals it under 560px. */
.eras .more {
  max-width: var(--maxw);
  margin-inline: auto;
  margin-top: 0;
  padding-inline: max(var(--gut), env(safe-area-inset-left)) max(var(--gut), env(safe-area-inset-right));
}
.eras .more[hidden] { display: none; }

.era__art {
  position: relative;
  aspect-ratio: 1;
  border-radius: 4px;
  overflow: hidden;
  background: var(--surface);
  box-shadow:
    0 0 0 1px color-mix(in oklab, var(--era-glow) 30%, transparent),
    0 30px 70px -20px color-mix(in oklab, var(--era-glow) 45%, transparent);
  transition: box-shadow 700ms var(--ease), transform 700ms var(--ease);
}
.era:hover .era__art { transform: translateY(-6px); }

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

/* Iridescent sheen sweeping across the artwork. `screen` keeps the album's
   own colour instead of washing it out the way a filter would. */
.era__art::after {
  content: '';
  position: absolute; inset: 0;
  background: linear-gradient(115deg,
    transparent 30%,
    color-mix(in oklab, var(--r5) 45%, transparent) 45%,
    color-mix(in oklab, var(--r1) 40%, transparent) 52%,
    transparent 68%);
  mix-blend-mode: screen;
  opacity: 0;
  transform: translateX(-40%);
  transition: opacity 500ms, transform 1100ms var(--ease);
  pointer-events: none;
}
.era:hover .era__art::after { opacity: 1; transform: translateX(40%); }

/* --era-glow, not --era-accent. Measured across all twelve palettes the accent
   bottoms out at 3.11:1 on Red, which fails AA for text this size. The glow's
   worst case is 5.98:1 and it reads as the same colour family. */
.era__no {
  font-family: var(--mono); font-size: 0.7rem;
  letter-spacing: 0.2em; color: var(--era-glow);
  margin-bottom: 0.75rem;
}

.era__name {
  font-family: var(--display);
  font-weight: 900;
  font-size: clamp(2.1rem, 7vw, 5rem);
  line-height: 0.95;
  letter-spacing: -0.025em;
  margin-bottom: 0.4rem;
  text-wrap: balance;
}

.era__year {
  font-family: var(--mono);
  font-size: clamp(0.8rem, 1.6vw, 1rem);
  letter-spacing: 0.22em;
  color: var(--era-glow);
  margin-bottom: 1.25rem;
}

.era__blurb {
  max-width: 46ch; color: var(--dim);
  font-size: clamp(0.98rem, 1.1vw, 1.12rem);
  margin-bottom: 1.5rem;
}

.era__meta { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-bottom: 1.5rem; }

.chip {
  padding: 0.35rem 0.8rem;
  border: 1px solid var(--line);
  border-radius: 999px;
  font-family: var(--mono); font-size: 0.63rem;
  letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--dim);
  transition: color 250ms, border-color 250ms, background 250ms;
}
a.chip:hover { color: var(--ink); border-color: var(--era-glow); }

/* Swatches — the era's palette made literal. */
.era__swatches { display: flex; gap: 0.4rem; }
.era__swatches i {
  width: 1.6rem; height: 1.6rem; border-radius: 50%;
  border: 1px solid color-mix(in oklab, var(--ink) 25%, transparent);
  transition: transform 400ms var(--ease);
}
.era:hover .era__swatches i { transform: translateY(-4px) scale(1.1); }
.era__swatches i:nth-child(2) { transition-delay: 60ms; }
.era__swatches i:nth-child(3) { transition-delay: 120ms; }

.btn {
  display: inline-flex; align-items: center; gap: 0.7rem;
  padding: 0.85rem 1.5rem;
  border: 1px solid var(--era-glow);
  border-radius: 999px;
  font-family: var(--mono); font-size: 0.66rem;
  letter-spacing: 0.16em; text-transform: uppercase;
  position: relative; overflow: hidden;
  transition: color 400ms var(--ease);
}
.btn::before {
  content: '';
  position: absolute; inset: 0; z-index: -1;
  background: linear-gradient(90deg, var(--r1), var(--r3), var(--r5));
  transform: translateY(101%);
  transition: transform 460ms var(--ease);
}
.btn:hover { color: #12101A; }
.btn:hover::before { transform: translateY(0); }
.btn--sm { padding: 0.6rem 1.1rem; font-size: 0.6rem; }

/* ─── latest ─────────────────────────────────────────────────────────── */

.latest__card {
  display: grid;
  grid-template-columns: minmax(0, 0.8fr) minmax(0, 1.2fr);
  gap: clamp(1.5rem, 5vw, 4rem);
  align-items: center;
}
@media (max-width: 860px) { .latest__card { grid-template-columns: 1fr; } }

.latest__art {
  position: relative; aspect-ratio: 1; overflow: hidden;
  border-radius: 4px; background: var(--surface);
  box-shadow: 0 24px 60px -20px color-mix(in oklab, var(--glow) 50%, transparent);
}
.latest__art img { width: 100%; height: 100%; object-fit: cover; }

.badge {
  position: absolute; top: 1rem; left: 1rem; z-index: 2;
  padding: 0.35rem 0.8rem; border-radius: 999px;
  background: linear-gradient(90deg, var(--r1), var(--r2));
  color: #12101A;
  font: 700 0.62rem var(--mono);
  letter-spacing: 0.14em; text-transform: uppercase;
}

.latest__title {
  font-family: var(--display); font-weight: 700;
  font-size: clamp(2rem, 5.5vw, 4rem);
  line-height: 1; letter-spacing: -0.02em;
  margin: 0.6rem 0 1.1rem;
  text-wrap: balance;
}

/* ─── discography ────────────────────────────────────────────────────── */

.filters { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-bottom: clamp(1.75rem, 4vw, 2.5rem); }
.filters button {
  padding: 0.45rem 1rem; border: 1px solid var(--line); border-radius: 999px;
  font-family: var(--mono); font-size: 0.63rem;
  letter-spacing: 0.14em; text-transform: uppercase; color: var(--dim);
  transition: color 250ms, border-color 250ms, background 250ms;
}
.filters button:hover { color: var(--ink); border-color: var(--glow); }
.filters button[aria-pressed="true"] {
  background: linear-gradient(90deg, var(--r1), var(--r5));
  border-color: transparent; color: #12101A;
}

.disco {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(200px, 100%), 1fr));
  gap: clamp(1rem, 2.2vw, 1.75rem);
}

.rel { display: block; }
.rel__art {
  position: relative; aspect-ratio: 1; overflow: hidden;
  border-radius: 4px; background: var(--surface); margin-bottom: 0.8rem;
  box-shadow: 0 10px 30px -14px rgba(0,0,0,0.7);
  transition: transform 600ms var(--ease), box-shadow 600ms var(--ease);
}
.rel:hover .rel__art {
  transform: translateY(-5px);
  box-shadow: 0 22px 46px -18px color-mix(in oklab, var(--glow) 60%, transparent);
}
.rel__art img { width: 100%; height: 100%; object-fit: cover; }

.rel__art::after {
  content: '';
  position: absolute; inset: 0;
  background: linear-gradient(115deg, transparent 35%, color-mix(in oklab, var(--r5) 40%, transparent) 50%, transparent 65%);
  mix-blend-mode: screen; opacity: 0;
  transform: translateX(-50%);
  transition: opacity 400ms, transform 900ms var(--ease);
}
.rel:hover .rel__art::after { opacity: 1; transform: translateX(50%); }

.rel__title {
  font-size: 0.9rem; font-weight: 500; line-height: 1.35; margin-bottom: 0.15rem;
  overflow-wrap: anywhere;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.rel__year { font-family: var(--mono); font-size: 0.65rem; letter-spacing: 0.1em; color: var(--dim); font-variant-numeric: tabular-nums; }

@media (max-width: 620px) {
  .disco { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0.8rem; }
  .rel__title { font-size: 0.8rem; }
}

/* ─── show more ──────────────────────────────────────────────────────── */

.more { display: flex; align-items: center; gap: 1rem; width: 100%; margin-top: clamp(1.5rem, 3vw, 2.25rem); }
.more button {
  display: inline-flex; align-items: center; gap: 0.7rem;
  padding: 0.8rem 1.5rem; border: 1px solid var(--line); border-radius: 999px;
  font-family: var(--mono); font-size: 0.65rem;
  letter-spacing: 0.16em; text-transform: uppercase; color: var(--dim);
  transition: color 300ms, border-color 300ms;
}
.more button:hover { color: var(--ink); border-color: var(--glow); }
.more button svg { transition: transform 400ms var(--ease); }
.more button[aria-expanded="true"] svg { transform: rotate(180deg); }
.more__line { flex: 1; height: 1px; background: var(--line-soft); }

/* ═══════════════════════════════════════════════════════════════════════
   THE CATS
   ═══════════════════════════════════════════════════════════════════════ */

.cats {
  max-width: var(--maxw); margin-inline: auto;
  padding: var(--section-y) max(var(--gut), env(safe-area-inset-right)) var(--section-y) max(var(--gut), env(safe-area-inset-left));
}

.cats__intro {
  max-width: 46ch;
  color: var(--dim);
  font-size: clamp(0.98rem, 1.15vw, 1.12rem);
  margin-bottom: clamp(2rem, 4vw, 3rem);
}

/* A magazine spread, not a trading-card grid: one feature profile plus two
   supporting mentions. The size difference is doing real work, not decorating
   — it maps to how famous each cat actually is. Olivia is in the music videos
   and the "richest pets" lists; Meredith avoids the camera; Benjamin is the
   youngest. The layout says that before the copy does.

   Capped narrower than the section's own max-width: at the full 1500px three
   cards this size read as oversized on an actual desktop monitor, not just in
   a narrow preview pane. */
.cats__grid {
  display: grid;
  grid-template-columns: minmax(0, 1.2fr) minmax(0, 0.85fr);
  /* start, not stretch — with stretch, spanning 2 rows forced the feature
     card to match the *combined* height of the two side cards, and since its
     own content is shorter, the leftover space just sat there as a dead gap
     under the text. Sizing to each card's own content removes that gap; the
     span is still what lines the feature card up beside both side cards. */
  align-items: start;
  gap: clamp(1.5rem, 3vw, 2.25rem);
  max-width: 1180px;
}
.cat--feature { grid-row: span 2; }

@media (max-width: 780px) {
  .cats__grid { grid-template-columns: 1fr; }
  .cat--feature { grid-row: auto; }
  /* The tilt reads as charming at magazine scale; stacked in a single mobile
     column it just looks crooked. Soften rather than drop it. */
  .cat { transform: rotate(calc(var(--tilt, 0deg) * 0.45)) !important; }
}

.cat {
  --tilt: 0deg;
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  padding: clamp(1.5rem, 3vw, 2.25rem) clamp(1.25rem, 2.5vw, 1.75rem) clamp(1.5rem, 2.5vw, 1.85rem);
  border-radius: 20px;
  background: linear-gradient(165deg,
    color-mix(in oklab, var(--surface) 90%, white 4%),
    color-mix(in oklab, var(--surface) 55%, black 25%));
  border: 1px solid var(--line);
  transform: rotate(var(--tilt));
  transition: transform 550ms var(--ease), box-shadow 550ms var(--ease), border-color 550ms;
}
.cat:nth-child(1) { --tilt: -0.6deg; }
.cat:nth-child(2) { --tilt: 0.9deg; }
.cat:nth-child(3) { --tilt: -1deg; }

.cat:hover {
  /* Softened, not flattened — like a hand lifting the photo off the page
     rather than the card snapping upright. */
  transform: rotate(calc(var(--tilt) * 0.3)) translateY(-10px) scale(1.015);
  border-color: color-mix(in oklab, var(--cat-glow, var(--glow)) 55%, transparent);
}

/* Fixed per breakpoint rather than a fluid clamp(): the Instagram embed has
   to be scaled by an exact circle-width ÷ 540 ratio to sit right, and a
   viewport-relative width would make that ratio a moving target. */
.cat__frame {
  position: relative;
  width: 6.5rem; /* 104px — paired with --ig-scale: 0.193 */
  aspect-ratio: 1;
  margin-bottom: 1.1rem;
  border-radius: 50%;
  overflow: hidden;
  background: radial-gradient(circle at 50% 38%,
    color-mix(in oklab, var(--cat-glow, var(--glow)) 42%, var(--bg)),
    var(--bg) 74%);
  box-shadow:
    0 0 0 1px color-mix(in oklab, var(--cat-glow, var(--glow)) 55%, transparent),
    0 0 40px 6px color-mix(in oklab, var(--cat-glow, var(--glow)) 30%, transparent);
  transition: box-shadow 500ms var(--ease);
}
.cat--feature .cat__frame { width: 8.5rem; } /* 136px — --ig-scale: 0.252 */

@media (min-width: 561px) {
  .cat__frame { width: 8rem; }                 /* 128px — --ig-scale: 0.237 */
  .cat--feature .cat__frame { width: 10.5rem; } /* 168px — --ig-scale: 0.311 */
}
.cat:hover .cat__frame {
  box-shadow:
    0 0 0 1px color-mix(in oklab, var(--cat-glow, var(--glow)) 78%, transparent),
    0 0 64px 12px color-mix(in oklab, var(--cat-glow, var(--glow)) 55%, transparent);
}
.cat__frame svg { width: 100%; height: 100%; display: block; }

/* embed.js replaces the <blockquote> outright with an <iframe> carrying the
   same instagram-media class, so this targets the iframe itself.

   Instagram renders a full post card — ~60px header, then the square photo at
   the card's full width, then the caption/likes footer — with no way to ask
   for just the photo. Earlier passes scaled the iframe *up* and showed a
   window into it, which meant the circle only ever saw a slice: whether that
   slice contained the cat depended entirely on where the cat happened to sit
   in that particular photo. It showed a chair for Olivia, a wall for Meredith
   and an ear for Benjamin.

   This instead scales the photo down so its full width maps to the circle's
   width. The whole photo is then inside the circle (corners clipped, which is
   the point of a circular crop) and the cat is in frame no matter where it
   sits in the shot — no per-post tuning, nothing to recalibrate if a caption
   changes length.

   Geometry here is measured, not guessed: loading Instagram's own /embed/
   page at exactly 540px wide put the header at rows 0–54 and the (square)
   photo immediately after it at rows 54–592. So positioned at its natural
   top-left with a top-left transform-origin, translateY(-54px) shifts the
   header up out of view and lands the photo's top edge at row 0 — before the
   scale applies, so the -54px is in the iframe's own coordinates. Everything
   below the photo (footer, comments) falls past the frame's bottom edge and
   is clipped by the circle's overflow:hidden, same as the header above.
   `min-width` has to be overridden explicitly; Instagram sets a 326px inline
   minimum. */
.cat__frame .instagram-media {
  position: absolute !important;
  min-width: 0 !important;
  width: 540px !important;
  height: 900px !important;
  top: 0 !important; left: 0 !important;
  margin: 0 !important;
  transform: scale(var(--ig-scale, 0.193)) translateY(calc(-54px + var(--ig-ty, 0px))) !important;
  transform-origin: 0 0 !important;
  border: 0 !important; border-radius: 0 !important;
}

/* Scale = circle width ÷ 540, so the photo's width exactly spans the circle.
   The circle sizes are fixed rem values per breakpoint (see .cat__frame), so
   these are the matching ratios rather than anything derived at runtime. */
.cat--feature .cat__frame .instagram-media { --ig-scale: 0.252; } /* 136 ÷ 540 */

@media (min-width: 561px) {
  .cat__frame .instagram-media { --ig-scale: 0.237; }             /* 128 ÷ 540 */
  .cat--feature .cat__frame .instagram-media { --ig-scale: 0.311; } /* 168 ÷ 540 */
}

/* The one new type role on the page, used only here: the handwritten-caption
   register Taylor's own album packaging leans on constantly (liner notes,
   vault-track scrawl, the folklore/evermore journal aesthetic). Everywhere
   else on the site stays Playfair + Inter + Space Grotesk. */
.cat__name {
  font-family: 'Caveat', cursive;
  font-weight: 700;
  font-size: clamp(1.6rem, 2.6vw, 1.95rem);
  line-height: 1;
  color: var(--ink);
  margin-bottom: 0.15rem;
}
.cat--feature .cat__name { font-size: clamp(1.9rem, 3.4vw, 2.4rem); }

.cat__caption {
  font-family: 'Caveat', cursive;
  font-weight: 500;
  font-size: clamp(1rem, 1.4vw, 1.15rem);
  color: var(--cat-glow, var(--glow));
  margin-bottom: 0.75rem;
}

.cat__meta {
  font-family: var(--mono); font-size: 0.58rem;
  letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--dim); margin-bottom: 0.9rem;
}

.cat__note { color: var(--dim); font-size: 0.85rem; max-width: 32ch; }
.cat--feature .cat__note { font-size: 0.9rem; max-width: 38ch; }

.cat__after {
  margin-top: 1rem; font-size: 0.78rem;
  color: var(--dim); opacity: 0.75;
}
.cat__after b { color: var(--ink); font-weight: 500; }

/* ─── videos ─────────────────────────────────────────────────────────── */

.videos { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(300px, 100%), 1fr)); gap: clamp(1rem, 2.2vw, 1.75rem); }
.vid { display: block; }
.vid__thumb {
  position: relative; aspect-ratio: 16/9; overflow: hidden;
  border-radius: 10px; background: var(--surface); margin-bottom: 0.8rem;
  transition: transform 600ms var(--ease), box-shadow 600ms var(--ease);
}
.vid:hover .vid__thumb {
  transform: translateY(-4px);
  box-shadow: 0 20px 40px -18px color-mix(in oklab, var(--glow) 60%, transparent);
}
.vid__thumb img { width: 100%; height: 100%; object-fit: cover; }
.vid__play { position: absolute; inset: 0; display: grid; place-items: center; opacity: 0; transition: opacity 400ms var(--ease); }
.vid:hover .vid__play { opacity: 1; }
.vid__play span {
  width: 3.4rem; height: 3.4rem; border-radius: 50%;
  background: linear-gradient(135deg, var(--r1), var(--r5));
  display: grid; place-items: center;
  transform: scale(0.8); transition: transform 450ms var(--ease);
}
.vid:hover .vid__play span { transform: scale(1); }
.vid__title {
  font-size: 0.92rem; line-height: 1.4; margin-bottom: 0.2rem;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}

/* ─── news ───────────────────────────────────────────────────────────── */

.news { list-style: none; padding: 0; }
.news li { border-bottom: 1px solid var(--line-soft); }
.news a {
  display: grid; grid-template-columns: 6.5rem 1fr auto;
  gap: clamp(1rem, 3vw, 2.5rem); align-items: baseline;
  padding: clamp(1rem, 2vw, 1.4rem) 0;
  transition: padding-left 450ms var(--ease);
}
.news a:hover { padding-left: 1.1rem; }
.news .date { font-family: var(--mono); font-size: 0.65rem; letter-spacing: 0.08em; color: var(--dim); font-variant-numeric: tabular-nums; }
.news .head { font-size: clamp(1rem, 1.6vw, 1.25rem); line-height: 1.4; min-width: 0; text-wrap: pretty; overflow-wrap: anywhere; transition: color 300ms; }
.news a:hover .head { color: var(--glow); }
.news .outlet { font-family: var(--mono); font-size: 0.6rem; letter-spacing: 0.12em; text-transform: uppercase; color: var(--dim); text-align: right; }
@media (max-width: 720px) {
  .news a { grid-template-columns: 1fr; gap: 0.35rem; }
  .news .outlet { text-align: left; }
}

/* ─── live ───────────────────────────────────────────────────────────── */

.tour { list-style: none; padding: 0; }
.tour li {
  display: grid; grid-template-columns: 5rem 1fr auto;
  gap: clamp(1rem, 3vw, 2.5rem); align-items: center;
  padding: clamp(1rem, 2vw, 1.4rem) 0; border-bottom: 1px solid var(--line-soft);
}
.tour__date { display: grid; font-family: var(--mono); line-height: 1.1; font-variant-numeric: tabular-nums; }
.tour__day { font-family: var(--display); font-weight: 700; font-size: 1.8rem; }
.tour__mon { font-size: 0.64rem; letter-spacing: 0.16em; text-transform: uppercase; color: var(--glow); }
.tour__yr { font-size: 0.58rem; letter-spacing: 0.12em; color: var(--dim); }
.tour__where { display: grid; gap: 0.2rem; min-width: 0; }
.tour__city { font-family: var(--display); font-weight: 700; font-size: clamp(1.1rem, 2.2vw, 1.6rem); line-height: 1.15; }
.tour__venue { font-size: 0.85rem; color: var(--dim); overflow-wrap: anywhere; }
@media (max-width: 640px) {
  .tour li { grid-template-columns: 4rem 1fr; row-gap: 0.7rem; }
  .tour li > :last-child { grid-column: 2; justify-self: start; }
}

.tour__none { max-width: 60ch; }
.tour__none-lead { font-family: var(--display); font-weight: 700; font-size: clamp(1.3rem, 3vw, 2.2rem); line-height: 1.15; margin-bottom: 0.75rem; }
.tour__none-sub { color: var(--dim); margin-bottom: 1.5rem; }
.tour__alerts { display: flex; flex-wrap: wrap; gap: 0.5rem; align-items: center; }
.tour__alerts--after { margin-top: clamp(1.75rem, 4vw, 2.5rem); padding-top: 1.5rem; border-top: 1px solid var(--line-soft); }

.tour__wire { margin-top: clamp(2rem, 5vw, 3rem); }
.tour__wire-head { padding-bottom: 0.8rem; border-bottom: 1px solid var(--line); font-weight: 400; }
.tour__wire-list { list-style: none; padding: 0; }
.tour__wire-list li { border-bottom: 1px solid var(--line-soft); }
.tour__wire-list a {
  display: grid; grid-template-columns: 4.5rem 1fr auto;
  gap: clamp(0.75rem, 2.5vw, 2rem); align-items: baseline; padding: 0.85rem 0;
  transition: padding-left 450ms var(--ease);
}
.tour__wire-list a:hover { padding-left: 1rem; }
.tour__wire-list .head { font-size: 0.95rem; text-wrap: pretty; overflow-wrap: anywhere; }
.tour__wire-list a:hover .head { color: var(--glow); }
@media (max-width: 640px) {
  .tour__wire-list a { grid-template-columns: 1fr; gap: 0.25rem; }
  .tour__wire-list .outlet { text-align: left; }
}

/* ─── timeline ───────────────────────────────────────────────────────── */

.timeline { list-style: none; padding: 0; position: relative; }
.timeline::before {
  content: ''; position: absolute;
  left: clamp(3.5rem, 8vw, 7rem); top: 0; bottom: 0; width: 2px;
  background: linear-gradient(to bottom, var(--r1), var(--r3), var(--r5), var(--r6));
  opacity: 0.5; border-radius: 2px;
}
.timeline li {
  position: relative; display: grid;
  grid-template-columns: clamp(3.5rem, 8vw, 7rem) 1fr;
  gap: clamp(1.5rem, 4vw, 3.5rem); padding-bottom: clamp(2rem, 4vw, 3rem);
}
.timeline .yr { font-family: var(--mono); font-size: 0.7rem; letter-spacing: 0.1em; color: var(--dim); padding-top: 0.4rem; font-variant-numeric: tabular-nums; }
.timeline .body { position: relative; padding-left: clamp(1.25rem, 3vw, 2.5rem); }
.timeline .body::before {
  content: ''; position: absolute;
  left: calc(-1 * clamp(1.5rem, 4vw, 3.5rem) / 2 - 4px);
  top: 0.7rem; width: 9px; height: 9px; border-radius: 50%;
  background: var(--dim); transform: translateX(-50%);
  transition: background 400ms, transform 400ms var(--ease), box-shadow 400ms;
}
.timeline li:hover .body::before { background: var(--glow); transform: translateX(-50%) scale(1.4); }
.timeline li.hl .body::before {
  background: linear-gradient(135deg, var(--r1), var(--r5));
  box-shadow: 0 0 0 5px color-mix(in oklab, var(--glow) 22%, transparent);
}
.timeline h3 { font-family: var(--display); font-weight: 700; font-size: clamp(1.25rem, 2.8vw, 2rem); line-height: 1.1; margin-bottom: 0.4rem; }
.timeline li.hl h3 { color: var(--glow); }
.timeline p { max-width: 58ch; color: var(--dim); font-size: 0.95rem; }
.timeline .tag {
  display: inline-block; margin-top: 0.55rem;
  font-family: var(--mono); font-size: 0.57rem;
  letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--dim); border: 1px solid var(--line); border-radius: 999px; padding: 0.2rem 0.6rem;
}

/* ─── facts ──────────────────────────────────────────────────────────── */

.facts {
  max-width: 1000px; margin-inline: auto; text-align: center;
  padding: var(--section-y) max(var(--gut), env(safe-area-inset-right)) var(--section-y) max(var(--gut), env(safe-area-inset-left));
}
.facts__quote {
  font-family: var(--display); font-weight: 700; font-style: italic;
  font-size: clamp(1.3rem, 3.2vw, 2.6rem); line-height: 1.28;
  min-height: 4.5em;
  transition: opacity 400ms var(--ease), transform 400ms var(--ease);
  text-wrap: balance;
}
.facts__quote.is-out { opacity: 0; transform: translateY(-10px); }
.facts__nav { display: flex; align-items: center; justify-content: center; gap: 2rem; margin-top: 2.25rem; }
.facts__nav button {
  width: 2.75rem; height: 2.75rem; border-radius: 50%;
  border: 1px solid var(--line);
  transition: border-color 300ms, background 300ms, color 300ms;
}
.facts__nav button:hover { border-color: transparent; background: linear-gradient(135deg, var(--r1), var(--r5)); color: #12101A; }

/* ─── footer ─────────────────────────────────────────────────────────── */

.footer {
  border-top: 1px solid var(--line);
  max-width: var(--maxw); margin-inline: auto;
  padding: clamp(3rem, 7vw, 5rem) max(var(--gut), env(safe-area-inset-right)) max(2.5rem, env(safe-area-inset-bottom)) max(var(--gut), env(safe-area-inset-left));
}
.footer__row { display: flex; flex-wrap: wrap; gap: clamp(1.5rem, 5vw, 4rem); justify-content: space-between; align-items: flex-start; }
.footer__row--end { align-items: center; margin-top: clamp(2.5rem, 6vw, 4rem); padding-top: 1.5rem; border-top: 1px solid var(--line-soft); }
.footer__mark { font-family: var(--display); font-weight: 900; font-size: clamp(1.75rem, 5vw, 3rem); letter-spacing: -0.01em; margin-bottom: 0.8rem; }
.footer__note { max-width: 52ch; font-size: 0.8rem; line-height: 1.7; color: var(--dim); }
.footer__links { display: flex; flex-direction: column; gap: 0.6rem; }
.footer__links a {
  font-family: var(--mono); font-size: 0.68rem;
  letter-spacing: 0.14em; text-transform: uppercase; color: var(--dim);
  transition: color 250ms, letter-spacing 350ms var(--ease);
}
.footer__links a:hover { color: var(--glow); letter-spacing: 0.2em; }

/* ─── empty ──────────────────────────────────────────────────────────── */

.empty { font-family: var(--mono); font-size: 0.7rem; letter-spacing: 0.12em; text-transform: uppercase; color: var(--dim); padding: 2rem 0; }

/* ─── motion / print ─────────────────────────────────────────────────── */

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
  /* The holographic sweep freezes rather than disappearing — still a rainbow,
     just a still one. The canvas is switched off in JS. */
  .holo { animation: none; background: linear-gradient(90deg, var(--r1), var(--r3), var(--r5)); }
  .dust, .sparkle { display: none; }
  [data-reveal] { opacity: 1; transform: none; }
}

@media print {
  .sparkle, .dust, .wash, .nav { display: none; }
  body { background: #fff; color: #000; }
}
