// aero-city.jsx — City forecast detail (editorial article-like)

function PageCity({ lang, cityId = "smr", setLang }) {
  const t = window.WX.T[lang];
  const city = window.WX.CITIES.find(c => c.id === cityId) || window.WX.CITIES[0];
  const [data, setData] = useState(window.WX.DATA);

  useEffect(() => {
    let alive = true;
    window.WX.fetchWeather(city.lat, city.lon, 7).then(j => {
      if (alive) setData({ ...j, _city: city });
    });
    return () => { alive = false; };
  }, [cityId]);

  const cur = data.current_complete || window.WX.DATA.current_complete;
  const hour = window.WX.hourOf(cur.time);
  const palette = window.WX.palette(cur.weathercode, hour);
  const today = data.forecast[0];

  return (
    <div>
      {/* ───── EDITORIAL HEADER ─────────────────────────────────── */}
      <section style={{ position: 'relative', overflow: 'hidden',
        borderBottom: `0.5px solid ${AERO.hair}` }}>
        <AtmosphericBackdrop palette={palette}
          weathercode={cur.weathercode} hour={hour}
          windDir={cur.wind_direction_10m} windSpd={cur.wind_speed_10m} />
        <div style={{ position: 'absolute', inset: 0,
          background: `linear-gradient(180deg, transparent 0%, ${AERO.paper}f0 100%)` }} />
        <div style={{ position: 'relative', maxWidth: 1320, margin: '0 auto', padding: '56px 36px 64px' }}>
          {/* breadcrumb */}
          <div className="aero-mono" style={{
            fontSize: 10.5, letterSpacing: 1.4, color: palette.inkSoft,
            textTransform: 'uppercase', display: 'flex', gap: 10, alignItems: 'center',
          }}>
            <a href="#/home" className="aero-link" style={{ color: palette.inkSoft }}>
              {lang === "pt" ? "Início" : "Home"}
            </a>
            <span>/</span>
            <a href="#/home" className="aero-link" style={{ color: palette.inkSoft }}>
              {lang === "pt" ? "Previsão" : "Forecast"}
            </a>
            <span>/</span>
            <span style={{ color: palette.ink }}>{city.region}</span>
          </div>

          <div style={{ display: 'grid', gridTemplateColumns: '1.4fr 1fr', gap: 64,
            marginTop: 24, alignItems: 'end' }}>
            <div>
              <div className="aero-mono" style={{
                fontSize: 11, letterSpacing: 1.6, color: palette.inkSoft,
                textTransform: 'uppercase',
              }}>
                {cur.time.slice(0, 10)} · {cur.time.slice(11)} {data.timezone_abbr || "GMT-3"}
                {data._fallback && ` · ${lang === "pt" ? "amostra local" : "local sample"}`}
              </div>
              <h1 className="aero-serif" style={{
                fontStyle: 'italic', fontWeight: 400,
                fontSize: 'clamp(72px, 9vw, 152px)',
                lineHeight: 0.9, letterSpacing: -4,
                color: palette.ink, margin: '12px 0 0',
              }}>{city.name}</h1>
              <div className="aero-serif" style={{
                fontStyle: 'italic', fontSize: 32, color: palette.inkDim,
                marginTop: 8, lineHeight: 1.2,
              }}>{cur.weathercode_desc[lang]}, {Math.round(cur.temperature_2m)}°C.</div>

              <CityPickerInline lang={lang} currentId={cityId} />
            </div>

            <div style={{ paddingBottom: 8 }}>
              <div className="aero-serif" style={{
                fontStyle: 'italic', fontSize: 240, lineHeight: 0.82,
                letterSpacing: -10, color: palette.ink, textAlign: 'right',
                fontFeatureSettings: '"lnum"',
              }}>
                {Math.round(cur.temperature_2m)}<span style={{ fontSize: 120 }}>°</span>
              </div>
              <div className="aero-mono" style={{
                fontSize: 11, color: palette.inkDim, textAlign: 'right', letterSpacing: 0.5,
              }}>
                {t.feels_like.toUpperCase()} {cur.apparent_temperature.toFixed(1)}° ·
                {" "}{Math.round(today.temperature_2m_min)}° / {Math.round(today.temperature_2m_max)}°
              </div>
            </div>
          </div>
        </div>
      </section>

      {/* ───── KEY METRIC TABLE ─────────────────────────────────── */}
      <Container style={{ marginTop: 56 }}>
        <SectionEyebrow hint={`${city.lat.toFixed(3)}, ${city.lon.toFixed(3)} · ${data.elevation || 77}m`}>
          {lang === "pt" ? "Leituras de superfície" : "Surface readings"}
        </SectionEyebrow>
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(6, 1fr)',
          borderTop: `0.5px solid ${AERO.hair}` }}>
          {[
            [t.humidity, cur.relative_humidity_2m + "%", null],
            [t.dewpoint, cur.dew_point_2m.toFixed(1) + "°", null],
            [t.pressure, Math.round(cur.surface_pressure) + " hPa", lang === "pt" ? "Caindo" : "Falling"],
            [t.wind, cur.wind_speed_10m.toFixed(1) + " m/s",
              `${window.WX.compassLabel(cur.wind_direction_10m, lang)} · ${cur.wind_direction_10m}°`],
            [t.gusts, cur.wind_gusts_10m.toFixed(0) + " m/s", null],
            [t.cloud, cur.cloud_cover + "%", null],
          ].map(([label, value, sub], i) => (
            <div key={i} style={{
              padding: '22px 20px 22px 0',
              borderRight: i < 5 ? `0.5px solid ${AERO.hair}` : 'none',
            }}>
              <div className="aero-mono" style={{
                fontSize: 9.5, letterSpacing: 1.4, color: AERO.inkSoft,
                textTransform: 'uppercase',
              }}>{label}</div>
              <div className="aero-serif" style={{
                fontStyle: 'italic', fontSize: 36, color: AERO.ink, lineHeight: 1,
                marginTop: 8, letterSpacing: -0.5,
              }}>{value}</div>
              {sub && <div className="aero-mono" style={{
                fontSize: 10, color: AERO.inkSoft, marginTop: 6, letterSpacing: 0.5,
              }}>{sub}</div>}
            </div>
          ))}
        </div>
      </Container>

      {/* ───── EDITORIAL BLURB + SUN/MOON ───────────────────────── */}
      <Container style={{ marginTop: 80 }}>
        <div style={{ display: 'grid', gridTemplateColumns: '1.4fr 1fr', gap: 64 }}>
          <div>
            <div className="aero-eyebrow" style={{ color: AERO.ink, fontWeight: 600 }}>
              {lang === "pt" ? "Análise do momento" : "Current analysis"}
            </div>
            <p className="aero-serif" style={{
              fontStyle: 'italic', fontSize: 28, lineHeight: 1.35,
              color: AERO.ink, marginTop: 14, textWrap: 'pretty',
            }}>
              {(() => {
                const code = cur.weathercode;
                const pt = lang === "pt";
                if (code <= 3) return pt ? "A massa de ar seco domina a região, garantindo estabilidade e amplas aberturas de sol. A pressão atmosférica em superfície se mantém controlada, inibindo a formação de nebulosidade." : "Dry air mass dominates the region, ensuring stability and wide sunny spells. Surface atmospheric pressure remains controlled, inhibiting cloudiness.";
                if (code >= 45 && code <= 48) return pt ? "Condições de inversão térmica favorecem o acúmulo de umidade e a formação de nevoeiro restrito à camada limite, reduzindo a visibilidade." : "Thermal inversion conditions favor moisture accumulation and boundary-layer fog, reducing visibility.";
                if (code >= 51 && code <= 67) return pt ? "A camada de superfície permanece saturada devido à constante advecção de umidade. Precipitação estratiforme de intensidade leve a moderada domina as observações." : "The surface layer remains saturated due to constant moisture advection. Stratiform precipitation of light to moderate intensity dominates observations.";
                if (code >= 71 && code <= 77) return pt ? "Advecção de ar polar nos baixos e médios níveis sustenta condições termodinâmicas para precipitação invernal ao longo do planalto." : "Polar air advection in low and mid levels sustains thermodynamic conditions for winter precipitation along the plateau.";
                if (code >= 80 && code <= 82) return pt ? "O escoamento instável gera núcleos convectivos rasos, resultando em pancadas de chuva intermitentes e localizadas na região." : "Unstable flow generates shallow convective cores, resulting in intermittent and localized rain showers.";
                if (code >= 95) return pt ? "Forte divergência em altos níveis aliada ao intenso cisalhamento sustenta atividade convectiva profunda. Condição de alerta para tempo severo." : "Strong high-level divergence coupled with intense shear sustains deep convective activity. Severe weather alert condition.";
                return pt ? "As condições meteorológicas seguem a climatologia típica da estação, com variações normais de temperatura na escala diária." : "Meteorological conditions follow typical seasonal climatology, with normal temperature variations on the daily scale.";
              })()}
            </p>
            <p style={{
              fontSize: 14.5, color: AERO.inkDim, marginTop: 18, lineHeight: 1.55,
              textWrap: 'pretty',
            }}>
              {(() => {
                const pt = lang === "pt";
                const wind = pt ? `Ventos de superfície em torno de ${cur.wind_speed_10m.toFixed(1)} m/s` : `Surface winds around ${cur.wind_speed_10m.toFixed(1)} m/s`;
                const press = pt ? `pressão em ${Math.round(cur.surface_pressure)} hPa` : `pressure at ${Math.round(cur.surface_pressure)} hPa`;
                const temp = pt ? `amplitude de ${Math.round(today.temperature_2m_min)}°C a ${Math.round(today.temperature_2m_max)}°C` : `amplitude from ${Math.round(today.temperature_2m_min)}°C to ${Math.round(today.temperature_2m_max)}°C`;
                return pt 
                  ? `${wind} comandam a advecção atual, combinados com a ${press}. O perfil térmico do dia deve apresentar uma ${temp}.`
                  : `${wind} drive the current advection, combined with a ${press}. The thermal profile of the day indicates an ${temp}.`;
              })()}
            </p>
            <div className="aero-mono" style={{
              fontSize: 10.5, color: AERO.inkSoft, marginTop: 22, letterSpacing: 0.5,
            }}>
              {lang === "pt" ? "Assinado" : "Signed"} · Sistema Agregador ·
              {" "}{lang === "pt" ? `Boletim Automático GMT-3` : `Auto Bulletin GMT-3`}
            </div>
          </div>

          {/* Sun/moon block */}
          <div style={{ display: 'flex', flexDirection: 'column', gap: 32 }}>
            <div>
              <div className="aero-eyebrow">{t.daylight}</div>
              <div style={{ marginTop: 12 }}>
                <SunArc palette={{ ...palette, hair: AERO.hair, line: AERO.line, inkSoft: AERO.inkSoft, warm: AERO.warm }}
                  sunrise={today.sunrise} sunset={today.sunset} now={cur.time}
                  width={400} height={100} />
              </div>
              <div className="aero-mono" style={{
                marginTop: 10, fontSize: 10.5, color: AERO.inkSoft, letterSpacing: 0.5,
              }}>
                {(today.daylight_duration / 3600).toFixed(1)}h {lang === "pt" ? "de luz" : "of daylight"}
                {" · "}{(today.sunshine_duration / 3600).toFixed(1)}h {lang === "pt" ? "de sol" : "of sun"}
              </div>
            </div>
            <div style={{ display: 'flex', gap: 22, alignItems: 'center' }}>
              <MoonGlyph phase={today.moon_phase} size={64} color={AERO.ink} bg={AERO.paperDeep} />
              <div>
                <div className="aero-eyebrow">{t.moon}</div>
                <div className="aero-serif" style={{ fontStyle: 'italic', fontSize: 26, color: AERO.ink, lineHeight: 1.1 }}>
                  {lang === "pt" ? "Crescente gibosa" : "Waxing gibbous"}
                </div>
                <div className="aero-mono" style={{ fontSize: 10.5, color: AERO.inkSoft, marginTop: 4 }}>
                  {(today.moon_phase * 100).toFixed(0)}% {lang === "pt" ? "iluminada" : "illuminated"}
                </div>
              </div>
            </div>
          </div>
        </div>
      </Container>

      {/* ───── HOURLY TIMELINE ──────────────────────────────────── */}
      <Container style={{ marginTop: 80 }}>
        <SectionEyebrow hint={`${data.hourly.time[0].slice(11)} → ${data.hourly.time[data.hourly.time.length - 1].slice(11)}`}>
          {lang === "pt" ? "Evolução horária · 24h" : "Hourly evolution · 24h"}
        </SectionEyebrow>
        <CityHourlyChart data={data} palette={palette} lang={lang} t={t} />
      </Container>

      {/* ───── 7-DAY ROW ───────────────────────────────────────── */}
      <Container style={{ marginTop: 80 }}>
        <SectionEyebrow hint={lang === "pt" ? "ECMWF · atualizado 06z" : "ECMWF · 06z init"}>
          {lang === "pt" ? "Próximos 7 dias" : "Next 7 days"}
        </SectionEyebrow>
        <SevenDayStrip data={data} lang={lang} t={t} />
      </Container>

      {/* ───── BOTTOM ATMOSPHERE GRID ──────────────────────────── */}
      <Container style={{ marginTop: 80 }}>
        <SectionEyebrow>{lang === "pt" ? "Aerograma · perfil termodinâmico" : "Aerogram · thermodynamic profile"}</SectionEyebrow>
        <div style={{ display: 'grid', gridTemplateColumns: '1.2fr 1fr', gap: 28 }}>
          <SkewT palette={palette} />
          <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 16, alignContent: 'start' }}>
            <DiagBigCard label={t.cape} value="412" unit="J/kg" status="LOW" />
            <DiagBigCard label={t.cin} value="-38" unit="J/kg" status="CAP" />
            <DiagBigCard label={t.lifted} value="+1.2" unit="°C" status="STABLE" />
            <DiagBigCard label={t.helicity} value="84" unit="m²/s²" status="LOW" />
            <DiagBigCard label="K-index" value="22" unit="" status="WEAK" />
            <DiagBigCard label="PWAT" value="34.6" unit="mm" status="HIGH" />
          </div>
        </div>
      </Container>
    </div>
  );
}

// ─────────────────────────────────────────────────────────────────────
function CityPickerInline({ lang, currentId }) {
  const opts = window.WX.CITIES.slice(0, 8);
  return (
    <div style={{ marginTop: 36, display: 'flex', flexWrap: 'wrap', gap: 6 }}>
      <span className="aero-mono" style={{
        fontSize: 10, letterSpacing: 1.4, color: AERO.inkSoft,
        textTransform: 'uppercase', alignSelf: 'center', marginRight: 6,
      }}>{lang === "pt" ? "Ir para" : "Jump to"}</span>
      {opts.map(c => (
        <a key={c.id} href={"#/city/" + c.id} style={{
          padding: '6px 12px', borderRadius: 999,
          border: `0.5px solid ${c.id === currentId ? AERO.ink : AERO.hair}`,
          background: c.id === currentId ? AERO.ink : 'transparent',
          color: c.id === currentId ? AERO.paper : AERO.inkDim,
          fontFamily: "'JetBrains Mono', monospace", fontSize: 10.5,
          letterSpacing: 0.8,
        }}>{c.name}</a>
      ))}
    </div>
  );
}

// ─────────────────────────────────────────────────────────────────────
// Hourly chart — bigger version of the mobile screen one
// ─────────────────────────────────────────────────────────────────────
function CityHourlyChart({ data, palette, lang, t }) {
  const h = data.hourly;
  const [idx, setIdx] = useState(window.WX.hourOf(data.current_complete.time));
  const W = 1200, H = 320;
  const cw = W - 80;

  function pickIdx(e) {
    const r = e.currentTarget.getBoundingClientRect();
    const x = (e.touches ? e.touches[0].clientX : e.clientX) - r.left - 60;
    const i = Math.max(0, Math.min(23, Math.round((x / cw) * 23)));
    setIdx(i);
  }

  const tempMin = Math.min(...h.temperature_2m, ...h.dew_point_2m) - 1;
  const tempMax = Math.max(...h.temperature_2m) + 1;
  const tempY = (v) => H - 90 - ((v - tempMin) / (tempMax - tempMin)) * (H - 130);

  return (
    <div style={{
      background: '#fff', border: `0.5px solid ${AERO.hair}`,
      borderRadius: 6, overflow: 'hidden',
    }}>
      {/* readout strip */}
      <div style={{
        display: 'grid', gridTemplateColumns: '180px repeat(6, 1fr)',
        borderBottom: `0.5px solid ${AERO.hair}`,
      }}>
        <div style={{ padding: '20px 24px', borderRight: `0.5px solid ${AERO.hair}` }}>
          <div className="aero-mono" style={{
            fontSize: 9.5, letterSpacing: 1.4, color: AERO.inkSoft, textTransform: 'uppercase',
          }}>{h.time[idx].slice(11)}</div>
          <div className="aero-serif" style={{
            fontStyle: 'italic', fontSize: 56, color: AERO.ink, lineHeight: 0.95,
            letterSpacing: -1.5, marginTop: 4,
          }}>{Math.round(h.temperature_2m[idx])}°</div>
        </div>
        {[
          [t.dewpoint, h.dew_point_2m[idx].toFixed(1) + "°"],
          [t.humidity, h.relative_humidity_2m[idx] + "%"],
          [t.precip, h.precipitation[idx] + " mm"],
          [t.wind, h.wind_speed_10m[idx].toFixed(1) + " m/s"],
          [t.pressure, Math.round(h.surface_pressure[idx]) + " hPa"],
          [t.cloud, h.cloud_cover[idx] + "%"],
        ].map(([k, v], i) => (
          <div key={i} style={{ padding: '20px 24px', borderRight: i < 5 ? `0.5px solid ${AERO.hair}` : 'none' }}>
            <div className="aero-mono" style={{
              fontSize: 9.5, letterSpacing: 1.4, color: AERO.inkSoft, textTransform: 'uppercase',
            }}>{k}</div>
            <div className="aero-mono" style={{
              fontSize: 18, color: AERO.ink, marginTop: 8, letterSpacing: 0.3,
            }}>{v}</div>
          </div>
        ))}
      </div>

      {/* chart */}
      <div onMouseDown={pickIdx} onMouseMove={(e) => e.buttons === 1 && pickIdx(e)}
        onTouchStart={pickIdx} onTouchMove={pickIdx}
        style={{ userSelect: 'none', cursor: 'col-resize' }}>
        <svg width="100%" height={H} viewBox={`0 0 ${W} ${H}`} preserveAspectRatio="none">
          {/* y-axis temp grid */}
          {(() => {
            const tics = [];
            const step = (tempMax - tempMin) > 12 ? 5 : 2;
            for (let v = Math.ceil(tempMin / step) * step; v < tempMax; v += step) {
              const y = tempY(v);
              tics.push(
                <g key={v}>
                  <line x1={60} y1={y} x2={W - 20} y2={y}
                    stroke={AERO.hair} strokeWidth={0.5} strokeDasharray="2 4" />
                  <text x={50} y={y + 3} fill={AERO.inkSoft} fontSize="11"
                    fontFamily="'JetBrains Mono', monospace" textAnchor="end">{v}°</text>
                </g>
              );
            }
            return tics;
          })()}
          {/* x ticks */}
          {[0, 3, 6, 9, 12, 15, 18, 21, 23].map(i => {
            const x = 60 + (i / 23) * cw;
            return <g key={i}>
              <line x1={x} y1={20} x2={x} y2={H - 80} stroke={AERO.hair} strokeWidth={0.5} />
              <text x={x} y={H - 60} textAnchor="middle" fill={AERO.inkSoft}
                fontSize="11" fontFamily="'JetBrains Mono', monospace">
                {String(i).padStart(2, "0")}h
              </text>
            </g>;
          })}
          {/* precip bars */}
          <g transform={`translate(60, ${H - 80})`}>
            {h.precipitation.map((v, i) => {
              const x = (i / 23) * cw;
              const bw = cw / 24 * 0.7;
              const ph = Math.min(50, v * 12);
              return <rect key={i} x={x - bw / 2} y={50 - ph} width={bw} height={ph}
                fill={palette.accent} opacity={0.5} />;
            })}
            <text x={0} y={68} fill={AERO.inkSoft} fontSize="10"
              fontFamily="'JetBrains Mono', monospace" letterSpacing="1">PRECIP (mm)</text>
          </g>
          {/* dewpoint */}
          <g transform="translate(60, 0)">
            <Sparkline values={h.dew_point_2m} width={cw} height={H - 90} color={palette.accentDim} strokeWidth={1.2} />
            {/* temp */}
            <Sparkline values={h.temperature_2m} width={cw} height={H - 90}
              color={palette.warm} strokeWidth={2}
              fill={palette.warm} />
          </g>
          {/* cursor */}
          <line x1={60 + (idx / 23) * cw} y1={10} x2={60 + (idx / 23) * cw} y2={H - 80}
            stroke={AERO.ink} strokeWidth={1} strokeDasharray="3 4" />
          <circle cx={60 + (idx / 23) * cw} cy={tempY(h.temperature_2m[idx])}
            r={6} fill={palette.warm} stroke="#fff" strokeWidth={2} />
        </svg>
      </div>

      {/* legend */}
      <div style={{
        display: 'flex', gap: 24, padding: '12px 24px 16px',
        fontFamily: "'JetBrains Mono', monospace", fontSize: 10.5,
        color: AERO.inkSoft, letterSpacing: 0.5,
        borderTop: `0.5px solid ${AERO.hair}`,
      }}>
        <span><i style={{ display: 'inline-block', width: 14, height: 2, background: palette.warm, marginRight: 8, verticalAlign: 'middle' }} />{lang === "pt" ? "Temperatura" : "Temperature"} 2m</span>
        <span><i style={{ display: 'inline-block', width: 14, height: 2, background: palette.accentDim, marginRight: 8, verticalAlign: 'middle' }} />{t.dewpoint}</span>
        <span><i style={{ display: 'inline-block', width: 12, height: 6, background: palette.accent, opacity: 0.5, marginRight: 8, verticalAlign: 'middle' }} />{t.precip}</span>
        <span style={{ marginLeft: 'auto' }}>{lang === "pt" ? "Arraste para escolher hora" : "Drag to scrub"}</span>
      </div>
    </div>
  );
}

// ─────────────────────────────────────────────────────────────────────
// 7-DAY STRIP
// ─────────────────────────────────────────────────────────────────────
function SevenDayStrip({ data, lang, t }) {
  const days = data.forecast.slice(0, 7);
  const allMin = Math.min(...days.map(d => d.temperature_2m_min));
  const allMax = Math.max(...days.map(d => d.temperature_2m_max));

  return (
    <div style={{
      background: '#fff', border: `0.5px solid ${AERO.hair}`, borderRadius: 6,
      display: 'grid', gridTemplateColumns: 'repeat(7, 1fr)',
    }}>
      {days.map((d, i) => {
        const lp = (d.temperature_2m_min - allMin) / (allMax - allMin);
        const rp = (d.temperature_2m_max - allMin) / (allMax - allMin);
        return (
          <div key={i} style={{
            padding: '22px 20px',
            borderRight: i < 6 ? `0.5px solid ${AERO.hair}` : 'none',
          }}>
            <div className="aero-mono" style={{
              fontSize: 11, letterSpacing: 1.4, color: i === 0 ? AERO.ink : AERO.inkSoft,
              textTransform: 'uppercase', fontWeight: i === 0 ? 600 : 400,
            }}>{i === 0 ? t.today : window.WX.fmtDate(d.date, lang)} · {d.date.slice(8, 10)}</div>
            <div className="aero-serif" style={{
              fontStyle: 'italic', fontSize: 38, color: AERO.ink, lineHeight: 1, marginTop: 10,
            }}>{Math.round(d.temperature_2m_max)}<span style={{ fontSize: 22 }}>°</span></div>
            <div className="aero-mono" style={{
              fontSize: 11, color: AERO.inkSoft, marginTop: 2,
            }}>↓ {Math.round(d.temperature_2m_min)}°</div>
            <div style={{ position: 'relative', height: 4, background: AERO.hair, borderRadius: 2, marginTop: 14 }}>
              <div style={{
                position: 'absolute', left: `${lp * 100}%`, right: `${(1 - rp) * 100}%`,
                top: 0, bottom: 0, background: `linear-gradient(90deg, ${AERO.accent}, ${AERO.warm})`,
                borderRadius: 2,
              }} />
            </div>
            <div className="aero-mono" style={{
              fontSize: 10, color: AERO.inkSoft, marginTop: 14, letterSpacing: 0.5,
              textTransform: 'uppercase',
            }}>{d.weathercode_desc[lang]}</div>
            <div className="aero-mono" style={{ fontSize: 10, color: AERO.accent, marginTop: 6 }}>
              ☂ {d.precipitation_probability_max}% · {d.precipitation_sum} mm
            </div>
          </div>
        );
      })}
    </div>
  );
}

// ─────────────────────────────────────────────────────────────────────
// Stylized Skew-T diagram — pure decorative SVG. Hand-drawn meteorological
// diagram with adiabats + temp/dewpoint traces.
// ─────────────────────────────────────────────────────────────────────
function SkewT({ palette }) {
  const W = 520, H = 420;
  const skewAngle = 30 * Math.PI / 180;
  const skew = Math.tan(skewAngle);

  // pressure levels (hPa) on y axis: 1000 bottom, 100 top
  const pLevels = [1000, 850, 700, 500, 300, 200, 100];
  const yOfP = (p) => 40 + (1 - Math.log(p / 100) / Math.log(1000 / 100)) * (H - 80);

  // isotherms (skewed) every 10°C from -90 to +40
  const isotherms = [];
  for (let T = -90; T <= 40; T += 10) {
    // x-axis 0..1 maps to -40..+40 at p=1000
    const x0 = ((T + 40) / 80) * (W - 120) + 60;
    const x1 = x0 + (yOfP(100) - yOfP(1000)) * skew;
    isotherms.push(
      <line key={T} x1={x0} y1={yOfP(1000)} x2={x1} y2={yOfP(100)}
        stroke={AERO.hair} strokeWidth={T === 0 ? 1 : 0.4}
        strokeDasharray={T === 0 ? "" : "2 4"} />
    );
  }
  // dry adiabats — decorative curves
  const dryAd = [];
  for (let i = 0; i < 8; i++) {
    const sx = 100 + i * 60;
    dryAd.push(
      <path key={i} d={`M ${sx} ${yOfP(1000)} Q ${sx - 60} ${yOfP(500)}, ${sx - 140} ${yOfP(100)}`}
        stroke={AERO.warm} strokeWidth={0.4} strokeOpacity="0.5" fill="none" />
    );
  }
  // Temperature trace (right curve)
  const tempPts = [
    [1000, 14], [950, 13.2], [900, 11], [850, 8],
    [700, -2], [500, -16], [300, -42], [200, -54], [100, -68],
  ];
  const dewPts = [
    [1000, 14], [950, 12.5], [900, 9], [850, 4],
    [700, -8], [500, -28], [300, -56], [200, -68], [100, -78],
  ];
  const toXY = ([p, T]) => {
    const x0 = ((T + 40) / 80) * (W - 120) + 60;
    const y = yOfP(p);
    return [x0 + (y - yOfP(1000)) * skew, y];
  };
  const tempPath = "M " + tempPts.map(p => toXY(p).join(",")).join(" L ");
  const dewPath = "M " + dewPts.map(p => toXY(p).join(",")).join(" L ");

  return (
    <div style={{
      background: '#fff', border: `0.5px solid ${AERO.hair}`,
      borderRadius: 6, padding: 24,
    }}>
      <div className="aero-eyebrow">Skew-T log-P</div>
      <svg width="100%" viewBox={`0 0 ${W} ${H}`}>
        {isotherms}
        {dryAd}
        {/* pressure axis labels */}
        {pLevels.map(p => (
          <g key={p}>
            <text x={50} y={yOfP(p) + 3} textAnchor="end" fill={AERO.inkSoft}
              fontSize="10" fontFamily="'JetBrains Mono', monospace">{p}</text>
            <line x1={60} y1={yOfP(p)} x2={W - 30} y2={yOfP(p)}
              stroke={AERO.hair} strokeWidth={0.5} />
          </g>
        ))}
        {/* temperature isotherms label */}
        <text x={W - 20} y={yOfP(1000) + 14} textAnchor="end" fill={AERO.inkSoft}
          fontSize="10" fontFamily="'JetBrains Mono', monospace">+40°C</text>
        <text x={60} y={yOfP(1000) + 14} fill={AERO.inkSoft}
          fontSize="10" fontFamily="'JetBrains Mono', monospace">-40°C</text>
        {/* axis title */}
        <text x={30} y={yOfP(316)} textAnchor="middle" fill={AERO.inkSoft}
          fontSize="10" fontFamily="'JetBrains Mono', monospace" letterSpacing="1"
          transform={`rotate(-90 30 ${yOfP(316)})`}>PRESSURE (hPa)</text>

        {/* Dewpoint then temp */}
        <path d={dewPath} stroke={palette.accent} strokeWidth={2} fill="none" />
        <path d={tempPath} stroke={palette.warm} strokeWidth={2} fill="none" />

        {/* wind barbs along right edge */}
        {[1000, 850, 700, 500, 300].map((p, i) => {
          const y = yOfP(p);
          return (
            <g key={p} transform={`translate(${W - 10}, ${y})`}>
              <line x1={-14} y1={0} x2={0} y2={0} stroke={AERO.ink} strokeWidth={1} />
              <line x1={0} y1={0} x2={-4} y2={-6 - i * 1.5} stroke={AERO.ink} strokeWidth={1} />
              {i > 1 && <line x1={-4} y1={0} x2={-8} y2={-6 - i * 1.5} stroke={AERO.ink} strokeWidth={1} />}
            </g>
          );
        })}
      </svg>
      <div style={{ display: 'flex', gap: 22, marginTop: 12,
        fontFamily: "'JetBrains Mono', monospace", fontSize: 10.5, color: AERO.inkSoft }}>
        <span><i style={{ display: 'inline-block', width: 12, height: 2, background: palette.warm, marginRight: 6, verticalAlign: 'middle' }} />T (env)</span>
        <span><i style={{ display: 'inline-block', width: 12, height: 2, background: palette.accent, marginRight: 6, verticalAlign: 'middle' }} />Td</span>
        <span style={{ marginLeft: 'auto' }}>06z init · ECMWF</span>
      </div>
    </div>
  );
}

function DiagBigCard({ label, value, unit, status }) {
  const sCol = status === "LOW" || status === "STABLE" || status === "WEAK" ? AERO.accent
    : status === "CAP" || status === "HIGH" ? AERO.warm : AERO.danger;
  return (
    <div style={{
      background: '#fff', border: `0.5px solid ${AERO.hair}`,
      borderRadius: 6, padding: '20px 22px',
    }}>
      <div className="aero-mono" style={{
        fontSize: 9.5, letterSpacing: 1.4, color: AERO.inkSoft, textTransform: 'uppercase',
      }}>{label}</div>
      <div className="aero-serif" style={{
        fontStyle: 'italic', fontSize: 36, color: AERO.ink, lineHeight: 1,
        marginTop: 10, display: 'flex', alignItems: 'baseline', gap: 4,
        letterSpacing: -0.5,
      }}>
        {value}
        <span className="aero-mono" style={{
          fontStyle: 'normal', fontSize: 11, color: AERO.inkSoft,
        }}>{unit}</span>
      </div>
      <div style={{ display: 'flex', alignItems: 'center', gap: 6, marginTop: 10 }}>
        <div style={{ width: 6, height: 6, borderRadius: 3, background: sCol }} />
        <div className="aero-mono" style={{
          fontSize: 9.5, letterSpacing: 1, color: AERO.inkSoft,
        }}>{status}</div>
      </div>
    </div>
  );
}

Object.assign(window, { PageCity });
