// Healify UI Kit — shared primitives. Single source of truth.
// All pure cosmetic JSX recreations of healify RN components.

const H = {
  orange: 'var(--brand-orange-vibey)',       // orangeVibey (brand CTA)
  orangeAlt: 'var(--brand-orange-vibey)',    // tokens.json variant
  gold: 'var(--brand-gold-sand)',         // goldSand
  paleGold: 'var(--brand-pale-gold-sand)',
  black: 'var(--brand-ink)',        // blackPrimary
  bg: 'var(--bg-app)',
  bgSecondary: 'var(--bg-secondary)',
  surface: '#FFFFFF',
  fg1: 'var(--brand-ink)',
  fg2: 'var(--fg-2)',
  fg3: 'var(--fg-3)',
  border: 'var(--border)',
  success: 'var(--success-500)',
  warning: 'var(--warning-500)',
  danger: 'var(--error-500)',
  saladGreen: 'var(--focus-fitness)',
  blue: 'var(--info-500)',
  userBubbleTeal: 'var(--teal-bubble)',
  // focus tints
  sleep: 'var(--focus-sleep)',
  nutrition: 'var(--brand-orange-vibey)',
  fitness: 'var(--focus-fitness)',
  mental: 'var(--focus-mental)',
  heart: 'var(--error-500)',
  activity: 'var(--brand-gold-sand)',
  display: '"ES Rebond Grotesque", -apple-system, system-ui, sans-serif',
  body: '"SF Pro Rounded", -apple-system, system-ui, sans-serif',
  // Primary button gradient — uses canonical --grad-vibey-cta (vertical, gold→orange).
  // Change colors_and_type.css and EVERY primary button updates automatically.
  gradOrange: 'var(--grad-vibey-cta)',
  gradBubble: 'var(--grad-user-bubble)',
  gradDarkWarm: 'var(--grad-ink-veil)',
};

// ──────────────────────────────────────────────────────────────────────────
// Primitives
// ──────────────────────────────────────────────────────────────────────────

function HCard({ children, style = {}, onClick, className }) {
  return (
    <div onClick={onClick} className={className} style={{
      background: H.surface, borderRadius: 16, padding: 14,
      boxShadow: '0 1px 2px rgba(3,4,13,0.05)',
      cursor: onClick ? 'pointer' : 'default',
      transition: 'transform 120ms ease-out, box-shadow 120ms',
      ...style,
    }}>{children}</div>
  );
}

// Tinted rounded-SQUARE icon tile (matches home screenshot).
function HIconTile({ color = H.orange, alpha = 0.12, tint, size = 44, children, rounded = 'square' }) {
  const bg = tint || (color.startsWith('#')
    ? `${color}${Math.round(alpha * 255).toString(16).padStart(2, '0')}`
    : `color-mix(in srgb, ${color} ${Math.round(alpha * 100)}%, transparent)`);
  return (
    <div style={{
      width: size, height: size,
      borderRadius: rounded === 'circle' ? 999 : 14,
      background: bg,
      display: 'grid', placeItems: 'center', flexShrink: 0,
    }}>{children}</div>
  );
}

function HStatusDot({ level = 'normal' }) {
  const m = { normal: H.success, fair: H.warning, bad: H.danger, info: 'var(--info-500)' };
  return <span style={{ width: 10, height: 10, borderRadius: 999, background: m[level], display: 'inline-block' }} />;
}

function HChevron({ dir = 'right', color = '#C9CBD0' }) {
  if (dir === 'down') return (
    <svg width="12" height="7" viewBox="0 0 14 8" style={{ flexShrink: 0 }}>
      <path d="M1 1l6 6 6-6" stroke={color} strokeWidth="2" fill="none" strokeLinecap="round" strokeLinejoin="round"/>
    </svg>
  );
  if (dir === 'up') return (
    <svg width="12" height="7" viewBox="0 0 14 8" style={{ flexShrink: 0 }}>
      <path d="M1 7l6-6 6 6" stroke={color} strokeWidth="2" fill="none" strokeLinecap="round" strokeLinejoin="round"/>
    </svg>
  );
  return (
    <svg width="7" height="12" viewBox="0 0 8 14" style={{ flexShrink: 0 }}>
      <path d="M1 1l6 6-6 6" stroke={color} strokeWidth="2" fill="none" strokeLinecap="round" strokeLinejoin="round"/>
    </svg>
  );
}

function HBadge({ title, level = 'normal' }) {
  return (
    <span style={{
      display: 'inline-flex', alignItems: 'center', gap: 8,
      background: H.bgSecondary, padding: '4px 10px', borderRadius: 999,
    }}>
      <HStatusDot level={level} />
      <span style={{ fontFamily: H.body, fontSize: 12, color: H.fg1, opacity: 0.64 }}>{title}</span>
    </span>
  );
}

// ──────────────────────────────────────────────────────────────────────────
// Buttons
// ──────────────────────────────────────────────────────────────────────────

function HPrimaryButton({ children, type = 'primary', gradient, onClick, style = {}, icon, disabled = false }) {
  if (gradient === false && type === 'primary') type = 'dark';
  const variants = {
    primary: {
      // Filled brand gradient — token-driven via --grad-vibey-cta.
      color: '#fff', background: H.gradOrange, border: 0,
      boxShadow: 'inset 0 1px 0 rgba(255,255,255,0.35), inset 0 -1px 0 rgba(0,0,0,0.12), 0 6px 16px -2px rgba(184,90,54,0.45), 0 1px 2px rgba(184,90,54,0.20)',
      textShadow: '0 1px 0 rgba(120,50,20,0.25)',
    },
    'filled-flat': {
      // Filled flat — solid brand orange, no gradient. Use when stacked on a busy background.
      color: '#fff', background: 'var(--brand-orange-vibey)', border: 0,
      boxShadow: '0 1px 2px rgba(3,4,13,0.10), 0 4px 12px -4px rgba(255,105,66,0.35)',
    },
    soft: {
      // Soft — quartz-tinted background with brand-orange text. Lower visual weight than filled,
      // reads as 'secondary CTA' or 'destructive-light alternative'.
      color: 'var(--brand-orange-vibey)', background: 'var(--quartz-100)', border: 0,
    },
    dark: {
      color: '#fff', background: H.black,
      boxShadow: '3px 4px 12px rgba(3,4,13,0.3)',
      border: '1px solid ' + H.fg2,
    },
    outline: {
      color: H.fg1, background: H.surface,
      border: '1px solid ' + H.border,
      boxShadow: '0 1px 2px rgba(3,4,13,0.04)',
    },
    'outline-brand': {
      // Outlined with brand orange — emphasises brand without filling. Use sparingly.
      color: 'var(--brand-orange-vibey)', background: H.surface,
      border: '1.5px solid var(--brand-orange-vibey)',
      boxShadow: '0 1px 2px rgba(3,4,13,0.04)',
    },
    ghost: {
      color: H.fg1, background: 'transparent', border: 0,
      boxShadow: 'none',
    },
  };
  return (
    <button onClick={onClick} disabled={disabled} style={{
      fontFamily: H.body, fontWeight: 500, fontSize: 16, letterSpacing: -0.2,
      cursor: disabled ? 'default' : 'pointer',
      padding: '12px 22px', borderRadius: 999, width: '100%',
      display: 'inline-flex', alignItems: 'center', justifyContent: 'center', gap: 8,
      opacity: disabled ? 0.5 : 1,
      ...variants[type], ...style,
    }}>
      {icon}{children}
    </button>
  );
}

// Back button — matches repo src/components/ui/back-button
function HBackButton({ onClick, label = 'Back', dark = false, variant = 'back' }) {
  const icon = variant === 'close'
    ? <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke={dark ? '#fff' : H.fg1} strokeWidth="2.2" strokeLinecap="round"><path d="M18 6 6 18M6 6l12 12"/></svg>
    : <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke={dark ? '#fff' : H.fg1} strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round"><path d="M15 18l-6-6 6-6"/></svg>;
  return (
    <div onClick={onClick} role="button" style={{
      display: 'inline-flex', alignItems: 'center', gap: 6,
      background: dark ? 'rgba(255,255,255,0.08)' : '#fff',
      borderRadius: 999, padding: label ? '8px 14px 8px 10px' : 8,
      width: label ? undefined : 36, height: label ? undefined : 36,
      justifyContent: label ? undefined : 'center',
      cursor: 'pointer',
      boxShadow: dark ? 'none' : '0 1px 2px rgba(3,4,13,0.04)',
      fontFamily: H.body, fontWeight: 500, fontSize: 14,
      color: dark ? '#fff' : H.fg1,
    }}>
      {icon}
      {label && <span>{label}</span>}
    </div>
  );
}

// ──────────────────────────────────────────────────────────────────────────
// Headers
// ──────────────────────────────────────────────────────────────────────────

// Greeting header (big type) — Home dashboard hero.
// 2026 pattern: surface the user's daily Health Score AS PART OF the hero so
// it's the first thing they read. The avatar/menu sits inside the score ring's
// bottom-right corner so the right slot stays a single visual unit instead of
// two competing circles.
function HGreetingHeader({ name = 'Kathryn', eyebrow, onMenu, photoUrl, score = 78, scoreDelta = +3, onScorePress }) {
  const greet = (() => {
    const h = new Date().getHours();
    if (h < 12) return 'Good morning';
    if (h < 18) return 'Good afternoon';
    return 'Good evening';
  })();
  const day = eyebrow || new Date().toLocaleDateString('en-US', { weekday: 'long', month: 'short', day: 'numeric' }).toUpperCase().replace(',', ' \u00b7');

  // Score ring geometry
  const tier = score >= 80 ? 'var(--success-500)' : score >= 60 ? 'var(--brand-gold-sand)' : 'var(--brand-orange-vibey)';
  const ring = 76; const stroke = 5;
  const r = (ring - stroke) / 2;
  const c = 2 * Math.PI * r;
  const pct = Math.max(0, Math.min(100, score)) / 100;

  return (
    <div>
      <div style={{
        fontFamily: H.body, fontSize: 11, letterSpacing: 1.2,
        color: H.fg3, textTransform: 'uppercase', fontWeight: 500, marginBottom: 8,
      }}>{day}</div>
      <div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
        <div style={{ flex: 1, minWidth: 0 }}>
          <div style={{ fontFamily: H.display, fontWeight: 600, fontSize: 32, lineHeight: 1.08, color: H.fg1, letterSpacing: -0.6 }}>{greet},</div>
          <div style={{ fontFamily: H.display, fontWeight: 300, fontSize: 32, lineHeight: 1.08, color: H.fg3, letterSpacing: -0.6 }}>{name}</div>
        </div>

        {/* Score + avatar combined unit */}
        <div onClick={onScorePress} role="button" aria-label={`Daily health score ${score}`} style={{
          position: 'relative', width: ring, height: ring, flexShrink: 0,
          cursor: onScorePress ? 'pointer' : 'default',
        }}>
          <svg width={ring} height={ring} viewBox={`0 0 ${ring} ${ring}`} style={{ transform: 'rotate(-90deg)' }}>
            <circle cx={ring/2} cy={ring/2} r={r} fill="#fff" stroke="var(--bg-app)" strokeWidth={stroke} />
            <circle cx={ring/2} cy={ring/2} r={r} fill="none" stroke={tier} strokeWidth={stroke}
              strokeLinecap="round" strokeDasharray={`${c*pct} ${c}`} />
          </svg>
          <div style={{
            position: 'absolute', inset: 0, display: 'flex', flexDirection: 'column',
            alignItems: 'center', justifyContent: 'center', lineHeight: 1, gap: 1,
          }}>
            <div style={{
              fontFamily: H.body, fontSize: 9, fontWeight: 500, letterSpacing: 0.6,
              textTransform: 'uppercase', color: H.fg3,
            }}>Today</div>
            <div style={{
              fontFamily: H.display, fontWeight: 600, fontSize: 26,
              color: H.fg1, letterSpacing: -0.6,
            }}>{score}</div>
            {scoreDelta != null && (
              <div style={{
                fontFamily: H.body, fontWeight: 500, fontSize: 10,
                color: scoreDelta >= 0 ? 'var(--success-500)' : 'var(--brand-orange-vibey)',
              }}>{scoreDelta >= 0 ? '↑' : '↓'}{Math.abs(scoreDelta)}</div>
            )}
          </div>
          {/* Avatar tucked into bottom-right, visually attached to ring */}
          <div onClick={(e) => { e.stopPropagation(); onMenu && onMenu(); }} role="button" aria-label="Menu" style={{
            position: 'absolute', bottom: -2, right: -2,
            width: 28, height: 28, borderRadius: 999, background: '#fff',
            display: 'grid', placeItems: 'center', cursor: 'pointer',
            boxShadow: '0 1px 3px rgba(3,4,13,0.12), 0 0 0 2px var(--bg-app)',
            backgroundImage: photoUrl ? `url(${photoUrl})` : undefined,
            backgroundSize: 'cover', backgroundPosition: 'center',
          }}>
            {!photoUrl && (
              <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke={H.fg1} strokeWidth="2.4" strokeLinecap="round"><path d="M4 7h16M4 12h16M4 17h16"/></svg>
            )}
          </div>
        </div>
      </div>
    </div>
  );
}

function HSectionLabel({ children, right, onPress, style = {} }) {
  return (
    <div style={{
      display: 'flex', justifyContent: 'space-between', alignItems: 'center',
      marginBottom: 16, ...style,
    }}>
      <div style={{
        // ES Rebond is reserved for ≥24px; section labels use SF Pro Rounded
        // at a single weight. No bold variant — uppercase + letterspacing
        // already provides the visual delineation a section header needs.
        fontFamily: H.body,
        fontWeight: 500,
        fontSize: 15, letterSpacing: 1,
        textTransform: 'uppercase', color: H.fg3,
        flex: 1, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap',
      }}>{children}</div>
      {(right || onPress) && (
        <div onClick={onPress} style={{ display: 'flex', alignItems: 'center', gap: 4, cursor: onPress ? 'pointer' : 'default' }}>
          {right && <span style={{ fontFamily: H.body, fontSize: 16, color: H.fg2 }}>{right}</span>}
          {onPress && (
            <svg width="7" height="12" viewBox="0 0 8 14" fill="none"><path d="M1 1l6 6-6 6" stroke={H.fg2} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/></svg>
          )}
        </div>
      )}
    </div>
  );
}

// HTopBar — stack-screen chrome.
//
// 56px row, single horizontal line, vertically centered. Title is absolutely
// positioned (60% max-width, ellipsis) so it stays optically centered
// regardless of left/right slot widths. Subtle warm-white → app-bg gradient
// + 1px hairline gives the floating circular buttons figure/ground contrast.
//
// The daily Health Score is NOT shown here — it lives in the Home dashboard
// hero (HGreetingHeader) instead. Stack screens already have their own
// context-specific titles; surfacing a generic score on top of "Blood report"
// or "Profile" would compete with the screen content.
function HTopBar({ onBack, title, right, dark = false, sticky = false }) {
  // iOS 26-style large-title chrome: transparent bar that BLENDS into the
  // screen surface. No gradient, no hairline divider — the back button and
  // title float over the content. When sticky=true (used by long-form
  // screens), we add a saturated blur so content scrolls under it cleanly.
  const fg = dark ? '#fff' : H.fg1;
  return (
    <div style={{
      position: sticky ? 'sticky' : 'relative', top: 0, zIndex: 10,
      height: 52, padding: '0 8px', display: 'flex', alignItems: 'center',
      background: sticky
        ? (dark ? 'rgba(13,15,20,0.72)' : 'rgba(244,246,247,0.72)')
        : 'transparent',
      borderBottom: 'none',
      backdropFilter: sticky ? 'saturate(1.4) blur(14px)' : 'none',
      WebkitBackdropFilter: sticky ? 'saturate(1.4) blur(14px)' : 'none',
    }}>
      {/* LEFT — back button */}
      <div style={{ display: 'flex', alignItems: 'center', flexShrink: 0, zIndex: 2 }}>
        {onBack && <HBackButton onClick={onBack} dark={dark} label="" />}
      </div>

      {/* CENTER — title, absolutely positioned to stay optically centered */}
      {title && (
        <div style={{
          position: 'absolute', left: 0, right: 0, top: 0, bottom: 0,
          display: 'flex', alignItems: 'center', justifyContent: 'center',
          pointerEvents: 'none',
        }}>
          <div style={{
            fontFamily: H.body, fontWeight: 500, fontSize: 17,
            color: fg, letterSpacing: -0.3,
            maxWidth: '60%', whiteSpace: 'nowrap',
            overflow: 'hidden', textOverflow: 'ellipsis',
          }}>{title}</div>
        </div>
      )}

      {/* RIGHT — optional action */}
      <div style={{ marginLeft: 'auto', display: 'flex', alignItems: 'center', gap: 8, flexShrink: 0, zIndex: 2 }}>
        {right}
      </div>
    </div>
  );
}

// ──────────────────────────────────────────────────────────────────────────
// Tool hero — shared across every AI mini-tool (Bloodwork, DNA, Meal plan,
// Workout, Meditation, Voice). The same compact pattern keeps them all
// recognizable: no colored bg block, just a tight kicker + large title +
// subtitle that sits flush under the (transparent) HTopBar. Use this
// EVERYWHERE inside a tool — never roll a one-off gradient hero, that
// breaks the "learn one tool, you know them all" contract.
// ──────────────────────────────────────────────────────────────────────────
// Slim intro line for AI mini-tools. The HTopBar already carries the tool
// name (Meal plan / Workout / Meditation / Bloodwork / DNA / Voice); the
// hero just gives one human sentence about what's about to happen.
// No background, no kicker, no giant duplicate title — that's what produced
// the "two top bars" bulk on Meal plan.
// Optional `chips` is a list of short hint pills (e.g. "Uses your profile",
// "Built on recent labs") to reinforce that the tool is personalized.
function HToolHero({ kicker, title, subtitle, chips }) {
  // `title` and `kicker` are accepted for back-compat but intentionally
  // ignored — every tool now relies on HTopBar for the name.
  return (
    <div style={{ padding: '2px 4px 16px' }}>
      {subtitle && (
        <div style={{
          fontFamily: H.body, fontSize: 14, lineHeight: 1.45,
          color: H.fg2, maxWidth: 320,
        }}>{subtitle}</div>
      )}
      {chips && chips.length > 0 && (
        <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6, marginTop: 12 }}>
          {chips.map((c, i) => (
            <span key={i} style={{
              fontFamily: H.body, fontSize: 11, fontWeight: 500,
              padding: '5px 10px', borderRadius: 999,
              background: 'var(--bg-secondary)', color: H.fg2,
              display: 'inline-flex', alignItems: 'center', gap: 5,
            }}>
              <svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"><path d="m5 12 5 5L20 7"/></svg>
              {c}
            </span>
          ))}
        </div>
      )}
    </div>
  );
}

// ──────────────────────────────────────────────────────────────────────────
// Home components
// ──────────────────────────────────────────────────────────────────────────

// Anna prompt card — shows Anna's daily check-in question at top of Home.
function HAnnaPromptCard({ message = 'How would you rate your sleep quality this week?', time = '10:12 PM', date = '17 Apr', onClick }) {
  return (
    <HCard onClick={onClick} style={{ padding: 14, display: 'flex', alignItems: 'center', gap: 12 }}>
      <img src="anna.png" alt="Anna" width="44" height="44" style={{ width: 44, height: 44, borderRadius: 999, objectFit: 'cover', flexShrink: 0 }}/>
      <div style={{ flex: 1, minWidth: 0 }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 6, marginBottom: 2 }}>
          <span style={{ fontFamily: H.body, fontWeight: 500, fontSize: 15, color: H.fg1 }}>Anna</span>
          <span style={{ fontFamily: H.body, fontSize: 12, color: H.fg3 }}>· {date} {time}</span>
        </div>
        <div style={{ fontFamily: H.body, fontSize: 14, lineHeight: 1.35, color: H.fg1, letterSpacing: -0.15 }}>{message}</div>
      </div>
      <HChevron />
    </HCard>
  );
}

// Expandable focus row
function HFocusRow({
  icon, title, status, level = 'normal', color = H.orange, tint, score,
  onClick, expandable = false, expanded: controlled, onToggle,
  metrics, recommendations, ctaLabel = 'Start Chat with Anna',
  onCtaPress, secondary, onSeePlan,
}) {
  const { useState } = React;
  const labels = { normal: 'On track', fair: 'Needs attention', bad: 'Needs attention' };
  const [internal, setInternal] = useState(false);
  const expanded = controlled != null ? controlled : internal;
  const toggle = () => {
    if (!expandable) { onClick && onClick(); return; }
    if (onToggle) onToggle(!expanded); else setInternal(!expanded);
  };
  return (
    <HCard onClick={toggle} style={{ padding: 0, overflow: 'hidden', borderRadius: 20 }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 14, padding: '14px 16px', minHeight: 44 }}>
        <HIconTile color={color} tint={tint} alpha={0.14} size={44} rounded="square">{icon}</HIconTile>
        <div style={{ flex: 1, minWidth: 0, display: 'flex', alignItems: 'center', gap: 8 }}>
          <div style={{
            flex: 1, minWidth: 0,
            fontFamily: H.body, fontWeight: 500, fontSize: 18, lineHeight: '24px',
            color: H.fg1, letterSpacing: -0.3,
            overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap',
          }}>{title}</div>
          <div style={{ display: 'flex', alignItems: 'center', gap: 8, flexShrink: 0 }}>
            <span style={{ fontFamily: H.body, fontSize: 14, color: H.fg2 }}>{status || labels[level]}</span>
            <HStatusDot level={level} />
            {expandable
              ? <HChevron dir={expanded ? 'up' : 'down'} color={H.fg3} />
              : <HChevron dir="right" color={H.fg3} />}
          </div>
        </div>
      </div>
      {expandable && expanded && (
        <div onClick={(e) => e.stopPropagation()} style={{
          padding: '0 12px 12px',
          display: 'flex', flexDirection: 'column', gap: 12,
        }}>
          {metrics && metrics.length > 0 && (
            <div style={{ display: 'flex', flexWrap: 'wrap', gap: 8 }}>
              {metrics.map(m => <HBadge key={m.title} title={m.title} level={m.level} />)}
            </div>
          )}
          {recommendations && recommendations.length > 0 && (
            <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
              {recommendations.map((r, i) => (
                <div key={i} style={{
                  background: H.bgSecondary, borderRadius: 12,
                  padding: 12, minHeight: 36,
                  fontFamily: H.body, fontSize: 14, lineHeight: '20px',
                  color: H.fg1, letterSpacing: -0.15,
                }}>{'\u2022 ' + r}</div>
              ))}
              <div onClick={onSeePlan} style={{
                alignSelf: 'flex-start', display: 'inline-flex', alignItems: 'center', gap: 4,
                padding: '2px 0', color: H.orange,
                fontFamily: H.body, fontSize: 14, fontWeight: 500, cursor: 'pointer',
              }}>
                See full plan
                <HChevron dir="right" color={H.orange} />
              </div>
            </div>
          )}
          <HPrimaryButton
            onClick={onCtaPress}
            style={{
              // Focus-row CTA uses a flatter treatment than the default primary —
              // no outer drop shadow, very subtle text shadow. The expanded card
              // already provides container depth; an additional shadowed pill
              // would fight that.
              boxShadow: 'inset 0 1px 0 rgba(255,255,255,0.30), inset 0 -1px 0 rgba(0,0,0,0.10)',
              textShadow: '0 1px 0 rgba(120,50,20,0.10)',
            }}
            icon={<svg width="20" height="20" viewBox="0 0 20 20" fill="none">
              <path d="M4 6a2 2 0 0 1 2-2h8a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2H9l-3 3v-3H6a2 2 0 0 1-2-2V6z" stroke="#fff" strokeWidth="1.8" strokeLinejoin="round"/>
            </svg>}
          >{ctaLabel}</HPrimaryButton>
          {secondary && (
            <HPrimaryButton type="outline" onClick={secondary.onPress} icon={secondary.icon}>
              {secondary.title}
            </HPrimaryButton>
          )}
        </div>
      )}
    </HCard>
  );
}

// ──────────────────────────────────────────────────────────────────────────
// Recommendations
// ──────────────────────────────────────────────────────────────────────────

function HRecommendationCard({ severity = 'good', title, body, onClick }) {
  // Single-word severity chips. Pinned hard right of the card so chip placement
  // is consistent regardless of how the title wraps. The text column flexes
  // between icon and chip — the title now has room to lay out cleanly without
  // competing with the chip for horizontal space.
  const palette = {
    bad:  { bg: 'var(--error-50)', fg: H.danger,   label: 'Action'  },
    meh:  { bg: '#FFF4E6', fg: '#FF8B2A',  label: 'Improve' },
    good: { bg: '#EAF9ED', fg: H.success,  label: 'Great'   },
  }[severity];
  const icon = severity === 'bad'
    ? <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke={palette.fg} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M12 3 2 20h20Z"/><path d="M12 10v4M12 17v.01"/></svg>
    : severity === 'meh'
    ? <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke={palette.fg} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="9"/><path d="M12 7v5M12 16v.01"/></svg>
    : <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke={palette.fg} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M5 13l4 4L19 7"/></svg>;
  return (
    <HCard onClick={onClick} style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
      <div style={{ width: 36, height: 36, borderRadius: 999, background: palette.bg, display: 'grid', placeItems: 'center', flexShrink: 0 }}>{icon}</div>
      <div style={{ flex: 1, minWidth: 0 }}>
        <div style={{
          fontFamily: H.body, fontWeight: 600, fontSize: 15, letterSpacing: -0.2,
          lineHeight: 1.3, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis',
        }}>{title}</div>
        {body && <div style={{
          fontFamily: H.body, fontSize: 13, color: H.fg2, marginTop: 3, lineHeight: 1.4,
          display: '-webkit-box', WebkitLineClamp: 2, WebkitBoxOrient: 'vertical',
          overflow: 'hidden',
        }}>{body}</div>}
      </div>
      <span style={{
        fontFamily: H.body, fontWeight: 500, fontSize: 11, letterSpacing: 0.4,
        textTransform: 'uppercase', color: palette.fg, background: palette.bg,
        padding: '5px 10px', borderRadius: 999, flexShrink: 0, alignSelf: 'center',
      }}>{palette.label}</span>
    </HCard>
  );
}

// ──────────────────────────────────────────────────────────────────────────
// Chat
// ──────────────────────────────────────────────────────────────────────────

function HAnnaAvatar({ size = 32 }) {
  return (
    <img src="anna.png" alt="Anna" width={size} height={size} style={{
      width: size, height: size, borderRadius: 999, objectFit: 'cover',
      boxShadow: '0 1px 3px rgba(3,4,13,0.08), 0 0 0 0.5px rgba(3,4,13,0.04)',
      flexShrink: 0,
    }} />
  );
}

function HTypingIndicator() {
  return (
    <div style={{
      display: 'inline-flex', alignItems: 'center', gap: 6,
      background: H.surface, padding: '14px 16px',
      borderRadius: 20, borderBottomLeftRadius: 4,
      boxShadow: '0 2px 8px rgba(3,4,13,0.05), 0 0 0 0.5px rgba(3,4,13,0.03)',
    }}>
      {[0, 100, 200].map(d => (
        <span key={d} style={{
          width: 6, height: 6, borderRadius: 999, background: H.fg3,
          animation: 'hTyping 750ms cubic-bezier(.4,0,.6,1) infinite',
          animationDelay: `${d}ms`, display: 'inline-block',
        }} />
      ))}
      <style>{`@keyframes hTyping {
        0%,40%,100% { transform: scale(1); opacity: 0.55; }
        20% { transform: scale(1.2); opacity: 1; }
      }`}</style>
    </div>
  );
}

// ──────────────────────────────────────────────────────────────────────────
// Tab bar + brand mark
// ──────────────────────────────────────────────────────────────────────────

function HealifyMark({ size = 58 }) {
  return (
    <svg width={size} height={size} viewBox="0 0 65 65" fill="none" xmlns="http://www.w3.org/2000/svg" style={{ display: 'block' }}>
      <defs>
        <radialGradient id="hm-bg" cx="32" cy="22" r="42" gradientUnits="userSpaceOnUse">
          <stop offset="0" stopColor="#23232C"/>
          <stop offset="1" stopColor="var(--brand-ink)"/>
        </radialGradient>
        <linearGradient id="hm-petal-big" x1="38" y1="17" x2="38" y2="52" gradientUnits="userSpaceOnUse">
          <stop stopColor="#FFFFFF"/><stop offset="1" stopColor="#FEF2E8"/>
        </linearGradient>
        <linearGradient id="hm-petal-sm" x1="23" y1="17" x2="23" y2="39" gradientUnits="userSpaceOnUse">
          <stop stopColor="#FFFFFF"/><stop offset="1" stopColor="#FEF2E8"/>
        </linearGradient>
      </defs>
      <circle cx="32.87" cy="32.82" r="32" fill="url(#hm-bg)"/>
      <circle cx="32.87" cy="32.82" r="31.5" fill="none" stroke="rgba(255,255,255,0.18)"/>
      <path d="M50.17 20.17C46.89 16.90 41.59 16.84 38.23 20.04L25.29 32.38C22.22 35.30 22.17 40.16 25.17 43.15L34.35 52.30V49.07C34.35 48.09 34.74 47.15 35.43 46.46L45.84 36.10L49.85 32.50C53.48 29.23 53.63 23.61 50.17 20.17Z" fill="url(#hm-petal-big)"/>
      <path d="M32.43 22.28L23.34 30.92C21.13 33.01 20.23 35.95 20.65 38.73L16.59 34.46C12.88 30.56 12.98 24.44 16.81 20.66C20.79 16.73 27.24 16.83 31.10 20.88L32.43 22.28Z" fill="url(#hm-petal-sm)"/>
    </svg>
  );
}

function HTabBar({ tab = 'home', onChange, showActivityDot = false }) {
  const TabIcon = ({ k, active }) => {
    const color = active ? H.orange : H.fg2;
    const common = { width: 22, height: 22, viewBox: '0 0 24 24', fill: 'none', stroke: color, strokeWidth: active ? 2.2 : 1.8, strokeLinecap: 'round', strokeLinejoin: 'round' };
    if (k === 'home') return active
      ? <svg width="22" height="22" viewBox="0 0 24 24" fill={color}><path d="M3.5 10.5 12 3l8.5 7.5V20a1 1 0 0 1-1 1h-5v-6h-5v6H4.5a1 1 0 0 1-1-1Z"/></svg>
      : <svg {...common}><path d="M3.5 10.5 12 3l8.5 7.5V20a1 1 0 0 1-1 1h-5v-6h-5v6H4.5a1 1 0 0 1-1-1Z"/></svg>;
    if (k === 'health') return <svg {...common}><path d="M3 12h3l2-5 4 10 2-6 2 3h5"/></svg>;
    if (k === 'nutrition') return <svg {...common}><path d="M6 3v5a2 2 0 0 0 2 2h1v11h2V10h1a2 2 0 0 0 2-2V3M8 3v5M12 3v5M18 3c-1.5 1-2.5 3-2.5 5v4H18v9"/></svg>;
    if (k === 'fitness') return <svg {...common}><path d="M20.8 6.6A5.5 5.5 0 0 0 13 6.5a5.5 5.5 0 0 0-7.8 7.8L12 21l6.8-6.7a5.5 5.5 0 0 0 2-7.7Z"/><path d="M4 12h3l2-3 3 6 2-4 2 2h4"/></svg>;
    // AI Tools — magic sparkle (one large 4-point star + a small companion).
    // The canonical "AI" glyph: Gemini / Apple Intelligence / Notion AI shape.
    // Filled when picker is open, stroked otherwise.
    if (k === 'tools') {
      const big = "M14 3l1.05 3.95a2 2 0 0 0 1.5 1.5L20.5 9.5l-3.95 1.05a2 2 0 0 0-1.5 1.5L14 16l-1.05-3.95a2 2 0 0 0-1.5-1.5L7.5 9.5l3.95-1.05a2 2 0 0 0 1.5-1.5L14 3z";
      const small = "M5.5 14.5l.55 1.5a1 1 0 0 0 .95.95l1.5.55-1.5.55a1 1 0 0 0-.95.95L5.5 20l-.55-1.5a1 1 0 0 0-.95-.95L2.5 17l1.5-.55a1 1 0 0 0 .95-.95L5.5 14.5z";
      return active
        ? <svg width="22" height="22" viewBox="0 0 24 24" fill={color}><path d={big}/><path d={small}/></svg>
        : <svg {...common}><path d={big}/><path d={small}/></svg>;
    }
    // Settings — gear icon. Tap navigates to settings from any tab.
    if (k === 'settings') return <svg {...common}><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 1 1-4 0v-.09a1.65 1.65 0 0 0-1-1.51 1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 1 1 0-4h.09a1.65 1.65 0 0 0 1.51-1 1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 1 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 1 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z"/></svg>;
    return null;
  };
  const Tab = ({ k, dot = false }) => {
    const active = tab === k;
    return (
      <div onClick={() => onChange && onChange(k)} style={{
        position: 'relative', flex: 1, alignSelf: 'stretch', cursor: 'pointer',
        display: 'flex', alignItems: 'center', justifyContent: 'center',
        padding: 4, margin: 4, borderRadius: 999,
        background: active ? 'var(--quartz-soft-bg)' : 'transparent',
        transition: 'background 160ms',
      }}>
        <TabIcon k={k} active={active} />
        {dot && (
          <span style={{
            position: 'absolute', top: 8, right: 14,
            width: 8, height: 8, borderRadius: 999,
            background: H.danger, border: '1.5px solid #fff',
          }}/>
        )}
      </div>
    );
  };
  const chatActive = tab === 'chat';
  // Long-press detection on the FAB. Tap → open Anna chat (primary action,
  // your always-available health coach). Long-press OR swipe-up → spawn the
  // AI Tools picker (secondary). The chevron handle above the FAB cues both
  // affordances. Pattern echoes iOS Action Button + Arc dial + Notion center
  // bubble — primary destination gets the prime slot; tools are one gesture away.
  const pressTimer = React.useRef(null);
  const longFired = React.useRef(false);
  const startY = React.useRef(0);
  const handleStart = (clientY) => {
    longFired.current = false;
    startY.current = clientY;
    pressTimer.current = setTimeout(() => {
      longFired.current = true;
      onChange && onChange('tools');
    }, 320);
  };
  const handleMove = (clientY) => {
    if (!pressTimer.current) return;
    if (startY.current - clientY > 24) {
      clearTimeout(pressTimer.current); pressTimer.current = null;
      longFired.current = true;
      onChange && onChange('tools');
    }
  };
  const handleEnd = () => {
    if (pressTimer.current) { clearTimeout(pressTimer.current); pressTimer.current = null; }
    if (!longFired.current) onChange && onChange('chat');
  };
  return (
    <div style={{
      position: 'absolute', left: 20, right: 20, bottom: 34,
      background: '#fff', borderRadius: 999,
      padding: '0 4px', height: 64, boxSizing: 'border-box',
      border: '1px solid rgba(3,4,13,0.04)',
      boxShadow: '0 8px 17px rgba(166,166,166,0.10), 0 31px 31px rgba(166,166,166,0.09), 0 70px 42px rgba(166,166,166,0.05)',
      display: 'flex', alignItems: 'center', gap: 0, zIndex: 40,
    }}>
      <Tab k="home" />
      <Tab k="health" dot={showActivityDot} />
      <div style={{ width: 76, position: 'relative', alignSelf: 'stretch', flexShrink: 0, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
        {/* Swipe-up handle — chevron + 'Tools' microcopy on hold/swipe-up */}
        <div aria-hidden="true" style={{
          position: 'absolute', top: -16, left: '50%', transform: 'translateX(-50%)',
          width: 28, height: 4, borderRadius: 999, background: 'rgba(3,4,13,0.18)',
        }}/>
        <div
          onMouseDown={(e) => handleStart(e.clientY)}
          onMouseMove={(e) => handleMove(e.clientY)}
          onMouseUp={handleEnd}
          onMouseLeave={() => { if (pressTimer.current) { clearTimeout(pressTimer.current); pressTimer.current = null; } }}
          onTouchStart={(e) => handleStart(e.touches[0].clientY)}
          onTouchMove={(e) => handleMove(e.touches[0].clientY)}
          onTouchEnd={handleEnd}
          role="button"
          aria-label="Talk to Anna · long-press for AI tools"
          style={{
            position: 'relative', width: 56, height: 56, borderRadius: 999, cursor: 'pointer',
            transform: chatActive ? 'scale(0.96)' : 'scale(1)', transition: 'transform 160ms',
            boxShadow: '0 6px 14px rgba(3,4,13,0.18)',
          }}
        >
          <HealifyMark size={56} />
          {/* Active speaking indicator — small chat dot pulses when Anna has
              an unread reply. Replaces the prior sparkle which falsely cued
              'tool launcher'. */}
          {showActivityDot && (
            <div style={{
              position: 'absolute', top: -1, right: -1,
              width: 14, height: 14, borderRadius: 999,
              background: '#22C55E', border: '2px solid #fff',
              boxShadow: '0 1px 2px rgba(3,4,13,0.18)',
            }}/>
          )}
        </div>
      </div>
      <Tab k="nutrition" />
      <Tab k="fitness" />
    </div>
  );
}

// ──────────────────────────────────────────────────────────────────────────
// Focus area icons (filled)
// ──────────────────────────────────────────────────────────────────────────

const HIcons = {
  sleep: (c = H.orange) => (
    <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke={c} strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round">
      <path d="M3 18v-6a3 3 0 0 1 3-3h6a4 4 0 0 1 4 4v5M3 18h18M3 18v2M21 16v4" fill={c} fillOpacity="0.15"/>
      <path d="M16 4a3 3 0 0 0 3 3 3 3 0 0 1-3 3 3 3 0 0 1-3-3 3 3 0 0 0 3-3z"/>
    </svg>
  ),
  fitness: (c = H.orange) => (
    <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke={c} strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round">
      <path d="M20.8 6.6A5.5 5.5 0 0 0 13 6.5a5.5 5.5 0 0 0-7.8 7.8L12 21l6.8-6.7a5.5 5.5 0 0 0 2-7.7Z" fill={c} fillOpacity="0.12"/>
      <path d="M4 12h3l2-3 3 6 2-4 2 2h4"/>
    </svg>
  ),
  vitals: (c = H.orange) => (
    <svg width="22" height="22" viewBox="0 0 24 24" fill={c} stroke={c} strokeWidth="1.4" strokeLinejoin="round">
      <path d="M12 3s-6 6.5-6 11a6 6 0 0 0 12 0c0-4.5-6-11-6-11Z"/>
    </svg>
  ),
  mind: (c = H.orange) => (
    <svg width="22" height="22" viewBox="0 0 24 24" fill={c} fillOpacity="0.18" stroke={c} strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round">
      <path d="M5 13c0-5 4-9 9-9 2 0 4 1 5 2-1 5-3 9-6 11-3 2-6 2-8 0-1-1-1-2 0-4z"/>
      <path d="M5 19c3-3 6-5 9-6" fill="none"/>
    </svg>
  ),
  // Legacy aliases
  activity: (c = H.orange) => HIcons.fitness(c),
  nutrition: (c = H.orange) => <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke={c} strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><path d="M6 3v5a2 2 0 0 0 2 2h1v11h2V10h1a2 2 0 0 0 2-2V3M8 3v5M12 3v5M18 3c-1.5 1-2.5 3-2.5 5v4H18v9"/></svg>,
  heart: (c = H.orange) => HIcons.vitals(c),
  mental: (c = H.orange) => HIcons.mind(c),
  alert: (c = H.danger) => <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke={c} strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><path d="M12 3 2 20h20Z"/><path d="M12 10v4M12 17v.01"/></svg>,
};

// ──────────────────────────────────────────────────────────────────────────
// Focus areas data (shared across screens)
// ──────────────────────────────────────────────────────────────────────────

const FOCUS_AREAS = [
  { k: 'sleep',   name: 'Sleep',   color: 'var(--focus-sleep-100)', tint: 'var(--focus-sleep-50)', icon: HIcons.sleep,   level: 'normal', val: 72, status: 'Normal' },
  { k: 'fitness', name: 'Fitness', color: 'var(--focus-fitness-100)', tint: 'var(--focus-fitness-50)', icon: HIcons.fitness, level: 'normal', val: 68, status: 'Normal' },
  { k: 'vitals',  name: 'Vitals',  color: 'var(--focus-heart-100)', tint: 'var(--error-100)', icon: HIcons.vitals,  level: 'fair',   val: 52, status: 'Fair'   },
  { k: 'mind',    name: 'Mind',    color: 'var(--focus-mental-100)', tint: '#DAF1F0', icon: HIcons.mind,    level: 'normal', val: 74, status: 'Normal' },
];

// ──────────────────────────────────────────────────────────────────────────
// Settings list (iOS-style grouped row)
// ──────────────────────────────────────────────────────────────────────────

function HSettingsRow({ icon, title, detail, toggle, toggleOn, onClick, isLast = false, destructive = false }) {
  return (
    <div onClick={onClick} style={{
      display: 'flex', alignItems: 'center', gap: 12, padding: '14px 16px',
      borderBottom: isLast ? 'none' : '0.5px solid ' + H.border,
      cursor: onClick ? 'pointer' : 'default',
    }}>
      {icon}
      <div style={{ flex: 1, fontFamily: H.body, fontSize: 15, color: destructive ? H.danger : H.fg1 }}>{title}</div>
      {detail != null && <span style={{ fontFamily: H.body, fontSize: 14, color: H.fg2 }}>{detail}</span>}
      {toggle != null && (
        <div style={{
          width: 44, height: 26, borderRadius: 999,
          background: toggleOn ? H.success : '#D1D5DB',
          padding: 2, boxSizing: 'border-box',
          transition: 'background 160ms',
        }}>
          <div style={{
            width: 22, height: 22, borderRadius: 999, background: '#fff',
            transform: toggleOn ? 'translateX(18px)' : 'translateX(0)',
            transition: 'transform 160ms',
            boxShadow: '0 1px 3px rgba(0,0,0,0.2)',
          }}/>
        </div>
      )}
      {onClick && toggle == null && detail == null && <HChevron />}
    </div>
  );
}

function HSettingsGroup({ children, title }) {
  return (
    <div style={{ marginBottom: 18 }}>
      {title && <HSectionLabel style={{ margin: '0 4px 10px' }}>{title}</HSectionLabel>}
      <div style={{ background: '#fff', borderRadius: 16, overflow: 'hidden', boxShadow: '0 1px 2px rgba(3,4,13,0.04)' }}>{children}</div>
    </div>
  );
}

// ──────────────────────────────────────────────────────────────────────────
// Export
// ──────────────────────────────────────────────────────────────────────────

Object.assign(window, {
  H, HCard, HIconTile, HStatusDot, HChevron, HBadge, HPrimaryButton, HBackButton,
  HGreetingHeader, HSectionLabel, HTopBar,
  HAnnaPromptCard, HFocusRow, HRecommendationCard,
  HAnnaAvatar, HTypingIndicator,
  HealifyMark, HTabBar,
  HIcons, FOCUS_AREAS,
  HSettingsRow, HSettingsGroup,
});
