/* ──────────────────────────────────────────────────────────────────
   German HR — Operational Confidence Assessment
   ====================================================================
   A landing page + audience-assessment tool for German HR leaders
   (CHRO / Head of People / Personalleiter / Arbeitsdirektor).

   Built on the ApprovedLeadMagnet "BAG Reconstruction Snapshot" stack
   (React 18 + Babel Standalone, ARAM "Neue Authority / Verfahrenscheck"
   brand). The single 10-question set is generalised into the 15-question
   architecture from `deploy/Audience Assessment Architecture.md`:

     Q1–Q10  Yes / Unknown / No  → the score (route-specific best practice)
     Q11     Current reality
     Q12     Desired reality
     Q13     Obstacles (multi-select)
     Q14     Preferred solution
     Q15     Open text

   The five Q1–Q10 question sets are derived, in plain HR language, from
   the five defensibility checklists in deploy/:
     conduct          ← CONDUCT_DEFENSIBILITY_CHECKLIST.md
     capability       ← PERSONALCAPAB_DEFENSIBILITY_CHECKLIST.md
     restructuring    ← RESTRUCTURING_DEFENSIBILITY_CHECKLIST.md
     extraordinary    ← EXTRAORDINARY_DEFENSIBILITY_CHECKLIST.md
     senior_executive ← SENIOR_EXECUTIVE_DEFENSIBILITY_CHECKLIST.md (DRAFT)

   Audience framing (ARAM_HR_BUYER_PERSONA.md): names the HR fear in their
   words on the first screen (Annahmeverzug, §102, the board file), reads
   as a co-pilot — never a prosecutor — and avoids system-internal
   vocabulary. Not legal advice (RDG).
─────────────────────────────────────────────────────────────────── */

const { useMemo, useState } = React;

/* ──────────────────────────────────────────────────────────────────
   CONFIG — fill these in before going live.
   ====================================================================
   Email delivery uses EmailJS (client-side, no backend). Create a free
   account at https://www.emailjs.com, add an email service and a
   template, then paste the three IDs below and flip `enabled` to true.
   Until then the gate still captures the lead and unlocks the report
   on-screen (the email send is skipped, with a small notice).

   The EmailJS template should reference these variables:
     to_name · to_email · route_label · score · band ·
     primary_failure_mode · gaps_list · report_text · consent_timestamp
─────────────────────────────────────────────────────────────────── */
const EMAILJS = {
  publicKey: "SM8sj-pNjL_dGZP2f",
  serviceId: "service_uyczdqf",
  templateId: "template_9q2y3oi",   // shared across all three assessments; Content is a single {{report}} tag
};

/* True only when the SDK has loaded and the IDs are real (not placeholders).
   When false, the gate still validates input and reveals the report — it just
   skips the send — so the page stays usable in dev / preview. */
function emailjsConfigured() {
  return (
    typeof window !== "undefined" &&
    !!window.emailjs &&
    !EMAILJS.publicKey.startsWith("YOUR_") &&
    !EMAILJS.serviceId.startsWith("YOUR_") &&
    !EMAILJS.templateId.startsWith("YOUR_")
  );
}

/* GDPR / Datenschutz — replace with your real details before going live. */
const PRIVACY = {
  controller: "ARAM Algorithm",            // ← your legal entity
  contact: "datenschutz@aram.ai",          // ← your data-protection contact
  privacyUrl: "#",                          // ← your Datenschutzerklärung URL
  retention: "until your request is handled, then deleted",
};

const EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;

/* ── The five route-specific question sets (Q1–Q10) + failure modes ── */
const ROUTES = [
  {
    id: "conduct",
    de: "Verhaltensbedingte Kündigung",
    en: "Conduct-based dismissal (§1 Abs. 2 KSchG / §626 BGB)",
    blurb:
      "A substantively correct conduct dismissal can still be voided by a missing Abmahnung or a procedural slip. This set checks whether the file carries what a later review looks for first.",
    questions: [
      { n: 1, text: "Is the triggering event (Kündigungsgrund) documented with specific facts and dates — not just a general conclusion?" },
      { n: 2, text: "Is a prior written Abmahnung for the same type of conduct on file — or a documented reason why a warning could be waived (grave breach, trust destroyed)?" },
      { n: 3, text: "Is the proportionality weighing on the record — severity, Betriebszugehörigkeit (tenure), prior conduct, and personal circumstances?" },
      { n: 4, text: "Were milder alternatives (Versetzung, Ermahnung, a further Abmahnung) considered and documented before terminating?" },
      { n: 5, text: "Was the special-protection status checked (pregnancy, parental leave, severe disability, works-council member)?" },
      { n: 6, text: "If a Betriebsrat exists, is the §102 hearing complete, dated, issued before notice, and matched to the stated reason?" },
      { n: 7, text: "Is the dismissal in written form with an original signature and proof of delivery (Zugang)?" },
      { n: 8, text: "Is the decision-maker — and their signing authority — identifiable from the file alone?" },
      { n: 9, text: "Is the decision basis free of any protected-ground (AGG) concern, or is a rebuttal documented?" },
      { n: 10, text: "Could outside counsel defend this dismissal from the file alone — without interviewing your managers?" },
    ],
    patterns: [
      { id: "abmahnung", name: "Warning gap (Abmahnung)", name_de: "Abmahnungs-Lücke", concern: "Without a documented prior warning — or a clearly justified waiver — a conduct dismissal is the easiest type to void, regardless of how serious the conduct was.", q: [2] },
      { id: "proportionality", name: "Proportionality / ultima ratio gap", name_de: "Verhältnismäßigkeits-Lücke", concern: "If the weighing and the milder alternatives aren't on the record, the file can't show why termination was the necessary step.", q: [3, 4] },
      { id: "works_council", name: "Works-council hearing gap (§102 BetrVG)", name_de: "Betriebsrat-Anhörungslücke", concern: "A defective §102 hearing voids a substantively correct dismissal. Process risk dwarfs substance risk here.", q: [6] },
      { id: "protection", name: "Special-protection gap", name_de: "Sonderkündigungsschutz-Lücke", concern: "An unchecked special-protection status (pregnancy, severe disability, BR member) can bar the dismissal outright.", q: [5] },
      { id: "form", name: "Form & delivery gap", name_de: "Form- und Zugangslücke", concern: "Written form (§623 BGB) and provable delivery are deterministic — a slip here ends the matter before substance is even reached.", q: [7] },
      { id: "evidence", name: "Reason & decision-owner gap", name_de: "Beweis- und Entscheidungsträger-Lücke", concern: "If the reason isn't bridged to evidence, or the decision-maker can't be identified from the file, the decision is hard to reconstruct later.", q: [1, 8] },
      { id: "discrimination", name: "Anti-discrimination gap (AGG)", name_de: "AGG-Lücke", concern: "Indicia of a protected-ground disadvantage shift the burden under §22 AGG; an undocumented rebuttal becomes an opening.", q: [9] },
      { id: "replayability", name: "File replayability gap", name_de: "Akten-Rekonstruierbarkeits-Lücke", concern: "The organisation may know what happened, but if the file can't prove it once memories fade, the decision is exposed.", q: [10] },
    ],
  },
  {
    id: "capability",
    de: "Personenbedingte Kündigung — Krankheit / Leistung",
    en: "Capability / illness-based dismissal (ROUTE_B)",
    blurb:
      "Illness and capability dismissals turn on the BEM and the prognosis. A missing BEM is one of the strongest defects an employee-side review can raise.",
    questions: [
      { n: 1, text: "Is an absence record documented over a representative period (around 24 months), with dates and a clear pattern?" },
      { n: 2, text: "Was a BEM (betriebliches Eingliederungsmanagement, §167 Abs. 2 SGB IX) offered in writing and documented before notice?" },
      { n: 3, text: "Is a negative health prognosis on file, with its basis and its date?" },
      { n: 4, text: "Is the operational impact documented — the disruption, cover costs, or why the absences hurt the business?" },
      { n: 5, text: "Is the Interessenabwägung on the record — tenure, age, cause of the illness, and labour-market position weighed?" },
      { n: 6, text: "Were milder alternatives evaluated (Versetzung, Teilzeit, Umschulung, workplace adaptation) with rejection reasons recorded?" },
      { n: 7, text: "If the employee is severely disabled, was Integrationsamt approval obtained before notice (§168 SGB IX)?" },
      { n: 8, text: "If a Betriebsrat exists, is the §102 hearing complete, dated, before notice, with the response window respected?" },
      { n: 9, text: "Is the dismissal in written form with an original signature and proof of delivery?" },
      { n: 10, text: "Could outside counsel defend this capability dismissal from the file alone?" },
    ],
    patterns: [
      { id: "bem", name: "BEM gap", name_de: "BEM-Lücke (§167 SGB IX)", concern: "BAG treats the BEM as an ultima-ratio indicator. Absent a documented BEM offer, the employer carries the burden — one of the strongest substantive defects in this route.", q: [2] },
      { id: "absence_prognosis", name: "Absence record & prognosis gap", name_de: "Fehlzeiten- und Prognose-Lücke", concern: "Without a representative absence record and a dated negative prognosis, the factual basis for the dismissal can't be reconstructed.", q: [1, 3] },
      { id: "operational_impact", name: "Operational-impact gap", name_de: "Betriebsbeeinträchtigungs-Lücke", concern: "If the business impact isn't documented, the file shows absences but not why they justified termination.", q: [4] },
      { id: "proportionality", name: "Proportionality & alternatives gap", name_de: "Verhältnismäßigkeits-Lücke", concern: "Tenure, illness cause, and milder means (Teilzeit, Umschulung, Versetzung) must be weighed on the record, or ultima ratio fails.", q: [5, 6] },
      { id: "protection", name: "Integrationsamt approval gap", name_de: "Integrationsamt-Lücke", concern: "For a severely disabled employee, prior Integrationsamt approval is mandatory — termination without it is void.", q: [7] },
      { id: "works_council", name: "Works-council hearing gap (§102 BetrVG)", name_de: "Betriebsrat-Anhörungslücke", concern: "A defective §102 hearing voids the dismissal independently of the medical substance.", q: [8] },
      { id: "form", name: "Form & delivery gap", name_de: "Form- und Zugangslücke", concern: "Written form and provable delivery are deterministic gates — a slip ends the matter early.", q: [9] },
      { id: "replayability", name: "File replayability gap", name_de: "Akten-Rekonstruierbarkeits-Lücke", concern: "If the file can't carry the prognosis-and-impact story on its own, the decision is exposed once memories fade.", q: [10] },
    ],
  },
  {
    id: "restructuring",
    de: "Betriebsbedingte Kündigung",
    en: "Operational / restructuring dismissal (ROUTE_C, §1 Abs. 2–3 KSchG)",
    blurb:
      "Restructuring is the type most exposed to reconstruction: a works council or an employee's lawyer rebuilds the Sozialauswahl after the fact. The pool, scores, and §102 hearing are where it most often breaks.",
    questions: [
      { n: 1, text: "Is the business decision documented — which positions are eliminated and the headcount rationale — and dated before notice?" },
      { n: 2, text: "Is the comparable pool (vergleichbare Arbeitnehmer) defined via the three-test (hierarchy / interchangeability / same establishment), with inclusion-exclusion reasoning?" },
      { n: 3, text: "Is the social data complete for every pool member — tenure, age, dependents, disability (Sozialauswahl)?" },
      { n: 4, text: "Is the weighting model for the Sozialauswahl documented and justified?" },
      { n: 5, text: "Is the scoring matrix complete, and does the selected employee actually carry the lowest score?" },
      { n: 6, text: "Were per-employee redeployment / Weiterbeschäftigung alternatives evaluated (ultima ratio)?" },
      { n: 7, text: "If the §17 KSchG threshold is met, was the Massenentlassungsanzeige filed before issuance?" },
      { n: 8, text: "If a Betriebsrat exists, does the §102 hearing include the Sozialauswahl data, complete and dated before notice?" },
      { n: 9, text: "Is the dismissal in written form with an original signature and proof of delivery, with no protected-ground (AGG) concern?" },
      { n: 10, text: "Could outside counsel defend the selection from the file alone — the pool, the scores, and the rationale?" },
    ],
    patterns: [
      { id: "social_selection", name: "Sozialauswahl gap", name_de: "Sozialauswahl-Lücke", concern: "The pool, the social data, the weighting, and the scoring are the heart of a restructuring file. A gap in any of them lets the selection be rebuilt — and overturned.", q: [2, 3, 4, 5] },
      { id: "works_council", name: "Works-council hearing gap (§102 BetrVG)", name_de: "Betriebsrat-Anhörungslücke", concern: "A §102 hearing that omits the pool and scores voids the dismissal even when the substance is perfect — the top reconstruction kill-shot for restructuring.", q: [8] },
      { id: "business_decision", name: "Business-decision gap", name_de: "Unternehmerentscheidungs-Lücke", concern: "Without a dated, documented business decision and rationale, the dringende betriebliche Erfordernisse can't be shown.", q: [1] },
      { id: "redeployment", name: "Redeployment gap", name_de: "Weiterbeschäftigungs-Lücke", concern: "If per-employee alternatives weren't evaluated, ultima ratio fails — termination wasn't shown to be the last resort.", q: [6] },
      { id: "mass_layoff", name: "Mass-layoff notification gap", name_de: "Massenentlassungsanzeige-Lücke", concern: "Where the §17 threshold is met, a late or missing Massenentlassungsanzeige voids the dismissals filed under it.", q: [7] },
      { id: "form_agg", name: "Form & anti-discrimination gap", name_de: "Form- und AGG-Lücke", concern: "Written form, provable delivery, and an AGG-clean decision basis are hard gates that sit underneath the whole selection.", q: [9] },
      { id: "replayability", name: "File replayability gap", name_de: "Akten-Rekonstruierbarkeits-Lücke", concern: "If the selection can't be replayed from the file, the obvious objection — 'the pool was gerrymandered' — has room to land.", q: [10] },
    ],
  },
  {
    id: "extraordinary",
    de: "Außerordentliche (fristlose) Kündigung",
    en: "Extraordinary / summary dismissal (§626 BGB)",
    blurb:
      "Extraordinary dismissals have the shortest fuse: a 14-day clock and, where a Betriebsrat exists, a compressed three-day hearing window. The deadline is the single hardest gate.",
    questions: [
      { n: 1, text: "Is the reliable-knowledge date (Kenntnis of the kündigungsberechtigte Person) documented — who knew, when, and how?" },
      { n: 2, text: "Was the dismissal issued AND delivered within 14 days of that knowledge (§626 Abs. 2 BGB)?" },
      { n: 3, text: "Is the triggering event fully documented — facts, date, time, and witnesses?" },
      { n: 4, text: "Is an important-reason (wichtiger Grund) analysis on file — why continued employment to ordinary notice was unzumutbar?" },
      { n: 5, text: "Was the Interessenabwägung performed — severity vs. tenure vs. prior conduct vs. circumstances?" },
      { n: 6, text: "Were milder means weighed and rejected on the record (ordinary notice, suspension, transfer)?" },
      { n: 7, text: "Is a prior Abmahnung on file, or a justified waiver (grave breach / trust destroyed)?" },
      { n: 8, text: "Is the dismissal in written form with an original signature, an authorized signatory, and proof of delivery?" },
      { n: 9, text: "If a Betriebsrat exists, is the §102 hearing complete and the compressed three-day window honoured before notice?" },
      { n: 10, text: "Are special protections cleared (pregnancy, severe disability, BR member §103) with no AGG concern — and is the decision defensible from the file alone?" },
    ],
    patterns: [
      { id: "deadline", name: "14-day deadline gap (§626 Abs. 2)", name_de: "Zwei-Wochen-Frist-Lücke", concern: "The 14-day clock is deterministic and runs from the authorized person's reliable knowledge. If the file can't prove notice and delivery inside it, nothing downstream matters.", q: [1, 2] },
      { id: "triggering_reason", name: "Triggering event & important-reason gap", name_de: "Sachverhalts- und wichtiger-Grund-Lücke", concern: "Without a fully documented event and a wichtiger-Grund analysis, the basis for going straight to summary dismissal can't be reconstructed.", q: [3, 4] },
      { id: "proportionality", name: "Proportionality / milder-means gap", name_de: "Verhältnismäßigkeits-Lücke", concern: "The Interessenabwägung and the rejection of milder means (ordinary notice, suspension) must be on the record, or ultima ratio fails.", q: [5, 6] },
      { id: "abmahnung", name: "Warning gap (Abmahnung)", name_de: "Abmahnungs-Lücke", concern: "Even for extraordinary dismissal, a prior warning is often expected; a waiver needs an explicit, justified basis.", q: [7] },
      { id: "works_council", name: "Works-council hearing gap (§102 BetrVG)", name_de: "Betriebsrat-Anhörungslücke", concern: "The three-day window compresses an already tight timeline — a §102 slip here voids the dismissal.", q: [9] },
      { id: "form", name: "Form & delivery gap", name_de: "Form- und Zugangslücke", concern: "Written form and provable delivery inside the window are deterministic — a defect ends the matter.", q: [8] },
      { id: "protection_agg", name: "Special-protection & AGG gap", name_de: "Sonderschutz- und AGG-Lücke", concern: "Unchecked special protections or a protected-ground concern can bar the dismissal regardless of the underlying reason.", q: [10] },
    ],
  },
  {
    id: "senior_executive",
    de: "Leitender Angestellter / Geschäftsführer",
    en: "Senior-executive dismissal (ROUTE_E — preliminary)",
    draft: true,
    blurb:
      "Senior-executive dismissals turn first on status: is the §5(3) BetrVG carve-out genuinely documented? If status fails, the case falls back to the ordinary route — and the §102 hearing the employer skipped becomes the problem.",
    questions: [
      { n: 1, text: "Is the §5(3) BetrVG executive status documented through hire/fire authority, Prokura, or genuine entrepreneurial tasks — not the title alone?" },
      { n: 2, text: "Is there contemporaneous proof that this authority was actually exercised?" },
      { n: 3, text: "For a Geschäftsführer: are the HRB-Bestellung, Dienstvertrag, and §621 BGB notice regime clear, so employment status is unambiguous?" },
      { n: 4, text: "Is the Sprecherausschuss hearing letter on file (§31 SprAuG) with core facts, the route, and favorable facts disclosed?" },
      { n: 5, text: "Was the statutory hearing window observed (7 days ordinary / 3 days extraordinary), and notice not issued prematurely?" },
      { n: 6, text: "Is there hearing-to-litigation congruence — no Nachschieben (no reasons added later that weren't in the hearing)?" },
      { n: 7, text: "Is the special-protection screen cleared (§15 KSchG, §168 SGB IX, §17 MuSchG, §18 BEEG)?" },
      { n: 8, text: "Is §623 BGB written form with an authorized signatory in place — and, if extraordinary, the §626(2) two-week Kenntnis clock documented?" },
      { n: 9, text: "Where KSchG still applies: are proportionality / ultima ratio, the Abmahnung (or a documented exception), and the Sozialauswahl (if betriebsbedingt) documented?" },
      { n: 10, text: "Could outside counsel defend both the executive status AND the dismissal from the file alone?" },
    ],
    patterns: [
      { id: "status", name: "Executive-status gap (§5(3) BetrVG)", name_de: "Status-Lücke", concern: "If status rests on the title alone, the carve-out can collapse — the case reverts to the ordinary route and the §102 hearing the employer skipped becomes catastrophic.", q: [1, 2, 3] },
      { id: "hearing", name: "Sprecherausschuss hearing gap (§31 SprAuG)", name_de: "Sprecherausschuss-Lücke", concern: "An incomplete hearing letter, a violated window, or Nachschieben (added reasons) are absolute bars on this route.", q: [4, 5, 6] },
      { id: "protection", name: "Special-protection gap", name_de: "Sonderkündigungsschutz-Lücke", concern: "Special protections persist for executives — an unchecked status can bar the dismissal.", q: [7] },
      { id: "form_deadline", name: "Form & deadline gap", name_de: "Form- und Fristlücke", concern: "Written form and, for summary dismissal, the §626(2) clock apply to executives identically.", q: [8] },
      { id: "substantive", name: "Substantive-file gap", name_de: "Materielle Lücke", concern: "Where KSchG still applies, proportionality, the Abmahnung, and any Sozialauswahl must still be on the record.", q: [9] },
      { id: "replayability", name: "File replayability gap", name_de: "Akten-Rekonstruierbarkeits-Lücke", concern: "Status and substance both have to be defensible from the file alone — counsel will probe whichever is thinner.", q: [10] },
    ],
  },
];

/* ── Shared context questions (Q11–Q15), per the architecture ───────── */
const CTX_CURRENT = {
  key: "current",
  n: 11,
  label: "Current reality",
  text: "How consistent are your termination files across managers and sites today?",
  options: [
    { v: "consistent", label: "Highly consistent — the same standard everywhere" },
    { v: "mostly", label: "Mostly consistent, with some variation" },
    { v: "variable", label: "Variable — it depends on the manager or site" },
    { v: "unsure", label: "Inconsistent, or I'm not sure" },
  ],
};
const CTX_DESIRED = {
  key: "desired",
  n: 12,
  label: "Desired reality",
  text: "Where do you want to be before your next contested termination?",
  options: [
    { v: "board_ready", label: "Every file board-ready and audit-ready" },
    { v: "high_value", label: "Confident on the high-value, high-risk cases" },
    { v: "forecast", label: "A faster way to forecast exposure before I decide" },
    { v: "exploring", label: "Just exploring for now" },
  ],
};
const CTX_OBSTACLES = {
  key: "obstacles",
  n: 13,
  label: "Obstacles",
  text: "What's getting in the way today? (select all that apply)",
  multi: true,
  options: [
    { v: "time", label: "Time" },
    { v: "budget", label: "Budget" },
    { v: "inconsistent", label: "Documentation varies across managers" },
    { v: "counsel", label: "Heavy reliance on outside counsel" },
    { v: "betriebsrat", label: "Betriebsrat friction" },
    { v: "conversations", label: "Decisions live in conversations, not records" },
    { v: "exposure", label: "Unclear exposure (Annahmeverzug, Streitwert)" },
  ],
};
const CTX_SOLUTION = {
  key: "solution",
  n: 14,
  label: "Preferred next step",
  text: "If you addressed this, what would suit you best?",
  options: [
    { v: "review", label: "A second read on individual files (a VerfahrensCheck review)" },
    { v: "checklist", label: "A repeatable internal checklist for my team" },
    { v: "software", label: "Software my team can run themselves" },
    { v: "training", label: "Training for managers and HR business partners" },
    { v: "unsure", label: "Not sure yet" },
  ],
};
const CTX_OPEN = {
  key: "open",
  n: 15,
  label: "Anything else",
  text: "Anything else about your situation we should know? An upcoming restructuring, a specific open case, a board review? (optional)",
};

const ANSWER_POINTS = { yes: 0, unknown: 1, no: 2 };

const RISK_BANDS = [
  { min: 80, max: 100, grade: "green", en: "Strongly defensible from the file", de: "Tragfähig aus der Akte verteidigbar" },
  { min: 60, max: 79, grade: "amber", en: "Mostly defensible, with gaps to close", de: "Überwiegend verteidigbar, mit Lücken" },
  { min: 40, max: 59, grade: "amber", en: "Partially defensible — meaningful exposure", de: "Teilweise verteidigbar — spürbares Risiko" },
  { min: 0, max: 39, grade: "red", en: "Weakly defensible — the file may not hold up", de: "Schwach verteidigbar — die Akte trägt womöglich nicht" },
];

function bandFor(score) {
  return RISK_BANDS.find((b) => score >= b.min && score <= b.max) || RISK_BANDS[RISK_BANDS.length - 1];
}

/* Build the EmailJS template params (and a plain-text report body) from a
   completed result. Kept framework-free so it is easy to test. */
function buildReportParams(route, result, ctx, lead) {
  const gapsList = result.activePatterns
    .map((p) => `• ${p.name} (${p.name_de}): ${p.concern}`)
    .join("\n");
  const reportText = [
    `Operational Confidence Assessment — ${route.de}`,
    `Documented defensibility: ${result.defensibility}% — ${result.band.en}`,
    result.primary ? `Primary failure mode: ${result.primary.name} — ${result.primary.concern}` : "",
    "",
    `Gaps answered "No": ${result.unsupportedCount} · Couldn't confirm ("Unknown"): ${result.unknownCount} · Active gap patterns: ${result.activePatterns.length}`,
    "",
    "Where the file could break down:",
    gapsList || "• No active gap patterns — the file scored cleanly.",
    "",
    route.draft ? "Note: this is a preliminary route (senior-executive criteria still in design); read the result as indicative." : "",
    "",
    "This is a non-legal, operational snapshot, not Rechtsberatung within the meaning of the RDG.",
  ]
    .filter((l) => l !== null && l !== undefined)
    .join("\n");
  return {
    to_name: lead.name,
    to_email: lead.email,
    route_label: route.de,
    score: String(result.defensibility),
    band: result.band.en,
    primary_failure_mode: result.primary ? result.primary.name : "—",
    gaps_list: gapsList,
    report_text: reportText,
    consent_timestamp: new Date().toISOString(),
  };
}

/* Escape dynamic values before embedding in the email HTML.
   EmailJS does NOT HTML-escape template variables, and `name` is visitor
   input — so everything interpolated into {{report}} runs through this. */
function esc(s) {
  return String(s == null ? "" : s)
    .replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;")
    .replace(/"/g, "&quot;").replace(/'/g, "&#39;");
}

// Self-contained, inline-styled HTML email body. The shared EmailJS template's
// whole Content is the single {{report}} tag, so this is the entire email.
function buildReportHtml({ name, routeLabelEn, routeLabelDe, defensibility, bandEn, bandDe, grade,
                           primary /* {name, name_de, concern} | null */,
                           rows /* [{name, name_de, concern}] gap patterns OR insights */,
                           qualLabel, nextCta, nextBody }) {
  const C = { ink:"#111111", slate:"#3D4452", muted:"#6B7280", rust:"#E5631F",
              rule:"#DDD9D3", fog:"#F3F2EE", green:"#2E7D32", amber:"#E65100", red:"#C62828" };
  const bandColor = grade === "green" ? C.green : grade === "red" ? C.red : C.amber;
  const serif = "Georgia,'Times New Roman',serif";
  const rowHtml = (rows && rows.length)
    ? rows.map(p => `
        <tr>
          <td style="padding:10px 12px 10px 0;vertical-align:top;border-top:1px solid ${C.rule};width:42%;">
            <strong style="color:${C.ink};">${esc(p.name)}</strong><br>
            <span style="font-family:'Courier New',monospace;font-size:12px;color:${C.muted};">${esc(p.name_de || "")}</span>
          </td>
          <td style="padding:10px 0;vertical-align:top;border-top:1px solid ${C.rule};color:${C.slate};font-size:14px;">${esc(p.concern)}</td>
        </tr>`).join("")
    : `<tr><td style="padding:10px 0;color:${C.slate};font-size:14px;">No active gap patterns — the file scored cleanly on the questions answered.</td></tr>`;
  return `
<div style="font-family:${serif};color:${C.ink};line-height:1.6;max-width:640px;margin:0 auto;padding:8px 4px;">
  <p style="font-family:'Courier New',monospace;font-size:11px;letter-spacing:0.14em;text-transform:uppercase;color:${C.rust};margin:0 0 6px;">Strategic Confidence Assessment · Deutsches Arbeitsrecht</p>
  <p style="margin:0 0 4px;">Hello ${esc(name)},</p>
  <p style="margin:0 0 18px;color:${C.slate};">Here is your documented-defensibility report for <strong style="color:${C.ink};">${esc(routeLabelDe)}</strong> <span style="color:${C.muted};">(${esc(routeLabelEn)})</span>.</p>
  <div style="border:1px solid ${C.rule};border-top:3px solid ${C.rust};border-radius:6px;padding:18px 20px;margin:0 0 18px;">
    <div style="font-family:'Courier New',monospace;font-size:11px;letter-spacing:0.1em;text-transform:uppercase;color:${C.muted};">Documented defensibility</div>
    <div style="font-size:40px;font-weight:700;color:${bandColor};line-height:1.1;margin:2px 0;">${esc(String(defensibility))}</div>
    <div style="font-size:16px;color:${C.ink};">${esc(bandEn)}</div>
    <div style="font-family:'Courier New',monospace;font-size:12px;color:${C.muted};">${esc(bandDe)}</div>
    ${primary ? `
    <div style="margin-top:14px;padding-top:14px;border-top:1px solid ${C.rule};">
      <div style="font-family:'Courier New',monospace;font-size:11px;letter-spacing:0.1em;text-transform:uppercase;color:${C.muted};">Primary failure mode</div>
      <div style="font-size:16px;color:${C.ink};margin:2px 0 4px;">${esc(primary.name)} <span style="font-family:'Courier New',monospace;font-size:12px;color:${C.muted};">${esc(primary.name_de || "")}</span></div>
      <div style="font-size:14px;color:${C.slate};">${esc(primary.concern)}</div>
    </div>` : ""}
  </div>
  <p style="font-family:'Courier New',monospace;font-size:11px;letter-spacing:0.1em;text-transform:uppercase;color:${C.rust};margin:18px 0 6px;">Where the file could break down</p>
  <table style="border-collapse:collapse;width:100%;">${rowHtml}</table>
  ${nextCta ? `
  <div style="background:${C.fog};border-radius:6px;padding:16px 18px;margin:18px 0;">
    <div style="font-family:'Courier New',monospace;font-size:11px;letter-spacing:0.08em;text-transform:uppercase;color:${C.muted};">${esc(qualLabel || "")}</div>
    <div style="font-size:16px;color:${C.ink};margin:4px 0;">${esc(nextCta)}</div>
    <div style="font-size:14px;color:${C.slate};">${esc(nextBody || "")}</div>
  </div>` : ""}
  <p style="font-family:'Courier New',monospace;font-size:11px;color:${C.muted};line-height:1.7;border-top:1px solid ${C.rule};padding-top:14px;margin-top:22px;">
    This is a non-legal, operational snapshot of how well a termination decision is documented, based on generalised patterns drawn from published BAG decisions. It supports counsel; it is not legal advice, does not predict outcomes, and does not constitute Rechtsberatung within the meaning of the RDG. The human remains the decider (no Art. 22 GDPR automated decision-making).
  </p>
</div>`.trim();
}

const STYLES = `
.brs-root{
  --paper:#F5F4F0;--surface:#FFFFFF;--fog:#F3F2EE;--warm:#E8E6E0;
  --ink:#111111;--slate:#3D4452;--muted:#6B7280;
  --rust:#E5631F;--accent-text:#B04714;
  --rule:#DDD9D3;--rule-light:#EDEAE5;--panel:#1D1D1D;
  --red:#C62828;--red-bg:#FFEBEE;--amber:#E65100;--amber-bg:#FFF3E0;--green:#2E7D32;--green-bg:#E8F5E9;
  --radius:6px;
  --display:"Bebas Neue","Impact","Arial Narrow",sans-serif;
  --body:"Source Serif 4","Source Serif Pro",Georgia,"Times New Roman",serif;
  --mono:"Roboto Mono",SFMono-Regular,"SF Mono",Menlo,Consolas,monospace;
  --shadow-sm:0 2px 8px rgba(0,0,0,0.08);--shadow-md:0 6px 24px rgba(0,0,0,0.12);
  font-family:var(--body);color:var(--ink);background:transparent;
  padding:3.5rem 1.5rem 5rem;line-height:1.65;-webkit-font-smoothing:antialiased;
}
.brs-wrap{max-width:780px;margin:0 auto;}

.brs-card{background:var(--surface);border:1px solid var(--rule);border-radius:var(--radius);padding:2rem;margin-bottom:1.25rem;box-shadow:var(--shadow-sm);}
.brs-card--accent{border-top:3px solid var(--rust);}

.brs-label{font-family:var(--mono);font-size:0.7rem;font-weight:500;letter-spacing:0.16em;text-transform:uppercase;color:var(--accent-text);margin:0 0 1rem;}
.brs-label--muted{color:var(--muted);}

.brs-h1{font-family:var(--display);font-size:clamp(2.25rem,5.5vw,3.5rem);font-weight:400;line-height:1.0;letter-spacing:0.02em;margin:0 0 0.85rem;color:var(--ink);}
.brs-sub{font-family:var(--body);font-size:1.18rem;line-height:1.5;color:var(--ink);margin:0 0 0.95rem;font-weight:600;}
.brs-help{font-size:1rem;color:var(--slate);margin:0 0 0.5rem;line-height:1.72;}
.brs-help strong{color:var(--ink);font-weight:600;}

/* Benefit / discover blocks */
.brs-benefits{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:1rem;}
.brs-benefit{border:1px solid var(--rule);border-radius:var(--radius);padding:1.1rem 1.15rem;background:var(--fog);}
.brs-benefit h3{font-family:var(--display);font-weight:400;letter-spacing:0.03em;font-size:1.15rem;margin:0 0 0.4rem;color:var(--ink);}
.brs-benefit p{margin:0;font-size:0.9rem;line-height:1.6;color:var(--slate);}
.brs-list{margin:0.4rem 0 0;padding-left:0;list-style:none;}
.brs-list li{font-size:0.95rem;line-height:1.7;color:var(--slate);padding-left:1.35rem;position:relative;}
.brs-list li::before{content:"—";position:absolute;left:0;color:var(--rust);}
.brs-quote{font-style:italic;color:var(--slate);font-size:0.97rem;line-height:1.65;margin:0 0 0.7rem;padding-left:0.95rem;border-left:2px solid var(--rule);}

/* ── BAG authority cards ─────────────────────────────── */
.bag-cases{margin-top:1.4rem;}
.bag-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(250px,1fr));gap:1rem;margin-top:1.1rem;}
.bag-card{position:relative;background:var(--surface);border:1px solid var(--rule);border-top:3px solid var(--rust);border-radius:var(--radius);padding:1.3rem 1.4rem 1.4rem;box-shadow:var(--shadow-sm);display:flex;flex-direction:column;transition:transform .18s,box-shadow .18s;}
.bag-card:hover{transform:translateY(-3px);box-shadow:var(--shadow-md);}
.bag-top{display:flex;align-items:flex-start;justify-content:space-between;gap:.6rem;margin-bottom:.8rem;}
.bag-badge{font-family:var(--mono);font-weight:600;font-size:0.98rem;letter-spacing:.01em;color:var(--ink);line-height:1.15;}
.bag-seal{flex:none;text-align:right;font-family:var(--mono);font-size:.52rem;letter-spacing:.1em;text-transform:uppercase;color:var(--muted);line-height:1.5;}
.bag-seal .scale{display:block;font-size:1rem;margin-bottom:.15rem;}
.bag-topic{font-family:var(--mono);font-weight:600;font-size:.64rem;letter-spacing:.12em;text-transform:uppercase;color:var(--accent-text);margin:0 0 .65rem;line-height:1.4;}
.bag-lesson{font-size:.95rem;line-height:1.55;color:var(--ink);margin:0 0 1rem;}
.bag-rule{border:0;border-top:1px solid var(--rule-light);margin:0 0 .85rem;}
.bag-check-lbl{font-family:var(--mono);font-size:.58rem;letter-spacing:.14em;text-transform:uppercase;color:var(--rust);margin:0 0 .55rem;}
.bag-checks{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:.5rem;}
.bag-checks li{position:relative;padding-left:1.4rem;font-size:.88rem;line-height:1.45;color:var(--slate);}
.bag-checks li::before{content:"";position:absolute;left:0;top:.18em;width:.82rem;height:.82rem;border:1.5px solid var(--rust);border-radius:3px;}
.bag-checks li::after{content:"";position:absolute;left:.27rem;top:.32em;width:.27rem;height:.48rem;border:solid var(--rust);border-width:0 1.5px 1.5px 0;transform:rotate(40deg);}
.bag-map{margin-top:.9rem;font-family:var(--mono);font-size:.6rem;letter-spacing:.05em;color:var(--muted);}
.bag-map b{color:var(--accent-text);}
.bag-also{margin-top:1.3rem;font-family:var(--mono);font-size:.72rem;line-height:1.7;color:var(--muted);border-left:2px solid var(--rule);padding-left:1rem;}
.bag-also strong{color:var(--slate);}
@media (prefers-reduced-motion: reduce){ .bag-card{transition:none;} .bag-card:hover{transform:none;} }
.brs-quote:last-child{margin-bottom:0;}

/* Route picker */
.brs-types{display:flex;flex-direction:column;gap:0.55rem;}
.brs-type{position:relative;display:flex;flex-direction:column;align-items:flex-start;text-align:left;padding:0.9rem 1rem;border:1px solid var(--rule);border-radius:var(--radius);background:var(--surface);cursor:pointer;font:inherit;color:inherit;transition:border-color .15s,background .15s,box-shadow .15s;width:100%;}
.brs-type:hover{border-color:var(--slate);}
.brs-type[aria-pressed="true"]{border-color:var(--ink);background:var(--fog);box-shadow:inset 3px 0 0 var(--rust);}
.brs-type-de{font-family:var(--body);font-weight:600;font-size:1rem;color:var(--ink);}
.brs-type-en{font-family:var(--mono);font-size:0.72rem;color:var(--muted);margin-top:0.25rem;letter-spacing:0.02em;}
.brs-draft-tag{display:inline-block;font-family:var(--mono);font-size:0.58rem;letter-spacing:0.1em;text-transform:uppercase;color:var(--amber);background:var(--amber-bg);border:1px solid var(--amber);border-radius:var(--radius);padding:0.1rem 0.4rem;margin-top:0.4rem;}

/* Chips row */
.brs-chips{display:flex;flex-wrap:wrap;gap:0.5rem;margin:0 0 0.25rem;}
.brs-chip{font-family:var(--mono);font-size:0.68rem;letter-spacing:0.06em;text-transform:uppercase;color:var(--slate);background:var(--fog);border:1px solid var(--rule);padding:0.3rem 0.6rem;border-radius:var(--radius);}
.brs-chip span{color:var(--rust);margin-right:0.3rem;}

/* Questions */
.brs-progress{font-family:var(--mono);font-size:0.72rem;text-transform:uppercase;letter-spacing:0.1em;color:var(--muted);margin:0 0 1.25rem;}
.brs-q{padding:1.1rem 0;border-top:1px solid var(--rule-light);}
.brs-q:first-of-type{border-top:none;padding-top:0;}
.brs-qtext{font-size:0.99rem;line-height:1.6;margin:0 0 0.7rem;color:var(--ink);}
.brs-qnum{font-family:var(--mono);color:var(--accent-text);font-weight:600;font-size:0.82rem;margin-right:0.45rem;}
.brs-qsub{font-family:var(--mono);font-size:0.64rem;letter-spacing:0.1em;text-transform:uppercase;color:var(--muted);margin:0 0 0.35rem;}

.brs-seg{display:inline-flex;border:1px solid var(--rule);border-radius:var(--radius);overflow:hidden;}
.brs-seg button{appearance:none;border:0;background:var(--surface);padding:0.5rem 1.1rem;font-family:var(--mono);font-size:0.74rem;letter-spacing:0.06em;text-transform:uppercase;cursor:pointer;color:var(--slate);border-right:1px solid var(--rule);transition:background .12s,color .12s;}
.brs-seg button:last-child{border-right:0;}
.brs-seg button:hover{background:var(--fog);color:var(--ink);}
.brs-seg button[aria-pressed="true"]{background:var(--ink);color:#fff;}

/* Choice list (single + multi) */
.brs-choices{display:flex;flex-direction:column;gap:0.45rem;}
.brs-choice{display:flex;align-items:flex-start;gap:0.6rem;text-align:left;padding:0.65rem 0.85rem;border:1px solid var(--rule);border-radius:var(--radius);background:var(--surface);cursor:pointer;font:inherit;color:var(--ink);font-size:0.93rem;line-height:1.5;transition:border-color .15s,background .15s;}
.brs-choice:hover{border-color:var(--slate);}
.brs-choice[aria-pressed="true"]{border-color:var(--ink);background:var(--fog);box-shadow:inset 3px 0 0 var(--rust);}
.brs-choice-box{flex:0 0 auto;width:1rem;height:1rem;margin-top:0.15rem;border:1.5px solid var(--slate);border-radius:3px;}
.brs-choice[aria-pressed="true"] .brs-choice-box{background:var(--rust);border-color:var(--rust);}
.brs-textarea{width:100%;box-sizing:border-box;min-height:90px;border:1px solid var(--rule);border-radius:var(--radius);background:var(--surface);color:var(--ink);font-family:var(--body);font-size:0.95rem;line-height:1.6;padding:0.75rem 0.85rem;resize:vertical;}
.brs-textarea:focus{outline:none;border-color:var(--ink);}

/* Lead-capture gate */
.brs-field{margin:0 0 0.85rem;}
.brs-field-label{display:block;font-family:var(--mono);font-size:0.64rem;letter-spacing:0.1em;text-transform:uppercase;color:var(--muted);margin:0 0 0.35rem;}
.brs-input{width:100%;box-sizing:border-box;border:1px solid var(--rule);border-radius:var(--radius);background:var(--surface);color:var(--ink);font-family:var(--body);font-size:0.97rem;line-height:1.5;padding:0.7rem 0.85rem;}
.brs-input:focus{outline:none;border-color:var(--ink);}
.brs-consent{display:flex;align-items:flex-start;gap:0.6rem;text-align:left;width:100%;padding:0.65rem 0.2rem;border:0;background:none;cursor:pointer;font:inherit;color:var(--slate);font-size:0.9rem;line-height:1.55;}
.brs-consent .brs-choice-box{flex:0 0 auto;width:1rem;height:1rem;margin-top:0.15rem;border:1.5px solid var(--slate);border-radius:3px;}
.brs-consent[aria-pressed="true"] .brs-choice-box{background:var(--rust);border-color:var(--rust);}
.brs-req{color:var(--accent-text);font-family:var(--mono);font-size:0.66rem;letter-spacing:0.04em;text-transform:uppercase;}
.brs-opt{color:var(--muted);font-family:var(--mono);font-size:0.66rem;letter-spacing:0.04em;text-transform:uppercase;}
.brs-gdpr{font-family:var(--mono);font-size:0.7rem;line-height:1.65;color:var(--muted);background:var(--fog);border:1px solid var(--rule-light);border-radius:var(--radius);padding:0.85rem 0.95rem;margin:0.6rem 0 0;letter-spacing:0.005em;}
.brs-gdpr strong{color:var(--slate);}
.brs-gdpr a{color:var(--accent-text);}

/* Buttons */
.brs-actions{display:flex;gap:0.85rem;flex-wrap:wrap;margin-top:0.5rem;align-items:center;}
.brs-btn{appearance:none;border:1px solid var(--ink);background:var(--ink);color:#fff;padding:0.8rem 1.6rem;border-radius:var(--radius);font-family:var(--body);font-size:0.92rem;font-weight:600;cursor:pointer;transition:transform .2s cubic-bezier(.16,1,.3,1),box-shadow .2s,background .18s,border-color .18s,color .18s;box-shadow:0 4px 14px rgba(17,17,17,0.22);}
.brs-btn:hover{background:#222;transform:translateY(-2px);box-shadow:0 10px 26px rgba(17,17,17,0.32);}
.brs-btn.rust{background:var(--rust);border-color:var(--rust);box-shadow:0 4px 16px rgba(229,99,31,0.32);}
.brs-btn.rust:hover{background:var(--accent-text);border-color:var(--accent-text);box-shadow:0 12px 28px rgba(229,99,31,0.48);}
.brs-btn.ghost{background:transparent;color:var(--slate);border-color:var(--rule);box-shadow:none;}
.brs-btn.ghost:hover{background:rgba(17,17,17,0.035);border-color:var(--ink);color:var(--ink);box-shadow:0 6px 18px rgba(17,17,17,0.12);}
.brs-btn:disabled{opacity:0.4;cursor:not-allowed;transform:none;box-shadow:none;}

.brs-validation{font-family:var(--body);font-size:0.88rem;color:var(--red);background:var(--red-bg);border:1px solid var(--red);border-radius:var(--radius);padding:0.7rem 0.85rem;margin-top:0.85rem;}
.brs-notice{font-family:var(--body);font-size:0.9rem;color:var(--slate);background:var(--amber-bg);border:1px solid var(--amber);border-radius:var(--radius);padding:0.8rem 0.95rem;margin:0 0 1.25rem;line-height:1.6;}

/* Score */
.brs-score{font-family:var(--display);font-size:clamp(3rem,9vw,4.75rem);font-weight:400;letter-spacing:0.01em;line-height:0.9;margin:0.25rem 0 0;color:var(--ink);}
.brs-score--green{color:var(--green);}.brs-score--amber{color:var(--amber);}.brs-score--red{color:var(--red);}
.brs-score-unit{font-family:var(--mono);font-size:0.7rem;letter-spacing:0.1em;text-transform:uppercase;color:var(--muted);display:block;margin-bottom:0.35rem;}
.brs-band{font-family:var(--display);font-size:1.45rem;font-weight:400;letter-spacing:0.03em;margin:0.6rem 0 0.1rem;color:var(--ink);}
.brs-band-de{font-family:var(--mono);font-size:0.74rem;letter-spacing:0.04em;color:var(--muted);}
.brs-light{display:inline-block;width:0.7rem;height:0.7rem;border-radius:50%;margin-right:0.5rem;vertical-align:middle;}
.brs-light--green{background:var(--green);}.brs-light--amber{background:var(--amber);}.brs-light--red{background:var(--red);}

.brs-primary{margin-top:1.5rem;padding-top:1.5rem;border-top:1px solid var(--rule);}
.brs-primary-name{font-family:var(--display);font-size:1.35rem;font-weight:400;letter-spacing:0.02em;margin:0 0 0.5rem;color:var(--ink);}
.brs-primary-concern{font-size:0.95rem;line-height:1.7;color:var(--slate);margin:0;}

/* Insights */
.brs-insight{padding:0.95rem 0;border-top:1px solid var(--rule-light);font-size:0.97rem;line-height:1.7;color:var(--slate);}
.brs-insight:first-of-type{border-top:none;padding-top:0.2rem;}
.brs-insight strong{color:var(--ink);font-weight:600;}

/* Qualification badge */
.brs-qual{display:inline-flex;align-items:center;gap:0.5rem;font-family:var(--mono);font-size:0.74rem;letter-spacing:0.08em;text-transform:uppercase;border:1px solid var(--rule);border-radius:var(--radius);padding:0.4rem 0.75rem;background:var(--fog);color:var(--ink);margin-bottom:0.85rem;}

/* Summary stat grid */
.brs-summary{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:0.85rem;}
.brs-sum{border:1px solid var(--rule);border-radius:var(--radius);padding:1rem;background:var(--fog);}
.brs-sum-val{font-family:var(--mono);font-size:2rem;font-weight:700;line-height:1;margin:0;color:var(--ink);}
.brs-sum-label{font-family:var(--mono);font-size:0.62rem;text-transform:uppercase;letter-spacing:0.1em;color:var(--muted);margin:0.55rem 0 0;line-height:1.4;}

/* Gap table */
.brs-table{width:100%;border-collapse:collapse;font-size:0.9rem;}
.brs-table th,.brs-table td{text-align:left;vertical-align:top;padding:0.85rem 0.65rem;border-bottom:1px solid var(--rule-light);line-height:1.55;}
.brs-table th{font-family:var(--mono);font-size:0.62rem;text-transform:uppercase;letter-spacing:0.1em;color:var(--muted);font-weight:500;}
.brs-gap-name{font-family:var(--body);font-weight:600;color:var(--ink);}
.brs-gap-de{font-family:var(--mono);color:var(--muted);font-size:0.72rem;margin-top:0.15rem;}
.brs-table td{color:var(--slate);}

/* Killer line + CTA */
.brs-killer{font-family:var(--body);font-size:1.2rem;font-style:italic;font-weight:400;line-height:1.55;margin:0;color:var(--ink);border-left:2px solid var(--rust);padding-left:1rem;}
.brs-cta-title{font-family:var(--display);font-size:1.65rem;font-weight:400;letter-spacing:0.02em;margin:0 0 0.6rem;color:var(--ink);}
.brs-cta-title span{color:var(--rust);}
.brs-cta-body{font-size:0.97rem;line-height:1.72;color:var(--slate);margin:0 0 1.25rem;}
.brs-disclaimer{font-family:var(--mono);font-size:0.68rem;color:var(--muted);line-height:1.7;margin:0;letter-spacing:0.01em;}

[data-theme="dark"] .brs-root{
  --paper:#0E1013;--surface:#16191F;--fog:#1C2027;--warm:#232830;
  --ink:#F2EFE8;--slate:#C7C3BA;--muted:#8A8F98;
  --rust:#E5631F;--accent-text:#F0834A;
  --rule:#2A2F38;--rule-light:#20242B;--panel:#0A0C10;
  --red:#E07A55;--red-bg:rgba(224,122,85,0.10);--amber:#D9B36A;--amber-bg:rgba(217,179,106,0.10);--green:#7FB994;--green-bg:rgba(127,185,148,0.10);
  --shadow-sm:0 1px 2px rgba(0,0,0,0.45);--shadow-md:0 4px 16px rgba(0,0,0,0.5);
}
[data-theme="dark"] .brs-seg button[aria-pressed="true"]{background:var(--ink);color:var(--paper);}
[data-theme="dark"] .brs-btn{background:var(--ink);color:var(--paper);border-color:var(--ink);box-shadow:var(--shadow-md);}
[data-theme="dark"] .brs-btn:hover{background:#fff;}
[data-theme="dark"] .brs-btn.rust{background:var(--rust);border-color:var(--rust);color:#fff;}
[data-theme="dark"] .brs-btn.ghost{background:transparent;color:var(--slate);border-color:var(--rule);}
[data-theme="dark"] .brs-btn.ghost:hover{color:var(--ink);border-color:var(--ink);}

@media (max-width:640px){
  .brs-root{padding:32px 14px;}
  .brs-card{padding:1.4rem;}
  .brs-seg{display:flex;width:100%;}
  .brs-seg button{flex:1;padding:0.6rem 0.4rem;}
  .brs-table,.brs-table thead,.brs-table tbody,.brs-table tr,.brs-table th,.brs-table td{display:block;}
  .brs-table thead{display:none;}
  .brs-table td{border-bottom:none;padding:0.3rem 0;}
  .brs-table tr{border-bottom:1px solid var(--rule);padding:0.85rem 0;}
}
`;

function GermanHRAssessment() {
  const [stage, setStage] = useState("intro"); // intro | questions | results
  const [routeId, setRouteId] = useState(null);
  const [answers, setAnswers] = useState({});  // Q1–Q10 → yes|no|unknown
  const [ctx, setCtx] = useState({ current: null, desired: null, obstacles: [], solution: null, open: "" });
  const [showValidation, setShowValidation] = useState(false);

  // Lead-capture gate (collected before the full report is revealed).
  const [unlocked, setUnlocked] = useState(false);
  const [lead, setLead] = useState({ name: "", email: "" });
  const [deliveryConsent, setDeliveryConsent] = useState(false);
  const [marketingConsent, setMarketingConsent] = useState(false);
  const [sending, setSending] = useState(false);
  const [sendError, setSendError] = useState(false);
  const [sent, setSent] = useState(false);
  const [gateError, setGateError] = useState(null);

  const route = ROUTES.find((r) => r.id === routeId) || null;

  const scoredAnswered = route ? route.questions.filter((q) => answers[q.n]).length : 0;
  const contextReady = ctx.current && ctx.desired && ctx.solution;
  const allAnswered = route && scoredAnswered === 10 && contextReady;

  const result = useMemo(() => {
    if (!route || scoredAnswered !== 10) return null;
    const points = {};
    let gapScore = 0;
    let unknownCount = 0;
    let unsupportedCount = 0;
    for (const q of route.questions) {
      const p = ANSWER_POINTS[answers[q.n]];
      points[q.n] = p;
      gapScore += p;
      if (answers[q.n] === "unknown") unknownCount += 1;
      if (answers[q.n] === "no") unsupportedCount += 1;
    }
    const defensibility = Math.round(((20 - gapScore) / 20) * 100);
    const band = bandFor(defensibility);
    const patterns = route.patterns
      .map((p) => ({ ...p, gap: p.q.reduce((s, qn) => s + (points[qn] || 0), 0) }))
      .filter((p) => p.gap > 0)
      .sort((a, b) => b.gap - a.gap);
    return {
      gapScore,
      defensibility,
      band,
      unknownCount,
      unsupportedCount,
      activePatterns: patterns,
      primary: patterns[0] || null,
    };
  }, [route, answers, scoredAnswered]);

  // Sales-qualification fit, transparent and score-led, modulated by intent.
  const qualification = useMemo(() => {
    if (!result) return null;
    let fit;
    if (result.defensibility < 60) fit = "high";
    else if (result.defensibility < 80) fit = "medium";
    else fit = "low";
    if (ctx.desired === "exploring" && fit === "high") fit = "medium";
    if (ctx.solution === "checklist" || ctx.solution === "training") {
      if (fit === "high") fit = "medium";
      else if (fit === "medium") fit = "low";
    }
    return fit;
  }, [result, ctx]);

  function setAnswer(qn, val) {
    setAnswers((prev) => ({ ...prev, [qn]: val }));
    setShowValidation(false);
  }
  function setSingle(key, val) {
    setCtx((prev) => ({ ...prev, [key]: val }));
    setShowValidation(false);
  }
  function toggleMulti(key, val) {
    setCtx((prev) => {
      const has = prev[key].includes(val);
      return { ...prev, [key]: has ? prev[key].filter((x) => x !== val) : [...prev[key], val] };
    });
  }

  function startRoute() {
    if (!routeId) {
      setShowValidation(true);
      return;
    }
    setShowValidation(false);
    setStage("questions");
    scrollTop();
  }
  function generate() {
    if (!allAnswered) {
      setShowValidation(true);
      return;
    }
    setShowValidation(false);
    setStage("results");
    scrollTop();
  }
  async function sendReport() {
    const name = lead.name.trim();
    const email = lead.email.trim();
    if (!name) { setGateError("Please enter your name."); return; }
    if (!EMAIL_RE.test(email)) { setGateError("Please enter a valid email address."); return; }
    if (!deliveryConsent) { setGateError("Please confirm consent so we can send your report."); return; }
    setGateError(null);
    setSendError(false);

    const next = nextStep();
    const report = buildReportHtml({
      name,
      routeLabelEn: route.en,
      routeLabelDe: route.de,
      defensibility: result.defensibility,
      bandEn: result.band.en,
      bandDe: result.band.de,
      grade: result.band.grade,
      primary: result.primary || null,
      rows: result.activePatterns,
      qualLabel: QUAL_LABEL[qualification],
      nextCta: next.cta,
      nextBody: next.body,
    });

    if (emailjsConfigured()) {
      setSending(true);
      try {
        window.emailjs.init({ publicKey: EMAILJS.publicKey });
        await window.emailjs.send(EMAILJS.serviceId, EMAILJS.templateId, {
          // Recipient aliases so the shared template's "To Email" always resolves.
          to_email: email, email: email, reply_to: email,
          to_name: name, name: name,
          report,                                          // the whole email body
          // optional structured fields the template could also use:
          route: `${route.de} (${route.en})`,
          score: String(result.defensibility),
          band: result.band.en,
          primary: result.primary ? result.primary.name : "—",
        }, { publicKey: EMAILJS.publicKey });
        setSent(true);
      } catch (e) {
        // Lead is captured; email is best-effort — don't trap the visitor.
        setSendError(true);
      } finally {
        setSending(false);
      }
    }
    // Unlock regardless: the lead + consent are captured, and the report is
    // always available on-screen. Email delivery is best-effort.
    setUnlocked(true);
    scrollTop();
  }

  function reset() {
    setStage("intro");
    setRouteId(null);
    setAnswers({});
    setCtx({ current: null, desired: null, obstacles: [], solution: null, open: "" });
    setShowValidation(false);
    setUnlocked(false);
    setLead({ name: "", email: "" });
    setDeliveryConsent(false);
    setMarketingConsent(false);
    setSending(false);
    setSendError(false);
    setSent(false);
    setGateError(null);
    scrollTop();
  }
  function scrollTop() {
    if (typeof window !== "undefined") window.scrollTo({ top: 0, behavior: "smooth" });
  }

  /* ── Insights (2–3 plain-language findings) ── */
  function buildInsights() {
    const out = [];
    out.push(
      <p className="brs-insight" key="band">
        Your file scores <strong>{result.defensibility}%</strong> on documented defensibility — <strong>{result.band.en.toLowerCase()}</strong>. This reflects what the record proves today, not the merits of the decision.
      </p>
    );
    if (result.primary) {
      out.push(
        <p className="brs-insight" key="primary">
          The largest gap is in <strong>{result.primary.name}</strong>. {result.primary.concern}
        </p>
      );
    }
    if (result.unknownCount >= 3 || ctx.obstacles.includes("conversations")) {
      out.push(
        <p className="brs-insight" key="unknown">
          {result.unknownCount > 0 ? (
            <>You marked <strong>{result.unknownCount}</strong> answer{result.unknownCount === 1 ? "" : "s"} as "Unknown". </>
          ) : null}
          On a contested file, what you can't quickly confirm is exactly what the other side probes first — decisions that live in conversations rather than records become the opening.
        </p>
      );
    } else if (result.defensibility >= 80) {
      out.push(
        <p className="brs-insight" key="strong">
          This file looks well-supported. The value now is consistency — making your weakest manager's file look like this one, every time.
        </p>
      );
    }
    return out;
  }

  function nextStep() {
    if (qualification === "high") {
      return {
        title: <>Where the gaps are, <span>VerfahrensCheck</span> begins.</>,
        body: "Your answers point to meaningful exposure on this file. A VerfahrensCheck is a structured second read: it walks the decision path, the evidence chain, and the procedural sequence for one anonymised matter, so you can fix the file — or decide settle-or-fight — before anyone else reviews it.",
        cta: "Request a VerfahrensCheck review",
      };
    }
    if (qualification === "medium") {
      return {
        title: <>Start with your <span>highest-value</span> open case.</>,
        body: "The file is partly there. The fastest return is a focused second read on the case with the most exposure — so you walk into the board or audit review already prepared, and reserve counsel budget for the genuinely hard matters.",
        cta: "Request a focused review",
      };
    }
    return {
      title: <>Make every file <span>look like this one</span>.</>,
      body: "This file holds up well. The opportunity is consistency across managers and sites. Use the route checklist as a repeatable internal standard, and keep a VerfahrensCheck in reserve for the cases that don't score this cleanly.",
      cta: "See the route checklist",
    };
  }

  const QUAL_LABEL = { high: "Ready for a direct review", medium: "A focused review fits", low: "Self-serve, with backup" };

  return (
    <div className="brs-root">
      <style>{STYLES}</style>
      <div className="brs-wrap">

        {/* ─────────────── INTRO / LANDING ─────────────── */}
        {stage === "intro" && (
          <>
            <section className="brs-card brs-card--accent">
              <p className="brs-label">Operational Confidence Assessment · Deutsches Arbeitsrecht</p>
              <h1 className="brs-h1">Could this dismissal hold up — before you decide?</h1>
              <p className="brs-help">
                Before you sign off on a termination, you carry the exposure: the <strong>Annahmeverzug</strong> bill that can land 14 months later, a <strong>§102</strong> hearing that voids a substantively correct decision, and the file you may have to defend in front of the board.
              </p>
              <p className="brs-help">
                This is a quick, structural read of how well a dismissal is documented — a co-pilot's view of where it could break down <strong>while you can still fix it</strong>. It is not legal advice and does not predict outcomes.
              </p>
            </section>

            <section className="brs-card">
              <p className="brs-label">This assessment measures and improves</p>
              <div className="brs-benefits">
                <div className="brs-benefit">
                  <h3>Process Robustness</h3>
                  <p>Can the file withstand review by someone who wasn't involved?</p>
                </div>
                <div className="brs-benefit">
                  <h3>Execution Consistency</h3>
                  <p>Would another HR team reach the same outcome from the same file?</p>
                </div>
                <div className="brs-benefit">
                  <h3>Operational Confidence</h3>
                  <p>Can you move forward knowing the decision is properly supported?</p>
                </div>
              </div>
            </section>

            <section className="brs-card">
              <p className="brs-label">Why this assessment exists</p>
              <p className="brs-help">
                Most terminations don't become difficult because the business reason was wrong. They become difficult when questions arise later and the process is no longer easy to explain. The criteria here reflect recurring review themes in published BAG decisions — decision chronology, evidence support, selection rationale, consultation records, and decision justification.
              </p>
              <div className="bag-cases">
                <div className="bag-grid">

                  <article className="bag-card">
                    <div className="bag-top">
                      <span className="bag-badge">BAG 6 AZR 157/22</span>
                      <span className="bag-seal"><span className="scale">⚖️</span>Bundes-<br/>arbeitsgericht<br/>Published</span>
                    </div>
                    <p className="bag-topic">§17 KSchG · Filing sequence</p>
                    <p className="bag-lesson">A termination issued before the mass-dismissal notice is on file <em>cannot take effect</em> &mdash; the file breaks at a step before the merits are ever reached.</p>
                    <hr className="bag-rule"/>
                    <p className="bag-check-lbl">What the assessment checks</p>
                    <ul className="bag-checks">
                      <li>Is the head-count check on the trigger date in the file, with date and source?</li>
                      <li>Is the dated filing receipt in the file <em>before</em> the letter date &mdash; not reconstructed afterwards?</li>
                    </ul>
                    <p className="bag-map">Maps to · <b>decision chronology</b></p>
                  </article>

                  <article className="bag-card">
                    <div className="bag-top">
                      <span className="bag-badge">BAG 2 AZR 68/24</span>
                      <span className="bag-seal"><span className="scale">⚖️</span>Bundes-<br/>arbeitsgericht<br/>Published</span>
                    </div>
                    <p className="bag-topic">§130 BGB · Zugang / delivery proof</p>
                    <p className="bag-lesson">A sent letter <em>cannot prove its own arrival</em>. Without a dated delivery-confirmation slip, <em>Zugang</em> is not proven &mdash; and the §4 KSchG clock never starts.</p>
                    <hr className="bag-rule"/>
                    <p className="bag-check-lbl">What the assessment checks</p>
                    <ul className="bag-checks">
                      <li>Will the delivery method produce proof of receipt on a <em>specific date</em> &mdash; not just proof you sent it?</li>
                      <li>If the employee disputes receipt, can you still retrieve the artifact &mdash; or does a retention clock run out (15 mo. at Deutsche Post)?</li>
                    </ul>
                    <p className="bag-map">Maps to · <b>evidence support</b></p>
                  </article>

                  <article className="bag-card">
                    <div className="bag-top">
                      <span className="bag-badge">BAG 2 AZR 296/22</span>
                      <span className="bag-seal"><span className="scale">⚖️</span>Bundes-<br/>arbeitsgericht<br/>Published</span>
                    </div>
                    <p className="bag-topic">§286 ZPO · Surveillance evidence</p>
                    <p className="bag-lesson">Open, marked surveillance of intentional misconduct is not caught by an evidence use-ban &mdash; but only a file that <em>proves the camera was open and the purpose documented</em> survives. &ldquo;Datenschutz ist kein Tatenschutz.&rdquo;</p>
                    <hr className="bag-rule"/>
                    <p className="bag-check-lbl">What the assessment checks</p>
                    <ul className="bag-checks">
                      <li>Is the surveillance evidence tied to a written purpose, with a date and a source, in the file?</li>
                      <li>Would this file survive a legal review next Monday without anyone patching the pleading first?</li>
                    </ul>
                    <p className="bag-map">Maps to · <b>decision justification</b></p>
                  </article>

                  <article className="bag-card">
                    <div className="bag-top">
                      <span className="bag-badge">BAG 2 AZR 55/25</span>
                      <span className="bag-seal"><span className="scale">⚖️</span>Bundes-<br/>arbeitsgericht<br/>Published</span>
                    </div>
                    <p className="bag-topic">§626 II BGB · Hearing deadline</p>
                    <p className="bag-lesson">A dismissal can be lost on the calendar, not the facts &mdash; the two-week clock runs from the knowledge date, and an undocumented hearing attempt cannot stop it.</p>
                    <hr className="bag-rule"/>
                    <p className="bag-check-lbl">What the assessment checks</p>
                    <ul className="bag-checks">
                      <li>Do you know the exact date you first learned the facts?</li>
                      <li>Is the attempt to reach the person &mdash; or the reason none was made &mdash; written down in the file, not just remembered?</li>
                    </ul>
                    <p className="bag-map">Maps to · <b>consultation records</b></p>
                  </article>

                </div>
                <p className="bag-also">
                  <strong>Also anchored in</strong> &mdash; BAG 2 AZR 297/22 (how surveillance evidence is weighed), BAG 2 AZR 736/13 (consultation judged on the decision basis).
                </p>
              </div>
            </section>

            <section className="brs-card">
              <p className="brs-label">What HR teams often discover</p>
              <p className="brs-quote">"The assessment showed where key decisions existed in conversations rather than records."</p>
              <p className="brs-quote">"It highlighted process gaps before implementation — while there was still time to act."</p>
              <p className="brs-quote">"It identified the points where future questions would be hardest to answer."</p>
            </section>

            <section className="brs-card">
              <p className="brs-label">Choose the dismissal type</p>
              <div className="brs-types" role="radiogroup" aria-label="Dismissal type">
                {ROUTES.map((r) => (
                  <button
                    key={r.id}
                    type="button"
                    className="brs-type"
                    aria-pressed={routeId === r.id}
                    onClick={() => { setRouteId(r.id); setShowValidation(false); }}
                  >
                    <span className="brs-type-de">{r.de}</span>
                    <span className="brs-type-en">{r.en}</span>
                    {r.draft && <span className="brs-draft-tag">Preliminary — results indicative</span>}
                  </button>
                ))}
              </div>

              <div className="brs-chips" style={{ marginTop: "1.5rem" }}>
                <span className="brs-chip"><span>✓</span>Free</span>
                <span className="brs-chip"><span>✓</span>15 questions</span>
                <span className="brs-chip"><span>✓</span>Under 3 minutes</span>
                <span className="brs-chip"><span>✓</span>Immediate results</span>
                <span className="brs-chip"><span>✓</span>No sign-up</span>
              </div>

              <div className="brs-actions" style={{ marginTop: "1.25rem" }}>
                <button className="brs-btn rust" type="button" onClick={startRoute}>Start the assessment — 3 min</button>
              </div>
              {showValidation && (
                <div className="brs-validation">Please choose a dismissal type to begin.</div>
              )}
            </section>
          </>
        )}

        {/* ─────────────── QUESTIONS ─────────────── */}
        {stage === "questions" && route && (
          <>
            <section className="brs-card brs-card--accent">
              <p className="brs-label">{route.de}</p>
              <p className="brs-sub">{route.en}</p>
              <p className="brs-help">{route.blurb}</p>
              {route.draft && (
                <div className="brs-notice" style={{ marginTop: "1rem", marginBottom: 0 }}>
                  This route is preliminary: the senior-executive criteria are still in design and not yet part of the active review process. Treat the result as indicative.
                </div>
              )}
            </section>

            <section className="brs-card">
              <p className="brs-label">Best-practice questions (1–10)</p>
              <p className="brs-progress">{scoredAnswered} of 10 answered · these produce your score</p>
              {route.questions.map((q) => (
                <div className="brs-q" key={q.n}>
                  <p className="brs-qtext"><span className="brs-qnum">Q{q.n}.</span>{q.text}</p>
                  <div className="brs-seg" role="radiogroup" aria-label={`Question ${q.n}`}>
                    {["yes", "no", "unknown"].map((v) => (
                      <button key={v} type="button" aria-pressed={answers[q.n] === v} onClick={() => setAnswer(q.n, v)}>
                        {v === "yes" ? "Yes" : v === "no" ? "No" : "Unknown"}
                      </button>
                    ))}
                  </div>
                </div>
              ))}
            </section>

            <section className="brs-card">
              <p className="brs-label">A little context (11–15)</p>

              {[CTX_CURRENT, CTX_DESIRED].map((cq) => (
                <div className="brs-q" key={cq.key}>
                  <p className="brs-qsub">Q{cq.n} · {cq.label}</p>
                  <p className="brs-qtext">{cq.text}</p>
                  <div className="brs-choices">
                    {cq.options.map((o) => (
                      <button key={o.v} type="button" className="brs-choice" aria-pressed={ctx[cq.key] === o.v} onClick={() => setSingle(cq.key, o.v)}>
                        <span className="brs-choice-box" aria-hidden="true" />{o.label}
                      </button>
                    ))}
                  </div>
                </div>
              ))}

              <div className="brs-q">
                <p className="brs-qsub">Q{CTX_OBSTACLES.n} · {CTX_OBSTACLES.label}</p>
                <p className="brs-qtext">{CTX_OBSTACLES.text}</p>
                <div className="brs-choices">
                  {CTX_OBSTACLES.options.map((o) => (
                    <button key={o.v} type="button" className="brs-choice" aria-pressed={ctx.obstacles.includes(o.v)} onClick={() => toggleMulti("obstacles", o.v)}>
                      <span className="brs-choice-box" aria-hidden="true" />{o.label}
                    </button>
                  ))}
                </div>
              </div>

              <div className="brs-q">
                <p className="brs-qsub">Q{CTX_SOLUTION.n} · {CTX_SOLUTION.label}</p>
                <p className="brs-qtext">{CTX_SOLUTION.text}</p>
                <div className="brs-choices">
                  {CTX_SOLUTION.options.map((o) => (
                    <button key={o.v} type="button" className="brs-choice" aria-pressed={ctx.solution === o.v} onClick={() => setSingle("solution", o.v)}>
                      <span className="brs-choice-box" aria-hidden="true" />{o.label}
                    </button>
                  ))}
                </div>
              </div>

              <div className="brs-q">
                <p className="brs-qsub">Q{CTX_OPEN.n} · {CTX_OPEN.label}</p>
                <p className="brs-qtext">{CTX_OPEN.text}</p>
                <textarea
                  className="brs-textarea"
                  value={ctx.open}
                  onChange={(e) => setCtx((prev) => ({ ...prev, open: e.target.value }))}
                  placeholder="Optional — anything that would help us read your result in context."
                />
              </div>

              <div className="brs-actions" style={{ marginTop: 16 }}>
                <button className="brs-btn" type="button" onClick={generate}>See my result</button>
                <button className="brs-btn ghost" type="button" onClick={reset}>Start over</button>
              </div>
              {showValidation && (
                <div className="brs-validation">
                  Please answer all ten best-practice questions and the three context questions (11, 12, 14) before continuing. Questions 13 and 15 are optional.
                </div>
              )}
            </section>
          </>
        )}

        {/* ─────────────── RESULTS ─────────────── */}
        {stage === "results" && result && route && (
          <>
            <section className="brs-card brs-card--accent">
              <p className="brs-label">Your result — {route.de}</p>
              <span className="brs-score-unit">Documented defensibility</span>
              <p className={`brs-score brs-score--${result.band.grade}`}>{result.defensibility}%</p>
              <p className="brs-band">
                <span className={`brs-light brs-light--${result.band.grade}`} aria-hidden="true" />
                {result.band.en}
              </p>
              <p className="brs-band-de">{result.band.de}</p>
              {route.draft && (
                <div className="brs-notice" style={{ marginTop: "1.1rem", marginBottom: 0 }}>
                  Preliminary route — the senior-executive criteria are still in design. Read this score as indicative, not definitive.
                </div>
              )}
              {result.primary && (
                <div className="brs-primary">
                  <p className="brs-label brs-label--muted">Primary failure mode</p>
                  <p className="brs-primary-name">{result.primary.name}</p>
                  <p className="brs-primary-concern">{result.primary.concern}</p>
                </div>
              )}
            </section>

            {!unlocked && (
              <section className="brs-card brs-card--accent">
                <p className="brs-label">Get your full report</p>
                <p className="brs-help">
                  You've seen your headline score. Add your details to unlock the full breakdown — every gap pattern, the insights, and your recommended next step — and we'll email you a copy to keep or share with the board.
                </p>

                <div className="brs-field">
                  <label className="brs-field-label" htmlFor="lead-name">Name</label>
                  <input id="lead-name" className="brs-input" type="text" autoComplete="name"
                    value={lead.name}
                    onChange={(e) => { setLead((p) => ({ ...p, name: e.target.value })); setGateError(null); }}
                    placeholder="Your name" />
                </div>
                <div className="brs-field">
                  <label className="brs-field-label" htmlFor="lead-email">Work email</label>
                  <input id="lead-email" className="brs-input" type="email" autoComplete="email"
                    value={lead.email}
                    onChange={(e) => { setLead((p) => ({ ...p, email: e.target.value })); setGateError(null); }}
                    placeholder="name@company.de" />
                </div>

                <button type="button" className="brs-consent" aria-pressed={deliveryConsent}
                  onClick={() => { setDeliveryConsent((v) => !v); setGateError(null); }}>
                  <span className="brs-choice-box" aria-hidden="true" />
                  <span>I agree that {PRIVACY.controller} may use my name and email to send me this report. <span className="brs-req">(required)</span></span>
                </button>
                <button type="button" className="brs-consent" aria-pressed={marketingConsent}
                  onClick={() => setMarketingConsent((v) => !v)}>
                  <span className="brs-choice-box" aria-hidden="true" />
                  <span>You may also contact me about a VerfahrensCheck review. <span className="brs-opt">(optional)</span></span>
                </button>

                <div className="brs-gdpr">
                  <strong>How your data is handled.</strong> Controller: {PRIVACY.controller} ({PRIVACY.contact}). We use your name and email only to send you this report — and, if you tick the optional box, to contact you about a review. Legal basis: your consent (Art. 6 Abs. 1 lit. a DSGVO); you can withdraw it at any time by emailing {PRIVACY.contact}. To deliver the email, your details and the report are transmitted to our email provider (EmailJS), which may process them outside the EU/EEA under appropriate safeguards, and are kept {PRIVACY.retention}. This assessment runs in your browser — your answers are not stored on our servers, are not used to monitor or score individual managers, and are not automated decision-making. See our <a href={PRIVACY.privacyUrl} target="_blank" rel="noopener noreferrer">Datenschutzerklärung</a>.
                </div>

                <div className="brs-actions" style={{ marginTop: 16 }}>
                  <button className="brs-btn rust" type="button" disabled={sending} onClick={sendReport}>
                    {sending ? "Sending…" : "Email me the full report"}
                  </button>
                  <button className="brs-btn ghost" type="button" onClick={() => { setStage("questions"); scrollTop(); }}>Back to questions</button>
                </div>
                {gateError && <div className="brs-validation">{gateError}</div>}
              </section>
            )}

            {unlocked && (<>
            {sent && (
              <div className="brs-notice" style={{ marginBottom: "1.25rem" }}>
                Your report is on its way to <strong>{lead.email}</strong>. The full breakdown is below.
              </div>
            )}
            {sendError && (
              <div className="brs-notice" style={{ marginBottom: "1.25rem" }}>
                We couldn't email the report just now, but your full breakdown is unlocked below. Please try again later if you'd like a copy by email.
              </div>
            )}
            {!sent && !sendError && !emailjsConfigured() && (
              <div className="brs-notice" style={{ marginBottom: "1.25rem" }}>
                Email delivery isn't configured in this preview (the EmailJS SDK didn't load). Your full breakdown is unlocked below.
              </div>
            )}

            <section className="brs-card">
              <p className="brs-label">What your answers say</p>
              {buildInsights()}
            </section>

            <section className="brs-card">
              <p className="brs-label">Summary</p>
              <div className="brs-summary">
                <div className="brs-sum"><p className="brs-sum-val">{result.unsupportedCount}</p><p className="brs-sum-label">Gaps (answered "No")</p></div>
                <div className="brs-sum"><p className="brs-sum-val">{result.unknownCount}</p><p className="brs-sum-label">Couldn't confirm ("Unknown")</p></div>
                <div className="brs-sum"><p className="brs-sum-val">{result.activePatterns.length}</p><p className="brs-sum-label">Active gap patterns</p></div>
              </div>
            </section>

            {result.activePatterns.length > 0 && (
              <section className="brs-card">
                <p className="brs-label">Where the file could break down</p>
                <table className="brs-table">
                  <thead>
                    <tr><th style={{ width: "38%" }}>Gap pattern</th><th style={{ width: "62%" }}>Why it matters</th></tr>
                  </thead>
                  <tbody>
                    {result.activePatterns.map((p) => (
                      <tr key={p.id}>
                        <td><div className="brs-gap-name">{p.name}</div><div className="brs-gap-de">{p.name_de}</div></td>
                        <td>{p.concern}</td>
                      </tr>
                    ))}
                  </tbody>
                </table>
              </section>
            )}

            <section className="brs-card">
              <p className="brs-killer">
                The question is not whether your team knows what happened. It's whether the file still proves it when no one remembers — and before you've decided to settle or fight.
              </p>
            </section>

            <section className="brs-card">
              <span className="brs-qual">{QUAL_LABEL[qualification]}</span>
              <p className="brs-cta-title">{nextStep().title}</p>
              <p className="brs-cta-body">{nextStep().body}</p>
              <div className="brs-actions">
                <button className="brs-btn rust" type="button" onClick={() => alert("Connect this to your booking / contact flow.")}>{nextStep().cta}</button>
                <button className="brs-btn ghost" type="button" onClick={() => { setStage("questions"); scrollTop(); }}>Back to questions</button>
                <button className="brs-btn ghost" type="button" onClick={reset}>Start over</button>
              </div>
            </section>
            </>)}

            <section className="brs-card">
              <p className="brs-disclaimer">
                This tool provides a non-legal, operational snapshot of how well a termination decision is documented, based on generalised review patterns drawn from published BAG decisions. It does not provide legal advice, does not predict litigation outcomes, does not monitor or score individual managers, and is not automated decision-making. It does not replace review by qualified German employment counsel and does not constitute Rechtsberatung within the meaning of the RDG.
              </p>
            </section>
          </>
        )}
      </div>
    </div>
  );
}
