

:root {
  --ink:        #0b0e1a;   /* page background, near-black navy */
  --ink-raised: #12172a;   /* cards */
  --ink-line:   #232a45;   /* borders */
  --text:       #e8ecf6;
  --text-dim:   #9aa4c0;

  /* --gold-lift exists only for hover states*/
  --gold:       #e4c32f;
  --gold-soft:  #e4c32f;
  --gold-lift:  #f2d95f;   /* hover only */
  --gold-dim:   rgba(228, 195, 47, 0.30);
  --gold-wash:  rgba(228, 195, 47, 0.10); 
  --on-gold:    #17130a;

  --cyan:       #00e5ff;   /* secondary accent */

  --warn:       #ff8b3d;
  --green:      #2ecc5a;

  --radius:     14px;
  --wrap:       1180px;
  --font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
}

* { box-sizing: border-box; }

html { scroll-behavior: smooth; }

body {
  margin: 0;
  background: var(--ink);
  color: var(--text);
  font-family: var(--font);
  font-size: 17px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

img { max-width: 100%; display: block; }
a { color: var(--gold-soft); text-decoration: none; }
a:hover { color: var(--gold-lift); }

h1, h2, h3, h4 { line-height: 1.15; margin: 0 0 .5em; letter-spacing: -0.02em; }
h1 { font-size: clamp(2.2rem, 5vw, 3.6rem); font-weight: 800; }
h2 { font-size: clamp(1.7rem, 3.4vw, 2.5rem); font-weight: 700; }
h3 { font-size: 1.2rem; font-weight: 700; }

.wrap { width: 100%; max-width: var(--wrap); margin: 0 auto; padding: 0 24px; }
.muted { color: var(--text-dim); }
.lede { font-size: 1.2rem; color: var(--text-dim); max-width: 62ch; }

.skipLink {
  position: absolute; left: -9999px; top: 0; background: var(--gold); color: var(--on-gold);
  padding: 10px 16px; z-index: 100;
}
.skipLink:focus { left: 0; }

/* ---------------------------------------------------------------- header */
.siteHeader {
  position: sticky; top: 0; z-index: 50;
  background: rgba(11, 14, 26, 0.82);
  backdrop-filter: blur(12px);
  border-bottom: 1px solid var(--ink-line);
}
.headerInner { display: flex; align-items: center; gap: 28px; height: 68px; }
.brand { display: flex; align-items: center; flex-shrink: 0; }
.siteNav { display: flex; gap: 24px; margin-left: auto; }
.siteNav a { color: var(--text-dim); font-size: 15px; font-weight: 500; }
.siteNav a:hover, .siteNav a.active { color: var(--text); }
.siteNav a.active { position: relative; }
.siteNav a.active::after {
  content: ''; position: absolute; left: 0; right: 0; bottom: -24px; height: 2px;
  background: var(--gold);
}
.headerCta { flex-shrink: 0; }
.navToggle { display: none; background: none; border: 0; cursor: pointer; padding: 8px; }
.navToggle span { display: block; width: 22px; height: 2px; background: var(--text); margin: 4px 0; }

/* ---------------------------------------------------------------- buttons */
.btn {
  display: inline-block; padding: 13px 26px; border-radius: 999px;
  background: var(--gold); color: var(--on-gold); font-weight: 700; font-size: 16px;
  border: 1px solid transparent; transition: transform .12s ease, background .15s ease;
}
.btn:hover { background: var(--gold-lift); color: var(--on-gold); transform: translateY(-1px); }
.btnSmall { padding: 8px 18px; font-size: 14px; }
.btnGhost { background: transparent; border-color: var(--ink-line); color: var(--text); }
.btnGhost:hover { background: var(--gold-wash); border-color: var(--gold); color: var(--text); }

/* ---------------------------------------------------------------- hero */
/* Full-bleed photograph with the headline over it. The scrim underneath is doing real work:
   text over a photo is unreadable without one, and it has to be heaviest where the type sits
   rather than an even wash, or the picture goes muddy for no benefit. */
.hero {
  position: relative;
  min-height: 82vh;
  display: flex;
  align-items: center;
  padding: 96px 0 84px;
  overflow: hidden;
  background-image: image-set(url('/images/hero-aircraft.webp') type('image/webp'),
                              url('/images/hero-aircraft.jpg') type('image/jpeg'));
  background-size: cover;
  background-position: center 42%;
  background-color: var(--ink);
}
.hero::before {
  content: ''; position: absolute; inset: 0; pointer-events: none;
  background:
    /* holds nearly opaque across the whole text column, then releases so the aircraft is still
       the picture.*/
    linear-gradient(100deg, rgba(9,12,22,.97) 0%, rgba(9,12,22,.94) 46%, rgba(9,12,22,.62) 72%, rgba(9,12,22,.78) 100%),
    linear-gradient(180deg, rgba(9,12,22,.6) 0%, transparent 24%, transparent 58%, var(--ink) 100%),
    rgba(9,12,22,.22);
}
/* a hint of gold glow*/
.hero::after {
  content: ''; position: absolute; inset: auto auto -20% -10%; width: 60%; height: 460px;
  background: radial-gradient(closest-side, rgba(228,195,47,.16), transparent 75%);
  pointer-events: none;
}
.heroInner { position: relative; z-index: 1; max-width: 760px; }
.heroInner .lede { max-width: 54ch; }
.heroKicker {
  display: inline-flex; align-items: center; gap: 8px; font-size: 13px; font-weight: 600;
  letter-spacing: .06em; text-transform: uppercase; color: var(--cyan);
  border: 1px solid rgba(0,229,255,.3); border-radius: 999px; padding: 5px 14px; margin-bottom: 22px;
}
.heroTitle { margin-bottom: 20px; }
.heroTitle em { font-style: normal; color: var(--gold-soft); }
.heroActions { display: flex; gap: 14px; flex-wrap: wrap; margin: 30px 0 18px; }
.heroNote { font-size: 14px; color: var(--text-dim); }

/*live airspace map */
.mapDemo { display: grid; grid-template-columns: 1fr 1.25fr; gap: 52px; align-items: center; }
.mapDemoText h2 { margin-bottom: 16px; }
.mapDemoText p { color: var(--text-dim); }
.mapDemoPoints { list-style: none; padding: 0; margin: 22px 0 0; }
.mapDemoPoints li {
  position: relative; padding-left: 26px; margin-bottom: 12px;
  color: var(--text-dim); font-size: 15px;
}
.mapDemoPoints li::before {
  content: ''; position: absolute; left: 0; top: 8px;
  width: 9px; height: 9px; border-radius: 2px; background: var(--gold);
}
.mapDemoPoints strong { color: var(--text); }

.heroMapFrame {
  position: relative; border-radius: var(--radius); overflow: hidden;
  border: 1px solid var(--ink-line); box-shadow: 0 30px 70px rgba(0,0,0,.55);
  background: var(--ink-raised);
}
.heroMap { width: 100%; height: 470px; }
.heroMapLabel {
  position: absolute; left: 12px; top: 12px; z-index: 2;
  background: rgba(11,14,26,.85); border: 1px solid var(--gold-dim); border-radius: 8px;
  padding: 6px 11px; font-size: 12px; color: var(--text-dim); pointer-events: none;
}
.heroMapLabel strong { color: var(--gold); font-weight: 600; }

/* ---------------------------------------------------------------- sections */
.section { padding: 84px 0; }
.sectionAlt { background: linear-gradient(180deg, transparent, rgba(18,23,42,.6), transparent); }
.sectionHead { max-width: 64ch; margin-bottom: 46px; }
.sectionHead h2 { margin-bottom: 14px; }
.eyebrow {
  font-size: 13px; font-weight: 700; letter-spacing: .1em; text-transform: uppercase;
  color: var(--gold-soft); margin-bottom: 12px;
}

.pageHead { padding: 72px 0 24px; max-width: var(--wrap); margin: 0 auto; padding-left: 24px; padding-right: 24px; }
.pageHead h1 { margin-bottom: 16px; }

/* ---------------------------------------------------------------- feature grid */
.featureGrid { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 20px; }
.featureCard {
  background: var(--ink-raised); border: 1px solid var(--ink-line); border-radius: var(--radius);
  padding: 28px; transition: border-color .15s ease, transform .15s ease;
}
.featureCard:hover { border-color: var(--gold-dim); transform: translateY(-2px); }
.featureIcon {
  width: 42px; height: 42px; border-radius: 11px; display: grid; place-items: center;
  background: var(--gold-wash); border: 1px solid var(--gold-dim); margin-bottom: 18px;
}
.featureIcon svg { width: 22px; height: 22px; stroke: var(--gold-soft); fill: none; stroke-width: 1.7; }
.featureCard h3 { margin-bottom: 8px; }
.featureCard p { margin: 0; color: var(--text-dim); font-size: 15px; }

/* alternating big feature rows with a screenshot */
.showcase { display: grid; grid-template-columns: 1fr 1fr; gap: 60px; align-items: center; margin-bottom: 96px; }
.showcase:nth-child(even) .showcaseText { order: 2; }
.showcase h2 { margin-bottom: 16px; }
.showcase p { color: var(--text-dim); }
.showcaseMedia {
  border-radius: var(--radius); overflow: hidden; 
  /* border: 1px solid var(--ink-line); */
  box-shadow: 0 24px 60px rgba(0,0,0,.5); 
  /* background: var(--ink-raised); */
}
/* height:auto is not optional here. The img tags carry width/height attributes so the browser can
   reserve the right space before the image loads, but without this the attribute height wins and
   the picture is stretched vertically once CSS scales the width down. */
.showcaseMedia img { width: 100%; height: auto; }

/* the animated wind demo. Pointer events are off entirely: leaflet is told not to handle any
   interaction, and this stops the cursor even suggesting otherwise. */
.windMapFrame { background: var(--ink); }
.windMap {
  width: 100%; height: 420px;
  background: var(--ink-raised);
  pointer-events: none;
}
.windMap .leaflet-control-attribution {
  background: rgba(11, 14, 26, .8); color: var(--text-dim); font-size: 10px;
}
.windMap .leaflet-control-attribution a { color: var(--text-dim); }

/* a placeholder that makes it obvious a real screenshot belongs here, cause I forget otherwise */
.mediaPlaceholder {
  aspect-ratio: 16 / 10; display: grid; place-items: center; text-align: center;
  color: var(--text-dim); font-size: 14px; padding: 24px;
  background:
    repeating-linear-gradient(45deg, rgba(255,255,255,.02) 0 12px, transparent 12px 24px),
    var(--ink-raised);
}

/* ---------------------------------------------------------------- stats */
/* five tiles now, so the minimum is set to let all five sit on one row at desktop width
   rather than leaving a single orphan underneath */
.statRow { display: grid; grid-template-columns: repeat(auto-fit, minmax(165px, 1fr)); gap: 16px; }
.stat {
  text-align: center; padding: 26px 14px;
  border: 1px solid var(--ink-line); border-radius: var(--radius); background: var(--ink-raised);
  /* lets the value size itself against THIS tile rather than the viewport - the tiles get narrow
     while the window stays wide, so a viewport-based size does not help here */
  container-type: inline-size;
}

/* Fixed 2.1rem overflowed the tile for the longer values ("07/08/2026" in a 165px column).
   The plain rule below is the fallback for anything without container query units; the cqi rule
   that follows wins where they are supported. 15cqi ~= 25px in a 165px tile, ~32px in a 210px
   one, so short values still look bold and long ones simply fit. */
.statValue {
  font-size: 1.5rem; font-weight: 800; color: var(--text); line-height: 1.15;
  /* last line of defence: values like "07/08/2026" are one unbreakable token, so once the font
     hits its floor they would escape the tile rather than wrap. This makes them wrap instead. */
  overflow-wrap: anywhere;
}
.statValue { font-size: clamp(1.15rem, 15cqi, 2.1rem); }
.statLabel { font-size: 14px; color: var(--text-dim); margin-top: 6px; }

/* the one figure on the page that is actually live, so it gets the gold and a pulse */
.statLive { border-color: var(--gold-dim); background: linear-gradient(180deg, var(--gold-wash), var(--ink-raised)); }
.statLive .statValue { color: var(--gold); }
.livePip {
  display: inline-block; width: 7px; height: 7px; border-radius: 50%;
  background: var(--green); margin-right: 7px; vertical-align: 1px;
  box-shadow: 0 0 0 0 rgba(46, 204, 90, .6);
  animation: livePulse 2.4s ease-out infinite;
}
@keyframes livePulse {
  0%   { box-shadow: 0 0 0 0 rgba(46, 204, 90, .55); }
  70%  { box-shadow: 0 0 0 7px rgba(46, 204, 90, 0); }
  100% { box-shadow: 0 0 0 0 rgba(46, 204, 90, 0); }
}
@media (prefers-reduced-motion: reduce) {
  .livePip { animation: none; }
}

/* ---------------------------------------------------------------- news */
.newsGrid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 20px;
  max-width: var(--wrap); margin: 0 auto 90px; padding: 0 24px;
}
.newsCard {
  display: block; background: var(--ink-raised); border: 1px solid var(--ink-line);
  border-radius: var(--radius); padding: 26px; color: var(--text);
  transition: border-color .15s ease, transform .15s ease;
}
.newsCard:hover { border-color: var(--gold-dim); transform: translateY(-2px); color: var(--text); }
.newsCard h3 { margin: 10px 0 6px; }
.newsCard time { font-size: 13px; color: var(--text-dim); }
.newsCard p { color: var(--text-dim); font-size: 15px; margin: 12px 0 16px; }
.newsTag {
  display: inline-block; font-size: 11px; font-weight: 700; letter-spacing: .08em;
  text-transform: uppercase; color: var(--cyan); background: rgba(0,229,255,.1);
  border: 1px solid rgba(0,229,255,.25); border-radius: 999px; padding: 3px 10px;
}
.newsMore { font-size: 14px; font-weight: 600; color: var(--gold-soft); }

/* ---------------------------------------------------------------- article */
.post { max-width: 760px; margin: 0 auto; padding: 64px 24px 90px; }
.post h1 { margin: 14px 0 10px; }
.post > time { color: var(--text-dim); font-size: 14px; }
.postBody { margin-top: 34px; }
.postBody h2 { margin-top: 44px; font-size: 1.55rem; }
.postBody h3 { margin-top: 32px; }
.postBody img { border-radius: var(--radius); border: 1px solid var(--ink-line); margin: 28px 0; width: 100%; }
.postBody figure { margin: 28px 0; }
.postBody figure img { margin: 0 0 10px; }
.postBody figcaption { font-size: 14px; color: var(--text-dim); text-align: center; }

/* optional lead image, from the post's `image:` front matter */
.postLead {
  width: 100%; border-radius: var(--radius); border: 1px solid var(--ink-line);
  margin: 26px 0 0;
}
/* Full bleed to the card edges. The card has 26px of padding, so the image is widened by twice
   that and pulled back out with negative margins - and max-width has to be released, because the
   global `img { max-width: 100% }` otherwise clamps it back inside the padding and leaves a gap
   down each side. object-fit crops the overflow rather than squashing the photo. */
.newsCardImage {
  width: calc(100% + 52px); max-width: none;
  margin: -26px -26px 18px; display: block;
  aspect-ratio: 16 / 9; object-fit: cover; object-position: center;
  border-radius: var(--radius) var(--radius) 0 0;
}
.postBody blockquote {
  margin: 26px 0; padding: 14px 20px; border-left: 3px solid var(--gold);
  background: var(--ink-raised); border-radius: 0 8px 8px 0; color: var(--text-dim);
}
.postBody code { background: var(--ink-raised); border: 1px solid var(--ink-line); border-radius: 5px; padding: 1px 6px; font-size: .9em; }
.postBody pre { background: var(--ink-raised); border: 1px solid var(--ink-line); border-radius: 10px; padding: 18px; overflow-x: auto; }
.postBody pre code { border: 0; padding: 0; background: none; }
.backLink { font-size: 14px; color: var(--text-dim); display: inline-block; margin-bottom: 20px; }

/* ---------------------------------------------------------------- prose pages */
.prose { max-width: 760px; margin: 0 auto; padding: 0 24px 90px; }
.prose h2 { margin-top: 48px; }
.prose h3 { margin-top: 32px; }
.prose p, .prose li { color: var(--text-dim); }
.prose strong { color: var(--text); }
.prose table { width: 100%; border-collapse: collapse; margin: 24px 0; font-size: 15px; }
.prose th, .prose td { text-align: left; padding: 10px 12px; border-bottom: 1px solid var(--ink-line); }
.prose th { color: var(--text); font-weight: 600; }
.prose td { color: var(--text-dim); }

/* ---------------------------------------------------------------- callouts */
.callout {
  border: 1px solid var(--ink-line); border-left: 4px solid var(--gold);
  background: var(--ink-raised); border-radius: 0 var(--radius) var(--radius) 0;
  padding: 20px 24px; margin: 28px 0;
}
.callout h3 { margin-bottom: 8px; }
.callout p:last-child { margin-bottom: 0; }
.calloutWarning { border-left-color: var(--warn); }
.calloutWarning h3 { color: var(--warn); }

/* ---------------------------------------------------------------- install steps */
.platformTabs { display: flex; gap: 10px; margin: 30px 0 26px; flex-wrap: wrap; }
.platformTab {
  padding: 10px 20px; border-radius: 999px; border: 1px solid var(--ink-line);
  background: var(--ink-raised); color: var(--text-dim); cursor: pointer; font-size: 15px;
  font-family: inherit;
}
.platformTab.active { border-color: var(--gold); color: var(--text); background: var(--gold-wash); }
.platformPanel { display: none; }
.platformPanel.active { display: block; }

.steps { list-style: none; counter-reset: step; padding: 0; margin: 0; }
.steps li {
  counter-increment: step; position: relative; padding: 0 0 26px 56px; color: var(--text-dim);
  border-left: 1px solid var(--ink-line); margin-left: 17px;
}
.steps li:last-child { border-left-color: transparent; padding-bottom: 0; }
.steps li::before {
  content: counter(step); position: absolute; left: -18px; top: -4px;
  width: 36px; height: 36px; border-radius: 50%; display: grid; place-items: center;
  background: var(--ink-raised); border: 1px solid var(--gold); color: var(--text);
  font-weight: 700; font-size: 15px;
}
.steps strong { color: var(--text); display: block; margin-bottom: 4px; }

/* ---------------------------------------------------------------- coverage page */
.coverageMap {
  width: 100%; height: 480px; border-radius: var(--radius);
  border: 1px solid var(--ink-line); overflow: hidden; background: var(--ink-raised);
}
.coverageStats { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 16px; margin: 26px 0; }

/* ---------------------------------------------------------------- patch notes */
.releases { max-width: 820px; margin: 0 auto; padding: 0 24px 40px; }
.release {
  border-left: 2px solid var(--ink-line);
  padding: 0 0 34px 28px;
  margin-left: 6px;
  position: relative;
}
.release:last-child { border-left-color: transparent; padding-bottom: 10px; }
/* a marker on the timeline; the newest release gets the gold one */
.release::before {
  content: ''; position: absolute; left: -7px; top: 6px;
  width: 12px; height: 12px; border-radius: 50%;
  background: var(--ink); border: 2px solid var(--ink-line);
}
.release:first-child::before { border-color: var(--gold); background: var(--gold); }

.releaseHead { display: flex; align-items: baseline; gap: 14px; flex-wrap: wrap; margin-bottom: 14px; }
.releaseHead h2 { font-size: 2 rem; margin: 0; }
.release:first-child .releaseHead h2 { color: var(--gold); }
.releaseHead time { font-size: 14px; color: var(--text-dim); }

.releaseGroup {
  font-size: 12px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase;
  margin: 18px 0 8px; color: var(--text-dim);
}
.releaseGroupNew { color: var(--gold); }
.releaseGroupFixes { color: var(--green); }

.releaseList { margin: 0; padding-left: 20px; }
.releaseList li { color: var(--text-dim); font-size: 15px; margin-bottom: 8px; line-height: 1.55; }

/* ---------------------------------------------------------------- faq */
.faqItem { border-bottom: 1px solid var(--ink-line); padding: 8px 0; }
.faqItem summary {
  cursor: pointer; padding: 18px 0; font-weight: 600; font-size: 1.05rem;
  list-style: none; display: flex; justify-content: space-between; gap: 20px; align-items: center;
}
.faqItem summary::-webkit-details-marker { display: none; }
.faqItem summary::after { content: '+'; color: var(--gold-soft); font-size: 1.5rem; font-weight: 400; }
.faqItem[open] summary::after { content: '\2212'; }
.faqItem p { color: var(--text-dim); margin: 0 0 18px; }

/* ---------------------------------------------------------------- cta band */
.ctaBand {
  border-top: 1px solid var(--ink-line); border-bottom: 1px solid var(--ink-line);
  background: linear-gradient(135deg, rgba(228,195,47,.12), rgba(0,229,255,.06));
  padding: 74px 0; text-align: center;
}
.ctaBand h2 { margin-bottom: 14px; }
.ctaBand p { color: var(--text-dim); max-width: 54ch; margin: 0 auto 28px; }
/* Two calls to action side by side. The wrap matters on narrow screens: these must stack rather
   than shrink, so the donate button never sits level with Get JVFR and starts competing with it. */
.ctaButtons { display: flex; gap: 14px; justify-content: center; flex-wrap: wrap; }

/* ---------------------------------------------------------------- footer */
.siteFooter { border-top: 1px solid var(--ink-line); padding: 62px 0 30px; margin-top: 40px; }
.footerInner { display: grid; grid-template-columns: 1.4fr 2fr; gap: 50px; }
.footerBrand p { color: var(--text-dim); font-size: 15px; margin: 16px 0 0; max-width: 34ch; }
.footerNote { font-size: 13px !important; opacity: .75; }
.footerCols { display: grid; grid-template-columns: repeat(3, 1fr); gap: 30px; }
.footerCols h4 { font-size: 13px; text-transform: uppercase; letter-spacing: .08em; color: var(--text); margin-bottom: 14px; }
.footerCols a { display: block; color: var(--text-dim); font-size: 15px; padding: 5px 0; }
.footerCols a:hover { color: var(--gold-lift); }
/* The one link in the footer that asks for something rather than offering it. Marked with a cup so
   it is identifiable at a glance, and left at the dim footer colour until hover so it does not
   outrank the links around it. */
.footerCoffee::before { content: '\2615'; margin-right: 7px; opacity: .8; }
.footerBase {
  display: flex; justify-content: space-between; gap: 20px; flex-wrap: wrap;
  border-top: 1px solid var(--ink-line); margin-top: 46px; padding-top: 24px;
  font-size: 13px; color: var(--text-dim);
}
.footerBase p { margin: 0; }
.footerWarning { color: var(--warn); }

/* ---------------------------------------------------------------- responsive */
@media (max-width: 900px) {
  /* every multi-column grid has to be listed here. .mapDemo was added later and missed, which
     left the map squeezed into a half-width column with the text crushed beside it on phones. */
  .heroInner, .showcase, .footerInner, .mapDemo { grid-template-columns: 1fr; }
  .mapDemo { gap: 28px; }
  .heroMap { height: 340px; }
  .windMap { height: 300px; }
  .showcase { gap: 30px; margin-bottom: 64px; }
  .showcase:nth-child(even) .showcaseText { order: 0; }
  .siteNav {
    display: none; position: absolute; top: 68px; left: 0; right: 0; flex-direction: column;
    gap: 0; background: var(--ink); border-bottom: 1px solid var(--ink-line); padding: 10px 24px 20px;
  }
  .siteNav.open { display: flex; }
  .siteNav a { padding: 12px 0; font-size: 16px; }
  .siteNav a.active::after { display: none; }
  .navToggle { display: block; margin-left: auto; }
  .headerCta { display: none; }
  .hero { padding: 54px 0 48px; }
  .heroMap { height: 320px; }
  .section { padding: 58px 0; }
  .footerCols { grid-template-columns: 1fr 1fr; }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  * { transition: none !important; }
}
