/* ============================================================
   MUI 2.0 — shared UI (icons, avatar, badges, scene, bits)
   Exports to window for the other Babel scripts.
   ============================================================ */

const StoreCtx = React.createContext(null);
const useStore = () => React.useContext(StoreCtx);

function Icon({ name, size = 22, color = 'currentColor', fill = 'none', sw = 2, style }) {
  const common = { width: size, height: size, viewBox: '0 0 24 24', fill, stroke: color, strokeWidth: sw, strokeLinecap: 'round', strokeLinejoin: 'round', style, className: 'ic' };
  const P = {
    home: <path d="M3 10.5 12 3l9 7.5M5 9v11h14V9" />,
    users: <g><circle cx="9" cy="8" r="3.2" /><path d="M3 20c0-3.3 2.7-5.5 6-5.5s6 2.2 6 5.5" /><path d="M16 5.2A3 3 0 0 1 16 11M17.5 14.6c2 .6 3.5 2.3 3.5 4.4" /></g>,
    chart: <g><path d="M4 4v16h16" /><path d="M7.5 14l3-3.5 3 2.5 4-5" /></g>,
    user: <g><circle cx="12" cy="8" r="3.6" /><path d="M5 20c0-3.6 3-6 7-6s7 2.4 7 6" /></g>,
    plus: <path d="M12 5v14M5 12h14" />,
    phone: <path d="M5 4h3l1.5 4-2 1.5a11 11 0 0 0 5 5l1.5-2 4 1.5v3a2 2 0 0 1-2 2A15 15 0 0 1 3 6a2 2 0 0 1 2-2z" fill={color} stroke="none" />,
    chat: <path d="M4 5h16v11H9l-4 3v-3H4z" />,
    search: <g><circle cx="11" cy="11" r="6.5" /><path d="M20 20l-3.5-3.5" /></g>,
    sort: <path d="M7 5v14M7 5l-3 3M7 5l3 3M17 19V5M17 19l-3-3M17 19l3-3" />,
    check: <path d="M5 12.5l4.5 4.5L19 6.5" />,
    checkCircle: <g><circle cx="12" cy="12" r="9" /><path d="M8 12.2l2.6 2.6L16 9" /></g>,
    clock: <g><circle cx="12" cy="12" r="9" /><path d="M12 7v5.3l3.3 2" /></g>,
    shield: <path d="M12 3l7 2.5v5.5c0 4.5-3 8-7 9.5-4-1.5-7-5-7-9.5V5.5z" />,
    x: <path d="M6 6l12 12M18 6L6 18" />,
    edit: <path d="M16 4l4 4-11 11H5v-4z" />,
    calendar: <g><rect x="4" y="5.5" width="16" height="15" rx="2.5" /><path d="M4 10h16M8 3.5v4M16 3.5v4" /></g>,
    drop: <path d="M12 3s6 6.5 6 11a6 6 0 0 1-12 0c0-4.5 6-11 6-11z" fill={fill === 'none' ? 'none' : fill} />,
    heart: <path d="M12 20S4 14.5 4 9a4 4 0 0 1 8-1 4 4 0 0 1 8 1c0 5.5-8 11-8 11z" fill={fill} />,
    pill: <g><rect x="3" y="9" width="18" height="6.5" rx="3.25" transform="rotate(-40 12 12)" /><path d="M9 7.5l5 5" /></g>,
    clipboard: <g><rect x="5" y="5" width="14" height="16" rx="2.5" /><rect x="9" y="3" width="6" height="4" rx="1.5" /><path d="M9 12h6M9 16h4" /></g>,
    chevR: <path d="M9 6l6 6-6 6" />,
    chevL: <path d="M15 6l-6 6 6 6" />,
    chevD: <path d="M6 9l6 6 6-6" />,
    flag: <path d="M6 21V4h11l-2 3.5L17 11H6" />,
    archive: <g><rect x="4" y="5" width="16" height="4" rx="1.5" /><path d="M5.5 9v10h13V9M10 13h4" /></g>,
    sun: <g><circle cx="12" cy="12" r="4" /><path d="M12 2v2M12 20v2M2 12h2M20 12h2M5 5l1.5 1.5M17.5 17.5L19 19M19 5l-1.5 1.5M6.5 17.5L5 19" /></g>,
    moon: <path d="M20 14.5A8 8 0 0 1 9.5 4 8 8 0 1 0 20 14.5z" />,
    candle: <g><path d="M12 3.2c1.8 1.8 2.4 3 2.4 4.1a2.4 2.4 0 0 1-4.8 0c0-1.1.6-2.3 2.4-4.1z" fill={color} stroke="none" /><rect x="9" y="9.5" width="6" height="11.3" rx="1.6" /></g>,
    cloud: <path d="M7 18a4 4 0 0 1 0-8 5 5 0 0 1 9.6-1.5A3.5 3.5 0 0 1 17 18z" />,
    download: <path d="M12 4v11m0 0l-4-4m4 4l4-4M5 20h14" />,
    upload: <path d="M12 20V9m0 0L8 13m4-4l4 4M5 5h14" />,
    camera: <g><path d="M3 8.5A2.5 2.5 0 0 1 5.5 6h1.2l1.1-1.8A1.5 1.5 0 0 1 9.1 3.5h5.8a1.5 1.5 0 0 1 1.3.7L17.3 6h1.2A2.5 2.5 0 0 1 21 8.5v8A2.5 2.5 0 0 1 18.5 19h-13A2.5 2.5 0 0 1 3 16.5z" /><circle cx="12" cy="12.5" r="3.4" /></g>,
    image: <g><rect x="3" y="5" width="18" height="14" rx="2.5" /><circle cx="8.5" cy="10" r="1.7" /><path d="M5 17.5l4.5-4.3 3 2.6 3.2-3.1L21 16.2" /></g>,
    bell: <path d="M6 9a6 6 0 0 1 12 0c0 5 2 6 2 6H4s2-1 2-6M9.5 19a2.5 2.5 0 0 0 5 0" />,
    whatsapp: <path d="M12 3a9 9 0 0 0-7.8 13.5L3 21l4.7-1.2A9 9 0 1 0 12 3zm4.2 12.3c-.2.5-1 1-1.4 1-.4 0-.9.2-3-1-2.4-1.4-3.8-4-3.9-4.2-.1-.2-.9-1.2-.9-2.3s.6-1.6.8-1.8c.2-.2.4-.3.6-.3h.4c.2 0 .4 0 .6.5l.7 1.7c.1.2.1.4 0 .5l-.3.5c-.1.1-.3.3-.1.6.1.2.6 1 1.3 1.6.9.8 1.6 1 1.8 1.1.2.1.4.1.5-.1l.6-.7c.2-.2.3-.2.5-.1l1.6.8c.2.1.4.2.4.3.1.1.1.6 0 1.1z" fill={color} stroke="none" />,
    sms: <g><rect x="3" y="5" width="18" height="13" rx="3" /><path d="M8 11h.01M12 11h.01M16 11h.01" /></g>,
    mail: <g><rect x="3" y="5" width="18" height="14" rx="2.5" /><path d="M4 7l8 6 8-6" /></g>,
    logout: <path d="M14 4H6a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h8M17 8l4 4-4 4M9 12h12" />,
    copy: <g><rect x="9" y="9" width="11" height="11" rx="2.5" /><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" /></g>,
    share: <g><circle cx="6" cy="12" r="2.6" /><circle cx="17.5" cy="6" r="2.6" /><circle cx="17.5" cy="18" r="2.6" /><path d="M8.3 10.8 15.2 7.2M8.3 13.2l6.9 3.6" /></g>,
    sparkle: <path d="M12 2c.9 5.2 3.9 8.1 9 9-5.1.9-8.1 3.8-9 9-.9-5.2-3.9-8.1-9-9 5.1-.9 8.1-3.8 9-9z" fill={color} stroke="none" />,
    info: <g><circle cx="12" cy="12" r="9" /><path d="M12 11v5M12 8h.01" /></g>,
    warn: <g><path d="M12 4l9 15H3z" /><path d="M12 10v4M12 17h.01" /></g>,
    trash: <path d="M5 7h14M9 7V5h6v2M6 7l1 13h10l1-13" />,
    grid: <g><rect x="4" y="4" width="7" height="7" rx="2" /><rect x="13" y="4" width="7" height="7" rx="2" /><rect x="4" y="13" width="7" height="7" rx="2" /><rect x="13" y="13" width="7" height="7" rx="2" /></g>,
    refresh: <path d="M4 12a8 8 0 0 1 14-5l2 2M20 12a8 8 0 0 1-14 5l-2-2M18 4v5h-5M6 20v-5h5" />,
    drupletOutline: <path d="M12 3s6 6.5 6 11a6 6 0 0 1-12 0c0-4.5 6-11 6-11z" />,
    trendUp: <g><path d="M3 17l6-6 4 4 8-8" /><path d="M16 7h5v5" /></g>,
    trendDown: <g><path d="M3 7l6 6 4-4 8 8" /><path d="M16 17h5v-5" /></g>,
    trendFlat: <path d="M4 12h12M14 8l4 4-4 4" />
  };
  return <svg {...common}>{P[name] || null}</svg>;
}

/* blood-group colors (decorative, on-palette) */
const BLOOD_COLORS = {
  'O+': 'var(--orange)', 'O-': 'var(--alert)', 'A+': '#65B017', 'A-': 'var(--success)',
  'B+': '#3E9AA0', 'B-': '#2f7e84', 'AB+': '#8a7CC0', 'AB-': '#6E63A8'
};
const bloodColor = (g) => BLOOD_COLORS[g] || '#9BB7BB';

function Avatar({ name, size = 46, count, photoUrl, alt }) {
  return (
    <div className="avatar-wrap" style={{ width: size, height: size }}>
      <div className={'avatar' + (alt ? ' alt' : '')} style={{ width: size, height: size, fontSize: size * 0.36, background: photoUrl ? '#eee' : TC.avatarGradient(name) }}>
        {photoUrl ? <div className="ph" style={{ backgroundImage: `url(${photoUrl})` }} /> : TC.initials(name)}
      </div>
      {count != null && count > 0 && <span className="av-count num">{count}×</span>}
    </div>);

}

function BloodBadge({ group, size = 11 }) {
  return <span className="blood" style={{ background: bloodColor(group), fontSize: size }}>{group}</span>;
}

/* status → visual */
function statusVisual(donor) {
  const s = TC.donorStatus(donor);
  if (s.status === 'ELIGIBLE') return { s, color: 'var(--eligible)', wash: 'var(--eligible-wash)', icon: 'checkCircle', short: 'Eligible', long: s.eligibleSince ? `Eligible · rested ${s.daysRested}d` : 'Eligible now' };
  if (s.status === 'SOON') return { s, color: 'var(--soon)', wash: 'var(--soon-wash)', icon: 'clock', short: `${s.daysRemaining}d`, long: `Eligible in ${s.daysRemaining} day${s.daysRemaining === 1 ? '' : 's'}` };
  if (s.status === 'DEFERRED') return { s, color: 'var(--deferred)', wash: 'var(--deferred-wash)', icon: 'shield', short: 'Deferred', long: `Deferred · ${s.reason || 'On hold'}` };
  return { s, color: 'var(--waiting)', wash: 'var(--waiting-wash)', icon: 'clock', short: `${s.daysRemaining}d`, long: `Waiting · ${s.daysRemaining} day${s.daysRemaining === 1 ? '' : 's'} left` };
}

function StatusChip({ donor }) {
  const v = statusVisual(donor);
  return (
    <span className="chip-status" style={{ background: v.wash, color: v.color }}>
      <Icon name={v.icon} size={13} color={v.color} /> {v.long}
    </span>);

}

function SectionHead({ title, link, onLink, spark = true, icon, iconColor, linkProminent }) {
  return (
    <div className="section">
      <span className="sec-title">{icon ? <Icon name={icon} size={15} color={iconColor || 'var(--sky-deep)'} fill={icon === 'heart' || icon === 'drop' ? (iconColor || 'var(--sky-deep)') : 'none'} /> : spark ? <Icon name="sparkle" size={14} color="var(--yellow)" /> : null}{title}</span>
      {link && (linkProminent ?
        <button className="link link-pill" onClick={onLink}><Icon name="plus" size={14} color="#fff" />{link.replace(/^\+\s*/, '')}</button> :
        <button className="link" onClick={onLink}>{link}<Icon name="chevR" size={14} color="var(--orange)" /></button>)}
    </div>);

}

function EmptyState({ title, sub, children }) {
  return (
    <div className="empty">
      <Pearl size={64} />
      <div className="h2">{title}</div>
      {sub && <div className="body" style={{ maxWidth: 250 }}>{sub}</div>}
      {children}
    </div>);

}

/* small reusable pearl illustration (flat) — MUI takes its name from
   muthu/muth (މުތް), the Dhivehi word for pearl. Three sonar-style rings
   (orange/teal/red) cradle the pearl. */
function Pearl({ size = 64 }) {
  const uid = React.useId();
  return (
    <svg width={size} height={size} viewBox="0 0 140 140" fill="none">
      <defs>
        <radialGradient id={'pearlBody' + uid} cx="35%" cy="30%" r="80%">
          <stop offset="0" stopColor="#ffffff" />
          <stop offset="1" stopColor="var(--ink-3)" />
        </radialGradient>
      </defs>
      <circle cx="74" cy="66" r="42" fill="none" stroke="var(--orange)" strokeWidth="2.4" opacity=".55" />
      <circle cx="72" cy="68" r="29" fill="none" stroke="var(--info)" strokeWidth="2.6" opacity=".65" />
      <circle cx="71" cy="69" r="19" fill="none" stroke="var(--danger)" strokeWidth="2.8" opacity=".75" />
      <circle cx="70" cy="70" r="16" fill={`url(#pearlBody${uid})`} stroke="var(--ink-3)" strokeWidth="1.5" />
      <ellipse cx="63" cy="63" rx="5" ry="3.6" fill="#fff" opacity=".95" />
    </svg>);

}

/* ============================================================
   HOME ILLUSTRATIONS — pure art, no text overlay.
   Pick one of four on-brand backdrops in Me → Preferences.
   ============================================================ */
const SCENE_VARIANTS = [
{ id: 'living', name: 'Living sky', desc: 'Follows the time of day' },
{ id: 'sprout', name: 'Sprout', desc: 'Plant on cream & sky' },
{ id: 'sunrise', name: 'Sunrise', desc: 'Warm hills at dawn' },
{ id: 'lagoon', name: 'Lagoon', desc: 'Maldivian ocean' },
{ id: 'bloom', name: 'Bloom', desc: 'Meadow in flower' },
{ id: 'midnight', name: 'Starry night', desc: 'Moonlit & calm' }];


/* one art SVG per variant, filling a 390×230 frame */
function SceneArt({ variant }) {
  if (variant === 'sunrise') return (
    <svg className="scene-art" viewBox="0 0 390 230" preserveAspectRatio="xMidYMax slice" fill="none">
      <circle className="bob" cx="195" cy="176" r="46" fill="#FFD27A" />
      <circle cx="195" cy="176" r="60" fill="#FFD27A" opacity=".28" />
      <g stroke="#FFC04D" strokeWidth="3" strokeLinecap="round" opacity=".7">
        <path d="M195 96v-20M243 110l13-14M147 110l-13-14M285 150l18-7M105 150l-18-7" />
      </g>
      <path className="bird" d="M70 70c5-6 9-6 13 0 4-6 8-6 13 0" stroke="#E0793C" strokeWidth="2.6" strokeLinecap="round" />
      <path className="bird" style={{ animationDelay: '1.1s' }} d="M285 56c4-5 7-5 10 0 3-5 6-5 10 0" stroke="#E0793C" strokeWidth="2.4" strokeLinecap="round" />
      <path d="M0 186c70-26 120-26 195 0s125 26 195 0v44H0z" fill="#F4A259" />
      <path d="M0 206c80-22 130-14 195 4s120 12 195-6v26H0z" fill="#E2823B" />
    </svg>);

  if (variant === 'lagoon') return (
    <svg className="scene-art" viewBox="0 0 390 230" preserveAspectRatio="xMidYMax slice" fill="none">
      <circle className="bob" cx="312" cy="58" r="30" fill="#FFE39A" />
      <circle cx="312" cy="58" r="40" fill="#FFE39A" opacity=".3" />
      <ellipse className="drift" cx="96" cy="62" rx="34" ry="11" fill="#fff" opacity=".85" />
      <ellipse className="drift" style={{ animationDelay: '2s' }} cx="150" cy="48" rx="22" ry="8" fill="#fff" opacity=".7" />
      <path d="M0 150c50-16 90-16 130 0s90 16 130 0 90-16 130 0v80H0z" fill="#7FD3E0" />
      <path d="M0 176c50-14 90-14 130 0s90 14 130 0 90-14 130 0v54H0z" fill="#49B6CC" />
      <path d="M0 198c50-12 90-12 130 0s90 12 130 0 90-12 130 0v32H0z" fill="#2E94AE" />
      <g transform="translate(252 96)">
        <path d="M14 70V30" stroke="#8A6A45" strokeWidth="6" strokeLinecap="round" />
        <path d="M14 30C2 24-6 26-12 34 2 30 10 30 14 30Z" fill="#3E9F6E" />
        <path d="M14 30C26 22 36 22 44 30 30 26 20 27 14 30Z" fill="#4DB97E" />
        <path d="M14 30C8 18 10 8 18 2 16 14 16 24 14 30Z" fill="#5FC98E" />
        <ellipse cx="14" cy="72" rx="30" ry="7" fill="#F4E2B8" />
      </g>
    </svg>);

  if (variant === 'bloom') return (
    <svg className="scene-art" viewBox="0 0 390 230" preserveAspectRatio="xMidYMax slice" fill="none">
      <circle className="bob" cx="318" cy="52" r="26" fill="#FFE39A" />
      <path d="M0 168c70-22 120-22 195 0s125 22 195 0v62H0z" fill="#9AD653" />
      <path d="M0 192c80-16 130-10 195 4s120 8 195-4v38H0z" fill="#74BE22" />
      {[{ x: 78, y: 168, c: 'var(--orange)', d: 0 }, { x: 195, y: 150, c: '#FFB62B', d: .6 }, { x: 312, y: 166, c: 'var(--alert)', d: 1.2 }].map((f, i) =>
      <g key={i} className="bob" style={{ animationDelay: `${f.d}s`, transformOrigin: `${f.x}px ${f.y}px` }}>
          <path d={`M${f.x} ${f.y + 40}V${f.y + 6}`} stroke="#5a9216" strokeWidth="4" strokeLinecap="round" />
          {[0, 72, 144, 216, 288].map((a) =>
        <ellipse key={a} cx={f.x} cy={f.y - 11} rx="6.5" ry="12" fill={f.c} transform={`rotate(${a} ${f.x} ${f.y})`} />
        )}
          <circle cx={f.x} cy={f.y} r="6" fill="#FFF3DC" />
        </g>
      )}
      <g className="tw"><path d="M150 70c.6 3.5 2.6 5.4 6 6-3.4.6-5.4 2.5-6 6-.6-3.5-2.6-5.4-6-6 3.4-.6 5.4-2.5 6-6z" fill="#FFB62B" /></g>
      <g className="tw" style={{ animationDelay: '1s' }}><path d="M250 92c.5 3 2.2 4.6 5 5-2.8.5-4.5 2.1-5 5-.5-3-2.2-4.6-5-5 2.8-.4 4.5-2 5-5z" fill="#65B017" /></g>
    </svg>);

  if (variant === 'midnight') {
    const rand = skyRng(13);
    const stars = Array.from({ length: 36 }, () => ({
      x: +(rand() * 390).toFixed(1), y: +(rand() * 150).toFixed(1),
      r: +(0.6 + rand() * 1.5).toFixed(2), d: (rand() * 3).toFixed(2),
    }));
    return (
      <svg className="scene-art" viewBox="0 0 390 230" preserveAspectRatio="xMidYMax slice" fill="none">
        <defs>
          <radialGradient id="moonGlowMid" cx="50%" cy="50%" r="50%">
            <stop offset="0%" stopColor="#C6CBFF" stopOpacity=".55" />
            <stop offset="60%" stopColor="#C6CBFF" stopOpacity=".15" />
            <stop offset="100%" stopColor="#C6CBFF" stopOpacity="0" />
          </radialGradient>
          <mask id="moonMaskMid">
            <rect width="390" height="230" fill="black" />
            <circle cx="312" cy="60" r="26" fill="white" />
            <circle cx="323" cy="52" r="24" fill="black" />
          </mask>
        </defs>
        {stars.map((s, i) => <circle key={i} className="tw" cx={s.x} cy={s.y} r={s.r} fill="#EAEDFF" style={{ animationDelay: s.d + 's' }} />)}
        <circle cx="312" cy="60" r="66" fill="url(#moonGlowMid)" />
        <g className="bob" style={{ transformOrigin: '312px 60px' }}>
          <g mask="url(#moonMaskMid)"><circle cx="312" cy="60" r="26" fill="#F4F2FF" /></g>
        </g>
        <g className="shoot"><line x1="36" y1="34" x2="80" y2="56" stroke="#FFFFFF" strokeWidth="2.2" strokeLinecap="round" /></g>
        <g className="drift" fill="#3a3d6e" opacity=".5"><g transform="translate(96 100)"><ellipse cx="0" cy="0" rx="26" ry="11" /><ellipse cx="20" cy="4" rx="17" ry="9" /><ellipse cx="-18" cy="4" rx="15" ry="8" /></g></g>
        <path d="M0 168c70-22 120-22 195 0s125 22 195 0v62H0z" fill="#272b56" />
        <path d="M0 192c80-16 130-10 195 4s120 8 195-4v38H0z" fill="#1b1e42" />
        <g className="bob" style={{ transformOrigin: '300px 206px', animationDelay: '1.4s' }}>
          <path d="M300 210V178" stroke="#6FA177" strokeWidth="4" strokeLinecap="round" />
          <path d="M300 192c-12-4-16-14-15-21 9 0 16 7 15 21z" fill="#5E8A66" />
          <path d="M300 186c12-5 17-15 16-22-10 0-15 8-16 22z" fill="#7DB285" />
        </g>
        <g className="tw" style={{ animationDelay: '.6s' }}><path d="M150 72c.6 3.5 2.6 5.4 6 6-3.4.6-5.4 2.5-6 6-.6-3.5-2.6-5.4-6-6 3.4-.6 5.4-2.5 6-6z" fill="#FFE08A" /></g>
        <g className="tw" style={{ animationDelay: '1.5s' }}><path d="M236 40c.5 3 2.2 4.6 5 5-2.8.5-4.5 2.1-5 5-.5-3-2.2-4.6-5-5 2.8-.4 4.5-2 5-5z" fill="#C6CBFF" /></g>
      </svg>);
  }

  // default — sprout
  return (
      <svg className="scene-art" viewBox="0 0 390 230" preserveAspectRatio="xMidYMax slice" fill="none">
      <circle className="bob" cx="312" cy="54" r="30" fill="#FFE7A8" />
      <circle cx="312" cy="54" r="42" fill="#FFE7A8" opacity=".3" />
      <ellipse className="drift" cx="84" cy="74" rx="32" ry="10" fill="#fff" opacity=".85" />
      <path d="M0 176c44-22 86-12 130 0s86 22 130 0 86-22 130 0v54H0z" fill="#BFE6E8" />
      <path d="M0 196c60-18 110-6 165 6s120 6 225-6v34H0z" fill="#86C932" />
      <g className="bob" style={{ transformOrigin: '195px 200px' }}>
        <path d="M195 206V120" stroke="#5a9216" strokeWidth="7" strokeLinecap="round" />
        <path d="M195 178C156 173 140 147 143 118 181 123 197 147 195 178Z" fill="#7CC52B" />
        <path d="M195 158C234 153 250 127 247 98 209 103 193 127 195 158Z" fill="#65B017" />
        <path d="M195 134C172 131 162 113 165 92 188 96 197 113 195 134Z" fill="#8FD23E" />
        <path d="M195 108S176 89 176 75a10 10 0 0 1 19-3 10 10 0 0 1 19 3c0 14-19 33-19 33z" fill="var(--orange)" style={{ fill: "rgb(252, 72, 5)" }} />
      </g>
      <g className="tw"><path d="M120 96c.6 3.5 2.6 5.4 6 6-3.4.6-5.4 2.5-6 6-.6-3.5-2.6-5.4-6-6 3.4-.6 5.4-2.5 6-6z" fill="#9BB7BB" /></g>
      <g className="tw" style={{ animationDelay: '.8s' }}><path d="M286 120c.5 3 2.2 4.6 5 5-2.8.5-4.5 2.1-5 5-.5-3-2.2-4.6-5-5 2.8-.4 4.5-2 5-5z" fill="#FFB62B" /></g>
    </svg>);

}

/* the Today hero scene — pure illustration, variant-driven */
function SproutScene({ patient, variant = 'sprout' }) {
  return (
    <div className={'scene scene--' + (variant || 'sprout')}>
      <SceneArt variant={variant || 'sprout'} />
    </div>);

}

/* ============================================================
   LIVING SKY — the hero whose sky tracks the time of day.
   dawn · day · dusk · night. No location, no permissions.
   ============================================================ */
function skyPhase(h) {
  if (h >= 5 && h < 8) return 'dawn';
  if (h >= 8 && h < 17) return 'day';
  if (h >= 17 && h < 20) return 'dusk';
  return 'night';
}

const SKY_PH = {
  dawn: { grad: ['#FFEEDD', '#FFDDC8', '#F7C8CC'], body: 'sun', bodyPos: [296, 176, 27], bodyFill: '#FF9E76', bodyGlow: '#FFC8A6',
    hillBack: '#D2E6B6', hillFront: '#ACD389', sprout: '#7CB342', cloud: '#FFF6EF', cloudOp: 0.85, stars: 0.35, birds: true, fireflies: false, rays: false, ink: '#5A4438', sub: '#8A6A5A', night: false },
  day: { grad: ['#EAF7F4', '#CFEFF6', '#BBE6F0'], body: 'sun', bodyPos: [324, 70, 25], bodyFill: '#FFC53D', bodyGlow: '#FFE596',
    hillBack: '#CFEBB7', hillFront: '#A1D07F', sprout: '#65B017', cloud: '#FFFFFF', cloudOp: 0.92, stars: 0, birds: true, fireflies: false, rays: true, ink: '#2E2A24', sub: '#7C7264', night: false },
  dusk: { grad: ['#FFD7A6', '#FBA47C', '#CE8AB4'], body: 'sun', bodyPos: [86, 158, 33], bodyFill: '#FF7A3D', bodyGlow: '#FFB678',
    hillBack: '#C9A98F', hillFront: '#9B7E74', sprout: '#7A8C3E', cloud: '#FFE7D6', cloudOp: 0.8, stars: 0.25, birds: true, fireflies: false, rays: false, ink: '#4A2E3E', sub: '#7A5466', night: false },
  night: { grad: ['#232650', '#33356A', '#433F73'], body: 'moon', bodyPos: [312, 74, 22], bodyFill: '#ECEAFF', bodyGlow: '#9C9AD8',
    hillBack: '#2B3550', hillFront: '#1E2740', sprout: '#5E8A66', cloud: '#4A4A86', cloudOp: 0.4, stars: 1, birds: false, fireflies: true, rays: false, ink: '#FBF4E8', sub: '#C9C2DE', night: true },
};

function skyRng(seed) { let s = seed; return () => { s = (s * 1103515245 + 12345) & 0x7fffffff; return s / 0x7fffffff; }; }

function LivingSky({ phase = 'day', w = 390, h = 300 }) {
  const c = SKY_PH[phase] || SKY_PH.day;
  const [bx, by, br] = c.bodyPos;
  const gid = 'sky_' + phase, bid = 'body_' + phase, glowId = 'glow_' + phase;
  const horizon = 212;
  const stars = [];
  if (c.stars > 0) {
    const rand = skyRng(7);
    for (let i = 0; i < 46; i++) stars.push({ x: rand() * w, y: rand() * (horizon - 30), r: 0.5 + rand() * 1.4, op: (0.4 + rand() * 0.6) * c.stars, d: (rand() * 3).toFixed(2) });
  }
  const flies = [];
  if (c.fireflies) { const rand = skyRng(19); for (let i = 0; i < 11; i++) flies.push({ x: 30 + rand() * (w - 60), y: 120 + rand() * 95, d: (rand() * 4).toFixed(2), s: (2.4 + rand() * 1.8) }); }
  return (
    <svg className="sky-art" viewBox={`0 0 ${w} ${h}`} width="100%" height="100%" preserveAspectRatio="xMidYMid slice" style={{ display: 'block' }}>
      <defs>
        <linearGradient id={gid} x1="0" y1="0" x2="0" y2="1">
          <stop offset="0%" stopColor={c.grad[0]} /><stop offset="55%" stopColor={c.grad[1]} /><stop offset="100%" stopColor={c.grad[2]} />
        </linearGradient>
        <radialGradient id={glowId} cx="50%" cy="50%" r="50%">
          <stop offset="0%" stopColor={c.bodyGlow} stopOpacity="0.9" /><stop offset="60%" stopColor={c.bodyGlow} stopOpacity="0.28" /><stop offset="100%" stopColor={c.bodyGlow} stopOpacity="0" />
        </radialGradient>
        <mask id={bid}>
          <rect width={w} height={h} fill="black" /><circle cx={bx} cy={by} r={br} fill="white" />
          {c.body === 'moon' && <circle cx={bx + 9} cy={by - 6} r={br} fill="black" />}
        </mask>
      </defs>
      <rect width={w} height={h} fill={`url(#${gid})`} />
      {stars.map((s, i) => <circle key={i} className="sky-tw" cx={s.x} cy={s.y} r={s.r} fill="#FFFFFF" opacity={s.op} style={{ animationDelay: s.d + 's' }} />)}
      <circle cx={bx} cy={by} r={br * 2.6} fill={`url(#${glowId})`} />
      {c.body === 'sun' ? <circle cx={bx} cy={by} r={br} fill={c.bodyFill} /> : <g mask={`url(#${bid})`}><circle cx={bx} cy={by} r={br} fill={c.bodyFill} /></g>}
      {c.rays && (
        <g className="sky-rays" style={{ transformOrigin: `${bx}px ${by}px` }} opacity="0.5">
          {Array.from({ length: 12 }).map((_, i) => { const a = (i / 12) * Math.PI * 2, r1 = br + 6, r2 = br + 15; return <line key={i} x1={bx + Math.cos(a) * r1} y1={by + Math.sin(a) * r1} x2={bx + Math.cos(a) * r2} y2={by + Math.sin(a) * r2} stroke={c.bodyFill} strokeWidth="2.4" strokeLinecap="round" />; })}
        </g>
      )}
      {phase !== 'night' ? (
        <g className="sky-drift" fill={c.cloud} opacity={c.cloudOp}>
          <g transform="translate(40 70)"><ellipse cx="0" cy="0" rx="26" ry="13" /><ellipse cx="22" cy="4" rx="20" ry="11" /><ellipse cx="-20" cy="5" rx="17" ry="10" /></g>
          <g transform="translate(250 116) scale(.8)"><ellipse cx="0" cy="0" rx="24" ry="12" /><ellipse cx="20" cy="4" rx="17" ry="10" /><ellipse cx="-18" cy="4" rx="15" ry="9" /></g>
        </g>
      ) : (
        <g className="sky-drift" fill={c.cloud} opacity={c.cloudOp}><g transform="translate(70 92) scale(.9)"><ellipse cx="0" cy="0" rx="24" ry="11" /><ellipse cx="20" cy="3" rx="16" ry="9" /><ellipse cx="-18" cy="4" rx="14" ry="8" /></g></g>
      )}
      {flies.map((f, i) => (
        <g key={i} className="sky-fly" style={{ animationDelay: f.d + 's', animationDuration: f.s + 's', transformOrigin: `${f.x}px ${f.y}px` }}>
          <circle cx={f.x} cy={f.y} r="3.4" fill="#FFE08A" opacity="0.35" /><circle cx={f.x} cy={f.y} r="1.5" fill="#FFF2C2" />
        </g>
      ))}
      {c.birds && (
        <g className="sky-bird" stroke={phase === 'dusk' ? '#6E4A52' : '#8A8270'} strokeWidth="2" strokeLinecap="round" fill="none" opacity="0.55">
          <path d="M120 64 q7 -7 14 0 q7 -7 14 0" /><path d="M160 80 q5.5 -5.5 11 0 q5.5 -5.5 11 0" transform="scale(.85)" />
        </g>
      )}
      <path d={`M0 ${horizon} Q 110 ${horizon - 34} 220 ${horizon - 8} T 390 ${horizon - 18} V ${h} H 0 Z`} fill={c.hillBack} />
      <path d={`M0 ${horizon + 22} Q 140 ${horizon - 6} 270 ${horizon + 18} T 390 ${horizon + 6} V ${h} H 0 Z`} fill={c.hillFront} />
      <g transform="translate(300 222)" className="sky-bob">
        <path d="M0 26 V 4" stroke={c.sprout} strokeWidth="3.4" strokeLinecap="round" fill="none" />
        <path d="M0 12 C -12 8 -16 -2 -15 -9 C -6 -9 1 -2 0 10 Z" fill={c.sprout} />
        <path d="M0 6 C 11 2 16 -8 15 -15 C 6 -14 -1 -6 0 4 Z" fill={c.sprout} opacity="0.9" />
      </g>
    </svg>
  );
}

/* the small companion sprite used in the warm insight card */
function Companion({ size = 44, color = '#65B017', wash = 'var(--green-wash)' }) {
  return (
    <div style={{ width: size, height: size, flex: 'none', borderRadius: '50%', background: wash, display: 'grid', placeItems: 'center', boxShadow: '0 2px 8px rgba(20,30,25,.06)' }}>
      <svg width={size * 0.62} height={size * 0.62} viewBox="0 0 40 40" fill="none">
        <path d="M20 6c5 5 9 9.5 9 15a9 9 0 0 1-18 0c0-5.5 4-10 9-15z" fill={color} opacity="0.18" />
        <circle cx="15.5" cy="20" r="2.1" fill={color} /><circle cx="24.5" cy="20" r="2.1" fill={color} />
        <path d="M15.5 25.5q4.5 3.5 9 0" stroke={color} strokeWidth="2" strokeLinecap="round" fill="none" />
        <path d="M20 9c2.5-2 5-2.4 6.4-2.2C26.6 8.2 25 11 22 12c-1.6.5-2.4-.6-2-3z" fill={color} />
      </svg>
    </div>
  );
}

/* ---- Sparkline: a quiet inline trend line (chronological values, oldest→newest) ---- */
function Sparkline({ values, color = 'var(--sky-deep)', height = 26, fill = true, strokeWidth = 2 }) {
  if (!values || values.length < 2) return null;
  const W = 100, H = 28, pad = 3.5;
  const min = Math.min(...values), max = Math.max(...values);
  const span = (max - min) || 1;
  const n = values.length;
  const x = (i) => pad + (i / (n - 1)) * (W - pad * 2);
  const y = (v) => pad + (1 - (v - min) / span) * (H - pad * 2);
  const pts = values.map((v, i) => [x(i), y(v)]);
  const line = pts.map((p, i) => `${i ? 'L' : 'M'} ${p[0].toFixed(1)} ${p[1].toFixed(1)}`).join(' ');
  const area = `${line} L ${pts[n - 1][0].toFixed(1)} ${H} L ${pts[0][0].toFixed(1)} ${H} Z`;
  const last = pts[n - 1];
  const gid = React.useMemo(() => 'spk' + Math.random().toString(36).slice(2, 8), []);
  return (
    <svg viewBox={`0 0 ${W} ${H}`} width="100%" height={height} preserveAspectRatio="none"
      style={{ display: 'block', overflow: 'visible' }} aria-hidden="true">
      {fill && (
        <React.Fragment>
          <defs>
            <linearGradient id={gid} x1="0" y1="0" x2="0" y2="1">
              <stop offset="0" stopColor={color} stopOpacity="0.16" />
              <stop offset="1" stopColor={color} stopOpacity="0" />
            </linearGradient>
          </defs>
          <path d={area} fill={`url(#${gid})`} stroke="none" />
        </React.Fragment>
      )}
      <path d={line} fill="none" stroke={color} strokeWidth={strokeWidth} strokeLinecap="round" strokeLinejoin="round" vectorEffect="non-scaling-stroke" />
      <circle cx={last[0]} cy={last[1]} r="2.2" fill={color} vectorEffect="non-scaling-stroke" />
    </svg>);

}

/* ---- FieldNote: inline clinical validation message under an input ----
   Renders a note from window.CLINICALGUARD ({level,msg,suggest?}). Levels:
   info (calm blue), warn (amber), block (red). An optional suggestion is a
   one-tap fix. role=alert for warn/block so screen readers announce it. */
function FieldNote({ note, onApplySuggest }) {
  if (!note) return null;
  const tone = note.level === 'block'
    ? { color: 'var(--danger, #C2410C)', wash: 'var(--danger-wash, #FDEBE3)', icon: 'warn' }
    : note.level === 'warn'
    ? { color: 'var(--orange)', wash: 'var(--orange-wash)', icon: 'warn' }
    : { color: 'var(--sky-deep)', wash: 'var(--sky-wash)', icon: 'info' };
  return (
    <div className="field-note" role={note.level === 'info' ? 'status' : 'alert'}
      style={{ display: 'flex', gap: 8, alignItems: 'flex-start', margin: '-6px 2px 14px', padding: '8px 11px', borderRadius: 11, background: tone.wash }}>
      <Icon name={tone.icon} size={14} color={tone.color} style={{ flex: 'none', marginTop: 1.5 }} />
      <span style={{ flex: 1, minWidth: 0, fontSize: 12, lineHeight: 1.45, color: 'var(--ink)', fontWeight: 600 }}>
        {note.msg}
        {note.suggest != null && onApplySuggest && (
          <>{' '}<button type="button" className="link" style={{ fontSize: 12, fontWeight: 800, color: tone.color }} onClick={() => onApplySuggest(note.suggest)}>Use {note.suggest}</button></>
        )}
      </span>
    </div>);
}

/* ---- MedicalDisclaimer: the standing "not medical advice" line ----
   variant 'inline' (compact, in a sheet) or 'card' (a soft standalone block). */
function MedicalDisclaimer({ variant = 'inline', style }) {
  if (variant === 'card') {
    return (
      <div className="med-disclaimer" role="note" style={Object.assign({ display: 'flex', gap: 10, alignItems: 'flex-start', padding: '12px 14px', borderRadius: 14, background: 'var(--surface-2)' }, style)}>
        <Icon name="info" size={15} color="var(--ink-3)" style={{ flex: 'none', marginTop: 1 }} />
        <span style={{ fontSize: 11.5, lineHeight: 1.5, color: 'var(--ink-2)' }}>
          MUIY helps you organise your care — its forecasts, dose targets and insights are <b>estimates, not medical advice</b>. Always follow your haematologist’s guidance. For urgent symptoms, contact your treatment centre.
        </span>
      </div>);
  }
  return (
    <div className="med-disclaimer" role="note" style={Object.assign({ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 7, margin: '4px 2px 0' }, style)}>
      <span style={{ width: 22, height: 2, borderRadius: 2, background: 'var(--ink-3)', opacity: 0.3 }} />
      <span style={{ fontSize: 11, lineHeight: 1.45, color: 'var(--ink-3)', textAlign: 'center', textWrap: 'balance', maxWidth: 280 }}>For information and tracking only — always consult your healthcare team for medical decisions.</span>
    </div>);
}

Object.assign(window, { StoreCtx, useStore, Icon, Avatar, BloodBadge, bloodColor, statusVisual, StatusChip, SectionHead, EmptyState, Pearl, SproutScene, SceneArt, SCENE_VARIANTS, LivingSky, skyPhase, SKY_PH, Companion, Sparkline, FieldNote, MedicalDisclaimer });