<?php
/**
 * gate.php — Allowlist-only email gate with single-session enforcement
 *
 * Usage:
 *   <?php require 'gate.php'; ?>  at the very top of any protected page.
 *
 * How it works:
 *   - Only emails pre-loaded into gate_emails.sqlite are allowed through.
 *   - Each email may hold exactly ONE active session at a time. A new login
 *     from any browser/device silently invalidates all previous sessions for
 *     that email (token rotation).
 *   - Banned emails see a 403 Denied screen regardless of session state.
 *   - Unknown emails see a "not on the list" error with a Patreon signup nudge.
 *
 * Requirements: PHP 7.4+, PDO + pdo_sqlite extension.
 * Manage the allowlist with gate_admin.php.
 */

// ── Config ────────────────────────────────────────────────────────────────────
define('GATE_DB_PATH',      __DIR__ . '/gate_emails.sqlite');
define('GATE_SESSION_KEY',  'gate_verified');
define('GATE_SESSION_EMAIL','gate_email');
define('GATE_SESSION_TOKEN','gate_token');
define('GATE_CAPTCHA_KEY',  'gate_captcha_answer');
define('GATE_CAPTCHA_Q',    'gate_captcha_q');
define('GATE_PATREON_URL',  'https://www.patreon.com/tyclifford'); // ← replace
// ─────────────────────────────────────────────────────────────────────────────

session_start();

// ═════════════════════════════════════════════════════════════════════════════
// DATABASE
// ═════════════════════════════════════════════════════════════════════════════

function gate_db(): PDO {
    static $pdo = null;
    if ($pdo !== null) return $pdo;

    $pdo = new PDO('sqlite:' . GATE_DB_PATH);
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $pdo->exec("PRAGMA journal_mode=WAL");

    $pdo->exec("CREATE TABLE IF NOT EXISTS gate_emails (
        id            INTEGER  PRIMARY KEY AUTOINCREMENT,
        email         TEXT     NOT NULL UNIQUE COLLATE NOCASE,
        status        TEXT     NOT NULL DEFAULT 'valid'
                               CHECK(status IN ('valid','banned')),
        session_token TEXT     DEFAULT NULL,
        added_at      DATETIME DEFAULT CURRENT_TIMESTAMP,
        last_login    DATETIME DEFAULT NULL,
        login_ip      TEXT     DEFAULT NULL,
        login_page    TEXT     DEFAULT NULL
    )");

    return $pdo;
}

function gate_get_record(string $email): ?array {
    $stmt = gate_db()->prepare(
        "SELECT * FROM gate_emails WHERE email = :e COLLATE NOCASE LIMIT 1"
    );
    $stmt->execute([':e' => strtolower(trim($email))]);
    $row = $stmt->fetch(PDO::FETCH_ASSOC);
    return $row ?: null;
}

function gate_create_session(string $email): void {
    $token = bin2hex(random_bytes(32));
    $db    = gate_db();

    $stmt = $db->prepare(
        "UPDATE gate_emails
            SET session_token = :t,
                last_login    = CURRENT_TIMESTAMP,
                login_ip      = :ip,
                login_page    = :p
          WHERE email = :e COLLATE NOCASE"
    );
    $stmt->execute([
        ':t'  => $token,
        ':ip' => $_SERVER['REMOTE_ADDR'] ?? 'unknown',
        ':p'  => $_SERVER['REQUEST_URI'] ?? '',
        ':e'  => strtolower(trim($email)),
    ]);

    $_SESSION[GATE_SESSION_KEY]   = true;
    $_SESSION[GATE_SESSION_EMAIL] = strtolower(trim($email));
    $_SESSION[GATE_SESSION_TOKEN] = $token;
}

// ═════════════════════════════════════════════════════════════════════════════
// REQUEST HANDLING
// ═════════════════════════════════════════════════════════════════════════════

function gate_kill_session(): void {
    $_SESSION = [];
    if (ini_get('session.use_cookies')) {
        $p = session_get_cookie_params();
        setcookie(session_name(), '', time() - 42000,
            $p['path'], $p['domain'], $p['secure'], $p['httponly']);
    }
    session_destroy();
    session_start();
}

if (!empty($_SESSION[GATE_SESSION_KEY])) {
    $sess_email = $_SESSION[GATE_SESSION_EMAIL] ?? '';
    $sess_token = $_SESSION[GATE_SESSION_TOKEN] ?? '';
    $record     = $sess_email !== '' ? gate_get_record($sess_email) : null;

    if ($record === null) {
        gate_kill_session();
        $gate_form_error = 'Your access has been removed. Please contact an administrator.';
    } elseif ($record['status'] === 'banned') {
        gate_kill_session();
        gate_render_denied($sess_email);
    } elseif ($record['session_token'] !== $sess_token) {
        gate_kill_session();
        $gate_form_error = 'Your session was ended because you signed in from another location.';
    } else {
        return;
    }
}

$gate_form_error   = $gate_form_error ?? '';
$gate_show_patreon = false;

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $email    = strtolower(trim($_POST['email']   ?? ''));
    $answer   = trim($_POST['captcha'] ?? '');
    $expected = $_SESSION[GATE_CAPTCHA_KEY] ?? null;

    if ($email === '' || !filter_var($email, FILTER_VALIDATE_EMAIL)) {
        $gate_form_error = 'Please enter a valid email address.';

    } elseif ($expected === null || (int)$answer !== (int)$expected) {
        $gate_form_error = 'Incorrect answer — please try again.';

    } else {
        $record = gate_get_record($email);

        if ($record === null) {
            $gate_form_error   = 'That email isn\'t on the access list yet.';
            $gate_show_patreon = true;

        } elseif ($record['status'] === 'banned') {
            gate_render_denied($email);

        } else {
            gate_create_session($email);
            unset($_SESSION[GATE_CAPTCHA_KEY], $_SESSION[GATE_CAPTCHA_Q]);
            $scheme = (($_SERVER['HTTPS'] ?? '') === 'on') ? 'https' : 'http';
            header('Location: ' . $scheme . '://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']);
            exit;
        }
    }
}

if (empty($_SESSION[GATE_CAPTCHA_KEY]) || $gate_form_error) {
    $a = random_int(2, 12);
    $b = random_int(1, 10);
    $_SESSION[GATE_CAPTCHA_Q]   = "$a + $b";
    $_SESSION[GATE_CAPTCHA_KEY] = $a + $b;
}
$captcha_question = $_SESSION[GATE_CAPTCHA_Q];

// ═════════════════════════════════════════════════════════════════════════════
// STYLES
// ═════════════════════════════════════════════════════════════════════════════

function gate_styles(): void { ?>
<style>
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Share+Tech+Mono&display=swap');

/* ── Reset & tokens ────────────────────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

:root {
  /* neutrals */
  --bg:         #09090f;
  --surface:    #0f0f1a;
  --surface-2:  #141425;
  --border:     #1e1e38;
  --border-2:   #2a2a48;
  --text:       #e8e8f8;
  --text-2:     #9898c0;
  --text-3:     #58587a;

  /* accents */
  --green:      #00e87a;
  --green-dim:  rgba(0,232,122,.08);
  --blue:       #00c8ff;
  --purple:     #b060ff;
  --red:        #ff3355;
  --orange:     #ff8800;

  /* Patreon */
  --pat:        #ff424d;
  --pat-lite:   rgba(255,66,77,.10);
  --pat-mid:    rgba(255,66,77,.22);
  --pat-border: rgba(255,66,77,.32);
  --pat-glow:   rgba(255,66,77,.18);

  /* spacing scale */
  --r:          6px;
  --gap:        1.25rem;
}

html { font-size: 16px; -webkit-text-size-adjust: 100%; }

body {
  min-height: 100dvh;
  background: var(--bg);
  font-family: 'Inter', system-ui, sans-serif;
  color: var(--text);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 1rem;
  gap: 0;

  /* ambient glows — subtle, not distracting on small screens */
  background-image:
    radial-gradient(ellipse 70% 50% at 20% 10%,  rgba(176,96,255,.05) 0%, transparent 60%),
    radial-gradient(ellipse 60% 40% at 80% 80%,  rgba(0,200,255,.04)  0%, transparent 60%),
    radial-gradient(ellipse 50% 60% at 50% 50%,  rgba(255,66,77,.03)  0%, transparent 70%);
}

/* scanline — very faint, performance-friendly */
body::after {
  content: '';
  position: fixed; inset: 0; pointer-events: none; z-index: 999;
  background: repeating-linear-gradient(
    0deg, transparent 0px, transparent 3px,
    rgba(0,0,0,.06) 3px, rgba(0,0,0,.06) 4px
  );
}

/* ── Shared animations ─────────────────────────────────────────────────────── */
@keyframes rise {
  from { opacity: 0; transform: translateY(16px) scale(.98); }
  to   { opacity: 1; transform: translateY(0)    scale(1);   }
}
@keyframes shimmer {
  from { background-position: 0%   50%; }
  to   { background-position: 200% 50%; }
}
@keyframes shake {
  0%,100% { transform: translateX(0); }
  20%,60% { transform: translateX(-6px); }
  40%,80% { transform: translateX(6px); }
}
@keyframes pulse-border {
  0%,100% { box-shadow: 0 0 0 0 var(--pat-glow); }
  50%      { box-shadow: 0 0 0 6px transparent; }
}

/* ── Outer wrapper ─────────────────────────────────────────────────────────── */
/* Mobile: single column stack. Desktop: side-by-side panels. */
.gate-wrap {
  width: 100%;
  max-width: 880px;
  display: flex;
  flex-direction: column;
  border-radius: calc(var(--r) + 2px);
  overflow: hidden;
  animation: rise .45s cubic-bezier(.22,.68,0,1.2) both;
  box-shadow:
    0 0 0 1px rgba(255,255,255,.04),
    0 4px 60px rgba(0,0,0,.7),
    0 0 80px rgba(176,96,255,.05);
}

@media (min-width: 700px) {
  .gate-wrap { flex-direction: row; min-height: 520px; }
}

/* ════════════════════════════════════════════════════════════════════════════
   LEFT PANEL — Patreon CTA
   ════════════════════════════════════════════════════════════════════════════ */
.panel-cta {
  background: var(--surface);
  border-bottom: 1px solid var(--border);
  padding: 2rem 1.75rem;
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
  position: relative;
  overflow: hidden;
}

@media (min-width: 700px) {
  .panel-cta {
    flex: 0 0 52%;
    border-bottom: none;
    border-right: 1px solid var(--border);
    padding: 2.75rem 2.25rem;
  }
}

/* Rainbow top rule (mobile) / left rule (desktop) */
.panel-cta::before {
  content: '';
  position: absolute;
  top: 0; left: 0; right: 0; height: 2px;
  background: linear-gradient(90deg,
    var(--pat), var(--purple), var(--blue), var(--green),
    var(--blue), var(--purple), var(--pat));
  background-size: 300% 100%;
  animation: shimmer 5s linear infinite;
}

@media (min-width: 700px) {
  .panel-cta::before {
    top: 0; bottom: 0; right: auto;
    width: 2px; height: auto;
    background: linear-gradient(180deg,
      var(--pat), var(--purple), var(--blue), var(--green),
      var(--blue), var(--purple), var(--pat));
    background-size: 100% 300%;
  }
}

/* Faint decorative blob */
.panel-cta::after {
  content: '';
  position: absolute;
  bottom: -60px; right: -60px;
  width: 220px; height: 220px;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(255,66,77,.07) 0%, transparent 70%);
  pointer-events: none;
}

/* Eyebrow */
.cta-eyebrow {
  display: flex;
  align-items: center;
  gap: .5rem;
  font-family: 'Share Tech Mono', monospace;
  font-size: .65rem;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--pat);
  text-shadow: 0 0 12px var(--pat-glow);
}

/* Patreon 'P' icon */
.icon-patreon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 20px; height: 20px;
  background: var(--pat);
  border-radius: 4px;
  flex-shrink: 0;
}

.cta-headline {
  font-size: clamp(1.55rem, 4vw, 2rem);
  font-weight: 700;
  line-height: 1.15;
  letter-spacing: -.01em;
  color: var(--text);
}
.cta-headline span {
  background: linear-gradient(120deg, var(--pat) 0%, #ff8c6a 100%);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
}

.cta-body {
  font-size: .92rem;
  color: var(--text-2);
  line-height: 1.7;
}
.cta-body strong { color: var(--text); font-weight: 600; }

/* ── 24-hour notice strip ───────────────────────────────────────────────────── */
.notice-24h {
  display: flex;
  align-items: flex-start;
  gap: .65rem;
  background: rgba(255,136,0,.08);
  border: 1px solid rgba(255,136,0,.28);
  border-radius: var(--r);
  padding: .75rem .9rem;
  font-size: .82rem;
  color: rgba(232,200,100,.9);
  line-height: 1.55;
}
.notice-24h .notice-icon {
  flex-shrink: 0;
  margin-top: 1px;
  color: var(--orange);
  filter: drop-shadow(0 0 5px rgba(255,136,0,.5));
}
.notice-24h strong {
  color: var(--orange);
  font-weight: 600;
  display: block;
  margin-bottom: .15rem;
}

/* ── Tier list ──────────────────────────────────────────────────────────────── */
.tier-list {
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: .5rem;
}
.tier-list li {
  display: flex;
  align-items: center;
  gap: .65rem;
  font-size: .88rem;
  color: var(--text-2);
}
.tier-dot {
  width: 8px; height: 8px;
  border-radius: 50%;
  flex-shrink: 0;
}
.tier-dot.free { background: var(--green);  box-shadow: 0 0 6px rgba(0,232,122,.6); }
.tier-dot.paid { background: var(--purple); box-shadow: 0 0 6px rgba(176,96,255,.6); }
.tier-list li strong { color: var(--text); font-weight: 600; }

/* ── Patreon CTA button ─────────────────────────────────────────────────────── */
.btn-patreon {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: .6rem;
  padding: .9rem 1.5rem;
  background: var(--pat);
  color: #fff;
  font-family: 'Inter', sans-serif;
  font-size: .92rem;
  font-weight: 700;
  letter-spacing: .02em;
  border-radius: var(--r);
  text-decoration: none;
  position: relative;
  overflow: hidden;
  transition: transform .15s, box-shadow .2s, background .15s;
  box-shadow: 0 0 0 1px rgba(255,255,255,.1) inset,
              0 4px 20px rgba(255,66,77,.35);
  animation: pulse-border 3s ease-in-out infinite;
  z-index: 1;
}
.btn-patreon::before {
  content: '';
  position: absolute; inset: 0;
  background: linear-gradient(180deg, rgba(255,255,255,.12) 0%, transparent 60%);
  pointer-events: none;
}
.btn-patreon:hover {
  background: #ff5a63;
  box-shadow: 0 0 0 1px rgba(255,255,255,.15) inset,
              0 6px 28px rgba(255,66,77,.55);
  transform: translateY(-2px);
}
.btn-patreon:active { transform: translateY(0) scale(.98); }

.btn-patreon-sub {
  text-align: center;
  font-size: .73rem;
  color: var(--text-3);
  font-family: 'Share Tech Mono', monospace;
  letter-spacing: .05em;
}
.btn-patreon-sub a {
  color: var(--pat);
  text-decoration: none;
  opacity: .7;
  transition: opacity .15s;
}
.btn-patreon-sub a:hover { opacity: 1; }

/* ════════════════════════════════════════════════════════════════════════════
   RIGHT PANEL — Login form
   ════════════════════════════════════════════════════════════════════════════ */
.panel-form {
  background: var(--surface-2);
  padding: 2rem 1.75rem;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: var(--gap);
}

@media (min-width: 700px) {
  .panel-form {
    flex: 1;
    padding: 2.75rem 2.25rem;
  }
}

.form-eyebrow {
  font-family: 'Share Tech Mono', monospace;
  font-size: .65rem;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--green);
  text-shadow: 0 0 10px rgba(0,232,122,.5);
}
.form-eyebrow::before { content: '> '; opacity: .5; }

.form-title {
  font-size: clamp(1.3rem, 3.5vw, 1.7rem);
  font-weight: 700;
  letter-spacing: -.015em;
  line-height: 1.2;
  background: linear-gradient(135deg, var(--blue) 0%, var(--purple) 100%);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
}

.form-hint {
  font-size: .82rem;
  color: var(--text-3);
  line-height: 1.6;
  font-family: 'Share Tech Mono', monospace;
  padding: .6rem .85rem;
  border-left: 2px solid var(--border-2);
}

/* ── Alerts ──────────────────────────────────────────────────────────────────── */
.alert {
  display: flex;
  align-items: flex-start;
  gap: .6rem;
  border-radius: var(--r);
  padding: .75rem 1rem;
  font-size: .8rem;
  line-height: 1.55;
  font-family: 'Share Tech Mono', monospace;
}
.alert svg { flex-shrink: 0; margin-top: 1px; }

.alert-error {
  background: rgba(255,51,85,.07);
  border: 1px solid rgba(255,51,85,.28);
  color: var(--red);
  text-shadow: 0 0 8px rgba(255,51,85,.3);
  animation: shake .35s ease;
}
.alert-info {
  background: rgba(0,200,255,.07);
  border: 1px solid rgba(0,200,255,.25);
  color: var(--blue);
}
/* Not-on-list variant — two-part with Patreon nudge */
.alert-unlisted {
  flex-direction: column;
  gap: .4rem;
  background: rgba(255,66,77,.07);
  border: 1px solid rgba(255,66,77,.28);
  color: var(--text-2);
  animation: shake .35s ease;
}
.alert-unlisted .al-head {
  display: flex; align-items: center; gap: .5rem;
  color: var(--pat);
  text-shadow: 0 0 8px var(--pat-glow);
  font-weight: 600;
}
.alert-unlisted a {
  color: var(--pat); text-decoration: none;
  border-bottom: 1px solid rgba(255,66,77,.3);
  transition: border-color .15s;
}
.alert-unlisted a:hover { border-color: rgba(255,66,77,.7); }

/* ── Form fields ──────────────────────────────────────────────────────────── */
.field { display: flex; flex-direction: column; gap: .45rem; }

.field label {
  font-family: 'Share Tech Mono', monospace;
  font-size: .62rem;
  letter-spacing: .15em;
  text-transform: uppercase;
  color: var(--blue);
  text-shadow: 0 0 8px rgba(0,200,255,.35);
}

.field input[type="email"],
.field input[type="number"] {
  width: 100%;
  padding: .8rem 1rem;
  font-family: 'Share Tech Mono', monospace;
  font-size: .9rem;
  color: var(--text);
  background: rgba(255,255,255,.03);
  border: 1px solid var(--border-2);
  border-radius: var(--r);
  outline: none;
  transition: border-color .2s, box-shadow .2s, background .2s;
  /* larger tap target on mobile */
  min-height: 48px;
  appearance: textfield;
  -moz-appearance: textfield;
}
.field input[type="number"]::-webkit-outer-spin-button,
.field input[type="number"]::-webkit-inner-spin-button { -webkit-appearance: none; }
.field input::placeholder { color: var(--text-3); }

.field input[type="email"]:focus {
  border-color: var(--blue);
  background: rgba(0,200,255,.04);
  box-shadow: 0 0 0 3px rgba(0,200,255,.1);
}
.field input[type="number"]:focus {
  border-color: var(--green);
  background: rgba(0,232,122,.03);
  box-shadow: 0 0 0 3px rgba(0,232,122,.1);
}

/* captcha row */
.captcha-row { display: flex; gap: .6rem; align-items: stretch; }
.captcha-eq {
  display: flex;
  align-items: center;
  padding: 0 .9rem;
  font-family: 'Share Tech Mono', monospace;
  font-size: 1rem;
  white-space: nowrap;
  color: var(--orange);
  background: rgba(255,136,0,.07);
  border: 1px solid rgba(255,136,0,.22);
  border-radius: var(--r);
  user-select: none;
  text-shadow: 0 0 8px rgba(255,136,0,.45);
  min-height: 48px;
  flex-shrink: 0;
}
.captcha-row .field { flex: 1; }

/* ── Submit button ────────────────────────────────────────────────────────── */
.btn-submit {
  width: 100%;
  min-height: 50px;
  padding: .9rem 1.5rem;
  background: var(--green);
  color: #050510;
  font-family: 'Inter', sans-serif;
  font-size: .9rem;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  border: none;
  border-radius: var(--r);
  cursor: pointer;
  position: relative;
  overflow: hidden;
  transition: transform .15s, box-shadow .2s;
  box-shadow: 0 0 20px rgba(0,232,122,.25), 0 0 40px rgba(0,232,122,.08);
}
.btn-submit::before {
  content: '';
  position: absolute; inset: 0;
  background: linear-gradient(90deg, transparent, rgba(255,255,255,.18), transparent);
  transform: translateX(-100%);
  transition: transform .5s ease;
}
.btn-submit:hover {
  box-shadow: 0 0 28px rgba(0,232,122,.45), 0 0 55px rgba(0,232,122,.15);
  transform: translateY(-1px);
}
.btn-submit:hover::before { transform: translateX(100%); }
.btn-submit:active { transform: scale(.985); }

/* ── Footer ───────────────────────────────────────────────────────────────── */
.form-footer {
  font-family: 'Share Tech Mono', monospace;
  font-size: .65rem;
  color: var(--text-3);
  text-align: center;
  letter-spacing: .05em;
  line-height: 1.8;
}
.form-footer a {
  color: rgba(255,66,77,.5);
  text-decoration: none;
  transition: color .15s;
}
.form-footer a:hover { color: rgba(255,66,77,.85); }

/* ════════════════════════════════════════════════════════════════════════════
   DENIED PAGE
   ════════════════════════════════════════════════════════════════════════════ */
.denied-wrap {
  width: 100%;
  max-width: 420px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: calc(var(--r) + 2px);
  padding: 2.5rem 2rem;
  display: flex;
  flex-direction: column;
  gap: 1.1rem;
  animation: rise .45s cubic-bezier(.22,.68,0,1.2) both;
  box-shadow: 0 4px 60px rgba(0,0,0,.7);
  position: relative;
  overflow: hidden;
}
.denied-wrap::before {
  content: '';
  position: absolute;
  top: 0; left: 0; right: 0; height: 2px;
  background: linear-gradient(90deg, var(--red), var(--pat), var(--orange), var(--red));
  background-size: 200% 100%;
  animation: shimmer 3s linear infinite;
}
.denied-icon {
  width: 52px; height: 52px; border-radius: 50%;
  background: rgba(255,51,85,.1);
  border: 1px solid rgba(255,51,85,.3);
  display: flex; align-items: center; justify-content: center;
  box-shadow: 0 0 20px rgba(255,51,85,.15);
  color: var(--red);
}
.denied-title {
  font-size: 1.8rem; font-weight: 700;
  letter-spacing: -.01em;
  background: linear-gradient(120deg, var(--red) 0%, #ff80a0 100%);
  -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text;
}
.denied-body {
  font-size: .88rem; color: var(--text-2); line-height: 1.7;
}
.denied-code {
  font-family: 'Share Tech Mono', monospace; font-size: .73rem;
  color: var(--red); background: rgba(255,51,85,.06);
  border: 1px solid rgba(255,51,85,.18); border-radius: var(--r);
  padding: .6rem 1rem; letter-spacing: .06em;
}
.denied-code::before { content: '// '; opacity: .5; }
</style>
<?php }

// ═════════════════════════════════════════════════════════════════════════════
// DENIED PAGE
// ═════════════════════════════════════════════════════════════════════════════

function gate_render_denied(string $email): never {
    http_response_code(403);
?><!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Access Denied</title>
<?php gate_styles(); ?>
</head>
<body>
<div class="denied-wrap">
  <div class="denied-icon">
    <svg width="22" height="22" viewBox="0 0 24 24" fill="none"
         stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
      <circle cx="12" cy="12" r="10"/>
      <line x1="4.93" y1="4.93" x2="19.07" y2="19.07"/>
    </svg>
  </div>
  <div class="denied-title">Account Suspended</div>
  <p class="denied-body">
    Access for this email address has been revoked.
  </p>
  <p class="denied-code">status: 403 forbidden &nbsp;|&nbsp; contact to appeal</p>
</div>
</body>
</html>
<?php exit; }

// ═════════════════════════════════════════════════════════════════════════════
// GATE FORM
// ═════════════════════════════════════════════════════════════════════════════

$is_info_msg = $gate_form_error !== '' && str_contains($gate_form_error, 'session was ended');

?><!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Members Access</title>
<?php gate_styles(); ?>
</head>
<body>

<div class="gate-wrap">

  <!-- ══════════════════════════════════════════════════════════════════════
       LEFT / TOP — Patreon CTA panel
       ══════════════════════════════════════════════════════════════════════ -->
  <div class="panel-cta">

    <div class="cta-eyebrow">
      <span class="icon-patreon" aria-hidden="true">
        <!-- Patreon 'P' wordmark -->
        <svg width="12" height="14" viewBox="0 0 12 14" fill="white" xmlns="http://www.w3.org/2000/svg">
          <ellipse cx="7.5" cy="4.8" rx="4.5" ry="4.5"/>
          <rect x="0" y="0" width="2.8" height="14" rx="1.2"/>
        </svg>
      </span>
      Membership via Patreon
    </div>

    <div>
      <div class="cta-headline">
        Get <span>free access</span><br>by joining my Patreon
      </div>
    </div>

    <p class="cta-body">
      This area is open to all my Patreon members — <strong>no payment required.</strong>
      Simply join as a free member and your email is added to the access list.
      You can choose to upgrade to a paid tier anytime to support the work and unlock extra perks.
    </p>

    <!-- 24-hour notice -->
    <div class="notice-24h" role="note">
      <span class="notice-icon" aria-hidden="true">
        <svg width="16" height="16" viewBox="0 0 24 24" fill="none"
             stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
          <circle cx="12" cy="12" r="10"/>
          <polyline points="12 6 12 12 16 14"/>
        </svg>
      </span>
      <div>
        <strong>Sign up at least 24 hours before your first visit.</strong>
        After joining Patreon, it may take up to 24 hours for your email to
        be synced and activated on the access list. Plan ahead!
      </div>
    </div>

    <!-- Tier breakdown -->
    <ul class="tier-list" aria-label="Membership tiers">
      <li>
        <span class="tier-dot free" aria-hidden="true"></span>
        <span><strong>Free member</strong> — full access to this area, no charge</span>
      </li>
      <li>
        <span class="tier-dot paid" aria-hidden="true"></span>
        <span><strong>Paid tier</strong> — support the work &amp; unlock extra perks</span>
      </li>
    </ul>

    <!-- CTA button -->
    <a class="btn-patreon"
       href="<?= htmlspecialchars(GATE_PATREON_URL) ?>"
       target="_blank" rel="noopener noreferrer"
       aria-label="Join Patreon — free membership grants access">
      <svg width="14" height="16" viewBox="0 0 12 14" fill="white" aria-hidden="true">
        <ellipse cx="7.5" cy="4.8" rx="4.5" ry="4.5"/>
        <rect x="0" y="0" width="2.8" height="14" rx="1.2"/>
      </svg>
      Join Free on Patreon
    </a>
    <p class="btn-patreon-sub">
      Already a paid member? &nbsp;<a href="<?= htmlspecialchars(GATE_PATREON_URL) ?>" target="_blank" rel="noopener">Manage your tier →</a>
    </p>

  </div>

  <!-- ══════════════════════════════════════════════════════════════════════
       RIGHT / BOTTOM — Login form panel
       ══════════════════════════════════════════════════════════════════════ -->
  <div class="panel-form">

    <div>
      <p class="form-eyebrow">Already a member</p>
      <h1 class="form-title">Sign in with<br>your Patreon email</h1>
    </div>

    <p class="form-hint">
      Use the email address linked to your Patreon account.
    </p>

    <!-- ── Alerts ── -->
    <?php if ($gate_show_patreon): ?>
    <div class="alert alert-unlisted" role="alert">
      <div class="al-head">
        <svg width="14" height="14" viewBox="0 0 15 15" fill="none" aria-hidden="true">
          <circle cx="7.5" cy="7.5" r="6.5" stroke="currentColor"/>
          <path d="M7.5 4v4M7.5 10.5v.5" stroke="currentColor" stroke-linecap="round"/>
        </svg>
        <?= htmlspecialchars($gate_form_error) ?>
      </div>
      <div>
        That address hasn't been activated yet.
        <a href="<?= htmlspecialchars(GATE_PATREON_URL) ?>" target="_blank" rel="noopener">Join Patreon as a free member</a>
        to get access — it may take up to 24 hours to sync after joining.
        If you joined recently, try again later.
      </div>
    </div>

    <?php elseif ($gate_form_error !== ''): ?>
    <div class="alert <?= $is_info_msg ? 'alert-info' : 'alert-error' ?>" role="alert">
      <svg width="14" height="14" viewBox="0 0 15 15" fill="none" aria-hidden="true">
        <circle cx="7.5" cy="7.5" r="6.5" stroke="currentColor"/>
        <path d="M7.5 4v4M7.5 10.5v.5" stroke="currentColor" stroke-linecap="round"/>
      </svg>
      <?= htmlspecialchars($gate_form_error) ?>
    </div>
    <?php endif; ?>

    <!-- ── Form ── -->
    <form method="POST" action="" novalidate>

      <div class="field" style="margin-bottom:var(--gap)">
        <label for="gate-email">Patreon email address</label>
        <input
          id="gate-email" type="email" name="email"
          autocomplete="email" placeholder="you@example.com"
          value="<?= htmlspecialchars($_POST['email'] ?? '') ?>"
          required autofocus
        >
      </div>

      <div style="margin-bottom:var(--gap)">
        <label style="
          display:block;
          font-family:'Share Tech Mono',monospace;
          font-size:.62rem; letter-spacing:.15em; text-transform:uppercase;
          color:var(--blue); text-shadow:0 0 8px rgba(0,200,255,.35);
          margin-bottom:.45rem;
        ">Verify — solve the equation</label>
        <div class="captcha-row">
          <div class="captcha-eq" aria-label="Captcha question: <?= htmlspecialchars($captcha_question) ?> equals what?">
            <?= htmlspecialchars($captcha_question) ?> =
          </div>
          <div class="field">
            <input
              type="number" name="captcha" inputmode="numeric"
              placeholder="?" min="0" max="99"
              required autocomplete="off"
              aria-label="Answer"
            >
          </div>
        </div>
      </div>

      <button type="submit" class="btn-submit">Go</button>
    </form>

    <p class="form-footer">
      Not a member yet?
      <a href="<?= htmlspecialchars(GATE_PATREON_URL) ?>" target="_blank" rel="noopener">Join free on Patreon</a>
      &nbsp;·&nbsp; Paid tier available &nbsp;·&nbsp; 24 hr activation
    </p>

  </div><!-- /panel-form -->

</div><!-- /gate-wrap -->

</body>
</html>
<?php exit;
