// Sportistry marketing website — components.jsx
// Shared primitives. Many are lifted from the web UI kit (webcomponents.jsx)
// and extended with marketing-site helpers (PhotoSlot, StoreBadges, Section…).

const SB = {
  blue: '#1652F0', blue600: '#0E40CC', blue700: '#0A33A6', blue50: '#EEF3FF',
  lime: '#C6F73C', lime400: '#A8DD1F',
  ink950: '#0A0E1C', ink900: '#121726', ink800: '#1F2638', ink700: '#333C52',
  ink600: '#4B556E', ink500: '#6B7691', ink400: '#95A0B5', ink300: '#C2CAD8',
  ink200: '#DDE2EC', ink100: '#ECEFF5', ink50: '#F6F8FB',
};
const FD = "Archivo, system-ui, sans-serif";
const FB = "Manrope, system-ui, sans-serif";
const FM = "'JetBrains Mono', ui-monospace, monospace";
const MAXW = 1200;

const WEB_SPORTS = {
  soccer:      { tint: '#2EB85C', label: 'Soccer'      },
  basket:      { tint: '#E27A2B', label: 'Basketball'  },
  tennis:      { tint: '#C6F73C', label: 'Tennis'      },
  running:     { tint: '#6A3FF0', label: 'Running'     },
  cycling:     { tint: '#0DB1C9', label: 'Cycling'     },
  volley:      { tint: '#F0498D', label: 'Volleyball'  },
  climbing:    { tint: '#8B5E2C', label: 'Climbing'    },
  padel:       { tint: '#00C2A8', label: 'Padel'       },
  fitness:     { tint: '#FF5733', label: 'Fitness'     },
  swimming:    { tint: '#1652F0', label: 'Swimming'    },
  hiking:      { tint: '#2D6A4F', label: 'Hiking'      },
  badminton:   { tint: '#FFB703', label: 'Badminton'   },
  yoga:        { tint: '#A78BFA', label: 'Yoga'        },
  bouldering:  { tint: '#8D99AE', label: 'Bouldering'  },
  boxing:      { tint: '#D62839', label: 'Boxing'      },
  handball:    { tint: '#FF6B6B', label: 'Handball'    },
  golf:        { tint: '#6A994E', label: 'Golf'        },
  martialarts: { tint: '#22223B', label: 'Martial Arts'},
  hockey:      { tint: '#3A6EA5', label: 'Hockey'      },
  baseball:    { tint: '#B5838D', label: 'Baseball'    },
};

function useIsMobile(bp = 760) {
  // document.documentElement.clientWidth (layout viewport) rather than window.innerWidth
  // (visual viewport) — a horizontally-overflowing page can make the browser zoom out,
  // which inflates innerWidth past the true device width and would break detection.
  const getWidth = () => typeof document !== 'undefined' && document.documentElement.clientWidth;
  const [isMobile, setIsMobile] = React.useState(() => getWidth() && getWidth() < bp);
  React.useEffect(() => {
    const f = () => setIsMobile(getWidth() < bp);
    f(); window.addEventListener('resize', f); return () => window.removeEventListener('resize', f);
  }, [bp]);
  return isMobile;
}

function shadeWeb(hex, percent) {
  const n = parseInt(hex.replace('#',''), 16);
  let r = (n>>16)&255, g = (n>>8)&255, b = n&255;
  const t = percent < 0 ? 0 : 255;
  const p = Math.abs(percent);
  r = Math.round((t - r) * p + r);
  g = Math.round((t - g) * p + g);
  b = Math.round((t - b) * p + b);
  return '#' + ((1<<24) + (r<<16) + (g<<8) + b).toString(16).slice(1);
}

// ───────────────────── Icons ─────────────────────
function WIcon({ name, size = 22, color = 'currentColor', strokeWidth = 2 }) {
  const props = {
    width: size, height: size, viewBox: '0 0 24 24',
    fill: 'none', stroke: color, strokeWidth, strokeLinecap: 'round', strokeLinejoin: 'round',
  };
  const paths = {
    home:        <><path d="M3 12 12 3l9 9"/><path d="M5 10v10h14V10"/></>,
    discover:    <><circle cx="12" cy="10" r="3"/><path d="M12 21s-7-7-7-12a7 7 0 0 1 14 0c0 5-7 12-7 12Z"/></>,
    plus:        <><path d="M12 5v14M5 12h14"/></>,
    minus:       <><path d="M5 12h14"/></>,
    users:       <><path d="M17 21v-2a4 4 0 0 0-4-4H7a4 4 0 0 0-4 4v2"/><circle cx="10" cy="7" r="4"/><path d="M22 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/></>,
    search:      <><circle cx="11" cy="11" r="7"/><path d="m20 20-3.5-3.5"/></>,
    pin:         <><path d="M12 21s-7-4-7-11a7 7 0 0 1 14 0c0 7-7 11-7 11Z"/><circle cx="12" cy="10" r="3"/></>,
    clock:       <><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></>,
    calendar:    <><rect x="3" y="5" width="18" height="16" rx="2"/><path d="M16 3v4M8 3v4M3 11h18"/></>,
    arrow:       <><path d="M5 12h14M13 5l7 7-7 7"/></>,
    arrowUp:     <><path d="M12 19V5M5 12l7-7 7 7"/></>,
    check:       <><path d="M5 12l5 5L20 7"/></>,
    star:        <><path d="m12 2 3 7 7 1-5 5 1 7-6-3-6 3 1-7-5-5 7-1 3-7Z"/></>,
    bolt:        <><path d="M13 2 4 13h7l-1 9 9-11h-7l1-9Z"/></>,
    trophy:      <><path d="M6 9h12l-1 12H7L6 9Z"/><path d="M12 5v4M9 5h6"/><path d="M3 5h3v4a3 3 0 0 1-3-3z M21 5h-3v4a3 3 0 0 0 3-3z"/></>,
    shield:      <><path d="M12 3 4 6v6c0 5 3.5 8.5 8 9 4.5-.5 8-4 8-9V6l-8-3Z"/></>,
    repeat:      <><path d="M17 2l4 4-4 4"/><path d="M3 11V9a4 4 0 0 1 4-4h14"/><path d="M7 22l-4-4 4-4"/><path d="M21 13v2a4 4 0 0 1-4 4H3"/></>,
    wallet:      <><path d="M3 7a2 2 0 0 1 2-2h13a2 2 0 0 1 2 2v3"/><path d="M3 7v10a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-3h-5a2 2 0 0 1 0-4h5"/></>,
    building:    <><rect x="4" y="3" width="16" height="18" rx="1.5"/><path d="M9 8h0M15 8h0M9 12h0M15 12h0M9 16h0M15 16h0"/></>,
    message:     <><path d="M21 12a8 8 0 0 1-11.5 7.2L4 21l1.8-5.5A8 8 0 1 1 21 12Z"/></>,
    heart:       <><path d="M20.8 5.6a5 5 0 0 0-7.1 0L12 7.3l-1.7-1.7a5 5 0 0 0-7.1 7.1L12 21l8.8-8.3a5 5 0 0 0 0-7.1Z"/></>,
    sliders:     <><path d="M4 6h11M19 6h1M4 12h7M15 12h5M4 18h13M21 18h0"/><circle cx="17" cy="6" r="2"/><circle cx="13" cy="12" r="2"/><circle cx="19" cy="18" r="2"/></>,
    sparkle:     <><path d="M12 3l1.8 5.2L19 10l-5.2 1.8L12 17l-1.8-5.2L5 10l5.2-1.8L12 3Z"/></>,
    download:    <><path d="M12 3v12M7 11l5 5 5-5"/><path d="M5 21h14"/></>,
    smartphone:  <><rect x="7" y="2" width="10" height="20" rx="2.5"/><path d="M11 18h2"/></>,
    ticket:      <><path d="M3 8a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2 2 2 0 0 0 0 4 2 2 0 0 1-2 2v0a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2 2 2 0 0 0 0-4 2 2 0 0 1 0-4Z"/><path d="M15 6v12" strokeDasharray="2 2"/></>,
    award:       <><circle cx="12" cy="9" r="6"/><path d="M9 14.5 8 22l4-2 4 2-1-7.5"/></>,
    play:        <><path d="M6 4l14 8-14 8V4Z"/></>,
    apple:       <><path d="M16 13c0-3 2.5-3.5 2.5-3.5C17.5 7.5 15.5 7.5 15 7.5c-1 0-2 .5-2.7.5-.7 0-1.7-.5-2.8-.5C7.3 7.5 5 9 5 12.5 5 16 7.5 20 9.5 20c.9 0 1.5-.6 2.7-.6 1.2 0 1.6.6 2.6.6 1.5 0 3.2-3 3.7-4.5 0 0-2.5-.8-2.5-2.5Z"/><path d="M14 5c.7-.8 1.2-1.9 1-3-1 .1-2.1.7-2.8 1.5-.6.7-1.1 1.8-1 2.8 1.1.1 2.1-.5 2.8-1.3Z"/></>,
    chevron:     <><path d="m9 18 6-6-6-6"/></>,
    chevronDown: <><path d="m6 9 6 6 6-6"/></>,
    globe:       <><circle cx="12" cy="12" r="9"/><path d="M3 12h18M12 3a13 13 0 0 1 0 18M12 3a13 13 0 0 0 0 18"/></>,
    menu:        <><path d="M4 6h16M4 12h16M4 18h16"/></>,
    close:       <><path d="M6 6l12 12M18 6L6 18"/></>,
    banknote:    <><rect x="2" y="6" width="20" height="12" rx="2"/><circle cx="12" cy="12" r="2"/><path d="M6 12h.01M18 12h.01"/></>,
    creditCard:  <><rect x="2" y="5" width="20" height="14" rx="2"/><path d="M2 10h20"/></>,
    alertTriangle: <><path d="M12 3 2 20h20L12 3Z"/><path d="M12 10v4M12 17h.01"/></>,
    fileCheck:   <><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8L14 2Z"/><path d="M14 2v6h6"/><path d="m9.5 15 2 2 4-4"/></>,
    link:        <><path d="M9 17H7a5 5 0 0 1 0-10h2"/><path d="M15 7h2a5 5 0 0 1 0 10h-2"/><path d="M8 12h8"/></>,
    bell:        <><path d="M6 8a6 6 0 0 1 12 0c0 7 3 9 3 9H3s3-2 3-9"/><path d="M10.3 21a1.94 1.94 0 0 0 3.4 0"/></>,
    trendingUp:  <><path d="m3 17 6-6 4 4 8-8"/><path d="M17 7h4v4"/></>,
    calendarCheck: <><rect x="3" y="5" width="18" height="16" rx="2"/><path d="M16 3v4M8 3v4M3 11h18"/><path d="m9 16 2 2 4-4"/></>,
    calendarPlus: <><rect x="3" y="5" width="18" height="16" rx="2"/><path d="M16 3v4M8 3v4M3 11h18"/><path d="M12 15v4M10 17h4"/></>,
    info:        <><circle cx="12" cy="12" r="9"/><path d="M12 11v5M12 8h.01"/></>,
    map:         <><path d="M3 6l6-2 6 2 6-2v14l-6 2-6-2-6 2Z"/><path d="M9 4v14M15 6v14"/></>,
  };
  return <svg {...props}>{paths[name] || null}</svg>;
}

// ───────────────────── Avatars ─────────────────────
function WAvatar({ name, tint = '#1652F0', size = 36 }) {
  const initials = name.split(' ').map(p => p[0]).slice(0, 2).join('').toUpperCase();
  return (
    <div style={{
      width: size, height: size, borderRadius: '50%', background: tint, color: 'white',
      display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
      fontFamily: FD, fontWeight: 800,
      fontSize: Math.round(size * 0.38), letterSpacing: '-0.02em', flexShrink: 0,
    }}>{initials}</div>
  );
}
function WAvatarStack({ people, size = 32, max = 5, extra }) {
  const shown = people.slice(0, max);
  const more = extra != null ? extra : Math.max(0, people.length - max);
  return (
    <div style={{ display: 'inline-flex' }}>
      {shown.map((p, i) => (
        <div key={i} style={{ marginLeft: i === 0 ? 0 : -size * 0.32, boxShadow: '0 0 0 2.5px white', borderRadius: '50%' }}>
          <WAvatar name={p.name} tint={p.tint} size={size}/>
        </div>
      ))}
      {more > 0 && (
        <div style={{
          marginLeft: -size * 0.32, width: size, height: size, borderRadius: '50%',
          background: '#ECEFF5', color: '#4B556E', boxShadow: '0 0 0 2.5px white',
          display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
          fontFamily: FB, fontWeight: 700, fontSize: Math.round(size * 0.35),
        }}>+{more}</div>
      )}
    </div>
  );
}

// ───────────────────── Button ─────────────────────
function WButton({ variant = 'primary', size = 'md', children, onClick, icon, full, iconRight, href }) {
  const sizes = {
    sm: { padding: '9px 16px', fontSize: 13 },
    md: { padding: '12px 22px', fontSize: 15 },
    lg: { padding: '16px 30px', fontSize: 17 },
  };
  const variants = {
    primary:   { background: SB.blue, color: 'white' },
    secondary: { background: SB.ink100, color: SB.ink900 },
    ghost:     { background: 'transparent', color: SB.ink900 },
    accent:    { background: SB.lime, color: SB.ink900 },
    inverse:   { background: SB.ink950, color: 'white' },
    onDark:    { background: 'rgba(255,255,255,0.12)', color: 'white' },
    outline:   { background: 'transparent', color: SB.ink900, boxShadow: 'inset 0 0 0 1.5px ' + SB.ink200 },
  };
  const Tag = href ? 'a' : 'button';
  return (
    <Tag href={href} onClick={onClick} style={{
      ...sizes[size], ...variants[variant],
      border: 'none', borderRadius: 999, cursor: 'pointer', textDecoration: 'none',
      fontFamily: FB, fontWeight: 700, lineHeight: 1, whiteSpace: 'nowrap',
      display: 'inline-flex', alignItems: 'center', justifyContent: 'center', gap: 8,
      width: full ? '100%' : undefined, boxSizing: 'border-box',
      transition: 'transform 80ms cubic-bezier(.22,1,.36,1), background 120ms, box-shadow 120ms',
    }}
      onMouseDown={e => e.currentTarget.style.transform = 'scale(.98)'}
      onMouseUp={e => e.currentTarget.style.transform = 'scale(1)'}
      onMouseEnter={e => { if (variant==='primary') e.currentTarget.style.background = SB.blue600;
        if (variant==='accent') e.currentTarget.style.background = SB.lime400; }}
      onMouseLeave={e => { e.currentTarget.style.transform = 'scale(1)';
        if (variant==='primary') e.currentTarget.style.background = SB.blue;
        if (variant==='accent') e.currentTarget.style.background = SB.lime; }}>
      {icon && <WIcon name={icon} size={size === 'lg' ? 20 : 16}/>}
      {children}
      {iconRight && <WIcon name={iconRight} size={size === 'lg' ? 20 : 16}/>}
    </Tag>
  );
}

function WChip({ active, children, onClick, color }) {
  return (
    <button onClick={onClick} style={{
      display: 'inline-flex', alignItems: 'center', gap: 6, padding: '8px 14px',
      borderRadius: 999, border: 'none',
      background: active ? SB.blue : SB.ink100,
      color: active ? 'white' : SB.ink900,
      fontFamily: FB, fontWeight: 600, fontSize: 13,
      cursor: 'pointer', lineHeight: 1, whiteSpace: 'nowrap',
    }}>
      {color && <span style={{width:7,height:7,borderRadius:'50%',background:color}}/>}
      {children}
    </button>
  );
}

function WStatusBadge({ status }) {
  const map = {
    live:   { bg: '#121726', fg: '#C6F73C', text: tr('LIVE', 'ÉLŐ'), dot: true, pulse: true },
    going:  { bg: '#E2F7EC', fg: '#0A6E40', text: tr('Going', 'Megyek'), dot: true },
    maybe:  { bg: '#FEF3DC', fg: '#7A4A00', text: tr('Maybe', 'Talán') },
    full:   { bg: '#FDE3E6', fg: '#8C1224', text: tr('Full', 'Megtelt') },
    open:   { bg: '#EEF3FF', fg: '#0A33A6', text: tr('Spots open', 'Van hely') },
  };
  const s = map[status] || map.open;
  return (
    <span style={{
      display: 'inline-flex', alignItems: 'center', gap: 6, background: s.bg, color: s.fg,
      fontFamily: FD, fontWeight: 700, fontSize: 10,
      letterSpacing: '.08em', textTransform: 'uppercase',
      padding: '5px 9px', borderRadius: 999, lineHeight: 1,
    }}>
      {s.dot && <span style={{
        width: 6, height: 6, borderRadius: '50%', background: s.fg,
        animation: s.pulse ? 'sb-pulse 1.4s ease-in-out infinite' : undefined,
      }}/>}
      {s.text}
    </span>
  );
}

function WEventCard({ event, compact, onTap }) {
  const sport = WEB_SPORTS[event.sport] || WEB_SPORTS.soccer;
  const heroGrad = `radial-gradient(circle at 30% 20%, ${sport.tint}, ${shadeWeb(sport.tint, -0.45)})`;
  return (
    <div onClick={onTap} style={{
      background: 'white', borderRadius: 16, overflow: 'hidden', cursor: 'pointer',
      boxShadow: '0 2px 4px rgba(18,23,38,0.06), 0 1px 2px rgba(18,23,38,0.04)',
      borderBottom: `4px solid ${sport.tint}`,
      transition: 'transform 160ms ease, box-shadow 160ms ease',
    }}
    onMouseEnter={e => { e.currentTarget.style.transform = 'translateY(-2px)'; e.currentTarget.style.boxShadow = '0 6px 14px rgba(18,23,38,0.08), 0 2px 4px rgba(18,23,38,0.04)'; }}
    onMouseLeave={e => { e.currentTarget.style.transform = 'translateY(0)'; e.currentTarget.style.boxShadow = '0 2px 4px rgba(18,23,38,0.06), 0 1px 2px rgba(18,23,38,0.04)'; }}
    >
      <div style={{ height: compact ? 120 : 156, background: heroGrad, position: 'relative' }}>
        <img src={uimg(SPORT_IMG[event.sport] || SPORT_IMG.soccer, 700, 65)} alt="" loading="lazy"
          style={{ position: 'absolute', inset: 0, width: '100%', height: '100%', objectFit: 'cover' }}/>
        <PhotoTexture/>
        <div style={{ position: 'absolute', right: -10, bottom: -10, opacity: 0.18, transform: 'rotate(-8deg)', lineHeight: 0 }}>
          <SportGlyph sport={event.sport} size={compact ? 92 : 116} color="#fff"/>
        </div>
        <div style={{ position: 'absolute', inset: 0,
          background: 'linear-gradient(to top, rgba(10,14,28,0.65), transparent 55%)' }}/>
        <div style={{ position: 'absolute', top: 14, left: 14, display: 'flex', gap: 6 }}>
          {event.status && <WStatusBadge status={event.status}/>}
        </div>
        <div style={{ position: 'absolute', top: 14, right: 14, color: 'white',
          fontFamily: FD, fontWeight: 700, fontSize: 11,
          letterSpacing: '.08em', textTransform: 'uppercase',
          background: 'rgba(10,14,28,0.4)', backdropFilter: 'blur(8px)',
          padding: '5px 10px', borderRadius: 999,
        }}>{sportLabel(event.sport)}</div>
        <div style={{ position: 'absolute', bottom: 14, left: 16, right: 16, color: 'white' }}>
          <div style={{ fontFamily: FD, fontWeight: 800,
            fontSize: compact ? 20 : 22, letterSpacing: '-0.01em', lineHeight: 1.15 }}>{event.title}</div>
        </div>
      </div>
      <div style={{ padding: '14px 16px', display: 'flex', flexDirection: 'column', gap: 10 }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 14, color: SB.ink600,
          fontFamily: FB, fontSize: 13 }}>
          <span style={{display:'inline-flex',alignItems:'center',gap:5}}><WIcon name="clock" size={14}/>{event.time}</span>
          <span style={{display:'inline-flex',alignItems:'center',gap:5}}><WIcon name="pin" size={14}/>{event.location}</span>
        </div>
        <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
            <WAvatarStack people={event.attendees} size={28} max={4}
              extra={Math.max(0, event.going - Math.min(event.attendees.length, 4))}/>
            <span style={{ fontFamily: FB, fontWeight: 600, fontSize: 13, color: SB.ink600 }}>
              {event.going} {tr('going', 'megy')}{event.left != null && ` · ${event.left} ${tr('left', 'hely')}`}
            </span>
          </div>
          <WButton size="sm" variant={event.joined ? 'secondary' : 'primary'}>
            {event.joined ? tr("You're in", 'Bent vagy') : tr("I'm in", 'Benne vagyok')}
          </WButton>
        </div>
      </div>
    </div>
  );
}

// ───────────────────── Marketing helpers ─────────────────────

// Subtle diagonal "photo" texture used inside gradient slots so they don't read flat
function PhotoTexture() {
  return (
    <div style={{ position: 'absolute', inset: 0, opacity: 0.5, mixBlendMode: 'overlay',
      backgroundImage: 'repeating-linear-gradient(135deg, rgba(255,255,255,0.10) 0 2px, transparent 2px 11px)' }}/>
  );
}

// Photo slot — a real photo layered over the app-card treatment (sport-tint
// gradient + faint sport-glyph watermark). If the photo fails to load, the
// on-brand gradient + glyph remain, so it never looks broken.
function PhotoSlot({ label, height = 320, radius = 20, tint = SB.ink800, aspect, glow,
  sport, src, imgPosition = '50% 50%', overlay = true, children, style }) {
  const h = typeof height === 'number' ? height : 220;
  return (
    <div style={{
      position: 'relative', overflow: 'hidden', borderRadius: radius,
      height: aspect ? undefined : height, aspectRatio: aspect,
      background: `radial-gradient(circle at 28% 18%, ${tint}, ${shadeWeb(tint, -0.42)})`,
      display: 'flex', alignItems: 'center', justifyContent: 'center',
      ...style,
    }}>
      {sport && (
        <div style={{ position: 'absolute', right: -14, bottom: -14, opacity: src ? 0.14 : 0.20,
          transform: 'rotate(-8deg)', lineHeight: 0 }}>
          <SportGlyph sport={sport} size={Math.max(120, Math.round(h * 0.72))} color="#fff"/>
        </div>
      )}
      <div style={{ position: 'absolute', inset: 0, opacity: 0.5,
        backgroundImage: 'repeating-linear-gradient(135deg, rgba(255,255,255,0.05) 0 3px, transparent 3px 16px)' }}/>
      {src && <img src={uimg(src, 900, 70)} alt={label || ''} loading="lazy"
        style={{ position: 'absolute', inset: 0, width: '100%', height: '100%', objectFit: 'cover', objectPosition: imgPosition }}/>}
      {src && overlay && <div style={{ position: 'absolute', inset: 0,
        background: 'linear-gradient(to top, rgba(10,14,28,0.62), rgba(10,14,28,0.04) 56%)' }}/>}
      {glow && <div style={{ position: 'absolute', top: -60, right: -40, width: 240, height: 240,
        borderRadius: '50%', background: `radial-gradient(circle, ${glow}, transparent 70%)`,
        opacity: src ? 0.35 : 0.55, mixBlendMode: 'screen' }}/>}
      {children && <div style={{ position: 'relative', width: '100%', height: '100%' }}>{children}</div>}
    </div>
  );
}

function Eyebrow({ children, color = SB.blue, style }) {
  return (
    <div style={{ fontFamily: FD, fontWeight: 700, fontSize: 12,
      letterSpacing: '.08em', textTransform: 'uppercase', color, ...style }}>{children}</div>
  );
}

function Container({ children, style, width = MAXW }) {
  const isMobile = useIsMobile();
  return <div style={{ maxWidth: width, margin: '0 auto', padding: isMobile ? '0 20px' : '0 32px', ...style }}>{children}</div>;
}

function Section({ children, bg = 'white', pad = '96px 0', id, style }) {
  const isMobile = useIsMobile();
  return <section id={id} style={{ background: bg, padding: isMobile ? '56px 0' : pad, ...style }}>{children}</section>;
}

// App-store links. Fill these in when the listings go live — badges switch
// from a dimmed "coming soon" placeholder to a real, clickable link automatically.
const STORE_LINKS = { ios: null, android: null };

// App-store download badges (clean, brand-safe approximations)
function StoreBadges({ dark = true, size = 'md' }) {
  const h = size === 'lg' ? 56 : 50;
  const badge = (href, eyebrow, name, glyph) => {
    const live = !!href;
    const content = (
      <>
        {glyph}
        <span style={{ display: 'flex', flexDirection: 'column', lineHeight: 1.15 }}>
          <span style={{ fontFamily: FB, fontWeight: 500, fontSize: 10, opacity: 0.8, letterSpacing: '0.02em' }}>{eyebrow}</span>
          <span style={{ fontFamily: FD, fontWeight: 700, fontSize: 16, letterSpacing: '-0.01em' }}>{name}</span>
        </span>
        {!live && (
          <span style={{
            fontFamily: FB, fontWeight: 700, fontSize: 9, letterSpacing: '.04em', textTransform: 'uppercase',
            color: SB.ink900, background: SB.lime, borderRadius: 999, padding: '3px 7px', marginLeft: 2,
          }}>
            {tr('Soon', 'Hamarosan')}
          </span>
        )}
      </>
    );
    const style = {
      display: 'inline-flex', alignItems: 'center', gap: 11, height: h, padding: '0 18px',
      borderRadius: 12, textDecoration: 'none', boxSizing: 'border-box',
      background: dark ? '#000' : SB.ink900, color: 'white',
      boxShadow: dark ? '0 1px 0 rgba(255,255,255,0.12) inset' : 'none',
      opacity: live ? 1 : 0.55,
      cursor: live ? 'pointer' : 'default',
    };
    return live
      ? <a href={href} target="_blank" rel="noopener" style={style}>{content}</a>
      : <div style={style} aria-disabled="true">{content}</div>;
  };
  return (
    <div style={{ display: 'flex', gap: 12, flexWrap: 'wrap' }}>
      {badge(STORE_LINKS.ios, tr('Download on the', 'Töltsd le az'), 'App Store', <WIcon name="apple" size={24} color="white"/>)}
      {badge(STORE_LINKS.android, tr('Get it on', 'Elérhető a'), 'Google Play', <WIcon name="play" size={22} color={SB.lime}/>)}
    </div>
  );
}

// ───────────────────── Brand mark ─────────────────────
// The icon: a location pin holding the two buddies (blue + green) — matches
// assets/app-icon.png exactly, so the app icon / favicon and this mark are one.
function LogoMark({ size = 32, radius = 0.22 }) {
  return (
    <svg viewBox="0 0 64 64" width={size} height={size} style={{ display: 'block', flexShrink: 0 }} aria-hidden="true">
      <rect width="64" height="64" rx={64 * radius} fill={SB.blue}/>
      <path d="M32 10c-9.5 0-16 7-16 15.5C16 36 32 54 32 54s16-18 16-28.5C48 17 41.5 10 32 10Z" fill="#fff"/>
      <circle cx="26.5" cy="26" r="5.4" fill={SB.blue}/>
      <circle cx="38" cy="26" r="5.4" fill="#10B981"/>
      <path d="M19.5 41v-1.2c0-4.3 3.2-7.3 7-7.3s5.5 2 5.5 2v6.5Z" fill={SB.blue}/>
      <path d="M32 34.5s1.7-2 5.2-2c3.8 0 7.3 3 7.3 7.3V41H32Z" fill="#10B981"/>
    </svg>
  );
}

// The wordmark: the “i” in Sport·i·stry is the two-people glyph (blue + green),
// so the mark and the word tell the same two-buddies story (brand Direction 08).
function Logo({ size = 30, light = false, showWord = true, collapse = 0, collapseAnim = false }) {
  if (!showWord) return <LogoMark size={size}/>;
  const blue  = light ? '#5479FF' : SB.blue;
  const green = light ? SB.lime    : '#10B981';
  const word  = light ? '#FFFFFF'  : SB.ink900;
  const gw = Math.round(size * 0.6), gh = Math.round(size * 0.96);
  // Trial (desktop only): past the header's scroll threshold, "Sport"/"stry" roll into
  // the glyph and vanish; a CSS transition carries the roll to completion even on a
  // tiny scroll, rather than scrubbing 1:1 with scroll distance.
  const rollTransition = 'max-width 320ms cubic-bezier(.22,1,.36,1), opacity 280ms ease, transform 320ms cubic-bezier(.22,1,.36,1)';
  const rollLeft  = collapseAnim ? { display: 'inline-block', overflow: 'hidden', whiteSpace: 'nowrap',
    maxWidth: (1 - collapse) * 3.4 + 'em', opacity: 1 - collapse, transform: 'translateX(' + collapse * 0.6 + 'em)',
    transition: rollTransition } : undefined;
  const rollRight = collapseAnim ? { display: 'inline-block', overflow: 'hidden', whiteSpace: 'nowrap',
    maxWidth: (1 - collapse) * 2.8 + 'em', opacity: 1 - collapse, transform: 'translateX(' + -collapse * 0.6 + 'em)',
    transition: rollTransition } : undefined;
  return (
    <span style={{ fontFamily: FD, fontWeight: 900, fontSize: size, letterSpacing: '-0.022em',
      lineHeight: 1, whiteSpace: 'nowrap', display: 'inline-flex', alignItems: 'baseline',
      color: word, userSelect: 'none' }}>
      {collapseAnim ? <span style={rollLeft}>Sport</span> : 'Sport'}
      <span style={{ display: 'inline-block', width: gw, margin: '0 0.04em' }}>
        <svg viewBox="0 0 60 96" width={gw} height={gh} style={{ display: 'block' }} aria-hidden="true">
          <path d="M2 96 V70 a18 18 0 0 1 36 0 V96 Z" fill={blue}/>
          <circle cx="20" cy="34" r="16" fill={blue}/>
          <path d="M22 96 V64 a19 19 0 0 1 38 0 V96 Z" fill={green}/>
          <circle cx="41" cy="26" r="17" fill={green}/>
        </svg>
      </span>
      {collapseAnim ? <span style={rollRight}>stry</span> : 'stry'}
    </span>
  );
}

// ───────────────────── Sport glyph (app-card watermark) ─────────────────────
function SportGlyph({ sport, size = 120, color = '#fff' }) {
  const props = { width: size, height: size, viewBox: '0 0 64 64', fill: 'none',
    stroke: color, strokeWidth: 3, strokeLinecap: 'round', strokeLinejoin: 'round' };
  const g = {
    soccer:   <><circle cx="32" cy="32" r="22"/><path d="M32 20l9 6.5-3.5 10.5h-11L23 26.5z" fill={color} stroke="none"/><path d="M32 20V11M41 26.5l8-4.5M37.5 37l5.5 7.5M26.5 37l-5.5 7.5M23 26.5l-8-4.5"/></>,
    basket:   <><circle cx="32" cy="32" r="22"/><path d="M10 32h44M32 10v44"/><path d="M16 16c8 6 8 26 0 32M48 16c-8 6-8 26 0 32"/></>,
    tennis:   <><circle cx="32" cy="32" r="22"/><path d="M14 18c10 6 10 22 0 28M50 18c-10 6-10 22 0 28"/></>,
    running:  <><circle cx="38" cy="14" r="6" fill={color} stroke="none"/><path d="M38 22l-6 10 8 6 2 12M32 32l-11 4M40 38l10 2M21 50l9-13"/></>,
    cycling:  <><circle cx="18" cy="44" r="11"/><circle cx="46" cy="44" r="11"/><path d="M18 44l10-18h12M28 26l8 18M40 26h6M28 26h12"/></>,
    volley:   <><circle cx="32" cy="32" r="22"/><path d="M32 10c-6 12-6 30 6 42M10 32c12 4 30 2 40-12M54 36c-12 6-28 4-38-12"/></>,
    climbing: <><path d="M8 52l14-26 8 12 8-20 18 34z"/><circle cx="40" cy="14" r="4" fill={color} stroke="none"/></>,
    padel:    <><ellipse cx="32" cy="24" rx="16" ry="18"/><path d="M32 42v14M26 56h12"/><circle cx="26" cy="20" r="1.8" fill={color} stroke="none"/><circle cx="38" cy="20" r="1.8" fill={color} stroke="none"/><circle cx="32" cy="29" r="1.8" fill={color} stroke="none"/></>,
    fitness:  <><rect x="8" y="22" width="10" height="20" rx="3"/><rect x="46" y="22" width="10" height="20" rx="3"/><path d="M20 32h24"/></>,
    swimming: <><circle cx="20" cy="18" r="5" fill={color} stroke="none"/><path d="M8 30c6-4 10 4 16 0s10-4 16 0 10-4 16 0M8 42c6-4 10 4 16 0s10-4 16 0 10-4 16 0M8 54c6-4 10 4 16 0s10-4 16 0 10-4 16 0"/></>,
    hiking:   <><path d="M10 54l12-30 8 12 6-16 16 34z"/><path d="M18 54c2-6 6-10 10-10s8 4 10 10" strokeDasharray="2 4"/></>,
    badminton:<><ellipse cx="24" cy="22" rx="14" ry="16"/><path d="M24 38v18M18 56h12"/><path d="M40 12l14 14"/><circle cx="52" cy="12" r="3" fill={color} stroke="none"/></>,
    yoga:     <><circle cx="32" cy="14" r="6" fill={color} stroke="none"/><path d="M14 50c4-14 12-20 18-20s14 6 18 20M20 50h24M32 30v14"/></>,
    bouldering:<><path d="M8 48c4-14 14-24 24-24s20 10 24 24z"/><circle cx="26" cy="34" r="3" fill={color} stroke="none"/><circle cx="38" cy="26" r="3" fill={color} stroke="none"/></>,
    boxing:   <><path d="M20 40V22a10 10 0 0 1 20 0v4a8 8 0 0 1 8 8v6a12 12 0 0 1-12 12H28a12 12 0 0 1-12-12v-2z"/><path d="M20 30h20"/></>,
    handball: <><circle cx="32" cy="32" r="20"/><path d="M17 17l30 30M47 17l-30 30"/></>,
    golf:     <><path d="M22 54V10"/><path d="M22 12l22 8-22 8"/><circle cx="40" cy="52" r="6" fill={color} stroke="none"/></>,
    martialarts:<><circle cx="32" cy="14" r="6" fill={color} stroke="none"/><path d="M18 54l6-24h16l6 24M20 34h24M26 30l-4-8M38 30l4-8"/></>,
    hockey:   <><path d="M44 8l-8 34-14 4"/><ellipse cx="18" cy="50" rx="8" ry="4"/></>,
    baseball: <><path d="M14 50l26-32"/><circle cx="46" cy="14" r="8"/><path d="M42 10q4 4 0 8M50 10q-4 4 0 8"/></>,
  };
  return <svg {...props}>{g[sport] || g.soccer}</svg>;
}

// ───────────────────── API base ─────────────────────
// One resolution for every API call the marketing site makes. It lives here,
// not in pages.jsx, because index.html loads components.jsx BEFORE home.jsx and
// pages.jsx — and home.jsx needs it too (the sports grid fetches real event
// counts). Moving this file later in the script order breaks both callers.
//
// Why it exists at all: these URLs used to be hardcoded to prod, so
// staging.sportistry.app talked to the PRODUCTION database — the coach form on
// staging created real coaches and emailed the admins (fixed 2026-07-18).
// Prod resolution is byte-identical to the strings it replaced, so prod is
// unchanged by construction; only staging and localhost move.
const SITE_API_BASE = /^http:\/\/localhost(:\d+)?$/.test(window.location.origin)
  ? window.location.origin + '/api'
  : window.location.hostname === 'staging.sportistry.app'
    ? 'https://staging-api.sportistry.app/api'
    : 'https://api.sportistry.app/api';

// ───────────────────── Royalty-free imagery (Unsplash, verified) ─────────────────────
function uimg(url, w = 900, q = 70) { return url + '?auto=format&fit=crop&w=' + w + '&q=' + q; }
const SPORT_IMG = {
  soccer:   'https://api.sportistry.app/stock-photos/photo-1574629810360-7efbbe195018.jpg',
  basket:   'https://api.sportistry.app/stock-photos/photo-1546519638-68e109498ffc.jpg',
  tennis:   'https://api.sportistry.app/stock-photos/photo-1595435934249-5df7ed86e1c0.jpg',
  running:  'https://api.sportistry.app/stock-photos/photo-1486218119243-13883505764c.jpg',
  cycling:  'https://api.sportistry.app/stock-photos/photo-1571333250630-f0230c320b6d.jpg',
  volley:   'https://api.sportistry.app/stock-photos/photo-1592656094267-764a45160876.jpg',
  climbing: 'https://api.sportistry.app/stock-photos/photo-1522163182402-834f871fd851.jpg',
  padel:    'https://api.sportistry.app/stock-photos/photo-1554068865-24cecd4e34b8.jpg',
  fitness:  'https://api.sportistry.app/stock-photos/photo-1517836357463-d25dfeac3438.jpg',
  // The homepage grid features the top 12 sports by SPORT_COUNTS; these four
  // are in that set, so a missing key here renders a bare gradient tile.
  swimming: 'https://api.sportistry.app/stock-photos/photo-1530549387789-4c1017266635.jpg',
  hiking:   'https://api.sportistry.app/stock-photos/photo-1459231978203-b7d0c47a2cb7.jpg',
  badminton:'https://api.sportistry.app/stock-photos/photo-1626224583764-f87db24ac4ea.jpg',
  yoga:     'https://api.sportistry.app/stock-photos/photo-1588286840104-8957b019727f.jpg',
};
const IMG = {
  lacing:  'https://api.sportistry.app/stock-photos/photo-1483721310020-03333e577078.jpg',  // lacing up
  golden:  'https://api.sportistry.app/stock-photos/photo-1612872087720-bb876e2e67d1.jpg',  // golden-hour play
  blocks:  'https://api.sportistry.app/stock-photos/photo-1461896836934-ffe607ba8211.jpg',  // sprint blocks
  soccer:  'https://api.sportistry.app/stock-photos/photo-1574629810360-7efbbe195018.jpg',  // soccer action
};

Object.assign(window, {
  SB, FD, FB, FM, MAXW, WEB_SPORTS, shadeWeb,
  WIcon, WAvatar, WAvatarStack, WButton, WChip, WStatusBadge, WEventCard,
  PhotoTexture, PhotoSlot, Eyebrow, Container, Section, StoreBadges, STORE_LINKS,
  Logo, LogoMark, SportGlyph, SPORT_IMG, IMG, uimg, SITE_API_BASE,
});
