/* app.css — the ONLY stylesheet we author.
   Every value below is a token generated by `stellar gen` from
   stellar.config.json. No hex codes, no color math, no clamps. */

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

/* Registering these as <color> is what lets a theme change animate: an
   unregistered custom property jumps, a registered one interpolates. */
@property --lit  { syntax: '<color>'; inherits: true; initial-value: #98b0d3; }
@property --mid  { syntax: '<color>'; inherits: true; initial-value: #b4cdf1; }
@property --deep { syntax: '<color>'; inherits: true; initial-value: #98b0d3; }
@property --glow { syntax: '<color>'; inherits: true; initial-value: #b4cdf1; }
@property --ink  { syntax: '<color>'; inherits: true; initial-value: #0b2744; }
@property --star { syntax: '<color>'; inherits: true; initial-value: transparent; }

/* surfaces ease between the two palettes; interactive chrome keeps its own
   quicker timing because those rules declare their own transition */
body, .mention, .stamp, .chip, input[type="search"], .timeline::before,
.landing, .target, .lede, .ctx, h1 {
  transition: background-color var(--anim-duration-long) var(--anim-ease-standard),
              color var(--anim-duration-long) var(--anim-ease-standard),
              border-color var(--anim-duration-long) var(--anim-ease-standard),
              box-shadow var(--anim-duration-long) var(--anim-ease-standard);
}

body {
  background: var(--neutral-1);
  color: var(--neutral-12);
  font-family: var(--font-sans);
  font-size: var(--font-size-1);
  line-height: var(--font-line-height-2);
  margin: 0;
  padding: 0;
}

/* --- upside down: the planet is the floor, results climb away above it ---
   The scroller is column-reverse, so its first child paints at the bottom and
   it opens already parked there — the page starts on the planet, with no
   scrolling and nothing pinned. */
.page {
  /* Named here because three things must agree on them: the sky's height, the
     length of the line's descent, and where the rocket comes to rest. */
  --sky: 67vh;
  --descent: calc(var(--size-9) + var(--size-5) + var(--size-3));
  height: 100dvh;
  overflow-y: auto;
  display: flex;
  flex-direction: column-reverse;

  --star: transparent;                 /* no stars in the daytime */
  transition: --star var(--anim-duration-long) var(--anim-ease-standard);
}
.ground {
  /* Named once here because which end of a Stellar ramp is the brighter one
     flips between light and dark. --ink is the lit surface's own contrast pair. */
  --lit: var(--primary-3);
  --mid: var(--primary-4);
  --deep: var(--primary-5);
  --glow: var(--primary-4);
  --ink: var(--primary-3-on);
  /* registered above, so switching themes CROSS-FADES the planet
     instead of snapping — plain custom properties cannot interpolate */
  transition: --lit var(--anim-duration-long) var(--anim-ease-standard),
              --mid var(--anim-duration-long) var(--anim-ease-standard),
              --deep var(--anim-duration-long) var(--anim-ease-standard),
              --glow var(--anim-duration-long) var(--anim-ease-standard),
              --ink var(--anim-duration-long) var(--anim-ease-standard);
  position: relative;
  flex: 0 0 auto;               /* flex items shrink by default; the sky must not */
  height: var(--sky);           /* tall enough that the atmosphere fades out INSIDE it */
  overflow: hidden;
}
/* the pad rides on the planet's surface, under its lit limb */
.pad {
  position: absolute;
  inset: auto 0 0 0;
  z-index: 1;
  max-width: 64rem;                    /* container width is an app decision */
  margin-inline: auto;
  padding: 0 var(--size-5) var(--size-6);
  color: var(--primary-5-on);          /* the contrast pair for the surface it sits on */
}
.pad .lede { color: var(--primary-5-on); opacity: 0.8; }
.pad .howmade {
  margin-left: var(--size-3);
  font-size: var(--font-size--1);
  color: inherit;
  opacity: 0.7;
  text-decoration: underline dotted;
  text-underline-offset: 0.2em;
}
.pad .howmade:hover { opacity: 1; }
#results {
  flex: 0 0 auto;
  max-width: 64rem;
  width: 100%;
  margin-inline: auto;
  padding: var(--size-9) var(--size-5) 0;
}


h1 {
  font-size: var(--font-size-6);
  line-height: var(--font-line-height--1);
  letter-spacing: var(--font-letter-spacing--1);
  margin: 0 0 var(--size-2);
}

.lede { color: var(--neutral-10); margin: 0 0 var(--size-5); }

/* search */
input[type="search"] {
  width: 100%;
  padding: var(--size-3) var(--size-4);
  font: inherit;
  color: var(--neutral-12);
  background: var(--neutral-2);
  border: var(--border-width-1) solid var(--neutral-4);
  border-radius: var(--border-radius-6);
}
input[type="search"]:focus-visible { outline: 2px solid var(--primary-6); }

/* term chips — each spends its own generated ramp, incl. the APCA text color.
   Split into two banks so the timeline falls down the channel between them. */
.chips {
  flex: 0 0 auto;                      /* floating just above the planet */
  position: relative;
  z-index: 2;                          /* layer above the planet's box-shadow */
  display: grid;
  grid-template-columns: 1fr 1fr;
  column-gap: var(--size-7);           /* the channel the line drops through */
  max-width: 64rem;
  width: 100%;
  margin-inline: auto;
  /* column-reverse: the ground is below, so the BOTTOM margin is the one facing
     it — pull the chips down to float over the outer edge of the atmosphere */
  margin-bottom: calc(var(--size-8) * -1);
  padding: var(--size-4) var(--size-5) var(--size-5);
}
/* the timeline continues down the channel, unbroken, towards the planet */
.chips::before {
  content: "";
  position: absolute;
  left: 50%; top: 0; bottom: 0;
  width: var(--border-width-2);
  transform: translateX(-50%);
  background: var(--primary-7);
  z-index: -1;
}
.chip-side { display: flex; flex-wrap: wrap; gap: var(--size-2); align-content: flex-start; }
.chip-side:first-child { justify-content: flex-end; }   /* both banks hug the channel */
.chip-side:last-child  { justify-content: flex-start; }
.chip {
  font-size: var(--font-size--1);
  padding: var(--size--1) var(--size-2);
  border-radius: var(--border-radius-6);
  border: var(--border-width-1) solid var(--neutral-4);
  background: var(--neutral-2);
  color: var(--neutral-11);
  cursor: pointer;
}
.chip small { opacity: 0.65; font-variant-numeric: tabular-nums; }
/* the three seeded ramps get their brand color + its computed text color */
.chip[data-term="rocket"]  { background: var(--term-rocket-0);  color: var(--term-rocket-0-on);  border-color: transparent; }
.chip[data-term="stellar"] { background: var(--term-stellar-0); color: var(--term-stellar-0-on); border-color: transparent; }
.chip[data-term="cult"]     { background: var(--term-cult-0);     color: var(--term-cult-0-on);     border-color: transparent; }
.chip[data-term="stardust"] { background: var(--term-stardust-0); color: var(--term-stardust-0-on); border-color: transparent; }
.chip:hover { border-color: var(--primary-6); }
mark { background: var(--term-cult-1); color: var(--term-cult-1-on); border-radius: var(--border-radius-1); padding: 0 0.15em; }

/* result cards */
.mention {
  background: var(--neutral-2);
  border: var(--border-width-1) solid var(--neutral-3);
  border-radius: var(--border-radius-3);
  padding: var(--size-4);
  margin-block: var(--size-4);
  box-shadow: var(--shadow-2);
}
/* The title and the thumbnail share the top row; the quote and the player then
   run the FULL width of the card beneath them, rather than being penned into
   the first column with dead space under the thumbnail. */
.mention {
  display: grid;
  grid-template-columns: 1fr 13rem;
  gap: var(--size-3) var(--size-4);
  align-items: start;
}
.mention header     { grid-column: 1; grid-row: 1; }
.mention .thumb     { grid-column: 2; grid-row: 1; }
.mention blockquote { grid-column: 1 / -1; }
.mention yt-clip    { grid-column: 1 / -1; }
.mention .thumb {
  width: 100%;
  height: auto;                      /* let the aspect ratio win over the attr */
  aspect-ratio: var(--aspect-ratio-widescreen);
  object-fit: cover;
  border-radius: var(--border-radius-2);
  display: block;
}
@media (width < 46rem) {
  .mention { grid-template-columns: 1fr; }
  .mention .thumb  { grid-column: 1; grid-row: 1; max-width: 16rem; }
  .mention header  { grid-row: 2; }
}
.mention header { display: flex; align-items: baseline; gap: var(--size-3); }
.mention h3 { font-size: var(--font-size-2); margin: 0; }
.mention time { color: var(--primary-8); font-weight: var(--font-weight-bold); font-variant-numeric: tabular-nums; }
.mention blockquote { margin: 0; color: var(--neutral-12); }
.ctx { color: var(--neutral-9); }

/* the Rocket component's button + player */
.btn {
  font: inherit;
  font-size: var(--font-size--1);
  padding: var(--size--1) var(--size-2);
  border: none;
  border-radius: var(--border-radius-6);
  background: var(--primary-6);
  color: var(--primary-6-on);          /* contrast pair, computed by Stellar */
  cursor: pointer;
  transition: background var(--anim-duration-fast) var(--anim-ease-standard);
}
.btn:hover { background: var(--primary-7); color: var(--primary-7-on); }
yt-clip iframe {
  width: min(100%, 40rem);
  aspect-ratio: var(--aspect-ratio-widescreen);
  border: 0;
  border-radius: var(--border-radius-2);
  margin-top: var(--size-3);
  display: block;
}

/* --- timeline: one line down the middle, months as nodes, cards alternating --- */
.timeline { position: relative; margin-top: var(--size-6); }
.timeline::before {
  content: "";
  position: absolute;
  left: 50%; top: 0; bottom: 0;
  width: var(--border-width-2);
  transform: translateX(-50%);
  background: linear-gradient(to bottom, transparent, var(--primary-7) 14% 100%);
  z-index: -1;
}
.stamp {
  width: fit-content;
  margin: var(--size-6) auto var(--size-4);
  font-size: var(--font-size--1);
  letter-spacing: var(--font-letter-spacing-2);
  text-transform: uppercase;
  background: var(--neutral-2);
  border: var(--border-width-1) solid var(--neutral-4);
  border-radius: var(--border-radius-6);
  padding: var(--size--1) var(--size-3);
}
.tl-items { display: grid; grid-template-columns: 1fr 1fr; gap: var(--size-4) var(--size-7); }
.tl-items > :nth-child(odd)  { grid-column: 1; justify-self: end; }
.tl-items > :nth-child(even) { grid-column: 2; justify-self: start; }
.tl-flip .tl-items > :nth-child(odd)  { grid-column: 2; justify-self: start; }
.tl-flip .tl-items > :nth-child(even) { grid-column: 1; justify-self: end; }
.tl-items .mention { max-width: 30rem; margin-block: 0; grid-template-columns: 1fr 7rem; }
/* --- the planet: a real limb (hard edge) with a soft atmosphere glow --- */
.planet {
  position: absolute;
  /* the limb sits one whole atmosphere below the top of the sky, so the glow
     (spread + blur) reaches zero before it ever meets the clip edge */
  left: 50%; top: calc(var(--size-9) + var(--size-5));
  width: 150vw; max-width: 2400px;     /* narrower than the page => real curve */
  aspect-ratio: var(--aspect-ratio-square);
  transform: translateX(-50%);
  border-radius: 50%;
  background: radial-gradient(circle at 50% 14%,
    var(--lit) 0%, var(--mid) 34%, var(--deep) 70%);
  box-shadow:
    0 0 var(--size-4) var(--size-0) var(--glow),     /* tight rim of air */
    0 0 var(--size-9) var(--size-5) var(--glow);     /* the wide halo */
}
/* Stellar now emits its dark palette under :root.dark rather than a media
   query, so our own theme-aware names follow the same switch. */
:root.dark .ground { --lit: var(--primary-8); --glow: var(--primary-7); --ink: var(--primary-8-on); }

/* --- the descent: the line leaves the sky and touches down on the surface --- */
.landing {
  position: absolute;
  left: 50%; top: 0;
  width: var(--border-width-2);
  /* down past the limb, so it lands ON the planet rather than at the horizon */
  height: var(--descent);
  transform: translateX(-50%);
  background: var(--primary-7);
}

/* --- the rocket: rests on the pad, then rides at that height as you climb ---
   sticky, not fixed: it is a real box in the column that the scroller carries. */
.flight {
  position: sticky;
  bottom: calc(var(--sky) - var(--descent));   /* exactly the pad's height */
  z-index: 3;
  height: 0;                                   /* takes up no room in the stack */
}
/* Datastar's own rocket (data-star.dev). It is pixel art, so it must scale on
   the pixel grid — never smoothed. */
.rocket {
  --rocket: var(--size-9);
  position: absolute;
  left: 50%;
  /* Rotating a square 45° swings its corner below the box by (√2−1)/2 = 0.2071
     of the width; the ship's base sits 127/512 further up that diagonal. Both
     pictures are the same pixels in the same place — the flame simply burns
     below the base — so this one offset rests the ship on the pad either way. */
  bottom: calc(var(--rocket) * (0.2071 - 0.2480));
  transform: translateX(-50%) rotate(-45deg);  /* the logo flies at 45°: stand it up */
  width: var(--rocket);
  height: auto;
  image-rendering: pixelated;
}
/* the pad itself: a circle painted on the ground, seen at a grazing angle */
.target {
  position: absolute;
  left: 50%; top: 100%;
  transform: translate(-50%, -50%);
  width: var(--size-12);
  aspect-ratio: 5 / 1;
  border: var(--border-width-2) solid var(--ink);
  border-radius: 50%;
  opacity: var(--anim-opacity-muted);
}
.target::before {
  content: "";
  position: absolute;
  inset: 26%;
  border: var(--border-width-1) solid var(--ink);
  border-radius: 50%;
}

/* --- narrow screens: one column, the whole line runs down the left rail ---
   Last in the file on purpose: these override rules of equal specificity, so
   source order is what decides (.landing is defined above). */
@media (width < 60rem) {
  /* One rail down the side, with room to breathe. --rail is the CENTRE of the
     gutter, so the line, the landing pad and the rocket all sit centred on it
     rather than hugging the edge. The timeline's own line subtracts #results'
     padding, because it is measured from inside that box — that is what keeps
     all three segments on the same x.
     The gutter and the rocket are given in rem on purpose: the fluid --size-*
     steps collapse to ~13px at phone widths, which is far too small here. */
  .page {
    --rail: 1.75rem;
    /* The rail sits off to the side, where the planet's curve has already
       fallen well below its apex — so the line must descend further to touch
       down. The planet is a circle 150vw wide, so that drop is
       r - sqrt(r² - dx²) with r = 75vw; across phone-to-tablet widths that
       works out at roughly 16vw. A fixed length cannot work here: the radius
       grows with the viewport while the rail stays put. */
    --descent: calc(var(--size-9) + var(--size-5) + 16vw);
  }
  .timeline { padding-left: 2.75rem; }        /* stamps AND cards clear the rail */
  .timeline::before { left: calc(var(--rail) - var(--size-5)); transform: translateX(-50%); }
  .chips::before, .landing { left: var(--rail); transform: translateX(-50%); }
  .rocket { left: var(--rail); --rocket: 2.5rem; }
  .chips { grid-template-columns: 1fr; padding-left: 3.5rem; }
  .chip-side:first-child, .chip-side:last-child { justify-content: flex-start; }
  .stamp { margin-inline: 0 auto; }
  .tl-items { grid-template-columns: 1fr; padding-left: 0; }
  /* .tl-items .mention is (0,2,0) and would otherwise keep its second column
     here, leaving a dead 7rem gutter that pushes the card off the screen */
  .tl-items .mention { grid-template-columns: 1fr; min-width: 0; }
  /* the .tl-flip rules carry an extra class, so they must be named here too or
     they out-specify this and keep flipped months in a second column */
  .tl-items > :nth-child(odd), .tl-items > :nth-child(even),
  .tl-flip .tl-items > :nth-child(odd), .tl-flip .tl-items > :nth-child(even) {
    grid-column: 1; justify-self: stretch;
  }
}

/* theme switch — a bare icon, no chrome */
.theme {
  position: fixed;                 /* the one pinned thing on the page */
  top: var(--size-4);
  right: var(--size-4);
  z-index: 4;                      /* above the rocket (3) and the chips (2) */
  padding: 0;
  background: none;
  border: 0;
  line-height: 0;
  color: var(--neutral-11);        /* outside .ground, so not --ink */
  opacity: 0.6;
  cursor: pointer;
  transition: opacity var(--anim-duration-fast) var(--anim-ease-standard),
              color var(--anim-duration-long) var(--anim-ease-standard);
}
.theme:hover { opacity: 1; }
.theme svg { display: block; }

:root.dark { --star: var(--neutral-12); }

/* --- the sky ---
   One 1400px tile of 30 stars, sizes 0.7-2.2px, each mixed down from --star to
   its own brightness so the depth comes from the stars rather than from layers.

   IMPORTANT: this is a viewport-sized FIXED element moved with transform, not a
   background-position on the scroller. background-position is a paint operation
   — animating it across a 13,000px element with 30 gradients re-rasterises the
   whole thing every frame. A transform is composited, so the layer is rastered
   once and the GPU just moves it. Same look, a fraction of the work. */
.sky {
  position: fixed;
  inset: -1400px 0 0 0;                /* one tile of headroom above the fold */
  z-index: -1;
  pointer-events: none;
  will-change: transform;              /* promote it to its own layer */
  background-size: 1400px 1400px;
  background-image:
    radial-gradient(1.8px 1.8px at 45.4% 55.7%, var(--star) 50%, transparent 52%),
    radial-gradient(0.9px 0.9px at 19.7% 51.1%, color-mix(in srgb, var(--star) 40%, transparent) 50%, transparent 52%),
    radial-gradient(2.2px 2.2px at 44.9% 15.6%, color-mix(in srgb, var(--star) 30%, transparent) 50%, transparent 52%),
    radial-gradient(1.8px 1.8px at 59.2% 40.0%, color-mix(in srgb, var(--star) 45%, transparent) 50%, transparent 52%),
    radial-gradient(0.8px 0.8px at 61.8% 81.8%, color-mix(in srgb, var(--star) 30%, transparent) 50%, transparent 52%),
    radial-gradient(0.7px 0.7px at 5.4% 86.4%, var(--star) 50%, transparent 52%),
    radial-gradient(1.0px 1.0px at 33.3% 58.7%, color-mix(in srgb, var(--star) 55%, transparent) 50%, transparent 52%),
    radial-gradient(0.8px 0.8px at 63.5% 50.0%, var(--star) 50%, transparent 52%),
    radial-gradient(0.8px 0.8px at 54.9% 91.4%, color-mix(in srgb, var(--star) 65%, transparent) 50%, transparent 52%),
    radial-gradient(1.1px 1.1px at 32.3% 24.0%, color-mix(in srgb, var(--star) 30%, transparent) 50%, transparent 52%),
    radial-gradient(1.5px 1.5px at 8.7% 75.6%, color-mix(in srgb, var(--star) 40%, transparent) 50%, transparent 52%),
    radial-gradient(0.7px 0.7px at 83.3% 39.1%, color-mix(in srgb, var(--star) 30%, transparent) 50%, transparent 52%),
    radial-gradient(0.7px 0.7px at 22.5% 91.0%, var(--star) 50%, transparent 52%),
    radial-gradient(1.5px 1.5px at 38.0% 70.1%, color-mix(in srgb, var(--star) 40%, transparent) 50%, transparent 52%),
    radial-gradient(1.1px 1.1px at 56.4% 21.1%, color-mix(in srgb, var(--star) 75%, transparent) 50%, transparent 52%),
    radial-gradient(1.5px 1.5px at 10.4% 33.9%, color-mix(in srgb, var(--star) 40%, transparent) 50%, transparent 52%),
    radial-gradient(0.7px 0.7px at 14.9% 69.9%, color-mix(in srgb, var(--star) 30%, transparent) 50%, transparent 52%),
    radial-gradient(2.2px 2.2px at 67.5% 20.1%, color-mix(in srgb, var(--star) 55%, transparent) 50%, transparent 52%),
    radial-gradient(1.5px 1.5px at 96.6% 75.9%, color-mix(in srgb, var(--star) 85%, transparent) 50%, transparent 52%),
    radial-gradient(1.0px 1.0px at 13.2% 42.4%, color-mix(in srgb, var(--star) 30%, transparent) 50%, transparent 52%),
    radial-gradient(0.7px 0.7px at 79.1% 31.2%, color-mix(in srgb, var(--star) 55%, transparent) 50%, transparent 52%),
    radial-gradient(1.8px 1.8px at 6.0% 16.1%, color-mix(in srgb, var(--star) 65%, transparent) 50%, transparent 52%),
    radial-gradient(1.1px 1.1px at 2.9% 60.6%, color-mix(in srgb, var(--star) 85%, transparent) 50%, transparent 52%),
    radial-gradient(1.8px 1.8px at 45.5% 94.1%, color-mix(in srgb, var(--star) 45%, transparent) 50%, transparent 52%),
    radial-gradient(0.9px 0.9px at 85.2% 19.6%, color-mix(in srgb, var(--star) 65%, transparent) 50%, transparent 52%),
    radial-gradient(1.0px 1.0px at 89.2% 80.5%, color-mix(in srgb, var(--star) 55%, transparent) 50%, transparent 52%),
    radial-gradient(1.5px 1.5px at 55.2% 67.9%, var(--star) 50%, transparent 52%),
    radial-gradient(1.1px 1.1px at 12.0% 5.7%, color-mix(in srgb, var(--star) 55%, transparent) 50%, transparent 52%),
    radial-gradient(1.5px 1.5px at 73.0% 39.6%, var(--star) 50%, transparent 52%),
    radial-gradient(1.0px 1.0px at 71.2% 8.6%, var(--star) 50%, transparent 52%);;
}
