/* ============================================================
   Árstraumur — design system.
   Realism contract: dark, desaturated, slow. The sky owns the
   color; the interface is quiet typography floating above it.
   Easing whitelist only: sine/power curves, never bounce/elastic.
   ============================================================ */

/* ---------- Fonts (self-hosted, Á + Swedish/Icelandic diacritics) -- */

@font-face {
  font-family: 'Marcellus';
  src: url('../fonts/marcellus-400.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Inter';
  src: url('../fonts/inter-400.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Inter';
  src: url('../fonts/inter-500.woff2') format('woff2');
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Inter';
  src: url('../fonts/inter-600.woff2') format('woff2');
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'IBM Plex Mono';
  src: url('../fonts/plexmono-400.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'IBM Plex Mono';
  src: url('../fonts/plexmono-500.woff2') format('woff2');
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}

/* ---------- Tokens -------------------------------------------------- */

:root {
  /* Sky: near black with a slight blue cast. Never navy, never purple. */
  --sky-zenith: #020308;
  --sky-mid: #04070e;
  --sky-horizon: #060b16;
  --bg: var(--sky-mid);

  /* Ink: near-white, cool. */
  --ink: rgba(230, 237, 245, 0.92);
  --ink-dim: rgba(199, 210, 222, 0.72);
  --ink-faint: rgba(176, 189, 204, 0.66);  /* keeps small-caps labels at WCAG AA */

  /* Single accent derived from atomic oxygen green (557.7 nm), desaturated
     for UI duty. Used for links and active states only. */
  --accent: #8fc7a4;
  --accent-dim: rgba(143, 199, 164, 0.55);

  --line: rgba(154, 176, 201, 0.16);
  --line-strong: rgba(154, 176, 201, 0.3);

  --font-display: 'Marcellus', 'Times New Roman', serif;
  --font-text: 'Inter', system-ui, -apple-system, 'Segoe UI', sans-serif;
  --font-mono: 'IBM Plex Mono', 'Consolas', monospace;

  /* Whitelisted easings (sine inOut, power2 out). */
  --ease-sine: cubic-bezier(0.45, 0.05, 0.55, 0.95);
  --ease-out: cubic-bezier(0.22, 0.61, 0.36, 1);

  --content-narrow: 44rem;
  --content-wide: 70rem;
  --pad-x: clamp(1.25rem, 4.5vw, 3rem);
  --header-h: 4.25rem;
}

/* ---------- Base ----------------------------------------------------- */

*, *::before, *::after { box-sizing: border-box; }

html {
  scroll-behavior: smooth;
  -webkit-text-size-adjust: 100%;
  /* The film lock and short pages drop the scrollbar; keep its gutter
     reserved so the page never shifts sideways when it comes and goes. */
  scrollbar-gutter: stable;
}
html.calm { scroll-behavior: auto; }
/* Owning the lock on the root keeps the reserved gutter well-defined
   (overflow propagated from body has patchy scrollbar-gutter behavior). */
html:has(body.film-lock) { overflow: hidden; }

body {
  margin: 0;
  background: var(--sky-zenith);
  color: var(--ink);
  font-family: var(--font-text);
  font-size: 1rem;
  line-height: 1.65;
  font-weight: 400;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  min-height: 100vh;
}

::selection { background: rgba(143, 199, 164, 0.25); color: #fff; }

/* ---------- The sky (static layer; the live canvas sits above it) --- */

#sky {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100vh;   /* large, stable viewport: never re-sizes with the mobile
                      address bar, so the scene holds its size on scroll */
  z-index: -1;
  display: block;
  opacity: 0;
  transition: opacity 2.4s var(--ease-sine);
}
html.scene-live #sky { opacity: 1; }
html.calm #sky { display: none; }
/* Subpages come back faster after a page turn; the long fade is for
   the first landing on the journey. */
body.subpage #sky { transition-duration: 1.1s; }

/* Static sky: a long-exposure night gradient with faint airglow at the
   horizon line, plus film grain to prevent banding. Always present, so
   content never waits for WebGL. */
.sky-static {
  position: fixed;
  inset: 0;
  z-index: -2;
  background:
    /* faint green airglow at the horizon, barely there */
    linear-gradient(to top,
      rgba(38, 66, 50, 0.16) 0%,
      rgba(16, 32, 30, 0.07) 7%,
      rgba(0, 0, 0, 0) 18%),
    linear-gradient(to top,
      var(--sky-horizon) 0%,
      var(--sky-mid) 34%,
      var(--sky-zenith) 78%);
}
.sky-static::after {
  /* Animated-free grain: breaks gradient banding, sells the photographic
     base even before the 3D layer loads. */
  content: '';
  position: absolute;
  inset: 0;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='240'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='240' height='240' filter='url(%23n)' opacity='0.5'/%3E%3C/svg%3E");
  background-size: 240px 240px;
  opacity: 0.05;
  pointer-events: none;
}

/* ---------- Accessibility helpers ------------------------------------ */

.skip-link {
  position: absolute;
  top: -3rem;
  left: 1rem;
  z-index: 100;
  padding: 0.6rem 1rem;
  background: var(--sky-zenith);
  color: var(--ink);
  border: 1px solid var(--line-strong);
  font-family: var(--font-mono);
  font-size: 0.75rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  text-decoration: none;
  transition: top 0.2s var(--ease-out);
}
.skip-link:focus { top: 1rem; }

.visually-hidden {
  position: absolute !important;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
  border-radius: 1px;
}

/* Soft-nav moves focus to the incoming page's heading for screen readers
   (nav.ts). That programmatic focus must never paint the green ring — iPad
   Safari (and sometimes desktop) treats it as focus-visible on the h1. */
main h1[tabindex="-1"]:focus,
main h1[tabindex="-1"]:focus-visible {
  outline: none;
}

/* ---------- Header ---------------------------------------------------- */

.site-header {
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: 50;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  height: var(--header-h);
  /* Right edge tightened to 1.1rem: Contact ends on the SAME line as the
     social column and the altitude readout — one straight edge down the side. */
  padding: 0 1.1rem 0 var(--pad-x);
  /* A soft darkening, not a bar: no border, no blur. */
  background: linear-gradient(to bottom, rgba(2, 3, 8, 0.92) 0%, rgba(2, 3, 8, 0.55) 60%, rgba(2, 3, 8, 0) 100%);
  pointer-events: none;
}
.site-header > * { pointer-events: auto; }

/* Brand mark matched to the loading-screen logo (180px wide), top-anchored
   with a gap so it never touches the top edge; sits over the content (header
   is z-index 50). */
.brand { display: inline-flex; align-items: center; align-self: flex-start; margin-top: 0.5rem; }
.brand img { display: block; width: min(180px, 46vw); height: auto; opacity: 0.92; }

.site-nav { display: flex; align-items: center; }

.site-menu {
  display: flex;
  align-items: center;
  gap: clamp(0.9rem, 2vw, 1.7rem);
  margin: 0;
  padding: 0;
  list-style: none;
}
.site-menu a {
  color: var(--ink-dim);
  text-decoration: none;
  font-family: var(--font-mono);
  font-size: 0.72rem;
  font-weight: 400;
  letter-spacing: 0.17em;
  text-transform: uppercase;
  transition: color 0.25s var(--ease-sine);
}
.site-menu a:hover { color: var(--ink); }
.site-menu a[aria-current="page"] { color: var(--accent); }
/* The tracking after the last letter would nudge CONTACT's visual edge off
   the right-side line: swallow it so the edge is optically flush. */
.site-menu li:last-child a { margin-right: -0.17em; }
/* The Transmissions push button ships hidden and is only un-hidden by push.js
   when notifications are available. While hidden, collapse its whole list item
   (not just the button) — otherwise the empty <li> leaves a double gap between
   Licensing and Contact. */
.site-menu li:has(> .menu-push[hidden]) { display: none; }

.nav-toggle { display: none; }

/* Calm toggle: a quiet instrument switch. */
.calm-toggle {
  display: inline-flex;
  align-items: center;
  gap: 0.5em;
  background: none;
  border: 1px solid var(--line);
  color: var(--ink-dim);
  font-family: var(--font-mono);
  font-size: 0.68rem;
  letter-spacing: 0.17em;
  text-transform: uppercase;
  padding: 0.42em 0.9em;
  cursor: pointer;
  transition: color 0.25s var(--ease-sine), border-color 0.25s var(--ease-sine);
}
.calm-toggle:hover { color: var(--ink); border-color: var(--line-strong); }
.calm-dot {
  width: 0.45em; height: 0.45em;
  border-radius: 50%;
  background: var(--ink-faint);
  transition: background 0.25s var(--ease-sine);
}
html.calm .calm-toggle { color: var(--accent); border-color: var(--accent-dim); }
html.calm .calm-dot { background: var(--accent); }

/* Mobile nav. Without JS the full menu simply wraps (navigation must work
   with JavaScript disabled). */
/* The hamburger takes over up to 1023px: with nine items since Licensing
   joined, the full row needs real width — mid sizes overlapped. */
@media (max-width: 1023px) {
  html.js .nav-toggle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2.6rem; height: 2.6rem;
    background: none;
    border: 1px solid var(--line);
    cursor: pointer;
    position: relative;
  }
  html.js .nav-toggle-bar,
  html.js .nav-toggle-bar::before,
  html.js .nav-toggle-bar::after {
    display: block;
    width: 1.1rem; height: 1px;
    background: var(--ink-dim);
    transition: transform 0.3s var(--ease-sine), opacity 0.3s var(--ease-sine);
  }
  html.js .nav-toggle-bar::before,
  html.js .nav-toggle-bar::after {
    content: '';
    position: absolute;
    left: 0.7rem;
  }
  html.js .nav-toggle-bar::before { transform: translateY(-5px); }
  html.js .nav-toggle-bar::after { transform: translateY(5px); }
  html.js .nav-toggle[aria-expanded="true"] .nav-toggle-bar { background: transparent; }
  html.js .nav-toggle[aria-expanded="true"] .nav-toggle-bar::before { transform: rotate(45deg); }
  html.js .nav-toggle[aria-expanded="true"] .nav-toggle-bar::after { transform: rotate(-45deg); }

  html.js .site-menu {
    position: fixed;
    top: var(--header-h);
    right: 0;
    left: 0;
    flex-direction: column;
    align-items: flex-start;
    gap: 0;
    padding: 0.5rem var(--pad-x) 1.4rem;
    background: rgba(2, 3, 8, 0.97);
    visibility: hidden;
    opacity: 0;
    transition: opacity 0.3s var(--ease-sine), visibility 0s linear 0.3s;
  }
  html.js .site-nav.open .site-menu {
    visibility: visible;
    opacity: 1;
    transition: opacity 0.3s var(--ease-sine);
  }
  html.js .site-menu li { width: 100%; }
  html.js .site-menu a {
    display: block;
    padding: 0.85rem 0;
    font-size: 0.8rem;
    border-bottom: 1px solid var(--line);
  }
  html.js .menu-calm { padding-top: 1rem; }

  html:not(.js) .site-menu { flex-wrap: wrap; justify-content: flex-end; }
  html:not(.js) .site-header { position: static; height: auto; padding: 1rem var(--pad-x); }
}

/* Between the hamburger and full width the row is still snug: compact type
   so the nine links, the brand and the icons all breathe. */
@media (min-width: 1024px) and (max-width: 1180px) {
  .site-menu { gap: 0.8rem; }
  .site-menu a, .menu-push { font-size: 0.66rem; letter-spacing: 0.12em; }
  .site-menu li:last-child a { margin-right: -0.12em; }   /* match the tighter tracking */
  .brand img { width: min(150px, 46vw); }
}

/* ---------- Typography ------------------------------------------------ */

h1, h2, h3 {
  font-family: var(--font-display);
  font-weight: 400;
  line-height: 1.15;
  color: var(--ink);
  margin: 0 0 1rem;
}
h1 { font-size: clamp(1.9rem, 4.5vw, 3.1rem); letter-spacing: 0.02em; }
h2 { font-size: clamp(1.4rem, 3vw, 2rem); }
h3 { font-size: 1.15rem; }

p { margin: 0 0 1.1em; }

a { color: var(--accent); text-decoration: underline; text-decoration-color: var(--accent-dim); text-underline-offset: 0.2em; transition: color 0.25s var(--ease-sine), text-decoration-color 0.25s var(--ease-sine); }
a:hover { color: #b1dcc0; text-decoration-color: currentColor; }

/* Small caps instrument label. */
.label {
  display: block;
  font-family: var(--font-mono);
  font-size: 0.7rem;
  font-weight: 400;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--ink-faint);
  margin: 0 0 1.2rem;
}

.lede { font-size: 1.12rem; color: var(--ink-dim); }

hr { border: 0; border-top: 1px solid var(--line); margin: 2.5rem 0; }

/* ---------- Page scaffolding ----------------------------------------- */

main { display: block; }

.page {
  max-width: var(--content-narrow);
  margin: 0 auto;
  padding: calc(var(--header-h) + 4.5rem) var(--pad-x) 5rem;
}
.page-wide { max-width: var(--content-wide); }

/* Solar panel model: with the live scene, content sits in a translucent
   frosted panel over the left half while the planet extends past it to
   the right (brief section 3). Scrim fallback guarantees contrast where
   backdrop-filter is unsupported. */
html.scene-live body.subpage .page {
  margin: 0;
  max-width: min(46rem, 52vw);
  min-height: 100vh;
  background: rgba(4, 6, 12, 0.62);
  border-right: 1px solid rgba(154, 176, 201, 0.12);
  padding-left: clamp(1.5rem, 4vw, 3.5rem);
  padding-right: clamp(1.5rem, 3vw, 3rem);
}
@supports (backdrop-filter: blur(1px)) {
  html.scene-live body.subpage .page {
    background: rgba(4, 6, 12, 0.42);
    backdrop-filter: blur(14px) saturate(1.05);
  }
}
@media (max-width: 880px) {
  /* Bottom sheet: the planet holds the upper half, content slides below
     with a solid top fade so text never fights the planet. */
  html.scene-live body.subpage .page {
    max-width: none;
    margin-top: 44vh;
    min-height: 56vh;
    border-right: 0;
    border-top: 1px solid rgba(154, 176, 201, 0.14);
    background: rgba(4, 6, 12, 0.78);
    padding-top: 2.2rem;
  }
  html.scene-live body.journey .band-content {
    position: relative;
  }
  html.scene-live body.journey .band-content::after {
    /* extra mobile scrim behind journey text */
    content: '';
    position: absolute;
    inset: -2rem -3rem;
    z-index: -2;
    background: rgba(2, 3, 8, 0.45);
    filter: blur(18px);
  }
}

/* A darkened area behind text columns, not a visible card. */
.scrim {
  position: relative;
}
.scrim::before {
  content: '';
  position: absolute;
  inset: -6rem -9rem;
  z-index: -1;
  /* closest-side: the gradient reaches zero before the box edge, so no
     straight edges ever show against a bright sky. */
  background: radial-gradient(closest-side at 50% 50%,
    rgba(2, 3, 8, 0.66) 0%,
    rgba(2, 3, 8, 0.42) 52%,
    rgba(2, 3, 8, 0.14) 78%,
    rgba(2, 3, 8, 0) 97%);
  pointer-events: none;
}
/* Over the bright twilight sky a heavy dark pool looks like a stain:
   keep just enough to anchor the type. */
html.twilight .scrim::before { opacity: 0.42; }

.page-title { margin-bottom: 0.4rem; }
.page-intro { color: var(--ink-dim); max-width: 38em; }

/* ---------- Journey sections (home) ----------------------------------- */

.band {
  position: relative;
  display: flex;
  align-items: center;
  min-height: 92vh;
  padding: 6rem var(--pad-x);
}
/* With the live scene, bands stretch so the climb breathes:
   section transitions take seconds of scroll, not a flick. */
html.scene-live body.journey .band { min-height: 135vh; }
html.scene-live body.journey .band-ground {
  min-height: 160vh;
  align-items: flex-start;
  padding-top: 19vh;
}
html.scene-live body.journey .band-footer { min-height: 80vh; }

/* Bands hand over softly: content rests dim until its band reaches the
   center of the viewport. Opacity only, never movement, and only while
   the live scene carries the journey. */
html.scene-live body.band-fade .band-content {
  opacity: 0.1;
  transition: opacity 1.1s var(--ease-sine);
}
html.scene-live body.band-fade .band-content.in-view { opacity: 1; }
html.calm body.band-fade .band-content { opacity: 1 !important; }
.band-inner {
  width: 100%;
  max-width: var(--content-wide);
  margin: 0 auto;
}
.band-content { max-width: 36rem; }

.band-ground {
  min-height: 100vh;
  align-items: flex-end;
  padding-bottom: 14vh;
}

/* Pull the journey text LEFT toward the edge, halving its gap to the viewport
   edge (desktop scene only; mobile keeps its own centred layout). Applied to
   every band so the hero and all scroll sections share one left edge. The gap
   is half the empty margin either side of the centred band, so shifting left by
   a quarter of (viewport - band width) lands it at half the original gap. */
@media (min-width: 881px) {
  html.scene-live body.journey .band-content {
    margin-left: min(0px, calc((var(--content-wide) - 100vw) / 4));
  }
}

.hero-logo img {
  width: clamp(220px, 34vw, 330px);
  height: auto;
  opacity: 0.97;
}
.hero-descriptor {
  font-family: var(--font-display);
  font-size: clamp(1.05rem, 2.1vw, 1.45rem);
  color: var(--ink-dim);
  letter-spacing: 0.04em;
  max-width: 26em;
  margin: 1.4rem 0 2rem;
}

/* Award splash under the descriptor, with a bit more air below the text than
   the logo has above it (David-tuned; the :has() sets the gap only while the
   splash exists). Fade in, hold, fade out — then .gone collapses the space
   smoothly so the scrim never jumps. */
.hero-descriptor:has(+ .hero-awards) { margin-bottom: 2.4rem; }
.hero-awards {
  display: block;
  width: clamp(230px, 30vw, 320px);
  margin-top: 0;
  max-height: 200px;
  opacity: 0;
  transition: opacity 1.1s ease, max-height 0.7s ease, margin-bottom 0.7s ease;
}
.hero-awards img { display: block; width: 100%; height: auto; }
.hero-awards[hidden] { display: none; }
.hero-awards.on { opacity: 1; }
.hero-awards.on:hover { opacity: 0.85; }   /* it is a link: a nudge of feedback */
.hero-awards.gone { max-height: 0; pointer-events: none; }

/* The quiet /awards page: the same trophy, sitting calmly in the text flow. */
/* Trophy and sleeve on one line. The sleeve is capped to the trophy's own
   height so the pair reads as a row rather than as two unrelated pictures. */
.rec-hero {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 1.2rem 1.8rem;
  margin: 1.6rem 0;
}
.rec-hero .awards-figure { margin: 0; }
.rec-cover {
  display: block;
  flex: 0 0 auto;
  width: clamp(110px, 19vw, 180px);
  opacity: 0.92;
  transition: opacity 0.35s var(--ease-sine), transform 0.35s var(--ease-sine);
}
.rec-cover:hover,
.rec-cover:focus-visible { opacity: 1; transform: translateY(-2px); }
.rec-cover img { display: block; width: 100%; height: auto; }
@media (prefers-reduced-motion: reduce) {
  .rec-cover { transition: opacity 0.2s linear; }
  .rec-cover:hover,
  .rec-cover:focus-visible { transform: none; }
}

.awards-figure {
  display: block;
  width: clamp(240px, 34vw, 346px);
  height: auto;
  margin: 1.6rem 0;
}
.hero-follow {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem 1.6rem;
  margin: 0; padding: 0;
  list-style: none;
}
.hero-follow a {
  font-family: var(--font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.17em;
  text-transform: uppercase;
  color: var(--ink-dim);
  text-decoration: none;
  transition: color 0.25s var(--ease-sine);
}
.hero-follow a:hover { color: var(--accent); }

.band-footer {
  min-height: 60vh;
  align-items: flex-end;
}

/* ---------- News ------------------------------------------------------ */

.news-list { list-style: none; margin: 0; padding: 0; }
.news-item {
  padding: 2rem 0;
  border-top: 1px solid var(--line);
}
.news-item:first-child { border-top: 0; }

.transmission-head {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem 1.4rem;
  font-family: var(--font-mono);
  font-size: 0.7rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-faint);
  margin-bottom: 0.55rem;
}
.transmission-head .t-no { color: var(--accent-dim); }

.news-item h2, .news-item h3 { margin-bottom: 0.4rem; }
.news-item h2 a, .news-item h3 a {
  color: var(--ink);
  text-decoration: none;
}
.news-item h2 a:hover, .news-item h3 a:hover { color: var(--accent); }
.news-item .excerpt { color: var(--ink-dim); margin: 0; max-width: 40em; }

.news-thumb {
  display: block;
  max-width: 100%;
  height: auto;
  margin: 1rem 0 0.4rem;
  opacity: 0.92;
}

/* Home news item: whole block clickable; title on top, thumb left of text. */
.ni-link { display: block; text-decoration: none; color: inherit; }
.ni-title { margin-bottom: 0.6rem; color: var(--ink); transition: color 0.25s var(--ease-sine); }
.ni-link:hover .ni-title { color: var(--accent); }
.ni-body { display: flex; gap: 1.2rem; align-items: flex-start; }
.ni-thumb {
  flex: 0 0 auto;
  width: 140px;
  height: auto;
  display: block;
  border: 1px solid var(--line);
  opacity: 0.94;
}
.ni-body .excerpt { margin: 0; }
@media (max-width: 560px) { .ni-thumb { width: 92px; } }

/* Right-aligned "more" links with » arrows. A shadow keeps them legible
   where they sit over a bright planet. */
.more-link { text-align: right; margin: 1.5rem 0 0; }
.more-link a {
  font-family: var(--font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--accent);
  text-decoration: none;
  text-shadow: 0 1px 10px rgba(0, 0, 0, 0.95), 0 0 3px rgba(0, 0, 0, 0.9);
}
.more-link a:hover { color: var(--ink); }

/* Feature card: latest release and latest video, cover left, info right,
   the whole card clickable (mirrors the release page layout). */
.feature-card {
  display: grid;
  grid-template-columns: minmax(0, 15rem) 1fr;
  gap: 1.8rem;
  align-items: center;
  text-decoration: none;
  color: inherit;
  margin-top: 1.3rem;
}
@media (max-width: 620px) {
  .feature-card { grid-template-columns: 1fr; gap: 1.1rem; }
  .feature-card .fc-cover { max-width: 15rem; }
}
.fc-cover { display: block; }
.fc-cover img { width: 100%; height: auto; display: block; }
.fc-cover-video {
  position: relative;
  aspect-ratio: 16 / 9;
  background-size: cover;
  background-position: center;
  border: 1px solid var(--line);
}
.fc-play {
  position: absolute;
  inset: 0;
  margin: auto;
  width: 0;
  height: 0;
  border-style: solid;
  border-width: 11px 0 11px 19px;
  border-color: transparent transparent transparent rgba(255, 255, 255, 0.92);
  filter: drop-shadow(0 0 8px rgba(0, 0, 0, 0.55));
  transition: transform 0.25s var(--ease-sine);
}
.feature-card:hover .fc-play { transform: scale(1.15); }
.fc-body { display: block; }
.fc-title {
  display: block;
  font-family: var(--font-display);
  font-size: 1.5rem;
  line-height: 1.15;
  color: var(--ink);
  margin-bottom: 0.35rem;
  transition: color 0.25s var(--ease-sine);
}
.feature-card:hover .fc-title { color: var(--accent); }
.fc-sub { display: block; color: var(--ink-dim); font-size: 0.95rem; }
.fc-awards { display: block; margin-top: 0.7rem; }
.fc-awards span {
  display: block;
  font-family: var(--font-mono);
  font-size: 0.68rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--accent-dim);
}

/* Article body (news post) */
.prose { font-size: 1.02rem; }
.prose img { max-width: 100%; height: auto; }
/* Embeds must never share a line with text: block them out with room. */
.prose iframe {
  display: block;
  max-width: 100%;
  width: 100%;
  border: 0;
  margin: 1.8rem 0;
  clear: both;
}
.prose figure { margin: 1.6rem 0; }
.prose blockquote {
  margin: 1.6rem 0;
  padding-left: 1.2rem;
  border-left: 1px solid var(--line-strong);
  color: var(--ink-dim);
  font-style: italic;
}
.prose h2, .prose h3 { margin-top: 2.2rem; }

.post-meta {
  font-family: var(--font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

.post-featured { margin: 1.6rem 0 2rem; }
.post-featured img { width: 100%; height: auto; display: block; opacity: 0.95; }

.pager {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  margin-top: 3rem;
  font-family: var(--font-mono);
  font-size: 0.75rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

/* News archive grid: thumbnail, title, date. */
.news-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
  gap: 2.2rem 1.8rem;
  margin: 2.6rem 0 0;
  padding: 0;
  list-style: none;
}
.news-grid a { display: block; color: var(--ink); text-decoration: none; }
.ng-thumb {
  display: block;
  aspect-ratio: 16 / 10;
  background-size: cover;
  background-position: center;
  background-color: rgba(20, 28, 44, 0.55);
  opacity: 0.9;
  transition: opacity 0.3s var(--ease-sine);
}
.news-grid a:hover .ng-thumb { opacity: 1; }
.ng-thumb-empty {
  background-image:
    linear-gradient(135deg, rgba(143, 199, 164, 0.06) 0%, rgba(20, 28, 44, 0.4) 60%);
}
.ng-title {
  display: block;
  font-family: var(--font-display);
  font-size: 1.02rem;
  line-height: 1.3;
  margin: 0.8rem 0 0.2rem;
}
.news-grid a:hover .ng-title { color: var(--accent); }
.ng-date {
  font-family: var(--font-mono);
  font-size: 0.66rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

/* ---------- Round platform icons (ported from the HQ link pages) ------- */

.platform-icons {
  display: flex;
  flex-wrap: wrap;
  gap: 0.65rem;
  margin: 1.5rem 0 0.4rem;
}
.platform-icon {
  display: inline-block;
  width: 2.85rem;
  height: 2.85rem;
  border-radius: 50%;
  opacity: 0.92;
  transition: opacity 0.25s var(--ease-sine), transform 0.25s var(--ease-sine);
}
.platform-icon:hover { opacity: 1; transform: translateY(-2px); }
.platform-icon > svg { display: block; width: 100%; height: 100%; }
.pi-circle {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
  border-radius: 50%;
}
.pi-circle svg { width: 54%; height: 54%; display: block; }

/* ---------- Video lightbox --------------------------------------------- */

.video-lightbox {
  position: fixed;
  inset: 0;
  z-index: 95;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: clamp(1rem, 4vw, 3rem);
  background: rgba(2, 3, 8, 0.92);
  opacity: 0;
  transition: opacity 0.35s var(--ease-sine);
}
.video-lightbox.open { opacity: 1; }
.video-lightbox .vl-frame {
  width: min(1100px, 100%);
  aspect-ratio: 16 / 9;
  background: #000;
}
.video-lightbox iframe {
  width: 100%;
  height: 100%;
  border: 0;
  display: block;
}
.video-lightbox .vl-close {
  position: absolute;
  top: 1rem;
  right: 1.2rem;
  width: 2.6rem;
  height: 2.6rem;
  background: rgba(2, 3, 8, 0.8);
  border: 1px solid var(--line);
  color: var(--ink-dim);
  font-size: 1.2rem;
  line-height: 1;
  cursor: pointer;
  transition: color 0.25s var(--ease-sine), border-color 0.25s var(--ease-sine);
}
.video-lightbox .vl-close:hover { color: var(--ink); border-color: var(--line-strong); }

/* Image variant: the frame is the picture, so drop the 16:9 box and let the
   image find its own size inside the viewport. */
.img-lightbox .vl-frame {
  width: auto;
  aspect-ratio: auto;
  background: none;
  max-width: min(1100px, 100%);
  max-height: 86vh;
}
.img-lightbox .vl-frame img {
  display: block;
  max-width: 100%;
  max-height: 86vh;
  width: auto;
  height: auto;
  border-radius: 2px;
  box-shadow: 0 30px 90px rgba(0, 0, 0, 0.6);
}

/* ---------- Awards: the site's own recognition ------------------------- */
/* The three CSSDA monograms. Colour variants on purpose: they are the marks
   people recognise, and three small discs carry the page without shouting.
   White variants ship alongside (cssda-*-white.svg) if the colour ever fights
   the palette. */
/* A label above each awarding body, set like the credits in the list below so
   the page reads as two named groups rather than one run of images. */
/* A publisher's own mark in place of the mono heading. The two wordmark logos
   carry their own name and stand alone; the Three.js mark is an abstract solid
   and keeps the text beside it. Heights are tuned so the NAMES land at roughly
   the same optical size, not so the boxes match: the Schallwelle lockup spends
   a third of its height on the symbol, the CSSDA logo is all letterform.
   The .svg files are recoloured copies (#b0bdcc); their originals ship in a
   near-black that would vanish on this background. */
.award-group--mark {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding-bottom: 0.1rem;
}
.ag-logo { display: block; width: auto; opacity: 0.82; }
.ag-logo--cssda { height: 28px; }
.ag-logo--schallwelle { height: 58px; }
.ag-logo--cyclical { height: 46px; }
.ag-mark { display: block; width: auto; height: 21px; opacity: 0.82; }

.award-group {
  margin: 3.2rem 0 0;
  padding-top: 2.2rem;
  border-top: 1px solid var(--line);
  font-family: var(--font-mono);
  font-size: 0.62rem;
  font-weight: 400;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--ink-faint);
}
/* Four across, filling exactly the same measure as the .asset-list below: the
   marks and the words they stand for line up on both edges. */
.cssda-row {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 1rem;
  max-width: 36rem;
  margin: 1.6rem 0 0;
  text-decoration: none;
}
.cssda-row img {
  display: block;
  width: 100%;
  height: auto;
  opacity: 0.92;
  transition: opacity 0.3s var(--ease-sine), transform 0.3s var(--ease-sine);
}
.cssda-row:hover img { opacity: 1; }
.cssda-row img:hover { transform: translateY(-3px); }
@media (prefers-reduced-motion: reduce) {
  .cssda-row img { transition: opacity 0.2s linear; }
  .cssda-row img:hover { transform: none; }
}
/* The Astonishing block sits under the CSSDA list: give it air and a rule so
   the two bodies read as separate. */
/* 4.5rem is the gap that separates the two halves from each other. The FIRST
   half follows the page title directly and would otherwise open with a hole. */
.page-title + .awards-h2 { margin-top: 1.8rem; }
.awards-h2 {
  margin: 4.5rem 0 0;
  font-family: var(--font-display);
  font-size: clamp(1.4rem, 1.05rem + 1.5vw, 2.1rem);
  font-weight: 400;
  line-height: 1.15;
}
.aa-block {
  margin: 1.6rem 0 0;
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: 1.8rem 2.4rem;
}
/* The badge arrives as a wide PNG carrying its own transparency, so it needs
   none of the paper treatment the scanned certificate did: no sheet, no
   shadow, just a cap on its width and the same quiet lift on hover that the
   CSSDA marks above it use. */
.aa-badge {
  display: block;
  width: min(36rem, 100%);   /* same measure as the list and the marks above */
  opacity: 0.92;
  transition: opacity 0.35s var(--ease-sine), transform 0.35s var(--ease-sine);
}
.aa-badge:hover,
.aa-badge:focus-visible { opacity: 1; transform: translateY(-2px); }
.aa-badge img { display: block; width: 100%; height: auto; }
@media (prefers-reduced-motion: reduce) {
  .aa-badge { transition: opacity 0.2s linear; }
  .aa-badge:hover,
  .aa-badge:focus-visible { transform: none; }
}

/* ---------- Home: the opening film --------------------------------------
   While the film runs the interface steps aside; the canvas owns the
   screen. The logotype rides the film back down. */

body.journey .brand { cursor: pointer; }

main, .site-footer { transition: opacity 1.2s var(--ease-sine); }
body.film-lock { overflow: hidden; }
body.film-lock main,
body.film-lock .site-footer {
  opacity: 0;
  pointer-events: none;
}
/* Keep the opening clean: only the logo rides over the film — the menu (the
   hamburger and links in the corner) waits until the descent lands. */
.site-nav { transition: opacity 0.7s var(--ease-sine); }
body.film-lock .site-nav { opacity: 0; pointer-events: none; }

/* Boot mask: set pre-paint by the inline script in layout.php, this hides
   exactly what film-lock hides so the home hero never flashes before the film /
   loading screen mounts. The scene clears .scene-booting on reveal and film-lock
   owns the hidden state from there until the descent lands. */
html.scene-booting, html.scene-booting body { overflow: hidden; }
html.scene-booting main,
html.scene-booting .site-footer { opacity: 0; pointer-events: none; }
html.scene-booting .site-nav { opacity: 0; pointer-events: none; }

/* ---------- Discography ----------------------------------------------- */

.release-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 2.6rem 2rem;
  margin: 3rem 0 0;
  padding: 0;
  list-style: none;
}
@media (max-width: 720px) { .release-grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 440px) { .release-grid { grid-template-columns: 1fr; } }
.release-card a {
  display: block;
  color: var(--ink);
  text-decoration: none;
}
.release-card img {
  width: 100%;
  height: auto;
  aspect-ratio: 1;
  object-fit: cover;
  display: block;
  opacity: 0.88;
  transition: opacity 0.35s var(--ease-sine);
}
.release-card a:hover img { opacity: 1; }
.release-card .r-title {
  font-family: var(--font-display);
  font-size: 1.02rem;
  margin: 0.85rem 0 0.15rem;
  line-height: 1.3;
}
.release-card .r-meta {
  font-family: var(--font-mono);
  font-size: 0.66rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-faint);
}
.release-card a:hover .r-title { color: var(--accent); }

/* Release detail */
.release-head {
  display: grid;
  grid-template-columns: minmax(0, 19rem) 1fr;
  gap: 2.6rem;
  align-items: start;
  margin-bottom: 2.4rem;
}
@media (max-width: 720px) {
  .release-head { grid-template-columns: 1fr; }
  .release-head .cover { max-width: 19rem; }
}
.release-head .cover img { width: 100%; height: auto; display: block; }
.release-title { margin-bottom: 0.3rem; }
.release-sub { color: var(--ink-dim); margin-bottom: 1.4rem; }

/* Quick-jump strip at the foot of a release page: every cover, tight, just
   the art, so you can hop between releases in a glance. */
.more-music { margin-top: 3.6rem; }
.cover-strip {
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  gap: 0.5rem;
  margin: 1.1rem 0 0;
  padding: 0;
  list-style: none;
}
.cover-strip li { margin: 0; }
.cover-strip a { display: block; position: relative; }
.cover-strip a:hover { z-index: 2; }
.cover-strip img {
  width: 100%;
  height: auto;
  aspect-ratio: 1;
  object-fit: cover;
  display: block;
  border-radius: 2px;
  opacity: 0.6;
  transition: opacity 0.28s var(--ease-sine), transform 0.28s var(--ease-sine);
}
.cover-strip a:hover img { opacity: 1; transform: scale(1.05); }
.cover-strip .is-current img {
  opacity: 1;
  outline: 1px solid var(--accent);
  outline-offset: 1px;
}
@media (max-width: 560px) { .cover-strip { grid-template-columns: repeat(4, 1fr); } }

.listen-links {
  display: flex;
  flex-wrap: wrap;
  gap: 0.55rem;
  margin: 1.4rem 0 0;
  padding: 0;
  list-style: none;
}
.listen-links a {
  display: inline-block;
  padding: 0.5em 1em;
  border: 1px solid var(--line);
  color: var(--ink-dim);
  font-family: var(--font-mono);
  font-size: 0.7rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  text-decoration: none;
  transition: color 0.25s var(--ease-sine), border-color 0.25s var(--ease-sine);
}
.listen-links a:hover { color: var(--ink); border-color: var(--accent-dim); }

.tracklist {
  margin: 2rem 0;
  padding: 0;
  list-style: none;
  counter-reset: track;
  max-width: 34rem;
}
.tracklist li {
  counter-increment: track;
  display: flex;
  gap: 1rem;
  align-items: baseline;
  padding: 0.55rem 0;
  border-bottom: 1px solid var(--line);
}
.tracklist li::before {
  content: counter(track, decimal-leading-zero);
  font-family: var(--font-mono);
  font-size: 0.72rem;
  color: var(--ink-faint);
}
.tracklist .t-title { flex: 1; }
.tracklist .t-len {
  font-family: var(--font-mono);
  font-size: 0.72rem;
  color: var(--ink-faint);
}
.tracklist .t-feat { color: var(--ink-dim); }

.credits {
  color: var(--ink-dim);
  font-size: 0.92rem;
  max-width: 40em;
}
.awards { margin: 1.2rem 0 0; padding: 0; list-style: none; }
.awards li {
  font-family: var(--font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--accent);
  padding: 0.2rem 0;
}

/* List/map toggle on /music */
.view-toggle {
  display: inline-flex;
  gap: 0;
  margin-top: 1.6rem;
  border: 1px solid var(--line);
}
.view-toggle button, .view-toggle a {
  padding: 0.45em 1.1em;
  background: none;
  border: 0;
  color: var(--ink-dim);
  font-family: var(--font-mono);
  font-size: 0.7rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  cursor: pointer;
  text-decoration: none;
}
.view-toggle [aria-pressed="true"], .view-toggle .active {
  color: var(--accent);
  background: rgba(143, 199, 164, 0.07);
}

/* Chronological list view */
.disco-list { margin: 2.5rem 0 0; padding: 0; list-style: none; }
.disco-list li {
  display: grid;
  grid-template-columns: 5.5rem 1fr auto;
  gap: 1rem;
  align-items: baseline;
  padding: 0.8rem 0;
  border-bottom: 1px solid var(--line);
}
.disco-list .d-year {
  font-family: var(--font-mono);
  font-size: 0.75rem;
  color: var(--ink-faint);
  white-space: nowrap;   /* the full ISO date stays on one line */
}
.disco-list .d-type {
  font-family: var(--font-mono);
  font-size: 0.66rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-faint);
}
.disco-list a { color: var(--ink); text-decoration: none; }
.disco-list a:hover { color: var(--accent); }
@media (max-width: 620px) {
  /* Tighter columns so the year sits close to the title and long titles keep
     to one line. */
  .disco-list li { grid-template-columns: 4.75rem 1fr auto; gap: 0.7rem; }
  .disco-list .d-year { font-size: 0.68rem; }
  .disco-list .d-type { font-size: 0.58rem; letter-spacing: 0.1em; }
}

/* ---------- Remixes / Videos ------------------------------------------ */

.remix-list { margin: 3rem 0 0; padding: 0; list-style: none; }
.remix-item {
  display: grid;
  grid-template-columns: minmax(0, 11rem) 1fr;
  gap: 2rem;
  padding: 2.2rem 0;
  border-top: 1px solid var(--line);
}
.remix-item:first-child { border-top: 0; }
@media (max-width: 620px) { .remix-item { grid-template-columns: 1fr; gap: 1.1rem; } .remix-item .cover { max-width: none; margin: 0; } }
.remix-item img { width: 100%; height: auto; display: block; opacity: 0.92; }
.remix-item h2 { font-size: 1.25rem; margin-bottom: 0.3rem; }

.video-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(19rem, 1fr));
  gap: 2.6rem 2rem;
  margin: 3rem 0 0;
  padding: 0;
  list-style: none;
}
.video-embed {
  position: relative;
  aspect-ratio: 16 / 9;
  background: #000;
}
.video-embed iframe,
.video-embed .video-poster {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
}
.video-poster {
  display: block;
  background-size: cover;
  background-position: center;
  cursor: pointer;
  border: 0;
  padding: 0;
}
.video-poster::after {
  content: '▶';
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  font-size: 1.5rem;
  color: rgba(230, 237, 245, 0.85);
  background: rgba(2, 3, 8, 0.25);
  transition: background 0.3s var(--ease-sine);
}
.video-poster:hover::after { background: rgba(2, 3, 8, 0.05); }
.video-grid figcaption {
  margin-top: 0.7rem;
  font-family: var(--font-mono);
  font-size: 0.7rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-dim);
}

/* ---------- Contact / press ------------------------------------------- */

/* The address list wears the same instrument-panel frame as the form:
   corner ticks, dark glass, two columns of label-over-address cells. */
.contact-rows {
  position: relative;
  margin: 2.4rem 0;
  padding: 1.5rem 1.6rem 1.4rem;
  list-style: none;
  max-width: 34rem;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1.3rem 1.5rem;
  border: 1px solid var(--line-strong);
  background: rgba(4, 6, 12, 0.55);
}
.contact-rows::before,
.contact-rows::after {
  content: '';
  position: absolute;
  width: 9px;
  height: 9px;
  pointer-events: none;
}
.contact-rows::before { top: -1px; left: -1px; border-top: 1px solid var(--accent-dim); border-left: 1px solid var(--accent-dim); }
.contact-rows::after { bottom: -1px; right: -1px; border-bottom: 1px solid var(--accent-dim); border-right: 1px solid var(--accent-dim); }
@media (max-width: 560px) { .contact-rows { grid-template-columns: 1fr; } }
.contact-rows .c-label {
  display: block;
  font-family: var(--font-mono);
  font-size: 0.6rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--ink-faint);
  margin: 0 0 0.4rem;
}
.contact-rows a {
  color: var(--ink);
  text-decoration: none;
  font-size: 0.92rem;
  transition: color 0.25s var(--ease-sine);
}
.contact-rows a:hover { color: var(--accent); }

.asset-list { margin: 1.4rem 0 2.6rem; padding: 0; list-style: none; max-width: 36rem; }
.asset-list li {
  padding: 0.6rem 0;
  border-bottom: 1px solid var(--line);
  display: flex;
  justify-content: space-between;
  gap: 1.5rem;
  align-items: baseline;
}
.asset-list .a-credit {
  font-family: var(--font-mono);
  font-size: 0.68rem;
  color: var(--ink-faint);
  letter-spacing: 0.08em;
  white-space: nowrap;
}

/* ---------- Footer ----------------------------------------------------- */

.site-footer {
  border-top: 1px solid var(--line);
  margin-top: 4rem;
  padding: 2.2rem var(--pad-x) 1.5rem;
  background: linear-gradient(to bottom, rgba(2, 3, 8, 0) 0%, rgba(2, 3, 8, 0.55) 100%);
}
body.journey .site-footer { margin-top: 0; }
/* The legal line shares the logo's left edge: no centered max-width, just
   the same --pad-x gutter the header carries. */
.footer-inner {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 1rem 2rem;
}

.footer-nav {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1.8rem;
  margin-bottom: 1.6rem;
}
.footer-nav a {
  font-family: var(--font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.17em;
  text-transform: uppercase;
  color: var(--ink-dim);
  text-decoration: none;
}
.footer-nav a:hover { color: var(--accent); }

.footer-social {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem 1.4rem;
  margin: 0 0 1.8rem;
  padding: 0;
  list-style: none;
}
.footer-social a {
  font-family: var(--font-mono);
  font-size: 0.66rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-faint);
  text-decoration: none;
}
.footer-social a:hover { color: var(--ink-dim); }

.footer-legal { color: var(--ink-faint); font-size: 0.82rem; margin: 0; }
.footer-legal a { color: var(--ink-faint); }
.footer-legal a:hover { color: var(--ink-dim); }
/* Builder logotypes ride inline with the legal line: dimmed to the same
   faint ink as the text, waking on hover. */
.fl-built { white-space: nowrap; }
.fl-logo { text-decoration: none; }
.fl-logo img {
  height: 15px;
  width: auto;
  vertical-align: -3px;
  opacity: 0.5;
  transition: opacity 0.25s var(--ease-sine);
}
.fl-logo:hover img { opacity: 0.95; }
.fl-plus { margin: 0 0.15rem; }
/* The round I/O Music mark needs a touch more size to stay legible. */
.fl-round img { height: 18px; vertical-align: -5px; }

/* On a phone the docked player bar runs nearly the full width along the
   bottom (up to 90vw), so the footer's last row lands right on it. Lift the
   footer clear of the player instead of jamming against it. */
@media (max-width: 620px) {
  .site-footer { padding-bottom: 4.75rem; }
}

/* ---------- Contact transmission form ---------------------------------- */

.ct-form-wrap { margin-top: 3.2rem; }
.ct-form {
  position: relative;
  margin-top: 1rem;
  max-width: 34rem;
  padding: 1.5rem 1.6rem 1.4rem;
  border: 1px solid var(--line-strong);
  background: rgba(4, 6, 12, 0.55);
}
.ct-form::before,
.ct-form::after {
  content: '';
  position: absolute;
  width: 9px;
  height: 9px;
  pointer-events: none;
}
.ct-form::before { top: -1px; left: -1px; border-top: 1px solid var(--accent-dim); border-left: 1px solid var(--accent-dim); }
.ct-form::after { bottom: -1px; right: -1px; border-bottom: 1px solid var(--accent-dim); border-right: 1px solid var(--accent-dim); }
.ct-form label {
  display: block;
  font-family: var(--font-mono);
  font-size: 0.6rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--ink-faint);
  margin: 0 0 0.4rem;
}
.ct-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 1.1rem; }
@media (max-width: 560px) { .ct-grid { grid-template-columns: 1fr; } }
.ct-form input[type="text"],
.ct-form input[type="email"],
.ct-form textarea {
  width: 100%;
  margin-bottom: 1.1rem;
  padding: 0.6em 0.75em;
  font: inherit;
  font-size: 0.92rem;
  color: var(--ink);
  background: rgba(2, 3, 8, 0.6);
  border: 1px solid var(--line);
  border-radius: 0;
  transition: border-color 0.25s var(--ease-sine);
}
.ct-form input:focus,
.ct-form textarea:focus {
  outline: none;
  border-color: var(--accent-dim);
}
.ct-form textarea { resize: vertical; min-height: 8.5em; }
.ct-hp { position: absolute; left: -9999px; top: -9999px; height: 1px; overflow: hidden; }
.ct-actions { display: flex; align-items: center; gap: 1rem; }
.ct-send {
  font-family: var(--font-mono);
  font-size: 0.62rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  padding: 0.75em 1.5em;
  color: var(--accent);
  background: rgba(143, 199, 164, 0.06);
  border: 1px solid var(--accent-dim);
  cursor: pointer;
  transition: color 0.25s var(--ease-sine), border-color 0.25s var(--ease-sine), background 0.25s var(--ease-sine);
}
.ct-send:hover { color: var(--ink); border-color: var(--accent); background: rgba(143, 199, 164, 0.12); }
.ct-send:disabled { opacity: 0.55; cursor: default; }
.ct-status { font-family: var(--font-mono); font-size: 0.66rem; letter-spacing: 0.12em; color: var(--ink-dim); }
.ct-status.ok { color: var(--accent); }
.ct-status.err { color: #d98a7a; }
.ct-error {
  font-family: var(--font-mono);
  font-size: 0.7rem;
  color: #d98a7a;
  margin: 0 0 1rem;
}
.ct-sent-block { text-align: left; }
.ct-sent-title {
  font-family: var(--font-mono);
  font-size: 0.8rem;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--accent);
  margin: 0 0 0.5rem;
}
.ct-sent-note { color: var(--ink-dim); margin: 0; font-size: 0.9rem; }

/* Web-push opt-in button (the modal's; revealed by push.js). */
.push-btn {
  font-family: var(--font-mono);
  font-size: 0.6rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-dim);
  background: transparent;
  border: 1px solid var(--line);
  padding: 0.55em 1.1em;
  cursor: pointer;
  transition: color 0.25s var(--ease-sine), border-color 0.25s var(--ease-sine);
}
.push-btn:hover { color: var(--ink); border-color: var(--line-strong); }
.push-btn.is-on { color: var(--accent); border-color: var(--accent-dim); }
.push-btn:disabled { opacity: 0.55; cursor: default; }
.push-ios { font-size: 0.74rem; color: var(--ink-faint); margin: 0.5rem 0 0; max-width: 30rem; }
.push-ios b { color: var(--ink-dim); font-weight: 600; }
/* Transmissions modal: the site's dark overlay language (lightbox backdrop,
   instrument corner ticks) around the explanation + the action. */
.push-modal {
  position: fixed;
  inset: 0;
  z-index: 95;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: clamp(1rem, 4vw, 3rem);
  background: rgba(2, 3, 8, 0.78);
  opacity: 0;
  transition: opacity 0.3s var(--ease-sine);
}
/* display:flex above would override the hidden attribute's display:none —
   without this rule the closed modal sits invisibly over the whole page and
   swallows every click (the menu first of all). */
.push-modal[hidden] { display: none; }
.push-modal.open { opacity: 1; }
.pm-box {
  position: relative;
  width: min(26rem, 92vw);
  padding: 1.6rem 1.7rem 1.5rem;
  border: 1px solid var(--line-strong);
  background: rgba(4, 6, 12, 0.92);
}
@supports (backdrop-filter: blur(1px)) {
  .pm-box { background: rgba(4, 6, 12, 0.78); backdrop-filter: blur(12px); }
}
.pm-box::before,
.pm-box::after {
  content: '';
  position: absolute;
  width: 9px;
  height: 9px;
  pointer-events: none;
}
.pm-box::before { top: -1px; left: -1px; border-top: 1px solid var(--accent-dim); border-left: 1px solid var(--accent-dim); }
.pm-box::after { bottom: -1px; right: -1px; border-bottom: 1px solid var(--accent-dim); border-right: 1px solid var(--accent-dim); }
.pm-close {
  position: absolute;
  top: 0.5rem;
  right: 0.55rem;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 1.8em;
  height: 1.8em;
  padding: 0;
  border: 1px solid var(--line);
  background: transparent;
  color: var(--ink-faint);
  font-family: var(--font-mono);
  font-size: 0.72rem;
  line-height: 1;
  cursor: pointer;
  transition: color 0.25s var(--ease-sine), border-color 0.25s var(--ease-sine);
}
.pm-close:hover { color: var(--ink); border-color: var(--line-strong); }
.pm-label {
  font-family: var(--font-mono);
  font-size: 0.6rem;
  letter-spacing: 0.26em;
  text-transform: uppercase;
  color: var(--ink-faint);
  margin: 0 0 0.5rem;
}
.pm-box h2 { font-size: 1.3rem; margin: 0 0 0.7rem; }
.pm-text, .pm-ios { font-size: 0.88rem; line-height: 1.6; color: var(--ink-dim); margin: 0 0 1.1rem; }
.pm-ios b { color: var(--ink); font-weight: 600; }
.pm-actions { display: flex; gap: 0.7rem; align-items: center; }
.pm-later {
  font-family: var(--font-mono);
  font-size: 0.6rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  padding: 0.55em 1.1em;
  border: 1px solid var(--line);
  background: transparent;
  color: var(--ink-faint);
  cursor: pointer;
  transition: color 0.25s var(--ease-sine), border-color 0.25s var(--ease-sine);
}
.pm-later:hover { color: var(--ink); border-color: var(--line-strong); }

/* The Transmissions item in the menu (a button among links). */
.menu-push {
  font-family: var(--font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.17em;
  text-transform: uppercase;
  color: var(--accent-dim);
  background: transparent;
  border: 0;
  padding: 0;
  cursor: pointer;
  transition: color 0.25s var(--ease-sine);
}
.menu-push:hover { color: var(--accent); }
@media (max-width: 1023px) {   /* matches the header's hamburger breakpoint */
  html.js .menu-push {
    display: block;
    width: 100%;
    text-align: left;
    padding: 0.85rem 0;
    font-size: 0.8rem;
    border-bottom: 1px solid var(--line);
  }
}

/* ---------- Altitude indicator (journey) ------------------------------- */

.altitude {
  position: fixed;
  right: 1.1rem;
  top: 50%;
  transform: translateY(-50%);
  z-index: 40;
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  align-items: flex-end;
  font-family: var(--font-mono);
  font-size: 0.62rem;
  letter-spacing: 0.22em;
  color: var(--ink-faint);
  text-transform: uppercase;
  writing-mode: vertical-rl;
}
.altitude .altitude-band { color: var(--ink-dim); }
.altitude[hidden] { display: none; }  /* display:flex must not defeat hidden */
html.calm .altitude { display: none; }
@media (max-width: 880px) { .altitude { display: none; } }

/* ---------- Star map (orbit altitude, /music) --------------------------- */

/* One viewport of pure scene; the page content follows below. Collapses
   entirely in calm mode or when the scene never starts: the grid leads. */
.starmap-stage {
  position: relative;
  height: 0;
  overflow: hidden;
  transition: height 0.6s var(--ease-sine);
}
html.scene-live .starmap-stage { height: 88vh; }
html.calm .starmap-stage { height: 0 !important; }

.starmap-hint {
  position: absolute;
  left: 50%;
  bottom: 2.2rem;
  transform: translateX(-50%);
  margin: 0;
  white-space: nowrap;
}

.starmap-labels { position: absolute; inset: 0; }

.starmap-label {
  position: absolute;
  top: 0; left: 0;
  transform: translate(-200px, -200px);
  padding: 0.5rem 0.7rem 0.5rem 1.1rem;
  display: block;
  text-decoration: none;
  opacity: 0;
  transition: opacity 0.6s var(--ease-sine);
  will-change: transform;
  white-space: nowrap;
}
.starmap-label::before {
  /* hairline from the body to its name */
  content: '';
  position: absolute;
  left: 0.2rem;
  top: 50%;
  width: 0.65rem;
  height: 1px;
  background: var(--line-strong);
}
.starmap-label .sl-title {
  display: block;
  font-family: var(--font-display);
  font-size: 0.92rem;
  color: var(--ink);
  text-shadow: 0 0 8px rgba(2, 3, 8, 0.9);
}
.starmap-label .sl-meta {
  display: block;
  font-family: var(--font-mono);
  font-size: 0.6rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-faint);
}
.starmap-label:hover .sl-title { color: var(--accent); }
.starmap-label.is-satellite .sl-title { font-size: 0.78rem; color: var(--ink-dim); }
.starmap-label.is-satellite .sl-meta { display: none; }
.starmap-label.is-satellite:hover .sl-meta { display: block; }

/* ---------- In-scene release panel (star map) --------------------------- */

.release-panel {
  position: fixed;
  top: 0; right: 0; bottom: 0;
  width: min(31rem, 94vw);
  z-index: 60;
  background: rgba(3, 5, 10, 0.97);
  border-left: 1px solid var(--line);
  overflow-y: auto;
  overscroll-behavior: contain;
  visibility: hidden;
  opacity: 0;
  transform: translateX(26px);
  transition: opacity 0.55s var(--ease-sine), transform 0.55s var(--ease-sine),
              visibility 0s linear 0.55s;
}
.release-panel.open {
  visibility: visible;
  opacity: 1;
  transform: translateX(0);
  transition: opacity 0.55s var(--ease-sine), transform 0.55s var(--ease-sine);
}
.release-panel .panel-close {
  position: sticky;
  top: 0.9rem;
  margin-left: calc(100% - 3.4rem);
  width: 2.5rem; height: 2.5rem;
  z-index: 2;
  background: rgba(2, 3, 8, 0.8);
  border: 1px solid var(--line);
  color: var(--ink-dim);
  font-size: 1.1rem;
  line-height: 1;
  cursor: pointer;
  transition: color 0.25s var(--ease-sine), border-color 0.25s var(--ease-sine);
}
.release-panel .panel-close:hover { color: var(--ink); border-color: var(--line-strong); }
.release-panel .page {
  padding: 1rem 2rem 3.5rem;
  max-width: none;
}
.release-panel .release-head { grid-template-columns: 1fr; gap: 1.6rem; }
.release-panel .release-head .cover { max-width: 15rem; margin: 0; }
.release-panel .panel-loading { padding: 4rem 2rem; }
.release-panel h1:focus { outline: none; }

/* While the panel is open, the map hint steps aside. */
body.panel-open .starmap-hint { opacity: 0; transition: opacity 0.4s var(--ease-sine); }
@media (max-width: 720px) {
  .release-panel {
    top: 16vh; right: 0; bottom: 0; left: 0;
    width: auto;
    border-left: 0;
    border-top: 1px solid var(--line);
    transform: translateY(26px);
  }
  .release-panel.open { transform: translateY(0); }
}

/* ---------- Transmission decode (header line only, spec 7) ------------- */

[data-decode] { min-height: 1em; }

/* ---------- Telemetry: storm notice + night view (spec 6.4, 6.5) ------- */

.storm-notice {
  position: fixed;
  left: var(--pad-x);
  bottom: 1.4rem;
  z-index: 45;
  margin: 0;
  padding: 0.45em 0.9em;
  border: 1px solid rgba(143, 199, 164, 0.35);
  background: rgba(2, 3, 8, 0.78);
  color: var(--accent);
  font-family: var(--font-mono);
  font-size: 0.66rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
}
html.calm .storm-notice { display: none; }

.night-view {
  position: fixed;
  right: var(--pad-x);
  bottom: 1.4rem;
  z-index: 45;
  padding: 0.45em 0.9em;
  border: 1px solid var(--line);
  background: rgba(2, 3, 8, 0.78);
  color: var(--ink-dim);
  font-family: var(--font-mono);
  font-size: 0.66rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  cursor: pointer;
  transition: color 0.25s var(--ease-sine), border-color 0.25s var(--ease-sine);
}
.night-view:hover { color: var(--ink); border-color: var(--line-strong); }
.night-view[aria-pressed="true"] { color: var(--accent); border-color: var(--accent-dim); }
html.calm .night-view { display: none; }

/* ---------- Motion discipline ------------------------------------------ */

/* Calm mode and reduced motion: no decorative animation anywhere. */
html.calm *, html.calm *::before, html.calm *::after {
  animation: none !important;
  transition: none !important;
}
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation: none !important;
    transition: none !important;
  }
}

/* ---------- Solar system shell (loading screen, mute) ------------------- */

.solar-loading {
  position: fixed;
  inset: 0;
  z-index: 90;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1.6rem;
  background: var(--sky-zenith);
  opacity: 1;
  transition: opacity 1.2s var(--ease-sine);
  pointer-events: none;
}
.solar-loading.sl-done { opacity: 0; }
/* Staged reveal: each part rises into place on its own delay (--d). The wait
   is the same length, but a screen that is still assembling does not read as
   a stall. Nothing here gates the download, which is already running. */
.solar-loading .sl-step {
  opacity: 0;
  transform: translateY(0.5rem);
  transition: opacity 1s var(--ease-sine), transform 1s var(--ease-sine);
  transition-delay: var(--d, 0s);
}
.solar-loading.sl-in .sl-step { opacity: 1; transform: none; }
.solar-loading .sl-tagline span { display: block; }
/* No exit rule on the steps on purpose: zeroing their delay while the screen
   is fading would snap every pending part to full opacity at once, a flash on
   the way out. Let them keep their schedule; the container fade hides it. */
@media (prefers-reduced-motion: reduce) {
  .solar-loading .sl-step { transition: opacity 0.3s linear; transform: none; transition-delay: 0s; }
}
.solar-loading .sl-logo { opacity: 0.92; height: auto; }
/* The descriptor, set like the hero line rather than the old wide-tracked
   uppercase label: that treatment was made for a two-word name and turns a
   full sentence into a wall. */
.solar-loading .sl-tagline {
  margin: -0.4rem 0 0;
  font-family: var(--font-display);
  font-size: clamp(0.95rem, 1.9vw, 1.2rem);
  letter-spacing: 0.04em;
  color: var(--ink-dim);
  max-width: 24em;
  padding: 0 1.5rem;
  text-align: center;
  text-wrap: balance;
}
.solar-loading .sl-load {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.9rem;
}
.solar-loading .sl-track {
  width: min(240px, 50vw);
  height: 1px;
  background: var(--line);
  overflow: hidden;
}
.solar-loading .sl-bar {
  height: 100%;
  background: var(--accent-dim);
  transform: scaleX(0.05);
  transform-origin: left center;
  transition: transform 0.5s var(--ease-out);
}
.solar-loading .sl-note {
  margin: 0;
  font-family: var(--font-mono);
  font-size: 0.62rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--ink-faint);
}
.solar-loading .sl-pct { color: var(--accent-dim); }
/* Status line under the counter: what the site is actually doing right now.
   Reserved height so swapping lines never nudges the layout. */
.solar-loading .sl-status {
  margin: 0.55rem 0 0;
  min-height: 1.1em;
  font-family: var(--font-mono);
  font-size: 0.58rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-faint);
  text-align: center;
  padding: 0 1.5rem;
  max-width: 26em;
}
.solar-loading .sl-msg {
  display: inline-block;
  opacity: 0;
  transform: translateY(0.25rem);
  transition: opacity 0.45s var(--ease-sine), transform 0.45s var(--ease-sine);
}
.solar-loading .sl-msg.is-on { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
  .solar-loading .sl-msg { transition: opacity 0.2s linear; transform: none; }
}
html.calm .solar-loading { display: none; }

/* A dead canvas is worse than no canvas: it holds the last frame, or garbage,
   over the .sky-static gradient that is already sitting behind it and looks
   perfectly good on its own. Hide both canvases and let the static sky take
   over, which is the same thing a device with no WebGL at all is shown. */
html.gl-lost #sky,
html.gl-lost .terrain-canvas { display: none; }

/* WebGL context loss. The browser hands the graphics context back to the system
   when a device runs out of GPU memory, which is a real risk on older phones.
   A band along the bottom rather than a full cover: the last rendered frame is
   often still on screen, and there is no reason to hide it while explaining. */
.gl-lost-panel {
  position: fixed;
  inset: auto 0 0 0;
  z-index: 95;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.85rem;
  padding: 2.5rem var(--pad-x) calc(2rem + env(safe-area-inset-bottom, 0px));
  background: linear-gradient(to top, var(--sky-zenith) 55%, rgba(2, 3, 8, 0));
  text-align: center;
}
.gl-lost-title {
  margin: 0;
  font-family: var(--font-display);
  font-size: clamp(1rem, 2.2vw, 1.25rem);
  letter-spacing: 0.04em;
  color: var(--ink);
}
.gl-lost-body {
  margin: 0;
  max-width: 32em;
  font-family: var(--font-text);
  font-size: 0.85rem;
  line-height: 1.5;
  color: var(--ink-dim);
  text-wrap: balance;
}
.gl-lost-btn {
  margin-top: 0.25rem;
  padding: 0.65rem 1.5rem;
  background: transparent;
  border: 1px solid var(--line-strong);
  color: var(--accent);
  font-family: var(--font-mono);
  font-size: 0.62rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  cursor: pointer;
  transition: border-color 0.3s var(--ease-sine), color 0.3s var(--ease-sine);
}
.gl-lost-btn:hover,
.gl-lost-btn:focus-visible { border-color: var(--accent-dim); color: var(--ink); }

/* Discography: caption over the sky while the system winds to a release date.
   Sits in the right half, where the content panel is not, above the planets.
   Fades rather than pops, and never intercepts a click. */
.sky-note {
  position: fixed;
  top: calc(var(--header-h) + 2.2rem);
  /* Centred over the planets: the band between the content panel's right edge
     (its width is min(46rem, 52vw)) and the viewport edge. The right inset
     keeps it off the fixed social rail so the optical centre stays true. */
  left: min(46rem, 52vw);
  right: 2.6rem;
  z-index: 6;
  margin: 0;
  text-align: center;
  font-family: var(--font-mono);
  font-size: 0.64rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  line-height: 1.7;
  color: var(--ink-faint);
  opacity: 0;
  transform: translateY(-0.35rem);
  transition: opacity 0.8s var(--ease-sine), transform 0.8s var(--ease-sine);
  pointer-events: none;
}
.sky-note.is-on { opacity: 1; transform: none; }
/* Narrow: the system sits in the band between header and sheet, so the caption
   goes full width just under the header instead of hugging a right edge that
   no longer has planets behind it. */
@media (max-width: 880px) {
  .sky-note {
    left: var(--pad-x);
    right: var(--pad-x);
    font-size: 0.58rem;
    letter-spacing: 0.14em;
  }
}
@media (prefers-reduced-motion: reduce) {
  .sky-note { transition: opacity 0.2s linear; transform: none; }
}

/* ---------- The onboard audio console ----------------------------------- */
/* Docked lower right like a ship systems panel: a slim pill with a live
   VU when minimized, a small console with the playlist when opened. */

.pdock {
  position: fixed;
  /* Framed with the rest of the chrome: right edge flush with the header's
     Facebook icon (--pad-x gutter), bottom gap matching the footer's own
     padding under the copyright line. */
  right: var(--pad-x);
  bottom: 1.5rem;
  z-index: 45;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 0;
  font-family: var(--font-mono);
}
html.calm .pdock { display: none; }

/* Idle attract loop: after a spell untouched the whole interface dissolves so
   the camera can tour the planets; the first interaction brings it back. Only
   the sky canvas stays. Slow, dreamy dissolve out; prompt return in. The dim
   class sits on each element directly (set by dimChrome in the app) so the
   fade never depends on the body's class list alone. */
.site-header, .site-footer, .altitude, .pdock, .planet-tip {
  transition: opacity 0.6s var(--ease-sine);
}
.chrome-dimmed,
body.attract .site-header,
body.attract .site-footer,
body.attract .altitude,
body.attract .pdock,
body.attract .planet-tip,
body.attract #content {
  opacity: 0 !important;
  pointer-events: none;
  transition: opacity 1.8s var(--ease-sine);
}

/* Homecoming: the logo flies the camera home by easing the scroll past every
   planet. Hide the page content for the flight so its sections don't swish
   by like a manual scroll; it fades back in the moment we land at START. */
body.homing #content {
  opacity: 0 !important;
  pointer-events: none;
  transition: opacity 0.5s var(--ease-sine);
}

.pdock-bar {
  display: flex;
  align-items: stretch;
  width: 24rem;
  max-width: 90vw;
}
.pdock-pill {
  flex: 1 1 auto;
  display: flex;
  align-items: center;
  gap: 0.7em;
  padding: 0.6em 0.9em;
  border: 1px solid var(--line);
  border-right: 0;
  border-bottom: 0;
  background: rgba(2, 3, 8, 0.82);
  color: var(--ink-dim);
  font-family: var(--font-mono);
  font-size: 0.58rem;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  cursor: pointer;
  transition: color 0.25s var(--ease-sine), border-color 0.25s var(--ease-sine);
  min-width: 0;
}
.pdock-play {
  display: flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 2.4em;
  padding: 0.6em 0;
  border: 1px solid var(--line);
  border-right: 0;
  border-bottom: 0;
  background: rgba(2, 3, 8, 0.82);
  color: var(--accent);
  font-size: 0.72rem;
  line-height: 1;
  cursor: pointer;
  transition: color 0.25s var(--ease-sine), border-color 0.25s var(--ease-sine);
}
.pdock-expand {
  display: flex;
  align-items: center;
  padding: 0.6em 0.7em;
  border: 1px solid var(--line);
  border-bottom: 0;
  background: rgba(2, 3, 8, 0.82);
  color: var(--ink-faint);
  cursor: pointer;
  flex: 0 0 auto;
  transition: color 0.25s var(--ease-sine), border-color 0.25s var(--ease-sine);
}
.pdock-play:hover, .pdock-pill:hover, .pdock-expand:hover { color: var(--ink); border-color: var(--line-strong); }
.pdock.playing .pdock-play { color: var(--accent); }
.pdock.playing .pdock-pill { color: var(--accent); border-color: var(--accent-dim); }
.pdock .pd-vu { display: block; flex: 0 0 auto; }
.pdock .pd-title {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.pdock .pd-chevron { display: block; line-height: 1; }

.pdock-panel {
  width: min(24rem, 90vw);
  border: 1px solid var(--line-strong);
  border-bottom: 0;
  background: rgba(4, 6, 12, 0.88);
  padding: 0.9rem 1rem 1rem;
  position: relative;
}
@supports (backdrop-filter: blur(1px)) {
  .pdock-panel { background: rgba(4, 6, 12, 0.66); backdrop-filter: blur(12px); }
}
/* Corner ticks: the panel reads as an instrument, not a card. */
.pdock-panel::before,
.pdock-panel::after {
  content: '';
  position: absolute;
  width: 9px;
  height: 9px;
  pointer-events: none;
}
.pdock-panel::before {
  top: -1px; left: -1px;
  border-top: 1px solid var(--accent-dim);
  border-left: 1px solid var(--accent-dim);
}
.pdock-panel::after {
  bottom: -1px; right: -1px;
  border-bottom: 1px solid var(--accent-dim);
  border-right: 1px solid var(--accent-dim);
}

.pdock-close {
  position: absolute;
  top: 0.3rem;
  right: 0.35rem;
  z-index: 2;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 1.7em;
  height: 1.7em;
  padding: 0;
  border: 1px solid var(--line);
  background: rgba(2, 3, 8, 0.6);
  color: var(--ink-faint);
  font-family: var(--font-mono);
  font-size: 0.72rem;
  line-height: 1;
  cursor: pointer;
  transition: color 0.25s var(--ease-sine), border-color 0.25s var(--ease-sine);
}
.pdock-close:hover { color: var(--ink); border-color: var(--line-strong); }

.pdock-head {
  font-size: 0.62rem;
  letter-spacing: 0.26em;
  text-transform: uppercase;
  color: var(--ink-faint);
  margin: 0 0 0.7rem;
}

.pdock-list {
  list-style: none;
  margin: 0 0 0.8rem;
  padding: 0;
  max-height: 13rem;
  overflow-y: auto;
}
.pdock-list button {
  display: flex;
  gap: 0.7em;
  align-items: baseline;
  width: 100%;
  background: none;
  border: 0;
  padding: 0.32em 0.2em;
  color: var(--ink-dim);
  font-family: var(--font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.06em;
  text-align: left;
  cursor: pointer;
}
.pdock-list button:hover { color: var(--ink); }
.pdock-list .pl-no { color: var(--ink-faint); flex: 0 0 auto; }
.pdock-list .pl-t { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pdock-list li.active button { color: var(--accent); }
.pdock-list li.active .pl-no { color: var(--accent-dim); }

.pdock-progress {
  display: flex;
  align-items: center;
  gap: 0.7em;
  margin-bottom: 0.7rem;
}
.pdock .pp-track {
  flex: 1;
  height: 10px;
  position: relative;
  cursor: pointer;
}
.pdock .pp-track::before {
  content: '';
  position: absolute;
  top: 4px;
  left: 0;
  right: 0;
  height: 2px;
  background: var(--line-strong);
}
.pdock .pp-track > .pp-bar {
  position: absolute;
  top: 4px;
  left: 0;
  width: 100%;
  height: 2px;
  background: var(--accent);
  transform-origin: 0 50%;
  transform: scaleX(0);
}
.pdock .pp-time { font-size: 0.62rem; color: var(--ink-faint); flex: 0 0 auto; }

.pdock-controls {
  display: flex;
  align-items: center;
  gap: 0.6em;
}
.pdock-controls button {
  background: none;
  border: 1px solid var(--line);
  color: var(--ink-dim);
  font-size: 0.7rem;
  padding: 0.35em 0.7em;
  cursor: pointer;
  transition: color 0.25s var(--ease-sine), border-color 0.25s var(--ease-sine);
}
.pdock-controls button:hover { color: var(--ink); border-color: var(--line-strong); }
.pdock-controls .pd-play { color: var(--accent); border-color: var(--accent-dim); min-width: 3em; }
.pdock-controls .pd-vol {
  flex: 1;
  appearance: none;
  -webkit-appearance: none;
  height: 2px;
  background: var(--line-strong);
  outline: none;
  cursor: pointer;
}
.pdock-controls .pd-vol::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--accent);
  border: 0;
}
.pdock-controls .pd-vol::-moz-range-thumb {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--accent);
  border: 0;
}

@media (max-width: 620px) {
  /* Full-width dock along the bottom edge on phones. */
  .pdock { left: 0; right: 0; bottom: 0; }
  .pdock-bar { width: 100vw; max-width: none; }
  .pdock-panel { width: 100vw; }
}

/* ---------- Soft navigation (never leave orbit) ------------------------- */

main { transition: opacity 0.9s var(--ease-sine); }
main.page-leaving { opacity: 0; }
html.calm main { transition: none; }

/* ---------- The Gävle opening ------------------------------------------- */

.terrain-canvas {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100vh;   /* matches #sky: stable across the mobile toolbar */
  z-index: 30;
  pointer-events: none;
  opacity: 0;
}

.zoom-stack {
  position: fixed;
  inset: 0;
  z-index: 30;
  overflow: hidden;
  pointer-events: none;
}
.zoom-stack .zs-layer {
  position: absolute;
  top: 50%;
  left: 50%;
  visibility: hidden;
  will-change: transform, opacity;
}
.zoom-stack .so-marker {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.9rem;
}
.zoom-stack .so-ring {
  width: 14px;
  height: 14px;
  border: 1px solid var(--accent);
  border-radius: 50%;
  box-shadow: 0 0 0 4px rgba(143, 199, 164, 0.15);
}
.zoom-stack .so-label {
  font-family: var(--font-mono);
  font-size: 0.66rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--ink-dim);
  white-space: nowrap;
  text-shadow: 0 0 8px rgba(2, 3, 8, 0.9);
}

/* ---------- Print ------------------------------------------------------- */

@media print {
  .site-header, .site-footer, #sky, .sky-static, .altitude { display: none; }
  body { background: #fff; color: #000; }
}


/* ---------- 2026-07-06 polish round ---------------------------------- */

/* Air between the coordinates label and the logotype on arrival. */
html.scene-live body.journey .band-ground .label { margin-bottom: 1.9rem; }

/* Social icons: a quiet fixed column at the right edge, just below the menu
   row, right-flush with the altitude readout (right: 1.1rem) so the two form
   one line down the edge. Out of the nav row, the menu (Contact last) runs
   all the way to the right. */
.menu-social {
  position: fixed;
  top: calc(var(--header-h) + 0.6rem);
  right: 1.1rem;
  z-index: 49;               /* under the header (50): the open mobile menu wins */
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 0.85rem;
  margin: 0;
  padding: 0;
  list-style: none;
}
.menu-social a { display: inline-flex; opacity: 0.5; transition: opacity 0.25s var(--ease-sine); }
.menu-social a:hover { opacity: 0.95; }
.menu-social img { width: 15px; height: 15px; display: block; }
/* Same cutoff as the altitude readout it aligns with. */
@media (max-width: 880px) { .menu-social { display: none; } }

/* Calm control retired. */
.calm-toggle, .menu-calm { display: none !important; }

/* ---------- /fyc (For Your Consideration) ------------------------------
   A single centred, semi-transparent panel floating over the slow backdrop
   tour. No altitude readout — the panel is the whole page. */
body:has(.fyc-wrap) .altitude { display: none; }
.fyc-wrap {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  /* "safe center": centred while it fits, but falls back to top-aligned (never
     clips) when the panel is taller than the viewport — then the whole PAGE
     scrolls instead of a scrollbox inside the panel, at every width. */
  justify-content: safe center;
  padding: calc(var(--header-h) + 1.5rem) var(--pad-x) 3rem;
}
/* "For Your Consideration" sits ABOVE the panel, outside the box. */
.fyc-above-label {
  margin: 0 0 1.1rem;
  font-family: var(--font-mono);
  font-size: 0.7rem;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: var(--ink-dim);
  text-align: center;
}
.fyc-panel {
  position: relative;
  width: min(980px, 100%);
  display: flex;
  flex-direction: column;
  padding: 2rem 2.6rem 1.4rem;   /* tighter, less dead space at the foot */
  border-radius: 3px;
  border: 1px solid var(--line);
  background: rgba(4, 6, 12, 0.40);   /* more see-through than the content scrim */
  -webkit-backdrop-filter: blur(14px);
  backdrop-filter: blur(14px);
  box-shadow: 0 24px 80px rgba(0, 0, 0, 0.40);
}
/* Passthrough wrapper (was the inner scrollbox — now the whole page scrolls,
   so it just flows). */
.fyc-scroll { overflow: visible; }

/* Edge glint: every so often a bright point flares up in one corner and runs
   one quick lap around the border, trailing a comet tail that eases back to
   the resting border colour. Purely decorative, and off for reduced-motion. */
@property --fyc-beam {
  syntax: "<angle>";
  inherits: false;
  initial-value: 0deg;
}
.fyc-panel::after {
  content: "";
  position: absolute;
  inset: -1px;                 /* ride on the 1px border */
  border-radius: inherit;
  padding: 1.5px;              /* ring thickness */
  background: conic-gradient(from var(--fyc-beam),
      rgba(255, 255, 255, 0.95) 0deg,
      rgba(150, 190, 255, 0)   5deg,
      rgba(150, 190, 255, 0)   294deg,
      rgba(150, 190, 255, 0.16) 330deg,
      rgba(205, 225, 255, 0.7)  353deg,
      rgba(255, 255, 255, 0.95) 360deg);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
          mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
          mask-composite: exclude;
  opacity: 0;
  z-index: 1;
  pointer-events: none;
  /* linear so the lap runs at a constant speed — no easing-out that would read
     as a stop when it completes the loop. */
  animation: fyc-beam-sweep 15s linear infinite;
}
@keyframes fyc-beam-sweep {
  0%   { --fyc-beam: 0deg;   opacity: 0; }
  1.5% { opacity: 1; }                       /* flare up in a corner */
  7%   { opacity: 1; }                       /* bright through most of the lap */
  12%  { --fyc-beam: 360deg; opacity: 0; }   /* fully out EXACTLY at one lap — still moving (linear), so no dead stop */
  100% { --fyc-beam: 360deg; opacity: 0; }   /* rest, then the next flare (less often now) */
}
@media (prefers-reduced-motion: reduce) {
  .fyc-panel::after { animation: none; opacity: 0; }
}

/* White I/O Music logo, top-right corner of the panel, linking to iomusic.se. */
.fyc-iologo {
  position: absolute;
  top: 1.3rem;
  right: 1.5rem;
  z-index: 2;
  display: block;
  width: 44px;
  opacity: 0.92;
  transition: opacity 0.25s var(--ease-sine);
}
.fyc-iologo:hover { opacity: 1; }
.fyc-iologo img { display: block; width: 100%; height: auto; }

/* Visit tally, bottom-right corner. Near-black so it barely reads against the
   dark panel — a quiet counter, not a badge. */
.fyc-visits {
  position: absolute;
  right: 0.9rem;
  bottom: 0.55rem;
  z-index: 2;
  font-family: var(--font-mono);
  font-size: 0.58rem;
  letter-spacing: 0.12em;
  color: #05070d;
  -webkit-user-select: none;
  user-select: none;
  pointer-events: none;
}

/* DOM order = mobile order (cover+stream, text, photos). Desktop: two columns
   via named areas — media stacks on the left, text fills the right. */
.fyc-grid { display: grid; grid-template-columns: 1fr; gap: 1.6rem; }
@media (min-width: 720px) {
  .fyc-grid {
    grid-template-columns: 280px minmax(0, 1fr);
    grid-template-areas: "mtop text" "mbot text";
    gap: 0 2.6rem;
    align-items: start;
  }
  .fyc-media-top    { grid-area: mtop; }
  .fyc-text         { grid-area: text; }
  .fyc-media-bottom { grid-area: mbot; margin-top: -0.6rem; }   /* pull the photo up close under the player */
}
.fyc-media-top, .fyc-media-bottom { display: flex; flex-direction: column; gap: 1.2rem; align-items: center; }
.fyc-cover {
  display: block;
  width: 100%; max-width: 280px; height: auto;
  border-radius: 2px;
  box-shadow: 0 12px 40px rgba(0, 0, 0, 0.5);
}
.fyc-stream { display: flex; justify-content: center; width: 100%; }
.fyc-stream iframe { max-width: 100%; }
.fyc-photo { margin: 0; width: 100%; max-width: 280px; }
.fyc-photo img { display: block; width: 100%; height: auto; border-radius: 2px; }
.fyc-photo figcaption {
  margin-top: 0.4rem;
  font-family: var(--font-mono);
  font-size: 0.58rem;          /* small so name + credit sit on one line */
  letter-spacing: 0.03em;
  text-transform: uppercase;
  color: var(--ink-dim);
  text-align: center;
  white-space: nowrap;
}
.fyc-photo .fyc-credit { color: var(--ink-faint); }
.fyc-photo .fyc-credit::before { content: " · "; color: var(--ink-faint); }

.fyc-text { text-align: left; }
.fyc-text .label { justify-content: flex-start; }
.fyc-title { margin: 0.3rem 0 0.1rem; font-size: clamp(2rem, 4.5vw, 2.7rem); }
.fyc-artist {
  margin: 0 0 0.9rem;
  font-family: var(--font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.17em;
  text-transform: uppercase;
  color: var(--ink-dim);
}
.fyc-category {
  margin: 0 0 1.3rem;
  font-family: var(--font-mono);
  font-size: 0.66rem;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: var(--ink-dim);
}
.fyc-tracks {
  list-style: none;
  margin: 0.3rem 0 0;
  padding: 0;
  color: var(--ink-dim);
  font-size: 0.85rem;
}
.fyc-tracks li { margin: 0.14rem 0; }
.fyc-tnum { display: inline-block; width: 1.9em; color: var(--ink-faint); }
.fyc-tdur { color: var(--ink-faint); }
.fyc-track-with { color: var(--ink-faint); }
.fyc-desc { color: var(--ink-dim); max-width: none; font-size: 0.92rem; }
/* Emphasis in the prose: person names italic, artist/act names bold + brighter. */
.fyc-text em { font-style: italic; }
.fyc-text strong { font-weight: 600; color: var(--ink); }
.fyc-credits { margin: 1.4rem 0 0; }
.fyc-credits .label { justify-content: flex-start; margin-bottom: 0.4rem; }
.fyc-credits p { color: var(--ink-dim); font-size: 0.85rem; }

/* Titles on posts and releases: strong, not shouting. */
.page h1.page-title, h1.release-title {
  font-size: clamp(1.7rem, 1.15rem + 2.1vw, 2.7rem);
  line-height: 1.15;
}

/* Streaming icons, sized to match the link.iomusic.se embed used on the
   release pages (25px circle, 6px gap, 14px glyph). They were 34px here, which
   measures small but reads LOUD: eight saturated discs are the brightest thing
   on a page otherwise built from thin type on near-black. Brand icons that
   carry their own disc fill the button; white glyphs sit in a colored circle. */
.platform-icons { gap: 6px; }
.platform-icons a { width: 25px; height: 25px; }
.platform-icons a .pi-circle { width: 25px; height: 25px; }
.platform-icons a .pi-circle svg { width: 14px; height: 14px; }
.platform-icons a > svg { width: 25px; height: 25px; display: block; border-radius: 50%; }

/* Credits read as one tight block. */
.credits p { margin: 0.12em 0; }

/* Release page: quiet mono section headings; credits live in the info
   column, stream links right under them. */
h2.rel-h {
  font-family: var(--font-mono);
  font-size: 0.7rem;
  font-weight: 400;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--ink-faint);
  margin: 0 0 0.55rem;
}
.release-head .awards { margin: 0 0 1.4rem; }
.release-head .rel-h { margin-top: 0.2rem; }
.rel-h + .tracklist { margin-top: 0.5rem; }

/* Press thumbnails. */
.press-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(170px, 1fr));
  gap: 1.1rem;
  margin: 1.2rem 0 2.4rem;
}
.press-grid a {
  display: block;
  text-decoration: none;
  color: var(--ink-dim);
  font-size: 0.82rem;
  line-height: 1.4;
}
.press-grid img {
  width: 100%;
  aspect-ratio: 1 / 1;
  object-fit: cover;
  display: block;
  border: 1px solid var(--line);
  margin-bottom: 0.5rem;
  transition: border-color 0.25s var(--ease-sine);
}
.press-grid a:hover img { border-color: var(--line-strong); }
.press-grid .pg-label { display: block; color: var(--ink); }
.press-grid .pg-credit { display: block; font-size: 0.74rem; }

/* The system band breathes; the canvas owns the show. */
.band-system .band-content-slim { max-width: 30rem; }
.system-hint { color: var(--ink-dim); }

/* Planet-doorway tooltip. */
.planet-tip {
  position: fixed;
  z-index: 60;
  padding: 0.35em 0.7em;
  background: rgba(2, 3, 8, 0.85);
  border: 1px solid var(--line-strong);
  color: var(--ink);
  font-family: var(--font-mono);
  font-size: 0.7rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  pointer-events: none;
  transform: translate(14px, -50%);
  white-space: nowrap;
}

/* Constellation name: a faint mono label that fades in when the cursor rests
   on the deep sky. Opacity is driven from the scene (matches the lines). */
.constellation-name {
  position: fixed;
  z-index: 58;
  pointer-events: none;
  font-family: var(--font-mono);
  font-size: 0.66rem;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: #cfe0ff;
  text-shadow: 0 0 8px rgba(120, 170, 255, 0.6);
  white-space: nowrap;
  transition: opacity 0.2s var(--ease-sine);
}

/* ISS hover panel: the spinning wireframe on the left, the readout on the
   right, fading and easing up into view. Pure overlay — the scene is untouched. */
.iss-panel {
  position: fixed;
  z-index: 61;
  display: flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.55rem 0.95rem;
  background: rgba(2, 3, 8, 0.82);
  border: 1px solid var(--line-strong);
  pointer-events: none;
  opacity: 0;
  transform: translateY(6px) scale(0.96);
  transition: opacity 0.3s var(--ease-sine), transform 0.3s var(--ease-sine);
}
.iss-panel::before {
  content: '';
  position: absolute;
  top: -1px; left: -1px;
  width: 9px; height: 9px;
  border-top: 1px solid var(--accent-dim);
  border-left: 1px solid var(--accent-dim);
}
.iss-panel.shown { opacity: 1; transform: none; }
.iss-info { font-family: var(--font-mono); line-height: 1.5; }
.iss-title {
  margin: 0 0 0.15rem;
  font-size: 0.56rem;
  letter-spacing: 0.16em;
  color: var(--ink-faint);
}
.iss-row {
  margin: 0;
  font-size: 0.66rem;
  letter-spacing: 0.1em;
  color: var(--ink);
}
.iss-coord { color: var(--ink); }
.iss-link {
  margin: 0.2rem 0 0;
  font-size: 0.58rem;
  letter-spacing: 0.16em;
  color: var(--accent);
}


/* A back arrow on second-level pages (an album, a news post) returning to its
   list. First-level pages have no close/back — the menu is the way around. */
.page-back {
  position: fixed;
  top: calc(var(--header-h) + 0.4rem + 15px);
  left: var(--pad-x);
  z-index: 55;
  display: inline-flex;
  align-items: center;
  gap: 0.55em;
  padding: 0.45em 0.9em 0.45em 0.75em;
  border: 1px solid var(--line-strong);
  background: rgba(2, 3, 8, 0.55);
  color: var(--ink-dim);
  font-family: var(--font-mono);
  font-size: 0.64rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  text-decoration: none;
  transition: color 0.25s var(--ease-sine), border-color 0.25s var(--ease-sine);
}
.page-back:hover { color: var(--ink); border-color: var(--ink-dim); }
.page-back .pb-arrow { font-size: 1.05em; transition: transform 0.25s var(--ease-sine); }
.page-back:hover .pb-arrow { transform: translateX(-3px); }
/* With the arrow dropped in, close the gap under a detail-page label
   (e.g. "SINGLE · 15 MAY 2026") so the title rides up to meet it. Scoped to
   pages that actually carry the arrow — the discography/about labels keep
   their air. */
body:has(.page-back) .label { margin-bottom: calc(1.2rem - 15px); }


/* Remix entries: date, artist over title, streaming embed underneath. */
.remix-item .rx-date {
  font-family: var(--font-mono);
  font-size: 0.7rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--ink-faint);
  margin: 0 0 0.45rem;
}
.remix-item .rx-artist {
  color: var(--ink-dim);
  margin: 0 0 0.1rem;
}
.remix-item h2.rx-title { font-size: 1.25rem; margin-bottom: 0.3rem; }
.remix-item .rx-embed { margin-top: 0.9rem; }
.rx-embed iframe { display: block; }
/* On release pages the embed takes the platform icons' slot. */
.release-head .rx-embed { margin: 1.4rem 0 0.4rem; }

/* The mark-heading can be the link itself; the other groups link their marks
   instead. Inherits the heading's colour so hover lifts both parts together. */
.ag-link {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  color: inherit;
  text-decoration: none;
  transition: opacity 0.3s var(--ease-sine);
}
.ag-link:hover,
.ag-link:focus-visible { opacity: 1; color: var(--ink-dim); }
