// shared.jsx — VI tokens, icon set, wordmark, gradient, global CSS.
// Ported from the design system at catches.world/vi/.

const VI = {
  bg:        '#08080A',
  bgElev:    '#0E0E12',
  bgCard:    '#13131A',
  bgCard2:   '#1A1A22',
  border:    'rgba(255,255,255,0.06)',
  borderHi:  'rgba(255,255,255,0.14)',

  text:      '#F0F4F8',
  textDim:   'rgba(240,244,248,0.62)',
  textMute:  'rgba(240,244,248,0.38)',
  textFaint: 'rgba(240,244,248,0.22)',

  accent:    '#7BD3C8',
  accent2:   '#5BB5AB',
  accentDim: 'rgba(123,211,200,0.18)',

  success:   '#9EE5A8',
  warn:      '#F5C56B',
  error:     '#F08A8A',

  fontDisp:  '"Fraunces", Georgia, serif',
  fontBody:  '"DM Sans", -apple-system, system-ui, sans-serif',
  fontMono:  '"JetBrains Mono", ui-monospace, monospace',

  ease:      'cubic-bezier(0.16, 1, 0.3, 1)',
};

// FishImage — primary: real cover photo via /api/image/{taxon_id}/{idx}.
// Fallback: deterministic gradient placeholder (kept from design).
function FishImage({ fish, height = 120, radius = 12, label = false, intensity = 1, style = {} }) {
  const [errored, setErrored] = React.useState(false);
  const useReal = fish.coverImg && !errored;
  if (useReal) {
    return (
      <div style={{
        position: 'relative', width: '100%', height, borderRadius: radius,
        overflow: 'hidden', background: VI.bgCard, isolation: 'isolate', ...style,
      }}>
        <img
          src={fish.coverImg}
          alt={fish.name}
          loading="lazy"
          onError={() => setErrored(true)}
          style={{
            width: '100%', height: '100%', objectFit: 'cover',
            display: 'block',
          }}
        />
        <div style={{
          position: 'absolute', inset: 0, pointerEvents: 'none',
          background: 'radial-gradient(ellipse at center, transparent 50%, rgba(0,0,0,0.35) 100%)',
        }}/>
        {label && (
          <div style={{
            position: 'absolute', left: 10, bottom: 8, right: 10,
            fontFamily: VI.fontMono, fontSize: 8.5, letterSpacing: '0.06em',
            textTransform: 'uppercase', color: 'rgba(255,255,255,0.92)',
            textShadow: '0 1px 4px rgba(0,0,0,0.7)',
            whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis',
          }}>{fish.name}</div>
        )}
      </div>
    );
  }
  return <FishGradient fish={fish} height={height} radius={radius} label={label} intensity={intensity} style={style}/>;
}

// FishGradient — original placeholder (used as fallback + in dive-in atmosphere).
function FishGradient({ fish, height = 120, radius = 12, label = false, intensity = 1, style = {} }) {
  const [a, b] = fish.gradient || ['#1a2a3a', '#5a7088'];
  const id = `fg-${fish.id}`;
  const hash = [...(fish.latin || fish.id || '')].reduce((h, c) => (h * 31 + c.charCodeAt(0)) | 0, 7);
  const angle = ((hash % 30) - 15);
  return (
    <div style={{
      position: 'relative', width: '100%', height, borderRadius: radius,
      overflow: 'hidden', background: `linear-gradient(135deg, ${a} 0%, ${b} 100%)`,
      isolation: 'isolate', ...style,
    }}>
      <svg width="100%" height="100%" viewBox="0 0 200 100" preserveAspectRatio="none"
        style={{ position: 'absolute', inset: 0, opacity: 0.18 * intensity, mixBlendMode: 'overlay' }}>
        <defs>
          <linearGradient id={id} x1="0" x2="1">
            <stop offset="0" stopColor="#fff" stopOpacity="0"/>
            <stop offset="0.5" stopColor="#fff" stopOpacity="1"/>
            <stop offset="1" stopColor="#fff" stopOpacity="0"/>
          </linearGradient>
        </defs>
        {[18, 32, 48, 64, 80].map((y, i) => (
          <line key={i} x1="0" y1={y} x2="200" y2={y + (i % 2 ? -2 : 2)}
            stroke={`url(#${id})`} strokeWidth="0.6" />
        ))}
      </svg>
      <svg width="100%" height="100%" viewBox="0 0 200 100" preserveAspectRatio="xMidYMid meet"
        style={{ position: 'absolute', inset: 0, opacity: 0.22 * intensity }}>
        <g transform={`translate(100 50) rotate(${angle})`}>
          <ellipse cx="0" cy="0" rx="62" ry="14" fill="rgba(255,255,255,0.5)"/>
          <path d="M 60 0 L 80 -16 L 80 16 Z" fill="rgba(255,255,255,0.5)"/>
          <circle cx="-44" cy="-3" r="2.4" fill="rgba(0,0,0,0.4)"/>
        </g>
      </svg>
      <div style={{
        position: 'absolute', inset: 0,
        background: 'radial-gradient(ellipse at center, transparent 50%, rgba(0,0,0,0.35) 100%)',
        pointerEvents: 'none',
      }}/>
      {label && (
        <div style={{
          position: 'absolute', left: 10, bottom: 8, right: 10,
          fontFamily: VI.fontMono, fontSize: 8.5, letterSpacing: '0.06em',
          textTransform: 'uppercase', color: 'rgba(255,255,255,0.85)',
          textShadow: '0 1px 4px rgba(0,0,0,0.6)',
          whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis',
        }}>{fish.name}</div>
      )}
    </div>
  );
}

// SCHOOL.CATCHES wordmark.
function Wordmark({ size = 13, mono = false, color, accent, prefix = true }) {
  const c = color || VI.text;
  const a = accent || VI.accent;
  return (
    <span style={{
      fontFamily: VI.fontMono, fontSize: size, fontWeight: 400,
      letterSpacing: '0.32em', textTransform: 'uppercase', color: c,
      whiteSpace: 'nowrap',
    }}>
      {prefix && (
        <span style={{ color: mono ? c : VI.textMute, marginRight: '0.18em' }}>
          SCHOOL<span style={{ color: mono ? c : a }}>.</span>
        </span>
      )}
      CATCH<span style={{ color: mono ? c : a }}>ES</span>
    </span>
  );
}

// Inline icon set (24-px stroke, currentColor).
const Icon = {
  search: (s = 18) => (
    <svg width={s} height={s} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round">
      <circle cx="11" cy="11" r="7"/><path d="M20 20l-4-4"/>
    </svg>
  ),
  filter: (s = 18) => (
    <svg width={s} height={s} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round">
      <path d="M3 5h18M6 12h12M10 19h4"/>
    </svg>
  ),
  grid: (s = 18) => (
    <svg width={s} height={s} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6">
      <rect x="3" y="3" width="7" height="7" rx="1"/><rect x="14" y="3" width="7" height="7" rx="1"/>
      <rect x="3" y="14" width="7" height="7" rx="1"/><rect x="14" y="14" width="7" height="7" rx="1"/>
    </svg>
  ),
  list: (s = 18) => (
    <svg width={s} height={s} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round">
      <path d="M3 6h18M3 12h18M3 18h18"/>
    </svg>
  ),
  collection: (s = 18) => (
    <svg width={s} height={s} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round">
      <path d="M4 5a2 2 0 012-2h9l5 5v11a2 2 0 01-2 2H6a2 2 0 01-2-2V5z"/><path d="M14 3v6h6"/>
    </svg>
  ),
  back: (s = 18) => (
    <svg width={s} height={s} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round">
      <path d="M15 18l-6-6 6-6"/>
    </svg>
  ),
  close: (s = 18) => (
    <svg width={s} height={s} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round">
      <path d="M6 6l12 12M18 6L6 18"/>
    </svg>
  ),
  bookmark: (s = 18) => (
    <svg width={s} height={s} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinejoin="round">
      <path d="M6 3h12v18l-6-4-6 4V3z"/>
    </svg>
  ),
  share: (s = 18) => (
    <svg width={s} height={s} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round">
      <path d="M12 3v13M7 8l5-5 5 5M5 14v5a2 2 0 002 2h10a2 2 0 002-2v-5"/>
    </svg>
  ),
  drop: (s = 18) => (
    <svg width={s} height={s} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinejoin="round">
      <path d="M12 3s7 7 7 12a7 7 0 11-14 0c0-5 7-12 7-12z"/>
    </svg>
  ),
  hook: (s = 18) => (
    <svg width={s} height={s} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round">
      <path d="M12 2v6"/><path d="M16 8a4 4 0 11-8 0"/><path d="M12 12v8"/>
    </svg>
  ),
  layers: (s = 18) => (
    <svg width={s} height={s} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinejoin="round">
      <path d="M12 3l9 5-9 5-9-5 9-5z"/><path d="M3 13l9 5 9-5"/>
    </svg>
  ),
  chevronR: (s = 18) => (
    <svg width={s} height={s} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round">
      <path d="M9 6l6 6-6 6"/>
    </svg>
  ),
  sparkle: (s = 18) => (
    <svg width={s} height={s} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinejoin="round">
      <path d="M12 3l1.8 5.4L19 10l-5.2 1.6L12 17l-1.8-5.4L5 10l5.2-1.6L12 3z"/>
    </svg>
  ),
};

const cx = (...a) => a.filter(Boolean).join(' ');

// Inject global stylesheet once.
if (typeof document !== 'undefined' && !document.getElementById('school-shared-css')) {
  const s = document.createElement('style');
  s.id = 'school-shared-css';
  s.textContent = `
    *,*::before,*::after{box-sizing:border-box}
    html,body{margin:0;padding:0;background:${VI.bg};color:${VI.text};
      font-family:${VI.fontBody};-webkit-font-smoothing:antialiased;
      font-feature-settings:"ss01","ss02","cv01";min-height:100%;}
    body::-webkit-scrollbar{display:none}
    body{scrollbar-width:none}
    a{color:inherit;text-decoration:none}
    input,button,textarea,select{font:inherit;color:inherit}

    .ctx-screen,.ctx-screen *{box-sizing:border-box}
    .ctx-screen{font-family:${VI.fontBody};color:${VI.text};background:${VI.bg};}
    .ctx-screen ::-webkit-scrollbar{display:none}
    .ctx-screen{scrollbar-width:none}

    @keyframes ctx-fadeUp{from{opacity:0;transform:translateY(22px)}to{opacity:1;transform:none}}
    @keyframes ctx-fadeIn{from{opacity:0}to{opacity:1}}
    @keyframes ctx-scaleIn{from{opacity:0;transform:scale(.92)}to{opacity:1;transform:none}}
    @keyframes ctx-shimmer{0%{transform:translateX(-100%)}100%{transform:translateX(100%)}}
    @keyframes ctx-float{0%,100%{transform:translateY(0)}50%{transform:translateY(-6px)}}
    @keyframes ctx-swim{0%{transform:translateX(-30px)}100%{transform:translateX(calc(100% + 30px))}}
    @keyframes ctx-pulse{0%,100%{opacity:.4}50%{opacity:.85}}

    .ctx-fadeUp{animation:ctx-fadeUp .6s ${VI.ease} both}
    .ctx-fadeIn{animation:ctx-fadeIn .6s ${VI.ease} both}
    .ctx-scaleIn{animation:ctx-scaleIn .6s ${VI.ease} both}

    button.ctx-btn{
      appearance:none;border:0;background:transparent;color:inherit;font:inherit;
      cursor:pointer;padding:0;
    }

    /* Mobile-first content column. Phone gets full width; tablet+ centers on a dark canvas. */
    .school-app{
      width:100%;min-height:100dvh;
      max-width:480px;margin:0 auto;
      position:relative;
      background:${VI.bg};
    }
    @media (min-width: 481px){
      body{
        background:
          radial-gradient(ellipse 60% 50% at 50% 0%, rgba(123,211,200,0.04), transparent 60%),
          ${VI.bg};
      }
      .school-app{
        box-shadow:0 0 80px rgba(123,211,200,0.06);
      }
    }
  `;
  document.head.appendChild(s);
}

Object.assign(window, { VI, FishImage, FishGradient, Wordmark, Icon, cx });
