:root{
    --bg: #07080a;
    --panel: #101213;
    --panel-alt: #17191b;
    --line: #2b2d2c;
    --line-soft: #1c1e1d;
    --amber: #ffb000;
    --amber-dim: #8a5f0f;
    --phosphor: #57e39c;
    --text: #f3efe8;
    --muted: #948d84;
    --muted-dim: #5e5850;
    --red: #ff6b57;
    --font-display: 'Oswald', sans-serif;
    --font-body: 'Inter', sans-serif;
    --font-mono: 'IBM Plex Mono', monospace;
    /* .wrap-wide's own effective left/right inset, as a formula rather than
       a fixed number (padding, plus half of whatever space is left over
       once .wrap-wide's 1920px max-width caps out) — global, not scoped to
       .wrap-wide itself, so .timeline-wrap (a sibling of a .wrap-wide
       header, not a descendant of it) can reuse the exact same value for
       its own edge margin and line up with it at any viewport width. */
    --wide-inset: max(28px, calc((100vw - 1920px) / 2 + 28px));
  }

  *{ box-sizing: border-box; }
  /* html carries the page background too: during /explore's blur-in
     arrival the <body> starts at opacity:0, and whatever is behind it
     shows through — without this that's a white flash, not black. */
  html{ scroll-behavior: smooth; background: var(--bg); }

  body{
    margin:0;
    background:
      radial-gradient(ellipse 900px 500px at 15% -10%, rgba(255,176,0,0.05), transparent),
      radial-gradient(ellipse 700px 600px at 100% 0%, rgba(87,227,156,0.04), transparent),
      var(--bg);
    color: var(--text);
    font-family: var(--font-body);
    -webkit-font-smoothing: antialiased;
    background-attachment: fixed;
  }

  ::selection{ background: var(--amber); color:#090b10; }
  a{ color: inherit; }

  .starfield{
    position: fixed; inset:0; pointer-events:none; z-index:0; opacity:.5;
    background-image:
      radial-gradient(1px 1px at 20px 30px, #fff, transparent),
      radial-gradient(1px 1px at 140px 90px, #fff, transparent),
      radial-gradient(1px 1px at 210px 40px, #ffffffaa, transparent),
      radial-gradient(1px 1px at 320px 160px, #fff, transparent),
      radial-gradient(1px 1px at 60px 190px, #ffffff88, transparent),
      radial-gradient(1px 1px at 400px 60px, #fff, transparent),
      radial-gradient(1px 1px at 470px 220px, #ffffff77, transparent),
      radial-gradient(1px 1px at 250px 260px, #fff, transparent);
    background-repeat: repeat;
    background-size: 500px 300px;
  }

  /* ---------- VIEWFINDER FRAME ---------- */
  /* Thick corner brackets pinned to the viewport — an optical HUD readout that
     stays put while the page scrolls beneath it. */
  .viewport-frame{ position:fixed; inset:16px; z-index:60; pointer-events:none; }
  .viewport-frame i{ position:absolute; width:34px; height:34px; display:block; opacity:.85; }
  .viewport-frame i.tl{ top:0; left:0; border-top:1.5px solid var(--amber); border-left:1.5px solid var(--amber); }
  .viewport-frame i.tr{ top:0; right:0; border-top:1.5px solid var(--amber); border-right:1.5px solid var(--amber); }
  .viewport-frame i.bl{ bottom:0; left:0; border-bottom:1.5px solid var(--amber); border-left:1.5px solid var(--amber); }
  .viewport-frame i.br{ bottom:0; right:0; border-bottom:1.5px solid var(--amber); border-right:1.5px solid var(--amber); }
  @media (max-width: 700px){ .viewport-frame{ display:none; } }

  .wrap{ max-width: 1280px; margin: 0 auto; padding: 0 28px; position:relative; z-index:1; }
  /* Wider variant for sections that felt cramped at the standard column on
     large screens (Recently Logged's grid, and Upcoming Launches' header
     right below it) — same element, so it still centers/pads itself
     identically, just with more room to breathe. Its 1920px cap has to
     match --wide-inset's own formula (see :root) for the two to actually
     agree on where the edge falls. */
  .wrap.wrap-wide{ max-width: 1920px; }

  /* ---------- BREADCRUMBS (every content page, below the header) ---------- */
  .crumbs{
    display:flex; flex-wrap:wrap; align-items:center; gap:8px;
    font-family: var(--font-mono); font-size:16px; text-transform:uppercase; letter-spacing:.06em;
    margin-bottom:34px;
  }
  .crumbs a{ color: var(--muted); text-decoration:none; }
  .crumbs a:hover{ color: var(--amber); }
  .crumbs .sep{ color: var(--muted-dim); opacity:.8; }
  .crumbs .here{ color: var(--amber); }

  /* ---------- HEADER (stripped to almost nothing) ---------- */
  header.top{
    position: sticky; top:0; z-index: 50;
    background: #0b0c0e;
    border-bottom: 1px solid var(--line-soft);
  }
  /* Overrides .wrap's max-width:1280px + margin:0 auto (see above) — on wide
     viewports that left the brand and clock stranded in a narrow centered
     column, far short of the viewport-frame corner brackets. The header
     spans the full width instead, so they sit out near those brackets. */
  .top-inner{
    display:flex; align-items:center; justify-content:space-between;
    padding: 22px 32px; gap: 24px; flex-wrap: wrap;
    max-width:none; margin:0;
  }
  .brand{ display:flex; align-items:center; gap:14px; }
  /* The Sputnik logo (static/logo.png) carries its own ring and centre, so
     the mark is now just a sized container — no bordered circle or centre
     dot of its own (that would double up on the logo's ring). */
  .brand-mark{ width:40px; height:40px; display:flex; align-items:center; justify-content:center; position:relative; flex-shrink:0; }
  .brand-mark img{ width:40px; height:40px; display:block; }
  .brand-mark svg{ width:20px; height:20px; }
  .brand-text h1{ font-family: var(--font-display); font-weight:600; font-size: 24px; letter-spacing: 0.1em; margin:0; text-transform: uppercase; }
  .brand-text p{ margin:2px 0 0; font-family: var(--font-mono); font-size: 16px; color: var(--muted); letter-spacing: 0.03em; }
  .clock{ font-family: var(--font-mono); font-size: 16px; color: var(--phosphor); text-transform: uppercase; letter-spacing:.08em; }
  .clock b{ display:block; font-size:21px; color: var(--phosphor); font-weight:600; }

  /* ---------- HERO (full viewport, cinematic) ---------- */
  /* The landing page has no header (cinematic full-bleed intro), so the
     hero starts at the very top — no negative offset needed anymore. */
  .hero{ position:relative; overflow:hidden; min-height: 100vh; display:flex; align-items:center; }
  .hero-bg{ position:absolute; inset:0; z-index:0; background:#050607; }
  .hero-bg img, .hero-bg video{
    position:absolute; inset:0;
    width:100%; height:100%; object-fit:cover; object-position: center 55%; display:block;
    filter: grayscale(.2) contrast(1.05);
  }
  .hero-bg img{
    animation: heroImgIn 2s cubic-bezier(.11,.7,.2,1) both, heroImgDrift 13s ease-in-out infinite 2s;
  }
  /* Intro clip plays once, in full, then hands off to the looping clip
     beneath it (see the .looping toggle below and initLaunchCounter() in
     home.js, which adds it exactly 3s before the intro video's natural end
     — the whole clip stays visible at full brightness right up until that
     final stretch). Intro's fade-out uses that entire 3s window, starting
     the instant .looping is added. The loop's fade-in (1.3s) overlaps the
     last 0.9s of it rather than waiting for it to finish — a purely
     sequential handoff looked right on paper (durations summed correctly)
     but read as a dark gap in practice, because ease-in-out slows down at
     both ends: right at the handoff intro was nearly invisible AND loop had
     barely started, so neither contributed much brightness for a beat. */
  #heroIntro{
    animation: heroImgIn 2s cubic-bezier(.11,.7,.2,1) both;
    opacity:1; transition: opacity 3s ease-in-out;
    z-index:2;
  }
  #heroLoop{ opacity:0; transition: opacity 1.3s ease-in-out 2.1s; z-index:1; }
  .hero-bg.looping #heroIntro{ opacity:0; }
  .hero-bg.looping #heroLoop{ opacity:1; }
  .hero-scrim{
    position:absolute; inset:0; z-index:1;
    background:
      linear-gradient(180deg, rgba(7,8,10,.55) 0%, rgba(7,8,10,.35) 30%, rgba(7,8,10,.55) 65%, var(--bg) 100%),
      linear-gradient(100deg, rgba(7,8,10,.94) 0%, rgba(7,8,10,.68) 32%, rgba(7,8,10,.12) 62%, rgba(7,8,10,0) 78%);
  }
  /* ignition flash — a bright burst timed to the moment the image starts pulling back */
  .hero-flash{
    position:absolute; inset:0; z-index:1; pointer-events:none; mix-blend-mode:screen;
    background: radial-gradient(ellipse 55% 45% at 28% 62%, rgba(255,236,196,.95), rgba(255,176,0,.35) 42%, transparent 72%);
    opacity:0; animation: heroFlash 1.3s cubic-bezier(.2,.6,.2,1) both;
  }
  @keyframes heroFlash{ 0%{ opacity:0; } 10%{ opacity:1; } 100%{ opacity:0; } }
  /* launch counter — a "T-minus" HUD readout synced to the hero video's own clock (see
     initLaunchCounter() in app.js). Reuses the title's own letterIn flip whenever the
     digit changes, so it reads as "the same effect" as the headline. */
  .launch-counter{
    position:absolute; top:118px; right:32px; z-index:3; text-align:right; pointer-events:none;
    animation: fadeUp .8s cubic-bezier(.16,.7,.2,1) both; animation-delay:.4s;
  }
  .lc-label{
    display:block; font-family:var(--font-mono); font-size:16px; letter-spacing:.24em;
    text-transform:uppercase; color:var(--muted); margin-bottom:6px;
  }
  .lc-num{
    display:inline-block; font-family:var(--font-display); font-weight:700;
    font-size:clamp(35px,4.3vw,56px); letter-spacing:.02em; color:var(--amber);
    font-variant-numeric:tabular-nums; filter:drop-shadow(0 4px 14px rgba(0,0,0,.5));
  }
  .lc-num.flip{ animation: letterIn .5s cubic-bezier(.2,.6,.2,1); }
  @media (max-width:800px){ .launch-counter{ display:none; } }

  /* Browsers only allow audio-with-sound autoplay after a genuine user
     gesture — the hero videos stay muted (see index.html) until this is
     clicked. See initLaunchCounter() in home.js for the mute/volume-ramp
     logic that keys off it. */
  .sound-toggle{
    position:absolute; left:32px; bottom:32px; z-index:5;
    width:44px; height:44px; display:flex; align-items:center; justify-content:center;
    border:1px solid var(--line); border-radius:50%; padding:0;
    background: rgba(7,8,10,.45); backdrop-filter: blur(6px);
    color: var(--muted); cursor:pointer;
    animation: fadeUp .8s cubic-bezier(.16,.7,.2,1) both; animation-delay:.4s;
    transition: border-color .3s ease, color .3s ease, background .3s ease;
  }
  .sound-toggle:hover{ border-color: var(--amber); color: var(--amber); }
  .sound-toggle.on{ border-color: var(--amber); color: var(--amber); background: rgba(7,8,10,.65); }
  .sound-toggle svg{ width:18px; height:18px; }
  .sound-toggle .icon-unmute{ display:none; }
  .sound-toggle.on .icon-mute{ display:none; }
  .sound-toggle.on .icon-unmute{ display:block; }
  @media (max-width:800px){ .sound-toggle{ left:20px; bottom:20px; width:38px; height:38px; } }
  @keyframes heroImgIn{ from{ opacity:0; transform:scale(1.4); } to{ opacity:1; transform:scale(1.05); } }
  /* ongoing "Ken Burns" pan/zoom so the photo keeps visible motion, not just a one-shot entrance */
  @keyframes heroImgDrift{
    0%, 100%{ transform:scale(1.05) translate(0,0); }
    50%{ transform:scale(1.19) translate(-2.4%,-1.8%); }
  }

  /* transversal targeting lines — a quiet technical flourish over the open sky */
  .hero-geo{ position:absolute; inset:0; width:100%; height:100%; z-index:2; pointer-events:none; opacity:.6; }
  .geo-line{ stroke: var(--amber); stroke-width:1; vector-effect:non-scaling-stroke; stroke-dasharray:1; stroke-dashoffset:1; animation: geoDraw 1.7s cubic-bezier(.3,.7,.2,1) both; animation-delay:.5s; }
  .geo-line.l2{ stroke: var(--muted); animation-delay:.68s; }
  .geo-line.l3{ opacity:.6; animation-delay:.86s; }
  .geo-tick{ fill: var(--amber); opacity:0; animation: geoTick .5s ease both; animation-delay:2.1s; }
  @keyframes geoDraw{ to{ stroke-dashoffset:0; } }
  @keyframes geoTick{ to{ opacity:.9; } }

  .hero-content{ position:relative; z-index:3; padding: 90px 0 140px; width:100%; }
  .hero-eyebrow{
    font-family: var(--font-mono); font-size: 16px; color: var(--amber); letter-spacing: .24em; text-transform: uppercase;
    display:flex; align-items:center; gap:10px; margin-bottom: 26px;
    animation: fadeUp 1s cubic-bezier(.16,.7,.2,1) both; animation-delay:.3s;
  }
  .hero-eyebrow::before{ content:''; width: 30px; height:1px; background: var(--amber); display:inline-block; }
  .hero h2{
    font-family: var(--font-display); font-weight: 700; text-transform: uppercase;
    font-size: clamp(52px, 10vw, 140px); line-height: .92; letter-spacing: 0; margin: 0 0 26px; max-width: 920px;
    filter: drop-shadow(0 10px 34px rgba(0,0,0,.6));
    perspective: 900px;
  }
  .hero h2 .line{ white-space:nowrap; }
  .hero h2 .accent{
    background: linear-gradient(180deg, var(--amber) 0%, var(--amber-dim) 100%);
    -webkit-background-clip: text; background-clip: text; color: transparent;
  }
  /* per-letter reveal: each character flips in out of a blur (3D rotateY + collapsing
     letter-spacing + focus pull), staggered by JS via animation-delay (see splitLetters()
     in app.js) — ported from a CodePen "opening sequence" effect, adapted to settle and
     hold rather than fade back out. */
  .hero h2 .letter{
    display:inline-block; transform-style: preserve-3d;
    background: linear-gradient(180deg, var(--text) 0%, rgba(243,239,232,.72) 66%, rgba(243,239,232,.4) 100%);
    -webkit-background-clip: text; background-clip: text; color: transparent;
    animation: letterIn 1s cubic-bezier(.2,.6,.2,1) both;
  }
  .hero h2 .accent .letter{
    background: linear-gradient(180deg, var(--amber) 0%, var(--amber-dim) 100%);
    -webkit-background-clip: text; background-clip: text; color: transparent;
  }
  @keyframes letterIn{
    0%{ opacity:0; filter: blur(16px); transform: rotateY(-90deg) translateZ(0); letter-spacing:.5em; }
    55%{ opacity:1; filter: blur(0); transform: rotateY(0deg); letter-spacing:normal; }
    100%{ opacity:1; filter: blur(0); transform: rotateY(0deg); letter-spacing:normal; }
  }
  .hero-rule{
    width:160px; height:1px; background: linear-gradient(90deg, var(--amber), transparent); margin: 0 0 28px;
    transform-origin: left center; animation: lineIn .9s cubic-bezier(.16,.7,.2,1) both; animation-delay:2.4s;
  }
  @keyframes fadeUp{ from{ opacity:0; transform:translateY(52px); } to{ opacity:1; transform:translateY(0); } }
  @keyframes lineIn{ from{ opacity:0; transform:scaleX(0); } to{ opacity:1; transform:scaleX(1); } }

  /* ---------- HERO EXIT (title leaves the same way it arrived; the scroll
     cue takes over as the focal point) — triggered by adding .exit-phase to
     .hero once the mission clock passes T+10, see initLaunchCounter() in
     home.js. Reuses each letter's own per-letter animation-delay (already
     set inline by splitLetters() for the entrance) so the exit dissolves in
     the same staggered rhythm it appeared in. */
  .hero.exit-phase h2 .letter{ animation: letterOut .8s cubic-bezier(.2,.6,.2,1) both; }
  .hero.exit-phase .hero-rule{ animation: lineOut .6s ease both; }
  @keyframes letterOut{
    0%{ opacity:1; filter: blur(0); transform: rotateY(0deg) translateZ(0); letter-spacing:normal; }
    45%{ opacity:1; filter: blur(0); transform: rotateY(0deg); letter-spacing:normal; }
    100%{ opacity:0; filter: blur(16px); transform: rotateY(-90deg) translateZ(0); letter-spacing:.5em; }
  }
  @keyframes lineOut{ from{ opacity:1; transform:scaleX(1); } to{ opacity:0; transform:scaleX(0); } }

  /* Always absolutely positioned and horizontally centered (left:50% +
     translateX(-50%), in both the default and .cue-prominent states) so
     "top" is the one thing that ever changes between them — that's what
     makes the promotion below animate as a smooth rise instead of a jump.
     A position:static→absolute mode switch can't be transitioned at all in
     CSS (it just snaps), which is what made the earlier version jerky.
     The resting "top" value is computed in JS (positionScrollCue() in
     home.js) from .hero-rule's actual position, since the title's height is
     responsive and a hard-coded value can't track it — see there for why.
     PROMO_MS below (1.3s) must match the "top"/"padding"/"font-size"/"gap"
     transition durations and the bob/cuePulse animation-delays further
     down — kept as one constant in spirit even though CSS can't share a
     literal across rules, search for "1.3s" if it ever needs to change. */
  .scroll-cue{
    position:absolute; left:50%; transform:translateX(-50%); z-index:4;
    display:flex; flex-direction:column; align-items:center; gap:10px;
    width: fit-content;
    text-align:center; white-space:nowrap;
    font-family: var(--font-mono); font-size:16px; letter-spacing:.22em; text-transform:uppercase;
    color: var(--text); text-decoration:none;
    border:1px solid var(--line); padding:14px 22px; border-radius:26px;
    background: rgba(7,8,10,.45); backdrop-filter: blur(6px);
    opacity:0; animation: cueFade .8s ease both 2.4s, bob 2.6s ease-in-out infinite 3.2s;
    transition: top 1.3s cubic-bezier(.16,.7,.2,1), padding 1.3s cubic-bezier(.16,.7,.2,1),
                font-size 1.3s cubic-bezier(.16,.7,.2,1), gap 1.3s cubic-bezier(.16,.7,.2,1),
                border-color 1.3s ease, border-radius 1.3s ease,
                background 1.3s ease, box-shadow 1.3s ease;
  }
  .scroll-cue:hover{ border-color: var(--amber); color: var(--amber); }
  .scroll-cue svg{ width:12px; height:12px; transition: width 1.3s cubic-bezier(.16,.7,.2,1), height 1.3s cubic-bezier(.16,.7,.2,1); }
  @keyframes cueFade{ to{ opacity:1; } }
  @keyframes bob{ 0%,100%{ transform:translate(-50%,0); } 50%{ transform:translate(-50%,7px); } }

  /* Promoted only once the exit-phase text has actually finished dissolving
     (see the animationend chain in initLaunchCounter(), home.js) — not the
     instant exit-phase is added, so the cue doesn't compete with the text
     for attention while it's still on its way out. home.js computes the
     precise pixel "top" that centers the cue's actual rendered height (not
     just its top edge) in the middle of .hero and sets that inline before
     adding this class, so the rise transitions smoothly to a true center —
     the top:50% here is only a fallback in case that JS never runs. bob's
     animation-delay is pushed out to 1.3s (matching the transition above)
     so it doesn't restart mid-rise: bob's own keyframes drive "transform",
     which would otherwise silently override the position transition and
     read as a jump right as the cue starts moving. */
  .hero.cue-prominent .scroll-cue{
    top: 50%;
    padding: 66px 120px; font-size: 52px;
    gap: 30px; border-radius: 999px;
    border-color: var(--amber); background: rgba(7,8,10,.65);
    box-shadow: 0 0 70px rgba(255,176,0,.35);
    /* Replacing the animation shorthand drops cueFade, which is what was
       holding opacity:1 via fill-mode — restate it as a plain value so the
       cue doesn't revert to its pre-entrance opacity:0. */
    opacity: 1;
    animation: bob 2.6s ease-in-out infinite 1.3s, cuePulse 2.4s ease-in-out infinite 1.3s;
  }
  .hero.cue-prominent .scroll-cue svg{ width:45px; height:45px; }
  @keyframes cuePulse{
    0%,100%{ box-shadow: 0 0 30px rgba(255,176,0,.2); }
    50%{ box-shadow: 0 0 58px rgba(255,176,0,.5); }
  }

  /* ---------- REPLAY INTRO BUTTON ----------
     Lives in /explore's header nav (the intro page — now its own separate
     landing at / — has no reason to offer it). explore.html bakes
     .intro-skipped onto its <body>, which is what reveals it. Styled to
     match the nav's other pills — those are inline-styled in the
     template, so the values here mirror them. */
  .replay-intro{
    display:none; align-items:center; gap:7px;
    font:inherit; letter-spacing:inherit; text-transform:inherit;
    color: var(--amber); background:none; cursor:pointer;
    border:1px solid var(--line); padding:8px 12px; border-radius:3px;
  }
  .replay-intro svg{ width:13px; height:13px; }
  .replay-intro:hover{ border-color: var(--amber); }
  body.intro-skipped .replay-intro{ display:inline-flex; }

  /* ---------- WARP TRANSITION (/ → /explore) ----------
     Fired by warpToExplore() in home.js when "Scroll to Explore" is
     clicked: the entire hero — video, title, cue, HUD — punches in toward
     the viewer while overexposing and losing focus, and the shroud closes
     the last stretch to solid page-black; navigation happens just before
     the final frame so the handoff is black-to-black with /explore's
     blur-in entrance below. Scaling the whole section (rather than its
     pieces) sidesteps every per-element animation that owns transform or
     opacity inside the hero. */
  body.warp-out{ overflow:hidden; }
  body.warp-out .hero{
    animation: warpZoom 1.25s cubic-bezier(.6,0,.8,1) forwards;
    will-change: transform, filter;
  }
  /* The hero falls away into darkness (dim, not overexpose) — the scene
     has to go black early so the star streaks own the frame. Blur kept
     mild: the heavy 26px blur of a scaled playing video was the prime
     suspect in a renderer crash during testing, and the streaks carry the
     speed sensation now anyway. */
  @keyframes warpZoom{
    from{ transform:scale(1); filter:brightness(1) blur(0); }
    to{ transform:scale(1.4); filter:brightness(.22) blur(6px); }
  }
  body.warp-out .top{ opacity:0; transition:opacity .35s ease; }
  .warp-shroud{ position:fixed; inset:0; z-index:2000; background:var(--bg); opacity:0; pointer-events:none; }
  body.warp-out .warp-shroud{ animation: warpShroud 1.25s cubic-bezier(.6,0,.85,1) forwards; pointer-events:auto; }
  @keyframes warpShroud{
    0%{ opacity:0; }
    45%{ opacity:.55; }
    75%{ opacity:.95; }
    100%{ opacity:1; }
  }
  /* The hyperspace canvas (built by runStarWarp() in home.js): sits above
     the shroud so the streaks stay visible while the scene beneath goes
     black — on /explore it overlays the whole page while the arrival
     deceleration plays out, then removes itself. */
  .warp-stars{ position:fixed; inset:0; z-index:2100; pointer-events:none; }

  /* ---------- ARRIVAL (/explore after the warp) ----------
     explore.html's head script adds .arriving to <html> before first
     paint when the almanacWarp flag is set. The page opens black (html
     itself carries the page background — see the base html rule), then
     the whole body focuses in from an over-scaled blur, answering the
     intro's punch-out. End values are "none", not identity transforms:
     a held transform/filter would make <body> the containing block for
     position:fixed children (starfield, viewport frame) forever after. */
  html.arriving body{ animation: pageBlurIn 1.1s cubic-bezier(.16,.7,.3,1) .05s both; }
  @keyframes pageBlurIn{
    from{ opacity:0; filter:blur(22px); transform:scale(1.05); }
    to{ opacity:1; filter:none; transform:none; }
  }

  @media (max-width: 800px){
    .hero{ min-height: 88vh; margin-top:-86px; }
    .hero-content{ padding: 84px 0 110px; }
  }

  /* ---------- SLIDER-SECTION SHARED CHROME ----------
     Shared by every homepage section (Recently Logged, Search the Log,
     Upcoming Launches, Spaceflight News) — the eyebrow/title header row
     and the CTA button are common; the bodies differ per section. */
  .slider-section{ padding: 48px 0 64px; }
  .slider-head{ display:flex; justify-content:space-between; align-items:flex-end; gap:20px; flex-wrap:wrap; margin-bottom: 44px; }
  .slider-title{ font-family: var(--font-display); font-weight:700; text-transform:uppercase; font-size: clamp(37px,4.5vw,58px); margin:0; line-height:1; }
  .slider-nav{ display:flex; align-items:center; gap:14px; }
  .slider-counter{ font-family: var(--font-mono); font-size:17px; color: var(--muted-dim); font-variant-numeric: tabular-nums; letter-spacing:.04em; }
  .slider-arrow{
    width:44px; height:44px; border-radius:50%; flex-shrink:0;
    border:1px solid var(--line); background: var(--panel); color: var(--muted);
    cursor:pointer; display:flex; align-items:center; justify-content:center;
    transition: border-color .15s, color .15s;
  }
  .slider-arrow:hover{ border-color: var(--amber); color: var(--amber); }
  .slider-arrow svg{ width:18px; height:18px; }

  /* ---------- RECENTLY LOGGED GRID ----------
     A plain editorial grid (photo, title, blurb, byline) rather than a
     carousel — six fixed cards need no navigation chrome at all, so unlike
     the timeline below there's no .slider-nav here. */
  .mission-grid{ display:grid; grid-template-columns: repeat(3, 1fr); gap:52px 32px; }
  .mission-card{ display:block; text-decoration:none; color:inherit; }
  .mission-card-photo{
    display:block; position:relative; aspect-ratio:16/10; border-radius:10px; overflow:hidden; margin-bottom:20px;
    background: radial-gradient(circle at 50% 38%, var(--panel-alt), var(--bg));
  }
  /* Hover dossier strip: category + status fade in over the photo's lower
     edge (mission cards only — launch cards have no status to show).
     Status colors reuse the .status-* classes the old poster grid used. */
  .mission-card-hover{
    position:absolute; left:0; right:0; bottom:0; z-index:2;
    display:flex; flex-direction:column; align-items:flex-start; gap:3px;
    padding: 36px 14px 12px;
    background: linear-gradient(180deg, transparent, rgba(5,6,7,.9));
    font-family: var(--font-mono); font-size:16px; text-transform:uppercase; letter-spacing:.06em;
    text-shadow: 0 1px 6px rgba(0,0,0,.7);
    opacity:0; transform: translateY(6px);
    transition: opacity .25s ease, transform .25s ease;
    pointer-events:none;
  }
  .mission-card:hover .mission-card-hover{ opacity:1; transform:none; }
  .mission-card-hover-cat{ color: var(--amber); }
  .mission-card-photo img{ width:100%; height:100%; object-fit:cover; display:block; filter: saturate(.9) brightness(.88); transition: transform .5s ease; }
  .mission-card:hover .mission-card-photo img{ transform: scale(1.05); }
  .mission-card.no-photo .mission-card-photo{ display:flex; align-items:center; justify-content:center; }
  .mission-card.no-photo .mission-card-photo img{ width:36%; height:36%; object-fit:contain; filter:none; border-radius:50%; transform:none; }
  .mission-card-title{
    display:block; font-family: var(--font-display); font-weight:700; font-size:25px;
    text-transform:uppercase; line-height:1.25; margin-bottom:8px; transition: color .15s ease;
  }
  .mission-card:hover .mission-card-title{ color: var(--amber); }
  .mission-card-desc{
    display:-webkit-box; -webkit-box-orient:vertical; -webkit-line-clamp:3; overflow:hidden;
    font-size:19px; color: var(--muted); line-height:1.6; margin-bottom:14px;
  }
  .mission-card-byline{ display:block; font-family: var(--font-mono); font-size:16px; color: var(--muted-dim); text-transform:uppercase; letter-spacing:.04em; }
  /* Live T-minus readout on Upcoming Launches cards (filled in by
     updateLaunchCardTimers in home.js) — phosphor + LED dot is the site's
     established "live data" signal (see .clock, .db-banner, .log-status). */
  .mission-card-timer{
    display:block; margin-top:8px;
    font-family: var(--font-mono); font-size:16px; letter-spacing:.06em; text-transform:uppercase;
    color: var(--phosphor); font-variant-numeric: tabular-nums;
  }
  .mission-card-timer::before{
    content:''; display:inline-block; width:7px; height:7px; border-radius:50%;
    background: var(--phosphor); box-shadow:0 0 6px var(--phosphor); margin-right:8px;
  }

  @media (max-width: 900px){
    .mission-grid{ grid-template-columns: repeat(2, 1fr); }
  }
  @media (max-width: 560px){
    .mission-grid{ grid-template-columns: 1fr; gap:36px; }
  }

  /* ---------- SEARCH THE LOG (its own section on /explore) ----------
     The filter console reuses /missions' console classes (.console-row,
     .search-field, .chip, select.era) so the two read identically; only the
     status readout and the decade-grouped result rows are new. Fonts match
     the established scale: 19px Oswald titles (.mission-card-title), 11px
     mono metadata (.mission-card-byline). Populated with the full log by
     default — filtering narrows it rather than revealing it. */
  #logSearchSection [hidden]{ display:none !important; }
  .log-status{
    display:flex; align-items:center; gap:10px;
    font-family: var(--font-mono); font-size:16px; letter-spacing:.05em; text-transform:uppercase;
    color: var(--phosphor);
    border-top:1px dashed var(--line-soft); border-bottom:1px dashed var(--line-soft);
    padding:10px 2px; margin-top:18px;
  }
  .log-status .led{ width:7px; height:7px; border-radius:50%; background: var(--phosphor); box-shadow:0 0 6px var(--phosphor); flex-shrink:0; }
  .log-status button{
    margin-left:auto; background:none; border:none; cursor:pointer; flex-shrink:0;
    font:inherit; letter-spacing:inherit; text-transform:inherit; color: var(--muted-dim);
  }
  .log-status button:hover{ color: var(--red); }
  .log-results{ margin-top:18px; }
  .log-decade{ font-family: var(--font-mono); font-size:16px; color: var(--muted-dim); letter-spacing:.14em; text-transform:uppercase; margin:20px 0 10px; }
  .log-decade:first-child{ margin-top:0; }
  .log-row{
    display:flex; align-items:center; gap:14px;
    padding:10px 12px; border:1px solid var(--line-soft); border-radius:8px;
    margin-bottom:6px; background: var(--panel);
    text-decoration:none; color:inherit; transition: border-color .15s;
  }
  .log-row:hover{ border-color: var(--amber); }
  .log-row-thumb{ width:44px; height:44px; border-radius:6px; overflow:hidden; background: var(--panel-alt); flex-shrink:0; display:flex; align-items:center; justify-content:center; }
  .log-row-thumb img{ width:100%; height:100%; object-fit:cover; display:block; }
  .log-row-name{ font-family: var(--font-display); font-weight:700; font-size:25px; text-transform:uppercase; line-height:1.25; transition: color .15s ease; }
  .log-row:hover .log-row-name{ color: var(--amber); }
  .log-row-meta{ font-family: var(--font-mono); font-size:16px; color: var(--muted); text-transform:uppercase; letter-spacing:.04em; }
  .log-row-why{ margin-left:auto; font-family: var(--font-mono); font-size:16px; color: var(--muted-dim); text-transform:uppercase; letter-spacing:.04em; text-align:right; flex-shrink:0; }
  .log-row-name b, .log-row-why b{ color: var(--amber); font-weight:inherit; }
  .log-empty{ font-family: var(--font-mono); font-size:16px; color: var(--muted); text-transform:uppercase; letter-spacing:.05em; padding:16px 2px; }
  /* Live-tracking position maps (trackmaps.js) — used on mission pages of
     live-tracked spacecraft; /live styles its own copy of this class. */
  .minimap{ border:1px solid var(--line); border-radius:8px; background:#0b0e14; overflow:hidden; }
  .minimap svg{ display:block; width:100%; height:auto; }
  .log-more{
    display:block; text-align:center; margin-top:8px;
    font-family: var(--font-mono); font-size:16px; color: var(--muted); text-transform:uppercase; letter-spacing:.05em;
    border:1px solid var(--line); border-radius:8px; padding:10px;
    text-decoration:none; transition: border-color .15s, color .15s;
  }
  .log-more:hover{ border-color: var(--amber); color: var(--amber); }
  @media (max-width: 700px){
    .log-row{ flex-wrap:wrap; }
    .log-row-why{ margin-left:58px; width:100%; text-align:left; }
  }

  /* ---------- LAUNCH MANIFEST TIMELINE (horizontal, free-scrolling) ----------
     Launches read better as a chronological left-to-right sequence (soonest
     first — see news.py) than as a single focal 3D slide, so this is a plain
     scrolling row rather than a coverflow: a dot per launch sits on a running
     axis line. Cards alternate above/below that line (odd items below with
     the date above, even items flipped) for a bit of rhythm instead of one
     flat row — see the .timeline-item/.timeline-node/.timeline-date/
     .timeline-card block further down for how that split works. The 28px
     below (item gap) has to stay in sync with the "calc(100% + 28px)" on
     .timeline-item::after, which draws each dot-to-dot connector segment —
     see the comment there. */
  /* Cards fade as whole units, not as a gradient painted at a fixed spot on
     the page: home.js's updateCardFade() computes one flat opacity per
     .timeline-item, based on how close that card's center is to the
     nearest edge of the visible strip, and applies it as a plain
     style.opacity. A pixel gradient overlay (an earlier approach here) was
     a genuinely different visual animal — it washed out part of whichever
     card happened to be sitting at the edge, rather than dimming a card as
     a unit, no matter how wide the gradient got. --margin here only sizes
     the empty edge spacer below; it no longer drives any fade rendering.
     Reuses --wide-inset (see :root) rather than a fixed length, so this
     full-bleed track's own edge lines up with the .wrap-wide header above
     it (Recently Logged's grid, Upcoming Launches' own title) at any
     viewport width, not just the one they happened to be measured at. */
  .timeline-wrap{ position:relative; --margin: var(--wide-inset); }
  .timeline-track{
    display:flex; gap:28px; overflow-x:auto; scroll-behavior:smooth;
    padding: 20px 0; cursor:grab; touch-action: pan-y;
    -ms-overflow-style:none; scrollbar-width:none;
  }
  .timeline-track::-webkit-scrollbar{ display:none; }
  /* Real 4cm edge margin at rest, matching --margin. Plain padding on
     .timeline-track would do the exact same job today — it only has to be
     a separate flex item because of scroll-snap's old jump-to-target
     behavior, which no longer applies now that snapping is gone (see the
     .timeline-track comment below) — left as its own element anyway since
     nothing depends on it being padding instead. */
  .timeline-spacer{ flex:0 0 var(--margin); }
  /* No scroll-snap here on purpose — deliberately different from the
     coverflow above, whose custom transform-based active-index logic
     always settles on a clean whole-slide position. Snapping this track to
     each card's edge did something coverflow never does: it forced every
     rest position to align a card flush with the visible edge, which
     always computed to either full opacity (comfortably inside) or zero
     (still inside the empty margin) — never the partial fade in between.
     Confirmed by watching a card visibly "pop" between the two rather than
     settling mid-fade. A plain free-scrolling strip can rest at any
     offset, including ones that leave a card partway through the fade —
     matching how the coverflow always shows a range of opacity levels at
     rest, just via a different mechanism (its own rounding-to-nearest-slide
     vs no rounding at all here). */
  .timeline-track.dragging{ cursor:grabbing; scroll-behavior:auto; user-select:none; -webkit-user-select:none; }
  .timeline-track.dragging .timeline-card{ pointer-events:none; }
  /* Tall enough to hold a full card on *either* side of the axis, since
     which side gets the card alternates per item (see below) and the axis
     has to sit at the same relative height for every item to draw a
     straight line. 380px half-height comfortably clears the tallest real
     card measured on this page (364px, including its 22px gap off the
     axis) with room to spare for longer mission names in future launches;
     760px total, axis dead center at top:50%. */
  .timeline-item{ position:relative; flex:0 0 360px; height:760px; }
  /* One segment per item, reaching from this item's dot to the next item's —
     i.e. its own half-width, plus the flex gap, plus the next item's
     half-width, which is exactly "100% + gap" starting from left:50%. Skipped
     on the last real item (marked .is-last by home.js) — :not(:last-child)
     would've been the obvious selector, but the trailing .timeline-spacer is
     now the actual last child, so every real item would otherwise match. */
  .timeline-item:not(.is-last)::after{
    content:''; position:absolute; top:50%; left:50%; width:calc(100% + 28px); height:1px;
    background: var(--line); z-index:0;
  }
  .timeline-node{
    position:absolute; top:50%; left:50%; transform:translate(-50%,-50%); z-index:2;
    width:11px; height:11px; border-radius:50%;
    background: var(--bg); border:2px solid var(--amber); box-shadow: 0 0 0 5px var(--bg);
  }
  /* Default (even .timeline-item — 1st, 3rd, ... in the real list): date
     sits above the axis, card hangs below it — anchored with "bottom" off
     the axis line (50% + a 12px gap) so its own height grows upward, away
     from the dot, rather than needing its height known in advance. */
  .timeline-date{
    position:absolute; left:50%; bottom:calc(50% + 12px); transform:translateX(-50%); z-index:2;
    display:block; white-space:nowrap;
    font-family: var(--font-mono); font-size:16px; letter-spacing:.1em; text-transform:uppercase; color: var(--amber);
  }
  .timeline-card{
    position:absolute; left:0; right:0; top:calc(50% + 22px);
    text-decoration:none; color:inherit;
    background: var(--panel-alt); border:1px solid var(--line); border-radius:12px; overflow:hidden;
    transition: border-color .2s ease, transform .2s ease;
  }
  .timeline-card:hover{ border-color: var(--amber); transform: translateY(-3px); }
  /* Odd .timeline-item (2nd, 4th, ... — :nth-child(odd) lands on these
     because the leading .timeline-spacer occupies child position 1, so the
     first real item is already child 2): flips both anchors, card above
     the axis and date below it, for a bit of visual rhythm instead of one
     flat row. */
  .timeline-item:nth-child(odd) .timeline-date{ bottom:auto; top:calc(50% + 12px); }
  .timeline-item:nth-child(odd) .timeline-card{ top:auto; bottom:calc(50% + 22px); }
  /* display:block is load-bearing, not tidying — .timeline-photo is a
     <span>, and inline elements ignore aspect-ratio/width/height entirely.
     Without this the box had no size of its own until its (often lazy-
     loaded) <img> finished loading, at which point height:100% resolved
     against an indefinite containing block and fell back to the image's
     own natural ratio instead of the intended 16/10 crop — confirmed by
     measuring real card heights on the page: 0px pre-load, then anywhere
     from 309-379px post-load depending on each photo's native aspect
     ratio. Cards need a reliably constant height for the alternating
     above/below layout below to line up cleanly. */
  .timeline-photo{ display:block; aspect-ratio: 16/10; background: radial-gradient(circle at 50% 38%, var(--panel-alt), var(--bg)); }
  .timeline-photo img{ width:100%; height:100%; object-fit:cover; display:block; filter: saturate(.88) brightness(.85); }
  .timeline-body{ display:block; padding: 16px 18px 18px; }
  .timeline-vehicle{ display:block; font-family: var(--font-display); font-weight:700; font-size:23px; text-transform:uppercase; line-height:1.25; }
  .timeline-mission{ display:block; font-family: var(--font-mono); font-size:17px; color: var(--muted); line-height:1.45; margin-top:4px; }
  .timeline-provider{
    display:block; font-family: var(--font-mono); font-size:16px; color: var(--muted-dim);
    text-transform:uppercase; letter-spacing:.04em; margin-top:12px; padding-top:10px; border-top:1px solid var(--line);
  }

  @media (max-width: 700px){
    /* --wide-inset's ~28px reads fine at desktop card widths (360px) but on
       a 285px mobile card it eats a big chunk of the screen — scaled down
       here to leave a card mostly visible; MOBILE_FADE_PX in home.js's
       updateCardFade() mirrors this breakpoint for the fade distance
       itself. Alignment with the header above isn't a concern at this
       width anyway, since .wrap-wide's own max-width has long since
       stopped mattering by 700px. */
    .timeline-wrap{ --margin: 8px; }
    .timeline-track{ gap:16px; padding: 20px 0; }
    /* Same reasoning as the desktop 760px above, just resized for the
       narrower 285px card (178px photo instead of 225px) — see there. */
    .timeline-item{ flex-basis: 285px; height:700px; }
    .timeline-item:not(.is-last)::after{ width: calc(100% + 16px); }
    .timeline-vehicle{ font-size:21px; }
    .timeline-mission{ font-size:16px; }
  }

  /* ---------- VERTICAL LAUNCH TIMELINE (/launches) ----------
     The full-manifest page's counterpart to the homepage's horizontal
     timeline: same axis-line/node/date/card language rotated 90° — a
     center line running down the page, cards alternating left/right of
     it, each date on the opposite side at the same height. Reuses the
     .timeline-card family (photo/vehicle/mission/provider) wholesale so
     the two timelines stay visually identical; only the card's base
     position:absolute anchoring (which only makes sense inside the
     horizontal track's fixed-height items) gets overridden here. */
  .vtimeline{ position:relative; max-width:1100px; margin:0 auto; }
  .vtimeline::before{
    content:''; position:absolute; top:6px; bottom:6px; left:50%; width:1px;
    background: var(--line);
  }
  .vtimeline-item{
    position:relative; display:grid; grid-template-columns:1fr 1fr; column-gap:56px;
    padding-bottom:48px;
  }
  .vtimeline-item:last-child{ padding-bottom:0; }
  .vtimeline-node{
    position:absolute; left:50%; top:22px; transform:translate(-50%,-50%); z-index:2;
    width:11px; height:11px; border-radius:50%;
    background: var(--bg); border:2px solid var(--amber); box-shadow: 0 0 0 5px var(--bg);
  }
  .vtimeline-item .timeline-card{
    position:static; grid-column:1; grid-row:1; justify-self:end;
    width:100%; max-width:420px;
  }
  .vtimeline-date{
    grid-column:2; grid-row:1; align-self:start; justify-self:start; padding-top:14px;
    font-family: var(--font-mono); font-size:16px; letter-spacing:.1em;
    text-transform:uppercase; color: var(--amber); white-space:nowrap;
  }
  /* Every other row mirrors: card right of the line, date left of it. */
  .vtimeline-item.flip .timeline-card{ grid-column:2; justify-self:start; }
  .vtimeline-item.flip .vtimeline-date{ grid-column:1; justify-self:end; }
  @media (max-width: 700px){
    /* Single column: the axis moves to the left edge, every card sits to
       its right with its date directly above it — alternating sides has
       no room to mean anything at this width. Flex (not block) because the
       date comes AFTER the card in source order; order:-1 is what actually
       lifts it above the card. */
    .vtimeline::before{ left:16px; }
    .vtimeline-item, .vtimeline-item.flip{ display:flex; flex-direction:column; padding-left:44px; padding-bottom:36px; }
    .vtimeline-node{ left:16px; top:8px; }
    .vtimeline-date, .vtimeline-item.flip .vtimeline-date{ order:-1; padding-top:0; margin-bottom:10px; }
    .vtimeline-item .timeline-card, .vtimeline-item.flip .timeline-card{ max-width:none; }
  }

  /* ---------- CONSOLE ---------- */
  .console{ padding: 24px 0 30px; border-bottom: 1px solid var(--line); position: sticky; top: 86px; z-index: 40; background: rgba(7,8,10,.92); backdrop-filter: blur(8px); }
  .console-row{ display:flex; gap: 16px; flex-wrap: wrap; align-items: center; }
  .search-field{ flex: 1 1 260px; display:flex; align-items:center; gap:10px; border: 1px solid var(--line); background: var(--panel); border-radius: 8px; padding: 11px 16px; }
  .search-field svg{ width:15px; height:15px; color: var(--muted-dim); flex-shrink:0; }
  .search-field input{ background: none; border: none; outline: none; color: var(--text); font-family: var(--font-mono); font-size: 19px; width: 100%; }
  .search-field input::placeholder{ color: var(--muted-dim); }
  .chip-group{ display:flex; gap:8px; flex-wrap: wrap; }
  .chip{ font-family: var(--font-mono); font-size: 16px; text-transform: uppercase; letter-spacing: .05em; padding: 10px 16px; border: 1px solid var(--line); background: var(--panel); color: var(--muted); border-radius: 8px; cursor: pointer; transition: border-color .15s, color .15s, background .15s; display:flex; align-items:center; gap:7px; }
  .chip:hover{ border-color: var(--amber-dim); color: var(--text); }
  .chip.active{ border-color: var(--amber); color: var(--amber); background: rgba(255,176,0,.06); }
  .chip .dot{ width:6px; height:6px; border-radius:50%; background: currentColor; }
  /* "Live Tracked" is an independent toggle, not one of the category
     radio-chips — phosphor-themed so it reads as live status */
  .chip.chip-live:hover{ border-color: var(--phosphor); color: var(--text); }
  .chip.chip-live.active{ border-color: var(--phosphor); color: var(--phosphor); background: rgba(87,227,156,.07); }
  .chip.chip-live.active .dot{ box-shadow: 0 0 6px var(--phosphor); }
  .live-badge{
    position:absolute; top:10px; left:10px; z-index:2;
    font-family: var(--font-mono); font-size:12px; letter-spacing:.08em; text-transform:uppercase;
    color: var(--phosphor); background: rgba(7,8,10,.72); border:1px solid rgba(87,227,156,.35);
    border-radius:999px; padding:3px 10px; text-shadow:0 0 8px rgba(87,227,156,.5);
  }
  /* live odometer chip — distance travelled since launch, ticking (app.js) */
  .live-dist{
    position:absolute; top:10px; right:10px; z-index:2;
    font-family: var(--font-mono); font-size:14px; letter-spacing:.04em;
    color: var(--phosphor); background: rgba(7,8,10,.78); border:1px solid rgba(87,227,156,.35);
    border-radius:999px; padding:3px 10px; font-variant-numeric: tabular-nums;
  }
  select.era{ font-family: var(--font-mono); font-size: 16px; text-transform: uppercase; letter-spacing: .05em; background: var(--panel); border: 1px solid var(--line); color: var(--muted); padding: 10px 14px; border-radius: 8px; cursor:pointer; }
  .result-count{ font-family: var(--font-mono); font-size: 16px; color: var(--muted-dim); margin-top: 14px; letter-spacing: .04em; }
  .result-count b{ color: var(--amber); }

  /* ---------- GRID — photographic poster tiles ---------- */
  main.wrap{ padding: 76px 28px 90px; }
  .grid{ display:grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 20px; }
  .card{
    position:relative; display:block; aspect-ratio: 3/4; border-radius: 10px; overflow:hidden;
    border: 1px solid var(--line); background: var(--panel-alt);
    text-align:left; text-decoration:none; color:inherit;
    transition: transform .25s ease, border-color .25s ease;
  }
  .card:hover, .card:focus-visible{ transform: translateY(-5px); border-color: var(--amber-dim); outline: none; }
  .card-photo{ position:absolute; inset:0; }
  .card-photo img{ width:100%; height:100%; object-fit:cover; display:block; filter: saturate(.88) brightness(.82); transition: transform .6s ease, filter .6s ease; }
  .card:hover .card-photo img{ transform: scale(1.07); filter: saturate(1) brightness(.72); }
  .card-scrim{
    position:absolute; inset:0;
    background: linear-gradient(180deg, rgba(7,8,10,.05) 0%, rgba(7,8,10,.1) 34%, rgba(7,8,10,.86) 82%, rgba(7,8,10,.96) 100%);
  }
  .card-stamp{ position:absolute; top:16px; left:16px; z-index:2; width:44px; height:44px; }
  .card-meta{ position:absolute; top:16px; right:16px; z-index:2; font-family: var(--font-mono); font-size: 16px; color: var(--text); text-transform: uppercase; letter-spacing:.06em; text-align:right; text-shadow:0 1px 6px rgba(0,0,0,.7); }
  .card-meta .status{ display:block; margin-top:4px; }
  .status-complete{ color: var(--muted); }
  .status-active{ color: var(--phosphor); }
  .status-aborted{ color: var(--red); }
  .card-info{ position:absolute; left:0; right:0; bottom:0; z-index:2; padding: 18px 18px 16px; }
  .card-name{ font-family: var(--font-display); font-size: 31px; font-weight:700; text-transform: uppercase; margin: 0 0 3px; letter-spacing: .005em; line-height:1.08; }
  .card-agency{ font-family: var(--font-mono); font-size: 16px; color: var(--amber); letter-spacing:.04em; margin-bottom:9px; }
  .card-summary{ font-size: 18px; color: var(--muted); line-height:1.5; margin-bottom:12px;
    display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; overflow:hidden; }
  .card-foot{ display:flex; align-items:center; justify-content:space-between; border-top:1px solid rgba(255,255,255,.1); padding-top:12px; }
  .card-date{ font-family: var(--font-mono); font-size:16px; color: var(--muted-dim); text-transform:uppercase; letter-spacing:.05em; }
  .card-photo-fallback{ display:flex; align-items:center; justify-content:center; background: radial-gradient(circle at 50% 38%, var(--panel-alt), var(--bg)); }
  .card.no-photo .card-scrim{ background: linear-gradient(180deg, rgba(7,8,10,0) 0%, rgba(7,8,10,.05) 40%, rgba(7,8,10,.9) 84%, rgba(7,8,10,.98) 100%); }
  .img-failed{ background: var(--panel-alt) !important; box-shadow:none !important; }
  .img-failed::before, .img-failed::after{ display:none; }
  .empty-state{ grid-column: 1/-1; text-align:center; padding: 70px 20px; color: var(--muted-dim); font-family: var(--font-mono); font-size: 19px; border: 1px dashed var(--line); border-radius: 8px; }
  .empty-state b{ display:block; color: var(--muted); font-family: var(--font-display); font-size:24px; text-transform:uppercase; margin-bottom:8px; letter-spacing:.05em;}

  /* ---------- MISSION LOGO / PATCH (shown as-is on a transparent ground) ---------- */
  .patch{
    position:relative; flex-shrink:0; background:transparent;
    display:flex; align-items:center; justify-content:center;
  }
  .patch img{ width:100%; height:100%; object-fit:contain; }
  .badge{ width: 54px; height:54px; }
  .badge.patch{ transition: transform .3s cubic-bezier(.2,.9,.3,1.4); filter: drop-shadow(0 4px 10px rgba(0,0,0,.5)); }
  .card:hover .card-stamp .badge.patch{ transform: rotate(-8deg) scale(1.1); }

  /* ---------- OVERLAY (record editor) ---------- */
  .overlay{ position: fixed; inset:0; background: rgba(4,5,6,.8); backdrop-filter: blur(3px); display:none; align-items:flex-start; justify-content:center; z-index: 100; padding: 40px 20px; overflow-y: auto; }
  .overlay.open{ display:flex; }
  .dossier{ background: var(--panel); border:1px solid var(--line); border-radius: 8px; max-width: 900px; width:100%; margin-bottom: 40px; position:relative; animation: rise .22s ease; }
  @keyframes rise{ from{ opacity:0; transform: translateY(14px); } to{ opacity:1; transform:none; } }
  .close-btn{ width:34px; height:34px; border-radius:50%; border:1px solid var(--line); background:none; color: var(--muted); cursor:pointer; flex-shrink:0; display:flex; align-items:center; justify-content:center; transition: border-color .15s, color .15s; }
  .close-btn:hover{ border-color: var(--amber); color: var(--amber); }

  /* ---------- FOOTER ---------- */
  footer{ border-top:1px solid var(--line); padding: 34px 0; }
  .footer-inner{ display:flex; justify-content:space-between; flex-wrap:wrap; gap:14px; font-family: var(--font-mono); font-size:16px; color: var(--muted-dim); letter-spacing:.03em;}

  ::-webkit-scrollbar{ width:10px; height:10px; }
  ::-webkit-scrollbar-track{ background: var(--bg); }
  ::-webkit-scrollbar-thumb{ background: var(--line); border-radius:5px; }
  ::-webkit-scrollbar-thumb:hover{ background: var(--amber-dim); }
  :focus-visible{ outline: 2px solid var(--amber); outline-offset:2px; }

  /* ---------- ADMIN / EDITOR ---------- */
  .btn{
    font-family: var(--font-mono); font-size:16px; text-transform:uppercase; letter-spacing:.06em;
    padding: 10px 16px; border-radius:8px; cursor:pointer; border:1px solid var(--line);
    background: var(--panel); color: var(--muted); transition: border-color .15s, color .15s, background .15s;
    display:inline-flex; align-items:center; gap:7px;
  }
  .btn:hover{ border-color: var(--amber); color: var(--amber); }
  .btn.primary{ border-color: var(--amber); color:#07080a; background: var(--amber); font-weight:600; }
  .btn.primary:hover{ background:#ffc23d; }
  .btn.danger{ border-color:#6b2a20; color: var(--red); }
  .btn.danger:hover{ border-color: var(--red); background: rgba(255,107,87,.08); }
  .btn.small{ padding:6px 12px; font-size:16px; }

  .db-banner{
    font-family: var(--font-mono); font-size:16px; letter-spacing:.04em; color: var(--muted-dim);
    display:flex; align-items:center; gap:8px; margin-top:10px;
  }
  .db-banner .led{ width:7px; height:7px; border-radius:50%; background: var(--phosphor); box-shadow:0 0 6px var(--phosphor); }
  .db-banner.offline .led{ background: var(--red); box-shadow:0 0 6px var(--red); }

  .editor{ padding: 0 0 10px; }
  .editor-head{ display:flex; justify-content:space-between; align-items:center; gap:16px; padding: 24px 30px; border-bottom:1px solid var(--line); background: linear-gradient(180deg, rgba(255,176,0,.05), transparent); }
  .editor-head h3{ font-family: var(--font-display); font-size:32px; text-transform:uppercase; margin:0; letter-spacing:.02em; }
  .editor-body{ padding: 22px 30px; display:grid; grid-template-columns: 1fr 1fr; gap: 16px 18px; }
  .editor-body .full{ grid-column: 1 / -1; }
  .field label{ display:block; font-family: var(--font-mono); font-size:16px; text-transform:uppercase; letter-spacing:.08em; color: var(--muted-dim); margin-bottom:6px; }
  .field input[type=text], .field select, .field textarea{
    width:100%; background: var(--panel-alt); border:1px solid var(--line); color: var(--text);
    font-family: var(--font-mono); font-size:18px; padding: 10px 12px; border-radius:6px; outline:none;
  }
  .field input:focus, .field select:focus, .field textarea:focus{ border-color: var(--amber); }
  .field textarea{ resize: vertical; min-height: 74px; line-height:1.55; }
  .field .hint{ font-size:16px; color: var(--muted-dim); font-family: var(--font-mono); margin-top:5px; line-height:1.5; }

  .gal-editor{ display:flex; flex-direction:column; gap:10px; }
  .gal-row{ display:grid; grid-template-columns: 64px 1fr 1fr auto; gap:10px; align-items:center;
    border:1px solid var(--line); border-radius:6px; padding:10px; background: var(--panel-alt); }
  .gal-thumb{ width:64px; height:48px; object-fit:cover; border-radius:4px; border:1px solid var(--line); background:#0c0e12; }
  .gal-row input[type=text]{ width:100%; background: var(--panel); border:1px solid var(--line); color: var(--text); font-family: var(--font-mono); font-size:17px; padding:8px 10px; border-radius:6px; outline:none; }
  .gal-row input[type=text]:focus{ border-color: var(--amber); }
  .gal-row .gal-btns{ display:flex; gap:6px; }
  .file-btn{ position:relative; overflow:hidden; }
  .file-btn input[type=file]{ position:absolute; inset:0; opacity:0; cursor:pointer; }
  .editor-foot{ display:flex; justify-content:space-between; align-items:center; gap:12px; padding: 18px 30px; border-top:1px solid var(--line); flex-wrap:wrap; }
  .editor-foot .right{ display:flex; gap:10px; }
  .editor-msg{ font-family: var(--font-mono); font-size:16px; color: var(--red); }
  @media (max-width: 700px){
    .editor-body{ grid-template-columns: 1fr; }
    .gal-row{ grid-template-columns: 64px 1fr; }
  }

  @media (max-width: 640px){
    .console{ position: static; }
  }
  @media (prefers-reduced-motion: reduce){
    *{ animation: none !important; transition: none !important; scroll-behavior:auto !important; }
    .card:hover{ transform:none; }
    .scroll-cue{ opacity:1; }
    .glitch-line::before, .glitch-line::after{ display:none; }
    /* The hero video crossfade is a plain opacity dissolve, not the kind of
       motion (parallax/spin/zoom) prefers-reduced-motion is meant to
       suppress — the blanket transition:none above would otherwise make it
       snap instantly regardless of the durations configured. Re-enable just
       these two, matching the values above (see #heroIntro/#heroLoop). */
    #heroIntro{ transition: opacity 3s ease-in-out !important; }
    #heroLoop{ transition: opacity 1.3s ease-in-out 2.1s !important; }
  }

/* ============================= LAUNCH DETAIL PAGE =============================
   Card-based layout for templates/launch.html — one bordered panel per
   topic (agency, mission, vehicle, core, site), echoing how the reference
   app (Space Launch Now) breaks a launch's info into separate cards rather
   than one long dossier page. */
.launch-card{
  background: var(--panel-alt); border:1px solid var(--line); border-radius:12px;
  padding: 22px 24px; margin-bottom:20px; overflow:hidden;
}
.launch-card-head{ display:flex; align-items:center; gap:16px; margin-bottom:16px; }
.launch-card-head img{ width:48px; height:48px; object-fit:contain; flex-shrink:0; border-radius:8px; background:var(--panel); }
.launch-card h3{
  margin:0; font-family: var(--font-display); font-size:19px; text-transform:uppercase;
  letter-spacing:.1em; color: var(--amber);
}
/* A handful of cards (Agency, Mission, Vehicle, Core) named themselves
   after a proper noun — "SpaceX", "Falcon 9 Block 5" — with the actual
   category (what KIND of card this is) as a small muted tag above it. Too
   subtle in practice: next to Launch Site/Latest Updates, whose h3 IS the
   category name in full amber prominence, that small gray tag read as if
   it wasn't there at all. Swapped instead of just resized: the category
   now uses the exact same h3 the other cards use (so it's unmistakably
   "the title" at a glance), and the proper noun moves to this subtitle
   line underneath — still prominent, just not competing for the same
   visual slot as the title. */
.launch-card-subtitle{
  margin:2px 0 0; font-family: var(--font-display); font-weight:700; font-size:23px;
  text-transform:uppercase; color: var(--text); line-height:1.2;
}
.launch-card-photo{ margin:-22px -24px 18px; }
.launch-card-photo img{ width:100%; display:block; max-height:280px; object-fit:cover; }
.launch-spec-grid{
  display:grid; grid-template-columns:repeat(auto-fit,minmax(130px,1fr)); gap:16px 24px;
  font-family: var(--font-mono); margin: 4px 0 16px;
}
.launch-spec-grid dt{ font-size:16px; color: var(--muted-dim); text-transform:uppercase; letter-spacing:.06em; margin-bottom:4px; }
.launch-spec-grid dd{ margin:0; font-size:20px; color: var(--text); font-weight:600; }
.launch-card-links{ display:flex; gap:20px; flex-wrap:wrap; font-family: var(--font-mono); font-size:17px; text-transform:uppercase; letter-spacing:.05em; }
.launch-card-links a{ color: var(--amber); text-decoration:none; display:inline-flex; align-items:center; gap:6px; }
.launch-card-links a:hover{ text-decoration:underline; }

/* Countdown — same tabular-numeral mono-space treatment as the homepage
   hero's own mission clock (see .lc-num in style.css), just bigger and
   with day/hour/min/sec broken into separate labeled cells instead of one
   T-plus/minus readout, since a specific future date benefits from the
   fuller breakdown a hero-strip countdown wouldn't have room for. */
.launch-countdown{ display:flex; gap: clamp(14px,3vw,32px); margin: 4px 0 18px; }
.launch-countdown div{ text-align:center; }
.launch-countdown b{
  display:block; font-family: var(--font-display); font-weight:700; font-variant-numeric:tabular-nums;
  font-size: clamp(35px,6vw,56px); color: var(--amber); line-height:1;
}
.launch-countdown span{
  display:block; margin-top:6px; font-family: var(--font-mono); font-size:16px; color: var(--muted-dim);
  text-transform:uppercase; letter-spacing:.08em;
}
.launch-status-pill{
  display:inline-block; font-family: var(--font-mono); font-size:16px; text-transform:uppercase; letter-spacing:.05em;
  padding:4px 12px; border-radius:999px; border:1px solid var(--phosphor); color: var(--phosphor);
}
.launch-map{ width:100%; height:300px; border:0; border-radius:10px; display:block; filter: saturate(.4) brightness(.85) invert(.92) hue-rotate(180deg) contrast(.92); }

/* Overview + Livestream sit side by side at the top instead of stacked —
   both are "read this first" content, and putting them in one row instead
   of two full-width blocks is most of what makes the page fit on one
   screen. Collapses to one column once there isn't room for both to be
   useful widths. When there's no video, launch.html adds .launch-span-full
   to the Overview card so it just takes the whole row instead of leaving
   an empty second column. */
.launch-top-row{ display:grid; grid-template-columns: 1.6fr 1fr; gap:20px; align-items:stretch; }
.launch-span-full{ grid-column: 1 / -1; }
@media (max-width:900px){ .launch-top-row{ grid-template-columns:1fr; } }

/* The overview card's own contents, side by side (photo | title+countdown)
   rather than stacked — the single biggest vertical-space saving on the
   page, since the countdown no longer waits below a full-width photo. */
.launch-hero{ display:flex; gap:20px; }
.launch-hero-photo{ flex:0 0 clamp(180px,22vw,260px); border-radius:10px; overflow:hidden; align-self:stretch; }
.launch-hero-photo img{ width:100%; height:100%; min-height:200px; object-fit:cover; display:block; }
.launch-hero-info{ flex:1; min-width:0; display:flex; flex-direction:column; justify-content:center; }
@media (max-width:560px){
  .launch-hero{ flex-direction:column; }
  .launch-hero-photo{ flex-basis:auto; height:160px; }
}

/* Everything below the top row (agency/mission/vehicle/core/site/etc.) is a
   CSS multi-column flow rather than a CSS Grid: these cards vary a lot in
   height (Vehicle's spec list + description dwarfs Core's), and a strict
   grid would leave large gaps under the shorter cards in the same row —
   multi-column lets each card just drop into whichever column has room
   next, like a masonry layout, with no JS needed. column-width (rather
   than a fixed column-count) is what makes the count itself responsive:
   the browser fits as many ~340px columns as the available width allows. */
.launch-columns{ columns: 340px 3; column-gap:20px; margin-bottom:20px; }
/* the tallest column's last card sits flush on the container edge (multicol
   truncates its bottom margin), so the container itself carries the same
   20px gap the cards use — keeps full-width tiles below from touching */
.launch-columns .launch-card{ break-inside:avoid; }

/* Mission page History. The card spans the full page width — flush with the
   info-card grid and the gallery below it — and the narrative flows in
   newspaper-style columns so it fills that width instead of leaving a void on
   the right. Column count is driven by width (min ~24em each, capped at 3), so
   it's 2–3 columns on a wide monitor and a single column on a phone. */
.mission-history-cols{ columns: 24em 3; column-gap:44px; }
.mission-history-cols p{
  color:var(--muted); line-height:1.75; font-size:20px;
  margin:0 0 1.1em; break-inside:avoid;
}
.mission-history-cols p:last-child{ margin-bottom:0; }
@media (max-width:640px){ .mission-history-cols{ columns:1; } }

@media (max-width:700px){
  .launch-card{ padding:18px; }
  .launch-card-photo{ margin:-18px -18px 16px; }
  .launch-countdown{ gap:14px; }
}

/* ============================= GALLERY (lightbox) =============================
   Simple CSS-only lightbox gallery, adapted from
   https://codefronts.com/try/?c=css-image-gallery&d=css-lightbox-gallery-overlay.
   No JavaScript: each thumbnail links to a #fragment matching a full-size
   overlay's id; :target reveals it, and its own back/✕ links point back to
   the grid's id (which matches nothing), closing it. The overlay markup is
   rendered outside <main> in the template (see mission.html) so it isn't
   trapped inside main's own stacking context (main.wrap sets its own
   position+z-index, which would otherwise cap how high a descendant's
   z-index could ever paint, regardless of the value used). */
.gallery__grid{
  display:grid; gap:14px; grid-template-columns:repeat(auto-fill, minmax(250px,1fr));
}
.gallery__thumb{
  display:block; position:relative; border-radius:10px; overflow:hidden;
  background: var(--panel-alt); border:1px solid var(--line);
}
/* admin-only marker on the current main image (gallery[0]) */
.gallery__main-badge{
  position:absolute; top:8px; left:8px; z-index:2;
  padding:3px 8px; border-radius:999px;
  font-family: var(--font-mono, 'IBM Plex Mono', monospace);
  font-size:11px; letter-spacing:.06em; text-transform:uppercase;
  color: var(--bg); background: var(--amber);
  box-shadow:0 4px 12px -4px rgba(0,0,0,.6);
}
.gallery__thumb img{
  display:block; width:100%; aspect-ratio:4/3; object-fit:cover;
  transform:scale(1); transition:transform .4s;
}
.gallery__thumb:hover img, .gallery__thumb:focus-visible img{ transform:scale(1.07); }
.gallery__thumb:focus-visible{ outline:3px solid var(--amber); outline-offset:2px; }

.gallery__lb{
  position:fixed; inset:0; z-index:500;
  display:flex; align-items:center; justify-content:center; padding:24px;
  opacity:0; visibility:hidden;
  transition:opacity .3s, visibility .3s;
}
.gallery__lb:target{ opacity:1; visibility:visible; }
.gallery__back{
  position:absolute; inset:0; background: rgba(7,8,10,.86);
  backdrop-filter:blur(3px); -webkit-backdrop-filter:blur(3px);
}
.gallery__panel{
  position:relative; max-width:min(1000px,92vw); max-height:86vh;
  transform:scale(.92); transition:transform .35s cubic-bezier(.2,.8,.2,1);
}
.gallery__lb:target .gallery__panel{ transform:scale(1); }
.gallery__panel img{
  display:block; max-width:100%; max-height:86vh; border-radius:8px;
  box-shadow:0 40px 80px -30px rgba(0,0,0,.8);
}
.gallery__x{
  position:absolute; top:-14px; right:-14px; width:40px; height:40px;
  border-radius:50%; display:flex; align-items:center; justify-content:center;
  text-decoration:none; background: var(--text); color: var(--bg);
  font-size:21px; font-weight:700; box-shadow:0 6px 16px -4px rgba(0,0,0,.5);
}
.gallery__x:hover{ background: var(--amber); }
.gallery__x:focus-visible{ outline:3px solid var(--amber); outline-offset:3px; }
.gallery__cap{
  margin-top:10px; max-width:min(1000px,92vw);
  font-family: var(--font-mono, 'IBM Plex Mono', monospace);
  color: var(--muted, #b8c0cc); text-align:left;
}
.gallery__cap-text{ display:block; font-size:14px; line-height:1.45; color: var(--text); }
.gallery__cap-meta{
  display:block; margin-top:4px; font-size:11px; letter-spacing:.04em;
  text-transform:uppercase; color: var(--muted-dim, #6b7686);
}
/* admin control inside the lightbox: promote this image to the main image */
.gallery__setmain{
  margin-top:12px; cursor:pointer;
  font-family: var(--font-mono, 'IBM Plex Mono', monospace);
  font-size:13px; letter-spacing:.05em; text-transform:uppercase;
  color: var(--amber); background:none;
  border:1px solid var(--amber); border-radius:4px; padding:8px 14px;
  transition:background .15s, color .15s;
}
.gallery__setmain:hover:not(:disabled){ background: var(--amber); color: var(--bg); }
.gallery__setmain:disabled{ opacity:.55; cursor:default; }
.gallery__main-flag{
  margin-top:12px; font-family: var(--font-mono, 'IBM Plex Mono', monospace);
  font-size:12px; letter-spacing:.05em; text-transform:uppercase;
  color: var(--amber);
}
/* the main-image and hero-image controls sit together in one row */
.gallery__admin{ margin-top:14px; display:flex; flex-wrap:wrap; gap:10px 14px; align-items:center; }
.gallery__admin>*{ margin-top:0; }
/* hero-image control mirrors the main-image control */
.gallery__sethero{
  cursor:pointer; font-family: var(--font-mono, 'IBM Plex Mono', monospace);
  font-size:13px; letter-spacing:.05em; text-transform:uppercase;
  color: var(--amber); background:none;
  border:1px solid var(--amber); border-radius:4px; padding:8px 14px;
  transition:background .15s, color .15s;
}
.gallery__sethero:hover:not(:disabled){ background: var(--amber); color: var(--bg); }
.gallery__sethero:disabled{ opacity:.55; cursor:default; }
.gallery__hero-flag{
  font-family: var(--font-mono, 'IBM Plex Mono', monospace);
  font-size:12px; letter-spacing:.05em; text-transform:uppercase; color: var(--amber);
}
/* article-photo control: pick up to two (first = right, second = left). */
.gallery__setarticle{
  cursor:pointer; font-family: var(--font-mono, 'IBM Plex Mono', monospace);
  font-size:13px; letter-spacing:.05em; text-transform:uppercase;
  color: var(--amber); background:none;
  border:1px solid var(--amber); border-radius:4px; padding:8px 14px;
  transition:background .15s, color .15s;
}
.gallery__setarticle:hover:not(:disabled){ background: var(--amber); color: var(--bg); }
.gallery__setarticle:disabled{ opacity:.45; cursor:not-allowed; }
/* selected: filled so it's obvious this photo is in the article, plus its slot */
.gallery__setarticle.is-on{ background: var(--amber); color: var(--bg); border-color: var(--amber); }

/* ===================== ON-PAGE EDITOR (Phase 1) ===================== */
/* Triggered by the header "✎ Edit page" button. Save bar shown while editing. */
.page-edit-bar{ position:fixed; left:0; right:0; bottom:0; z-index:60; display:flex; align-items:center;
  justify-content:space-between; gap:16px; background:rgba(10,12,14,.96); border-top:1px solid var(--amber-dim, #8a5f0f);
  padding:14px 30px; backdrop-filter:blur(6px); }
/* respect the `hidden` attribute — .page-edit-bar's display:flex would otherwise
   override the browser's [hidden]{display:none}, so the bar showed all the time */
.page-edit-bar[hidden]{ display:none; }

/* --- edit-mode "Mission settings" panel (category / status / flight profile / patch) --- */
.pe-settings{ display:none; }
.page-editing .pe-settings{ display:flex; flex-wrap:wrap; align-items:center; gap:14px 22px; margin-top:16px;
  padding:14px 16px; border:1px dashed var(--amber-dim); border-radius:8px; background:rgba(255,176,0,.04); }
.pe-set-title{ font-family:var(--font-mono); font-size:12px; letter-spacing:.1em; text-transform:uppercase; color:var(--amber); }
.pe-set-field{ display:inline-flex; align-items:center; gap:8px; font-family:var(--font-mono); font-size:11px;
  letter-spacing:.05em; text-transform:uppercase; color:var(--muted); }
.pe-set-field select{ font-family:var(--font-body); font-size:14px; text-transform:none; letter-spacing:0;
  color:var(--text); background:var(--panel); border:1px solid var(--line); border-radius:4px; padding:5px 8px; }
.pe-patch img{ width:34px; height:34px; object-fit:contain; border:1px solid var(--line); border-radius:4px; background:var(--panel); }
.pe-upl, .pe-patch button, .pe-gal-upload{ font-family:var(--font-mono); font-size:11px; letter-spacing:.05em;
  text-transform:uppercase; color:var(--amber); background:none; border:1px solid var(--amber-dim); border-radius:4px;
  padding:5px 10px; cursor:pointer; }
.pe-upl input, .pe-gal-upload input{ display:none; }

/* --- gallery: upload button + per-photo meta editing / delete (in the lightbox) --- */
.pe-gal-upload{ display:none; margin-top:14px; }
.page-editing .pe-gal-upload{ display:inline-block; }
.pe-gal-meta{ display:none; }
.page-editing .pe-gal-meta{ display:block; margin-top:12px; max-width:420px; }
.pe-gal-meta label{ display:flex; align-items:center; gap:10px; margin-bottom:6px; font-family:var(--font-mono);
  font-size:11px; letter-spacing:.05em; text-transform:uppercase; color:var(--muted-dim); }
.pe-gm{ flex:1; min-width:0; font-family:var(--font-body); font-size:14px; color:var(--text);
  border:1px solid var(--line); border-radius:4px; padding:4px 8px; min-height:1.5em; }
.pe-gm:focus{ outline:2px solid var(--amber); }
.pe-gal-del{ margin-top:6px; font-family:var(--font-mono); font-size:11px; letter-spacing:.05em; text-transform:uppercase;
  color:#ff9f8f; background:none; border:1px solid #5a2020; border-radius:4px; padding:6px 10px; cursor:pointer; }
.pe-gal-del:hover{ background:#5a2020; color:#fff; }
.peb-msg{ font-family:var(--font-mono); font-size:13px; letter-spacing:.04em; color:var(--amber);
  display:flex; align-items:center; gap:9px; }
.peb-dot{ width:8px; height:8px; border-radius:50%; background:var(--amber); flex-shrink:0; }
.peb-actions{ display:flex; gap:10px; }
.page-edit-bar button{ font-family:var(--font-mono); font-size:13px; letter-spacing:.05em; text-transform:uppercase;
  border-radius:5px; padding:9px 18px; cursor:pointer; }
.peb-cancel{ color:var(--muted); background:none; border:1px solid var(--line); }
.peb-save{ color:var(--bg); background:var(--amber); border:1px solid var(--amber); }
.peb-save:disabled{ opacity:.6; cursor:default; }
/* keep the fixed save bar clear of the last content */
.page-editing main.wrap{ padding-bottom:150px; }
/* editable affordances — only in edit mode. A persistent tint + dashed outline
   makes it obvious which text is editable; hover/focus intensify. (No transition
   here: transitioning outline-color/background left them stuck when edit mode
   toggled on, so the highlight never appeared.) */
.page-editing [contenteditable="true"]{ outline:1px dashed rgba(255,176,0,.65); outline-offset:3px;
  border-radius:3px; cursor:text; background:rgba(255,176,0,.08); }
.page-editing [contenteditable="true"]:hover{ outline-color:var(--amber); background:rgba(255,176,0,.14); }
.page-editing [contenteditable="true"]:focus{ outline:2px solid var(--amber); background:rgba(255,176,0,.18); }

/* --- Phase 2: place & size article photos in edit mode --- */
.page-editing .feat-band{ position:relative; outline:1px dashed rgba(255,176,0,.5); outline-offset:5px; }
.page-editing .feat-band:hover, .page-editing .feat-band.pe-sel{ outline:2px solid var(--amber); }
.feat-band.side-right .pe-resize{ right:auto; left:-7px; cursor:nesw-resize; }
/* per-photo toolbar (side / size / move / drag / remove) */
.pe-figbar{ position:absolute; top:-40px; left:0; z-index:14; display:flex; align-items:center; gap:2px;
  background:#1b1e20; border:1px solid var(--line); border-radius:8px; padding:4px;
  box-shadow:0 8px 24px rgba(0,0,0,.5); font-family:var(--font-mono); }
.pe-figbar button{ height:28px; min-width:30px; padding:0 7px; border:none; background:none; color:var(--text);
  border-radius:5px; cursor:pointer; font-size:12px; display:flex; align-items:center; justify-content:center; }
.pe-figbar button:hover{ background:#2a2d2f; }
.pe-figbar button.on{ background:var(--amber); color:var(--bg); }
.pe-figbar .sep{ width:1px; align-self:stretch; background:var(--line); margin:2px 3px; }
.pe-figbar .grip{ cursor:grab; }
.pe-figbar .rm:hover{ background:#5a2020; color:#ff9f8f; }
/* resize handle at the bottom-right corner (not for full-width photos) */
.pe-resize{ position:absolute; right:-7px; bottom:-7px; width:16px; height:16px; z-index:14; cursor:nwse-resize;
  background:var(--amber); border:2px solid var(--bg); border-radius:50%; }
.feat-band.side-full .pe-resize{ display:none; }
/* drop indicator shown between blocks while dragging a photo */
.pe-dropline{ height:0; border-top:3px solid var(--amber); margin:6px 0; box-shadow:0 0 10px var(--amber); }

/* --- adding blocks: insert bars between article blocks (+ paragraph / quote) --- */
.pe-ins{ position:relative; height:18px; display:flex; align-items:center; justify-content:center; clear:both; }
.pe-ins::before{ content:""; position:absolute; left:0; right:0; top:50%; height:1px; background:var(--amber-dim); opacity:0; transition:opacity .12s; }
.pe-ins:hover::before, .pe-ins.open::before{ opacity:.55; }
.pe-ins-plus{ position:relative; z-index:2; width:22px; height:22px; border-radius:50%; background:var(--bg);
  border:1px solid var(--amber); color:var(--amber); font-size:15px; line-height:1; cursor:pointer; opacity:.3;
  display:flex; align-items:center; justify-content:center; transition:opacity .12s; }
.pe-ins:hover .pe-ins-plus, .pe-ins.open .pe-ins-plus{ opacity:1; }
.pe-ins-menu{ display:none; position:absolute; top:26px; left:50%; transform:translateX(-50%); z-index:20; gap:4px;
  background:#1b1e20; border:1px solid var(--line); border-radius:9px; padding:6px; box-shadow:0 12px 30px rgba(0,0,0,.55); white-space:nowrap; }
.pe-ins.open .pe-ins-menu{ display:flex; }
.pe-ins-menu button{ font-family:var(--font-mono); font-size:12px; letter-spacing:.03em; text-transform:uppercase;
  color:var(--text); background:none; border:none; border-radius:6px; padding:8px 12px; cursor:pointer; }
.pe-ins-menu button:hover{ background:#26292b; color:var(--amber); }
/* placeholder text in a freshly-added empty paragraph (class-based, so the
   injected move toolbar doesn't stop :empty from matching) */
.page-editing .feat-body > p.pe-ph::before{ content:"New paragraph — type here…"; color:var(--muted-dim); }

/* --- move any article block up/down: a small toolbar in the left margin --- */
.page-editing .feat-body > p, .page-editing .feat-pull{ position:relative; }
.pe-movebar{ position:absolute; top:-2px; left:-42px; z-index:13; display:flex; flex-direction:column; gap:2px;
  opacity:0; transition:opacity .12s; }
.page-editing .feat-body > p:hover > .pe-movebar, .page-editing .feat-pull:hover > .pe-movebar,
.pe-movebar:hover{ opacity:1; }
.pe-movebar button{ width:26px; height:20px; border:1px solid var(--line); background:#1b1e20; color:var(--amber);
  border-radius:5px; font-size:12px; line-height:1; padding:0; cursor:pointer; display:flex; align-items:center; justify-content:center; }
.pe-movebar button:hover{ background:var(--amber); color:var(--bg); }
.pe-movebar .pe-rm:hover{ background:#5a2020; color:#ff9f8f; }

/* --- rail list add / move / remove (crew, objectives, achievements) --- */
.pe-add{ margin-top:12px; font-family:var(--font-mono); font-size:12px; letter-spacing:.05em; text-transform:uppercase;
  color:var(--amber); background:none; border:1px dashed var(--amber-dim); border-radius:5px; padding:7px 12px; cursor:pointer; }
.pe-add:hover{ border-color:var(--amber); }
.rail-crew li, .rail-list li{ position:relative; }
/* controls sit in the left gutter beside the rail so they never cover the text */
.pe-itemctl{ position:absolute; left:-64px; top:0; display:inline-flex; gap:3px; }
.pe-itemctl button{ width:19px; height:19px; border-radius:5px; border:1px solid var(--line); background:#1b1e20;
  color:var(--muted); font-size:11px; line-height:1; padding:0; cursor:pointer; }
.pe-itemctl button:hover{ background:#2a2d2f; color:var(--amber); }
.pe-itemctl .pe-del:hover{ background:#5a2020; color:#ff9f8f; border-color:#5a2020; }

/* ---- ISS live video beside the tracking map ---- */
/* Single maps (deep-space / Mars / non-ISS ground track) stay capped; the ISS
   split spreads across the whole section. */
#liveTrackMap{ max-width:1280px; }
#liveTrackMap.livetrack-split{ max-width:none; }
.livetrack-split{
  display:grid; grid-template-columns:minmax(0,1fr) minmax(0,1fr);
  gap:20px; align-items:start;
}
@media (max-width:860px){ .livetrack-split{ grid-template-columns:1fr; } }
/* Map and video share an identical frame so the two sit perfectly symmetrical;
   the 2:1 world map is centred within it. A 3:2 frame gives extra height. */
.iss-video-frame,
.livetrack-split .minimap{
  position:relative; width:100%; aspect-ratio:3/2; margin:0;
  border-radius:8px; overflow:hidden; background:#0b0e14;
  display:flex; align-items:center; justify-content:center;
}
.iss-video-frame iframe{ position:absolute; inset:0; width:100%; height:100%; border:0; }
.livetrack-split .minimap svg{ width:100%; height:auto; max-height:100%; display:block; }
.iss-video-note{
  font-family:var(--font-mono, 'IBM Plex Mono', monospace); font-size:12px;
  color:#5e5850; text-transform:uppercase; letter-spacing:.05em; margin:6px 0 0;
}

/* ---- Mission archive pagination ---- */
.pagination{
  display:flex; flex-wrap:wrap; justify-content:center; align-items:center;
  gap:6px; margin-top:48px;
}
.pagination:empty{ display:none; }
.page-btn{
  font-family: var(--font-mono, 'IBM Plex Mono', monospace);
  font-size:14px; min-width:40px; padding:9px 13px;
  color: var(--muted, #b8c0cc); background: var(--panel-alt, #12151c);
  border:1px solid var(--line, #262b36); border-radius:4px; cursor:pointer;
  transition: color .15s, border-color .15s, background .15s;
}
.page-btn:hover:not(:disabled):not(.active){ color: var(--text); border-color: var(--amber); }
.page-btn.active{
  color: var(--bg, #0b0e14); background: var(--amber);
  border-color: var(--amber); font-weight:600; cursor:default;
}
.page-btn:disabled{ opacity:.35; cursor:not-allowed; }
.page-btn:focus-visible{ outline:2px solid var(--amber); outline-offset:2px; }
.page-ellipsis{
  color: var(--muted-dim, #6b7686); padding:0 4px; user-select:none;
  font-family: var(--font-mono, 'IBM Plex Mono', monospace);
}

@media (max-width:560px){
  .gallery__grid{ grid-template-columns:repeat(2,1fr); }
}
@media (prefers-reduced-motion:reduce){
  .gallery__thumb img, .gallery__lb, .gallery__panel{ transition:none; }
}

/* ===================== MISSION FEATURE (magazine layout) =====================
   The mission body reads as a magazine feature: the History is the article
   (serif, justified, drop cap) with photos woven in as a lead image and inline
   bands, and a data rail alongside. Header/breadcrumb above stay unchanged. */
/* The mission page sits in a ~1500px measure: wide, but narrow enough that the
   single-column article and single-column data rail read well side by side with
   a clear gap. Header, hero, byline, article and gallery share this width. */
.mission-page .top .top-inner{ max-width:1500px; }
.mission-main > .crumbs,
.mission-main > .mhero,
.mission-main > .feat-byline,
.mission-main > .launch-card,
.mission-main > .mfeature,
.mission-main > .gallery-feature{ max-width:1500px; margin-inline:auto; }

/* ---- Immersive hero: main image covers the section, title overlaid. Height is
   tall enough to read the photo but capped so it never dominates the page. The
   breadcrumb above is the way back, so there's no separate "All Missions"
   button here. ---- */
.mhero{ position:relative; margin-top:20px; height:clamp(430px, 50vh, 530px);
  border-radius:8px; overflow:hidden; display:flex; align-items:flex-end;
  background:var(--panel-alt); }
/* the hero image: a box scaled by --hz (zoom, centred) whose <img> fills it with
   object-fit:cover and object-position for the crop focal point. */
.mhero-media{ position:absolute; top:50%; left:50%; z-index:0;
  width:calc(100% * var(--hz, 1)); height:calc(100% * var(--hz, 1)); transform:translate(-50%, -50%); }
.mhero-media img{ width:100%; height:100%; object-fit:cover; display:block; }
.mhero::after{ content:""; position:absolute; inset:0; pointer-events:none; z-index:1;
  background:linear-gradient(to top, rgba(7,8,10,.94) 4%, rgba(7,8,10,.36) 50%, rgba(7,8,10,.10) 100%); }
/* --- hero reframe controls (admin, edit mode) --- */
.mhero-reframe-btn{ position:absolute; top:16px; right:16px; z-index:6; display:none; font-family:var(--font-mono);
  font-size:12px; letter-spacing:.06em; text-transform:uppercase; color:var(--amber); background:rgba(16,18,19,.8);
  border:1px solid var(--amber-dim); border-radius:5px; padding:8px 13px; cursor:pointer; }
.page-editing .mhero-reframe-btn{ display:block; }
.mhero.reframing .mhero-reframe-btn{ display:none; }
.mhero-reframe-bar{ position:absolute; top:14px; left:14px; right:14px; z-index:7; display:none; align-items:center;
  gap:14px; flex-wrap:wrap; background:rgba(16,18,19,.9); border:1px solid var(--amber-dim); border-radius:8px;
  padding:9px 14px; backdrop-filter:blur(6px); }
.mhero.reframing .mhero-reframe-bar{ display:flex; }
.hrb-label{ font-family:var(--font-mono); font-size:12px; letter-spacing:.08em; text-transform:uppercase; color:var(--amber); }
.hrb-hint{ font-family:var(--font-mono); font-size:11px; color:var(--muted); }
.hrb-zoom{ display:flex; align-items:center; gap:8px; margin-left:auto; font-family:var(--font-mono); font-size:11px;
  text-transform:uppercase; letter-spacing:.05em; color:var(--muted); }
.hrb-zoom input[type=range]{ width:150px; accent-color:var(--amber); }
.hrb-zoom #heroZoomVal{ color:var(--text); min-width:36px; text-align:right; font-variant-numeric:tabular-nums; }
.mhero-reframe-bar button{ font-family:var(--font-mono); font-size:11px; letter-spacing:.05em; text-transform:uppercase;
  color:var(--muted); background:none; border:1px solid var(--line); border-radius:4px; padding:6px 11px; cursor:pointer; }
.mhero-reframe-bar button:hover{ border-color:var(--amber); color:var(--amber); }
.mhero.reframing{ cursor:grab; }
.mhero.reframing.grabbing{ cursor:grabbing; }
.mhero.reframing::after{ opacity:.4; }
.mhero.reframing .mhero-cap{ opacity:.5; pointer-events:none; }
/* the patch and title block share a row; `align-items:stretch` sizes the patch
   to the height of the text beside it */
.mhero-cap{ position:relative; z-index:2; width:100%; display:flex; align-items:stretch;
  gap:clamp(18px,2.4vw,30px); padding:0 clamp(22px,4vw,44px) clamp(24px,3.4vw,36px); }
.mhero-patch{ flex-shrink:0; align-self:stretch; }
.mhero-patch img{ display:block; height:100%; width:auto; max-height:240px; object-fit:contain;
  filter:drop-shadow(0 4px 14px rgba(0,0,0,.5)); }
.mhero-titles{ min-width:0; }
.mhero-eyebrow{ font-family:var(--font-mono); font-size:13px; letter-spacing:.2em;
  text-transform:uppercase; color:var(--amber); margin:0 0 12px; }
.mhero-title{ font-family:Georgia,'Iowan Old Style','Times New Roman',serif;
  font-size:clamp(40px,5.4vw,74px); line-height:.95; margin:0; color:#f8f5ee;
  font-weight:700; letter-spacing:-.01em; text-shadow:0 3px 34px rgba(0,0,0,.55); }
.mhero-stand{ font-family:Georgia,'Iowan Old Style','Times New Roman',serif;
  font-size:clamp(17px,1.5vw,21px); font-style:italic; color:#efe9df; margin:14px 0 0; max-width:60ch; }

/* ---- Byline strip under the hero ---- */
.feat-byline{ display:flex; flex-wrap:wrap; align-items:baseline; margin-top:18px;
  padding:16px 2px; border-bottom:1px solid var(--line); font-family:var(--font-mono);
  font-size:14px; letter-spacing:.03em; color:var(--muted); }
.feat-byline .seg{ display:inline-flex; align-items:baseline; }
.feat-byline .seg::before{ content:"/"; margin:0 16px; color:var(--muted-dim); }
.feat-byline .seg:first-child::before{ content:none; }
.feat-byline b{ color:var(--text); font-weight:400; }

/* Single-column article on the left; single-column technical-details rail on the
   right (expanded to 500px), with a clear gap between the two. */
.mfeature{ margin:42px auto 0; display:grid;
  grid-template-columns:minmax(0,1fr) 500px; gap:104px; align-items:start; }
.mfeature-main{ min-width:0; }

/* Magazine text: a single readable column, justified, with a drop cap. Inline
   photos float and the text wraps around them; pull-quotes break the column. */
.feat-body{ font-family:Georgia,'Iowan Old Style','Times New Roman',serif; }
.feat-body::after{ content:""; display:block; clear:both; }   /* contain the floats */
.feat-body p{ font-size:19px; line-height:1.66; margin:0 0 20px; color:#e6e1d6;
  text-align:justify; hyphens:auto; -webkit-hyphens:auto; }
.feat-body p:first-of-type::first-letter{ float:left; font-family:Georgia,serif; font-weight:700;
  font-size:72px; line-height:.66; padding:9px 12px 0 0; color:var(--amber); }

/* inline photos: kept at their true aspect ratio (no cropping), sized to a
   tasteful width and floated left/right so the text wraps around them. The
   margin:… 0 clears the browser's default <figure> side margin so the photo
   sits flush to the column edge; the side rules add the text-side gap. */
.feat-band{ margin:8px 0 22px; }
.feat-band img{ display:block; width:100%; height:auto; border-radius:6px; border:1px solid var(--line); }
.feat-band figcaption{ font-family:var(--font-mono); font-size:11.5px; color:var(--muted-dim);
  letter-spacing:.02em; line-height:1.5; margin-top:8px; }
/* width comes from the inline style the editor writes; the clamp is the
   fallback for legacy missions with no per-photo width saved. */
.feat-band.side-right{ float:right; clear:right; width:clamp(240px,40%,360px); margin-left:50px; }
.feat-band.side-left{ float:left; clear:left; width:clamp(220px,36%,330px); margin-right:50px; }
.feat-band.side-full{ float:none; clear:both; width:100%; margin:16px 0 24px; }

/* owner-authored pull-quote — breaks the full column width */
.feat-pull{ clear:both; margin:26px 0; padding:8px 0 8px 26px; border-left:3px solid var(--amber); }
.feat-pull p{ font-family:Georgia,serif; font-size:29px; line-height:1.24; font-style:italic;
  color:#f5f2ea; margin:0; text-align:left; hyphens:none; max-width:30ch; }
.feat-pull cite{ display:block; margin-top:12px; font-family:var(--font-mono); font-style:normal;
  font-size:11.5px; letter-spacing:.13em; text-transform:uppercase; color:var(--amber); }
.feat-empty{ color:var(--muted-dim); font-style:italic; font-size:18px; line-height:1.7; margin:0; }

/* A single column of data cards, expanded to fill the wider rail. */
.mfeature-rail{ align-self:start; position:sticky; top:24px; display:flex; flex-direction:column; gap:30px; }
.rail-block{ border-top:2px solid var(--line); padding-top:18px; }
.rail-block h4{ font-family:var(--font-mono); font-size:13px; letter-spacing:.16em;
  text-transform:uppercase; color:var(--amber); margin:0 0 16px; }
.rail-dl{ margin:0; display:grid; gap:13px; }
.rail-dl>div{ display:grid; grid-template-columns:auto 1fr; gap:18px; align-items:baseline; }
.rail-dl dt{ font-family:var(--font-mono); font-size:12.5px; letter-spacing:.05em; text-transform:uppercase;
  color:var(--muted-dim); }
.rail-dl dd{ margin:0; text-align:right; font-family:var(--font-body); font-size:19px; color:var(--text);
  font-variant-numeric:tabular-nums; }
.rail-crew{ list-style:none; margin:0; padding:0; display:flex; flex-direction:column; gap:12px; }
.rail-crew li{ font-family:var(--font-body); font-size:19px; color:var(--text); display:flex;
  justify-content:space-between; gap:12px; align-items:baseline; }
.rail-crew li .crew-role{ font-family:var(--font-mono); font-size:12px; letter-spacing:.04em;
  text-transform:uppercase; color:var(--muted); }
.rail-list{ margin:0; padding-left:20px; font-family:var(--font-body); font-size:17px; line-height:1.6;
  color:var(--muted); }
.rail-list li{ margin-bottom:10px; }
.rail-text{ margin:0; font-family:var(--font-body); font-size:17px; line-height:1.6; color:var(--muted); }

.gallery-feature{ margin:60px auto 0; }
.gallery-feature>h4{ font-family:var(--font-mono); font-size:12px; letter-spacing:.16em;
  text-transform:uppercase; color:var(--amber); margin:0 0 18px; padding-bottom:12px;
  border-bottom:1px solid var(--line); }

/* Below ~1280px there isn't room for the article and the rail side by side, so
   the rail drops beneath the article and its cards flow in a row, full width. */
@media (max-width:1280px){
  .mfeature{ grid-template-columns:1fr; gap:40px; }
  .mfeature-rail{ position:static; flex-direction:row; flex-wrap:wrap; gap:34px; }
  .rail-block{ flex:1 1 240px; }
}
@media (max-width:900px){
  .mhero-stand{ font-size:17px; }
}
@media (max-width:640px){
  .feat-band.side-right, .feat-band.side-left{ float:none; width:100%; margin-left:0; margin-right:0; }
  .feat-pull p{ font-size:24px; }
}
/* record editor: the "In article" (feature) toggle on each gallery row */
.gal-show{ display:inline-flex; align-items:center; gap:6px; white-space:nowrap; cursor:pointer;
  font-family:var(--font-mono); font-size:11px; letter-spacing:.03em; text-transform:uppercase;
  color:var(--muted); }
.gal-show input{ accent-color:var(--amber); }
/* record editor: pull-quote inputs (quote text + attribution) */
.pq-row{ display:grid; grid-template-columns:1fr 250px; gap:8px; margin-bottom:8px; }
.pq-row input{ width:100%; }

/* ========================= SITE FOOTER + DOCUMENT PAGES =========================
   The footer carries the privacy link (which has to be reachable from every
   page) and the "not affiliated with any agency" line. Kept deliberately quiet:
   it is legal furniture, not part of the archive. */
.site-foot{
  margin-top:96px; border-top:1px solid var(--line);
  background:linear-gradient(180deg, transparent, rgba(0,0,0,.35));
  padding:26px 0 34px;
}
.foot-inner{
  display:flex; gap:28px; align-items:baseline; justify-content:space-between;
  flex-wrap:wrap;
}
.foot-note{
  margin:0; max-width:78ch; color:var(--muted-dim);
  font-family:var(--font-body); font-size:14px; line-height:1.65;
}
.foot-note b{ color:var(--muted); font-weight:600; }
.foot-links{
  display:flex; gap:18px; font-family:var(--font-mono); font-size:13px;
  letter-spacing:.09em; text-transform:uppercase; flex-shrink:0;
}
.foot-links a{ color:var(--muted); text-decoration:none; border-bottom:1px solid transparent; }
.foot-links a:hover{ color:var(--amber); border-bottom-color:var(--amber); }
.foot-links a:focus-visible{ outline:1px solid var(--amber); outline-offset:3px; }

/* the landing page keeps its full-bleed cinematic, so it gets one corner link */
.hero-legal{
  position:fixed; right:22px; bottom:18px; z-index:6;
  font-family:var(--font-mono); font-size:12px; letter-spacing:.1em;
  text-transform:uppercase; color:var(--muted-dim); text-decoration:none;
  opacity:.65; transition:opacity .2s, color .2s;
}
.hero-legal:hover{ opacity:1; color:var(--amber); }
.hero-legal:focus-visible{ outline:1px solid var(--amber); outline-offset:4px; opacity:1; }
@media (max-width:700px){ .hero-legal{ right:14px; bottom:12px; } }

/* --- the document (privacy notice) itself ---
   Set at a reading measure rather than the archive's wide grid: this is prose
   to be read once, not data to be scanned. */
.doc{ max-width:820px; margin:0 auto; padding:14px 24px 40px; }
.doc-head{ padding-bottom:30px; border-bottom:1px solid var(--line); margin-bottom:34px; }
.doc-eyebrow{
  margin:0 0 10px; font-family:var(--font-mono); font-size:12px;
  letter-spacing:.22em; text-transform:uppercase; color:var(--amber);
}
.doc-title{
  margin:0; font-family:var(--font-display); font-weight:600; font-size:52px;
  line-height:1.04; letter-spacing:.01em; text-transform:uppercase;
  color:var(--text); text-wrap:balance;
}
.doc-updated{
  margin:14px 0 0; font-family:var(--font-mono); font-size:13px;
  letter-spacing:.07em; color:var(--muted-dim);
}
.doc-lede{
  margin:22px 0 0; font-family:var(--font-body); font-size:18px; line-height:1.72;
  color:var(--muted);
}

.doc-summary{
  border:1px solid var(--line); border-left:2px solid var(--amber);
  background:var(--panel); border-radius:6px; padding:24px 28px; margin-bottom:44px;
}
.doc-summary-title{
  margin:0 0 14px; font-family:var(--font-mono); font-size:12px;
  letter-spacing:.18em; text-transform:uppercase; color:var(--amber); font-weight:500;
}
.doc-summary ul{ margin:0; padding-left:20px; display:grid; gap:11px; }
.doc-summary li{
  font-family:var(--font-body); font-size:16px; line-height:1.62; color:var(--muted);
}
.doc-summary li::marker{ color:var(--muted-dim); }
.doc-summary b{ color:var(--text); font-weight:600; }

.doc-body h3{
  margin:44px 0 16px; font-family:var(--font-display); font-weight:600;
  font-size:23px; letter-spacing:.05em; text-transform:uppercase; color:var(--text);
  padding-bottom:9px; border-bottom:1px solid var(--line);
}
.doc-body h4{
  margin:28px 0 10px; font-family:var(--font-mono); font-size:13px;
  letter-spacing:.13em; text-transform:uppercase; color:var(--phosphor); font-weight:500;
}
.doc-body p{
  margin:0 0 15px; font-family:var(--font-body); font-size:16.5px;
  line-height:1.78; color:var(--muted); max-width:70ch;
}
.doc-body a{ color:var(--amber); text-decoration:underline; text-underline-offset:3px; }
.doc-body code{
  font-family:var(--font-mono); font-size:.88em; color:var(--phosphor);
  background:var(--panel-alt); border:1px solid var(--line);
  border-radius:3px; padding:1px 6px;
}
.doc-body b{ color:var(--text); font-weight:600; }
.doc-list{ margin:0 0 15px; padding-left:22px; display:grid; gap:9px; max-width:70ch; }
.doc-list li{
  font-family:var(--font-body); font-size:16.5px; line-height:1.7; color:var(--muted);
}
.doc-list li::marker{ color:var(--muted-dim); }
.doc-basis{
  font-size:14px !important; color:var(--muted-dim) !important;
  border-left:1px solid var(--line); padding-left:14px; font-style:italic;
}
.doc-callout{
  border:1px solid var(--amber-dim); background:rgba(255,176,0,.045);
  border-radius:6px; padding:18px 22px; margin:20px 0 22px;
}
.doc-callout p{ margin:0; color:var(--muted); }
.doc-todo{
  background:var(--amber); color:#07080a; font-family:var(--font-mono);
  font-size:.85em; padding:2px 7px; border-radius:3px;
}

.doc-table-wrap{ overflow-x:auto; margin:0 0 20px; }
.doc-table{ border-collapse:collapse; width:100%; min-width:520px; }
.doc-table th, .doc-table td{
  text-align:left; padding:11px 16px; border-bottom:1px solid var(--line);
  font-family:var(--font-body); font-size:15.5px; color:var(--muted);
}
.doc-table th{
  font-family:var(--font-mono); font-size:11.5px; letter-spacing:.14em;
  text-transform:uppercase; color:var(--muted-dim); font-weight:500;
  border-bottom-color:var(--amber-dim);
}
.doc-table tbody tr:last-child td{ border-bottom:none; }
.doc-table td:first-child{ color:var(--text); }

@media (max-width:700px){
  .doc{ padding:8px 18px 30px; }
  .doc-title{ font-size:38px; }
  .doc-lede{ font-size:16.5px; }
  .doc-summary{ padding:20px; }
  .doc-body h3{ font-size:20px; }
  .foot-inner{ gap:18px; }
}
