// ═══════════════ ADMIN PAGE ═══════════════
// Page protégée par password (POST /admin-auth)
// Permet de modifier la config du site stockée côté worker via /admin-api/config
//
// Stocke ces clés dans KV via le worker :
//   site:config            = { inscriptions, season, socials, live_cast, casters[] }
//   awards:clips:<award_id> = [ { id, title, video_url, contributor, votes } ]

const AdminPage = () => {
  const [token, setToken] = React.useState(() => sessionStorage.getItem('czf_admin_token') || null);
  const [error, setError] = React.useState('');
  const [pwd, setPwd] = React.useState('');

  const login = async () => {
    setError('');
    try {
      const base = (window.CZF && CZF.API_BASE) || '';
      const r = await fetch(`${base}/admin-auth`, {
        method: 'POST', headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ password: pwd }),
      });
      const j = await r.json();
      if (!r.ok) { setError(j.error || 'Erreur'); return; }
      sessionStorage.setItem('czf_admin_token', j.token);
      setToken(j.token);
    } catch (e) { setError(e.message); }
  };

  const logout = () => { sessionStorage.removeItem('czf_admin_token'); setToken(null); };

  if (!token) {
    return (
      <div className="page-frame grain" data-screen-label="Admin">
        <CZFHeader active="admin" />
        <main style={{ padding: '4rem 2.5rem', display: 'flex', justifyContent: 'center' }}>
          <div className="card-paper grain" style={{ width: 360, padding: '2rem', position: 'relative', overflow: 'hidden' }}>
            <div className="eyebrow" style={{ color: 'var(--red-2)', marginBottom: '.85rem' }}>Admin CZF</div>
            <div style={{ fontFamily: 'var(--fd)', fontSize: '1.8rem', color: 'var(--paper-ink)', letterSpacing: '.05em', marginBottom: '1.5rem' }}>CONNEXION</div>
            <input type="password" value={pwd} onChange={e => setPwd(e.target.value)}
                   onKeyDown={e => e.key === 'Enter' && login()}
                   placeholder="Mot de passe administrateur"
                   style={{
                     width: '100%', padding: '.6rem .85rem', borderRadius: 3,
                     background: 'rgba(0,0,0,.08)', border: '1px solid rgba(0,0,0,.15)',
                     fontFamily: 'var(--fc)', fontSize: '.9rem', color: 'var(--paper-ink)',
                     outline: 'none',
                   }} />
            <button onClick={login} className="btn btn-red" style={{ width: '100%', marginTop: '.85rem', justifyContent: 'center', padding: '.6rem' }}>
              Se connecter <Icon.ChevronR />
            </button>
            {error && <div style={{ marginTop: '.85rem', fontFamily: 'var(--fc)', fontSize: '.75rem', color: 'var(--red-2)' }}>{error}</div>}
          </div>
        </main>
      </div>
    );
  }

  return <AdminDashboard token={token} onLogout={logout} />;
};

// ─── Dashboard ───
const AdminDashboard = ({ token, onLogout }) => {
  const [tab, setTab] = React.useState('config');
  const TABS = [
    { id: 'config',  label: 'Configuration site' },
    { id: 'cast',    label: 'Cast en direct' },
    { id: 'awards',  label: 'Clips Awards' },
    { id: 'matches', label: 'Matchs & Scores' },
    { id: 'danger',  label: 'Zone danger' },
  ];

  return (
    <div className="page-frame grain" data-screen-label="Admin">
      <CZFHeader active="admin" />
      <main style={{ padding: '2rem 2.5rem 3rem' }}>
        <div style={{ display: 'flex', alignItems: 'flex-end', justifyContent: 'space-between', marginBottom: '1.5rem' }}>
          <div>
            <div className="eyebrow" style={{ marginBottom: '.6rem', color: 'var(--red)' }}>Espace admin</div>
            <h1 className="display" style={{ fontSize: '3rem' }}>ADMIN</h1>
          </div>
          <button onClick={onLogout} className="filter-btn" style={{ color: 'var(--red)', borderColor: 'rgba(230,57,70,.3)' }}>
            Déconnexion
          </button>
        </div>

        {/* Tabs */}
        <div style={{
          display: 'flex', gap: 0,
          borderBottom: '1px solid var(--border)', marginBottom: '1.5rem',
        }}>
          {TABS.map(t => (
            <button key={t.id} onClick={() => setTab(t.id)} style={{
              fontFamily: 'var(--fc)', fontSize: '.78rem', fontWeight: 700,
              letterSpacing: '.14em', textTransform: 'uppercase',
              padding: '.6rem 1.1rem', cursor: 'pointer',
              background: 'transparent', border: 'none', position: 'relative',
              color: tab === t.id ? 'var(--bone)' : 'var(--muted)',
              borderBottom: tab === t.id ? '2px solid var(--gold)' : '2px solid transparent',
              marginBottom: -1,
            }}>{t.label}</button>
          ))}
        </div>

        {tab === 'config'  && <AdminConfig token={token} />}
        {tab === 'cast'    && <AdminCast token={token} />}
        {tab === 'awards'  && <AdminAwards token={token} />}
        {tab === 'matches' && <AdminMatches token={token} />}
        {tab === 'danger'  && <AdminDanger token={token} />}
      </main>
    </div>
  );
};

// ─── Helper: fetch config ───
const useAdminConfig = (token) => {
  const [cfg, setCfg] = React.useState(null);
  const [loading, setLoading] = React.useState(true);
  const reload = React.useCallback(async () => {
    setLoading(true);
    try {
      const base = (window.CZF && CZF.API_BASE) || '';
      const r = await fetch(`${base}/public/config`);
      const j = await r.json();
      setCfg(j);
    } catch (e) { console.error(e); }
    setLoading(false);
  }, []);
  React.useEffect(() => { reload(); }, []);
  const save = async (next) => {
    const base = (window.CZF && CZF.API_BASE) || '';
    const r = await fetch(`${base}/admin-api/config`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` },
      body: JSON.stringify(next),
    });
    if (r.ok) { setCfg(next); window.__CZF_CONFIG__ = next; }
    return r.ok;
  };
  return { cfg, setCfg, loading, save, reload };
};

// ─── CONFIG : inscriptions, saison, socials ───
const AdminConfig = ({ token }) => {
  const { cfg, setCfg, loading, save } = useAdminConfig(token);
  const [status, setStatus] = React.useState('');

  if (loading || !cfg) return <div style={{ color: 'var(--muted)' }}>Chargement…</div>;

  const update = (path, value) => {
    const next = JSON.parse(JSON.stringify(cfg));
    const parts = path.split('.');
    let cur = next;
    for (let i = 0; i < parts.length - 1; i++) {
      cur[parts[i]] = cur[parts[i]] || {};
      cur = cur[parts[i]];
    }
    cur[parts[parts.length - 1]] = value;
    setCfg(next);
  };
  const submit = async () => {
    setStatus('saving');
    const ok = await save(cfg);
    setStatus(ok ? 'saved' : 'error');
    setTimeout(() => setStatus(''), 2000);
  };

  return (
    <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '1.5rem' }}>
      {/* Inscriptions */}
      <AdminCard title="Inscriptions">
        <Row label="Statut">
          <select value={cfg.inscriptions?.open ? '1' : '0'} onChange={e => update('inscriptions.open', e.target.value === '1')} className="admin-select">
            <option value="1">Ouvertes</option>
            <option value="0">Fermées</option>
          </select>
        </Row>
        <Row label="Date de clôture">
          <input type="text" value={cfg.inscriptions?.deadline || ''} onChange={e => update('inscriptions.deadline', e.target.value)} placeholder="12 juin" className="admin-input" />
        </Row>
        <p style={{ fontFamily: 'var(--fc)', fontSize: '.7rem', color: 'var(--muted)', letterSpacing: '.04em', marginTop: '.5rem' }}>
          Affecte le texte sous le bouton "S'inscrire" sur l'accueil.
        </p>
      </AdminCard>

      {/* Saison */}
      <AdminCard title="Saison">
        <Row label="Numéro">
          <input type="number" value={cfg.season?.number || 4} onChange={e => update('season.number', parseInt(e.target.value) || 1)} className="admin-input" />
        </Row>
        <Row label="État">
          <select value={cfg.season?.state || 'EN COURS'} onChange={e => update('season.state', e.target.value)} className="admin-select">
            <option>EN COURS</option>
            <option>PHASE DE POULES</option>
            <option>PLAYOFFS</option>
            <option>TERMINÉE</option>
            <option>BIENTÔT</option>
          </select>
        </Row>
        <p style={{ fontFamily: 'var(--fc)', fontSize: '.7rem', color: 'var(--muted)', letterSpacing: '.04em', marginTop: '.5rem' }}>
          Affecte les eyebrows "Saison 4 · MYG Community" et le bandeau dans le header.
        </p>
      </AdminCard>

      {/* Socials */}
      <AdminCard title="Liens sociaux">
        <Row label="Discord">
          <input value={cfg.socials?.discord_url || ''} onChange={e => update('socials.discord_url', e.target.value)} placeholder="https://discord.gg/…" className="admin-input" />
        </Row>
        <Row label="Discord (membres)">
          <input value={cfg.socials?.discord_members || ''} onChange={e => update('socials.discord_members', e.target.value)} placeholder="2 480 membres" className="admin-input" />
        </Row>
        <Row label="Twitch">
          <input value={cfg.socials?.twitch_url || ''} onChange={e => update('socials.twitch_url', e.target.value)} placeholder="https://twitch.tv/…" className="admin-input" />
        </Row>
        <Row label="Twitch (handle)">
          <input value={cfg.socials?.twitch_handle || ''} onChange={e => update('socials.twitch_handle', e.target.value)} placeholder="mygcommunity" className="admin-input" />
        </Row>
        <Row label="YouTube">
          <input value={cfg.socials?.yt_url || ''} onChange={e => update('socials.yt_url', e.target.value)} placeholder="https://youtube.com/@…" className="admin-input" />
        </Row>
        <Row label="YouTube (handle)">
          <input value={cfg.socials?.yt_handle || ''} onChange={e => update('socials.yt_handle', e.target.value)} placeholder="@mygcommunity" className="admin-input" />
        </Row>
      </AdminCard>

      {/* Save bar */}
      <div style={{ gridColumn: '1 / -1', display: 'flex', alignItems: 'center', justifyContent: 'flex-end', gap: '.85rem' }}>
        {status === 'saved' && <span style={{ fontFamily: 'var(--fc)', fontSize: '.75rem', color: 'var(--ok)' }}>✓ Enregistré</span>}
        {status === 'error' && <span style={{ fontFamily: 'var(--fc)', fontSize: '.75rem', color: 'var(--red)' }}>✗ Erreur</span>}
        <button onClick={submit} className="btn btn-red" style={{ padding: '.6rem 1.5rem' }}>
          {status === 'saving' ? 'Enregistrement…' : 'Enregistrer'} <Icon.ChevronR />
        </button>
      </div>
    </div>
  );
};

// ─── CAST en direct ───
const AdminCast = ({ token }) => {
  const { cfg, setCfg, loading, save } = useAdminConfig(token);
  const [status, setStatus] = React.useState('');

  if (loading || !cfg) return <div style={{ color: 'var(--muted)' }}>Chargement…</div>;

  const lc = cfg.live_cast || { duo: ['',''], match: '', description: '', twitch_url: '', yt_url: '', is_live: false };
  const update = (k, v) => {
    const next = { ...cfg, live_cast: { ...lc, [k]: v } };
    setCfg(next);
  };
  const submit = async () => { setStatus('saving'); const ok = await save(cfg); setStatus(ok ? 'saved' : 'error'); setTimeout(() => setStatus(''), 2000); };

  return (
    <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '1.5rem' }}>
      <AdminCard title="Duo qui caste actuellement">
        <Row label="Caster 1">
          <input value={lc.duo?.[0] || ''} onChange={e => update('duo', [e.target.value, lc.duo?.[1] || ''])} placeholder="Hadès" className="admin-input" />
        </Row>
        <Row label="Caster 2">
          <input value={lc.duo?.[1] || ''} onChange={e => update('duo', [lc.duo?.[0] || '', e.target.value])} placeholder="BigBoss" className="admin-input" />
        </Row>
        <Row label="Match (label)">
          <input value={lc.match || ''} onChange={e => update('match', e.target.value)} placeholder="Iron Howl vs Volt Riders" className="admin-input" />
        </Row>
        <Row label="Description">
          <textarea value={lc.description || ''} onChange={e => update('description', e.target.value)} rows="2"
                    placeholder="Le duo historique du CZF. Play-by-play nerveux…"
                    className="admin-input" style={{ resize: 'vertical' }} />
        </Row>
      </AdminCard>

      <AdminCard title="Diffusion">
        <Row label="État">
          <select value={lc.is_live ? '1' : '0'} onChange={e => update('is_live', e.target.value === '1')} className="admin-select">
            <option value="0">Pas en direct</option>
            <option value="1">En direct (LIVE)</option>
          </select>
        </Row>
        <Row label="URL Twitch">
          <input value={lc.twitch_url || ''} onChange={e => update('twitch_url', e.target.value)} placeholder="https://twitch.tv/…" className="admin-input" />
        </Row>
        <Row label="URL YouTube">
          <input value={lc.yt_url || ''} onChange={e => update('yt_url', e.target.value)} placeholder="https://youtube.com/…" className="admin-input" />
        </Row>
        <p style={{ fontFamily: 'var(--fc)', fontSize: '.7rem', color: 'var(--muted)', letterSpacing: '.04em', marginTop: '.5rem' }}>
          Les casters mettent à jour leur photo via la commande <code style={{ color: 'var(--gold)' }}>/caster-photo</code> sur Discord.
        </p>
      </AdminCard>

      <div style={{ gridColumn: '1 / -1', display: 'flex', alignItems: 'center', justifyContent: 'flex-end', gap: '.85rem' }}>
        {status === 'saved' && <span style={{ fontFamily: 'var(--fc)', fontSize: '.75rem', color: 'var(--ok)' }}>✓ Enregistré</span>}
        {status === 'error' && <span style={{ fontFamily: 'var(--fc)', fontSize: '.75rem', color: 'var(--red)' }}>✗ Erreur</span>}
        <button onClick={submit} className="btn btn-red" style={{ padding: '.6rem 1.5rem' }}>
          {status === 'saving' ? 'Enregistrement…' : 'Enregistrer'} <Icon.ChevronR />
        </button>
      </div>
    </div>
  );
};

// ─── AWARDS clips ───
const AdminAwards = ({ token }) => {
  const AWARDS = [
    { id: 'best-play',  label: 'Le plus beau play' },
    { id: 'funniest',   label: 'Moment le plus drôle' },
    { id: 'wtf',        label: 'WTF moment' },
    { id: 'wombo',      label: 'Wombo combo' },
  ];
  const [selected, setSelected] = React.useState(AWARDS[0].id);
  const [clips, setClips] = React.useState([]);
  const [loading, setLoading] = React.useState(false);
  const [form, setForm] = React.useState({ title: '', video_url: '', contributor: '', thumbnail: '' });

  const load = async (id) => {
    setLoading(true);
    try {
      const base = (window.CZF && CZF.API_BASE) || '';
      const r = await fetch(`${base}/public/awards-clips?award_id=${id}`);
      const j = await r.json();
      setClips(Array.isArray(j) ? j : []);
    } catch (e) { setClips([]); }
    setLoading(false);
  };
  React.useEffect(() => { load(selected); }, [selected]);

  const submit = async () => {
    if (!form.title || !form.video_url) return;
    const base = (window.CZF && CZF.API_BASE) || '';
    await fetch(`${base}/admin-api/awards-clip`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` },
      body: JSON.stringify({ action: 'add', award_id: selected, clip: { ...form, id: 'c-' + Date.now(), votes: 0 } }),
    });
    setForm({ title: '', video_url: '', contributor: '', thumbnail: '' });
    load(selected);
  };
  const remove = async (clipId) => {
    if (!confirm('Supprimer ce clip ?')) return;
    const base = (window.CZF && CZF.API_BASE) || '';
    await fetch(`${base}/admin-api/awards-clip`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` },
      body: JSON.stringify({ action: 'delete', award_id: selected, clip_id: clipId }),
    });
    load(selected);
  };

  return (
    <div>
      {/* Award tabs */}
      <div style={{ display: 'flex', gap: '.4rem', marginBottom: '1.25rem', flexWrap: 'wrap' }}>
        {AWARDS.map(a => (
          <button key={a.id} onClick={() => setSelected(a.id)}
                  className={`filter-btn ${selected === a.id ? 'on' : ''}`}>
            {a.label}
          </button>
        ))}
      </div>

      <div style={{ display: 'grid', gridTemplateColumns: '1fr 1.4fr', gap: '1.5rem' }}>
        {/* Add new clip */}
        <AdminCard title="Ajouter un clip">
          <Row label="Titre"><input value={form.title} onChange={e => setForm({ ...form, title: e.target.value })} placeholder="Outplay 1v4 de Nyx" className="admin-input" /></Row>
          <Row label="URL vidéo"><input value={form.video_url} onChange={e => setForm({ ...form, video_url: e.target.value })} placeholder="https://twitch.tv/…/clip/… ou YouTube" className="admin-input" /></Row>
          <Row label="Auteur"><input value={form.contributor} onChange={e => setForm({ ...form, contributor: e.target.value })} placeholder="Pseudo Discord" className="admin-input" /></Row>
          <Row label="Thumbnail (optionnel)"><input value={form.thumbnail} onChange={e => setForm({ ...form, thumbnail: e.target.value })} placeholder="URL image" className="admin-input" /></Row>
          <button onClick={submit} className="btn btn-red" style={{ width: '100%', justifyContent: 'center', padding: '.6rem', marginTop: '.85rem' }}>
            Ajouter le clip <Icon.ChevronR />
          </button>
        </AdminCard>

        {/* Existing clips */}
        <AdminCard title={`Clips soumis (${clips.length})`}>
          {loading && <div style={{ color: 'var(--muted)' }}>Chargement…</div>}
          {!loading && clips.length === 0 && <div style={{ color: 'var(--muted)', fontFamily: 'var(--fc)', fontSize: '.8rem' }}>Aucun clip pour cette catégorie.</div>}
          <div style={{ display: 'flex', flexDirection: 'column', gap: '.5rem' }}>
            {clips.map(c => (
              <div key={c.id} style={{
                background: 'rgba(0,0,0,.06)', padding: '.55rem .7rem', borderRadius: 3,
                display: 'flex', alignItems: 'center', gap: '.6rem',
              }}>
                <div style={{
                  width: 36, height: 36, borderRadius: 3,
                  background: c.thumbnail ? `url(${c.thumbnail}) center/cover` : 'rgba(0,0,0,.15)',
                  display: 'flex', alignItems: 'center', justifyContent: 'center',
                  color: 'var(--gold)', flexShrink: 0,
                }}>{!c.thumbnail && <div style={{ width: 0, height: 0, borderLeft: '8px solid currentColor', borderTop: '5px solid transparent', borderBottom: '5px solid transparent' }} />}</div>
                <div style={{ flex: 1, minWidth: 0 }}>
                  <div style={{ fontFamily: 'var(--fc)', fontSize: '.85rem', fontWeight: 700, color: 'var(--paper-ink)' }}>{c.title}</div>
                  <div style={{ fontFamily: 'var(--fc)', fontSize: '.65rem', color: 'var(--paper-mut)' }}>{c.contributor} · {c.votes ?? 0} votes</div>
                </div>
                <a href={c.video_url} target="_blank" rel="noopener" style={{ fontFamily: 'var(--fc)', fontSize: '.7rem', color: 'var(--red-2)', textDecoration: 'none' }}>Voir →</a>
                <button onClick={() => remove(c.id)} style={{
                  background: 'transparent', border: '1px solid rgba(230,57,70,.3)', color: 'var(--red-2)',
                  fontFamily: 'var(--fc)', fontSize: '.65rem', padding: '.2rem .5rem', borderRadius: 2, cursor: 'pointer', letterSpacing: '.1em', textTransform: 'uppercase',
                }}>Supp.</button>
              </div>
            ))}
          </div>
        </AdminCard>
      </div>
    </div>
  );
};

// ─── MATCHES — rappels rapides ───
const AdminMatches = ({ token }) => (
  <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '1.5rem' }}>
    <AdminCard title="Schedule un match">
      <p style={{ fontFamily: 'var(--fc)', fontSize: '.85rem', color: 'var(--paper-mut)', lineHeight: 1.5 }}>
        Pour planifier un match, utilise la commande Discord <code style={{ color: 'var(--red-2)' }}>/schedule</code> ou la commande <code style={{ color: 'var(--red-2)' }}>/match report</code> pour enregistrer un résultat.
      </p>
      <p style={{ fontFamily: 'var(--fc)', fontSize: '.85rem', color: 'var(--paper-mut)', marginTop: '.75rem', lineHeight: 1.5 }}>
        L'endpoint <code style={{ color: 'var(--gold)' }}>POST /admin-api/schedule</code> et <code style={{ color: 'var(--gold)' }}>POST /admin-api/report</code> sont également exposés.
      </p>
    </AdminCard>
    <AdminCard title="Bracket">
      <p style={{ fontFamily: 'var(--fc)', fontSize: '.85rem', color: 'var(--paper-mut)', lineHeight: 1.5 }}>
        Configure le bracket via <code style={{ color: 'var(--red-2)' }}>/admin bracket-setup</code> sur Discord ou via l'endpoint <code style={{ color: 'var(--gold)' }}>POST /admin-api/bracket-setup</code>.
      </p>
    </AdminCard>
  </div>
);

// ─── DANGER ZONE ───
const AdminDanger = ({ token }) => {
  const [confirmation, setConfirmation] = React.useState('');
  const [type, setType] = React.useState('Split');
  const [status, setStatus] = React.useState('');

  const reset = async () => {
    if (confirmation !== 'CONFIRMER') return;
    setStatus('working');
    const base = (window.CZF && CZF.API_BASE) || '';
    const r = await fetch(`${base}/admin-api/reset`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` },
      body: JSON.stringify({ type, confirmation }),
    });
    setStatus(r.ok ? 'done' : 'error');
    setTimeout(() => setStatus(''), 2500);
    setConfirmation('');
  };

  return (
    <AdminCard title="Reset des données" tone="danger">
      <Row label="Type">
        <select value={type} onChange={e => setType(e.target.value)} className="admin-select">
          <option value="Split">Split seulement (matchs, scrims, brackets, paris)</option>
          <option value="Complet">Complet (vide tout y compris joueurs/équipes)</option>
        </select>
      </Row>
      <Row label="Confirmation">
        <input value={confirmation} onChange={e => setConfirmation(e.target.value)} placeholder="Tape CONFIRMER pour valider" className="admin-input" />
      </Row>
      <button onClick={reset} disabled={confirmation !== 'CONFIRMER'} className="btn btn-red" style={{
        width: '100%', marginTop: '.85rem', justifyContent: 'center', padding: '.7rem',
        opacity: confirmation === 'CONFIRMER' ? 1 : .4, cursor: confirmation === 'CONFIRMER' ? 'pointer' : 'not-allowed',
      }}>
        ⚠️ Effacer les données ({type})
      </button>
      {status === 'done'   && <div style={{ marginTop: '.85rem', color: 'var(--ok)', fontFamily: 'var(--fc)', fontSize: '.85rem' }}>✓ Reset effectué.</div>}
      {status === 'error'  && <div style={{ marginTop: '.85rem', color: 'var(--red)', fontFamily: 'var(--fc)', fontSize: '.85rem' }}>✗ Erreur.</div>}
    </AdminCard>
  );
};

// ─── Atoms ───
const AdminCard = ({ title, children, tone }) => (
  <div className="card-paper grain" style={{
    padding: '1.25rem 1.4rem', position: 'relative', overflow: 'hidden',
    border: tone === 'danger' ? '1px solid var(--red)' : undefined,
  }}>
    <div style={{ fontFamily: 'var(--fd)', fontSize: '1.2rem', letterSpacing: '.05em',
      color: tone === 'danger' ? 'var(--red-2)' : 'var(--paper-ink)',
      marginBottom: '1rem',
    }}>{(title || '').toUpperCase()}</div>
    <style>{`
      .admin-input, .admin-select {
        width: 100%; padding: .45rem .7rem; border-radius: 3px;
        background: rgba(0,0,0,.05); border: 1px solid rgba(0,0,0,.12);
        font-family: var(--fc); font-size: .85rem; color: var(--paper-ink);
        outline: none;
      }
      .admin-input:focus, .admin-select:focus { border-color: var(--red-2); }
    `}</style>
    {children}
  </div>
);

const Row = ({ label, children }) => (
  <div style={{ marginBottom: '.7rem' }}>
    <div style={{ fontFamily: 'var(--fc)', fontSize: '.6rem', fontWeight: 700, letterSpacing: '.18em', textTransform: 'uppercase', color: 'var(--paper-mut)', marginBottom: '.3rem' }}>{label}</div>
    {children}
  </div>
);

Object.assign(window, { AdminPage });
