/* page-shell.jsx — extracted verbatim from pages.jsx. IIFE-scoped; exports via window. */
(function(){
const { useState, useMemo, useEffect, useRef } = React;
/**
 * @spec S-001 — Login
 * US-033. Email + password + optional MFA step. Success routes by role_type.
 * Since role selector lives in header for prototype, this page only handles the email/password/MFA dance.
 */
function LoginPage({ onLogin }) {
  const [step, setStep] = useState("credentials"); // credentials | mfa | forgot | forgot-sent
  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");
  const [code, setCode] = useState("");
  const [error, setError] = useState(null);
  const [remember, setRemember] = useState(true);
  const [resetEmail, setResetEmail] = useState("");

  const submit = () => {
    setError(null);
    if (step === "credentials") {
      if (!email || !password) { setError("Email and password are required."); return; }
      setStep("mfa");
    } else if (step === "mfa") {
      if (code.length < 4) { setError("Enter the 6-digit code from your authenticator."); return; }
      onLogin && onLogin();
    } else if (step === "forgot") {
      if (!resetEmail) { setError("Enter your work email to receive a reset link."); return; }
      setStep("forgot-sent");
    }
  };

  const titleFor = {
    credentials: "Sign in",
    mfa: "Two-factor verification",
    forgot: "Reset your password",
    "forgot-sent": "Check your inbox",
  }[step];

  return (
    <div className="login">
      <div style={{ display: "flex", flexDirection: "column", alignItems: "center", gap: 6 }}>
        <img src="assets/logo.svg" height="32" alt="sixhands"/>
        <div className="logo-sub">ADMIN CONSOLE</div>
      </div>

      <Card elevation="elevated" padding={28} style={{ width: 380, display: "flex", flexDirection: "column", gap: 16 }}>
        <div style={{ font: "700 22px/1.2 var(--font)", color: "var(--forest)" }}>{titleFor}</div>
        {error && <InlineAlert kind="error">{error}</InlineAlert>}

        {step === "credentials" && (
          <>
            <Field label="Work email">
              <Input value={email} onChange={setEmail} placeholder="you@sixhands.co" autoComplete="email" leftIcon={<span style={{ color: "var(--forest)" }}>{Ic.mail(18)}</span>}/>
            </Field>
            <Field label="Password">
              <Input type="password" value={password} onChange={setPassword} placeholder="••••••••" autoComplete="current-password"/>
            </Field>
            <div className="row jc-e ai-c">
              <button onClick={() => { setError(null); setResetEmail(email); setStep("forgot"); }}
                style={{ font: "600 13px/1 var(--font-ui)", color: "var(--forest)", textDecoration: "underline" }}>Forgot?</button>
            </div>
            <Btn variant="primary" block onClick={submit}>Continue</Btn>
          </>
        )}

        {step === "mfa" && (
          <>
            <div style={{ color: "var(--ink-2)", font: "500 14px/1.5 var(--font-ui)" }}>
              Enter the 6-digit code from your authenticator app.
            </div>
            <Field label="Authentication code">
              <Input value={code} onChange={v => setCode(v.replace(/\D/g, "").slice(0, 6))} placeholder="123 456" autoComplete="one-time-code"/>
            </Field>
            <Toggle on={remember} onToggle={() => setRemember(!remember)} label="Don't ask for a code on this device for 30 days."/>
            <div className="row jc-sb">
              <button onClick={() => setStep("credentials")} style={{ font: "600 13px/1 var(--font-ui)", color: "var(--ink-2)" }}>{Ic.arrL(14)} Back</button>
              <button style={{ font: "600 13px/1 var(--font-ui)", color: "var(--forest)" }}>Use recovery code</button>
            </div>
            <Btn variant="primary" block onClick={submit}>Verify & sign in</Btn>
          </>
        )}

        {step === "forgot" && (
          <>
            <div style={{ color: "var(--ink-2)", font: "500 14px/1.5 var(--font-ui)" }}>
              Enter your work email and we'll send you a link to reset your password.
            </div>
            <Field label="Work email">
              <Input value={resetEmail} onChange={setResetEmail} placeholder="you@sixhands.co" autoComplete="email"
                leftIcon={<span style={{ color: "var(--forest)" }}>{Ic.mail(18)}</span>}/>
            </Field>
            <Btn variant="primary" block onClick={submit}>Send reset link</Btn>
            <button onClick={() => { setError(null); setStep("credentials"); }}
              style={{ font: "600 13px/1 var(--font-ui)", color: "var(--ink-2)", textAlign: "center" }}>
              {Ic.arrL(14)} Back to sign in
            </button>
          </>
        )}

        {step === "forgot-sent" && (
          <>
            <InlineAlert kind="success">
              If that email exists, we sent a reset link. Check your inbox.
            </InlineAlert>
            <div style={{ color: "var(--ink-2)", font: "500 13px/1.5 var(--font-ui)" }}>
              Didn't receive it within a few minutes? Check your spam folder or contact your administrator.
            </div>
            <Btn variant="primary" block onClick={() => { setError(null); setStep("credentials"); }}>
              Back to sign in
            </Btn>
          </>
        )}
      </Card>

      <div style={{ font: "500 12px/1 var(--font-ui)", color: "var(--ink-2)", letterSpacing: ".08em" }}>
        PHASE 2 · PROTOTYPE · NOT FOR PRODUCTION
      </div>
    </div>
  );
}

/**
 * @spec X-001 — 403 Not permitted
 * US-111. Shows attempted path, user role, required role, and a "Back to dashboard" CTA.
 */
function Error403({ role = "GA", requiredRoles = [], attemptedPath }) {
  const path = attemptedPath || (typeof window !== "undefined" && window.__sixhands_lastRoute) || "/admin";
  const requiredValue = requiredRoles.length
    ? requiredRoles.map(r => <RoleBadge key={r} role={r}/>).reduce((a,b) => [a," ",b])
    : <span style={{ color: "var(--ink-2)" }}>Unknown — contact your admin</span>;
  const mailto = `mailto:admin@sixhands.co?subject=Access%20request&body=I%20need%20access%20to%20${encodeURIComponent(path)}%20(role:%20${role}).`;
  return (
    <div className="page-inner" style={{ maxWidth: 640, margin: "40px auto" }}>
      <Card elevation="soft" padding={32} style={{ display: "flex", flexDirection: "column", gap: 20 }}>
        <div style={{ font: "700 12px/1 var(--font-ui)", letterSpacing: ".14em", color: "var(--orange)" }}>ERROR · 403</div>
        <h1 className="h-page" style={{ fontSize: 36 }}>You don’t have access to this page.</h1>

        <InlineAlert kind="warn">
          Your role is missing one of the required permissions for this route. If you believe this is a mistake, contact your Country Manager or Global Admin.
        </InlineAlert>

        <KeyValueGrid
          columns={2}
          items={[
            { label: "Attempted path", value: path, mono: true },
            { label: "Your role", value: <RoleBadge role={role}/> },
            { label: "Required role(s)", value: requiredValue },
            { label: "Incident logged", value: "Yes — audit_logs" },
          ]}
        />

        <div className="row jc-e" style={{ gap: 10 }}>
          <Btn variant="ghost" onClick={() => { if (typeof window !== "undefined") window.location.href = mailto; }}>Request access</Btn>
          <Btn variant="secondary" onClick={() => typeof history !== "undefined" && history.back && history.back()}>Go back</Btn>
          <Btn variant="primary" onClick={() => { if (typeof window !== "undefined" && window.__sixhands_setRoute) window.__sixhands_setRoute("ga-dashboard"); }}>Back to dashboard</Btn>
        </div>
      </Card>
    </div>
  );
}

/**
 * @spec S-005 — Profile & account
 * US-033. View-only by default; Edit unlocks fields; Save/Cancel at top and bottom.
 */
function ProfilePage({ role = "GA", scope = {} }) {
  const [name, setName] = useState("Ju Hu");
  const [email, setEmail] = useState("juhu@humankind.design");
  const [phone, setPhone] = useState("+65 9123 4567");
  const [language, setLanguage] = useState("en-SG");
  const [timezone, setTimezone] = useState("Asia/Singapore");
  const [mfaOn, setMfaOn] = useState(true);
  const [mfaEnrolOpen, setMfaEnrolOpen] = useState(false);
  const [mfaCode, setMfaCode] = useState("");
  const [pushOn, setPushOn] = useState(false);
  const [savedToast, setSavedToast] = useState(false);
  const [editing, setEditing] = useState(false);

  const save = () => {
    setEditing(false);
    setSavedToast(true);
    setTimeout(() => setSavedToast(false), 2400);
  };
  const cancel = () => setEditing(false);

  // Scope string — one country for CM, country + area for AM, single outlet for OM
  const scopeLabel =
    role === "GA" ? "Global (all countries)" :
    role === "CM" ? (COUNTRY_LABEL[scope.countryId] || scope.countryId || "—") :
    role === "AM" ? `${COUNTRY_LABEL[scope.countryId] || scope.countryId || "—"} · ${AREA_LABEL[scope.areaId] || scope.areaId || "—"}` :
    role === "OM" ? `Outlet: ${scope.outletId || "—"}` :
    "—";

  const handleMfaToggle = () => {
    if (!mfaOn) {
      setMfaCode("");
      setMfaEnrolOpen(true);
    } else {
      setMfaOn(false);
    }
  };

  const confirmMfaEnrol = () => {
    if (mfaCode.length < 4) return;
    setMfaOn(true);
    setMfaEnrolOpen(false);
  };

  const pageActions = editing ? (
    <div className="row ai-c" style={{ gap: 8 }}>
      <Btn variant="secondary" onClick={cancel}>Cancel</Btn>
      <Btn variant="primary" onClick={save}>Save changes</Btn>
    </div>
  ) : (
    <Btn variant="primary" onClick={() => setEditing(true)}>Edit</Btn>
  );

  return (
    <div className="page-inner">
      <PageHead title="Account"
        description="Your profile, security, and preferences."
        actions={pageActions}/>

      <KeyValueGrid
        columns={2}
        items={[
          { label: "Role", value: <RoleBadge role={role}/> },
          { label: "Scope", value: scopeLabel },
          { label: "User ID", value: "0191-b2f4-7a58-4c9e-b13d-2a6ff05e8c71", mono: true },
          { label: "Last login", value: _syncCell("2026-06-04T00:14:00Z", "SG", MOCK_NOW) },
        ]}
      />

      <FormSection title="Personal details" description="Visible to your teammates in audit trails and notifications.">
        {/* ISSUE-030: OM personal details are managed upstream (AM / GA). Lock + explain. */}
        <Field label="Full name"><Input value={name} onChange={setName} autoComplete="name" disabled={!editing || role === "OM"}/></Field>
        <div className="row" style={{ gap: 16 }}>
          <div className="grow"><Field label="Email"><Input value={email} onChange={setEmail} autoComplete="email" disabled={!editing || role === "OM"} leftIcon={<span style={{ color: "var(--forest)" }}>{Ic.mail(16)}</span>}/></Field></div>
          <div className="grow"><Field label="Phone"><Input value={phone} onChange={setPhone} autoComplete="tel" disabled={!editing || role === "OM"} leftIcon={<span style={{ color: "var(--forest)" }}>{Ic.phone(16)}</span>}/></Field></div>
        </div>
        {role === "OM" && (
          <div style={{ ...T_MUTED, fontSize: 12 }}>
            Personal details can only be updated by your Area Manager or Global Admin. Contact them for changes.
          </div>
        )}
      </FormSection>

      {editing && (
        <FormSection title="Password" description="Use at least 12 characters with a mix of letters, numbers, and symbols.">
          <div className="row" style={{ gap: 16 }}>
            <div className="grow"><Field label="Current password"><Input type="password" placeholder="••••••••" autoComplete="current-password"/></Field></div>
            <div className="grow"><Field label="New password"><Input type="password" placeholder="••••••••" autoComplete="new-password"/></Field></div>
          </div>
          <Btn variant="secondary" size="sm">Update password</Btn>
        </FormSection>
      )}

      <FormSection title="Two-factor authentication" description="Required for Global and Country admins.">
        <Toggle on={mfaOn} onToggle={handleMfaToggle} label="Authenticator app enabled"/>
        {!mfaOn && <InlineAlert kind="warn">MFA is currently off. Your role requires MFA — re-enable to keep access.</InlineAlert>}
        <Btn variant="secondary" size="sm" disabled={!mfaOn}>Regenerate recovery codes</Btn>
      </FormSection>

      <FormSection title="Preferences">
        <Field label="Interface language">
          <Select value={language} onChange={setLanguage} placeholder="Choose language" disabled={!editing}>
            <option value="en-SG">English (Singapore)</option>
            <option value="en-PH">English (Philippines)</option>
            <option value="fil-PH">Filipino</option>
            <option value="id-ID">Bahasa Indonesia</option>
            <option value="th-TH">ไทย (Thai)</option>
          </Select>
        </Field>
        <Field label="Timezone">
          <Select value={timezone} onChange={setTimezone} placeholder="Choose timezone" disabled={!editing}>
            <option value="Asia/Singapore">Asia/Singapore (SGT)</option>
            <option value="Asia/Manila">Asia/Manila (PHT)</option>
            <option value="Asia/Jakarta">Asia/Jakarta (WIB)</option>
            <option value="Asia/Bangkok">Asia/Bangkok (ICT)</option>
          </Select>
          <div style={{ font: "500 12px/1.4 var(--font-ui)", color: "var(--ink-2)", marginTop: 4 }}>
            Takes effect on next page load.
          </div>
        </Field>
        <Toggle on={pushOn} onToggle={() => editing && setPushOn(!pushOn)} label="Email me when a system alert matches my scope"/>
      </FormSection>

      {editing && (
        <div className="row jc-e" style={{ gap: 8, paddingTop: 8 }}>
          <Btn variant="secondary" onClick={cancel}>Cancel</Btn>
          <Btn variant="primary" onClick={save}>Save changes</Btn>
        </div>
      )}

      <Toast message="Profile saved." show={savedToast}/>

      {/* MFA enrolment modal */}
      {mfaEnrolOpen && (
        <>
          <div className="sub-scrim open" onClick={() => setMfaEnrolOpen(false)} style={{ zIndex: 80 }}/>
          <div role="dialog" aria-modal="true" style={{
            position: "absolute", top: "50%", left: "50%", transform: "translate(-50%,-50%)",
            background: "var(--cream)", borderRadius: "var(--r-lg)",
            boxShadow: "var(--shadow-modal)", padding: 28, width: 440, zIndex: 90,
            display: "flex", flexDirection: "column", gap: 16,
          }}>
            <div style={{ font: "700 22px/1.2 var(--font)", color: "var(--forest)" }}>Set up authenticator</div>
            <div style={{ font: "500 14px/1.5 var(--font-ui)", color: "var(--ink-2)" }}>
              Scan this QR code with your authenticator app (1Password, Authy, Google Authenticator), then enter the first 6-digit code below.
            </div>
            <div style={{
              width: 160, height: 160, alignSelf: "center",
              background: `repeating-conic-gradient(var(--ink) 0% 25%, var(--cream) 0% 50%) 50% / 20px 20px`,
              border: "1.5px solid var(--line)", borderRadius: "var(--r)",
            }} aria-label="QR code placeholder"/>
            <Field label="Enter first code">
              <Input value={mfaCode} onChange={v => setMfaCode(v.replace(/\D/g, "").slice(0, 6))} placeholder="123 456" autoComplete="one-time-code"/>
            </Field>
            <button style={{ font: "600 13px/1 var(--font-ui)", color: "var(--forest)", textDecoration: "underline", alignSelf: "flex-start" }}>
              Save recovery codes
            </button>
            <div className="row jc-e" style={{ gap: 10 }}>
              <Btn variant="secondary" onClick={() => setMfaEnrolOpen(false)}>Cancel</Btn>
              <Btn variant="primary" onClick={confirmMfaEnrol} disabled={mfaCode.length < 4}>Confirm & enable</Btn>
            </div>
          </div>
        </>
      )}
    </div>
  );
}

/**
 * @spec X-003 — Help & support
 * Static links: docs, contact, system status, version.
 */
function HelpPage() {
  const groups = [
    {
      title: "Documentation",
      items: [
        { icon: Ic.cube(18), label: "Admin handbook", sub: "Role guides, onboarding playbooks, field glossary.", href: "#" },
        { icon: Ic.sparkle(18), label: "Release notes", sub: "What changed in the last 30 days.", href: "#" },
        { icon: Ic.tag(18), label: "Country onboarding checklist", sub: "Step-by-step protocol for new markets.", href: "#" },
      ],
    },
    {
      title: "Account & access",
      items: [
        { icon: Ic.user(18), label: "Trouble signing in?", sub: "Reset your password via the sign-in screen.", href: "mailto:admin@sixhands.co?subject=Password%20reset%20help" },
      ],
    },
    {
      title: "Get in touch",
      items: [
        { icon: Ic.mail(18), label: "support@sixhands.co", sub: "Response within 1 business day.", href: "mailto:support@sixhands.co" },
        { icon: Ic.phone(18), label: "+65 6000 0000", sub: "Mon–Fri 09:00–18:00 SGT.", href: "tel:+6560000000" },
      ],
    },
    {
      title: "System status",
      items: [
        { icon: Ic.check(18), label: "All services operational", sub: "Last checked 2 minutes ago.", href: "#" },
        { icon: Ic.clock(18), label: "Scheduled maintenance", sub: "Sun 02:00–03:00 SGT · POS sync pause.", href: "#" },
      ],
    },
  ];

  return (
    <div className="page-inner">
      <PageHead title="Help & support"/>
      <InlineAlert kind="note">
        Looking for a specific screen? The admin handbook has a full map with role-by-role access.
      </InlineAlert>

      {groups.map(g => (
        <FormSection key={g.title} title={g.title}>
          <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fill, minmax(280px, 1fr))", gap: 12 }}>
            {g.items.map((it, i) => (
              <Card key={i} interactive as="a" padding={16}
                style={{ textDecoration: "none", display: "flex", gap: 12, alignItems: "flex-start", borderRadius: "var(--r)" }}
                className=""
                onClick={() => { if (typeof window !== "undefined" && it.href && it.href !== "#") window.location.href = it.href; }}
              >
                <span style={{
                  width: 36, height: 36, borderRadius: 10,
                  background: "var(--mint-soft)", color: "var(--forest)",
                  display: "inline-flex", alignItems: "center", justifyContent: "center",
                  flexShrink: 0,
                }}>{it.icon}</span>
                <div style={{ display: "flex", flexDirection: "column", gap: 4, minWidth: 0 }}>
                  <span style={{ ...T.primary() }}>{it.label}</span>
                  <span style={{ font: "500 13px/1.4 var(--font-ui)", color: "var(--ink-2)" }}>{it.sub}</span>
                </div>
              </Card>
            ))}
          </div>
        </FormSection>
      ))}

      <div style={{ display: "flex", gap: 24, font: "500 12px/1 var(--font-ui)", color: "var(--ink-2)", letterSpacing: ".06em" }}>
        <span>Version 2.0.0-alpha.3</span>
        <span>Build 2026-04-22</span>
        <span>API v2</span>
      </div>
    </div>
  );
}

/**
 * @spec X-002 — Notifications inbox
 * US-080/085/111. Role-filtered feed of system alerts; click opens DetailDrawer.
 */
function InboxPage({ role = "GA", scope = {} }) {
  // Mock data — aligned to spec-03 fields:
  // country_id, entity_type + entity_id (match audit_logs pattern), read_at (null = unread).
  const all = useMemo(() => [
    { id: "n1", kind: "payment", sev: "error",   title: "Stripe gateway errored (PH)", body: "3 consecutive auth failures on franchisee SH-PH-003 merchant account.", ts: "08:42",      country_id: "PH", area_id: null,            outlet_id: null,         status: "errored", entity_type: "franchisee", entity_id: "SH-PH-003",         read_at: null },
    { id: "n2", kind: "sync",    sev: "warn",    title: "POS sync stale — SH-PH-004",   body: "No inventory heartbeat for 18 minutes (SLA 10).",                         ts: "08:10",      country_id: "PH", area_id: "metro-manila", outlet_id: "SH-PH-004",  status: "stale",   entity_type: "outlet",     entity_id: "SH-PH-004",         read_at: null },
    { id: "n3", kind: "audit",   sev: "info",    title: "CM-PH invited 2 new Outlet Managers", body: "Reyes, Cruz — pending invite acceptance.",                         ts: "Yesterday",  country_id: "PH", area_id: null,            outlet_id: null,         status: "info",    entity_type: "user",       entity_id: "invite_batch_91",   read_at: "2026-04-21T10:12:00Z" },
    { id: "n4", kind: "config",  sev: "info",    title: "Country onboarding 83% complete (PH)", body: "Remaining: loyalty catalog upload, legal review sign-off.",        ts: "Yesterday",  country_id: "PH", area_id: null,            outlet_id: null,         status: "pending", entity_type: "country",    entity_id: "PH",                read_at: "2026-04-21T09:30:00Z" },
    { id: "n5", kind: "payment", sev: "success", title: "Reconciliation matched — SG",  body: "All 412 orders settled against Stripe for 2026-04-21.",                   ts: "2d ago",     country_id: "SG", area_id: null,            outlet_id: null,         status: "healthy", entity_type: "country",    entity_id: "SG",                read_at: "2026-04-20T22:00:00Z" },
    { id: "n6", kind: "sync",    sev: "warn",    title: "POS sync stale — SH-PH-004 (repeat)", body: "Recovered after 4 minutes.",                                       ts: "3d ago",     country_id: "PH", area_id: "metro-manila", outlet_id: "SH-PH-004",  status: "ok",      entity_type: "outlet",     entity_id: "SH-PH-004",         read_at: null },
  ], []);

  // Scope + role baseline filter (spec-02). OM has no payment-gateway visibility.
  const scoped = useMemo(() => all.filter(n => {
    if (role === "GA") return true;
    if (role === "CM") return n.country_id === scope.countryId;
    if (role === "AM") return n.country_id === scope.countryId && (!n.area_id || n.area_id === scope.areaId);
    if (role === "OM") return n.outlet_id === scope.outletId && (n.kind === "sync" || n.kind === "audit");
    return false;
  }), [all, role, scope.countryId, scope.areaId, scope.outletId]);

  // Read-state held locally (mock) so the mark-read toggle works visually.
  const [readState, setReadState] = useState({});
  const isRead = (n) => readState[n.id] != null ? readState[n.id] : !!n.read_at;
  const toggleRead = (n) => setReadState(s => ({ ...s, [n.id]: !isRead(n) ? new Date().toISOString() : null }));

  const [filters, setFilters] = useState({});
  const [searchQuery, setSearchQuery] = useState("");
  const [selected, setSelected] = useState(null);

  // Country filter options derived from what the current role can see.
  const countryOptions = useMemo(() => {
    const seen = new Set(scoped.map(n => n.country_id).filter(Boolean));
    const map = { SG: "Singapore", PH: "Philippines", ID: "Indonesia", TH: "Thailand" };
    return Array.from(seen).map(c => ({ value: c, label: map[c] || c }));
  }, [scoped]);

  const visible = scoped.filter(n =>
    (!filters.country || n.country_id === filters.country) &&
    (!filters.kind    || n.kind       === filters.kind) &&
    (!filters.read    || (filters.read === "unread" ? !isRead(n) : isRead(n))) &&
    (!filters.status  || n.status === filters.status)
  );

  // Kind-aware actions for the detail drawer
  const actionsForKind = (n) => {
    if (!n) return null;
    if (n.kind === "payment") return (
      <>
        <Btn variant="secondary" size="sm">Open integration</Btn>
        <Btn variant="primary"   size="sm">Test connection</Btn>
      </>
    );
    if (n.kind === "sync") return (
      <>
        <Btn variant="secondary" size="sm">Open outlet</Btn>
        <Btn variant="primary"   size="sm">Retry POS sync</Btn>
      </>
    );
    if (n.kind === "audit") return <Btn variant="primary" size="sm">Open audit log entry</Btn>;
    if (n.kind === "config") return <Btn variant="primary" size="sm">Open setting</Btn>;
    return <Btn variant="secondary" size="sm" onClick={() => setSelected(null)}>Close</Btn>;
  };

  // ISSUE-015 (2): notification status pills use the `notif` kind so stale (amber)
  // and pending (info/blue) are visually distinct from each other.
  const pillKindFor = () => "notif";

  return (
    <div className="page-inner">
      <PageHead title="Notifications"
        description="System alerts and activity updates across your scope."
        actions={
          <div className="row ai-c" style={{ gap: 8 }}>
            <Btn variant="ghost" size="sm"
              onClick={() => setReadState({})}>
              Clear all
            </Btn>
            <Btn variant="secondary" size="sm"
              onClick={() => setReadState(Object.fromEntries(scoped.map(n => [n.id, new Date().toISOString()])))}>
              Mark all read
            </Btn>
          </div>
        }/>

      <FilterBar
        primaryFilter={{ key: "status", label: "Status", options: [
          { value: "",        label: "All statuses" },
          { value: "errored", label: "Errored" },
          { value: "stale",   label: "Stale" },
          { value: "pending", label: "Pending" },
          { value: "info",    label: "Info" },
          { value: "ok",      label: "OK" },
          { value: "healthy", label: "Healthy" },
        ]}}
        primaryValue={filters.status || ""}
        onPrimaryChange={v => setFilters({ ...filters, status: v })}
        advancedFilters={[
          // Hide Country for CM/AM/OM (already scoped); show for GA only.
          ...(role === "GA" ? [{ key: "country", kind: "select", label: "Country", options: [{ value: "", label: "All countries" }, ...countryOptions] }] : []),
          { key: "kind", kind: "select", label: "Type", options: [
            { value: "",        label: "All types" },
            { value: "payment", label: "Payment" },
            { value: "sync",    label: "Sync" },
            { value: "audit",   label: "Audit" },
            { value: "config",  label: "Config" },
          ]},
          { key: "read", kind: "select", label: "Read state", options: [
            { value: "",       label: "All" },
            { value: "unread", label: "Unread" },
            { value: "read",   label: "Read" },
          ]},
        ]}
        advancedValues={filters}
        onAdvancedChange={(k, v) => setFilters({ ...filters, [k]: v })}
        onAdvancedReset={() => setFilters(f => ({ status: f.status || "" }))}
        onReset={() => setFilters({})}
        search={searchQuery}
        onSearch={setSearchQuery}
        searchPlaceholder="Search notifications…"
      />

      {visible.length === 0 ? (
        <EmptyState icon={Ic.bell(32)} title="Nothing here." body="No notifications match your filters. Try resetting or widening the date range."/>
      ) : (
        <div style={{ display: "flex", flexDirection: "column", gap: 10 }}>
          {visible.map(n => {
            const read = isRead(n);
            return (
              <div key={n.id} className="notif-item"
                style={{ textAlign: "left", width: "100%", border: read ? "1.5px solid var(--line)" : "1.5px solid var(--forest)", cursor: "pointer" }}
                onClick={() => setSelected(n)}>
                <span className={`dot ${read ? "read" : ""}`}/>
                <div className="content">
                  <div className="row ai-c" style={{ gap: 8, flexWrap: "wrap" }}>
                    <span className="t">{n.title}</span>
                    <StatusPill status={n.status} kind={pillKindFor(n)}/>
                    <span style={{ font: "500 12px/1 var(--font-ui)", color: "var(--mint)", letterSpacing: ".04em" }}>· {n.country_id}</span>
                  </div>
                  <div className="m">{n.body}</div>
                  <div className="meta">{n.ts} · {n.entity_type}:{n.entity_id}</div>
                </div>
                <button
                  onClick={e => { e.stopPropagation(); toggleRead(n); }}
                  style={{
                    alignSelf: "flex-start",
                    font: "600 12px/1 var(--font-ui)",
                    color: "var(--forest)",
                    padding: "6px 10px",
                    borderRadius: "var(--r-pill)",
                    border: "1.5px solid var(--line)",
                    background: "transparent",
                  }}
                  aria-label={read ? "Mark unread" : "Mark read"}
                >
                  {read ? "Mark unread" : "Mark read"}
                </button>
              </div>
            );
          })}
        </div>
      )}

      <DetailDrawer
        open={!!selected}
        onClose={() => setSelected(null)}
        title={selected && selected.title}
        subtitle={selected && `${selected.country_id} · ${selected.ts}`}
        actions={actionsForKind(selected)}
      >
        {selected && (
          <>
            <InlineAlert kind={selected.sev === "error" ? "error" : selected.sev === "warn" ? "warn" : selected.sev === "success" ? "success" : "info"}>
              {selected.body}
            </InlineAlert>
            <KeyValueGrid
              columns={2}
              items={[
                { label: "Type",        value: selected.kind },
                { label: "Severity",    value: selected.sev },
                { label: "Country",     value: selected.country_id },
                { label: "Entity type", value: selected.entity_type },
                { label: "Entity id",   value: selected.entity_id, mono: true },
                { label: "Received",    value: selected.ts },
                { label: "Read state",  value: isRead(selected) ? "Read" : "Unread" },
              ]}
            />
          </>
        )}
      </DetailDrawer>
    </div>
  );
}

// ── Global Admin (T1) ────────────────────────────────────────────────

Object.assign(window, { LoginPage, Error403, ProfilePage, HelpPage, InboxPage });
})();
