:root{
  --bg:#0c1912;
  --bg2:#122417;
  --bg3:#183020;
  --paper:#f5f0e2;
  --paper2:#ece3cc;
  --cane:#8fd14f;
  --cane-dark:#3f7a34;
  --cane-light:#c8ef9a;
  --ethanol:#f4b740;
  --ethanol-dark:#c98a1f;
  --pop:#ff5c7a;
  --pop-dark:#d63f60;
  --ink:#0f2116;
  --muted:#9db79f;
  --line: rgba(143,209,79,0.18);
  --radius: 18px;
}

/* Sugarcane-themed scrollbar, to match the cane-field aesthetic instead
   of the browser's default grey bar. Custom scrollbar styling only
   applies on desktop engines (Chrome/Edge/desktop Safari via
   ::-webkit-scrollbar, Firefox via scrollbar-color) -- iOS Safari and
   iOS Chrome always render the system's own overlay scrollbar and
   ignore both, so this is a desktop-only visual touch, not a bug if it
   doesn't show up on a phone.
   Revision (2026-08-21, real feedback: "just a green scrollbar" didn't
   read as sugarcane): real cane stalks are a warmer straw-gold-to-green
   gradient with visible darker rings at each joint/node, not a flat
   green fill. repeating-linear-gradient across the thumb's cross-axis
   draws those joint rings; the base gradient runs ethanol-gold (top) to
   cane-green (bottom) instead of green-on-green, so it actually reads
   as a stalk rather than a plain colored bar. */
::-webkit-scrollbar{ width:16px; height:16px; }
::-webkit-scrollbar-track{ background:var(--bg2); }
::-webkit-scrollbar-thumb{
  background:
    repeating-linear-gradient(180deg,
      rgba(63,122,52,0.55) 0px, rgba(63,122,52,0.55) 3px,
      rgba(0,0,0,0) 3px, rgba(0,0,0,0) 26px),
    linear-gradient(180deg, var(--ethanol) 0%, var(--cane-light) 35%, var(--cane) 70%, var(--cane-dark) 100%);
  border-radius:9px;
  border:3px solid var(--bg2);
  background-clip:padding-box;
}
::-webkit-scrollbar-thumb:hover{
  background:
    repeating-linear-gradient(180deg,
      rgba(63,122,52,0.65) 0px, rgba(63,122,52,0.65) 3px,
      rgba(0,0,0,0) 3px, rgba(0,0,0,0) 26px),
    linear-gradient(180deg, var(--ethanol-dark) 0%, var(--cane) 35%, var(--cane-light) 70%, var(--cane) 100%);
  background-clip:padding-box;
}
::-webkit-scrollbar-corner{ background:var(--bg2); }
html{ scrollbar-width:thin; scrollbar-color:var(--cane) var(--bg2); }
*{box-sizing:border-box;}
/* Real bug found via live browser inspection (2026-08-21): body{font-family}
   does NOT inherit into form controls by browser default -- only elements
   with the .btn class or their own explicit font-family were ever getting
   'Inter'. Every other button/input/select/textarea (nav-auth chip, "Check
   My Car" CTA, filter chips, etc) was silently rendering in the browser's
   native UI font (Arial on most setups) the whole time. This one rule fixes
   it everywhere at once instead of patching each class individually. */
button, input, select, textarea{ font-family:inherit; }
/* Correction (2026-08-21): this was originally written as a "Safari/WebKit
   flex-stretch quirk" fix. Live testing with a real narrow viewport (not
   just a small screenshot of the desktop layout) showed that theory was
   wrong -- max-width:100% here, alone, did NOT fix the report-form
   <select> overflow (still measured 556px wide against a 386px viewport
   after this rule was already live). The real root cause was a CSS Grid
   `1fr`-track blowout in the @media(max-width:920px) block below (see
   the comment there) -- the select's long option text was the trigger,
   but it was propagating all the way up through a whole grid track, not
   just stretching its own flex parent. Fixed at the source (minmax(0,1fr)
   + min-width:0 on the flex chain) below. Leaving max-width:100% here
   anyway as a harmless general safety net for any form control. */
select, input, textarea{ max-width:100%; }
html{scroll-behavior:smooth; overflow-x:hidden;}
/* Real bug fix, 2026-08-24: reported specifically as "the page is locked
   against left/right swipe UNTIL you open 'Report a pump's fuel blend',
   then it's swipable, then closing the form re-locks it." Part 30 already
   added maximum-scale=1.0/user-scalable=no to the viewport meta tag to
   stop the "pinch-zoom-then-pan" class of bug, but that only blocks
   PINCH gestures -- and several mobile browsers (notably Android Chrome)
   don't fully honor user-scalable=no at all for accessibility reasons, so
   it was never a complete lock on horizontal panning by itself. A taller
   page (the report form adding real height below it) is exactly the kind
   of reflow that can surface a sub-pixel horizontal overflow that's
   invisible to the eye but still swipeable once the browser's own
   dynamic UI (address bar collapse, etc.) recalculates the viewport.
   touch-action:pan-y is the direct, standard fix for "this page should
   only ever scroll vertically" -- it tells the browser to handle
   vertical touch-drags as a scroll gesture and NOT hand horizontal drags
   to page panning at all, independent of whatever the exact overflow
   trigger turns out to be. The Cane-O-Meter's own horizontal scroller
   (.timeline-card, deliberately swipeable to see all 6 years on a narrow
   phone) is explicitly re-opted back in below so this doesn't remove
   that one legitimate horizontal gesture. */
body{
  margin:0;
  background:var(--bg);
  color:var(--paper);
  font-family:'Inter',sans-serif;
  overflow-x:hidden;
  touch-action:pan-y;
}
h1,h2,h3,h4,.display{ font-family:'Space Grotesk',sans-serif; letter-spacing:-0.02em; }
.mono{font-family:'JetBrains Mono',monospace;}
a{color:inherit;}
::selection{background:var(--ethanol); color:var(--ink);}

/* background texture */
.grain-bg{
  position:fixed; inset:0; z-index:0; pointer-events:none; opacity:0.5;
  background:
    radial-gradient(circle at 15% 10%, rgba(143,209,79,0.10), transparent 40%),
    radial-gradient(circle at 85% 30%, rgba(244,183,64,0.08), transparent 45%),
    radial-gradient(circle at 50% 90%, rgba(255,92,122,0.06), transparent 40%);
}

.wrap{max-width:1180px; margin:0 auto; padding:0 24px; position:relative; z-index:2;}

/* ---------- NAV ---------- */
nav{
  position:sticky; top:0; z-index:50;
  backdrop-filter: blur(14px);
  background:rgba(12,25,18,0.72);
  border-bottom:1px solid var(--line);
}
/* Real bug report from live use (2026-08-21): `justify-content:space-between`
   on exactly 3 children (logo, .navlinks, .nav-actions) only creates 2 gaps
   total, and splits whatever free space is left between them evenly -- it
   does NOT guarantee either gap a minimum size. At a moderate (not
   ultra-wide) window, logo+navlinks+nav-actions can add up to nearly the
   full 1180px max-width, leaving almost nothing for the navlinks<->
   nav-actions gap specifically -- Glossary and the signed-in email pill
   end up nearly touching. `gap` works alongside `justify-content` as a
   floor: space-between still expands the gaps when there's room, but they
   can never collapse below this value the way they could before. */
.nav-inner{max-width:1180px; margin:0 auto; padding:14px 24px; display:flex; align-items:center; justify-content:space-between; gap:24px;}
.logo{display:flex; align-items:center; gap:10px; font-weight:700; font-size:20px;}
.logo-text{display:flex; flex-direction:column; line-height:1.05;}
.logo-e20{font-family:'Bricolage Grotesque', sans-serif; font-weight:800; font-size:11px; letter-spacing:0.14em; color:var(--ethanol); text-transform:uppercase;}
.logo-name{font-family:'Bricolage Grotesque', sans-serif; font-weight:800; font-size:22px; letter-spacing:-0.01em; color:var(--paper);}
.logo-question{font-size:10.5px; font-weight:500; color:var(--muted); font-family:'JetBrains Mono',monospace; margin-top:2px; white-space:nowrap; opacity:0.9; transition:opacity .4s ease; width:235px; overflow:hidden;}
.logo-question.fade{opacity:0;}
.logo .stalk{font-size:22px; display:inline-block; animation:sway 3.2s ease-in-out infinite;}
@keyframes sway{0%,100%{transform:rotate(-6deg);}50%{transform:rotate(6deg);}}
.navlinks{display:flex; gap:28px; font-size:14px; font-weight:500;}
.navlinks a{opacity:0.8; text-decoration:none; position:relative; padding:4px 0; transition:opacity .2s;}
.navlinks a:hover{opacity:1;}
.navlinks a::after{content:'';position:absolute;left:0;bottom:-2px;width:0;height:2px;background:var(--cane);transition:width .25s ease;}
.navlinks a:hover::after{width:100%;}
.nav-actions{display:flex; align-items:center; gap:14px;}
.navcta{
  background:var(--cane); color:var(--ink); border:none; padding:10px 18px; border-radius:999px;
  font-weight:700; font-size:13px; cursor:pointer; transition:transform .18s ease, box-shadow .18s ease;
}
.navcta:hover{transform:translateY(-2px); box-shadow:0 8px 22px rgba(143,209,79,0.35);}

/* Always-visible sign-in state, in the sticky nav -- see the comment on
   #navAuth in index.html for why this exists (a real bug report: sign-in
   state was invisible above the fold after a magic-link click). */
.nav-auth{ position:relative; display:flex; align-items:center; }
/* Real bug report from live use (2026-08-21): this was sized smaller than
   .navcta (8px/14px padding + 12.5px font here vs 10px/18px + 13px there),
   so "Sign in" visibly reads as a smaller, lower-priority button next to
   "Check My Car ->" even though they sit side by side at the same height
   in the nav. Matched the padding/font to .navcta so both buttons read as
   the same size -- the color/fill difference alone (transparent+border vs
   solid cane green) is enough to show which one is primary. */
.nav-auth-signedout{
  background:transparent; color:var(--paper); border:1px solid var(--line); padding:10px 18px;
  border-radius:999px; font-size:13px; font-weight:600; cursor:pointer; white-space:nowrap;
  transition:border-color .18s ease, color .18s ease;
}
.nav-auth-signedout:hover{ border-color:var(--cane); color:var(--cane-light); }
.nav-auth-signedin{ display:none; position:relative; }
.nav-auth-pill{
  display:flex; align-items:center; gap:7px; background:var(--bg3); border:1px solid var(--line);
  color:var(--paper); padding:6px 12px 6px 6px; border-radius:999px; cursor:pointer; font-size:12.5px;
}
.nav-auth-pill:hover{ border-color:var(--cane); }
.nav-auth-avatar{
  width:24px; height:24px; border-radius:50%; background:linear-gradient(135deg, var(--cane), var(--cane-dark));
  color:var(--ink); display:flex; align-items:center; justify-content:center; font-weight:800; font-size:12px; flex-shrink:0;
}
.nav-auth-email{ font-weight:600; }
.nav-auth-caret{ color:var(--muted); font-size:10px; transition:transform .18s ease; }
.nav-auth-pill[aria-expanded="true"] .nav-auth-caret{ transform:rotate(180deg); }
.nav-auth-menu{
  display:none; position:absolute; top:calc(100% + 8px); right:0; min-width:220px;
  background:var(--bg2); border:1px solid var(--line); border-radius:14px; padding:14px;
  box-shadow:0 16px 32px rgba(0,0,0,0.4); z-index:70;
}
.nav-auth-menu.open{ display:block; }
.nav-auth-menu-email{ font-size:12px; color:var(--muted); word-break:break-all; margin-bottom:8px; padding-bottom:8px; border-bottom:1px dashed var(--line); }
.nav-auth-menu-points{ font-size:13px; color:var(--paper); margin-bottom:10px; }
.nav-auth-menu-points span{ color:var(--cane); font-weight:700; }
.nav-auth-menu-link{
  display:block; font-size:13px; color:var(--paper); text-decoration:none; margin-bottom:10px; opacity:0.85;
}
.nav-auth-menu-link:hover{ opacity:1; color:var(--cane); }
.nav-auth-menu-signout{
  width:100%; background:transparent; border:1px solid var(--line); color:var(--pop); padding:8px 12px;
  border-radius:10px; font-size:12.5px; font-weight:600; cursor:pointer;
}
.nav-auth-menu-signout:hover{ border-color:var(--pop); background:rgba(255,92,122,0.08); }
/* Profile name editing, reachable from the account/profile menu itself
   (real feature request 2026-08-22: name editing should live where a
   person expects "edit my profile" controls to be). As of the final V1
   cleanup (2026-08-23) this is the ONLY surface for it -- the old eco-card
   copy (#displayNameInput) was removed along with the rest of that card's
   duplicate sign-in/out widget. Same saveDisplayName()/clearDisplayName()
   functions as always, just pointed at these element ids. */
.nav-auth-menu-name{ margin:10px 0; padding:10px 0; border-top:1px dashed var(--line); border-bottom:1px dashed var(--line); }
.nav-auth-menu-name label{ display:block; font-size:11px; color:var(--muted); margin-bottom:6px; }
.nav-auth-menu-name input{
  width:100%; background:var(--bg3); border:1px solid var(--line); color:var(--paper);
  padding:7px 10px; border-radius:8px; font-size:12px; margin-bottom:6px;
}
.nav-auth-menu-name-actions{ display:flex; gap:6px; margin-bottom:6px; }
.nav-auth-menu-name-actions button{
  flex:1; background:transparent; border:1px solid var(--line); color:var(--paper);
  padding:6px 8px; border-radius:8px; font-size:11px; font-weight:600; cursor:pointer;
}
.nav-auth-menu-name-actions button:hover{ border-color:var(--cane); color:var(--cane); }
.nav-auth-menu-name-status{ font-size:10.5px; color:var(--muted); line-height:1.4; }
/* Real feature request 2026-08-23: the leaderboard card used to
   auto-load and sit there permanently open, leaving the right side of the
   Community section feeling static/empty at first glance. Now it's a
   collapsed toggle by default -- click "Top Cane Farmers" to open it with
   a cane-toss animation, click again ("Minimise leaderboard") to close it
   smoothly with no animation replay. Height/opacity driven by JS adding
   .open to #leaderboardPanel in toggleDesktopLeaderboard() (app.js). */
/* Real fix, 2026-08-24, per direct request: this used to be
   justify-content:space-between with the label and chevron as two flex
   siblings -- fine when the label was long ("Top Gadbaddies Leaderboard")
   and roughly balanced the chevron's width, but with the shorter "Top
   Gadbaddies 🏆" label it visibly hugged the left edge instead of sitting
   centered in the button. Fixed properly rather than just eyeballing a
   margin: the chevron is pulled out of the flex flow entirely (absolutely
   positioned, vertically centered via top:50%/translateY(-50%) so its own
   rotate-on-open transform can compose with that via a single transform
   value) and pinned to the button's right edge regardless of button
   width. That leaves the label as the ONLY flex child, so
   justify-content:center centers it truly in the middle of the button at
   every viewport width, not just approximately -- verified at 1280px,
   768px, and 375px (iPhone-width) in the same pass that changed this. */
.leaderboard-toggle-btn{
  position:relative;
  width:100%; display:flex; align-items:center; justify-content:center; gap:10px;
  background:transparent; border:1px solid var(--line); color:var(--paper);
  padding:13px 44px; border-radius:12px; font-size:14.5px; font-weight:700; cursor:pointer;
  transition:border-color .2s ease, color .2s ease, background .2s ease;
}
.leaderboard-toggle-btn:hover{ border-color:var(--cane); color:var(--cane); background:var(--bg3); }
/* Funky display font for the label only, per direct request with visual
   references attached (bold Western/stencil-style specimens) -- scoped to
   just this one label span, not applied sitewide, so body text/inputs
   etc. keep their normal Inter/Bricolage Grotesque fonts. "Rye" (Google
   Fonts) was picked for its bracketed, wanted-poster-style caps, closest
   free/self-hostable match to the bold bracket-serif look in the
   reference images without tipping into full blackletter, which gets
   illegible at UI button sizes. Slightly larger + wider letter-spacing
   than the plain 14.5px button font because Rye's glyphs read smaller and
   denser at equivalent font-size. The 🏆 emoji still renders from the
   system emoji font regardless -- font-family fallback only ever applies
   to glyphs the custom font doesn't cover, so nothing extra needed there. */
#leaderboardToggleLabel{
  font-family:'Rye', 'Bricolage Grotesque', cursive; font-size:16px; letter-spacing:0.03em; font-weight:400;
}
.leaderboard-toggle-btn .chevron{
  display:inline-block; font-size:13px; color:var(--muted);
  position:absolute; right:18px; top:50%;
  transform:translateY(-50%) rotate(0deg);
  transition:transform .4s cubic-bezier(.2,.8,.2,1);
}
.leaderboard-toggle-btn.is-open .chevron{ transform:translateY(-50%) rotate(180deg); }

.leaderboard-panel{
  max-height:0; opacity:0; overflow:hidden;
  transition:max-height .55s cubic-bezier(.2,.8,.2,1), opacity .45s ease .05s;
}
.leaderboard-panel.open{ max-height:900px; opacity:1; }
.leaderboard-panel-inner{ padding-top:16px; position:relative; }
/* Real bug fix, 2026-08-24: same class of problem as the "My Cane Field"
   garage modal -- the row list had no height cap of its own, so it just
   kept growing the whole .leaderboard-panel (and with it the page) past
   the open/close transition's 900px ceiling instead of staying on
   screen. .leaderboard-list now caps at ~7 rows' worth of height and
   scrolls internally past that, so the toggle card itself never grows
   taller than the viewport regardless of how many Cane Farmers are on
   the board. Panel still animates open/closed exactly as before; only
   the list inside it scrolls. */
.leaderboard-list{ max-height:min(52vh, 360px); overflow-y:auto; padding-right:6px; margin-right:-6px; }

/* Real feature request 2026-08-23: a lighthearted one-liner explaining
   what the leaderboard even is, placed AFTER .leaderboard-panel in the
   DOM on purpose -- that's what makes it "slide down when opened, slide
   back up when closed" for free. It never moves itself; the panel above
   it grows/shrinks via its own max-height transition, and this blurb just
   gets pushed along by normal document flow every frame of that
   transition, so the two stay in perfect sync with zero extra JS. */
.leaderboard-blurb{
  margin-top:14px; padding-top:14px; border-top:1px dashed var(--line);
  font-size:11.5px; color:var(--muted); line-height:1.6;
}

/* Particle host for the opening "sugarcane toss" -- purely decorative,
   absolutely positioned over the panel so it never affects layout/height,
   and cleared from the DOM shortly after the toss finishes (see
   throwCaneEffect() in app.js) so nothing lingers or replays on close.
   Real feedback 2026-08-23: switched from a dozen small text emoji to a
   handful of larger real cane-illustration images (img/sugarcane-
   particle.png, the exact art supplied) -- fewer particles, each much
   bigger, closer to a real toss than a sprinkle of tiny icons. */
.leaderboard-canes{
  position:absolute; inset:-8px 0 auto 0; height:0; overflow:visible; pointer-events:none; z-index:2;
}
.cane-particle{
  position:absolute; top:0; left:0; width:44px; height:auto;
  animation:caneToss .85s cubic-bezier(.16,.84,.32,1) both;
  animation-delay:var(--delay, 0ms);
  will-change:transform, opacity;
  filter:drop-shadow(0 4px 10px rgba(0,0,0,0.35));
}
@keyframes caneToss{
  0%   { transform:translate(-60px,-10px) rotate(-45deg) scale(calc(var(--scale, 1) * .35)); opacity:0; }
  30%  { opacity:1; }
  100% { transform:translate(var(--dist,140px), var(--drop,54px)) rotate(var(--rotate,140deg)) scale(var(--scale, 1)); opacity:0; }
}
@media (prefers-reduced-motion: reduce){
  .cane-particle{ animation:none; opacity:0; }
  .leaderboard-panel{ transition:max-height .3s ease, opacity .3s ease; }
}

/* Mobile menu toggle -- hidden on desktop, .navlinks already shows as a
   normal inline row there so there's nothing for it to control. */
.nav-hamburger{
  display:none; flex-direction:column; justify-content:center; align-items:center; gap:5px;
  width:38px; height:38px; background:transparent; border:1px solid var(--line); border-radius:10px; cursor:pointer;
  flex-shrink:0;
}
.nav-hamburger span{width:18px; height:2px; background:var(--paper); border-radius:1px; transition:transform .2s ease, opacity .2s ease;}
.nav-hamburger[aria-expanded="true"] span:nth-child(1){transform:translateY(7px) rotate(45deg);}
.nav-hamburger[aria-expanded="true"] span:nth-child(2){opacity:0;}
.nav-hamburger[aria-expanded="true"] span:nth-child(3){transform:translateY(-7px) rotate(-45deg);}

/* ---------- MARQUEE ---------- */
.marquee{ background:var(--cane); color:var(--ink); font-family:'JetBrains Mono',monospace; font-weight:700; font-size:12.5px; padding:7px 0; overflow:hidden; white-space:nowrap; border-bottom:2px solid var(--ink);}
.marquee-track{display:inline-block; animation:scrollLeft 26s linear infinite;}
@keyframes scrollLeft{from{transform:translateX(0);} to{transform:translateX(-50%);}}
.marquee span{margin:0 22px;}

/* ---------- HERO ---------- */
.hero{position:relative; padding:60px 0 20px; overflow:hidden;}
.hero-grid{display:grid; grid-template-columns:1.1fr 0.9fr; gap:40px; align-items:center;}
.eyebrow{
  display:inline-flex; align-items:center; gap:8px; background:rgba(244,183,64,0.12); color:var(--ethanol);
  border:1px solid rgba(244,183,64,0.35); padding:6px 14px; border-radius:999px; font-size:12.5px; font-weight:600; font-family:'JetBrains Mono',monospace;
  margin-bottom:20px;
}
.hero h1{font-size:clamp(38px,5.4vw,64px); line-height:1.02; margin:0 0 18px; font-weight:700;}
.hero h1 .hl{color:var(--cane);}
.hero h1 .hl2{color:var(--pop);}
.hero p.lede{font-size:17px; color:var(--muted); max-width:520px; line-height:1.6; margin-bottom:30px;}
.hero-ctas{display:flex; gap:14px; flex-wrap:wrap;}
.btn{
  border:none; border-radius:14px; padding:14px 24px; font-weight:700; font-size:14.5px; cursor:pointer;
  display:inline-flex; align-items:center; gap:8px; transition:transform .18s ease, box-shadow .18s ease, background .2s;
  font-family:'Inter',sans-serif;
}
.btn-primary{background:var(--cane); color:var(--ink);}
.btn-primary:hover{transform:translateY(-3px) rotate(-0.4deg); box-shadow:0 12px 28px rgba(143,209,79,0.32);}
.btn-outline{background:transparent; border:1.5px solid var(--paper); color:var(--paper);}
.btn-outline:hover{background:var(--paper); color:var(--ink); transform:translateY(-3px);}
.btn-pop{background:var(--pop); color:#fff;}
.btn-pop:hover{transform:translateY(-3px); box-shadow:0 12px 26px rgba(255,92,122,0.35);}

/* cane-o-meter */
.meter-card{
  background:linear-gradient(160deg, var(--bg3), var(--bg2)); border:1px solid var(--line); border-radius:24px; padding:26px;
  position:relative; min-height:400px; display:flex; flex-direction:column;
}
.meter-title{font-size:13px; font-family:'JetBrains Mono',monospace; color:var(--muted); display:flex; justify-content:space-between; margin-bottom:6px;}
.meter-value{font-size:15px; color:var(--ethanol); font-weight:700;}
.cane-field{ flex:1; position:relative; display:flex; align-items:flex-end; justify-content:center; gap:10px; padding:10px 0 6px; }
.cane-stalk{ width:14px; background:linear-gradient(180deg, var(--cane-light), var(--cane) 40%, var(--cane-dark)); border-radius:8px 8px 3px 3px; position:relative; transition:height .6s cubic-bezier(.2,.9,.3,1.2); transform-origin:bottom center; animation:swayStalk 3.6s ease-in-out infinite;}
.cane-stalk::before{content:'';position:absolute; top:16%; left:0; right:0; height:3px; background:rgba(15,33,22,0.35); border-radius:2px;}
.cane-stalk::after{content:'';position:absolute; top:38%; left:0; right:0; height:3px; background:rgba(15,33,22,0.35); border-radius:2px;}
.cane-stalk .leaf{position:absolute; top:-2px; left:50%; width:26px; height:14px; background:var(--cane-light); border-radius:0 60% 0 60%; transform-origin:0 50%;}
.cane-stalk .leaf.l1{transform:translateX(-100%) rotate(-25deg);}
.cane-stalk .leaf.l2{transform:translateX(2px) rotate(20deg) scaleX(-1);}
@keyframes swayStalk{0%,100%{transform:rotate(-2.5deg);}50%{transform:rotate(2.5deg);}}
.slider-row{margin-top:16px;}
input[type=range]{width:100%; accent-color:var(--ethanol); height:4px;}
.slider-labels{position:relative; height:14px; margin-top:8px;}
.slider-labels .lbl{position:absolute; top:0; transform:translateX(-50%); font-size:11px; color:var(--muted); font-family:'JetBrains Mono',monospace; white-space:nowrap;}
.slider-labels .lbl:first-child{transform:translateX(0);}
.slider-labels .lbl:last-child{transform:translateX(-100%);}
.meter-info{cursor:help; opacity:0.6; font-size:12px; border:1px solid var(--muted); border-radius:50%; width:15px; height:15px; display:inline-flex; align-items:center; justify-content:center; margin-left:4px; transition:opacity .18s;}
.meter-info:hover{opacity:1; color:var(--ethanol); border-color:var(--ethanol);}
.meter-caption{font-size:12px; color:var(--muted); margin-top:14px; line-height:1.5; border-top:1px dashed var(--line); padding-top:12px;}

/* ---------- SECTION GENERIC ---------- */
section{padding:60px 0; position:relative;}
.section-tag{font-family:'JetBrains Mono',monospace; color:var(--ethanol); font-size:12.5px; font-weight:700; letter-spacing:0.06em; text-transform:uppercase; margin-bottom:10px; display:block;}
.section-head{max-width:640px; margin-bottom:32px;}
.section-head h2{font-size:clamp(28px,3.6vw,42px); margin:0 0 14px;}
.section-head p{color:var(--muted); font-size:15.5px; line-height:1.6;}
.card{background:var(--bg2); border:1px solid var(--line); border-radius:var(--radius);}

/* ---------- CHECKER ---------- */
.vtype-toggle{display:flex; gap:10px; margin-bottom:18px;}
.vtype-btn{background:var(--bg2); border:1px solid var(--line); color:var(--muted); padding:10px 20px; border-radius:999px; font-weight:700; font-size:13.5px; cursor:pointer; transition:all .18s;}
.vtype-btn:hover{border-color:var(--cane); color:var(--paper);}
.vtype-btn.active{background:var(--cane); color:var(--ink); border-color:var(--cane);}
.checker-card{padding:34px; display:grid; grid-template-columns:1fr 1fr 1fr auto; gap:16px; align-items:end;}
.field{display:flex; flex-direction:column; gap:6px;}
.field label{font-size:11.5px; text-transform:uppercase; letter-spacing:0.05em; color:var(--muted); font-family:'JetBrains Mono',monospace;}
select{
  background:var(--bg3); color:var(--paper); border:1px solid var(--line); border-radius:12px; padding:12px 14px; font-size:14.5px;
  font-family:'Inter',sans-serif; cursor:pointer; appearance:none;
  background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='14' height='9'><path d='M1 1l6 6 6-6' stroke='%238fd14f' stroke-width='2' fill='none'/></svg>");
  background-repeat:no-repeat; background-position:right 14px center;
}
select:disabled{opacity:0.4; cursor:not-allowed;}
.check-btn{background:var(--pop); color:#fff; border:none; border-radius:12px; padding:13px 26px; font-weight:700; cursor:pointer; white-space:nowrap; transition:transform .18s;}
.check-btn:hover{transform:translateY(-2px);}
.check-btn:disabled{opacity:0.35; cursor:not-allowed; transform:none;}

.result-wrap{margin-top:28px; display:none;}
.result-wrap.show{display:block; animation:riseIn .5s ease;}
@keyframes riseIn{from{opacity:0; transform:translateY(16px);} to{opacity:1; transform:translateY(0);}}
.result-top{display:flex; gap:18px; align-items:center; padding:24px; border-radius:18px 18px 0 0; }
.badge-ring{width:70px; height:70px; border-radius:50%; display:flex; align-items:center; justify-content:center; font-size:28px; flex-shrink:0; border:3px solid;}
.status-ok{background:rgba(143,209,79,0.12); border-color:var(--cane); color:var(--cane);}
.status-warn{background:rgba(244,183,64,0.12); border-color:var(--ethanol); color:var(--ethanol);}
.status-bad{background:rgba(255,92,122,0.12); border-color:var(--pop); color:var(--pop);}
.result-title{font-size:22px; font-weight:700; margin:0 0 4px;}
.result-sub{color:var(--muted); font-size:13.5px;}
.fuel-grid{display:grid; grid-template-columns:repeat(4,1fr); gap:1px; background:var(--line);}
.fuel-cell{background:var(--bg2); padding:18px; text-align:center;}
.fuel-cell .fname{font-family:'JetBrains Mono',monospace; font-size:12px; color:var(--muted); margin-bottom:8px;}
.gauge-track{width:100%; height:6px; border-radius:999px; background:rgba(255,255,255,0.08); overflow:hidden; margin:2px 0 10px;}
.gauge-fill{height:100%; width:0%; border-radius:999px; transition:width 900ms cubic-bezier(.2,.9,.3,1.2);}
.fuel-pill{display:inline-block; padding:4px 12px; border-radius:999px; font-size:12px; font-weight:700;}
.pill-yes{background:rgba(143,209,79,0.18); color:var(--cane);}
.pill-caution{background:rgba(244,183,64,0.18); color:var(--ethanol);}
.pill-no{background:rgba(255,92,122,0.18); color:var(--pop);}
.pill-na{background:rgba(157,183,159,0.15); color:var(--muted);}
.ai-box{margin:0; padding:22px 24px; border-radius:0 0 18px 18px; background:linear-gradient(135deg, rgba(255,92,122,0.06), rgba(244,183,64,0.06)); border-top:1px dashed var(--line);}
.ai-label{display:flex; align-items:center; gap:8px; font-family:'JetBrains Mono',monospace; font-size:11.5px; color:var(--pop); text-transform:uppercase; margin-bottom:10px; font-weight:700;}
.ai-dot{width:7px; height:7px; border-radius:50%; background:var(--pop); animation:pulse 1.4s infinite;}
@keyframes pulse{0%,100%{opacity:1;}50%{opacity:0.3;}}
.ai-text{font-size:15px; line-height:1.65; color:var(--paper);}
.ai-text.loading{color:var(--muted); font-style:italic;}

/* ---------- MAP ---------- */
.region-row{display:flex; gap:10px; flex-wrap:wrap; margin-bottom:18px;}
.region-pill{
  background:var(--bg2); border:1px solid var(--line); color:var(--paper); padding:9px 16px; border-radius:999px;
  font-size:13px; font-weight:600; cursor:pointer; display:flex; align-items:center; gap:6px; transition:all .18s;
}
.region-pill.active{background:var(--cane); color:var(--ink); border-color:var(--cane);}
.region-pill.disabled{color:var(--muted); cursor:pointer; opacity:0.65;}
.region-pill.disabled:hover{border-color:var(--ethanol); opacity:1;}
.region-pill .soon{font-family:'JetBrains Mono',monospace; font-size:9.5px; background:rgba(244,183,64,0.18); color:var(--ethanol); padding:2px 6px; border-radius:999px; text-transform:uppercase;}
.side-label{font-size:11px; text-transform:uppercase; letter-spacing:0.05em; color:var(--muted); font-family:'JetBrains Mono',monospace; margin-bottom:2px;}
.map-shell{ display:grid; grid-template-columns:280px 1fr; gap:0; border-radius:var(--radius); overflow:hidden; border:1px solid var(--line);}
.map-side{background:var(--bg2); padding:22px; display:flex; flex-direction:column; gap:10px;}
.filter-chip{
  display:flex; align-items:center; justify-content:space-between; padding:11px 14px; border-radius:12px; border:1px solid var(--line);
  cursor:pointer; font-size:13.5px; font-weight:600; transition:all .18s; background:var(--bg3);
}
.filter-chip:hover{border-color:var(--cane);}
.filter-chip.active{background:rgba(143,209,79,0.14); border-color:var(--cane); color:var(--cane);}
.filter-chip .swatch{width:10px; height:10px; border-radius:50%; margin-right:8px;}
.filter-chip-label{display:flex; align-items:center;}
#map-el{height:560px; width:100%;}
.map-note{font-size:11.5px; color:var(--muted); line-height:1.5; margin-top:auto; padding-top:14px; border-top:1px dashed var(--line);}
.leaflet-popup-content-wrapper{background:var(--bg2); color:var(--paper); border-radius:14px;}
.leaflet-popup-tip{background:var(--bg2);}
.popup-title{font-weight:700; font-size:14.5px; margin-bottom:4px; font-family:'Space Grotesk',sans-serif;}
.popup-addr{font-size:12px; color:var(--muted); margin-bottom:8px;}
.popup-tags{display:flex; gap:5px; flex-wrap:wrap; margin-bottom:10px;}
.popup-tag{font-size:10px; font-family:'JetBrains Mono',monospace; padding:2px 8px; border-radius:999px; background:rgba(143,209,79,0.15); color:var(--cane);}
.popup-dirs{display:flex; gap:6px;}
.popup-dirs a{flex:1; text-align:center; font-size:11px; font-weight:700; padding:7px 4px; border-radius:8px; text-decoration:none; background:var(--bg3); color:var(--paper); border:1px solid var(--line);}
.popup-dirs a:hover{background:var(--cane); color:var(--ink);}

/* Real fix, 2026-08-24, per direct request: popup-flagrow (Confirm
   accurate / Flag as wrong / Report fuel here) never had its own CSS
   rule at all -- unlike popup-dirs right above it, which is why those
   three rendered as bare blue underlined browser-default links instead
   of buttons, looking out of place directly under three real button-
   styled directions links. Same button shape/sizing as popup-dirs so the
   two rows read as one consistent set, but each gets its own hover tint
   matching what the action actually does: green for the positive
   "confirm" action, red/pink for "flag", amber for "report fuel" (the
   fuel/ethanol color used everywhere else on the site). Labels wrap to a
   second line rather than truncating, since "Confirm accurate" and
   "Report fuel here" don't fit one line at popup width -- wrapping reads
   fine on a button this size and keeps every word intact. */
.popup-flagrow{display:flex; gap:6px; margin-top:8px;}
.popup-flagrow a{flex:1; text-align:center; font-size:10.5px; font-weight:700; line-height:1.35; padding:7px 4px; border-radius:8px; text-decoration:none; background:var(--bg3); color:var(--paper); border:1px solid var(--line); transition:transform .15s ease, box-shadow .15s ease, background-color .15s ease, color .15s ease;}
.popup-flagrow a:hover{transform:translateY(-2px);}
.popup-flagrow a:nth-child(1):hover{background:var(--cane); color:var(--ink); box-shadow:0 8px 18px rgba(143,209,79,0.32);}
.popup-flagrow a:nth-child(2):hover{background:var(--pop); color:#fff; box-shadow:0 8px 18px rgba(255,92,122,0.32);}
.popup-flagrow a:nth-child(3):hover{background:var(--ethanol); color:var(--ink); box-shadow:0 8px 18px rgba(244,183,64,0.32);}

/* racing-map route lines + pulsing station markers */
.route-line{ stroke-dasharray:10 8; animation:raceDash 0.7s linear infinite; filter:drop-shadow(0 0 3px currentColor); }
@keyframes raceDash{ to{ stroke-dashoffset:-36; } }
/* Real bug found live 2026-08-22 (part 7) from a user screenshot: with a
   single fuel filter active, every matching pin appeared to "float
   randomly" instead of pulsing in place. Root cause: raceToFuelType() adds
   the 'pulse-marker' class straight onto m.getElement() -- that's Leaflet's
   OWN positioned marker element, which Leaflet keeps on the map by setting
   its `transform: translate3d(x,y,0)` inline style directly. This rule
   animated `transform:scale(...)` on that exact same element, and a CSS
   animation on a property fully overrides any inline value for that
   property for the animation's whole duration -- so every pulsing marker's
   real map position (Leaflet's translate3d) was being clobbered by the
   scale-only animation and rendered wherever the browser puts an
   untransformed element, snapping back only between pulses. Fixed by
   animating a separate inner element instead: stationIcon()'s divIcon HTML
   is one child <div> inside that outer positioned element, so scoping this
   rule to `.pulse-marker > div` scales that inner circle without ever
   touching the outer element's own positioning transform. */
.pulse-marker > div{ animation:pulseMarker 1.1s ease-in-out infinite; }
@keyframes pulseMarker{ 0%,100%{ transform:scale(1); } 50%{ transform:scale(1.35); } }
.hq-marker{ animation:hqSpin 3.5s linear infinite; transform-origin:center; }
@keyframes hqSpin{ from{ filter:drop-shadow(0 0 2px #ff5c7a); } 50%{ filter:drop-shadow(0 0 8px #ff5c7a); } to{ filter:drop-shadow(0 0 2px #ff5c7a); } }
.you-marker{ animation:youPulse 1.6s ease-in-out infinite; transform-origin:center; }
@keyframes youPulse{ 0%,100%{ filter:drop-shadow(0 0 3px #7ac6f0); } 50%{ filter:drop-shadow(0 0 10px #7ac6f0); } }
.nearest-item{display:flex; justify-content:space-between; align-items:center; padding:9px 10px; border-radius:10px; background:var(--bg3); border:1px solid var(--line); cursor:pointer; margin-top:6px; transition:border-color .18s;}
.nearest-item:hover{border-color:var(--cane);}
.nearest-item .nname{font-size:12.5px; font-weight:600; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; max-width:150px;}
.nearest-item .ndist{font-size:11px; font-family:'JetBrains Mono',monospace; color:var(--ethanol); white-space:nowrap; margin-left:8px;}
.popup-distance{font-size:11px; color:var(--ethanol); font-family:'JetBrains Mono',monospace; margin-bottom:6px;}

/* ---------- CANE-O-METER TIMELINE ---------- */
.timeline-card{padding:36px; overflow-x:auto; touch-action:pan-x pan-y;}
.tl-row{display:flex; align-items:flex-end; gap:22px; min-width:760px; height:220px; padding-bottom:10px; border-bottom:1px solid var(--line);}
.tl-col{display:flex; flex-direction:column; align-items:center; gap:8px; flex:1;}
.tl-year{font-size:11px; color:var(--muted); font-family:'JetBrains Mono',monospace;}

/* Real feature, 2026-08-24: swapped the flat gradient .tl-bar for the
   actual sugarcane photo asset (img/sugarcane-particle.png, same
   transparent-background image used in the leaderboard toss animation),
   plus small decorative bushes at each stalk's base, both with a subtle
   hover wobble. Layout notes so nothing overlaps:
   - .tl-cane-wrap is a fixed 90px-wide box per column. The cane image's
     HEIGHT is set directly in px by JS (proportional to that year's
     blend %, same pct*8 scale the old bar used) with width:auto, so the
     stalk visibly grows/shrinks with the data like before, and stays
     centered in the 90px box even at its widest (~82px at the current
     max of 20.0%).
   - The % tag sits at top:-22px above the wrap -- same offset the old
     .tl-bar used -- so it's always well clear of the tallest stalk
     (shortest real value is 8.1% = 64.8px tall, far more than the
     22px gap needs).
   - The bush is bottom:0 *inside* the wrap, only 16px tall, so it only
     ever overlaps the lower 16px of the stalk graphic itself -- it never
     reaches up into the % tag and never reaches down past the wrap into
     the gap/year label below. Its color is --cane-light at low opacity
     (not the saturated --cane) specifically so any text near it stays
     legible, though at this position nothing actually sits behind it.
   - Cane and bush wobble only on hover, in opposite rotation directions
     (bush mirrors the cane's angle) so they read as swaying against each
     other rather than as one rigid unit, and both run slow (3.4s) with a
     tiny 2deg amplitude so it's a lazy sway, not a shake. Respects
     prefers-reduced-motion. */
.tl-cane-wrap{position:relative; width:90px; display:flex; align-items:flex-end; justify-content:center;}
.tl-cane-wrap .tag{position:absolute; top:-22px; left:50%; transform:translateX(-50%); font-size:11px; font-family:'JetBrains Mono',monospace; color:var(--ethanol); white-space:nowrap; z-index:3;}
.tl-cane{height:4px; width:auto; max-width:82px; display:block; position:relative; z-index:2; transform-origin:bottom center; transition:height 1s cubic-bezier(.2,.9,.3,1);}
.tl-bush{position:absolute; bottom:0; left:50%; width:54px; height:16px; transform:translateX(-50%); z-index:1; pointer-events:none; transform-origin:bottom center;}
.tl-bush::before,.tl-bush::after{content:''; position:absolute; bottom:0; width:26px; height:15px; border-radius:50% 50% 40% 40% / 65% 65% 35% 35%; background:var(--cane-light); opacity:0.38;}
.tl-bush::before{left:-3px;}
.tl-bush::after{right:-3px; transform:scaleX(-1);}
@keyframes caneWobble{0%,100%{transform:rotate(0deg);} 50%{transform:rotate(2deg);}}
@keyframes bushWobble{0%,100%{transform:translateX(-50%) rotate(0deg);} 50%{transform:translateX(-50%) rotate(-2deg);}}
.tl-col:hover .tl-cane{animation:caneWobble 3.4s ease-in-out infinite;}
.tl-col:hover .tl-bush{animation:bushWobble 3.4s ease-in-out infinite;}
@media (prefers-reduced-motion: reduce){
  .tl-col:hover .tl-cane, .tl-col:hover .tl-bush{animation:none;}
}

/* ---------- CALCULATOR ---------- */
.calc-grid{display:grid; grid-template-columns:1fr 1fr; gap:24px;}
.calc-inputs{padding:30px; display:flex; flex-direction:column; gap:18px;}
.calc-inputs input{background:var(--bg3); border:1px solid var(--line); color:var(--paper); padding:12px 14px; border-radius:12px; font-size:14.5px; width:100%; font-family:'Inter',sans-serif;}
.calc-results{padding:30px; display:flex; flex-direction:column; gap:14px;}
.calc-result-row{display:flex; justify-content:space-between; align-items:center; padding:14px 16px; border-radius:12px; background:var(--bg3);}
.calc-result-row .rname{font-weight:600; font-size:14px;}
.calc-result-row .rval{font-family:'JetBrains Mono',monospace; font-weight:700; color:var(--cane);}

/* ---------- FAQ ---------- */
.faq-item{border-bottom:1px solid var(--line); padding:20px 4px; cursor:pointer;}
.faq-q{display:flex; justify-content:space-between; align-items:center; font-weight:600; font-size:16px;}
.faq-q .plus{transition:transform .25s; color:var(--cane); font-size:20px;}
.faq-item.open .plus{transform:rotate(45deg);}
.faq-a{max-height:0; overflow:hidden; transition:max-height .35s ease; color:var(--muted); font-size:14.5px; line-height:1.6;}
.faq-item.open .faq-a{max-height:200px; margin-top:12px;}

/* ---------- ECO POINTS ---------- */
.eco-grid{display:grid; grid-template-columns:1.2fr 1fr; gap:24px; align-items:stretch;}
.eco-card{padding:30px;}
.eco-points{display:flex; align-items:baseline; gap:10px; margin-bottom:6px;}
.eco-points .num{font-size:44px; font-weight:700; color:var(--ethanol); font-family:'Space Grotesk',sans-serif;}
.eco-actions{display:flex; flex-direction:column; gap:10px; margin-top:18px;}
.eco-btn{display:flex; justify-content:space-between; align-items:center; background:var(--bg3); border:1px solid var(--line); padding:13px 16px; border-radius:12px; cursor:pointer; font-size:13.5px; font-weight:600; transition:all .18s;}
.eco-btn:hover{border-color:var(--ethanol);}
.eco-btn .pts{color:var(--ethanol); font-family:'JetBrains Mono',monospace;}
.badge-row{display:flex; gap:10px; flex-wrap:wrap; margin-top:16px;}
.badge-pill{padding:6px 12px; border-radius:999px; font-size:11.5px; font-weight:700; background:rgba(157,183,159,0.12); color:var(--muted); border:1px solid var(--line);}
.badge-pill.unlocked{background:rgba(244,183,64,0.16); color:var(--ethanol); border-color:var(--ethanol);}

/* ---------- QUIZ ---------- */
.quiz-card{padding:34px;}
.quiz-opts{display:grid; grid-template-columns:1fr 1fr; gap:12px; margin-top:18px;}
.quiz-opt{background:var(--bg3); border:1px solid var(--line); padding:16px; border-radius:14px; cursor:pointer; font-size:14px; transition:all .18s;}
.quiz-opt:hover{border-color:var(--pop); transform:translateY(-2px);}
.quiz-result{display:none; margin-top:20px; padding:20px; border-radius:14px; background:rgba(255,92,122,0.08); border:1px solid rgba(255,92,122,0.3);}
.quiz-result.show{display:block; animation:riseIn .4s ease;}

/* share modal */
.modal-overlay{position:fixed; inset:0; background:rgba(0,0,0,0.6); z-index:200; display:flex; align-items:center; justify-content:center; padding:20px; animation:riseIn .2s ease;}
.modal-card{background:var(--bg2); border:1px solid var(--line); border-radius:20px; padding:28px; max-width:440px; width:100%; position:relative; max-height:calc(100vh - 40px); display:flex; flex-direction:column;}
/* Real bug fix, 2026-08-24: "My Cane Field" has no cap on saved vehicles.
   Once a user had 5+ vehicles the card just grew past the viewport with
   no way to reach the rest. .modal-card is now capped to the viewport
   (matching .modal-overlay's own 20px-per-side padding) and laid out as
   a column so only #garageModalBody -- the one part that actually grows
   with vehicle count -- scrolls internally; the title and close button
   stay put. Every other modal (sign-in, share, etc.) is short enough
   that the inner scroll never engages, so this is safe site-wide. */
#garageModalBody{overflow-y:auto; padding-right:4px; min-height:0;}
.modal-title{font-family:'Space Grotesk',sans-serif; font-weight:700; font-size:18px; margin-bottom:14px;}
.modal-preview{background:var(--bg3); border:1px solid var(--line); border-radius:12px; padding:14px 16px; font-size:13.5px; line-height:1.6; color:var(--paper); margin-bottom:18px;}
.modal-actions{display:flex; flex-wrap:wrap; gap:10px;}
.modal-actions .btn{flex:1; min-width:120px; justify-content:center; font-size:13px; padding:11px 14px;}
.modal-close{position:absolute; top:16px; right:16px; background:none; border:none; color:var(--muted); font-size:16px; cursor:pointer; padding:4px;}
.modal-close:hover{color:var(--paper);}

/* ---------- FOOTER ---------- */
footer{padding:60px 0 40px; border-top:1px solid var(--line);}
.foot-grid{display:grid; grid-template-columns:2fr 1fr 1fr; gap:40px;}
.foot-note{font-size:12.5px; color:var(--muted); line-height:1.7; max-width:420px;}
.foot-col h4{font-size:13px; margin-bottom:14px; color:var(--paper);}
.foot-col a{display:block; font-size:13.5px; color:var(--muted); text-decoration:none; margin-bottom:9px;}
.foot-col a:hover{color:var(--cane);}
.foot-bottom{margin-top:40px; padding-top:20px; border-top:1px dashed var(--line); display:flex; justify-content:space-between; font-size:12px; color:var(--muted); flex-wrap:wrap; gap:10px;}

.disclaimer-banner{
  background:rgba(244,183,64,0.08); border:1px solid rgba(244,183,64,0.3); border-radius:14px; padding:14px 18px; font-size:12.5px; color:var(--muted); line-height:1.6; margin-bottom:34px;
}
.disclaimer-banner b{color:var(--ethanol);}

/* ---------- RESPONSIVE ---------- */
@media(max-width:920px){
  /* Real bug found via live phone screenshots + a real narrow-viewport
     render test (2026-08-21, using an iframe pinned to 390px width so
     media queries actually apply -- window.resizeTo doesn't work in this
     testing setup, so this was the only way to get a genuine narrow
     viewport instead of a desktop layout screenshotted small).
     A bare `1fr` grid track is NOT the same as "shrink to fit the
     container" -- by spec a `1fr` track still carries an implicit
     min-width:auto, so if ANY child can't shrink below its own
     content width (the worst offender here: the "Where is it?" <select>
     in the report-a-pump form, whose longest <option> text is long
     enough to force its own intrinsic width past a phone screen), the
     whole grid track -- and therefore .eco-card / .checker-card / etc,
     and everything inside them -- gets stretched out to fit it. That one
     grid item then overflows every ancestor up to <body>, which is what
     actually produced "abnormal screen ratio, requires manual pinch/zoom
     to use", and separately reads as "shrunk, clustered content with
     void spaces" -- that's the OK content rendered at its real (narrower)
     size while sitting inside a wider, overflowed, mostly-empty box.
     `min-width:0` on the flex .field/select chain (added below) was step
     one but didn't fix it -- confirmed live (reportForm still measured
     556px wide against a 386px viewport after that alone). The actual
     fix is `minmax(0,1fr)` instead of `1fr` on every grid track in this
     breakpoint, which removes that implicit auto-minimum and forces the
     track to actually respect the container width. Verified after this
     fix: document.body.scrollWidth === document.documentElement.clientWidth
     (zero horizontal overflow) at a real 390px viewport, and the report
     form, hero, checker, and fuel-map sections all render fully inside
     the screen with no zoom needed. */
  .hero-grid{grid-template-columns:minmax(0,1fr);}
  .checker-card{grid-template-columns:minmax(0,1fr);}
  .map-shell{grid-template-columns:minmax(0,1fr);}
  .calc-grid, .eco-grid, .foot-grid{grid-template-columns:minmax(0,1fr);}
  .fuel-grid{grid-template-columns:minmax(0,1fr) minmax(0,1fr);}
  .quiz-opts{grid-template-columns:minmax(0,1fr);}
  /* Belt-and-suspenders for the same underlying issue in flex contexts
     (#reportForm and its .field children are flex columns, so a select
     with a long option can force ITS OWN flex item wider too, same root
     cause as above but for flexbox instead of grid). Doesn't fix the
     grid blowout by itself (confirmed live) but still needed so the
     select truncates to the field's real width instead of the field
     growing to the select's content width in the first place. */
  .field, #reportForm, .fuel-report-row{ min-width:0; }
  select, input, textarea{ min-width:0; }

  /* .navlinks used to just be display:none here with nothing replacing
     it -- a phone user lost all in-page navigation except the one CTA
     button, and had to manually scroll to reach Brands/Fuel Map/Savings
     Calc/Myths/Glossary. Now it's a dropdown panel toggled by
     .nav-hamburger (navToggle() in app.js adds/removes .open). */
  /* Real bug report from live phone screenshots (2026-08-21): on mobile
     .nav-inner wraps and .nav-actions (pill/sign-in + CTA + hamburger)
     drops to its own row -- but that row defaulted to flex-start, so the
     whole group hugged the left edge with the hamburger sitting wherever
     the group's content happened to end, nowhere near the right edge of
     the phone. Read exactly like "hamburger weirdly placed in the middle,
     not to the right" and, combined with no vertical margin, like the
     buttons were crammed against the tagline above and the marquee below.
     First attempt at a fix used width:100% + justify-content:space-between
     on .nav-actions -- that was WRONG and created a different version of
     the same complaint: space-between spreads ALL of its children apart
     evenly, and with 3 children (sign-in, CTA, hamburger) that put "Check
     My Car" floating alone in the dead centre of the row instead of
     sitting next to sign-in, which is exactly what the next round of live
     testing reported ("Check My Car looks weird in the centre, should be
     shifted left with sign-in"). Confirmed by re-reading the actual
     screenshot from that verification pass instead of just checking
     "is the hamburger on the right" -- it was, but at the cost of breaking
     the sign-in/CTA grouping. Real fix: leave .nav-actions at its default
     justify-content (flex-start) so sign-in and CTA sit together using
     their existing gap:14px, and push ONLY the hamburger to the right
     edge with its own margin-left:auto (which consumes all remaining
     flex space on its own, without touching the other two items). */
  .nav-inner{position:relative; flex-wrap:wrap; row-gap:12px;}
  .nav-actions{width:100%; margin-top:2px;}
  .nav-hamburger{display:flex; margin-left:auto;}
  /* Room is tight next to the CTA + hamburger on a phone -- keep the
     avatar/caret as the tap target but drop the email text so the chip
     doesn't fight the rest of the nav for space. Full email is still in
     the dropdown once tapped. */
  .nav-auth-email{ display:none; }
  .nav-auth-signedout{ padding:8px 10px; font-size:11.5px; }
  /* Real bug found via live phone screenshots + a real narrow-viewport
     render test (2026-08-21): this `right:-8px` was written assuming
     .nav-auth still sits near the RIGHT edge of the nav bar like it does
     on desktop. On mobile, .nav-inner wraps (flex-wrap:wrap, see
     .nav-inner rule above) and .nav-actions -- the pill + CTA + hamburger
     group -- drops to a new row starting from the LEFT edge instead of
     staying pinned right. Anchoring a 220px-wide dropdown via `right`
     off an element that's now near x=24 instead of near the right edge
     pushed the menu's own left edge to roughly -130px -- entirely off
     the left side of the screen, unrecoverable by zooming out because
     zooming doesn't change layout position, only scale. This is exactly
     what "you can't see your eco points, it's out of the screen, doesn't
     appear on zoom out" was. Verified live: switching to `left` (where
     .nav-auth actually is on mobile) puts the whole menu on-screen.
     max-width is a safety net in case an even narrower phone still can't
     fit the full 220px. */
  .nav-auth-menu{ left:-8px; right:auto; max-width:calc(100vw - 32px); }
  .navlinks{
    display:none; flex-direction:column; gap:0; width:100%;
    position:absolute; top:100%; left:0; right:0;
    background:var(--bg2); border:1px solid var(--line); border-top:none;
    border-radius:0 0 16px 16px; padding:8px 24px 14px; z-index:60;
    box-shadow:0 16px 32px rgba(0,0,0,0.35);
  }
  .navlinks.open{display:flex;}
  .navlinks a{padding:12px 4px; border-bottom:1px dashed var(--line);}
  .navlinks a:last-child{border-bottom:none;}

  /* iOS Safari auto-zooms the whole page when a form control with
     font-size under 16px receives focus, and the zoom/pan state often
     doesn't cleanly reset afterward -- reads exactly like "the screen
     widens up and the original frame is lost" (a real bug report from a
     phone). Every input/select on this site was sized well under 16px
     for visual density (12-14.5px), which is fine on desktop where this
     zoom behavior doesn't exist, but breaks every text field, dropdown,
     and the fuel-report modal's <select> rows on an iPhone. Fixing with
     a floor here instead of touching each declaration -- desktop
     typography is untouched, only viewports narrow enough to be phones
     get the 16px floor. `!important` is deliberate: several of these
     fields set font-size via inline style (highest specificity short of
     !important) in JS-generated modal markup, so a plain rule wouldn't
     win against them. */
  input, select, textarea{ font-size:16px !important; }

  /* A <select> inside a flex row (the fuel-status dropdowns in the report
     modal and the community-report form) defaults to min-width:auto, so
     its own content can force the flex item wider than its flex-basis
     instead of shrinking to fit -- normally masked by the small font-size
     above, more likely to actually show up now that the fix above makes
     that text bigger. min-width:0 lets it shrink and wrap/ellipsis
     instead of pushing the row (and the page) wider than the viewport. */
  .fr-status, .frr-status{ min-width:0; }

  /* Real bug report from live phone screenshots (2026-08-21): the scrolling
     marquee ("SUGARCANE ACTUALLY MAKES YOUR ETHANOL" etc) uses a bold,
     uppercase, letter-spaced monospace font -- at the same 12.5px it uses
     on desktop, that combination reads much larger and chunkier on a
     narrow phone screen than the numeric size suggests, and eats a
     disproportionate amount of vertical space right below an already-
     tight nav. Sized down and tightened up for phones only; desktop is
     untouched. */
  .marquee{ font-size:10.5px; padding:6px 0; }
}
:focus-visible{outline:2px solid var(--ethanol); outline-offset:2px;}
@media (prefers-reduced-motion: reduce){
  *{animation-duration:0.001s !important; transition-duration:0.001s !important;}
}
