@font-face{font-family:'Inter';src:url('/assets/fonts/InterVariable.woff2') format('woff2');font-weight:100 900;font-style:normal;font-display:swap}

:root {
  /* ---------------------------------------------------------------------
     Brand tokens. Added 2026-08-12 after an audit found 81 distinct colours
     against 9 tokens — including five ambers and a green tint that existed in
     six near-identical values. The drift was not a design decision; it was the
     absence of a name for each role, so every new component invented its own.

     Rule: if a colour has a job, it has a token. Never write a brand hex in a
     rule. Heat ramps and confidence grades are DATA colour, live with their
     tools, and are deliberately not tokenised here.
     --------------------------------------------------------------------- */

  /* surfaces */
  --white:        #ffffff;   /* cards, raised panels                        */
  --paper:        #f7f5ef;   /* page background, warm not clinical          */
  --paper-warm:   #efeade;   /* table headers, quiet panels                 */

  /* text */
  --ink:          #17201f;   /* body copy                                   */
  --muted:        #52605e;   /* secondary copy, captions                    */

  /* structure */
  --line:         #d7d1c4;   /* hairlines, borders                          */

  /* green — the brand spine */
  --green-950:    #0d2b22;   /* deepest, large dark fields                  */
  --green-deep:   #124539;   /* headings, dark sections, the mark           */
  --green:        #1d6f5b;   /* primary actions, links                      */
  --green-200:    #cfe0d8;   /* borders inside green panels                 */
  --green-100:    #e2ebe7;   /* panel fill                                  */
  --green-50:     #eef3f1;   /* faintest tint                               */

  /* mint — the bright green in the logo's E.
     Added 2026-08-15 with the new mark. It is genuinely new: CIELAB dE 31.6
     from the nearest existing token, so it could not be folded into the green
     scale.

     DARK SURFACES ONLY, and this is a hard constraint, not a preference:
       on --paper  1.89:1   fails text (4.5) and fails UI (3.0)
       on #0B4F42  4.61:1   passes both
     It may carry links, hover states and accents on the header, the footer and
     dark panels. It may never be link or body colour on cream. If you find
     yourself reaching for it on a light background, use --green instead. */
  --mint:         #7fd3bc;
  --mint-deep:    #0b4f42;   /* the field mint is designed to sit on           */

  /* amber — the accent, and "opportunity found" in the mark */
  --amber-800:    #7a5310;   /* amber text on light                         */
  --amber:        #c98b2f;   /* the accent                                  */
  --amber-300:    #f3c76a;   /* amber ON dark; too light for cream          */
  --amber-50:     #fdf6e8;   /* callout fill                                */

  /* state */
  --danger:       #c0392b;
  --danger-50:    #fdecec;

  /* Filling gaps the audit found rather than leaving one-off literals in rules.
     Each measured 6-20 dE from its nearest neighbour, so these are real steps
     in the scale, not drift. */
  --ink-deep:     #0b1312;   /* deepest field, below --ink                  */
  --ink-on-tint:  #283633;   /* body copy sitting on a green tint           */
  --ink-on-deep:  #304340;   /* quieter copy on a green tint                */
  --amber-900:    #50320b;   /* amber text needing more weight than 800     */
  --amber-400:    #d9b264;   /* amber on the cream page; 300 fails contrast */
  --amber-100:    #f2d79b;   /* amber chip fill                             */

  --shadow: 0 18px 44px rgba(16, 24, 24, 0.18);
}

* {
  box-sizing: border-box;
}

html {
  scroll-behavior: smooth;
}

body {
  margin: 0;
  font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  color: var(--ink);
  background: var(--paper);
  letter-spacing: 0;
}

a {
  color: inherit;
  text-decoration: none;
}

.topbar {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 10;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  padding: 14px clamp(16px, 4vw, 54px);
  color: var(--white);
  /* The gradient faded to 20% opacity at its lower edge. That reads well over
     the dark hero it was designed for, but the bar is position:fixed and every
     other page scrolls light content underneath it — so body text showed
     straight through the navigation. Keep the gradient for depth, put an opaque
     base behind it, and blur what passes below where the browser supports it. */
  background:
    linear-gradient(180deg, rgba(9, 15, 15, 0.92), rgba(9, 15, 15, 0.72)),
    rgba(9, 15, 15, 0.86);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  min-width: 0;
  font-weight: 700;
}

/* The mark is 1.9:1. It used to be framed in a 34x34 rounded box with a hairline
   ring, which letterboxed it to roughly half the available height and left the
   ring outlining empty space on both sides. Sized by height instead, so the
   letterforms get the full 26px and the chrome goes away. */
.brand-mark {
  display: block;
  width: auto;
  height: 26px;
  object-fit: contain;
}

.brand-name {
  white-space: nowrap;
}

nav {
  display: flex;
  align-items: center;
  gap: clamp(12px, 3vw, 28px);
  font-size: 0.92rem;
}

/* The header had no hover affordance at all: nav links were white and stayed
   white, so nothing confirmed a target before clicking. Mint on the dark bar
   is 4.61:1, which clears the 3:1 needed for a UI state change. */
.topbar nav a:hover,
.topbar nav a:focus-visible {
  color: var(--mint);
}

.hero {
  position: relative;
  min-height: 92vh;
  overflow: hidden;
  color: var(--white);
}

.hero-image,
.hero-shade {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

.hero-image {
  object-fit: cover;
}

.hero-shade {
  background:
    linear-gradient(90deg, rgba(9, 16, 16, 0.92) 0%, rgba(9, 16, 16, 0.66) 36%, rgba(9, 16, 16, 0.16) 76%),
    linear-gradient(180deg, rgba(9, 16, 16, 0.2) 0%, rgba(9, 16, 16, 0.62) 100%);
}

.hero-copy .eyebrow {
  /* Light amber ONLY where the eyebrow actually sits on the shaded hero image.
     This was scoped to .hero-content, which also contains the diagnostic panel
     — a 94%-opaque white card. The eyebrow inside it inherited the light amber
     and measured 2.0:1 against white, against a 4.5:1 requirement. Scoping to
     .hero-copy leaves the panel on the base rule's --amber-800 (5.17:1).
     Verified by hit-testing the paint stack, not by reading the markup: the
     shade is a sibling overlay, so an ancestor walk reports the page
     background and makes the correct case look like a failure too. */
  color: var(--amber-400);
}

.hero-content {
  position: relative;
  z-index: 1;
  min-height: 92vh;
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(330px, 420px);
  align-items: center;
  gap: clamp(24px, 5vw, 68px);
  padding: 96px clamp(18px, 5vw, 70px) 44px;
}

.hero-copy {
  max-width: 760px;
}

.eyebrow {
  margin: 0 0 10px;
  /* Darkened for the cream page background: the original var(--amber-400) measured
     1.83:1 against --paper, far below the 4.5:1 AA threshold, which makes these
     section kickers effectively unreadable for anyone with reduced contrast
     sensitivity. This value measures 5.17:1. The hero keeps the light amber
     below, because there it sits on a dark shaded image. */
  color: var(--amber-800);
  font-size: 0.78rem;
  line-height: 1.25;
  font-weight: 800;
  text-transform: uppercase;
}

h1,
h2,
h3,
p {
  margin-top: 0;
}

h1 {
  margin-bottom: 18px;
  max-width: 700px;
  font-size: clamp(3rem, 7vw, 5.8rem);
  line-height: 0.94;
  font-weight: 850;
}

.hero-lede {
  max-width: 660px;
  color: rgba(255, 255, 255, 0.88);
  font-size: clamp(1.05rem, 2vw, 1.32rem);
  line-height: 1.55;
}

.hero-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin-top: 30px;
}

.button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  padding: 11px 18px;
  border: 1px solid transparent;
  border-radius: 8px;
  font: inherit;
  font-weight: 800;
  cursor: pointer;
}

.button.primary {
  /* Brand green, not amber. Amber was doing double duty as both the primary
     call-to-action and every warning notice on the site - the same colour
     cannot mean "act now" here and "be careful" there. Green is the one
     action colour everywhere now; amber is reserved for caution. */
  background: var(--green);
  color: var(--white);
}

.button:disabled {
  cursor: progress;
  opacity: 0.68;
}

.button.secondary {
  color: var(--white);
  border-color: rgba(255, 255, 255, 0.44);
  background: rgba(255, 255, 255, 0.09);
}

.diagnostic-panel {
  width: 100%;
  padding: 22px;
  color: var(--ink);
  background: rgba(255, 255, 255, 0.94);
  border: 1px solid rgba(255, 255, 255, 0.7);
  border-radius: 8px;
  box-shadow: var(--shadow);
  backdrop-filter: blur(12px);
}

.panel-heading h2 {
  margin-bottom: 18px;
  font-size: 1.6rem;
}

.fit-form {
  display: grid;
  gap: 16px;
}

label,
fieldset {
  display: grid;
  gap: 8px;
  margin: 0;
  padding: 0;
  border: 0;
  font-weight: 700;
}

legend {
  margin-bottom: 8px;
  font-weight: 700;
}

input,
select,
textarea {
  width: 100%;
  min-height: 42px;
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 9px 11px;
  color: var(--ink);
  background: var(--white);
  font: inherit;
}

textarea {
  resize: vertical;
  line-height: 1.45;
}

input[type="range"] {
  padding: 0;
  accent-color: var(--green);
}

output {
  color: var(--green);
  font-weight: 850;
}

.segmented {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  overflow: hidden;
  border: 1px solid var(--line);
  border-radius: 8px;
}

.segmented label {
  position: relative;
  display: grid;
  place-items: center;
  min-height: 38px;
  padding: 0 8px;
  border-right: 1px solid var(--line);
  font-size: 0.88rem;
  cursor: pointer;
}

.segmented label:last-child {
  border-right: 0;
}

.segmented input {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}

.segmented input:checked + span {
  color: var(--white);
}

.segmented label:has(input:checked) {
  background: var(--green);
}

.score-card {
  display: grid;
  gap: 10px;
  margin-top: 18px;
  padding: 16px;
  border: 1px solid var(--green-200);
  border-radius: 8px;
  background: var(--green-50);
}

.score-card div {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 16px;
}

.score-label {
  color: var(--muted);
  font-weight: 800;
}

#score {
  color: var(--green-deep);
  font-size: 2.3rem;
  line-height: 1;
}

#recommendation {
  margin: 0;
  color: var(--ink-on-deep);
  line-height: 1.45;
}

.band {
  padding: 22px clamp(18px, 5vw, 70px);
  background: var(--green-950);
}

.metrics {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 1px;
  color: var(--white);
}

.metric {
  min-height: 124px;
  padding: 20px;
  border-left: 1px solid rgba(255, 255, 255, 0.14);
}

.metric:first-child {
  border-left: 0;
}

.metric strong {
  display: block;
  margin-bottom: 8px;
  color: var(--amber-300);
  font-size: 2rem;
  line-height: 1;
}

.metric span {
  color: rgba(255, 255, 255, 0.78);
  line-height: 1.4;
}

.section {
  padding: clamp(54px, 8vw, 92px) clamp(18px, 5vw, 70px);
}

.section-header {
  max-width: 760px;
  margin-bottom: 28px;
}

.contact-channel {
  margin: 0;
  color: var(--muted);
  font-size: 1rem;
  line-height: 1.5;
}

.contact-channel a,
footer a {
  color: var(--green-deep);
  font-weight: 800;
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 4px;
}

.section h2 {
  margin-bottom: 10px;
  font-size: clamp(2rem, 4vw, 3.5rem);
  line-height: 1.05;
}

.offer-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 14px;
}

.offer-grid.compact .offer-card {
  min-height: 210px;
}

/* The ladder has six rungs. In the default four-column grid that lands as
   4 + 2, orphaning Steps 4 and 5 in a ragged row — the two that carry the
   most revenue and the longest copy. Three columns give 3 + 3 and a wider
   card.
   Written as a min-width query on purpose. The narrow-screen rules below
   match .offer-grid, one class; .offer-grid.ladder is two, so it would have
   beaten them at every width regardless of source order and pinned six cards
   into three columns on a phone. Bounding it above 1040px keeps the cascade
   where the rest of the file expects it. */
@media (min-width: 1041px) {
  .offer-grid.ladder {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

.offer-card {
  display: grid;
  align-content: start;
  min-height: 280px;
  padding: 22px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--white);
}

.link-card {
  transition: border-color 160ms ease, transform 160ms ease;
}

.link-card:hover {
  border-color: var(--green);
  transform: translateY(-2px);
}

.offer-tag {
  width: fit-content;
  margin-bottom: 18px;
  padding: 5px 8px;
  border-radius: 6px;
  color: var(--amber-900);
  background: var(--amber-100);
  font-size: 0.78rem;
  font-weight: 850;
}

.offer-card h3 {
  font-size: 1.26rem;
  line-height: 1.2;
}

.offer-card p {
  color: var(--muted);
  line-height: 1.5;
}

.offer-card strong {
  align-self: end;
  color: var(--green-deep);
}

.split {
  display: grid;
  grid-template-columns: minmax(0, 0.84fr) minmax(320px, 1fr);
  gap: clamp(24px, 6vw, 80px);
  align-items: start;
  color: var(--white);
  background: var(--ink);
}

.split p {
  color: rgba(255, 255, 255, 0.78);
  line-height: 1.6;
}

.timeline {
  display: grid;
  gap: 12px;
}

.timeline div {
  padding: 18px;
  border: 1px solid rgba(255, 255, 255, 0.14);
  border-radius: 8px;
  background: rgba(255, 255, 255, 0.06);
}

.timeline span {
  display: block;
  margin-bottom: 8px;
  color: var(--amber-300);
  font-weight: 850;
}

.timeline p {
  margin: 0;
}

.contact-form {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 12px;
  align-items: end;
}

.contact-form .full {
  grid-column: 1 / -1;
}

.hotspot-context {
  margin: 0 0 18px;
  padding: 16px 18px;
  border-left: 3px solid var(--green);
  border-radius: 0 12px 12px 0;
  background: var(--green-50);
}
.hotspot-context-title {
  margin: 0;
  font-size: 0.74rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
}
.hotspot-context-area {
  margin: 4px 0 0;
  font-size: 1.05rem;
  font-weight: 700;
  color: var(--green-deep);
}
.hotspot-context-meta {
  margin: 4px 0 0;
  font-size: 0.86rem;
  color: var(--ink);
}
.hotspot-context-note {
  margin: 9px 0 0;
  font-size: 0.8rem;
  line-height: 1.55;
  color: var(--muted);
}

.hidden-field {
  display: none;
}

.consent-row {
  display: grid;
  grid-template-columns: 22px minmax(0, 1fr);
  align-items: start;
  color: var(--muted);
  font-size: 0.92rem;
  line-height: 1.45;
}

.consent-row input {
  min-height: auto;
  margin-top: 2px;
}

.brief-output {
  min-height: 130px;
  margin: 20px 0 0;
  padding: 18px;
  border: 1px solid var(--line);
  border-radius: 8px;
  overflow: auto;
  white-space: pre-wrap;
  color: var(--ink-on-tint);
  background: var(--white);
  font: 0.95rem/1.5 ui-monospace, SFMono-Regular, Consolas, "Liberation Mono", monospace;
}

footer {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 18px;
  padding: 26px clamp(18px, 5vw, 70px);
  color: rgba(255, 255, 255, 0.76);
  background: var(--ink-deep);
}

.footer-brand {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  color: var(--white);
  font-weight: 800;
}

footer a {
  color: var(--amber-300);
}

.page-hero {
  padding: 118px clamp(18px, 5vw, 70px) 54px;
  color: var(--white);
  background:
    linear-gradient(90deg, rgba(9, 16, 16, 0.92), rgba(9, 16, 16, 0.74)),
    url("./assets/hero-ev-infra.png") center/cover;
}

.page-hero h1 {
  max-width: 900px;
  margin-bottom: 16px;
  font-size: clamp(2.5rem, 6vw, 5rem);
}

.page-hero p {
  max-width: 760px;
  color: rgba(255, 255, 255, 0.86);
  font-size: 1.13rem;
  line-height: 1.55;
}

.content-grid {
  display: grid;
  grid-template-columns: minmax(0, 0.72fr) minmax(280px, 0.28fr);
  gap: clamp(24px, 5vw, 72px);
}

.content-grid article {
  display: grid;
  gap: 18px;
}

.content-grid h2 {
  font-size: clamp(1.6rem, 3vw, 2.5rem);
}

.content-grid p,
.content-grid li {
  color: var(--muted);
  line-height: 1.6;
}

.side-panel {
  position: sticky;
  top: 92px;
  align-self: start;
  padding: 20px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--white);
}

.side-panel h2 {
  font-size: 1.24rem;
}

.side-panel .button {
  width: 100%;
  margin-top: 12px;
}

@media (max-width: 1040px) {
  .hero-content {
    grid-template-columns: 1fr;
    align-items: end;
  }

  .hero-copy {
    padding-top: 70px;
  }

  .diagnostic-panel {
    max-width: 620px;
  }

  .metrics,
  .offer-grid,
  .contact-form {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .split {
    grid-template-columns: 1fr;
  }

  .content-grid {
    grid-template-columns: 1fr;
  }

  .side-panel {
    position: static;
  }
}

@media (max-width: 720px) {
  .topbar {
    position: absolute;
    align-items: flex-start;
  }

  /* The nav was display:none below 720px with no hamburger to replace it, so
     every link in the header -- Tools, Site Score, Opportunity Maps, ROI
     Calculator, Request a diagnostic -- was unreachable on a phone. Most of
     this audience is on a phone. It now stays visible and scrolls sideways
     rather than disappearing or breaking the layout. */
  nav {
    display: flex;
    flex-wrap: nowrap;
    gap: 14px;
    width: 100%;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    padding: 6px 0 2px;
    font-size: 0.86rem;
  }

  nav::-webkit-scrollbar {
    display: none;
  }

  nav a {
    white-space: nowrap;
  }

  .hero-content {
    padding-top: 86px;
  }

  h1 {
    font-size: 3.1rem;
  }

  .metrics,
  .offer-grid,
  .contact-form {
    grid-template-columns: 1fr;
  }

  .metric {
    min-height: auto;
    border-left: 0;
    border-top: 1px solid rgba(255, 255, 255, 0.14);
  }

  .metric:first-child {
    border-top: 0;
  }

  .segmented {
    grid-template-columns: 1fr;
  }

  .segmented label {
    border-right: 0;
    border-bottom: 1px solid var(--line);
  }

  .segmented label:last-child {
    border-bottom: 0;
  }

  footer {
    display: grid;
  }
}


.faq-list {
  display: grid;
  gap: 10px;
  max-width: 72ch;
}

.faq-list details {
  background: #fff;
  border: 1px solid var(--line, var(--line));
  border-radius: 12px;
  padding: 14px 18px;
}

.faq-list summary {
  cursor: pointer;
  font-weight: 600;
}

.faq-list p {
  margin: 8px 0 0;
  color: var(--muted, var(--muted));
  font-size: 0.94rem;
}

/* ---------------------------------------------------------------------------
   Tap-target sizing  (added 2026-08-10)

   Audited at 375px: 13 of 22 interactive elements were under the WCAG 2.5.8
   minimum of 24x24 CSS px. Header nav links measured 17px tall and footer links
   19px, both with zero padding — they were exactly as tall as their text.

   Inline links inside a sentence are exempt under 2.5.8 and are left alone;
   padding them would wreck the line spacing of the legal pages. This targets
   navigation only, where the tap target is the whole point.

   min-height plus flex centring rather than padding alone, so the target grows
   without shifting the layout the header already depends on.
--------------------------------------------------------------------------- */
.topbar nav a,
footer > span a {
  display: inline-flex;
  align-items: center;
  min-height: 24px;
  padding-inline: 2px;
}

@media (pointer: coarse) {
  /* Touch devices: go to the 44px platform guidance, not just the 24px floor. */
  .topbar nav a {
    min-height: 44px;
    padding-inline: 6px;
  }
  footer > span a {
    min-height: 36px;
    padding-inline: 4px;
  }
  .mode {
    min-height: 44px;
    display: flex;
    align-items: center;
    justify-content: center;
  }
}

/* Keyboard focus (2026-08-10).
   Nothing on the site defined a focus ring, so keyboard users depended on the
   browser default, which varies and disappears entirely against dark headers.
   :focus-visible means mouse users never see it.
   The suggestion list suppressed the outline and substituted var(--green-50) on white
   — about a 1.05:1 difference, effectively invisible when stepping through
   results with the arrow keys. It now keeps a real ring. */
:focus-visible{outline:3px solid var(--amber);outline-offset:2px;border-radius:2px}
.topbar :focus-visible,footer :focus-visible{outline-color:var(--amber-300)}
#suggest li:focus,#suggest li:focus-visible{outline:3px solid var(--amber);outline-offset:-3px;background:var(--green-100)}

/* Hero panel list — replaced the fit-score readout when that tool was retired
   on 2026-08-12. Kept deliberately plain: the panel's job is now to hand the
   visitor to GeoSite, not to display a number. */
.diagnostic-panel .panel-list {
  margin: 0 0 4px;
  padding-left: 18px;
  display: grid;
  gap: 6px;
  font-size: 0.93rem;
  color: var(--ink);
}
