/* Fonts are requested from each page's <head> instead of an @import here.
   Two reasons: an @import inside the stylesheet cannot start downloading
   until this file itself has arrived (a serial round-trip on a phone), and
   it had to name every script at once — so an English user was pulling the
   full Bengali and Tamil faces, several hundred KB they would never render.
   The head script requests Latin + Devanagari (the wordmark is always
   मौसम) and adds the Bengali or Tamil face only when that locale is on. */

/* Hindi/Bengali/Tamil script fallbacks — the base font stack only covers
   Latin + Devanagari, so Bengali/Tamil text would fall back to a system
   serif and look inconsistent without these. */
:lang(hi){font-family:'Noto Sans','Noto Serif Devanagari',system-ui,sans-serif}
:lang(bn){font-family:'Noto Sans Bengali','Noto Sans',system-ui,sans-serif}
:lang(ta){font-family:'Noto Sans Tamil','Noto Sans',system-ui,sans-serif}

/* Colour through the evening.

   The app has no light/dark switch and no setting. It carries a --dusk
   level from 0 (full daylight) to 1 (full night), hung off the location's
   own sunrise and sunset, and the palette below is built from it. A fixed
   "after 7 PM" rule could not do this: a December evening in Delhi is dark
   by 5:30 while June is still bright at 7.

   Two dials come out of that one level, and the split is the whole point:

   --night picks the palette, and it is 0 or 1 — never in between. Fading a
   palette across its own inversion does not work: halfway between near-black
   text and near-white text, over a background making the same journey, both
   land on the same grey and the words are simply gone (1:1 contrast, and
   under 3:1 for a good stretch either side of it). So the palette steps, at
   the one honest moment for it — sunset — and a short transition carries it
   over so the step reads as a dissolve rather than a flip.

   --deep is where the gradual part actually lives. It runs 0 at sunset to 1
   about two hours later, and the night surfaces ride it from a twilight
   slate down to midnight. So the app is only lightly dark at 7 PM, settles
   all the way down by 9, and comes back up through the same slate before
   sunrise. The text stays white throughout, so nothing has to cross over
   twice. */
@property --night{syntax:'<number>';inherits:true;initial-value:0}
@property --deep{syntax:'<number>';inherits:true;initial-value:0}

/* The weather sky. These are set on <html> by sky.js and transitioned here,
   which is what makes a change of weather a crossfade rather than a cut —
   and because they live on the root rather than on the elements, a
   re-render halfway through picks up the value in flight instead of
   snapping to the end. */
@property --wx-tint{syntax:'<color>';inherits:true;initial-value:#8FC0E8}
@property --wx-top{syntax:'<number>';inherits:true;initial-value:0}
@property --wx-bot{syntax:'<number>';inherits:true;initial-value:0}
@property --sky-1{syntax:'<color>';inherits:true;initial-value:#A9CFEE}
@property --sky-2{syntax:'<color>';inherits:true;initial-value:#D2E3F0}
@property --sky-3{syntax:'<color>';inherits:true;initial-value:#EEEDE5}
@property --sky-4{syntax:'<color>';inherits:true;initial-value:#F5F4EF}

:root{
  --dusk:0;    /* the raw dial, 0..1 — published for inspection; the two
                  below are what the palette is actually built from */
  --night:0;   /* which palette: 0 daylight, 1 night */
  --deep:0;    /* how far into the night: 0 twilight, 1 midnight */
  --night-pct:calc(var(--night) * 100%);
  --deep-pct:calc(var(--deep) * 100%);

  /* Every ramp's ends, named once. d- daylight, t- twilight, n- midnight.
     Only surfaces need a twilight value; ink is white from sunset on. */
  --d-ink:#171A1C;                          --n-ink:#EEF3FB;
  --d-ink-secondary:rgba(23,26,28,.66);     --n-ink-secondary:rgba(238,243,251,.72);
  --d-ink-tertiary:rgba(23,26,28,.62);      --n-ink-tertiary:rgba(238,243,251,.58);
  --d-card-border:rgba(23,26,28,.07);       --n-card-border:rgba(255,255,255,.09);
  --d-chip:rgba(255,255,255,.9);            --n-chip:rgba(255,255,255,.10);
  --d-chip-ink:rgba(23,26,28,.72);          --n-chip-ink:rgba(238,243,251,.78);
  --d-chip-border:rgba(23,26,28,.10);       --n-chip-border:rgba(255,255,255,.14);
  --d-chip-on-bg:#171A1C;                   --n-chip-on-bg:#EEF3FB;
  --d-chip-on-ink:#fff;                     --n-chip-on-ink:#101825;
  --d-icon-btn:rgba(255,255,255,.66);       --n-icon-btn:rgba(255,255,255,.12);
  --d-icon-btn-hover:rgba(255,255,255,.95); --n-icon-btn-hover:rgba(255,255,255,.2);
  --d-cloud:rgba(255,255,255,.86);          --n-cloud:rgba(226,235,247,.5);
  /* The night greens and reds are lifted off their daylight values: the
     same ones go muddy and fail contrast against a dark card. */
  --d-ok:#2E7D5B;      --n-ok:#5FBF92;
  --d-warn:#C9772A;    --n-warn:#E8A45C;
  --d-bad:#C2452D;     --n-bad:#E8705C;
  --d-info:#2C6EA8;    --n-info:#7FB2E5;

  /* Surfaces: daylight, then twilight settling to midnight. */
  --d-page:#F5F4EF;                --t-page:#223047;          --n-page:#101825;
  --d-card:#fff;                   --t-card:#2C3B54;          --n-card:#1A2634;
  --d-panel:#fff;                  --t-panel:#2C3B54;         --n-panel:#1A2634;
  --d-backdrop:#E7E5DF;            --t-backdrop:#16203A;      --n-backdrop:#070C13;
  --d-glass:rgba(245,244,239,.88); --t-glass:rgba(34,48,71,.9); --n-glass:rgba(16,24,37,.9);

  --ink:color-mix(in oklab, var(--n-ink) var(--night-pct), var(--d-ink));
  --ink-secondary:color-mix(in oklab, var(--n-ink-secondary) var(--night-pct), var(--d-ink-secondary));
  --ink-tertiary:color-mix(in oklab, var(--n-ink-tertiary) var(--night-pct), var(--d-ink-tertiary));
  --card-border:color-mix(in oklab, var(--n-card-border) var(--night-pct), var(--d-card-border));
  --chip:color-mix(in oklab, var(--n-chip) var(--night-pct), var(--d-chip));
  --chip-ink:color-mix(in oklab, var(--n-chip-ink) var(--night-pct), var(--d-chip-ink));
  --chip-border:color-mix(in oklab, var(--n-chip-border) var(--night-pct), var(--d-chip-border));
  --chip-on-bg:color-mix(in oklab, var(--n-chip-on-bg) var(--night-pct), var(--d-chip-on-bg));
  --chip-on-ink:color-mix(in oklab, var(--n-chip-on-ink) var(--night-pct), var(--d-chip-on-ink));
  --icon-btn:color-mix(in oklab, var(--n-icon-btn) var(--night-pct), var(--d-icon-btn));
  --icon-btn-hover:color-mix(in oklab, var(--n-icon-btn-hover) var(--night-pct), var(--d-icon-btn-hover));
  --cloud:color-mix(in oklab, var(--n-cloud) var(--night-pct), var(--d-cloud));
  --ok:color-mix(in oklab, var(--n-ok) var(--night-pct), var(--d-ok));
  --warn:color-mix(in oklab, var(--n-warn) var(--night-pct), var(--d-warn));
  --bad:color-mix(in oklab, var(--n-bad) var(--night-pct), var(--d-bad));
  --info:color-mix(in oklab, var(--n-info) var(--night-pct), var(--d-info));

  /* Twilight settling to midnight first, then that against daylight. */
  --page:color-mix(in oklab, color-mix(in oklab, var(--n-page) var(--deep-pct), var(--t-page)) var(--night-pct), var(--d-page));
  --card:color-mix(in oklab, color-mix(in oklab, var(--n-card) var(--deep-pct), var(--t-card)) var(--night-pct), var(--d-card));
  --panel:color-mix(in oklab, color-mix(in oklab, var(--n-panel) var(--deep-pct), var(--t-panel)) var(--night-pct), var(--d-panel));
  --backdrop:color-mix(in oklab, color-mix(in oklab, var(--n-backdrop) var(--deep-pct), var(--t-backdrop)) var(--night-pct), var(--d-backdrop));
  --glass:color-mix(in oklab, color-mix(in oklab, var(--n-glass) var(--deep-pct), var(--t-glass)) var(--night-pct), var(--d-glass));
}

/* --night is what needs easing; --deep only ever moves a minute at a time,
   but carrying it too keeps even that from reading as a redraw. */
html{transition:--night .9s ease, --deep 1.2s linear,
     --wx-tint .8s ease, --wx-top .8s ease, --wx-bot .8s ease,
     --sky-1 .8s ease, --sky-2 .8s ease, --sky-3 .8s ease, --sky-4 .8s ease}
@media (prefers-reduced-motion:reduce){ html{transition:none} }

/* Without color-mix there is no dissolve to be had, so fall back to the
   plain two-step switch on the attribute that already marks the crossover,
   and pin the night surfaces at midnight rather than twilight. */
@supports not (color: color-mix(in oklab, #000 50%, #fff)){
  [data-theme="dark"]{
    --ink:var(--n-ink);
    --ink-secondary:var(--n-ink-secondary);
    --ink-tertiary:var(--n-ink-tertiary);
    --card-border:var(--n-card-border);
    --chip:var(--n-chip);
    --chip-ink:var(--n-chip-ink);
    --chip-border:var(--n-chip-border);
    --chip-on-bg:var(--n-chip-on-bg);
    --chip-on-ink:var(--n-chip-on-ink);
    --icon-btn:var(--n-icon-btn);
    --icon-btn-hover:var(--n-icon-btn-hover);
    --cloud:var(--n-cloud);
    --ok:var(--n-ok);
    --warn:var(--n-warn);
    --bad:var(--n-bad);
    --info:var(--n-info);
    --page:var(--n-page);
    --card:var(--n-card);
    --panel:var(--n-panel);
    --backdrop:var(--n-backdrop);
    --glass:var(--n-glass);
  }
}

*{box-sizing:border-box}
html,body{margin:0;padding:0}
body{
  background:var(--backdrop);
  font-family:'Noto Sans',system-ui,sans-serif;
  color:var(--ink);
  display:flex;
  justify-content:center;
  align-items:flex-start;
  min-height:100vh;
  padding:24px 12px 60px;
}
a{color:#1C5C93;text-decoration:none}
a:hover{color:#123f66}
::-webkit-scrollbar{display:none}
button{font-family:inherit;border:none;background:none;padding:0;cursor:pointer}
input{font-family:inherit}

.app-shell{
  position:relative;
  width:402px;
  max-width:100vw;
  min-height:874px;
  background:var(--page);
  border-radius:44px;
  overflow:hidden;
  box-shadow:0 35px 80px -10px rgba(0,0,0,.22), 0 0 0 1px rgba(23,26,28,.10), 0 0 0 8px #E2DFD8;
}

@media (max-width:440px){
  body{padding:0}
  .app-shell{border-radius:0;width:100%;box-shadow:none;min-height:100vh}
}

/* Phone Status Bar & Dynamic Island */
.phone-status-bar{
  position:absolute;top:0;left:0;right:0;height:48px;
  display:flex;justify-content:space-between;align-items:center;
  padding:0 24px;z-index:40;pointer-events:none;
  font-size:13px;font-weight:600;color:var(--ink);
}
.phone-status-bar.dark{color:#fff}
.dynamic-island{
  position:absolute;left:50%;transform:translateX(-50%);top:9px;
  width:112px;height:28px;border-radius:14px;background:#000;
  box-shadow:0 1px 4px rgba(0,0,0,.2);
}
.status-badges{display:flex;align-items:center;gap:8px}
.status-imd-pill{
  font-size:9.5px;font-weight:700;letter-spacing:.06em;
  padding:2px 7px;border-radius:999px;background:rgba(23,26,28,.08);
  color:var(--ink);
}
.phone-status-bar.dark .status-imd-pill{
  background:rgba(255,255,255,.16);color:#fff;
}
.home-indicator{
  position:fixed;bottom:8px;left:50%;transform:translateX(-50%);
  width:134px;height:5px;border-radius:100px;background:rgba(23,26,28,.22);
  z-index:60;pointer-events:none;
}
.dark .home-indicator{background:rgba(255,255,255,.5)}
@media (max-width:440px){
  /* On a real phone the OS already shows a real status bar (real clock,
     real signal). This simulated one is desktop-mockup chrome only —
     showing it on an actual device just draws a fake clock/IMD pill on
     top of the real one. */
  .phone-status-bar{display:none}
  .dynamic-island{display:none}
  .home-indicator{display:none}
}

/* Behind the photograph, so mostly what you see while the photograph is
   still arriving. Its stops come from the same weather table as the wash,
   and at night sky.js settles them with --deep like every other surface. */
.sky-gradient{
  position:absolute;top:0;left:0;right:0;height:440px;pointer-events:none;z-index:0;
  background:linear-gradient(180deg,var(--sky-1) 0%,var(--sky-2) 42%,var(--sky-3) 78%,var(--sky-4) 100%);
}

.texture-glow{
  position:absolute;inset:0;pointer-events:none;z-index:0;
  background:
    radial-gradient(120% 55% at 12% 46%,rgba(44,110,168,.10),transparent 62%),
    radial-gradient(90% 45% at 92% 68%,rgba(242,169,59,.13),transparent 60%),
    radial-gradient(110% 40% at 50% 100%,rgba(46,125,91,.10),transparent 65%);
}
.texture-grain{
  position:absolute;inset:0;pointer-events:none;opacity:.5;z-index:0;
  background-image:repeating-linear-gradient(135deg,rgba(23,26,28,.035) 0 1px,transparent 1px 7px);
}

/* Photo Crop Band: Subject strictly on right half, left protected for text column.
   Fixed to the viewport (not app-shell) so it stays put as the page scrolls —
   the header and persona chips scroll normally over it, and content-sheet
   below (opaque) covers it completely once scrolled far enough. */
.hero-photo-band{
  position:fixed;top:0;left:50%;transform:translateX(-50%);
  width:402px;max-width:100vw;overflow:hidden;z-index:0;
  height:100vh;height:100dvh; /* dvh tracks the real visible viewport (iOS Safari's
    collapsing address bar included) — a fixed px guess was consistently shorter
    than people's actual screens, leaving a gap before the content sheet. */
}
.hero-photo-wrapper{position:absolute;transition:all .35s ease}
.hero-photo-wrapper img{width:100%;height:100%;object-fit:cover;display:block}
.hero-scrim{
  position:fixed;top:0;left:50%;transform:translateX(-50%);
  width:402px;max-width:100vw;pointer-events:none;z-index:2;transition:background .35s ease;
  height:100vh;height:100dvh;
}
.hero-scrim.night{opacity:calc(var(--night) * (.7 + .3 * var(--deep)))}
.hero-accent-bar{
  position:fixed;top:0;left:50%;transform:translateX(-50%);
  width:402px;max-width:100vw;height:4px;z-index:3;
}
@media (max-width:440px){
  .hero-photo-band, .hero-scrim, .hero-accent-bar,
  .weather-wash, .weather-fx{left:0;transform:none;width:100%}
}

/* ---------- weather sky ----------
   Two layers between the photograph and the scrim: a wash that carries the
   weather's colour, and the animated layer in front of it. Both sit under
   the scrim on purpose — the scrim is what fades the lower hero towards the
   page colour, and that is what keeps body text legible over a photograph.
   Rain painted on top of it would undo that, and it also means the drops
   fade out exactly where the reading starts. */
.weather-wash, .weather-fx{
  position:fixed;top:0;left:50%;transform:translateX(-50%);
  width:402px;max-width:100vw;height:100vh;height:100dvh;
  pointer-events:none;z-index:3;overflow:hidden;
}
/* Both sit above the scrim rather than below it. Under it they were all
   but invisible in daylight: the scrim carries the persona tint at .88
   alpha across the top corner, which is most of where the weather would
   have shown. Above it they are legible — and safe, because the wash is
   gone by two thirds down and the falling layer is masked out before it,
   so neither of them ever reaches the text the scrim exists to protect.
   Measured worst case (a daytime thunderstorm, the heaviest wash here):
   the wordmark still sits at 8.5:1. */
.weather-fx{
  -webkit-mask-image:linear-gradient(180deg,#000 0%,#000 44%,transparent 66%);
  mask-image:linear-gradient(180deg,#000 0%,#000 44%,transparent 66%);
}
.weather-wash{
  background:linear-gradient(180deg,
    color-mix(in srgb, var(--wx-tint) calc(var(--wx-top) * 100%), transparent) 0%,
    color-mix(in srgb, var(--wx-tint) calc(var(--wx-top) * 62%), transparent) 34%,
    color-mix(in srgb, var(--wx-tint) calc(var(--wx-bot) * 100%), transparent) 68%,
    transparent 100%);
}

/* Every particle below animates transform and opacity only, so none of it
   touches layout or paint — and none of it runs a JS loop. The negative
   delays start each one mid-flight, so the layer reads as weather already
   under way the moment it appears rather than everything falling from the
   top at once. */
.wx-drop{
  position:absolute;top:0;width:2px;height:24px;border-radius:1px;
  background:linear-gradient(180deg,rgba(220,236,255,0),rgba(220,236,255,.92));
  animation:wxRain linear infinite;
}
@keyframes wxRain{
  from{transform:translate3d(0,-8vh,0);opacity:0}
  8%{opacity:1}
  to{transform:translate3d(-26px,86vh,0);opacity:.15}
}

.wx-flake{
  position:absolute;top:0;width:7px;height:7px;border-radius:50%;
  background:rgba(255,255,255,.95);box-shadow:0 0 4px rgba(255,255,255,.5);
  animation:wxSnow linear infinite;
}
@keyframes wxSnow{
  from{transform:translate3d(0,-6vh,0);opacity:0}
  10%{opacity:.9}
  50%{transform:translate3d(15px,38vh,0)}
  to{transform:translate3d(-8px,84vh,0);opacity:.1}
}

.wx-cloud{
  position:absolute;left:0;height:76px;border-radius:50%;
  background:radial-gradient(closest-side,rgba(255,255,255,.85),rgba(255,255,255,0));
  filter:blur(6px);animation:wxDrift linear infinite;
}
@keyframes wxDrift{
  from{transform:translate3d(-60%,0,0)}
  to{transform:translate3d(420px,0,0)}
}

.wx-fog{
  position:absolute;left:-20%;width:140%;height:120px;
  background:linear-gradient(180deg,rgba(232,232,228,0),rgba(232,232,228,.75),rgba(232,232,228,0));
  filter:blur(10px);animation:wxFog ease-in-out infinite alternate;
}
@keyframes wxFog{
  from{transform:translate3d(-40px,0,0) scaleY(.9)}
  to{transform:translate3d(40px,0,0) scaleY(1.15)}
}

/* The sun. One element, pulsing slowly — bright enough to notice on a clear
   afternoon and not so much that it competes with the temperature. */
.wx-ray{
  position:absolute;top:-70px;right:-60px;width:300px;height:300px;border-radius:50%;
  background:radial-gradient(closest-side,rgba(255,226,164,.55),rgba(255,214,132,.16) 52%,rgba(255,214,132,0));
  animation:wxPulse 7s ease-in-out infinite;
}
@keyframes wxPulse{
  0%,100%{transform:scale(1);opacity:.75}
  50%{transform:scale(1.13);opacity:1}
}

.wx-star{
  position:absolute;width:2px;height:2px;border-radius:50%;background:#fff;
  animation:wxTwinkle 4.5s ease-in-out infinite;
}
@keyframes wxTwinkle{
  0%,100%{opacity:.25;transform:scale(1)}
  50%{opacity:.95;transform:scale(1.5)}
}

/* Lightning: dark almost all of the time, with two quick strikes near the
   end of a long cycle so it stays startling instead of decorative. */
.wx-flash{
  position:absolute;inset:0;background:rgba(226,238,255,.85);opacity:0;
  animation:wxFlash 11s linear infinite;
}
@keyframes wxFlash{
  0%,88%,100%{opacity:0}
  89%{opacity:.5}
  90.5%{opacity:0}
  92%{opacity:.34}
  93.5%{opacity:0}
}

/* Falling and flashing is the part that can genuinely bother people, so it
   goes entirely; the slow drifts just hold still. */
@media (prefers-reduced-motion:reduce){
  .wx-drop, .wx-flake, .wx-flash{display:none}
  .wx-cloud, .wx-fog, .wx-ray, .wx-star{animation:none}
}

.content{position:relative;z-index:4}
/* No background here on purpose — the fixed photo behind stays visible
   through the gaps around cards for the whole page, not just the first
   screen. Individual cards (tiles, panels, footer) stay opaque on their
   own, so text is never sitting directly on the photo. */
/* Clears the bottom nav plus the floating assistant button, so the last
   card on the page is never parked permanently underneath either. */
.content-sheet{position:relative;padding-bottom:148px}

.header-block{padding:54px 20px 24px}
@media (max-width:440px){
  /* That 54px was reserved for the fake status bar, which is now hidden on
     real phones. The page is viewport-fit=cover and the PWA runs
     standalone, so content really does extend under the clock and notch —
     the inset is what keeps the wordmark out from under them. The fallback
     0px covers every non-notched device and desktop. */
  .header-block{padding-top:max(18px, calc(6px + env(safe-area-inset-top, 0px)))}
}
.wordmark-row{display:flex;align-items:center;justify-content:space-between;margin-bottom:20px}
.wordmark{display:flex;align-items:baseline;gap:9px}
.wordmark .en{font-size:22px;font-weight:700;line-height:1;letter-spacing:-.015em}
.wordmark .hi{font-family:'Noto Serif Devanagari',serif;font-weight:500;font-size:15px;color:var(--ink-secondary)}
.header-icons{display:flex;align-items:center;gap:8px}
.icon-btn{
  width:32px;height:32px;border-radius:16px;background:var(--icon-btn);
  border:1px solid rgba(23,26,28,.09);display:flex;align-items:center;justify-content:center;
  color:var(--ink);transition:background .15s;
}
.icon-btn:hover{background:var(--icon-btn-hover)}
.lang-btn{width:auto;padding:0 10px;font-size:11px;font-weight:700;letter-spacing:.03em}
.lang-panel{gap:2px}
.lang-list{margin-top:4px}
.lang-row{
  display:flex;align-items:center;justify-content:space-between;padding:14px 4px;
  border-top:1px solid rgba(23,26,28,.07);font-size:14px;font-weight:600;cursor:pointer;
}
.lang-row:first-of-type{border-top:none}
.lang-row.active{color:var(--ok)}
.lang-row svg{width:16px;height:16px}

.location-row{display:flex;align-items:center;gap:6px;margin-bottom:2px;cursor:pointer;user-select:none}
.location-dot{width:6px;height:6px;border-radius:3px;background:var(--bad)}
.location-city{font-size:16px;font-weight:600;letter-spacing:-.01em}
.location-caret{font-size:11px;color:var(--ink-tertiary)}
.location-sub{font-size:11px;color:var(--ink-tertiary);margin-bottom:14px}

.current-row{display:flex;align-items:flex-start;justify-content:space-between;gap:12px}
.temp-block .deg-row{display:flex;align-items:flex-start}
.temp-block .deg{font-size:80px;font-weight:300;line-height:.92;letter-spacing:-.045em}
.temp-block .unit{font-size:26px;font-weight:300;line-height:1;padding-top:8px}
.raining-now{
  display:inline-flex;align-items:center;gap:6px;margin-top:8px;
  padding:5px 10px;border-radius:999px;background:rgba(44,110,168,.12);
  border:1px solid rgba(44,110,168,.28);color:var(--info);
  font-size:11.5px;font-weight:700;letter-spacing:.01em;
}
.live-dot{
  width:6px;height:6px;border-radius:50%;background:var(--info);flex:none;
  animation:livePulse 1.8s ease-in-out infinite;
}
@keyframes livePulse{0%,100%{opacity:1}50%{opacity:.25}}
@media (prefers-reduced-motion:reduce){.live-dot{animation:none}}

.temp-block .condition{font-size:14px;font-weight:600;margin-top:6px}
.temp-block .minmax{font-size:12px;color:var(--ink-secondary);margin-top:3px}

.condition-icon{width:96px;height:96px;flex:none;position:relative}
.condition-icon .sun{position:absolute;inset:14px;border-radius:50%;overflow:hidden;background:radial-gradient(circle at 34% 32%,#FFE9B0,#F2A93B 70%,#E0872A);box-shadow:0 0 34px rgba(242,169,59,.45)}
.condition-icon .cloud-a{position:absolute;left:6px;right:0;bottom:20px;height:26px;border-radius:16px;background:var(--cloud);box-shadow:0 6px 16px rgba(23,26,28,.10)}
.condition-icon .cloud-b{position:absolute;left:22px;bottom:32px;width:34px;height:34px;border-radius:50%;background:var(--cloud)}
.condition-icon.rain .sun{background:radial-gradient(circle at 34% 32%,#DCE6EE,#8FA8BC 70%,#5F7C93);box-shadow:0 0 24px rgba(95,124,147,.35)}
.condition-icon.cloud .sun{background:radial-gradient(circle at 34% 32%,#EDEFF1,#C9CFD4 70%,#9AA5AC);box-shadow:0 0 20px rgba(154,165,172,.3)}

.alert-banner{margin-top:18px;display:flex;gap:11px;align-items:flex-start;padding:13px 14px;border-radius:16px;background:#FDF1DC;border:1px solid rgba(201,119,42,.28)}
.alert-badge{width:22px;height:22px;flex:none;border-radius:7px;background:var(--warn);color:#fff;font-size:13px;font-weight:700;display:flex;align-items:center;justify-content:center}
.alert-eyebrow{font-size:12px;font-weight:700;color:#8A4F13;letter-spacing:.04em}
.alert-body{font-size:12.5px;line-height:1.45;color:#5D3A11;margin-top:3px}

.persona-scroll{display:flex;gap:8px;overflow-x:auto;padding:2px 20px 12px}
.persona-chip{
  flex:none;display:flex;align-items:center;gap:7px;padding:9px 14px;border-radius:999px;
  cursor:pointer;font-size:12.5px;font-weight:600;white-space:nowrap;user-select:none;
  transition:background .18s,color .18s,border-color .18s,transform .12s;
  background:var(--chip);color:var(--chip-ink);border:1px solid var(--chip-border);
}
.persona-chip:active{transform:scale(.96)}
.persona-chip .dot{width:6px;height:6px;border-radius:3px}
.persona-chip.active{background:var(--chip-on-bg);color:var(--chip-on-ink);border-color:var(--chip-on-bg)}

.section-body{padding:4px 20px 0}
.section-heading{display:flex;align-items:baseline;justify-content:space-between;margin-bottom:11px}
.section-heading .title{font-size:13px;font-weight:700;letter-spacing:-.01em}
.section-heading .meta{font-size:11px;color:var(--ink-secondary)}

.tile-grid{display:grid;grid-template-columns:1fr 1fr;gap:10px}
.tile{background:var(--card);border:1px solid var(--card-border);border-radius:18px;padding:13px 14px 12px;box-shadow:0 1px 2px rgba(23,26,28,.04);transition:transform .15s}
.tile .eyebrow{font-size:9.5px;font-weight:700;letter-spacing:.13em;color:var(--ink-secondary)}
.tile .value-row{display:flex;align-items:baseline;gap:4px;margin-top:7px}
.tile .value{font-size:23px;font-weight:600;letter-spacing:-.03em;line-height:1}
.tile .unit{font-size:11px;font-weight:600;color:var(--ink-tertiary)}
.tile .status-row{display:flex;align-items:center;gap:6px;margin-top:8px}
.tile .status-dot{width:7px;height:7px;border-radius:4px;flex:none}
.tile .status-text{font-size:11.5px;font-weight:600}
.tile .progress-track{margin-top:9px;height:4px;border-radius:3px;background:rgba(23,26,28,.07);overflow:hidden}
.tile .progress-fill{height:100%;border-radius:3px;transition:width .4s ease}
.tile.skeleton .value,.tile.skeleton .status-text,.tile.skeleton .eyebrow{
  background:rgba(23,26,28,.08);color:transparent;border-radius:4px;
}

.panel{margin-top:12px;background:var(--card);border:1px solid var(--card-border);border-radius:20px;padding:15px 16px 6px;box-shadow:0 1px 2px rgba(23,26,28,.04)}
.panel-header{display:flex;align-items:baseline;justify-content:space-between}
.panel-header .title{font-size:13px;font-weight:700}
.panel-header .meta{font-size:11px;color:var(--ink-secondary)}
.panel-row{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:11px 0;border-top:1px solid rgba(23,26,28,.07)}
.panel-row .label{font-size:13px;font-weight:600}
.panel-row .note{font-size:11.5px;color:var(--ink-tertiary);margin-top:2px}
.panel-row .rvalue{font-size:13.5px;font-weight:700;white-space:nowrap}

.guidance-card{margin-top:12px;display:flex;gap:11px;align-items:flex-start;padding:14px;border-radius:18px;background:#EAF0EC;border:1px solid rgba(46,125,91,.22)}
.guidance-badge{width:22px;height:22px;flex:none;border-radius:7px;background:var(--ok)}
.guidance-eyebrow{font-size:9.5px;font-weight:700;letter-spacing:.13em;color:var(--ok)}
.guidance-body{font-size:12.5px;line-height:1.5;color:#22392F;margin-top:4px}

.outlook{margin-top:14px;background:var(--card);border:1px solid var(--card-border);border-radius:20px;padding:15px 14px 14px;box-shadow:0 1px 2px rgba(23,26,28,.04)}
.outlook-header{display:flex;align-items:baseline;justify-content:space-between;padding:0 2px 12px}
.outlook-header .title{font-size:13px;font-weight:700}
.outlook-header .meta{font-size:11px;color:var(--ink-secondary)}
.outlook-grid{display:grid;grid-template-columns:repeat(7,1fr);gap:2px}
.outlook-col{display:flex;flex-direction:column;align-items:center;gap:7px}
.outlook-col .day{font-size:10.5px;font-weight:700;color:var(--ink-secondary)}
.outlook-col .dot{width:18px;height:18px;border-radius:50%}
.outlook-col .bar-track{width:6px;height:44px;border-radius:4px;background:rgba(23,26,28,.07);display:flex;align-items:flex-end;overflow:hidden}
.outlook-col .bar-fill{width:100%;border-radius:4px;background:var(--info);transition:height .4s ease}
.outlook-col .rain-label{font-size:10px;font-weight:700;color:var(--info)}
.outlook-col .hi{font-size:12px;font-weight:700}
.outlook-col .lo{font-size:11px;color:var(--ink-secondary);margin-top:-4px}

.footer-note{
  font-size:10.5px;line-height:1.6;color:var(--ink-secondary);text-align:center;
  margin:16px 20px 8px;padding:10px 14px;border-radius:14px;
  background:var(--glass);backdrop-filter:blur(6px);
  border:1px solid rgba(23,26,28,.06);
}

/* Unified SVG Bottom Navigation — fixed to the viewport so it's always
   visible, not just once you scroll far enough for a sticky element to
   catch up (that was the bug: it "appeared" only near the bottom). */
.bottom-nav{
  position:fixed;bottom:0;left:50%;transform:translateX(-50%);
  width:402px;max-width:100vw;
  background:var(--glass);backdrop-filter:blur(16px);
  border-top:1px solid var(--card-border);display:grid;grid-template-columns:repeat(4,1fr);
  padding:10px 8px max(26px, calc(10px + env(safe-area-inset-bottom, 0px)));z-index:30;
}
@media (max-width:440px){
  .bottom-nav{left:0;transform:none;width:100%}
}
.nav-item{
  /* currentColor, not a colour baked into the SVG markup: the icons then
     ride the same --ink ramp as the labels and dim with the page rather
     than flipping in one step at the halfway mark. */
  color:var(--ink-secondary);
  display:flex;flex-direction:column;align-items:center;gap:4px;
  text-decoration:none;cursor:pointer;transition:transform .12s ease;
  /* Each tab is a full page load. Without an instant pressed state the tap
     looks ignored for as long as the next page takes to arrive, and people
     tap again — which is what made the radar tab feel like it needed two or
     three presses. manipulation also drops the legacy double-tap delay. */
  touch-action:manipulation;-webkit-tap-highlight-color:transparent;
}
.nav-item:active{transform:scale(.94)}
.nav-item.active{color:var(--ink)}
.nav-item.nav-pressed .label{font-weight:700;color:var(--ink)}
.nav-item.nav-pressed .nav-svg{stroke:var(--ink)}
.dark .nav-item.nav-pressed .label{color:#fff}
.dark .nav-item.nav-pressed .nav-svg{stroke:#fff}
.nav-icon-wrap{
  position:relative;width:24px;height:24px;display:flex;align-items:center;justify-content:center;
}
.nav-svg{display:block;transition:stroke .18s ease, fill .18s ease}
.nav-badge-dot{
  position:absolute;top:0px;right:-3px;width:7px;height:7px;border-radius:50%;
  background:var(--bad);box-shadow:0 0 0 1.5px var(--page);
}
.nav-item .label{font-size:10.5px;font-weight:600;color:var(--ink-secondary);transition:color .18s ease}
.nav-item.active .label{font-weight:700;color:var(--ink)}

.dark .bottom-nav{background:rgba(12,22,34,.92);border-top-color:rgba(255,255,255,.10)}
.dark .nav-item{color:rgba(255,255,255,.68)}
.dark .nav-item.active{color:#fff}
.dark .nav-item .label{color:rgba(255,255,255,.68)}
.dark .nav-item.active .label{color:#fff}
.dark .nav-badge-dot{box-shadow:0 0 0 1.5px #0C1622}

.error-card{margin:16px 20px;background:var(--card);border:1px solid var(--card-border);border-radius:20px;padding:20px;text-align:center;font-size:13px;color:var(--ink-secondary)}

/* Search Overlay & Shortcuts */
.search-overlay{
  position:absolute;inset:0;z-index:60;background:rgba(23,26,28,.55);
  display:flex;flex-direction:column;padding:54px 16px 20px;backdrop-filter:blur(4px);
}
.search-panel{
  background:var(--panel);border-radius:24px;padding:18px 16px;max-height:80%;
  display:flex;flex-direction:column;overflow:hidden;box-shadow:0 12px 36px rgba(0,0,0,.25);
}
.search-input-row{display:flex;gap:10px;align-items:center}
.search-input{
  flex:1;border:1px solid rgba(23,26,28,.15);border-radius:14px;padding:11px 14px;
  font-size:14px;outline:none;background:rgba(23,26,28,.02);transition:border-color .15s;
}
.search-input:focus{border-color:var(--ink);background:var(--panel)}
.search-close{font-size:13px;font-weight:600;color:var(--ink-secondary);padding:6px 10px}
.search-quick-title{font-size:10px;font-weight:700;letter-spacing:.08em;color:var(--ink-secondary);margin:12px 2px 8px}
.search-chips{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:6px}
.search-chip{
  font-size:11.5px;font-weight:600;padding:6px 11px;border-radius:999px;
  background:rgba(23,26,28,.05);color:var(--ink);cursor:pointer;
  border:1px solid rgba(23,26,28,.08);transition:all .15s ease;
}
.search-chip:hover{background:var(--chip-on-bg);color:var(--chip-on-ink);border-color:var(--chip-on-bg)}
.geo-btn{
  display:flex;align-items:center;justify-content:center;gap:7px;
  width:100%;padding:10px 14px;border-radius:12px;background:#EAF0EC;
  color:var(--ok);font-size:12.5px;font-weight:600;margin-top:8px;
  border:1px solid rgba(46,125,91,.2);cursor:pointer;transition:background .15s;
}
.geo-btn:hover{background:#dbe8de}
.geo-btn:disabled{background:rgba(23,26,28,.05);color:var(--ink-tertiary);border-color:rgba(23,26,28,.1);cursor:not-allowed}
.geo-btn:disabled:hover{background:rgba(23,26,28,.05)}
.search-results{margin-top:8px;overflow-y:auto}
.search-result{padding:10px 8px;border-top:1px solid rgba(23,26,28,.07);cursor:pointer;font-size:13px;border-radius:8px}
.search-result:hover{background:rgba(23,26,28,.04)}
.search-result:first-child{border-top:none}
.search-result .name{font-weight:600}
.search-result .region{font-size:11px;color:var(--ink-tertiary)}
.search-empty{font-size:12.5px;color:var(--ink-tertiary);padding:10px 6px;text-align:center}
.sample-tag{font-size:9px;font-weight:700;letter-spacing:.05em;color:rgba(23,26,28,.4);margin-left:4px}

/* Alerts screen */
.alerts-list{display:flex;flex-direction:column;gap:10px}
.alert-card{border-radius:18px;padding:14px;border:1px solid;display:flex;flex-direction:column;gap:6px}
.alert-card.tone-bad{background:#FCEAE5;border-color:rgba(194,69,45,.3)}
.alert-card.tone-warn{background:#FDF1DC;border-color:rgba(201,119,42,.28)}
.alert-card.tone-info{background:#EAF1F7;border-color:rgba(44,110,168,.25)}
.alert-card-top{display:flex;align-items:center;justify-content:space-between;gap:8px}
.alert-card-badge{font-size:10.5px;font-weight:700;letter-spacing:.05em}
.tone-bad .alert-card-badge{color:#8A2A18}
.tone-warn .alert-card-badge{color:#8A4F13}
.tone-info .alert-card-badge{color:#1A4E78}
.alert-card-time{font-size:10.5px;color:var(--ink-tertiary);white-space:nowrap}
.alert-card-title{font-size:14px;font-weight:700;color:var(--ink)}
.alert-card-body{font-size:12.5px;line-height:1.45}
.tone-bad .alert-card-body{color:#6B241A}
.tone-warn .alert-card-body{color:#5D3A11}
.tone-info .alert-card-body{color:#173C5C}
.no-alerts-card{margin-top:4px;background:var(--card);border:1px solid var(--card-border);border-radius:20px;padding:28px 20px;text-align:center}
.no-alerts-badge{width:40px;height:40px;border-radius:20px;background:#EAF0EC;color:var(--ok);font-size:20px;font-weight:700;display:flex;align-items:center;justify-content:center;margin:0 auto 12px}
.no-alerts-title{font-size:14px;font-weight:700;color:var(--ink)}
.no-alerts-sub{font-size:12px;color:var(--ink-secondary);margin-top:4px}

/* Saved screen */
.saved-list{display:flex;flex-direction:column;gap:10px}
.saved-card{background:var(--card);border:1px solid var(--card-border);border-radius:18px;padding:13px 14px;display:flex;align-items:center;gap:12px;box-shadow:0 1px 2px rgba(23,26,28,.04);cursor:pointer;transition:transform .12s}
.saved-card:active{transform:scale(.98)}
.saved-card-main{flex:1;min-width:0}
.saved-card-name{font-size:13.5px;font-weight:700;color:var(--ink)}
.saved-card-note{font-size:11.5px;color:var(--ink-tertiary);margin-top:2px}
.saved-card-temp{font-size:18px;font-weight:600;white-space:nowrap}
.saved-remove{width:26px;height:26px;border-radius:13px;background:rgba(23,26,28,.06);color:var(--ink-secondary);font-size:13px;display:flex;align-items:center;justify-content:center;flex:none;transition:background .15s}
.saved-remove:hover{background:rgba(23,26,28,.14)}
.add-city-card{border:1px dashed rgba(23,26,28,.2);border-radius:18px;padding:14px;text-align:center;font-size:12.5px;font-weight:600;color:var(--ink-secondary);cursor:pointer;transition:all .15s}
.add-city-card:hover{background:rgba(23,26,28,.04);color:var(--ink)}
.current-city-tag{font-size:9px;font-weight:700;letter-spacing:.04em;color:var(--ok);background:rgba(46,125,91,.12);border-radius:999px;padding:2px 7px;margin-left:6px}

/* Sky Events — night-sky palette on purpose: the rest of the app is a
   daylight off-white, so an astronomical event reads instantly as a
   different kind of thing rather than another weather card. Each event
   type sets --astro-accent inline and gets its own piece of animated art;
   all of it is CSS on empty spans, so there is no image to download and
   nothing running on the main thread per frame. */
.astro-strip{
  position:relative;overflow:hidden;
  display:flex;align-items:center;gap:11px;width:100%;margin-top:10px;
  padding:12px 14px;border-radius:16px;text-align:left;
  background:linear-gradient(105deg,#16233A,#0E1626 60%,#1A2440);
  border:1px solid rgba(255,255,255,.13);color:#EAF0FA;
  box-shadow:0 6px 18px rgba(12,22,34,.22);transition:transform .14s ease;
}
.astro-strip:active{transform:scale(.985)}
/* Same art as the modal hero, shrunk: the strip is the only place most
   people will ever see a sky event, so it gets the real thing rather than
   a flat icon. Sizes are overridden here; everything else is shared. */
.astro-thumb{
  position:relative;display:block;flex:none;width:46px;height:46px;
  border-radius:14px;overflow:hidden;
  background:radial-gradient(95% 130% at 50% 0%,#26385C,#0A111C 82%);
  border:1px solid rgba(255,255,255,.12);
}
.astro-thumb .ah-moon{width:30px;height:30px;margin:-15px 0 0 -15px;box-shadow:0 0 11px 2px rgba(235,217,166,.32)}
.astro-thumb .ah-moon.glow{animation-name:ahGlowSm}
@keyframes ahGlowSm{
  0%,100%{box-shadow:0 0 9px 1px rgba(235,217,166,.24)}
  50%{box-shadow:0 0 16px 4px rgba(235,217,166,.5)}
}
.astro-thumb .ah-sun,.astro-thumb .ah-occluder{width:26px;height:26px;margin:-13px 0 0 -13px}
.astro-thumb .ah-sun{animation-name:ahSunGlowSm}
@keyframes ahSunGlowSm{
  0%,100%{box-shadow:0 0 10px 2px rgba(242,197,116,.34)}
  50%{box-shadow:0 0 18px 5px rgba(242,197,116,.55)}
}
.astro-thumb .ah-occluder{background:#0A111C}
.astro-thumb .ah-meteor{--ah-travel:70px;height:20px;width:1.6px;animation-duration:3.4s}
.astro-thumb .ah-meteor::after{width:3px;height:3px;margin-left:-1.5px;box-shadow:0 0 4px 1px rgba(255,255,255,.75)}
.astro-strip-text{position:relative;flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}
.astro-strip-eyebrow{font-size:9.5px;font-weight:700;letter-spacing:.12em;text-transform:uppercase;color:rgba(234,240,250,.55)}
.astro-strip-name{font-size:13px;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
/* The plain rgba lines are the fallback for browsers without color-mix
   (pre-16.2 Safari) — without them the badge would lose its background
   entirely rather than just its per-event tint. */
.astro-strip-when{
  position:relative;flex:none;font-size:10.5px;font-weight:700;padding:5px 9px;border-radius:999px;
  background:rgba(157,196,240,.16);
  background:color-mix(in srgb,var(--astro-accent,#9DC4F0) 16%,transparent);
  color:var(--astro-accent,#9DC4F0);
  border:1px solid rgba(157,196,240,.26);
  border-color:color-mix(in srgb,var(--astro-accent,#9DC4F0) 26%,transparent);
}

/* Fixed, not absolute like the search overlay: .app-shell grows to the
   full height of the scrolling page, so an absolutely-positioned overlay
   centres its card against the whole document rather than the screen —
   and the sky strip that opens this sits well down the page, so the card
   would have landed off the bottom of the view. */
.astro-overlay{
  position:fixed;inset:0;z-index:90;background:rgba(8,13,22,.66);
  display:flex;align-items:center;justify-content:center;padding:24px 16px;
  backdrop-filter:blur(6px);
}
.astro-card{
  position:relative;width:100%;max-width:390px;max-height:100%;overflow:hidden;border-radius:26px;
  display:flex;flex-direction:column;
  background:radial-gradient(130% 100% at 50% 0%,#1D2B47,#0C1420 72%);
  border:1px solid rgba(255,255,255,.14);color:#EEF3FB;
  box-shadow:0 26px 60px rgba(0,0,0,.5);animation:astroRise .26s cubic-bezier(.2,.8,.3,1);
}
@keyframes astroRise{from{transform:translateY(14px) scale(.97)}to{transform:none}}
/* Scrolls; the actions below it do not. A long card (the eclipses run to
   three full paragraphs) otherwise pushed "Got it" past the fold, leaving
   a modal whose dismiss button you had to go looking for.
   background-attachment:local anchors the scrim to the content, so the
   clear window at the top (where the moon/sun sits) scrolls away with it
   and text is never left sitting on bare artwork. */
.astro-card-inner{
  position:relative;z-index:1;flex:1;min-height:0;padding:118px 20px 6px;overflow-y:auto;
  /* Deliberately stops well short of opaque: the starfield and meteors are
     meant to keep moving behind the text, not be buried under it. Contrast
     is bought back with a text-shadow instead of more ink. */
  background:linear-gradient(180deg,
    rgba(11,18,29,0) 0,
    rgba(11,18,29,.22) 88px,
    rgba(11,18,29,.6) 150px,
    rgba(11,18,29,.68) 100%);
  background-attachment:local;
  text-shadow:0 1px 3px rgba(6,11,19,.55);
}

/* Full-card animated background: the art runs behind the whole modal, not
   just a band at the top. The readability scrim lives on the scrolling
   content instead (see .astro-card-inner) so it travels with the text
   rather than staying pinned — otherwise scrolled text would ride over
   the bright moon with nothing behind it. */
.astro-bg{
  position:absolute;inset:0;display:block;overflow:hidden;pointer-events:none;
  background:radial-gradient(95% 58% at 50% 0%,#25375C,#0B121D 76%);
}
.astro-bg .ah-moon{top:62px;width:78px;height:78px;margin:-39px 0 0 -39px}
.astro-bg .ah-sun,.astro-bg .ah-occluder{top:60px;width:70px;height:70px;margin:-35px 0 0 -35px}
.astro-bg .ah-meteor{--ah-travel:900px;height:96px}
.ah-star{
  position:absolute;width:2px;height:2px;border-radius:50%;background:#fff;
  animation:ahTwinkle 3.4s ease-in-out infinite;
}
@keyframes ahTwinkle{0%,100%{opacity:.2}50%{opacity:.95}}
.ah-meteor{
  --ah-travel:190px;
  position:absolute;top:0;width:2.5px;height:66px;border-radius:2px;
  /* Trail fades in from nothing and burns white at the leading end, with a
     glowing head on ::after — a flat 2px line was technically animating but
     nobody could actually see it against the starfield. */
  background:linear-gradient(to bottom,transparent,var(--astro-accent,#9DC4F0) 55%,#fff);
  filter:drop-shadow(0 0 4px rgba(255,255,255,.45));
  opacity:0;animation:ahFall 4.2s linear infinite;
}
.ah-meteor::after{
  content:'';position:absolute;left:50%;bottom:-2px;
  width:5px;height:5px;margin-left:-2.5px;border-radius:50%;background:#fff;
  box-shadow:0 0 7px 2px rgba(255,255,255,.8);
}
@keyframes ahFall{
  0%{opacity:0;transform:rotate(32deg) translate3d(0,-80px,0)}
  10%{opacity:1}
  82%{opacity:1}
  100%{opacity:0;transform:rotate(32deg) translate3d(0,var(--ah-travel),0)}
}
.ah-moon{
  position:absolute;left:50%;top:50%;width:92px;height:92px;margin:-46px 0 0 -46px;
  border-radius:50%;overflow:hidden;
  background:radial-gradient(circle at 34% 28%,#FFF9EC,#F0E2C2 52%,#BFAE87);
  box-shadow:0 0 34px 6px rgba(235,217,166,.28);
}
.ah-moon.glow{animation:ahGlow 5.5s ease-in-out infinite}
@keyframes ahGlow{
  0%,100%{box-shadow:0 0 28px 4px rgba(235,217,166,.24)}
  50%{box-shadow:0 0 46px 12px rgba(235,217,166,.46)}
}
.ah-crater{position:absolute;border-radius:50%;background:rgba(120,104,74,.28)}
.ah-umbra{
  position:absolute;inset:-2px;border-radius:50%;
  background:radial-gradient(circle at 32% 46%,rgba(146,54,38,.9),rgba(48,17,15,.96));
  animation:ahUmbra 9s ease-in-out infinite;
}
@keyframes ahUmbra{
  0%{transform:translateX(-110%)}
  42%,58%{transform:translateX(-8%)}
  100%{transform:translateX(110%)}
}
.ah-sun{
  position:absolute;left:50%;top:50%;width:80px;height:80px;margin:-40px 0 0 -40px;
  border-radius:50%;background:radial-gradient(circle,#FFF6DC,#F6C86E 58%,#E29B37);
  animation:ahSunGlow 4.5s ease-in-out infinite;
}
@keyframes ahSunGlow{
  0%,100%{box-shadow:0 0 34px 8px rgba(242,197,116,.34)}
  50%{box-shadow:0 0 54px 16px rgba(242,197,116,.55)}
}
.ah-occluder{
  position:absolute;left:50%;top:50%;width:80px;height:80px;margin:-40px 0 0 -40px;
  border-radius:50%;background:#0B121D;animation:ahOcclude 9s ease-in-out infinite;
}
@keyframes ahOcclude{
  0%{transform:translate(-118%,-16%)}
  44%,60%{transform:translate(-46%,-8%)}
  100%{transform:translate(118%,-16%)}
}

.astro-head{display:flex;align-items:center;gap:9px;margin-top:4px}
.astro-glyph{width:26px;height:26px;flex:none;color:var(--astro-accent,#9DC4F0)}
.astro-glyph svg{width:100%;height:100%;display:block}
.astro-eyebrow{flex:1;font-size:9.5px;font-weight:700;letter-spacing:.14em;text-transform:uppercase;color:rgba(238,243,251,.6)}
.astro-countdown{
  font-size:10.5px;font-weight:700;padding:5px 10px;border-radius:999px;
  background:rgba(157,196,240,.18);
  background:color-mix(in srgb,var(--astro-accent,#9DC4F0) 18%,transparent);
  color:var(--astro-accent,#9DC4F0);
  border:1px solid rgba(157,196,240,.28);
  border-color:color-mix(in srgb,var(--astro-accent,#9DC4F0) 28%,transparent);
}
.astro-title{margin:13px 0 0;font-size:21px;line-height:1.25;font-weight:700}
.astro-sub{margin:6px 0 0;font-size:12.5px;line-height:1.5;color:rgba(238,243,251,.72)}
.astro-meta{
  margin-top:14px;padding:12px 13px;border-radius:15px;
  background:rgba(255,255,255,.055);border:1px solid rgba(255,255,255,.1);
  display:flex;flex-direction:column;gap:8px;
}
.astro-meta-row{display:flex;align-items:flex-start;gap:9px;font-size:12px;line-height:1.45;color:rgba(238,243,251,.88)}
.astro-meta-dot{width:5px;height:5px;flex:none;margin-top:6px;border-radius:50%;background:var(--astro-accent,#9DC4F0)}
.astro-facts-title{margin-top:16px;font-size:9.5px;font-weight:700;letter-spacing:.14em;text-transform:uppercase;color:rgba(238,243,251,.55)}
.astro-facts{margin:9px 0 0;padding:0;list-style:none;display:flex;flex-direction:column;gap:10px}
.astro-facts li{position:relative;padding-left:15px;font-size:12.5px;line-height:1.55;color:rgba(238,243,251,.86)}
.astro-facts li::before{
  content:'';position:absolute;left:0;top:7px;width:5px;height:5px;
  border-radius:50%;background:var(--astro-accent,#9DC4F0);opacity:.8;
}
.astro-actions{
  position:relative;z-index:1;
  flex:none;display:flex;align-items:center;gap:10px;
  padding:13px 20px 16px;border-top:1px solid rgba(255,255,255,.09);
  background:rgba(9,15,25,.82);
}
.astro-link{
  flex:1;text-align:center;padding:11px;border-radius:13px;font-size:12.5px;font-weight:600;
  background:rgba(255,255,255,.07);border:1px solid rgba(255,255,255,.16);color:var(--astro-accent,#9DC4F0);
}
.astro-link:hover{background:rgba(255,255,255,.12)}
.astro-ok{flex:1;padding:11px;border-radius:13px;font-size:12.5px;font-weight:700;background:#EEF3FB;color:#0C1420}

@media (prefers-reduced-motion:reduce){
  .ah-star,.ah-meteor,.ah-moon.glow,.ah-umbra,.ah-sun,.ah-occluder,
  .astro-overlay,.astro-card{animation:none}
  .ah-meteor{opacity:.85}
  .ah-umbra{transform:translateX(-8%)}
  .ah-occluder{transform:translate(-46%,-8%)}
}

/* Assistant — a light surface deliberately unlike the Sky Events night
   card, so the two never read as the same kind of thing. */
.ask-fab{
  position:fixed;right:16px;bottom:88px;z-index:55;
  width:52px;height:52px;border-radius:26px;
  display:flex;align-items:center;justify-content:center;
  background:#171A1C;color:#F5F4EF;
  box-shadow:0 8px 22px rgba(23,26,28,.32);transition:transform .14s ease;
}
.ask-fab:active{transform:scale(.93)}
.ask-fab svg{width:23px;height:23px}
.ask-fab-dot{
  position:absolute;top:9px;right:10px;width:9px;height:9px;border-radius:50%;
  background:var(--bad);border:2px solid #171A1C;
}
@media (max-width:440px){ .ask-fab{bottom:92px} }

.ask-overlay{
  position:fixed;inset:0;z-index:85;background:rgba(23,26,28,.5);
  display:flex;align-items:flex-end;justify-content:center;
  backdrop-filter:blur(4px);
}
/* An author `display` beats the browser's own [hidden]{display:none}, so
   without this the panel stayed on screen no matter what closed it. */
.ask-overlay[hidden]{display:none}
.ask-panel{
  width:100%;max-width:420px;max-height:88vh;display:flex;flex-direction:column;
  background:var(--page);border-radius:24px 24px 0 0;
  box-shadow:0 -14px 40px rgba(0,0,0,.28);
  animation:askUp .24s cubic-bezier(.2,.8,.3,1);
}
@keyframes askUp{from{transform:translateY(24px)}to{transform:none}}
.ask-head{
  flex:none;display:flex;align-items:flex-start;justify-content:space-between;gap:12px;
  padding:16px 18px 12px;border-bottom:1px solid var(--card-border);
}
.ask-title{font-size:15px;font-weight:700}
.ask-sub{font-size:11px;color:var(--ink-tertiary);margin-top:2px}
.ask-close{font-size:22px;line-height:1;color:var(--ink-secondary);padding:0 4px}

.ask-log{flex:1;min-height:120px;overflow-y:auto;padding:14px 16px;display:flex;flex-direction:column;gap:10px}
.ask-msg{border-radius:16px;font-size:12.5px;line-height:1.5}
.ask-msg.user{
  align-self:flex-end;max-width:85%;padding:9px 13px;
  background:#171A1C;color:#F5F4EF;border-bottom-right-radius:6px;
}
.ask-msg.bot{
  align-self:flex-start;width:100%;padding:13px 14px;
  background:var(--card);border:1px solid var(--card-border);border-bottom-left-radius:6px;
}
.ask-pending{color:var(--ink-tertiary);font-style:italic}
.ask-ans{font-size:13.5px;font-weight:600;line-height:1.45;margin-bottom:10px}
/* Labels sit above their values rather than beside them: "RECOMMENDATION"
   in English, and the Tamil and Bengali section names, all overflow any
   fixed label column that still leaves room for the value. */
.ask-row{display:flex;flex-direction:column;gap:3px;padding:8px 0;border-top:1px solid rgba(23,26,28,.06)}
.ask-k{
  font-size:8.5px;font-weight:700;letter-spacing:.1em;color:var(--ink-tertiary);
}
.ask-v{flex:1;min-width:0;font-size:12px;line-height:1.5;color:var(--ink-secondary)}
.ask-lvl{
  align-self:flex-start;font-size:10.5px;font-weight:700;padding:3px 9px;border-radius:999px;
}
.ask-lvl-good{background:rgba(46,125,91,.13);color:var(--ok)}
.ask-lvl-caution{background:rgba(201,119,42,.14);color:var(--warn)}
.ask-lvl-avoid{background:rgba(194,69,45,.13);color:var(--bad)}
.ask-alert{
  display:flex;flex-direction:column;gap:3px;margin-top:10px;padding:9px 11px;border-radius:12px;
  background:rgba(194,69,45,.08);border:1px solid rgba(194,69,45,.2);
}
.ask-alert .ask-k{color:var(--bad)}
.ask-alert .ask-v{color:var(--bad)}
.ask-proactive{
  margin-top:8px;padding:9px 11px;border-radius:12px;font-size:12px;line-height:1.45;
  background:rgba(44,110,168,.08);border:1px solid rgba(44,110,168,.18);color:#245A88;
}
.ask-proactive.urgent{background:rgba(201,119,42,.1);border-color:rgba(201,119,42,.24);color:#8A5015}
.ask-alts{display:flex;flex-direction:column;gap:8px;margin-top:10px}
.ask-alt{padding:10px 12px;border-radius:13px;background:rgba(23,26,28,.035);border:1px solid var(--card-border)}
.ask-alt-top{display:flex;align-items:center;justify-content:space-between;gap:8px}
.ask-alt-name{font-size:12.5px;font-weight:600}
.ask-alt-meta{font-size:11px;color:var(--ink-tertiary);margin-top:3px}
.ask-alt-why{font-size:11px;color:var(--warn);margin-top:3px}
.ask-noalt{margin-top:10px}

.ask-chips{flex:none;display:flex;gap:6px;overflow-x:auto;padding:0 16px 10px}
.ask-chip{
  flex:none;font-size:11.5px;font-weight:600;padding:7px 12px;border-radius:999px;
  background:rgba(23,26,28,.05);border:1px solid rgba(23,26,28,.08);color:var(--ink);
}
.ask-chip:hover{background:#171A1C;color:#fff;border-color:#171A1C}
.ask-form{flex:none;display:flex;gap:8px;padding:0 16px}
.ask-input{
  flex:1;min-width:0;border:1px solid rgba(23,26,28,.15);border-radius:14px;padding:11px 14px;
  font-size:14px;outline:none;background:#fff;
}
.ask-input:focus{border-color:#171A1C}
.ask-send{
  flex:none;padding:0 17px;border-radius:14px;background:var(--chip-on-bg);color:var(--chip-on-ink);
  font-size:12.5px;font-weight:700;
}
.ask-disclaimer{
  flex:none;padding:10px 16px 16px;font-size:9.5px;line-height:1.45;color:var(--ink-tertiary);
}
.ask-mic{
  flex:none;width:44px;height:44px;border-radius:14px;
  display:flex;align-items:center;justify-content:center;
  background:rgba(23,26,28,.05);border:1px solid rgba(23,26,28,.12);color:var(--ink);
  transition:background .15s, color .15s;touch-action:manipulation;
}
.ask-mic svg{width:19px;height:19px}
.ask-mic:active{transform:scale(.94)}
.ask-mic.listening{
  background:var(--bad);border-color:var(--bad);color:#fff;
  animation:askMicPulse 1.4s ease-in-out infinite;
}
@keyframes askMicPulse{
  0%,100%{box-shadow:0 0 0 0 rgba(194,69,45,.42)}
  50%{box-shadow:0 0 0 8px rgba(194,69,45,0)}
}
.ask-mic-status{
  flex:none;padding:6px 16px 0;font-size:11px;line-height:1.4;color:var(--ink-tertiary);
}
.ask-mic-status:empty{padding:0}
@media (prefers-reduced-motion:reduce){ .ask-mic.listening{animation:none} }
.ask-hint{
  margin-top:9px;padding:8px 10px;border-radius:11px;font-size:11px;line-height:1.45;
  background:rgba(23,26,28,.04);border:1px solid var(--card-border);color:var(--ink-tertiary);
}

/* Meteor spawned where the reader taps the card. */
.ah-spark{
  position:absolute;width:2px;height:58px;border-radius:2px;pointer-events:none;
  background:linear-gradient(to bottom,transparent,#fff);
  opacity:0;animation:ahSpark 1s ease-out forwards;
}
@keyframes ahSpark{
  0%{opacity:0;transform:rotate(32deg) translate3d(0,-26px,0) scaleY(.35)}
  18%{opacity:1}
  100%{opacity:0;transform:rotate(32deg) translate3d(0,210px,0) scaleY(1)}
}
.astro-bg{transition:transform .12s linear}
@media (prefers-reduced-motion:reduce){ .ah-spark{display:none} .astro-bg{transition:none} }
.astro-hist-next{
  margin-top:16px;padding:10px 12px;border-radius:13px;font-size:11.5px;line-height:1.45;
  background:rgba(255,255,255,.06);border:1px solid rgba(255,255,255,.12);
  color:rgba(238,243,251,.78);
}
.retry-btn{
  margin-top:12px;padding:9px 20px;border-radius:12px;
  background:var(--chip-on-bg);color:var(--chip-on-ink);font-size:12.5px;font-weight:600;
}
.location-sub.stale{color:var(--warn);font-weight:600}
.ask-speak{
  display:flex;align-items:center;justify-content:center;
  width:32px;height:32px;margin-top:10px;border-radius:10px;
  background:rgba(23,26,28,.05);border:1px solid rgba(23,26,28,.1);color:var(--ink-secondary);
  transition:background .15s, color .15s;touch-action:manipulation;
}
.ask-speak svg{width:16px;height:16px}
.ask-speak:active{transform:scale(.93)}
.ask-speak.on{background:var(--info);border-color:var(--info);color:#fff}
.ask-city-note{
  margin-bottom:8px;padding:6px 9px;border-radius:9px;font-size:11px;line-height:1.4;
  background:rgba(44,110,168,.09);border:1px solid rgba(44,110,168,.18);color:#245A88;
}

/* Alert cards keep their warning colour in both themes — a red or amber
   card is the signal. But --ink flips to near-white in dark, which on those
   pale backgrounds left the title and body invisible. Pin the text on these
   surfaces to the dark ink regardless of theme. */
[data-theme="dark"] .alert-card,
[data-theme="dark"] .alert-banner{color:#171A1C}
[data-theme="dark"] .alert-card .alert-card-title,
[data-theme="dark"] .alert-card .alert-card-body,
[data-theme="dark"] .alert-banner .alert-eyebrow,
[data-theme="dark"] .alert-banner .alert-body{color:#171A1C}
[data-theme="dark"] .alert-card-meta{color:rgba(23,26,28,.66)}

/* Faint dark-ink fills (tracks, chips, hover states) disappear against a
   dark surface. One override lifts them all to a faint light fill instead
   of rewriting each rule for both themes. */
[data-theme="dark"]{
  --fill-1:rgba(255,255,255,.06);
  --fill-2:rgba(255,255,255,.1);
  --fill-3:rgba(255,255,255,.16);
}
[data-theme="dark"] .tile .progress-track,
[data-theme="dark"] .outlook-col .bar-track,
[data-theme="dark"] .search-input,
[data-theme="dark"] .status-imd-pill{background:var(--fill-1)}
[data-theme="dark"] .search-chip,
[data-theme="dark"] .ask-chip,
[data-theme="dark"] .ask-speak,
[data-theme="dark"] .ask-mic,
[data-theme="dark"] .saved-remove,
[data-theme="dark"] .ask-alt,
[data-theme="dark"] .ask-hint,
[data-theme="dark"] .geo-btn:disabled{background:var(--fill-2);border-color:var(--fill-3)}
[data-theme="dark"] .search-result:hover,
[data-theme="dark"] .add-city-card:hover,
[data-theme="dark"] .saved-remove:hover,
[data-theme="dark"] .ask-mic:hover{background:var(--fill-3)}
[data-theme="dark"] .tile.skeleton .eyebrow,
[data-theme="dark"] .tile.skeleton .value,
[data-theme="dark"] .tile.skeleton .status-text{background:var(--fill-2)}
[data-theme="dark"] .ask-msg.user{background:var(--chip-on-bg);color:var(--chip-on-ink)}
[data-theme="dark"] .ask-proactive,
[data-theme="dark"] .ask-city-note{
  background:rgba(127,178,229,.14);border-color:rgba(127,178,229,.28);color:#AFCEEC;
}
[data-theme="dark"] .ask-proactive.urgent{
  background:rgba(232,164,92,.15);border-color:rgba(232,164,92,.3);color:#F0C48A;
}

/* At night the disc is a moon, not a dimmed sun. Showing a blazing sun at
   2 AM is wrong however tastefully it is coloured, and every weather app
   people already use switches the glyph rather than just its brightness.
   The shaded limb and craters are pseudo-elements layered over the disc —
   translucent, not punched out, since this sits over the hero photo and a
   solid "bite" would show the wrong colour through it. */
[data-theme="dark"] .condition-icon .sun{
  background:radial-gradient(circle at 42% 38%,#FFFFFF,#F2F6FC 46%,#D3DDEB 78%,#B9C6D8);
  box-shadow:0 0 26px rgba(206,224,248,.35), 0 0 60px rgba(150,180,220,.18);
}
/* Craters, not a terminator. A shaded limb needs a light direction to be
   believable and at this size it just read as a donut; three soft dents on
   a full disc say "moon" immediately. */
[data-theme="dark"] .condition-icon .sun::before{
  content:'';position:absolute;left:24%;top:26%;width:15px;height:15px;border-radius:50%;
  background:rgba(126,146,176,.28);
  box-shadow:20px 18px 0 -3px rgba(126,146,176,.24),
             -1px 30px 0 -5px rgba(126,146,176,.2),
             30px -2px 0 -7px rgba(126,146,176,.18);
}
[data-theme="dark"] .condition-icon.rain .sun,
[data-theme="dark"] .condition-icon.cloud .sun{
  background:radial-gradient(circle at 34% 32%,#C8D4E2,#8E9DB0 70%,#65748A);
  box-shadow:0 0 20px rgba(142,157,176,.28);
}
[data-theme="dark"] .condition-icon.rain .sun::before,
[data-theme="dark"] .condition-icon.cloud .sun::before{display:none}

/* Safe areas. viewport-fit=cover lets the hero photo run edge to edge —
   which is the point — but every piece of *text* and every tap target has
   to sit inside the insets or it ends up under the clock or the home
   indicator. env() resolves to 0 on hardware without them. */
.content-sheet{padding-bottom:calc(148px + env(safe-area-inset-bottom, 0px))}
.ask-fab{bottom:max(88px, calc(76px + env(safe-area-inset-bottom, 0px)))}
@media (max-width:440px){ .ask-fab{bottom:max(92px, calc(80px + env(safe-area-inset-bottom, 0px)))} }
.search-overlay{padding-top:calc(54px + env(safe-area-inset-top, 0px))}
.ask-overlay{padding-bottom:env(safe-area-inset-bottom, 0px)}
.astro-overlay{
  padding-top:calc(24px + env(safe-area-inset-top, 0px));
  padding-bottom:calc(24px + env(safe-area-inset-bottom, 0px));
}
.ask-panel{padding-bottom:env(safe-area-inset-bottom, 0px)}
/* Landscape notches eat into the sides too. */
@media (max-width:440px){
  .header-block{
    padding-left:calc(20px + env(safe-area-inset-left, 0px));
    padding-right:calc(20px + env(safe-area-inset-right, 0px));
  }
  .bottom-nav{
    padding-left:calc(8px + env(safe-area-inset-left, 0px));
    padding-right:calc(8px + env(safe-area-inset-right, 0px));
  }
}

/* A dark wash exactly as tall as the status bar inset. iOS draws the clock
   and battery in white over the page in black-translucent mode, so they need
   something behind them regardless of theme or of what the hero photo
   happens to be showing at the top. Zero height on hardware with no inset,
   so nothing appears on desktop or Android. */
.status-scrim{
  position:fixed;top:0;left:0;right:0;z-index:50;pointer-events:none;
  height:env(safe-area-inset-top, 0px);
  background:linear-gradient(180deg,rgba(8,13,20,.55),rgba(8,13,20,.12));
}


/* ---------- moon phase ----------
   The strip sits with the sky-event strip on the home screen after dark;
   the card is the fuller version inside the astronomy sheet. One drawing,
   two sizes — moon.js builds the SVG from the same numbers for both. */
.moon-strip{
  display:flex;align-items:center;gap:12px;width:100%;margin-top:10px;
  padding:11px 14px;border-radius:18px;text-align:left;
  background:var(--card);border:1px solid var(--card-border);
  color:var(--ink);transition:transform .12s ease, background .2s ease;
  touch-action:manipulation;-webkit-tap-highlight-color:transparent;
}
.moon-strip:active{transform:scale(.985)}
.moon-strip-text{display:flex;flex-direction:column;gap:2px;flex:1;min-width:0}
.moon-strip-eyebrow{
  font-size:9px;font-weight:700;letter-spacing:.14em;color:var(--ink-tertiary);
}
.moon-strip-name{font-size:13.5px;font-weight:600;color:var(--ink)}
.moon-strip-illum{font-size:11.5px;font-weight:600;color:var(--ink-secondary);flex:none}

.moon-card{
  display:flex;gap:16px;align-items:flex-start;margin-top:18px;padding:15px 16px;
  border-radius:18px;background:rgba(255,255,255,.06);border:1px solid rgba(255,255,255,.12);
}
.moon-card-art{flex:none;line-height:0}
.moon-card-body{flex:1;min-width:0}
.moon-card-eyebrow{
  font-size:9px;font-weight:700;letter-spacing:.14em;color:rgba(255,255,255,.6);
}
.moon-card-name{font-size:17px;font-weight:700;color:#fff;margin-top:4px;letter-spacing:-.01em}
.moon-card-meta{font-size:12px;color:rgba(255,255,255,.68);margin-top:3px;line-height:1.45}
.moon-next{margin-top:11px;display:flex;flex-direction:column;gap:6px}
.moon-next-row{display:flex;justify-content:space-between;gap:10px;font-size:11.5px}
.moon-next-label{color:rgba(255,255,255,.6);font-weight:600}
.moon-next-when{color:#fff;font-weight:600;text-align:right}

/* The disc reads against the astronomy sheet's deep sky, but on the home
   strip it sits on a card — so the unlit half needs to be visible there
   rather than dissolving into the background. */
.moon-strip .moon-disc{--moon-shadow:rgba(120,138,168,.30);--moon-rim:var(--card-border)}
.moon-card .moon-disc{--moon-shadow:rgba(255,255,255,.10);--moon-rim:rgba(255,255,255,.18)}
.moon-disc{display:block}

/* Below about 380px the two next-moon rows stop fitting side by side. */
@media (max-width:379px){
  .moon-next-row{flex-direction:column;gap:1px}
  .moon-next-when{text-align:left}
}

/* Desktop shows the app in a phone frame, so nothing here needs to widen —
   but the astronomy sheet does get roomier, and the card can breathe. */
@media (min-width:441px){
  .moon-card{gap:20px;padding:17px 18px}
}


/* ---------- what this number means ----------
   An ⓘ in the corner of every tile that has an explainer. Deliberately
   quiet — it is there when you go looking and invisible when you are not —
   but sized to a real 28px touch target, with the visible disc smaller than
   the tappable area rather than the other way round. */
.tile{position:relative}
.tile-info{
  position:absolute;top:4px;right:4px;width:28px;height:28px;
  display:flex;align-items:center;justify-content:center;
  font-size:10.5px;font-weight:700;font-style:italic;line-height:1;
  color:var(--ink-tertiary);border-radius:50%;
  touch-action:manipulation;-webkit-tap-highlight-color:transparent;
  transition:color .15s ease, background .15s ease;
}
.tile-info::before{
  content:'';position:absolute;width:17px;height:17px;border-radius:50%;
  border:1.2px solid var(--card-border);
}
.tile-info:hover{color:var(--ink)}
.tile-info:hover::before{border-color:var(--ink-tertiary)}
.tile-info:active{transform:scale(.9)}

.explain-overlay{
  position:fixed;inset:0;z-index:70;display:flex;align-items:flex-end;justify-content:center;
  background:rgba(12,18,28,.5);backdrop-filter:blur(3px);
  padding:0 0 max(0px, env(safe-area-inset-bottom, 0px));
}
.explain-card{
  width:402px;max-width:100vw;max-height:86vh;overflow-y:auto;
  background:var(--panel);color:var(--ink);
  border-radius:26px 26px 0 0;padding:20px 20px 22px;
  /* Transform-only, no opacity keyframe: an entrance animation that starts
     at opacity 0 leaves the sheet invisible whenever animations are paused
     or the keyframe never runs. That has bitten this app twice. */
  animation:explainUp .24s cubic-bezier(.22,.9,.3,1);
}
@keyframes explainUp{from{transform:translateY(14px)}to{transform:translateY(0)}}
@media (prefers-reduced-motion:reduce){ .explain-card{animation:none} }

.explain-head{display:flex;align-items:flex-start;justify-content:space-between;gap:14px}
.explain-eyebrow{font-size:9px;font-weight:700;letter-spacing:.14em;color:var(--ink-tertiary)}
.explain-title{font-size:19px;font-weight:700;letter-spacing:-.015em;margin:5px 0 0}
.explain-now{display:flex;align-items:baseline;gap:3px;flex:none}
.explain-now-value{font-size:26px;font-weight:600;letter-spacing:-.02em}
.explain-now-unit{font-size:11px;font-weight:600}

/* Says where the number came from. The simulated case is the one that
   matters: this app carries the IMD's name, and a made-up figure has to
   admit it on the same screen that shows it, not only in a README. */
.explain-source{
  margin-top:13px;padding:7px 11px;border-radius:10px;
  font-size:11px;font-weight:600;line-height:1.4;
}
.explain-source.src-live{background:rgba(46,125,91,.12);color:var(--ok)}
.explain-source.src-derived{background:rgba(44,110,168,.12);color:var(--info)}
.explain-source.src-simulated{background:rgba(201,119,42,.14);color:var(--warn)}

.explain-label{
  margin-top:17px;font-size:9px;font-weight:700;letter-spacing:.14em;color:var(--ink-tertiary);
}
.explain-body{margin:6px 0 0;font-size:13px;line-height:1.55;color:var(--ink-secondary)}

.explain-scale{margin-top:9px;display:flex;flex-direction:column;gap:2px}
.explain-scale-hint{
  margin-top:2px;font-size:11px;color:var(--ink-tertiary);
}
.explain-band{
  display:block;padding:8px 9px;border-radius:9px;
  font-size:12px;color:var(--ink-secondary);
}
.explain-band-head{display:flex;align-items:center;gap:9px}
/* The line that turns the scale from a reference table into advice. Indented
   under the band it belongs to so a glance down the column reads as
   band → what to do, band → what to do. */
.explain-band-do{
  margin:3px 0 0 17px;font-size:11.5px;line-height:1.45;color:var(--ink-tertiary);
}
.explain-band.mine .explain-band-do{color:var(--ink-secondary)}
.explain-band.mine{background:var(--chip);color:var(--ink);font-weight:600}
.explain-band-dot{width:8px;height:8px;border-radius:50%;flex:none}
.explain-band-range{min-width:58px;font-variant-numeric:tabular-nums;font-weight:600}
.explain-band-label{flex:1;min-width:0}
.explain-band-you{
  font-size:9.5px;font-weight:700;letter-spacing:.08em;text-transform:uppercase;
  color:var(--ink-tertiary);flex:none;
}

.explain-ok{
  margin-top:20px;width:100%;padding:13px;border-radius:14px;
  background:var(--chip-on-bg);color:var(--chip-on-ink);
  font-size:13.5px;font-weight:700;
}
.explain-ok:active{transform:scale(.985)}

/* Desktop shows the app in a phone frame, so the sheet stays phone-width and
   simply centres itself rather than stretching. */
@media (min-width:441px){
  .explain-card{border-radius:26px;margin-bottom:24px}
  .explain-overlay{align-items:center}
}


/* ---------- ask by speaking ----------
   The way in: a full-width button, not another icon tucked into the text
   row. Someone who opened the assistant because typing is the problem
   should not have to find a 28px microphone to escape the keyboard. */
.ask-talk{
  display:flex;align-items:center;justify-content:center;gap:9px;
  width:100%;margin:2px 0 10px;padding:13px;border-radius:14px;
  background:var(--chip-on-bg);color:var(--chip-on-ink);
  font-size:14px;font-weight:700;
  touch-action:manipulation;-webkit-tap-highlight-color:transparent;
}
.ask-talk svg{width:18px;height:18px}
.ask-talk:active{transform:scale(.985)}

/* Above .ask-overlay (85), not below it. The conversation is opened from
   the assistant sheet and that sheet stays mounted underneath, so at 80
   this whole screen rendered *behind* the sheet's translucent dark backdrop
   — you got a blurred orb through a grey wash, with the sheet sitting on
   top of it. */
.conv-overlay{
  position:fixed;inset:0;z-index:90;
  display:flex;flex-direction:column;align-items:center;justify-content:center;gap:18px;
  padding:32px 26px calc(32px + env(safe-area-inset-bottom, 0px));
  background:var(--page);text-align:center;
}

/* One element that says which of the three things is happening, because a
   caption alone is too slow to read while you are mid-sentence. */
.conv-orb{
  position:relative;width:132px;height:132px;flex:none;
  display:flex;align-items:center;justify-content:center;cursor:pointer;
  touch-action:manipulation;-webkit-tap-highlight-color:transparent;
}
.conv-orb-core{
  position:absolute;inset:22px;border-radius:50%;
  background:radial-gradient(circle at 38% 32%,#7FB2E5,#2C6EA8 70%);
  box-shadow:0 8px 30px rgba(44,110,168,.35);
}
.conv-orb-ring{
  position:absolute;inset:0;border-radius:50%;
  border:2px solid var(--info);opacity:0;
}
[data-state="listening"] .conv-orb-ring{animation:convPulse 1.9s ease-out infinite}
[data-state="listening"] .conv-orb-core{animation:convBreathe 1.9s ease-in-out infinite}
@keyframes convPulse{
  0%{transform:scale(.72);opacity:.75}
  100%{transform:scale(1.12);opacity:0}
}
@keyframes convBreathe{
  0%,100%{transform:scale(1)}
  50%{transform:scale(1.06)}
}
/* Thinking spins; speaking swells. Different motions, so the state is
   readable from across a field without reading the caption. */
[data-state="thinking"] .conv-orb-ring{
  opacity:.9;border-color:transparent;border-top-color:var(--info);
  animation:convSpin 1s linear infinite;
}
@keyframes convSpin{to{transform:rotate(360deg)}}
[data-state="speaking"] .conv-orb-core{
  background:radial-gradient(circle at 38% 32%,#8FD6B4,#2E7D5B 70%);
  animation:convTalk .9s ease-in-out infinite;
}
@keyframes convTalk{
  0%,100%{transform:scale(1)}
  50%{transform:scale(1.09)}
}
[data-state="idle"] .conv-orb-core{background:radial-gradient(circle at 38% 32%,#B9C6D8,#7E8A9B 70%)}

.conv-transcript{
  min-height:26px;font-size:17px;font-weight:600;line-height:1.35;color:var(--ink);
  max-width:22em;
}
.conv-caption{font-size:14.5px;line-height:1.5;color:var(--ink-secondary);max-width:24em}
.conv-hint{font-size:12px;line-height:1.5;color:var(--ink-tertiary);max-width:24em}
.conv-end{
  margin-top:8px;padding:12px 28px;border-radius:999px;
  background:var(--chip);border:1px solid var(--chip-border);color:var(--chip-ink);
  font-size:14px;font-weight:700;
}
.conv-end:active{transform:scale(.97)}

@media (prefers-reduced-motion:reduce){
  .conv-orb-core, .conv-orb-ring{animation:none!important}
  [data-state="listening"] .conv-orb-ring{opacity:.5;transform:scale(1)}
}

/* Desktop keeps the app in its phone frame, so the overlay does too. */
@media (min-width:441px){
  .conv-overlay{
    left:50%;transform:translateX(-50%);width:402px;
    border-radius:44px;
  }
}
