/* =========================================================================
 * RainOrRinse — styles.css
 * =========================================================================
 * Design system, layout, components, themes (light/dark), splash, mobile.
 *
 * Section index:
 *   - Design tokens                  : :root  vars
 *   - Mobile tightening               : @media (max-width: 380px)
 *   - Touch tap targets               : @media (hover: none) and (pointer: coarse)
 *   - Splash loader                   : .splash + @keyframes
 *   - Subtle radial background        : body::before
 *   - Topbar                          : .topbar, .brand, .loc, .iconbtn
 *   - Screens                         : .screen + animations
 *   - Hero card                       : .hero
 *   - Chips                           : .chip
 *   - Score ring                      : .ring + svg
 *   - Impact window card              : .impact
 *   - Section titles + cards          : .section-title, .card, .kv
 *   - Buttons                         : .btn (primary, ghost, danger)
 *   - Forecast timeline               : .timeline, .day, .hours, .forecast-legend
 *   - Wash log entries                : .log-entry
 *   - Forms                           : .field, .opts, .opt, .tiles, .tile, .swatches, .swatch
 *   - Bottom nav                      : .nav
 *   - Onboarding                      : .onboard
 *   - Modals                          : .modal
 *   - Banners                         : .banner, .alert, .update-banner, .consent
 *   - Sponsored mentions              : .sponsored, .sponsored-tag, .ad
 *   - Version tag                     : .version-tag
 * ========================================================================= */

/* ===== Defensive fallbacks — guarantee something renders even if vars fail ===== */
html,body{background:#FBF7F2;color:#1A2638}
html[data-theme="dark"],html[data-theme="dark"] body{background:#0B1220;color:#F5F7FA}
.app{background:transparent;min-height:100vh}
.hero{background:#FFFFFF;color:#1A2638}
.card{background:#FFFFFF;color:#1A2638}
html[data-theme="dark"] .hero{background:#1B243C;color:#F5F7FA}
html[data-theme="dark"] .card{background:#141C2F;color:#F5F7FA}
.hero-status, .hero-reason, .hero-label, .impact-title, .impact-sub, .kv .k, .kv .v{color:inherit}
/* ============================================================================== */




/* ========== Design tokens ========== */
:root{
  /* === Dark theme (premium but readable — cards now visibly stand off the bg) === */
  --bg:#0B1220;
  --bg-2:#121A2E;
  --surface:rgba(255,255,255,0.07);
  --surface-2:rgba(255,255,255,0.11);
  --surface-strong:#1B243C;
  --line:rgba(255,255,255,0.10);
  --line-2:rgba(255,255,255,0.18);
  --text:#F5F7FA;
  --text-2:#9BA4B8;
  --text-3:#5F687E;
  --rain:#5AA9FF;
  --rain-2:#1F6CD2;
  --rain-soft:rgba(90,169,255,0.14);
  --good:#3DDC97;
  --good-2:#1FA876;
  --warn:#F4B740;
  --bad:#FF6E6E;
  --accent:#9FD0FF;
  --radius:16px;
  --radius-lg:22px;
  --radius-xl:28px;
  --shadow-sm:0 1px 2px rgba(0,0,0,0.30);
  --shadow:0 18px 40px -16px rgba(0,0,0,0.55), 0 2px 6px rgba(0,0,0,0.30);
  --shadow-lg:0 30px 60px -20px rgba(0,0,0,0.70);
  --glow:0 0 0 1px rgba(255,255,255,0.04) inset;
  --font:"SF Pro Display","SF Pro Text",-apple-system,BlinkMacSystemFont,"Inter","Segoe UI",system-ui,sans-serif;
  --safe-top:env(safe-area-inset-top,0px);
  --safe-bot:env(safe-area-inset-bottom,0px);
}

  /* === Light theme (soft, sleek — inspired by the reference mockup) === */
  html[data-theme="light"]{
    --bg:#FBF7F2;            /* warm cream */
    --bg-2:#FFFFFF;
    --surface:#FFFFFF;
    --surface-2:#F4EFE7;     /* peach-cream card hover */
    --surface-strong:#FFFFFF;
    --line:rgba(15,30,60,0.06);
    --line-2:rgba(15,30,60,0.12);
    --text:#1A2638;
    --text-2:#5B6678;
    --text-3:#8B95A8;
    --rain:#2BAFAF;          /* soft teal — primary accent */
    --rain-2:#1E8E8E;
    --rain-soft:rgba(43,175,175,0.10);
    --good:#5BC9A7;
    --good-2:#3FAA89;
    --warn:#E8A340;
    --bad:#E26B6B;
    --accent:#2BAFAF;
    --shadow-sm:0 1px 2px rgba(20,40,80,0.04);
    --shadow:0 12px 32px -14px rgba(40,80,120,0.16), 0 2px 6px rgba(40,80,120,0.04);
    --shadow-lg:0 26px 56px -20px rgba(40,80,120,0.22);
    --glow:0 0 0 1px rgba(0,0,0,0.02) inset;
  }


  html[data-theme="auto"]{--bg:#F4F6FB; --bg-2:#FFFFFF;
    --surface:rgba(255,255,255,0.85); --surface-2:rgba(255,255,255,0.95); --surface-strong:#FFFFFF;
    --line:rgba(15,30,60,0.07); --line-2:rgba(15,30,60,0.14);
    --text:#0B1220; --text-2:#4B5566; --text-3:#8089A0;
    --shadow-sm:0 1px 2px rgba(15,30,60,0.05);
    --shadow:0 16px 40px -16px rgba(15,30,60,0.18), 0 2px 6px rgba(15,30,60,0.04);
    --shadow-lg:0 30px 60px -20px rgba(15,30,60,0.28);
    --glow:0 0 0 1px rgba(0,0,0,0.02) inset;
    --rain-soft:rgba(90,169,255,0.10);}

/* ===== Mobile-specific tightening (small phones, narrow widths) ===== */
@media (max-width: 380px){
  .topbar{padding:14px 16px 8px}
  .brand{font-size:14px}
  .loc{max-width:130px;font-size:11px}
  .iconbtn{width:30px;height:30px}
  .screen{padding:8px 14px 20px}
  .hero{padding:10px 12px 8px;border-radius:16px}
  /* phone: 1-line reason by default */
  .hero-reason{-webkit-line-clamp:1;font-size:12px}
  /* v1.27.1 — on 380px phones hero-status clamp resolves to ~19px, keep bold */
  .hero-status{font-size:clamp(20px,5vw,24px)}
  .impact-title{font-size:20px}
  .opts{gap:6px}
  .opt{padding:10px 12px}
  .tiles{grid-template-columns:repeat(3,1fr);gap:6px}
  .swatches{grid-template-columns:repeat(4,1fr);gap:6px}
  .swatch .dot{width:24px;height:24px}
  .btn{padding:12px 14px;font-size:14.5px}
}
/* Touch-friendly tap targets (iOS minimum 44pt) */
@media (hover: none) and (pointer: coarse){
  .btn{min-height:44px}
  .iconbtn{min-width:36px;min-height:36px}
  .opt,.tile,.swatch{min-height:44px}
  .nav button{min-height:54px}
}


/* ===== Seasonal / monsoon notice ===== */
.seasonal-card{margin:14px 0 0;background:linear-gradient(180deg,rgba(90,169,255,0.10),rgba(90,169,255,0.02));
  border:1px solid rgba(90,169,255,0.30);border-radius:14px;padding:12px 14px;
  display:flex;gap:12px;align-items:flex-start}
html[data-theme="light"] .seasonal-card{background:linear-gradient(180deg,rgba(43,175,175,0.10),rgba(43,175,175,0.02));border-color:rgba(43,175,175,0.30)}
.seasonal-icon{font-size:24px;line-height:1;flex-shrink:0}
.seasonal-body{flex:1}
.seasonal-title{font-weight:600;font-size:14px;color:var(--text);margin-bottom:4px;letter-spacing:-0.005em}
.seasonal-desc{font-size:12.5px;color:var(--text-2);line-height:1.5}
.seasonal-desc strong{color:var(--text)}

/* ===== Splash loader (shown until App boots) ===== */
/* Splash loader — two-stage fade.
 *   Stage 1: full splash with brand mark over a solid bg + falling rain
 *   Stage 2 (".ready"): bg fades to transparent, brand fades out, rain keeps
 *           falling at lower opacity over the now-visible app. The whole
 *           splash is click-through, so users can already tap buttons.
 *   Stage 3 (".gone"): everything fades out completely.
 * pointer-events:none on the splash itself means the UI is interactive at
 * every stage — the rain is purely decorative. */
.splash{position:fixed;inset:0;z-index:99;background:var(--bg);display:flex;flex-direction:column;
  align-items:center;justify-content:center;gap:24px;pointer-events:none;
  transition:background-color .7s ease,opacity .7s ease,visibility .7s}
/* Bare splash mode — atmospheric weather animation only, no brand block.
 * Transparent background so the actual app is visible behind the rain/sun
 * from the moment of paint. The animation just fades out gracefully at .gone. */
.splash.splash-bare{background:transparent}

/* Install bottom sheet — appears on 2nd visit to nudge add-to-home-screen.
 * Backdrop dims the page; card slides up from the bottom on mobile.
 * v1.25.0 — card now has z-index:1 (was painting UNDER the backdrop because
 * source-order put .install-backdrop after .install-card with no stacking
 * context). Also adds a max-height + internal scroll so the larger
 * cross-platform sheet (with disclosure for "other browsers") fits on
 * short Android viewports. */
.install-sheet{position:fixed;inset:0;z-index:120;display:none;align-items:flex-end;justify-content:center}
.install-sheet.show{display:flex}
.install-backdrop{position:absolute;inset:0;background:rgba(0,0,0,0.55);z-index:0}
.install-card{position:relative;z-index:1;background:var(--surface-strong,var(--surface));color:var(--text);
  border-radius:18px 18px 0 0;padding:22px 22px 28px;width:100%;max-width:520px;
  border-top:1px solid var(--line);box-shadow:0 -10px 40px -10px rgba(0,0,0,0.45);
  animation:slideUpIn .35s ease;max-height:88vh;overflow-y:auto;-webkit-overflow-scrolling:touch}
@media (min-width: 600px){
  .install-sheet{align-items:center}
  .install-card{border-radius:18px;max-width:460px;padding:24px;max-height:84vh}
}
@keyframes slideUpIn{from{transform:translateY(40px);opacity:0}to{transform:none;opacity:1}}

/* v1.25.0 — Cross-platform install sheet content styles. */
.install-card h3{margin:0 0 6px;font-size:17px;font-weight:600}
.install-card .install-sub{margin:0 0 14px;font-size:13px;line-height:1.55;color:var(--text-2,var(--text))}
.install-card .install-platform-pill{display:inline-flex;align-items:center;gap:6px;
  font-size:11px;text-transform:uppercase;letter-spacing:0.08em;color:var(--text-3);
  background:var(--surface-2);padding:4px 10px;border-radius:999px;margin-bottom:10px}
.install-card ol.install-steps{list-style:none;margin:0 0 12px;padding:0;display:flex;flex-direction:column;gap:10px}
.install-card ol.install-steps > li{display:flex;gap:12px;align-items:flex-start;
  background:var(--surface-2);border-radius:12px;padding:10px 12px;font-size:13.5px;line-height:1.5}
.install-card .step-num{flex:0 0 auto;width:26px;height:26px;border-radius:50%;
  background:var(--rain);color:#fff;font-weight:700;font-size:13px;
  display:inline-flex;align-items:center;justify-content:center;margin-top:1px}
.install-card .step-body{flex:1 1 auto;min-width:0}
.install-card .step-body strong{font-weight:600}
.install-card .icon-chip{display:inline-flex;align-items:center;justify-content:center;
  width:22px;height:22px;background:var(--surface-strong,var(--surface));
  border:1px solid var(--line);border-radius:6px;vertical-align:-5px;margin:0 2px}
.install-card .icon-chip svg{width:14px;height:14px}
.install-card .install-note{margin:10px 0 12px;padding:10px 12px;border-radius:10px;
  background:rgba(255,180,60,0.10);border:1px solid rgba(255,180,60,0.30);
  font-size:12.5px;line-height:1.5;color:var(--text)}
.install-card .install-note.error{background:rgba(255,80,80,0.10);border-color:rgba(255,80,80,0.30)}
.install-card .install-url-row{display:flex;gap:6px;align-items:stretch;margin:8px 0 12px}
.install-card .install-url-chip{flex:1 1 auto;font-family:ui-monospace,Menlo,Consolas,monospace;
  font-size:12px;background:var(--surface-2);border:1px solid var(--line);
  border-radius:8px;padding:8px 10px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.install-card .install-url-copy{flex:0 0 auto;padding:8px 12px;font-size:12px;
  background:var(--rain);color:#fff;border:0;border-radius:8px;cursor:pointer}
.install-card .install-actions{display:flex;flex-direction:column;gap:8px;margin-top:6px}
.install-card details.install-more{margin-top:14px;border-top:1px solid var(--line);padding-top:12px}
.install-card details.install-more > summary{cursor:pointer;font-size:13px;font-weight:600;
  list-style:none;display:flex;align-items:center;gap:6px;color:var(--rain)}
.install-card details.install-more > summary::-webkit-details-marker{display:none}
.install-card details.install-more > summary::after{content:'⌄';margin-left:auto;transition:transform .2s ease}
.install-card details.install-more[open] > summary::after{transform:rotate(180deg)}
.install-card .install-chip-row{display:flex;flex-wrap:wrap;gap:6px;margin:10px 0 6px}
.install-card .install-chip{font-size:11.5px;padding:5px 10px;border-radius:999px;
  background:var(--surface-2);border:1px solid var(--line);cursor:pointer;color:var(--text)}
.install-card .install-chip.active{background:var(--rain);color:#fff;border-color:var(--rain)}
.install-card .install-other-panel{display:none;margin-top:8px;padding-top:8px;border-top:1px dashed var(--line)}
.install-card .install-other-panel.show{display:block}
.install-card details.install-advanced{margin-top:8px;font-size:12px;color:var(--text-3)}
.install-card details.install-advanced > summary{cursor:pointer;list-style:none}
.install-card details.install-advanced > summary::-webkit-details-marker{display:none}
.install-card details.install-advanced code{font-family:ui-monospace,Menlo,Consolas,monospace;
  font-size:11.5px;background:var(--surface-2);padding:1px 5px;border-radius:4px;word-break:break-all}
.splash.ready{background:transparent}
.splash.ready .mark,
.splash.ready .wordmark,
.splash.ready .tagline,
.splash.ready .pulse{opacity:0;transition:opacity .55s ease}
.splash.ready .drop{opacity:0.32}        /* dim rain so it never obstructs */
.splash.gone{opacity:0!important;visibility:hidden!important;pointer-events:none!important}
/* v1.20.1 — stop all child animations the moment .gone is added. Defense in
 * depth: if any animation kept playing (e.g. moon rays rotating with infinite
 * loop), they could still flicker through the visibility transition on slower
 * devices. animation:none kills them instantly. */
.splash.gone *,
.splash.gone *::before,
.splash.gone *::after{animation:none!important}
.splash .mark{width:96px;height:96px;border-radius:24px;
  background:linear-gradient(135deg,var(--rain),var(--rain-2));
  display:flex;align-items:center;justify-content:center;color:#fff;
  box-shadow:0 16px 40px -10px rgba(43,123,216,0.45);
  transition:opacity .55s ease}
.splash .mark svg{width:48px;height:48px}
.splash .wordmark{font-size:18px;font-weight:600;letter-spacing:-0.01em;color:var(--text);transition:opacity .55s ease}
.splash .tagline{font-size:12px;color:var(--text-3);text-transform:uppercase;letter-spacing:0.18em;margin-top:-14px;transition:opacity .55s ease}
.splash .rain-svg{position:absolute;inset:0;pointer-events:none;overflow:hidden}
.splash .drop{position:absolute;width:3px;border-radius:999px;
  background:linear-gradient(180deg,transparent,var(--rain) 40%,var(--rain-2));
  animation:dropFall 1.6s linear infinite;opacity:0.7;
  transition:opacity .55s ease}
@keyframes dropFall{
  0%   {transform:translateY(-40px) scaleY(0.6);opacity:0}
  10%  {opacity:0.8}
  100% {transform:translateY(105vh) scaleY(1);opacity:0}
}
.splash .pulse{position:absolute;width:140px;height:140px;border-radius:50%;
  border:2px solid var(--rain);opacity:0;animation:pulseRing 1.8s ease-out infinite;
  transition:opacity .55s ease}
@keyframes pulseRing{
  0%   {transform:scale(0.6);opacity:0.6}
  100% {transform:scale(1.4);opacity:0}
}

/* Sun-glare backdrop — shown when next-24h forecast is dry. The sun sits above
 * the brand mark, with 12 rays radiating outward and a slow rotation. A soft
 * flare in the centre adds warmth. Hidden by default; shown only on
 * .splash.mood-sun. Rain is hidden in sun mode and vice-versa. */
.splash .sun-svg{position:absolute;inset:0;pointer-events:none;overflow:hidden;
  display:none;align-items:center;justify-content:center}
.splash.mood-sun .sun-svg{display:flex}
.splash.mood-sun .rain-svg{display:none}
.splash.mood-rain .sun-svg{display:none}

.sun-core{position:absolute;width:90px;height:90px;border-radius:50%;
  background:radial-gradient(circle at 35% 30%,#FFE89A 0%,#FFC857 45%,#FFA438 80%);
  box-shadow:0 0 60px rgba(255,200,87,0.55),0 0 120px rgba(255,164,56,0.35);
  animation:sunPulse 2.4s ease-in-out infinite}
@keyframes sunPulse{
  0%,100%{transform:scale(1);box-shadow:0 0 60px rgba(255,200,87,0.55),0 0 120px rgba(255,164,56,0.35)}
  50%   {transform:scale(1.08);box-shadow:0 0 90px rgba(255,200,87,0.7),0 0 160px rgba(255,164,56,0.45)}
}

.sun-rays{position:absolute;width:260px;height:260px;animation:sunRot 14s linear infinite}
.sun-rays span{position:absolute;top:50%;left:50%;width:4px;height:60px;
  background:linear-gradient(180deg,rgba(255,200,87,0.85),rgba(255,200,87,0));
  border-radius:999px;transform-origin:50% 0%}
.sun-rays span:nth-child(1)  {transform:translate(-50%,0) rotate(0deg)   translateY(55px)}
.sun-rays span:nth-child(2)  {transform:translate(-50%,0) rotate(30deg)  translateY(55px)}
.sun-rays span:nth-child(3)  {transform:translate(-50%,0) rotate(60deg)  translateY(55px)}
.sun-rays span:nth-child(4)  {transform:translate(-50%,0) rotate(90deg)  translateY(55px)}
.sun-rays span:nth-child(5)  {transform:translate(-50%,0) rotate(120deg) translateY(55px)}
.sun-rays span:nth-child(6)  {transform:translate(-50%,0) rotate(150deg) translateY(55px)}
.sun-rays span:nth-child(7)  {transform:translate(-50%,0) rotate(180deg) translateY(55px)}
.sun-rays span:nth-child(8)  {transform:translate(-50%,0) rotate(210deg) translateY(55px)}
.sun-rays span:nth-child(9)  {transform:translate(-50%,0) rotate(240deg) translateY(55px)}
.sun-rays span:nth-child(10) {transform:translate(-50%,0) rotate(270deg) translateY(55px)}
.sun-rays span:nth-child(11) {transform:translate(-50%,0) rotate(300deg) translateY(55px)}
.sun-rays span:nth-child(12) {transform:translate(-50%,0) rotate(330deg) translateY(55px)}
@keyframes sunRot{ from{transform:rotate(0deg)} to{transform:rotate(360deg)} }

.sun-flare{position:absolute;width:600px;height:600px;border-radius:50%;
  background:radial-gradient(circle,rgba(255,228,160,0.18) 0%,rgba(255,228,160,0) 70%);
  animation:sunFlare 4s ease-in-out infinite;pointer-events:none}
@keyframes sunFlare{
  0%,100% {opacity:0.5;transform:scale(1)}
  50%     {opacity:0.85;transform:scale(1.12)}
}

/* When sun mood is active, brand mark uses warm tone */
.splash.mood-sun .mark{background:linear-gradient(135deg,#FFC857,#FFA438);
  box-shadow:0 16px 40px -10px rgba(255,164,56,0.55)}

/* Fade-out: sun fades like rain does, gracefully */
.splash.ready .sun-core,
.splash.ready .sun-rays,
.splash.ready .sun-flare{opacity:0.4;transition:opacity .55s ease}
.splash.gone   .sun-svg{opacity:0;transition:opacity .7s ease}

/* ---------- MOON mood — shown when next-24h is dry AND it's nighttime ---------- */
/* Cool silvery palette, 8 soft beams, twinkling stars scattered around. */
.splash .moon-svg{position:absolute;inset:0;pointer-events:none;overflow:hidden;
  display:none;align-items:center;justify-content:center}
.splash.mood-moon .moon-svg{display:flex}
.splash.mood-moon .rain-svg,
.splash.mood-moon .sun-svg{display:none}
.splash.mood-rain .moon-svg,
.splash.mood-sun  .moon-svg{display:none}

/* v1.20.2 — Calmer moon. Rays REMOVED (they looked like the sun). The
 * moon is now a static crescent with a soft glow; only the stars twinkle.
 * Subtle opacity pulse instead of a scale animation so nothing "moves around". */
.moon-core{position:absolute;width:84px;height:84px;border-radius:50%;
  background:radial-gradient(circle at 65% 35%,#FCFCEB 0%,#E5E7F0 55%,#B6BCD0 100%);
  box-shadow:0 0 50px rgba(220,225,245,0.40),0 0 90px rgba(170,180,210,0.22),
             inset -14px -10px 22px rgba(50,60,90,0.45);
  animation:moonPulse 6s ease-in-out infinite}
@keyframes moonPulse{
  0%,100% {opacity:0.92}
  50%     {opacity:1}
}

/* v1.20.3 — Moon glow is now completely STATIC. Previously had a pulsing
 * scale animation (1.0 → 1.08) that visually read as "outward rays expanding
 * and contracting" — exactly what the user said they were still seeing. No
 * animation now; the glow is just a soft halo behind the crescent. */
.moon-glow{position:absolute;width:380px;height:380px;border-radius:50%;
  background:radial-gradient(circle,rgba(200,210,240,0.18) 0%,rgba(200,210,240,0) 65%);
  pointer-events:none;opacity:0.6}

/* Twinkling stars scattered around the moon */
.stars{position:absolute;inset:0;width:100%;height:100%}
.star{position:absolute;width:3px;height:3px;border-radius:50%;
  background:#FFFFFF;
  box-shadow:0 0 6px rgba(255,255,255,0.9),0 0 12px rgba(220,225,245,0.6);
  opacity:0;animation:starTwinkle 2.6s ease-in-out infinite}
@keyframes starTwinkle{
  0%,100% {opacity:0;transform:scale(0.8)}
  50%     {opacity:1;transform:scale(1.2)}
}

/* Slight cool tint over the whole page when moon mood is active.
 * Keeps the bare/transparent feel but adds a hint of nighttime. */
.splash.mood-moon{background:rgba(10,15,35,0.10)}
.splash.mood-moon.splash-bare{background:rgba(10,15,35,0.06)}

/* Fade behaviour parallels sun. .moon-rays removed in v1.20.2. */
.splash.ready .moon-core,
.splash.ready .moon-glow,
.splash.ready .stars{opacity:0.4;transition:opacity .55s ease}
.splash.gone   .moon-svg{opacity:0;transition:opacity .7s ease}

/* Subtle radial background */
body::before{
  content:"";position:fixed;inset:-20%;pointer-events:none;z-index:-1;
  background:
    radial-gradient(40% 30% at 20% 0%,rgba(90,169,255,0.10),transparent 70%),
    radial-gradient(40% 30% at 85% 10%,rgba(124,196,255,0.06),transparent 70%);
}

  html[data-theme="light"] body::before {
    background:
      radial-gradient(50% 40% at 15% 0%,rgba(43,175,175,0.14),transparent 70%),
      radial-gradient(50% 40% at 85% 10%,rgba(232,163,64,0.10),transparent 70%);
  }


  html[data-theme="auto"] body::before{background:
      radial-gradient(40% 30% at 20% 0%,rgba(90,169,255,0.18),transparent 70%),
      radial-gradient(40% 30% at 85% 10%,rgba(244,183,64,0.07),transparent 70%);}
*{box-sizing:border-box;-webkit-tap-highlight-color:transparent}
html,body{margin:0;padding:0;background:var(--bg);color:var(--text);font-family:var(--font);
  font-feature-settings:"ss01","cv11";-webkit-font-smoothing:antialiased;
  /* Prevent iOS text-size auto-inflation in landscape, which can shift the layout */
  -webkit-text-size-adjust:100%;text-size-adjust:100%}
/* v1.24.5 — NUCLEAR RESET. After three rounds of chasing this scroll bug
 * across Samsung Internet (broken in v1.24.2), then Chrome on Android
 * (broken in v1.24.3/4 after we added `overflow-x:hidden` + `width:100%`
 * + `max-width:100vw` + `overscroll-behavior-y:none` to body), the only
 * configuration that works on EVERY browser is the one where neither
 * <html> nor <body> own any scroll-blocking property. Both browsers'
 * root-scrolling-element heuristic gets confused when body becomes a
 * scroll container or its own width is pinned to 100vw with overflow
 * clipping. Let the browser do its native thing.
 *
 * Horizontal swipe lock now lives ONE level down on `.app`, which is
 * already a max-width:540px centered column. Clipping there cannot
 * interfere with the root scroll layer because `.app` is not the root.
 *
 * The pinch-suppression JS for iOS Safari (gated by window.GestureEvent)
 * still handles two-finger zoom; nothing in HTML/CSS needs to. */
body{
  min-height:100vh;min-height:100dvh;
}
/* v1.24.5 — Horizontal-swipe lock moved here. `.app` is the inner column
 * (max-width:540px, margin:0 auto) — clipping its overflow-x cannot
 * affect the root scroller because the root scroller is <html>/<body>.
 * On the rare desktop window wider than 540px, the body still scrolls
 * vertically normally; .app just doesn't let any sloppy child element
 * push the layout sideways. */
.app{overflow-x:clip}
/* Fallback for browsers without `overflow:clip` support (pre-Chrome 90,
 * pre-Samsung Internet 16, pre-iOS Safari 16). `clip` is the modern
 * primitive that hides overflow WITHOUT creating a scroll container.
 * `hidden` does create a scroll container, but on an inner element
 * (not body/html) that's fine. */
@supports not (overflow:clip){
  .app{overflow-x:hidden}
}
button{font-family:inherit;color:inherit;background:none;border:0;cursor:pointer;font-size:inherit;
  touch-action:manipulation;-webkit-user-select:none;user-select:none;
  /* defensive: never let a button overflow horizontally and force a scroll */
  max-width:100%}
/* iOS zooms the viewport when you focus an input whose font-size < 16px.
 * Force 16px+ on every text input and select to suppress that zoom. */
input,select,textarea{font-family:inherit;color:inherit;font-size:16px}
input[type=checkbox],input[type=radio]{font-size:inherit}
a{color:var(--accent);text-decoration:none;touch-action:manipulation}
/* Cover everything tappable explicitly — belt-and-suspenders. */
.opt,.tile,.swatch,.chip,.iconbtn,.btn,.nav button,.tabs button,[data-go],[data-rain],[data-contam],[data-v]{
  touch-action:manipulation;-webkit-user-select:none;user-select:none
}
.app{min-height:100dvh;display:flex;flex-direction:column;padding-top:var(--safe-top);
  padding-bottom:calc(76px + var(--safe-bot));max-width:540px;margin:0 auto;position:relative}
/* ========== Top bar ========== */
.topbar{display:flex;align-items:center;justify-content:space-between;padding:18px 22px 10px}
.brand{display:flex;align-items:center;gap:10px;font-weight:600;letter-spacing:-0.005em;font-size:15px}
.brand svg{width:26px;height:26px}
.topbar-right{display:flex;align-items:center;gap:8px}
/* v1.25.8 — Always-visible "I'm busy" toggle in the topbar. Small moon
 * chip when inactive; expands to show days-remaining label when burst
 * mode is on so the user knows it's actively quieting the app. */
.quick-burst{
  display:inline-flex;align-items:center;gap:5px;
  padding:5px 9px;border-radius:999px;
  background:var(--surface);border:1px solid var(--line);
  color:var(--text-2);font-size:12px;font-weight:600;
  cursor:pointer;flex-shrink:0;
  transition:background 0.15s ease,border-color 0.15s ease,color 0.15s ease
}
.quick-burst:hover{background:var(--surface-2);color:var(--text)}
.quick-burst .qb-ico{font-size:14px;line-height:1}
.quick-burst.on{
  background:rgba(124,196,255,0.14);
  border-color:rgba(124,196,255,0.40);
  color:var(--accent)
}
html[data-theme="light"] .quick-burst.on{
  background:rgba(43,123,216,0.10);
  border-color:rgba(43,123,216,0.35);
  color:var(--accent)
}
.quick-burst .qb-label{font-size:11.5px;letter-spacing:0.01em}
@media (max-width: 380px){
  .quick-burst{padding:5px 7px}
  .quick-burst .qb-label{display:none !important}
}
/* ===== v1.20 Car switcher (multi-car) ===== */
.brand{position:relative}
.car-switch{
  background:var(--surface);border:1px solid var(--line);
  border-radius:999px;padding:4px 10px;
  font-size:12.5px;font-weight:600;color:var(--text-2);
  display:inline-flex;align-items:center;gap:4px;cursor:pointer;
  transition:background .15s ease,color .15s ease;
  font-family:inherit;
}
.car-switch:hover{background:var(--surface-2);color:var(--text)}
.car-switch-chev{font-size:10px;opacity:0.7}
.car-switch-menu{
  position:absolute;top:calc(100% + 6px);left:38px;
  min-width:200px;
  background:var(--bg-2);
  border:1px solid var(--line-2);
  border-radius:14px;
  padding:6px;z-index:200;
  box-shadow:0 16px 40px -16px rgba(0,0,0,0.5);
}
.car-switch-menu[hidden]{display:none}
.car-switch-menu .car-item{
  display:flex;align-items:center;justify-content:space-between;
  gap:8px;padding:9px 12px;border-radius:10px;
  font-size:13.5px;cursor:pointer;color:var(--text);
}
.car-switch-menu .car-item:hover{background:var(--surface)}
.car-switch-menu .car-item.active{background:var(--rain-soft);color:var(--accent);font-weight:600}
.car-switch-menu .car-item .car-tag{font-size:11px;color:var(--text-3);font-weight:500}
.car-switch-menu .car-item .car-del{
  background:transparent;border:none;color:var(--text-3);cursor:pointer;
  font-size:14px;padding:2px 6px;border-radius:6px;
}
.car-switch-menu .car-item .car-del:hover{background:rgba(255,110,110,0.15);color:var(--bad)}
.car-switch-menu .car-add{
  display:flex;align-items:center;gap:8px;padding:9px 12px;
  border-radius:10px;font-size:13.5px;color:var(--accent);
  cursor:pointer;font-weight:600;
  border-top:1px solid var(--line);margin-top:4px;padding-top:11px;
}
.car-switch-menu .car-add:hover{background:var(--surface)}
.loc{font-size:12px;color:var(--text-2);display:flex;align-items:center;gap:6px;background:var(--surface);
  border:1px solid var(--line);border-radius:999px;padding:5px 10px;max-width:170px;font-variant-numeric:tabular-nums;font-weight:500;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.loc #locText,.loc #qrLocText{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.loc-dot{width:5px;height:5px;border-radius:50%;background:var(--good);flex-shrink:0}
.loc.stale .loc-dot{background:var(--warn)}
.loc.off .loc-dot{background:var(--bad)}
.loc-name{font-weight:600;color:var(--text)}
.loc-coords{color:var(--text-3);font-size:11px;margin-left:4px}
.iconbtn{background:var(--surface);border:1px solid var(--line);width:32px;height:32px;border-radius:50%;
  display:flex;align-items:center;justify-content:center;cursor:pointer;color:var(--text-2);transition:all .15s}
.iconbtn:hover{color:var(--text);border-color:var(--line-2)}
.iconbtn:active{transform:scale(0.94)}
.iconbtn svg{width:16px;height:16px}
.iconbtn .ic-sun{display:none}
.iconbtn .ic-moon{display:block}
html[data-theme="light"] .iconbtn .ic-sun{display:block}
html[data-theme="light"] .iconbtn .ic-moon{display:none}
/* ========== Screens ========== */
.screen{padding:10px 20px 24px;display:none;animation:fade .3s cubic-bezier(.2,.7,.2,1)}
.screen.active{display:block}
@keyframes fade{from{opacity:0;transform:translateY(4px)}to{opacity:1;transform:none}}
/* ========== Hero card (Wash now?) ========== */
/* v1.27.1 — hero padding trimmed 2px each side for a slimmer card */
.hero{background:linear-gradient(165deg,rgba(255,255,255,0.10) 0%,rgba(255,255,255,0.04) 100%);
  backdrop-filter:blur(20px);-webkit-backdrop-filter:blur(20px);
  border:1px solid var(--line-2);border-radius:var(--radius-xl);padding:14px 16px 12px;
  box-shadow:var(--shadow),var(--glow);position:relative;overflow:hidden}
html[data-theme="light"] .hero{background:linear-gradient(165deg,#FFFFFF 0%,#F5F8FE 100%);border-color:rgba(15,30,60,0.06)}
.hero::before{content:"";position:absolute;inset:-50% -30% auto auto;width:80%;height:80%;
  background:radial-gradient(closest-side,rgba(90,169,255,0.18),transparent 70%);pointer-events:none;
  filter:blur(20px)}
.hero::after{content:"";position:absolute;left:-30%;top:60%;width:60%;height:60%;
  background:radial-gradient(closest-side,rgba(124,196,255,0.10),transparent 70%);pointer-events:none;filter:blur(28px)}
.hero-label{font-size:11px;color:var(--text-2);text-transform:uppercase;letter-spacing:0.14em;font-weight:700}
/* v1.27.1 — headline shrunk: clamp(22px,5vw,28px), tighter line-height */
.hero-status{font-size:clamp(20px,4.5vw,24px);line-height:1.1;font-weight:700;letter-spacing:-0.02em;margin:2px 0 2px;
  display:flex;align-items:center;gap:12px;flex-wrap:wrap}
.hero-status .emoji{font-size:clamp(22px,5vw,28px)}
/* v1.27.1 — reason: 2-line cap via <details>/<summary>. The summary IS
 * the #heroReason element so JS textContent writes work unchanged.
 * Closed = 2 lines + "More…" via ::after pseudo; open = full text. */
.hero-reason-details{margin-top:4px}
.hero-reason-details summary{list-style:none}
.hero-reason-details summary::-webkit-details-marker{display:none}
/* v1.27.2 — clamp reason to 2 lines on tablet+ but only 1 line on phone
 * to keep the hero tight. Tap "More…" to expand the full reason. */
.hero-reason{color:var(--text-2);font-size:12.5px;line-height:1.38;
  overflow:hidden;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;
  cursor:pointer;position:relative}
.hero-reason-details[open] .hero-reason{-webkit-line-clamp:unset;display:block;overflow:visible}
.hero-reason::after{content:" More…";font-size:12px;font-weight:600;color:var(--accent);white-space:nowrap}
.hero-reason-details[open] .hero-reason::after{display:none}
/* v1.27.1 — chip row margin trimmed */
.hero-meta{display:flex;gap:6px;flex-wrap:wrap;margin-top:8px}
.chip{display:inline-flex;align-items:center;gap:6px;padding:6px 11px;border-radius:999px;
  background:rgba(255,255,255,0.06);border:1px solid var(--line);font-size:12.5px;color:var(--text-2);font-weight:600;
  transition:background .15s,border-color .15s}
 html[data-theme="light"] .chip{background:rgba(0,0,0,0.04)}
.chip.good{color:var(--good);border-color:rgba(61,220,151,0.30);background:rgba(61,220,151,0.10)}
.chip.warn{color:var(--warn);border-color:rgba(244,183,64,0.30);background:rgba(244,183,64,0.10)}
.chip.bad{color:var(--bad);border-color:rgba(255,110,110,0.30);background:rgba(255,110,110,0.10)}
.chip.rain{color:var(--rain);border-color:rgba(90,169,255,0.30);background:rgba(90,169,255,0.10)}
/* v1.27.9 — Mini chips: icon-first, tappable, much tighter than the legacy
 * chip pills. Used on the hero meta row so the hero stays compact. Tap any
 * chip → Info popover with the full value + explanation. */
.chip-mini{
  display:inline-flex;align-items:center;gap:4px;
  padding:4px 9px;border-radius:999px;
  background:rgba(255,255,255,0.06);border:1px solid var(--line);
  font-size:12px;font-weight:600;color:var(--text-2);
  cursor:pointer;line-height:1.25;
  transition:background .15s,border-color .15s,transform .1s;
  -webkit-tap-highlight-color:transparent
}
html[data-theme="light"] .chip-mini{background:rgba(0,0,0,0.04)}
.chip-mini:active{transform:scale(0.96)}
.chip-mini.chip-rain{color:var(--rain);border-color:rgba(90,169,255,0.30);background:rgba(90,169,255,0.10)}
.chip-mini.chip-good{color:var(--good);border-color:rgba(61,220,151,0.30);background:rgba(61,220,151,0.10)}
.chip-mini.chip-warn{color:var(--warn);border-color:rgba(244,183,64,0.30);background:rgba(244,183,64,0.10)}
.chip-mini.chip-burst{color:var(--accent);border-color:rgba(124,196,255,0.30);background:rgba(124,196,255,0.10)}
.chip-mini.chip-legend{opacity:0.65;font-size:13px;padding:4px 8px}
.chip-mini.chip-legend:hover{opacity:1}
/* Legend modal rows */
.legend-list{display:flex;flex-direction:column;gap:8px;margin-top:2px}
.legend-row{
  display:flex;align-items:flex-start;gap:12px;
  padding:10px 12px;border-radius:12px;
  background:var(--surface);border:1px solid var(--line);
}
.legend-ico{font-size:20px;line-height:1.2;flex-shrink:0;width:24px;text-align:center}
.legend-body{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}
.legend-body strong{font-size:13.5px;font-weight:600;color:var(--text);line-height:1.3}
.legend-body span{font-size:12px;color:var(--text-2);line-height:1.45}
/* v1.27.1 — Wash Timing: compact collapsible row replaces the full score-row.
 * Old .score-row kept as dead stub for safety; new .score-details is the live UI. */
.score-row{display:flex;align-items:center;gap:18px;margin-top:18px;padding-top:18px;border-top:1px dashed var(--line)}
/* Compact <details> wrapper */
.score-details{margin-top:8px;padding-top:8px;border-top:1px dashed var(--line)}
.score-details summary{list-style:none}
.score-details summary::-webkit-details-marker{display:none}
/* Compact summary row — ring (40px) + label text on one line */
.score-row-compact{display:flex;align-items:center;gap:10px;cursor:pointer;
  padding:2px 0;-webkit-tap-highlight-color:transparent}
.score-row-compact:active{opacity:0.75}
/* Small ring (40×40 display, 84×84 SVG viewBox) */
.ring{position:relative;width:84px;height:84px;flex:0 0 auto}
.ring.ring-sm{width:40px;height:40px}
.ring svg{transform:rotate(-90deg)}
.ring circle{fill:none;stroke-width:9;stroke-linecap:round}
.ring .bg{stroke:rgba(255,255,255,0.08)}
 html[data-theme="light"] .ring .bg{stroke:rgba(0,0,0,0.07)}
.ring .fg{stroke:var(--good);transition:stroke-dasharray .8s cubic-bezier(.2,.7,.2,1),stroke .3s}
/* Ring contents — stacks word (big) + number (small) vertically.
 * Word is the at-a-glance answer; number is detail underneath. */
.ring-inner{position:absolute;inset:0;display:flex;flex-direction:column;
  align-items:center;justify-content:center;line-height:1;text-align:center}
/* Scale ring text down proportionally for ring-sm (40/84 ≈ 0.48× scale) */
.ring-sm .ring-inner{transform:scale(0.52);transform-origin:center}
.ring-word{font-weight:700;font-size:15px;letter-spacing:-0.005em;line-height:1}
/* v1.30.8 — Reduced font size since the ring-num now carries "/100" suffix
   instead of a bare number (e.g. "30/100"). Slightly smaller so it still
   fits inside the small ring without crowding the word above it. */
.ring-num{font-weight:600;font-size:9.5px;letter-spacing:0.02em;color:var(--text-3);margin-top:2px}
/* Compact row text area */
.score-compact-text{flex:1;min-width:0;display:flex;flex-direction:column;gap:1px}
.sc-title{font-size:12px;color:var(--text-2);font-weight:600;letter-spacing:0.04em;text-transform:uppercase}
.sc-label{font-weight:600;font-size:14px;color:var(--text);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.score-chevron{font-size:18px;color:var(--text-3);line-height:1;transition:transform 0.2s;flex-shrink:0}
.score-details[open] .score-chevron{transform:rotate(90deg)}
/* Expanded explainer shown below the summary */
.score-expanded{padding:8px 0 2px;font-size:12.5px;color:var(--text-2);line-height:1.5}
.score-text .t1{font-size:14px;color:var(--text-2)}
.score-text .t2{font-weight:600;font-size:16px;margin-top:2px}

/* v1.27.1 — Hero burst CTA pill (Now-screen only, between chips and Timing row)
 * Inactive state is the default. Active class .hbc-on added by refreshQuickBurst(). */
.hero-burst-cta{display:flex;align-items:center;gap:7px;width:100%;
  margin-top:8px;padding:8px 12px;border-radius:999px;
  background:rgba(124,196,255,0.10);border:1px solid rgba(124,196,255,0.22);
  color:var(--text-2);font-size:13px;font-weight:500;
  cursor:pointer;text-align:left;
  transition:background 0.15s,border-color 0.15s,color 0.15s;
  -webkit-tap-highlight-color:transparent}
.hero-burst-cta:active{opacity:0.75}
html[data-theme="light"] .hero-burst-cta{
  background:rgba(43,123,216,0.07);border-color:rgba(43,123,216,0.18)}
.hero-burst-cta.hbc-on{
  background:rgba(124,196,255,0.18);border-color:rgba(124,196,255,0.45);
  color:var(--accent)}
html[data-theme="light"] .hero-burst-cta.hbc-on{
  background:rgba(43,123,216,0.12);border-color:rgba(43,123,216,0.35);
  color:var(--accent)}
.hbc-ico{font-size:15px;line-height:1;flex-shrink:0}
.hbc-text{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* v1.31.1 — Hero CTA row holds the two pills (Quiet mode + Event date) side
   by side. Stacks vertically on narrow screens. Inside the row, each pill
   gets margin-top:0 to override the standalone-style top spacing. */
.hero-cta-row{display:flex;flex-wrap:wrap;gap:8px;margin-top:8px}
.hero-cta-row .hero-burst-cta{margin-top:0;flex:1 1 180px;min-width:0}
/* Event CTA tinted warm — visually distinct from the cool-blue burst pill
   so the two functions are obviously different. */
.hero-event-cta{
  background:rgba(244,183,64,0.10) !important;
  border-color:rgba(244,183,64,0.30) !important;
}
.hero-event-cta.hbc-on{
  background:rgba(244,183,64,0.20) !important;
  border-color:rgba(244,183,64,0.55) !important;
  color:var(--warn) !important;
}
html[data-theme="light"] .hero-event-cta{
  background:rgba(214,143,0,0.07) !important;
  border-color:rgba(214,143,0,0.22) !important;
}

/* v1.31.1 — Event planner modal — single answer card, no clutter */
.ev-result{
  background:linear-gradient(180deg, rgba(61,220,151,0.10), rgba(61,220,151,0.04));
  border:1px solid rgba(61,220,151,0.30);
  border-radius:14px;padding:16px;margin:14px 0 8px;
}
.ev-result.ev-tight{
  background:linear-gradient(180deg, rgba(244,183,64,0.10), rgba(244,183,64,0.04));
  border-color:rgba(244,183,64,0.35);
}
.ev-result.ev-impossible{
  background:linear-gradient(180deg, rgba(255,110,110,0.08), rgba(255,110,110,0.03));
  border-color:rgba(255,110,110,0.30);
}
.ev-headline{font-size:15.5px;font-weight:700;color:var(--text);line-height:1.4;margin-bottom:8px}
.ev-sub{font-size:13px;line-height:1.55;color:var(--text-2)}
.ev-stats{display:flex;flex-wrap:wrap;gap:8px;margin-top:10px}
.ev-stat{
  background:var(--surface);border:1px solid var(--line);
  border-radius:8px;padding:6px 10px;font-size:11.5px;color:var(--text-2);
}
.ev-stat strong{color:var(--text);font-weight:700}
.ev-date-input{
  width:100%;padding:10px 12px;font-size:15px;
  background:var(--surface);border:1px solid var(--line);
  border-radius:10px;color:var(--text);font-family:inherit;
  -webkit-appearance:none;appearance:none;
}
.ev-date-input:focus{outline:none;border-color:var(--accent)}
/* v1.27.7 — Tide-through tip cards rendered inside the burst-mode picker.
 * Compact rows: emoji icon left, two-line title + description right. */
.bk-tips{display:flex;flex-direction:column;gap:6px;margin-top:2px}
.bk-tip{
  display:flex;align-items:flex-start;gap:10px;
  padding:9px 11px;border-radius:12px;
  background:var(--surface);border:1px solid var(--line);
}
.bk-tip-ico{font-size:18px;line-height:1.2;flex-shrink:0;margin-top:1px}
.bk-tip-body{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}
.bk-tip-body strong{font-size:13px;font-weight:600;color:var(--text);line-height:1.3}
.bk-tip-body span{font-size:11.5px;color:var(--text-2);line-height:1.4}
/* v1.27.5 — Standalone variant: pill now sits OUTSIDE the hero card with
 * its own breathing space. Larger padding, more separation. */
.hero-burst-cta-standalone{
  margin-top:12px;margin-bottom:0;
  padding:11px 16px;font-size:13.5px;
  box-shadow:0 1px 0 rgba(255,255,255,0.04) inset;
}
html[data-theme="light"] .hero-burst-cta-standalone{
  box-shadow:0 1px 2px rgba(15,30,60,0.04);
}
/* ========== Impact window card (the hero of the app) ========== */
.impact{margin-top:14px;background:var(--surface);border:1px solid var(--line);border-radius:var(--radius);
  padding:18px 18px 16px;position:relative;overflow:hidden}
.impact::before{content:"";position:absolute;inset:auto -10% -50% auto;width:55%;height:80%;
  background:radial-gradient(closest-side,rgba(124,196,255,0.16),transparent 70%);pointer-events:none}
.impact-label{font-size:12px;color:var(--accent);font-weight:700;letter-spacing:0.10em;text-transform:uppercase}
.impact-title{font-size:24px;font-weight:700;letter-spacing:-0.018em;line-height:1.22;margin-top:6px}
.impact-sub{color:var(--text-2);font-size:14px;margin-top:6px;line-height:1.5}
.impact-bar{margin-top:14px;height:8px;background:rgba(255,255,255,0.06);border-radius:999px;overflow:hidden;position:relative}
 html[data-theme="light"] .impact-bar{background:rgba(0,0,0,0.05)}
.impact-fill{height:100%;background:linear-gradient(90deg,var(--good),var(--rain));border-radius:999px;
  transition:width .8s cubic-bezier(.2,.7,.2,1)}
.impact-legend{display:flex;justify-content:space-between;color:var(--text-3);font-size:12px;margin-top:6px}

/* "Updated X ago" indicator under the hero CTAs. Subtle by default; pulses
 * gently when actively refreshing so the user knows a fetch is in flight. */
.last-updated{margin-top:8px;text-align:center;font-size:11px;color:var(--text-3);
  letter-spacing:0.05em;font-weight:500;opacity:0.75}
.last-updated.refreshing{color:var(--rain);animation:lastUpdPulse 1.4s ease-in-out infinite}
@keyframes lastUpdPulse{0%,100%{opacity:0.55}50%{opacity:1}}
/* v1.27.2 — Compact refresh row: replaces the heavier .cta row. The wash
 * button moved into the "Just happened?" quick-log card directly below
 * the hero; only the refresh icon stays inline with the timestamp. */
.last-updated-row{
  display:flex;align-items:center;justify-content:center;gap:8px;
  margin-top:4px;opacity:0.85
}
.last-updated-row #lastUpdatedText{font-size:11px;color:var(--text-3);letter-spacing:0.04em}
.btn-icon-tiny{
  background:var(--surface-2);border:1px solid var(--line);
  color:var(--text-2);border-radius:999px;
  width:26px;height:26px;display:inline-flex;align-items:center;justify-content:center;
  cursor:pointer;font-size:13px;line-height:1;padding:0;flex-shrink:0;
  transition:background 0.15s ease,color 0.15s ease
}
.btn-icon-tiny:hover{background:var(--surface);color:var(--text)}
.btn-icon-tiny:active{transform:scale(0.94)}
/* The "I washed my car" button promoted into Quick Log */
.btn.qlog-wash{font-size:15px;padding:13px 16px}
.btn.qlog-wash .ico{margin-right:6px;font-size:18px}

/* Saved-pulse badge on the Car profile's Save button.
 * The button is decorative now (auto-save handles persistence), but pulses
 * green for ~1.5s after each save so the user gets visual confirmation. */
#pfSave.saved-ok{
  background:linear-gradient(135deg, #3DDC97, #2AB47A) !important;
  color:#fff !important; opacity:1 !important;
  box-shadow:0 0 0 4px rgba(61,220,151,0.18);
  transition:background .25s ease, box-shadow .25s ease, opacity .25s ease;
}
#pfSave.saved-bad{
  background:linear-gradient(135deg, #FF6E6E, #C72E2E) !important;
  color:#fff !important; opacity:1 !important;
  box-shadow:0 0 0 4px rgba(255,110,110,0.18);
}

/* "Did rain hit your car?" confirmation banner.
 * Appears on Now screen when engine auto-detects unconfirmed rain in last 6h.
 * Inline below the hero so it can't be missed but doesn't block the verdict. */
.rain-ask{display:flex;gap:14px;align-items:flex-start;background:linear-gradient(180deg,rgba(90,169,255,0.10),rgba(90,169,255,0.02));
  border:1px solid rgba(90,169,255,0.30);border-radius:14px;padding:14px 16px;margin:14px 0 0}
.rain-ask-icon{font-size:24px;line-height:1;flex-shrink:0}
.rain-ask-body{flex:1;min-width:0}
.rain-ask-body strong{display:block;font-size:14.5px;color:var(--text);margin-bottom:10px;letter-spacing:-0.005em;line-height:1.4}
.rain-ask-body p{margin:0 0 10px;font-size:12.5px;color:var(--text-2);line-height:1.5}
.rain-ask-actions{display:flex;flex-wrap:wrap;gap:6px}
.rain-ask-actions .btn{flex:1;min-width:0;font-size:12.5px;padding:8px 10px}
.rain-ask-actions .btn.ghost{flex:0 0 auto;padding:8px 12px;opacity:0.7}
/* v1.23.1 — Situation profiling option list. Stacked vertical for clean
 * tap targets on mobile, full width, with a subtle "Why we ask" line below. */
.rain-ask-options{display:flex;flex-direction:column;gap:6px;margin-bottom:8px}
.rain-ask-options .btn.rain-ask-opt{width:100%;text-align:left;font-size:13px;padding:10px 12px;justify-content:flex-start}
.rain-ask-why{font-size:11.5px;color:var(--text-3);line-height:1.5;opacity:0.85;margin-top:2px}

/* Grime score meter — fills as dirt + acid accumulates. Green → amber → red.
 * Shown in the "Your car" card. Tap the i for the breakdown. */
.grime-bar{height:8px;background:rgba(255,255,255,0.06);border-radius:999px;overflow:hidden;position:relative}
html[data-theme="light"] .grime-bar{background:rgba(0,0,0,0.05)}
.grime-fill{height:100%;border-radius:999px;width:0%;
  transition:width 1s cubic-bezier(.2,.7,.2,1), background .5s}
.grime-fill.lvl-clean    { background:linear-gradient(90deg,#3DDC97,#5AA9FF) }
.grime-fill.lvl-building { background:linear-gradient(90deg,#5AA9FF,#FFC857) }
.grime-fill.lvl-pressure { background:linear-gradient(90deg,#FFC857,#FF8845) }
.grime-fill.lvl-urgent   { background:linear-gradient(90deg,#FF8845,#FF5252) }
/* ========== Sections ========== */
.section-title{font-size:11.5px;letter-spacing:0.12em;text-transform:uppercase;color:var(--text-3);
  font-weight:700;margin:24px 6px 10px;display:flex;align-items:center;gap:8px}
.section-title::after{content:"";flex:1;height:1px;background:var(--line)}
/* v1.29.0 — Typography rhythm utilities. Replaces ad-hoc inline margins
 * on <p class="small muted"> subtitle / explainer paragraphs so section
 * title → subtitle → content spacing stays uniform across every screen.
 *   .p-tight  — micro spacing (notes inside cards)
 *   .p-normal — default body paragraph spacing
 *   .p-loose  — extra breathing room between paragraphs
 *   .p-sub    — sits directly under a label/title (negative top margin
 *               pulls it close to the heading, normal bottom margin
 *               separates it from the picker below). Replaces the
 *               recurring `style="margin:-6px 0 8px"` pattern. */
.p-tight{margin:4px 0;line-height:1.45}
.p-normal{margin:8px 0;line-height:1.5}
.p-loose{margin:12px 0;line-height:1.5}
.p-sub{margin:-2px 4px 12px;font-size:12px;line-height:1.5}
.card{background:var(--surface);backdrop-filter:blur(14px);-webkit-backdrop-filter:blur(14px);
  border:1px solid var(--line);border-radius:var(--radius);padding:8px 18px;box-shadow:var(--shadow-sm),var(--glow)}
 html[data-theme="light"] .card{background:var(--surface-strong)}
.kv{display:flex;justify-content:space-between;align-items:center;padding:10px 0;border-top:1px solid var(--line)}
.kv:first-child{border-top:0}
.kv .k{color:var(--text-2);font-size:14px}
.kv .v{font-weight:600;font-size:14.5px}
/* Primary CTA */
.cta{display:flex;gap:10px;margin-top:14px}
.btn{flex:1;padding:14px 16px;border-radius:14px;font-weight:600;font-size:15px;letter-spacing:-0.005em;
  background:var(--surface-2);color:var(--text);border:1px solid var(--line);
  transition:transform .12s cubic-bezier(.2,.7,.2,1),box-shadow .15s,background .15s;
  display:inline-flex;align-items:center;justify-content:center;gap:6px}
.btn:hover{background:var(--surface-strong)}
.btn:active{transform:scale(0.97)}
.btn.primary{background:linear-gradient(180deg,color-mix(in srgb, var(--rain) 90%, white 10%) 0%,var(--rain) 40%,var(--rain-2) 100%);
  color:#fff;border-color:transparent;
  box-shadow:0 10px 24px -8px color-mix(in srgb, var(--rain) 60%, transparent), 0 1px 0 rgba(255,255,255,0.20) inset;
  text-shadow:0 1px 1px rgba(0,0,0,0.10)}
.btn.primary:hover{transform:translateY(-1px);box-shadow:0 12px 28px -8px rgba(43,123,216,0.62), 0 1px 0 rgba(255,255,255,0.22) inset}
.btn.ghost{background:transparent;border-color:var(--line)}
.btn.ghost:hover{background:var(--surface-2)}
.btn.danger{color:var(--bad);border-color:rgba(255,110,110,0.30);background:rgba(255,110,110,0.05)}
.btn .ico{margin-right:2px}
/* ========== Forecast timeline ========== */
.forecast-legend{display:flex;flex-wrap:wrap;gap:6px 10px;margin:0 4px 14px;padding:10px 12px;
  background:var(--surface);border:1px solid var(--line);border-radius:12px;font-size:11.5px;color:var(--text-2)}
.lg-item{display:inline-flex;align-items:center;gap:5px;white-space:nowrap}
.lg-sw{width:14px;height:10px;border-radius:3px;display:inline-block}
.lg-dry{background:rgba(255,255,255,0.06);border:1px solid var(--line)}
html[data-theme="light"] .lg-dry{background:rgba(0,0,0,0.05)}
.lg-r{background:linear-gradient(180deg,rgba(90,169,255,0.25),rgba(90,169,255,0.7))}
.lg-r2{background:linear-gradient(180deg,rgba(90,169,255,0.45),rgba(43,123,216,0.85))}
.lg-r3{background:linear-gradient(180deg,rgba(43,123,216,0.7),rgba(43,123,216,1))}
/* Light-mode overrides — the dark-mode gradients sit on a near-white card and
   wash out to invisible. Bump opacity + darken the lower stop so all three
   rain tiers (light / moderate / heavy) read clearly. */
html[data-theme="light"] .lg-r{background:linear-gradient(180deg,rgba(124,196,255,0.55),rgba(43,123,216,0.85))}
html[data-theme="light"] .lg-r2{background:linear-gradient(180deg,rgba(43,123,216,0.75),rgba(31,108,210,0.95))}
html[data-theme="light"] .lg-r3{background:linear-gradient(180deg,rgba(31,108,210,0.95),rgba(15,75,170,1))}
.lg-win{background:rgba(255,255,255,0.06);outline:1.5px solid var(--good);outline-offset:-1px}
html[data-theme="light"] .lg-win{background:rgba(0,0,0,0.05)}
.timeline{display:flex;flex-direction:column;gap:10px}
.day{background:var(--surface);border:1px solid var(--line);border-radius:var(--radius);padding:14px 16px}
.day-head{display:flex;justify-content:space-between;align-items:center;gap:10px}
.day-name{font-weight:700}
.day-sub{color:var(--text-2);font-size:13px;margin-top:2px}
.day-tag{font-size:12px;font-weight:700;padding:5px 9px;border-radius:999px}
.day-tag.good{background:rgba(61,220,151,0.12);color:var(--good)}
.day-tag.warn{background:rgba(244,183,64,0.14);color:var(--warn)}
.day-tag.bad{background:rgba(255,110,110,0.12);color:var(--bad)}
.day-tag.ok{background:rgba(124,196,255,0.14);color:var(--accent)}
.hours{display:grid;grid-template-columns:repeat(24,1fr);gap:2px;margin-top:12px;height:30px}
.hr{background:rgba(255,255,255,0.06);border-radius:3px;position:relative}
 html[data-theme="light"] .hr{background:rgba(0,0,0,0.05)}
.hr.r{background:linear-gradient(180deg,rgba(90,169,255,0.25),rgba(90,169,255,0.7))}
.hr.r2{background:linear-gradient(180deg,rgba(90,169,255,0.45),rgba(43,123,216,0.85))}
.hr.r3{background:linear-gradient(180deg,rgba(43,123,216,0.7),rgba(43,123,216,1))}
/* Light-mode timeline cells — same problem, same fix. The forecast hour
   cells need to be unmistakable as blue when seen on a white card. */
html[data-theme="light"] .hr.r{background:linear-gradient(180deg,rgba(124,196,255,0.55),rgba(43,123,216,0.85))}
html[data-theme="light"] .hr.r2{background:linear-gradient(180deg,rgba(43,123,216,0.75),rgba(31,108,210,0.95))}
html[data-theme="light"] .hr.r3{background:linear-gradient(180deg,rgba(31,108,210,0.95),rgba(15,75,170,1))}
.hr.win{outline:1.5px solid var(--good);outline-offset:-1px}
.hours-legend{display:flex;justify-content:space-between;color:var(--text-3);font-size:11px;margin-top:4px}
/* ========== Wash log ========== */
.log-entry{background:var(--surface);border:1px solid var(--line);border-radius:14px;padding:12px 14px;
  display:flex;justify-content:space-between;align-items:center;gap:10px;margin-top:10px}
.log-entry .t1{font-weight:600}
.log-entry .t2{color:var(--text-2);font-size:13px;margin-top:2px}
.empty{color:var(--text-3);text-align:center;padding:30px 10px}
/* ========== Forms ========== */
.field{display:flex;flex-direction:column;gap:6px;margin-top:14px}
.field label{font-size:13px;color:var(--text-2);font-weight:600}
.field input,.field select{background:var(--surface);border:1px solid var(--line);color:var(--text);
  padding:12px 14px;border-radius:12px;font-size:15px;outline:none;
  /* v1.27.12 — Without these, inputs default to their intrinsic content
   * width (placeholder + padding ≈ 140px) and overflow narrow grid columns.
   * width:100%+box-sizing:border-box makes them fill the column cleanly. */
  width:100%;box-sizing:border-box;min-width:0;max-width:100%}
.field input:focus,.field select:focus{border-color:var(--rain)}
.opts{display:grid;grid-template-columns:repeat(2,1fr);gap:8px;margin-top:8px}
.opt{padding:12px 14px;border-radius:14px;background:var(--surface);border:1px solid var(--line);
  text-align:left;font-size:14px;font-weight:600;display:flex;flex-direction:column;gap:2px;
  transition:transform .12s,border-color .15s,background .15s;color:var(--text);
  position:relative;overflow:hidden}
.opt:hover{border-color:var(--line-2);background:var(--surface-2)}
.opt:active{transform:scale(0.98)}
.opt .sub{font-weight:500;color:var(--text-2);font-size:12px;line-height:1.4}
.opt.sel{border-color:var(--rain);background:linear-gradient(180deg,rgba(90,169,255,0.10),rgba(90,169,255,0.04));
  box-shadow:0 0 0 3px rgba(90,169,255,0.10), 0 4px 14px -6px rgba(90,169,255,0.30)}
.opt.sel::before{content:"";position:absolute;top:8px;right:10px;width:14px;height:14px;border-radius:50%;
  background:var(--rain);background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14 14'><path d='M3 7l3 3 5-6' fill='none' stroke='white' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/></svg>");
  background-size:14px;background-position:center}

/* Care-level scale — emoji on the left, label + sub stacked on the right.
 * Used in onboarding (#obCareLevel) and Car screen Quick Set (#pfCareLevel). */
.care-scale .opt{flex-direction:row;align-items:center;gap:14px;padding:14px 16px}
.care-scale .opt .emoji{font-size:28px;line-height:1;flex-shrink:0;width:36px;text-align:center}
.care-scale .opt .label{display:block;font-weight:600;font-size:14.5px;color:var(--text);margin-bottom:2px}
.care-scale .opt .sub{display:block;font-weight:500;color:var(--text-2);font-size:12.5px;line-height:1.4}
.care-scale .opt > span:nth-child(2),
.care-scale .opt > span:nth-child(3){flex:1;min-width:0}
/* Make label + sub flow as a single stacked column to the right of the emoji */
.care-scale .opt{display:grid;grid-template-columns:36px 1fr;grid-template-areas:"emoji text" "emoji sub";align-items:center}
.care-scale .opt .emoji{grid-area:emoji}
.care-scale .opt .label{grid-area:text}
.care-scale .opt .sub{grid-area:sub}

/* Color swatch picker — replaces colour emojis */
.swatches{display:grid;grid-template-columns:repeat(4,1fr);gap:8px;margin-top:8px}
.swatch{aspect-ratio:1/1;border-radius:14px;background:var(--surface);border:1px solid var(--line);
  display:flex;flex-direction:column;align-items:center;justify-content:center;gap:6px;cursor:pointer;
  transition:transform .12s,border-color .15s,background .15s;position:relative;color:var(--text);font-size:11.5px;font-weight:600}
.swatch:hover{border-color:var(--line-2)}
.swatch:active{transform:scale(0.95)}
.swatch .dot{width:28px;height:28px;border-radius:50%;box-shadow:0 2px 8px rgba(0,0,0,0.25),0 0 0 1px rgba(255,255,255,0.10) inset}
.swatch.sel{border-color:var(--rain);background:linear-gradient(180deg,rgba(90,169,255,0.10),rgba(90,169,255,0.04));
  box-shadow:0 0 0 3px rgba(90,169,255,0.10)}
.swatch.sel::after{content:"";position:absolute;top:6px;right:6px;width:14px;height:14px;border-radius:50%;
  background:var(--rain);background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14 14'><path d='M3 7l3 3 5-6' fill='none' stroke='white' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/></svg>");
  background-size:14px;background-position:center}

/* Car type tiles with SVG icons */
.tiles{display:grid;grid-template-columns:repeat(3,1fr);gap:8px;margin-top:8px}
.tile{aspect-ratio:1.5/1;border-radius:14px;background:var(--surface);border:1px solid var(--line);
  display:flex;flex-direction:column;align-items:center;justify-content:center;gap:4px;cursor:pointer;
  transition:transform .12s,border-color .15s,background .15s;position:relative;color:var(--text);font-size:12.5px;font-weight:600;padding:4px}
.tile:hover{border-color:var(--line-2)}
.tile:active{transform:scale(0.97)}
.tile svg{width:36px;height:24px;color:var(--text-2);transition:color .15s}
.tile.sel{border-color:var(--rain);background:linear-gradient(180deg,rgba(90,169,255,0.10),rgba(90,169,255,0.04));
  box-shadow:0 0 0 3px rgba(90,169,255,0.10)}
.tile.sel svg{color:var(--rain)}
.tile.sel::after{content:"";position:absolute;top:6px;right:6px;width:12px;height:12px;border-radius:50%;
  background:var(--rain);background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14 14'><path d='M3 7l3 3 5-6' fill='none' stroke='white' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/></svg>");
  background-size:12px;background-position:center}
/* ========== Bottom nav ========== */
.nav{position:fixed;left:0;right:0;bottom:0;display:flex;justify-content:center;
  padding-bottom:var(--safe-bot);background:linear-gradient(180deg,rgba(11,18,32,0) 0%, var(--bg) 40%);
  pointer-events:none;z-index:5}

  html[data-theme="light"] .nav{background:linear-gradient(180deg,rgba(246,248,252,0) 0%, var(--bg) 40%)}
.nav-inner{pointer-events:auto;display:grid;grid-template-columns:repeat(5,1fr);
  background:var(--surface-strong);border:1px solid var(--line);border-radius:22px;
  margin:0 12px 12px;width:100%;max-width:516px;box-shadow:var(--shadow);backdrop-filter:blur(20px);-webkit-backdrop-filter:blur(20px)}
.nav button{padding:10px 0 12px;display:flex;flex-direction:column;align-items:center;gap:3px;
  color:var(--text-3);font-size:11px;font-weight:600}
.nav button.active{color:var(--text)}
.nav svg{width:22px;height:22px}
/* ========== Onboarding ========== */
.onboard{position:fixed;inset:0;background:var(--bg);z-index:10;display:none;overflow-y:auto;
  padding:max(24px,var(--safe-top)) 22px max(24px,var(--safe-bot))}
.onboard.show{display:block}
.onboard h1{font-size:30px;letter-spacing:-0.02em;margin:18px 0 6px;font-weight:700;line-height:1.15}
.onboard .lead{color:var(--text-2);font-size:15.5px;line-height:1.5}
.onboard .step{display:none;animation:fade .25s ease}
.onboard .step.active{display:block}
.dots{display:flex;gap:6px;justify-content:center;margin-top:18px}
.dots span{width:6px;height:6px;background:var(--line-2);border-radius:999px;transition:.2s}
.dots span.on{background:var(--rain);width:18px}
.onboard footer{position:sticky;bottom:0;padding:14px 0 calc(8px + var(--safe-bot));
  background:linear-gradient(180deg,rgba(11,18,32,0),var(--bg) 30%);display:flex;gap:10px;margin-top:18px}

  .onboard footer{background:linear-gradient(180deg,rgba(246,248,252,0),var(--bg) 30%)}


  html[data-theme="light"] .onboard footer{background:linear-gradient(180deg,rgba(246,248,252,0),var(--bg) 30%)}
/* ========== Banners ========== */
.banner{margin:12px 0 0;padding:12px 14px;border-radius:12px;background:rgba(244,183,64,0.10);
  border:1px solid rgba(244,183,64,0.30);color:var(--warn);font-size:13.5px;display:flex;align-items:center;gap:10px}
.banner.info{background:rgba(90,169,255,0.10);border-color:rgba(90,169,255,0.30);color:var(--rain)}
.banner.bad{background:rgba(255,110,110,0.10);border-color:rgba(255,110,110,0.30);color:var(--bad)}
.banner button{margin-left:auto;color:inherit;font-weight:700;font-size:13px}
/* ========== Modal ========== */
.modal{position:fixed;inset:0;background:rgba(0,0,0,0.50);z-index:20;display:none;
  align-items:flex-end;justify-content:center;padding:0 0 var(--safe-bot)}
.modal.show{display:flex}
.modal-card{background:var(--bg-2);border-top-left-radius:24px;border-top-right-radius:24px;
  padding:18px 22px 24px;width:100%;max-width:540px;border-top:1px solid var(--line);animation:slideup .25s ease;
  /* v1.28.2 — momentum scrolling for the card body on iOS. Many modal-cards
   * set max-height:90vh + overflow-y:auto inline; without this they scroll
   * jerkily on older iOS and can lock up under safe-area constraints. */
  -webkit-overflow-scrolling:touch}
@keyframes slideup{from{transform:translateY(20px);opacity:0}to{transform:none;opacity:1}}
.modal h2{margin:6px 0 4px;font-size:20px}
.handle{width:38px;height:4px;background:var(--line-2);border-radius:999px;margin:0 auto 10px}
/* v1.28.1 — Universal modal close button. Sticky to the top-right of the
 * .modal-card so it stays reachable even when the card content scrolls.
 * On iOS PWA the modal-card can fill nearly the whole viewport (safe-area
 * eats the backdrop above), making the bottom Close button hard to reach
 * if there's any content above it. This × is always tappable. */
.modal-close-x{
  position:sticky;top:0;float:right;
  display:inline-flex;align-items:center;justify-content:center;
  width:36px;height:36px;border-radius:999px;
  background:var(--surface-2);border:1px solid var(--line);
  color:var(--text);font-size:22px;line-height:1;font-weight:400;
  padding:0;cursor:pointer;flex-shrink:0;
  -webkit-tap-highlight-color:transparent;
  z-index:2;
  /* Negative margin pulls it up into the safe-area padding so it sits
   * neatly in the top corner without offsetting the content below. */
  margin:-4px -8px 0 0
}
.modal-close-x:active{transform:scale(0.93);background:var(--surface)}
.modal-close-x:hover{background:var(--surface)}
html[data-theme="light"] .modal-close-x{background:rgba(0,0,0,0.06);color:var(--text)}
.skel{background:linear-gradient(90deg,var(--surface) 0%,var(--surface-2) 50%,var(--surface) 100%);
  background-size:200% 100%;animation:sh 1.2s linear infinite;border-radius:8px}
@keyframes sh{from{background-position:200% 0}to{background-position:-200% 0}}
.muted{color:var(--text-2)}
.small{font-size:13px}
.center{text-align:center}
.spaced{margin-top:14px}
.row{display:flex;align-items:center;gap:10px}
.spread{justify-content:space-between}
.grow{flex:1}
/* v1.28.3 — `minmax(0, 1fr)` instead of `1fr`. The default 1fr expands to
 * `minmax(auto, 1fr)` where `auto` = content's min-width — so a cell
 * containing "100%" forces the column to be at least ~30px wide, and 7
 * columns × 30px + gaps overflow narrow card widths. minmax(0,…) lets
 * columns shrink below their content. Gap also trimmed for narrow phones
 * to give the cells more room. */
.month{display:grid;grid-template-columns:repeat(7,minmax(0,1fr));gap:5px;margin-top:10px;width:100%}
.mday{aspect-ratio:1/1;border-radius:10px;background:var(--surface);border:1px solid var(--line);
  display:flex;flex-direction:column;align-items:center;justify-content:center;font-size:12px;position:relative;padding:4px 2px;
  min-width:0;overflow:hidden}
.mday .d{font-weight:700;font-size:13px}
.mday .p{font-size:10px;color:var(--text-2);margin-top:2px;line-height:1}
/* Very narrow phones (≤360px): tighter gap + smaller text so 7 cells fit */
@media (max-width: 380px){
  .month{gap:4px}
  .mday{padding:3px 1px;font-size:11px}
  .mday .d{font-size:12px}
  .mday .p{font-size:9px}
}
.mday.good{border-color:rgba(61,220,151,0.45);background:rgba(61,220,151,0.10)}
.mday.warn{border-color:rgba(244,183,64,0.40);background:rgba(244,183,64,0.10)}
.mday.bad{border-color:rgba(255,110,110,0.35);background:rgba(255,110,110,0.10)}
.mday.muted{opacity:0.4}
/* v1.30.1 — future days beyond forecast horizon: dashed border, faded text,
   so users see "we don't know yet" instead of a blank-looking cell. */
.mday.future-unknown{
  border-style:dashed;
  border-color:var(--line);
  background:transparent;
  opacity:0.55;
}
.mday.future-unknown .d{color:var(--text-2);font-weight:600}
.mday.future-unknown .p{color:var(--text-2);opacity:0.7}
.legend-unk-dot{display:inline-block;width:8px;height:8px;border-radius:50%;
  border:1.5px dashed var(--text-2);background:transparent;vertical-align:middle;margin-right:2px}
.mday .dot{position:absolute;top:6px;right:6px;width:6px;height:6px;border-radius:50%;background:var(--rain)}
hr.sep{border:0;border-top:1px solid var(--line);margin:14px 0}
/* Contamination banner */
.alert{margin:14px 0 0;background:linear-gradient(180deg,rgba(255,110,110,0.10),rgba(255,110,110,0.04));
  border:1px solid rgba(255,110,110,0.35);border-radius:var(--radius);padding:14px 16px}
.alert.med{background:linear-gradient(180deg,rgba(244,183,64,0.10),rgba(244,183,64,0.04));border-color:rgba(244,183,64,0.35)}
.alert .top{display:flex;align-items:center;gap:8px;font-weight:700;font-size:14px;color:var(--bad)}
.alert.med .top{color:var(--warn)}
.alert .desc{color:var(--text-2);font-size:13.5px;margin-top:6px;line-height:1.45}
.alert .row{display:flex;gap:8px;margin-top:10px}
.alert .row .btn{padding:8px 12px;font-size:13px}
/* Quick log chips */
.quick{display:grid;grid-template-columns:repeat(3,1fr);gap:8px;margin-top:10px}
.quick button{background:var(--surface);border:1px solid var(--line);border-radius:12px;padding:12px 8px;
  font-size:13px;font-weight:600;display:flex;flex-direction:column;align-items:center;gap:4px;color:var(--text)}
.quick button .e{font-size:22px}
.quick button:active{transform:scale(0.96)}
.tabs{display:flex;gap:6px;background:var(--surface);border:1px solid var(--line);
  border-radius:12px;padding:3px;margin-top:10px}
.tabs button{flex:1;padding:8px;border-radius:9px;color:var(--text-2);font-weight:600;font-size:13px}
.tabs button.on{background:var(--surface-2);color:var(--text)}
/* Ad / Donate card */
.ad{margin-top:14px;background:var(--surface);border:1px solid var(--line);border-radius:var(--radius);
  padding:14px 16px;display:flex;gap:12px;align-items:flex-start;text-align:left;width:100%}
.ad-thumb{width:42px;height:42px;border-radius:10px;background:linear-gradient(135deg,#7CC4FF,#2B7BD8);
  display:flex;align-items:center;justify-content:center;color:#fff;font-weight:700;flex:0 0 auto;font-size:18px}
.ad-thumb img{width:100%;height:100%;object-fit:cover;border-radius:10px}
.ad-body{flex:1;min-width:0}
.ad-sp{color:var(--text-3);font-size:10.5px;font-weight:700;text-transform:uppercase;letter-spacing:0.10em}
.ad-ti{font-weight:600;font-size:14.5px;margin-top:2px}
.ad-bd{color:var(--text-2);font-size:13px;margin-top:2px;line-height:1.4}
.ad-cta{color:var(--rain);font-size:12.5px;font-weight:700;margin-top:6px}
.ad-x{background:none;border:0;color:var(--text-3);font-size:18px;padding:0 4px;cursor:pointer}

/* ===== Info-tooltip system (mobile-friendly tap-to-explain) ===== */
.info-i{display:inline-flex;align-items:center;justify-content:center;
  width:16px;height:16px;border-radius:50%;background:transparent;
  border:1px solid var(--line-2);color:var(--text-3);
  font-size:10.5px;font-weight:700;cursor:pointer;
  margin-left:6px;vertical-align:middle;line-height:1;
  font-family:Georgia,serif;font-style:italic;
  transition:all .15s;flex-shrink:0;
  -webkit-user-select:none;user-select:none}
.info-i:hover,.info-i:focus{border-color:var(--rain);color:var(--rain);outline:none}
.info-i:active{transform:scale(0.92)}
.info-pop{position:fixed;z-index:50;max-width:280px;
  background:var(--surface-strong);color:var(--text);
  border:1px solid var(--line-2);border-radius:12px;
  padding:12px 14px;font-size:13px;line-height:1.45;font-weight:400;
  box-shadow:var(--shadow);display:none;letter-spacing:normal;text-transform:none}
.info-pop.show{display:block;animation:fade .15s ease}
.info-pop::before{content:"";position:absolute;width:10px;height:10px;
  background:inherit;border-left:1px solid var(--line-2);border-top:1px solid var(--line-2);
  transform:rotate(45deg);top:-6px;left:var(--arrow-x,16px)}
.info-pop .x{position:absolute;top:6px;right:8px;background:none;border:0;
  color:var(--text-3);font-size:16px;cursor:pointer;padding:2px 4px;line-height:1}
.info-pop .x:hover{color:var(--text)}
.info-pop strong{display:block;font-weight:600;margin-bottom:4px;color:var(--text)}

/* Subtle version tag at page bottom, above bottom nav */
.version-tag{position:fixed;left:0;right:0;bottom:calc(82px + var(--safe-bot));
  text-align:center;font-size:10.5px;color:var(--text-3);letter-spacing:0.10em;font-weight:600;
  pointer-events:none;opacity:0.55;text-transform:uppercase;z-index:4;
  text-shadow:0 0 0 transparent}
.version-tag .pulse{display:inline-block;width:5px;height:5px;border-radius:50%;background:var(--good);
  vertical-align:middle;margin-right:6px;animation:vp 2.4s ease-in-out infinite}
@keyframes vp{0%,100%{opacity:1}50%{opacity:0.3}}

/* Test mode badge — auto-shown by inline script on localhost / staging / ?test=1 */
.test-badge{display:inline-block;margin-left:8px;padding:1px 6px;border-radius:6px;
  background:linear-gradient(135deg,#FFC857,#FF8845);color:#1a0e00;
  font-size:9.5px;font-weight:800;letter-spacing:0.10em;line-height:1.4;
  opacity:0.95;vertical-align:middle;
  box-shadow:0 2px 8px -2px rgba(255,164,56,0.45)}
.sponsored{color:var(--accent);text-decoration:underline;text-decoration-thickness:1px;text-underline-offset:3px}
.sponsored:hover{color:var(--rain)}
.sponsored-tag{display:inline-block;font-size:10px;font-weight:700;letter-spacing:0.08em;text-transform:uppercase;
  color:var(--text-3);background:var(--surface-2);padding:2px 6px;border-radius:6px;margin-left:4px;vertical-align:1px;border:1px solid var(--line)}
/* Cookie consent banner */
/* Update banner shown when SW has a new version waiting */
.update-banner{margin:0 0 12px;background:linear-gradient(180deg,rgba(90,169,255,0.10),rgba(90,169,255,0.04));
  border:1px solid rgba(90,169,255,0.30);border-radius:14px;padding:12px 14px;display:flex;align-items:center;gap:10px}
html[data-theme="light"] .update-banner{background:linear-gradient(180deg,rgba(43,175,175,0.10),rgba(43,175,175,0.04));border-color:rgba(43,175,175,0.35)}
.update-banner .ico{font-size:18px;line-height:1}
.update-banner .body{flex:1;font-size:13.5px;line-height:1.4}
.update-banner .body strong{display:block;font-size:14px;color:var(--text);margin-bottom:2px}
.update-banner .body span{color:var(--text-2)}
.update-banner button{padding:8px 14px;font-size:13px;font-weight:700;border-radius:10px;border:0;cursor:pointer;
  background:linear-gradient(180deg,var(--rain),var(--rain-2));color:#fff;flex-shrink:0}
.update-banner button:active{transform:scale(0.97)}
.consent{position:fixed;left:12px;right:12px;bottom:calc(12px + var(--safe-bot));z-index:40;
  background:var(--surface-strong);border:1px solid var(--line-2);border-radius:18px;
  box-shadow:var(--shadow-lg);padding:18px 18px 16px;display:none;max-width:520px;margin:0 auto}
.consent.show{display:block;animation:slideup .25s cubic-bezier(.2,.7,.2,1)}
.consent h3{margin:0 0 6px;font-size:16px;letter-spacing:-0.01em}
.consent p{margin:0 0 10px;color:var(--text-2);font-size:13.5px;line-height:1.5}
.consent .row{display:flex;gap:8px;flex-wrap:wrap;margin-top:12px}
.consent .row .btn{flex:1 0 auto;font-size:13px;padding:10px 12px}
.consent details{margin-top:8px;font-size:13px}
.consent summary{cursor:pointer;color:var(--accent);font-weight:600;font-size:13px;list-style:none;padding:4px 0}
.consent summary::-webkit-details-marker{display:none}
.consent .switch{display:flex;justify-content:space-between;align-items:center;padding:8px 0;border-top:1px solid var(--line)}
.consent .switch:first-of-type{border-top:0;margin-top:6px}
.consent .switch label{font-weight:600;font-size:13.5px}
.consent .switch .desc{display:block;color:var(--text-3);font-size:11.5px;font-weight:400;margin-top:2px}
.consent .switch input[type="checkbox"]{transform:scale(1.2);accent-color:var(--rain)}
.consent .switch input[disabled]{opacity:0.5}
.toast{position:fixed;bottom:calc(96px + var(--safe-bot));left:50%;transform:translateX(-50%);
  background:var(--surface-2);border:1px solid var(--line-2);padding:10px 16px;border-radius:999px;
  font-size:13.5px;font-weight:600;box-shadow:var(--shadow);z-index:30;display:none;animation:fade .2s ease}
.toast.show{display:block}
/* Branding flourish */
.logo-mark{display:inline-flex;align-items:center;justify-content:center;width:52px;height:52px;border-radius:16px;
  background:linear-gradient(135deg,var(--rain),var(--rain-2));box-shadow:0 10px 22px -6px color-mix(in srgb, var(--rain) 50%, transparent)}
.logo-mark svg{width:28px;height:28px;color:#fff}
.hero-h{display:flex;align-items:flex-start;gap:14px;margin-bottom:6px}
.hero-h .meta{flex:1}
.hero-temp{font-weight:700;font-size:32px;letter-spacing:-0.02em}
.hero-temp small{font-size:14px;font-weight:600;color:var(--text-2);margin-left:2px}
.hidden{display:none !important}

/* ===== EngagementEngine — v1.24.0 =====
 * Modal: piggybacks on existing .modal styles. Bottom-sheet on mobile,
 * centered card on desktop (≥ 600px). Opt buttons stack full-width.
 * Banner: lives inside #banners — reuses .banner.info and stacks vertically.
 */
.eng-modal{align-items:flex-end}
@media (min-width:600px){
  .eng-modal{align-items:center}
}
.eng-modal-card{max-width:480px;padding:16px 20px 22px;border-radius:24px;
  box-shadow:var(--shadow-lg);border:1px solid var(--line)}
@media (min-width:600px){
  .eng-modal-card{border-radius:22px;margin:0 16px}
}
.eng-modal h2{font-size:18px;letter-spacing:-0.01em;line-height:1.3}
.eng-modal-opts{display:flex;flex-direction:column;gap:8px;margin-top:10px}
.eng-modal-opts .btn.eng-opt{width:100%;justify-content:flex-start;text-align:left;
  font-size:14px;padding:12px 14px;border-radius:12px;background:var(--surface-2);
  border:1px solid var(--line-2);color:var(--text);transition:border-color .15s, background .15s}
.eng-modal-opts .btn.eng-opt:hover,
.eng-modal-opts .btn.eng-opt:focus{border-color:var(--rain);background:var(--rain-soft);outline:none}
.eng-modal-dismiss{opacity:0.7;font-size:13px}
.eng-modal-dismiss:hover{opacity:1}
#engagementBanner .btn.eng-opt{background:rgba(255,255,255,0.10);
  border:1px solid var(--line-2);color:var(--text);border-radius:8px}
#engagementBanner .btn.eng-opt:hover{border-color:var(--rain);background:var(--rain-soft)}
html[data-theme="light"] #engagementBanner .btn.eng-opt{background:#FFF}

/* ============================================================
   v1.27.0 — IA pass helpers
   ------------------------------------------------------------
   .row2-grid pairs two .field blocks (e.g. Brand/Model,
   Country/Region) into a single horizontal row on wider screens.
   On phones it collapses to a stacked column. Breakpoint bumped
   to 480px in v1.27.12 because 375–414px phones (iPhone 14,
   Samsung Galaxy, Pixel) were squeezing the inputs off-screen.
   ------------------------------------------------------------ */
.row2-grid{display:grid;grid-template-columns:1fr 1fr;gap:10px;align-items:end}
.row2-grid > .field{margin-top:14px;min-width:0}
.row2-grid > .field input,
.row2-grid > .field select{width:100%;min-width:0;max-width:100%;box-sizing:border-box}
.row2-grid select{padding:12px 14px;border-radius:12px;
  background:var(--surface);border:1px solid var(--line);color:var(--text);font-size:15px}
.row2-grid select:focus{border-color:var(--rain)}
/* v1.27.12 — Stack rows on ALL phones (≤ 480px). Brand/Model + Country/Region
 * have text-input width that doesn't compress well below ~170px each. */
@media (max-width: 480px){
  .row2-grid{grid-template-columns:1fr;gap:0}
  .row2-grid > .field{margin-top:14px}
}

/* v1.27.0 — Customize disclosure under Quick Set. Sits below the care
   scale and exposes wash cycle / strictness / rinse / wash time. The
   summary keeps a subtle chevron so users know it's expandable. */
#pfCustomizeWash[open] > summary{margin-bottom:8px}
#pfCustomizeWash > summary{padding:10px 12px;background:var(--surface);
  border:1px solid var(--line);border-radius:12px;list-style:none}
#pfCustomizeWash > summary::-webkit-details-marker{display:none}
#pfCustomizeWash > summary::before{content:"▸ ";color:var(--text-3);
  font-size:11px;margin-right:4px;transition:transform .15s}
#pfCustomizeWash[open] > summary::before{content:"▾ "}

/* Same affordance for "Different at work?" disclosure */
#pfWorkParkingDifferent > summary{padding:8px 12px;background:transparent;
  border:1px dashed var(--line);border-radius:10px;list-style:none;font-size:13px}
#pfWorkParkingDifferent > summary::-webkit-details-marker{display:none}
#pfWorkParkingDifferent > summary::before{content:"▸ ";color:var(--text-3);
  font-size:11px;margin-right:4px}
#pfWorkParkingDifferent[open] > summary::before{content:"▾ "}

/* Cache & troubleshooting disclosure in Settings */
#screen-settings details > summary{padding:10px 12px;background:var(--surface);
  border:1px solid var(--line);border-radius:12px;list-style:none}
#screen-settings details > summary::-webkit-details-marker{display:none}
#screen-settings details > summary::before{content:"▸ ";color:var(--text-3);
  font-size:11px;margin-right:4px}
#screen-settings details[open] > summary::before{content:"▾ "}

/* ========== v1.28.0 — Glossary modal + (?) link buttons ==========
 * `.g-link`     — the tiny "(?)" affordance you drop next to a term.
 * `.g-modal`    — the bottom-sheet glossary, reuses .modal / .modal-card.
 * `.g-entry`    — each <details> inside the glossary list.
 */
.g-link{display:inline-flex;align-items:center;justify-content:center;
  width:16px;height:16px;border-radius:50%;border:1px solid var(--line-2);
  background:var(--surface);color:var(--text-2);font-size:10px;font-weight:700;
  line-height:1;padding:0;margin-left:4px;vertical-align:1px;cursor:pointer;
  text-transform:none;letter-spacing:0;font-family:inherit;
  transition:transform .12s ease, background .12s ease, color .12s ease}
.g-link:hover,.g-link:focus{background:var(--rain);color:#fff;border-color:var(--rain);
  outline:none;transform:scale(1.08)}
.g-link-md{width:18px;height:18px;font-size:11px}

/* Tappable Settings rows (Glossary, future deep-links) */
.kv.kv-tappable{cursor:pointer;transition:background .12s ease}
.kv.kv-tappable:hover,.kv.kv-tappable:focus{background:var(--surface);outline:none}
.kv.kv-tappable .v{color:var(--text-2);font-size:18px;font-weight:600}

/* Glossary modal */
.g-modal .modal-card{padding-bottom:28px}
.g-list{display:flex;flex-direction:column;gap:8px}
.g-entry{background:var(--surface);border:1px solid var(--line);border-radius:12px;
  padding:0;transition:border-color .15s ease}
.g-entry[open]{border-color:rgba(124,196,255,0.40)}
.g-entry > summary{list-style:none;padding:12px 14px;cursor:pointer;
  display:flex;align-items:center;justify-content:space-between;gap:10px;
  font-size:14.5px;color:var(--text)}
.g-entry > summary::-webkit-details-marker{display:none}
.g-entry > summary strong{font-weight:700}
.g-entry .g-chevron{color:var(--text-3);font-size:18px;line-height:1;
  transition:transform .18s ease;transform:rotate(0deg)}
.g-entry[open] > summary .g-chevron{transform:rotate(90deg)}
.g-entry .g-body{margin:0;padding:0 14px 14px;font-size:13px;line-height:1.55;
  color:var(--text-2)}

/* ============ v1.30.0 — "What's new" modal ============
 * Renders the CHANGELOG mapping (version → {title, bullets}) as a stack of
 * entries inside the standard .modal/.modal-card bottom-sheet. The latest
 * three versions are rendered up front; the rest sit inside a <details>
 * collapsed by default so the modal stays tight on mobile.
 */
.wn-modal .modal-card{padding-bottom:24px}
.wn-list{display:flex;flex-direction:column;gap:14px}
.wn-entry{background:var(--surface);border:1px solid var(--line);
  border-radius:14px;padding:14px 16px;position:relative}
.wn-entry-first{border-color:rgba(124,196,255,0.40);
  box-shadow:0 0 0 1px rgba(124,196,255,0.18) inset}
.wn-version-row{display:flex;align-items:center;gap:6px;
  font-size:11.5px;color:var(--text-3);font-weight:600;
  letter-spacing:0.02em;text-transform:uppercase;margin-bottom:4px}
.wn-version{color:var(--rain);font-weight:700;letter-spacing:0.04em}
.wn-dot{color:var(--text-3)}
.wn-brand{color:var(--text-3);font-weight:500}
.wn-title{font-size:15px;font-weight:700;color:var(--text);line-height:1.35;
  margin-bottom:8px}
.wn-bullets{margin:0;padding-left:20px;list-style:disc;
  display:flex;flex-direction:column;gap:6px}
.wn-bullets li{font-size:13.5px;line-height:1.55;color:var(--text-2)}
.wn-older{margin-top:6px;border-top:1px solid var(--line);padding-top:14px}
.wn-older > summary{cursor:pointer;font-weight:600;font-size:13px;
  color:var(--text-2);padding:6px 2px;list-style:none}
.wn-older > summary::-webkit-details-marker{display:none}

/* v1.30.4 — "Why this verdict?" affordance under the hero verdict */
.why-verdict-btn{
  background:transparent;border:0;padding:4px 0 0;margin:0;
  font-size:12px;line-height:1.3;color:var(--accent);
  text-decoration:underline;text-underline-offset:2px;
  cursor:pointer;font-family:inherit;font-weight:500;
  align-self:flex-start;display:inline-block;
}
.why-verdict-btn:hover{opacity:0.85}
.why-verdict-btn:active{opacity:0.7}

/* "Why this verdict?" modal — uses the same modal-card pattern as What's new */
.wv-modal .modal-card{max-height:88vh;overflow-y:auto;position:relative}
.wv-summary{font-size:14.5px;font-weight:700;color:var(--text);line-height:1.4;margin:4px 0 6px}
.wv-section{margin-top:14px;padding-top:12px;border-top:1px solid var(--line)}
.wv-section:first-of-type{border-top:0;padding-top:0;margin-top:6px}
.wv-section-h{font-size:12px;font-weight:700;text-transform:uppercase;letter-spacing:0.06em;
  color:var(--text-3);margin-bottom:8px}
.wv-row{display:flex;justify-content:space-between;gap:12px;font-size:13px;line-height:1.5;
  padding:5px 0;color:var(--text-2)}
.wv-row .wv-k{color:var(--text-2)}
.wv-row .wv-v{color:var(--text);font-weight:600;text-align:right}
.wv-bullets{margin:8px 0 0;padding-left:18px;list-style:disc;
  display:flex;flex-direction:column;gap:5px}
.wv-bullets li{font-size:13px;line-height:1.5;color:var(--text-2)}
.wv-note{font-size:12px;line-height:1.5;color:var(--text-3);margin-top:10px;font-style:italic}
.wn-older[open] > summary{margin-bottom:10px}
.wn-older-body{display:flex;flex-direction:column;gap:14px}
@media (max-width: 380px){
  .wn-entry{padding:12px 14px}
  .wn-title{font-size:14.5px}
  .wn-bullets li{font-size:13px}
}
