import {
  ensureMathJax,
  groupDecls,
  installMathRules,
  lib_default,
  texToPlain,
  texToSvg,
  tokenizeFindsl
} from "./chunk-Q3JWOKBG.js";
import "./chunk-MZHE4QUL.js";

// src/shims/empty.ts
var empty_default = {};

// ../core/out/docgen/pdf.js
function cjsDefault(mod) {
  const m = mod;
  return m && typeof m === "object" && "default" in m ? m.default : mod;
}
var C = {
  pageBg: "#faf9f5",
  // Papier (Creme)
  fg: "#1a1813",
  // Überschriften/Ink
  body: "#3c392f",
  // Fließtext
  muted: "#8a8475",
  // Eyebrows/Meta/Captions
  faint: "#b3ad9c",
  // dezenteste Schrift
  rule: "#e5e1d4",
  // Haarlinien/Rahmen
  accent: "#bf512e",
  // Terracotta
  accentDeep: "#9a3f22",
  accentSoft: "#f6e9e0",
  // Callout-/Tab-Füllung
  codeBg: "#f4f1e9",
  codeBorder: "#e6e1d2",
  codeFg: "#2b281f",
  zebra: "#f3efe5",
  tableHead: "#efeadd",
  surface: "#ffffff"
};
var TK = {
  kw: { color: "#9a2bd8", bold: true },
  type: { color: "#0a7d6c" },
  str: { color: "#b3541e" },
  num: { color: "#1f6feb" },
  com: { color: "#8a8475", italics: true },
  anno: { color: "#a8341f", bold: true },
  plain: { color: "#2b281f" }
};
var CONTENT_W = 495;
var MD = new lib_default({ html: false, linkify: true, typographer: false });
installMathRules(MD);
function findslSpans(code) {
  return tokenizeFindsl(code).map((t) => ({
    text: t.text.replace(/ /g, "\xA0"),
    ...TK[t.kind]
  }));
}
var codeLayout = {
  hLineWidth: () => 0.75,
  vLineWidth: (i) => i === 0 ? 2.5 : 0.75,
  hLineColor: () => C.codeBorder,
  vLineColor: (i) => i === 0 ? C.accent : C.codeBorder,
  fillColor: () => C.codeBg,
  paddingLeft: () => 12,
  paddingRight: () => 11,
  paddingTop: () => 8,
  paddingBottom: () => 8
};
var quelleLayout = {
  hLineWidth: () => 0,
  vLineWidth: (i) => i === 0 ? 1.5 : 0,
  vLineColor: () => C.accent,
  fillColor: () => null,
  paddingLeft: () => 9,
  paddingRight: () => 0,
  paddingTop: () => 2,
  paddingBottom: () => 2
};
var gridLayout = {
  hLineWidth: (i) => i === 1 ? 1.5 : 0,
  vLineWidth: () => 0,
  hLineColor: () => C.accent,
  fillColor: (rowIndex) => rowIndex === 0 ? C.tableHead : rowIndex % 2 === 0 ? C.zebra : null,
  paddingLeft: () => 10,
  paddingRight: () => 10,
  paddingTop: () => 7,
  paddingBottom: () => 7
};
function codeBlock(code) {
  return {
    stack: [
      { text: "FINDSL", style: "codeLabel" },
      {
        table: {
          widths: ["*"],
          // `preserveLeadingSpaces`: pdfmake trimmt sonst die
          // führende Whitespace JEDER Zeile (auch NBSP) →
          // Einrückung ginge verloren. NBSP (findslSpans)
          // hält zusätzlich das interne Spalten-Padding.
          body: [[{
            text: findslSpans(code),
            style: "code",
            preserveLeadingSpaces: true
          }]]
        },
        layout: codeLayout
      }
    ],
    margin: [0, 3, 0, 10]
  };
}
function quelleCallout(body) {
  return {
    table: {
      widths: ["*"],
      body: [[{
        text: [{ text: "Quelle  ", color: C.muted }, ...body],
        fontSize: 8.5,
        color: C.muted,
        lineHeight: 1.3
      }]]
    },
    layout: quelleLayout,
    margin: [0, 3, 0, 5]
  };
}
function hairline(weight, color, top, bottom) {
  return {
    canvas: [{
      type: "line",
      x1: 0,
      y1: 0,
      x2: CONTENT_W,
      y2: 0,
      lineWidth: weight,
      lineColor: color
    }],
    margin: [0, top, 0, bottom]
  };
}
function inlineSpans(children) {
  const out = [];
  let bold = false, italic = false, link;
  for (const t of children) {
    switch (t.type) {
      case "text":
        out.push({
          text: t.content,
          bold,
          italics: italic,
          ...link ? { link, color: C.accent } : {}
        });
        break;
      case "code_inline":
        out.push({
          text: t.content,
          style: "code",
          ...link ? { link, color: C.accent } : {}
        });
        break;
      case "strong_open":
        bold = true;
        break;
      case "strong_close":
        bold = false;
        break;
      case "em_open":
        italic = true;
        break;
      case "em_close":
        italic = false;
        break;
      case "link_open":
        link = t.attrGet("href") ?? void 0;
        break;
      case "link_close":
        link = void 0;
        break;
      case "softbreak":
        out.push({ text: " " });
        break;
      case "hardbreak":
        out.push({ text: "\n" });
        break;
      // Inline-Mathe: pdfmake kann kein SVG im fließenden Text-
      // Array platzieren → lesbarer, WinAnsi-sicherer Klartext
      // (kursiv, math-artig) statt Roh-TeX. (HTML rendert Inline-
      // Mathe voll via KaTeX; Block-Mathe ist auch im PDF echtes
      // SVG. Siehe SPEC § 4.x.)
      case "math_inline":
        out.push({
          text: texToPlain(t.content),
          italics: true,
          ...link ? { link, color: C.accent } : {}
        });
        break;
      default:
        break;
    }
  }
  return out.length ? out : [{ text: "" }];
}
function inlineMd(src) {
  const toks = MD.parseInline(src ?? "", {});
  return inlineSpans(toks[0]?.children ?? []);
}
var measureDoc = null;
function measurer() {
  if (!measureDoc) {
    const PDFDocument = cjsDefault(empty_default);
    measureDoc = new PDFDocument({ autoFirstPage: false });
  }
  return measureDoc;
}
function fontFor(s) {
  if (s.code)
    return "Courier";
  if (s.bold && s.italic)
    return "Helvetica-BoldOblique";
  if (s.bold)
    return "Helvetica-Bold";
  if (s.italic)
    return "Helvetica-Oblique";
  return "Helvetica";
}
function sizeFor(s, base) {
  return s.code ? base - 1.5 : base;
}
function measure(text, s, base) {
  const d = measurer();
  d.font(fontFor(s));
  d.fontSize(sizeFor(s, base));
  return d.widthOfString(text);
}
function inlineAtoms(children, base) {
  const atoms = [];
  let bold = false, italic = false;
  let link;
  const st = (code) => ({ bold, italic, code, link });
  for (const t of children) {
    switch (t.type) {
      case "text":
      case "code_inline": {
        const code = t.type === "code_inline";
        const s = st(code);
        for (const p of t.content.split(/(\s+)/)) {
          if (p === "")
            continue;
          if (/^\s+$/.test(p))
            atoms.push({ k: "space", w: measure(" ", s, base) });
          else
            atoms.push({ k: "word", text: p, s, w: measure(p, s, base) });
        }
        break;
      }
      case "strong_open":
        bold = true;
        break;
      case "strong_close":
        bold = false;
        break;
      case "em_open":
        italic = true;
        break;
      case "em_close":
        italic = false;
        break;
      case "link_open":
        link = t.attrGet("href") ?? void 0;
        break;
      case "link_close":
        link = void 0;
        break;
      case "softbreak":
        atoms.push({ k: "space", w: measure(" ", st(false), base) });
        break;
      case "hardbreak":
        atoms.push({ k: "br" });
        break;
      case "math_inline": {
        try {
          const { svg, width, height } = texToSvg(t.content, false);
          atoms.push({ k: "math", svg, w: Math.max(width, 1), h: Math.max(height, 1) });
        } catch {
          const s = st(false);
          const txt = texToPlain(t.content);
          atoms.push({ k: "word", text: txt, s, w: measure(txt, s, base) });
        }
        break;
      }
      default:
        break;
    }
  }
  return atoms;
}
function runOf(text, s) {
  if (s.code) {
    return { text, style: "code", ...s.link ? { link: s.link, color: C.accent } : {} };
  }
  return {
    text,
    bold: s.bold,
    italics: s.italic,
    ...s.link ? { link: s.link, color: C.accent } : {}
  };
}
var MATH_PAD_L = 3;
var MATH_PAD_R = 6;
function layoutFlow(atoms, maxWidth, base) {
  const lines = [];
  let line = [];
  let w = 0;
  const flush = () => {
    while (line.length && line[line.length - 1].k === "space")
      line.pop();
    lines.push(line);
    line = [];
    w = 0;
  };
  const effW = (a) => a.k === "math" ? a.w + MATH_PAD_L + MATH_PAD_R : a.k === "br" ? 0 : a.w;
  for (const a of atoms) {
    if (a.k === "br") {
      flush();
      continue;
    }
    if (a.k === "space") {
      if (line.length === 0)
        continue;
      if (w + a.w > maxWidth) {
        flush();
        continue;
      }
      line.push(a);
      w += a.w;
      continue;
    }
    const ew = effW(a);
    if (line.length > 0 && w + ew > maxWidth)
      flush();
    line.push(a);
    w += ew;
  }
  flush();
  const gap = base * 0.4;
  const out = [];
  for (const ln of lines) {
    if (ln.length === 0) {
      out.push({ text: " ", fontSize: base * 0.5 });
      continue;
    }
    const rowH = Math.max(base * 1.18, ...ln.map((a) => a.k === "math" ? a.h : 0));
    if (!ln.some((a) => a.k === "math")) {
      const runs = [];
      for (const a of ln) {
        if (a.k === "space")
          runs.push({ text: " " });
        else if (a.k === "word")
          runs.push(runOf(a.text, a.s));
      }
      out.push({ text: runs, margin: [0, 0, 0, gap] });
      continue;
    }
    const cols = [];
    let buf = [];
    const flushBuf = () => {
      if (buf.length) {
        cols.push({
          width: "auto",
          text: buf,
          margin: [0, Math.round((rowH - base) / 2), 0, 0]
        });
        buf = [];
      }
    };
    for (const a of ln) {
      if (a.k === "math") {
        flushBuf();
        cols.push({
          width: a.w,
          svg: a.svg,
          height: a.h,
          margin: [MATH_PAD_L, Math.round((rowH - a.h) / 2), 0, 0]
        });
        cols.push({ text: "", width: MATH_PAD_R });
      } else if (a.k === "space") {
        buf.push({ text: " " });
      } else if (a.k === "word") {
        buf.push(runOf(a.text, a.s));
      }
    }
    flushBuf();
    out.push({ columns: cols, columnGap: 0, margin: [0, 0, 0, gap] });
  }
  return out;
}
function hasInlineMath(children) {
  return children.some((t) => t.type === "math_inline");
}
function flowOrText(children, maxWidth, base = 10) {
  if (!hasInlineMath(children))
    return { text: inlineSpans(children) };
  return { stack: layoutFlow(inlineAtoms(children, base), maxWidth, base) };
}
var WINANSI_HIGH = /* @__PURE__ */ new Set([
  8364,
  8218,
  402,
  8222,
  8230,
  8224,
  8225,
  710,
  8240,
  352,
  8249,
  338,
  381,
  8216,
  8217,
  8220,
  8221,
  8226,
  8211,
  8212,
  732,
  8482,
  353,
  8250,
  339,
  382,
  376
]);
var WA_MAP = {
  "\u2265": ">=",
  "\u2264": "<=",
  "\u2260": "!=",
  "\u2248": "~",
  "\u2245": "~",
  "\u2261": "=",
  "\u2259": "=",
  "\u223C": "~",
  "\u226A": "<<",
  "\u226B": ">>",
  "\u2192": "->",
  "\u2190": "<-",
  "\u2194": "<->",
  "\u21A6": "->",
  "\u21D2": "=>",
  "\u21D0": "<=",
  "\u21D4": "<=>",
  "\u2191": "^",
  "\u2193": "v",
  "\u2212": "-",
  "\u2213": "-/+",
  "\u2217": "*",
  "\u2219": "\xB7",
  "\u2218": "o",
  "\xB7": "\xB7",
  "\u221A": "sqrt",
  "\u221B": "cbrt",
  "\u221E": "unendlich",
  "\u221D": "~",
  "\u2202": "d",
  "\u2207": "grad",
  "\u2211": "Summe",
  "\u220F": "Produkt",
  "\u222B": "Integral",
  "\u2208": " in ",
  "\u2209": " nicht in ",
  "\u220B": " enthaelt ",
  "\u2205": "{}",
  "\u2282": " Teilmenge ",
  "\u2286": " Teilmenge ",
  "\u2283": " Obermenge ",
  "\u2287": " Obermenge ",
  "\u222A": " vereinigt ",
  "\u2229": " geschnitten ",
  "\u2200": "fuer alle ",
  "\u2203": "es existiert ",
  "\u2204": "kein ",
  "\u2295": "(+)",
  "\u2297": "(x)",
  "\u22EF": "...",
  "\u22EE": "...",
  "\u22F1": "...",
  "\u2032": "'",
  "\u2033": "''",
  "\u2031": " pro 10000",
  "\u2308": "[",
  "\u2309": "]",
  "\u230A": "[",
  "\u230B": "]",
  "\u27E8": "<",
  "\u27E9": ">",
  "\u2070": "^0",
  "\u2074": "^4",
  "\u2075": "^5",
  "\u2076": "^6",
  "\u2077": "^7",
  "\u2078": "^8",
  "\u2079": "^9",
  "\u207A": "^+",
  "\u207B": "^-",
  "\u207C": "^=",
  "\u207D": "^(",
  "\u207E": "^)",
  "\u207F": "^n",
  "\u2071": "^i",
  "\u2080": "_0",
  "\u2081": "_1",
  "\u2082": "_2",
  "\u2083": "_3",
  "\u2084": "_4",
  "\u2085": "_5",
  "\u2086": "_6",
  "\u2087": "_7",
  "\u2088": "_8",
  "\u2089": "_9",
  "\u208A": "_+",
  "\u208B": "_-",
  "\u208C": "_=",
  "\u208D": "_(",
  "\u208E": "_)",
  "\u03B1": "alpha",
  "\u03B2": "beta",
  "\u03B3": "gamma",
  "\u03B4": "delta",
  "\u03B5": "epsilon",
  "\u03B6": "zeta",
  "\u03B7": "eta",
  "\u03B8": "theta",
  "\u03B9": "iota",
  "\u03BA": "kappa",
  "\u03BB": "lambda",
  "\u03BC": "mu",
  "\u03BD": "nu",
  "\u03BE": "xi",
  "\u03C0": "pi",
  "\u03C1": "rho",
  "\u03C3": "sigma",
  "\u03C4": "tau",
  "\u03C5": "ypsilon",
  "\u03C6": "phi",
  "\u03C7": "chi",
  "\u03C8": "psi",
  "\u03C9": "omega",
  "\u0393": "Gamma",
  "\u0394": "Delta",
  "\u0398": "Theta",
  "\u039B": "Lambda",
  "\u039E": "Xi",
  "\u03A0": "Pi",
  "\u03A3": "Sigma",
  "\u03A6": "Phi",
  "\u03A8": "Psi",
  "\u03A9": "Omega"
};
function winAnsi(s) {
  let out = "";
  for (const ch of s) {
    const cp = ch.codePointAt(0) ?? 0;
    if (cp <= 255 || WINANSI_HIGH.has(cp)) {
      out += ch;
      continue;
    }
    if (ch in WA_MAP) {
      out += WA_MAP[ch];
      continue;
    }
  }
  return out;
}
function sanitizeWinAnsi(node) {
  if (Array.isArray(node)) {
    for (const n of node)
      sanitizeWinAnsi(n);
    return;
  }
  if (!node || typeof node !== "object")
    return;
  const o = node;
  for (const k of Object.keys(o)) {
    if (k === "svg")
      continue;
    const v = o[k];
    if (k === "text" && typeof v === "string")
      o[k] = winAnsi(v);
    else
      sanitizeWinAnsi(v);
  }
}
var HEAD_STYLE = {
  h1: "mdH1",
  h2: "mdH2",
  h3: "mdH3",
  h4: "mdH4",
  h5: "mdH4",
  h6: "mdH4"
};
function mdContent(src) {
  if (!src)
    return [];
  const toks = MD.parse(src, {});
  const out = [];
  for (let i = 0; i < toks.length; i++) {
    const t = toks[i];
    if (t.type === "heading_open") {
      const inl = toks[i + 1];
      out.push({
        text: inl?.children ? inlineSpans(inl.children) : inl?.content ?? "",
        style: HEAD_STYLE[t.tag] ?? "mdH4"
      });
      i += 2;
    } else if (t.type === "paragraph_open") {
      const inl = toks[i + 1];
      const node = inl?.children ? flowOrText(inl.children, CONTENT_W) : { text: [{ text: inl?.content ?? "" }] };
      out.push({ ...node, margin: [0, 2, 0, 6] });
      i += 2;
    } else if (t.type === "math_block") {
      try {
        const { svg, width } = texToSvg(t.content, true);
        out.push({
          svg,
          width: Math.min(width, CONTENT_W),
          alignment: "center",
          margin: [0, 6, 0, 10]
        });
      } catch {
        out.push({
          text: texToPlain(t.content),
          italics: true,
          alignment: "center",
          margin: [0, 6, 0, 10]
        });
      }
    } else if (t.type === "fence" || t.type === "code_block") {
      out.push(codeBlock(t.content.replace(/\n$/, "")));
    } else if (t.type === "bullet_list_open" || t.type === "ordered_list_open") {
      const ordered = t.type === "ordered_list_open";
      const items = [];
      i++;
      while (i < toks.length && toks[i].type !== (ordered ? "ordered_list_close" : "bullet_list_close")) {
        if (toks[i].type === "inline") {
          items.push(flowOrText(toks[i].children ?? [], CONTENT_W - 22));
        }
        i++;
      }
      out.push(ordered ? { ol: items, margin: [0, 2, 0, 8] } : { ul: items, margin: [0, 2, 0, 8] });
    }
  }
  return out;
}
function gridTable(head, rows) {
  const body = [
    head.map((h) => ({ text: h, bold: true, color: C.fg })),
    ...rows.map((r) => r.map((c) => ({ text: inlineMd(c) })))
  ];
  return {
    table: { headerRows: 1, widths: ["auto", "auto", "*"], body },
    layout: gridLayout,
    margin: [0, 4, 0, 10]
  };
}
function declContent(d) {
  const out = [
    {
      text: [
        { text: d.kind, decoration: "underline", decorationColor: TK.kw.color },
        { text: ` ${d.name}` }
      ],
      style: "decl",
      tocItem: true,
      tocStyle: "tocDecl",
      // pdfmake liest die ToC-Einrückung aus `tocMargin`
      // (nicht aus `tocStyle.margin`) → Decls deutlich rechts
      // eingerückt unter ihrem Bereich.
      tocMargin: [42, 1.5, 0, 1.5]
    },
    codeBlock(d.signature),
    ...mdContent(d.doc)
  ];
  if (d.params && d.params.length > 0) {
    out.push({ text: "Parameter", style: "tagLabel" });
    out.push({
      table: {
        headerRows: 1,
        widths: ["auto", "*"],
        body: [
          [
            { text: "Name", bold: true, color: C.fg },
            { text: "Beschreibung", bold: true, color: C.fg }
          ],
          ...d.params.map((p) => [
            { text: p.name },
            { text: inlineMd(p.desc) }
          ])
        ]
      },
      layout: gridLayout,
      margin: [0, 4, 0, 8]
    });
  }
  if (d.returns) {
    out.push({
      text: [
        { text: "R\xFCckgabe  ", bold: true, color: C.accent },
        ...inlineMd(d.returns)
      ],
      style: "tagReturn"
    });
  }
  if (d.fields && d.fields.length > 0) {
    out.push(gridTable(["Feld", "Typ", "Bedeutung"], d.fields.map((f) => [f.name, f.type, f.doc ?? ""])));
  }
  if (d.values && d.values.length > 0) {
    out.push({
      text: [{ text: "Werte: ", bold: true }, d.values.join(", ")],
      margin: [0, 2, 0, 6]
    });
  }
  for (const e of d.examples ?? []) {
    out.push({
      stack: [
        {
          text: `Testfall \u2014 ${e.label}${e.erwartetAbbruch ? " (erwartet abbruch)" : ""}`,
          style: "exLabel"
        },
        codeBlock(e.code)
      ],
      margin: [0, 16, 0, 0]
    });
  }
  for (const q of d.quellen) {
    if (q.refs.length === 0) {
      out.push(quelleCallout([{ text: q.text, color: C.muted }]));
    } else {
      const links = q.refs.flatMap((r, i) => [
        ...i ? [{ text: ", ", color: C.muted }] : [],
        {
          text: `\xA7 ${r.num} ${r.abk}`,
          link: r.url,
          color: C.accent,
          decoration: "underline"
        }
      ]);
      out.push(quelleCallout([{ text: q.text, color: C.muted }, "   ", ...links]));
    }
  }
  return out;
}
function buildPdfDoc(model, opts = {}) {
  const kopf = opts.kopf;
  const titel = winAnsi(kopf?.titel ?? opts.titel ?? "FinDSL-Dokumentation");
  const untertitel = kopf ? kopf.untertitel != null ? winAnsi(kopf.untertitel) : kopf.untertitel : "Dom\xE4nenspezifische Sprache f\xFCr die deutsche\nsteuerliche Finanzverwaltung";
  const nMod = model.modules.length;
  const nDecl = model.modules.reduce((a, m) => a + m.decls.length, 0);
  const metaZeile = (label, wert) => ({ text: `${label}: ${wert}`, style: "coverMeta" });
  const content = [
    { text: "F I N D S L   \xB7   A U D I T", style: "coverEyebrow", margin: [0, 158, 0, 0] },
    { text: titel, style: "coverTitle" },
    {
      canvas: [{
        type: "line",
        x1: 0,
        y1: 0,
        x2: 132,
        y2: 0,
        lineWidth: 3,
        lineColor: C.accent
      }],
      margin: [0, 16, 0, 18]
    },
    ...untertitel ? [{ text: untertitel, style: "coverSub" }] : [],
    hairline(0.75, C.rule, untertitel ? 64 : 10, 14),
    ...kopf?.autor ? [metaZeile("Autor", kopf.autor)] : [],
    ...kopf?.lizenz ? [metaZeile("Lizenz", kopf.lizenz)] : [],
    ...opts.stand ? [{ text: `Stand: ${opts.stand}`, style: "coverMeta" }] : [],
    {
      text: `${nMod} Dateien \xB7 ${nDecl} Deklarationen`,
      style: "coverMetaFaint",
      margin: [0, 4, 0, 0]
    },
    ...kopf?.beschreibung ? [{ text: kopf.beschreibung, style: "coverMetaFaint", margin: [0, 8, 0, 0] }] : [],
    ...kopf && kopf.metadaten.length > 0 ? [{
      text: kopf.metadaten.map(([k, v]) => `${k}: ${v}`).join("   \xB7   "),
      style: "coverMetaFaint",
      margin: [0, 6, 0, 0]
    }] : [],
    { text: "Erzeugt mit  findsl doku", style: "coverFoot", margin: [0, 26, 0, 0] },
    { text: "", pageBreak: "after" },
    // Einleitung (Front-Matter-Rumpf) als eigene Seite(n) vor dem ToC.
    ...kopf?.einleitung ? [...mdContent(kopf.einleitung), { text: "", pageBreak: "after" }] : [],
    // KEIN pageBreak:'after' nach dem ToC — das erste Kapitel erzwingt
    // selbst `pageBreak:'before'`; sonst leere Seite dazwischen.
    { toc: { title: { text: "Inhalt", style: "tocTitle" } } }
  ];
  model.modules.forEach((m, mi) => {
    content.push({
      text: String(mi + 1).padStart(2, "0"),
      style: "chapNum",
      pageBreak: "before"
    });
    content.push({ text: "DATEI", style: "chapEyebrow", margin: [0, 4, 0, 3] });
    content.push({
      text: m.name,
      style: "h1",
      tocItem: true,
      tocStyle: "tocModule",
      tocMargin: [0, 13, 0, 3]
    });
    content.push({ text: m.pfad, style: "modulePfad" });
    content.push(hairline(2.5, C.accent, 6, 16));
    content.push(...mdContent(m.doc));
    for (const g of groupDecls(m.decls)) {
      content.push({
        text: g.header.toUpperCase(),
        style: "group",
        tocItem: true,
        tocStyle: "tocGroup",
        tocMargin: [16, 7, 0, 2]
      });
      content.push(hairline(0.75, C.rule, 5, 16));
      for (const d of g.decls)
        content.push(...declContent(d));
    }
    if (m.abbruchSites.length > 0) {
      content.push({
        text: "EXPLIZIT AUSGESCHLOSSENE KONSTELLATIONEN",
        style: "group"
      });
      content.push(hairline(0.75, C.rule, 5, 16));
      content.push(gridTable(["In", "Stelle", "Begr\xFCndung"], m.abbruchSites.map((s) => [
        s.enthaltenIn ?? "\u2014",
        `Z. ${s.zeile}`,
        (s.begruendung ?? "(dynamisch)") + (s.quelle ? ` \xB7 ${s.quelle}` : "")
      ])));
    }
  });
  sanitizeWinAnsi(content);
  return {
    info: { title: titel },
    // Cremeweißer Seitenhintergrund (Claude-Docs-Palette) auf
    // jeder Seite — Volltön-Rechteck hinter dem Inhalt.
    background: (_cur, size) => ({
      canvas: [{
        type: "rect",
        x: 0,
        y: 0,
        w: size.width,
        h: size.height,
        color: C.pageBg
      }]
    }),
    defaultStyle: { font: "Helvetica", fontSize: 10, color: C.body, lineHeight: 1.4 },
    pageMargins: [50, 60, 50, 58],
    header: (cur) => cur === 1 ? "" : {
      stack: [
        {
          columns: [
            {
              text: "FINDSL",
              width: "auto",
              font: "Helvetica",
              bold: true,
              fontSize: 7,
              color: C.accent,
              characterSpacing: 2
            },
            {
              text: titel,
              width: "*",
              alignment: "right",
              fontSize: 7.5,
              color: C.muted
            }
          ]
        },
        {
          canvas: [{
            type: "line",
            x1: 0,
            y1: 0,
            x2: CONTENT_W,
            y2: 0,
            lineWidth: 0.5,
            lineColor: C.rule
          }],
          margin: [0, 6, 0, 0]
        }
      ],
      margin: [50, 26, 50, 0]
    },
    footer: (cur, count) => cur === 1 ? "" : {
      stack: [
        {
          canvas: [{
            type: "line",
            x1: 0,
            y1: 0,
            x2: CONTENT_W,
            y2: 0,
            lineWidth: 0.5,
            lineColor: C.rule
          }]
        },
        {
          columns: [
            {
              text: titel,
              width: "*",
              fontSize: 7,
              color: C.faint
            },
            {
              text: `Seite ${cur} / ${count}`,
              width: "auto",
              alignment: "right",
              fontSize: 7.5,
              color: C.muted
            }
          ],
          margin: [0, 7, 0, 0]
        }
      ],
      margin: [50, 14, 50, 0]
    },
    content,
    styles: {
      // Deckblatt
      coverEyebrow: { font: "Helvetica", fontSize: 9, bold: true, color: C.accent, characterSpacing: 3 },
      coverTitle: { font: "Times", fontSize: 37, bold: true, color: C.fg, margin: [0, 12, 0, 0] },
      coverSub: { font: "Times", italics: true, fontSize: 14, color: C.muted, lineHeight: 1.35 },
      coverMeta: { font: "Helvetica", fontSize: 10, color: C.body, characterSpacing: 0.3 },
      coverMetaFaint: { font: "Helvetica", fontSize: 9.5, color: C.muted },
      coverFoot: { font: "Helvetica", fontSize: 8, color: C.faint, characterSpacing: 1 },
      // Kapitel-Opener
      chapNum: { font: "Times", fontSize: 42, color: C.accent },
      chapEyebrow: { font: "Helvetica", fontSize: 9, bold: true, color: C.muted, characterSpacing: 4 },
      // Struktur-Überschriften (Ink, kein Akzent)
      h1: { font: "Times", fontSize: 24, bold: true, color: C.fg, margin: [0, 2, 0, 0] },
      modulePfad: { font: "Courier", fontSize: 8, color: C.muted, margin: [0, 4, 0, 0] },
      h2: { font: "Helvetica", fontSize: 13, bold: true, color: C.fg, margin: [0, 14, 0, 5] },
      group: {
        font: "Helvetica",
        fontSize: 12,
        bold: true,
        color: C.fg,
        characterSpacing: 2.4,
        margin: [0, 30, 0, 4]
      },
      decl: { font: "Helvetica", fontSize: 14, bold: true, color: C.fg, margin: [0, 18, 0, 4] },
      // Code + Labels
      code: { font: "Courier", fontSize: 8.5, color: C.codeFg, lineHeight: 1.35 },
      codeLabel: {
        font: "Helvetica",
        fontSize: 6,
        bold: true,
        color: C.accent,
        characterSpacing: 2,
        alignment: "right",
        margin: [0, 0, 2, 2]
      },
      exLabel: { font: "Times", italics: true, fontSize: 10.5, color: C.muted, margin: [0, 0, 0, 2] },
      tagLabel: {
        font: "Helvetica",
        fontSize: 8,
        bold: true,
        color: C.muted,
        characterSpacing: 1.5,
        margin: [0, 12, 0, 4]
      },
      tagReturn: { font: "Helvetica", fontSize: 10, margin: [0, 6, 0, 8] },
      // Inhaltsverzeichnis
      tocTitle: { font: "Times", fontSize: 24, bold: true, color: C.fg, margin: [0, 0, 0, 8] },
      tocModule: { font: "Times", fontSize: 12.5, bold: true, color: C.fg, margin: [0, 12, 0, 3] },
      tocGroup: {
        font: "Helvetica",
        fontSize: 8,
        bold: true,
        color: C.muted,
        characterSpacing: 1.5,
        margin: [16, 5, 0, 2]
      },
      tocDecl: { font: "Helvetica", fontSize: 9.5, color: C.body, margin: [40, 1.5, 0, 1.5] },
      // Doc-Kommentar-Überschriften (untergeordnet)
      mdH1: { font: "Helvetica", fontSize: 13, bold: true, color: C.fg, margin: [0, 12, 0, 5] },
      mdH2: { font: "Helvetica", fontSize: 11.5, bold: true, color: C.fg, margin: [0, 9, 0, 4] },
      mdH3: { font: "Helvetica", fontSize: 10.5, bold: true, color: C.fg, margin: [0, 7, 0, 3] },
      mdH4: {
        font: "Helvetica",
        fontSize: 9,
        bold: true,
        color: C.muted,
        characterSpacing: 0.5,
        margin: [0, 6, 0, 3]
      }
    }
  };
}

// src/pdf-browser.ts
async function pdfDocDefinition(model, hasMath) {
  if (hasMath) await ensureMathJax();
  return JSON.stringify(buildPdfDoc(model));
}
export {
  pdfDocDefinition
};
