// Homepage — search, map, featured cities, insights

const { useState: useStateH, useEffect: useEffectH, useRef: useRefH, useMemo: useMemoH } = React;

// =============================================================================
// BIG RADAR — the focal element of the entire site. Dark "control-room" map
// showing every position-bearing freight signal we ingest, with live cargo
// aircraft from OpenSky overlaid as moving plane icons. Anonymous visitors
// see the visual + counts; signed-in users get full popups + tighter polling.
// =============================================================================

const RADAR_AIRPORT_LATLNG = {
  KMEM: [35.0424, -89.9767], KSDF: [38.1740, -85.7361], KCVG: [39.0489, -84.6678],
  KIND: [39.7173, -86.2944], KANC: [61.1744, -149.9962], KORD: [41.9742, -87.9073],
  KLAX: [33.9416, -118.4085], KJFK: [40.6413, -73.7781], KEWR: [40.6925, -74.1687],
  KDFW: [32.8998, -97.0403], KATL: [33.6407, -84.4277], KMIA: [25.7959, -80.2870],
  KOAK: [37.7126, -122.2197], KSEA: [47.4502, -122.3088], KPHX: [33.4373, -112.0078],
  KBOS: [42.3656, -71.0096], KIAH: [29.9844, -95.3414], KPHL: [39.8744, -75.2424],
};

// Brand colors for cargo carriers — tuned for visibility on the dark map.
const CARRIER_COLOR = {
  fedex: "#FF6600", ups: "#9F8F4A", atlas: "#5BA9DE", polar: "#5BA9DE",
  abx: "#E25555", kalitta: "#FFD466", "kalitta-charters": "#FFD466",
  "western-global": "#7BD66B", amerijet: "#FF6F61", ati: "#A78BFA",
  national: "#F472B6", "21-air": "#34D399",
  cargojet: "#FBBF24", dhl: "#FFD400", aerologic: "#FFD400",
  cargolux: "#22D3EE", "lufthansa-cargo": "#F97316",
  martinair: "#60A5FA", "atlas-charters": "#5BA9DE", "asl-belgium": "#A3E635",
};

// Plane silhouette as inline SVG path (rotates via CSS transform).
const PLANE_SVG_PATH = "M12 2 L13.5 11 L22 13 L22 14 L13.5 14.5 L13 21 L14 22 L11 22 L10 21 L10.5 14.5 L2 14 L2 13 L10.5 11 Z";

// =============================================================================
// Popup-text formatters. Database fields are stored as slugs ("los-angeles"),
// CHP-system codes ("1180-Trfc Collision-Major Inj"), or ALL-CAPS location
// strings ("I-5 NB AT MAIN ST"). Rendering them raw in Leaflet popups looks
// like ops-system noise, not journalism. These three helpers normalize.
// =============================================================================

// "los-angeles" → "Los Angeles". Handles slugs and underscored strings.
function slugTitle(s) {
  if (s == null) return "";
  return String(s)
    .replace(/[-_]+/g, " ")
    .replace(/\s+/g, " ")
    .trim()
    .replace(/\b([a-z])/g, (_, c) => c.toUpperCase());
}

// "I-5 NB AT MAIN ST" → "I-5 NB at Main St". Only re-cases if input is
// mostly uppercase (avoids breaking already-cased strings).
function smartCase(s) {
  if (s == null) return "";
  s = String(s).trim();
  if (!s) return "";
  // If string contains lowercase, leave it alone — it's already cased.
  if (/[a-z]/.test(s)) return s;
  // Otherwise title-case it, preserving small route prefixes (I-5, US-101, SR-1).
  return s.toLowerCase().replace(/\b([a-z])/g, (_, c) => c.toUpperCase())
    // Re-uppercase known route prefixes
    .replace(/\b(I|Us|Sr|Ca|Hwy)-/gi, m => m.toUpperCase())
    // Common compass directions stay capitalized
    .replace(/\b(Nb|Sb|Eb|Wb|Ne|Nw|Se|Sw)\b/g, m => m.toUpperCase());
}

// Filter null/empty pieces and join — no leading/trailing/double separators.
function joinClean(parts, sep) {
  if (sep == null) sep = " · ";
  return (parts || [])
    .filter(p => p != null && String(p).trim() !== "")
    .join(sep);
}

// CHP incident-type cleanup. Strips leading numeric codes, expands the most
// common abbreviations to readable English. Returns "Incident" if nothing.
function cleanChpType(s) {
  if (!s) return "Incident";
  let out = String(s).replace(/^[0-9]+-/, "").trim();
  out = out
    .replace(/\bTrfc\b/gi, "Traffic")
    .replace(/\bCollision-Major Inj\b/gi, "Collision · major injury")
    .replace(/\bCollision-Minor Inj\b/gi, "Collision · minor injury")
    .replace(/\bCollision-No Inj\b/gi, "Collision · no injury")
    .replace(/\bCollision-Fatal\b/gi, "Collision · fatal")
    .replace(/\bHit and Run No Inj\b/gi, "Hit and run · no injury")
    .replace(/\bHit and Run Inj\b/gi, "Hit and run · injury")
    .replace(/\bMajor Inj\b/gi, "Major injury")
    .replace(/\bMinor Inj\b/gi, "Minor injury")
    .replace(/\bNo Inj\b/gi, "No injury")
    .replace(/\bDui\b/gi, "DUI");
  return out;
}

// Carrier-name cleanup for aircraft popups. Slugs come in as "fedex-express"
// → "FedEx Express". Some are short codes ("ups" → "UPS").
function cleanCarrier(s) {
  if (!s) return "";
  const slug = String(s).toLowerCase().trim();
  // Short carrier codes that should stay all-caps
  const upper = new Set(["ups", "dhl", "abx", "ati", "atsg", "ana", "klm"]);
  if (upper.has(slug)) return slug.toUpperCase();
  // Special-cased display names where slug → branded mixed-case
  const specialCase = {
    "fedex": "FedEx",
    "fedex-express": "FedEx Express",
    "fedex-ground": "FedEx Ground",
    "kalitta": "Kalitta",
    "kalitta-charters": "Kalitta Charters",
    "western-global": "Western Global",
    "atlas": "Atlas Air",
    "atlas-charters": "Atlas Air",
    "polar": "Polar Air Cargo",
    "amerijet": "Amerijet",
    "national": "National Airlines",
    "21-air": "21 Air",
    "cargojet": "Cargojet",
    "aerologic": "AeroLogic",
    "cargolux": "Cargolux",
    "lufthansa-cargo": "Lufthansa Cargo",
    "martinair": "Martinair",
    "asl-belgium": "ASL Belgium",
  };
  if (specialCase[slug]) return specialCase[slug];
  // Fallback: slug → title case
  return slugTitle(slug);
}

function BigRadar({ user, onNav }) {
  const mapRef = useRefH(null);
  const containerRef = useRefH(null);
  const layersRef = useRefH({});
  const lcRef = useRefH(null);
  const [aircraft, setAircraft] = useStateH([]);
  const [chp, setChp] = useStateH([]);
  const [fires, setFires] = useStateH([]);
  const [metar, setMetar] = useStateH([]);
  const [quakes, setQuakes] = useStateH([]);
  const [weatherAlerts, setWeatherAlerts] = useStateH([]);
  const [refineries, setRefineries] = useStateH([]);
  const [now, setNow] = useStateH(Date.now());
  const [loading, setLoading] = useStateH(true);

  const isAuthed = !!user && !!user.email;

  // Load everything on mount. Aircraft re-polls every 30s for live feel.
  useEffectH(() => {
    let alive = true;
    if (!window.SI_DB || !window.SI_DB.raw) return;
    (async () => {
      const since24h = new Date(Date.now() - 24*3600*1000).toISOString();
      const [planes, chps, frs, mts, qks, wxs, refs] = await Promise.all([
        window.SI_DB.raw.select("cargo_aircraft",
          "select=icao24,callsign,carrier,lat,lng,altitude_m,velocity_kt,heading_deg,on_ground" +
          "&on_ground=eq.false&order=retrieved_at.desc&limit=400"
        ).catch(() => []),
        window.SI_DB.raw.select("chp_incidents",
          `select=id,incident_type,category,location,location_desc,area,freeway,lat,lng,metro_city_id,log_time` +
          `&last_seen_at=gte.${since24h}` +
          `&category=in.(collision,hazard,closure)` +
          `&order=last_seen_at.desc&limit=300`
        ).catch(() => []),
        window.SI_DB.raw.select("wildfires",
          "select=id,name,acres,pct_contained,state,county,lat,lng,near_metro_id" +
          "&or=(acres.gte.500,near_metro_id.not.is.null)" +
          "&status=neq.Out&order=acres.desc&limit=200"
        ).catch(() => []),
        window.SI_DB.raw.select("airport_weather",
          "select=icao_id,flight_cat,visibility,ceiling_ft,wind_dir_deg,wind_speed_kt,wind_gust_kt,station_name,raw_obs"
        ).catch(() => []),
        window.SI_DB.raw.select("earthquakes",
          "select=id,magnitude,depth_km,lat,lng,place,occurred_at,tsunami,near_metro_id" +
          "&or=(near_metro_id.not.is.null,near_refinery_id.not.is.null,near_port_id.not.is.null)" +
          "&order=occurred_at.desc&limit=20"
        ).catch(() => []),
        window.SI_DB.raw.select("active_weather_signals",
          "select=event,severity,headline,city_id,description&kind=eq.alert&order=severity.desc&limit=30"
        ).catch(() => []),
        window.SI_DB.raw.select("refineries",
          "select=id,name,operator,city,state,padd,lat,lng,capacity_kbpd"
        ).catch(() => []),
      ]);
      if (!alive) return;
      setAircraft(Array.isArray(planes) ? planes : []);
      setChp(Array.isArray(chps) ? chps : []);
      setFires(Array.isArray(frs) ? frs : []);
      setMetar(Array.isArray(mts) ? mts : []);
      setQuakes(Array.isArray(qks) ? qks : []);
      setWeatherAlerts(Array.isArray(wxs) ? wxs : []);
      setRefineries(Array.isArray(refs) ? refs : []);
      setLoading(false);
    })();
    return () => { alive = false; };
  }, []);

  // Aircraft re-poll. Signed-in users get tighter polling so the planes
  // appear to "move" between snapshots; anon gets a single snapshot.
  useEffectH(() => {
    if (!isAuthed) return;
    const interval = setInterval(async () => {
      try {
        const planes = await window.SI_DB.raw.select("cargo_aircraft",
          "select=icao24,callsign,carrier,lat,lng,altitude_m,velocity_kt,heading_deg,on_ground" +
          "&on_ground=eq.false&order=retrieved_at.desc&limit=400");
        if (Array.isArray(planes)) setAircraft(planes);
        setNow(Date.now());
      } catch {}
    }, 60_000);
    return () => clearInterval(interval);
  }, [isAuthed]);

  // Memoize filtered/derived sets so layer rebuilds are gated properly.
  const planes = useMemoH(() => (aircraft || []).filter(a =>
    a.lat != null && a.lng != null && !a.on_ground
  ), [aircraft]);
  const fireRows = useMemoH(() => (fires || []).filter(f =>
    f.lat != null && f.lng != null
  ), [fires]);
  const chpRows = useMemoH(() => (chp || []).filter(c =>
    c.lat != null && c.lng != null
  ), [chp]);
  const metarRows = useMemoH(() => (metar || []).filter(m =>
    RADAR_AIRPORT_LATLNG[m.icao_id]
  ), [metar]);
  const quakeRows = useMemoH(() => (quakes || []).filter(q =>
    q.lat != null && q.lng != null
  ), [quakes]);
  const refRows = useMemoH(() => (refineries || []).filter(r =>
    r.lat != null && r.lng != null
  ), [refineries]);

  // Mount-only: build the map once.
  useEffectH(() => {
    if (!containerRef.current || !window.L || mapRef.current) return;
    const map = window.L.map(containerRef.current, {
      zoomControl: false, scrollWheelZoom: false, attributionControl: true,
      fadeAnimation: false, zoomAnimation: false, markerZoomAnimation: false,
      worldCopyJump: false, minZoom: 3, maxZoom: 9,
      // Prevent panning/wrapping the globe horizontally — keeps the map
      // anchored over North America.
      maxBounds: [[10, -175], [72, -50]],
      maxBoundsViscosity: 1.0,
    }).setView([39.5, -98.5], 4);
    window.L.tileLayer(
      "https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png",
      {
        attribution: "© OpenStreetMap · © CARTO",
        subdomains: "abcd", maxZoom: 9,
        noWrap: true,                    // do not repeat tiles past the antimeridian
        bounds: [[-90, -180], [90, 180]],
      }
    ).addTo(map);
    window.L.control.zoom({ position: "bottomright" }).addTo(map);
    mapRef.current = map;
    setTimeout(() => map.invalidateSize(), 80);
    return () => { map.remove(); mapRef.current = null; };
  }, []);

  // Layer build. Re-runs only when filtered sets change reference.
  useEffectH(() => {
    const map = mapRef.current;
    if (!map || !window.L) return;

    // Capture the OLD layer set before clearing so we can also remove
    // the old entries from the layer control. (Was duplicating entries
    // on every data refresh because we cleared layersRef before reading.)
    const oldLayers = Object.values(layersRef.current);
    oldLayers.forEach(lg => {
      if (lg && map.hasLayer(lg)) map.removeLayer(lg);
    });
    layersRef.current = {};

    function pulsePin(latLng, color, size, popupHtml, pulse = true) {
      const html = `
        <span class="radar-dot${pulse ? ' radar-dot-pulse' : ''}" style="
          width:${size}px;height:${size}px;background:${color};
        "></span>`;
      const icon = window.L.divIcon({
        className: "radar-icon", html,
        iconSize: [size + 8, size + 8],
        iconAnchor: [(size + 8) / 2, (size + 8) / 2],
      });
      const m = window.L.marker(latLng, { icon, riseOnHover: true });
      if (popupHtml) m.bindPopup(popupHtml);
      return m;
    }
    function planeIcon(a) {
      const heading = a.heading_deg ?? 0;
      const color = CARRIER_COLOR[a.carrier] || "#fff";
      const html = `
        <svg viewBox="0 0 24 24" width="14" height="14"
             style="transform:rotate(${heading - 45}deg);
                    transform-origin:50% 50%;
                    filter:drop-shadow(0 0 2px rgba(0,0,0,0.6))">
          <path d="${PLANE_SVG_PATH}" fill="${color}" stroke="rgba(0,0,0,0.5)" stroke-width="0.5"/>
        </svg>`;
      const icon = window.L.divIcon({
        className: "radar-plane", html,
        iconSize: [16, 16], iconAnchor: [8, 8],
      });
      const m = window.L.marker([a.lat, a.lng], { icon, riseOnHover: true });
      // Popup detail varies by auth state.
      const carrierName = cleanCarrier(a.carrier);
      const flightId = a.callsign || a.icao24 || "";
      const headerAuthed = joinClean(["✈ " + (flightId || "Flight"), carrierName]);
      const headerAnon = "✈ " + (carrierName ? carrierName + " flight" : "Cargo flight");
      const popup = isAuthed ? `
        <div class="radar-pop">
          <div class="radar-pop-eye" style="color:${color}">${headerAuthed}</div>
          <div class="radar-pop-num">${a.velocity_kt ?? "?"} kt</div>
          <div class="radar-pop-meta">${joinClean([
            a.altitude_m != null ? `${Math.round(a.altitude_m * 3.281).toLocaleString()} ft` : null,
            `heading ${Math.round(heading)}°`,
          ])}</div>
        </div>` : `
        <div class="radar-pop">
          <div class="radar-pop-eye" style="color:${color}">${headerAnon}</div>
          <div class="radar-pop-meta radar-pop-cta">Sign in for callsign · altitude · routing →</div>
        </div>`;
      m.bindPopup(popup);
      return m;
    }

    const planesLayer = window.L.layerGroup(planes.map(planeIcon));
    const firesLayer = window.L.layerGroup(fireRows.map(f => {
      const ac = Number(f.acres) || 0;
      const size = ac >= 10000 ? 14 : ac >= 1000 ? 10 : 7;
      const acStr = ac >= 1000 ? `${(ac/1000).toFixed(ac >= 10000 ? 0 : 1)}K` : Math.round(ac).toLocaleString();
      const stateClean = (f.state || "").replace(/^US-/, "");
      const fireHeader = joinClean(["🔥 " + (stateClean || "US"), "wildfire"]);
      const popup = isAuthed ? `
        <div class="radar-pop">
          <div class="radar-pop-eye" style="color:#FF8A4A">${fireHeader}</div>
          <div class="radar-pop-num">${acStr} ac</div>
          <div class="radar-pop-meta">${joinClean([
            smartCase(f.name) || "Unnamed",
            f.pct_contained != null ? `${f.pct_contained}% contained` : null,
            f.county ? `${smartCase(f.county)} Co.` : null,
          ])}</div>
        </div>` : `
        <div class="radar-pop">
          <div class="radar-pop-eye" style="color:#FF8A4A">🔥 Wildfire</div>
          <div class="radar-pop-num">${acStr} ac</div>
          <div class="radar-pop-meta radar-pop-cta">Sign in for name · containment · cause →</div>
        </div>`;
      return pulsePin([f.lat, f.lng], "#FF6B3D", size, popup, ac >= 1000);
    }));
    const chpLayer = window.L.layerGroup(chpRows.map(c => {
      const tag = c.category || "other";
      const color = tag === "collision" ? "#FF4D6A"
                  : tag === "hazard"    ? "#FFA94D" : "#FF4D6A";
      const tagDisplay = tag.charAt(0).toUpperCase() + tag.slice(1);
      const chpHeader = joinClean(["🛣 " + tagDisplay, c.freeway]);
      const popup = isAuthed ? `
        <div class="radar-pop">
          <div class="radar-pop-eye" style="color:${color}">${chpHeader}</div>
          <div class="radar-pop-num">${cleanChpType(c.incident_type)}</div>
          <div class="radar-pop-meta">${joinClean([
            smartCase(c.area),
            smartCase(c.location_desc),
            slugTitle(c.metro_city_id),
          ])}</div>
        </div>` : `
        <div class="radar-pop">
          <div class="radar-pop-eye" style="color:${color}">🛣 California ${tag}</div>
          <div class="radar-pop-meta radar-pop-cta">Sign in for freeway · area · details →</div>
        </div>`;
      return pulsePin([c.lat, c.lng], color, tag === "collision" ? 7 : 6, popup, false);
    }));
    const metarLayer = window.L.layerGroup(metarRows.map(a => {
      const ll = RADAR_AIRPORT_LATLNG[a.icao_id];
      const cat = a.flight_cat || "VFR";
      const degraded = cat !== "VFR";
      const color = cat === "LIFR" ? "#E879F9"
                  : cat === "IFR"  ? "#FF4D6A"
                  : cat === "MVFR" ? "#FFA94D"
                  : "#34D399";
      const stationName = (a.station_name || "").split("·")[0].trim();
      const windText = a.wind_dir_deg != null
        ? `wind ${a.wind_dir_deg}°/${a.wind_speed_kt}kt${a.wind_gust_kt ? "G"+a.wind_gust_kt : ""}`
        : null;
      // 🛬 = airport (unambiguously not a single aircraft); ✈ stays
      // for the actual aircraft layer above. The flight-category color
      // (green/orange/red/magenta) carries the urgency on top of the
      // weather code.
      const popup = isAuthed ? `
        <div class="radar-pop">
          <div class="radar-pop-eye" style="color:${color}">${joinClean(["🛬 " + a.icao_id + " airport", cat + " weather"])}</div>
          <div class="radar-pop-num">${a.visibility ?? "?"} mi visibility</div>
          <div class="radar-pop-meta">${joinClean([stationName, windText])}</div>
        </div>` : `
        <div class="radar-pop">
          <div class="radar-pop-eye" style="color:${color}">${joinClean(["🛬 " + a.icao_id + " airport", cat + " weather"])}</div>
          <div class="radar-pop-meta radar-pop-cta">Sign in for live METAR + winds →</div>
        </div>`;
      return pulsePin(ll, color, degraded ? 11 : 6, popup, degraded);
    }));
    const quakeLayer = window.L.layerGroup(quakeRows.map(q => {
      const m = Number(q.magnitude) || 0;
      const size = m >= 6 ? 14 : m >= 5 ? 11 : 8;
      const eqHeader = joinClean(["🌋 M" + m.toFixed(1), q.tsunami ? "TSUNAMI" : null]);
      const popup = isAuthed ? `
        <div class="radar-pop">
          <div class="radar-pop-eye" style="color:#C084FC">${eqHeader}</div>
          <div class="radar-pop-num">${smartCase(q.place) || "Earthquake"}</div>
          <div class="radar-pop-meta">${joinClean([
            q.depth_km ? Number(q.depth_km).toFixed(0) + " km depth" : null,
            q.near_metro_id ? "near " + slugTitle(q.near_metro_id) : null,
          ])}</div>
        </div>` : `
        <div class="radar-pop">
          <div class="radar-pop-eye" style="color:#C084FC">🌋 M${m.toFixed(1)} earthquake</div>
          <div class="radar-pop-meta radar-pop-cta">Sign in for place · depth · proximity →</div>
        </div>`;
      return pulsePin([q.lat, q.lng], "#C084FC", size, popup, true);
    }));
    const refLayer = window.L.layerGroup(refRows.map(r => {
      const refHeader = joinClean([
        r.padd ? "🛢 PADD " + r.padd : "🛢 Refinery",
        smartCase(r.operator),
      ]);
      const cityState = joinClean([smartCase(r.city), r.state], ", ");
      const popup = isAuthed ? `
        <div class="radar-pop">
          <div class="radar-pop-eye" style="color:#94A3B8">${refHeader}</div>
          <div class="radar-pop-num">${smartCase(r.name) || "Refinery"}</div>
          <div class="radar-pop-meta">${joinClean([
            r.capacity_kbpd ? r.capacity_kbpd.toLocaleString() + " kbpd capacity" : null,
            cityState,
          ])}</div>
        </div>` : `
        <div class="radar-pop">
          <div class="radar-pop-eye" style="color:#94A3B8">🛢 Refinery</div>
          <div class="radar-pop-meta radar-pop-cta">Sign in for operator · capacity · utilization →</div>
        </div>`;
      return pulsePin([r.lat, r.lng], "#64748B", 5, popup, false);
    }));

    planesLayer.addTo(map);
    firesLayer.addTo(map);
    chpLayer.addTo(map);
    metarLayer.addTo(map);
    quakeLayer.addTo(map);
    refLayer.addTo(map);
    layersRef.current = {
      planes: planesLayer, fires: firesLayer, chp: chpLayer,
      metar: metarLayer, quake: quakeLayer, refineries: refLayer,
    };

    if (!lcRef.current) {
      lcRef.current = window.L.control.layers(null, {}, {
        collapsed: false, position: "bottomleft",
      }).addTo(map);
    } else {
      oldLayers.forEach(lg => lcRef.current.removeLayer(lg));
    }
    lcRef.current.addOverlay(planesLayer, `✈ Cargo aircraft (${planes.length})`);
    lcRef.current.addOverlay(firesLayer,  `🔥 Wildfires (${fireRows.length})`);
    lcRef.current.addOverlay(chpLayer,    `🛣 California highways (${chpRows.length})`);
    lcRef.current.addOverlay(metarLayer,  `✈ Airports (${metarRows.length})`);
    lcRef.current.addOverlay(quakeLayer,  `🌋 Earthquakes (${quakeRows.length})`);
    lcRef.current.addOverlay(refLayer,    `🛢 Refineries (${refRows.length})`);
  }, [planes, fireRows, chpRows, metarRows, quakeRows, refRows, isAuthed]);

  // Build the live ticker text — rolling stats and headlines.
  const tickerItems = useMemoH(() => {
    const items = [];
    items.push(`✈ ${planes.length} cargo aircraft airborne`);
    const worstMetar = metarRows.find(m => m.flight_cat === "LIFR")
                    || metarRows.find(m => m.flight_cat === "IFR")
                    || metarRows.find(m => m.flight_cat === "MVFR");
    if (worstMetar) items.push(`⚠ ${worstMetar.icao_id} flying ${worstMetar.flight_cat}`);
    items.push(`🛣 ${chpRows.length} CHP incidents · CA`);
    if (fireRows[0]) {
      const ac = Number(fireRows[0].acres) || 0;
      const acStr = ac >= 1000 ? `${(ac/1000).toFixed(0)}K` : ac;
      items.push(`🔥 ${fireRows[0].name || "fire"} · ${acStr} ac · ${(fireRows[0].state||"").replace(/^US-/,"")}`);
    }
    items.push(`🔥 ${fireRows.length} active fires`);
    if (quakeRows[0]) items.push(`🌋 M${Number(quakeRows[0].magnitude).toFixed(1)} · ${(quakeRows[0].place||"").slice(0, 40)}`);
    items.push(`🛢 ${refRows.length} refineries online`);
    if (weatherAlerts[0]) items.push(`🌩 ${weatherAlerts[0].event}`);
    return items;
  }, [planes, metarRows, chpRows, fireRows, quakeRows, refRows, weatherAlerts]);

  return (
    <section className="big-radar">
      <style>{`
        .big-radar {
          position: relative; background: #0a0e15;
          overflow: hidden;
          border-bottom: 1px solid #1f2937;
        }
        .big-radar-map {
          width: 100%; height: 78vh; min-height: 560px; max-height: 820px;
          background: #0a0e15;
        }
        @media (max-width: 760px) {
          .big-radar-map { height: 70vh; min-height: 440px; }
        }
        /* Radar sweep — slow conic gradient that rotates over the map.
           Subtle but unmistakably "alive". Pointer-events:none so it
           doesn't block map interaction. */
        .big-radar-map::after {
          content: ""; position: absolute; inset: 0; pointer-events: none;
          background: conic-gradient(from 0deg at 50% 50%,
            transparent 0deg,
            rgba(80, 200, 120, 0.05) 8deg,
            rgba(80, 200, 120, 0.10) 14deg,
            rgba(80, 200, 120, 0.05) 20deg,
            transparent 28deg);
          mix-blend-mode: screen;
          animation: radar-sweep 8s linear infinite;
          z-index: 401;  /* above tiles, below markers */
        }
        @keyframes radar-sweep { to { transform: rotate(360deg); } }

        /* Pulsing hotspot dot */
        .radar-icon { background: transparent !important; border: 0 !important; }
        .radar-dot {
          display: inline-block; border-radius: 50%;
          border: 1.5px solid rgba(255,255,255,0.55);
          box-shadow: 0 0 8px rgba(0,0,0,0.6);
        }
        .radar-dot-pulse::before {
          content: ""; display: block;
          width: 100%; height: 100%; border-radius: 50%;
          background: inherit; position: relative; top: -1.5px; left: -1.5px;
          animation: radar-pulse 2.4s cubic-bezier(0.2, 0.7, 0.3, 1) infinite;
          pointer-events: none;
        }
        @keyframes radar-pulse {
          0% { transform: scale(1); opacity: 0.7; }
          80%, 100% { transform: scale(3.4); opacity: 0; }
        }
        .radar-plane { background: transparent !important; border: 0 !important; }

        /* Floating chrome */
        .br-title {
          position: absolute; top: 18px; left: 22px; z-index: 500;
          color: #fff; pointer-events: none;
        }
        .br-title-eyebrow {
          font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.18em;
          text-transform: uppercase; color: #50C878;
          display: inline-flex; align-items: center; gap: 8px;
          padding: 6px 10px; background: rgba(0,0,0,0.5); border-radius: 4px;
          backdrop-filter: blur(6px);
        }
        .br-title-eyebrow .dot {
          display: inline-block; width: 8px; height: 8px; border-radius: 50%;
          background: #50C878; box-shadow: 0 0 0 0 #50C878;
          animation: radar-livedot 1.6s ease-in-out infinite;
        }
        @keyframes radar-livedot {
          0%, 100% { box-shadow: 0 0 0 0 rgba(80,200,120,0.7); }
          70% { box-shadow: 0 0 0 8px rgba(80,200,120,0); }
        }
        .br-title-h {
          font-family: var(--font-serif); font-size: clamp(28px, 4vw, 48px);
          line-height: 1.05; letter-spacing: -0.025em;
          margin: 12px 0 6px; max-width: 600px;
          text-shadow: 0 2px 16px rgba(0,0,0,0.6);
        }
        .br-title-h em { font-style: italic; color: #50C878; }
        .br-title-sub {
          font-size: 14px; color: #cbd5e1; line-height: 1.4;
          max-width: 480px;
          text-shadow: 0 1px 8px rgba(0,0,0,0.6);
        }

        /* Ticker bar at the bottom */
        .br-ticker {
          position: absolute; left: 0; right: 0; bottom: 0; z-index: 500;
          background: linear-gradient(180deg, rgba(10,14,21,0) 0%, rgba(10,14,21,0.95) 35%);
          padding: 28px 0 14px;
          pointer-events: none;
        }
        .br-ticker-inner {
          max-width: 1300px; margin: 0 auto; padding: 0 22px;
          display: flex; gap: 22px; overflow: hidden; white-space: nowrap;
          font-family: var(--font-mono); font-size: 12px; letter-spacing: 0.05em;
          color: #cbd5e1;
          mask-image: linear-gradient(90deg, transparent 0, #000 6%, #000 94%, transparent 100%);
        }
        .br-ticker-track {
          display: inline-flex; gap: 22px; animation: radar-ticker 60s linear infinite;
          flex-shrink: 0;
        }
        @keyframes radar-ticker { to { transform: translateX(-50%); } }
        .br-ticker-item { display: inline-flex; align-items: center; flex-shrink: 0; }

        /* Auth-CTA overlay for anon users */
        .br-cta-overlay {
          position: absolute; top: 18px; right: 22px; z-index: 500;
          background: rgba(10,14,21,0.85); backdrop-filter: blur(10px);
          border: 1px solid rgba(80,200,120,0.35); border-radius: 8px;
          padding: 14px 18px; max-width: 340px;
          color: #f1f5f9;
          box-shadow: 0 12px 36px rgba(0,0,0,0.4);
        }
        .br-cta-eye {
          font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.18em;
          text-transform: uppercase; color: #50C878; margin-bottom: 6px;
        }
        .br-cta-h { font-family: var(--font-serif); font-size: 17px;
          letter-spacing: -0.015em; margin: 0 0 6px; }
        .br-cta-sub { font-size: 12px; color: #94a3b8; line-height: 1.45;
          margin-bottom: 10px; }
        .br-cta-btn {
          display: inline-flex; align-items: center; gap: 6px;
          background: #50C878; color: #0a0e15; border: 0;
          padding: 8px 14px; border-radius: 5px; font-family: inherit;
          font-weight: 600; font-size: 13px; cursor: pointer;
        }
        .br-cta-btn:hover { background: #6BD89A; }

        /* Layer control restyled for the dark map */
        .leaflet-control-layers {
          background: rgba(10,14,21,0.85) !important;
          backdrop-filter: blur(10px);
          border: 1px solid rgba(255,255,255,0.08) !important;
          border-radius: 6px !important;
          padding: 10px 12px !important;
          color: #cbd5e1 !important;
          font-family: var(--font-mono); font-size: 11px;
        }
        .leaflet-control-layers label { color: #cbd5e1 !important; }
        .leaflet-control-layers-base, .leaflet-control-layers-overlays { color: #cbd5e1; }
        .leaflet-popup-content-wrapper {
          background: rgba(10,14,21,0.95) !important; color: #f1f5f9;
          border: 1px solid rgba(255,255,255,0.08); border-radius: 8px;
        }
        .leaflet-popup-tip { background: rgba(10,14,21,0.95) !important; }
        .leaflet-popup-close-button { color: #94a3b8 !important; }
        .leaflet-control-zoom a {
          background: rgba(10,14,21,0.85) !important; color: #cbd5e1 !important;
          border: 1px solid rgba(255,255,255,0.08) !important;
        }
        .leaflet-container .leaflet-control-attribution {
          background: rgba(10,14,21,0.6) !important; color: #94a3b8 !important;
          font-size: 10px;
        }
        .leaflet-container .leaflet-control-attribution a { color: #cbd5e1 !important; }

        /* Popup interior */
        .radar-pop { font-family: var(--font-sans, system-ui); min-width: 200px; padding: 4px 2px; }
        .radar-pop-eye {
          font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.14em;
          text-transform: uppercase; margin-bottom: 4px;
        }
        .radar-pop-num {
          font-family: var(--font-serif); font-size: 18px; letter-spacing: -0.01em;
          color: #f1f5f9;
        }
        .radar-pop-meta { font-size: 11px; color: #94a3b8; margin-top: 4px; line-height: 1.45; }
        .radar-pop-cta { color: #50C878; font-weight: 500; }
      `}</style>

      <div ref={containerRef} className="big-radar-map" />

      <div className="br-title">
        <span className="br-title-eyebrow">
          <span className="dot" /> {loading ? "Calibrating…" : `LIVE · ${planes.length} aircraft tracked`}
        </span>
        <h1 className="br-title-h">
          Is your shipment going to make it?<br/>
          <em>Did you check the pulse?</em>
        </h1>
        <p className="br-title-sub">
          Live cargo aircraft, active wildfires, weather-grounded airports, California traffic,
          earthquakes near freight infrastructure, every refinery — overlaid in one map. Public
          data, stitched.
        </p>
      </div>

      {!isAuthed && (
        <div className="br-cta-overlay">
          <div className="br-cta-eye"><span style={{display:"inline-block",width:6,height:6,borderRadius:"50%",background:"#50C878",marginRight:6,verticalAlign:"middle"}}/>Anonymous view</div>
          <h3 className="br-cta-h">Sign in for the full intel.</h3>
          <p className="br-cta-sub">
            You're seeing every signal we track — but tap any pin and you'll see "sign in for details."
            Free magic-link · no password · no credit card.
          </p>
          <button className="br-cta-btn" onClick={() => onNav("signin")}>
            Sign in →
          </button>
        </div>
      )}

      <div className="br-ticker">
        <div className="br-ticker-inner">
          <div className="br-ticker-track">
            {[...tickerItems, ...tickerItems].map((t, i) => (
              <span key={i} className="br-ticker-item">{t}</span>
            ))}
          </div>
        </div>
      </div>
    </section>
  );
}

// =============================================================================
// AIR HORN — easter egg on truck click. Pure Web Audio synth (no audio file).
// =============================================================================
let _audioCtx = null;
function honkAirHorn() {
  try {
    if (!_audioCtx) {
      const Ctx = window.AudioContext || window.webkitAudioContext;
      if (!Ctx) return;
      _audioCtx = new Ctx();
    }
    const ctx = _audioCtx;
    if (ctx.state === "suspended") ctx.resume();

    const now = ctx.currentTime;
    const duration = 0.85;

    // Three slightly detuned square-wave oscillators give the "blat" of a real air horn
    const freqs = [220, 277, 330];
    const master = ctx.createGain();
    master.gain.setValueAtTime(0, now);
    master.gain.linearRampToValueAtTime(0.18, now + 0.04);
    master.gain.setValueAtTime(0.18, now + duration - 0.18);
    master.gain.exponentialRampToValueAtTime(0.001, now + duration);
    master.connect(ctx.destination);

    // Slight low-pass to take harsh edges off the squarewave
    const filter = ctx.createBiquadFilter();
    filter.type = "lowpass";
    filter.frequency.value = 1800;
    filter.Q.value = 1.2;
    filter.connect(master);

    freqs.forEach((f, i) => {
      const osc = ctx.createOscillator();
      osc.type = "square";
      osc.frequency.setValueAtTime(f, now);
      // Tiny pitch wobble for realism
      osc.frequency.linearRampToValueAtTime(f * 1.02, now + 0.15);
      osc.frequency.linearRampToValueAtTime(f * 0.98, now + duration - 0.1);
      const oscGain = ctx.createGain();
      oscGain.gain.value = i === 0 ? 0.6 : 0.4;
      osc.connect(oscGain);
      oscGain.connect(filter);
      osc.start(now);
      osc.stop(now + duration + 0.05);
    });
  } catch (e) {
    console.warn("honk failed", e);
  }
}
window.honkAirHorn = honkAirHorn;

// =============================================================================
// LIVE NETWORK RADAR — public-facing teaser of the operator-signal pipeline.
// Pulls verified+public intel via the anon supabase client and shows a live
// counter, a top-3 chronic-pattern list, and a 4-row recent feed (text faded
// out so non-subscribers see the shape of the signal but not every word).
// =============================================================================
function LiveRadar({ onNav }) {
  const [rows, setRows] = useStateH([]);
  const [loading, setLoading] = useStateH(true);
  useEffectH(() => {
    let alive = true;
    async function load() {
      if (!window.SI_DB || !window.SI_DB.raw) { setLoading(false); return; }
      try {
        const data = await window.SI_DB.raw.select(
          "intel_submissions",
          "select=parsed_carrier,parsed_intel_type,parsed_city,severity,raw_text,created_at&order=created_at.desc&limit=300"
        );
        if (!alive) return;
        setRows(Array.isArray(data) ? data : []);
      } catch {}
      finally { if (alive) setLoading(false); }
    }
    load();
    return () => { alive = false; };
  }, []);

  const day = 86400000;
  const now = Date.now();
  const recent7 = rows.filter(r => now - new Date(r.posted_at || r.created_at).getTime() < 7 * day);
  const recent30 = rows.filter(r => now - new Date(r.posted_at || r.created_at).getTime() < 30 * day);

  // Build top patterns the same way the dashboard does
  const sevWeight = { critical: 4, high: 3, moderate: 1.5, low: 1 };
  const carrierIdx = {};
  recent30.forEach(r => {
    if (!r.parsed_carrier || !r.parsed_intel_type) return;
    const k = `${r.parsed_carrier}|${r.parsed_intel_type}`;
    if (!carrierIdx[k]) carrierIdx[k] = { carrier: r.parsed_carrier, type: r.parsed_intel_type, count: 0, score: 0, sev: { high: 0, critical: 0 } };
    carrierIdx[k].count += 1;
    carrierIdx[k].score += sevWeight[r.severity] || 1;
    if (r.severity === "high" || r.severity === "critical") carrierIdx[k].sev[r.severity] += 1;
  });
  const topPatterns = Object.values(carrierIdx)
    .filter(p => p.count >= 3)
    .sort((a, b) => b.score - a.score)
    .slice(0, 3);

  const carriers = (window.SI_DATA && window.SI_DATA.LA_REPORT && window.SI_DATA.LA_REPORT.carriers) || {};
  function carrierName(slug) {
    for (const cat of Object.values(carriers)) {
      const hit = (cat || []).find(c => c.id === slug);
      if (hit) return hit.name;
    }
    return (slug || "").toUpperCase();
  }
  function fmtType(t) { return (t || "").replace(/_/g, " "); }
  function fmtAge(ts) {
    const d = Math.floor((now - new Date(ts).getTime()) / day);
    if (d <= 0) return "today";
    if (d === 1) return "1d ago";
    return `${d}d ago`;
  }

  const recentFeed = recent7.slice(0, 4);
  const totalVerified = rows.length;
  const high7 = recent7.filter(r => r.severity === "high" || r.severity === "critical").length;
  const carriersTracked = new Set(recent30.map(r => r.parsed_carrier).filter(Boolean)).size;

  return (
    <section className="radar-section">
      <div className="radar-inner">
        <div className="radar-head">
          <div className="radar-head-left">
            <div className="radar-eyebrow">
              <span className="radar-live-dot" /> LIVE NETWORK RADAR · UPDATED CONTINUOUSLY
            </div>
            <h2 className="radar-title">
              The freight reality your carrier <em>didn't email you about.</em>
            </h2>
            <p className="radar-sub">
              Live patterns, carrier-by-carrier and metro-by-metro — the operational
              picture you'd otherwise piece together from twelve emails, three Slacks,
              and a phone call you didn't make. Updated through the day.
            </p>
          </div>
          <div className="radar-stats">
            <div className="radar-stat">
              <div className="radar-stat-num">{totalVerified.toLocaleString()}</div>
              <div className="radar-stat-l">verified signals</div>
            </div>
            <div className="radar-stat">
              <div className="radar-stat-num" style={{ color: high7 ? "oklch(0.55 0.20 25)" : "var(--ink)" }}>{high7}</div>
              <div className="radar-stat-l">high-severity · 7d</div>
            </div>
            <div className="radar-stat">
              <div className="radar-stat-num">{carriersTracked}</div>
              <div className="radar-stat-l">carriers w/ chatter</div>
            </div>
          </div>
        </div>

        <div className="radar-grid">
          <div className="radar-card">
            <div className="radar-card-head">
              <span className="radar-card-eyebrow">🔁 PATTERN RADAR</span>
              <span className="radar-card-sub">Chronic problems · last 30 days</span>
            </div>
            {loading ? (
              <div className="radar-loading">Reading the network…</div>
            ) : topPatterns.length === 0 ? (
              <div className="radar-loading">Pipeline still warming up.</div>
            ) : (
              <ul className="radar-pattern-list">
                {topPatterns.map((p) => (
                  <li key={`${p.carrier}-${p.type}`} className="radar-pattern-row">
                    <div>
                      <div className="radar-pattern-headline">
                        <strong>{carrierName(p.carrier)}</strong>
                        <span className="radar-pattern-arrow">→</span>
                        <span className="radar-pattern-type">{fmtType(p.type)}</span>
                      </div>
                      <div className="radar-pattern-meta">
                        {p.count} reports
                        {(p.sev.high + p.sev.critical) > 0 && (
                          <span className="radar-pattern-flag"> · <strong>{p.sev.high + p.sev.critical}</strong> high+critical</span>
                        )}
                      </div>
                    </div>
                    <div className="radar-pattern-count">{p.count}</div>
                  </li>
                ))}
              </ul>
            )}
            <button className="radar-card-cta" onClick={() => onNav && onNav("signin")}>See full pattern radar →</button>
          </div>

          <div className="radar-card radar-card-feed">
            <div className="radar-card-head">
              <span className="radar-card-eyebrow">📡 LIVE FEED · LAST 7 DAYS</span>
              <span className="radar-card-sub">Most recent verified intel · sample</span>
            </div>
            {loading ? (
              <div className="radar-loading">Tuning in…</div>
            ) : recentFeed.length === 0 ? (
              <div className="radar-loading">Quiet across the network.</div>
            ) : (
              <ul className="radar-feed-list">
                {recentFeed.map((r, i) => (
                  <li key={i} className="radar-feed-row">
                    <span className={`radar-feed-sev radar-feed-sev-${r.severity || "low"}`}>{(r.severity || "—").toUpperCase()}</span>
                    <div>
                      <div className="radar-feed-meta">
                        <strong>{carrierName(r.parsed_carrier)}</strong>
                        {r.parsed_intel_type && (<span className="radar-feed-type">{fmtType(r.parsed_intel_type)}</span>)}
                        <span className="radar-feed-age">{fmtAge(r.posted_at || r.created_at)}</span>
                      </div>
                      <div className="radar-feed-text">{(r.raw_text || "").slice(0, 140)}</div>
                    </div>
                  </li>
                ))}
              </ul>
            )}
            <div className="radar-feed-fade" />
          </div>
        </div>

        <div className="radar-cta">
          <div>
            <div className="radar-cta-eyebrow">Get this for your metro</div>
            <h3 className="radar-cta-h">The daily Pulse digest — free.</h3>
            <p className="radar-cta-sub">
              One email a morning. Top patterns, carrier alerts, weather + road
              conditions, port and fuel signals — all scoped to the metros you
              care about. Drivers stay anonymous. We never sell your address.
            </p>
          </div>
          <button className="radar-cta-btn" onClick={() => {
            const el = document.querySelector(".pulse-section");
            if (el) el.scrollIntoView({ behavior: "smooth" });
          }}>
            Subscribe — it's free →
          </button>
        </div>
      </div>
    </section>
  );
}

// =============================================================
// TONIGHT'S PULSE — live alerts strip above the hero. Pulls the
// synthesizer output (intel_alerts) and surfaces the top critical/
// high-severity pattern in a breaking-news ribbon. Anonymous-readable
// (RLS allows status=published). Cycles through if multiple.
// =============================================================
function TonightsPulse({ onNav }) {
  const [alerts, setAlerts] = useStateH([]);
  const [idx, setIdx] = useStateH(0);

  useEffectH(() => {
    let alive = true;
    if (!window.SI_DB || !window.SI_DB.raw) return;
    (async () => {
      try {
        const rows = await window.SI_DB.raw.select(
          "intel_alerts",
          "select=id,topic,severity,city_id,carrier_slug,evidence_count&status=eq.published&order=published_at.desc&limit=5"
        );
        if (!alive) return;
        // Sort by severity weight (critical first), then keep the order from DB.
        const W = { critical: 0, high: 1, moderate: 2, low: 3 };
        const sorted = (Array.isArray(rows) ? rows : []).slice().sort(
          (a,b) => (W[a.severity] ?? 9) - (W[b.severity] ?? 9)
        );
        setAlerts(sorted);
      } catch {}
    })();
    return () => { alive = false; };
  }, []);

  useEffectH(() => {
    if (alerts.length <= 1) return;
    const t = setInterval(() => setIdx(i => (i + 1) % alerts.length), 6000);
    return () => clearInterval(t);
  }, [alerts.length]);

  if (alerts.length === 0) return null;
  const a = alerts[idx];
  // Soft tinted-blue treatment matches the dashboard `.dash-bar` command bar
  // (hue 250). Severity now rides the badge color only — not the whole ribbon —
  // so the ribbon visually ties to BigRadar above and the dashboard surface
  // it links to, rather than blasting red across the homepage.
  const sevBadge = {
    critical: { bg: "oklch(0.50 0.22 25)",  fg: "#fff" },
    high:     { bg: "oklch(0.55 0.20 25)",  fg: "#fff" },
    moderate: { bg: "oklch(0.60 0.15 75)",  fg: "#fff" },
    low:      { bg: "oklch(0.50 0.12 250)", fg: "#fff" },
  }[a.severity] || { bg: "oklch(0.45 0.10 250)", fg: "#fff" };

  return (
    <button
      type="button"
      onClick={() => onNav("account")}
      style={{
        display: "block", width: "100%", padding: 0, border: "none",
        background: "oklch(0.965 0.025 250)",
        borderBottom: "1px solid oklch(0.88 0.04 250)",
        cursor: "pointer", textAlign: "left",
        color: "var(--ink)", overflow: "hidden", position: "relative",
      }}
      title="Open the dashboard for the full read"
    >
      <div style={{
        maxWidth: 1280, margin: "0 auto", padding: "14px 24px",
        display: "flex", alignItems: "center", gap: 16, flexWrap: "wrap",
      }}>
        <span style={{
          display: "inline-flex", alignItems: "center", gap: 8,
          fontFamily: "var(--font-mono)", fontSize: 11, letterSpacing: "0.18em",
          textTransform: "uppercase", color: "oklch(0.40 0.16 250)",
          fontWeight: 600,
        }}>
          <span style={{
            display: "inline-block", width: 8, height: 8, borderRadius: "50%",
            background: "oklch(0.50 0.16 250)", animation: "tp-pulse 1.6s infinite",
          }} />
          Market signal
        </span>
        <span style={{
          fontFamily: "var(--font-mono)", fontSize: 10, letterSpacing: "0.16em",
          textTransform: "uppercase", padding: "2px 8px", borderRadius: 4,
          background: sevBadge.bg, color: sevBadge.fg, fontWeight: 700,
        }}>
          {(a.severity || "moderate").toUpperCase()}
        </span>
        <span style={{
          fontFamily: "var(--font-serif)", fontSize: 17, lineHeight: 1.3,
          letterSpacing: "-0.01em", flex: 1, minWidth: 0, color: "var(--ink)",
        }}>
          {a.topic}
        </span>
        <span style={{
          fontFamily: "var(--font-mono)", fontSize: 11, letterSpacing: "0.14em",
          textTransform: "uppercase", color: "var(--ink-soft)",
        }}>
          Read more →
        </span>
        {alerts.length > 1 && (
          <span style={{
            position: "absolute", bottom: 0, left: 0, right: 0, height: 2,
            background: "oklch(0.88 0.04 250)",
          }}>
            <span style={{
              display: "block", height: "100%",
              background: "oklch(0.50 0.16 250)",
              width: `${((idx + 1) / alerts.length) * 100}%`,
              transition: "width 6s linear",
            }} />
          </span>
        )}
      </div>
      <style>{`
        @keyframes tp-pulse {
          0%, 100% { opacity: 1; transform: scale(1); }
          50%      { opacity: 0.4; transform: scale(0.85); }
        }
      `}</style>
    </button>
  );
}

// =============================================================
// LIVE ALERTS FEED — sits below TonightsPulse on the home page.
// While the ribbon cycles through alerts one at a time, this is
// the persistent "what's open right now" board: up to 5 published
// intel_alerts rendered as cards, each a click-through to the
// dashboard's full "What we're watching" panel. Anon-readable
// (RLS allows SELECT on intel_alerts where status='published').
// =============================================================
function LiveAlertsFeed({ onNav }) {
  const [alerts, setAlerts] = useStateH([]);

  useEffectH(() => {
    let alive = true;
    if (!window.SI_DB || !window.SI_DB.raw) return;
    (async () => {
      try {
        const rows = await window.SI_DB.raw.select(
          "intel_alerts",
          "select=id,topic,severity,city_id,carrier_slug,evidence_count,published_at" +
          "&status=eq.published&order=published_at.desc&limit=5"
        );
        if (!alive) return;
        setAlerts(Array.isArray(rows) ? rows : []);
      } catch {}
    })();
    return () => { alive = false; };
  }, []);

  if (alerts.length === 0) return null;

  // Severity → color. Same hue-25 deep-red palette the dashboard uses, so
  // a critical alert reads the same on home as on /#/account.
  const sevColor = {
    critical: "oklch(0.50 0.22 25)",
    high:     "oklch(0.55 0.20 25)",
    moderate: "oklch(0.55 0.16 75)",
    low:      "oklch(0.55 0.05 250)",
  };

  // "Friday 4:11 PM" / "12 min ago" — short, glanceable.
  function ago(ts) {
    if (!ts) return null;
    const ms = Date.now() - new Date(ts).getTime();
    if (ms < 60_000) return "just now";
    if (ms < 3_600_000) return `${Math.floor(ms / 60_000)}m ago`;
    if (ms < 86_400_000) return `${Math.floor(ms / 3_600_000)}h ago`;
    if (ms < 7 * 86_400_000) return `${Math.floor(ms / 86_400_000)}d ago`;
    return new Date(ts).toLocaleDateString(undefined, { month: "short", day: "numeric" });
  }

  return (
    <section className="laf-section">
      <style>{`
        .laf-section {
          max-width: 1280px; margin: 0 auto; padding: 24px 24px 0;
        }
        .laf-head {
          display: flex; align-items: center; gap: 10px; margin-bottom: 14px;
          font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.18em;
          text-transform: uppercase; color: var(--ink-soft);
        }
        .laf-head-dot {
          display: inline-block; width: 8px; height: 8px; border-radius: 50%;
          background: oklch(0.50 0.16 250); animation: laf-pulse 1.6s infinite;
        }
        .laf-grid {
          display: grid;
          grid-template-columns: repeat(5, minmax(0, 1fr));
          gap: 12px;
        }
        @media (max-width: 1100px) { .laf-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
        @media (max-width: 760px)  { .laf-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
        @media (max-width: 480px)  { .laf-grid { grid-template-columns: 1fr; } }
        .laf-card {
          display: flex; flex-direction: column; align-items: stretch;
          background: var(--paper); border: 1px solid var(--rule); border-radius: 8px;
          padding: 0; overflow: hidden; cursor: pointer; text-align: left;
          transition: border-color 150ms, transform 150ms;
          position: relative;
        }
        .laf-card:hover {
          border-color: var(--ink-soft); transform: translateY(-1px);
        }
        .laf-card-bar {
          height: 3px; width: 100%;
        }
        .laf-card-body { padding: 12px 14px 14px; }
        .laf-card-meta {
          display: flex; gap: 8px; align-items: center; flex-wrap: wrap;
          font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.12em;
          text-transform: uppercase; color: var(--ink-soft); margin-bottom: 8px;
        }
        .laf-card-pill {
          padding: 2px 7px; border-radius: 3px; font-weight: 700;
          color: #fff; letter-spacing: 0.1em;
        }
        .laf-card-topic {
          font-family: var(--font-serif); font-size: 14px; line-height: 1.35;
          letter-spacing: -0.005em; color: var(--ink); margin: 0 0 10px;
          display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical;
          overflow: hidden;
        }
        .laf-card-foot {
          display: flex; justify-content: space-between; align-items: center;
          font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.1em;
          color: var(--ink-soft); text-transform: uppercase;
          margin-top: auto;
        }
        @keyframes laf-pulse {
          0%, 100% { opacity: 1; transform: scale(1); }
          50%      { opacity: 0.4; transform: scale(0.85); }
        }
      `}</style>
      <div className="laf-head">
        <span className="laf-head-dot" />
        Network conditions · {alerts.length} active signal{alerts.length === 1 ? "" : "s"}
        <span style={{ marginLeft: "auto", textTransform: "none", letterSpacing: "0.04em" }}>
          <a href="#/account" onClick={e => { e.preventDefault(); onNav("account"); }} style={{
            color: "var(--ink-soft)", textDecoration: "none", borderBottom: "1px solid var(--rule)",
            paddingBottom: 1,
          }}>
            Full read on the Clarity dashboard →
          </a>
        </span>
      </div>
      <div className="laf-grid">
        {alerts.map(a => {
          const sev = a.severity || "moderate";
          const color = sevColor[sev] || sevColor.moderate;
          return (
            <button
              type="button"
              key={a.id}
              className="laf-card"
              onClick={() => onNav("account")}
              title={a.topic}
            >
              <div className="laf-card-bar" style={{ background: color }} />
              <div className="laf-card-body" style={{ display: "flex", flexDirection: "column", height: "100%" }}>
                {/* No signal count and no carrier_slug — both leak the
                    operator-pull moat per two-tier disclosure rule. The
                    dashboard (authed users only) keeps the full attribution. */}
                <div className="laf-card-meta">
                  <span className="laf-card-pill" style={{ background: color }}>{sev.toUpperCase()}</span>
                </div>
                <h4 className="laf-card-topic">{a.topic}</h4>
                <div className="laf-card-foot">
                  <span>{a.city_id ? a.city_id : "Network"}</span>
                  <span>{ago(a.published_at)}</span>
                </div>
              </div>
            </button>
          );
        })}
      </div>
    </section>
  );
}

// =============================================================
// THREE-DOOR FRAME — every audience sees their own door above the
// fold. Shippers/brokers go to the Pulse signup. Drivers go to The
// Yard. Oil/finance go straight to the dashboard.
// =============================================================
function ThreeDoors({ onNav }) {
  const doors = [
    {
      id: "ship",
      icon: "📦",
      eyebrow: "Ship freight?",
      title: "See your carriers from the inside.",
      body: "Daily metro Pulse — terminal status, lane conditions, carrier reliability. Read it before freight starts moving.",
      cta: "Subscribe to a metro Pulse →",
      action: () => { document.getElementById("dash-pulse-signup")?.scrollIntoView({ behavior: "smooth", block: "start" }); },
      accent: "var(--red, oklch(0.50 0.16 250))",
    },
    {
      id: "drive",
      icon: "🛻",
      eyebrow: "Drive?",
      title: "Free tools the carriers won't show you.",
      body: "Find your dock, check the truck stops, read the trust contract. Submit a tip — sealed by default, deletable any time.",
      cta: "Open The Yard →",
      action: () => onNav("drivers"),
      accent: "oklch(0.50 0.18 145)",
    },
    {
      id: "watch",
      icon: "🛢",
      eyebrow: "Watch oil & finance?",
      title: "The market read others miss.",
      body: "Refinery utilization · crack spreads · state-by-state crude · per-carrier financial dirt · synthesized cross-source alerts.",
      cta: "See the dashboard →",
      action: () => onNav("account"),
      accent: "oklch(0.50 0.20 50)",
    },
  ];
  return (
    <section style={{
      maxWidth: 1200, margin: "32px auto 0", padding: "0 24px",
    }}>
      <style>{`
        .three-doors { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; }
        @media (max-width: 880px) { .three-doors { grid-template-columns: 1fr; } }
        .three-door {
          background: #fff; border: 1px solid var(--rule); border-radius: 10px;
          padding: 24px; cursor: pointer; transition: all 0.15s;
          display: flex; flex-direction: column;
          text-align: left; font-family: inherit; color: inherit;
          position: relative; overflow: hidden;
        }
        .three-door::before {
          content: ""; position: absolute; top: 0; left: 0; right: 0; height: 3px;
        }
        .three-door:hover { border-color: var(--ink); transform: translateY(-2px); }
        .td-icon { font-size: 28px; line-height: 1; margin-bottom: 12px; }
        .td-eyebrow {
          font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.18em;
          text-transform: uppercase; color: var(--ink-soft); margin-bottom: 6px;
        }
        .td-title {
          font-family: var(--font-serif); font-size: 21px; line-height: 1.25;
          letter-spacing: -0.015em; margin: 0 0 12px;
        }
        .td-body {
          color: var(--ink-soft); font-size: 14px; line-height: 1.55;
          margin: 0 0 18px; flex: 1;
        }
        .td-cta {
          font-family: var(--font-mono); font-size: 12px; letter-spacing: 0.1em;
          text-transform: uppercase; font-weight: 600;
        }
      `}</style>
      <div className="three-doors">
        {doors.map(d => (
          <button key={d.id} className="three-door" onClick={d.action}
                  style={{ ['--door-accent']: d.accent }}>
            <span style={{ position: "absolute", top: 0, left: 0, right: 0,
                           height: 3, background: d.accent }} />
            <div className="td-icon">{d.icon}</div>
            <div className="td-eyebrow">{d.eyebrow}</div>
            <h3 className="td-title">{d.title}</h3>
            <p className="td-body">{d.body}</p>
            <div className="td-cta" style={{ color: d.accent }}>{d.cta}</div>
          </button>
        ))}
      </div>
    </section>
  );
}

// =============================================================
// CONNECTION BOARD PREVIEW — homepage section that promotes the
// shippers-connect load board. For signed-in users we pull a few
// recent open loads (RLS-protected, so anon gets a teaser). Either
// way, two big CTAs: post a load, browse loads. This is the active
// shipper entrance — Pulse subscription is the passive one.
// =============================================================
function ConnectionBoardPreview({ onNav, user }) {
  const [loads, setLoads] = useStateH([]);
  const [loading, setLoading] = useStateH(!!user);

  useEffectH(() => {
    if (!user) return;
    let alive = true;
    (async () => {
      try {
        const rows = await window.SI_DB.raw.selectAuthed(
          "shipper_loads",
          "select=id,origin_city,origin_state,dest_city,dest_state,pickup_earliest,equipment_type,willing_to_share,total_pallets,rate_offered_usd&status=in.(open,matched)&order=created_at.desc&limit=4"
        );
        if (!alive) return;
        setLoads(Array.isArray(rows) ? rows : []);
      } catch {} finally { if (alive) setLoading(false); }
    })();
    return () => { alive = false; };
  }, [user]);

  const TEASERS = [
    { origin_city: "Los Angeles", origin_state: "CA", dest_city: "Phoenix", dest_state: "AZ",
      equipment_type: "dry_van", willing_to_share: true, total_pallets: 18,
      pickup_earliest: "2026-05-04T14:00:00Z" },
    { origin_city: "Chicago", origin_state: "IL", dest_city: "Atlanta", dest_state: "GA",
      equipment_type: "reefer", willing_to_share: false, total_pallets: 22,
      pickup_earliest: "2026-05-05T07:00:00Z" },
    { origin_city: "Dallas", origin_state: "TX", dest_city: "Memphis", dest_state: "TN",
      equipment_type: "flatbed", willing_to_share: true, total_pallets: 8,
      pickup_earliest: "2026-05-06T10:00:00Z" },
    { origin_city: "Newark", origin_state: "NJ", dest_city: "Charlotte", dest_state: "NC",
      equipment_type: "dry_van", willing_to_share: true, total_pallets: 14,
      pickup_earliest: "2026-05-04T18:00:00Z" },
  ];

  const display = (user && loads.length > 0) ? loads : TEASERS;
  const isLive = user && loads.length > 0;

  function fmtPickup(iso) {
    if (!iso) return "—";
    return new Date(iso).toLocaleString(undefined, {
      weekday: "short", month: "short", day: "numeric", hour: "numeric",
    });
  }
  function fmtEquip(t) {
    return ({
      dry_van: "Dry van", vented_van: "Vented van", insulated_van: "Insulated van",
      reefer: "Reefer · frozen", reefer_fresh: "Reefer · fresh", reefer_temp: "Reefer · temp",
      flatbed: "Flatbed", step_deck: "Step deck", rgn: "RGN",
      conestoga: "Conestoga", tanker: "Tanker",
      oversized: "Oversized", partial: "Partial / LTL", box_truck: "Box truck",
    })[t] || t;
  }

  return (
    <section style={{
      maxWidth: 1200, margin: "48px auto 0", padding: "0 24px",
    }}>
      <style>{`
        .cbp-wrap {
          background: #fff; border: 1px solid var(--rule); border-radius: 12px;
          padding: 32px; position: relative; overflow: hidden;
        }
        .cbp-wrap::before {
          content: ""; position: absolute; top: 0; left: 0; right: 0; height: 4px;
          background: linear-gradient(90deg, oklch(0.50 0.18 250), oklch(0.50 0.18 145));
        }
        .cbp-head {
          display: grid; grid-template-columns: 1.2fr 1fr; gap: 32px; align-items: end;
          margin-bottom: 24px;
        }
        @media (max-width: 800px) { .cbp-head { grid-template-columns: 1fr; gap: 20px; } }
        .cbp-eyebrow {
          font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.32em;
          text-transform: uppercase; color: var(--ink-soft); margin-bottom: 12px;
          display: inline-flex; align-items: center; gap: 10px;
        }
        .cbp-eyebrow .dot {
          display: inline-block; width: 8px; height: 8px; border-radius: 50%;
          background: oklch(0.55 0.20 145); animation: cbp-pulse 2.4s infinite;
        }
        @keyframes cbp-pulse {
          0%, 100% { opacity: 1; }
          50% { opacity: 0.4; }
        }
        .cbp-h {
          font-family: var(--font-serif); font-size: 38px; line-height: 1.05;
          letter-spacing: -0.025em; margin: 0 0 12px;
        }
        .cbp-h em { font-style: italic; color: oklch(0.50 0.18 250); }
        @media (max-width: 700px) { .cbp-h { font-size: 28px; } }
        .cbp-dek { font-size: 15px; line-height: 1.6; color: var(--ink-soft); margin: 0; }
        .cbp-ctas { display: flex; flex-direction: column; gap: 10px; }
        .cbp-cta {
          font-family: inherit; font-size: 15px; padding: 14px 22px;
          border-radius: 6px; cursor: pointer; font-weight: 600;
          text-align: center; border: 1px solid var(--ink);
        }
        .cbp-cta-primary { background: var(--ink); color: #fff; }
        .cbp-cta-primary:hover { opacity: 0.9; }
        .cbp-cta-ghost { background: #fff; color: var(--ink); }
        .cbp-cta-ghost:hover { background: var(--ink); color: #fff; }

        .cbp-grid {
          display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px;
        }
        @media (max-width: 1000px) { .cbp-grid { grid-template-columns: repeat(2, 1fr); } }
        @media (max-width: 600px)  { .cbp-grid { grid-template-columns: 1fr; } }
        .cbp-card {
          background: var(--paper-2); border: 1px solid var(--rule); border-radius: 8px;
          padding: 16px; transition: all 0.15s; cursor: pointer;
          display: flex; flex-direction: column; gap: 10px; min-height: 140px;
        }
        .cbp-card:hover { border-color: var(--ink); transform: translateY(-2px); }
        .cbp-card-route {
          font-family: var(--font-serif); font-size: 16px; letter-spacing: -0.01em;
          line-height: 1.3;
        }
        .cbp-card-arrow { color: var(--ink-soft); margin: 0 6px; }
        .cbp-card-when {
          font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.06em;
          color: var(--ink-soft);
        }
        .cbp-card-tags {
          display: flex; flex-wrap: wrap; gap: 6px; margin-top: auto;
        }
        .cbp-tag {
          font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.06em;
          padding: 3px 8px; border-radius: 3px; text-transform: uppercase;
        }
        .cbp-tag-equip { background: var(--ink); color: #fff; font-weight: 700; }
        .cbp-tag-share {
          background: oklch(0.94 0.06 145); color: oklch(0.36 0.14 145);
          border: 1px solid oklch(0.85 0.08 145);
        }
        .cbp-tag-pal {
          background: var(--paper); color: var(--ink-soft); border: 1px solid var(--rule);
        }
        .cbp-foot {
          margin-top: 18px; padding-top: 16px; border-top: 1px dashed var(--rule);
          display: flex; justify-content: space-between; align-items: center;
          flex-wrap: wrap; gap: 12px;
        }
        .cbp-foot-note {
          font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.14em;
          text-transform: uppercase; color: var(--ink-soft);
        }
        .cbp-foot-link {
          font-family: inherit; font-size: 14px; color: var(--ink); font-weight: 600;
          background: transparent; border: 0; cursor: pointer; padding: 0;
        }
        .cbp-foot-link:hover { text-decoration: underline; }
      `}</style>

      <div className="cbp-wrap">
        <div className="cbp-head">
          <div>
            <div className="cbp-eyebrow"><span className="dot" /> Connection Board · Live</div>
            <h2 className="cbp-h">Post a load. Find a <em>partner.</em></h2>
            <p className="cbp-dek">
              Shippers heading the same way split the truck. Carriers see the
              open board and pick a run that matches their next available
              trailer. Email the load owner directly — no broker in the middle,
              no commission on a handshake.
            </p>
          </div>
          <div className="cbp-ctas">
            <button className="cbp-cta cbp-cta-primary"
                    onClick={() => onNav(user ? "load-board" : "signin")}>
              {user ? "＋ Post a load" : "Sign in to post a load"}
            </button>
            <button className="cbp-cta cbp-cta-ghost"
                    onClick={() => onNav(user ? "load-board" : "signin")}>
              {user ? "📋 Browse the board →" : "Sign in to view the board →"}
            </button>
          </div>
        </div>

        <div className="cbp-grid" style={{ position: "relative" }}>
          {display.map((l, idx) => (
            <button key={l.id || idx} className="cbp-card"
                    onClick={() => onNav(user ? "load-board" : "signin")}
                    style={!user ? { filter: "blur(2.5px)", opacity: 0.7, pointerEvents: "none" } : {}}>
              <div className="cbp-card-route">
                {l.origin_city}, {l.origin_state}
                <span className="cbp-card-arrow">→</span>
                {l.dest_city}, {l.dest_state}
              </div>
              <div className="cbp-card-when">Pickup {fmtPickup(l.pickup_earliest)}</div>
              <div className="cbp-card-tags">
                <span className="cbp-tag cbp-tag-equip">{fmtEquip(l.equipment_type)}</span>
                {l.willing_to_share && <span className="cbp-tag cbp-tag-share">Open to share</span>}
                {l.total_pallets != null && <span className="cbp-tag cbp-tag-pal">{l.total_pallets} pal</span>}
              </div>
            </button>
          ))}
          {!user && (
            <div style={{
              position: "absolute", inset: 0, display: "flex",
              alignItems: "center", justifyContent: "center", pointerEvents: "auto",
            }}>
              <button onClick={() => onNav("signin")}
                      style={{
                        background: "var(--ink)", color: "#fff",
                        border: "1px solid var(--ink)", borderRadius: 6,
                        padding: "12px 20px", fontFamily: "inherit",
                        fontSize: 14, fontWeight: 600, cursor: "pointer",
                        boxShadow: "0 4px 12px rgba(0,0,0,0.18)",
                      }}>
                🔒 Sign in to view live loads
              </button>
            </div>
          )}
        </div>

        <div className="cbp-foot">
          <span className="cbp-foot-note">
            {isLive
              ? `Showing the 4 most recent open loads · live from the board`
              : (user
                  ? `No open loads on the board right now — yours could be the first.`
                  : `The Connection Board is for signed-in users · sample lanes shown above`)}
          </span>
          <button className="cbp-foot-link" onClick={() => onNav(user ? "load-board" : "signin")}>
            {user ? "Open Connection Board →" : "Sign in →"}
          </button>
        </div>
      </div>
    </section>
  );
}

// =============================================================
// HUB GROUP PROOF BLOCK — credibility anchor. The synthesizer caught
// Hub Group's financial distress on Apr 28, 2026 (delisting + late
// 10-K + Item 4.02 restatement) before mainstream trade press picked
// it up. Permanent feature on the home page.
// =============================================================
function HubGroupProof({ onNav }) {
  return (
    <section className="hgp-section" style={{
      maxWidth: 1200, margin: "48px auto 0", padding: "32px 24px",
      background: "linear-gradient(180deg, oklch(0.98 0.01 250) 0%, oklch(0.99 0.005 250) 100%)",
      border: "1px solid var(--rule)", borderRadius: 10, position: "relative",
    }}>
      <div style={{
        position: "absolute", top: 0, left: 0, right: 0, height: 3,
        background: "linear-gradient(90deg, oklch(0.50 0.18 250), oklch(0.50 0.18 145))",
        borderRadius: "10px 10px 0 0",
      }} />
      <div style={{
        fontFamily: "var(--font-mono)", fontSize: 11, letterSpacing: "0.18em",
        textTransform: "uppercase", color: "var(--ink-soft)", marginBottom: 14,
        display: "inline-flex", alignItems: "center", gap: 8,
      }}>
        <span style={{
          display: "inline-block", width: 8, height: 8, borderRadius: "50%",
          background: "oklch(0.50 0.18 250)",
        }} />
        Real-time market intelligence
      </div>
      <h2 style={{
        fontFamily: "var(--font-serif)", fontSize: 30, letterSpacing: "-0.02em",
        lineHeight: 1.2, margin: "0 0 16px", maxWidth: 820,
      }}>
        Distress signals, <em style={{ color: "oklch(0.50 0.18 250)" }}>caught early.</em>
      </h2>
      <p style={{
        fontSize: 15, lineHeight: 1.6, color: "var(--ink)", margin: "0 0 20px",
        maxWidth: 820,
      }}>
        Our system reads SEC filings, court dockets, and operational data side by
        side — the kind of cross-source synthesis that takes a research team
        weeks to assemble manually. When a carrier&rsquo;s financial picture
        starts to wobble, we tend to see it before it shows up in trade press,
        and well before it disrupts a shipper&rsquo;s freight.
      </p>
      <div style={{
        display: "grid", gridTemplateColumns: "repeat(3, 1fr)", gap: 14,
        marginBottom: 22,
      }}>
        {[
          ["SEC EDGAR",       "8-K, NT 10-K, Item 4.02 restatements, Item 3.01 listing notices"],
          ["Court dockets",   "Chapter 11 filings, lien notices, judgment liens via CourtListener"],
          ["Operational data","Port flows, lane disruption signals, fuel + weather context"],
        ].map(([d, t]) => (
          <div key={d} className="hgp-card" style={{
            background: "#fff", border: "1px solid var(--rule)",
            borderRadius: 6, padding: "12px 14px",
          }}>
            <div style={{
              fontFamily: "var(--font-mono)", fontSize: 10,
              letterSpacing: "0.14em", textTransform: "uppercase",
              color: "oklch(0.40 0.16 250)", marginBottom: 4,
            }}>
              {d}
            </div>
            <div style={{ fontSize: 13, lineHeight: 1.4, color: "var(--ink)" }}>
              {t}
            </div>
          </div>
        ))}
      </div>
      <p style={{
        fontSize: 13, color: "var(--ink-soft)", lineHeight: 1.55,
        margin: "0 0 20px", maxWidth: 820, fontStyle: "italic",
      }}>
        Every input is a public record. The work is the synthesis — connecting
        signals across the three streams above so a shipper sees the picture
        before it&rsquo;s too late to route around it.
      </p>
      <div style={{ display: "flex", gap: 12, flexWrap: "wrap" }}>
        <button className="btn-primary-lg" onClick={() => onNav("risk-report")}>
          Order a Carrier Risk Report — $499 →
        </button>
        <button className="btn-ghost-lg" onClick={() => {
          window.location.hash = '#/insights';
        }}>
          Read the market analysis
        </button>
      </div>
    </section>
  );
}

// =============================================================
// CARRIER DEEP-DIVE SEARCH — the conversion surface. Sits directly
// after HubGroupProof to ride the credibility moment: "we caught
// Hub Group three weeks early → run this on the carrier you book."
// Search matches against tracked carriers + investigated names;
// fallback works for any typed string (we'll run on any active
// US carrier with a USDOT). Order CTA is a mailto with the
// carrier name pre-filled into hello@shippingclarity.com.
// =============================================================
function CarrierDeepDiveSearch() {
  const [query, setQuery] = useStateH("");
  const [focused, setFocused] = useStateH(false);
  const [picked, setPicked] = useStateH(null);

  const carriers = useMemoH(() => {
    const out = [];
    const seen = new Set();
    const la = (window.SI_DATA && window.SI_DATA.LA_REPORT && window.SI_DATA.LA_REPORT.carriers) || {};
    const labels = { small: "Small Package", ltl: "LTL Freight", ftl: "Truckload", courier: "Last-Mile", intl: "International" };
    for (const cat of Object.keys(la)) {
      for (const c of la[cat]) {
        if (seen.has(c.id)) continue;
        seen.add(c.id);
        out.push({ id: c.id, name: c.name, category: labels[cat] || cat, tracked: true });
      }
    }
    // Investigated and well-known carriers we surface even if
    // they don't appear in the LA category grid.
    const extras = [
      { id: "hub-group", name: "Hub Group", category: "Intermodal · Investigated", tracked: true,
        articleSlug: "hub-group-distress-three-weeks-early-2026" },
      { id: "ffe", name: "FFE Transportation Services", category: "Refrigerated LTL · Investigated", tracked: true,
        articleSlug: "ffe-discipline-in-refrigerated-2026" },
      { id: "ups-investigation", name: "UPS · 51 facility closures", category: "Small Package · Investigated", tracked: true,
        articleSlug: "when-a-ups-hub-goes-dark-2026" },
      { id: "ch-robinson", name: "C.H. Robinson", category: "Brokerage", tracked: false },
      { id: "yellow", name: "Yellow Corp", category: "LTL · Defunct 2023", tracked: false },
      { id: "kal-freight", name: "Kal Freight", category: "Refrigerated · Defunct 2025", tracked: false },
      { id: "rxo", name: "RXO", category: "Brokerage", tracked: false },
      { id: "landstar", name: "Landstar System", category: "Truckload", tracked: false },
      { id: "stg-logistics", name: "STG Logistics", category: "Intermodal", tracked: false },
    ];
    for (const e of extras) {
      if (seen.has(e.id)) continue;
      seen.add(e.id);
      out.push(e);
    }
    return out;
  }, []);

  const matches = useMemoH(() => {
    const q = query.trim().toLowerCase();
    if (!q) return [];
    return carriers.filter(c => c.name.toLowerCase().includes(q)).slice(0, 6);
  }, [query, carriers]);

  // What we'll pre-fill in the order email: explicit pick, else first match,
  // else just the typed string (any US carrier with a USDOT works).
  const target = picked
    || matches[0]
    || (query.trim() ? { id: null, name: query.trim(), tracked: false } : null);

  function orderHref(carrier) {
    const name = carrier ? carrier.name : "";
    const subj = encodeURIComponent("Deep-dive report request" + (name ? ` · ${name}` : ""));
    const body = encodeURIComponent(
      `Carrier name: ${name}\r\n\r\n` +
      `Your name:\r\n\r\n` +
      `Best email:\r\n\r\n` +
      `Carrier USDOT or MC (if known):\r\n\r\n` +
      `Anything specific you want us to dig into:\r\n\r\n` +
      `(We deliver the 10-page PDF inside 24 hours of payment. Reply with how you'd like to pay.)\r\n`
    );
    return `mailto:hello@shippingclarity.com?subject=${subj}&body=${body}`;
  }

  // Show preview when user has explicitly picked, or typed a name we don't
  // recognize (zero matches). While they're still typing into a recognized
  // carrier, the dropdown is enough — don't double up the surface.
  const showPreview = picked || (query.trim() && matches.length === 0);

  return (
    <section className="cdds-section">
      <div className="cdds-inner">
        <div className="cdds-eyebrow">
          <span className="cdds-eyebrow-dot" />
          On-demand · Any US carrier with a USDOT · 24-hour turnaround
        </div>
        <h2 className="cdds-title">
          Want this kind of read on the carrier <em>you</em> book?
        </h2>
        <p className="cdds-sub">
          Per-carrier deep-dive: Z-Score history, full SEC filing scan, court-record creditor pattern,
          FMCSA inspection trail, BBB, driver-network chatter — assembled into a 10-page PDF inside
          24 hours. <strong>$500 per carrier.</strong> The on-demand alternative to the subscription-only
          ratings reports the freight industry has run on for thirty years.
        </p>

        <div className="hero-search-wrap" style={{ maxWidth: 720, marginTop: 8 }}>
          <div className={`hero-search ${focused ? "focused" : ""}`}>
            <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" style={{ flexShrink: 0, color: "var(--ink-soft)" }}>
              <circle cx="11" cy="11" r="7" /><path d="m20 20-3.5-3.5" />
            </svg>
            <input
              type="text"
              placeholder="Type a carrier name (e.g., Hub Group, FFE, Knight-Swift)"
              value={query}
              onChange={(e) => { setQuery(e.target.value); setPicked(null); }}
              onFocus={() => setFocused(true)}
              onBlur={() => setTimeout(() => setFocused(false), 180)}
              className="hero-search-input"
            />
            <a
              className="hero-search-btn cdds-order-btn"
              href={orderHref(target)}
              onClick={(e) => { if (!target) { e.preventDefault(); } }}
              style={!target ? { opacity: 0.5, pointerEvents: "none" } : undefined}
            >Order · $500 →</a>
          </div>
          {focused && matches.length > 0 && (
            <div className="search-dropdown">
              {matches.map(m => (
                <button
                  key={m.id || m.name}
                  className="search-result"
                  onMouseDown={() => { setPicked(m); setQuery(m.name); }}
                >
                  <span className="search-result-name">{m.name}</span>
                  <span className="search-result-meta">{m.category}{m.tracked ? " · tracked" : ""}</span>
                </button>
              ))}
            </div>
          )}
        </div>

        {showPreview && target && (
          <div className="cdds-preview">
            {target.tracked && target.articleSlug ? (
              <>
                We've already published an investigation on <strong>{target.name}</strong>.{" "}
                <a href={`#/insights/${target.articleSlug}`} className="cdds-link">
                  Read it →
                </a>{" "}
                The deep-dive layers full court records, inspection-by-inspection FMCSA history, and
                Z-Score modeling on top.
              </>
            ) : target.tracked ? (
              <>
                <strong>{target.name}</strong> is in our public profile graph. Your deep-dive will
                pull every public source we run — SEC, FMCSA, CourtListener, BBB, driver-network
                chatter — assembled into a single PDF.
              </>
            ) : (
              <>
                We don't have a public profile on <strong>{target.name}</strong> yet — but the
                deep-dive runs on any active US carrier with a USDOT number. Order and we'll have
                the PDF back in your inbox inside 24 hours.
              </>
            )}
          </div>
        )}

        <div className="cdds-foot">
          <span>One report · $500 · PDF in 24 hours · No subscription required.</span>
          <span className="cdds-foot-sep">·</span>
          <a className="cdds-link" href="#/members?for=shippers">
            Or get the daily Pulse →
          </a>
        </div>
      </div>
    </section>
  );
}

// =============================================================
// FEATURED INVESTIGATIONS — two-card grid surfacing the major
// public-records investigations on the home page above the fold.
// Replaces the LiveRadar slot we cleared earlier (LiveRadar
// duplicated the BigRadar / TonightsPulse / LiveReceipts story).
// Each card carries dek + 3 punchy stats + click-through to the
// full article. Hand-curated list — add new investigations here
// as they publish.
// =============================================================
function FeaturedInvestigations() {
  const articles = [
    {
      slug: "hub-group-distress-three-weeks-early-2026",
      tag: "Hub Group · Investigation",
      title: "Thirteen Chapter 11s at Hub Group's door",
      dek: "$77 million of payables to underlying carriers, understated. Internal controls, admitted ineffective. Thirteen customers in Chapter 11 since March 2024. A covenant waiver. A Nasdaq deficiency notice.",
      stats: [
        ["$77M", "Payables understated · Q1-Q3 2025"],
        ["13", "Customer Ch.11s · since March 2024"],
        ["−20%", "Stock drop on the day"],
      ],
      accent: "oklch(0.50 0.22 25)",
    },
    {
      slug: "when-a-ups-hub-goes-dark-2026",
      tag: "UPS · Investigation",
      title: "When a UPS hub goes dark",
      dek: "Fifty-one permanent UPS facility closures announced for 2026. An unspecified number of temporary remodels. The Worldport plane crash that took the largest UPS air hub offline for three days. UPS does not email its shippers when a hub goes dark.",
      stats: [
        ["51", "Permanent closures · 2026"],
        ["30,000", "Workforce reduction · 2026"],
        ["Nov 5 2025", "Worldport plane crash"],
      ],
      accent: "oklch(0.50 0.16 50)",
    },
    {
      slug: "ffe-discipline-in-refrigerated-2026",
      tag: "FFE · Profile",
      title: "Refrigerated trucking is in distress. FFE is not.",
      dek: "Kal Freight took down with fraud allegations and liquidated. Reefer capacity contracted. Rates moved. FFE — the largest refrigerated LTL carrier in the U.S. — kept its trucks moving. The federal data explains how.",
      stats: [
        ["0", "Fatal crashes · 24 mo · 829 PU"],
        ["0.71%", "Driver OOS · vs 6.67% national"],
        ["14.35%", "Vehicle OOS · vs 22.26% national"],
      ],
      accent: "oklch(0.55 0.16 165)",
    },
  ];

  return (
    <section style={{
      maxWidth: 1200, margin: "48px auto 0", padding: "0 24px",
    }}>
      <style>{`
        .fi-head {
          display: flex; align-items: baseline; justify-content: space-between;
          padding-bottom: 14px; border-bottom: 1px solid var(--rule);
          margin-bottom: 22px; gap: 24px; flex-wrap: wrap;
        }
        .fi-eyebrow {
          font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.18em;
          text-transform: uppercase; color: var(--ink-soft); margin-bottom: 4px;
        }
        .fi-h2 {
          font-family: var(--font-serif); font-size: 26px; line-height: 1.2;
          letter-spacing: -0.02em; margin: 0; max-width: 700px;
        }
        .fi-h2 em { color: oklch(0.50 0.22 25); font-style: italic; }
        .fi-all {
          font-family: var(--font-mono); font-size: 12px; letter-spacing: 0.1em;
          text-transform: uppercase; color: var(--ink); background: transparent;
          border: 1px solid var(--rule); padding: 9px 16px; border-radius: 6px;
          cursor: pointer; transition: all 0.12s; flex-shrink: 0; align-self: center;
        }
        .fi-all:hover { background: var(--ink); color: var(--paper); border-color: var(--ink); }
        .fi-grid {
          display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px;
        }
        @media (max-width: 1100px) { .fi-grid { grid-template-columns: 1fr 1fr; } }
        @media (max-width: 720px)  { .fi-grid { grid-template-columns: 1fr; } }
        .fi-card {
          background: #fff; border: 1px solid var(--rule);
          border-radius: 10px; padding: 24px; cursor: pointer;
          text-align: left; font-family: inherit; color: inherit;
          position: relative; overflow: hidden; transition: all 0.15s;
          display: flex; flex-direction: column;
        }
        .fi-card:hover { border-color: var(--ink); transform: translateY(-2px);
          box-shadow: 0 4px 16px rgba(0,0,0,0.08); }
        .fi-card-stripe {
          position: absolute; top: 0; left: 0; right: 0; height: 3px;
        }
        .fi-tag {
          font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.18em;
          text-transform: uppercase; color: var(--ink-soft); margin-bottom: 12px;
          margin-top: 4px;
        }
        .fi-title {
          font-family: var(--font-serif); font-size: 22px; line-height: 1.25;
          letter-spacing: -0.018em; margin: 0 0 12px; color: var(--ink);
        }
        .fi-dek {
          font-size: 14px; line-height: 1.55; color: var(--ink-soft);
          margin: 0 0 18px; flex: 1;
        }
        .fi-stats {
          display: grid; grid-template-columns: repeat(3, 1fr);
          gap: 12px; padding: 14px 0; margin-bottom: 14px;
          border-top: 1px solid var(--rule-soft);
          border-bottom: 1px solid var(--rule-soft);
        }
        .fi-stat-v {
          font-family: var(--font-serif); font-size: 18px; font-weight: 600;
          letter-spacing: -0.01em; line-height: 1.1; color: var(--ink);
          margin-bottom: 3px;
        }
        .fi-stat-l {
          font-size: 11px; line-height: 1.35; color: var(--ink-soft);
        }
        .fi-cta {
          font-family: var(--font-mono); font-size: 12px; letter-spacing: 0.1em;
          text-transform: uppercase; font-weight: 600; color: var(--ink);
        }
      `}</style>
      <div className="fi-head">
        <div>
          <div className="fi-eyebrow">Investigations</div>
          <h2 className="fi-h2">
            Public-records reporting on the carriers <em>in your network.</em>
          </h2>
        </div>
        <button className="fi-all"
                onClick={() => { window.location.hash = '#/insights'; }}>
          All investigations →
        </button>
      </div>
      <div className="fi-grid">
        {articles.map(a => (
          <button key={a.slug} className="fi-card"
                  onClick={() => { window.location.hash = `#/insights/${a.slug}`; }}>
            <span className="fi-card-stripe" style={{ background: a.accent }} />
            <div className="fi-tag" style={{ color: a.accent }}>{a.tag}</div>
            <h3 className="fi-title">{a.title}</h3>
            <p className="fi-dek">{a.dek}</p>
            <div className="fi-stats">
              {a.stats.map(([v, l], i) => (
                <div key={i}>
                  <div className="fi-stat-v">{v}</div>
                  <div className="fi-stat-l">{l}</div>
                </div>
              ))}
            </div>
            <div className="fi-cta" style={{ color: a.accent }}>
              Read investigation →
            </div>
          </button>
        ))}
      </div>
    </section>
  );
}

// =============================================================
// LIVE RECEIPTS — public-readable counts pulled from anon RLS
// tables. Each tile is a "we know this right now" card. Renders
// a tile only when there's something concrete to show.
// =============================================================
function LiveReceipts({ onNav }) {
  const [data, setData] = useStateH(null);

  useEffectH(() => {
    let alive = true;
    if (!window.SI_DB || !window.SI_DB.raw) return;
    (async () => {
      const since24h = new Date(Date.now() - 24*3600*1000).toISOString();
      const [
        chpCount, chpCollisions, chpHazards,
        topFire, fireCount,
        metars,
        receiverCount,
        fuel,
      ] = await Promise.all([
        window.SI_DB.raw.count("chp_incidents", `last_seen_at=gte.${since24h}`).catch(() => null),
        window.SI_DB.raw.count("chp_incidents", `last_seen_at=gte.${since24h}&category=eq.collision`).catch(() => null),
        window.SI_DB.raw.count("chp_incidents", `last_seen_at=gte.${since24h}&category=eq.hazard`).catch(() => null),
        window.SI_DB.raw.select("wildfires",
          "select=name,acres,pct_contained,state&status=neq.Out&order=acres.desc&limit=1"
        ).catch(() => []),
        window.SI_DB.raw.count("wildfires", "status=neq.Out&acres=gte.500").catch(() => null),
        window.SI_DB.raw.select("airport_weather",
          "select=icao_id,flight_cat,visibility,station_name&order=observed_at.desc&limit=20"
        ).catch(() => []),
        window.SI_DB.raw.count("receiver_locations", "").catch(() => null),
        window.SI_DB.raw.select("fuel_signals",
          "select=series,value_num&series=in.(diesel_retail_us,ulsd_diesel_futures)&order=period.desc"
        ).catch(() => []),
      ]);
      if (!alive) return;
      const retailUS = (fuel || []).find(f => f.series === "diesel_retail_us");
      const ulsd     = (fuel || []).find(f => f.series === "ulsd_diesel_futures");
      const pumpGap  = (retailUS && ulsd)
        ? parseFloat(retailUS.value_num) - (parseFloat(ulsd.value_num) + 1.10)
        : null;
      setData({
        chpCount, chpCollisions, chpHazards,
        topFire: (topFire && topFire[0]) || null,
        fireCount,
        metars: metars || [],
        receiverCount,
        retailUS: retailUS ? parseFloat(retailUS.value_num) : null,
        pumpGap,
      });
    })();
    return () => { alive = false; };
  }, []);

  if (!data) return null;

  // Build tiles. Each tile is { key, emoji, num, label, sub, onClick? }
  const tiles = [];

  if (data.chpCount && data.chpCount > 0) {
    tiles.push({
      key: "chp",
      emoji: "🛣",
      num: data.chpCount.toLocaleString(),
      label: "California live now",
      // Drop "CHP feed" attribution — name of the dataset is moat-adjacent.
      // The number itself + "California live now" frame is the value.
      sub: `${data.chpCollisions || 0} collisions · ${data.chpHazards || 0} hazards reported · across CA freeways`,
      cta: "Operational dashboard",
    });
  }

  if (data.topFire && Number(data.topFire.acres) >= 1000) {
    const ac = Number(data.topFire.acres);
    const acStr = ac >= 1000 ? `${(ac/1000).toFixed(ac >= 10000 ? 0 : 1)}K` : Math.round(ac).toLocaleString();
    const fireState = (data.topFire.state || "").replace(/^US-/, "");
    tiles.push({
      key: "fire",
      emoji: "🔥",
      num: `${acStr} ac`,
      // NIFC fire names are typically ALL CAPS — smartCase normalizes
      // ("PARK FIRE" → "Park Fire") without breaking already-cased names.
      label: smartCase(data.topFire.name) || "Largest active fire",
      // joinClean drops empty fields so we never get a leading " · " when
      // state is null or pct_contained is missing.
      sub: joinClean([
        fireState,
        data.topFire.pct_contained != null ? `${data.topFire.pct_contained}% contained` : null,
        `${data.fireCount || 0} fires ≥500 ac`,
      ]),
      cta: "Wildfire watch",
    });
  } else if (data.fireCount && data.fireCount > 0) {
    tiles.push({
      key: "fire",
      emoji: "🔥",
      num: data.fireCount.toLocaleString(),
      label: "Active wildfires ≥500 acres",
      sub: "burning across the lower 48",
      cta: "Wildfire watch",
    });
  }

  // Air cargo: surface degraded conditions if any, else "all hubs VFR".
  const degraded = (data.metars || []).filter(m => m.flight_cat && m.flight_cat !== "VFR");
  if (degraded.length > 0) {
    const worst = ["LIFR", "IFR", "MVFR"].map(c => degraded.find(m => m.flight_cat === c)).find(Boolean);
    tiles.push({
      key: "metar",
      emoji: "✈️",
      num: worst.flight_cat,
      label: (worst.station_name || worst.icao_id || "").split("·")[0].trim(),
      sub: `${degraded.length} of ${(data.metars || []).length} hubs flying degraded · live conditions`,
      cta: "Air cargo dashboard",
    });
  } else if ((data.metars || []).length > 0) {
    tiles.push({
      key: "metar",
      emoji: "✈️",
      num: `${(data.metars || []).length} VFR`,
      label: "Air cargo hubs clear",
      sub: "all hubs flying VFR · live conditions",
      cta: "Air cargo dashboard",
    });
  }

  if (data.pumpGap != null && data.retailUS != null) {
    const sign = data.pumpGap >= 0 ? "+" : "";
    tiles.push({
      key: "fuel",
      emoji: "🛢",
      num: `${sign}$${data.pumpGap.toFixed(2)}`,
      label: "Diesel pump-vs-futures gap",
      sub: `US retail $${data.retailUS.toFixed(2)} · ULSD futures + $1.10/gal benchmark`,
      cta: "Fuel & oil dashboard",
    });
  }

  if (data.receiverCount && data.receiverCount > 1000) {
    tiles.push({
      key: "receivers",
      emoji: "📦",
      num: data.receiverCount.toLocaleString(),
      label: "Delivery docks mapped",
      sub: "Walmart · Home Depot · Lowe's · Walgreens · CVS · Dollar General · 23 more",
      cta: "Find your dock",
    });
  }

  if (tiles.length === 0) return null;

  // Each tile drops the visitor at its specific dashboard section. The
  // dashboard has two tabs ("now" / "carriers") — air-cargo lives under
  // "carriers" so we route there explicitly. AccountPage reads
  // sc.scrollAnchor after data loads and scrolls once. Receivers has
  // its own page, no anchor needed.
  const TILE_NAV = {
    chp:       { hash: "#/account",          anchor: "dash-chp-california" },
    fire:      { hash: "#/account",          anchor: "dash-wildfires" },
    metar:     { hash: "#/account/carriers", anchor: "dash-air-cargo" },
    fuel:      { hash: "#/account",          anchor: "dash-markets" },
    receivers: { hash: "#/receivers",        anchor: null },
  };
  function tileNav(key) {
    const cfg = TILE_NAV[key] || TILE_NAV.chp;
    if (cfg.anchor) {
      try { sessionStorage.setItem("sc.scrollAnchor", cfg.anchor); } catch {}
    }
    if (window.location.hash === cfg.hash) {
      // already there — fire the scroll directly
      window.dispatchEvent(new HashChangeEvent("hashchange"));
    } else {
      window.location.hash = cfg.hash;
    }
  }

  return (
    <section style={{ maxWidth: 1200, margin: "32px auto 0", padding: "0 24px" }}>
      <style>{`
        .lr-head { display: flex; align-items: baseline; justify-content: space-between;
          padding-bottom: 14px; border-bottom: 1px solid var(--rule); margin-bottom: 18px; }
        .lr-eyebrow { font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.18em;
          text-transform: uppercase; color: var(--ink-soft); display: inline-flex;
          align-items: center; gap: 8px; }
        .lr-eyebrow .pulse-dot {
          display: inline-block; width: 8px; height: 8px; border-radius: 50%;
          background: oklch(0.55 0.18 145); animation: lr-pulse 2s ease-in-out infinite;
        }
        @keyframes lr-pulse {
          0%, 100% { opacity: 1; transform: scale(1); }
          50% { opacity: 0.55; transform: scale(0.8); }
        }
        .lr-title { font-family: var(--font-serif); font-size: 26px; letter-spacing: -0.02em;
          margin: 0; }
        .lr-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
          gap: 14px; }
        .lr-tile { background: #fff; border: 1px solid var(--rule); border-radius: 8px;
          padding: 18px 20px; cursor: pointer; transition: all 0.15s; text-align: left;
          display: flex; flex-direction: column; gap: 4px; min-height: 142px; position: relative; }
        .lr-tile:hover { border-color: var(--ink); transform: translateY(-2px);
          box-shadow: 0 6px 22px -10px rgba(0,0,0,0.18); }
        .lr-tile-emoji { font-size: 22px; line-height: 1; margin-bottom: 4px; }
        .lr-tile-num { font-family: var(--font-serif); font-size: 26px; letter-spacing: -0.02em;
          margin: 0; line-height: 1.1; }
        .lr-tile-label { font-size: 13px; color: var(--ink); font-weight: 500;
          margin-top: 2px; }
        .lr-tile-sub { font-size: 11px; color: var(--ink-soft); line-height: 1.45;
          margin-top: 4px; flex: 1; }
        .lr-tile-cta { font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.14em;
          text-transform: uppercase; color: var(--ink-soft); margin-top: 8px;
          border-top: 1px solid var(--rule); padding-top: 8px; }
        .lr-foot { font-size: 11px; color: var(--ink-soft); line-height: 1.5;
          margin-top: 14px; font-style: italic; }
      `}</style>
      <div className="lr-head">
        <div>
          <div className="lr-eyebrow"><span className="pulse-dot" />What we're tracking right now</div>
          <h2 className="lr-title">Live receipts.</h2>
        </div>
        <div className="lr-eyebrow" style={{ display: window.innerWidth > 600 ? "inline-flex" : "none" }}>
          Updated every cron tick · public sources only
        </div>
      </div>
      <div className="lr-grid">
        {tiles.map(t => (
          <button key={t.key} className="lr-tile"
                  onClick={() => tileNav(t.key)}>
            <span className="lr-tile-emoji">{t.emoji}</span>
            <div className="lr-tile-num">{t.num}</div>
            <div className="lr-tile-label">{t.label}</div>
            <div className="lr-tile-sub">{t.sub}</div>
            <div className="lr-tile-cta">{t.cta} →</div>
          </button>
        ))}
      </div>
      <p className="lr-foot">
        Real-time public records, stitched into one read. Updated every cron tick.
      </p>
    </section>
  );
}

// =============================================================
// HERO STAT STRIP — four live numbers from anon-readable tables.
// Brand-aligned, OPAQUE labels: never reference the source
// mechanism (no "posts analyzed", no "forums", no platform names).
// Numbers fall back to current-state defaults so the strip never
// reads as "0 / 0 / 0" while the queries resolve.
// =============================================================

function HeroStatStrip() {
  const [stats, setStats] = useStateH({
    metros: 22, carriers: 31, refineries: 30, signals: null,
  });

  useEffectH(() => {
    let alive = true;
    if (!window.SI_DB || !window.SI_DB.raw || !window.SI_DB.raw.count) return;
    (async () => {
      const [carriers, refineries, signals, docks, planes] = await Promise.all([
        window.SI_DB.raw.count("entities", "type=eq.carrier").catch(() => null),
        window.SI_DB.raw.count("refineries", "").catch(() => null),
        window.SI_DB.raw.count("intel_submissions",
          "status=eq.verified&visibility=eq.public&published_at=not.is.null"
        ).catch(() => null),
        window.SI_DB.raw.count("receiver_locations", "").catch(() => null),
        window.SI_DB.raw.count("cargo_aircraft", "on_ground=eq.false").catch(() => null),
      ]);
      if (!alive) return;
      setStats(s => ({
        ...s,
        carriers: carriers || s.carriers,
        refineries: refineries || s.refineries,
        signals: signals,
        docks: docks,
        planes: planes,
      }));
    })();
    return () => { alive = false; };
  }, []);

  const fmt = (n) => n == null ? "—" : n.toLocaleString();

  return (
    <div className="hero-stats">
      <div className="hero-stat">
        <div className="hero-stat-num">{fmt(stats.docks || 86080)}</div>
        <div className="hero-stat-label">Delivery docks mapped</div>
      </div>
      <div className="hero-stat">
        <div className="hero-stat-num">{fmt(stats.carriers)}</div>
        <div className="hero-stat-label">Carriers tracked</div>
      </div>
      <div className="hero-stat">
        <div className="hero-stat-num">{fmt(stats.refineries)}</div>
        <div className="hero-stat-label">Refineries monitored</div>
      </div>
      <div className="hero-stat">
        <div className="hero-stat-num">{stats.planes != null ? fmt(stats.planes) : "—"}</div>
        <div className="hero-stat-label">Cargo aircraft live</div>
      </div>
    </div>
  );
}


// =============================================================
// HEADLINE CRAWLER — Bloomberg-style scrolling ticker that pulls
// the most recent published intel_alerts and glides them across
// the top of the homepage. Anon-readable. Click anywhere to dive
// into the Clarity dashboard. Pauses on hover.
// =============================================================
function HeadlineCrawler({ onNav }) {
  const [alerts, setAlerts] = useStateH([]);
  useEffectH(() => {
    let alive = true;
    if (!window.SI_DB || !window.SI_DB.raw) return;
    (async () => {
      try {
        const rows = await window.SI_DB.raw.select(
          "intel_alerts",
          "select=id,topic,severity&status=eq.published&order=published_at.desc&limit=12"
        );
        if (!alive) return;
        setAlerts(Array.isArray(rows) ? rows : []);
      } catch {}
    })();
    return () => { alive = false; };
  }, []);
  if (alerts.length === 0) return null;
  // Duplicate so the keyframe translateX(-50%) gives a seamless loop.
  const items = [...alerts, ...alerts];
  return (
    <button type="button" className="hc-bar" onClick={() => onNav("clarity")}
            title="Open the Clarity dashboard for the full read">
      <style>{`
        .hc-bar {
          display: flex; align-items: center; width: 100%;
          background: linear-gradient(90deg, oklch(0.96 0.035 250 / 0.85) 0%, oklch(0.94 0.045 250 / 0.85) 100%);
          color: oklch(0.32 0.05 250); padding: 0; border: 0;
          border-bottom: 1px solid oklch(0.88 0.03 250 / 0.6);
          cursor: pointer; overflow: hidden; font-family: inherit; text-align: left;
        }
        .hc-bar:hover { background: linear-gradient(90deg, oklch(0.94 0.04 250 / 0.9) 0%, oklch(0.92 0.05 250 / 0.9) 100%); }
        .hc-label {
          flex-shrink: 0; padding: 12px 16px; margin-left: 12px;
          font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.22em;
          text-transform: uppercase;
          color: oklch(0.42 0.10 250);
          display: inline-flex; align-items: center; gap: 8px;
        }
        .hc-label .dot {
          width: 7px; height: 7px; border-radius: 50%;
          background: oklch(0.62 0.18 145);
          animation: hc-pulse 1.4s infinite;
        }
        @keyframes hc-pulse {
          0%, 100% { opacity: 1; }
          50% { opacity: 0.35; }
        }
        .hc-track {
          flex: 1; overflow: hidden; padding: 11px 0; min-width: 0;
          mask-image: linear-gradient(90deg, transparent 0, #000 24px, #000 calc(100% - 24px), transparent 100%);
          -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 24px, #000 calc(100% - 24px), transparent 100%);
        }
        .hc-content {
          display: inline-flex; gap: 36px; white-space: nowrap;
          animation: hc-scroll 80s linear infinite;
        }
        .hc-bar:hover .hc-content { animation-play-state: paused; }
        .hc-item { display: inline-flex; align-items: center; gap: 10px; font-size: 15px; }
        .hc-sev {
          font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.16em;
          text-transform: uppercase; padding: 2px 7px; border-radius: 2px;
          font-weight: 700;
        }
        .hc-sev-critical { background: oklch(0.45 0.22 25);              color: #fff; }
        .hc-sev-high     { background: oklch(0.55 0.20 25);              color: #fff; }
        .hc-sev-moderate { background: oklch(0.50 0.10 250 / 0.18);      color: oklch(0.35 0.08 250); }
        .hc-sev-low      { background: oklch(0.50 0.05 250 / 0.10);      color: oklch(0.45 0.05 250); }
        .hc-topic {
          font-family: var(--font-serif); letter-spacing: -0.005em;
          color: oklch(0.28 0.04 250);
        }
        .hc-sep { color: oklch(0.55 0.05 250); opacity: 0.5; font-weight: 700; }
        @keyframes hc-scroll {
          from { transform: translateX(0); }
          to   { transform: translateX(-50%); }
        }
      `}</style>
      <span className="hc-label"><span className="dot" /> Live signals · Clarity</span>
      <div className="hc-track">
        <div className="hc-content">
          {items.map((a, i) => (
            <span key={i} className="hc-item">
              <span className={`hc-sev hc-sev-${a.severity || "moderate"}`}>{(a.severity || "moderate").toUpperCase()}</span>
              <span className="hc-topic">{a.topic}</span>
              <span className="hc-sep">·</span>
            </span>
          ))}
        </div>
      </div>
    </button>
  );
}

// =============================================================
// SHIPPERS CONNECT HOME PAGE — the new front door (2026-04-30 brand
// pivot). The marketplace is the headline product. The intel/scoring
// surface (formerly the homepage) lives at /#/clarity now and is
// reachable from this page via the "More" tiles. Tone: respectable,
// inviting for carriers, no gotcha framing.
// =============================================================
function ShippersConnectHomePage({ onNav, onCity }) {
  const [authedUser, setAuthedUser] = useStateH(null);

  useEffectH(() => {
    let alive = true;
    if (window.SI_DB && window.SI_DB.auth && window.SI_DB.auth.getCurrentUser) {
      window.SI_DB.auth.getCurrentUser().then(u => { if (alive) setAuthedUser(u); }).catch(() => {});
    }
    return () => { alive = false; };
  }, []);

  return (
    <div className="page-sc-home">
      <style>{`
        .page-sc-home { background: var(--paper); padding-bottom: 96px; }

        /* Hero */
        .sch-hero {
          max-width: 1200px; margin: 0 auto; padding: 64px 24px 32px;
          display: grid; grid-template-columns: 1.4fr 1fr; gap: 48px; align-items: center;
        }
        .sch-hero-solo { grid-template-columns: 1fr; max-width: 920px; padding: 80px 24px 24px; }
        @media (max-width: 900px) {
          .sch-hero { grid-template-columns: 1fr; padding-top: 40px; gap: 24px; }
        }
        .sch-eyebrow {
          font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.32em;
          text-transform: uppercase; color: var(--ink-soft); margin-bottom: 14px;
          display: inline-flex; align-items: center; gap: 10px;
        }
        .sch-eyebrow .dot {
          width: 8px; height: 8px; border-radius: 50%;
          background: oklch(0.55 0.20 145); animation: sch-pulse 2.4s infinite;
        }
        @keyframes sch-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.4; } }
        .sch-h1 {
          font-family: var(--font-serif); font-size: 64px; line-height: 1.02;
          letter-spacing: -0.03em; margin: 0 0 18px; color: var(--ink);
        }
        .sch-h1 em { font-style: italic; color: oklch(0.50 0.18 250); }
        @media (max-width: 900px) { .sch-h1 { font-size: 44px; } }
        @media (max-width: 600px) { .sch-h1 { font-size: 34px; } }
        .sch-dek {
          font-size: 17px; line-height: 1.6; color: var(--ink-soft); margin: 0 0 24px;
          max-width: 560px;
        }
        .sch-cta-row { display: flex; gap: 12px; flex-wrap: wrap; }
        .sch-cta {
          font-family: inherit; font-size: 15px; padding: 14px 26px;
          border-radius: 6px; cursor: pointer; font-weight: 600;
          border: 1px solid oklch(0.50 0.18 250); transition: all 0.15s;
        }
        .sch-cta-primary {
          background: oklch(0.50 0.18 250); color: #fff;
          box-shadow: 0 6px 16px oklch(0.50 0.18 250 / 0.25);
        }
        .sch-cta-primary:hover {
          background: oklch(0.45 0.20 250); transform: translateY(-1px);
          box-shadow: 0 10px 22px oklch(0.50 0.18 250 / 0.35);
        }
        .sch-cta-ghost {
          background: #fff; color: oklch(0.40 0.18 250);
          border-color: oklch(0.50 0.18 250);
        }
        .sch-cta-ghost:hover {
          background: oklch(0.50 0.18 250); color: #fff;
          transform: translateY(-1px);
          box-shadow: 0 6px 18px oklch(0.50 0.18 250 / 0.30);
        }

        .sch-hero-side {
          background: linear-gradient(180deg, #fff 0%, oklch(0.99 0.012 250) 100%);
          border: 1px solid oklch(0.88 0.04 250); border-radius: 12px;
          padding: 24px; position: relative; overflow: hidden;
          border-left: 5px solid oklch(0.50 0.18 250);
          box-shadow: 0 6px 20px oklch(0.50 0.18 250 / 0.10);
        }
        .sch-hero-side::before {
          content: ""; position: absolute; top: 0; left: 0; right: 0; height: 3px;
          background: linear-gradient(90deg, oklch(0.50 0.18 250), oklch(0.50 0.18 145));
        }
        .sch-side-h {
          font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.18em;
          text-transform: uppercase; color: var(--ink-soft); margin: 0 0 16px;
        }
        .sch-stats { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
        .sch-stat-num {
          font-family: var(--font-serif); font-size: 30px; letter-spacing: -0.02em;
          color: var(--ink); line-height: 1;
        }
        .sch-stat-lab {
          font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.14em;
          text-transform: uppercase; color: var(--ink-soft); margin-top: 6px;
        }

        /* Network strip — slim horizontal stat bar (moved out of the hero) */
        .sch-network-strip {
          max-width: 1200px; margin: 32px auto 0; padding: 0 24px;
          display: grid; grid-template-columns: auto 1fr; align-items: center;
          gap: 32px;
        }
        @media (max-width: 760px) {
          .sch-network-strip { grid-template-columns: 1fr; gap: 12px; }
        }
        .sch-network-strip-eyebrow {
          font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.32em;
          text-transform: uppercase; color: var(--ink-soft);
        }
        .sch-network-strip-stats {
          display: grid; grid-template-columns: repeat(4, 1fr); gap: 14px;
          padding: 14px 18px; background: #fff;
          border: 1px solid var(--rule); border-radius: 8px;
        }
        @media (max-width: 760px) {
          .sch-network-strip-stats { grid-template-columns: 1fr 1fr; }
        }
        .sch-ns {
          display: flex; flex-direction: column; gap: 2px;
          padding: 4px 12px; border-right: 1px solid var(--rule);
        }
        .sch-ns:last-child { border-right: 0; }
        @media (max-width: 760px) { .sch-ns { border-right: 0; } }
        .sch-ns-v {
          font-family: var(--font-serif); font-size: 22px; letter-spacing: -0.015em;
          line-height: 1; color: var(--ink);
        }
        .sch-ns-l {
          font-family: var(--font-mono); font-size: 9px; letter-spacing: 0.14em;
          text-transform: uppercase; color: var(--ink-soft); margin-top: 4px;
        }

        /* By the numbers */
        .sch-bynumbers {
          max-width: 1200px; margin: 56px auto 0; padding: 0 24px;
        }
        .sch-bn-head { margin-bottom: 28px; }
        .sch-bn-eyebrow {
          font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.32em;
          text-transform: uppercase; color: var(--ink-soft); margin-bottom: 12px;
          display: inline-flex; align-items: center; gap: 10px;
        }
        .sch-bn-eyebrow::before {
          content: ""; display: inline-block; width: 8px; height: 8px;
          border-radius: 50%; background: oklch(0.55 0.20 145);
          animation: bn-pulse 2.4s infinite;
        }
        @keyframes bn-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.4; } }
        .sch-bn-h {
          font-family: var(--font-serif); font-size: 32px; letter-spacing: -0.02em;
          line-height: 1.1; margin: 0;
        }
        .sch-bn-h em { font-style: italic; color: oklch(0.50 0.18 250); }
        @media (max-width: 700px) { .sch-bn-h { font-size: 24px; } }
        .sch-bn-grid {
          display: grid; grid-template-columns: repeat(4, 1fr); gap: 14px;
        }
        @media (max-width: 1000px) { .sch-bn-grid { grid-template-columns: repeat(2, 1fr); } }
        @media (max-width: 600px)  { .sch-bn-grid { grid-template-columns: 1fr; } }
        .sch-bn-cell {
          background: #fff; border: 1px solid var(--rule); border-radius: 10px;
          padding: 22px 22px 20px;
          display: flex; flex-direction: column; gap: 6px;
          transition: border-color 0.15s, transform 0.15s;
        }
        .sch-bn-cell:hover {
          border-color: var(--ink); transform: translateY(-2px);
        }
        .sch-bn-v {
          font-family: var(--font-serif); font-size: 38px; line-height: 1;
          letter-spacing: -0.025em; color: var(--ink);
        }
        @media (max-width: 700px) { .sch-bn-v { font-size: 30px; } }
        .sch-bn-l {
          font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.18em;
          text-transform: uppercase; color: var(--ink-soft); margin-top: 4px;
        }
        .sch-bn-d {
          font-size: 13px; line-height: 1.55; color: var(--ink); margin-top: 6px;
        }

        /* How it works */
        .sch-how-top { padding-top: 56px; }
        .sch-how {
          max-width: 1200px; margin: 56px auto 0; padding: 0 24px;
        }
        .sch-section-eyebrow {
          font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.32em;
          text-transform: uppercase; color: oklch(0.45 0.14 250);
          margin-bottom: 12px; font-weight: 600;
          display: inline-flex; align-items: center; gap: 8px;
        }
        .sch-section-eyebrow::before {
          content: ""; width: 6px; height: 6px; border-radius: 50%;
          background: oklch(0.50 0.18 250);
        }
        .sch-section-h {
          font-family: var(--font-serif); font-size: 32px; letter-spacing: -0.02em;
          line-height: 1.1; margin: 0 0 28px;
        }
        .sch-steps {
          display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px;
        }
        @media (max-width: 800px) { .sch-steps { grid-template-columns: 1fr; } }
        .sch-step {
          background: linear-gradient(180deg, #fff 0%, oklch(0.99 0.012 250) 100%);
          border: 1px solid oklch(0.90 0.04 250);
          border-radius: 8px; padding: 24px; position: relative;
          border-left: 3px solid oklch(0.85 0.08 250);
          transition: border-left-color 0.18s, box-shadow 0.18s, transform 0.12s;
        }
        .sch-step:hover {
          border-left-color: oklch(0.50 0.18 250);
          box-shadow: 0 8px 22px oklch(0.50 0.18 250 / 0.12);
          transform: translateY(-2px);
        }
        .sch-step-n {
          font-family: var(--font-serif); font-size: 44px; line-height: 1;
          color: oklch(0.50 0.18 250); margin-bottom: 12px; font-weight: 700;
          letter-spacing: -0.02em;
        }
        .sch-step-h {
          font-family: var(--font-serif); font-size: 19px; letter-spacing: -0.01em;
          margin: 0 0 8px;
        }
        .sch-step-body {
          color: var(--ink-soft); font-size: 14px; line-height: 1.55; margin: 0;
        }

        /* For shippers / for carriers */
        .sch-twoup {
          max-width: 1200px; margin: 56px auto 0; padding: 0 24px;
          display: grid; grid-template-columns: 1fr 1fr; gap: 20px;
        }
        @media (max-width: 800px) { .sch-twoup { grid-template-columns: 1fr; } }
        .sch-aud {
          background: linear-gradient(180deg, #fff 0%, oklch(0.99 0.012 250) 100%);
          border: 1px solid oklch(0.88 0.04 250); border-radius: 12px;
          padding: 32px; display: flex; flex-direction: column;
          border-left: 4px solid oklch(0.50 0.18 250);
          transition: box-shadow 0.18s, transform 0.12s;
        }
        .sch-aud:hover {
          box-shadow: 0 10px 28px oklch(0.50 0.18 250 / 0.12);
          transform: translateY(-2px);
        }
        .sch-aud-eyebrow {
          font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.18em;
          text-transform: uppercase; color: oklch(0.45 0.14 250);
          margin-bottom: 8px; font-weight: 600;
        }
        .sch-aud-h {
          font-family: var(--font-serif); font-size: 24px; letter-spacing: -0.015em;
          margin: 0 0 14px;
        }
        .sch-aud-list { list-style: none; padding: 0; margin: 0 0 22px; }
        .sch-aud-list li {
          padding: 8px 0 8px 22px; position: relative; font-size: 14px;
          line-height: 1.5; color: var(--ink);
        }
        .sch-aud-list li::before {
          content: "→"; position: absolute; left: 0; color: oklch(0.50 0.18 250);
          font-weight: 700;
        }
        .sch-aud-cta {
          font-family: inherit; font-size: 14px; padding: 12px 22px;
          border-radius: 6px; cursor: pointer; font-weight: 600;
          border: 1px solid oklch(0.50 0.18 250);
          background: oklch(0.50 0.18 250); color: #fff;
          align-self: flex-start; margin-top: auto;
          transition: background 0.15s, transform 0.1s, box-shadow 0.15s;
          box-shadow: 0 4px 12px oklch(0.50 0.18 250 / 0.20);
        }
        .sch-aud-cta:hover {
          background: oklch(0.45 0.20 250); transform: translateY(-1px);
          box-shadow: 0 8px 18px oklch(0.50 0.18 250 / 0.32);
        }
        .sch-aud-cta-ghost {
          background: #fff; color: oklch(0.40 0.18 250);
          box-shadow: none;
        }
        .sch-aud-cta-ghost:hover {
          background: oklch(0.50 0.18 250); color: #fff;
          box-shadow: 0 4px 14px oklch(0.50 0.18 250 / 0.25);
        }

        /* Driver tip — small, modest */
        .sch-driver {
          max-width: 1200px; margin: 56px auto 0; padding: 0 24px;
        }
        .sch-driver-box {
          background: var(--paper-2); border: 1px solid var(--rule); border-radius: 8px;
          padding: 20px 24px; display: grid; grid-template-columns: 1fr auto;
          gap: 24px; align-items: center;
        }
        @media (max-width: 700px) {
          .sch-driver-box { grid-template-columns: 1fr; gap: 12px; }
        }
        .sch-driver-text { font-size: 14px; line-height: 1.55; color: var(--ink); margin: 0; }
        .sch-driver-text strong { color: var(--ink); font-weight: 700; }
        .sch-driver-cta {
          font-family: inherit; font-size: 13px; padding: 10px 18px;
          border-radius: 4px; cursor: pointer; font-weight: 600;
          border: 1px solid var(--ink); background: #fff; color: var(--ink);
          white-space: nowrap;
        }
        .sch-driver-cta:hover { background: var(--ink); color: #fff; }

        /* More tiles */
        .sch-more {
          max-width: 1200px; margin: 56px auto 0; padding: 0 24px;
        }
        .sch-more-grid {
          display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px;
        }
        @media (max-width: 1000px) { .sch-more-grid { grid-template-columns: repeat(2, 1fr); } }
        @media (max-width: 600px)  { .sch-more-grid { grid-template-columns: 1fr; } }
        .sch-more-tile {
          background: #fff; border: 1px solid var(--rule); border-radius: 8px;
          padding: 18px 20px; cursor: pointer; transition: all 0.15s;
          text-align: left; font-family: inherit; color: var(--ink);
        }
        .sch-more-tile:hover { border-color: var(--ink); transform: translateY(-2px); }
        .sch-more-icon { font-size: 22px; margin-bottom: 10px; line-height: 1; }
        .sch-more-h {
          font-family: var(--font-serif); font-size: 17px; letter-spacing: -0.01em;
          margin: 0 0 6px;
        }
        .sch-more-body { font-size: 12px; line-height: 1.5; color: var(--ink-soft); margin: 0; }
      `}</style>

      {/* LIVE SIGNALS CRAWLER — Bloomberg-style ticker pulling published
          intel_alerts. Sits at the very top, edge-to-edge. Click → /clarity. */}
      <HeadlineCrawler onNav={onNav} />

      {/* HOW IT WORKS — top of the home content. Step numbers are
          rendered as a rotating freight-themed icon set (mile marker /
          exit sign / smoke stack / fuel pump / gear shift) so the page
          feels playful instead of stamped. */}
      <section className="sch-how sch-how-top">
        <div className="sch-section-eyebrow">How it works</div>
        <h2 className="sch-section-h">Three simple steps. No middleman.</h2>
        <div className="sch-steps">
          <div className="sch-step">
            <StepIcon n={1} />
            <h3 className="sch-step-h">Shippers post a load.</h3>
            <p className="sch-step-body">
              Origin, destination, equipment, pickup window, rate. Open to
              consolidation if you've got room to share.
            </p>
          </div>
          <div className="sch-step">
            <StepIcon n={2} />
            <h3 className="sch-step-h">Carriers and partners reach out.</h3>
            <p className="sch-step-body">
              Browse the open board, filter by lane and equipment, send your
              MC and message. The load owner sees it the moment it lands.
            </p>
          </div>
          <div className="sch-step">
            <StepIcon n={3} />
            <h3 className="sch-step-h">You connect directly.</h3>
            <p className="sch-step-body">
              We email the shipper your message and your contact info. They
              reply straight to you. We don't take a cut of the handshake.
            </p>
          </div>
        </div>
      </section>

      {/* HERO — sits below How it works, full width, no side stats */}
      <section className="sch-hero sch-hero-solo">
        <div>
          <div className="sch-eyebrow"><span className="dot" /> Shippers Connect · Live</div>
          <h1 className="sch-h1">Where shippers and carriers <em>connect</em>.</h1>
          <p className="sch-dek">
            Post your load. See open trucks. Reach the load owner directly — no
            broker in the middle, no commission on a handshake. A respectful
            marketplace built for the people who actually move the freight.
          </p>
          <div className="sch-cta-row">
            <button className="sch-cta sch-cta-primary"
                    onClick={() => onNav("load-board")}>＋ Post a load</button>
            <button className="sch-cta sch-cta-ghost"
                    onClick={() => onNav("load-board")}>📋 Browse the board</button>
          </div>
        </div>
      </section>

      {/* BY THE NUMBERS — 8 stats grouped into Coverage / Intelligence / Trust.
          Sits between the Hero and the Connection Board so the credibility
          signals land before the live load board preview. */}
      <section className="sch-bynumbers">
        <div className="sch-bn-head">
          <div className="sch-bn-eyebrow">By the numbers · live network</div>
          <h2 className="sch-bn-h">A marketplace built on <em>real coverage</em>.</h2>
        </div>
        <div className="sch-bn-grid">
          {[
            { v: "33,455", l: "Receiver docks",    d: "Across 18 retail + cold-storage brands. Searchable by state and brand." },
            { v: "22",     l: "Freight metros",    d: "Major US lanes — LA, Chicago, Dallas, Atlanta, Newark, Memphis, and more." },
            { v: "2,254",  l: "Truck stops mapped",d: "Every TA, Pilot, Love's, Petro plus regional independents." },
            { v: "Major carriers", l: "Hub atlas", d: "Old Dominion, FedEx Freight, XPO, Saia, Estes, ABF, UPS, Amazon — every named hub we track." },
            { v: "30",     l: "US refineries",     d: "PADD-level utilization tracked daily so fuel cost shifts don't surprise you." },
            { v: "1,162",  l: "Market signals",    d: "Verified intel from public records, court dockets, news, and operator chatter." },
            { v: "24 hr",  l: "Risk Report",       d: "Public-records synthesis on any US carrier — in your inbox tomorrow morning." },
            { v: "$0",     l: "Commission",        d: "We don't take a cut of any deal closed on Shippers Connect. Ever." },
          ].map((s, i) => (
            <div key={i} className="sch-bn-cell">
              <div className="sch-bn-v">{s.v}</div>
              <div className="sch-bn-l">{s.l}</div>
              <div className="sch-bn-d">{s.d}</div>
            </div>
          ))}
        </div>
      </section>

      {/* WHAT THE DATA SHOWS — specific data-driven findings, not generic stats.
          Each card is one real finding from our pipeline, with a punchy
          number + the supporting context + a CTA to the page that proves it. */}
      <section className="sch-findings">
        <style>{`
          .sch-findings {
            max-width: 1180px; margin: 56px auto 0; padding: 0 24px;
          }
          .sch-findings-eyebrow {
            font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.32em;
            text-transform: uppercase; color: var(--ink-soft); margin-bottom: 14px;
            display: inline-flex; align-items: center; gap: 10px;
          }
          .sch-findings-eyebrow .dot {
            width: 8px; height: 8px; border-radius: 50%;
            background: oklch(0.55 0.20 25); animation: sch-find-pulse 1.6s infinite;
          }
          @keyframes sch-find-pulse { 0%,100%{opacity:1} 50%{opacity:0.4} }
          .sch-findings-h {
            font-family: var(--font-serif); font-size: 44px; line-height: 1.05;
            letter-spacing: -0.025em; margin: 0 0 10px; font-weight: 500; color: var(--ink);
            max-width: 880px;
          }
          .sch-findings-sub {
            color: var(--ink-soft); font-size: 17px; line-height: 1.5;
            max-width: 760px; margin: 0 0 36px;
          }
          @media (max-width: 700px) { .sch-findings-h { font-size: 30px; } }
          .sch-findings-grid {
            display: grid; grid-template-columns: repeat(3, 1fr); gap: 18px;
          }
          @media (max-width: 980px) { .sch-findings-grid { grid-template-columns: repeat(2, 1fr); } }
          @media (max-width: 640px)  { .sch-findings-grid { grid-template-columns: 1fr; } }
          .sch-finding {
            background: #fff; border: 1px solid var(--rule); border-radius: 8px;
            padding: 24px; cursor: pointer; transition: border-color 0.15s, transform 0.15s, box-shadow 0.15s;
            display: flex; flex-direction: column; position: relative; overflow: hidden;
            min-height: 220px;
          }
          .sch-finding::before {
            content: ""; position: absolute; top: 0; bottom: 0; left: 0; width: 3px;
            background: var(--accent, var(--ink));
          }
          .sch-finding:hover {
            border-color: var(--ink); transform: translateY(-2px);
            box-shadow: 0 12px 28px -16px oklch(0.25 0.02 250 / 0.25);
          }
          .sch-finding-tag {
            font-family: var(--font-mono); font-size: 9px; letter-spacing: 0.18em;
            text-transform: uppercase; color: var(--accent, var(--ink-soft));
            margin-bottom: 14px; font-weight: 700;
          }
          .sch-finding-num {
            font-family: var(--font-serif); font-size: 42px; line-height: 1;
            letter-spacing: -0.02em; color: var(--ink); font-weight: 600;
            margin-bottom: 4px;
          }
          .sch-finding-num-sub {
            font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.06em;
            color: var(--ink-soft); margin-bottom: 14px; text-transform: uppercase;
          }
          .sch-finding-h {
            font-family: var(--font-serif); font-size: 18px; letter-spacing: -0.005em;
            line-height: 1.25; margin: 0 0 10px; color: var(--ink);
          }
          .sch-finding-body {
            color: var(--ink-soft); font-size: 13.5px; line-height: 1.5;
            margin: 0 0 16px; flex: 1;
          }
          .sch-finding-cta {
            font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.18em;
            text-transform: uppercase; color: var(--accent, var(--ink)); font-weight: 700;
            margin-top: auto;
          }
          .sch-finding-cta::after { content: " →"; }
        `}</style>
        <div className="sch-findings-eyebrow"><span className="dot" /> What the data shows · live</div>
        <h2 className="sch-findings-h">Specific findings, not generic stats.</h2>
        <p className="sch-findings-sub">
          Real numbers from this week's market. Click any card to see the data behind it.
        </p>
        <div className="sch-findings-grid">
          {[
            { num: "?", numSub: "before you tender", tag: "Verification",
              accent: "oklch(0.50 0.22 25)",
              title: "How do you know the carrier you booked is actually legal to haul your freight?",
              body: "Lapsed MC authority. No MC at all. Broker-only operations posting trucks they don't own. We run a real-time check against the federal carrier registry so you don't tender a load to a chain that breaks the second something goes sideways.",
              cta: "Verify a carrier", goto: "find-carrier" },
            { num: "$4.06", numSub: "per mile · Chicago→Detroit", tag: "Hot lane",
              accent: "oklch(0.50 0.22 25)",
              title: "Auto industry corridor is the tightest market we've measured.",
              body: "1,303 similar loads available, $4.06/mi rate — 71% above the dry-van national median. Detroit factories pulling Midwest distribution at peak demand.",
              cta: "See the lane heat map", goto: "rates" },
            { num: "$4.41", numSub: "per mile · McAllen→Atlanta", tag: "Reefer",
              accent: "oklch(0.50 0.18 145)",
              title: "Mexico-Texas produce season opens at premium rates.",
              body: "Reefer rates spike May 1 as TX/MX produce season starts. 51% premium over dry van on the same lane.",
              cta: "See the rate map", goto: "rates" },
            { num: "8x", numSub: "named for #1 customer", tag: "Concentration",
              accent: "oklch(0.45 0.22 60)",
              title: "Walmart is the largest customer for 8+ public CPG companies.",
              body: "Tyson 18.7%, General Mills 22%, Kraft Heinz 21%, P&G 16%, Kimberly-Clark 16%, Hormel 15.6%, Colgate 11%, PepsiCo 14%. CPG concentration risk made structured.",
              cta: "Browse the directory", goto: "shippers" },
            { num: "34%", numSub: "backhaul discount · LA↔Dallas", tag: "Asymmetry",
              accent: "oklch(0.50 0.18 250)",
              title: "Backhauls run 19-34% below headhauls. The biggest gap is LA-Dallas.",
              body: "A carrier doing LA→Dallas at $2.64/mi headhaul + Dallas→LA at $1.73/mi backhaul leaves $1,311 per truck on the table per round trip. Empty miles cost real money.",
              cta: "See asymmetry table", goto: "rates" },
            { num: "29,762", numSub: "shippers indexed", tag: "Coverage",
              accent: "oklch(0.40 0.16 250)",
              title: "Every meaningful US freight shipper, free to browse.",
              body: "Stacked from SEC filings + OpenStreetMap industrial polygons + Wayback Machine + craft-brewery registry + manual seeds. 8,300+ food shippers tagged. Nobody else does this end-to-end.",
              cta: "Open the directory", goto: "shippers" },
          ].map((f, i) => (
            <button key={i} className="sch-finding" style={{ ["--accent"]: f.accent }} onClick={() => onNav(f.goto)}>
              <div className="sch-finding-tag">{f.tag}</div>
              <div className="sch-finding-num">{f.num}</div>
              <div className="sch-finding-num-sub">{f.numSub}</div>
              <h3 className="sch-finding-h">{f.title}</h3>
              <p className="sch-finding-body">{f.body}</p>
              <div className="sch-finding-cta">{f.cta}</div>
            </button>
          ))}
        </div>
      </section>

      {/* CONNECTION BOARD PREVIEW — reused */}
      <ConnectionBoardPreview onNav={onNav} user={authedUser} />

      {/* FOR SHIPPERS / FOR CARRIERS */}
      <section className="sch-twoup">
        <div className="sch-aud">
          <div className="sch-aud-eyebrow">For shippers</div>
          <h3 className="sch-aud-h">Move freight without the broker tax.</h3>
          <ul className="sch-aud-list">
            <li>Post a load in two minutes</li>
            <li>See who's heading to the same dock — share the truck</li>
            <li>Manage your loads, mark them booked, see who reached out</li>
            <li>Email arrives the moment a carrier responds</li>
          </ul>
          <button className="sch-aud-cta" onClick={() => onNav("load-board")}>
            Post your first load →
          </button>
        </div>
        <div className="sch-aud">
          <div className="sch-aud-eyebrow">For carriers</div>
          <h3 className="sch-aud-h">Find runs that match your trailer.</h3>
          <ul className="sch-aud-list">
            <li>Browse open loads by destination radius and equipment</li>
            <li>Reach out directly — no booking fees, no commission</li>
            <li>List your company so shippers find you</li>
            <li>Backed by real market data, not just spot-rate boards</li>
          </ul>
          <button className="sch-aud-cta sch-aud-cta-ghost" onClick={() => onNav("for-carriers")}>
            Claim your profile — $99/mo →
          </button>
        </div>
      </section>

      {/* CARRIER RISK REPORT — paid product. Sits right after the
          For Shippers / For Carriers split because it's the natural
          adjacency: the marketplace is free, this is the paid
          intelligence product for shippers who want a deeper read. */}
      <section style={{ maxWidth: 1200, margin: "56px auto 0", padding: "0 24px" }}>
        <div style={{
          background: "linear-gradient(180deg, oklch(0.98 0.01 250) 0%, #fff 100%)",
          border: "1px solid var(--rule)", borderRadius: 12, padding: 32,
          position: "relative", overflow: "hidden",
          display: "grid", gridTemplateColumns: "1.4fr 1fr", gap: 32, alignItems: "center",
        }}
        className="sch-risk">
          <div style={{
            position: "absolute", top: 0, left: 0, right: 0, height: 3,
            background: "linear-gradient(90deg, oklch(0.50 0.18 250), oklch(0.45 0.16 250))",
          }} />
          <div>
            <div style={{
              fontFamily: "var(--font-mono)", fontSize: 11, letterSpacing: "0.32em",
              textTransform: "uppercase", color: "var(--ink-soft)", marginBottom: 12,
            }}>
              Carrier Risk Report · 24-hour delivery
            </div>
            <h2 style={{
              fontFamily: "var(--font-serif)", fontSize: 32, letterSpacing: "-0.02em",
              lineHeight: 1.1, margin: "0 0 14px",
            }}>
              Know what your carrier looks like — <em style={{ fontStyle: "italic", color: "oklch(0.50 0.18 250)" }}>before</em> you book.
            </h2>
            <p style={{
              fontSize: 15, lineHeight: 1.6, color: "var(--ink-soft)", margin: "0 0 6px", maxWidth: 580,
            }}>
              Ten pages. Public records, synthesized. SEC filings, court dockets,
              listing-status changes, FMCSA inspections, operational signals.
              The picture that takes a research team three days to assemble — in
              your inbox tomorrow morning.
            </p>
          </div>
          <div style={{
            background: "#fff", border: "1px solid var(--rule)", borderRadius: 10,
            padding: 24, textAlign: "left",
          }}>
            <div style={{
              display: "flex", alignItems: "baseline", gap: 10, marginBottom: 18,
            }}>
              <span style={{
                fontFamily: "var(--font-serif)", fontSize: 44, lineHeight: 1,
                letterSpacing: "-0.02em",
              }}>$499</span>
              <span style={{
                fontFamily: "var(--font-mono)", fontSize: 11, letterSpacing: "0.14em",
                textTransform: "uppercase", color: "var(--ink-soft)",
              }}>per carrier</span>
            </div>
            <button onClick={() => onNav("risk-report")}
                    style={{
                      width: "100%", fontFamily: "inherit", fontSize: 15,
                      padding: "14px 24px", borderRadius: 6, cursor: "pointer",
                      fontWeight: 600, border: "1px solid var(--ink)",
                      background: "var(--ink)", color: "#fff", marginBottom: 10,
                    }}>
              Order a Risk Report →
            </button>
            <button onClick={() => onNav("risk-report")}
                    style={{
                      width: "100%", fontFamily: "inherit", fontSize: 14,
                      padding: "10px 20px", borderRadius: 6, cursor: "pointer",
                      fontWeight: 500, border: "1px solid var(--rule)",
                      background: "transparent", color: "var(--ink)",
                    }}>
              See what's in it
            </button>
          </div>
        </div>
        <style>{`
          @media (max-width: 800px) {
            .sch-risk { grid-template-columns: 1fr !important; }
          }
        `}</style>
      </section>

      {/* DRIVER TIP — modest, single line */}
      <section className="sch-driver">
        <div className="sch-driver-box">
          <p className="sch-driver-text">
            <strong>Drivers</strong> — see something on the road that other
            drivers should know? Detention, parking, a dock that needs a heads-up?
            We collect it carefully and you can always delete what you submit.
          </p>
          <button className="sch-driver-cta" onClick={() => onNav("drivers")}>
            Open The Yard →
          </button>
        </div>
      </section>

      {/* MORE — surfaces the data products */}
      <section className="sch-more">
        <div className="sch-section-eyebrow">The data behind the marketplace</div>
        <h2 className="sch-section-h">Free public data, stacked into something nobody else has.</h2>
        <div className="sch-more-grid">
          <button className="sch-more-tile" onClick={() => onNav("shippers")}>
            <div className="sch-more-icon">🏭</div>
            <h4 className="sch-more-h">Shipper directory</h4>
            <p className="sch-more-body">29,762 US shippers indexed. SEC + OSM + Wayback + private mega-shippers, with 8,300+ food shippers tagged. Free to browse.</p>
          </button>
          <button className="sch-more-tile" onClick={() => onNav("rates")}>
            <div className="sch-more-icon">💵</div>
            <h4 className="sch-more-h">Lane rates</h4>
            <p className="sch-more-body">$1.70–$4.41/mi market range across 18 lanes. Headhaul-vs-backhaul asymmetry computed. Reefer-vs-van premium quantified.</p>
          </button>
          <button className="sch-more-tile" onClick={() => onNav("find-carrier")}>
            <div className="sch-more-icon">🚛</div>
            <h4 className="sch-more-h">Verify carrier</h4>
            <p className="sch-more-body">How do you know the carrier you booked is actually legal? Lapsed MC, no MC, broker-only operations — we run the federal check in real time so you don't have to wonder.</p>
          </button>
          <button className="sch-more-tile" onClick={() => onNav("receivers")}>
            <div className="sch-more-icon">📦</div>
            <h4 className="sch-more-h">Receiver locations</h4>
            <p className="sch-more-body">33,000+ docks across 18 brands. Find the right back door before the truck rolls.</p>
          </button>
          <button className="sch-more-tile" onClick={() => onNav("clarity")}>
            <div className="sch-more-icon">📡</div>
            <h4 className="sch-more-h">Clarity dashboard</h4>
            <p className="sch-more-body">Live freight signals — fuel, ports, weather, refineries, regulatory. The market read others miss.</p>
          </button>
          <button className="sch-more-tile" onClick={() => onNav("insights")}>
            <div className="sch-more-icon">📰</div>
            <h4 className="sch-more-h">Stories</h4>
            <p className="sch-more-body">What we're seeing across the network — quarterly trends, deep dives, market context.</p>
          </button>
        </div>
      </section>
    </div>
  );
}

window.ShippersConnectHomePage = ShippersConnectHomePage;

// =============================================================================
// CLARITY DASHBOARD — Bloomberg-style data wall on /#/clarity. The point of
// this surface is density: a visitor lands here and immediately sees how
// large the dataset behind the platform is. Live counts across every layer
// (shippers, carriers, lanes, metros, refineries, signals) sit in a tight
// stat strip; below it, four panels summarize what's currently moving in
// the market with deep-links into the entity pages.
// =============================================================================
function ClarityDashboard({ onNav, onCity }) {
  const [counts, setCounts] = useStateH({
    shippers: null, facilities: null, signals: null,
    carriers: null, refineries: null, intelLast30: null,
    lanes: null, receivers: null,
    bondRisk: null, locksClosed: null, warn30: null, bk30: null,
  });
  const [recentSignals, setRecentSignals] = useStateH([]);
  const [hotLanes, setHotLanes] = useStateH([]);
  const [topShippers, setTopShippers] = useStateH([]);
  const [riskCarriers, setRiskCarriers] = useStateH([]);
  const [newsItems, setNewsItems] = useStateH([]);
  const [newsLens, setNewsLens] = useStateH("all");

  useEffectH(() => {
    let alive = true;
    if (!window.SI_DB || !window.SI_DB.raw) return;
    (async () => {
      const day = 24 * 3600 * 1000;
      const cutoff = new Date(Date.now() - 30 * day).toISOString();
      const cutoffDate = new Date(Date.now() - 30 * day).toISOString().slice(0, 10);
      const [shippers, facilities, signals, carriers, refineries, intel30, lanes, receivers,
             bondRisk, locksClosed, warn30, bk30,
             recent, hot, leaders, risky, news] = await Promise.all([
        window.SI_DB.raw.count("shippers", "").catch(() => null),
        window.SI_DB.raw.count("shipper_facilities", "").catch(() => null),
        window.SI_DB.raw.count("shipper_signals", "").catch(() => null),
        window.SI_DB.raw.count("entities", "type=eq.carrier").catch(() => null),
        window.SI_DB.raw.count("refineries", "").catch(() => null),
        window.SI_DB.raw.count(
          "intel_submissions",
          `status=eq.verified&visibility=eq.public&created_at=gte.${encodeURIComponent(cutoff)}`
        ).catch(() => null),
        window.SI_DB.raw.count("dat_lane_rates", "").catch(() => null),
        window.SI_DB.raw.count("receiver_locations", "").catch(() => null),
        // New live-distress counts:
        window.SI_DB.raw.count("broker_bond_red_flags", "").catch(() => null),
        window.SI_DB.raw.count("waterway_locks_now", "status=eq.closed").catch(() => null),
        window.SI_DB.raw.count("warn_notices",
          `notice_date=gte.${cutoffDate}`).catch(() => null),
        window.SI_DB.raw.count("bankruptcy_filings",
          `filed_date=gte.${cutoffDate}&business_filing=eq.true`).catch(() => null),
        window.SI_DB.raw.select(
          "intel_submissions",
          `select=id,parsed_carrier,parsed_intel_type,severity,raw_text,created_at,city_id`
          + `&status=eq.verified&visibility=eq.public&order=created_at.desc&limit=8`
        ).catch(() => []),
        window.SI_DB.raw.select(
          "dat_lane_rates",
          `select=*&order=lane_rate_per_mi.desc&limit=6`
        ).catch(() => []),
        window.SI_DB.raw.select(
          "shippers",
          `select=canonical_name,slug,size_band,description&size_band=eq.enterprise&limit=8&order=canonical_name.asc`
        ).catch(() => []),
        window.SI_DB.raw.select(
          "dat_carriers",
          `select=canonical_name,dot_number,mc_status,authority_status&mc_status=in.(no_mc_dot_only,has_mc_inactive)&limit=6`
        ).catch(() => []),
        // Aggregated news firehose — Google News + direct publisher RSS
        // (lands via ingest-news.py). 30 freshest; client filters by lens.
        window.SI_DB.raw.select(
          "forum_raw_posts",
          `select=source,source_id,source_url,subforum,author_handle,posted_at,raw_title`
          + `&source=in.(google-news,publisher-rss)`
          + `&order=posted_at.desc.nullslast&limit=30`
        ).catch(() => []),
      ]);
      if (!alive) return;
      setCounts({
        shippers, facilities, signals, carriers, refineries,
        intelLast30: intel30, lanes, receivers,
        bondRisk, locksClosed, warn30, bk30,
      });
      setRecentSignals(Array.isArray(recent) ? recent : []);
      setHotLanes(Array.isArray(hot) ? hot : []);
      setTopShippers(Array.isArray(leaders) ? leaders : []);
      setRiskCarriers(Array.isArray(risky) ? risky : []);
      setNewsItems(Array.isArray(news) ? news : []);
    })();
    return () => { alive = false; };
  }, []);

  const fmt = (n) => n == null ? "—" : n.toLocaleString();
  const sev = (r) => r.severity || "low";
  const sevColor = (s) => ({
    critical: "oklch(0.50 0.22 25)",
    high: "oklch(0.55 0.18 25)",
    moderate: "oklch(0.55 0.14 80)",
    low: "var(--ink-soft)",
  }[s] || "var(--ink-soft)");

  function fmtAge(s) {
    const d = new Date(s);
    const days = Math.round((Date.now() - d.getTime()) / (24 * 3600 * 1000));
    if (days === 0) return "today";
    if (days === 1) return "1d";
    if (days < 30) return `${days}d`;
    return d.toLocaleDateString("en-US", { month: "short", day: "numeric" });
  }

  // ── Audience-lens classifier ──────────────────────────────────────
  // Maps a news item's subforum (= the ingest query label or publisher
  // slug) onto an audience lens. Lightweight + deterministic — no LLM
  // round-trip at fetch time. The lens drives the editorial framing
  // beneath each headline ("why this matters · for shippers", etc.).
  const NEWS_LENSES = [
    { id: "all",      label: "All", framing: "" },
    { id: "shippers", label: "Shippers", framing: "Shipper signal" },
    { id: "carriers", label: "Carriers", framing: "Carrier signal" },
    { id: "fuel",     label: "Fuel + diesel", framing: "Fuel cost driver" },
    { id: "regional", label: "Regional", framing: "Regional flow" },
    { id: "macro",    label: "Macro", framing: "Macro disruption" },
  ];
  // Tag heuristics keyed on the subforum value the ingest writes.
  // First match wins; fall through to "macro" for anything generic.
  function newsLensFor(item) {
    const sf = (item.subforum || "").toLowerCase();
    const ah = (item.author_handle || "").toLowerCase();
    // Direct publisher RSS — assign by publication mix.
    if (item.source === "publisher-rss") {
      if (/gcaptain|maritime-executive|loadstar|joc|splash247/.test(sf)) return "regional";
      if (/land-line|overdrive|the-trucker|truckinginfo|ccj-digital/.test(sf)) return "carriers";
      if (/dc-velocity|supply-chain-dive/.test(sf)) return "shippers";
      return "macro"; // freightwaves + general
    }
    // Google News query labels — the ingest sets subforum = label.
    if (/walmart|amazon|target|costco|home depot|lowe|best buy|kroger|albertsons|publix|cvs|walgreens|dollar |tjx|gap inc|macy|kohl|nike|lululemon/.test(sf)) return "shippers";
    if (/general motors|ford motor|stellantis|tesla|toyota|honda|hyundai|volkswagen|rivian|lucid/.test(sf)) return "shippers";
    if (/procter|unilever|pepsi|coca-cola|kraft|general mills|mondelez|tyson|jbs|cargill|archer daniels/.test(sf)) return "shippers";
    if (/caterpillar|john deere|3m company|whirlpool|usg|vulcan|martin marietta/.test(sf)) return "shippers";
    if (/apple|microsoft|dell|hp inc/.test(sf)) return "shippers";
    if (/prologis|duke realty|americold|lineage/.test(sf)) return "shippers";
    if (/international paper|smurfit|amcor|sonoco/.test(sf)) return "shippers";
    if (/ups|fedex|usps|amazon logistics|dhl|ontrac|old dominion|saia|arcbest|estes|xpo|forward air|yellow|knight-swift|jb hunt|schneider|werner|heartland|marten|usa truck|covenant|gxo|rxo|hub group|ryder|penske|robinson|uber freight|convoy|coyote|union pacific|bnsf|norfolk southern|csx|kansas city|canadian pacific|maersk|msc mediterranean|zim|hapag|one ocean|cma cgm|evergreen|yang ming|hmm korea|cosco/.test(sf)) return "carriers";
    if (/exxonmobil|chevron|shell usa|bp america|conocophillips|phillips 66|marathon petroleum|valero|hf sinclair|pbf|eia weekly|diesel inventory padd|diesel|fuel|padd/.test(sf)) return "fuel";
    if (/freight|port|logistics|trucking|shipping|drayage|border|corridor/.test(sf)) {
      // Cities live here — match against "X freight", "X port", etc.
      return "regional";
    }
    return "macro";
  }
  function newsLensLabel(lensId) {
    return (NEWS_LENSES.find((l) => l.id === lensId) || NEWS_LENSES[0]).label;
  }
  function newsFraming(lensId) {
    return (NEWS_LENSES.find((l) => l.id === lensId) || NEWS_LENSES[0]).framing;
  }
  // Pretty publisher name from the slug we store in author_handle.
  const PUBLISHER_NAMES = {
    "freightwaves": "FreightWaves",
    "dc-velocity": "DC Velocity",
    "supply-chain-dive": "Supply Chain Dive",
    "ccj-digital": "CCJ",
    "overdrive": "Overdrive",
    "land-line": "Land Line",
    "the-trucker": "The Trucker",
    "heavy-duty-trucking": "Heavy Duty Trucking",
    "the-loadstar": "The Loadstar",
    "gcaptain": "gCaptain",
    "maritime-executive": "Maritime Executive",
    "joc": "JOC",
    "splash247": "Splash247",
    "google-news": "Google News",
  };
  function publisherName(item) {
    const ah = (item.author_handle || "").toLowerCase();
    if (PUBLISHER_NAMES[ah]) return PUBLISHER_NAMES[ah];
    // For Google News rows the source publisher comes through as the
    // <source> element parsed into author_handle (or the literal label).
    if (item.author_handle && item.author_handle !== "google-news") {
      return item.author_handle;
    }
    return "Google News";
  }

  // Generate a branded 1200×630 share card for a news item and trigger
  // a PNG download. Kris uploads it manually on x.com after the intent
  // dialog opens. Keeps the API-free path: no auth, no rate limit, no
  // server. Visual vocabulary mirrors the admin Share-card studio
  // (radar mark + accent stripe + dark navy ground) but stripped to
  // the one template that fits a news headline.
  function downloadNewsShareCard(item) {
    const W = 1200, H = 630;
    const PAD = 64;
    const canvas = document.createElement("canvas");
    canvas.width = W; canvas.height = H;
    const ctx = canvas.getContext("2d");

    // Background — dark navy radial gradient
    const grad = ctx.createRadialGradient(W * 0.30, H * 0.20, 0, W * 0.30, H * 0.20, W * 0.95);
    grad.addColorStop(0,    "#1d2d52");
    grad.addColorStop(0.55, "#0a1224");
    grad.addColorStop(1,    "#050913");
    ctx.fillStyle = grad;
    ctx.fillRect(0, 0, W, H);

    // Subtle grid texture
    ctx.save();
    ctx.globalAlpha = 0.06;
    ctx.strokeStyle = "#5fa9ff";
    ctx.lineWidth = 1;
    for (let x = 0; x <= W; x += 60) { ctx.beginPath(); ctx.moveTo(x, 0); ctx.lineTo(x, H); ctx.stroke(); }
    for (let y = 0; y <= H; y += 60) { ctx.beginPath(); ctx.moveTo(0, y); ctx.lineTo(W, y); ctx.stroke(); }
    ctx.restore();

    // Top accent stripe
    ctx.fillStyle = "#5fa9ff";
    ctx.fillRect(0, 0, W, 4);

    // Radar mark
    const cx = PAD + 18, cy = 74, r = 16;
    ctx.save();
    ctx.strokeStyle = "rgba(255,255,255,0.85)"; ctx.lineWidth = 1.6;
    ctx.beginPath(); ctx.arc(cx, cy, r, 0, Math.PI * 2); ctx.stroke();
    ctx.strokeStyle = "rgba(255,255,255,0.40)"; ctx.lineWidth = 1;
    ctx.beginPath(); ctx.arc(cx, cy, r * 0.62, 0, Math.PI * 2); ctx.stroke();
    ctx.strokeStyle = "rgba(255,255,255,0.30)";
    ctx.beginPath(); ctx.moveTo(cx - r, cy); ctx.lineTo(cx + r, cy); ctx.stroke();
    ctx.beginPath(); ctx.moveTo(cx, cy - r); ctx.lineTo(cx, cy + r); ctx.stroke();
    const wedge = ctx.createLinearGradient(cx, cy, cx + r * 0.86, cy - r * 0.50);
    wedge.addColorStop(0, "rgba(95,169,255,0.65)");
    wedge.addColorStop(1, "rgba(95,169,255,0.00)");
    ctx.fillStyle = wedge;
    ctx.beginPath();
    ctx.moveTo(cx, cy); ctx.lineTo(cx, cy - r);
    ctx.arc(cx, cy, r, -Math.PI / 2, -Math.PI / 4);
    ctx.closePath(); ctx.fill();
    ctx.strokeStyle = "#5fa9ff"; ctx.lineWidth = 1.6;
    ctx.beginPath();
    ctx.moveTo(cx, cy);
    ctx.lineTo(cx + Math.cos(-Math.PI / 4) * r, cy + Math.sin(-Math.PI / 4) * r);
    ctx.stroke();
    ctx.restore();

    // Wordmark
    ctx.fillStyle = "#ffffff";
    ctx.font = "700 22px 'Helvetica Neue', Helvetica, Arial, sans-serif";
    ctx.textBaseline = "alphabetic";
    ctx.fillText("Shipping", PAD + 50, 80);
    ctx.fillStyle = "#5fa9ff";
    ctx.fillText("Clarity", PAD + 50 + ctx.measureText("Shipping").width + 4, 80);

    // Lens framing pill (e.g., "CARRIER SIGNAL")
    const lens = newsLensFor(item);
    const framing = newsFraming(lens);
    if (framing) {
      const text = framing.toUpperCase();
      ctx.font = "700 13px 'Helvetica Neue', Helvetica, Arial, sans-serif";
      const textW = ctx.measureText(text).width;
      const pillW = textW + 28;
      const pillH = 28;
      ctx.fillStyle = "#5fa9ff";
      ctx.beginPath();
      const px = PAD, py = 130;
      ctx.moveTo(px + pillH / 2, py);
      ctx.arcTo(px + pillW, py, px + pillW, py + pillH, pillH / 2);
      ctx.arcTo(px + pillW, py + pillH, px, py + pillH, pillH / 2);
      ctx.arcTo(px, py + pillH, px, py, pillH / 2);
      ctx.arcTo(px, py, px + pillW, py, pillH / 2);
      ctx.closePath(); ctx.fill();
      ctx.fillStyle = "#0a1224";
      ctx.textBaseline = "middle";
      ctx.fillText(text, px + 14, py + pillH / 2 + 1);
    }

    // Headline — serif, wrapped
    ctx.fillStyle = "#ffffff";
    ctx.font = "700 56px Georgia, 'Times New Roman', serif";
    ctx.textBaseline = "top";
    const maxW = W - PAD * 2;
    const headline = (item.raw_title || "").trim();
    const words = headline.split(/\s+/);
    const lines = [];
    let line = "";
    for (const w of words) {
      const test = line ? line + " " + w : w;
      if (ctx.measureText(test).width > maxW && line) {
        lines.push(line); line = w;
      } else {
        line = test;
      }
    }
    if (line) lines.push(line);
    const maxLines = 4;
    const showLines = lines.slice(0, maxLines);
    if (lines.length > maxLines) {
      // Truncate with ellipsis on last line
      let last = showLines[maxLines - 1];
      while (last && ctx.measureText(last + "…").width > maxW) {
        last = last.slice(0, -1);
      }
      showLines[maxLines - 1] = last + "…";
    }
    let y = 195;
    for (const ln of showLines) {
      ctx.fillText(ln, PAD, y);
      y += 68;
    }

    // Footer — publisher attribution + domain
    ctx.fillStyle = "rgba(255,255,255,0.62)";
    ctx.font = "500 18px 'Helvetica Neue', Helvetica, Arial, sans-serif";
    ctx.textBaseline = "alphabetic";
    const pubLine = `via ${publisherName(item)}${item.subforum && item.subforum !== item.author_handle ? ` · ${item.subforum}` : ""}`;
    ctx.fillText(pubLine, PAD, H - 60);
    ctx.fillStyle = "#5fa9ff";
    ctx.font = "700 16px 'Helvetica Neue', Helvetica, Arial, sans-serif";
    ctx.fillText("shippingclarity.com", PAD, H - 32);

    // Right-rule accent
    ctx.fillStyle = "rgba(255,255,255,0.16)";
    ctx.fillRect(W - PAD - 1, 110, 1, H - 200);

    // Trigger download
    const safeName = headline.toLowerCase()
      .replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "").slice(0, 50) || "share-card";
    canvas.toBlob((blob) => {
      if (!blob) return;
      const url = URL.createObjectURL(blob);
      const a = document.createElement("a");
      a.href = url;
      a.download = `sc-${safeName}-1200x630.png`;
      document.body.appendChild(a);
      a.click();
      a.remove();
      setTimeout(() => URL.revokeObjectURL(url), 1000);
    }, "image/png");
  }

  const filteredNews = (newsItems || []).filter((n) =>
    newsLens === "all" ? true : newsLensFor(n) === newsLens
  ).slice(0, 14);
  const lensCounts = NEWS_LENSES.reduce((acc, l) => {
    acc[l.id] = l.id === "all"
      ? newsItems.length
      : newsItems.filter((n) => newsLensFor(n) === l.id).length;
    return acc;
  }, {});

  return (
    <div className="page-clarity">
      <style>{`
        .cd-hero { max-width: 1280px; margin: 0 auto; padding: 32px 24px 16px; }
        .cd-eyebrow {
          font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.32em;
          text-transform: uppercase; color: var(--ink-soft); margin-bottom: 14px;
        }
        .cd-h1 {
          font-family: var(--font-serif); font-size: 44px; line-height: 1.05;
          letter-spacing: -0.02em; margin: 0 0 10px; font-weight: 600;
        }
        @media (max-width: 700px) { .cd-h1 { font-size: 30px; } }
        .cd-dek {
          font-size: 16px; line-height: 1.55; color: var(--ink-soft);
          margin: 0; max-width: 760px;
        }
        .cd-statbar {
          max-width: 1280px; margin: 24px auto 0; padding: 0 24px;
          display: grid; grid-template-columns: repeat(8, 1fr); gap: 0;
          border: 1px solid var(--rule); border-radius: 8px; overflow: hidden;
          background: #fff;
        }
        @media (max-width: 1100px) { .cd-statbar { grid-template-columns: repeat(4, 1fr); } }
        @media (max-width: 600px)  { .cd-statbar { grid-template-columns: repeat(2, 1fr); } }
        .cd-statbar { box-shadow: 0 1px 0 rgba(0,0,0,0.02); }
        .cd-stat-cell {
          padding: 16px 14px; border-right: 1px solid var(--rule); border-bottom: 1px solid var(--rule);
        }
        .cd-stat-cell:last-child { border-right: none; }
        .cd-stat-num {
          font-family: var(--font-serif); font-size: 22px; line-height: 1;
          letter-spacing: -0.02em; color: var(--ink); font-weight: 600;
        }
        .cd-stat-label {
          font-family: var(--font-mono); font-size: 9px; letter-spacing: 0.16em;
          text-transform: uppercase; color: var(--ink-soft); margin-top: 6px;
        }
        .cd-statbar-distress {
          max-width: 1280px; margin: 8px auto 0; padding: 0 24px;
          display: grid; grid-template-columns: repeat(4, 1fr); gap: 0;
          border: 1px solid oklch(0.88 0.05 25); border-radius: 8px; overflow: hidden;
          background: oklch(0.99 0.01 25);
        }
        @media (max-width: 700px) { .cd-statbar-distress { grid-template-columns: repeat(2, 1fr); } }
        .cd-statbar-distress .cd-stat-cell {
          border-right-color: oklch(0.92 0.03 25);
          border-bottom-color: oklch(0.92 0.03 25);
        }
        .cd-statbar-distress .cd-stat-num { color: oklch(0.45 0.20 25); }
        .cd-statbar-caption {
          max-width: 1280px; margin: 14px auto 0; padding: 0 24px;
          font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.18em;
          text-transform: uppercase; color: var(--ink-soft);
        }
        .cd-grid {
          max-width: 1280px; margin: 24px auto; padding: 0 24px;
          display: grid; grid-template-columns: 1fr 1fr; gap: 16px;
        }
        @media (max-width: 900px) { .cd-grid { grid-template-columns: 1fr; } }
        .cd-panel {
          background: #fff; border: 1px solid var(--rule); border-radius: 8px;
          overflow: hidden;
        }
        .cd-panel-h {
          padding: 12px 16px; border-bottom: 1px solid var(--rule);
          display: flex; justify-content: space-between; align-items: baseline;
          font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.18em;
          text-transform: uppercase; color: var(--ink-soft);
          background: var(--paper-2, #f7f4ee);
        }
        .cd-panel-h .more {
          color: var(--ink); cursor: pointer; text-decoration: none;
          border-bottom: 1px solid var(--rule);
        }
        .cd-panel-h .more:hover { border-bottom-color: var(--ink); }
        .cd-news { grid-column: 1 / -1; }
        @media (max-width: 900px) { .cd-news { grid-column: auto; } }
        .cd-news-tabs {
          display: flex; flex-wrap: wrap; gap: 4px;
          padding: 8px 12px; border-bottom: 1px solid var(--rule);
          background: #fafaf6;
        }
        .cd-news-tab {
          font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.12em;
          text-transform: uppercase; color: var(--ink-soft);
          background: transparent; border: 1px solid transparent;
          padding: 4px 10px; border-radius: 999px;
          cursor: pointer; display: inline-flex; align-items: center; gap: 6px;
          transition: background 120ms, color 120ms, border-color 120ms;
        }
        .cd-news-tab:hover { color: var(--ink); border-color: var(--rule); }
        .cd-news-tab.is-on {
          background: var(--ink); color: #fff; border-color: var(--ink);
        }
        .cd-news-tab.is-on .cd-news-tab-c { background: rgba(255,255,255,0.18); color: #fff; }
        .cd-news-tab-c {
          font-size: 9px; padding: 1px 6px; border-radius: 999px;
          background: var(--rule); color: var(--ink-soft);
        }
        .cd-news-row {
          display: flex; align-items: stretch; gap: 0;
          padding: 0; cursor: default;
        }
        .cd-news-link {
          display: block; flex: 1; padding: 10px 14px;
          color: inherit; text-decoration: none;
          border-bottom: 1px solid var(--rule-soft);
        }
        .cd-news-link:hover { background: var(--paper-2, #f7f4ee); }
        .cd-news-share {
          display: inline-flex; align-items: center; gap: 6px;
          padding: 0 14px; flex-shrink: 0;
          color: var(--ink-soft);
          border-left: 1px solid var(--rule-soft);
          border-bottom: 1px solid var(--rule-soft);
          text-decoration: none;
          font-family: var(--font-mono); font-size: 11px;
          letter-spacing: 0.08em; text-transform: uppercase;
          transition: background 120ms, color 120ms;
        }
        .cd-news-share:hover { background: #0f172a; color: #fff; }
        .cd-news-share span[aria-hidden] { font-size: 14px; }
        .cd-news-card {
          display: inline-flex; align-items: center; gap: 6px;
          padding: 0 14px; flex-shrink: 0;
          color: var(--ink-soft);
          background: transparent;
          border: none;
          border-left: 1px solid var(--rule-soft);
          border-bottom: 1px solid var(--rule-soft);
          font-family: var(--font-mono); font-size: 11px;
          letter-spacing: 0.08em; text-transform: uppercase;
          cursor: pointer;
          transition: background 120ms, color 120ms;
        }
        .cd-news-card:hover { background: #5fa9ff; color: #0a1224; }
        .cd-news-card span[aria-hidden] { font-size: 14px; }
        @media (max-width: 600px) {
          .cd-news-share-l { display: none; }
          .cd-news-share, .cd-news-card { padding: 0 10px; }
        }
        .cd-row {
          display: block; width: 100%; text-align: left;
          padding: 10px 16px; border: none; background: transparent;
          border-bottom: 1px solid var(--rule-soft);
          cursor: pointer; font-family: inherit; color: var(--ink);
          text-decoration: none;
        }
        .cd-row:last-child { border-bottom: none; }
        .cd-row:hover { background: var(--paper-2, #f7f4ee); }
        .cd-row-top {
          display: flex; justify-content: space-between; align-items: baseline; gap: 12px;
          margin-bottom: 4px;
        }
        .cd-row-name { font-size: 14px; line-height: 1.3; flex: 1; }
        .cd-row-meta {
          font-family: var(--font-mono); font-size: 10px; color: var(--ink-soft);
          letter-spacing: 0.04em; flex-shrink: 0;
        }
        .cd-row-text {
          font-size: 12px; color: var(--ink-soft); line-height: 1.4;
          display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
          overflow: hidden;
        }
        .cd-pill {
          display: inline-block; padding: 1px 7px; border-radius: 3px;
          font-family: var(--font-mono); font-size: 9px; letter-spacing: 0.08em;
          text-transform: uppercase; font-weight: 700;
        }

        /* ─── DARK THEME OVERRIDES — Pulse / Clarity Dashboard ─────────
             Same navy palette as the rest of the site. Light-touch:
             flips backgrounds + text, doesn't redo chart internals.
        */
        .page-clarity { background: #0f172a; color: #e8edf5; padding-bottom: 96px; }

        /* Hero */
        .cd-eyebrow { color: rgba(255,255,255,0.55); }
        .cd-h1 { color: #ffffff; }
        .cd-h1 em { color: var(--red); }
        .cd-dek { color: rgba(255,255,255,0.72); }

        /* Stat bars */
        .cd-statbar { background: #0a1224; border-color: #1f2937; }
        .cd-stat-cell { border-right-color: #1f2937; border-bottom-color: #1f2937; }
        .cd-stat-num { color: #ffffff; }
        .cd-stat-label { color: rgba(255,255,255,0.55); }
        .cd-statbar-distress {
          background: rgba(239, 68, 68, 0.08); border-color: rgba(239, 68, 68, 0.30);
        }
        .cd-statbar-distress .cd-stat-cell {
          border-right-color: rgba(239, 68, 68, 0.20);
          border-bottom-color: rgba(239, 68, 68, 0.20);
        }
        .cd-statbar-distress .cd-stat-num { color: oklch(0.70 0.20 25); }
        .cd-statbar-caption { color: rgba(255,255,255,0.55); }

        /* Panels */
        .cd-panel { background: rgba(255,255,255,0.03); border-color: #1f2937; }
        .cd-panel-h {
          background: #0a1224; border-bottom-color: #1f2937; color: rgba(255,255,255,0.55);
        }
        .cd-panel-h .more { color: #ffffff; border-bottom-color: #1f2937; }
        .cd-panel-h .more:hover { border-bottom-color: var(--red); color: var(--red); }

        /* Generic dashboard rows / hover states using paper-2 */
        .cd-news-link:hover { background: rgba(255,255,255,0.06) !important; }
        .cd-row:hover { background: rgba(255,255,255,0.06) !important; }
      `}</style>

      <section className="cd-hero">
        <div className="cd-eyebrow"><span className="eyebrow-dot" /> Pulse · Live data wall</div>
        <h1 className="cd-h1">The shipping market, <em>at a glance.</em></h1>
        <p className="cd-dek">
          Eight layers of freight intelligence in one view: shippers indexed,
          carriers verified, lanes priced, signals corroborated, refineries
          monitored, receiver docks mapped. Click any tile to drill into the
          entity behind it.
        </p>
      </section>

      <div className="cd-statbar">
        <div className="cd-stat-cell">
          <div className="cd-stat-num">{fmt(counts.shippers)}</div>
          <div className="cd-stat-label">Shippers indexed</div>
        </div>
        <div className="cd-stat-cell">
          <div className="cd-stat-num">{fmt(counts.facilities)}</div>
          <div className="cd-stat-label">Facilities tracked</div>
        </div>
        <div className="cd-stat-cell">
          <div className="cd-stat-num">{fmt(counts.receivers)}</div>
          <div className="cd-stat-label">Receiver docks</div>
        </div>
        <div className="cd-stat-cell">
          <div className="cd-stat-num">{fmt(counts.carriers)}</div>
          <div className="cd-stat-label">Carriers tracked</div>
        </div>
        <div className="cd-stat-cell">
          <div className="cd-stat-num">{fmt(counts.lanes)}</div>
          <div className="cd-stat-label">Lane rates priced</div>
        </div>
        <div className="cd-stat-cell">
          <div className="cd-stat-num">{fmt(counts.refineries)}</div>
          <div className="cd-stat-label">Refineries monitored</div>
        </div>
        <div className="cd-stat-cell">
          <div className="cd-stat-num">{fmt(counts.intelLast30)}</div>
          <div className="cd-stat-label">Signals · 30d</div>
        </div>
        <div className="cd-stat-cell">
          <div className="cd-stat-num">22</div>
          <div className="cd-stat-label">Freight metros</div>
        </div>
      </div>

      <div className="cd-statbar-caption">⚠ Active distress signals</div>
      <div className="cd-statbar-distress">
        <div className="cd-stat-cell">
          <div className="cd-stat-num">{fmt(counts.bondRisk)}</div>
          <div className="cd-stat-label">Broker bond red flags</div>
        </div>
        <div className="cd-stat-cell">
          <div className="cd-stat-num">{fmt(counts.locksClosed)}</div>
          <div className="cd-stat-label">USACE locks closed</div>
        </div>
        <div className="cd-stat-cell">
          <div className="cd-stat-num">{fmt(counts.warn30)}</div>
          <div className="cd-stat-label">WARN notices · 30d</div>
        </div>
        <div className="cd-stat-cell">
          <div className="cd-stat-num">{fmt(counts.bk30)}</div>
          <div className="cd-stat-label">Business bankruptcies · 30d</div>
        </div>
      </div>

      <div className="cd-grid">
        {/* News firehose — public-facing aggregated headlines from Google News
            + direct publisher RSS, lensed by audience. See ingest-news.py. */}
        <div className="cd-panel cd-news">
          <div className="cd-panel-h">
            <span>News firehose · live</span>
            <span className="cd-row-meta" style={{ fontSize: 10 }}>
              {newsItems.length ? `${newsItems.length} fresh` : "—"}
            </span>
          </div>
          <div className="cd-news-tabs">
            {NEWS_LENSES.map((l) => (
              <button
                key={l.id}
                className={"cd-news-tab" + (newsLens === l.id ? " is-on" : "")}
                onClick={() => setNewsLens(l.id)}
                title={l.framing || "Everything"}
              >
                <span>{l.label}</span>
                <span className="cd-news-tab-c">{lensCounts[l.id] || 0}</span>
              </button>
            ))}
          </div>
          {filteredNews.length === 0 ? (
            <div style={{ padding: 24, textAlign: "center", color: "var(--ink-soft)", fontSize: 13 }}>
              {newsItems.length === 0 ? "Loading the firehose…" : "Nothing in this lens right now."}
            </div>
          ) : (
            filteredNews.map((n) => {
              const lens = newsLensFor(n);
              const framing = newsFraming(lens);
              // Build the X (Twitter) intent URL. We pre-fill the post with
              // the headline + a #freight tag for discoverability; the user
              // can edit before posting. Including the article URL lets X
              // auto-attach the publisher's Open Graph card image — no API
              // call, no auth, no rate limit. Branded share cards live in
              // the admin Share-cards tab (next step: per-news share-card).
              const tweetText = `${n.raw_title}\n\nvia ${publisherName(n)}`;
              const xIntent = "https://x.com/intent/post"
                + "?text=" + encodeURIComponent(tweetText)
                + (n.source_url ? "&url=" + encodeURIComponent(n.source_url) : "");
              return (
                <div key={n.source_id} className="cd-row cd-news-row">
                  <a
                    href={n.source_url || "#"}
                    target="_blank"
                    rel="noopener noreferrer"
                    className="cd-news-link"
                  >
                    <div className="cd-row-top">
                      <span className="cd-row-name" style={{ fontWeight: 600 }}>{n.raw_title}</span>
                      <span className="cd-row-meta">{fmtAge(n.posted_at || new Date().toISOString())}</span>
                    </div>
                    <div className="cd-row-text" style={{ display: "flex", gap: 6, alignItems: "center", flexWrap: "wrap" }}>
                      {framing && (
                        <span className="cd-pill" style={{ background: "#0f172a", color: "#fff" }}>
                          {framing}
                        </span>
                      )}
                      <span style={{ fontFamily: "var(--font-mono)", fontSize: 10, color: "var(--ink-soft)" }}>
                        {publisherName(n)}{n.subforum ? ` · ${n.subforum}` : ""}
                      </span>
                    </div>
                  </a>
                  <button
                    type="button"
                    className="cd-news-card"
                    title="Generate a Shipping Clarity-branded card · upload manually on X compose"
                    aria-label={`Generate share card for "${n.raw_title}"`}
                    onClick={(e) => { e.stopPropagation(); downloadNewsShareCard(n); }}
                  >
                    <span aria-hidden="true">▦</span>
                    <span className="cd-news-share-l">Card</span>
                  </button>
                  <a
                    href={xIntent}
                    target="_blank"
                    rel="noopener noreferrer"
                    className="cd-news-share"
                    title="Post on X · publisher's image attaches via Open Graph card"
                    aria-label={`Share "${n.raw_title}" on X`}
                    onClick={(e) => e.stopPropagation()}
                  >
                    <span aria-hidden="true">𝕏</span>
                    <span className="cd-news-share-l">Post</span>
                  </a>
                </div>
              );
            })
          )}
        </div>

        {/* Recent signals — operator-network ticker (read-only on the public dashboard;
            the full feed lives in the editor admin board → Intel tab) */}
        <div className="cd-panel">
          <div className="cd-panel-h">
            <span>Live signal ticker · last 30 days</span>
          </div>
          {recentSignals.length === 0 ? (
            <div style={{ padding: 24, textAlign: "center", color: "var(--ink-soft)", fontSize: 13 }}>
              Loading signal feed…
            </div>
          ) : (
            recentSignals.map(r => (
              <div key={r.id} className="cd-row" style={{ cursor: "default" }}>
                <div className="cd-row-top">
                  <span className="cd-pill" style={{ background: sevColor(sev(r)), color: "#fff" }}>{sev(r)}</span>
                  <span className="cd-row-meta">{(r.parsed_intel_type || "other").replace(/_/g, " ")} · {fmtAge(r.created_at)}</span>
                </div>
                <div className="cd-row-text">{r.raw_text}</div>
              </div>
            ))
          )}
        </div>

        {/* Hot lanes — rate intelligence */}
        <div className="cd-panel">
          <div className="cd-panel-h">
            <span>Hottest lanes · live rates</span>
            <a href="#/rates" className="more" onClick={(e) => { e.preventDefault(); onNav("rates"); }}>Lane heat →</a>
          </div>
          {hotLanes.length === 0 ? (
            <div style={{ padding: 24, textAlign: "center", color: "var(--ink-soft)", fontSize: 13 }}>
              Loading lane data…
            </div>
          ) : (
            hotLanes.map((l, i) => (
              <a key={i} href="#/rates" className="cd-row"
                onClick={(e) => { e.preventDefault(); onNav("rates"); }}>
                <div className="cd-row-top">
                  <span className="cd-row-name">{l.origin_city}, {l.origin_state} → {l.dest_city}, {l.dest_state}</span>
                  <span className="cd-row-meta" style={{ fontFamily: "var(--font-serif)", fontSize: 14, color: "var(--ink)" }}>
                    ${parseFloat(l.lane_rate_per_mi).toFixed(2)}/mi
                  </span>
                </div>
                <div className="cd-row-text">{l.equipment_type} · {l.heat_band || "—"}</div>
              </a>
            ))
          )}
        </div>

        {/* Top shippers — directory anchor */}
        <div className="cd-panel">
          <div className="cd-panel-h">
            <span>Shippers in the index · enterprise tier</span>
            <a href="#/shippers" className="more" onClick={(e) => { e.preventDefault(); onNav("shippers"); }}>Directory →</a>
          </div>
          {topShippers.length === 0 ? (
            <div style={{ padding: 24, textAlign: "center", color: "var(--ink-soft)", fontSize: 13 }}>
              Loading directory…
            </div>
          ) : (
            topShippers.map(s => (
              <a key={s.slug} href={`#/shipper/${s.slug}`} className="cd-row"
                onClick={(e) => { e.preventDefault(); window.location.hash = `#/shipper/${s.slug}`; }}>
                <div className="cd-row-top">
                  <span className="cd-row-name">{s.canonical_name}</span>
                  <span className="cd-row-meta">{s.size_band || "shipper"}</span>
                </div>
                {s.description && <div className="cd-row-text">{s.description}</div>}
              </a>
            ))
          )}
        </div>

        {/* Risk carriers — verification surface */}
        <div className="cd-panel">
          <div className="cd-panel-h">
            <span>Carriers flagged · verification needed</span>
            <a href="#/find-carrier" className="more" onClick={(e) => { e.preventDefault(); onNav("find-carrier"); }}>Verify →</a>
          </div>
          {riskCarriers.length === 0 ? (
            <div style={{ padding: 24, textAlign: "center", color: "var(--ink-soft)", fontSize: 13 }}>
              Loading verification queue…
            </div>
          ) : (
            riskCarriers.map((c, i) => (
              <a key={i} href="#/find-carrier" className="cd-row"
                onClick={(e) => { e.preventDefault(); onNav("find-carrier"); }}>
                <div className="cd-row-top">
                  <span className="cd-row-name">{c.canonical_name}</span>
                  <span className="cd-row-meta">DOT {c.dot_number || "—"}</span>
                </div>
                <div className="cd-row-text">
                  {c.mc_status === "no_mc_dot_only" && "DOT only · no interstate authority on file"}
                  {c.mc_status === "has_mc_inactive" && "MC authority lapsed · was active, now inactive"}
                </div>
              </a>
            ))
          )}
        </div>
      </div>

      {/* Anchor — keep the radar + alerts the home page already shows below
          so signed-in visitors who are used to the rest of the home flow
          can keep scrolling without losing context. */}
      <BigRadar user={null} onNav={onNav} />
      <TonightsPulse onNav={onNav} />
      <LiveAlertsFeed onNav={onNav} />

      <div style={{ height: 96 }} />
    </div>
  );
}

window.ClarityDashboard = ClarityDashboard;

// =============================================================================
// SHIPPING CLARITY HOME — the all-products showcase. Different from the
// load-board home (now /#/shippers-connect) and the data wall (/#/clarity).
// This page exists to answer "what does Shipping Clarity actually do?" with
// a grid of every product surface plus the credibility proof and contact CTA.
// =============================================================================
function ShippingClarityHomePage({ onNav }) {
  const [counts, setCounts] = useStateH({
    shippers: null, carriers: null, lanes: null, signals: null,
    docks: null, refineries: null,
  });

  useEffectH(() => {
    let alive = true;
    if (!window.SI_DB || !window.SI_DB.raw) return;
    (async () => {
      const [sh, ca, la, sg, dk, rf] = await Promise.all([
        window.SI_DB.raw.count("shippers", "").catch(() => null),
        window.SI_DB.raw.count("entities", "type=eq.carrier").catch(() => null),
        window.SI_DB.raw.count("dat_lane_rates", "").catch(() => null),
        window.SI_DB.raw.count(
          "intel_submissions",
          "status=eq.verified&visibility=eq.public&published_at=not.is.null"
        ).catch(() => null),
        window.SI_DB.raw.count("receiver_locations", "").catch(() => null),
        window.SI_DB.raw.count("refineries", "").catch(() => null),
      ]);
      if (!alive) return;
      setCounts({ shippers: sh, carriers: ca, lanes: la, signals: sg, docks: dk, refineries: rf });
    })();
    return () => { alive = false; };
  }, []);

  const fmt = (n) => n == null ? "—" : n.toLocaleString();

  // Product tiles. Each has an icon, title, one-line proposition, route, and
  // an accent color. Order matters: data products lead, marketplace center,
  // editorial + driver tools at the end.
  const products = [
    {
      key: "wms-software",
      eyebrow: "New · Founding-customer program",
      title: "Shipping Clarity SCE",
      body: "Unified Supply Chain Execution Platform — WMS, TMS, LMS, inventory, picking, carriers, returns, quality. One system that configures itself around how your operation actually works. Built by a 30-year ops veteran.",
      cta: "See the SCE platform",
      accent: "oklch(0.45 0.18 25)",
      onClick: () => onNav("wms-software"),
    },
    {
      key: "wizard",
      eyebrow: "New · Early-access list open",
      title: "The Wizard",
      body: "A 5-minute AI interview, then your team's tools configure themselves around each user. Live on Shipping Clarity SCE today. Salesforce coming Q4 2026, NetSuite + HubSpot in 2027.",
      cta: "Get on the list",
      accent: "oklch(0.50 0.18 25)",
      onClick: () => onNav("wizard"),
    },
    {
      key: "clarity",
      eyebrow: "Live data wall",
      title: "Clarity Dashboard",
      body: "Every layer of the freight network in one view: shippers, carriers, lanes, signals, refineries. The control room.",
      cta: "Open the dashboard",
      accent: "oklch(0.50 0.18 250)",
      onClick: () => onNav("clarity"),
    },
    {
      key: "shippers-connect",
      eyebrow: "Marketplace",
      title: "Shippers Connect Load Board",
      body: "Where shippers post loads and carriers find runs. Direct, no commission, full visibility.",
      cta: "Browse the load board",
      accent: "oklch(0.50 0.20 25)",
      onClick: () => onNav("shippers-connect"),
    },
    {
      key: "rates",
      eyebrow: "Rate intelligence",
      title: "Lane Rates",
      body: "Live $/mi by lane, hot/cold heat bands, headhaul-vs-backhaul asymmetry. Defend a number with a customer.",
      cta: "See the lane heat",
      accent: "oklch(0.55 0.16 50)",
      onClick: () => onNav("rates"),
    },
    {
      key: "markets",
      eyebrow: "Live markets",
      title: "Fuel & Oil Markets",
      body: "Crude futures, diesel retail, futures-vs-pump gap, refinery utilization across all five PADDs, top 30 US refineries.",
      cta: "Open the markets dashboard",
      accent: "oklch(0.55 0.16 145)",
      onClick: () => onNav("markets"),
    },
    {
      key: "find-carrier",
      eyebrow: "Verification",
      title: "Verify a Carrier",
      body: "Authority, safety, fleet, MC status, federal cross-check. Catch the broken chain before it touches your freight.",
      cta: "Run a check",
      accent: "oklch(0.50 0.22 25)",
      onClick: () => onNav("find-carrier"),
    },
    {
      key: "shippers",
      eyebrow: "Directory",
      title: "Shipper Directory",
      body: `${fmt(counts.shippers)} shippers indexed with relationships, facilities, and material events on file.`,
      cta: "Browse shippers",
      accent: "oklch(0.50 0.16 165)",
      onClick: () => onNav("shippers"),
    },
    {
      key: "top100",
      eyebrow: "Company intelligence",
      title: "Top 100 — Carriers & Shippers",
      body: "365 curated dossiers cross-referenced against SEC EDGAR + FMCSA. Trust verdicts, hex US footprint, sealed-intel counts, $499 deep-dive ready.",
      cta: "Browse the Top 100",
      accent: "oklch(0.55 0.18 250)",
      onClick: () => onNav("top100"),
    },
    {
      key: "opportunities",
      eyebrow: "Findings",
      title: "Opportunities",
      body: "Specific actions you can take this quarter — for carriers, shippers, and the broader market.",
      cta: "See findings",
      accent: "oklch(0.50 0.14 145)",
      onClick: () => onNav("opportunities"),
    },
    {
      key: "report",
      eyebrow: "Per metro",
      title: "City Reports",
      body: "Live pulse for 22 freight metros — signals, lane heat, top shippers, carrier hubs, weather, fuel.",
      cta: "Pick a metro",
      accent: "oklch(0.50 0.18 250)",
      onClick: () => onNav("report"),
    },
    {
      key: "risk-report",
      eyebrow: "$499 deep-dive",
      title: "Carrier Risk Report",
      body: "10-page synthesis on any US carrier — financial, regulatory, lane density, operational signal — in 24 hours.",
      cta: "Order a Risk Report",
      accent: "oklch(0.45 0.22 25)",
      onClick: () => onNav("risk-report"),
    },
    {
      key: "drivers",
      eyebrow: "Free for drivers",
      title: "The Yard",
      body: "Detention timer, HOS clock, weigh stations, repair shops, toll passes, carrier hubs. Built for drivers, free forever.",
      cta: "Open The Yard",
      accent: "oklch(0.45 0.16 145)",
      onClick: () => onNav("drivers"),
    },
    {
      key: "insights",
      eyebrow: "Editorial",
      title: "Stories",
      body: "Investigations and trend reports — Hub Group's exposure, the FedEx Ground contractor wave, what nobody else is publishing.",
      cta: "Read the latest",
      accent: "oklch(0.40 0.16 250)",
      onClick: () => onNav("insights"),
    },
    {
      key: "for-carriers",
      eyebrow: "$99/mo subscription",
      title: "For Carriers",
      body: "Claim your profile, earn the green Verified ✓ badge on every reach-out, get listed first when shippers compare carriers.",
      cta: "Claim a profile",
      accent: "oklch(0.50 0.18 165)",
      onClick: () => onNav("for-carriers"),
    },
    {
      key: "methodology",
      eyebrow: "How it works",
      title: "Methodology",
      body: "Nine metrics, four data sources, the trust contract with drivers, and the math behind every score.",
      cta: "Read the method",
      accent: "var(--ink)",
      onClick: () => onNav("methodology"),
    },
  ];

  return (
    <div className="page-sc-home">
      {/* Video strip removed per Kris — was distracting from the new Software pitch.
          Component definition (HomeVideoStrip) is preserved below for easy revert. */}
      <NationalFreightRadar onNav={onNav} />
      <style>{`
        .sch2-hero {
          max-width: 1280px; margin: 0 auto; padding: 56px 24px 24px;
        }
        .sch2-eyebrow {
          font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.32em;
          text-transform: uppercase; color: var(--ink-soft); margin-bottom: 18px;
          display: inline-flex; align-items: center; gap: 10px;
        }
        .sch2-eyebrow .dot { width: 8px; height: 8px; border-radius: 50%;
          background: oklch(0.55 0.18 25); animation: sch2-pulse 1.6s infinite; }
        @keyframes sch2-pulse { 0%,100%{opacity:1} 50%{opacity:0.4} }
        .sch2-h1 {
          font-family: var(--font-serif); font-size: 56px; line-height: 1.04;
          letter-spacing: -0.025em; margin: 0 0 18px; font-weight: 600; color: var(--ink);
          max-width: 940px;
        }
        @media (max-width: 700px) { .sch2-h1 { font-size: 36px; } }
        .sch2-sub {
          margin-top: 8px; font-size: 19px; line-height: 1.55; color: var(--ink-soft);
          max-width: 800px;
        }
        .sch2-statbar {
          max-width: 1280px; margin: 28px auto 0; padding: 0 24px;
          display: grid; grid-template-columns: repeat(6, 1fr); gap: 0;
          border: 1px solid var(--rule); border-radius: 8px; overflow: hidden;
          background: #fff;
        }
        @media (max-width: 900px) { .sch2-statbar { grid-template-columns: repeat(3, 1fr); } }
        @media (max-width: 540px) { .sch2-statbar { grid-template-columns: repeat(2, 1fr); } }
        .sch2-stat-cell {
          padding: 18px 16px; border-right: 1px solid var(--rule); border-bottom: 1px solid var(--rule);
        }
        .sch2-stat-cell:last-child { border-right: none; }
        .sch2-stat-num {
          font-family: var(--font-serif); font-size: 26px; line-height: 1;
          letter-spacing: -0.02em; color: var(--ink); font-weight: 600;
        }
        .sch2-stat-label {
          font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.16em;
          text-transform: uppercase; color: var(--ink-soft); margin-top: 6px;
        }
        .sch2-grid-section { max-width: 1280px; margin: 56px auto 32px; padding: 0 24px; }
        .sch2-grid-eyebrow {
          font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.22em;
          text-transform: uppercase; color: var(--ink-soft); margin-bottom: 8px;
        }
        .sch2-grid-h {
          font-family: var(--font-serif); font-size: 32px; letter-spacing: -0.02em;
          margin: 0 0 28px; line-height: 1.1; color: var(--ink); font-weight: 600;
        }
        .sch2-grid {
          display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px;
        }
        @media (max-width: 1000px) { .sch2-grid { grid-template-columns: repeat(2, 1fr); } }
        @media (max-width: 640px)  { .sch2-grid { grid-template-columns: 1fr; } }
        .sch2-tile {
          display: flex; flex-direction: column; gap: 8px;
          padding: 22px 22px 20px; background: #fff;
          border: 1px solid var(--rule); border-radius: 10px;
          cursor: pointer; transition: border-color 0.15s, box-shadow 0.15s, transform 0.1s;
          font: inherit; text-align: left; color: inherit;
          position: relative; overflow: hidden;
        }
        .sch2-tile:hover {
          border-color: var(--ink-soft);
          box-shadow: 0 6px 20px rgba(0,0,0,0.04);
          transform: translateY(-1px);
        }
        .sch2-tile-accent {
          height: 3px; border-radius: 2px; margin-bottom: 6px;
        }
        .sch2-tile-eyebrow {
          font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.18em;
          text-transform: uppercase; color: var(--ink-soft);
        }
        .sch2-tile-title {
          font-family: var(--font-serif); font-size: 22px; line-height: 1.2;
          letter-spacing: -0.01em; color: var(--ink); margin: 0;
          font-weight: 600;
        }
        .sch2-tile-body {
          font-size: 14px; line-height: 1.5; color: var(--ink-soft);
          margin: 4px 0 12px;
        }
        .sch2-tile-cta {
          font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.08em;
          color: var(--ink); margin-top: auto;
          border-bottom: 1px solid var(--rule);
          align-self: flex-start; padding-bottom: 2px;
        }
        .sch2-tile:hover .sch2-tile-cta { border-bottom-color: var(--ink); }

        .sch2-cta-band {
          max-width: 1280px; margin: 56px auto; padding: 36px 32px;
          background: var(--ink); color: var(--paper); border-radius: 12px;
          display: grid; grid-template-columns: 1fr auto; gap: 24px; align-items: center;
        }
        @media (max-width: 760px) { .sch2-cta-band { grid-template-columns: 1fr; } }
        .sch2-cta-h {
          font-family: var(--font-serif); font-size: 26px; letter-spacing: -0.01em;
          margin: 0 0 8px; line-height: 1.2; font-weight: 600;
        }
        .sch2-cta-sub { color: color-mix(in srgb, var(--paper) 70%, transparent); margin: 0; font-size: 15px; line-height: 1.5; max-width: 640px; }
        .sch2-cta-btn {
          background: var(--paper); color: var(--ink); border: none;
          padding: 14px 22px; border-radius: 8px; font-family: inherit;
          font-size: 14px; font-weight: 600; cursor: pointer;
          transition: opacity 0.15s;
        }
        .sch2-cta-btn:hover { opacity: 0.9; }

        /* ─── DARK THEME OVERRIDES — same navy palette as SCE / Wizard ──
             background       #0f172a   (slate-900, freight-radar map base)
             section alt      #0a1224   (deeper navy)
             border           #1f2937   (slate-800)
             accent           var(--red) → "Shipping Clarity blue"
        */
        .page-sc-home { background: #0f172a; color: #e8edf5; }

        /* Hero block */
        .sch2-eyebrow { color: rgba(255,255,255,0.55); }
        .sch2-h1 { color: #ffffff; }
        .sch2-sub { color: rgba(255,255,255,0.72); }

        /* Stat bar (was white) */
        .sch2-statbar {
          background: #0a1224; border-color: #1f2937;
        }
        .sch2-stat-cell { border-right-color: #1f2937; border-bottom-color: #1f2937; }
        .sch2-stat-num { color: #ffffff; }
        .sch2-stat-label { color: rgba(255,255,255,0.55); }

        /* Products grid */
        .sch2-grid-eyebrow { color: rgba(255,255,255,0.55); }
        .sch2-grid-h { color: #ffffff; }
        .sch2-tile {
          background: rgba(255,255,255,0.03); border-color: #1f2937;
        }
        .sch2-tile:hover {
          border-color: color-mix(in srgb, var(--red) 50%, #1f2937);
          box-shadow: 0 6px 20px rgba(0,0,0,0.35);
          background: rgba(255,255,255,0.05);
        }
        .sch2-tile-eyebrow { color: rgba(255,255,255,0.55); }
        .sch2-tile-title { color: #ffffff; }
        .sch2-tile-body { color: rgba(255,255,255,0.72); }
        .sch2-tile-cta { color: #ffffff; border-bottom-color: #1f2937; }
        .sch2-tile:hover .sch2-tile-cta { border-bottom-color: var(--red); }

        /* CTA band already dark; tighten the look */
        .sch2-cta-band { background: var(--red); }
        .sch2-cta-h { color: #ffffff; }
        .sch2-cta-sub { color: rgba(255,255,255,0.85); }
        .sch2-cta-btn { background: #ffffff; color: var(--red); }

        /* HubGroupProof block has inline styles — override with !important */
        .hgp-section {
          background: rgba(255,255,255,0.03) !important;
          border-color: #1f2937 !important;
          color: #e8edf5;
        }
        .hgp-section h2, .hgp-section h3 { color: #ffffff !important; }
        .hgp-section p, .hgp-section span, .hgp-section div { color: rgba(255,255,255,0.78); }
        .hgp-section em { color: var(--red) !important; }
      `}</style>

      <section className="sch2-hero">
        <div className="sch2-eyebrow"><span className="dot" /> Independent freight intelligence · live</div>
        <h1 className="sch2-h1">
          The shipping market, <em>told straight</em> — plus the load board where shippers and carriers meet direct.
        </h1>
        <p className="sch2-sub">
          Shipping Clarity is the independent intelligence layer for U.S. freight: shippers, carriers, lanes, fuel, refineries, regulators, and the operator-network signal nobody else publishes. Inside it, <strong>Shippers Connect</strong> is the marketplace — direct connections, no commission, no middleman tax on a handshake.
        </p>
      </section>

      <div className="sch2-statbar">
        <div className="sch2-stat-cell">
          <div className="sch2-stat-num">{fmt(counts.shippers)}</div>
          <div className="sch2-stat-label">Shippers indexed</div>
        </div>
        <div className="sch2-stat-cell">
          <div className="sch2-stat-num">{fmt(counts.carriers)}</div>
          <div className="sch2-stat-label">Carriers tracked</div>
        </div>
        <div className="sch2-stat-cell">
          <div className="sch2-stat-num">{fmt(counts.lanes)}</div>
          <div className="sch2-stat-label">Lanes priced</div>
        </div>
        <div className="sch2-stat-cell">
          <div className="sch2-stat-num">{fmt(counts.docks)}</div>
          <div className="sch2-stat-label">Receiver docks</div>
        </div>
        <div className="sch2-stat-cell">
          <div className="sch2-stat-num">{fmt(counts.refineries)}</div>
          <div className="sch2-stat-label">Refineries</div>
        </div>
        <div className="sch2-stat-cell">
          <div className="sch2-stat-num">22</div>
          <div className="sch2-stat-label">Freight metros</div>
        </div>
      </div>

      <section className="sch2-grid-section">
        <div className="sch2-grid-eyebrow">What we make</div>
        <h2 className="sch2-grid-h">Twelve products. One data graph.</h2>
        <div className="sch2-grid">
          {products.map(p => (
            <button key={p.key} className="sch2-tile" onClick={p.onClick}>
              <div className="sch2-tile-accent" style={{ background: p.accent }} />
              <div className="sch2-tile-eyebrow">{p.eyebrow}</div>
              <h3 className="sch2-tile-title">{p.title}</h3>
              <p className="sch2-tile-body">{p.body}</p>
              <span className="sch2-tile-cta">{p.cta} →</span>
            </button>
          ))}
        </div>
      </section>

      {/* Hub Group credibility receipt — stays as the proof anchor */}
      <HubGroupProof onNav={onNav} />

      <div className="sch2-cta-band">
        <div>
          <h3 className="sch2-cta-h">Want a deep-dive on a specific carrier you book?</h3>
          <p className="sch2-cta-sub">
            Z-Score history, full SEC filing scan, court-record creditor pattern, FMCSA inspection trail, lane density, operator-network chatter — all in a 10-page PDF inside 24 hours. $499 per carrier.
          </p>
        </div>
        <button className="sch2-cta-btn" onClick={() => onNav("risk-report")}>
          Order a Risk Report →
        </button>
      </div>

      <div style={{ height: 96 }} />
    </div>
  );
}

window.ShippingClarityHomePage = ShippingClarityHomePage;

// =============================================================================
// NATIONAL FREIGHT RADAR — the wow-factor hero. A dark-mode US Leaflet map
// with three concurrent live layers: signal pulses (last 48h verified intel),
// lane heat polylines (dat_lane_rates), and carrier hub dots (130 hubs).
// New signals animate in with a radar-pulse ring. Auto-refreshes on a 60s
// interval. The signature visual of the platform.
// =============================================================================
const RADAR_CITY_COORDS = {
  "los angeles,ca": [34.0522, -118.2437],
  "chicago,il":     [41.8781, -87.6298],
  "dallas,tx":      [32.7767, -96.7970],
  "atlanta,ga":     [33.7490, -84.3880],
  "new york,ny":    [40.7128, -74.0060],
  "newark,nj":      [40.7357, -74.1724],
  "mcallen,tx":     [26.2034, -98.2300],
  "salinas,ca":     [36.6777, -121.6555],
  "yakima,wa":      [46.6021, -120.5059],
  "lakeland,fl":    [28.0395, -81.9498],
  "detroit,mi":     [42.3314, -83.0458],
  "houston,tx":     [29.7604, -95.3698],
  "memphis,tn":     [35.1495, -90.0490],
  "miami,fl":       [25.7617, -80.1918],
  "philadelphia,pa":[39.9526, -75.1652],
  "phoenix,az":     [33.4484, -112.0740],
  "seattle,wa":     [47.6062, -122.3321],
  "denver,co":      [39.7392, -104.9903],
  "boston,ma":      [42.3601, -71.0589],
  "minneapolis,mn": [44.9778, -93.2650],
  "san francisco,ca":[37.7749, -122.4194],
  "san diego,ca":   [32.7157, -117.1611],
  "portland,or":    [45.5152, -122.6784],
  "tampa,fl":       [27.9506, -82.4572],
  "orlando,fl":     [28.5383, -81.3792],
  "charlotte,nc":   [35.2271, -80.8431],
  "nashville,tn":   [36.1627, -86.7816],
  "austin,tx":      [30.2672, -97.7431],
  "las vegas,nv":   [36.1699, -115.1398],
  "kansas city,mo": [39.0997, -94.5786],
  "indianapolis,in":[39.7684, -86.1581],
  "columbus,oh":    [39.9612, -82.9988],
  "savannah,ga":    [32.0809, -81.0912],
  "charleston,sc":  [32.7765, -79.9311],
  "oakland,ca":     [37.8044, -122.2712],
  "baltimore,md":   [39.2904, -76.6122],
  "norfolk,va":     [36.8508, -76.2859],
  "long beach,ca":  [33.7701, -118.1937],
  "sacramento,ca":  [38.5816, -121.4944],
  // City-id → coords for intel_submissions joins
  "los-angeles":    [34.0522, -118.2437],
  "new-york":       [40.7128, -74.0060],
  "san-francisco":  [37.7749, -122.4194],
  "san-diego":      [32.7157, -117.1611],
  "kansas-city":    [39.0997, -94.5786],
  "las-vegas":      [36.1699, -115.1398],
};
function radarCoordsFor(city, state) {
  if (!city) return null;
  const k1 = `${(city || "").toLowerCase().trim()},${(state || "").toLowerCase().trim()}`;
  if (RADAR_CITY_COORDS[k1]) return RADAR_CITY_COORDS[k1];
  const k2 = (city || "").toLowerCase().trim();
  if (RADAR_CITY_COORDS[k2]) return RADAR_CITY_COORDS[k2];
  return null;
}

// Static lookup for the major commercial-cargo POEs since the CBP API
// doesn't return lat/lng. Used to render border-wait pulses on the radar.
const BORDER_POE_COORDS = {
  "Laredo":                    [27.5036, -99.5075],
  "Otay Mesa":                 [32.5468, -116.9359],
  "Pharr":                     [26.1671, -98.1611],
  "Calexico East":             [32.6722, -115.3886],
  "El Paso":                   [31.7619, -106.4459],
  "Eagle Pass":                [28.7091, -100.4995],
  "Brownsville":               [25.9026, -97.4974],
  "Hidalgo":                   [26.0892, -98.2700],
  "Tecate":                    [32.5773, -116.6300],
  "Buffalo-Niagara Falls":     [42.8995, -78.9097],
  "Detroit":                   [42.3133, -83.0746],
  "Champlain-Rouses Point":    [44.9909, -73.4495],
  "Blaine":                    [49.0006, -122.7567],
  "Port Huron":                [42.9956, -82.4244],
  "Sault Sainte Marie":        [46.5034, -84.3461],
  "Sweetgrass":                [49.0014, -111.9667],
  "Pembina":                   [48.9685, -97.2417],
  "Calais":                    [45.1856, -67.2669],
  "Houlton":                   [46.1262, -67.8367],
};

function NationalFreightRadar({ onNav }) {
  const [signals, setSignals] = useStateH([]);
  const [lanes, setLanes] = useStateH([]);
  const [hubs, setHubs] = useStateH([]);
  const [locks, setLocks] = useStateH([]);
  const [borders, setBorders] = useStateH([]);
  const [counts, setCounts] = useStateH({ s48: 0, lanes: 0, hubs: 0, locks: 0, borders: 0 });
  const [activeLayers, setActiveLayers] = useStateH({
    signals: true, lanes: true, hubs: true, locks: true, borders: true,
  });
  const containerRef = React.useRef(null);
  const mapRef = React.useRef(null);
  const layersRef = React.useRef({ signal: null, lane: null, hub: null, pulse: null, lock: null, border: null });

  useEffectH(() => {
    let alive = true;
    if (!window.SI_DB || !window.SI_DB.raw) return;
    const load = async () => {
      const cutoff = new Date(Date.now() - 48 * 3600 * 1000).toISOString();
      const [sig, ln, hb, lk, bw] = await Promise.all([
        window.SI_DB.raw.select(
          "intel_submissions",
          "select=id,parsed_carrier,parsed_intel_type,severity,raw_text,created_at,city_id"
          + "&status=eq.verified&visibility=eq.public&city_id=not.is.null"
          + `&created_at=gte.${encodeURIComponent(cutoff)}&order=created_at.desc&limit=80`
        ).catch(() => []),
        window.SI_DB.raw.select(
          "dat_lane_rates",
          "select=*&order=lane_rate_per_mi.desc&limit=40"
        ).catch(() => []),
        window.SI_DB.raw.select(
          "entities",
          "select=name,lat,lng,parent_id&type=eq.facility_xdock&lat=not.is.null&limit=200"
        ).catch(() => []),
        // USACE locks currently disrupted (closed/restricted) — drop normal/open locks
        window.SI_DB.raw.select(
          "waterway_locks_now",
          "select=lock_id,lock_name,river,state,status,closure_reason,avg_wait_hours,lat,lng,observed_at"
          + "&status=in.(closed,restricted)&lat=not.is.null&limit=100"
        ).catch(() => []),
        // CBP commercial-lane delays > 60 minutes — the freight-impacting ones
        window.SI_DB.raw.select(
          "cbp_freight_waits_now",
          "select=port_number,port_name,border,state,lane_subtype,delay_minutes,lanes_open,status,observed_at"
          + "&delay_minutes=gte.60&lane_subtype=eq.standard&limit=60"
        ).catch(() => []),
      ]);
      if (!alive) return;
      setSignals(Array.isArray(sig) ? sig : []);
      setLanes(Array.isArray(ln) ? ln : []);
      setHubs(Array.isArray(hb) ? hb : []);
      setLocks(Array.isArray(lk) ? lk : []);
      setBorders(Array.isArray(bw) ? bw : []);
      setCounts({
        s48: (sig || []).length,
        lanes: (ln || []).length,
        hubs: (hb || []).length,
        locks: (lk || []).length,
        borders: (bw || []).length,
      });
    };
    load();
    const t = setInterval(load, 60000);  // refresh every 60s
    return () => { alive = false; clearInterval(t); };
  }, []);

  // Mount the Leaflet map once
  useEffectH(() => {
    if (!containerRef.current || !window.L || mapRef.current) return;
    const map = window.L.map(containerRef.current, {
      center: [38.5, -96], zoom: 4,
      scrollWheelZoom: false, attributionControl: false,
      zoomControl: false, dragging: true,
      worldCopyJump: false, fadeAnimation: false,
    });
    // Dark basemap — Carto Voyager Dark
    window.L.tileLayer(
      "https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png",
      { attribution: "© OpenStreetMap · © CARTO", subdomains: "abcd", maxZoom: 10, noWrap: true }
    ).addTo(map);
    mapRef.current = map;
    setTimeout(() => map.invalidateSize(), 100);
    return () => { map.remove(); mapRef.current = null; };
  }, []);

  // Re-render the layers when data or visibility changes
  useEffectH(() => {
    const map = mapRef.current;
    if (!map || !window.L) return;

    // Clear existing layers
    Object.values(layersRef.current).forEach(layer => {
      if (layer && map.hasLayer(layer)) map.removeLayer(layer);
    });
    layersRef.current = { signal: null, lane: null, hub: null, pulse: null };

    // Lane polylines — done first so they sit beneath everything else
    if (activeLayers.lanes) {
      const laneGroup = window.L.layerGroup();
      lanes.forEach(l => {
        const a = radarCoordsFor(l.origin_city, l.origin_state);
        const b = radarCoordsFor(l.dest_city, l.dest_state);
        if (!a || !b) return;
        const rate = parseFloat(l.lane_rate_per_mi) || 2;
        const color = l.heat_band === "hot" ? "#ef4444"
                    : l.heat_band === "cold" ? "#3b82f6"
                    : "#94a3b8";
        const weight = Math.min(5, Math.max(1.2, rate * 0.9));
        const line = window.L.polyline([a, b], {
          color, weight, opacity: 0.55, smoothFactor: 1,
        });
        line.bindPopup(
          `<div style="font-family:system-ui;font-size:12px;color:#fff;background:#0f172a;padding:6px 10px;border-radius:4px;border:1px solid #334155">
            <div style="font-weight:600">${l.origin_city} → ${l.dest_city}</div>
            <div style="opacity:0.8;font-size:11px">$${rate.toFixed(2)}/mi · ${l.equipment_type} · ${l.heat_band}</div>
          </div>`
        );
        laneGroup.addLayer(line);
      });
      laneGroup.addTo(map);
      layersRef.current.lane = laneGroup;
    }

    // Carrier hub dots — small, faint
    if (activeLayers.hubs) {
      const hubGroup = window.L.layerGroup();
      hubs.forEach(h => {
        if (h.lat == null || h.lng == null) return;
        const dot = window.L.circleMarker([h.lat, h.lng], {
          radius: 2.5, color: "#64748b", weight: 0.5,
          fillColor: "#64748b", fillOpacity: 0.6,
        });
        dot.bindTooltip(h.name || "Carrier hub", { sticky: true, opacity: 0.9 });
        hubGroup.addLayer(dot);
      });
      hubGroup.addTo(map);
      layersRef.current.hub = hubGroup;
    }

    // Signal pulses — colored by severity, with radar-style animation rings
    if (activeLayers.signals) {
      const sigGroup = window.L.layerGroup();
      const pulseGroup = window.L.layerGroup();
      signals.forEach(s => {
        const coords = radarCoordsFor(s.city_id);
        if (!coords) return;
        const sev = s.severity || "low";
        const color = sev === "critical" ? "#ef4444"
                    : sev === "high" ? "#f97316"
                    : sev === "moderate" ? "#eab308"
                    : "#22d3ee";
        const radius = sev === "critical" ? 7 : sev === "high" ? 5.5 : sev === "moderate" ? 4 : 3;
        // Static dot
        const dot = window.L.circleMarker(coords, {
          radius, color: "#fff", weight: 1,
          fillColor: color, fillOpacity: 0.92,
        });
        dot.bindPopup(
          `<div style="font-family:system-ui;font-size:12px;color:#fff;background:#0f172a;padding:8px 12px;border-radius:4px;border:1px solid #334155;max-width:280px">
            <div style="font-family:ui-monospace,Menlo,monospace;font-size:9px;letter-spacing:0.1em;text-transform:uppercase;color:${color};margin-bottom:4px">${sev} · ${(s.parsed_intel_type || "other").replace(/_/g, " ")}</div>
            <div style="font-size:13px;line-height:1.4">${(s.raw_text || "").slice(0, 200)}</div>
          </div>`
        );
        sigGroup.addLayer(dot);

        // Animated pulse ring — only for high/critical, only on the most
        // recent ones. Rendered as expanding/fading divs over the marker.
        if ((sev === "critical" || sev === "high") && pulseGroup) {
          const pulse = window.L.divIcon({
            className: "fr-pulse",
            html: `<div class="fr-pulse-ring" style="--c:${color}"></div>`,
            iconSize: [40, 40],
            iconAnchor: [20, 20],
          });
          pulseGroup.addLayer(window.L.marker(coords, { icon: pulse, interactive: false }));
        }
      });
      pulseGroup.addTo(map);
      sigGroup.addTo(map);
      layersRef.current.signal = sigGroup;
      layersRef.current.pulse = pulseGroup;
    }

    // USACE locks currently disrupted — red square markers with pulse rings
    if (activeLayers.locks) {
      const lockGroup = window.L.layerGroup();
      locks.forEach(l => {
        if (l.lat == null || l.lng == null) return;
        const isClosed = l.status === "closed";
        const color = isClosed ? "#ef4444" : "#f97316";
        const marker = window.L.circleMarker([l.lat, l.lng], {
          radius: isClosed ? 6 : 5,
          color: "#fff", weight: 1.5,
          fillColor: color, fillOpacity: 0.95,
        });
        const reason = (l.closure_reason || "").replace(/_/g, " ") || "—";
        const wait = l.avg_wait_hours != null ? `${parseFloat(l.avg_wait_hours).toFixed(1)} h avg wait` : "";
        marker.bindPopup(
          `<div style="font-family:system-ui;font-size:12px;color:#fff;background:#0f172a;padding:8px 12px;border-radius:4px;border:1px solid #334155;max-width:260px">
            <div style="font-family:ui-monospace,Menlo,monospace;font-size:9px;letter-spacing:0.1em;text-transform:uppercase;color:${color};margin-bottom:4px">${l.status} · barge lock</div>
            <div style="font-weight:600;font-size:13px">${l.lock_name}</div>
            <div style="opacity:0.8;font-size:11px;margin-top:2px">${[l.river, l.state].filter(Boolean).join(" · ") || "—"}</div>
            <div style="opacity:0.8;font-size:11px;margin-top:4px">Reason: ${reason}${wait ? " · " + wait : ""}</div>
          </div>`
        );
        lockGroup.addLayer(marker);
        // Pulse ring on closed locks (most disruptive)
        if (isClosed) {
          const pulse = window.L.divIcon({
            className: "fr-pulse",
            html: `<div class="fr-pulse-ring" style="--c:${color}"></div>`,
            iconSize: [40, 40], iconAnchor: [20, 20],
          });
          lockGroup.addLayer(window.L.marker([l.lat, l.lng], { icon: pulse, interactive: false }));
        }
      });
      lockGroup.addTo(map);
      layersRef.current.lock = lockGroup;
    }

    // CBP commercial-cargo waits — amber rings on POEs with > 60 min delay
    if (activeLayers.borders) {
      const borderGroup = window.L.layerGroup();
      borders.forEach(b => {
        const coords = BORDER_POE_COORDS[b.port_name];
        if (!coords) return;
        const min = parseInt(b.delay_minutes || 0, 10);
        const isSevere = min >= 120;
        const color = isSevere ? "#ef4444" : "#f59e0b";
        const marker = window.L.circleMarker(coords, {
          radius: isSevere ? 7 : 5.5,
          color: "#fff", weight: 1.5,
          fillColor: color, fillOpacity: 0.95,
        });
        marker.bindPopup(
          `<div style="font-family:system-ui;font-size:12px;color:#fff;background:#0f172a;padding:8px 12px;border-radius:4px;border:1px solid #334155;max-width:240px">
            <div style="font-family:ui-monospace,Menlo,monospace;font-size:9px;letter-spacing:0.1em;text-transform:uppercase;color:${color};margin-bottom:4px">${b.border} border · cargo</div>
            <div style="font-weight:600;font-size:13px">${b.port_name}</div>
            <div style="opacity:0.9;font-size:13px;margin-top:4px"><strong>${min} min</strong> commercial standard wait</div>
            ${b.lanes_open != null ? `<div style="opacity:0.7;font-size:11px;margin-top:2px">${b.lanes_open} lanes open</div>` : ""}
          </div>`
        );
        borderGroup.addLayer(marker);
        if (isSevere) {
          const pulse = window.L.divIcon({
            className: "fr-pulse",
            html: `<div class="fr-pulse-ring" style="--c:${color}"></div>`,
            iconSize: [40, 40], iconAnchor: [20, 20],
          });
          borderGroup.addLayer(window.L.marker(coords, { icon: pulse, interactive: false }));
        }
      });
      borderGroup.addTo(map);
      layersRef.current.border = borderGroup;
    }
  }, [signals, lanes, hubs, locks, borders, activeLayers]);

  return (
    <section className="freight-radar">
      <style>{`
        .freight-radar {
          position: relative;
          background: #0f172a;
          color: #f1f5f9;
          overflow: hidden;
          border-bottom: 1px solid #1e293b;
        }
        .fr-inner {
          position: relative;
          max-width: 1280px;
          margin: 0 auto;
          padding: 24px 24px 0;
        }
        .fr-head {
          display: flex; justify-content: space-between; align-items: flex-end;
          flex-wrap: wrap; gap: 24px;
          padding-bottom: 16px;
        }
        .fr-eyebrow {
          font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.32em;
          text-transform: uppercase; color: #94a3b8; margin-bottom: 8px;
          display: inline-flex; align-items: center; gap: 10px;
        }
        .fr-eyebrow .dot {
          width: 8px; height: 8px; border-radius: 50%;
          background: #ef4444; box-shadow: 0 0 0 0 rgba(239,68,68,0.4);
          animation: fr-blink 1.4s infinite;
        }
        @keyframes fr-blink {
          0%, 100% { box-shadow: 0 0 0 0 rgba(239,68,68,0.4); }
          50%      { box-shadow: 0 0 0 6px rgba(239,68,68,0); }
        }
        .fr-h1 {
          font-family: var(--font-serif); font-size: 38px; line-height: 1.05;
          letter-spacing: -0.025em; margin: 0; color: #fff; font-weight: 600;
          max-width: 720px;
        }
        @media (max-width: 700px) { .fr-h1 { font-size: 26px; } }
        .fr-stats {
          display: flex; gap: 0;
          border: 1px solid #1e293b; border-radius: 8px; overflow: hidden;
          background: rgba(15,23,42,0.6); backdrop-filter: blur(4px);
        }
        .fr-stat {
          padding: 12px 18px; border-right: 1px solid #1e293b;
        }
        .fr-stat:last-child { border-right: none; }
        .fr-stat-num {
          font-family: var(--font-serif); font-size: 22px; line-height: 1;
          letter-spacing: -0.01em; color: #fff; font-weight: 600;
        }
        .fr-stat-label {
          font-family: var(--font-mono); font-size: 9px; letter-spacing: 0.16em;
          text-transform: uppercase; color: #94a3b8; margin-top: 6px;
        }
        .fr-map-wrap {
          position: relative;
          margin-top: 0;
          height: 460px;
          border-top: 1px solid #1e293b;
        }
        @media (max-width: 700px) { .fr-map-wrap { height: 320px; } }
        .fr-map { width: 100%; height: 100%; background: #0f172a; }

        .fr-legend {
          position: absolute; left: 16px; bottom: 16px;
          background: rgba(15,23,42,0.85);
          border: 1px solid #334155; border-radius: 6px;
          padding: 10px 14px; backdrop-filter: blur(8px);
          font-size: 11px; color: #cbd5e1;
          z-index: 400; max-width: 220px;
        }
        .fr-legend-row { display: flex; align-items: center; gap: 8px; margin: 4px 0; }
        .fr-legend-dot { width: 10px; height: 10px; border-radius: 50%; }
        .fr-legend-line { width: 18px; height: 2px; }

        .fr-toggles {
          position: absolute; right: 16px; bottom: 16px;
          background: rgba(15,23,42,0.85);
          border: 1px solid #334155; border-radius: 6px;
          padding: 6px; backdrop-filter: blur(8px);
          display: flex; gap: 4px;
          z-index: 400;
        }
        .fr-toggle {
          background: transparent; color: #cbd5e1;
          border: 1px solid transparent; border-radius: 4px;
          padding: 5px 10px; font-family: var(--font-mono);
          font-size: 10px; letter-spacing: 0.1em; text-transform: uppercase;
          cursor: pointer; font-weight: 600;
        }
        .fr-toggle.active {
          background: #f1f5f9; color: #0f172a; border-color: #f1f5f9;
        }
        .fr-toggle:not(.active):hover { background: #1e293b; color: #fff; }

        /* Pulse ring animation */
        .fr-pulse-ring {
          width: 40px; height: 40px; border-radius: 50%;
          border: 2px solid var(--c); opacity: 0.7;
          animation: fr-ping 2.4s infinite;
        }
        @keyframes fr-ping {
          0%   { transform: scale(0.3); opacity: 0.85; }
          80%  { transform: scale(2.2); opacity: 0; }
          100% { transform: scale(2.2); opacity: 0; }
        }

        /* Override Leaflet popup styling for dark theme */
        .freight-radar .leaflet-popup-content-wrapper,
        .freight-radar .leaflet-popup-tip {
          background: transparent; box-shadow: none; padding: 0;
        }
        .freight-radar .leaflet-popup-content { margin: 0; }
        .freight-radar .leaflet-control-attribution {
          background: rgba(15,23,42,0.7); color: #94a3b8;
          font-size: 9px; padding: 2px 6px;
        }
        .freight-radar .leaflet-control-attribution a { color: #94a3b8; }
      `}</style>
      <div className="fr-inner">
        <div className="fr-head">
          <div>
            <div className="fr-eyebrow"><span className="dot" /> National Freight Radar · live</div>
            <h2 className="fr-h1">
              The U.S. freight network, <em>watched in real time.</em>
            </h2>
          </div>
          <div className="fr-stats">
            <div className="fr-stat">
              <div className="fr-stat-num">{counts.s48}</div>
              <div className="fr-stat-label">Signals · 48h</div>
            </div>
            <div className="fr-stat">
              <div className="fr-stat-num">{counts.lanes}</div>
              <div className="fr-stat-label">Lanes priced</div>
            </div>
            <div className="fr-stat">
              <div className="fr-stat-num">{counts.hubs}</div>
              <div className="fr-stat-label">Carrier hubs</div>
            </div>
            <div className="fr-stat">
              <div className="fr-stat-num">{counts.locks}</div>
              <div className="fr-stat-label">Lock disruptions</div>
            </div>
            <div className="fr-stat">
              <div className="fr-stat-num">{counts.borders}</div>
              <div className="fr-stat-label">Border delays</div>
            </div>
          </div>
        </div>
      </div>
      <div className="fr-map-wrap">
        <div className="fr-map" ref={containerRef} />
        <div className="fr-legend">
          <div style={{ fontFamily: "var(--font-mono)", fontSize: 9, letterSpacing: "0.16em", textTransform: "uppercase", color: "#94a3b8", marginBottom: 6 }}>Legend</div>
          <div className="fr-legend-row"><span className="fr-legend-dot" style={{ background: "#ef4444" }} /> Critical signal</div>
          <div className="fr-legend-row"><span className="fr-legend-dot" style={{ background: "#f97316" }} /> High signal</div>
          <div className="fr-legend-row"><span className="fr-legend-line" style={{ background: "#ef4444" }} /> Hot lane</div>
          <div className="fr-legend-row"><span className="fr-legend-line" style={{ background: "#3b82f6" }} /> Cold lane</div>
          <div className="fr-legend-row"><span className="fr-legend-dot" style={{ background: "#64748b", opacity: 0.6 }} /> Carrier hub</div>
          <div className="fr-legend-row"><span className="fr-legend-dot" style={{ background: "#ef4444" }} /> Lock closed (barge → truck)</div>
          <div className="fr-legend-row"><span className="fr-legend-dot" style={{ background: "#f59e0b" }} /> Border wait &gt; 60 min</div>
        </div>
        <div className="fr-toggles">
          <button className={`fr-toggle ${activeLayers.signals ? "active" : ""}`}
            onClick={() => setActiveLayers(l => ({ ...l, signals: !l.signals }))}>Signals</button>
          <button className={`fr-toggle ${activeLayers.lanes ? "active" : ""}`}
            onClick={() => setActiveLayers(l => ({ ...l, lanes: !l.lanes }))}>Lanes</button>
          <button className={`fr-toggle ${activeLayers.hubs ? "active" : ""}`}
            onClick={() => setActiveLayers(l => ({ ...l, hubs: !l.hubs }))}>Hubs</button>
          <button className={`fr-toggle ${activeLayers.locks ? "active" : ""}`}
            onClick={() => setActiveLayers(l => ({ ...l, locks: !l.locks }))}>Locks</button>
          <button className={`fr-toggle ${activeLayers.borders ? "active" : ""}`}
            onClick={() => setActiveLayers(l => ({ ...l, borders: !l.borders }))}>Borders</button>
        </div>
      </div>
    </section>
  );
}

window.NationalFreightRadar = NationalFreightRadar;

// =============================================================================
// STEP ICON — freight-themed numbered visual for the "How it works" steps.
// One theme is picked once per page-load and used consistently for all
// three steps in that view (so the icons feel like a set, not a salad).
// Refreshing the page rolls a new theme.
// =============================================================================

// Drivers asked for one consistent professional icon — no rotation, no
// children's-toy variety. Mile marker is universal: every interstate has
// them, instantly recognized. Holding the other variants (exit-sign /
// smoke-stack / fuel-pump / gear-shift) in code as future-options but
// not exposing them.
const STEP_THEME = "mile-marker";

function StepIcon({ n }) {
  const t = STEP_THEME;
  return (
    <div className="sch-step-icon" aria-label={`Step ${n}`} title={`Step ${n} · ${t}`}>
      <style>{`
        .sch-step-icon {
          width: 70px; height: 86px; margin-bottom: 16px;
          display: flex; align-items: center; justify-content: center;
          position: relative;
          filter: drop-shadow(0 4px 6px rgba(15,23,42,0.10));
        }
        .sch-step-icon svg { width: 100%; height: 100%; display: block; overflow: visible; }
        .sch-step-icon .num {
          font-family: var(--font-serif); font-weight: 800;
          letter-spacing: -0.03em;
        }
        @keyframes step-puff {
          0%   { transform: translateY(0) scale(1);   opacity: 0.85; }
          100% { transform: translateY(-12px) scale(1.4); opacity: 0; }
        }
        .smoke-puff { animation: step-puff 2.6s ease-out infinite; transform-origin: center; }
      `}</style>
      {t === "mile-marker"   && <MileMarker n={n} />}
      {t === "exit-sign"     && <ExitSign n={n} />}
      {t === "smoke-stack"   && <SmokeStack n={n} />}
      {t === "fuel-pump"     && <FuelPump n={n} />}
      {t === "gear-shift"    && <GearShift n={n} />}
    </div>
  );
}

// Highway-style mile marker — green pentagon with white "MILE" + number.
function MileMarker({ n }) {
  return (
    <svg viewBox="0 0 70 86">
      <path d="M5 8 H65 V60 L35 80 L5 60 Z" fill="#10643a" stroke="#0d4f2e" strokeWidth="2" />
      <text x="35" y="28" textAnchor="middle" fill="#fff" fontFamily="Helvetica, Arial, sans-serif"
            fontSize="11" fontWeight="700" letterSpacing="0.18em">MILE</text>
      <text x="35" y="58" textAnchor="middle" fill="#fff"
            className="num" fontSize="32">{n}</text>
    </svg>
  );
}

// Highway exit sign — yellow EXIT tab + number on green field.
function ExitSign({ n }) {
  return (
    <svg viewBox="0 0 70 86">
      <rect x="2" y="22" width="66" height="56" rx="6" fill="#10643a" stroke="#0d4f2e" strokeWidth="2" />
      <rect x="14" y="6" width="42" height="22" rx="3" fill="#f5c945" stroke="#a17f06" strokeWidth="1.5" />
      <text x="35" y="22" textAnchor="middle" fill="#1a1a1a" fontFamily="Helvetica, Arial, sans-serif"
            fontSize="13" fontWeight="800" letterSpacing="0.10em">EXIT</text>
      <text x="35" y="62" textAnchor="middle" fill="#fff"
            className="num" fontSize="34">{n}</text>
    </svg>
  );
}

// Industrial smoke stack with rising puffs — number lives on the stack.
function SmokeStack({ n }) {
  return (
    <svg viewBox="0 0 70 86">
      {/* puffs (rising) */}
      <circle className="smoke-puff" cx="34" cy="20" r="6"  fill="#cdd5e0" style={{ animationDelay: "0s"   }} />
      <circle className="smoke-puff" cx="40" cy="16" r="4"  fill="#cdd5e0" style={{ animationDelay: "0.6s" }} />
      <circle className="smoke-puff" cx="28" cy="14" r="5"  fill="#cdd5e0" style={{ animationDelay: "1.2s" }} />
      {/* stack */}
      <rect x="22" y="28" width="26" height="50" fill="#a64119" stroke="#7d2e10" strokeWidth="2" />
      {/* lip */}
      <rect x="18" y="26" width="34" height="6" fill="#7d2e10" />
      {/* base */}
      <rect x="14" y="76" width="42" height="6" fill="#3a2010" />
      <text x="35" y="60" textAnchor="middle" fill="#fff"
            className="num" fontSize="26">{n}</text>
    </svg>
  );
}

// Diesel fuel pump — yellow body, pump handle, number on the side.
function FuelPump({ n }) {
  return (
    <svg viewBox="0 0 70 86">
      {/* base */}
      <rect x="10" y="78" width="46" height="4" fill="#3a3a3a" />
      {/* body */}
      <rect x="14" y="22" width="38" height="58" rx="3" fill="#f5c945" stroke="#a17f06" strokeWidth="2" />
      {/* digital readout */}
      <rect x="20" y="28" width="26" height="14" fill="#0a1a0a" />
      <text x="33" y="38" textAnchor="middle" fill="#7af56b" fontFamily="ui-monospace, monospace"
            fontSize="9" fontWeight="700">DIESEL</text>
      {/* number */}
      <text x="33" y="68" textAnchor="middle" fill="#1a1a1a"
            className="num" fontSize="22">{n}</text>
      {/* hose */}
      <path d="M52 32 Q62 36 60 56" stroke="#1a1a1a" strokeWidth="3" fill="none" strokeLinecap="round" />
      {/* nozzle */}
      <rect x="56" y="54" width="9" height="14" rx="2" fill="#1a1a1a" />
    </svg>
  );
}

// Manual gear shift knob — round ball with labeled number on top.
function GearShift({ n }) {
  return (
    <svg viewBox="0 0 70 86">
      {/* base plate */}
      <ellipse cx="35" cy="80" rx="20" ry="4" fill="#1a1a1a" />
      {/* shaft */}
      <rect x="32" y="44" width="6" height="36" fill="#444" />
      <rect x="30" y="42" width="10" height="4" fill="#666" />
      {/* knob */}
      <circle cx="35" cy="30" r="22" fill="#0a1224" stroke="#5fa9ff" strokeWidth="2" />
      <circle cx="35" cy="30" r="22" fill="url(#knob-grad)" />
      <defs>
        <radialGradient id="knob-grad" cx="0.35" cy="0.30">
          <stop offset="0" stopColor="#5fa9ff" stopOpacity="0.55" />
          <stop offset="1" stopColor="#0a1224" stopOpacity="0" />
        </radialGradient>
      </defs>
      <text x="35" y="38" textAnchor="middle" fill="#fff"
            className="num" fontSize="22">{n}</text>
    </svg>
  );
}

// =============================================================================
// HOME VIDEO STRIP — pinned-to-home videos posted by the editor.
// Sits above the freight radar. Holds up to 3 published+featured rows.
// Self-hides when nothing is featured. Featured embeds get an iframe;
// MP4 uploads get a poster-with-play-overlay (no MP4 bytes loaded
// until the user clicks through — egress-friendly).
// =============================================================================

const HARDCODED_HOME_VIDEOS = [
  {
    slug: "hub-group-decade-nonpayment",
    embed_url: "https://www.youtube.com/embed/ywMHxBJeH3U",
    youtube_url: "https://youtu.be/ywMHxBJeH3U",
    title: "Hub Group shows over a decade of continued non payment to Carriers",
    published_at: null,
    duration_seconds: null,
  },
  {
    slug: "ups-closes-50-distribution-centers",
    embed_url: "https://www.youtube.com/embed/75tcYshTRX4",
    youtube_url: "https://youtu.be/75tcYshTRX4",
    title: "UPS Closes over 50 Distribution Centers",
    published_at: null,
    duration_seconds: null,
  },
];

function HomeVideoStrip({ onNav }) {
  const videos = HARDCODED_HOME_VIDEOS;
  const isAdmin = false;

  return (
    <section className="hv-strip">
      <style>{`
        .hv-strip {
          max-width: 1280px; margin: 0 auto; padding: 20px 24px 0;
        }
        .hv-strip-head {
          display: flex; align-items: baseline; justify-content: space-between;
          gap: 12px; margin-bottom: 10px;
        }
        .hv-strip-eyebrow {
          font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.22em;
          text-transform: uppercase; color: var(--ink-soft); font-weight: 600;
          display: inline-flex; align-items: center; gap: 8px;
        }
        .hv-strip-eyebrow .dot {
          width: 6px; height: 6px; border-radius: 50%;
          background: #ef4444; animation: hv-pulse 1.6s infinite;
        }
        @keyframes hv-pulse { 0%,100%{opacity:1} 50%{opacity:0.35} }
        .hv-strip-grid {
          display: grid; grid-template-columns: repeat(2, 1fr); gap: 14px;
        }
        @media (max-width: 760px) {
          .hv-strip-grid { grid-template-columns: 1fr; }
        }
        .hv-card {
          display: block; text-decoration: none; color: inherit;
          background: rgba(15,23,42,0.04); border: 1px solid rgba(15,23,42,0.10);
          border-radius: 6px; overflow: hidden; transition: transform 140ms, box-shadow 140ms;
          cursor: pointer;
        }
        .hv-card:hover {
          transform: translateY(-2px);
          box-shadow: 0 10px 28px rgba(15,23,42,0.12);
          border-color: rgba(15,23,42,0.22);
        }
        .hv-thumb {
          position: relative; width: 100%; aspect-ratio: 16 / 9;
          background: linear-gradient(135deg, #1d2d52 0%, #0a1224 100%);
          display: flex; align-items: center; justify-content: center;
          overflow: hidden;
        }
        .hv-title-card {
          position: absolute; inset: 0; padding: 20px 22px 18px;
          display: flex; flex-direction: column; justify-content: space-between;
          background: linear-gradient(140deg, #0f1e3d 0%, #081428 60%, #060e1e 100%);
        }
        .hv-tc-top {
          display: flex; align-items: center; gap: 8px;
        }
        .hv-tc-logo {
          font-family: var(--font-serif); font-size: 11px; font-weight: 700;
          color: rgba(255,255,255,0.55); letter-spacing: 0.01em;
        }
        .hv-tc-logo em { font-style: italic; color: #ef4444; }
        .hv-tc-eyebrow {
          font-family: var(--font-mono); font-size: 9px; letter-spacing: 0.28em;
          text-transform: uppercase; color: #ef4444; font-weight: 600;
          border: 1px solid rgba(239,68,68,0.4); padding: 2px 7px; border-radius: 2px;
        }
        .hv-tc-title {
          font-family: var(--font-serif); font-size: 20px; font-weight: 700;
          color: #fff; line-height: 1.2; letter-spacing: -0.02em;
          display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical;
          overflow: hidden;
        }
        @media (max-width: 900px) { .hv-tc-title { font-size: 17px; } }
        .hv-tc-bottom {
          font-family: var(--font-mono); font-size: 9px; letter-spacing: 0.08em;
          color: rgba(255,255,255,0.35); text-align: right;
        }
        .hv-play {
          position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
          pointer-events: none;
        }
        .hv-play-icon {
          width: 52px; height: 52px; border-radius: 50%;
          background: rgba(255,255,255,0.18); border: 2px solid rgba(255,255,255,0.6);
          color: #fff; display: flex; align-items: center; justify-content: center;
          font-size: 20px; padding-left: 4px;
          backdrop-filter: blur(4px);
          box-shadow: 0 4px 20px rgba(0,0,0,0.4);
          transition: background 0.15s;
        }
        .hv-card:hover .hv-play-icon {
          background: rgba(255,255,255,0.28);
        }
        .hv-meta {
          padding: 10px 12px 12px;
        }
        .hv-title {
          font-family: var(--font-serif); font-size: 15px; line-height: 1.3;
          font-weight: 600; margin: 0 0 4px; color: var(--ink);
          display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
          overflow: hidden;
        }
        .hv-sub {
          font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.08em;
          text-transform: uppercase; color: var(--ink-soft);
        }
      `}</style>
      <div className="hv-strip-head">
        <span className="hv-strip-eyebrow">
          <span className="dot" />
          {videos.length === 0 ? "Editor view · no videos pinned yet" : "Watch · latest reports"}
        </span>
      </div>
      <div className="hv-strip-grid">
        {/* Admin empty-state — three placeholder upload cards. Only ever
            rendered when isAdmin && videos.length === 0 (the gate above
            self-hides for the public). Each card links to the admin
            Video Studio upload form. */}
        {videos.length === 0 && [0, 1, 2].map((i) => (
          <a
            key={`placeholder-${i}`}
            className="hv-card hv-placeholder"
            href="#/admin?mode=video"
            title="Upload a video in the admin Video Studio"
          >
            <div className="hv-thumb" style={{
              background: "repeating-linear-gradient(135deg, #1d2d52 0 12px, #18243f 12px 24px)",
            }}>
              <div style={{
                color: "rgba(255,255,255,0.85)", fontSize: 32, fontWeight: 700,
                fontFamily: "var(--font-serif)", textShadow: "0 2px 4px rgba(0,0,0,0.4)",
              }}>＋</div>
            </div>
            <div className="hv-meta">
              <h3 className="hv-title">Upload your video #{i + 1}</h3>
              <div className="hv-sub">Admin → video studio →</div>
            </div>
          </a>
        ))}
        {videos.map((v) => {
          const poster = v.poster_url || ytPoster(v.embed_url);
          const stamp = v.published_at
            ? new Date(v.published_at).toLocaleDateString("en-US", { month: "short", day: "numeric" })
            : null;
          const mins = v.duration_seconds ? `${Math.max(1, Math.round(v.duration_seconds / 60))} min` : null;
          return (
            <a
              key={v.slug}
              className="hv-card"
              href={v.youtube_url || `#/v/${v.slug}`}
              target={v.youtube_url ? "_blank" : undefined}
              rel={v.youtube_url ? "noopener noreferrer" : undefined}
            >
              <div className="hv-thumb">
                <div className="hv-title-card">
                  <div className="hv-tc-top">
                    <span className="hv-tc-logo">Shipping<em>Clarity</em></span>
                    <span className="hv-tc-eyebrow">Report</span>
                  </div>
                  <div className="hv-tc-title">{v.title}</div>
                  <div className="hv-tc-bottom">shippingclarity.com</div>
                </div>
                <div className="hv-play"><div className="hv-play-icon">▶</div></div>
              </div>
              <div className="hv-meta">
                <h3 className="hv-title">{v.title}</h3>
                <div className="hv-sub">
                  {[mins, stamp].filter(Boolean).join(" · ") || "Video"}
                </div>
              </div>
            </a>
          );
        })}
      </div>
    </section>
  );
}

// Best-effort YouTube/Vimeo poster derivation. Returns null if we can't
// figure it out from the embed URL alone.
function ytPoster(embedUrl) {
  if (!embedUrl) return null;
  try {
    const u = new URL(embedUrl);
    const m = u.pathname.match(/\/embed\/([^/?#]+)/);
    if (u.hostname.includes("youtube.com") && m) {
      return `https://i.ytimg.com/vi/${m[1]}/hqdefault.jpg`;
    }
  } catch (_) { /* noop */ }
  return null;
}

window.HomeVideoStrip = HomeVideoStrip;

// =============================================================================
// PULSE SIGNUP — daily intelligence subscription waitlist
// =============================================================================
function PulseSignupSection() {
  const [email, setEmail] = useStateH("");
  const [city, setCity] = useStateH("denver");
  const [submitted, setSubmitted] = useStateH(false);
  const cities = (window.SI_DATA && window.SI_DATA.FEATURED_CITIES) || [
    { id: "denver", name: "Denver" },
    { id: "los-angeles", name: "Los Angeles" },
    { id: "new-york", name: "New York" },
    { id: "chicago", name: "Chicago" },
    { id: "atlanta", name: "Atlanta" },
  ];
  const cityName = (cities.find((c) => c.id === city) || cities[0]).name;

  async function submit(e) {
    e.preventDefault();
    if (!email.trim() || !email.includes("@")) return;
    // Write to pulse_subscriptions (per-metro, has unsubscribe token).
    // Fall back to newsletter_signups if the new table isn't deployed yet.
    if (window.SI_DB) {
      try {
        if (window.SI_DB.submitPulseSubscription) {
          await window.SI_DB.submitPulseSubscription(email.trim(), city, "homepage");
        } else if (window.SI_DB.submitNewsletterSignup) {
          await window.SI_DB.submitNewsletterSignup(email.trim(), `pulse_${city}`);
        }
      } catch (err) { console.warn("pulse signup err", err); }
    }
    setSubmitted(true);
  }

  return (
    <section className="pulse-section">
      <div className="pulse-inner">
        <div className="pulse-grid">
          <div className="pulse-pitch">
            <div className="section-eyebrow">Shippers Connect Pulse</div>
            <h2 className="section-title">
              Daily intelligence for your <em>shipping reality.</em>
            </h2>
            <p className="pulse-sub">
              Every morning at 7am, get the pulse for your metro: which terminals
              are running hot, where wait times are spiking, which lanes are degraded,
              and what's expected this week. The intelligence shippers need before
              freight starts moving.
            </p>
            <ul className="pulse-bullets">
              <li>Terminal status changes and live wait times</li>
              <li>Lane conditions and corridor health</li>
              <li>Capacity shifts and carrier ratings updates</li>
              <li>Weekly trend reports per metro</li>
            </ul>
          </div>

          <div className="pulse-card">
            <div className="pulse-card-tag">Daily intelligence · Get notified</div>
            {submitted ? (
              <div className="pulse-card-thanks">
                <div className="pulse-card-thanks-h">✓ You're on the list.</div>
                <p>We'll let you know when the {cityName} Pulse goes live.</p>
              </div>
            ) : (
              <form className="pulse-form" onSubmit={submit}>
                <label className="pulse-label">Your metro</label>
                <select
                  className="pulse-select"
                  value={city}
                  onChange={(e) => setCity(e.target.value)}
                >
                  {cities.map((c) => (
                    <option key={c.id} value={c.id}>{c.name}</option>
                  ))}
                </select>
                <label className="pulse-label">Work email</label>
                <input
                  type="email"
                  required
                  className="pulse-email"
                  placeholder="you@company.com"
                  value={email}
                  onChange={(e) => setEmail(e.target.value)}
                />
                <button type="submit" className="btn-primary pulse-submit">
                  Get the {cityName} Pulse →
                </button>
                <p className="pulse-fineprint">
                  Free preview. We'll never share your address.
                </p>
              </form>
            )}
          </div>
        </div>
      </div>
    </section>
  );
}

// =============================================================================
// PERSPECTIVES — kept defined but unused on homepage. Will reuse on internal
// audience-specific pages once the four Reports launch.
// =============================================================================
function PerspectivesSection() {
  const PERSPECTIVES = [
    {
      key: "shippers",
      tone: "blue",
      audience: "Shippers don't see",
      body: (<>
        <p>
          Did you know that when you ship UPS air freight out of Denver, your package
          isn't moved by one truck? It's relayed between drivers — Commerce City to
          Englewood — to make the plane that night. <em>Hope they relayed them all.</em>
        </p>
        <p>
          Right now Commerce City is closed for remodel. Trucks are routing through
          Littleton. Every relay just got longer. Your package's odds of making the
          plane just got shorter.
        </p>
      </>),
      pitch: <><strong>Shippers Report</strong> shows you the chain you're paying for, not just the carrier name on the invoice.</>,
    },
    {
      key: "receivers",
      tone: "green",
      audience: "Receivers don't see",
      body: (<>
        <p>
          Did you know the freight that just hit your dock came off a relay from a driver
          who waited 4 hours at a shipper, then ran tired? Or that one of your regular
          inbound carriers is known across the operator network as <em>"the one that pays
          for damage and never pays the claim"</em>?
        </p>
        <p>
          Receivers judge carriers by what arrives. We show you the trip that got it
          there — and what the next one will look like.
        </p>
      </>),
      pitch: <><strong>Receivers Report</strong> turns inbound freight from a black box into a forecast.</>,
    },
    {
      key: "carriers",
      tone: "amber",
      audience: "What carriers learn from us",
      body: (<>
        <p>
          What does the operator community say about your service when they're not
          on a customer call? What permits, regulatory changes, or capacity shifts
          are reshaping your competitive set this quarter?
        </p>
        <p>
          You shouldn't have to wait for the RFP loss to find out. Verified carriers
          on Shippers Connect see the same market read shippers see — including
          how their own service is being read.
        </p>
      </>),
      pitch: <><strong>Carriers Report</strong> is your ground truth — including the parts about you.</>,
    },
  ];

  return (
    <section className="perspectives-section">
      <div className="perspectives-inner">
        <div className="section-eyebrow">What you don't see</div>
        <h2 className="section-title">Three perspectives. <em>One picture.</em></h2>
        <p className="perspectives-sub">
          Every player in the supply chain sees a different slice of the truth.
          Shippers Connect is the first time everyone sees the whole thing.
        </p>

        <div className="perspectives-grid">
          {PERSPECTIVES.map((p) => (
            <PerspectiveCard key={p.key} {...p} />
          ))}
        </div>
      </div>
    </section>
  );
}

function PerspectiveCard({ key: k, tone, audience, body, pitch }) {
  const [email, setEmail] = useStateH("");
  const [submitted, setSubmitted] = useStateH(false);
  const [open, setOpen] = useStateH(false);
  const audienceKey = audience.split(" ")[0].toLowerCase(); // "shippers" / "receivers" / etc.

  async function submit(e) {
    e.preventDefault();
    if (!email.trim() || !email.includes("@")) return;
    if (window.SI_DB && window.SI_DB.submitNewsletterSignup) {
      try {
        await window.SI_DB.submitNewsletterSignup(email.trim(), `report_${audienceKey}`);
      } catch (err) { console.warn("signup err", err); }
    }
    setSubmitted(true);
  }

  return (
    <div className={`p-card p-card-${tone}`}>
      <div className="p-card-tag">{audience}</div>
      <div className="p-card-body">{body}</div>
      <div className="p-card-pitch">{pitch}</div>
      <div className="p-card-cta">
        {!open && !submitted && (
          <button className="p-card-btn" onClick={() => setOpen(true)}>
            Notify me when it's live →
          </button>
        )}
        {open && !submitted && (
          <form className="p-card-form" onSubmit={submit}>
            <input
              type="email"
              required
              placeholder="you@company.com"
              value={email}
              onChange={(e) => setEmail(e.target.value)}
              autoFocus
            />
            <button type="submit" className="btn-primary">Notify me</button>
          </form>
        )}
        {submitted && (
          <div className="p-card-thanks">✓ You're on the list. We'll write when it launches.</div>
        )}
        <div className="p-card-meta">Live · Powered by Shipping Clarity</div>
      </div>
    </div>
  );
}
