/* global React, Common, I18n */
const { Eyebrow, SectionTitle, Card } = Common;
const { useT, useI18n } = I18n;
const { useEffect, useRef, useState } = React;

// =============================================================
// Privacy page. Mirrors the live PRIVACY.md ground truth in the
// app repo so the website never drifts from what the binary
// actually does. Sections expose stable id="..." anchors so we
// can deep-link (e.g. /privacy#data).
// =============================================================

const COPY = {
  lastUpdated: { en: "Last updated: 2026-05-11", it: "Ultimo aggiornamento: 11 maggio 2026" },
  eyebrow: { en: "privacy", it: "privacy" },
  title: {
    en: ["Your voice doesn't", "leave your machine."],
    it: ["La tua voce non", "lascia il tuo computer."],
  },
  lead: {
    en: "Dimmy runs locally by default. We collect a deliberately small amount of anonymous telemetry to understand how the app is used and to fix crashes. Never enough to identify you, never enough to recover what you said.",
    it: "Dimmy gira di default sul tuo computer. Raccogliamo deliberatamente una piccola quantità di telemetria anonima per capire come l'app viene usata e correggere i crash. Mai abbastanza per identificarti, mai abbastanza per ricostruire ciò che hai detto.",
  },
  disableHint: {
    en: ["Disable it any time in", "Settings → Privacy", "(each toggle is independent)."],
    it: ["Puoi disattivare tutto in qualsiasi momento da", "Impostazioni → Privacy", "(ogni interruttore è indipendente)."],
  },

  tocTitle: { en: "On this page", it: "In questa pagina" },
  toc: [
    { id: "tldr",     en: "TL;DR",                   it: "In breve" },
    { id: "data",     en: "What we collect",         it: "Cosa raccogliamo" },
    { id: "never",    en: "What we never collect",   it: "Cosa non raccogliamo mai" },
    { id: "where",    en: "Where the data goes",     it: "Dove finiscono i dati" },
    { id: "inspect",  en: "Inspect what's sent",     it: "Ispezionare ciò che viene inviato" },
    { id: "disable",  en: "How to disable",          it: "Come disattivare" },
    { id: "changes",  en: "Changes to this policy",  it: "Modifiche a questa policy" },
    { id: "contact",  en: "Contact",                 it: "Contatti" },
  ],

  tldrTitle:  { en: "TL;DR",                                       it: "In breve" },
  tldrPoints: {
    en: [
      "Local mode is the default. Audio and transcripts never leave your device.",
      "Telemetry is anonymous, opt-out, two independent toggles (analytics, crash reports).",
      "We send event names and numbers (counts, durations, error categories) to PostHog EU and Sentry EU. No audio, no text, no prompts, no IP, no API keys.",
      "Your API keys live encrypted on your machine with AES-256-GCM and a machine-bound key.",
      "No account, no signup, no email required.",
    ],
    it: [
      "La modalità locale è quella di default. Audio e trascrizioni non lasciano mai il dispositivo.",
      "La telemetria è anonima e opt-out: due interruttori indipendenti (analytics, crash report).",
      "Mandiamo nomi di eventi e numeri (conteggi, durate, categorie di errore) a PostHog EU e Sentry EU. Nessun audio, nessun testo, nessun prompt, nessun IP, nessuna API key.",
      "Le tue API key vivono cifrate sul tuo computer con AES-256-GCM legato alla macchina.",
      "Nessun account, nessuna registrazione, nessuna email richiesta.",
    ],
  },

  whatWeCollectTitle: { en: "What we collect", it: "Cosa raccogliamo" },
  whatWeCollectIntro: {
    en: "Every section below corresponds to specific code paths in the Rust core. The full list of events and their payloads is below.",
    it: "Ogni sezione qui sotto corrisponde a percorsi di codice precisi nel core Rust. La lista completa degli eventi e dei loro payload è qui sotto.",
  },

  // What never collect
  neverTitle: { en: "What we never collect", it: "Cosa non raccogliamo mai" },
  neverLead: {
    en: "There is no telemetry path in the codebase that sends any of the following. Audit the source if you want to verify, every send site is logged with [telemetry] in the local log.",
    it: "Non esiste alcun percorso di telemetria nel codice che invii quanto segue. Se vuoi verificare, controlla il sorgente: ogni invio è loggato localmente con [telemetry].",
  },
  neverItems: {
    en: [
      "The audio you record.",
      "The text of any transcription.",
      "Any prompt text (system, user, custom).",
      "Any LLM output.",
      "Names of contacts, files, or applications you transcribe into.",
      "Microphone device names or hardware fingerprints.",
      "File paths beyond a categorical \"where this kind of file lives\" tag (and even those are scrubbed).",
      "API keys. They live in ~/.config/dimmy/keys.enc, AES-256-GCM encrypted, and are sent only to the provider you configured.",
      "IP addresses. Sentry EU drops them server-side; PostHog is forced to $ip: null in every event.",
      "Username, hostname, email (the only exception is the explicit email you may type into the Feedback form).",
    ],
    it: [
      "L'audio che registri.",
      "Il testo di nessuna trascrizione.",
      "Nessun testo di prompt (sistema, utente, custom).",
      "Nessun output di LLM.",
      "Nomi di contatti, file o applicazioni in cui trascrivi.",
      "Nomi del dispositivo microfono o fingerprint hardware.",
      "Percorsi di file (oltre a un tag categorico \"dove vive questo tipo di file\", comunque ripulito).",
      "Le API key. Vivono in ~/.config/dimmy/keys.enc, cifrate con AES-256-GCM, e vengono inviate solo al provider che hai configurato.",
      "Gli indirizzi IP. Sentry EU li scarta lato server; PostHog è forzato a $ip: null in ogni evento.",
      "Username, hostname, email (l'unica eccezione è l'email che inserisci esplicitamente nel modulo Feedback).",
    ],
  },

  // Where data goes
  whereTitle: { en: "Where the data goes", it: "Dove finiscono i dati" },
  whereIntro: {
    en: "Two destinations, both hardcoded in the binary, both in EU data centres, both GDPR-aligned.",
    it: "Due destinazioni, entrambe hardcoded nel binario, entrambe in data center europei, entrambe conformi al GDPR.",
  },
  whereItems: [
    {
      title: { en: "Analytics events", it: "Eventi di analytics" },
      target: "PostHog EU",
      host: "https://eu.i.posthog.com",
      desc: {
        en: "Anonymous usage events. The endpoint is hardcoded and cannot be overridden at runtime.",
        it: "Eventi di utilizzo anonimi. L'endpoint è hardcoded e non può essere sovrascritto a runtime.",
      },
    },
    {
      title: { en: "Crash reports + feedback", it: "Crash report e feedback" },
      target: "Sentry EU",
      host: "https://o*.ingest.de.sentry.io",
      desc: {
        en: "Stack traces, error messages (truncated and secret-redacted), and the optional text you submit through the Feedback form.",
        it: "Stack trace, messaggi di errore (troncati e con i segreti ripuliti), e il testo opzionale che invii tramite il modulo Feedback.",
      },
    },
  ],
  whereFooter: {
    en: "We control both projects. Only the Dimmy team can read the data.",
    it: "Entrambi i progetti sono nostri. Solo il team Dimmy può leggere i dati.",
  },

  // Inspect
  inspectTitle: { en: "Inspect what's being sent", it: "Ispezionare ciò che viene inviato" },
  inspectLead: {
    en: "Every telemetry call is logged locally. Open the log file and look for lines starting with [telemetry].",
    it: "Ogni chiamata di telemetria viene loggata localmente. Apri il file di log e cerca le righe che iniziano con [telemetry].",
  },
  inspectPaths: [
    { os: "Windows", path: "%APPDATA%\\dimmy\\dimmy.log" },
    { os: "macOS",   path: "~/.config/dimmy/dimmy.log" },
    { os: "Linux",   path: "~/.config/dimmy/dimmy.log" },
  ],
  inspectExample: {
    en: "Example of what you'll see in the log:",
    it: "Esempio di ciò che vedrai nel log:",
  },
  inspectKeyDiag: {
    en: "You can also confirm the PostHog and Sentry project keys embedded in the build: search for key-diag in the same log. The prefix is logged once per process, so you can verify we're sending to the project we claim and nowhere else.",
    it: "Puoi anche verificare le chiavi di progetto PostHog e Sentry incorporate nella build: cerca key-diag nello stesso log. Il prefisso viene loggato una volta per processo, così puoi confermare che inviamo al progetto dichiarato e a nessun altro.",
  },

  // Disable
  disableTitle: { en: "How to disable", it: "Come disattivare" },
  disableSteps: {
    en: [
      "Open the app, click the gear on the pill (or right-click the menu-bar / tray icon).",
      "Go to Privacy.",
      "Flip Send anonymous usage data off to stop PostHog analytics.",
      "Flip Send crash reports off to stop Sentry.",
      "Each toggle takes effect immediately for events emitted after the flip. Events already sent cannot be recalled.",
    ],
    it: [
      "Apri l'app, clicca l'ingranaggio sulla pill (o fai click destro sull'icona della menu-bar / tray).",
      "Vai su Privacy.",
      "Disattiva Invia dati di utilizzo anonimi per fermare gli analytics PostHog.",
      "Disattiva Invia report di crash per fermare Sentry.",
      "Ogni interruttore ha effetto immediato sugli eventi futuri. Gli eventi già inviati non possono essere ritirati.",
    ],
  },
  disableExtra: {
    en: "Want to start fresh? Settings → Privacy → Reset anonymous ID rotates your per-install UUID.",
    it: "Vuoi ricominciare da zero? Impostazioni → Privacy → Reset anonymous ID rigenera lo UUID per-installazione.",
  },

  // Changes
  changesTitle: { en: "Changes to this policy", it: "Modifiche a questa policy" },
  changesBody: {
    en: "Material changes are announced in the release notes. The ground truth lives in PRIVACY.md inside the app repository. Run git log PRIVACY.md to see the full history of changes.",
    it: "Le modifiche sostanziali sono annunciate nelle note di rilascio. La fonte autorevole è PRIVACY.md nel repository dell'app. Esegui git log PRIVACY.md per vedere lo storico completo.",
  },

  // Contact
  contactTitle: { en: "Contact", it: "Contatti" },
  contactBody: {
    en: "Questions, deletion requests, or anything else: konrad.dalla@gmail.com. Security issues: security@dimmy.app.",
    it: "Domande, richieste di cancellazione o qualsiasi altra cosa: konrad.dalla@gmail.com. Problemi di sicurezza: security@dimmy.app.",
  },
};

// Buckets: each one becomes a subsection under #data.
const DATA_BUCKETS = [
  {
    id: "data-installation",
    icon: "id",
    title: { en: "Per-install identifier", it: "Identificatore per-installazione" },
    body: {
      en: "A random UUIDv4 generated on first launch, stored locally in ~/.config/dimmy/analytics_id (or %APPDATA%\\dimmy\\analytics_id on Windows). It only exists to de-duplicate \"1 user did X 5 times\" from \"5 users each did X once\". Reset it any time from Settings → Privacy → Reset anonymous ID. It is never linked to anything that could identify you.",
      it: "Un UUIDv4 casuale generato al primo avvio, salvato localmente in ~/.config/dimmy/analytics_id (oppure %APPDATA%\\dimmy\\analytics_id su Windows). Esiste solo per distinguere \"1 utente che fa X 5 volte\" da \"5 utenti che fanno X una volta\". Puoi rigenerarlo in qualsiasi momento da Impostazioni → Privacy → Reset anonymous ID. Non è mai collegato a nulla che possa identificarti.",
    },
  },
  {
    id: "data-session",
    icon: "session",
    title: { en: "Per-process session identifier", it: "Identificatore di sessione" },
    body: {
      en: "A fresh UUIDv4 generated on each app launch, not persisted. Lets us answer questions like \"how many transcriptions per session?\" without tracking open or close events.",
      it: "Un UUIDv4 nuovo generato a ogni avvio dell'app, non persistito. Ci permette di rispondere a domande come \"quante trascrizioni per sessione?\" senza tracciare eventi di apertura o chiusura.",
    },
  },
  {
    id: "data-platform",
    icon: "platform",
    title: { en: "Platform context", it: "Contesto di piattaforma" },
    body: {
      en: "Attached to every event:",
      it: "Allegato a ogni evento:",
    },
    items: {
      en: [
        "App version (e.g. 0.6.27).",
        "Operating system family (windows / macos / linux).",
        "CPU architecture (x86_64 / aarch64).",
      ],
      it: [
        "Versione dell'app (es. 0.6.27).",
        "Famiglia di sistema operativo (windows / macos / linux).",
        "Architettura CPU (x86_64 / aarch64).",
      ],
    },
  },
  {
    id: "data-lifecycle",
    icon: "lifecycle",
    title: { en: "Lifecycle events", it: "Eventi del ciclo di vita" },
    items: {
      en: [
        { ev: "app.started",       desc: "When the app launches. Includes cold-start time in milliseconds." },
        { ev: "app.session_ended", desc: "When the app closes. Includes total session duration (seconds) and number of transcriptions in the session." },
      ],
      it: [
        { ev: "app.started",       desc: "Quando l'app si avvia. Include il tempo di cold-start in millisecondi." },
        { ev: "app.session_ended", desc: "Quando l'app si chiude. Include la durata totale della sessione (secondi) e il numero di trascrizioni effettuate." },
      ],
    },
  },
  {
    id: "data-transcription",
    icon: "transcription",
    title: { en: "Transcription events", it: "Eventi di trascrizione" },
    items: {
      en: [
        { ev: "transcription.completed", desc: "When a transcription succeeds. Path (local whisper.cpp vs cloud provider), provider category (groq / openai / anthropic / gemini / deepgram / openrouter / local: only the tag, never the URL or API key), audio duration in seconds, processing time in milliseconds, word count (the number only, never the words), language ISO code (e.g. en, it), whether filler removal ran (boolean), whether LLM post-processing ran (boolean)." },
        { ev: "transcription.failed",    desc: "Provider category and error category (e.g. 401, timeout)." },
        { ev: "transcription.cancelled", desc: "Audio duration up to the cancel." },
      ],
      it: [
        { ev: "transcription.completed", desc: "Quando una trascrizione va a buon fine. Percorso (local whisper.cpp vs cloud), categoria del provider (groq / openai / anthropic / gemini / deepgram / openrouter / local: solo il tag, mai URL o API key), durata audio in secondi, tempo di elaborazione in millisecondi, conteggio parole (solo il numero, mai le parole), codice lingua ISO (es. en, it), se il filler removal è stato eseguito (bool), se il post-processing LLM è stato eseguito (bool)." },
        { ev: "transcription.failed",    desc: "Categoria del provider e categoria di errore (es. 401, timeout)." },
        { ev: "transcription.cancelled", desc: "Durata audio fino al momento del cancel." },
      ],
    },
  },
  {
    id: "data-llm",
    icon: "llm",
    title: { en: "LLM post-processing events", it: "Eventi di post-processing LLM" },
    items: {
      en: [
        { ev: "llm.applied", desc: "Provider category, style name, tone name, processing time. Never the prompt. Never the output." },
        { ev: "llm.failed",  desc: "Provider category and error category." },
      ],
      it: [
        { ev: "llm.applied", desc: "Categoria del provider, nome dello stile, nome del tono, tempo di elaborazione. Mai il prompt. Mai l'output." },
        { ev: "llm.failed",  desc: "Categoria del provider e categoria di errore." },
      ],
    },
  },
  {
    id: "data-config",
    icon: "config",
    title: { en: "Configuration changes", it: "Modifiche di configurazione" },
    body: {
      en: "When you change any of these in Settings, we log that the change happened. For free-text fields we never log the value, just that something changed.",
      it: "Quando cambi una di queste impostazioni, logghiamo solo che il cambio è avvenuto. Per i campi a testo libero non logghiamo il valore, ma solo che qualcosa è cambiato.",
    },
    items: {
      en: [
        "STT mode toggle (local ↔ cloud)",
        "Cloud provider switch (categorical: groq → openai, etc.)",
        "LLM enabled toggle",
        "LLM style dropdown",
        "Preprocessing toggle",
        "Input gain slider value (number)",
      ],
      it: [
        "Toggle modalità STT (local ↔ cloud)",
        "Cambio provider cloud (categorico: groq → openai, ecc.)",
        "Toggle LLM abilitato",
        "Dropdown stile LLM",
        "Toggle preprocessing",
        "Valore slider input gain (numero)",
      ],
    },
    footer: {
      en: "Not tracked: prompt text, custom LLM prompt, microphone device name, shortcut combo string.",
      it: "Non tracciati: testo del prompt, prompt LLM custom, nome del dispositivo microfono, combinazione di scorciatoie.",
    },
  },
  {
    id: "data-feature",
    icon: "feature",
    title: { en: "Feature usage", it: "Uso delle feature" },
    items: {
      en: [
        { ev: "feature.hotkey_triggered", desc: "When the global hotkey starts a recording. Helps us understand whether people prefer hotkey or button." },
        { ev: "feature.api_key_set",      desc: "When you save an API key, we log the scope (stt / llm) and the provider category. The key itself never leaves your machine." },
      ],
      it: [
        { ev: "feature.hotkey_triggered", desc: "Quando l'hotkey globale avvia una registrazione. Ci aiuta a capire se la gente preferisce hotkey o bottone." },
        { ev: "feature.api_key_set",      desc: "Quando salvi una API key, logghiamo lo scope (stt / llm) e la categoria del provider. La chiave stessa non lascia mai il tuo computer." },
      ],
    },
  },
  {
    id: "data-perf",
    icon: "perf",
    title: { en: "Performance + stability", it: "Performance e stabilità" },
    items: {
      en: [
        { ev: "perf.startup_ms", desc: "Cold-start duration in milliseconds." },
        { ev: "perf.gpu_status", desc: "On each launch: which GPU backend was compiled (vulkan / cuda / metal / cpu), whether the previous launch crashed during GPU init, whether a sticky known-bad marker is set." },
        { ev: "error.gpu_crash", desc: "Only on the launch immediately after a GPU crash: which backend, which call site (e.g. whisper_load: <path>, with paths scrubbed)." },
      ],
      it: [
        { ev: "perf.startup_ms", desc: "Durata del cold-start in millisecondi." },
        { ev: "perf.gpu_status", desc: "A ogni avvio: quale backend GPU è stato compilato (vulkan / cuda / metal / cpu), se l'avvio precedente è andato in crash durante l'init GPU, se è settato un marker sticky di stato compromesso." },
        { ev: "error.gpu_crash", desc: "Solo nell'avvio immediatamente successivo a un crash GPU: quale backend, in quale call site (es. whisper_load: <path>, con i path ripuliti)." },
      ],
    },
  },
  {
    id: "data-counters",
    icon: "counters",
    title: { en: "Counters", it: "Contatori" },
    body: {
      en: "Atomic increment operators on a small set of cumulative per-user counters. They let us segment active users from users who installed but never tried it, without scanning every event.",
      it: "Operatori di incremento atomico su un piccolo set di contatori cumulativi per utente. Ci permettono di separare gli utenti attivi da chi ha installato senza mai provare, senza dover scansionare ogni singolo evento.",
    },
    items: {
      en: [
        "total_transcriptions",
        "total_transcription_failures",
        "total_transcriptions_cancelled",
        "total_llm_uses",
        "total_llm_failures",
        "total_sessions",
      ],
      it: [
        "total_transcriptions",
        "total_transcription_failures",
        "total_transcriptions_cancelled",
        "total_llm_uses",
        "total_llm_failures",
        "total_sessions",
      ],
    },
  },
  {
    id: "data-person",
    icon: "person",
    title: { en: "Person properties", it: "Proprietà di profilo" },
    body: {
      en: "Attached to your anonymous-ID record so dashboards can build cohorts and retention curves.",
      it: "Allegate al tuo record con ID anonimo, così le dashboard possono costruire coorti e curve di retention.",
    },
    items: {
      en: [
        "first_seen_at: timestamp of your first event (set once).",
        "first_app_version, first_os, first_arch: your install context (set once).",
        "latest_app_version, latest_seen_at, latest_os, latest_arch: refreshed on every event.",
        "latest_stt_provider, latest_stt_mode: last STT provider used.",
        "latest_llm_provider: last LLM provider used.",
      ],
      it: [
        "first_seen_at: timestamp del tuo primo evento (impostato una volta sola).",
        "first_app_version, first_os, first_arch: il contesto di installazione (impostati una volta sola).",
        "latest_app_version, latest_seen_at, latest_os, latest_arch: aggiornati a ogni evento.",
        "latest_stt_provider, latest_stt_mode: ultimo provider STT usato.",
        "latest_llm_provider: ultimo provider LLM usato.",
      ],
    },
  },
  {
    id: "data-crash",
    icon: "crash",
    title: { en: "Crash reports (Sentry)", it: "Crash report (Sentry)" },
    body: {
      en: "When the app crashes or hits an error path, we send to Sentry EU:",
      it: "Quando l'app va in crash o entra in un percorso di errore, inviamo a Sentry EU:",
    },
    items: {
      en: [
        "Error message, truncated to 4 KB. Secret-shaped substrings are replaced with <redacted>.",
        "A Rust stack trace (function names, currently mangled in shipping builds, source-mapped in a future release).",
        "Platform context (OS, arch, app version, environment = production).",
        "The anonymous ID (so we can de-duplicate the same crash from the same user).",
      ],
      it: [
        "Il messaggio di errore, troncato a 4 KB. Sottostringhe che sembrano segreti vengono sostituite con <redacted>.",
        "Uno stack trace Rust (nomi di funzione, attualmente mangled nelle build di rilascio, source-mapped in una release futura).",
        "Contesto di piattaforma (OS, arch, versione app, environment = production).",
        "L'ID anonimo (per de-duplicare lo stesso crash dello stesso utente).",
      ],
    },
    footer: {
      en: "We do not send server name, hostname, username, environment variables (PATH, HOME, USERPROFILE and similar are stripped), IP addresses (Sentry EU drops them at ingest), file paths, microphone device names, transcripts, prompts.",
      it: "Non inviamo nome del server, hostname, username, variabili d'ambiente (PATH, HOME, USERPROFILE e simili vengono rimosse), indirizzi IP (Sentry EU li scarta in ingresso), percorsi di file, nomi del dispositivo microfono, trascrizioni, prompt.",
    },
  },
  {
    id: "data-feedback",
    icon: "feedback",
    title: { en: "Feedback form", it: "Modulo Feedback" },
    body: {
      en: "The Settings → Send feedback form goes to Sentry as a tagged message. The text you type is included verbatim. The email field is optional and only included if you explicitly type it. We never auto-fill it from anywhere.",
      it: "Il modulo Impostazioni → Invia feedback arriva a Sentry come messaggio taggato. Il testo che scrivi viene incluso testualmente. Il campo email è opzionale e viene incluso solo se lo scrivi esplicitamente. Non lo precompiliamo mai da nessuna parte.",
    },
  },
];

function PrivacyHero() {
  const lead = useT(COPY.lead);
  const lastUpdated = useT(COPY.lastUpdated);
  const [a, b] = useT(COPY.title);
  const [hint1, settingsPath, hint3] = useT(COPY.disableHint);
  return (
    <section style={{
      position: "relative",
      padding: "120px 32px 64px",
      overflow: "hidden",
    }}>
      <div className="bg-grid" style={{
        position: "absolute", inset: 0,
        maskImage: "radial-gradient(ellipse 70% 50% at 50% 30%, black, transparent 70%)",
        WebkitMaskImage: "radial-gradient(ellipse 70% 50% at 50% 30%, black, transparent 70%)",
        pointerEvents: "none",
      }}/>
      <div style={{
        position: "absolute", top: -180, left: "50%",
        transform: "translateX(-50%)",
        width: 900, height: 500,
        background: "radial-gradient(circle, rgba(74,222,128,0.16), transparent 60%), radial-gradient(circle at 30% 60%, rgba(56,189,248,0.12), transparent 60%)",
        filter: "blur(60px)",
        pointerEvents: "none",
      }}/>
      <div className="container-narrow" style={{ position: "relative", textAlign: "center" }}>
        <Eyebrow color="#4ADE80">{useT(COPY.eyebrow)}</Eyebrow>
        <div style={{ height: 18 }}/>
        <h1 className="reveal" style={{
          fontFamily: "var(--font-display)",
          fontSize: "clamp(40px, 7vw, 80px)",
          fontWeight: 700,
          letterSpacing: "-0.03em",
          lineHeight: 1.02,
          margin: 0,
          color: "var(--fg)",
          textWrap: "balance",
        }}>
          {a}<br/>
          <span className="grad-text">{b}</span>
        </h1>
        <p className="reveal" style={{
          marginTop: 22,
          fontSize: 19, lineHeight: 1.55,
          color: "var(--fg-muted)",
          maxWidth: 640, marginInline: "auto",
          textWrap: "pretty",
        }}>{lead}</p>
        <div className="reveal" style={{
          marginTop: 28,
          display: "inline-flex", alignItems: "center", gap: 8, flexWrap: "wrap", justifyContent: "center",
          fontFamily: "var(--font-mono)", fontSize: 12,
          color: "var(--fg-faint)",
          padding: "8px 14px", borderRadius: 999,
          border: "1px dashed var(--line-strong)",
        }}>
          <span>{hint1}</span>
          <code style={{ color: "var(--fg)", fontFamily: "var(--font-mono)" }}>{settingsPath}</code>
          <span>{hint3}</span>
        </div>
        <div className="reveal" style={{
          marginTop: 18, fontFamily: "var(--font-mono)", fontSize: 11,
          color: "var(--fg-faint)", letterSpacing: "0.06em",
        }}>{lastUpdated}</div>
      </div>
    </section>
  );
}

// Sticky right-side TOC, desktop only. Mobile gets nothing here.
function Toc() {
  const tocTitle = useT(COPY.tocTitle);
  const { lang } = useI18n();
  const [activeId, setActiveId] = useState("");
  useEffect(() => {
    const ids = COPY.toc.map((t) => t.id);
    const observers = ids.map((id) => {
      const el = document.getElementById(id);
      if (!el) return null;
      const io = new IntersectionObserver(
        (entries) => {
          entries.forEach((e) => {
            if (e.isIntersecting) setActiveId(id);
          });
        },
        { rootMargin: "-30% 0px -55% 0px", threshold: 0 }
      );
      io.observe(el);
      return io;
    });
    return () => observers.forEach((io) => io && io.disconnect());
  }, []);
  return (
    <aside className="privacy-toc" style={{
      position: "sticky", top: 96,
      alignSelf: "start",
      padding: 20,
      borderLeft: "1px solid var(--line)",
      fontFamily: "var(--font-sans)",
      fontSize: 13,
    }}>
      <div style={{
        fontFamily: "var(--font-mono)", fontSize: 10,
        color: "var(--fg-faint)", letterSpacing: "0.10em",
        textTransform: "uppercase", marginBottom: 14,
      }}>{tocTitle}</div>
      <ol style={{ listStyle: "none", padding: 0, margin: 0, display: "flex", flexDirection: "column", gap: 4 }}>
        {COPY.toc.map((t, i) => {
          const isActive = activeId === t.id;
          return (
            <li key={t.id}>
              <a href={`#${t.id}`} style={{
                display: "flex", alignItems: "baseline", gap: 8,
                padding: "4px 0",
                color: isActive ? "var(--fg)" : "var(--fg-muted)",
                textDecoration: "none",
                borderLeft: `2px solid ${isActive ? "var(--fg)" : "transparent"}`,
                paddingLeft: 10,
                marginLeft: -12,
                transition: "color 180ms, border-color 180ms",
              }}>
                <span style={{
                  fontFamily: "var(--font-mono)", fontSize: 10,
                  color: "var(--fg-faint)",
                  minWidth: 16,
                }}>{String(i + 1).padStart(2, "0")}</span>
                <span>{t[lang]}</span>
              </a>
            </li>
          );
        })}
      </ol>
    </aside>
  );
}

function SectionBlock({ id, eyebrow, title, children }) {
  return (
    <section id={id} style={{
      padding: "56px 0",
      borderTop: "1px solid var(--line)",
    }}>
      {eyebrow && <div style={{ marginBottom: 14 }}><Eyebrow color="#4ADE80">{eyebrow}</Eyebrow></div>}
      <h2 className="reveal" style={{
        fontFamily: "var(--font-display)", fontSize: "clamp(28px, 3.5vw, 40px)",
        fontWeight: 700, letterSpacing: "-0.02em",
        lineHeight: 1.1, margin: 0, color: "var(--fg)",
      }}>{title}</h2>
      <div style={{ marginTop: 24 }}>{children}</div>
    </section>
  );
}

function Tldr() {
  const points = useT(COPY.tldrPoints);
  return (
    <SectionBlock id="tldr" title={useT(COPY.tldrTitle)}>
      <ul style={{
        listStyle: "none", padding: 0, margin: 0,
        display: "flex", flexDirection: "column", gap: 12,
      }}>
        {points.map((p, i) => (
          <li key={i} className="reveal" style={{
            display: "flex", gap: 14, alignItems: "flex-start",
            padding: "14px 16px",
            background: "linear-gradient(180deg, var(--bg-elev), transparent)",
            border: "1px solid var(--line)",
            borderRadius: 12,
            fontSize: 15, lineHeight: 1.55,
            color: "var(--fg)",
          }}>
            <span aria-hidden="true" style={{
              width: 6, height: 6, borderRadius: 99,
              background: "#4ADE80", boxShadow: "0 0 8px #4ADE80",
              marginTop: 8, flexShrink: 0,
            }}/>
            <span>{p}</span>
          </li>
        ))}
      </ul>
    </SectionBlock>
  );
}

function EventBadge({ name }) {
  return (
    <code style={{
      display: "inline-block",
      padding: "2px 8px",
      background: "rgba(56,189,248,0.10)",
      border: "1px solid rgba(56,189,248,0.25)",
      borderRadius: 6,
      fontFamily: "var(--font-mono)", fontSize: 12,
      color: "#7DD3FC",
      letterSpacing: "-0.01em",
    }}>{name}</code>
  );
}

function DataBucket({ bucket }) {
  const { lang } = useI18n();
  const title = bucket.title[lang];
  const body = bucket.body ? bucket.body[lang] : null;
  const items = bucket.items ? bucket.items[lang] : null;
  const footer = bucket.footer ? bucket.footer[lang] : null;
  return (
    <article id={bucket.id} className="reveal" style={{
      padding: "22px 22px 24px",
      borderRadius: 14,
      background: "linear-gradient(180deg, var(--bg-elev), transparent)",
      border: "1px solid var(--line)",
      scrollMarginTop: 96,
    }}>
      <h3 style={{
        fontFamily: "var(--font-display)", fontSize: 19, fontWeight: 600,
        letterSpacing: "-0.01em",
        color: "var(--fg)",
        margin: 0,
      }}>{title}</h3>
      {body && (
        <p style={{
          marginTop: 10, marginBottom: 0,
          fontSize: 14.5, lineHeight: 1.6, color: "var(--fg-muted)",
        }}>{body}</p>
      )}
      {items && (
        <ul style={{
          listStyle: "none", padding: 0, margin: "14px 0 0",
          display: "flex", flexDirection: "column", gap: 8,
        }}>
          {items.map((it, i) => {
            if (typeof it === "string") {
              return (
                <li key={i} style={{
                  fontSize: 14, lineHeight: 1.55,
                  color: "var(--fg-muted)",
                  paddingLeft: 16, position: "relative",
                }}>
                  <span style={{ position: "absolute", left: 0, top: 9, width: 6, height: 1, background: "var(--fg-faint)" }}/>
                  {it}
                </li>
              );
            }
            return (
              <li key={i} style={{
                display: "flex", gap: 12, alignItems: "flex-start",
                fontSize: 14, lineHeight: 1.55, color: "var(--fg-muted)",
              }}>
                <EventBadge name={it.ev}/>
                <span style={{ paddingTop: 2 }}>{it.desc}</span>
              </li>
            );
          })}
        </ul>
      )}
      {footer && (
        <div style={{
          marginTop: 14, padding: "10px 12px",
          background: "rgba(0,0,0,0.25)",
          border: "1px dashed var(--line)",
          borderRadius: 8,
          fontSize: 13, lineHeight: 1.5,
          color: "var(--fg-faint)",
          fontFamily: "var(--font-mono)",
        }}>{footer}</div>
      )}
    </article>
  );
}

function WhatWeCollect() {
  return (
    <SectionBlock
      id="data"
      eyebrow={<code style={{ fontFamily: "var(--font-mono)", fontSize: 11, letterSpacing: "0.06em" }}>#data</code>}
      title={useT(COPY.whatWeCollectTitle)}
    >
      <p style={{
        margin: "0 0 22px", fontSize: 16, lineHeight: 1.6,
        color: "var(--fg-muted)",
      }}>{useT(COPY.whatWeCollectIntro)}</p>
      <div className="data-grid" style={{
        display: "grid",
        gridTemplateColumns: "repeat(2, 1fr)",
        gap: 14,
      }}>
        {DATA_BUCKETS.map((b) => <DataBucket key={b.id} bucket={b}/>)}
      </div>
    </SectionBlock>
  );
}

function NeverCollect() {
  const items = useT(COPY.neverItems);
  return (
    <SectionBlock id="never" title={useT(COPY.neverTitle)}>
      <p style={{ margin: "0 0 22px", fontSize: 16, lineHeight: 1.6, color: "var(--fg-muted)" }}>
        {useT(COPY.neverLead)}
      </p>
      <ul className="reveal" style={{
        listStyle: "none", padding: 0, margin: 0,
        display: "grid", gridTemplateColumns: "repeat(2, 1fr)", gap: 1,
        background: "var(--line)",
        border: "1px solid var(--line)",
        borderRadius: 14, overflow: "hidden",
      }}>
        {items.map((t, i) => (
          <li key={i} style={{
            padding: "18px 20px",
            background: "var(--bg-deep)",
            display: "flex", alignItems: "flex-start", gap: 12,
            fontSize: 14.5, lineHeight: 1.55, color: "var(--fg)",
          }}>
            <span aria-hidden="true" style={{
              width: 18, height: 18, borderRadius: 99,
              background: "rgba(239,68,68,0.10)",
              border: "1px solid rgba(239,68,68,0.30)",
              color: "#F87171",
              display: "inline-flex", alignItems: "center", justifyContent: "center",
              flexShrink: 0, marginTop: 1,
              fontSize: 12, fontWeight: 700, fontFamily: "var(--font-mono)",
            }}>✕</span>
            <span>{t}</span>
          </li>
        ))}
      </ul>
    </SectionBlock>
  );
}

function WhereGoes() {
  const { lang } = useI18n();
  return (
    <SectionBlock id="where" title={useT(COPY.whereTitle)}>
      <p style={{ margin: "0 0 22px", fontSize: 16, lineHeight: 1.6, color: "var(--fg-muted)" }}>
        {useT(COPY.whereIntro)}
      </p>
      <div style={{
        display: "grid", gridTemplateColumns: "repeat(2, 1fr)", gap: 14,
      }} className="where-grid">
        {COPY.whereItems.map((w, i) => (
          <div key={i} className="reveal" style={{
            padding: 22,
            borderRadius: 14,
            background: "linear-gradient(180deg, var(--bg-elev), transparent)",
            border: "1px solid var(--line)",
          }}>
            <div style={{
              fontFamily: "var(--font-mono)", fontSize: 11,
              color: "#4ADE80",
              letterSpacing: "0.08em", textTransform: "uppercase",
            }}>{w.title[lang]}</div>
            <div style={{
              marginTop: 8,
              fontFamily: "var(--font-display)", fontSize: 22, fontWeight: 700,
              letterSpacing: "-0.01em",
              color: "var(--fg)",
            }}>{w.target}</div>
            <div style={{
              marginTop: 6,
              fontFamily: "var(--font-mono)", fontSize: 12,
              color: "var(--fg-faint)",
              wordBreak: "break-all",
            }}>{w.host}</div>
            <p style={{
              marginTop: 14, marginBottom: 0,
              fontSize: 14, lineHeight: 1.55,
              color: "var(--fg-muted)",
            }}>{w.desc[lang]}</p>
          </div>
        ))}
      </div>
      <p style={{
        marginTop: 18, fontSize: 13, lineHeight: 1.55,
        color: "var(--fg-faint)", fontStyle: "italic",
      }}>{useT(COPY.whereFooter)}</p>
    </SectionBlock>
  );
}

function Inspect() {
  return (
    <SectionBlock id="inspect" title={useT(COPY.inspectTitle)}>
      <p style={{ margin: "0 0 18px", fontSize: 16, lineHeight: 1.6, color: "var(--fg-muted)" }}>
        {useT(COPY.inspectLead)}
      </p>
      <div className="reveal" style={{
        background: "rgba(0,0,0,0.4)",
        border: "1px solid var(--line)",
        borderRadius: 12,
        overflow: "hidden",
        fontFamily: "var(--font-mono)", fontSize: 13,
      }}>
        {COPY.inspectPaths.map((p, i) => (
          <div key={i} style={{
            display: "grid", gridTemplateColumns: "100px 1fr",
            padding: "12px 16px",
            borderBottom: i < COPY.inspectPaths.length - 1 ? "1px solid var(--line)" : "none",
            alignItems: "center",
          }}>
            <span style={{ color: "var(--fg-faint)", letterSpacing: "0.04em" }}>{p.os}</span>
            <code style={{ color: "var(--fg)", wordBreak: "break-all" }}>{p.path}</code>
          </div>
        ))}
      </div>
      <p style={{ margin: "22px 0 10px", fontSize: 14, color: "var(--fg-muted)" }}>
        {useT(COPY.inspectExample)}
      </p>
      <pre className="reveal" style={{
        margin: 0,
        padding: 18,
        background: "rgba(0,0,0,0.55)",
        border: "1px solid var(--line)",
        borderRadius: 12,
        fontFamily: "var(--font-mono)", fontSize: 12.5, lineHeight: 1.55,
        color: "var(--fg-muted)",
        overflowX: "auto",
        whiteSpace: "pre",
      }}>{`[2026-05-11 09:47:06] [telemetry] track event=transcription.completed
[2026-05-11 09:47:06] [telemetry] spawn send for event=transcription.completed (payload 275 bytes)
[2026-05-11 09:47:06] [telemetry] send: HTTP 200 OK (sent=4)`}</pre>
      <p style={{
        marginTop: 22, fontSize: 14, lineHeight: 1.6,
        color: "var(--fg-muted)",
      }}>{useT(COPY.inspectKeyDiag)}</p>
    </SectionBlock>
  );
}

function Disable() {
  const steps = useT(COPY.disableSteps);
  return (
    <SectionBlock id="disable" title={useT(COPY.disableTitle)}>
      <ol style={{
        listStyle: "none", padding: 0, margin: 0, counterReset: "step",
        display: "flex", flexDirection: "column", gap: 12,
      }}>
        {steps.map((s, i) => (
          <li key={i} className="reveal" style={{
            counterIncrement: "step",
            display: "flex", gap: 14, alignItems: "flex-start",
            padding: "14px 16px",
            background: "linear-gradient(180deg, var(--bg-elev), transparent)",
            border: "1px solid var(--line)",
            borderRadius: 12,
            fontSize: 15, lineHeight: 1.55,
            color: "var(--fg)",
          }}>
            <span style={{
              width: 26, height: 26, borderRadius: 99,
              border: "1px solid var(--line-strong)",
              display: "inline-flex", alignItems: "center", justifyContent: "center",
              flexShrink: 0,
              fontFamily: "var(--font-mono)", fontSize: 12,
              color: "var(--fg-muted)",
            }}>{i + 1}</span>
            <span>{s}</span>
          </li>
        ))}
      </ol>
      <p style={{
        marginTop: 18, fontSize: 14, lineHeight: 1.55,
        color: "var(--fg-faint)",
      }}>{useT(COPY.disableExtra)}</p>
    </SectionBlock>
  );
}

function Changes() {
  return (
    <SectionBlock id="changes" title={useT(COPY.changesTitle)}>
      <p style={{ margin: 0, fontSize: 16, lineHeight: 1.6, color: "var(--fg-muted)" }}>
        {useT(COPY.changesBody)}
      </p>
    </SectionBlock>
  );
}

function Contact() {
  return (
    <SectionBlock id="contact" title={useT(COPY.contactTitle)}>
      <p style={{ margin: 0, fontSize: 16, lineHeight: 1.6, color: "var(--fg-muted)" }}>
        {useT(COPY.contactBody)}
      </p>
    </SectionBlock>
  );
}

function Privacy() {
  return (
    <>
      <PrivacyHero/>
      <div className="container-narrow privacy-layout" style={{
        position: "relative",
        display: "grid",
        gridTemplateColumns: "1fr 220px",
        gap: 48,
        paddingBottom: 96,
      }}>
        <main>
          <Tldr/>
          <WhatWeCollect/>
          <NeverCollect/>
          <WhereGoes/>
          <Inspect/>
          <Disable/>
          <Changes/>
          <Contact/>
        </main>
        <Toc/>
      </div>
      <style>{`
        @media (max-width: 960px) {
          .privacy-layout { grid-template-columns: 1fr !important; }
          .privacy-toc { display: none !important; }
          .data-grid { grid-template-columns: 1fr !important; }
          .where-grid { grid-template-columns: 1fr !important; }
        }
      `}</style>
    </>
  );
}

window.PrivacyPage = Privacy;
