/* the turn - shared chrome + primitives for the redesign.
   Verdict/posture/confidence vocabulary, status pips, chips, the conditions
   strip, the 7-day Ahead strip, and the 4-tab bottom nav. Composes the
   design-system primitives; exports everything to window for the screens. */
const { Chip: DChip } = window.TheTurnDesignSystem_583d9e;

/* ===== vocabulary maps ===== */
const VERDICT = {
  go:   { color: 'var(--verdict-go)',   label: 'GO' },
  scout:{ color: 'var(--verdict-worth)',label: 'SCOUT' },
  skip: { color: 'var(--verdict-dont)', label: 'SKIP' },
};
const POSTURE = {
  atlas: { label: 'Public Atlas', glyph: '◇' },
  scout: { label: 'DIY Scout',    glyph: '◈' },
  guide: { label: 'Guide',        glyph: '◆' },
};
const LADDER = ['none', 'scouted', 'validated', 'guide'];
const LADDER_LABEL = { none: 'none', scouted: 'scouted', validated: 'personally validated', guide: 'guide confident' };
const METHOD_LABEL = { fly: 'fly', spin: 'spin', bait: 'bait' };
const PLATFORM_LABEL = { shore: 'shore', kayak: 'kayak', boat: 'boat' };

const speciesById = (id) => window.TURN.species.find(s => s.id === id);
const areaById = (id) => window.TURN.areas.find(a => a.id === id);

/* ===== verdict badge - GO solid lime (rationed), SCOUT/SKIP outline ===== */
function VerdictBadge({ verdict, size = 'md', style = {} }) {
  const v = VERDICT[verdict] || VERDICT.skip;
  const isGo = verdict === 'go';
  const h = size === 'lg' ? 34 : size === 'sm' ? 24 : 28;
  const fs = size === 'lg' ? 15 : size === 'sm' ? 11 : 13;
  return (
    <span style={{
      display: 'inline-flex', alignItems: 'center', height: h, padding: `0 ${size === 'sm' ? 9 : 12}px`,
      borderRadius: 'var(--r-pill)', fontFamily: 'var(--font-mono)', fontWeight: 700,
      fontSize: fs, letterSpacing: '0.12em',
      background: isGo ? v.color : 'transparent',
      color: isGo ? 'var(--text-on-go)' : v.color,
      border: `2px solid ${v.color}`,
      ...style,
    }}>{v.label}</span>
  );
}

/* ===== verdict dot (Explore rank, map) - colour + solidity ===== */
function VerdictDot({ verdict, confidence = 'high', size = 13 }) {
  const c = (VERDICT[verdict] || VERDICT.skip).color;
  const low = confidence === 'low';
  return <span style={{
    width: size, height: size, borderRadius: '50%', flex: '0 0 auto',
    background: low ? 'transparent' : c, border: `${low ? 2.5 : 2}px ${low ? 'dashed' : 'solid'} ${c}`,
    boxShadow: (verdict === 'go' && !low) ? `0 0 8px color-mix(in srgb, ${c} 55%, transparent)` : 'none',
  }} />;
}

/* ===== posture badge ===== */
function PostureBadge({ posture, style = {} }) {
  const p = POSTURE[posture] || POSTURE.atlas;
  return (
    <span style={{
      display: 'inline-flex', alignItems: 'center', gap: 5, height: 24, padding: '0 9px',
      borderRadius: 'var(--r-pill)', border: '1px solid var(--border-strong)', background: 'var(--surface-raised)',
      fontFamily: 'var(--font-mono)', fontSize: 10, letterSpacing: '0.08em', textTransform: 'uppercase',
      color: 'var(--text-dim)', whiteSpace: 'nowrap', ...style,
    }}>
      <span style={{ color: posture === 'guide' ? 'var(--text)' : 'var(--text-label)', fontSize: 11 }}>{p.glyph}</span>
      {p.label}
    </span>
  );
}

/* ===== field-confidence ladder badge ===== */
function ConfidenceBadge({ lifecycle, showLabel = true, style = {} }) {
  const idx = LADDER.indexOf(lifecycle); // none=0 … guide=3
  const isGuide = lifecycle === 'guide';
  const c = isGuide ? 'var(--verdict-go)' : 'var(--text-dim)';
  return (
    <span style={{ display: 'inline-flex', alignItems: 'center', gap: 7, ...style }}>
      <span style={{ display: 'inline-flex', gap: 3, alignItems: 'center' }}>
        {[0, 1, 2, 3].map(i => (
          <span key={i} style={{
            width: 6, height: 11, borderRadius: 2,
            background: i <= idx ? c : 'transparent',
            border: `1.5px solid ${i <= idx ? c : 'var(--border-strong)'}`,
          }} />
        ))}
      </span>
      {showLabel && <span style={{
        fontFamily: 'var(--font-mono)', fontSize: 10, letterSpacing: '0.06em', textTransform: 'uppercase',
        color: isGuide ? 'var(--text)' : 'var(--text-label)',
      }}>{LADDER_LABEL[lifecycle]}</span>}
    </span>
  );
}

/* ===== SASSI / IUCN / Season status pips (Field Guide) ===== */
const SASSI = { green: { c: 'var(--verdict-go)', t: 'SASSI Green' }, orange: { c: 'var(--verdict-caution)', t: 'SASSI Orange' }, red: { c: 'var(--verdict-danger)', t: 'SASSI Red' } };
function SassiPip({ status, style = {} }) {
  const s = SASSI[status] || SASSI.orange;
  return <StatusPip dot={s.c} label={s.t} style={style} />;
}
function IucnPip({ status, style = {} }) {
  const danger = ['EN', 'CR', 'VU'].includes(status);
  return <StatusPip label={`IUCN ${status}`} tone={danger ? 'var(--verdict-caution)' : 'var(--text-dim)'} style={style} />;
}
function SeasonPip({ season, style = {} }) {
  const open = season.open;
  return (
    <span style={{
      display: 'inline-flex', alignItems: 'center', gap: 6, height: 24, padding: '0 10px',
      borderRadius: 'var(--r-pill)', fontFamily: 'var(--font-mono)', fontSize: 10, letterSpacing: '0.08em',
      border: `1.5px solid ${open ? 'var(--verdict-go)' : 'var(--verdict-danger)'}`,
      color: open ? 'var(--verdict-go)' : 'var(--verdict-danger)',
      background: open ? 'color-mix(in srgb, var(--verdict-go) 12%, var(--bg))' : 'color-mix(in srgb, var(--verdict-danger) 12%, var(--bg))',
      whiteSpace: 'nowrap', ...style,
    }}>{open ? 'OPEN' : `CLOSED${season.until ? ' · ' + season.until : ''}`}</span>
  );
}
function StatusPip({ dot, label, tone = 'var(--text-dim)', style = {} }) {
  return (
    <span style={{
      display: 'inline-flex', alignItems: 'center', gap: 6, height: 24, padding: '0 10px',
      borderRadius: 'var(--r-pill)', border: '1px solid var(--border)', background: 'var(--surface-raised)',
      fontFamily: 'var(--font-mono)', fontSize: 10, letterSpacing: '0.06em', color: tone, whiteSpace: 'nowrap', ...style,
    }}>
      {dot && <span style={{ width: 8, height: 8, borderRadius: '50%', background: dot, flex: '0 0 auto' }} />}
      {label}
    </span>
  );
}

/* ===== lure tier (1-5 dots) ===== */
function LureTier({ tier, style = {} }) {
  return (
    <span style={{ display: 'inline-flex', alignItems: 'center', gap: 4, ...style }} title={`lure tier ${tier}/5`}>
      {[1, 2, 3, 4, 5].map(i => (
        <span key={i} style={{
          width: 7, height: 7, borderRadius: '50%',
          background: i <= tier ? 'var(--verdict-go)' : 'transparent',
          border: `1.5px solid ${i <= tier ? 'var(--verdict-go)' : 'var(--border-strong)'}`,
        }} />
      ))}
    </span>
  );
}

/* ===== species chip (tappable, with silhouette) ===== */
function SpeciesChip({ id, onClick, color = 'var(--text-dim)', style = {} }) {
  const sp = speciesById(id);
  if (!sp) return null;
  return (
    <button type="button" onClick={() => onClick && onClick(id)} style={{
      display: 'inline-flex', alignItems: 'center', gap: 7, height: 'var(--chip-h)', padding: '0 12px 0 9px',
      background: 'var(--surface-raised)', color: 'var(--text)', border: '1px solid var(--border)',
      borderRadius: 'var(--r-pill)', fontSize: 'var(--t-caption)', fontWeight: 500, cursor: onClick ? 'pointer' : 'default',
      whiteSpace: 'nowrap', ...style,
    }}>
      <FishIcon species={sp.id} size={18} color={color} />
      {sp.common.replace(/ \/.*/, '')}
    </button>
  );
}

/* ===== method / platform chips ===== */
function TagChip({ children, mono = true, icon = null, style = {} }) {
  return (
    <span style={{
      display: 'inline-flex', alignItems: 'center', gap: 6, height: 26, padding: '0 10px',
      borderRadius: 'var(--r-pill)', border: '1px solid var(--border)', background: 'var(--surface)',
      fontFamily: mono ? 'var(--font-mono)' : 'var(--font-body)', fontSize: 12, color: 'var(--text-dim)',
      letterSpacing: mono ? '0.04em' : 0, whiteSpace: 'nowrap', ...style,
    }}>{icon}{children}</span>
  );
}

/* ===== filter chip group ===== */
function FilterChip({ active, onClick, children }) {
  return (
    <button type="button" onClick={onClick} style={{
      display: 'inline-flex', alignItems: 'center', height: 34, padding: '0 14px', cursor: 'pointer',
      borderRadius: 'var(--r-pill)', fontSize: 13, fontWeight: active ? 600 : 500, whiteSpace: 'nowrap',
      background: active ? 'color-mix(in srgb, var(--keyline) 12%, var(--surface))' : 'var(--surface)',
      color: active ? 'var(--text)' : 'var(--text-dim)',
      border: `1.5px solid ${active ? 'var(--keyline-soft)' : 'var(--border)'}`,
    }}>{children}</button>
  );
}
function FilterRow({ label, options, value, onChange, style = {} }) {
  return (
    <div style={{ display: 'flex', alignItems: 'center', gap: 8, ...style }}>
      {label && <span className="overline" style={{ flex: '0 0 auto' }}>{label}</span>}
      <div style={{ display: 'flex', gap: 7, overflowX: 'auto', paddingBottom: 2, scrollbarWidth: 'none' }}>
        {options.map(o => (
          <FilterChip key={o.value} active={value === o.value} onClick={() => onChange(o.value)}>{o.label}</FilterChip>
        ))}
      </div>
    </div>
  );
}

/* ===== conditions strip (Today + Explore headers) =====
   Optional onClick makes the whole 4-cell strip a button (with trailing
   chevron + role/key handling) that routes to the Conditions tab. */
function ConditionsStrip({ c, onClick, style = {} }) {
  const trendArrow = { rising: '▲', falling: '▼', steady: '→' }[c.pressure.trend] || '→';
  const tideArrow = { rising: '▲', falling: '▼', high: '•', low: '•' }[c.tide.phase] || '•';
  // Good conditions (grade A/B) light the value GREEN so the strip reads
  // good/fair/bad at a glance; poor (D) goes amber, dead (E) muted.
  const gradeColor = (g) =>
    g === 'A' || g === 'B' ? 'var(--verdict-go)' :
    g === 'D' ? 'var(--verdict-caution)' :
    g === 'E' ? 'var(--verdict-dont)' : 'var(--text)';
  // Gust differential IS the risk number for paddlers - once gusts run
  // ~15 km/h over the mean, the gust joins the readout instead of hiding in
  // a footnote. All wind numbers are km/h (the engine converts from knots).
  const windNow = c.wind.kmh != null ? c.wind.kmh : c.wind.kt; // kt = old demo data fallback
  const gustyBy = (c.wind.gust != null && c.wind.gust - windNow >= 15) ? c.wind.gust : null;
  const cells = [
    { label: 'wind', value: `${windNow}`, unit: gustyBy ? `${c.wind.dir} g${gustyBy}` : c.wind.dir, rot: c.wind.deg, kind: 'wind', valTone: gustyBy ? 'var(--verdict-caution)' : gradeColor(c.wind.grade) },
    { label: 'swell', value: `${c.swell.m}`, unit: `m·${c.swell.period}s`, valTone: gradeColor(c.swell.grade) },
    { label: 'pressure', value: `${c.pressure.hpa}`, unit: trendArrow, valTone: gradeColor(c.pressure.grade), tone: c.pressure.trend === 'falling' ? 'var(--verdict-caution)' : 'var(--text-label)' },
    { label: 'tide', value: c.tide.phase, unit: tideArrow, text: true, valTone: gradeColor(c.tide.grade) },
  ];
  const tappable = typeof onClick === 'function';
  return (
    <div
      onClick={tappable ? onClick : undefined}
      role={tappable ? 'button' : undefined}
      tabIndex={tappable ? 0 : undefined}
      aria-label={tappable ? 'open full conditions' : undefined}
      onKeyDown={tappable ? (e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); onClick(); } } : undefined}
      style={{
        display: 'flex', alignItems: 'stretch', background: 'var(--surface)', border: '1px solid var(--border)',
        borderRadius: 'var(--r-md)', overflow: 'hidden',
        cursor: tappable ? 'pointer' : 'default', ...style,
      }}
    >
      {cells.map((cell, i) => (
        <div key={cell.label} style={{
          flex: 1, padding: '9px 10px', display: 'flex', flexDirection: 'column', gap: 3,
          borderLeft: i ? '1px solid var(--hairline)' : 'none', minWidth: 0,
        }}>
          <span className="overline" style={{ fontSize: 10, display: 'inline-flex', alignItems: 'center', gap: 4 }}>
            {cell.kind === 'wind' && <span style={{ display: 'inline-block', transform: `rotate(${cell.rot}deg)`, color: 'var(--text-label)' }}>↑</span>}
            {cell.label}
          </span>
          <span className="metric" style={{ fontSize: cell.text ? 13 : 17, fontWeight: 700, color: cell.valTone || 'var(--text)', lineHeight: 1, textTransform: cell.text ? 'capitalize' : 'none', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>
            {cell.value}{cell.unit && <span style={{ fontSize: cell.text ? '0.85em' : '0.6em', color: cell.tone || 'var(--text-label)', marginLeft: 3 }}>{cell.unit}</span>}
          </span>
        </div>
      ))}
      {tappable && (
        <div style={{ flex: '0 0 auto', display: 'grid', placeItems: 'center', padding: '0 8px', borderLeft: '1px solid var(--hairline)', color: 'var(--text-label)' }}>
          <Icon name="chevron" size={16} />
        </div>
      )}
    </div>
  );
}

/* Small grade chip beside each condition row. */
function GradePip({ grade }) {
  const color = grade === 'good' ? 'var(--verdict-go)'
              : grade === 'fair' ? 'var(--verdict-worth)'
              : 'var(--verdict-dont)';
  const fill  = grade === 'good' ? 'var(--verdict-go)'
              : grade === 'fair' ? 'transparent'
              : 'transparent';
  const border = grade === 'good' ? '0' : `1.5px solid ${color}`;
  return (
    <span style={{
      flex: '0 0 auto', marginTop: 4,
      width: 10, height: 10, borderRadius: '50%',
      background: fill, border,
    }} />
  );
}

/* ===== Tap-to-expand deep conditions panel =====
   Every condition row is graded good / fair / poor with a one-line "why",
   so the user learns how each input affects the catch. Colours pull from
   the verdict palette: lime = good, sage = fair, muted = poor. */
function ConditionsDetail({ c }) {
  const Row = ({ label, value, sub, grade, reason }) => {
    const tone = grade === 'good' ? 'var(--verdict-go)'
               : grade === 'fair' ? 'var(--verdict-worth)'
               : grade === 'poor' ? 'var(--verdict-dont)'
               : 'var(--text)';
    return (
      <div style={{
        display: 'flex', alignItems: 'flex-start', gap: 12,
        padding: '10px 12px', borderTop: '1px solid var(--hairline)',
      }}>
        {/* grade pip */}
        {grade && <GradePip grade={grade} />}
        {/* label + reason */}
        <div style={{ flex: 1, minWidth: 0 }}>
          <span className="overline" style={{ fontSize: 10, color: 'var(--text-label)' }}>{label}</span>
          {reason && <div style={{ fontSize: 11, color: 'var(--text-dim)', marginTop: 2, lineHeight: 1.35 }}>{reason}</div>}
        </div>
        {/* value */}
        <span style={{ textAlign: 'right', minWidth: 0, flex: '0 0 auto' }}>
          <span style={{ fontFamily: 'var(--font-mono)', fontSize: 14, fontWeight: 700, color: tone, whiteSpace: 'nowrap' }}>{value}</span>
          {sub && <span style={{ display: 'block', fontFamily: 'var(--font-mono)', fontSize: 10, color: 'var(--text-label)', marginTop: 2 }}>{sub}</span>}
        </span>
      </div>
    );
  };

  // Tide visual: each phase encoded as a 0-1 progress (rough sine cycle).
  // Phase has 'rising' | 'falling' | 'high' | 'low' so we render a sine
  // wave + a marker at the current phase position.
  const tideProgress = { low: 0, rising: 0.25, high: 0.5, falling: 0.75 }[c.tide.phase] ?? 0.5;

  const moonGlyph = ({
    'new':            '🌑',
    'waxing-crescent':'🌒',
    'first-quarter':  '🌓',
    'waxing-gibbous': '🌔',
    'full':           '🌕',
    'waning-gibbous': '🌖',
    'last-quarter':   '🌗',
    'waning-crescent':'🌘',
  })[c.moon?.phase] ?? '🌙';

  return (
    <div style={{ background: 'var(--surface-sunk)' }}>
      {/* TIDE SCHEMATIC */}
      <div style={{ padding: '12px', borderTop: '1px solid var(--hairline)' }}>
        <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between', marginBottom: 8 }}>
          <span className="overline" style={{ fontSize: 10 }}>tide</span>
          <span style={{ fontFamily: 'var(--font-mono)', fontSize: 11, color: 'var(--text-label)' }}>
            {c.tide.height} · next {c.tide.next}
          </span>
        </div>
        <TideSineWave progress={tideProgress} phase={c.tide.phase} />
      </div>

      {/* WIND */}
      <Row label="wind" value={`${c.wind.kt}kt ${c.wind.dir}`} sub={`gust ${c.wind.gustKt}kt · ${c.wind.trend}`} grade={c.wind.grade} reason={c.wind.reason} />

      {/* SWELL + WAVE */}
      <Row label="swell" value={`${c.swell.m}m · ${c.swell.period}s`} sub={`from ${c.swell.dir}`} grade={c.swell.grade} reason={c.swell.reason} />
      <Row label="wind wave" value={`${c.wave.m}m · ${c.wave.period}s`} sub={`from ${c.wave.dir}`} />

      {/* PRESSURE */}
      <Row label="pressure" value={`${c.pressure.hpa} hPa`} sub={c.pressure.trend} grade={c.pressure.grade} reason={c.pressure.reason} />

      {/* TIDE row (re-stated with grade since the schematic above is visual only) */}
      <Row label="tide phase" value={c.tide.phase} sub={c.tide.next ? `next ${c.tide.next}` : ''} grade={c.tide.grade} reason={c.tide.reason} />

      {/* TEMP */}
      <Row label="water" value={`${c.water}°C`} grade={c.waterMeta?.grade} reason={c.waterMeta?.reason} />
      <Row label="air" value={`${c.air}°C`} />

      {/* SKY */}
      <Row label="cloud cover" value={`${c.cloud}%`} grade={c.cloudMeta?.grade} reason={c.cloudMeta?.reason} />
      <Row label="visibility" value={`${c.visibilityKm} km`} grade={c.visibilityMeta?.grade} reason={c.visibilityMeta?.reason} />
      <Row label="precip · 6h" value={`${c.precip?.mm6h ?? 0} mm`} sub={`1h: ${c.precip?.mm1h ?? 0} mm`} grade={c.precip?.grade} reason={c.precip?.reason} />

      {/* ASTRO */}
      <Row label="sun" value={`${c.sun?.rise} → ${c.sun?.set}`} />
      <Row
        label="moon"
        value={`${moonGlyph}  ${c.moon?.illumination}%`}
        sub={(c.moon?.phase || '').replace(/-/g, ' ')}
        grade={c.moon?.grade}
        reason={c.moon?.reason}
      />
    </div>
  );
}

/* ===== Tiny tide sine SVG ===== */
function TideSineWave({ progress, phase }) {
  const W = 320;
  const H = 36;
  const pts = [];
  for (let i = 0; i <= 80; i++) {
    const x = (i / 80) * W;
    const t = (i / 80) * Math.PI * 2;
    const y = H / 2 - Math.cos(t) * (H / 2 - 4);
    pts.push(`${x.toFixed(1)},${y.toFixed(1)}`);
  }
  const markerX = progress * W;
  const markerT = progress * Math.PI * 2;
  const markerY = H / 2 - Math.cos(markerT) * (H / 2 - 4);

  return (
    <svg viewBox={`0 0 ${W} ${H + 14}`} width="100%" height={H + 14} aria-hidden="true">
      {/* zero line */}
      <line x1="0" y1={H / 2} x2={W} y2={H / 2} stroke="var(--hairline)" strokeWidth="1" strokeDasharray="2 3" />
      {/* sine */}
      <polyline points={pts.join(' ')} fill="none" stroke="var(--text-label)" strokeWidth="1.5" />
      {/* current marker */}
      <circle cx={markerX} cy={markerY} r="5" fill="var(--verdict-go)" stroke="var(--bg)" strokeWidth="2" />
      {/* low/high labels */}
      <text x="0"  y={H + 12} fontSize="9" fontFamily="var(--font-mono)" fill="var(--text-label)">low</text>
      <text x={W * 0.25 - 14} y={H + 12} fontSize="9" fontFamily="var(--font-mono)" fill="var(--text-label)">rising</text>
      <text x={W * 0.5 - 8}  y={H + 12} fontSize="9" fontFamily="var(--font-mono)" fill="var(--text-label)">high</text>
      <text x={W * 0.75 - 16} y={H + 12} fontSize="9" fontFamily="var(--font-mono)" fill="var(--text-label)">falling</text>
    </svg>
  );
}

/* ===== 7-day Ahead strip (collapsible, top of Today) ===== */
function AheadStrip({ ahead, open, onToggle, active, onPick, style = {} }) {
  return (
    <div style={{ background: 'var(--surface)', border: '1px solid var(--border)', borderRadius: 'var(--r-md)', overflow: 'hidden', ...style }}>
      <button type="button" onClick={onToggle} style={{
        width: '100%', display: 'flex', alignItems: 'center', justifyContent: 'space-between',
        padding: '11px 14px', background: 'none', border: 'none', cursor: 'pointer', color: 'var(--text-dim)',
      }}>
        <span style={{ display: 'inline-flex', alignItems: 'center', gap: 9 }}>
          <span className="overline">Ahead · next 7 days</span>
          <span style={{ display: 'inline-flex', gap: 4 }}>
            {ahead.slice(0, 7).map((d, i) => <VerdictDot key={i} verdict={d.verdict} size={7} />)}
          </span>
        </span>
        <span style={{ transform: open ? 'rotate(90deg)' : 'none', transition: 'transform var(--dur-base) var(--ease-out)', color: 'var(--text-label)' }}>
          <Icon name="chevron" size={16} />
        </span>
      </button>
      {open && (
        <div style={{ display: 'flex', borderTop: '1px solid var(--hairline)' }}>
          {ahead.map((d, i) => {
            const isActive = active === i;
            return (
              <button key={i} type="button" onClick={() => onPick(i)} style={{
                flex: 1, display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', gap: 5, padding: '10px 2px 10px',
                background: isActive ? 'var(--surface-raised)' : 'none', border: 'none', cursor: 'pointer',
                borderLeft: i ? '1px solid var(--hairline)' : 'none',
                boxShadow: isActive ? 'inset 0 2px 0 var(--keyline)' : 'none',
                minWidth: 0, minHeight: 48,
              }}>
                <span style={{ fontFamily: 'var(--font-mono)', fontSize: 11, fontWeight: 700, color: isActive ? 'var(--text)' : 'var(--text-dim)' }}>{d.label || d.day}</span>
                <VerdictDot verdict={d.verdict} size={11} />
                <span style={{ fontFamily: 'var(--font-mono)', fontSize: 9, color: 'var(--text-label)', whiteSpace: 'nowrap' }}>{d.wind.replace('kt', '')}</span>
                {d.areaShort && (
                  <span style={{
                    fontFamily: 'var(--font-mono)', fontSize: 8.5, fontWeight: 600,
                    color: isActive ? 'var(--text-dim)' : 'var(--text-label)',
                    width: '100%', textAlign: 'center', padding: '0 3px',
                    overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap',
                    lineHeight: 1.15,
                  }}>{d.areaShort}</span>
                )}
              </button>
            );
          })}
        </div>
      )}
    </div>
  );
}

/* ===== bottom nav - 4 tabs (Today / Explore / Log / Field Guide) ===== */
function NavGlyph({ name, size = 24 }) {
  const P = { fill: 'none', stroke: 'currentColor', strokeWidth: 2, strokeLinecap: 'round', strokeLinejoin: 'round' };
  const g = {
    today: <g {...P}><path d="M3 16c3 0 4-9 9-9s6 9 9 9" /><circle cx="12" cy="7" r="1.5" fill="currentColor" stroke="none" /></g>,
    explore: <g {...P}><circle cx="12" cy="12" r="8.5" /><path d="M15.5 8.5l-2 5-5 2 2-5z" fill="currentColor" stroke="none" opacity="0.9" /></g>,
    log: <g {...P}><path d="M5 4h11a2 2 0 0 1 2 2v14l-3-2-3 2-3-2-3 2V6a2 2 0 0 1 2-2z" /><path d="M8.5 9h6M8.5 12.5h4" /></g>,
    // From DS4 brief: two wave strokes + a small sun circle
    conditions: <g {...P}>
      <path d="M3 14c2.2 0 2.8-2.6 5-2.6s2.8 2.6 5 2.6 2.8-2.6 5-2.6 2.8 2.6 5 2.6" />
      <path d="M3 18.5c2.2 0 2.8-2.6 5-2.6s2.8 2.6 5 2.6 2.8-2.6 5-2.6 2.8 2.6 5 2.6" />
      <circle cx="17" cy="6" r="2.6" />
    </g>,
    guide: <g {...P}><path d="M12 6c-2-1.4-4.5-1.6-7-1v12c2.5-.6 5-.4 7 1 2-1.4 4.5-1.6 7-1V5c-2.5-.6-5-.4-7 1z" /><path d="M12 6v13" /></g>,
  };
  return <svg width={size} height={size} viewBox="0 0 24 24" aria-hidden="true">{g[name]}</svg>;
}
function BottomNav({ tab, onTab, style = {} }) {
  const tabs = [
    { id: 'today', label: 'Today', icon: 'today' },
    { id: 'explore', label: 'Explore', icon: 'explore' },
    { id: 'conditions', label: 'Conditions', icon: 'conditions' },
    { id: 'guide', label: 'Field Guide', icon: 'guide' },
  ];
  return (
    <nav style={{
      display: 'flex', background: 'var(--surface)', borderTop: '1px solid var(--hairline-bold)',
      boxShadow: '0 -10px 26px rgba(7,38,31,0.22)', padding: '0 4px', paddingBottom: 'var(--safe-bottom)', ...style,
    }}>
      {tabs.map(t => {
        const active = tab === t.id;
        return (
          <button key={t.id} onClick={() => onTab(t.id)} style={{
            flex: 1, display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 4,
            padding: '10px 0 8px', background: 'none', border: 'none', cursor: 'pointer',
            borderTop: active ? '2px solid var(--keyline)' : '2px solid transparent', marginTop: -1,
            color: active ? 'var(--keyline)' : 'var(--text-dim)',
          }}>
            <NavGlyph name={t.icon} size={23} />
            <span style={{ fontSize: 10.5, fontWeight: active ? 700 : 500, letterSpacing: '.01em' }}>{t.label}</span>
          </button>
        );
      })}
    </nav>
  );
}

/* ===== small shared bits ===== */
function SectionLabel({ children, right, style = {} }) {
  return (
    <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between', margin: '0 0 12px', ...style }}>
      <span className="overline">{children}</span>
      {right}
    </div>
  );
}
function DrillHeader({ onBack, title, sub, right }) {
  return (
    <header style={{ display: 'flex', alignItems: 'center', gap: 12, padding: '8px var(--gutter) 14px', borderBottom: '1px solid var(--hairline)' }}>
      <button onClick={onBack} aria-label="back" style={{
        flex: '0 0 auto', width: 40, height: 40, borderRadius: '50%', display: 'grid', placeItems: 'center',
        background: 'var(--surface)', border: '1px solid var(--border-strong)', color: 'var(--text)', cursor: 'pointer',
      }}><Icon name="back" size={20} /></button>
      <div style={{ flex: 1, minWidth: 0 }}>
        <div style={{ fontFamily: 'var(--font-display)', fontWeight: 700, fontSize: 19, color: 'var(--text)', lineHeight: 1.1, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{title}</div>
        {sub && <div style={{ fontSize: 13, color: 'var(--text-dim)', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{sub}</div>}
      </div>
      {right}
    </header>
  );
}

Object.assign(window, {
  VERDICT, POSTURE, LADDER, LADDER_LABEL, METHOD_LABEL, PLATFORM_LABEL, SASSI,
  speciesById, areaById,
  VerdictBadge, VerdictDot, PostureBadge, ConfidenceBadge,
  SassiPip, IucnPip, SeasonPip, StatusPip, LureTier,
  SpeciesChip, TagChip, FilterChip, FilterRow,
  ConditionsStrip, AheadStrip, BottomNav, NavGlyph, SectionLabel, DrillHeader,
});
