/* Endless Noir — Art Deco reskin: design tokens + the primitives every screen shares.
 *
 * Values come from design_handoff_endless_noir_reskin/README.md and the prototype frames.
 * Per-screen CSS lives in home.css / how.css / pages.css / archive.css / board.css so that
 * page work never has to touch this file.
 *
 * NO border-radius anywhere except circles — Deco is chamfered and square.
 * Gold surfaces are ALWAYS a gradient, never a flat fill (see --grad-*).
 */

:root {
  /* ---- colour ------------------------------------------------------------------------ */
  --black: #08070a;
  --black-2: #0b0906;
  --bakelite: #20130a;
  --board-fallback: #2a1608;

  --gold: #c9a24a;
  --gold-bright: #e3c377;
  --gold-pale: #f4e6c0;
  --gold-deep: #8a6f34;
  --gold-deepest: #7d6330;

  --cream: #f6ecd2;
  --cream-2: #f2ead8;

  --paper-base: #e6d9b4;
  --ink: #231c12;
  --ink-2: #2f2618;
  --ink-body: #453a2a;
  --ink-muted: #5a4c35;
  /* THE paper label token. Every muted label, count, meta line and gutter number on a paper
   * surface is this one brown — measured 4.5:1 against the real texture's worst-case luminance.
   * Never --gold-deep on paper (2.18:1) and no intermediate browns; each of those shipped at
   * some point because it *looked* like a paper colour. */
  --paper-label: #54401c;

  --text-muted: #bdb298;
  --text-muted-2: #a89e88;
  --text-dim: #8c8069;
  --text-dimmest: #6b6252;
  --nav: #cbbfa4;

  --string: #7d2118;
  --string-lit: #c0392b;
  --stamp-red: rgba(150, 44, 30, .5);
  --meter-red: #a8331d;
  --lamp-glow: rgba(226, 74, 32, .55);

  /* Hairlines and double borders — the Deco rule system. */
  --rule: rgba(201, 162, 74, .35);
  --rule-soft: rgba(201, 162, 74, .18);
  --rule-mid: rgba(201, 162, 74, .3);
  --frame-outer: rgba(201, 162, 74, .45);
  --frame-inner: rgba(201, 162, 74, .2);

  /* ---- gold gradients ---------------------------------------------------------------- */
  --grad-object: linear-gradient(150deg, #f4e6c0, #c9a24a 60%, #8a6f34);
  --grad-button: linear-gradient(#e3c377, #c9a24a);
  --grad-text: linear-gradient(140deg, #f8ecc9, #e3c377 30%, #c9a24a 58%, #8a6f34);

  /* ---- type -------------------------------------------------------------------------- */
  --deco: 'Poiret One', 'Century Gothic', sans-serif;
  --cond: Oswald, 'Helvetica Neue', sans-serif;
  --serif: 'Playfair Display', Georgia, serif;
  --mono: 'Space Mono', ui-monospace, Menlo, monospace;

  /* ---- structure --------------------------------------------------------------------- */
  --page: 1180px;
  --pad-x: 52px;

  /* ---- shadows ----------------------------------------------------------------------- */
  --sh-card: 0 12px 16px rgba(0, 0, 0, .55);
  --sh-card-sel: 0 22px 28px rgba(0, 0, 0, .6);
  --sh-board: 0 30px 60px -28px #000;
  --sh-drawer: -24px 0 50px -18px rgba(0, 0, 0, .8);
  --sink-paper: inset 0 0 50px rgba(120, 90, 40, .26);
}

/* ==== keyframes ======================================================================== */

@keyframes rayspin { to { transform: rotate(360deg); } }
@keyframes ringsweep { to { transform: rotate(360deg); } }
@keyframes glowbreathe { 0%, 100% { opacity: .7; } 50% { opacity: 1; } }
@keyframes stringsag { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(1.5px); } }

/* VU ballistics: deliberately irregular — fast attack, lazy fallback, −29° to +10°.
 * Not a sine wave. Do not "smooth" these stops. */
@keyframes vuphoto {
  0%   { transform: rotate(-29deg); }
  5%   { transform: rotate(-2deg); }
  10%  { transform: rotate(-12deg); }
  17%  { transform: rotate(6deg); }
  24%  { transform: rotate(-7deg); }
  33%  { transform: rotate(-23deg); }
  40%  { transform: rotate(1deg); }
  47%  { transform: rotate(-11deg); }
  55%  { transform: rotate(10deg); }
  62%  { transform: rotate(-5deg); }
  70%  { transform: rotate(-19deg); }
  78%  { transform: rotate(3deg); }
  86%  { transform: rotate(-14deg); }
  93%  { transform: rotate(-26deg); }
  100% { transform: rotate(-29deg); }
}

/* Lamp flicker: a tube settling, NOT a strobe. Long steady stretches, shallow dips that
 * never go below 82%, clustered into two brief tremors. Linear easing is load-bearing. */
@keyframes onairflicker {
  0%    { opacity: .97; }
  6%    { opacity: 1; }
  14%   { opacity: .95; }
  22%   { opacity: 1; }
  30%   { opacity: .96; }
  36%   { opacity: 1; }
  40%   { opacity: .89; }
  41.5% { opacity: .99; }
  43%   { opacity: .82; }
  44%   { opacity: .97; }
  45.5% { opacity: .91; }
  47%   { opacity: 1; }
  58%   { opacity: .96; }
  66%   { opacity: 1; }
  74%   { opacity: .98; }
  80%   { opacity: .87; }
  81%   { opacity: .98; }
  82.5% { opacity: .93; }
  84%   { opacity: 1; }
  92%   { opacity: .96; }
  100%  { opacity: .97; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .001ms !important; animation-iteration-count: 1 !important; transition-duration: .001ms !important; }
}

/* ==== base ============================================================================= */

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

body {
  margin: 0;
  background: var(--black);
  color: #efe6d2;
  font-family: var(--cond);
  font-weight: 300;
  -webkit-font-smoothing: antialiased;
}

img { max-width: 100%; }
p { text-wrap: pretty; }

a { color: var(--gold-bright); }

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

/* Desktop is a fixed 1180px column; below it the 8a/8b breakpoints reflow (see the media
 * queries at the end of this file and each per-screen sheet). */
.page { width: var(--page); margin: 0 auto; position: relative; }

/* ==== typography primitives ============================================================ */
/* THE TYPE FLOOR: no text anywhere below 11px — data labels that carry meaning sit at
 * 11.5-12px. Where a label grew from the comps' 9-10px, its tracking came down a notch so
 * the row still fits. Do not reintroduce sub-11px sizes. */

.eyebrow    { font-weight: 300; font-size: 11px; letter-spacing: .5em;  text-transform: uppercase; color: var(--gold); }
.slug       { font-weight: 500; font-size: 11px; letter-spacing: .44em; text-transform: uppercase; color: var(--gold-bright); }
a.slug      { text-decoration: none; }
a.slug:hover { color: var(--gold-pale); }
.label-sm   { font-weight: 300; font-size: 11px; letter-spacing: .3em; text-transform: uppercase; color: var(--gold); }
.step-head  { font-weight: 500; font-size: 13px; letter-spacing: .18em; text-transform: uppercase; }
.data       { font-family: var(--mono); font-size: 11px; letter-spacing: .16em; text-transform: uppercase; color: var(--text-dim); }
.data-wide  { font-family: var(--mono); font-size: 11px; letter-spacing: .2em; text-transform: uppercase; }

.d-hero    { font-family: var(--deco); font-weight: 400; font-size: 104px; line-height: .86; letter-spacing: .03em; text-transform: uppercase; color: var(--cream); margin: 0; }
.d-page    { font-family: var(--deco); font-weight: 400; font-size: 58px;  line-height: 1;   letter-spacing: .05em; text-transform: uppercase; color: var(--cream); margin: 0; }
.d-section { font-family: var(--deco); font-weight: 400; font-size: 40px;  line-height: 1.1; letter-spacing: .04em; text-transform: uppercase; color: var(--cream); margin: 0; }
.d-card    { font-family: var(--deco); font-weight: 400; font-size: 28px;  line-height: 1.15; letter-spacing: .03em; text-transform: uppercase; margin: 0; }

.lede { font-family: var(--serif); font-style: italic; font-weight: 400; font-size: 20px; line-height: 1.6; color: var(--text-muted); max-width: 34ch; }
.body { font-family: var(--serif); font-style: italic; font-weight: 400; font-size: 16px; line-height: 1.6; color: var(--text-muted); max-width: 56ch; }
.body-paper { font-family: var(--serif); font-style: normal; font-weight: 400; font-size: 16px; line-height: 1.66; color: var(--ink-body); max-width: 56ch; }

/* Gold gradient clipped into display type. */
.gilt {
  background: var(--grad-text);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  color: transparent;
  filter: drop-shadow(3px 6px 10px rgba(0, 0, 0, .75));
}

/* ==== header / nav ===================================================================== */

.masthead {
  display: flex; align-items: center; gap: 26px;
  padding-bottom: 18px;
  border-bottom: 1px solid var(--rule);
}
.masthead .spacer { flex: 1; }
/* The nav is a semantic wrapper, not a layout box — `display:contents` lets its links become
 * direct flex items of the masthead so they inherit the 26px gap. Without it every nav link
 * runs together into one unreadable string. */
.masthead nav { display: contents; }

.nav-link {
  font-weight: 300; font-size: 11px; letter-spacing: .26em; text-transform: uppercase;
  color: var(--nav); text-decoration: none;
  transition: color .2s;
}
.nav-link:hover { color: var(--gold-bright); }
.nav-link[aria-current] {
  font-weight: 400; color: var(--gold-bright);
  border-bottom: 1px solid rgba(201, 162, 74, .6); padding-bottom: 3px;
}

/* ==== ON AIR lamp ====================================================================== */
/* Two stacked images at identical size. Animating OPACITY on the lit layer is deliberate:
 * opacity composites after filter, so the drop-shadow glow dims with it automatically. */

.lamp { position: relative; flex: none; width: 116px; height: 62px; margin: -8px 0; }
.lamp img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: contain; }
.lamp .lit {
  animation: onairflicker 11s linear infinite;
  filter: drop-shadow(0 0 14px var(--lamp-glow));
}
/* Off air: hold the lit layer dark, no animation. */
.lamp.off .lit { animation: none; opacity: 0; }

/* The home page uses a dot + text instead of the lamp — that difference is in the comp. */
.onair-dot {
  display: inline-flex; align-items: center; gap: 8px;
  font-family: var(--mono); font-size: 11px; letter-spacing: .2em; text-transform: uppercase;
  color: var(--gold-bright);
}
.onair-dot .dot {
  width: 6px; height: 6px; border-radius: 50%; background: var(--text-dimmest);
  transition: background .3s, box-shadow .3s;
}
.onair-dot.live .dot {
  background: var(--gold-bright);
  box-shadow: 0 0 7px 2px rgba(227, 195, 119, .65);
  animation: glowbreathe 3.2s ease-in-out infinite;
}

/* ==== VU meter ========================================================================= */
/* Geometry is fitted to the printed scale — arc centre (651,802) r550, span ±31° = −10..+10 VU.
 * The centre sits 145px BELOW the image, so the movement lives behind the bezel like a real
 * meter. The clip wrapper at 83.9% height is the face's bottom edge: it hides the stem so no
 * pivot hardware shows. Changing any number here makes the needle disagree with the printed
 * numbers. */

.vu { position: relative; width: 212px; filter: drop-shadow(0 14px 24px rgba(0, 0, 0, .75)); }
.vu > img { display: block; width: 100%; height: auto; }
.vu .clip { position: absolute; left: 0; right: 0; top: 0; height: 83.9%; overflow: hidden; pointer-events: none; }
.vu .needle {
  position: absolute;
  left: 45.61%; top: 41.18%; width: 10.41%;
  transform-origin: 49.7% 88.5%;
  animation: vuphoto 6.5s cubic-bezier(.25, .85, .35, 1) infinite;
}

/* ==== Deco devices ===================================================================== */

/* Sunburst ray field. The mask is what makes it read as rays rather than a disc — vary the
 * transparent stop per placement with --ray-hole. */
.rays {
  position: absolute;
  background: repeating-conic-gradient(from 0deg at 50% 50%, rgba(201, 162, 74, .3) 0deg .5deg, transparent .5deg 4deg);
  -webkit-mask-image: radial-gradient(closest-side, transparent var(--ray-hole, 46%), #000 60%, transparent 92%);
  mask-image: radial-gradient(closest-side, transparent var(--ray-hole, 46%), #000 60%, transparent 92%);
  animation: rayspin var(--ray-speed, 220s) linear infinite;
  pointer-events: none;
}

/* Diamond-and-rule divider: a 7px square on its corner beside a fading hairline. */
.divider { display: flex; align-items: center; gap: 12px; }
.divider::before {
  content: ""; flex: none; width: 7px; height: 7px;
  border: 1px solid var(--gold); transform: rotate(45deg);
}
.divider::after {
  content: ""; flex: 1; height: 1px;
  background: linear-gradient(90deg, rgba(201, 162, 74, .7), transparent);
}

/* Decorative double border, inset from the element edge. */
.double-frame::before,
.double-frame::after { content: ""; position: absolute; pointer-events: none; }
.double-frame::before { inset: 14px; border: 1px solid var(--frame-outer); }
.double-frame::after  { inset: 20px; border: 1px solid var(--frame-inner); }

/* ==== paper stock ====================================================================== */

.paper {
  position: relative; overflow: hidden;
  background: var(--paper-base) url(/assets/paper.webp) center/cover;
  color: var(--ink);
  box-shadow: var(--sink-paper);
  /* Grayscale antialiasing is a dark-background optimization — the body sets it globally for
   * the cream-on-black surfaces, but on light stock it shaves dark glyphs a half-stroke thin.
   * Paper reverts to the platform default. */
  -webkit-font-smoothing: auto;
}
/* Gold is a dark-background token — on paper it lands at 2.2:1. One brown, everywhere. */
.paper .eyebrow { color: var(--paper-label); }

/* Coffee ring: multiply blend, rotated, bleeding off an edge. Never a full circle inside
 * the card — that reads as a sticker, not a stain. */
.ring {
  position: absolute; pointer-events: none;
  mix-blend-mode: multiply; opacity: .78;
}

.stamp {
  position: absolute; transform: rotate(-9deg); mix-blend-mode: multiply;
  border: 2px solid var(--stamp-red); color: rgba(150, 44, 30, .62);
  font-family: var(--cond); font-weight: 500; font-size: 11px;
  letter-spacing: .24em; text-transform: uppercase; padding: 5px 10px;
}

/* ==== buttons ========================================================================== */

.btn-gold {
  display: inline-block;
  font-family: var(--cond); font-weight: 400; font-size: 11px;
  letter-spacing: .28em; text-transform: uppercase;
  color: var(--black-2); background: var(--grad-button);
  padding: 16px 28px; text-decoration: none; border: 0; cursor: pointer;
  transition: filter .2s;
}
.btn-gold:hover { filter: brightness(1.08); }

.btn-outline {
  display: inline-block;
  font-family: var(--cond); font-weight: 400; font-size: 11px;
  letter-spacing: .26em; text-transform: uppercase;
  color: var(--gold-bright); background: rgba(8, 7, 10, .7);
  border: 1px solid rgba(201, 162, 74, .5); padding: 12px 20px;
  text-decoration: none; cursor: pointer;
  transition: border-color .2s, color .2s;
}
.btn-outline:hover { border-color: var(--gold-bright); color: var(--cream); }

/* ==== listen badges ==================================================================== */
/* One identical plate for all three. The assets are NOT comparable: Spotify and Amazon ship
 * their own dark plate (artwork fills 59% / 65% of the file), Apple ships bare artwork filling
 * 100%. Equal CSS heights would render Apple ~70% larger. Normalize on the ARTWORK: vendors
 * fill the plate as supplied, Apple centres inside at 62% of plate height. Keep the vendors'
 * plates intact — their badge guidelines require it. */

.badges { display: flex; gap: 12px; align-items: center; }
.badge {
  display: flex; align-items: center; justify-content: center;
  width: 190px; height: 46px; overflow: hidden;
  background: #000; border: 1px solid var(--rule-mid);
  text-decoration: none;
}
.badge img { display: block; width: 100%; height: 100%; object-fit: cover; }
.badge.apple img { width: auto; height: 62%; object-fit: contain; }

/* ==== footers ========================================================================== */

.footstrip {
  display: flex; align-items: baseline; justify-content: space-between; gap: 30px;
  padding: 22px var(--pad-x) 30px;
  border-top: 1px solid var(--rule);
}
.footstrip .cap { font-family: var(--serif); font-style: italic; font-size: 14px; color: var(--text-dimmest); margin: 0; }
.footstrip .stamp-time { font-family: var(--mono); font-size: 11px; letter-spacing: .18em; text-transform: uppercase; color: var(--text-dimmest); }

/* Footer navigation — two routes home on every page. Centred row above the disclosure line:
 * nav-link styling, 4px gold diamonds between. Without it the long pages (Corkboard, case
 * detail, press kit) are dead ends once the masthead has scrolled away. */
.footnav {
  display: flex; align-items: center; justify-content: center; gap: 20px; flex-wrap: wrap;
  padding: 26px var(--pad-x);
  border-top: 1px solid var(--rule-soft);
}
.footnav .dia { flex: none; width: 4px; height: 4px; transform: rotate(45deg); background: rgba(201, 162, 74, .45); }

.disclosure {
  font-family: var(--mono); font-size: 11px; line-height: 2; letter-spacing: .14em;
  /* --text-dim, not --text-dimmest: the dimmest token is under AA on black,
   * and this is the AI-disclosure line. Same nudge the old skin made to --amber-dim. */
  text-transform: uppercase; color: var(--text-dim);
  padding: 26px var(--pad-x) 44px;
  border-top: 1px solid var(--rule-soft);
}
.disclosure a { color: var(--nav); text-decoration: none; }
.disclosure a:hover { color: var(--gold-bright); }

/* ==== responsive frame (8a phone · 8b tablet) ========================================== */
/* Desktop stays the fixed 1180px column. Below it, two breakpoints; every desktop rule still
 * holds — no border radius, gold as gradient, one job per face, the 11px type floor. */

/* The hamburger: checkbox-hack, no script. Markup (in every masthead below 1180px):
 *   <input type="checkbox" id="navtoggle" class="sr-only navtoggle-input">
 *   …<label class="navtoggle" for="navtoggle"><span></span><span></span><span></span></label>
 * The nav collapses into a dropdown panel under the masthead. Desktop hides the label and
 * restores display:contents. */
.navtoggle { display: none; }
.navtoggle-input { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0; }

@media (max-width: 1179px) {
  :root { --pad-x: 32px; }
  .page { width: 100%; }

  .masthead { position: relative; flex-wrap: wrap; }
  /* order:10 sends the opened panel to its own wrapped row below the slug/lamp/burger row —
   * DOM order keeps nav before the lamp for the desktop display:contents layout. */
  .masthead nav {
    display: none; order: 10;
    flex-basis: 100%; flex-direction: column; align-items: flex-start; gap: 0;
    padding-top: 16px;
  }
  .navtoggle-input:checked ~ nav { display: flex; }
  .masthead nav .nav-link { display: block; padding: 12px 0; }
  .navtoggle {
    display: flex; flex-direction: column; justify-content: center; gap: 5px;
    width: 40px; height: 40px; padding: 8px; margin: -8px -8px -8px 0;
    cursor: pointer; flex: none;
  }
  .navtoggle span { display: block; height: 1px; background: var(--nav); }
  .navtoggle:hover span { background: var(--gold-bright); }

  /* The ON AIR lamp stays in the header — it is the station's state, not decoration. */
  .lamp { width: 98px; height: 52px; margin: -6px 0; }

  .d-hero    { font-size: 76px; }
  .d-page    { font-size: 44px; }
  .d-section { font-size: 34px; }

  .footnav { gap: 14px; }
}

@media (max-width: 599px) {
  :root { --pad-x: 20px; }

  .lamp { width: 76px; height: 41px; margin: -4px 0; }
  .slug { letter-spacing: .34em; }

  .d-hero    { font-size: 56px; }
  .d-page    { font-size: 40px; }
  .d-section { font-size: 28px; }

  .lede { font-size: 17px; max-width: 32ch; }
  .body { max-width: none; }
  .body-paper { max-width: none; }

  .badges { flex-wrap: wrap; }
  .footstrip { flex-direction: column; align-items: flex-start; gap: 10px; }
}
