/* Shared chrome: Logo, TopStrip, Nav, Footer + small helpers (Icon, Flag, VS hex, status badges). */
const { useState, useEffect, useRef, useMemo } = React;

/* ---------- Custom flag overrides context ---------- */
// Populated by App on startup via /api/custom-flags.
// Maps FIFA 3-letter code -> Supabase Storage public URL.
const CustomFlagsCtx = React.createContext({});
window.CustomFlagsCtx = CustomFlagsCtx;

/* ---------- Logo (real brand image) ---------- */
function SunFrontLogo({ height = 34, onWhite = true }) {
  return (
    <img
      src="/assets/images/logo.jpg"
      alt="SunFront"
      height={height}
      style={{
        height,
        width: 'auto',
        display: 'block',
        // On dark backgrounds: brand-approved all-white single-colour variant
        filter: onWhite ? 'none' : 'brightness(0) invert(1)',
      }}
    />
  );
}

/* ---------- Flag -- flagcdn.com SVG (CORS open, direct browser fetch, no proxy) ---------- */
// flagcdn.com is a dedicated flag CDN with CORS * headers.
// Supports subdivision codes natively: gb-sct (Scotland), gb-eng (England).
// Admin-uploaded custom flags (Supabase Storage) take priority.
const _FIFA_ISO = {
  MEX:'mx', RSA:'za', KOR:'kr', CZE:'cz', CAN:'ca', BIH:'ba', QAT:'qa', SUI:'ch',
  BRA:'br', MAR:'ma', HAI:'ht', SCO:'gb-sct', USA:'us', PAR:'py', AUS:'au', TUR:'tr',
  GER:'de', CUW:'cw', CIV:'ci', ECU:'ec', NED:'nl', JPN:'jp', SWE:'se', TUN:'tn',
  BEL:'be', EGY:'eg', IRN:'ir', NZL:'nz', ESP:'es', CPV:'cv', KSA:'sa', URU:'uy',
  FRA:'fr', SEN:'sn', IRQ:'iq', NOR:'no', ARG:'ar', ALG:'dz', AUT:'at', JOR:'jo',
  POR:'pt', COD:'cd', UZB:'uz', COL:'co', ENG:'gb-eng', CRO:'hr', GHA:'gh', PAN:'pa',
};
// Expose for admin flag upload preview (admin-views.jsx uses this)
window._FIFA_ISO_ADMIN = _FIFA_ISO;

function Flag({ code, w = 42, h = 28, rounded = 4, alt = '' }) {
  const customFlags = React.useContext(CustomFlagsCtx);
  const iso = _FIFA_ISO[code] || code.toLowerCase();
  const src = (customFlags && customFlags[code])
    ? customFlags[code]
    : 'https://flagcdn.com/' + iso + '.svg';
  return (
    <img
      src={src}
      width={w} height={h} alt={alt}
      style={{
        display: 'block',
        objectFit: 'cover',
        borderRadius: rounded,
        boxShadow: '0 0 0 1px rgba(26,15,31,0.10)',
        background: 'var(--grey-100)',
        width: w, height: h,
      }}
      loading="lazy"
      onError={function(e){ e.currentTarget.style.opacity='0'; }}
    />
  );
}

/* ---------- Hex VS badge ---------- */
function VSHex({ size = 36 }) {
  return (
    <div className="clip-hex font-display" aria-hidden="true"
      style={{
        width: size, height: size, background: 'var(--ink)', color: 'var(--orange)',
        display: 'flex', alignItems: 'center', justifyContent: 'center',
        fontSize: size * 0.36, letterSpacing: '0.02em', flexShrink: 0,
      }}>VS</div>
  );
}

/* ---------- Status badge (parallelogram skew tag) ---------- */
function StatusBadge({ status, size = 'md' }) {
  const map = {
    OPEN:      { label: 'Open now',   bg: 'var(--success)', fg: '#fff', dot: true },
    SCHEDULED: { label: '', bg: 'var(--grey-200)', fg: 'var(--ink)', dot: false },
    CLOSED:    { label: 'Closed',     bg: 'var(--ink)',      fg: '#fff',         dot: false },
    SETTLED:   { label: 'Settled',    bg: 'var(--orange)',   fg: '#fff',         dot: false },
  };
  const cfg = map[status] || map.SCHEDULED;
  if (!cfg.label) return null;
  const pad = size === 'sm' ? '4px 14px' : '6px 18px';
  const fs  = size === 'sm' ? 11 : 12;
  return (
    <div className="skew-tag" style={{
      background: cfg.bg, color: cfg.fg, padding: pad,
      fontSize: fs, fontWeight: 700, letterSpacing: '0.06em', textTransform: 'uppercase',
      display: 'inline-flex', alignItems: 'center', gap: 6, flexShrink: 0,
    }}>
      <span className="skew-tag-inner" style={{ display: 'inline-flex', alignItems: 'center', gap: 6 }}>
        {cfg.dot && <span className="pulse-dot" style={{ width: 7, height: 7, background: '#fff', borderRadius: '50%' }} />}
        {cfg.label}
      </span>
    </div>
  );
}

/* ---------- Icons (stroke, ink) ---------- */
const Icon = ({ name, size = 18, color = 'currentColor', stroke = 2 }) => {
  const props = { width: size, height: size, viewBox: '0 0 24 24', fill: 'none', stroke: color, strokeWidth: stroke, strokeLinecap: 'round', strokeLinejoin: 'round', 'aria-hidden': 'true', focusable: 'false' };
  switch (name) {
    case 'receipt':   return (<svg {...props}><path d="M5 3v18l2-1.5L9 21l2-1.5L13 21l2-1.5L17 21l2-1.5V3z"/><path d="M8 8h8M8 12h8M8 16h5"/></svg>);
    case 'message':   return (<svg {...props}><path d="M21 11.5a8.38 8.38 0 0 1-8.5 8.5 8.5 8.5 0 0 1-4.6-1.3L3 20l1.3-4.8A8.5 8.5 0 1 1 21 11.5z"/></svg>);
    case 'target':    return (<svg {...props}><circle cx="12" cy="12" r="9"/><circle cx="12" cy="12" r="5"/><circle cx="12" cy="12" r="1.5" fill={color}/></svg>);
    case 'trophy':    return (<svg {...props}><path d="M7 4h10v4a5 5 0 0 1-10 0z"/><path d="M5 6H3a2 2 0 0 0 2 4M19 6h2a2 2 0 0 1-2 4"/><path d="M9 14h6v3H9zM8 21h8"/></svg>);
    case 'calendar': return (<svg {...props}><rect x="3" y="5" width="18" height="16" rx="2"/><path d="M16 3v4M8 3v4M3 10h18"/></svg>);
    case 'flag':      return (<svg {...props}><path d="M4 22V4l13 2-3 4 3 4-13-2"/></svg>);
    case 'pin':       return (<svg {...props}><path d="M12 22s7-7.6 7-12a7 7 0 1 0-14 0c0 4.4 7 12 7 12z"/><circle cx="12" cy="10" r="2.5"/></svg>);
    case 'check':     return (<svg {...props}><path d="M5 12l5 5L20 7"/></svg>);
    case 'scale':     return (<svg {...props}><path d="M12 3v18"/><path d="M3 8h18"/><path d="M7 8l-3 6a3 3 0 0 0 6 0z"/><path d="M17 8l-3 6a3 3 0 0 0 6 0z"/></svg>);
    case 'arrow':     return (<svg {...props}><path d="M5 12h14M13 6l6 6-6 6"/></svg>);
    case 'phone':     return (<svg {...props}><path d="M22 16.9v3a2 2 0 0 1-2.2 2 19.8 19.8 0 0 1-8.6-3.1 19.5 19.5 0 0 1-6-6 19.8 19.8 0 0 1-3.1-8.7A2 2 0 0 1 4.1 2h3a2 2 0 0 1 2 1.7c.1.9.3 1.8.6 2.6a2 2 0 0 1-.5 2.1L8 9.6a16 16 0 0 0 6 6l1.2-1.2a2 2 0 0 1 2.1-.5c.8.3 1.7.5 2.6.6a2 2 0 0 1 1.7 2z"/></svg>);
    case 'bolt':      return (<svg {...props}><path d="M13 2 4 14h7l-1 8 9-12h-7z"/></svg>);
    case 'close':     return (<svg {...props}><path d="M18 6L6 18M6 6l12 12"/></svg>);
    case 'chart':     return (<svg {...props}><path d="M4 20V10M10 20V4M16 20v-7M22 20H2"/></svg>);
    case 'pizza':     return (<svg {...props}><path d="M12 2 22 21H2z"/><circle cx="12" cy="9" r="1" fill={color}/><circle cx="9" cy="13.5" r="1" fill={color}/><circle cx="15" cy="13.5" r="1" fill={color}/></svg>);
    case 'gift':      return (<svg {...props}><rect x="3" y="8" width="18" height="13" rx="1"/><path d="M3 8h18M12 8v13"/><path d="M12 8c0-3-2.5-5-4.5-3.5C5.5 6 8 8 12 8zM12 8c0-3 2.5-5 4.5-3.5C18.5 6 16 8 12 8z"/></svg>);
    default: return null;
  }
};

/* ---------- Top strip ---------- */
function TopStrip() {
  return (
    <div style={{ background: 'var(--ink)', color: '#fff', fontSize: 12 }}>
      <div className="container" style={containerStyle({ py: 8, justify: 'space-between' })}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
          <Icon name="phone" size={13} color="var(--orange)" />
          <span style={{ letterSpacing: '0.04em' }}>
            <strong style={{ fontWeight: 700 }}>HOTLINE</strong> +960 781-5113 · Maldives
          </span>
        </div>
        <div className="hide-mobile" style={{ letterSpacing: '0.14em', textTransform: 'uppercase', fontWeight: 600, color: '#d4d4d8' }}>
          Since 1989 · <span style={{ color: '#fff' }}>Quality &amp; Style</span>
        </div>
      </div>
    </div>
  );
}

/* ---------- Nav (top, desktop) ---------- */
function Nav({ route, onNav }) {
  const tabs = [
    { key: 'home',           label: 'Home' },
    { key: 'fixtures',       label: 'Fixtures' },
    { key: 'predict',        label: 'Predict' },
    { key: 'dashboard',      label: 'Live stats' },
    { key: 'my-predictions', label: 'My Picks' },
  ];
  const navRef = React.useRef(null);
  const [hoverKey, setHoverKey] = React.useState(null);

  function movePill(e, key) {
    setHoverKey(key);
    const nav = navRef.current;
    if (!nav || !e) return;
    const b = e.currentTarget.getBoundingClientRect();
    const n = nav.getBoundingClientRect();
    nav.style.setProperty('--pill-left', (b.left - n.left) + 'px');
    nav.style.setProperty('--pill-width', b.width + 'px');
    nav.style.setProperty('--pill-h', b.height + 'px');
    nav.style.setProperty('--pill-op', '1');
  }
  function hidePill() {
    setHoverKey(null);
    if (navRef.current) navRef.current.style.setProperty('--pill-op', '0');
  }

  return (
    <div style={{
      background: '#fff',
      borderBottom: '1px solid var(--grey-200)',
      boxShadow: '0 2px 12px rgba(17,6,24,0.06)',
      position: 'relative',
    }}>
      {/* Orange accent line under nav */}
      <div style={{
        position: 'absolute', left: 0, right: 0, bottom: 0, height: 2,
        background: 'linear-gradient(to right, var(--orange) 0%, var(--orange) 38%, transparent 38%)',
      }} />
      <div className="nav-inner" style={{ ...containerStyle({ py: 4, justify: 'space-between' }) }}>
        {/* Campaign logo */}
        <button onClick={() => onNav('home')} aria-label="SunFront World Cup Foari 2026 - Go to home"
          style={{ background: 'none', border: 'none', padding: 0, cursor: 'pointer', lineHeight: 0 }}>
          <img
            src="/assets/images/wc-logo-v3.png"
            alt="SunFront World Cup Foari 2026"
            className="nav-campaign-logo"
            style={{ height: 96, width: 'auto', display: 'block' }}
          />
        </button>
        {/* Desktop nav with color-popping box */}
        <nav ref={navRef} onMouseLeave={hidePill}
          className="hide-mobile"
          style={{ display: 'flex', gap: 0, position: 'relative' }}>
          {/* Sliding orange pill -- positioned via CSS vars */}
          <div aria-hidden="true" style={{
            position: 'absolute',
            left: 'var(--pill-left, 0px)',
            width: 'var(--pill-width, 60px)',
            height: 'var(--pill-h, 40px)',
            top: '50%', transform: 'translateY(-50%)',
            background: 'var(--orange)',
            borderRadius: 5,
            opacity: 'var(--pill-op, 0)',
            transition: 'left 0.22s cubic-bezier(.2,.8,.2,1), width 0.18s cubic-bezier(.2,.8,.2,1), opacity 0.14s',
            pointerEvents: 'none',
            zIndex: 0,
          }} />
          {tabs.map(t => {
            const active = route === t.key;
            const hovered = hoverKey === t.key;
            return (
              <button key={t.key}
                onMouseEnter={e => movePill(e, t.key)}
                onClick={() => onNav(t.key)}
                aria-current={active ? 'page' : undefined}
                style={{
                  position: 'relative', zIndex: 1,
                  background: 'none', border: 'none', padding: '10px 15px',
                  fontWeight: 700, fontSize: 13, letterSpacing: '0.05em', textTransform: 'uppercase',
                  color: hovered ? '#fff' : active ? 'var(--ink)' : 'var(--grey-600)',
                  borderBottom: active && !hovered ? '3px solid var(--orange)' : '3px solid transparent',
                  marginBottom: -2,
                  transition: 'color 0.12s',
                  cursor: 'pointer',
                  whiteSpace: 'nowrap',
                }}>
                {t.label}
              </button>
            );
          })}
        </nav>
        {/* Mobile: tiny CTA pill on the right */}
        <button className="only-mobile" onClick={() => onNav('predict')} aria-label="Go to Predict page" style={{
          background: 'var(--orange)', color: '#fff', border: 'none',
          padding: '8px 14px', fontSize: 12, fontWeight: 800, letterSpacing: '0.12em', textTransform: 'uppercase',
          fontFamily: "'Archivo Black', sans-serif",
          boxShadow: '3px 3px 0 0 var(--ink)',
        }}>Predict</button>
      </div>
    </div>
  );
}

/* ---------- Footer ---------- */
function Footer() {
  return (
    <footer style={{
      background: 'var(--ink)', color: '#fff',
      borderTop: '3px solid var(--orange)',
      marginTop: 48,
    }}>
      <div className="footer-inner" style={containerStyle({ py: 22, justify: 'space-between', wrap: true, gap: 14 })}>
        <div>
          <img
            src="/assets/images/wc-logo-v3.png"
            alt="SunFront World Cup Foari 2026"
            className="footer-logo-pill"
            style={{ height: 72, width: 'auto', display: 'block' }}
          />
          <p style={{ marginTop: 10, color: '#d4d4d8', fontSize: 12.5, maxWidth: 480 }}>
            © 2026 SunFront Pvt Ltd. Independent campaign, not affiliated with FIFA.
          </p>
        </div>
        <div className="footer-links" style={{ textAlign: 'right', display: 'flex', flexDirection: 'column', gap: 8, alignItems: 'flex-end' }}>
          <div style={{ display: 'flex', gap: 20, flexWrap: 'wrap', justifyContent: 'flex-end' }}>
            <a href="#/about" style={{ fontSize: 13, color: '#d4d4d8', textDecoration: 'none', fontWeight: 600, letterSpacing: '0.04em' }}
              onMouseEnter={e => e.currentTarget.style.color='var(--orange)'}
              onMouseLeave={e => e.currentTarget.style.color='#d4d4d8'}>
              About SunFront
            </a>
            <a href="#/terms" style={{ fontSize: 13, color: '#d4d4d8', textDecoration: 'none', fontWeight: 600, letterSpacing: '0.04em' }}
              onMouseEnter={e => e.currentTarget.style.color='var(--orange)'}
              onMouseLeave={e => e.currentTarget.style.color='#d4d4d8'}>
              Terms &amp; Conditions
            </a>
          </div>
        </div>
      </div>
    </footer>
  );
}

/* ---------- Container utility ---------- */
function containerStyle({ py = 0, justify = 'flex-start', align = 'center', wrap = false, gap = 0 } = {}) {
  return {
    maxWidth: 1200, margin: '0 auto', padding: `${py}px clamp(16px, 4vw, 28px)`,
    display: 'flex', alignItems: align, justifyContent: justify, gap, flexWrap: wrap ? 'wrap' : 'nowrap',
  };
}

/* ---------- Eyebrow ---------- */
function Eyebrow({ children, color = 'var(--orange)' }) {
  return (
    <div style={{
      display: 'inline-flex', alignItems: 'center', gap: 10,
      fontSize: 12, letterSpacing: '0.22em', textTransform: 'uppercase',
      fontWeight: 700, color,
    }}>
      <span style={{ display: 'inline-block', width: 28, height: 2, background: color }} />
      {children}
    </div>
  );
}

/* ---------- Page header band ---------- */
function PageBand({ eyebrow, title, sub, right }) {
  return (
    <section style={{ background: '#fff', borderBottom: '1px solid var(--grey-200)' }}>
      <div className="page-band-inner" style={{
        maxWidth: 1200, margin: '0 auto',
        padding: 'clamp(22px, 5vw, 40px) clamp(16px, 4vw, 28px) clamp(18px, 4vw, 32px)',
        display: 'grid', gridTemplateColumns: right ? '1fr auto' : '1fr', gap: 20, alignItems: 'end',
      }}>
        <div>
          <Eyebrow>{eyebrow}</Eyebrow>
          <h1 className="font-display" style={{ fontSize: 'clamp(26px, 5vw, 56px)', lineHeight: 1.05, margin: '10px 0 8px', maxWidth: 820 }}>
            {title}
          </h1>
          {sub && <p style={{ color: 'var(--grey-600)', maxWidth: 620, fontSize: 'clamp(13px, 2vw, 15px)', lineHeight: 1.5 }}>{sub}</p>}
        </div>
        {right && <div className="hide-mobile">{right}</div>}
      </div>
    </section>
  );
}

/* ---------- Format helpers ---------- */
function formatKickoff(date) {
  const d = new Date(date);
  // Offset to UTC+5 (Maldives Time)
  const mvt = new Date(d.getTime() + 5 * 60 * 60 * 1000);
  const days = ['Sun','Mon','Tue','Wed','Thu','Fri','Sat'];
  const months = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'];
  const h = mvt.getUTCHours();
  const m = mvt.getUTCMinutes();
  const hh = ((h + 11) % 12 + 1);
  const ampm = h >= 12 ? 'PM' : 'AM';
  return days[mvt.getUTCDay()] + ' ' + mvt.getUTCDate() + ' ' + months[mvt.getUTCMonth()] + ' · ' + hh + ':' + String(m).padStart(2,'0') + ' ' + ampm + ' MVT';
}
function relativeWindow(kickoffMs, now) {
  const diff = kickoffMs - now;
  const hrs = Math.round(diff / 3600000);
  if (diff <= 0) return 'kickoff passed';
  if (hrs <= 24) return `kicks off in ${hrs}h`;
  return `kicks off in ${Math.round(hrs/24)}d`;
}

/* ---------- Live clock + countdown ---------- */
function useNow(interval = 1000) {
  const [now, setNow] = useState(Date.now());
  useEffect(() => {
    const id = setInterval(() => setNow(Date.now()), interval);
    return () => clearInterval(id);
  }, [interval]);
  return now;
}
function diffParts(ms) {
  if (ms <= 0) return { d:0, h:0, m:0, s:0, total: 0, past: true };
  const s = Math.floor(ms / 1000);
  return {
    d: Math.floor(s / 86400),
    h: Math.floor((s % 86400) / 3600),
    m: Math.floor((s % 3600) / 60),
    s: s % 60,
    total: s,
    past: false,
  };
}
function pad(n) { return String(n).padStart(2, '0'); }

/* Compact countdown chip (Dd Hh Mm Ss always) */
function Countdown({ to, tone = 'orange', size = 'md', prefix = '', live = true }) {
  const now = useNow(live ? 1000 : 60000);
  const p = diffParts(to - now);
  const inWindow = (to - now) <= HOURS(24) && (to - now) > 0;
  const palette = {
    orange: { bg: 'var(--orange)', fg: '#fff' },
    ink:    { bg: 'var(--ink)',    fg: 'var(--orange)' },
    light:  { bg: 'var(--orange-50)', fg: 'var(--orange-dark)' },
  }[tone] || {};
  const dims = size === 'sm' ? { fs: 11, pad: '4px 8px', gap: 4 } : { fs: 13, pad: '6px 10px', gap: 6 };

  if (p.past) {
    return (
      <span className="font-mono" style={{
        display: 'inline-flex', alignItems: 'center', gap: dims.gap,
        background: palette.bg, color: palette.fg,
        padding: dims.pad, fontSize: dims.fs, fontWeight: 700, letterSpacing: '0.04em',
      }}>
        {prefix && <span style={{ fontFamily: 'Inter', letterSpacing: '0.14em' }}>{prefix}</span>}
        <span>KICKED OFF</span>
      </span>
    );
  }

  /* Always show D H M S -- days hidden when 0 */
  const parts = [];
  if (p.d > 0) parts.push({ v: String(p.d), u: 'd' });
  parts.push({ v: pad(p.h), u: 'h' });
  parts.push({ v: pad(p.m), u: 'm' });
  parts.push({ v: pad(p.s), u: 's' });

  return (
    <span className="font-mono" style={{
      display: 'inline-flex', alignItems: 'center', gap: dims.gap,
      background: palette.bg, color: palette.fg,
      padding: dims.pad, fontSize: dims.fs, fontWeight: 700, letterSpacing: '0.02em',
      whiteSpace: 'nowrap',
    }}>
      {inWindow && (
        <span className="pulse-dot" style={{ width: 6, height: 6, background: 'currentColor', borderRadius: '50%', flexShrink: 0 }} />
      )}
      {prefix && <span style={{ fontFamily: 'Inter', letterSpacing: '0.12em', marginRight: 2 }}>{prefix}</span>}
      {parts.map((pt, i) => (
        <span key={i} style={{ display: 'inline-flex', alignItems: 'baseline', gap: 1 }}>
          <span>{pt.v}</span>
          <span style={{ fontSize: Math.max(dims.fs * 0.72, 9), fontWeight: 600, opacity: 0.80 }}>{pt.u}</span>
        </span>
      ))}
    </span>
  );
}

/* Animated counter -- eases into target on mount */
function AnimatedCounter({ value, duration = 1100, format = (n) => Math.round(n).toLocaleString() }) {
  const [v, setV] = useState(0);
  const startRef = useRef(null);
  useEffect(() => {
    let raf;
    const step = (t) => {
      if (!startRef.current) startRef.current = t;
      const k = Math.min(1, (t - startRef.current) / duration);
      const eased = 1 - Math.pow(1 - k, 3);
      setV(value * eased);
      if (k < 1) raf = requestAnimationFrame(step);
    };
    raf = requestAnimationFrame(step);
    return () => cancelAnimationFrame(raf);
  }, [value, duration]);
  return <>{format(v)}</>;
}

/* Live match ticker -- auto-scrolling marquee */
/* TickerItem is stable (defined outside MatchTicker) so CSS animation never resets */
var TickerItem = React.memo(function TickerItem({ m }) {
  /* Static time string computed once -- no live timer = no width jitter */
  var timeStr = formatKickoff(m.kickoffMs);
  return (
    <span style={{ display: 'inline-flex', alignItems: 'center', gap: 8, fontSize: 11.5, fontWeight: 600, letterSpacing: '0.05em' }}>
      <span className="pulse-dot" style={{ width: 5, height: 5, background: 'var(--orange)', borderRadius: '50%', flexShrink: 0 }} />
      <Flag code={m.teamA.flag} w={18} h={18} rounded={999} alt={m.teamA.name} />
      <span style={{ textTransform: 'uppercase', color: '#fff' }}>{m.teamA.name}</span>
      <span style={{ color: 'var(--orange)' }}>vs</span>
      <Flag code={m.teamB.flag} w={18} h={18} rounded={999} alt={m.teamB.name} />
      <span style={{ textTransform: 'uppercase', color: '#fff' }}>{m.teamB.name}</span>
      <span className="font-mono" style={{
        fontSize: 10, color: '#fff', letterSpacing: '0.08em', whiteSpace: 'nowrap',
      }}>{timeStr}</span>
    </span>
  );
});

var MatchTicker = React.memo(function MatchTicker({ matches }) {
  var open = React.useMemo(function() {
    return matches.filter(function(m) { return m.status === 'OPEN'; });
  }, [matches]);
  if (open.length === 0) return null;
  /*
   * Build a doubled list long enough to fill any viewport without gaps.
   * Repeat the source until we have >= 16 items, then double that for the
   * seamless -50% loop. Always ends up an even multiple of open.length.
   */
  var tripled = React.useMemo(function() {
    var src = open;
    while (src.length < 8) { src = src.concat(open); }
    return src.concat(src); /* double for seamless -50% loop */
  }, [open]);
  /*
   * Speed target: ~260px/s feels natural for a news ticker.
   * Each item is roughly 260px wide (name + vs + name + time + gap).
   * Half the array scrolls past during one cycle (the -50% half).
   * duration = (half-array item count * item_width_px) / px_per_second
   */
  var duration = React.useMemo(function() {
    var halfCount = tripled.length / 2; /* items in the visible "half" */
    var itemPx = 260;                   /* estimated px per item incl gap */
    var pxPerSec = 55;                  /* comfortable reading speed ~55px/s */
    return Math.round((halfCount * itemPx) / pxPerSec);
  }, [tripled.length]);
  return (
    <div style={{ background: 'var(--ink)', overflow: 'hidden', borderBottom: '1px solid #000' }}>
      <div style={{ display: 'flex', alignItems: 'center' }}>
        <div style={{
          background: 'var(--orange)', color: 'var(--ink)',
          padding: '8px 14px', fontSize: 11, fontWeight: 800, letterSpacing: '0.18em',
          fontFamily: "'Nunito', sans-serif", flexShrink: 0,
          display: 'inline-flex', alignItems: 'center', gap: 8,
        }}>
          <span className="pulse-dot" style={{ width: 7, height: 7, background: 'var(--ink)', borderRadius: '50%' }} />
          LIVE
        </div>
        <div style={{ overflow: 'hidden', flex: 1, padding: '8px 0' }}>
          <div className="ticker-track" style={{ animationDuration: duration + 's' }}>
            {tripled.map(function(m, i) { return <TickerItem key={m.id + '-' + i} m={m} />; })}
          </div>
        </div>
      </div>
    </div>
  );
});

/* Shared inner-page banner strip with campaign logo overlay */
function InnerPageBanner() {
  return (
    <div style={{ position: 'relative', overflow: 'hidden', lineHeight: 0 }}>
      <img
        src="/assets/images/fixture-banner.png"
        alt=""
        aria-hidden="true"
        className="inner-banner-img"
        style={{ width: '100%', display: 'block', objectFit: 'cover', objectPosition: 'center 25%', maxHeight: 160 }}
      />
    </div>
  );
}

/* ---------- Mobile bottom nav ---------- */
function BottomNav({ route, onNav }) {
  const tabs = [
    { key: 'home',           label: 'Home',     icon: 'bolt' },
    { key: 'fixtures',       label: 'Fixtures', icon: 'calendar' },
    { key: 'predict',        label: 'Predict',  icon: 'target' },
    { key: 'dashboard',      label: 'Stats',    icon: 'trophy' },
    { key: 'my-predictions', label: 'My Picks', icon: 'flag' },
  ];
  return (
    <nav className="only-mobile" style={{
      position: 'fixed', left: 0, right: 0, bottom: 0, zIndex: 40,
      background: '#fff',
      borderTop: '2px solid var(--ink)',
      paddingBottom: 'env(safe-area-inset-bottom)',
      boxShadow: '0 -6px 24px rgba(26,15,31,0.06)',
    }}>
      {/* Top orange accent split */}
      <div style={{
        position: 'absolute', left: 0, right: 0, top: -2, height: 2,
        background: 'linear-gradient(to right, var(--orange) 25%, var(--ink) 25%)',
      }} />
      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(5, 1fr)' }}>
        {tabs.map(t => {
          const active = route === t.key;
          return (
            <button key={t.key} onClick={() => onNav(t.key)}
              aria-label={t.label} aria-current={active ? 'page' : undefined}
              style={{
              background: 'none', border: 'none', padding: '12px 4px 10px',
              display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 4,
              color: active ? 'var(--ink)' : 'var(--grey-500)',
              fontWeight: 700, fontSize: 10, letterSpacing: '0.08em', textTransform: 'uppercase',
              position: 'relative',
              cursor: 'pointer',
              minHeight: 56, justifyContent: 'center',
              WebkitTapHighlightColor: 'transparent',
            }}>
              <Icon name={t.icon} size={24} color={active ? 'var(--orange)' : 'var(--grey-400)'} stroke={active ? 2.2 : 1.8} />
              <span style={{ lineHeight: 1.2 }}>{t.label}</span>
              {active && (
                <span style={{
                  position: 'absolute', bottom: 0, left: '50%', transform: 'translateX(-50%)',
                  width: 28, height: 3, background: 'var(--orange)',
                }} />
              )}
            </button>
          );
        })}
      </div>
    </nav>
  );
}

/* Export an array of plain row objects to an .xlsx file (admin tables). */
function exportRowsToXlsx(filename, sheetName, rows) {
  if (!window.XLSX) {
    console.error('XLSX library not loaded');
    return false;
  }
  const ws = window.XLSX.utils.json_to_sheet(rows);
  const wb = window.XLSX.utils.book_new();
  window.XLSX.utils.book_append_sheet(wb, ws, sheetName || 'Sheet1');
  window.XLSX.writeFile(wb, filename);
  return true;
}

Object.assign(window, {
  SunFrontLogo, Flag, VSHex, StatusBadge, Icon,
  TopStrip, Nav, Footer, Eyebrow, PageBand, InnerPageBanner,
  containerStyle, formatKickoff, relativeWindow,
  useNow, diffParts, Countdown, AnimatedCounter, MatchTicker, BottomNav,
  exportRowsToXlsx,
});

