// shared.jsx — Fitbody design tokens + core UI primitives
// Loaded first. Exports everything to window for the screen files.

// Faithful iOS system colors. Light = systemBackground / grouped neutrals + iOS
// system accents; Dark = true-black elevated surfaces + iOS dark accents.
// PRIMARY = systemBlue. Token KEY names kept; values reskinned per theme.
// (xxxDark = darker shade for 3D lips & accent text in LIGHT; in DARK it's a
//  brighter shade so accent text stays legible on dark tinted fills.)

const LIGHT = {
  // labels
  ink: '#1C1C1E', ink2: '#6C6C70', ink3: '#8E8E93',
  // grouped backgrounds
  bg: '#FFFFFF', surface: '#F2F2F7', surface2: '#E5E5EA',
  line: 'rgba(60,60,67,0.12)', line2: 'rgba(60,60,67,0.22)',
  glass: 'rgba(249,249,249,0.94)', glassBorder: 'rgba(60,60,67,0.12)',
  // accents (iOS system, light)
  coral: '#007AFF', coralDark: '#0062CC',   // PRIMARY — systemBlue
  amber: '#FF9500', amberDark: '#C2660A',   // streak — systemOrange
  calm:  '#30B0C7', calmDark:  '#1E8299',   // recovery — systemTeal
  good:  '#34C759',                          // success — systemGreen
  violet:'#5856D6', violetDark:'#3D3CB0',   // strength — systemIndigo
  teal:  '#32ADE6', tealDark:  '#1B89BC',   // cardio — systemCyan
  pink:  '#FF2D55', pinkDark:  '#D11440',   // social — systemPink
  energy:'#34C759', energyDark:'#248A43',   // energy — systemGreen
  // tinted fills (~12%)
  coralSoft: '#E1EDFF', coralTint: '#F0F6FF',
  amberSoft: '#FFEFD9',
  calmSoft: '#DEF3F7',
  goodSoft: '#DDF5E3',
  violetSoft: '#E8E8FB',
  tealSoft: '#DEF1FC',
  pinkSoft: '#FFE0E6',
  energySoft: '#DDF5E3',
};

const DARK = {
  ink: '#FFFFFF', ink2: '#AEAEB2', ink3: '#8E8E93',
  // true-black grouped: base #000, elevated cards #1C1C1E
  bg: '#1C1C1E', surface: '#000000', surface2: '#2C2C2E',
  line: 'rgba(255,255,255,0.10)', line2: 'rgba(255,255,255,0.20)',
  glass: 'rgba(30,30,32,0.82)', glassBorder: 'rgba(255,255,255,0.12)',
  // accents (iOS system, dark — brighter)
  coral: '#0A84FF', coralDark: '#409CFF',   // PRIMARY — systemBlue (dark)
  amber: '#FF9F0A', amberDark: '#FFB340',   // streak — systemOrange (dark)
  calm:  '#5AC8E0', calmDark:  '#7FD9EC',   // recovery — systemTeal (dark)
  good:  '#30D158',                          // success — systemGreen (dark)
  violet:'#5E5CE6', violetDark:'#8482FF',   // strength — systemIndigo (dark)
  teal:  '#64D2FF', tealDark:  '#9BE0FF',   // cardio — systemCyan (dark)
  pink:  '#FF375F', pinkDark:  '#FF6B86',   // social — systemPink (dark)
  energy:'#30D158', energyDark:'#5FE07F',   // energy — systemGreen (dark)
  // tinted fills (dark, ~18% over black)
  coralSoft: '#14294A', coralTint: '#102038',
  amberSoft: '#3A2A0E',
  calmSoft: '#0F2A33',
  goodSoft: '#0E2A18',
  violetSoft: '#1E1E3C',
  tealSoft: '#0E2733',
  pinkSoft: '#331620',
  energySoft: '#0E2A18',
};

const T = { ...LIGHT, r1: 14, r2: 20, r3: 28, r4: 36 };
window.T = T;
window.applyTheme = (mode) => {
  Object.assign(T, mode === 'dark' ? DARK : LIGHT);
  document.documentElement.dataset.theme = mode;
  try { localStorage.setItem('fb_theme', mode); } catch (e) {}
};

// category accent map — resolved LIVE against T (so soft-tints follow theme)
const CAT_KEY = {
  mobility: { k: 'coral',  label: 'Mobility' },
  strength: { k: 'violet', label: 'Strength' },
  recovery: { k: 'calm',   label: 'Recovery' },
  cardio:   { k: 'teal',   label: 'Cardio' },
  breath:   { k: 'amber',  label: 'Breath' },
  social:   { k: 'pink',   label: 'Social' },
};
function catColor(name) {
  const e = CAT_KEY[name] || CAT_KEY.mobility;
  return { c: T[e.k], d: T[e.k + 'Dark'], s: T[e.k + 'Soft'], label: e.label };
}
window.catColor = catColor;

// ── Phone metrics ──────────────────────────────────────────
const PHONE_W = 390, PHONE_H = 844;
window.PHONE_W = PHONE_W; window.PHONE_H = PHONE_H;

// ── iOS-style status bar (tintable) ────────────────────────
function StatusBar({ light = false }) {
  const c = light ? '#fff' : T.ink;
  return (
    <div style={{
      position: 'absolute', top: 0, left: 0, right: 0, height: 54, zIndex: 40,
      display: 'flex', alignItems: 'center', justifyContent: 'space-between',
      padding: '0 32px', paddingTop: 14, boxSizing: 'border-box',
      pointerEvents: 'none',
    }}>
      <span style={{ fontSize: 16, fontWeight: 700, color: c, letterSpacing: 0.2 }}>9:41</span>
      <div style={{ display: 'flex', alignItems: 'center', gap: 7 }}>
        <svg width="18" height="11" viewBox="0 0 18 11"><g fill={c}>
          <rect x="0" y="7" width="3" height="4" rx="0.7"/><rect x="4.5" y="4.8" width="3" height="6.2" rx="0.7"/>
          <rect x="9" y="2.5" width="3" height="8.5" rx="0.7"/><rect x="13.5" y="0" width="3" height="11" rx="0.7"/>
        </g></svg>
        <svg width="16" height="11" viewBox="0 0 16 11" fill="none"><path d="M8 3C10.1 3 12 3.8 13.4 5.2L14.4 4.2C12.7 2.5 10.5 1.5 8 1.5C5.5 1.5 3.3 2.5 1.6 4.2L2.6 5.2C4 3.8 5.9 3 8 3Z" fill={c}/><path d="M8 6.3C9.2 6.3 10.3 6.8 11.1 7.6L12.1 6.6C11 5.5 9.6 4.8 8 4.8C6.4 4.8 5 5.5 3.9 6.6L4.9 7.6C5.7 6.8 6.8 6.3 8 6.3Z" fill={c}/><circle cx="8" cy="9.4" r="1.4" fill={c}/></svg>
        <svg width="25" height="12" viewBox="0 0 25 12"><rect x="0.5" y="0.5" width="21" height="11" rx="3" stroke={c} strokeOpacity="0.4" fill="none"/><rect x="2" y="2" width="18" height="8" rx="1.7" fill={c}/><path d="M23 4V8C23.7 7.7 24.2 7 24.2 6C24.2 5 23.7 4.3 23 4Z" fill={c} fillOpacity="0.5"/></svg>
      </div>
    </div>
  );
}

// ── Icons (clean 1.9 stroke line set) ──────────────────────
function Icon({ name, size = 24, color = 'currentColor', sw = 1.9, fill = 'none', style }) {
  const p = { fill, stroke: fill === 'none' ? color : 'none', strokeWidth: sw, strokeLinecap: 'round', strokeLinejoin: 'round' };
  const paths = {
    home:    <path d="M3 10.5L12 3l9 7.5M5.5 9.5V20h13V9.5" {...p}/>,
    quest:   <g {...p}><path d="M5 3v18l3.5-2.5L12 21l3.5-2.5L19 21V3z"/><path d="M9 8h6M9 12h6"/></g>,
    coach:   <g {...p}><path d="M21 11.5a8.5 7.5 0 11-3.2 5.9L3 20l1.6-4.3A7.8 7.8 0 0121 11.5z"/></g>,
    academy: <g {...p}><circle cx="12" cy="12" r="9"/><path d="M10 8.5l6 3.5-6 3.5z" fill={color} stroke="none"/></g>,
    progress:<g {...p}><path d="M4 20V10M10 20V4M16 20v-7M22 20H2"/></g>,
    gear:    <g {...p}><circle cx="12" cy="12" r="3.2"/><path d="M12 2.5v2.5M12 19v2.5M4.2 4.2l1.8 1.8M18 18l1.8 1.8M2.5 12H5M19 12h2.5M4.2 19.8L6 18M18 6l1.8-1.8"/></g>,
    back:    <path d="M15 5l-7 7 7 7" {...p}/>,
    close:   <path d="M6 6l12 12M18 6L6 18" {...p}/>,
    chevron: <path d="M9 5l7 7-7 7" {...p}/>,
    flame:   <path d="M12 3c.5 3-2.5 4.2-2.5 7A2.5 2.5 0 0012 12.5 2.4 2.4 0 0014.3 9c1 1.2 1.7 2.6 1.7 4.3a4 4 0 11-8 0C8 9.5 11 7 12 3z" fill={color} stroke="none"/>,
    bolt:    <path d="M13 2L4 14h6l-1 8 9-12h-6z" {...p}/>,
    clock:   <g {...p}><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3.5 2"/></g>,
    seat:    <g {...p}><path d="M7 4v9M7 13h8M15 13V8M5 13l-1.5 7M17.5 13l1.5 7M7 8h8"/></g>,
    camera_off: <g {...p}><path d="M3 8.5A1.5 1.5 0 014.5 7H7l1.5-2h5l.6.8M21 8.8V17a1.5 1.5 0 01-1.5 1.5H8M3 8.5V17A1.5 1.5 0 004.5 18.5"/><path d="M3 3l18 18"/></g>,
    cameraline: <g {...p}><path d="M3 8.5A1.5 1.5 0 014.5 7H7l1.5-2h7L17 7h2.5A1.5 1.5 0 0121 8.5V17a1.5 1.5 0 01-1.5 1.5h-15A1.5 1.5 0 013 17z"/><circle cx="12" cy="12" r="3.4"/></g>,
    check:   <path d="M5 12.5l4.5 4.5L19 7.5" {...p}/>,
    drop:    <path d="M12 3.5C12 3.5 5.5 10 5.5 14.5a6.5 6.5 0 0013 0C18.5 10 12 3.5 12 3.5z" {...p}/>,
    moon:    <path d="M20 14.5A8 8 0 119.5 4 6.5 6.5 0 0020 14.5z" {...p}/>,
    wind:    <g {...p}><path d="M3 8h11a2.5 2.5 0 10-2.5-2.5M3 12h15a2.5 2.5 0 11-2.5 2.5M3 16h9a2 2 0 11-2 2"/></g>,
    pause:   <g><rect x="7" y="5" width="3.4" height="14" rx="1.4" fill={color}/><rect x="13.6" y="5" width="3.4" height="14" rx="1.4" fill={color}/></g>,
    play:    <path d="M8 5.5v13l11-6.5z" fill={color} stroke="none"/>,
    bell:    <g {...p}><path d="M6 9a6 6 0 1112 0c0 5 2 6 2 6H4s2-1 2-6z"/><path d="M10 19a2 2 0 004 0"/></g>,
    user:    <g {...p}><circle cx="12" cy="8" r="3.8"/><path d="M5 20c0-3.6 3.1-6 7-6s7 2.4 7 6"/></g>,
    sparkle: <path d="M12 3l1.8 5.5L19 10l-5.2 1.5L12 17l-1.8-5.5L5 10l5.2-1.5z" fill={color} stroke="none"/>,
    arrow:   <path d="M5 12h14M13 6l6 6-6 6" {...p}/>,
    plus:    <path d="M12 5v14M5 12h14" {...p}/>,
    lock:    <g {...p}><rect x="5" y="10" width="14" height="10" rx="2.5"/><path d="M8 10V7.5a4 4 0 018 0V10"/></g>,
    share:   <g {...p}><circle cx="6" cy="12" r="2.4"/><circle cx="17" cy="6" r="2.4"/><circle cx="17" cy="18" r="2.4"/><path d="M8.2 11l6.6-3.8M8.2 13l6.6 3.8"/></g>,
    leaf:    <g {...p}><path d="M20 4S8 3 5 11c-1.5 4 1 7 1 7s6-1 9-5c2.2-3 5-9 5-9z"/><path d="M6 18C9 13 13 9 18 6"/></g>,
    dumbbell:<g {...p}><path d="M3 9v6M6 7v10M18 7v10M21 9v6M6 12h12"/></g>,
    target:  <g {...p}><circle cx="12" cy="12" r="8.5"/><circle cx="12" cy="12" r="4.2"/><circle cx="12" cy="12" r="0.6" fill={color} stroke="none"/></g>,
    gem:     <g><path d="M6 3h12l4 6-10 12L2 9z" fill={color}/><path d="M2 9h20M8 3l-2 6 6 12 6-12-2-6" stroke="#fff" strokeOpacity="0.55" strokeWidth="1.1" fill="none"/></g>,
    freeze:  <g {...p}><path d="M12 2v20M4 7l16 10M20 7L4 17M12 2l-3 3 3 3 3-3zM12 22l-3-3 3-3 3 3z"/></g>,
    chest:   <g {...p}><path d="M3 9a2 2 0 012-2h14a2 2 0 012 2v10H3z"/><path d="M3 12h18M10 12v3h4v-3"/><path d="M5 7l1-3h12l1 3"/></g>,
    crown:   <g><path d="M3 8l4 4 5-7 5 7 4-4-2 11H5z" fill={color}/><circle cx="12" cy="20" r="0" /></g>,
    heart:   <path d="M12 20S4 14.5 4 9a4.2 4.2 0 018-1.5A4.2 4.2 0 0120 9c0 5.5-8 11-8 11z" fill={color} stroke="none"/>,
    star:    <path d="M12 3l2.6 6.3L21 9.8l-4.8 4.3 1.4 6.4L12 17.4 6.4 20.5l1.4-6.4L3 9.8l6.4-.5z" fill={color} stroke="none"/>,
    medal:   <g {...p}><path d="M8.5 3l3.5 6 3.5-6"/><circle cx="12" cy="14.5" r="6.2"/><circle cx="12" cy="14.5" r="2.3" fill={color} stroke="none"/></g>,
    scan:    <g {...p}><path d="M4 8V6a2 2 0 012-2h2M16 4h2a2 2 0 012 2v2M20 16v2a2 2 0 01-2 2h-2M8 20H6a2 2 0 01-2-2v-2"/><circle cx="12" cy="9.6" r="2.3"/><path d="M8.6 16c.5-2 1.7-3 3.4-3s2.9 1 3.4 3"/></g>,
    chat:    <g {...p}><path d="M21 11.5a8.5 7.5 0 11-3.2 5.9L3 20l1.6-4.3A7.8 7.8 0 0121 11.5z"/><circle cx="8.5" cy="11.8" r="1" fill={color} stroke="none"/><circle cx="12" cy="11.8" r="1" fill={color} stroke="none"/><circle cx="15.5" cy="11.8" r="1" fill={color} stroke="none"/></g>,
  };
  return <svg width={size} height={size} viewBox="0 0 24 24" style={style}>{paths[name]}</svg>;
}

// ── Ava — coral character with face + bounce (game mode) ───
function AvaOrb({ size = 44, speaking = false, mood = 'happy', style }) {
  const eyeY = size * 0.42, eyeDx = size * 0.17, eyeR = size * 0.082;
  return (
    <div style={{ position: 'relative', width: size, height: size, flexShrink: 0, animation: speaking ? 'avaBounce 1.4s ease-in-out infinite' : 'avaBreath 3.6s ease-in-out infinite', ...style }}>
      <div style={{
        position: 'absolute', inset: -size * 0.28, borderRadius: '50%',
        background: `radial-gradient(circle, ${T.coral}40 0%, ${T.coral}00 68%)`,
        animation: 'avaGlow 2.4s ease-in-out infinite',
      }}/>
      <div style={{
        position: 'absolute', inset: 0, borderRadius: '50%',
        background: `radial-gradient(circle at 36% 30%, #7FB5FF 0%, ${T.coral} 54%, ${T.coralDark} 100%)`,
        boxShadow: `inset 0 ${size*0.05}px ${size*0.12}px rgba(255,255,255,0.5), inset 0 -${size*0.06}px ${size*0.12}px ${T.coralDark}aa, 0 ${size*0.12}px ${size*0.26}px ${T.coral}48`,
      }}/>
      {/* eyes */}
      <svg width={size} height={size} viewBox={`0 0 ${size} ${size}`} style={{ position: 'absolute', inset: 0 }}>
        <g style={{ transformOrigin: `${size/2}px ${eyeY}px`, animation: 'avaBlink 4.2s infinite' }}>
          <circle cx={size/2 - eyeDx} cy={eyeY} r={eyeR} fill="#0B2A52"/>
          <circle cx={size/2 + eyeDx} cy={eyeY} r={eyeR} fill="#0B2A52"/>
          <circle cx={size/2 - eyeDx + eyeR*0.35} cy={eyeY - eyeR*0.4} r={eyeR*0.42} fill="#fff"/>
          <circle cx={size/2 + eyeDx + eyeR*0.35} cy={eyeY - eyeR*0.4} r={eyeR*0.42} fill="#fff"/>
        </g>
        {/* smile */}
        <path d={`M${size/2 - size*0.11} ${size*0.6} Q${size/2} ${size*0.72} ${size/2 + size*0.11} ${size*0.6}`} stroke="#0B2A52" strokeWidth={size*0.05} fill="none" strokeLinecap="round" opacity="0.9"/>
        {/* cheeks */}
        <circle cx={size/2 - size*0.24} cy={size*0.56} r={size*0.07} fill="#7FB5FF" opacity="0.55"/>
        <circle cx={size/2 + size*0.24} cy={size*0.56} r={size*0.07} fill="#7FB5FF" opacity="0.55"/>
      </svg>
      {/* glossy highlight */}
      <div style={{ position: 'absolute', top: size * 0.12, left: size * 0.2, width: size * 0.3, height: size * 0.2, borderRadius: '50%', background: 'rgba(255,255,255,0.55)', filter: 'blur(1.5px)' }}/>
      {speaking && (
        <div style={{ position: 'absolute', inset: -3, borderRadius: '50%', border: `2.5px solid ${T.coral}`, opacity: 0.45, animation: 'avaPing 1.6s ease-out infinite' }}/>
      )}
    </div>
  );
}

// ── Buttons — flat iOS filled / tinted (system style) ──────
function Btn({ children, onClick, variant = 'primary', size = 'lg', disabled, icon, style }) {
  const base = {
    display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 8,
    width: '100%', border: 'none', cursor: disabled ? 'default' : 'pointer',
    fontFamily: 'inherit', fontWeight: 600, letterSpacing: -0.3,
    borderRadius: 14, transition: 'opacity .12s ease, transform .12s ease',
    height: size === 'lg' ? 52 : size === 'md' ? 48 : 40,
    fontSize: size === 'lg' ? 17 : size === 'md' ? 16 : 15,
    opacity: disabled ? 0.4 : 1,
  };
  const variants = {
    primary:  { background: T.coral, color: '#fff' },
    calm:     { background: T.calm, color: '#fff' },
    good:     { background: T.good, color: '#fff' },
    amber:    { background: T.amber, color: '#fff' },
    violet:   { background: T.violet, color: '#fff' },
    teal:     { background: T.teal, color: '#fff' },
    pink:     { background: T.pink, color: '#fff' },
    dark:     { background: T.ink, color: T.bg },
    soft:     { background: T.surface2, color: T.ink },
    coralSoft:{ background: T.coralSoft, color: T.coralDark },
    ghost:    { background: 'transparent', color: T.coral, weight: 600 },
    outline:  { background: 'transparent', color: T.coral, edge: T.line2 },
  };
  const v = variants[variant];
  const press = (el, on) => {
    if (disabled) return;
    el.style.opacity = on ? '0.62' : (disabled ? '0.4' : '1');
    el.style.transform = on ? 'scale(0.985)' : 'scale(1)';
  };
  return (
    <button onClick={disabled ? undefined : onClick}
      onMouseDown={e => press(e.currentTarget, true)}
      onMouseUp={e => press(e.currentTarget, false)}
      onMouseLeave={e => press(e.currentTarget, false)}
      style={{ ...base, background: v.background, color: v.color,
        boxShadow: v.edge ? `inset 0 0 0 1px ${v.edge}` : 'none', ...style }}>
      {icon}{children}
    </button>
  );
}

// ── Chip (selectable) ──────────────────────────────────────
function Chip({ children, active, onClick, icon, style }) {
  return (
    <button onClick={onClick} style={{
      display: 'flex', alignItems: 'center', gap: 8, fontFamily: 'inherit',
      padding: '0 18px', height: 52, borderRadius: 16, cursor: 'pointer',
      fontSize: 16, fontWeight: 600, letterSpacing: -0.2, transition: 'all .14s ease',
      background: active ? T.coralTint : T.bg,
      color: active ? T.coralDark : T.ink,
      boxShadow: active ? `inset 0 0 0 2px ${T.coral}` : `inset 0 0 0 1.5px ${T.line2}`,
      ...style,
    }}>
      {icon}{children}
    </button>
  );
}

// ── Card ───────────────────────────────────────────────────
function Card({ children, style, pad = 20, onClick }) {
  return (
    <div onClick={onClick} style={{
      background: T.bg, borderRadius: T.r3, padding: pad,
      boxShadow: '0 1px 3px rgba(28,27,25,0.04), 0 8px 24px rgba(28,27,25,0.05)',
      ...style,
    }}>{children}</div>
  );
}

// ── Progress bar — flat solid iOS fill ─────────────────────
function XPBar({ value, max, color = T.coral, height = 8, animate }) {
  const pct = Math.min(100, (value / max) * 100);
  return (
    <div style={{ width: '100%', height, background: T.surface2, borderRadius: 999, overflow: 'hidden' }}>
      <div style={{
        width: pct + '%', height: '100%', borderRadius: 999, background: color,
        transition: animate ? 'width 1.1s cubic-bezier(.2,.8,.2,1)' : 'none',
      }}/>
    </div>
  );
}

// ── Streak / energy pills for headers (chunky game style) ──
function StatPill({ icon, label, tone = 'amber' }) {
  const tones = {
    amber: { bg: T.amberSoft, fg: T.amberDark },
    coral: { bg: T.coralSoft, fg: T.coralDark },
    calm:  { bg: T.calmSoft, fg: T.calmDark },
    teal:  { bg: T.tealSoft, fg: T.tealDark },
    ink:   { bg: T.surface2, fg: T.ink },
  };
  const t = tones[tone];
  return (
    <div style={{
      display: 'flex', alignItems: 'center', gap: 5, height: 34, padding: '0 12px',
      borderRadius: 999, background: t.bg, color: t.fg, fontWeight: 700, fontSize: 14.5,
      fontVariantNumeric: 'tabular-nums',
    }}>{icon}{label}</div>
  );
}

// ── Energy pill — the play resource w/ recharge countdown ──
function fmtClock(s) {
  const m = Math.floor(s / 60), ss = s % 60;
  return `${String(m).padStart(2, '0')}:${String(ss).padStart(2, '0')}`;
}
function EnergyPill({ energy, max, pro, nextSec, onClick }) {
  const full = energy >= max;
  return (
    <button onClick={onClick} style={{
      display: 'flex', alignItems: 'center', gap: 6, height: 34, padding: '0 11px 0 12px',
      borderRadius: 999, background: T.tealSoft, border: 'none', cursor: 'pointer', fontFamily: 'inherit',
    }}>
      <Icon name="bolt" size={16} color={T.tealDark} fill={T.tealDark} sw={0}/>
      <span style={{ fontWeight: 700, fontSize: 14.5, color: T.tealDark, fontVariantNumeric: 'tabular-nums' }}>{pro ? '∞' : energy}</span>
      {!pro && !full && (
        <span style={{ fontSize: 11, fontWeight: 700, color: T.tealDark, opacity: 0.66, fontVariantNumeric: 'tabular-nums', marginLeft: 1 }}>{fmtClock(nextSec)}</span>
      )}
    </button>
  );
}

// ── Daily goal ring (Duolingo-style) ───────────────────────
function DailyGoalRing({ value, goal, size = 56 }) {
  const r = size / 2 - 5, c = 2 * Math.PI * r, pct = Math.min(1, value / goal);
  return (
    <div style={{ position: 'relative', width: size, height: size }}>
      <svg width={size} height={size} style={{ transform: 'rotate(-90deg)' }}>
        <circle cx={size/2} cy={size/2} r={r} fill="none" stroke={T.surface2} strokeWidth="5"/>
        <circle cx={size/2} cy={size/2} r={r} fill="none" stroke={T.amber} strokeWidth="5" strokeLinecap="round" strokeDasharray={c} strokeDashoffset={c * (1 - pct)} style={{ transition: 'stroke-dashoffset 1s cubic-bezier(.2,.8,.2,1)' }}/>
      </svg>
      <div style={{ position: 'absolute', inset: 0, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
        <Icon name="bolt" size={size * 0.4} color={T.amber} fill={T.amber} sw={0}/>
      </div>
    </div>
  );
}

// ── Ava speech block ───────────────────────────────────────
function AvaSays({ children, size = 44, align = 'row', style }) {
  return (
    <div style={{ display: 'flex', alignItems: 'flex-start', gap: 12, ...style }}>
      <AvaOrb size={size} speaking />
      <div style={{ flex: 1, paddingTop: 2 }}>
        <div style={{ fontSize: 12, fontWeight: 800, color: T.coral, letterSpacing: 1, marginBottom: 4 }}>AVA</div>
        <div style={{ fontSize: 16.5, lineHeight: 1.5, color: T.ink, fontWeight: 500, letterSpacing: -0.2, textWrap: 'pretty' }}>{children}</div>
      </div>
    </div>
  );
}

// ── Quest meta condition tags ──────────────────────────────
function MetaTags({ tags }) {
  return (
    <div style={{ display: 'flex', flexWrap: 'wrap', gap: 8 }}>
      {tags.map((t, i) => (
        <span key={i} style={{
          display: 'inline-flex', alignItems: 'center', gap: 5,
          padding: '7px 12px', borderRadius: 11, background: T.surface,
          fontSize: 13.5, fontWeight: 600, color: T.ink2, letterSpacing: -0.2,
        }}>{t.icon && <Icon name={t.icon} size={15} color={T.ink3} sw={2}/>}{t.label}</span>
      ))}
    </div>
  );
}

// ── Bottom sheet modal ─────────────────────────────────────
function Sheet({ open, onClose, children, light }) {
  if (!open) return null;
  return (
    <div onClick={onClose} style={{
      position: 'absolute', inset: 0, zIndex: 60,
      background: 'rgba(20,18,16,0.42)', display: 'flex', alignItems: 'flex-end',
      animation: 'fadeIn .2s ease',
    }}>
      <div onClick={e => e.stopPropagation()} style={{
        width: '100%', background: T.bg, borderRadius: '28px 28px 0 0',
        padding: '12px 22px 30px', boxSizing: 'border-box',
        animation: 'sheetUp .32s cubic-bezier(.2,.9,.2,1)',
      }}>
        <div style={{ width: 40, height: 5, borderRadius: 999, background: T.line2, margin: '0 auto 18px' }}/>
        {children}
      </div>
    </div>
  );
}

// ── Bottom navigation ──────────────────────────────────────
function BottomNav({ active, onNav }) {
  const items = [
    { id: 'home', label: 'Home', icon: 'home' },
    { id: 'quest', label: 'Quest', icon: 'quest' },
    { id: 'academy', label: 'Academy', icon: 'academy' },
    { id: 'progress', label: 'Progress', icon: 'progress' },
    { id: 'league', label: 'League', icon: 'medal' },
  ];
  return (
    <div style={{
      position: 'absolute', bottom: 0, left: 0, right: 0, zIndex: 30,
      height: 86, paddingBottom: 18, boxSizing: 'border-box',
      background: T.glass, backdropFilter: 'blur(18px) saturate(180%)',
      WebkitBackdropFilter: 'blur(18px) saturate(180%)',
      borderTop: `0.5px solid ${T.line}`,
      display: 'flex', alignItems: 'center', justifyContent: 'space-around', padding: '8px 6px 18px',
    }}>
      {items.map(it => {
        const on = active === it.id;
        return (
          <button key={it.id} onClick={() => onNav(it.id)} style={{
            background: 'none', border: 'none', cursor: 'pointer', fontFamily: 'inherit',
            display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 3, flex: 1,
            color: on ? T.coral : T.ink3, transition: 'color .15s',
          }}>
            <Icon name={it.icon} size={25} color={on ? T.coral : T.ink3} fill="none" sw={on ? 2.4 : 1.9}/>
            <span style={{ fontSize: 10.5, fontWeight: on ? 800 : 600, letterSpacing: 0.1 }}>{it.label}</span>
          </button>
        );
      })}
    </div>
  );
}

// ── Scrollable screen body with safe paddings ──────────────
function Screen({ children, bg = T.surface, light, pad = true, nav, scroll = true, style }) {
  return (
    <div style={{
      position: 'absolute', inset: 0, background: bg, overflow: 'hidden',
      display: 'flex', flexDirection: 'column',
    }}>
      <StatusBar light={light}/>
      <div style={{
        flex: 1, overflowY: scroll ? 'auto' : 'hidden', overflowX: 'hidden',
        paddingTop: 54, paddingBottom: nav ? 86 : 0,
        ...style,
      }}>
        <div style={{ padding: pad ? '0 22px' : 0 }}>{children}</div>
      </div>
      {nav && <BottomNav active={nav} onNav={window.__nav}/>}
    </div>
  );
}

// ── Floating Ava chat button (replaces Coach tab) ──────────
function ChatFab({ onClick }) {
  return (
    <button onClick={onClick} aria-label="Ava Coach" style={{
      position: 'absolute', right: 16, bottom: 98, zIndex: 35,
      width: 58, height: 58, borderRadius: 999, border: 'none', cursor: 'pointer',
      background: T.bg, boxShadow: '0 10px 26px rgba(0,0,0,0.22), inset 0 0 0 1px ' + T.glassBorder,
      display: 'flex', alignItems: 'center', justifyContent: 'center', padding: 0,
    }}>
      <AvaOrb size={40} speaking/>
      <span style={{ position: 'absolute', top: 2, right: 2, width: 16, height: 16, borderRadius: 999, background: T.coral, border: '2px solid #fff', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
        <Icon name="chat" size={9} color="#fff" sw={2}/>
      </span>
    </button>
  );
}

// ── Top bar with optional back ─────────────────────────────
function TopBar({ title, onBack, right, light, transparent }) {
  return (
    <div style={{
      display: 'flex', alignItems: 'center', gap: 8, height: 52,
      marginTop: 4, marginBottom: 6,
    }}>
      {onBack && (
        <button onClick={onBack} style={{
          width: 42, height: 42, borderRadius: 999, border: 'none', cursor: 'pointer', marginLeft: -6,
          background: transparent ? 'rgba(255,255,255,0.7)' : T.surface2,
          display: 'flex', alignItems: 'center', justifyContent: 'center',
        }}>
          <Icon name="back" size={22} color={light ? '#fff' : T.ink} sw={2.2}/>
        </button>
      )}
      <div style={{ flex: 1, fontSize: 19, fontWeight: 800, color: light ? '#fff' : T.ink, letterSpacing: -0.3 }}>{title}</div>
      {right}
    </div>
  );
}

Object.assign(window, {
  StatusBar, Icon, AvaOrb, Btn, Chip, Card, XPBar, StatPill, EnergyPill, fmtClock, DailyGoalRing, AvaSays,
  MetaTags, Sheet, BottomNav, ChatFab, Screen, TopBar,
});
