/* ==========================================================================
   EMPHN Workbench — design system
   --------------------------------------------------------------------------
   Direction: "instrument panel". Tesla's restraint applied to population
   health. Near-monochrome, precision typography, generous negative space.
   Colour is reserved almost entirely for data — when everything is grey,
   a single teal bar carries real meaning.

   Type: General Sans (Fontshare, free commercial). Tesla moved from Gotham
   to Universal Sans Display in Jun 2024; General Sans is the closest free
   geometric match — same tight apertures, same slightly condensed caps.

   Accent is eucalypt green, not the usual health-tech blue. It's chosen
   for the catchment itself: EMPHN runs from inner-eastern Hawthorn out to
   the Yarra Ranges green wedge, and no competitor in this space uses it.
   ========================================================================== */

/* ---------------------------------------------------------------- reset */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body, h1, h2, h3, h4, p, figure, blockquote, dl, dd { margin: 0; }
ul[class], ol[class] { list-style: none; margin: 0; padding: 0; }
img, picture, svg { max-width: 100%; display: block; }
input, button, textarea, select { font: inherit; color: inherit; }
button { background: none; border: 0; padding: 0; cursor: pointer; }
a { color: inherit; text-decoration: none; }

/* --------------------------------------------------------------- tokens */
:root {
  /* Surface — a near-black with a trace of warmth reads richer than #000
     behind photography, and stops the hero looking like a void. */
  --ink:        #0B0B0C;
  --ink-soft:   #16171A;
  --ink-lift:   #202227;

  --paper:      #FFFFFF;
  --paper-warm: #FAFAF8;
  --paper-sunk: #F4F4F1;

  /* Neutrals — a single desaturated ramp. Everything structural lives here. */
  --n-900: #16171A;
  --n-700: #3A3D44;
  --n-500: #6B6F78;
  --n-400: #8E939C;
  --n-300: #C3C7CD;
  --n-200: #E2E4E7;
  --n-100: #EFF0F2;

  /* Accent — eucalypt. Used sparingly: active state, key data, one CTA. */
  --accent:      #0E7C66;
  --accent-lift: #12A085;
  --accent-pale: #E6F2EF;
  --accent-deep: #0A5647;

  /* Data palette — for charts. Ordered by visual weight so series 1 always
     reads as the primary. Tested for adjacent-pair contrast. */
  --d1: #0E7C66;  /* eucalypt   */
  --d2: #1F3A5F;  /* deep navy  */
  --d3: #C4551F;  /* burnt clay */
  --d4: #6B8E9E;  /* slate blue */
  --d5: #8A6D3B;  /* ochre      */
  --d6: #4A6B52;  /* moss       */
  --d7: #A63D53;  /* rosewood   */
  --d8: #5D5470;  /* plum grey  */

  /* Semantic */
  --pos:  #1B7F4B;
  --neg:  #B4352A;
  --warn: #A8730D;
  --warn-bg: #FDF6E7;

  /* EMPHN's three geographic zones — carried into map + chip styling */
  --zone-urban:  #1F3A5F;
  --zone-green:  #4A6B52;
  --zone-peri:   #8A6D3B;

  /* Type */
  --sans: "General Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  --mono: "JetBrains Mono", ui-monospace, "SF Mono", Menlo, monospace;

  /* Layout */
  --gutter: clamp(1.25rem, 4vw, 4rem);
  --maxw: 1440px;
  --navh: 68px;

  --r-xs: 3px;
  --r-sm: 6px;
  --r:    10px;
  --r-lg: 16px;
  --r-pill: 100px;

  /* Motion — Tesla's easing is slow-out, almost no bounce. */
  --ease: cubic-bezier(0.25, 0.1, 0.25, 1);
  --fast: 160ms var(--ease);
  --med:  320ms var(--ease);
  --slow: 640ms var(--ease);
}

/* ------------------------------------------------------------------ base */
html, body { height: 100%; }
body {
  font-family: var(--sans);
  font-weight: 400;
  color: var(--ink);
  background: var(--paper);
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  font-feature-settings: "kern" 1, "liga" 1, "cv11" 1;
}

/* Tabular figures everywhere a number can change — stops dashboards
   jittering as values update. */
.num, .kpi-v, td.is-num, .stat-v { font-variant-numeric: tabular-nums; }

/* ------------------------------------------------------------ typography */
/* Display sizes lean on tight negative tracking — the single strongest
   Tesla tell. Weight stays at 500/600; never 800. */
.d1 {
  font-size: clamp(2.75rem, 7vw, 5.5rem);
  font-weight: 600;
  letter-spacing: -0.035em;
  line-height: 1.02;
}
.d2 {
  font-size: clamp(2rem, 4.5vw, 3.5rem);
  font-weight: 600;
  letter-spacing: -0.03em;
  line-height: 1.06;
}
.d3 {
  font-size: clamp(1.5rem, 2.6vw, 2.25rem);
  font-weight: 600;
  letter-spacing: -0.022em;
  line-height: 1.14;
}
.h4 {
  font-size: 1.0625rem;
  font-weight: 600;
  letter-spacing: -0.012em;
}

/* The counterpoint: micro-labels with wide positive tracking. The tension
   between -0.035em display and +0.14em labels is what makes it read as
   designed rather than defaulted. */
.eyebrow {
  font-size: 0.6875rem;
  font-weight: 500;
  letter-spacing: 0.145em;
  text-transform: uppercase;
  color: var(--n-500);
}
.lede {
  font-size: clamp(1rem, 1.35vw, 1.1875rem);
  line-height: 1.6;
  color: var(--n-700);
  font-weight: 400;
}
.fine {
  font-size: 0.8125rem;
  line-height: 1.55;
  color: var(--n-500);
}
.mono-tag {
  font-family: var(--mono);
  font-size: 0.6875rem;
  letter-spacing: 0.02em;
  color: var(--n-500);
}

/* --------------------------------------------------------------- buttons */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  min-width: 190px;
  height: 42px;
  padding: 0 1.75rem;
  border-radius: var(--r-pill);
  font-size: 0.8125rem;
  font-weight: 500;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  transition: background var(--fast), color var(--fast),
              border-color var(--fast), transform var(--fast);
  border: 1px solid transparent;
  white-space: nowrap;
}
.btn:active { transform: scale(0.985); }

.btn-solid       { background: var(--ink); color: var(--paper); }
.btn-solid:hover { background: var(--ink-lift); }

.btn-ghost       { background: transparent; color: var(--ink); border-color: var(--n-300); }
.btn-ghost:hover { border-color: var(--ink); }

.btn-accent       { background: var(--accent); color: #fff; }
.btn-accent:hover { background: var(--accent-lift); }

/* On photography — the Tesla hero pattern. Frosted, never solid. */
.btn-on-media {
  background: rgba(255,255,255,0.92);
  color: var(--ink);
  backdrop-filter: blur(8px);
}
.btn-on-media:hover { background: #fff; }

.btn-on-media-alt {
  background: rgba(20,20,22,0.58);
  color: #fff;
  backdrop-filter: blur(8px);
  border-color: rgba(255,255,255,0.28);
}
.btn-on-media-alt:hover { background: rgba(20,20,22,0.78); }

.btn-row {
  display: flex;
  gap: 0.875rem;
  flex-wrap: wrap;
  justify-content: center;
}
@media (max-width: 560px) {
  .btn-row { flex-direction: column; width: min(320px, 100%); }
  .btn { width: 100%; }
}

/* ------------------------------------------------------------------- nav */
.nav {
  position: fixed;
  inset: 0 0 auto 0;
  height: var(--navh);
  z-index: 100;
  display: flex;
  align-items: center;
  padding: 0 var(--gutter);
  transition: background var(--med), border-color var(--med);
  border-bottom: 1px solid transparent;
}
/* Over the hero the nav is invisible furniture; it materialises on scroll. */
.nav[data-mode="over"] { color: #fff; }
.nav[data-mode="solid"] {
  background: rgba(255,255,255,0.86);
  backdrop-filter: saturate(180%) blur(18px);
  border-bottom-color: var(--n-200);
  color: var(--ink);
}
.nav-inner {
  width: 100%;
  max-width: var(--maxw);
  margin: 0 auto;
  display: flex;
  align-items: center;
  gap: 2.5rem;
}
/* Brand lockup — [EMPHN logo] │ Workbench
   The supplied logo is a full lockup: it already carries "phn", "EASTERN
   MELBOURNE" and the government-initiative line. Repeating the org name in
   an adjacent wordmark duplicated it twice inside a 68px bar. So the logo
   carries identity, a hairline divides, and only the product name follows.
   36px is the floor at which the logo's own tagline stops turning to mush. */
.nav-brand { display: flex; align-items: center; gap: 0.875rem; flex: none; }
.nav-brand img { height: 36px; width: auto; }
/* brightness(0) forces black whatever the source paints, preserving alpha —
   more predictable than invert() if the asset is ever re-exported in colour. */
.nav[data-mode="solid"] .nav-brand img { filter: brightness(0); }
.nav-divider {
  width: 1px;
  height: 24px;
  background: currentColor;
  opacity: 0.3;
  flex: none;
}
.nav-product {
  font-size: 0.9375rem;
  font-weight: 500;
  letter-spacing: -0.012em;
  white-space: nowrap;
}
.nav-links { display: flex; gap: 0.25rem; margin-left: auto; }
.nav-link {
  padding: 0.5rem 0.9rem;
  border-radius: var(--r-sm);
  font-size: 0.8125rem;
  font-weight: 500;
  transition: background var(--fast), opacity var(--fast);
  opacity: 0.82;
}
.nav-link:hover { opacity: 1; background: rgba(128,128,128,0.12); }
.nav-link.is-on { opacity: 1; background: rgba(128,128,128,0.16); }
.nav-cta { margin-left: 1rem; }
@media (max-width: 860px) { .nav-links { display: none; } }

/* Below ~560px the brand lockup plus a CTA can't both fit, so the
   wordmark drops and the logo carries the identity on its own — the same
   move Tesla's mobile header makes. `margin-left:auto` keeps the CTA
   pinned right now that the nav-links flex spacer is gone. */
@media (max-width: 560px) {
  .nav-divider, .nav-product { display: none; }
  .nav-brand img { height: 32px; }
  .nav-cta { margin-left: auto; min-width: 0 !important; padding: 0 1.1rem; }
  .nav-inner { gap: 0.75rem; }
}

/* ------------------------------------------------------------ hero/media */
/* Full-viewport scroll-snap sections — the Tesla homepage skeleton. */
.snap {
  scroll-snap-type: y proximity;
  overflow-y: auto;
  height: 100vh;
}
.panel {
  position: relative;
  min-height: 100vh;
  scroll-snap-align: start;
  display: grid;
  grid-template-rows: 1fr auto;
  isolation: isolate;
}
.panel-media {
  position: absolute;
  inset: 0;
  z-index: -2;
  overflow: hidden;
  background: var(--ink-soft);
}
.panel-media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
}
/* Global scrim: anchors the top and bottom, leaves the middle of the
   photograph legible. On its own this is NOT enough for white text —
   measured worst-case contrast over a sunlit rooftop was 1.74:1 — so the
   text block carries its own local wash below. */
.panel-media::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background:
    linear-gradient(180deg, rgba(8,8,10,0.58) 0%, rgba(8,8,10,0.30) 34%,
                    rgba(8,8,10,0.18) 58%, rgba(8,8,10,0.56) 100%);
}
.panel-head {
  padding: calc(var(--navh) + clamp(3rem, 9vh, 7rem)) var(--gutter) 0;
  text-align: center;
  color: #fff;
  max-width: 940px;
  margin: 0 auto;
  position: relative;
  z-index: 0;
  /* Don't stretch to fill the 1fr grid row. The local wash below is sized
     from this box, so a stretched box would dim the whole photograph
     instead of just the area behind the text. */
  align-self: start;
}
/* Local wash, shaped to the text block itself. A soft ellipse that fades
   to nothing well before its own edge, so there is no visible seam and the
   photograph either side stays open. This is what actually guarantees the
   headline is readable over a bright roofline. */
.panel:not(.is-light):not(.is-warm) .panel-head::before {
  content: "";
  position: absolute;
  inset: -14% -20% -24%;
  z-index: -1;
  pointer-events: none;
  background: radial-gradient(ellipse 76% 62% at 50% 44%,
              rgba(6,7,9,0.62) 0%,
              rgba(6,7,9,0.50) 40%,
              rgba(6,7,9,0.24) 70%,
              rgba(6,7,9,0.00) 100%);
}
/* Backstop for the few pixels the wash can't reach — a wide, soft shadow
   reads as depth rather than a hard 1990s drop shadow. */
.panel:not(.is-light):not(.is-warm) .panel-head > * {
  text-shadow: 0 1px 2px rgba(0,0,0,0.34), 0 2px 22px rgba(0,0,0,0.30);
}
.panel-head .eyebrow { color: rgba(255,255,255,0.82); margin-bottom: 0.875rem; }
/* Near-white rather than 0.9 — measured worst-case contrast for the lede
   over a bright roofline lands at ~4.5:1, which is exactly the AA floor.
   The extra 5% buys margin and costs nothing visually. */
.panel-head .lede {
  color: rgba(255,255,255,0.96);
  margin: 0.875rem auto 0;
  max-width: 620px;
}
.panel-foot {
  padding: 0 var(--gutter) clamp(2.5rem, 7vh, 4.5rem);
  display: grid;
  gap: 1.5rem;
  justify-items: center;
}
/* Light panels — same skeleton, no photograph. */
.panel.is-light { background: var(--paper); }
.panel.is-light .panel-head { color: var(--ink); }
.panel.is-light .panel-head .eyebrow { color: var(--n-500); }
.panel.is-light .panel-head .lede { color: var(--n-700); }
.panel.is-warm { background: var(--paper-warm); }

/* Scroll cue — a slow, patient bounce. Anything faster feels anxious. */
.scroll-cue {
  width: 22px; height: 34px;
  border: 1.5px solid currentColor;
  border-radius: var(--r-pill);
  opacity: 0.5;
  position: relative;
}
.scroll-cue::after {
  content: "";
  position: absolute;
  left: 50%; top: 7px;
  width: 2px; height: 6px;
  margin-left: -1px;
  border-radius: 2px;
  background: currentColor;
  animation: cue 2.4s var(--ease) infinite;
}
@keyframes cue {
  0%, 100% { transform: translateY(0);    opacity: 1; }
  50%      { transform: translateY(10px); opacity: 0.2; }
}

/* --------------------------------------------------------------- entrance */
/* One orchestrated reveal per panel beats scattered micro-animations.
   Content is visible by DEFAULT and only hidden once the script has
   confirmed it can reveal it again (it sets data-anim="on" on <html>).
   Hiding first and revealing later means any failure of the observer —
   no JS, an old browser, a non-compositing tab — leaves a blank page. */
[data-anim="on"] .rise { opacity: 0; transform: translateY(18px); }
[data-anim="on"] .is-in .rise {
  opacity: 1;
  transform: none;
  transition: opacity var(--slow), transform var(--slow);
}
[data-anim="on"] .is-in .rise:nth-child(2) { transition-delay: 90ms; }
[data-anim="on"] .is-in .rise:nth-child(3) { transition-delay: 180ms; }
[data-anim="on"] .is-in .rise:nth-child(4) { transition-delay: 270ms; }

@media (prefers-reduced-motion: reduce) {
  [data-anim="on"] .rise { opacity: 1; transform: none; transition: none; }
  .scroll-cue::after { animation: none; }
  * { scroll-behavior: auto !important; }
}

/* ------------------------------------------------------------------ grid */
.wrap { width: 100%; max-width: var(--maxw); margin: 0 auto; padding: 0 var(--gutter); }
.stack { display: grid; gap: clamp(1rem, 2vw, 1.75rem); }

/* Capability cards — hairline rules, no shadows. Depth from type, not chrome. */
.cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(258px, 1fr));
  gap: 1px;
  background: var(--n-200);
  border: 1px solid var(--n-200);
  border-radius: var(--r-lg);
  overflow: hidden;
}
.card {
  background: var(--paper);
  padding: clamp(1.75rem, 3vw, 2.75rem);
  display: grid;
  align-content: start;
  gap: 0.75rem;
  transition: background var(--med);
}
.card:hover { background: var(--paper-warm); }
.card .idx {
  font-family: var(--mono);
  font-size: 0.6875rem;
  color: var(--accent);
  letter-spacing: 0.06em;
}
.card p { color: var(--n-700); font-size: 0.9375rem; line-height: 1.6; }

/* Stat row — the credibility strip. Big tabular figures, tiny labels. */
.stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: clamp(1.5rem, 4vw, 3.5rem);
}
.stat-v {
  font-size: clamp(2rem, 3.6vw, 3rem);
  font-weight: 600;
  letter-spacing: -0.035em;
  line-height: 1;
}
.stat-l {
  margin-top: 0.5rem;
  font-size: 0.75rem;
  color: var(--n-500);
  line-height: 1.45;
}
.panel-head .stat-l { color: rgba(255,255,255,0.72); }

/* Zone chips — EMPHN's urban / green-wedge / peri-urban split */
.zone {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  font-size: 0.6875rem;
  font-weight: 500;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--n-500);
}
.zone::before {
  content: "";
  width: 7px; height: 7px;
  border-radius: 2px;
  background: var(--n-400);
}
.zone[data-zone="urban"]::before      { background: var(--zone-urban); }
.zone[data-zone="green-wedge"]::before{ background: var(--zone-green); }
.zone[data-zone="peri-urban"]::before { background: var(--zone-peri); }

/* ---------------------------------------------------------------- footer */
.foot {
  background: var(--ink);
  color: rgba(255,255,255,0.66);
  padding: clamp(3rem, 6vw, 5rem) var(--gutter) 2.5rem;
  font-size: 0.8125rem;
}
.foot-inner {
  max-width: var(--maxw);
  margin: 0 auto;
  display: flex;
  flex-wrap: wrap;
  gap: 2rem;
  justify-content: space-between;
  align-items: flex-end;
}
.foot a:hover { color: #fff; }
.foot .rule {
  height: 1px;
  background: rgba(255,255,255,0.12);
  margin: 2.5rem 0 1.5rem;
}

/* -------------------------------------------------------------- a11y */
:focus-visible {
  outline: 2px solid var(--accent-lift);
  outline-offset: 3px;
  border-radius: var(--r-xs);
}
.skip {
  position: absolute; left: -9999px;
  z-index: 200; padding: 0.75rem 1.25rem;
  background: var(--ink); color: #fff; border-radius: var(--r-sm);
}
.skip:focus { left: var(--gutter); top: 0.75rem; }
.sr {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
