$ cat node-template.py

S

Slide Generator

// Generates a single presentation slide from text content and an instruction. Connect multiple Slide Generator outputs to a Presentation Composer to build a full presentation.

Process
Document
template.py
1import sys2import json3import re4import base645import mimetypes6import traceback7from html.parser import HTMLParser89from gais import Gais1011SYSTEM_PROMPT = '''You are a presentation slide designer. Your task is to generate exactly ONE Reveal.js slide as an HTML <section> element.1213RULES:141. Output ONLY a single <section>...</section> element. No <!DOCTYPE>, no <html>, no <head>, no wrapper.152. Use <h2> for the slide title (not <h1>).163. Use semantic HTML: <ul>/<ol> for lists, <p> for text, <table> for data, <blockquote> for quotes.174. Use class="fragment" on elements that should appear one-by-one during the presentation.185. Use <aside class="notes">...</aside> for speaker notes (always include brief notes).196. Do NOT set data-background-color on <section>. The presentation theme controls all colors — never override it.207. Keep content concise — slides should be scannable, not walls of text.218. Do NOT include any CSS <style> blocks or <script> tags.229. Do NOT set color, background-color, or any color-related inline styles. Let the Reveal.js theme handle all colors.2310. Only use inline styles for LAYOUT purposes (display:flex, display:grid, gap, font-size). Never for colors or backgrounds.2411. Use plain HTML that Reveal.js themes will style automatically.2512. THEME × TEMPLATE COUPLING: each slide layout template in this system is theme-specific. marina-* templates (marina-intro, marina-content, marina-metrics, marina-timeline, marina-comparison, marina-outro) require the 'marina' Reveal theme and use Marina-only classes (.title-slide, .closing-slide, data-header-title, .card-grid, .tag.commercial, etc.). emblema-* templates (emblema-cover, emblema-agenda, emblema-section, …, emblema-closing) require the 'emblema' theme and use Emblema-only classes (.slide-cover, .slide-section, .slide-pad, .slide-bullets, etc.). NEVER emit a marina-* slide structure when the deck theme is emblema (the cover and closing collapse to unstyled white pages because emblema CSS does not define .title-slide / .closing-slide). NEVER emit an emblema-* slide structure when the deck theme is marina. If you are asked to produce a cover or closing for an emblema deck, use emblema-cover and emblema-closing — not marina-intro / marina-outro.2627IMAGE PLACEHOLDERS:28When a slide layout requires images, use picsum.photos for royalty-free placeholder images:29- Landscape: <img src="https://picsum.photos/seed/{topic}/600/400" alt="description">30- Portrait: <img src="https://picsum.photos/seed/{topic}/400/600" alt="description">31- Square: <img src="https://picsum.photos/seed/{topic}/400/400" alt="description">32Replace {topic} with a short keyword related to the slide content (e.g. "analytics", "team", "growth").33Always include a descriptive alt attribute. Set width via style if needed for layout.3435LAYOUT PATTERNS you can use:36- Title slide: <h2> + <p> subtitle37- Bullet points: <h2> + <ul> with <li class="fragment">38- Two columns: <div style="display:flex;gap:2em"> with two <div> children39- Data table: <h2> + <table>40- Quote: <blockquote> + attribution41- Image + text: <h2> + <div style="display:flex;gap:2em"> with <img> and text side by side4243Always output valid HTML. The content should be based ONLY on the provided source material — do not invent facts or data.'''4445# Layout instructions for each slide template46TEMPLATE_INSTRUCTIONS = {47    # ─── Marina Militare layouts ───48    "marina-intro": "[THEME GATE: this template is valid ONLY when the active deck theme is 'marina'. If the active theme is 'emblema', DO NOT emit this structure — switch to the 'emblema-cover' template instead, which is the Emblema brand cover. The Marina .title-slide class is unstyled in the Emblema theme and would render as a blank white slide.] "49        "Create a Marina Militare INTRO/COVER slide. The <section> MUST start with class='title-slide' — WITHOUT THIS CLASS, the Marina Militare crest will NOT render and the Graduate uppercase title font will NOT apply. The slide will collapse to a plain navy background with default text. Use this EXACT structure:\n"50        "<section class='title-slide'>\n"51        "  <h1>OPERATION OR BRIEFING TITLE</h1>\n"52        "  <p class='subtitle'>Subtitle line — short, two lines maximum</p>\n"53        "  <p class='meta'>Mission ID &nbsp;|&nbsp; Unit &nbsp;|&nbsp; Date &nbsp;|&nbsp; Classification</p>\n"54        "  <aside class='notes'>Cover slide — set the audience and the mission.</aside>\n"55        "</section>\n"56        "The Marina Militare crest is injected by the theme via a CSS pseudo-element above the title — do NOT add an <img> for the logo. The <h1> renders in uppercase Graduate font and tolerates a <br> mid-line for a two-line title. Keep the subtitle to one or two lines using <p class='subtitle'>. Use <p class='meta'> for the small operational metadata (mission ID, unit, date, classification). Keep all class names EXACTLY as shown — class='title-slide' on the section is LOAD-BEARING.",5758    "marina-content": "Create a Marina Militare CONTENT slide. This is the marina theme's GENERAL-PURPOSE / FREE-FORM content layout — use it for any textual, discursive, narrative or free-structure content, and whenever the user asks for a 'content' / 'testuale' / 'free-form' / 'libera' slide. The ONLY fixed parts are the <section data-header-title='...'> wrapper and the <h2> heading; everything below the <h2> is HTML you choose to fit the content. "59        "CRITICAL HEADING RULE: The <h2> MUST be 3-8 words describing THIS specific slide's content, written in the SAME LANGUAGE as the source document (Italian source → Italian heading). Extract the heading from the actual source content — do NOT invent generic English dashboard phrases. BANNED headings that you MUST NOT use as <h2>: 'Overview', 'Summary', 'Key Points', 'Main Content', 'Content Summary', 'Information', 'Details'. These are hallucinations from other templates and look unprofessional. Good examples for an Italian Navy briefing: 'Identificazione Missione', 'Assetto della Piattaforma', 'Quadro Operativo Generale'. "60        "The <section> MUST have a data-header-title='SHORT TITLE' attribute — WITHOUT THIS ATTRIBUTE, the top header bar with the Marina Militare logo and uppercase title will NOT render and the slide will look unbranded. After the <h2> you may put any mix of: prose <p> paragraphs, <ul>/<ol> bullet lists, sub-<h3> headings, a <table> for genuinely tabular data (fully theme-styled — navy header row, gold column headers, bordered rows; you do NOT need to switch to marina-comparison for a small table inside a content slide), an optional <p class='section-label'> small subtitle, and/or the marina .card-grid / .card blocks for numeric/KPI/dashboard data — in any order. Do NOT add background-color or color inline styles — the theme owns them. "61        "ALIGNMENT: the outer <section> MUST carry class='marina-content' in addition to data-header-title='SHORT TITLE' — that class is the CSS hook the theme uses to flush body content left. Inside that section everything below the header bar is LEFT-aligned by the theme — the <h2>, every <h3>, all <p> paragraphs, all <ul>/<ol> lists, and every <table>. The one EXCEPTION is <p class='section-label'>: it is the uppercase brand subtitle and the theme keeps it centered — leave it alone, don't try to left-align it. The theme owns alignment, so do NOT add style='text-align:center', style='text-align:left', a <center> tag, an align='center' attribute, or a centered wrapper <div> around any body element — just emit clean HTML and the CSS handles it. (Centered slide bodies belong only to the separate marina-intro and marina-outro layouts, which use different classes — never here.) "62        "EXAMPLE — free-form / discursive content (the default for narrative text):\n"63        "<section class='marina-content' data-header-title='SHORT SLIDE TITLE'>\n"64        "  <h2>HEADING_DERIVED_FROM_SOURCE_CONTENT</h2>\n"65        "  <p class='section-label'>Optional small label / subtitle</p>\n"66        "  <h3>Optional sub-heading</h3>\n"67        "  <p>A paragraph of discursive content drawn from the source.</p>\n"68        "  <p>Another paragraph.</p>\n"69        "  <ul>\n"70        "    <li>A bullet point.</li>\n"71        "    <li>Another bullet point.</li>\n"72        "  </ul>\n"73        "  <aside class='notes'>Speaker notes.</aside>\n"74        "</section>\n"75        "EXAMPLE — data / KPI content (use cards when the slide is a set of numbers or capability readings):\n"76        "<section class='marina-content' data-header-title='SHORT SLIDE TITLE'>\n"77        "  <h2>HEADING_DERIVED_FROM_SOURCE_CONTENT</h2>\n"78        "  <p class='section-label'>Optional small label / subtitle</p>\n"79        "  <div class='card-grid cols-3'>\n"80        "    <div class='card'><div class='label'>LABEL</div><div class='value gold'>VALUE</div><div class='detail'>Detail</div></div>\n"81        "    <!-- ...more cards... -->\n"82        "  </div>\n"83        "  <aside class='notes'>Speaker notes.</aside>\n"84        "</section>\n"85        "The data-header-title attribute on <section> drives the fixed header bar — the theme injects the Marina Militare logo on the left and this title text in uppercase on the right. The <h2> is the slide body heading. CHOOSING THE BODY: when the slide content is numeric / KPI / capability-reading / dashboard-shaped, PREFER a <div class='card-grid cols-2|cols-3|cols-4'> with <div class='card'> children over a plain <ul> — cards are the marina theme's signature visual for data. When the slide content is narrative / discursive, prose paragraphs, sub-headings and bullet lists are the right choice — that is NOT 'unbranded', it is exactly what this layout is for. "86        "WHEN YOU DO USE CARDS: each card contains <div class='label'> (uppercase blue), <div class='value'> (large, MUST add a color modifier class: .gold for highlights, .cyan for cool readings, .red for alerts, .green for OK status), and optional <div class='detail'>. "87        "CRITICAL CARD STATE COUPLING RULE (applies only when you use cards): the color modifier on <div class='value'> MUST be mirrored by a matching class on the parent <div class='card'>: "88        "<div class='value red'> (alert/threat/critical) → parent MUST be <div class='card alert'> (red border + red glow + red-tinted background + red label); "89        "<div class='value gold'> (the single most important metric) → parent MUST be <div class='card highlight'> (gold border + gold label); "90        "<div class='value cyan'> or <div class='value green'> → parent stays as plain <div class='card'> (no parent modifier). "91        "Do NOT emit <div class='card'><div class='value red'>...</div></div> — a red value inside a blue card looks inconsistent and unprofessional. Always pair .value.red with .card.alert and .value.gold with .card.highlight. "92        "Anti-pattern to AVOID: forcing a metrics / KPI dashboard (a set of numbers or capability readings) into a plain <ul> instead of a .card-grid — use cards there. (A <ul> for genuine narrative bullet points, or prose paragraphs for discursive content, is correct in a content slide — do not 'card-ify' everything.)",9394    "marina-metrics": "Create a Marina Militare METRICS / CAPABILITY DASHBOARD slide. "95        "CRITICAL HEADING RULE: The <h2> MUST be 3-8 words describing THIS specific slide's metric set, written in the SAME LANGUAGE as the source document. Extract the heading from the actual source content — do NOT invent generic English dashboard phrases. BANNED headings that you MUST NOT use as <h2>: 'Capability Snapshot', 'Key Metrics', 'Performance Overview', 'KPI Dashboard', 'Metrics Dashboard', 'Operational Metrics', 'Overview', 'Summary', 'Snapshot', 'Performance Dashboard'. These are hallucinations from other dashboard templates and look unprofessional in a naval briefing. Good examples for an Italian Navy briefing: 'ITS Margottini — Snapshot T+12 h', 'Assetto Piattaforma al T+24 h', 'Meteo e Condizioni del Mare', 'Readiness e Asset Operativi'. "96        "The <section> MUST have data-header-title='SHORT TITLE' AND the body MUST contain a <div class='card-grid cols-N'> with at least 3 <div class='card'> children — WITHOUT THE CARD GRID, this layout has no visual and degrades to plain text. Each card's <div class='value'> MUST have a color modifier class (.gold, .cyan, .red, or .green) — without it, values render in plain white and lose all semantic meaning. Use this EXACT structure:\n"97        "<section data-header-title='SHORT SLIDE TITLE'>\n"98        "  <h2>HEADING_DERIVED_FROM_SOURCE_CONTENT</h2>\n"99        "  <p class='section-label'>Optional small label (e.g. timestamp or unit)</p>\n"100        "  <div class='card-grid cols-3'>\n"101        "    <div class='card'>\n"102        "      <div class='label'>METRIC LABEL</div>\n"103        "      <div class='value cyan'>VALUE</div>\n"104        "      <div class='detail'>Brief detail</div>\n"105        "    </div>\n"106        "    <!-- Repeat for 3-6 metric cards -->\n"107        "  </div>\n"108        "  <div class='metrics-callout highlight'>  <!-- OPTIONAL: include only if the source content has operational interpretation of the metrics -->\n"109        "    <div class='label'>IMPATTO OPERATIVO</div>\n"110        "    <p>Short editorial paragraph interpreting the metrics. Use <strong>bold</strong> on the most important phrases to highlight them in gold.</p>\n"111        "  </div>\n"112        "  <aside class='notes'>Speaker notes.</aside>\n"113        "</section>\n"114        "Produce 3-6 capability cards in a grid row (cols-2 / cols-3 / cols-4 depending on count). Each card MUST contain: <div class='label'> (uppercase blue), <div class='value COLOR'> with one of {gold|cyan|red|green} (gold for highlights, cyan for cool/neutral readings, red for alerts/threats, green for OK/operational), and <div class='detail'> for a short subtitle. Vary the colors based on the meaning of each value — do NOT make every card the same color. "115        "CRITICAL CARD STATE COUPLING RULE: the color modifier on <div class='value'> MUST be mirrored by a matching class on the parent <div class='card'>: "116        "<div class='value red'> (alert/threat/critical) → parent MUST be <div class='card alert'> (red border + red glow + red-tinted background + red label); "117        "<div class='value gold'> (the single most important metric) → parent MUST be <div class='card highlight'> (gold border + gold label); "118        "<div class='value cyan'> or <div class='value green'> → parent stays as plain <div class='card'> (no parent modifier). "119        "Do NOT emit <div class='card'><div class='value red'>...</div></div> — a red value floating inside a blue card looks broken and unprofessional. Always pair .value.red with .card.alert and .value.gold with .card.highlight. "120        "Extract real numbers from the source content. Optional class='fragment' on each card for staggered reveal. "121        "The <div class='metrics-callout highlight'> below the card grid is OPTIONAL — include it ONLY when the source content contains a short editorial interpretation of the metrics (e.g. 'IMPATTO OPERATIVO', 'VALUTAZIONE', 'SIGNIFICATO OPERATIVO'). It has a <div class='label'> header (uppercase, short) and a single <p> body with 1-3 sentences; use <strong> on key phrases to highlight them in gold. The .highlight variant has a gold left border and gold label; omit .highlight for a blue-accent variant. When there is no editorial interpretation to show, OMIT the whole .metrics-callout block. "122        "Anti-pattern to AVOID: producing plain text rows or <ul><li>Metric: value</li></ul> instead of the card grid.",123124    "marina-timeline": "Create a Marina Militare VERTICAL TIMELINE slide. "125        "CRITICAL HEADING RULE: The <h2> MUST be 3-8 words describing what this specific timeline covers, written in the SAME LANGUAGE as the source document. Extract the heading from the actual source content — do NOT invent generic English phrases. BANNED headings that you MUST NOT use as <h2>: 'Timeline Overview', 'Chronology', 'Events', 'Timeline', 'Event Timeline', 'Operational Timeline', 'Timeline Summary', 'Schedule'. These are hallucinations from generic templates. Good examples for an Italian Navy briefing: 'Cronologia Operativa — 13 Aprile 2026', 'Sequenza Eventi T-004', 'Fasi della Missione MV-2026-0413', 'Log Operativo'. "126        "The <section> MUST have data-header-title='SHORT TITLE' AND the body MUST contain a <div class='timeline'> with <div class='event'> children — WITHOUT THIS STRUCTURE, the vertical rail and circular markers will NOT render and the slide will degrade to plain text. Do NOT produce <ul><li>HH:MM Event</li></ul> for chronological content — always use the .timeline/.event structure. Use this EXACT structure:\n"127        "<section data-header-title='SHORT SLIDE TITLE'>\n"128        "  <h2>HEADING_DERIVED_FROM_SOURCE_CONTENT</h2>\n"129        "  <div class='timeline-layout'>\n"130        "    <div class='timeline'>\n"131        "      <div class='event'><span class='time'>HH:MM</span> Event description</div>\n"132        "      <div class='event alert'><span class='time'>HH:MM</span> Critical event (red marker)</div>\n"133        "      <div class='event gold'><span class='time'>HH:MM</span> Milestone event (gold marker)</div>\n"134        "      <!-- Repeat for 4-8 events -->\n"135        "    </div>\n"136        "    <div class='timeline-aside'>  <!-- OPTIONAL: include only if the source content has a natural sidebar (next-actions, summary, related contacts, etc.) -->\n"137        "      <div class='card highlight'>\n"138        "        <div class='label'>PROSSIME AZIONI</div>\n"139        "        <ul><li>Action one</li><li>Action two</li></ul>\n"140        "      </div>\n"141        "      <div class='card'>\n"142        "        <div class='label'>RIEPILOGO FINALE</div>\n"143        "        <ul><li>Summary point one</li><li>Summary point two</li></ul>\n"144        "      </div>\n"145        "    </div>\n"146        "  </div>\n"147        "  <aside class='notes'>Speaker notes.</aside>\n"148        "</section>\n"149        "Vertical timeline with circular markers along a left rail. Each event is <div class='event'> with a leading <span class='time'> for the timestamp and the description text after the closing </span>. Add class='event alert' for critical events (red marker with glow halo) and class='event gold' for milestones (gold marker). Extract real timestamps and event descriptions from the source content (4-8 events ideal). "150        "The <div class='timeline-aside'> right column is OPTIONAL — include it ONLY when the source content naturally has sidebar information (next-actions, summary of contacts, related entities, follow-up items). Each aside card has a <div class='label'> header and a short <ul> or <p> body. Use class='card highlight' for the primary aside card (gold accent) and plain class='card' for secondary cards. When there is no sidebar content, OMIT the whole .timeline-layout wrapper and .timeline-aside — use just a bare <div class='timeline'>. "151        "Anti-pattern to AVOID: <ul><li>10:00 - Event</li><li>11:00 - Event</li></ul> — this completely bypasses the timeline visual.",152153    "marina-comparison": "Create a Marina Militare COMPARISON / TRACKING TABLE slide. "154        "CRITICAL HEADING RULE: The <h2> MUST be 3-8 words describing what this specific table shows, written in the SAME LANGUAGE as the source document. Extract the heading from the actual source content — do NOT invent generic English phrases. BANNED headings that you MUST NOT use as <h2>: 'Comparison Table', 'Data Table', 'Summary Table', 'Overview Table', 'Tracking Table', 'Comparison', 'Summary', 'Overview', 'Data'. These are hallucinations from generic templates. Good examples for an Italian Navy briefing: 'Tabella Tracce — T+12 h', 'Contatti Attivi nello Stretto', 'Confronto Assetti Alleati', 'Situazione Tattica Corrente'. "155        "The <section> MUST have data-header-title='SHORT TITLE' AND the body MUST contain a real <table> with <thead> and <tbody> — WITHOUT THE TABLE, this layout has no visual and degrades to plain text columns. Do NOT produce two-column <div> layouts or bullet lists for tabular content. Use this EXACT structure:\n"156        "<section data-header-title='SHORT SLIDE TITLE'>\n"157        "  <h2>HEADING_DERIVED_FROM_SOURCE_CONTENT</h2>\n"158        "  <p class='section-label'>Optional context line (row count, source, etc.)</p>\n"159        "  <table>\n"160        "    <thead><tr><th>Col 1</th><th>Col 2</th><th>Col 3</th><th>Status</th></tr></thead>\n"161        "    <tbody>\n"162        "      <tr><td>Row 1</td><td>Value</td><td>Value</td><td><span class='tag commercial'>Commercial</span></td></tr>\n"163        "      <!-- Repeat for 4-10 rows -->\n"164        "    </tbody>\n"165        "  </table>\n"166        "  <aside class='notes'>Speaker notes.</aside>\n"167        "</section>\n"168        "Wide HTML table with a navy header (gold accent column labels) and bordered rows. For status pills inside cells, use <span class='tag X'>...</span> where X is one of: commercial (blue), allied (green), friendly (cyan), fishing (olive), high-threat (red), humanitarian (gold). For inline status indicators, use <span class='status-dot Y'></span> where Y is one of: green, gold, red, blue. To highlight a critical row, add class='alert' to the <tr> (red row background). Extract real comparison/tracking data from the source content (4-10 rows ideal). Anti-pattern to AVOID: producing <div> column layouts or <ul> lists instead of a real <table>.",169170    "marina-outro": "[THEME GATE: this template is valid ONLY when the active deck theme is 'marina'. If the active theme is 'emblema', DO NOT emit this structure — switch to the 'emblema-closing' template instead, which is the Emblema brand closing slide. The Marina .closing-slide class is unstyled in the Emblema theme and would render as a blank white slide.] "171        "Create a Marina Militare CLOSING slide. The <section> MUST start with class='closing-slide' — WITHOUT THIS CLASS, the Marina Militare crest will NOT render and the slide will collapse to a plain navy background with default text. Use this EXACT structure:\n"172        "<section class='closing-slide'>\n"173        "  <h1>Grazie</h1>\n"174        "  <p class='hashtag'>#NoiSiamoLaMarina</p>\n"175        "  <aside class='notes'>Closing slide.</aside>\n"176        "</section>\n"177        "The Marina Militare crest is injected by the theme via a CSS pseudo-element above the headline — do NOT add an <img> for the logo. The <h1> renders in Montserrat bold (use 'Grazie' / 'Grazie dell'attenzione' / 'Domande?' for Italian briefings, 'Thank You' for English). The <p class='hashtag'> renders in normal weight below — keep it relevant to the unit/operation (e.g. #NoiSiamoLaMarina, #MarinaMilitare). Keep all class names EXACTLY as shown — class='closing-slide' on the section is LOAD-BEARING.",178179    # ─── Emblema layouts ───180    "emblema-cover": "Create an Emblema COVER slide. The <section> MUST contain a <div class='slide-cover'> with two child columns; WITHOUT THIS WRAPPER the title will not render against the brand split-panel layout (white left, full-bleed teal right). CRITICAL HEADING RULE: The <h2> MUST be 3-8 words describing THIS specific slide's content, written in the SAME LANGUAGE as the source document (Italian source -> Italian heading, English source -> English heading). Extract the heading from the actual source content -- do NOT invent generic phrases. BANNED <h1> values: 'Welcome', 'Title Slide', 'Cover', 'Introduction', 'Presentation'. Good examples: 'Building thoughtful AI products.', 'Operazione Mediterraneo Sicuro 2026'. Use this EXACT structure:\n<section>\n  <div class='slide-cover'>\n    <div class='left'>\n      <div class='brand'><span class='eyebrow'>SHORT EYEBROW (2-4 words, uppercase)</span></div>\n      <div>\n        <h1>Headline derived<br>from source content.</h1>\n        <p class='subtitle'>One- or two-line subtitle pulled from the source.</p>\n      </div>\n      <p class='meta'>AUTHOR &nbsp;&middot;&nbsp; DATE &nbsp;&middot;&nbsp; VERSION</p>\n    </div>\n    <div class='right'></div>\n  </div>\n  <aside class='notes'>One-line speaker note.</aside>\n</section>\nThe <div class='right'> is intentionally empty -- the theme renders the teal panel + decorative gradients via CSS. The <h1> may use a <br> to break across lines. The eyebrow is the small uppercase label above the title, the subtitle is one or two lines of secondary copy, and the meta line carries author / date / version separated by middots. Do NOT add background-color or color inline styles -- the theme owns them.",181    "emblema-agenda": "Create an Emblema AGENDA slide. The body MUST contain a <div class='slide-pad slide-agenda'> with an <ol> of agenda items; WITHOUT THE .slide-agenda CLASS the numbered counters and 2-column grid will not render and the items will fall back to default <ol> bullets. CRITICAL HEADING RULE: The <h2> MUST be 3-8 words describing THIS specific slide's content, written in the SAME LANGUAGE as the source document (Italian source -> Italian heading, English source -> English heading). Extract the heading from the actual source content -- do NOT invent generic phrases. BANNED <h2> values: 'Agenda', 'Outline', 'Overview', 'Topics', 'Schedule', 'Today'. Good examples: 'What we'll cover today.', 'Programma del briefing.'. Use this EXACT structure:\n<section>\n  <div class='slide-pad slide-agenda'>\n    <div>\n      <span class='eyebrow'>Agenda</span>\n      <h2>HEADING_DERIVED_FROM_SOURCE_CONTENT</h2>\n      <hr class='divider'>\n    </div>\n    <ol>\n      <li><span class='topic'>Topic name</span><span class='duration'>X min</span></li>\n      <!-- 4-8 items total -->\n    </ol>\n  </div>\n  <div class='brand-mark'>Brand</div>\n  <div class='page-num'>NN / NN</div>\n  <aside class='notes'>Speaker notes.</aside>\n</section>\nEach <li> MUST contain a <span class='topic'> for the topic and <span class='duration'> for the duration -- these are CSS-targeted for two-column alignment. The leading numbered counter (01, 02, ...) is auto-generated by CSS counter, do NOT add it as text. Use 4-8 items; fewer collapses the layout, more wraps awkwardly. Anti-pattern to AVOID: <ul> bullets or plain <p> lines without <span> wrappers.",182    "emblema-section": "Create an Emblema SECTION DIVIDER slide. The body MUST contain a <div class='slide-section'> with a <div class='num'> and a <div class='meta'>; WITHOUT THIS STRUCTURE the big section number, teal background, and 2-column layout will not render. CRITICAL HEADING RULE: The <h2> MUST be 3-8 words describing THIS specific slide's content, written in the SAME LANGUAGE as the source document (Italian source -> Italian heading, English source -> English heading). Extract the heading from the actual source content -- do NOT invent generic phrases. BANNED <h2> values: 'Section Two', 'Part One', 'Section Divider', 'Next Section', 'Chapter', 'Overview'. Good examples: 'The opportunity in front of us.', 'I numeri dietro la storia.'. Use this EXACT structure:\n<section>\n  <div class='slide-section'>\n    <div class='num'>NN</div>\n    <div class='meta'>\n      <span class='label'>Section N or Capitolo N</span>\n      <h2>HEADING_DERIVED_FROM_SOURCE_CONTENT</h2>\n      <p>One- or two-sentence framing pulled from the source content.</p>\n    </div>\n  </div>\n  <aside class='notes'>Speaker notes.</aside>\n</section>\nThe <div class='num'> renders as a 280px Plex Sans Light digit pair (use '01', '02', etc.). The <span class='label'> is the small uppercase label above the section title. The <p> body is restrained to 1-3 sentences -- this is a divider, not a content slide. Anti-pattern to AVOID: cramming bullet lists or KPI cards into a section divider.",183    "emblema-statement": "Create an Emblema STATEMENT / PULL QUOTE slide. The body MUST contain a <div class='slide-statement'> with a <p class='quote'> that highlights one phrase via <em>; WITHOUT THE <em> the teal accent on the key phrase will not appear and the slide loses its rhetorical hook. CRITICAL HEADING RULE: The pull quote MUST be 3-8 words describing THIS specific slide's content, written in the SAME LANGUAGE as the source document (Italian source -> Italian heading, English source -> English heading). Extract the heading from the actual source content -- do NOT invent generic phrases. The <em> wraps the SINGLE most important phrase in the quote (2-6 words). Use this EXACT structure:\n<section>\n  <div class='slide-statement'>\n    <div>\n      <p class='quote'>The quote text with one <em>key phrase</em> highlighted in teal.</p>\n      <p class='attribution'>&mdash; Source or speaker, ROLE</p>\n    </div>\n  </div>\n  <div class='corner-index'>SECTION <span class='num'>NN</span> &middot; SLIDE_NUM</div>\n  <aside class='notes'>Speaker notes.</aside>\n</section>\nDo NOT use <h1> or <h2> on this layout -- the quote IS the headline and is styled via .slide-statement .quote (64px Plex Light). Use exactly ONE <em> in the quote (zero loses the accent, multiple looks busy). The <p class='attribution'> is uppercase tracked-out text below the quote. Anti-pattern to AVOID: <blockquote> or <h2> instead of <p class='quote'>.",184    "emblema-two-col": "Create an Emblema TWO-COLUMN slide. The body MUST contain a <div class='slide-grid-2 slide-two-col'> with exactly two child <div>s; WITHOUT BOTH CLASSES the 50/50 grid and centered alignment will not render. CRITICAL HEADING RULE: The <h2> MUST be 3-8 words describing THIS specific slide's content, written in the SAME LANGUAGE as the source document (Italian source -> Italian heading, English source -> English heading). Extract the heading from the actual source content -- do NOT invent generic phrases. BANNED <h2> values: 'Two Columns', 'Comparison', 'Side by Side', 'Overview', 'Summary'. Good examples: 'Knowledge work is drowning.', 'Domanda e offerta.'. Use this EXACT structure:\n<section>\n  <div class='slide-grid-2 slide-two-col'>\n    <div>\n      <span class='eyebrow'>SHORT EYEBROW</span>\n      <h2>HEADING_DERIVED_FROM_SOURCE_CONTENT</h2>\n      <p>Body paragraph 1 from source.</p>\n      <p class='muted' style='font-size:16px'>Source or footnote.</p>\n    </div>\n    <div class='visual'>\n      <!-- Either an <img> or a decorative SVG. Theme styles .visual as an et-50 panel. -->\n    </div>\n  </div>\n  <div class='brand-mark'>Brand</div>\n  <div class='page-num'>NN / NN</div>\n  <aside class='notes'>Speaker notes.</aside>\n</section>\nLeft column is text; right column has class='visual' which the theme styles as a soft teal-tinted panel for an SVG/image. If no visual is available, leave the .visual div empty -- do NOT replace it with a body paragraph. Anti-pattern to AVOID: 50/50 with TWO text columns (use emblema-bullets or emblema-compare instead).",185    "emblema-bullets": "Create an Emblema BULLET TAKEAWAYS slide. The body MUST contain a <div class='slide-pad slide-bullets'> with a <ul> of 3-4 <li> items; EACH <li> MUST contain a <span class='marker'>NN</span> and a <div> wrapping <h4>+<p>; WITHOUT THE .marker SPAN the numbered teal-tint circles will not render and bullets will fall back to plain dots. CRITICAL HEADING RULE: The <h2> MUST be 3-8 words describing THIS specific slide's content, written in the SAME LANGUAGE as the source document (Italian source -> Italian heading, English source -> English heading). Extract the heading from the actual source content -- do NOT invent generic phrases. BANNED <h2> values: 'Key Takeaways', 'Bullet Points', 'Summary', 'Main Points', 'Highlights', 'Overview'. Use this EXACT structure:\n<section>\n  <div class='slide-pad slide-bullets'>\n    <div>\n      <span class='eyebrow'>SHORT EYEBROW</span>\n      <h2>HEADING_DERIVED_FROM_SOURCE_CONTENT</h2>\n      <hr class='divider'>\n    </div>\n    <ul>\n      <li>\n        <span class='marker'>01</span>\n        <div>\n          <h4>Bullet headline.</h4>\n          <p>1-2 sentence body for this bullet.</p>\n        </div>\n      </li>\n      <!-- 3-4 bullets total -->\n    </ul>\n  </div>\n  <aside class='notes'>Speaker notes.</aside>\n</section>\nUse 3 or 4 bullets in a 2-column grid. Marker numbers MUST use leading zeros: 01, 02, 03, 04. Anti-pattern to AVOID: plain <ul><li>text</li></ul> without the marker/div structure -- the theme requires the wrapper to render the numbered circles.",186    "emblema-image": "Create an Emblema FULL-BLEED IMAGE slide. The body MUST contain a <div class='slide-image'> with a <div class='overlay'> child for the text; WITHOUT THIS STRUCTURE the bottom dark-gradient overlay and white text positioning will not render. The .slide-image background is a teal gradient by default; an <img> tag may be appended INSIDE .slide-image to override. CRITICAL HEADING RULE: The <h2> MUST be 3-8 words describing THIS specific slide's content, written in the SAME LANGUAGE as the source document (Italian source -> Italian heading, English source -> English heading). Extract the heading from the actual source content -- do NOT invent generic phrases. BANNED <h2> values: 'Image', 'Photo', 'Visual', 'Picture', 'Background'. Use this EXACT structure:\n<section>\n  <div class='slide-image'>\n    <!-- Optional: <img src='...' alt='...' style='position:absolute;inset:0;width:100%;height:100%;object-fit:cover;'> -->\n    <div class='overlay'>\n      <span class='eyebrow eyebrow--inverse'>SHORT LOCATION OR LABEL</span>\n      <h2>Image headline pulled from source.</h2>\n      <p>Caption or context, 1-2 sentences.</p>\n    </div>\n  </div>\n  <div class='page-num' style='color: rgba(255,255,255,0.7);'>NN / NN</div>\n  <aside class='notes'>Speaker notes.</aside>\n</section>\nThe .eyebrow MUST also have eyebrow--inverse so the small uppercase label renders in light teal against the dark background. Page number is forced to translucent white via inline style (the only inline color allowed on this layout, and only because the chrome lives outside the gradient). Anti-pattern to AVOID: omitting the .overlay wrapper -- the text falls through onto a transparent background.",187    "emblema-magazine": "Create an Emblema MAGAZINE SPREAD slide. The body MUST contain a <div class='slide-mag'> with a <div class='photo-col'> on the left and <div class='text-col'> on the right; WITHOUT BOTH CHILDREN the asymmetric photo-left / text-right grid will not render. CRITICAL HEADING RULE: The <h2> MUST be 3-8 words describing THIS specific slide's content, written in the SAME LANGUAGE as the source document (Italian source -> Italian heading, English source -> English heading). Extract the heading from the actual source content -- do NOT invent generic phrases. BANNED <h2> values: 'Magazine', 'Spread', 'Story', 'Customer Story', 'Case Study'. Good examples: 'From four spreadsheets to one workflow.', 'Da quattro fogli a un flusso.'. Use this EXACT structure:\n<section>\n  <div class='slide-mag'>\n    <div class='photo-col'>\n      <div class='photo photo--var2'><span class='photo-tag'>Photo &middot; MM.YYYY</span></div>\n    </div>\n    <div class='text-col'>\n      <span class='eyebrow'>Customer story &middot; Subject</span>\n      <h2>HEADING_DERIVED_FROM_SOURCE_CONTENT</h2>\n      <p class='body'>Long-form body paragraph -- 3-5 sentences pulled from the source.</p>\n      <div class='meta'>\n        <span><strong>Photographed at</strong> &mdash; Place</span>\n        <span><strong>Words by</strong> &mdash; Author</span>\n        <span><strong>Month YYYY</strong></span>\n      </div>\n    </div>\n  </div>\n  <div class='page-num'>NN / NN</div>\n  <aside class='notes'>Speaker notes.</aside>\n</section>\nPick ONE of .photo--var1 through .photo--var8 to set the gradient placeholder colour. To use a real image, replace the .photo div with an <img> covering the photo-col area. The .meta uses <strong> labels for byline-style metadata. Anti-pattern to AVOID: <table> or <ul> instead of the .meta <span> structure.",188    "emblema-two-img": "Create an Emblema TWO IMAGES slide. The body MUST contain a <div class='slide-pad slide-two-img'> with a <div class='grid'> of exactly two <div class='item'> children; WITHOUT THE .grid AND .item CLASSES the side-by-side layout and per-item caption styling will not render. CRITICAL HEADING RULE: The <h2> MUST be 3-8 words describing THIS specific slide's content, written in the SAME LANGUAGE as the source document (Italian source -> Italian heading, English source -> English heading). Extract the heading from the actual source content -- do NOT invent generic phrases. BANNED <h2> values: 'Two Images', 'Photos', 'Pictures', 'Gallery', 'Examples'. Good examples: 'Two teams, two transformations.', 'Field studies &mdash; Spring 2026'. Use this EXACT structure:\n<section>\n  <div class='slide-pad slide-two-img'>\n    <div>\n      <span class='eyebrow'>SHORT EYEBROW</span>\n      <h2>HEADING_DERIVED_FROM_SOURCE_CONTENT</h2>\n      <hr class='divider'>\n    </div>\n    <div class='grid'>\n      <div class='item'>\n        <div class='photo photo--var1'><span class='photo-tag'>Tag 1</span></div>\n        <h4>Item 1 title</h4>\n        <p>One- or two-sentence description.</p>\n        <div class='cap'>&mdash; Credit, Date</div>\n      </div>\n      <div class='item'>\n        <div class='photo photo--var6'><span class='photo-tag'>Tag 2</span></div>\n        <h4>Item 2 title</h4>\n        <p>One- or two-sentence description.</p>\n        <div class='cap'>&mdash; Credit, Date</div>\n      </div>\n    </div>\n  </div>\n  <div class='page-num'>NN / NN</div>\n  <aside class='notes'>Speaker notes.</aside>\n</section>\nExactly TWO .item children -- adding a third breaks the equal-width grid. Each .item has photo + h4 + p + .cap. Anti-pattern to AVOID: omitting the .photo wrapper around an <img> (the .photo class is what gives images their teal-tint placeholder fallback).",189    "emblema-grid-img": "Create an Emblema 2x2 IMAGE GRID slide. The body MUST contain a <div class='slide-grid-img'> with a <div class='header'> and a <div class='grid'> of exactly four <div class='photo'> children; WITHOUT THIS STRUCTURE the full-bleed teal background, white header, and 2x2 image grid will not render. CRITICAL HEADING RULE: The <h2> MUST be 3-8 words describing THIS specific slide's content, written in the SAME LANGUAGE as the source document (Italian source -> Italian heading, English source -> English heading). Extract the heading from the actual source content -- do NOT invent generic phrases. BANNED <h2> values: 'Image Grid', 'Gallery', 'Photos', '2x2', 'Examples'. Use this EXACT structure:\n<section>\n  <div class='slide-grid-img'>\n    <div class='header'>\n      <span class='eyebrow eyebrow--inverse'>SHORT EYEBROW</span>\n      <h2>HEADING_DERIVED_FROM_SOURCE_CONTENT</h2>\n      <p>One- or two-sentence framing.</p>\n    </div>\n    <div class='grid'>\n      <div class='photo photo--var4'><span class='photo-tag'>Caption 1</span></div>\n      <div class='photo photo--var5'><span class='photo-tag'>Caption 2</span></div>\n      <div class='photo photo--var7'><span class='photo-tag'>Caption 3</span></div>\n      <div class='photo photo--var8'><span class='photo-tag'>Caption 4</span></div>\n    </div>\n  </div>\n  <div class='page-num' style='color: rgba(255,255,255,0.7);'>NN / NN</div>\n  <aside class='notes'>Speaker notes.</aside>\n</section>\nUse eyebrow--inverse for light teal text against the dark background. Pick distinct .photo--varN values for visual variety. Exactly 4 photos. Anti-pattern to AVOID: 3 or 5 photos -- breaks the 2x2 grid.",190    "emblema-hero-centered": "Create an Emblema CENTERED HERO slide. The body MUST contain a <div class='slide-hero-centered'> with a <div class='header'>, a <div class='photo'>, and a <p class='caption'>; WITHOUT THIS STRUCTURE the centered alignment, hero photo sizing, and italic caption styling will not render. CRITICAL HEADING RULE: The <h2> MUST be 3-8 words describing THIS specific slide's content, written in the SAME LANGUAGE as the source document (Italian source -> Italian heading, English source -> English heading). Extract the heading from the actual source content -- do NOT invent generic phrases. BANNED <h2> values: 'Hero', 'Image', 'Photo', 'Featured Image'. Good examples: 'The room where the first prototype shipped.', 'La sala riunioni del comando.'. Use this EXACT structure:\n<section>\n  <div class='slide-hero-centered'>\n    <div class='header'>\n      <span class='eyebrow'>SHORT EYEBROW</span>\n      <h2>HEADING_DERIVED_FROM_SOURCE_CONTENT</h2>\n    </div>\n    <div class='photo photo--var2'><span class='photo-tag'>Photo &middot; MM.YYYY</span></div>\n    <p class='caption'>Italic caption text. <em>Photographed by NAME &middot; Month YYYY</em></p>\n  </div>\n  <div class='brand-mark'>Brand</div>\n  <div class='page-num'>NN / NN</div>\n  <aside class='notes'>Speaker notes.</aside>\n</section>\nThe .photo grows to fill the available vertical space between header and caption. To use a real <img>, place it INSIDE the .photo div with object-fit:cover. Anti-pattern to AVOID: large <img> without the .photo wrapper -- inherits composer's max-width:100% rule and shrinks awkwardly.",191    "emblema-hero-card": "Create an Emblema HERO + FLOATING CARD slide. The body MUST contain a <div class='slide-hero-card'> with a full-bleed <div class='photo'> and a floating <div class='card'>; WITHOUT BOTH CHILDREN the hero image background and white card with shadow will not render. CRITICAL HEADING RULE: The <h2> MUST be 3-8 words describing THIS specific slide's content, written in the SAME LANGUAGE as the source document (Italian source -> Italian heading, English source -> English heading). Extract the heading from the actual source content -- do NOT invent generic phrases. BANNED <h2> values: 'Spotlight', 'Featured', 'Card', 'Highlight'. Good examples: 'Inside the launch of our largest deployment yet.', 'Dietro le quinte della missione X.'. Use this EXACT structure:\n<section>\n  <div class='slide-hero-card'>\n    <div class='photo photo--var5'><span class='photo-tag'>SHORT TAG</span></div>\n    <div class='card'>\n      <span class='eyebrow'>SHORT EYEBROW</span>\n      <h2>HEADING_DERIVED_FROM_SOURCE_CONTENT</h2>\n      <p>1-3 sentence body pulled from source.</p>\n      <div class='meta'>Subject &middot; Place &middot; Month YYYY</div>\n    </div>\n  </div>\n  <div class='page-num' style='color: rgba(255,255,255,0.7);'>NN / NN</div>\n  <aside class='notes'>Speaker notes.</aside>\n</section>\nThe .card floats absolute bottom-left over the hero photo with a drop-shadow. The .meta is a tracked-out uppercase metadata line at the card's bottom. Anti-pattern to AVOID: putting all content inside .photo -- the card layer is what creates the magazine-style legibility against the photo.",192    "emblema-collage": "Create an Emblema IMAGE COLLAGE slide. The body MUST contain a <div class='slide-collage'> with a <div class='text-col'> and a <div class='stack'> of exactly THREE <div class='photo'> children; WITHOUT THE .stack AND THREE PHOTOS the rotated layered photo collage will not render (each photo has a nth-child rule that positions it). CRITICAL HEADING RULE: The <h2> MUST be 3-8 words describing THIS specific slide's content, written in the SAME LANGUAGE as the source document (Italian source -> Italian heading, English source -> English heading). Extract the heading from the actual source content -- do NOT invent generic phrases. BANNED <h2> values: 'Collage', 'Gallery', 'Photos', 'Year in Review'. Use this EXACT structure:\n<section>\n  <div class='slide-collage'>\n    <div class='text-col'>\n      <span class='eyebrow'>SHORT EYEBROW</span>\n      <h2>HEADING_DERIVED_FROM_SOURCE_CONTENT</h2>\n      <p>One paragraph framing the collage.</p>\n      <p class='caption'>Optional caption identifying the photos clockwise.</p>\n    </div>\n    <div class='stack'>\n      <div class='photo photo--var1'><span class='photo-tag'>01</span></div>\n      <div class='photo photo--var3'><span class='photo-tag'>02</span></div>\n      <div class='photo photo--var5'><span class='photo-tag'>03</span></div>\n    </div>\n  </div>\n  <div class='brand-mark'>Brand</div>\n  <div class='page-num'>NN / NN</div>\n  <aside class='notes'>Speaker notes.</aside>\n</section>\nExactly THREE .photo children -- the CSS targets :nth-child(1), :nth-child(2), :nth-child(3) for rotation/positioning. Anti-pattern to AVOID: 2 or 4 photos -- breaks the layered effect.",193    "emblema-stat": "Create an Emblema BIG STAT slide. The body MUST contain a <div class='slide-stat'> with a <div class='number'> and a <div class='copy'>; WITHOUT THIS STRUCTURE the 280px teal stat number and side-by-side copy will not render. CRITICAL HEADING RULE: The <h3> MUST be 3-8 words describing THIS specific slide's content, written in the SAME LANGUAGE as the source document (Italian source -> Italian heading, English source -> English heading). Extract the heading from the actual source content -- do NOT invent generic phrases. BANNED <h3> values: 'Big Number', 'Stat', 'Metric', 'Key Number'. The <h3> is the supporting headline -- the BIG NUMBER itself goes in <div class='number'> NOT in a heading. Use this EXACT structure:\n<section>\n  <div class='slide-stat'>\n    <div class='number'>NN<span class='unit'>%</span></div>\n    <div class='copy'>\n      <span class='eyebrow'>SHORT EYEBROW</span>\n      <h3>One-sentence interpretation derived from the source.</h3>\n      <p>1-2 sentence body explaining the number.</p>\n    </div>\n  </div>\n  <div class='brand-mark'>Brand</div>\n  <div class='page-num'>NN / NN</div>\n  <aside class='notes'>Speaker notes.</aside>\n</section>\nThe <div class='number'> takes the bare numeric (no euro/dollar sign in front -- prefix those into the <span class='unit'> if needed; e.g. '<span class=\"unit\">&euro;</span>1.2M'). The <span class='unit'> renders at half size in lighter teal. Use a single number per slide -- for multiples use emblema-kpis. Anti-pattern to AVOID: <h2>NN%</h2> -- defeats the purpose of the layout.",194    "emblema-kpis": "Create an Emblema KPI GRID slide. The body MUST contain a <div class='slide-pad slide-kpis'> with a <div class='grid'> of BETWEEN 3 AND 9 <div class='kpi'> children — prefer multiples of 3 (3, 6, or 9); WITHOUT THE .kpi WRAPPER each metric loses its top teal accent, soft background, and large-number styling. CRITICAL HEADING RULE: The <h2> MUST be 3-8 words describing THIS specific slide's content, written in the SAME LANGUAGE as the source document (Italian source -> Italian heading, English source -> English heading). Extract the heading from the actual source content -- do NOT invent generic phrases. BANNED <h2> values: 'KPIs', 'Key Metrics', 'Numbers', 'Performance', 'Dashboard', 'Overview', 'Stats'. Good examples: 'Three numbers we're proud of.', 'Tre KPI del Q1 2026'. Use this EXACT structure:\n<section>\n  <div class='slide-pad slide-kpis'>\n    <div>\n      <span class='eyebrow'>SHORT EYEBROW</span>\n      <h2>HEADING_DERIVED_FROM_SOURCE_CONTENT</h2>\n      <hr class='divider'>\n    </div>\n    <div class='grid'>\n      <div class='kpi'>\n        <div class='num'>NN<span class='delta'>&uarr; X</span></div>\n        <h4>KPI title</h4>\n        <p>One-line context derived from source.</p>\n      </div>\n      <!-- 3 to 9 KPIs, prefer multiples of 3 -->\n    </div>\n  </div>\n  <aside class='notes'>Speaker notes.</aside>\n</section>\nUse 3, 6, or 9 KPIs based on content density: 3 (single row) for headline metrics, 6 (2 rows) for paired-metric dashboards, 9 (3 rows) for full quarterly scorecards. CSS uses grid-template-columns: repeat(3, 1fr) — counts that aren't multiples of 3 leave a partial last row. The <span class='delta'> is OPTIONAL and renders in green by default; for a NEGATIVE delta change the arrow to &darr;. Anti-pattern to AVOID: more than 9 KPIs (likely belong in emblema-table or emblema-chart instead — the kpi card design loses impact at higher counts). Counts that aren't multiples of 3 (4, 5, 7, 8) are acceptable but visually weaker than a clean 3/6/9 grid.",195    "emblema-compare": "Create an Emblema BEFORE/AFTER COMPARISON slide. The body MUST contain a <div class='slide-pad slide-compare'> with a <div class='grid'> containing a .col, a .arrow span, and a .col.col--after; WITHOUT THE 1fr-80px-1fr GRID and the .col--after class on the right column, the highlighted 'after' state will not render and the arrow will not be centered. CRITICAL HEADING RULE: The <h2> MUST be 3-8 words describing THIS specific slide's content, written in the SAME LANGUAGE as the source document (Italian source -> Italian heading, English source -> English heading). Extract the heading from the actual source content -- do NOT invent generic phrases. BANNED <h2> values: 'Comparison', 'Before/After', 'Then/Now', 'Old vs New'. Good examples: 'How a quarterly review changes after Emblema.', 'Da manuale ad automatico.'. Use this EXACT structure:\n<section>\n  <div class='slide-pad slide-compare'>\n    <div>\n      <span class='eyebrow'>SHORT EYEBROW</span>\n      <h2>HEADING_DERIVED_FROM_SOURCE_CONTENT</h2>\n      <hr class='divider'>\n    </div>\n    <div class='grid'>\n      <div class='col'>\n        <h4>BEFORE / OLD STATE</h4>\n        <ul>\n          <li>Pain point 1</li>\n          <li>Pain point 2</li>\n          <li>Pain point 3</li>\n        </ul>\n      </div>\n      <div class='arrow'>&rarr;</div>\n      <div class='col col--after'>\n        <h4>AFTER / NEW STATE</h4>\n        <ul>\n          <li>Resolution 1</li>\n          <li>Resolution 2</li>\n          <li>Resolution 3</li>\n        </ul>\n      </div>\n    </div>\n  </div>\n  <aside class='notes'>Speaker notes.</aside>\n</section>\nCRITICAL: the AFTER column MUST have BOTH .col AND .col--after classes -- without .col--after it loses the teal-tint background and teal border that signal 'this is the improved state'. Match item count between columns (3-5 items each). Anti-pattern to AVOID: <table> with 2 columns, or putting both lists in a single .col div.",196    "emblema-chart": "Create an Emblema CHART slide. The body MUST contain a <div class='slide-pad slide-chart'> with a <div class='chart-wrap'> wrapping the visualization, plus a <div class='legend'>; WITHOUT THE .chart-wrap container the chart panel border and padding will not render. CRITICAL HEADING RULE: The <h2> MUST be 3-8 words describing THIS specific slide's content, written in the SAME LANGUAGE as the source document (Italian source -> Italian heading, English source -> English heading). Extract the heading from the actual source content -- do NOT invent generic phrases. BANNED <h2> values: 'Chart', 'Graph', 'Data', 'Trend'. Good examples: 'Revenue lift across the cohort.', 'Andamento clienti 2024-2026'. Use this EXACT structure:\n<section>\n  <div class='slide-pad slide-chart'>\n    <div>\n      <span class='eyebrow'>SHORT EYEBROW</span>\n      <h2>HEADING_DERIVED_FROM_SOURCE_CONTENT</h2>\n      <hr class='divider'>\n    </div>\n    <div class='chart-wrap'>\n      <!-- An inline <svg viewBox='0 0 W H'> for bar/line/area chart, OR a placeholder. -->\n      <svg viewBox='0 0 800 320' style='width:100%;height:auto'>\n        <!-- bars/lines using <rect>, <line>, <path>; reuse var(--et-500) color -->\n      </svg>\n    </div>\n    <div class='legend'>\n      <span><i style='background:var(--et-500)'></i>Series 1</span>\n      <span><i style='background:var(--et-300)'></i>Series 2</span>\n    </div>\n    <p class='muted' style='font-size:14px;margin-top:1em'>Source &mdash; reference</p>\n  </div>\n  <aside class='notes'>Speaker notes.</aside>\n</section>\nThe <i> in legend items is intentionally empty -- CSS sizes it as a 12px swatch. Inline style `background:var(--et-500)` is the ONLY allowed inline color (legend swatches need it because there is no enumerable class for arbitrary swatch colors). Anti-pattern to AVOID: <table> instead of an SVG chart -- use emblema-table for data tables.",197    "emblema-table": "Create an Emblema DATA TABLE slide. The body MUST contain a <div class='slide-pad slide-table'> with a real <table> containing <thead>, <tbody>, and optionally <tfoot>; WITHOUT A REAL <table> the column-aligned numerics and uppercase tracked-out header styling will not render. CRITICAL HEADING RULE: The <h2> MUST be 3-8 words describing THIS specific slide's content, written in the SAME LANGUAGE as the source document (Italian source -> Italian heading, English source -> English heading). Extract the heading from the actual source content -- do NOT invent generic phrases. BANNED <h2> values: 'Data Table', 'Table', 'Numbers', 'Financials', 'Metrics'. Good examples: 'Q1 2026 financial summary.', 'Bilancio operativo del primo trimestre.'. Use this EXACT structure:\n<section>\n  <div class='slide-pad slide-table'>\n    <div>\n      <span class='eyebrow'>SHORT EYEBROW</span>\n      <h2>HEADING_DERIVED_FROM_SOURCE_CONTENT</h2>\n      <hr class='divider'>\n    </div>\n    <table>\n      <thead><tr><th>Metric</th><th class='num'>Period A</th><th class='num'>Period B</th><th class='num'>Delta</th></tr></thead>\n      <tbody>\n        <tr><td class='label'>Row name</td><td class='num'>1,234</td><td class='num'>2,345</td><td class='num up'>+90%</td></tr>\n        <!-- 4-8 rows -->\n      </tbody>\n      <tfoot><tr><td>Total</td><td class='num'>X</td><td class='num'>Y</td><td class='num up'>Z</td></tr></tfoot>\n    </table>\n    <p class='src'>Source &mdash; reference</p>\n  </div>\n  <aside class='notes'>Speaker notes.</aside>\n</section>\nNumeric columns MUST have class='num' on every <th> and <td> -- this right-aligns and applies tabular-nums. For deltas, use class='up' (green), class='down' (red), or class='flat' (grey) on the <td>. The class='label' on the first body cell makes the row label semibold. Anti-pattern to AVOID: <div> grids with manual alignment -- use a real table.",198    "emblema-matrix": "Create an Emblema COMPARISON MATRIX slide. The body MUST contain a <div class='slide-pad slide-matrix'> with a <table> whose <thead> has EXACTLY ONE <th class='featured'>; WITHOUT .featured on one column the 'OUR PICK' badge and teal column highlight will not render. CRITICAL HEADING RULE: The <h2> MUST be 3-8 words describing THIS specific slide's content, written in the SAME LANGUAGE as the source document (Italian source -> Italian heading, English source -> English heading). Extract the heading from the actual source content -- do NOT invent generic phrases. BANNED <h2> values: 'Comparison', 'Matrix', 'Options', 'Compare'. Good examples: 'Why Emblema vs the build/buy alternatives.', 'Confronto con le alternative di mercato.'. Use this EXACT structure:\n<section>\n  <div class='slide-pad slide-matrix'>\n    <div>\n      <span class='eyebrow'>SHORT EYEBROW</span>\n      <h2>HEADING_DERIVED_FROM_SOURCE_CONTENT</h2>\n      <hr class='divider'>\n    </div>\n    <table>\n      <thead><tr><th>Feature</th><th>Option A</th><th class='featured'>Emblema</th><th>Option C</th></tr></thead>\n      <tbody>\n        <tr><td>Capability label</td><td><span class='no'>&times;</span></td><td class='featured'><span class='yes'>&check;</span></td><td><span class='partial'>partial</span></td></tr>\n        <!-- 4-8 rows -->\n      </tbody>\n    </table>\n  </div>\n  <aside class='notes'>Speaker notes.</aside>\n</section>\nEXACTLY ONE <th class='featured'> -- having two means the 'OUR PICK' badge appears twice and the visual hierarchy collapses. Each row's cell under the featured column ALSO needs class='featured' so it inherits the teal-tint background. Cell content uses <span class='yes'>&check;</span>, <span class='no'>&times;</span>, or <span class='partial'>partial</span>. Anti-pattern to AVOID: emoji ✓/✗ instead of the styled span variants -- emoji bypasses the theme color logic.",199    "emblema-spec": "Create an Emblema SPEC SHEET slide. The body MUST contain a <div class='slide-pad slide-spec'> with a <div class='spec-grid'> of 2 or 4 <div class='spec-section'> children, each with an <h4> and a <dl>; WITHOUT THIS STRUCTURE the 2-column spec layout, dashed dividers, and uppercase teal section headers will not render. CRITICAL HEADING RULE: The <h2> MUST be 3-8 words describing THIS specific slide's content, written in the SAME LANGUAGE as the source document (Italian source -> Italian heading, English source -> English heading). Extract the heading from the actual source content -- do NOT invent generic phrases. BANNED <h2> values: 'Specifications', 'Specs', 'Details', 'Properties', 'Information'. Good examples: 'Platform technical specifications.', 'Specifiche piattaforma ITS Margottini.'. Use this EXACT structure:\n<section>\n  <div class='slide-pad slide-spec'>\n    <div>\n      <span class='eyebrow'>SHORT EYEBROW</span>\n      <h2>HEADING_DERIVED_FROM_SOURCE_CONTENT</h2>\n      <hr class='divider'>\n    </div>\n    <div class='spec-grid'>\n      <div class='spec-section'>\n        <h4>Section Name<span class='num'>01</span></h4>\n        <dl>\n          <div><dt>Key</dt><dd>Value <span class='badge'>BADGE</span></dd></div>\n          <div><dt>Key</dt><dd>Value</dd></div>\n          <!-- 3-6 entries per section -->\n        </dl>\n      </div>\n      <!-- 2 or 4 .spec-section blocks -->\n    </div>\n  </div>\n  <aside class='notes'>Speaker notes.</aside>\n</section>\nThe <dl> uses a non-standard <div> wrapper around each <dt>/<dd> pair -- this is REQUIRED because the CSS uses .slide-spec dl > div for grid alignment. The <span class='badge'> is OPTIONAL inline highlight inside a <dd>. Anti-pattern to AVOID: flat <dl><dt><dd></dl> without div wrappers (loses the per-row alignment) or <table> (visual is wrong for spec sheets).",200    "emblema-status": "Create an Emblema PROJECT STATUS slide. The body MUST contain a <div class='slide-pad slide-status'> with a <table> whose status cells contain <span class='dot dot--COLOR'> elements; WITHOUT THE .dot--COLOR CLASSES the green/amber/red/gray RAG indicators will not render and the table looks like generic data. CRITICAL HEADING RULE: The <h2> MUST be 3-8 words describing THIS specific slide's content, written in the SAME LANGUAGE as the source document (Italian source -> Italian heading, English source -> English heading). Extract the heading from the actual source content -- do NOT invent generic phrases. BANNED <h2> values: 'Status', 'RAG', 'Project Status', 'Portfolio', 'Health'. Good examples: 'Q1 portfolio &mdash; status at week 11.', 'Stato del portafoglio progetti.'. Use this EXACT structure:\n<section>\n  <div class='slide-pad slide-status'>\n    <div>\n      <span class='eyebrow'>SHORT EYEBROW</span>\n      <h2>HEADING_DERIVED_FROM_SOURCE_CONTENT</h2>\n      <hr class='divider'>\n    </div>\n    <table>\n      <thead><tr><th>Project</th><th class='owner'>Owner</th><th class='note'>Note</th><th class='status'>Status</th></tr></thead>\n      <tbody>\n        <tr><td>Project A</td><td class='owner'>Owner</td><td class='note'>Short note.</td><td class='status'><span class='dot dot--green'></span></td></tr>\n        <tr><td>Project B</td><td class='owner'>Owner</td><td class='note'>Short note.</td><td class='status'><span class='dot dot--amber'></span></td></tr>\n        <tr><td>Project C</td><td class='owner'>Owner</td><td class='note'>Short note.</td><td class='status'><span class='dot dot--red'></span></td></tr>\n        <!-- 4-8 rows -->\n      </tbody>\n    </table>\n    <div class='legend'>\n      <span><span class='dot dot--green'></span>On track</span>\n      <span><span class='dot dot--amber'></span>At risk</span>\n      <span><span class='dot dot--red'></span>Off track</span>\n      <span><span class='dot dot--gray'></span>Not started</span>\n    </div>\n  </div>\n  <aside class='notes'>Speaker notes.</aside>\n</section>\nSTATUS COUPLING RULE: dot--green = on track, dot--amber = at risk, dot--red = off track, dot--gray = not started. Use the dot color that matches the SEMANTICS of each project's status -- do NOT assign colors arbitrarily. Anti-pattern to AVOID: emoji 🟢🟡🔴 instead of styled spans (no theme control over color), or omitting the dot wrapper inside the .status td.",201    "emblema-process": "Create an Emblema PROCESS / STEPS slide. The body MUST contain a <div class='slide-pad slide-process'> with a <div class='steps'> of BETWEEN 4 AND 8 <div class='step'> children — prefer multiples of 4 (4 or 8); WITHOUT THE .step WRAPPER each card loses its left teal border and uppercase step label. CRITICAL HEADING RULE: The <h2> MUST be 3-8 words describing THIS specific slide's content, written in the SAME LANGUAGE as the source document (Italian source -> Italian heading, English source -> English heading). Extract the heading from the actual source content -- do NOT invent generic phrases. BANNED <h2> values: 'Process', 'Steps', 'Workflow', 'How it works', 'Methodology'. Good examples: 'How an Emblema rollout flows.', 'Le quattro fasi del nostro metodo.'. Use this EXACT structure:\n<section>\n  <div class='slide-pad slide-process'>\n    <div>\n      <span class='eyebrow'>SHORT EYEBROW</span>\n      <h2>HEADING_DERIVED_FROM_SOURCE_CONTENT</h2>\n      <hr class='divider'>\n    </div>\n    <div class='steps'>\n      <div class='step'>\n        <div class='icon'><svg viewBox='0 0 22 22'><!-- 22x22 icon --></svg></div>\n        <span class='num'>STEP 01</span>\n        <h4>Step title</h4>\n        <p>1-2 sentences describing the step.</p>\n      </div>\n      <!-- 4 to 8 .step children, prefer multiples of 4 -->\n    </div>\n  </div>\n  <aside class='notes'>Speaker notes.</aside>\n</section>\nUse 4 (single row) or 8 (two rows) based on process complexity. CSS uses grid-template-columns: repeat(4, 1fr) — counts other than 4 or 8 (5, 6, 7) produce a partial last row that's acceptable but visually unbalanced. Use leading zeros on the step numbers (01, 02, ..., 0N). The <div class='icon'> can be empty if no icon is available -- it still renders as a teal-tinted square placeholder. Anti-pattern to AVOID: fewer than 4 steps (use emblema-statement or emblema-bullets for short sequences). Counts other than 4 or 8 are acceptable when content has that many genuine steps, but 4 and 8 are visually cleanest.",202    "emblema-timeline": "Create an Emblema HORIZONTAL TIMELINE slide. The body MUST contain a <div class='slide-pad slide-timeline'> with a <div class='track'> wrapping a <div class='line'> and a <div class='points'> of EXACTLY FIVE <div class='point'> children; STATE COUPLING RULE: at most ONE <div class='point now'> (the present moment), all earlier points use <div class='point done'>, all later points use plain <div class='point'>. Without these state classes the dots are blank circles. CRITICAL HEADING RULE: The <h2> MUST be 3-8 words describing THIS specific slide's content, written in the SAME LANGUAGE as the source document (Italian source -> Italian heading, English source -> English heading). Extract the heading from the actual source content -- do NOT invent generic phrases. BANNED <h2> values: 'Timeline', 'Schedule', 'Roadmap', 'Milestones', 'Plan'. Good examples: 'A year of Emblema, milestone by milestone.', 'I cinque snodi del 2025.'. Use this EXACT structure:\n<section>\n  <div class='slide-pad slide-timeline'>\n    <div>\n      <span class='eyebrow'>SHORT EYEBROW</span>\n      <h2>HEADING_DERIVED_FROM_SOURCE_CONTENT</h2>\n      <hr class='divider'>\n    </div>\n    <div class='track'>\n      <div class='line'></div>\n      <div class='points'>\n        <div class='point done'><div class='dot'></div><span class='date'>Q1 2025</span><h4>Milestone</h4><p>1-line description.</p></div>\n        <div class='point done'><div class='dot'></div><span class='date'>Q2 2025</span><h4>Milestone</h4><p>1-line description.</p></div>\n        <div class='point now'><div class='dot'></div><span class='date'>NOW</span><h4>Current focus</h4><p>1-line description.</p></div>\n        <div class='point'><div class='dot'></div><span class='date'>Q4 2025</span><h4>Upcoming</h4><p>1-line description.</p></div>\n        <div class='point'><div class='dot'></div><span class='date'>Q1 2026</span><h4>Upcoming</h4><p>1-line description.</p></div>\n      </div>\n    </div>\n  </div>\n  <aside class='notes'>Speaker notes.</aside>\n</section>\nEXACTLY 5 .point children -- the CSS uses grid-template-columns: repeat(5, 1fr). At most one .now; .done points must come before .now in DOM order; plain .point come after. The <div class='line'> is intentionally empty (CSS-styled track). Anti-pattern to AVOID: vertical <ul><li> timeline (use a different layout for vertical chronology) or 4/6 points (breaks the grid).",203    "emblema-roadmap": "Create an Emblema ROADMAP slide. The body MUST contain a <div class='slide-pad slide-roadmap'> with a <div class='phases'> of EXACTLY THREE <div class='phase'> children: 'Now' (default), 'Next' (.phase--next), and 'Later' (.phase--later); WITHOUT THE .phase--next AND .phase--later modifiers the three phases all render with the same teal header and the time hierarchy is lost. CRITICAL HEADING RULE: The <h2> MUST be 3-8 words describing THIS specific slide's content, written in the SAME LANGUAGE as the source document (Italian source -> Italian heading, English source -> English heading). Extract the heading from the actual source content -- do NOT invent generic phrases. BANNED <h2> values: 'Roadmap', 'Plan', 'Phases', 'Schedule', 'Timeline'. Good examples: 'What ships next, and what comes after.', 'Roadmap del prodotto 2026.'. Use this EXACT structure:\n<section>\n  <div class='slide-pad slide-roadmap'>\n    <div>\n      <span class='eyebrow'>SHORT EYEBROW</span>\n      <h2>HEADING_DERIVED_FROM_SOURCE_CONTENT</h2>\n      <hr class='divider'>\n    </div>\n    <div class='phases'>\n      <div class='phase'><header><h4>Now</h4><span class='when'>Q1 2026</span></header><ul><li>Item 1</li><li>Item 2</li><li>Item 3</li></ul></div>\n      <div class='phase phase--next'><header><h4>Next</h4><span class='when'>Q2 2026</span></header><ul><li>Item 1</li><li>Item 2</li></ul></div>\n      <div class='phase phase--later'><header><h4>Later</h4><span class='when'>H2 2026</span></header><ul><li>Item 1</li><li>Item 2</li></ul></div>\n    </div>\n  </div>\n  <aside class='notes'>Speaker notes.</aside>\n</section>\nPHASE COUPLING RULE: first .phase = default (teal header), second = .phase.phase--next (teal-mid header), third = .phase.phase--later (gray header). The DOM order encodes the time order. Each .phase has a <header> with <h4> + <span class='when'> followed by a <ul>. Anti-pattern to AVOID: 4 phases (breaks the 3-col grid) or omitting the modifier classes (all phases look identical).",204    "emblema-team": "Create an Emblema TEAM GRID slide. The body MUST contain a <div class='slide-pad slide-team'> with a <div class='grid'> of EXACTLY FOUR <div class='person'> children, each with .avatar + h4 + .role + p.bio; WITHOUT THE .person AND .avatar CLASSES the square avatar tiles and team-card layout will not render. CRITICAL HEADING RULE: The <h2> MUST be 3-8 words describing THIS specific slide's content, written in the SAME LANGUAGE as the source document (Italian source -> Italian heading, English source -> English heading). Extract the heading from the actual source content -- do NOT invent generic phrases. BANNED <h2> values: 'Team', 'Our Team', 'Founders', 'People', 'Who We Are'. Good examples: 'Four people, fifteen years of compounding craft.', 'Il team che fa funzionare tutto.'. Use this EXACT structure:\n<section>\n  <div class='slide-pad slide-team'>\n    <div>\n      <span class='eyebrow'>SHORT EYEBROW</span>\n      <h2>HEADING_DERIVED_FROM_SOURCE_CONTENT</h2>\n      <hr class='divider'>\n    </div>\n    <div class='grid'>\n      <div class='person'>\n        <div class='avatar'>FN</div>  <!-- Two-letter initials, OR replace with <img src='...' alt='...'> -->\n        <h4>Full Name</h4>\n        <p class='role'>Role &middot; Department</p>\n        <p class='bio'>1-2 sentence bio derived from source content.</p>\n      </div>\n      <!-- Exactly 4 .person children -->\n    </div>\n  </div>\n  <aside class='notes'>Speaker notes.</aside>\n</section>\nEXACTLY 4 people -- the CSS uses repeat(4, 1fr). The .avatar div renders as a teal-tinted square; if no real photo, place 2-letter initials inside; if a photo is available, use <img> with width/height filling the .avatar. Anti-pattern to AVOID: <ul> of names (loses the grid + avatar) or 5+ people (rows wrap awkwardly).",205    "emblema-testimonial": "Create an Emblema TESTIMONIAL slide. The body MUST contain a <div class='slide-testimonial'> with a <div class='photo'> on the left and a <div> wrapping <p class='quote'> + <p class='who'> + <p class='who-meta'> on the right; WITHOUT THE .quote CLASS the leading large opening-quote pseudo-element will not render. CRITICAL HEADING RULE: The pull quote MUST be 3-8 words describing THIS specific slide's content, written in the SAME LANGUAGE as the source document (Italian source -> Italian heading, English source -> English heading). Extract the heading from the actual source content -- do NOT invent generic phrases. The quote is the headline, NOT a separate <h2>. Use this EXACT structure:\n<section>\n  <div class='slide-testimonial'>\n    <div class='photo'>FN</div>  <!-- Initials, OR replace with <img> -->\n    <div>\n      <p class='quote'>The full quote text from the source.</p>\n      <p class='who'>Speaker Name</p>\n      <p class='who-meta'>Role &middot; Company &middot; Subject</p>\n    </div>\n  </div>\n  <aside class='notes'>Speaker notes.</aside>\n</section>\nDo NOT use <blockquote> or <h2> for the quote -- the <p class='quote'> is what triggers the styled opening-quote pseudo-element and 36px Plex Light styling. The .photo renders as a circular gradient by default; replace with an <img> for a real headshot. Anti-pattern to AVOID: <em>quote</em> wrappers (italics fight the existing styling) or splitting attribution across multiple unstyled <p>.",206    "emblema-logos": "Create an Emblema LOGO CLOUD slide. The body MUST contain a <div class='slide-pad slide-logos'> with a <div class='grid'> of <div class='cell'> children (5 columns); WITHOUT THE .cell WRAPPER the 16:9 logo cells with hairline borders will not render. CRITICAL HEADING RULE: The <h2> MUST be 3-8 words describing THIS specific slide's content, written in the SAME LANGUAGE as the source document (Italian source -> Italian heading, English source -> English heading). Extract the heading from the actual source content -- do NOT invent generic phrases. BANNED <h2> values: 'Logos', 'Customers', 'Partners', 'Clients', 'Brands'. Good examples: 'Teams that quietly run on Emblema.', 'I clienti che ci hanno scelto nel 2025.'. Use this EXACT structure:\n<section>\n  <div class='slide-pad slide-logos'>\n    <div>\n      <span class='eyebrow'>SHORT EYEBROW</span>\n      <h2>HEADING_DERIVED_FROM_SOURCE_CONTENT</h2>\n      <hr class='divider'>\n    </div>\n    <div class='grid'>\n      <div class='cell'>BRAND</div>\n      <!-- 10 or 15 cells (5 per row, 2-3 rows) -->\n    </div>\n  </div>\n  <aside class='notes'>Speaker notes.</aside>\n</section>\nEach .cell contains a brand wordmark as plain text (Plex Sans 600), or replace with an <img>. Use a multiple of 5 cells (10 or 15) for clean rows. Anti-pattern to AVOID: <ul><li>brand</li></ul> (loses the cell border + 16:9 aspect ratio).",207    "emblema-ui": "Create an Emblema UI SHOWCASE slide. The body MUST contain a <div class='slide-ui'> with a <div class='left'> for copy and a <div class='browser'> for the screenshot mockup; WITHOUT THE .browser WRAPPER the chrome bar with traffic-light dots and URL bar will not render. CRITICAL HEADING RULE: The <h2> MUST be 3-8 words describing THIS specific slide's content, written in the SAME LANGUAGE as the source document (Italian source -> Italian heading, English source -> English heading). Extract the heading from the actual source content -- do NOT invent generic phrases. BANNED <h2> values: 'UI', 'Product', 'Screenshot', 'App', 'Interface'. Good examples: 'Inside the workspace -- one panel, one source of truth.', 'Una sola interfaccia per tutto il flusso operativo.'. Use this EXACT structure:\n<section>\n  <div class='slide-ui'>\n    <div class='left'>\n      <span class='eyebrow'>SHORT EYEBROW</span>\n      <h2>HEADING_DERIVED_FROM_SOURCE_CONTENT</h2>\n      <ul>\n        <li>Feature point 1</li>\n        <li>Feature point 2</li>\n        <li>Feature point 3</li>\n        <li>Feature point 4</li>\n      </ul>\n    </div>\n    <div class='browser'>\n      <div class='chrome'>\n        <span></span><span></span><span></span>\n        <div class='url'>app.emblema.ai/workspaces</div>\n      </div>\n      <div class='body'>\n        <!-- Optional: <img> for a real screenshot. Otherwise placeholder rows: -->\n        <div class='ui-row'></div>\n        <div class='ui-row short'></div>\n        <div class='ui-card'><h5>Card label</h5><p>Card body.</p></div>\n      </div>\n    </div>\n  </div>\n  <aside class='notes'>Speaker notes.</aside>\n</section>\nThe three empty <span> elements in .chrome are the traffic-light dots (CSS sizes them). The .url div is the address bar. Inside .body, use empty <div class='ui-row'> for placeholder lines or insert a real <img> screenshot. Anti-pattern to AVOID: full-bleed <img> outside the .browser wrapper (loses the framing chrome).",208    "emblema-features": "Create an Emblema FEATURE GRID slide. The body MUST contain a <div class='slide-pad slide-features'> with a <div class='grid'> of BETWEEN 6 AND 12 <div class='card'> children — prefer multiples of 3 (6, 9, or 12) so the 3-col grid wraps cleanly, each with .icon + h4 + p; WITHOUT THE .card AND .icon WRAPPERS the cards lose their hairline borders and teal-tint icon tiles. CRITICAL HEADING RULE: The <h2> MUST be 3-8 words describing THIS specific slide's content, written in the SAME LANGUAGE as the source document (Italian source -> Italian heading, English source -> English heading). Extract the heading from the actual source content -- do NOT invent generic phrases. BANNED <h2> values: 'Features', 'Capabilities', 'What we do', 'Highlights', 'Functionality'. Good examples: 'Six things Emblema does that others don't.', 'Sei capacita' che ci distinguono.'. Use this EXACT structure:\n<section>\n  <div class='slide-pad slide-features'>\n    <div>\n      <span class='eyebrow'>SHORT EYEBROW</span>\n      <h2>HEADING_DERIVED_FROM_SOURCE_CONTENT</h2>\n      <hr class='divider'>\n    </div>\n    <div class='grid'>\n      <div class='card'>\n        <div class='icon'><svg viewBox='0 0 22 22'><!-- 22x22 icon --></svg></div>\n        <h4>Feature title</h4>\n        <p>1-2 sentences derived from source.</p>\n      </div>\n      <!-- 6 to 12 .card children, prefer multiples of 3 -->\n    </div>\n  </div>\n  <aside class='notes'>Speaker notes.</aside>\n</section>\nUse 6, 9, or 12 cards based on content density: 6 (3x2) for sparse content, 9 (3x3) for medium-dense feature lists, 12 (3x4) for very dense lists. CSS uses grid-template-columns: repeat(3, 1fr) — counts that aren't multiples of 3 (7, 8, 10, 11) leave a partial last row that's acceptable but visually weaker. The .icon div is a teal-tinted square; the inline SVG is OPTIONAL (an empty .icon still renders as the swatch). Anti-pattern to AVOID: fewer than 6 cards (under-fills the layout, leaves the slide looking sparse). Counts that aren't multiples of 3 are acceptable when content genuinely has that many discrete points, but multiples of 3 always look cleaner.",209    "emblema-pricing": "Create an Emblema PRICING TIERS slide. The body MUST contain a <div class='slide-pad slide-pricing'> with a <div class='grid'> of EXACTLY THREE <div class='tier'> children, with EXACTLY ONE marked .tier--featured (the recommended tier); WITHOUT .tier--featured on one card, the lifted shadow + teal CTA + 'Most popular' badge will not render. CRITICAL HEADING RULE: The <h2> MUST be 3-8 words describing THIS specific slide's content, written in the SAME LANGUAGE as the source document (Italian source -> Italian heading, English source -> English heading). Extract the heading from the actual source content -- do NOT invent generic phrases. BANNED <h2> values: 'Pricing', 'Plans', 'Tiers', 'Subscriptions', 'Cost'. Good examples: 'Pricing for teams of every size.', 'I tre piani di Emblema.'. Use this EXACT structure:\n<section>\n  <div class='slide-pad slide-pricing'>\n    <div>\n      <span class='eyebrow'>SHORT EYEBROW</span>\n      <h2>HEADING_DERIVED_FROM_SOURCE_CONTENT</h2>\n      <hr class='divider'>\n    </div>\n    <div class='grid'>\n      <div class='tier'>\n        <h4>Tier name</h4>\n        <div class='price'>&euro;X<span class='per'>/mo</span></div>\n        <p class='desc'>Short description of who it's for.</p>\n        <ul class='feats'><li>Feature 1</li><li>Feature 2</li></ul>\n        <a class='cta'>Choose plan</a>\n      </div>\n      <div class='tier tier--featured'>\n        <span class='badge'>Most popular</span>\n        <h4>Tier name</h4>\n        <div class='price'>&euro;Y<span class='per'>/mo</span></div>\n        <p class='desc'>Description.</p>\n        <ul class='feats'><li>Feature 1</li><li>Feature 2</li><li>Feature 3</li></ul>\n        <a class='cta'>Choose plan</a>\n      </div>\n      <div class='tier'>\n        <!-- Same structure as tier 1 -->\n      </div>\n    </div>\n  </div>\n  <aside class='notes'>Speaker notes.</aside>\n</section>\nTIER COUPLING RULE: EXACTLY ONE .tier--featured (typically the middle one). The .badge span ONLY appears inside .tier--featured. Each tier has h4 (label) + .price (with .per for the period suffix) + .desc + ul.feats + a.cta. Anti-pattern to AVOID: zero or two .tier--featured (visual hierarchy collapses) or 4 tiers (breaks the 3-col grid).",210    "emblema-question": "Create an Emblema BIG QUESTION slide. The body MUST contain a <div class='slide-question'> with a <p class='q'> for the question; the CSS pseudo-element appends a TEAL '?' automatically -- do NOT include the question mark in the text. CRITICAL HEADING RULE: The question text MUST be 3-8 words describing THIS specific slide's content, written in the SAME LANGUAGE as the source document (Italian source -> Italian heading, English source -> English heading). Extract the heading from the actual source content -- do NOT invent generic phrases. Use this EXACT structure:\n<section>\n  <div class='slide-question'>\n    <p class='q'>What if the smallest team did the most thoughtful work</p>\n    <p class='hint'>Optional one-line hint or framing for the audience.</p>\n  </div>\n  <aside class='notes'>Speaker notes.</aside>\n</section>\nThe <p class='q'> renders at 96px Plex Light. The CSS adds a teal '?' via ::after -- so the text inside <p class='q'> must NOT end with a question mark (otherwise you get two: '??'). The <p class='hint'> is OPTIONAL and renders smaller and tracked-out below. Anti-pattern to AVOID: <h1> or <h2> for the question text -- loses the styled '?' pseudo-element.",211    "emblema-definition": "Create an Emblema DEFINITION slide. The body MUST contain a <div class='slide-definition'> with a <div class='term'> on the left (with optional <span class='ipa'>) and a body block on the right with .pos + .meaning + .example; WITHOUT THE .term AND .meaning CLASSES the dictionary-style typography and teal vertical rule will not render. CRITICAL HEADING RULE: The term MUST be 3-8 words describing THIS specific slide's content, written in the SAME LANGUAGE as the source document (Italian source -> Italian heading, English source -> English heading). Extract the heading from the actual source content -- do NOT invent generic phrases. Use this EXACT structure:\n<section>\n  <div class='slide-definition'>\n    <div class='term'>\n      Word or phrase\n      <span class='ipa'>/&aelig;Ipa\u02c8not&aelig;Si&Eta;n/</span>\n    </div>\n    <div>\n      <p class='pos'>Part of Speech</p>\n      <p class='meaning'>Plain-language definition derived from source.</p>\n      <p class='example'>An italic example sentence using the term.</p>\n    </div>\n  </div>\n  <aside class='notes'>Speaker notes.</aside>\n</section>\nThe <div class='term'> sits left of a teal vertical rule (CSS-applied). The <span class='ipa'> is OPTIONAL pronunciation; omit if the source doesn't include it. The .pos is the small uppercase part-of-speech label. Anti-pattern to AVOID: <dl><dt><dd> (semantically tempting but the styling is wrong) or wrapping everything in a single <p>.",212    "emblema-code": "Create an Emblema CODE slide. The body MUST contain a <div class='slide-code'> with a <div> for copy on the left and a <pre> on the right; WITHOUT <pre> THE DARK SYNTAX BACKGROUND AND IBM PLEX MONO STYLING will not render -- the theme styles `.slide-code pre` specifically. CRITICAL HEADING RULE: The <h2> MUST be 3-8 words describing THIS specific slide's content, written in the SAME LANGUAGE as the source document (Italian source -> Italian heading, English source -> English heading). Extract the heading from the actual source content -- do NOT invent generic phrases. BANNED <h2> values: 'Code', 'Snippet', 'Example', 'Programming'. Use this EXACT structure:\n<section>\n  <div class='slide-code'>\n    <div>\n      <span class='eyebrow'>SHORT EYEBROW</span>\n      <h2>HEADING_DERIVED_FROM_SOURCE_CONTENT</h2>\n      <p>1-2 sentence framing of what the code does.</p>\n    </div>\n    <pre>\n<span class='c'># Comment</span>\n<span class='k'>def</span> <span class='f'>function_name</span>(<span class='n'>arg</span>):\n    <span class='k'>return</span> <span class='s'>'string'</span>\n    </pre>\n  </div>\n  <aside class='notes'>Speaker notes.</aside>\n</section>\nUse the theme's syntax-color spans inside <pre>: .k = keyword (cyan), .s = string (yellow), .c = comment (grey italic), .f = function name (teal), .n = identifier (white). The <pre>::before pseudo-element shows a 'python' label in the top-right corner -- this is hardcoded in the theme; if you need a different language, the label still says 'python' (limitation of the theme; do not try to override). Indent code with spaces, not tabs. Anti-pattern to AVOID: emitting `<script>` (composer strips it) or styling code with inline color (bypasses the theme).",213    "emblema-closing": "Create an Emblema CLOSING slide. The body MUST contain a <div class='slide-closing'> with a <div class='left'> and a <div class='right'>; WITHOUT BOTH the teal split layout, gradient right panel, and contact-pair layout will not render. CRITICAL HEADING RULE: The <h1> MUST be 3-8 words describing THIS specific slide's content, written in the SAME LANGUAGE as the source document (Italian source -> Italian heading, English source -> English heading). Extract the heading from the actual source content -- do NOT invent generic phrases. BANNED <h1> values: 'Thank you', 'Questions?', 'The end' (use them ONLY if they're the literal close in the source language and tone). Good examples: 'Let's build something thoughtful together.', 'Costruiamo qualcosa di importante.'. Use this EXACT structure:\n<section>\n  <div class='slide-closing'>\n    <div class='left'>\n      <span class='eyebrow'>SHORT EYEBROW</span>\n      <h1>Closing headline derived from source.</h1>\n      <dl class='contacts'>\n        <div><dt>Email</dt><dd>hello@example.com</dd></div>\n        <div><dt>Web</dt><dd>example.com</dd></div>\n        <div><dt>Phone</dt><dd>+39 02 1234 5678</dd></div>\n        <div><dt>Address</dt><dd>City, Country</dd></div>\n      </dl>\n    </div>\n    <div class='right'></div>\n  </div>\n  <aside class='notes'>Closing slide.</aside>\n</section>\nThe <div class='right'> is intentionally empty -- the theme renders the radial gradient via CSS. The <dl class='contacts'> uses the same div-per-pair wrapper as the spec sheet. Up to 4 contact pairs (CSS uses 2x2 grid). Anti-pattern to AVOID: putting contact info inline as <p> rows -- breaks the styled key:value alignment.",214}215216217# Output-language directive (language-persistence workstream). Values are218# platform locale codes; legacy full names are accepted via the allowlist.219# Anything else (wired upstream output, free-form strings) falls back to220# auto: the value is interpolated into the system prompt, so unknown221# strings must never pass through.222LANGUAGE_NAMES = {223    "de": "German", "en": "English", "es": "Spanish", "fr": "French",224    "it": "Italian", "ja": "Japanese", "ko": "Korean", "nl": "Dutch",225    "pt": "Portuguese", "ru": "Russian", "zh": "Chinese",226}227228229def resolve_language_name(language):230    """Full display name for an allowlisted language value, else None."""231    if not isinstance(language, str):232        return None233    value = language.strip()234    if not value or value == "auto":235        return None236    if value in LANGUAGE_NAMES:237        return LANGUAGE_NAMES[value]238    if value in LANGUAGE_NAMES.values():239        return value240    print(f"[language] unrecognized value {value!r} ignored - using auto", file=sys.stderr)241    return None242243244def language_directive(language):245    """System-prompt suffix forcing the output language; '' when auto."""246    name = resolve_language_name(language)247    if not name:248        return ""249    return (250        f"\n\nOUTPUT LANGUAGE: {name}. All slide text — headings, body copy, "251        f"table/chart labels, and speaker notes — MUST be written in {name}. "252        "This OVERRIDES any 'same language as the source document' rule in the "253        "layout instructions above. Keep proper nouns, product names, and "254        "verbatim quotes in their original language."255    )256257258def build_layout_instruction(template_name):259    """Build additional system prompt instruction for the selected layout template."""260    if not template_name or template_name == "auto":261        return ""262    instruction = TEMPLATE_INSTRUCTIONS.get(template_name, "")263    if instruction:264        result = f"\n\nIMPORTANT LAYOUT INSTRUCTION: The user selected the '{template_name}' layout. {instruction}\nFollow this layout pattern precisely while adapting the content."265        if template_name.startswith("marina-") or template_name.startswith("emblema-"):266            result += "\n\nANIMATION: Do NOT add class='fragment' to any element. The entire slide MUST appear at once — no staggered reveal. Arrow keys move between slides, not between items within a slide."267        return result268    return f"\n\nThe user selected the '{template_name}' layout. Use this layout pattern."269270271# Tags that have no closing tag in HTML — they never go on the open-tag stack.272_VOID_TAGS = frozenset({273    "area", "base", "br", "col", "embed", "hr", "img", "input",274    "link", "meta", "param", "source", "track", "wbr",275})276277# Tags whose closing tag is optional in HTML — leftover open ones at end-of-parse278# are tolerated (browsers auto-close them) so we don't fail otherwise-valid slides.279_OPTIONAL_CLOSE_TAGS = frozenset({280    "p", "li", "td", "th", "tr", "thead", "tbody", "tfoot",281    "option", "dt", "dd", "colgroup", "caption",282})283284# Literal placeholder tokens from the prompt's layout templates. If any survive285# into the output, the model echoed the template scaffold or leaked its scratch286# work instead of producing a real slide — treat that as invalid so we retry.287_PLACEHOLDER_TOKENS = (288    "HEADING_DERIVED_FROM_SOURCE_CONTENT",289    "HEADING_DERIVED_FROM",290    "SHORT EYEBROW",291    "SHORT SLIDE TITLE",292    "...code...",293)294295296class _SlideHtmlValidator(HTMLParser):297    """Parse a slide candidate and record structural problems.298299    A valid slide is EXACTLY ONE well-formed top-level <section> element with no300    stray text or extra elements outside it and no unclosed structural tags.301    """302303    def __init__(self):304        super().__init__(convert_charrefs=True)305        self.stack = []306        self.root_tag = None307        self.top_level_starts = 0308        self.text_outside = False309        self.parse_error = None310311    def _note_start(self, tag):312        if len(self.stack) == 0:313            self.top_level_starts += 1314            if self.root_tag is None:315                self.root_tag = tag316317    def handle_starttag(self, tag, attrs):318        self._note_start(tag)319        if tag not in _VOID_TAGS:320            self.stack.append(tag)321322    def handle_startendtag(self, tag, attrs):323        # Self-closing tag, e.g. <img/> or <br/> — counts toward top level but324        # never goes on the open-tag stack.325        self._note_start(tag)326327    def handle_endtag(self, tag):328        if tag in _VOID_TAGS:329            return330        if tag not in self.stack:331            # Closing tag with no matching open tag → malformed.332            if self.parse_error is None:333                self.parse_error = f"stray closing tag </{tag}>"334            return335        # Pop down to the matching open tag. Optional-close tags (<li>, <p>, …)336        # left open in between are fine — browsers auto-close them. But a337        # structural tag (<div>, <ul>, …) being closed implicitly by an338        # ancestor's end tag means it was never closed → malformed nesting.339        while self.stack and self.stack[-1] != tag:340            popped = self.stack.pop()341            if popped not in _OPTIONAL_CLOSE_TAGS and self.parse_error is None:342                self.parse_error = f"unclosed <{popped}> before </{tag}>"343        if self.stack:344            self.stack.pop()345346    def handle_data(self, data):347        if len(self.stack) == 0 and data.strip():348            self.text_outside = True349350    def error(self, message):  # pragma: no cover - legacy HTMLParser hook351        if self.parse_error is None:352            self.parse_error = message353354355def validate_slide_html(html):356    """Validate that `html` is a single, well-formed Reveal.js <section>.357358    Returns (is_valid, reason). `reason` is empty when valid.359    """360    if not html or not html.strip():361        return False, "empty output"362363    stripped = html.strip()364365    for token in _PLACEHOLDER_TOKENS:366        if token in stripped:367            return False, f"contains unfilled template placeholder '{token}'"368369    parser = _SlideHtmlValidator()370    try:371        parser.feed(stripped)372        parser.close()373    except Exception as exc:  # noqa: BLE001 - any parse failure means "invalid"374        return False, f"unparseable HTML: {exc}"375376    if parser.parse_error:377        return False, parser.parse_error378    if parser.root_tag != "section":379        return False, f"top-level element is <{parser.root_tag}>, expected <section>"380    if parser.top_level_starts != 1:381        return False, (382            f"expected exactly one top-level <section>, found "383            f"{parser.top_level_starts} top-level elements (leaked reasoning or "384            f"multiple draft slides)"385        )386    if parser.text_outside:387        return False, "stray text outside the <section> (leaked reasoning or prose)"388389    unclosed = [t for t in parser.stack if t not in _OPTIONAL_CLOSE_TAGS]390    if unclosed:391        return False, f"unclosed tag(s): {', '.join(unclosed)}"392393    return True, ""394395396def _strip_code_fences(text):397    text = re.sub(r"^```(?:html)?\s*", "", text, flags=re.MULTILINE)398    text = re.sub(r"```\s*$", "", text, flags=re.MULTILINE)399    return text.strip()400401402def extract_section(html: str) -> str:403    # Extract the <section>...</section> from LLM output, handling markdown404    # fences and reasoning-model output that interleaves prose with one or more405    # draft sections.406    html = _strip_code_fences(html)407408    # NON-greedy so reasoning prose between draft sections is NOT swallowed by a409    # single greedy first-open-to-last-close match (the bug that produced decks410    # full of leaked scratch work and blank renders).411    candidates = re.findall(r"<section\b[\s\S]*?</section>", html, re.IGNORECASE)412    if candidates:413        # Reasoning models put the final answer last — prefer the last candidate414        # that validates; otherwise return the last one and let the caller's415        # retry loop catch the invalid output.416        for candidate in reversed(candidates):417            is_valid, _ = validate_slide_html(candidate)418            if is_valid:419                return candidate.strip()420        return candidates[-1].strip()421422    # No <section> at all — return the raw text so validation fails and the423    # caller retries instead of shipping a wrapped blob of prose.424    return html425426427def _fix_flex_styles(html):428    # Ensure flex children have min-width:0 to prevent overflow. LLMs output429    # flex:1 without min-width:0, causing text to expand and hide images.430    result = []431    i = 0432    tag = 'style="'433    while i < len(html):434        pos = html.find(tag, i)435        if pos == -1:436            # Also try single quotes437            pos2 = html.find("style='", i)438            if pos2 == -1:439                result.append(html[i:])440                break441            pos = pos2442            tag = "style='"443            q = "'"444        else:445            q = '"'446        result.append(html[i:pos])447        # Find end of style attribute448        start = pos + len('style=') + 1449        end = html.find(q, start)450        if end == -1:451            result.append(html[pos:])452            break453        style_val = html[start:end]454        # Fix: add min-width:0 if has flex:1 but not min-width455        if 'flex:' in style_val and '1' in style_val.split('flex:')[-1][:3] and 'min-width' not in style_val:456            style_val = style_val.rstrip(';') + ';min-width:0;overflow:hidden'457        result.append(f'style={q}{style_val}{q}')458        i = end + 1459        tag = 'style="'460    return ''.join(result)461462463def main():464    try:465        execution_input = json.loads(sys.stdin.read())466        inputs = execution_input.get("inputs", {})467468        content = inputs.get("content")469        instruction = inputs.get("instruction")470        image_filename = inputs.get("image", "")471        template_name = inputs.get("template_name", "auto")472        llm_model_id = inputs.get("llmModelId")473        language = inputs.get("language", "auto")474475        if not content:476            raise ValueError("Required input 'content' not provided")477        if not instruction:478            raise ValueError("Required input 'instruction' not provided")479        if not llm_model_id:480            raise ValueError("Required input 'llmModelId' not provided")481482        # Read image and convert to base64 data URI if provided.483        # os/pathlib are lint-blocked in new-format nodes, so probe the input by484        # attempting to open it (the executor mounts inputs under /data/input).485        image_data_uri = ""486        if image_filename:487            image_path = f"/data/input/{image_filename}"488            try:489                with open(image_path, "rb") as f:490                    b64 = base64.b64encode(f.read()).decode("ascii")491                mime = mimetypes.guess_type(image_filename)[0] or "image/png"492                image_data_uri = f"data:{mime};base64,{b64}"493                print(f"Image loaded: {image_filename} ({len(b64)} base64 chars)", file=sys.stderr)494            except FileNotFoundError:495                print(f"Image not found: {image_path}", file=sys.stderr)496497        print(f"Generating slide with model_id: {llm_model_id}", file=sys.stderr)498        print(f"Content length: {len(content)} chars", file=sys.stderr)499        print(f"Instruction: {instruction[:100]}...", file=sys.stderr)500        print(f"Layout template: {template_name}", file=sys.stderr)501502        # Build system prompt with optional layout instruction503        system_prompt = SYSTEM_PROMPT + build_layout_instruction(template_name)504        system_prompt += language_directive(language)505506        # If image provided, add instruction to use {{IMAGE}} placeholder507        if image_data_uri:508            system_prompt += (509                "\n\nIMAGE INPUT: The user has provided an image. "510                "Use {{IMAGE}} as the exact src attribute value for the <img> tag. "511                "CRITICAL: Always wrap the <img> inside a <div style='flex:1;min-width:0'> when using flex layout. "512                "Never place <img> as a direct flex child — it will overflow. "513                "Example: <div style='flex:1;min-width:0'><img src='{{IMAGE}}' alt='description' style='width:100%;border-radius:8px'></div>. "514                "Do NOT use picsum.photos — use {{IMAGE}} instead."515            )516517        user_message = (518            f"<instruction>{instruction}</instruction>\n\n"519            f"<source_content>\n{content}\n</source_content>"520        )521522        base_messages = [523            {"role": "system", "content": system_prompt},524            {"role": "user", "content": user_message},525        ]526527        # Generate the slide, validating that the model returned a single528        # well-formed <section>. Reasoning models sometimes leak scratch work or529        # emit several draft sections, which produced decks that rendered blank530        # (malformed HTML). Retry up to MAX_ATTEMPTS, nudging the model to fix531        # the specific problem, then fail loudly rather than emit bad HTML.532        MAX_ATTEMPTS = 3533        messages = list(base_messages)534        slide_html = None535        last_reason = ""536        for attempt in range(1, MAX_ATTEMPTS + 1):537            print(f"Slide generation attempt {attempt}/{MAX_ATTEMPTS}", file=sys.stderr)538            # thinking=False: reasoning models leak <think> scratch work + draft539            # sections into the HTML, which breaks the slide (blank decks) and540            # forces the retry loop below. Suppressing reasoning removes the541            # cause — cleaner single-<section> output, fewer/no retries.542            raw_output = Gais.llm.chat(543                messages, model_id=llm_model_id, temperature=0.3, thinking=False544            ).text545            candidate = _fix_flex_styles(extract_section(raw_output))546            is_valid, reason = validate_slide_html(candidate)547            if is_valid:548                slide_html = candidate549                print(f"Attempt {attempt}: valid slide HTML", file=sys.stderr)550                break551            last_reason = reason552            print(f"Attempt {attempt}: invalid slide HTML — {reason}", file=sys.stderr)553            # Add a corrective instruction for the next attempt.554            messages = base_messages + [555                {556                    "role": "user",557                    "content": (558                        f"Your previous response was not valid slide HTML: {reason}. "559                        "Respond with EXACTLY ONE well-formed <section>...</section> "560                        "element and NOTHING else: no reasoning, no explanation, no "561                        "markdown code fences, no extra <section> blocks, and every "562                        "tag properly closed."563                    ),564                }565            ]566567        if slide_html is None:568            raise ValueError(569                f"Slide generator could not produce valid HTML after {MAX_ATTEMPTS} "570                f"attempts. Last validation error: {last_reason}"571            )572573        # Replace {{IMAGE}} placeholder with actual base64 data URI574        if image_data_uri and "{{IMAGE}}" in slide_html:575            slide_html = slide_html.replace("{{IMAGE}}", image_data_uri)576            print("Replaced {{IMAGE}} placeholder with base64 data URI", file=sys.stderr)577578        print(f"Generated slide: {len(slide_html)} chars", file=sys.stderr)579580        output = {"slide_html": slide_html}581        print(json.dumps(output))582583    except Exception as e:584        error_output = {585            "error": str(e),586            "errorType": type(e).__name__,587            "traceback": traceback.format_exc(),588        }589        print(json.dumps(error_output), file=sys.stderr)590        sys.exit(1)591592593if __name__ == "__main__":594    main()

$ git log --oneline

v1.10.0
HEAD
2026-08-18
v1.9.02026-06-27
v1.8.12026-06-26
v1.8.02026-06-24
v1.6.72026-05-22
v1.6.62026-05-19
v1.6.32026-05-19
v1.6.22026-05-19
v1.5.02026-05-07
v1.3.12026-04-23
v1.1.02026-04-07
v1.0.02026-03-29