:root {
  --bg: #0B1220;
  --surface: #141D2E;
  --surface-2: #182338;
  --border: #232D42;
  --text: #E8ECF4;
  --text-muted: #8993A8;
  --amber: #F2A93B;
  --amber-dim: #7A5A25;
  --teal: #3DD9C4;
  --teal-dim: #1F6E63;
  --radius: 14px;
  --font-display: 'Space Grotesk', sans-serif;
  --font-body: 'Inter', sans-serif;
  --font-mono: 'JetBrains Mono', monospace;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-body);
  scroll-behavior: smooth;
}

h1, h2 {
  font-family: var(--font-display);
  font-weight: 600;
  letter-spacing: -0.01em;
}

a { color: var(--teal); }

/* ---------- Header ---------- */
.site-header {
  border-bottom: 1px solid var(--border);
  position: sticky;
  top: 0;
  background: rgba(11, 18, 32, 0.9);
  backdrop-filter: blur(8px);
  z-index: 50;
}
.header-inner {
  max-width: 1100px;
  margin: 0 auto;
  padding: 14px 20px;
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.logo {
  display: flex;
  align-items: center;
  gap: 8px;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 1.05rem;
}
.lang-toggle {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 100px;
  padding: 6px 10px;
  display: flex;
  align-items: center;
  gap: 6px;
  cursor: pointer;
  color: var(--text-muted);
  font-family: var(--font-mono);
  font-size: 0.8rem;
}
.lang-opt { padding: 2px 4px; border-radius: 6px; }
.lang-opt.active { color: var(--bg); background: var(--amber); font-weight: 600; }
.lang-divider { opacity: 0.4; }

/* ---------- Ad slots ---------- */
.ad-slot {
  position: relative;
  border: 1px dashed #3a4560;
  background: repeating-linear-gradient(45deg, #10182a, #10182a 10px, #141d30 10px, #141d30 20px);
  color: var(--text-muted);
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-mono);
  font-size: 0.7rem;
  letter-spacing: 0.05em;
  text-align: center;
  border-radius: 8px;
}
/* Once a real ad image loads (script.js adds .ad-loaded), drop the dashed
   placeholder chrome entirely so the creative reads as a real ad, not a
   box with a placeholder frame around it. Slots that are still empty or
   in .img-error keep the dashed/striped styling above. */
.ad-slot.ad-loaded {
  border-color: transparent;
  background: transparent;
}
.ad-top, .ad-bottom {
  max-width: 1100px;
  margin: 20px auto;
  padding: 14px 20px;
}
/* Fixed-aspect container for the top/bottom banner slots, shaped to match
   a real 728x90 banner (~8:1). Capped at 728px — the creative's own native
   width — so it renders at true size on desktop instead of a small box
   floating in the middle of the 1100px slot; still well short of the full
   slot width so it reads as a normal ad unit, not an edge-to-edge stretch.
   aspect-ratio reserves the correct height up front so swapping in a real
   ad tag causes no layout shift. */
.ad-media {
  position: relative;
  width: 100%;
  max-width: 728px;
  aspect-ratio: 728 / 90;
  display: flex;
  align-items: center;
  justify-content: center;
}
.ad-mobile-inline { display: none; margin: 24px 20px; height: 100px; }
/* Dedicated mobile hero slot — fills the gap left by the gauge (hidden
   below 860px, see .gauge-wrap). Unlike .ad-mobile-inline (a sibling of
   .hero, so it needs its own 20px side margin), this slot is a *child* of
   .hero and stretches to .hero's content width via align-items: stretch
   on mobile (see the 860px query below) — .hero's own 20px padding
   already provides the side inset, so no horizontal margin here (adding
   one would double the inset to 40px). Only vertical margin for spacing
   above/below within the gap. aspect-ratio (not a fixed height) sizes it
   proportionally to the viewport — at a ~390px phone width this lands
   close to the gauge's old footprint, and 16:9 reads as a real standalone
   placement instead of a thin banner squeezed between text. */
.ad-mobile-hero { display: none; margin: 24px 0; aspect-ratio: 16 / 9; }
/* The house-ad placeholder graphics are banner/skyscraper shaped, not
   16:9 — contain keeps the whole creative visible (small letterboxing)
   instead of cover cropping its text/logo off, same reasoning as
   .ad-media above. */
.ad-mobile-hero img,
.ad-mobile-hero video {
  object-fit: contain;
}
.ad-side {
  width: 160px;
  min-width: 160px;
  align-self: stretch;
  writing-mode: initial;
}

/* Absolutely positioned to fill its nearest positioned ancestor exactly
   (.ad-media for top/bottom, .ad-slot itself for sidebars/mobile) — avoids
   relying on percentage-height resolving through a flex + aspect-ratio
   chain, which some browsers don't handle consistently. */
.ad-link {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
}
.ad-slot img,
.ad-slot video {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: inherit;
}
/* Top/bottom banner creatives vary in native shape per advertiser (a real
   728x90 SVG fits .ad-media's box exactly, but e.g. the current OEM parts
   ad is a ~1.9:1 photo, not a true 8:1 banner) — .ad-media's box can't be
   tuned to match every advertiser's image at once, so use contain here
   instead of the sidebar/mobile slots' cover: the full creative is always
   visible, with small letterboxing rather than cropping off its edges. */
.ad-media img,
.ad-media video {
  object-fit: contain;
}

/* If the ad image 404s or fails to load, script.js adds .img-error to the
   .ad-slot; hide the broken image/link and fall back to the dashed
   placeholder box with the ad's alt text instead of a broken-image icon. */
.ad-slot.img-error .ad-link,
.ad-slot.img-error .ad-media {
  display: none;
}
.ad-slot.img-error::after {
  content: attr(data-ad-alt);
  padding: 8px;
}

/* ---------- Hero ---------- */
.hero {
  max-width: 1100px;
  margin: 20px auto 10px;
  padding: 40px 20px 20px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 40px;
  flex-wrap: wrap;
}
.hero-text { flex: 1 1 380px; }
.hero h1 {
  font-size: clamp(1.7rem, 4vw, 2.6rem);
  margin: 0 0 14px;
  line-height: 1.15;
}
.hero-sub {
  color: var(--text-muted);
  font-size: 1.05rem;
  max-width: 480px;
  margin: 0;
}

.gauge-wrap {
  flex: 0 0 260px;
  display: flex;
  flex-direction: column;
  align-items: center;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 18px 10px 14px;
}
.gauge { width: 220px; height: 140px; }
.gauge-readout {
  display: flex;
  flex-direction: column;
  align-items: center;
  margin-top: -8px;
}
.gauge-value {
  font-family: var(--font-mono);
  font-size: 1.6rem;
  font-weight: 600;
  color: var(--amber);
}
.gauge-label {
  font-size: 0.75rem;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

/* ---------- Calculator area ---------- */
.calc-area {
  max-width: 1100px;
  margin: 20px auto;
  padding: 0 20px;
  display: flex;
  gap: 20px;
  align-items: flex-start;
  justify-content: center;
}
.calc-card {
  flex: 1 1 560px;
  max-width: 560px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 24px;
}
/* .ad-side uses align-self: stretch to match this card's height, but Trip
   Cost (4 fields + split-cost box) and Consumption (2 fields, no split
   box) render very different amounts of content — without a floor,
   switching to Consumption shrinks the card and crops the sidebar ads
   along with it. min-height pins the card at Trip Cost's (the taller tab)
   natural height so both tabs render the same height and the sidebar
   never crops. Scoped to min-width: 861px — .ad-side is hidden below
   that (see the 860px mobile query), so there's no sidebar height to
   protect there, and this rule never needs a separate reset to cancel
   it back out. Estimated from the current field/result layout — if
   fonts or copy change enough to make Trip Cost taller than this, bump
   the value up to match. */
@media (min-width: 861px) {
  .calc-card {
    min-height: 1020px;
  }
}

.mode-tabs {
  display: flex;
  background: var(--surface-2);
  border-radius: 10px;
  padding: 4px;
  margin-bottom: 18px;
}
.tab {
  flex: 1;
  background: transparent;
  border: none;
  color: var(--text-muted);
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 0.88rem;
  padding: 10px 8px;
  border-radius: 8px;
  cursor: pointer;
}
.tab.active { background: var(--amber); color: #1a1200; }

.unit-row {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 18px;
}
.unit-label { font-size: 0.8rem; color: var(--text-muted); }
.unit-toggle {
  display: flex;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 100px;
  padding: 3px;
  cursor: pointer;
}
.unit-opt {
  padding: 5px 12px;
  border-radius: 100px;
  font-family: var(--font-mono);
  font-size: 0.78rem;
  color: var(--text-muted);
}
.unit-opt.active { background: var(--teal); color: #06231f; font-weight: 600; }

.mode-panel { display: none; }
.mode-panel.active { display: block; }

.field { margin-bottom: 14px; }
.field.inline { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.field label {
  display: block;
  font-size: 0.85rem;
  color: var(--text-muted);
  margin-bottom: 6px;
}
.input-suffix {
  display: flex;
  align-items: stretch;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 10px;
  overflow: hidden;
}
.input-suffix:focus-within { border-color: var(--amber); }
.input-suffix input {
  flex: 1;
  border: none;
  background: transparent;
  color: var(--text);
  font-family: var(--font-mono);
  font-size: 1.1rem;
  padding: 12px 14px;
  min-width: 0;
}
.input-suffix input:focus { outline: none; }
/* Explicit rule rather than relying on default browser placeholder
   greying — Firefox in particular dims placeholder text via opacity on
   top of its own color, which can make it read closer to --text than
   --text-muted depending on the theme; pin both explicitly instead. */
.input-suffix input::placeholder {
  color: var(--text-muted);
  opacity: 1;
}
.input-suffix .suffix {
  display: flex;
  align-items: center;
  padding: 0 14px;
  font-family: var(--font-mono);
  font-size: 0.85rem;
  color: var(--text-muted);
  background: rgba(255,255,255,0.02);
  border-left: 1px solid var(--border);
  white-space: nowrap;
}

select {
  width: 100%;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 10px;
  color: var(--text);
  font-family: var(--font-body);
  font-size: 1rem;
  padding: 12px 14px;
}

.checkbox-row {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 0.9rem;
  color: var(--text-muted);
  cursor: pointer;
  margin-top: 4px;
}
.checkbox-row input { accent-color: var(--amber); width: 16px; height: 16px; }

.results {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
  margin-top: 20px;
}
.result-box {
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 14px;
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.result-box:first-child { grid-column: span 2; }
.result-box.eco { grid-column: span 2; border-color: var(--teal-dim); }
.result-box.small { grid-column: span 1; }
.result-box.highlight { border-color: var(--amber-dim); background: rgba(242,169,59,0.06); }
.results.no-cost .result-box.eco { grid-column: span 1; }
.result-label { font-size: 0.75rem; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.04em; }
.result-value { font-size: 1.4rem; font-weight: 600; }
.result-box:first-child .result-value { color: var(--amber); }
.result-box.eco .result-value { color: var(--teal); }
/* Shown alongside "—" so the dash reads as "waiting for input," not
   "broken"; script.js hides it (via .hidden) once a real value computes. */
.result-hint { font-size: 0.7rem; color: var(--text-muted); font-style: italic; }
.mono { font-family: var(--font-mono); }

/* Generic show/hide utility — used by resultCostBox, splitCostBox, and
   each result-hint depending on mode/input state (see calculate() in
   script.js). */
.hidden { display: none; }

.expandable {
  margin-top: 14px;
  border-top: 1px solid var(--border);
  padding-top: 12px;
}
/* Split cost only makes sense against a real total price, which
   Consumption mode doesn't compute — hidden there via .hidden (see
   calculate() in script.js). display: none removes it from flow entirely
   so .calc-card's own bottom padding closes the card cleanly instead of
   leaving a gap. */
.expandable summary {
  cursor: pointer;
  color: var(--teal);
  font-size: 0.88rem;
  font-weight: 600;
  list-style: none;
}
.expandable summary::-webkit-details-marker { display: none; }
.expandable-body { margin-top: 12px; display: flex; flex-direction: column; gap: 12px; }
.expandable .results { margin-top: 0; }

/* ---------- Info / FAQ / Tips ---------- */
.info-section, .faq-section, .tips-section {
  max-width: 760px;
  margin: 50px auto;
  padding: 0 20px;
}
.info-section h2, .faq-section h2, .tips-section h2 {
  font-size: 1.5rem;
  margin-bottom: 14px;
}
.info-section p { color: var(--text-muted); line-height: 1.6; }

.faq-list { display: flex; flex-direction: column; gap: 10px; }
.faq-item {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 14px 16px;
}
.faq-item summary {
  cursor: pointer;
  font-weight: 600;
  font-size: 0.95rem;
  list-style: none;
}
.faq-item summary::-webkit-details-marker { display: none; }
.faq-item p { color: var(--text-muted); margin: 10px 0 0; line-height: 1.6; font-size: 0.92rem; }

.tips-list { color: var(--text-muted); line-height: 1.8; padding-left: 20px; }
.tips-list li::marker { color: var(--amber); }

/* ---------- Footer ---------- */
.site-footer {
  border-top: 1px solid var(--border);
  text-align: center;
  padding: 24px 20px;
  color: var(--text-muted);
  font-size: 0.82rem;
}

/* ---------- Focus visibility ---------- */
button:focus-visible, input:focus-visible, select:focus-visible, summary:focus-visible {
  outline: 2px solid var(--teal);
  outline-offset: 2px;
}

/* ---------- Mobile ---------- */
@media (max-width: 860px) {
  .ad-side { display: none; }
  .ad-mobile-inline { display: flex; }
  .ad-mobile-hero { display: flex; }
  .calc-area { flex-direction: column; }
  .calc-card { max-width: 100%; width: 100%; }
  /* Frees up vertical space on mobile — the gauge is a nice-to-have visual,
     not essential info (the same numbers are in the result boxes below).
     .hero no longer needs flex-direction: column-reverse (that existed
     only to put the gauge above the text); switching to plain column
     keeps DOM order = visual order, so hero-text renders first and the
     .ad-mobile-hero slot after it. align-items: stretch replaces the
     base center alignment so hero-text (and the ad slot) fill the full
     width instead of shrinking to their own content width and floating
     off-center — text-align: center still centers the text within that
     full-width box. */
  .gauge-wrap { display: none; }
  /* flex-wrap: nowrap resets the desktop rule's "wrap" (needed there so
     .hero-text/.gauge-wrap can wrap at intermediate widths). Left as
     "wrap" here, a column-direction auto-height flex container with an
     aspect-ratio-sized child (.ad-mobile-hero) hits a real Chromium
     flex-layout bug: wrap's line-breaking pass computes each item's
     provisional main-axis (height) size before cross-axis stretch is
     resolved, so a child whose only content is absolutely positioned
     (zero intrinsic height) collapses to ~0 and aspect-ratio never gets
     a chance to expand it — verified by toggling this single property
     against the live DOM via the Chrome DevTools Protocol; flipping wrap
     to nowrap alone took .ad-mobile-hero's rendered height from 2px to
     the fully correct 16:9 value with no other change. It also removes
     the phantom extra height that let justify-content: space-between
     (also inherited from desktop) shove the ad slot down against .hero's
     bottom edge, leaving blank space floating above it. */
  .hero { flex-direction: column; align-items: stretch; text-align: center; flex-wrap: nowrap; }
  /* .hero-text's desktop rule (flex: 1 1 380px) sets flex-grow:1 with a
     380px flex-basis for the ROW layout's horizontal axis, so it grows to
     fill the space beside the fixed 260px .gauge-wrap. Once .hero switches
     to flex-direction: column above, that same flex-basis becomes a
     vertical size floor instead — and with .gauge-wrap display:none
     removing the only other flex-grow competitor, .hero-text inflates to
     380px tall regardless of its actual (~180px) content height. That
     dead space at the bottom of the oversized box was the "gap" above the
     ad slot — reset to content-sized (flex: 0 1 auto) on mobile so
     .hero-text only takes the height its text actually needs. */
  .hero-text { flex: 0 1 auto; }
  .hero-sub { margin: 0 auto; }
}

@media (max-width: 480px) {
  .results { grid-template-columns: 1fr; }
  .result-box, .result-box.eco, .result-box.small, .result-box:first-child { grid-column: span 1; }
  .ad-top, .ad-bottom { margin: 14px auto; padding: 8px 20px; }
  /* Below 480px, a 728x90-shaped box would be squeezed uncomfortably
     narrow. Switch to a standard mobile banner ratio (320x100) so the
     box shape matches an actual mobile creative instead of a squished
     desktop one. */
  .ad-media { max-width: 320px; aspect-ratio: 320 / 100; }
  .calc-card { padding: 18px; }
  .field.inline { flex-direction: column; align-items: stretch; }
}

@media (prefers-reduced-motion: reduce) {
  #needle { transition: none !important; }
  html { scroll-behavior: auto; }
}
