// 22hrs — shared UI primitives
// Dark-first. All sizes assume a ~390px viewport.
const { useState, useEffect, useRef } = React;

// ──────────────────────────────────────────────
// Brand: case glyph (the device, drawn for SVG use)
// ──────────────────────────────────────────────
function CaseGlyph({ size = 120, glow = false, lid = 'closed' }) {
  // Photoreal case mockup. Image is pre-cropped to a tight bbox around the
  // device (725×424, aspect 1.71) so the device naturally sits centered in
  // its bounding box — no transform tricks needed.
  const aspect = 725 / 424;
  const h = size / aspect;
  return (
    <div style={{
      position: 'relative',
      width: size,
      height: h,
      pointerEvents: 'none',
      isolation: 'isolate'
    }}>
      <img
        src="assets/case-mockup.png"
        alt=""
        draggable={false}
        style={{
          width: '100%', height: '100%', display: 'block',
          filter: `drop-shadow(0 ${Math.round(size * 0.04)}px ${Math.round(size * 0.06)}px rgba(0,0,0,0.55))`,
          userSelect: 'none', WebkitUserDrag: 'none'
        }} />
      {lid === 'scanning' &&
      <span aria-hidden style={{
        position: 'absolute',
        left: '53.4%', top: '25%',
        width: Math.max(size * 0.09, 8),
        height: Math.max(size * 0.09, 8),
        transform: 'translate(-50%, -50%)',
        borderRadius: '50%',
        boxShadow: '0 0 0 1.5px rgba(31,184,224,0.9), 0 0 14px 3px rgba(60,191,158,0.55)',
        animation: 'pp-pulse 1.6s ease-out infinite',
        zIndex: 2
      }} />
      }
    </div>);
}

// ──────────────────────────────────────────────
// The wear-time ring (hero)
// pct 0–100, draws stroke-dashoffset over duration-pour
// ──────────────────────────────────────────────
function WearRing({ pct = 97, size = 280, primary = '#FFFFFF', accent = 'gradient', label = 'TODAY', children, animateIn = true }) {
  const r = size * 0.42;
  const sw = size * 0.052;
  const c = 2 * Math.PI * r;
  const target = c * (1 - Math.min(pct, 100) / 100);
  const [off, setOff] = useState(animateIn ? c : target);
  useEffect(() => {
    if (!animateIn) {setOff(target);return;}
    const t = setTimeout(() => setOff(target), 60);
    return () => clearTimeout(t);
  }, [target, animateIn]);
  const cx = size / 2,cy = size / 2;
  const stroke = accent === 'gradient' ? 'url(#wr-grad)' : accent;
  const met = pct >= 100;

  return (
    <div style={{ position: 'relative', width: size, height: size }}>
      <svg width={size} height={size} viewBox={`0 0 ${size} ${size}`} style={{ display: 'block' }}>
        <defs>
          <linearGradient id="wr-grad" x1="0%" y1="0%" x2="100%" y2="100%">
            <stop offset="0%" stopColor="#1FB8E0" />
            <stop offset="100%" stopColor="#3CBF9E" />
          </linearGradient>
          {met &&
          <filter id="wr-glow" x="-30%" y="-30%" width="160%" height="160%">
              <feGaussianBlur stdDeviation="6" />
            </filter>
          }
        </defs>
        {met && <circle cx={cx} cy={cy} r={r} fill="none" stroke="url(#wr-grad)" strokeWidth={sw} opacity="0.35" filter="url(#wr-glow)" />}
        <circle cx={cx} cy={cy} r={r} fill="none" stroke="var(--t-ring-track)" strokeWidth={sw} />
        <circle cx={cx} cy={cy} r={r} fill="none" stroke={stroke} strokeWidth={sw} strokeLinecap="round"
        strokeDasharray={c} strokeDashoffset={off}
        transform={`rotate(-90 ${cx} ${cy})`}
        style={{ transition: 'stroke-dashoffset 900ms cubic-bezier(0.22, 0.61, 0.36, 1)' }} />
        {/* tick at 100% (top) */}
        <circle cx={cx} cy={cy - r} r={sw * 0.6} fill="var(--t-ring-tick)" />
      </svg>
      <div style={{ position: 'absolute', inset: 0, display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', textAlign: 'center' }}>
        {children}
      </div>
    </div>);

}

// ──────────────────────────────────────────────
// Status pill (Listening / Synced / Out of range)
// ──────────────────────────────────────────────
function StatusPill({ status = 'listening' }) {
  const map = {
    listening: { label: 'Case listening', dot: '#3CBF9E', bg: 'rgba(60,191,158,0.12)', fg: '#5FCFB2', pulse: true },
    synced: { label: 'Synced just now', dot: '#1FB8E0', bg: 'rgba(31,184,224,0.12)', fg: '#4FCBE8' },
    outofrange: { label: 'Out of range', dot: '#9BA1AB', bg: 'rgba(155,161,171,0.10)', fg: '#9BA1AB' },
    wearing: { label: 'Wearing now', dot: '#3CBF9E', bg: 'rgba(60,191,158,0.12)', fg: '#5FCFB2', pulse: true }
  };
  const s = map[status];
  return (
    <div style={{ display: 'inline-flex', alignItems: 'center', gap: 8, padding: '7px 12px 7px 10px', borderRadius: 999, background: s.bg, color: s.fg, fontSize: 12, fontWeight: 500, letterSpacing: '-0.005em' }}>
      <span style={{ position: 'relative', width: 8, height: 8 }}>
        <span style={{ position: 'absolute', inset: 0, borderRadius: '50%', background: s.dot }} />
        {s.pulse && <span style={{ position: 'absolute', inset: -4, borderRadius: '50%', background: s.dot, opacity: 0.35, animation: 'pp-pulse 1.6s ease-out infinite' }} />}
      </span>
      {s.label}
    </div>);

}

// ──────────────────────────────────────────────
// Eyebrow / kicker label
// ──────────────────────────────────────────────
function Eyebrow({ children, color, style = {} }) {
  return <div style={{ fontSize: 10.5, letterSpacing: '0.18em', textTransform: 'uppercase', fontWeight: 500, color: color || 'var(--t-fg-3)', ...style }}>{children}</div>;
}

// ──────────────────────────────────────────────
// Buttons
// ──────────────────────────────────────────────
function Btn({ children, variant = 'primary', block = false, onClick, disabled = false, leading, trailing, style = {} }) {
  const base = {
    display: 'inline-flex', alignItems: 'center', justifyContent: 'center', gap: 8,
    fontFamily: 'inherit', fontWeight: 500, fontSize: 15, letterSpacing: '-0.005em',
    border: 0, cursor: disabled ? 'not-allowed' : 'pointer', padding: '15px 20px',
    borderRadius: 14, transition: 'transform 80ms ease, background 160ms ease, color 160ms ease, opacity 160ms',
    width: block ? '100%' : undefined,
    opacity: disabled ? 0.4 : 1
  };
  const variants = {
    primary: { background: 'var(--t-btn-primary-bg)', color: 'var(--t-btn-primary-fg)' },
    primaryBrand: { background: '#1FB8E0', color: '#FFFFFF' },
    quiet: { background: 'var(--t-quiet)', color: 'var(--t-fg-1)' },
    ghost: { background: 'transparent', color: 'var(--t-fg-1)' },
    outline: { background: 'transparent', color: 'var(--t-fg-1)', boxShadow: 'inset 0 0 0 1px var(--t-border-strong)' }
  };
  const [press, setPress] = useState(false);
  return (
    <button
      onMouseDown={() => setPress(true)} onMouseUp={() => setPress(false)} onMouseLeave={() => setPress(false)}
      onTouchStart={() => setPress(true)} onTouchEnd={() => setPress(false)}
      onClick={disabled ? undefined : onClick}
      style={{ ...base, ...variants[variant], transform: press ? 'scale(0.97)' : 'scale(1)', ...style }}>
      {leading}
      {children}
      {trailing}
    </button>);

}

// ──────────────────────────────────────────────
// Text input
// ──────────────────────────────────────────────
function Field({ label, type = 'text', value, onChange, placeholder, autoFocus, trailing }) {
  const [focus, setFocus] = useState(false);
  return (
    <label style={{ display: 'block' }}>
      <div style={{ fontSize: 12, letterSpacing: '0.04em', color: 'var(--t-fg-3)', marginBottom: 8, fontWeight: 500, textTransform: 'uppercase' }}>{label}</div>
      <div style={{
        display: 'flex', alignItems: 'center', gap: 8,
        background: 'var(--t-input-bg)',
        borderRadius: 12,
        padding: '14px 14px',
        boxShadow: focus ? '0 0 0 1.5px #1FB8E0, inset 0 0 0 1px rgba(31,184,224,0.4)' : 'inset 0 0 0 1px var(--t-input-stroke)',
        transition: 'box-shadow 160ms'
      }}>
        <input
          type={type} value={value} onChange={(e) => onChange?.(e.target.value)} placeholder={placeholder} autoFocus={autoFocus}
          onFocus={() => setFocus(true)} onBlur={() => setFocus(false)}
          style={{ flex: 1, background: 'transparent', color: 'var(--t-fg-1)', border: 0, outline: 'none', fontFamily: 'inherit', fontSize: 15, padding: 0 }} />
        
        {trailing}
      </div>
    </label>);

}

// ──────────────────────────────────────────────
// Card
// ──────────────────────────────────────────────
function Card({ children, padding = 18, style = {} }) {
  return <div style={{ background: 'var(--t-bg-card)', borderRadius: 16, padding, boxShadow: 'var(--t-card-shadow)', ...style }}>{children}</div>;
}

// ──────────────────────────────────────────────
// Sonar — concentric pulse rings (used during scan)
// ──────────────────────────────────────────────
function Sonar({ size = 280, color = '#1FB8E0' }) {
  return (
    <div style={{ position: 'relative', width: size, height: size, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
      {[0, 0.7, 1.4, 2.1].map((d, i) =>
      <span key={i} style={{
        position: 'absolute', inset: 0, borderRadius: '50%',
        boxShadow: `0 0 0 1.5px ${color}`,
        opacity: 0,
        animation: `pp-sonar 2.8s ease-out ${d}s infinite`
      }} />
      )}
    </div>);

}

// ──────────────────────────────────────────────
// 24h timeline strip (today's wear pattern)
// segments: [{startMin, endMin, type: 'wearing' | 'gap'}]
// ──────────────────────────────────────────────
function DayTimeline({ segments, now = 18 * 60 }) {
  const total = 24 * 60;
  return (
    <div>
      <div style={{ position: 'relative', height: 36, borderRadius: 8, background: 'var(--t-track)', overflow: 'hidden' }}>
        {segments.map((s, i) => {
          if (s.type !== 'wearing') return null;
          const left = s.startMin / total * 100;
          const width = (s.endMin - s.startMin) / total * 100;
          return (
            <div key={i} style={{
              position: 'absolute', top: 6, bottom: 6, left: left + '%', width: width + '%',
              background: 'linear-gradient(180deg,#3CBF9E,#2E9B80)', borderRadius: 4
            }} />);

        })}
        {/* now indicator */}
        <div style={{ position: 'absolute', top: -2, bottom: -2, left: `${now / total * 100}%`, width: 1.5, background: 'var(--t-now-line)', boxShadow: 'var(--t-now-glow)' }} />
      </div>
      <div style={{ display: 'flex', justifyContent: 'space-between', marginTop: 8, fontSize: 10, color: 'var(--t-fg-3)', letterSpacing: '0.04em', fontVariantNumeric: 'tabular-nums' }}>
        <span>12a</span><span>6a</span><span>12p</span><span>6p</span><span>12a</span>
      </div>
    </div>);

}

// ──────────────────────────────────────────────
// Mini sparkline / trend bars (week)
// ──────────────────────────────────────────────
function MiniBars({ values = [], target = 22, height = 38 }) {
  return (
    <div style={{ display: 'flex', alignItems: 'flex-end', gap: 4, height }}>
      {values.map((v, i) => {
        const h = Math.min(v / 24 * 100, 100);
        const met = v >= target;
        const today = i === values.length - 1;
        return (
          <div key={i} style={{ flex: 1, height: '100%', display: 'flex', flexDirection: 'column', justifyContent: 'flex-end' }}>
            <div style={{
              height: h + '%',
              background: met ? 'linear-gradient(180deg,#3CBF9E,#2E9B80)' : 'var(--t-bar-empty)',
              borderRadius: 3,
              outline: today ? '1.5px solid var(--t-now-line)' : 'none',
              outlineOffset: 1
            }} />
          </div>);

      })}
    </div>);

}

// ──────────────────────────────────────────────
// Global keyframes (drop once at the page root)
// ──────────────────────────────────────────────
const protoCSS = `
@keyframes pp-pulse { 0%{transform:scale(1);opacity:0.4} 100%{transform:scale(2.2);opacity:0} }
@keyframes pp-sonar { 0%{transform:scale(0.4);opacity:0.0} 15%{opacity:0.7} 100%{transform:scale(1);opacity:0} }
@keyframes pp-fade { from{opacity:0;transform:translateY(8px)} to{opacity:1;transform:translateY(0)} }
@keyframes pp-fade-fast { from{opacity:0} to{opacity:1} }
@keyframes pp-spin { to{transform:rotate(360deg)} }
@keyframes pp-bob { 0%,100%{transform:translateY(0)} 50%{transform:translateY(-6px)} }
@keyframes pp-tick { 0%{stroke-dashoffset:24} 100%{stroke-dashoffset:0} }

/* Theme tokens — dark default */
[data-theme] {
  --t-fg-1: #FFFFFF;
  --t-fg-2: #C0C5CD;
  --t-fg-3: #9BA1AB;
  --t-fg-muted: #6B7280;
  --t-bg-app: #0E1014;
  --t-bg-card: #1A1D23;
  --t-quiet: rgba(255,255,255,0.06);
  --t-quiet-2: rgba(255,255,255,0.04);
  --t-quiet-3: rgba(255,255,255,0.08);
  --t-border: rgba(255,255,255,0.06);
  --t-border-2: rgba(255,255,255,0.04);
  --t-border-strong: rgba(255,255,255,0.16);
  --t-divider: rgba(255,255,255,0.06);
  --t-divider-soft: rgba(255,255,255,0.04);
  --t-card-shadow: inset 0 0 0 1px rgba(255,255,255,0.04);
  --t-card-tint: rgba(255,255,255,0.02);
  --t-input-bg: rgba(255,255,255,0.04);
  --t-input-stroke: rgba(255,255,255,0.08);
  --t-placeholder: rgba(255,255,255,0.32);
  --t-btn-primary-bg: #FFFFFF;
  --t-btn-primary-fg: #0E1014;
  --t-pill-active-bg: #FFFFFF;
  --t-pill-active-fg: #0E1014;
  --t-tabbar-bg: rgba(14,16,20,0.85);
  --t-tabbar-border: rgba(255,255,255,0.06);
  --t-tab-inactive: #6B7280;
  --t-sticky-grad: linear-gradient(180deg, rgba(14,16,20,0.92) 0%, rgba(14,16,20,0.7) 80%, rgba(14,16,20,0));
  --t-track: rgba(255,255,255,0.04);
  --t-bar-track: rgba(255,255,255,0.08);
  --t-bar-empty: rgba(255,255,255,0.18);
  --t-now-line: #FFFFFF;
  --t-now-glow: 0 0 8px rgba(255,255,255,0.6);
  --t-ring-track: rgba(255,255,255,0.08);
  --t-ring-tick: rgba(255,255,255,0.18);
  --t-checkbox-stroke: rgba(255,255,255,0.18);
  --t-checkbox-tick: #0E1014;
  --t-toggle-off: rgba(255,255,255,0.12);
  --t-icon-faint: rgba(255,255,255,0.32);
  --t-icon-faint-fill: rgba(255,255,255,0.16);
  --t-unread-tint: rgba(31,184,224,0.06);
  --t-info-tint-bg: rgba(31,184,224,0.06);
  --t-info-tint-stroke: rgba(31,184,224,0.22);
  --t-status-bullet-ring: #1A1D23;
  --t-shadow-card-soft: none;
}
[data-theme="light"] {
  --t-fg-1: #1A1D23;
  --t-fg-2: #4B5563;
  --t-fg-3: #6B7280;
  --t-fg-muted: #8A8F99;
  --t-bg-app: #F3F5F8;
  --t-bg-card: #FFFFFF;
  --t-quiet: rgba(15,18,23,0.05);
  --t-quiet-2: rgba(15,18,23,0.035);
  --t-quiet-3: rgba(15,18,23,0.08);
  --t-border: rgba(15,18,23,0.08);
  --t-border-2: rgba(15,18,23,0.06);
  --t-border-strong: rgba(15,18,23,0.14);
  --t-divider: rgba(15,18,23,0.08);
  --t-divider-soft: rgba(15,18,23,0.06);
  --t-card-shadow: 0 1px 2px rgba(15,18,23,0.04), inset 0 0 0 1px rgba(15,18,23,0.06);
  --t-card-tint: rgba(15,18,23,0.02);
  --t-input-bg: #FFFFFF;
  --t-input-stroke: rgba(15,18,23,0.14);
  --t-placeholder: rgba(15,18,23,0.36);
  --t-btn-primary-bg: #1A1D23;
  --t-btn-primary-fg: #FFFFFF;
  --t-pill-active-bg: #1A1D23;
  --t-pill-active-fg: #FFFFFF;
  --t-tabbar-bg: rgba(255,255,255,0.92);
  --t-tabbar-border: rgba(15,18,23,0.08);
  --t-tab-inactive: #6B7280;
  --t-sticky-grad: linear-gradient(180deg, rgba(243,245,248,0.94) 0%, rgba(243,245,248,0.7) 80%, rgba(243,245,248,0));
  --t-track: rgba(15,18,23,0.05);
  --t-bar-track: rgba(15,18,23,0.08);
  --t-bar-empty: rgba(15,18,23,0.14);
  --t-now-line: #1A1D23;
  --t-now-glow: 0 0 6px rgba(15,18,23,0.25);
  --t-ring-track: rgba(15,18,23,0.08);
  --t-ring-tick: rgba(15,18,23,0.18);
  --t-checkbox-stroke: rgba(15,18,23,0.22);
  --t-checkbox-tick: #FFFFFF;
  --t-toggle-off: rgba(15,18,23,0.14);
  --t-icon-faint: rgba(15,18,23,0.32);
  --t-icon-faint-fill: rgba(15,18,23,0.18);
  --t-unread-tint: rgba(31,184,224,0.07);
  --t-info-tint-bg: rgba(31,184,224,0.06);
  --t-info-tint-stroke: rgba(31,184,224,0.22);
  --t-status-bullet-ring: #FFFFFF;
}

.pp-screen { animation: pp-fade 420ms cubic-bezier(0.22, 0.61, 0.36, 1); box-sizing: border-box; }
.pp-screen *, .pp-screen *::before, .pp-screen *::after { box-sizing: border-box; }
.pp-screen-fast { animation: pp-fade-fast 220ms ease-out; }
input::placeholder { color: var(--t-placeholder); }
* { -webkit-tap-highlight-color: transparent; }
`;
function ProtoStyle() {return <style dangerouslySetInnerHTML={{ __html: protoCSS }} />;}

// ──────────────────────────────────────────────
// Big check (success state)
// ──────────────────────────────────────────────
function BigCheck({ size = 96 }) {
  return (
    <svg width={size} height={size} viewBox="0 0 96 96" fill="none">
      <defs>
        <linearGradient id="bc-g" x1="0" y1="0" x2="1" y2="1">
          <stop offset="0%" stopColor="#1FB8E0" />
          <stop offset="100%" stopColor="#3CBF9E" />
        </linearGradient>
      </defs>
      <circle cx="48" cy="48" r="46" stroke="url(#bc-g)" strokeWidth="1.5" fill="rgba(60,191,158,0.08)" />
      <path d="M30 49 L43 62 L67 36" stroke="url(#bc-g)" strokeWidth="3.5" strokeLinecap="round" strokeLinejoin="round" fill="none"
      strokeDasharray="60" style={{ animation: 'pp-tick 600ms cubic-bezier(0.22, 0.61, 0.36, 1) forwards' }} />
    </svg>);

}

// ──────────────────────────────────────────────
// Battery glyph
// ──────────────────────────────────────────────
function Battery({ pct = 84, w = 38 }) {
  const fill = pct < 20 ? '#E5484D' : '#3CBF9E';
  return (
    <svg width={w} height={w * 0.42} viewBox="0 0 38 16">
      <rect x="0.5" y="0.5" width="33" height="15" rx="3.5" fill="none" stroke="var(--t-icon-faint)" />
      <rect x="35" y="5" width="2.5" height="6" rx="1" fill="var(--t-icon-faint)" />
      <rect x="2.5" y="2.5" width={pct / 100 * 29} height="11" rx="1.6" fill={fill} />
    </svg>);

}

Object.assign(window, {
  CaseGlyph, WearRing, StatusPill, Eyebrow, Btn, Field, Card, Sonar, DayTimeline, MiniBars, ProtoStyle, BigCheck, Battery
});