// portal-ui.jsx — design tokens + reusable UI primitives

// ─── Design tokens (also exposed as CSS vars in HTML) ──────
const T = {
  bg: '#0a1424',
  surface: '#11203a',
  surface2: '#182b4a',
  surface3: '#1f3358',
  border: '#26406d',
  borderSoft: '#1d3258',
  text: '#e9ecf3',
  textMute: '#94a3c1',
  textFaint: '#6b7a99',
  gold: '#c8a25a',
  goldBright: '#e0bb70',
  goldSoft: 'rgba(200,162,90,0.14)',
  goldBorder: 'rgba(200,162,90,0.35)',
  silver: '#94a3b8',
  silverBorder: 'rgba(148,163,184,0.3)',
  silverSoft: 'rgba(148,163,184,0.1)',
  good: '#4ade80',
  warn: '#f59e0b',
  bad: '#ef4444',
  shadow: '0 12px 40px rgba(0,0,0,0.35)',
};

// ─── Inject base styles once ───────────────────────────────
if (typeof document !== 'undefined' && !document.getElementById('portal-base-styles')) {
  const s = document.createElement('style');
  s.id = 'portal-base-styles';
  s.textContent = `
    :root {
      --bg: ${T.bg};
      --surface: ${T.surface};
      --surface-2: ${T.surface2};
      --border: ${T.border};
      --text: ${T.text};
      --text-mute: ${T.textMute};
      --gold: ${T.gold};
    }
    .pt, .pt * { box-sizing: border-box; }
    .pt {
      font-family: 'Poppins', 'Manrope', ui-sans-serif, system-ui, -apple-system, sans-serif;
      color: ${T.text};
      background: ${T.bg};
      font-size: 14px;
      line-height: 1.5;
      letter-spacing: -0.005em;
    }
    .pt-display {
      font-family: 'Cormorant Garamond', 'Cormorant', Georgia, serif;
      font-weight: 600;
      letter-spacing: -0.01em;
      line-height: 1.05;
    }
    .pt button {
      font-family: inherit;
      cursor: pointer;
    }
    .pt input, .pt textarea, .pt select {
      font-family: inherit;
      font-size: 14px;
      color: inherit;
    }
    .pt-num { font-variant-numeric: tabular-nums; }

    /* Scrollbars */
    .pt *::-webkit-scrollbar { width: 10px; height: 10px; }
    .pt *::-webkit-scrollbar-track { background: transparent; }
    .pt *::-webkit-scrollbar-thumb {
      background: rgba(255,255,255,0.08);
      border-radius: 999px;
      border: 2px solid transparent;
      background-clip: content-box;
    }
    .pt *::-webkit-scrollbar-thumb:hover { background: rgba(255,255,255,0.15); background-clip: content-box; }

    /* Inputs */
    .pt-input, .pt-select, .pt-textarea {
      width: 100%;
      background: rgba(255,255,255,0.03);
      border: 1px solid ${T.borderSoft};
      border-radius: 8px;
      padding: 9px 12px;
      color: ${T.text};
      transition: border-color .15s, background .15s, box-shadow .15s;
      outline: none;
    }
    .pt-input::placeholder, .pt-textarea::placeholder { color: ${T.textFaint}; }
    .pt-input:hover, .pt-select:hover, .pt-textarea:hover { border-color: ${T.border}; }
    .pt-input:focus, .pt-select:focus, .pt-textarea:focus {
      border-color: ${T.gold};
      background: rgba(255,255,255,0.05);
      box-shadow: 0 0 0 3px rgba(200,162,90,0.12);
    }
    .pt-select {
      appearance: none;
      background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'><path fill='${encodeURIComponent('#94a3c1')}' d='M0 0h10L5 6z'/></svg>");
      background-repeat: no-repeat;
      background-position: right 12px center;
      padding-right: 32px;
    }
    .pt-label {
      display: block;
      font-size: 11px;
      font-weight: 600;
      letter-spacing: 0.06em;
      text-transform: uppercase;
      color: ${T.textMute};
      margin-bottom: 6px;
    }

    /* Buttons */
    .pt-btn {
      display: inline-flex;
      align-items: center;
      justify-content: center;
      gap: 6px;
      padding: 9px 14px;
      border-radius: 8px;
      border: 1px solid ${T.border};
      background: rgba(255,255,255,0.03);
      color: ${T.text};
      font-weight: 500;
      font-size: 13px;
      transition: background .15s, border-color .15s, transform .05s;
    }
    .pt-btn:hover { background: rgba(255,255,255,0.07); border-color: ${T.gold}; }
    .pt-btn:active { transform: translateY(1px); }
    .pt-btn:disabled { opacity: 0.4; cursor: not-allowed; pointer-events: none; }
    .pt-btn-gold {
      background: linear-gradient(180deg, ${T.goldBright}, ${T.gold});
      color: #1a1207;
      border-color: ${T.goldBright};
      font-weight: 600;
    }
    .pt-btn-gold:hover {
      background: linear-gradient(180deg, #ecca80, ${T.goldBright});
      border-color: ${T.goldBright};
    }
    .pt-btn-ghost {
      background: transparent;
      border-color: transparent;
      color: ${T.textMute};
    }
    .pt-btn-ghost:hover { background: rgba(255,255,255,0.05); color: ${T.text}; border-color: transparent; }
    .pt-btn-danger {
      border-color: rgba(239,68,68,0.3);
      color: #fca5a5;
    }
    .pt-btn-danger:hover { background: rgba(239,68,68,0.1); border-color: rgba(239,68,68,0.5); }
    .pt-btn-sm { padding: 5px 10px; font-size: 12px; border-radius: 6px; }
    .pt-btn-lg { padding: 12px 18px; font-size: 15px; }

    /* Cards */
    .pt-card {
      background: linear-gradient(180deg, ${T.surface}, ${T.surface2});
      border: 1px solid ${T.borderSoft};
      border-radius: 14px;
      padding: 18px;
      position: relative;
    }
    .pt-card-flat {
      background: ${T.surface};
      border: 1px solid ${T.borderSoft};
      border-radius: 12px;
      padding: 16px;
    }
    .pt-card-gold {
      background: linear-gradient(180deg, rgba(200,162,90,0.08), rgba(200,162,90,0.02));
      border: 1px solid ${T.goldBorder};
      border-radius: 14px;
    }

    /* Badges */
    .pt-badge {
      display: inline-flex;
      align-items: center;
      gap: 5px;
      padding: 3px 9px;
      font-size: 11px;
      font-weight: 600;
      letter-spacing: 0.04em;
      border-radius: 999px;
      border: 1px solid ${T.borderSoft};
      background: rgba(255,255,255,0.03);
      color: ${T.textMute};
      white-space: nowrap;
    }
    .pt-badge-gold {
      border-color: ${T.goldBorder};
      background: ${T.goldSoft};
      color: ${T.goldBright};
    }
    .pt-badge-silver {
      border-color: ${T.silverBorder};
      background: ${T.silverSoft};
      color: #cbd5e1;
    }
    .pt-badge-good {
      border-color: rgba(74,222,128,0.3);
      background: rgba(74,222,128,0.08);
      color: ${T.good};
    }
    .pt-badge-bad {
      border-color: rgba(239,68,68,0.3);
      background: rgba(239,68,68,0.08);
      color: #fca5a5;
    }
    .pt-badge-warn {
      border-color: rgba(245,158,11,0.3);
      background: rgba(245,158,11,0.08);
      color: ${T.warn};
    }
    .pt-dot { width: 6px; height: 6px; border-radius: 50%; background: currentColor; display: inline-block; }

    /* Headings */
    .pt h1, .pt h2, .pt h3, .pt h4 { margin: 0; font-weight: 600; }
    .pt-h1 { font-family: 'Cormorant Garamond', serif; font-weight: 600; font-size: 32px; letter-spacing: -0.01em; }
    .pt-h2 { font-family: 'Cormorant Garamond', serif; font-weight: 600; font-size: 24px; }
    .pt-h3 { font-size: 15px; font-weight: 600; }
    .pt-eyebrow {
      font-size: 11px;
      font-weight: 700;
      letter-spacing: 0.16em;
      text-transform: uppercase;
      color: ${T.textMute};
    }

    /* Table */
    .pt-table { width: 100%; border-collapse: separate; border-spacing: 0; font-size: 13px; }
    .pt-table th {
      text-align: left;
      padding: 12px 14px;
      font-size: 11px;
      font-weight: 600;
      letter-spacing: 0.06em;
      text-transform: uppercase;
      color: ${T.textMute};
      border-bottom: 1px solid ${T.borderSoft};
      background: rgba(255,255,255,0.02);
      position: sticky;
      top: 0;
    }
    .pt-table td {
      padding: 12px 14px;
      border-bottom: 1px solid ${T.borderSoft};
      color: ${T.text};
    }
    .pt-table tr:last-child td { border-bottom: none; }
    .pt-table tr.pt-row-link { cursor: pointer; transition: background .12s; }
    .pt-table tr.pt-row-link:hover td { background: rgba(200,162,90,0.05); }

    /* Toast */
    .pt-toast {
      position: fixed;
      bottom: 28px;
      left: 50%;
      transform: translateX(-50%);
      background: linear-gradient(135deg, rgba(22,36,58,0.98), rgba(15,26,44,0.98));
      border: 1px solid ${T.goldBorder};
      box-shadow: 0 8px 32px rgba(0,0,0,0.45), 0 2px 8px rgba(0,0,0,0.3), inset 0 1px 0 rgba(200,162,90,0.12);
      backdrop-filter: blur(12px);
      color: ${T.text};
      padding: 13px 18px;
      border-radius: 14px;
      font-size: 13.5px;
      font-weight: 500;
      z-index: 9999;
      display: flex;
      align-items: center;
      gap: 12px;
      min-width: 220px;
      max-width: 420px;
      animation: pt-toast-in .3s cubic-bezier(0.34,1.56,0.64,1);
      white-space: nowrap;
    }
    .pt-toast-icon {
      width: 28px; height: 28px;
      border-radius: 50%;
      display: flex; align-items: center; justify-content: center;
      flex-shrink: 0;
      background: rgba(200,162,90,0.15);
      color: ${T.gold};
      font-size: 13px;
    }
    .pt-toast.bad { border-color: rgba(239,68,68,0.45); box-shadow: 0 8px 32px rgba(0,0,0,0.45), 0 0 0 1px rgba(239,68,68,0.1); }
    .pt-toast.bad .pt-toast-icon { background: rgba(239,68,68,0.12); color: #fca5a5; }
    .pt-toast-close {
      margin-left: auto; padding-left: 10px;
      color: ${T.muted}; cursor: pointer; font-size: 16px; line-height: 1;
      opacity: 0.6; transition: opacity .15s;
    }
    .pt-toast-close:hover { opacity: 1; }
    @keyframes pt-toast-in {
      from { transform: translate(-50%, 16px); opacity: 0; }
      to   { transform: translate(-50%, 0); opacity: 1; }
    }
    @keyframes pt-toast-out {
      from { transform: translate(-50%, 0); opacity: 1; }
      to   { transform: translate(-50%, 8px); opacity: 0; }
    }
    .pt-toast.leaving { animation: pt-toast-out .2s ease-in forwards; }

    /* Modal */
    .pt-modal-backdrop {
      position: fixed; inset: 0;
      background: rgba(10,20,36,0.75);
      backdrop-filter: blur(4px);
      z-index: 900;
      display: flex; align-items: center; justify-content: center;
      padding: 24px;
      animation: pt-fade .15s ease-out;
    }
    @keyframes pt-fade { from { opacity: 0 } to { opacity: 1 } }
    .pt-modal {
      background: ${T.surface};
      border: 1px solid ${T.border};
      border-radius: 16px;
      padding: 22px;
      max-width: 560px;
      width: 100%;
      box-shadow: ${T.shadow};
      animation: pt-pop .2s ease-out;
    }
    @keyframes pt-pop { from { transform: scale(0.96); opacity: 0 } to { transform: scale(1); opacity: 1 } }

    /* Progress bar */
    .pt-progress {
      height: 6px;
      background: rgba(255,255,255,0.06);
      border-radius: 999px;
      overflow: hidden;
    }
    .pt-progress > i {
      display: block;
      height: 100%;
      background: linear-gradient(90deg, ${T.gold}, ${T.goldBright});
      border-radius: 999px;
      transition: width .3s ease;
    }
    .pt-progress.silver > i { background: linear-gradient(90deg, #64748b, ${T.silver}); }

    /* Misc */
    .pt-divider { height: 1px; background: ${T.borderSoft}; border: 0; margin: 0; }
    .pt-link { color: ${T.gold}; text-decoration: none; cursor: pointer; }
    .pt-link:hover { text-decoration: underline; }
    .pt-mute { color: ${T.textMute}; }
    .pt-faint { color: ${T.textFaint}; }
    .pt-gold { color: ${T.gold}; }
    .pt-row { display: flex; align-items: center; }
    .pt-col { display: flex; flex-direction: column; }
  `;
  document.head.appendChild(s);
}

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

function Card({ children, className = '', style, gold, flat, onClick }) {
  const cls = gold ? 'pt-card-gold' : (flat ? 'pt-card-flat' : 'pt-card');
  return <div className={cls + ' ' + className} style={style} onClick={onClick}>{children}</div>;
}

function Button({ children, variant, size, onClick, disabled, type, icon, style }) {
  const cls = ['pt-btn'];
  if (variant === 'gold') cls.push('pt-btn-gold');
  if (variant === 'ghost') cls.push('pt-btn-ghost');
  if (variant === 'danger') cls.push('pt-btn-danger');
  if (size === 'sm') cls.push('pt-btn-sm');
  if (size === 'lg') cls.push('pt-btn-lg');
  return (
    <button type={type || 'button'} className={cls.join(' ')} onClick={onClick} disabled={disabled} style={style}>
      {icon && <span>{icon}</span>}
      {children}
    </button>
  );
}

function Input({ label, hint, error, value, onChange, type = 'text', placeholder, readOnly }) {
  const [showPw, setShowPw] = React.useState(false);
  const isPassword = type === 'password';
  const inputType = isPassword ? (showPw ? 'text' : 'password') : type;
  return (
    <div className="pt-col">
      {label && <label className="pt-label">{label}{error && <span style={{ color: T.bad, marginLeft: 6, textTransform: 'none', letterSpacing: 0 }}>· {error}</span>}</label>}
      <div style={{ position: 'relative' }}>
        <input
          className="pt-input"
          type={inputType}
          value={value || ''}
          onChange={e => onChange && onChange(e.target.value)}
          placeholder={placeholder}
          readOnly={readOnly}
          style={{ width: '100%', boxSizing: 'border-box', paddingRight: isPassword ? 38 : undefined, opacity: readOnly ? 0.7 : 1 }}
        />
        {isPassword && (
          <button
            type="button"
            onClick={() => setShowPw(v => !v)}
            style={{
              position: 'absolute', right: 10, top: '50%', transform: 'translateY(-50%)',
              background: 'none', border: 'none', cursor: 'pointer', padding: 2,
              color: T.muted, lineHeight: 1, display: 'flex', alignItems: 'center',
            }}
            tabIndex={-1}
          >
            {showPw
              ? <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94"/><path d="M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19"/><line x1="1" y1="1" x2="23" y2="23"/></svg>
              : <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/></svg>
            }
          </button>
        )}
      </div>
      {hint && <div className="pt-faint" style={{ fontSize: 11, marginTop: 4 }}>{hint}</div>}
    </div>
  );
}

function Select({ label, value, onChange, options }) {
  return (
    <div className="pt-col">
      {label && <label className="pt-label">{label}</label>}
      <select className="pt-select" value={value} onChange={e => onChange && onChange(e.target.value)}>
        {options.map(o => {
          if (typeof o === 'string') return <option key={o} value={o}>{o}</option>;
          return <option key={o.value} value={o.value}>{o.label}</option>;
        })}
      </select>
    </div>
  );
}

function Badge({ variant, children, style }) {
  const cls = ['pt-badge'];
  if (variant === 'gold') cls.push('pt-badge-gold');
  if (variant === 'silver') cls.push('pt-badge-silver');
  if (variant === 'good') cls.push('pt-badge-good');
  if (variant === 'bad') cls.push('pt-badge-bad');
  if (variant === 'warn') cls.push('pt-badge-warn');
  return <span className={cls.join(' ')} style={style}>{children}</span>;
}

function TierBadge({ type }) {
  if (type === 'wellness') return <Badge variant="gold">◆ WELLNESS</Badge>;
  if (type === 'gold') return <Badge variant="gold">◈ GOLD</Badge>;
  return <Badge variant="silver">◇ SILVER</Badge>;
}

function StatusBadge({ status }) {
  if (status === 'active') return <Badge variant="good"><span className="pt-dot" />Active</Badge>;
  if (status === 'inactive') return <Badge variant="bad">Inactive</Badge>;
  if (status === 'expired') return <Badge variant="bad">Expired</Badge>;
  if (status === 'deleted') return <Badge variant="bad">Deleted</Badge>;
  return <Badge>{status}</Badge>;
}

function Avatar({ name, size = 36, type, photo }) {
  const initials = (name || '?').split(' ').filter(Boolean).slice(0, 2).map(s => s[0]).join('').toUpperCase();
  const isGoldish = type === 'wellness' || type === 'gold';
  const ring = isGoldish ? T.gold : T.silver;
  // If a member photo is supplied, show it. Otherwise fall back to initials.
  if (photo) {
    return (
      <div style={{
        width: size, height: size, borderRadius: '50%',
        border: '1.5px solid ' + ring, overflow: 'hidden', flexShrink: 0,
        background: '#0e1a2f',
      }}>
        <img src={photo} alt={name || ''} style={{ width: '100%', height: '100%', objectFit: 'cover', display: 'block' }} />
      </div>
    );
  }
  return (
    <div style={{
      width: size, height: size, borderRadius: '50%',
      background: isGoldish ? 'linear-gradient(135deg, #3d2c0e, #1a1207)' : 'linear-gradient(135deg, #1c2a45, #0e1a2f)',
      border: '1.5px solid ' + ring,
      display: 'flex', alignItems: 'center', justifyContent: 'center',
      color: isGoldish ? T.goldBright : '#cbd5e1',
      fontWeight: 600, fontSize: size * 0.36,
      flexShrink: 0,
    }}>{initials}</div>
  );
}

function Progress({ value, max, gold }) {
  const pct = Math.min(100, Math.max(0, (value / Math.max(1, max)) * 100));
  return (
    <div className={'pt-progress' + (gold ? '' : ' silver')}>
      <i style={{ width: pct + '%' }} />
    </div>
  );
}

function Modal({ open, onClose, children, title, footer, width = 560 }) {
  if (!open) return null;
  return (
    <div className="pt-modal-backdrop" onClick={(e) => { if (e.target === e.currentTarget) onClose && onClose(); }}>
      <div className="pt-modal" style={{ maxWidth: width }} onClick={e => e.stopPropagation()}>
        {title && (
          <div className="pt-row" style={{ justifyContent: 'space-between', marginBottom: 14 }}>
            <h3 className="pt-h2">{title}</h3>
            <button className="pt-btn pt-btn-ghost pt-btn-sm" onClick={onClose}>✕</button>
          </div>
        )}
        {children}
        {footer && <div className="pt-row" style={{ marginTop: 18, gap: 8, justifyContent: 'flex-end' }}>{footer}</div>}
      </div>
    </div>
  );
}

// Toast system
const ToastCtx = React.createContext({ show: () => {} });
function ToastProvider({ children }) {
  const [toast, setToast] = React.useState(null);
  const timerRef = React.useRef(null);
  const show = React.useCallback((msg, opts = {}) => {
    clearTimeout(timerRef.current);
    setToast({ msg, bad: opts.bad, leaving: false });
    const duration = opts.duration || 2800;
    timerRef.current = setTimeout(() => {
      setToast(t => t ? { ...t, leaving: true } : null);
      setTimeout(() => setToast(null), 220);
    }, duration);
  }, []);
  return (
    <ToastCtx.Provider value={{ show }}>
      {children}
      {toast && (
        <div className={'pt-toast' + (toast.bad ? ' bad' : '') + (toast.leaving ? ' leaving' : '')}>
          <div className="pt-toast-icon">
            {toast.bad
              ? <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round"><path d="M12 9v4m0 4h.01M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/></svg>
              : <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"><polyline points="20 6 9 17 4 12"/></svg>
            }
          </div>
          <span style={{ flex: 1 }}>{toast.msg}</span>
          <span className="pt-toast-close" onClick={() => { clearTimeout(timerRef.current); setToast(null); }}>✕</span>
        </div>
      )}
    </ToastCtx.Provider>
  );
}
function useToast() { return React.useContext(ToastCtx); }

// Global notify modal (replaces browser alert())
const NotifyCtx = React.createContext({ notify: () => {} });
function NotifyProvider({ children }) {
  const [msg, setMsg] = React.useState(null);
  const notify = React.useCallback((text, opts = {}) => {
    setMsg({ text, icon: opts.icon || 'info', title: opts.title || null });
  }, []);
  return (
    <NotifyCtx.Provider value={{ notify }}>
      {children}
      {msg && (
        <div className="pt-modal-backdrop" style={{ zIndex: 9998 }}>
          <div style={{
            background: 'linear-gradient(160deg, rgba(22,36,58,0.99), rgba(12,22,38,0.99))',
            border: '1px solid ' + (msg.icon === 'warn' ? 'rgba(239,68,68,0.35)' : T.goldBorder),
            borderRadius: 18,
            padding: '32px 28px 24px',
            maxWidth: 380,
            width: '100%',
            boxShadow: '0 24px 64px rgba(0,0,0,0.6), inset 0 1px 0 rgba(255,255,255,0.05)',
            display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 16, textAlign: 'center',
            animation: 'pt-pop .22s cubic-bezier(0.34,1.56,0.64,1)',
          }}>
            <div style={{
              width: 52, height: 52, borderRadius: '50%',
              background: msg.icon === 'warn' ? 'rgba(239,68,68,0.1)' : 'rgba(200,162,90,0.12)',
              border: '1px solid ' + (msg.icon === 'warn' ? 'rgba(239,68,68,0.3)' : T.goldBorder),
              display: 'flex', alignItems: 'center', justifyContent: 'center',
              color: msg.icon === 'warn' ? '#fca5a5' : T.gold, fontSize: 22,
            }}>
              {msg.icon === 'warn' ? '⚠' : msg.icon === 'lock' ? '🔒' : 'ℹ'}
            </div>
            {msg.title && <div style={{ fontWeight: 700, fontSize: 17, letterSpacing: '-0.01em' }}>{msg.title}</div>}
            <div style={{ color: T.muted, fontSize: 14, lineHeight: 1.6 }}>{msg.text}</div>
            <button
              onClick={() => setMsg(null)}
              style={{
                marginTop: 4, padding: '10px 32px',
                background: 'linear-gradient(135deg, #c8a25a, #a8803a)',
                border: 'none', borderRadius: 10,
                color: '#0a1424', fontWeight: 700, fontSize: 14,
                cursor: 'pointer', letterSpacing: '0.02em',
                boxShadow: '0 4px 12px rgba(200,162,90,0.3)',
                transition: 'opacity .15s',
              }}
              onMouseOver={e => e.target.style.opacity = '0.85'}
              onMouseOut={e => e.target.style.opacity = '1'}
            >
              OK
            </button>
          </div>
        </div>
      )}
    </NotifyCtx.Provider>
  );
}
function useNotify() { return React.useContext(NotifyCtx); }

// Confirm dialog (replaces browser confirm())
const ConfirmCtx = React.createContext({ confirm: () => Promise.resolve(false) });
function ConfirmProvider({ children }) {
  const [state, setState] = React.useState(null);
  const resolveRef = React.useRef(null);
  const openConfirm = React.useCallback((msg, opts = {}) => {
    return new Promise(resolve => {
      resolveRef.current = resolve;
      setState({ msg, title: opts.title || null, danger: opts.danger || false, confirmLabel: opts.confirmLabel || 'Confirm' });
    });
  }, []);
  function respond(val) {
    setState(null);
    if (resolveRef.current) { resolveRef.current(val); resolveRef.current = null; }
  }
  return (
    <ConfirmCtx.Provider value={{ confirm: openConfirm }}>
      {children}
      {state && (
        <div className="pt-modal-backdrop" style={{ zIndex: 9997 }}>
          <div style={{
            background: 'linear-gradient(160deg, rgba(22,36,58,0.99), rgba(12,22,38,0.99))',
            border: '1px solid ' + (state.danger ? 'rgba(239,68,68,0.35)' : T.border),
            borderRadius: 18,
            padding: '28px 24px 22px',
            maxWidth: 400,
            width: '100%',
            boxShadow: '0 24px 64px rgba(0,0,0,0.6), inset 0 1px 0 rgba(255,255,255,0.05)',
            display: 'flex', flexDirection: 'column', gap: 14,
            animation: 'pt-pop .22s cubic-bezier(0.34,1.56,0.64,1)',
          }}>
            <div style={{ display: 'flex', alignItems: 'flex-start', gap: 14 }}>
              <div style={{
                width: 38, height: 38, borderRadius: '50%', flexShrink: 0,
                background: state.danger ? 'rgba(239,68,68,0.1)' : 'rgba(200,162,90,0.1)',
                border: '1px solid ' + (state.danger ? 'rgba(239,68,68,0.3)' : T.goldBorder),
                display: 'flex', alignItems: 'center', justifyContent: 'center',
                color: state.danger ? '#fca5a5' : T.gold, fontSize: 16, marginTop: 2,
              }}>
                {state.danger ? '⚠' : '?'}
              </div>
              <div style={{ flex: 1 }}>
                {state.title && <div style={{ fontWeight: 700, fontSize: 15, marginBottom: 6 }}>{state.title}</div>}
                <div style={{ color: T.muted, fontSize: 13.5, lineHeight: 1.6 }}>{state.msg}</div>
              </div>
            </div>
            <div style={{ display: 'flex', gap: 10, justifyContent: 'flex-end', marginTop: 4 }}>
              <button onClick={() => respond(false)} style={{
                padding: '9px 20px', borderRadius: 9,
                background: 'rgba(255,255,255,0.05)', border: '1px solid ' + T.border,
                color: T.text, fontSize: 13, fontWeight: 500, cursor: 'pointer',
                transition: 'background .15s',
              }}
              onMouseOver={e => e.target.style.background = 'rgba(255,255,255,0.09)'}
              onMouseOut={e => e.target.style.background = 'rgba(255,255,255,0.05)'}>
                Cancel
              </button>
              <button onClick={() => respond(true)} style={{
                padding: '9px 20px', borderRadius: 9,
                background: state.danger ? 'rgba(239,68,68,0.15)' : 'linear-gradient(135deg, #c8a25a, #a8803a)',
                border: '1px solid ' + (state.danger ? 'rgba(239,68,68,0.4)' : 'transparent'),
                color: state.danger ? '#fca5a5' : '#0a1424',
                fontSize: 13, fontWeight: 700, cursor: 'pointer',
                boxShadow: state.danger ? 'none' : '0 4px 12px rgba(200,162,90,0.3)',
                transition: 'opacity .15s',
              }}
              onMouseOver={e => e.target.style.opacity = '0.85'}
              onMouseOut={e => e.target.style.opacity = '1'}>
                {state.confirmLabel}
              </button>
            </div>
          </div>
        </div>
      )}
    </ConfirmCtx.Provider>
  );
}
function useConfirm() { return React.useContext(ConfirmCtx).confirm; }

// QR mark
function QRMark({ size = 80, seed = 7 }) {
  const cells = 13;
  const cs = size / cells;
  const rand = (i, j) => {
    const x = Math.sin(i * 13.37 + j * 7.91 + seed * 3.14) * 10000;
    return (x - Math.floor(x)) > 0.5;
  };
  const finder = (x, y) => (
    <g key={'f' + x + y} transform={`translate(${x * cs} ${y * cs})`}>
      <rect width={cs * 3} height={cs * 3} fill={T.text} />
      <rect x={cs * 0.5} y={cs * 0.5} width={cs * 2} height={cs * 2} fill={T.bg} />
      <rect x={cs * 1} y={cs * 1} width={cs} height={cs} fill={T.text} />
    </g>
  );
  const dots = [];
  for (let i = 0; i < cells; i++) {
    for (let j = 0; j < cells; j++) {
      if ((i < 3 && j < 3) || (i < 3 && j > cells - 4) || (i > cells - 4 && j < 3)) continue;
      if (rand(i, j)) dots.push(<rect key={i + '_' + j} x={i * cs + 0.5} y={j * cs + 0.5} width={cs - 1} height={cs - 1} fill={T.text} />);
    }
  }
  return (
    <svg width={size} height={size} viewBox={`0 0 ${size} ${size}`} style={{ display: 'block', background: '#fff', padding: cs * 0.5, borderRadius: 6, boxSizing: 'content-box' }}>
      {dots}{finder(0, 0)}{finder(cells - 3, 0)}{finder(0, cells - 3)}
    </svg>
  );
}

// Hotel mark
function Mark({ size = 28 }) {
  return (
    <svg width={size} height={size} viewBox="0 0 32 32">
      <defs>
        <linearGradient id="ptmg" x1="0" x2="0" y1="0" y2="1">
          <stop offset="0" stopColor={T.goldBright} />
          <stop offset="1" stopColor={T.gold} />
        </linearGradient>
      </defs>
      <rect x="2" y="2" width="28" height="28" rx="6" fill="url(#ptmg)" />
      <path d="M9 23 V10 L21 23 V10" fill="none" stroke="#1a1207" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round" />
      <circle cx="23" cy="9" r="1.8" fill="#1a1207" />
    </svg>
  );
}

// Format helpers
const fmtNPR = (n) => '₨ ' + Math.round(Number(n) || 0).toLocaleString('en-IN');

// All date formatting uses Nepal Standard Time (NPT, UTC+5:45) regardless of
// the browser's local timezone. Storage stays UTC-ISO for compatibility.
const NPT_TZ = 'Asia/Kathmandu';

// ─── Bikram Sambat (BS) conversion ────────────────────────────────
// Approximation: BS = AD + 56 years 8 months 15 days. Good for renewal/expiry
// context. For legal documents use a dedicated BS library.
function adToBS(date) {
  if (!date || isNaN(date)) return null;
  const offsetMs = (56 * 365 + 14) * 86400000 + (8 * 30 + 15) * 86400000;
  const bs = new Date(date.getTime() + offsetMs);
  return {
    year: bs.getUTCFullYear(),
    month: bs.getUTCMonth() + 1,
    day: bs.getUTCDate(),
  };
}
const BS_MONTHS = ['Baisakh','Jestha','Asar','Shrawan','Bhadau','Asoj','Kartik','Mangsir','Poush','Magh','Falgun','Chaitra'];
function fmtBS(date) {
  const b = adToBS(date); if (!b) return '';
  return `${b.day} ${BS_MONTHS[(b.month - 1 + 12) % 12]} ${b.year}`;
}

function currentDateSystem() {
  try {
    const s = window.Store && window.Store.getState && window.Store.getState().settings;
    return (s && s.dateSystem) || 'AD';
  } catch { return 'AD'; }
}

const fmtDate = (iso) => {
  if (!iso) return '—';
  try {
    const d = new Date(iso);
    if (isNaN(d)) return iso;
    const ad = d.toLocaleDateString('en-GB', { day: '2-digit', month: 'short', year: 'numeric', timeZone: NPT_TZ });
    if (currentDateSystem() === 'BS') return `${ad} · BS ${fmtBS(d)}`;
    return ad;
  } catch { return iso; }
};
const fmtDateTime = (iso) => {
  if (!iso) return '—';
  try {
    const d = new Date(iso);
    if (isNaN(d)) return iso;
    const ad = d.toLocaleString('en-GB', { day: '2-digit', month: 'short', hour: '2-digit', minute: '2-digit', timeZone: NPT_TZ });
    if (currentDateSystem() === 'BS') return `${ad} NPT · BS ${fmtBS(d)}`;
    return ad + ' NPT';
  } catch { return iso; }
};
const sumSpend = (s) => (s.rooms || 0) + (s.fnb || 0) + (s.wellness || 0);

// Today/Yesterday helpers that respect Nepal timezone for date-range filters.
function nptToday() {
  // Returns a Date set to local midnight in NPT.
  const nowStr = new Date().toLocaleString('en-US', { timeZone: NPT_TZ });
  const d = new Date(nowStr);
  d.setHours(0, 0, 0, 0);
  return d;
}

Object.assign(window, {
  T, Card, Button, Input, Select, Badge, TierBadge, StatusBadge, Avatar, Progress,
  Modal, ToastProvider, useToast, NotifyProvider, useNotify, ConfirmProvider, useConfirm, QRMark, Mark,
  fmtNPR, fmtDate, fmtDateTime, fmtBS, adToBS, sumSpend, nptToday, NPT_TZ,
});
