/* ─────────────────────────────────────────────
   INOCULATE — main site app.
   One specimen with operating-table interactions,
   transitioning into wire-style narrative.
   ───────────────────────────────────────────── */

const SPECIMENS = window.SPECIMENS;

/* Zones over the screenshot — defined as % of the card.
   Each specimen gets its own zone layout because real
   screenshots vary in composition. */
const SCREENSHOT_MAP = {
  'spec-014': 'framer',
  'spec-011': 'linear',
  'spec-009': 'stripe',
  'spec-007': 'vercel',
  'spec-005': 'notion',
  'spec-002': 'raycast'
};

/* Zone dimensions calibrated to actual screenshot heights:
   framer=12555px, linear=10781px, stripe=14739px,
   vercel=5918px,  notion=7574px,  raycast=15626px   */
const Z = (id, top, left, width, height, tagPos, label, payload) =>
  ({ id, top, left, width, height, tagPos, label, payload });
const k = s => `<span class="k">"${s}"</span>`;
const sv = s => `<span class="s">"${s}"</span>`;
const nv = n => `<span class="n">${n}</span>`;
const kv = (key, val, isNum) => `${k(key)}: ${isNum ? nv(val) : sv(val)}`;

const ZONE_LAYOUTS = {
  'spec-014': [ /* framer.com — 12555px tall */
    Z('nav-bg',       '0%',    '0%',   '100%', '0.44%', 'bottom', 'nav · background #000000 no-border',         `${k('background')}: ${sv('#000000')}, ${k('border')}: ${sv('none')}, ${k('backdropFilter')}: ${sv('none')}`),
    Z('f-mark',       '0%',    '1.5%', '5%',   '0.44%', 'bottom', 'wordmark · "F" 600w -0.04em 22px',           `${k('fontWeight')}: ${nv(600)}, ${k('letterSpacing')}: ${sv('-0.04em')}, ${k('fontSize')}: ${sv('22px')}`),
    Z('nav-links',    '0%',    '28%',  '44%',  '0.44%', 'bottom', 'nav links · 500w 0.45 opacity 28px gap',     `${k('fontWeight')}: ${nv(500)}, ${k('opacity')}: ${nv(0.45)}, ${k('gap')}: ${sv('28px')}`),
    Z('nav-cta',      '0%',    '83%',  '13%',  '0.44%', 'bottom', 'nav CTA · pill 100px radius dark fill',      `${k('borderRadius')}: ${sv('100px')}, ${k('background')}: ${sv('#fff')}, ${k('color')}: ${sv('#000')}`),
    Z('announcement', '0.44%', '22%',  '56%',  '0.4%',  'bottom', 'announcement · pill 8px radius 0.08 opacity bg', `${k('borderRadius')}: ${sv('8px')}, ${k('background')}: ${sv('rgba(255,255,255,0.08)')}, ${k('fontSize')}: ${sv('13px')}`),
    Z('hero-surface', '0.84%', '0%',   '100%', '6.3%',  'bottom', 'ANTI · hero surface zero gradient pure black', `${k('ANTI')}: ${sv('hero gradients')}, ${k('background')}: ${sv('#000000')}, ${k('gradient')}: ${sv('none')}`),
    Z('hero-headline','1.4%',  '8%',   '84%',  '2.0%',  'bottom', 'headline · Inter 800w -0.04em clamp(56,6vw,96px)', `${k('fontWeight')}: ${nv(800)}, ${k('letterSpacing')}: ${sv('-0.04em')}, ${k('fontSize')}: ${sv('clamp(56px,6vw,96px)')}`),
    Z('hero-sub',     '3.4%',  '20%',  '60%',  '1.1%',  'bottom', 'subtext · 18px 0.65 opacity lineHeight 1.6', `${k('fontSize')}: ${sv('18px')}, ${k('opacity')}: ${nv(0.65)}, ${k('lineHeight')}: ${nv(1.6)}`),
    Z('cta-pair',     '4.5%',  '28%',  '44%',  '0.8%',  'top',    'CTA pair · pill primary + ghost secondary',  `${k('MUST')}: ${sv('pill shape')}, ${k('primary')}: ${sv('white fill')}, ${k('secondary')}: ${sv('1px border ghost')}`),
    Z('section-label','7.2%',  '3%',   '30%',  '0.5%',  'bottom', 'section eyebrow · 11px 600w 0.22em caps',   `${k('fontSize')}: ${sv('11px')}, ${k('fontWeight')}: ${nv(600)}, ${k('letterSpacing')}: ${sv('0.22em')}, ${k('textTransform')}: ${sv('uppercase')}`),
    Z('template-grid','7.7%',  '2%',   '96%',  '6.0%',  'top',    'template gallery · no-border 6px card radius masonry', `${k('borderRadius')}: ${sv('6px')}, ${k('border')}: ${sv('none')}, ${k('boxShadow')}: ${sv('none')}, ${k('layout')}: ${sv('masonry')}`),
    Z('card-radius',  '8.5%',  '2%',   '30%',  '2.5%',  'bottom', 'card · 6px radius zero box-shadow hover scale', `${k('borderRadius')}: ${sv('6px')}, ${k('boxShadow')}: ${sv('none')}, ${k('hoverTransform')}: ${sv('scale(1.02)')}`),
    Z('logo-strip',   '13.3%', '5%',   '90%',  '1.0%',  'bottom', 'logo strip · white 0.35 opacity monochrome', `${k('filter')}: ${sv('grayscale(1)')}, ${k('opacity')}: ${nv(0.35)}, ${k('color')}: ${sv('#ffffff')}`),
    Z('feat-eyebrow', '14.3%', '3%',   '25%',  '0.5%',  'bottom', 'feature tag · 12px 600w caps no icon',       `${k('fontSize')}: ${sv('12px')}, ${k('fontWeight')}: ${nv(600)}, ${k('textTransform')}: ${sv('uppercase')}, ${k('icon')}: ${sv('none')}`),
    Z('feat-h2',      '14.8%', '3%',   '60%',  '1.1%',  'bottom', 'feature H2 · 700w -0.03em clamp(32,3.5vw,52px)', `${k('fontWeight')}: ${nv(700)}, ${k('letterSpacing')}: ${sv('-0.03em')}, ${k('fontSize')}: ${sv('clamp(32px,3.5vw,52px)')}`),
    Z('feat-body',    '15.9%', '3%',   '50%',  '1.1%',  'bottom', 'feature copy · 16px 0.65 opacity lh 1.6',   `${k('fontSize')}: ${sv('16px')}, ${k('opacity')}: ${nv(0.65)}, ${k('lineHeight')}: ${nv(1.6)}`),
    Z('product-insert','17.0%','10%',  '80%',  '4.8%',  'bottom', 'product insert · dark chrome dark bg surface', `${k('background')}: ${sv('#111')}, ${k('borderRadius')}: ${sv('8px')}, ${k('border')}: ${sv('1px solid rgba(255,255,255,0.08)')}`),
    Z('tab-nav',      '21.8%', '3%',   '50%',  '0.9%',  'bottom', 'tab nav · underline active state no bg fill', `${k('activeIndicator')}: ${sv('border-bottom 2px')}, ${k('background')}: ${sv('none')}, ${k('tabStyle')}: ${sv('underline-only')}`),
    Z('canvas-dark',  '22.7%', '3%',   '94%',  '5.8%',  'bottom', 'canvas surface · #1A1A1A icon-only minimal', `${k('background')}: ${sv('#1A1A1A')}, ${k('iconStyle')}: ${sv('icon-only no labels')}, ${k('toolbarBorder')}: ${sv('none')}`),
    Z('testimonial',  '43.0%', '5%',   '90%',  '6.0%',  'bottom', 'testimonials · no card pull-quote layout',   `${k('cardBackground')}: ${sv('none')}, ${k('quoteStyle')}: ${sv('pull-quote')}, ${k('ANTI')}: ${sv('testimonial cards')}`),
    Z('pricing-h2',   '70.0%', '10%',  '80%',  '1.2%',  'bottom', 'pricing heading · 700w 48px centered',       `${k('fontWeight')}: ${nv(700)}, ${k('fontSize')}: ${sv('48px')}, ${k('textAlign')}: ${sv('center')}`),
    Z('plan-grid',    '71.2%', '3%',   '94%',  '5.5%',  'top',    'plan grid · 3-col white surface signal on Pro', `${k('columns')}: ${nv(3)}, ${k('background')}: ${sv('#ffffff')}, ${k('proTier')}: ${sv('signal accent border')}`),
    Z('pro-cta',      '74.5%', '55%',  '38%',  '1.5%',  'top',    'Pro CTA · signal fill pill full-width',      `${k('background')}: ${sv('#0066ff')}, ${k('borderRadius')}: ${sv('100px')}, ${k('width')}: ${sv('100%')}`),
    Z('free-tier',    '74.5%', '7%',   '38%',  '1.5%',  'top',    'ANTI · free tier outline-only no gradient',  `${k('ANTI')}: ${sv('filled free CTA')}, ${k('background')}: ${sv('transparent')}, ${k('border')}: ${sv('1px solid currentColor')}`),
    Z('faq',          '79.0%', '10%',  '80%',  '6.5%',  'bottom', 'FAQ · hairline dividers 0.1 opacity no icons', `${k('divider')}: ${sv('1px solid rgba(0,0,0,0.1)')}, ${k('icon')}: ${sv('none')}, ${k('accordionStyle')}: ${sv('text-only')}`),
    Z('footer-cta',   '85.5%', '15%',  '70%',  '4.0%',  'bottom', 'footer CTA · email input inline no box-shadow', `${k('inputBorder')}: ${sv('1px solid rgba(255,255,255,0.2)')}, ${k('boxShadow')}: ${sv('none')}, ${k('layout')}: ${sv('inline row')}`),
    Z('footer',       '89.5%', '0%',   '100%', '10.5%', 'top',    'footer · 5-col link grid ANTI social icons', `${k('columns')}: ${nv(5)}, ${k('ANTI')}: ${sv('social icons')}, ${k('background')}: ${sv('#000000')}`)
  ],
  'spec-011': [ /* linear.app — 10781px tall */
    Z('nav-glass',    '0%',    '0%',   '100%', '0.51%', 'bottom', 'nav · glass blur(12px) rgba(15,16,24,0.6)', `${k('backdropFilter')}: ${sv('blur(12px)')}, ${k('background')}: ${sv('rgba(15,16,24,0.6)')}, ${k('border')}: ${sv('none')}`),
    Z('gradient-mark','0%',    '2%',   '4%',   '0.51%', 'bottom', 'mark · gradient square 135deg #5E6AD2→#963CF5', `${k('background')}: ${sv('linear-gradient(135deg,#5E6AD2,#963CF5)')}, ${k('borderRadius')}: ${sv('4px')}, ${k('shape')}: ${sv('square')}`),
    Z('nav-links-dim','0%',    '30%',  '40%',  '0.51%', 'bottom', 'nav links · 500w opacity 0.55',              `${k('fontWeight')}: ${nv(500)}, ${k('opacity')}: ${nv(0.55)}, ${k('hoverOpacity')}: ${nv(1)}`),
    Z('nav-cta-sign', '0%',    '82%',  '14%',  '0.51%', 'bottom', 'nav CTA · #5E6AD2 6px radius',               `${k('background')}: ${sv('#5E6AD2')}, ${k('borderRadius')}: ${sv('6px')}, ${k('border')}: ${sv('none')}`),
    Z('announcement', '0.51%', '24%',  '52%',  '0.46%', 'bottom', 'announcement · rgba(94,106,210,0.15) pill',  `${k('background')}: ${sv('rgba(94,106,210,0.15)')}, ${k('borderRadius')}: ${sv('100px')}, ${k('fontSize')}: ${sv('13px')}`),
    Z('hero-headline','0.97%', '10%',  '80%',  '2.8%',  'bottom', 'headline · 700w -0.03em clamp(40,5vw,64px)', `${k('fontWeight')}: ${nv(700)}, ${k('letterSpacing')}: ${sv('-0.03em')}, ${k('fontSize')}: ${sv('clamp(40px,5vw,64px)')}`),
    Z('hero-sub',     '3.77%', '20%',  '60%',  '1.1%',  'bottom', 'subtext · 0.55 opacity 18px lineHeight 1.5', `${k('opacity')}: ${nv(0.55)}, ${k('fontSize')}: ${sv('18px')}, ${k('lineHeight')}: ${nv(1.5)}`),
    Z('cta-pair',     '4.87%', '34%',  '32%',  '0.93%', 'top',    'CTA · signal fill + ghost outline pair',     `${k('primary')}: ${sv('#5E6AD2 fill')}, ${k('secondary')}: ${sv('ghost 1px border')}, ${k('gap')}: ${sv('12px')}`),
    Z('logo-row',     '6.0%',  '5%',   '90%',  '1.3%',  'bottom', 'logos · 0.35 opacity grayscale centered',   `${k('opacity')}: ${nv(0.35)}, ${k('filter')}: ${sv('grayscale(1)')}, ${k('textTransform')}: ${sv('uppercase')}`),
    Z('feat-grid',    '7.3%',  '3%',   '94%',  '6.5%',  'top',    'feature grid · 3-col mono labels no border', `${k('columns')}: ${nv(3)}, ${k('border')}: ${sv('none')}, ${k('labelStyle')}: ${sv('monospace caps')}`),
    Z('feat-cell-div','8.0%',  '3%',   '30%',  '5.8%',  'bottom', 'feature cell · 1px divider no icon',        `${k('divider')}: ${sv('1px solid rgba(255,255,255,0.08)')}, ${k('icon')}: ${sv('none')}, ${k('background')}: ${sv('none')}`),
    Z('feat-h2',      '13.8%', '3%',   '60%',  '1.1%',  'bottom', 'feature H2 · 700w -0.025em dark',           `${k('fontWeight')}: ${nv(700)}, ${k('letterSpacing')}: ${sv('-0.025em')}, ${k('color')}: ${sv('#ffffff')}`),
    Z('app-insert',   '14.9%', '5%',   '90%',  '8.5%',  'bottom', 'app insert · instant-feedback ANTI slide-in', `${k('interaction')}: ${sv('instant-feedback')}, ${k('ANTI')}: ${sv('slide-in modal')}, ${k('motionArchetype')}: ${sv('snap')}`),
    Z('roadmap',      '23.4%', '3%',   '94%',  '8.5%',  'bottom', 'roadmap · timeline dots 1px connector line', `${k('dotStyle')}: ${sv('4px circle')}, ${k('connector')}: ${sv('1px dashed rgba(255,255,255,0.2)')}, ${k('background')}: ${sv('none')}`),
    Z('cycles',       '31.9%', '3%',   '94%',  '8.5%',  'bottom', 'cycles · kanban tiles 1px grid dark surface', `${k('tileBackground')}: ${sv('rgba(255,255,255,0.04)')}, ${k('tileBorder')}: ${sv('1px solid rgba(255,255,255,0.08)')}, ${k('borderRadius')}: ${sv('6px')}`),
    Z('integrations', '40.4%', '3%',   '94%',  '8.5%',  'bottom', 'integrations · monochrome icon grid no labels', `${k('filter')}: ${sv('grayscale(1)')}, ${k('labels')}: ${sv('none')}, ${k('gap')}: ${sv('24px')}`),
    Z('security',     '48.9%', '10%',  '80%',  '7.5%',  'bottom', 'security · SOC2 text-only ANTI badge icons', `${k('ANTI')}: ${sv('security badge icons')}, ${k('style')}: ${sv('text-only certification list')}`),
    Z('testimonials', '56.4%', '3%',   '94%',  '8.5%',  'bottom', 'testimonials · dark card #1A1B25 6px radius', `${k('cardBackground')}: ${sv('#1A1B25')}, ${k('borderRadius')}: ${sv('6px')}, ${k('attribution')}: ${sv('name + role')}`),
    Z('pricing-h2',   '64.9%', '20%',  '60%',  '1.2%',  'bottom', 'pricing heading · 700w 48px center',         `${k('fontWeight')}: ${nv(700)}, ${k('fontSize')}: ${sv('48px')}, ${k('textAlign')}: ${sv('center')}`),
    Z('plan-grid',    '66.1%', '3%',   '94%',  '8.0%',  'top',    'plan grid · signal accent on Growth tier',   `${k('highlight')}: ${sv('Growth')}, ${k('accentColor')}: ${sv('#5E6AD2')}, ${k('columns')}: ${nv(3)}`),
    Z('plan-cta',     '72.5%', '37%',  '26%',  '1.2%',  'top',    'plan CTA · #5E6AD2 full-width 6px radius',   `${k('background')}: ${sv('#5E6AD2')}, ${k('width')}: ${sv('100%')}, ${k('borderRadius')}: ${sv('6px')}`),
    Z('footer-cta',   '74.1%', '10%',  '80%',  '4.0%',  'bottom', 'footer CTA · dark centered headline button', `${k('background')}: ${sv('#0F1018')}, ${k('textAlign')}: ${sv('center')}, ${k('layout')}: ${sv('stacked')}`),
    Z('footer',       '88.0%', '0%',   '100%', '12.0%', 'top',    'footer · 6-col ANTI visible-scrollbars',     `${k('columns')}: ${nv(6)}, ${k('ANTI')}: ${sv('visible scrollbars')}, ${k('background')}: ${sv('#0F1018')}`)
  ],
  'spec-009': [ /* stripe.com — 14739px tall */
    Z('nav-blur',     '0%',    '0%',   '100%', '0.37%', 'bottom', 'nav · white 70% blur Camphor typeface',      `${k('backdropFilter')}: ${sv('blur(20px)')}, ${k('background')}: ${sv('rgba(255,255,255,0.7)')}, ${k('fontFamily')}: ${sv('Camphor')}`),
    Z('stripe-logo',  '0%',    '2%',   '8%',   '0.37%', 'bottom', 'logotype · #0A2540 600w anti-rounded',       `${k('color')}: ${sv('#0A2540')}, ${k('fontWeight')}: ${nv(600)}, ${k('letterSpacing')}: ${sv('-0.02em')}`),
    Z('nav-links-w',  '0%',    '28%',  '42%',  '0.37%', 'bottom', 'nav links · #3C4257 500w no hover bg',       `${k('color')}: ${sv('#3C4257')}, ${k('fontWeight')}: ${nv(500)}, ${k('hoverBackground')}: ${sv('none')}`),
    Z('nav-cta-pill', '0%',    '83%',  '13%',  '0.37%', 'bottom', 'nav CTA · #635BFF pill 100px radius',        `${k('background')}: ${sv('#635BFF')}, ${k('borderRadius')}: ${sv('100px')}, ${k('color')}: ${sv('#ffffff')}`),
    Z('mesh-gradient','0.37%', '48%',  '52%',  '5.5%',  'left',   'mesh gradient · scroll-tied hue shift warmth', `${k('type')}: ${sv('webgl gradient mesh')}, ${k('animation')}: ${sv('scroll-tied hue shift')}, ${k('warmth')}: ${nv(0.74)}`),
    Z('hero-surface', '0.37%', '0%',   '50%',  '5.5%',  'bottom', 'hero surface · #fff warmth:0.74 left-aligned', `${k('background')}: ${sv('#ffffff')}, ${k('warmth')}: ${nv(0.74)}, ${k('textAlign')}: ${sv('left')}`),
    Z('hero-headline','0.7%',  '3%',   '45%',  '2.5%',  'bottom', 'headline · left-aligned #0A2540 700w -0.025em', `${k('color')}: ${sv('#0A2540')}, ${k('fontWeight')}: ${nv(700)}, ${k('letterSpacing')}: ${sv('-0.025em')}, ${k('textAlign')}: ${sv('left')}`),
    Z('hero-sub',     '3.2%',  '3%',   '38%',  '1.0%',  'bottom', 'subtext · #3C4257 max-width 440px lh1.5',    `${k('color')}: ${sv('#3C4257')}, ${k('maxWidth')}: ${sv('440px')}, ${k('lineHeight')}: ${nv(1.5)}`),
    Z('hero-cta',     '4.2%',  '3%',   '22%',  '0.8%',  'bottom', 'CTA · #635BFF pill left-aligned',            `${k('background')}: ${sv('#635BFF')}, ${k('borderRadius')}: ${sv('100px')}, ${k('textAlign')}: ${sv('left')}`),
    Z('product-cards','6.5%',  '3%',   '94%',  '7.5%',  'top',    'product cards · warm gradient top accent 8px', `${k('accentGradient')}: ${sv('top-edge 8px warm')}, ${k('borderRadius')}: ${sv('8px')}, ${k('warmth')}: ${nv(0.74)}`),
    Z('card-accent',  '7.2%',  '3%',   '28%',  '3.5%',  'bottom', 'card top accent · gradient warm 8px strip',  `${k('borderTop')}: ${sv('8px solid gradient')}, ${k('gradientColors')}: ${sv('warm purple-blue')}, ${k('borderRadius')}: ${sv('8px 8px 0 0')}`),
    Z('payments',     '14.0%', '3%',   '94%',  '8.0%',  'bottom', 'payments · split layout code on right',      `${k('layout')}: ${sv('50/50 split')}, ${k('codePosition')}: ${sv('right')}, ${k('ANTI')}: ${sv('hero illustrations')}`),
    Z('billing',      '22.0%', '3%',   '94%',  '8.0%',  'bottom', 'billing · warm invoice preview #F6F9FC bg',  `${k('insertBackground')}: ${sv('#F6F9FC')}, ${k('warmth')}: ${nv(0.74)}, ${k('invoiceStyle')}: ${sv('realistic preview')}`),
    Z('radar-dark',   '38.0%', '3%',   '94%',  '8.0%',  'bottom', 'Radar · dark risk dashboard ANTI flat charts', `${k('background')}: ${sv('#0A2540')}, ${k('chartStyle')}: ${sv('dark dashboard')}, ${k('ANTI')}: ${sv('flat data viz')}`),
    Z('climate-green','46.0%', '3%',   '94%',  '7.5%',  'bottom', 'Climate · #00D924 accent carbon offset',     `${k('accentColor')}: ${sv('#00D924')}, ${k('section')}: ${sv('carbon offset')}, ${k('iconStyle')}: ${sv('minimal leaf')}`),
    Z('dev-tools',    '53.5%', '3%',   '94%',  '7.5%',  'bottom', 'dev tools · code-first ANTI hero illustration', `${k('ANTI')}: ${sv('hero illustrations')}, ${k('primary')}: ${sv('code blocks')}, ${k('devFirst')}: ${nv(true)}`),
    Z('enterprise',   '61.0%', '3%',   '94%',  '7.5%',  'bottom', 'enterprise · mono grid text-heavy no icons', `${k('layout')}: ${sv('text grid')}, ${k('icons')}: ${sv('none')}, ${k('style')}: ${sv('enterprise density')}`),
    Z('testimonials', '68.5%', '5%',   '90%',  '7.5%',  'bottom', 'testimonials · #F6F9FC warm card surface',   `${k('cardBackground')}: ${sv('#F6F9FC')}, ${k('warmth')}: ${nv(0.74)}, ${k('attributionStyle')}: ${sv('enterprise names')}`),
    Z('pricing-h2',   '76.0%', '15%',  '70%',  '1.2%',  'bottom', 'pricing heading · #0A2540 700w centered',   `${k('color')}: ${sv('#0A2540')}, ${k('fontWeight')}: ${nv(700)}, ${k('textAlign')}: ${sv('center')}`),
    Z('plan-grid',    '77.2%', '3%',   '94%',  '8.5%',  'top',    'plan grid · #635BFF gradient CTA no table borders', `${k('ctaBackground')}: ${sv('#635BFF')}, ${k('tableBorder')}: ${sv('none')}, ${k('borderRadius')}: ${sv('100px')}`),
    Z('footer-warm',  '85.7%', '0%',   '100%', '3.5%',  'top',    'footer bar · #0A2540 Camphor warm anchored', `${k('background')}: ${sv('#0A2540')}, ${k('fontFamily')}: ${sv('Camphor')}, ${k('warmth')}: ${nv(0.74)}`),
    Z('footer',       '89.2%', '0%',   '100%', '10.8%', 'top',    'footer · 5-col #0A2540 no social',           `${k('columns')}: ${nv(5)}, ${k('background')}: ${sv('#0A2540')}, ${k('ANTI')}: ${sv('social icons')}`)
  ],
  'spec-007': [ /* vercel.com — 5918px tall */
    Z('nav-zero',     '0%',    '0%',   '100%', '0.93%', 'bottom', 'nav · #000000 no-border no-blur zero chrome', `${k('background')}: ${sv('#000000')}, ${k('border')}: ${sv('none')}, ${k('backdropFilter')}: ${sv('none')}`),
    Z('triangle-mark','0%',    '2%',   '3.5%', '0.93%', 'bottom', 'mark · ▲ Geist 600w pure white',             `${k('symbol')}: ${sv('▲')}, ${k('fontWeight')}: ${nv(600)}, ${k('color')}: ${sv('#ffffff')}`),
    Z('nav-links-w',  '0%',    '33%',  '34%',  '0.93%', 'bottom', 'nav links · rgba(255,255,255,0.65) no hover bg', `${k('color')}: ${sv('rgba(255,255,255,0.65)')}, ${k('hoverBackground')}: ${sv('none')}, ${k('hoverColor')}: ${sv('#ffffff')}`),
    Z('cta-pair',     '0%',    '79%',  '18%',  '0.93%', 'bottom', 'CTA pair · white fill + 1px outline',        `${k('primary')}: ${sv('#ffffff fill #000000 text')}, ${k('secondary')}: ${sv('1px solid rgba(255,255,255,0.3)')}`),
    Z('hero-surface', '0.93%', '0%',   '100%', '8.5%',  'bottom', 'surface · #000000 darkness:0.98 zero gradient', `${k('background')}: ${sv('#000000')}, ${k('darkness')}: ${nv(0.98)}, ${k('ANTI')}: ${sv('hero gradients')}`),
    Z('hero-headline','1.5%',  '10%',  '80%',  '3.5%',  'bottom', 'headline · Geist 700w -0.04em gradient fade', `${k('fontFamily')}: ${sv('Geist')}, ${k('fontWeight')}: ${nv(700)}, ${k('letterSpacing')}: ${sv('-0.04em')}, ${k('gradient')}: ${sv('#fff→rgba(255,255,255,0.7)')}`),
    Z('hero-sub',     '5.0%',  '20%',  '60%',  '1.2%',  'bottom', 'subtext · Geist rgba(255,255,255,0.7) 18px', `${k('fontFamily')}: ${sv('Geist')}, ${k('color')}: ${sv('rgba(255,255,255,0.7)')}, ${k('fontSize')}: ${sv('18px')}`),
    Z('logo-strip',   '9.5%',  '5%',   '90%',  '2.0%',  'bottom', 'logo strip · 0.35 opacity white monochrome', `${k('opacity')}: ${nv(0.35)}, ${k('filter')}: ${sv('brightness(10)')}, ${k('gap')}: ${sv('40px')}`),
    Z('product-grid', '11.5%', '3%',   '94%',  '10.0%', 'top',    'product grid · dark tiles brutalism:0.71',   `${k('tileBackground')}: ${sv('#111')}, ${k('brutalism')}: ${nv(0.71)}, ${k('borderRadius')}: ${sv('0')}`),
    Z('tile-style',   '12.0%', '3%',   '30%',  '9.0%',  'bottom', 'product tile · zero border-radius dark',     `${k('borderRadius')}: ${sv('0')}, ${k('background')}: ${sv('#0a0a0a')}, ${k('border')}: ${sv('1px solid rgba(255,255,255,0.06)')}`),
    Z('cli-insert',   '21.5%', '5%',   '90%',  '9.5%',  'bottom', 'CLI insert · Geist Mono dark terminal',      `${k('fontFamily')}: ${sv('Geist Mono')}, ${k('background')}: ${sv('#000')}, ${k('promptColor')}: ${sv('rgba(255,255,255,0.4)')}`),
    Z('deploy-block', '31.0%', '3%',   '94%',  '9.5%',  'bottom', 'deploy · sharp easing ANTI gradients',       `${k('motionEasing')}: ${sv('cubic-bezier(0,0,0.2,1) sharp')}, ${k('ANTI')}: ${sv('hero gradients rounded corners')}`),
    Z('enterprise',   '40.5%', '5%',   '90%',  '9.5%',  'bottom', 'enterprise · minimalism:0.92 ANTI rounded',  `${k('minimalism')}: ${nv(0.92)}, ${k('ANTI')}: ${sv('rounded corners serif type')}, ${k('density')}: ${sv('low')}`),
    Z('testimonials', '50.0%', '5%',   '90%',  '10.0%', 'bottom', 'testimonials · stark white on black no card', `${k('cardBackground')}: ${sv('none')}, ${k('color')}: ${sv('#ffffff')}, ${k('ANTI')}: ${sv('testimonial card borders')}`),
    Z('footer-cta',   '60.0%', '10%',  '80%',  '7.5%',  'bottom', 'footer CTA · minimal single button centered', `${k('buttons')}: ${nv(1)}, ${k('textAlign')}: ${sv('center')}, ${k('ANTI')}: ${sv('multi-button layouts')}`),
    Z('footer',       '67.5%', '0%',   '100%', '32.5%', 'top',    'footer · 6-col Geist dark ANTI serifs',      `${k('columns')}: ${nv(6)}, ${k('fontFamily')}: ${sv('Geist')}, ${k('ANTI')}: ${sv('serif type')}`)
  ],
  'spec-005': [ /* notion.so — 7574px tall */
    Z('nav-paper',    '0%',    '0%',   '100%', '0.73%', 'bottom', 'nav · #FEFDF9 paper no blur warm',           `${k('background')}: ${sv('#FEFDF9')}, ${k('backdropFilter')}: ${sv('none')}, ${k('warmth')}: ${nv(0.62)}`),
    Z('notion-mark',  '0%',    '2%',   '8%',   '0.73%', 'bottom', 'wordmark · Notion 800w -0.02em',             `${k('fontWeight')}: ${nv(800)}, ${k('letterSpacing')}: ${sv('-0.02em')}, ${k('color')}: ${sv('#191919')}`),
    Z('nav-links-w',  '0%',    '28%',  '44%',  '0.73%', 'bottom', 'nav links · #6B6860 500w 11px caps',         `${k('color')}: ${sv('#6B6860')}, ${k('fontWeight')}: ${nv(500)}, ${k('fontSize')}: ${sv('11px')}, ${k('textTransform')}: ${sv('uppercase')}`),
    Z('nav-cta-dark', '0%',    '82%',  '14%',  '0.73%', 'bottom', 'nav CTA · #191919 6px radius warm',          `${k('background')}: ${sv('#191919')}, ${k('borderRadius')}: ${sv('6px')}, ${k('color')}: ${sv('#ffffff')}`),
    Z('hero-surface', '0.73%', '0%',   '100%', '6.5%',  'bottom', 'hero surface · #FEFDF9 warmth:0.62 ANTI dark', `${k('background')}: ${sv('#FEFDF9')}, ${k('warmth')}: ${nv(0.62)}, ${k('ANTI')}: ${sv('dark mode hero')}`),
    Z('hero-headline','1.0%',  '5%',   '90%',  '2.8%',  'bottom', 'ANTI · headline sans-serif display Georgia', `${k('ANTI')}: ${sv('sans-serif display type')}, ${k('fontFamily')}: ${sv('Georgia')}, ${k('fontWeight')}: ${nv(400)}, ${k('letterSpacing')}: ${sv('-0.015em')}`),
    Z('hero-sub',     '3.8%',  '10%',  '80%',  '1.2%',  'bottom', 'subtext · #6B6860 16px lh1.5 warm muted',   `${k('color')}: ${sv('#6B6860')}, ${k('fontSize')}: ${sv('16px')}, ${k('lineHeight')}: ${nv(1.5)}`),
    Z('cta-pair',     '5.0%',  '25%',  '50%',  '1.2%',  'top',    'CTA · #191919 dark primary + warm ghost',    `${k('primary')}: ${sv('#191919 fill')}, ${k('secondary')}: ${sv('warm border rgba(0,0,0,0.2)')}, ${k('borderRadius')}: ${sv('6px')}`),
    Z('product-shot', '7.3%',  '3%',   '94%',  '8.5%',  'bottom', 'product screenshot · dark float warm bg',    `${k('insertBackground')}: ${sv('dark')}, ${k('pageBackground')}: ${sv('#FEFDF9')}, ${k('boxShadow')}: ${sv('0 24px 64px rgba(0,0,0,0.15)')}`),
    Z('logo-row',     '15.8%', '5%',   '90%',  '1.8%',  'bottom', 'logo row · warm muted 0.35 opacity Georgia',  `${k('opacity')}: ${nv(0.35)}, ${k('filter')}: ${sv('grayscale(1)')}, ${k('warmth')}: ${nv(0.62)}`),
    Z('use-case-tabs','17.6%', '3%',   '94%',  '8.5%',  'bottom', 'use-case tabs · pill active no underline',   `${k('tabActiveStyle')}: ${sv('pill background')}, ${k('underline')}: ${sv('none')}, ${k('icon')}: ${sv('none')}`),
    Z('wiki-serif',   '26.1%', '3%',   '94%',  '9.0%',  'bottom', 'wiki · Georgia serif H2 ANTI sans-display',  `${k('ANTI')}: ${sv('sans-serif headings')}, ${k('fontFamily')}: ${sv('Georgia')}, ${k('background')}: ${sv('#FEFDF9')}`),
    Z('projects',     '35.1%', '3%',   '94%',  '9.0%',  'bottom', 'projects · timeline row no icon decoration', `${k('layout')}: ${sv('horizontal timeline')}, ${k('icons')}: ${sv('none')}, ${k('warmth')}: ${nv(0.62)}`),
    Z('ai-insert',    '44.1%', '3%',   '94%',  '9.0%',  'bottom', 'AI · dark insert soft-fade animation',       `${k('insertBackground')}: ${sv('dark')}, ${k('animation')}: ${sv('soft fade on enter')}, ${k('ANTI')}: ${sv('neon accents')}`),
    Z('templates',    '53.1%', '3%',   '94%',  '8.0%',  'bottom', 'templates · warm hover no borders card grid', `${k('hoverBackground')}: ${sv('#F5F4EE')}, ${k('border')}: ${sv('none')}, ${k('cardRadius')}: ${sv('6px')}`),
    Z('testimonials', '61.1%', '5%',   '90%',  '9.0%',  'bottom', 'testimonials · #F5F4EE warm card serif attr', `${k('cardBackground')}: ${sv('#F5F4EE')}, ${k('attribution')}: ${sv('Georgia serif')}, ${k('warmth')}: ${nv(0.62)}`),
    Z('pricing-serif','70.1%', '10%',  '80%',  '1.2%',  'bottom', 'pricing heading · Georgia 400w centered warm', `${k('fontFamily')}: ${sv('Georgia')}, ${k('fontWeight')}: ${nv(400)}, ${k('textAlign')}: ${sv('center')}, ${k('color')}: ${sv('#191919')}`),
    Z('plan-warm',    '71.3%', '3%',   '94%',  '8.5%',  'top',    'plan cards · warm #FEFDF9 surface 3-col',    `${k('background')}: ${sv('#FEFDF9')}, ${k('columns')}: ${nv(3)}, ${k('border')}: ${sv('1px solid rgba(0,0,0,0.1)')}`),
    Z('free-tier',    '77.5%', '3%',   '30%',  '2.0%',  'top',    'free tier · warm border-only CTA',           `${k('background')}: ${sv('transparent')}, ${k('border')}: ${sv('1px solid rgba(0,0,0,0.2)')}, ${k('warmth')}: ${nv(0.62)}`),
    Z('footer',       '90.3%', '0%',   '100%', '9.7%',  'top',    'footer · warm paper 5-col Georgia links',    `${k('background')}: ${sv('#FEFDF9')}, ${k('columns')}: ${nv(5)}, ${k('fontFamily')}: ${sv('Georgia')}`)
  ],
  'spec-002': [ /* raycast.com — 15626px tall */
    Z('nav-invis',    '0%',    '0%',   '100%', '0.35%', 'bottom', 'nav · fully transparent no-border',          `${k('background')}: ${sv('transparent')}, ${k('border')}: ${sv('none')}, ${k('backdropFilter')}: ${sv('none')}`),
    Z('orb-gradient', '0.35%', '12%',  '76%',  '2.5%',  'bottom', 'orb · scroll-parallax #FF6363 gradient',     `${k('background')}: ${sv('radial-gradient(#FF6363,#FF3636,transparent)')}, ${k('animation')}: ${sv('scroll-parallax')}, ${k('brand')}: ${sv('only warm element')}`),
    Z('hero-surface', '0.35%', '0%',   '100%', '5.5%',  'bottom', 'surface · #111113 darkness:0.94',            `${k('background')}: ${sv('#111113')}, ${k('darkness')}: ${nv(0.94)}, ${k('gradient')}: ${sv('none')}`),
    Z('hero-headline','1.3%',  '10%',  '80%',  '2.0%',  'bottom', 'headline · 700w -0.03em clamp(40,5vw,64px)', `${k('fontWeight')}: ${nv(700)}, ${k('letterSpacing')}: ${sv('-0.03em')}, ${k('fontSize')}: ${sv('clamp(40px,5vw,64px)')}, ${k('color')}: ${sv('#ffffff')}`),
    Z('hero-sub',     '3.3%',  '20%',  '60%',  '1.2%',  'bottom', 'subtext · 0.55 opacity 17px lh1.5',          `${k('opacity')}: ${nv(0.55)}, ${k('fontSize')}: ${sv('17px')}, ${k('lineHeight')}: ${nv(1.5)}`),
    Z('cta-badge',    '4.5%',  '30%',  '40%',  '0.9%',  'top',    'CTA · macOS App Store badge dark outline',   `${k('style')}: ${sv('macOS badge')}, ${k('background')}: ${sv('transparent')}, ${k('border')}: ${sv('1px solid rgba(255,255,255,0.3)')}`),
    Z('red-signal',   '2.0%',  '5%',   '15%',  '1.0%',  'bottom', 'brand red · #FF6363 only warm signal element', `${k('signalColor')}: ${sv('#FF6363')}, ${k('usage')}: ${sv('brand-only')}, ${k('warmth')}: ${sv('isolated to brand')}`),
    Z('app-window',   '5.4%',  '3%',   '94%',  '7.5%',  'top',    'app window · command palette #111113 dark',  `${k('background')}: ${sv('#111113')}, ${k('windowChrome')}: ${sv('dark macOS')}, ${k('interaction')}: ${sv('command palette')}`),
    Z('feat-h2',      '12.9%', '5%',   '60%',  '1.0%',  'bottom', 'feature H2 · 700w white -0.025em',           `${k('fontWeight')}: ${nv(700)}, ${k('color')}: ${sv('#ffffff')}, ${k('letterSpacing')}: ${sv('-0.025em')}`),
    Z('ext-insert',   '13.9%', '3%',   '94%',  '7.0%',  'bottom', 'extensions · no icon rows monospace list',   `${k('icons')}: ${sv('none')}, ${k('fontFamily')}: ${sv('monospace')}, ${k('listStyle')}: ${sv('dense rows')}`),
    Z('ai-cmd',       '20.9%', '3%',   '94%',  '7.0%',  'bottom', 'AI commands · command palette pattern dark', `${k('pattern')}: ${sv('command palette')}, ${k('background')}: ${sv('#111113')}, ${k('accentColor')}: ${sv('#FF6363')}`),
    Z('snippets-red', '27.9%', '3%',   '94%',  '7.0%',  'bottom', 'snippets · red variable highlight #FF6363',  `${k('highlightColor')}: ${sv('#FF6363')}, ${k('variableStyle')}: ${sv('{{placeholder}}')}, ${k('background')}: ${sv('#111113')}`),
    Z('clipboard',    '34.9%', '3%',   '94%',  '7.0%',  'bottom', 'clipboard · dark tile stack history list',   `${k('tileBackground')}: ${sv('#1a1a1c')}, ${k('stackStyle')}: ${sv('offset shadows')}, ${k('border')}: ${sv('none')}`),
    Z('window-mgmt',  '41.9%', '3%',   '94%',  '7.0%',  'bottom', 'window mgmt · halftone grid preview',        `${k('previewStyle')}: ${sv('halftone grid')}, ${k('gridColor')}: ${sv('rgba(255,255,255,0.1)')}, ${k('background')}: ${sv('#111113')}`),
    Z('pro-section',  '48.9%', '3%',   '94%',  '7.0%',  'bottom', 'Raycast Pro · red gradient CTA section',     `${k('gradient')}: ${sv('radial #FF6363 glow')}, ${k('ctaStyle')}: ${sv('dark modal')}, ${k('accentColor')}: ${sv('#FF6363')}`),
    Z('team-shared',  '55.9%', '3%',   '94%',  '7.0%',  'bottom', 'team · shared snippets org namespace',       `${k('featureType')}: ${sv('team shared snippets')}, ${k('namespaceStyle')}: ${sv('@org/snippet')}, ${k('background')}: ${sv('#111113')}`),
    Z('anti-borders', '62.9%', '3%',   '94%',  '3.0%',  'bottom', 'ANTI · visible nav borders',                 `${k('ANTI')}: ${sv('visible nav borders')}, ${k('navBorder')}: ${sv('none')}, ${k('navBackground')}: ${sv('transparent')}`),
    Z('testimonials', '65.9%', '5%',   '90%',  '7.0%',  'bottom', 'testimonials · dark card dev-centric',       `${k('cardBackground')}: ${sv('#1a1a1c')}, ${k('attribution')}: ${sv('dev role + company')}, ${k('border')}: ${sv('none')}`),
    Z('footer-badge', '72.9%', '20%',  '60%',  '4.5%',  'bottom', 'footer CTA · macOS badge red accent',        `${k('style')}: ${sv('macOS App Store badge')}, ${k('accentColor')}: ${sv('#FF6363')}, ${k('background')}: ${sv('#111113')}`),
    Z('footer',       '77.4%', '0%',   '100%', '22.6%', 'top',    'footer · pure #000000 4-col ANTI social',    `${k('background')}: ${sv('#000000')}, ${k('columns')}: ${nv(4)}, ${k('ANTI')}: ${sv('social media icons')}`)
  ]
};

function syntaxHighlightJson(obj) {
  let str = JSON.stringify(obj, null, 2);
  str = str.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
  str = str.replace(/^(\s*)("(?:[^"\\]|\\.)*")(\s*:)/gm,
    '$1<span class="k">$2</span>$3');
  str = str.replace(/(:\s*)("(?:[^"\\]|\\.)*")/g,
    '$1<span class="s">$2</span>');
  str = str.replace(/(:\s*)(-?\d+\.?\d*)/g,
    '$1<span class="n">$2</span>');
  str = str.replace(/^(\s{4,})("(?:[^"\\]|\\.)*")(,?)$/gm,
    '$1<span class="s">$2</span>$3');
  return str;
}

const REAL_MARKS = window.DESIGN_MARKS || {
  'spec-014': {
    "$schema": "https://inoculate.design/schema/mark/v1.json",
    "source": "framer.com",
    "designTokens": {
      "colorSemantics": { "bg-primary": "rgb(0,0,0)", "text-primary": "rgb(0,0,238)", "accent": "#0066ff", "surface": "rgb(17,17,17)" },
      "typographySystem": "Inter Variable: 400,500,600,700; 110/73/48/24/16/14",
      "borderRadiusScale": "0 / 8px / 100px / 10px / full"
    },
    "compositionProfile": { "layoutPersonality": "modular-grid", "asymmetry": 0.72, "density": 0.94, "pacing": "measured", "surpriseMoments": ["oversized hero typography", "mixed corner language", "layered gradient field"] },
    "motionConstitution": { "alwaysAnimate": ["transform", "opacity", "color"], "neverAnimate": ["background-color", "background", "border-radius"], "constitutionStatement": "Surgical motion: only transform, opacity, color animate. background-color, background, border-radius are intentionally static." },
    "antiDefaults": [{ "avoid": "bg-gray-900 for primary surfaces", "instead": "bg-[rgb(0,0,0)]", "reason": "Reference anchors on pure black." }, { "avoid": "generic brand blues for CTA", "instead": "bg-[#0066ff]", "reason": "Accent color is site-specific." }]
  },
  'spec-011': {
    "$schema": "https://inoculate.design/schema/mark/v1.json",
    "source": "linear.app",
    "designTokens": {
      "colorSemantics": { "bg-primary": "rgb(8,9,10)", "text-primary": "rgb(247,248,248)", "accent": "#5E6AD2", "surface": "rgb(15,16,17)" },
      "typographySystem": "Inter Variable: 400,500,600,700; 72/48/32/24/16/14",
      "borderRadiusScale": "0 / 2px / 6px / 50% / full"
    },
    "compositionProfile": { "layoutPersonality": "modular-grid", "asymmetry": 0.72, "density": 0.93, "pacing": "chaptered", "surpriseMoments": ["oversized hero typography", "mixed corner language", "layered gradient field"] },
    "motionConstitution": { "alwaysAnimate": ["opacity", "transform", "color"], "neverAnimate": ["background", "border-radius", "font-size", "width"], "constitutionStatement": "Constrained vocabulary: opacity, transform, color animate. background, border-radius, font-size never animate — treated as fixed. 607 CSS keyframe animations." },
    "antiDefaults": [{ "avoid": "bg-gray-900 for primary surfaces", "instead": "bg-[rgb(8,9,10)]", "reason": "Reference anchors on near-black." }, { "avoid": "rounded-lg everywhere", "instead": "border-radius: 2px or 6px max", "reason": "Sharp geometry is identity." }]
  },
  'spec-009': {
    "$schema": "https://inoculate.design/schema/mark/v1.json",
    "source": "stripe.com",
    "designTokens": {
      "colorSemantics": { "bg-primary": "rgb(0,0,0)", "bg-secondary": "rgb(255,255,255)", "accent": "#635BFF", "surface": "rgb(229,237,245)" },
      "typographySystem": "sohne-var: 400,500,600,700; 56/37/25/24/16/14",
      "borderRadiusScale": "0 / 4px / 6px / 1px / full"
    },
    "compositionProfile": { "layoutPersonality": "modular-grid", "hierarchyStrategy": "restrained-minimal", "density": 1, "pacing": "chaptered", "surpriseMoments": ["immersive canvas scene", "layered gradient field"] },
    "motionConstitution": { "alwaysAnimate": ["opacity", "transform", "color"], "neverAnimate": ["background", "border-radius", "font-size", "width"], "constitutionStatement": "Constrained vocabulary with WebGL2 orchestration: opacity, transform, color animate. JS-orchestrated, mouse-reactive shaders." },
    "antiDefaults": [{ "avoid": "generic blue for CTA", "instead": "bg-[#635BFF]", "reason": "Stripe purple is precise identity." }, { "avoid": "sharp or fully rounded corners", "instead": "border-radius: 4px or 6px", "reason": "Subtle rounding, never pill or square." }]
  },
  'spec-007': {
    "$schema": "https://inoculate.design/schema/mark/v1.json",
    "source": "vercel.com",
    "designTokens": {
      "colorSemantics": { "bg-primary": "rgb(0,0,0)", "text-primary": "rgb(161,161,161)", "accent": "#ffffff", "surface": "rgb(10,10,10)" },
      "typographySystem": "Geist: 400,500,600,700; 48/32/21/24/16/14",
      "borderRadiusScale": "0 / 6px / 4px / full"
    },
    "compositionProfile": { "layoutPersonality": "modular-grid", "hierarchyStrategy": "distributed", "density": 0.99, "pacing": "measured", "surpriseMoments": ["immersive canvas scene", "mixed corner language", "layered gradient field"] },
    "motionConstitution": { "alwaysAnimate": ["opacity", "transform", "color"], "neverAnimate": ["background", "border-radius", "font-size", "width"], "constitutionStatement": "Pure speed: primary duration 0.09s ease. WebGL2 + 120 CSS keyframe animations. Background and radius are static." },
    "antiDefaults": [{ "avoid": "any warm-gray surface", "instead": "bg-[rgb(0,0,0)] or bg-[rgb(10,10,10)]", "reason": "Reference is cold black only." }, { "avoid": "non-Geist type", "instead": "font-family: Geist", "reason": "Geist is load-bearing brand." }]
  },
  'spec-005': {
    "$schema": "https://inoculate.design/schema/mark/v1.json",
    "source": "notion.so",
    "designTokens": {
      "colorSemantics": { "bg-primary": "rgb(255,255,255)", "bg-secondary": "rgb(25,25,24)", "text-primary": "rgba(0,0,0,0.9)", "surface": "rgb(246,245,244)" },
      "typographySystem": "NotionInter: 400,500,600,700; 64/42/28/24/16/14",
      "borderRadiusScale": "0 / 8px / 5px / 12px / full"
    },
    "compositionProfile": { "layoutPersonality": "modular-grid", "hierarchyStrategy": "hero-led", "density": 0.99, "pacing": "chaptered", "surpriseMoments": ["oversized hero typography", "mixed corner language"] },
    "motionConstitution": { "alwaysAnimate": ["transform", "opacity", "translate", "background-color"], "neverAnimate": ["background", "border-radius", "font-size", "width"], "constitutionStatement": "Warm and mechanical: 0.6s primary duration, linear + ease-in-out easing. 21 CSS animations. Paper surface never animates." },
    "antiDefaults": [{ "avoid": "cool-white background", "instead": "bg-[rgb(255,255,255)] with warm-paper surface rgb(246,245,244)", "reason": "Warmth is identity." }, { "avoid": "system font stack", "instead": "font-family: NotionInter", "reason": "Custom typeface is signature." }]
  },
  'spec-002': {
    "$schema": "https://inoculate.design/schema/mark/v1.json",
    "source": "raycast.com",
    "designTokens": {
      "colorSemantics": { "bg-primary": "rgb(7,8,10)", "text-primary": "#111111", "accent": "#FF6363", "surface": "rgba(0,0,0,0.44)" },
      "typographySystem": "Inter: 400,500,600,700; 64/42/28/24/16/14",
      "borderRadiusScale": "0 / 11px / 8px / 100% / full"
    },
    "compositionProfile": { "layoutPersonality": "modular-grid", "hierarchyStrategy": "hero-led", "density": 1, "pacing": "chaptered", "surpriseMoments": ["oversized hero typography", "immersive canvas scene", "layered gradient field"] },
    "motionConstitution": { "alwaysAnimate": ["transform", "opacity", "color"], "neverAnimate": ["background", "border-color", "border-radius", "font-size"], "constitutionStatement": "Mechanical at 0.3s: WebGL2 + Three.js mouse-reactive. Siblings stagger by -0.64s. Only warm element is the #FF6363 orb." },
    "antiDefaults": [{ "avoid": "bg-gray-900 for primary surfaces", "instead": "bg-[rgb(7,8,10)]", "reason": "Reference anchors on near-void black." }, { "avoid": "blue accent", "instead": "accent: #FF6363", "reason": "#FF6363 orb is the sole warm signal — brand-critical." }]
  }
};

function buildDesignMark(spec) {
  const marks = window.DESIGN_MARKS || REAL_MARKS;
  return marks[spec.id] || marks['spec-014'];
}

function BeforeAfter() {
  function Mock({ isBefore }) {
    return React.createElement('div', { className: 'io-ba-mock ' + (isBefore ? 'io-ba-b' : 'io-ba-a') },
      React.createElement('div', { className: 'm-nav' },
        isBefore
          ? React.createElement('div', { className: 'm-logo' }, '⬡')
          : React.createElement('div', { className: 'm-logo' }, 'F'),
        React.createElement('div', { className: 'm-cta' }, 'Get started')
      ),
      React.createElement('div', { className: 'm-hero' },
        React.createElement('div', { className: 'm-hl' }, 'Build something amazing.'),
        React.createElement('div', { className: 'm-sub' }, 'The platform for modern teams.'),
        React.createElement('div', { className: 'm-btn' }, 'Start for free →')
      ),
      React.createElement('div', { className: 'm-cards' },
        React.createElement('div', { className: 'm-card' }),
        React.createElement('div', { className: 'm-card' }),
        React.createElement('div', { className: 'm-card' })
      )
    );
  }
  return React.createElement('div', { className: 'io-ba' },
    React.createElement('div', null,
      React.createElement('div', { className: 'io-ba-label' },
        React.createElement('span', { className: 'io-ba-badge before' }, 'BEFORE'),
        ' generic AI output'
      ),
      React.createElement(Mock, { isBefore: true })
    ),
    React.createElement('div', null,
      React.createElement('div', { className: 'io-ba-label' },
        React.createElement('span', { className: 'io-ba-badge after' }, 'AFTER'),
        ' design mark applied'
      ),
      React.createElement(Mock, { isBefore: false })
    )
  );
}

/* ── narrative stations ── */
const STATIONS = [
  { num: '01', label: 'WHAT YOU JUST DID' },
  { num: '02', label: 'HOW IT WORKS' },
  { num: '03', label: 'WHAT WE BUILT' },
  { num: '04', label: 'REBRAND' },
  { num: '05', label: 'A POSITION' },
  { num: '06', label: 'JOIN' }
];

/* ── CLI TERMINAL — animated extraction demo ── */
function CliTerminalInner({ onReplay, isActive }) {
  const CMD = 'npx inoculate@latest add linear.app';
  const OUTPUT = [
    { t: '',                                                     cls: '',       delay: 180 },
    { t: '  inoculate v0.9.4 · extraction engine',              cls: 'dim',    delay: 120 },
    { t: '',                                                     cls: '',       delay: 200 },
    { t: '  ◉ CONNECT     linear.app:443 ............ ok',      cls: 'good',   delay: 520 },
    { t: '  ◉ INTERCEPT   webgl contexts ............. 4',      cls: 'good',   delay: 420 },
    { t: '  ◉ CAPTURE     scroll steps .............. 60/60',   cls: 'good',   delay: 680 },
    { t: '  ◉ CLASSIFY    motion archetype ........... INSTANT_FEEDBACK', cls: 'signal', delay: 540 },
    { t: '  ◉ SCORE       IDF-weighted .............. 847 signals', cls: 'signal', delay: 460 },
    { t: '  ◉ EXTRACT     css properties ............. done',   cls: 'good',   delay: 380 },
    { t: '  ◉ WRITE       design-mark.json ........... 16 keys',cls: 'good',   delay: 320 },
    { t: '',                                                     cls: '',       delay: 120 },
    { t: '  DESIGN MARK · linear.app',                         cls: 'mute',   delay: 80  },
    { t: '  ────────────────────────────────────────',          cls: 'mute',   delay: 60  },
  ];

  const [started, setStarted] = React.useState(false);
  const [typedCmd, setTypedCmd] = React.useState('');
  const [cmdDone, setCmdDone] = React.useState(false);
  const [lines, setLines] = React.useState([]);
  const [showBars, setShowBars] = React.useState(false);
  const [barProgress, setBarProgress] = React.useState(0);
  const [done, setDone] = React.useState(false);

  /* latch started on first isActive */
  React.useEffect(() => {
    if (isActive && !started) setStarted(true);
  }, [isActive]);

  /* phase 1: typewriter — only after started */
  React.useEffect(() => {
    if (!started) return;
    let i = 0;
    const iv = setInterval(() => {
      i++;
      setTypedCmd(CMD.slice(0, i));
      if (i >= CMD.length) { clearInterval(iv); setTimeout(() => setCmdDone(true), 260); }
    }, 36);
    return () => clearInterval(iv);
  }, [started]);

  /* phase 2: output lines */
  React.useEffect(() => {
    if (!cmdDone) return;
    let i = 0;
    function next() {
      if (i >= OUTPUT.length) { setShowBars(true); return; }
      const line = OUTPUT[i++];
      setLines(prev => [...prev, line]);
      setTimeout(next, line.delay);
    }
    setTimeout(next, 200);
  }, [cmdDone]);

  /* phase 3: animate bars */
  React.useEffect(() => {
    if (!showBars) return;
    let p = 0;
    const iv = setInterval(() => {
      p = Math.min(1, p + 0.022);
      setBarProgress(p);
      if (p >= 1) { clearInterval(iv); setTimeout(() => setDone(true), 400); }
    }, 28);
    return () => clearInterval(iv);
  }, [showBars]);

  const BARS = [
    { label: 'darkness',   val: 0.88 },
    { label: 'minimalism', val: 0.84 },
    { label: 'motion',     val: 0.42 },
    { label: 'warmth',     val: 0.10 },
  ];

  function barBlocks(val) {
    const filled = Math.round(val * 20);
    return '█'.repeat(filled) + '░'.repeat(20 - filled);
  }

  return React.createElement('div', { className: 'cli-terminal' },
    React.createElement('div', { className: 'cli-titlebar' },
      React.createElement('span', { className: 'cli-dot r' }),
      React.createElement('span', { className: 'cli-dot y' }),
      React.createElement('span', { className: 'cli-dot g' }),
      React.createElement('span', { className: 'cli-titlebar-label' }, 'TERMINAL — inoculate')
    ),
    React.createElement('div', { className: 'cli-body' },
      React.createElement('div', { className: 'cli-prompt-row' },
        React.createElement('span', { className: 'cli-prompt' }, '$ '),
        React.createElement('span', { className: 'cli-cmd' }, typedCmd),
        !cmdDone && React.createElement('span', { className: 'cli-cursor' })
      ),
      lines.map((l, i) =>
        React.createElement('span', { key: i, className: 'cli-line ' + l.cls }, l.t)
      ),
      showBars && BARS.map(b =>
        React.createElement('div', { key: b.label, className: 'cli-bar-row' },
          React.createElement('span', { className: 'cli-bar-label' }, b.label),
          React.createElement('span', { className: 'cli-bar-track-text' },
            barBlocks(b.val * barProgress)
          ),
          React.createElement('span', { className: 'cli-bar-val' }, (b.val * barProgress).toFixed(2))
        )
      ),
      showBars && React.createElement('div', { className: 'cli-line mute' }, '  ────────────────────────────────────────'),
      done && React.createElement('div', { className: 'cli-done' },
        React.createElement('span', { className: 'cli-line good' }, '  ✓ saved → .inoculate/design-mark.json'),
        React.createElement('span', { className: 'cli-line good' }, '  ✓ 847 signals · 16 keys · 0 errors'),
        React.createElement('br'),
        React.createElement('button', { className: 'cli-replay', onClick: onReplay }, '↺ REPLAY')
      )
    )
  );
}

function CliTerminal({ isActive }) {
  const [key, setKey] = React.useState(0);
  return React.createElement(CliTerminalInner, { key: key, isActive: isActive, onReplay: () => setKey(k => k + 1) });
}

/* ── Inoculate Mark — inline SVG, works everywhere ── */
function InoculateMark({ size = 22, dark = false }) {
  const stroke = dark ? '#ffffff' : '#0a0a0a';
  // At small sizes, use non-scaling-stroke so strokes stay crisp;
  // at large sizes, use SVG-unit stroke so weight scales naturally.
  const small = size <= 48;
  const strokeProps = small
    ? { strokeWidth: 2, vectorEffect: 'non-scaling-stroke' }
    : { strokeWidth: 10 };
  // dot radius: ~2.5px visual at any small size, 14 SVG units at large
  const dotR = small ? Math.round(2.5 * 300 / size) : 14;

  return React.createElement('svg', {
    viewBox: '0 0 300 300',
    style: { height: size + 'px', width: size + 'px', display: 'block', flexShrink: 0 }
  },
    React.createElement('path', Object.assign({
      d: 'M 128,38 L 112,38 C 90,38 90,54 90,68 L 90,132 C 90,143 68,150 68,150 C 68,150 90,157 90,168 L 90,232 C 90,246 112,262 128,262',
      fill: 'none', stroke: stroke, strokeLinecap: 'round', strokeLinejoin: 'round'
    }, strokeProps)),
    React.createElement('path', Object.assign({
      d: 'M 172,38 L 188,38 C 210,38 210,54 210,68 L 210,132 C 210,143 232,150 232,150 C 232,150 210,157 210,168 L 210,232 C 210,246 188,262 172,262',
      fill: 'none', stroke: stroke, strokeLinecap: 'round', strokeLinejoin: 'round'
    }, strokeProps)),
    React.createElement('circle', { cx: 150, cy: 150, r: dotR, fill: '#2563FF' })
  );
}

function InoculateWordmark({ size = 22, dark = false }) {
  const textColor = dark ? '#ffffff' : '#0a0a0a';
  return React.createElement('div', { className: 'ino-wordmark' },
    React.createElement(InoculateMark, { size, dark }),
    React.createElement('span', {
      style: {
        fontFamily: "'Space Mono', monospace",
        fontWeight: 400,
        fontSize: Math.round(size * 0.78) + 'px',
        color: textColor,
        letterSpacing: '-0.03em',
        lineHeight: 1
      }
    }, 'inoculate')
  );
}

window.InoculateMark = InoculateMark;
window.InoculateWordmark = InoculateWordmark;

function Site() {
  const [activeId, setActiveId] = React.useState('spec-014');
  const [extractsBySpecimen, setExtracts] = React.useState({});
  const [extractLog, setExtractLog] = React.useState([]);
  const [clock, setClock] = React.useState('');
  const [fullscreenId, setFullscreenId] = React.useState(null);
  const [fullscreenOrigin, setFullscreenOrigin] = React.useState(null);
  const [showModal, setShowModal] = React.useState(false);
  const [modalSpecId, setModalSpecId] = React.useState(null);

  /* live clock — adds presence */
  React.useEffect(() => {
    function tick() { setClock(new Date().toISOString().slice(11, 19) + 'Z'); }
    tick();
    const id = setInterval(tick, 1000);
    return () => clearInterval(id);
  }, []);

  /* keyboard shortcuts: 1-6 to jump specimens, Escape to close fullscreen */
  React.useEffect(() => {
    function onKey(e) {
      if (e.key === 'Escape') { setFullscreenId(null); return; }
      const idx = parseInt(e.key, 10);
      if (idx >= 1 && idx <= SPECIMENS.length) {
        setActiveId(SPECIMENS[SPECIMENS.length - idx].id);
      }
    }
    window.addEventListener('keydown', onKey);
    return () => window.removeEventListener('keydown', onKey);
  }, []);

  const spec = SPECIMENS.find(s => s.id === activeId);
  const zones = ZONE_LAYOUTS[activeId] || [];
  const extracted = extractsBySpecimen[activeId] || [];
  const isComplete = extracted.length >= 5;
  const cardRef = React.useRef(null);

  function openFullscreen() {
    let origin = null;
    if (cardRef.current) {
      const r = cardRef.current.getBoundingClientRect();
      const vw = window.innerWidth, vh = window.innerHeight;
      const t = (r.top / vh * 100).toFixed(2);
      const ri = ((1 - r.right / vw) * 100).toFixed(2);
      const b = ((1 - r.bottom / vh) * 100).toFixed(2);
      const l = (r.left / vw * 100).toFixed(2);
      origin = `inset(${t}% ${ri}% ${b}% ${l}%)`;
    }
    setFullscreenOrigin(origin);
    setFullscreenId(activeId);
  }

  function incise(zoneId, forSpecId) {
    const sid = forSpecId || activeId;
    const already = extractsBySpecimen[sid] || [];
    if (already.includes(zoneId)) return;
    const z = (ZONE_LAYOUTS[sid] || []).find(z => z.id === zoneId);
    if (!z) return;
    const s = SPECIMENS.find(s => s.id === sid);
    setExtracts(prev => ({
      ...prev,
      [sid]: [...(prev[sid] || []), zoneId]
    }));
    setExtractLog(prev => [
      ...prev.slice(-6),
      {
        id: zoneId + '-' + Date.now(),
        label: z.label,
        payload: z.payload,
        stamp: new Date().toISOString().slice(11, 19),
        specimen: s.n,
        specimenName: s.name
      }
    ]);
  }

  return React.createElement(React.Fragment, null,

    /* TOP CHROME */
    React.createElement('div', { className: 'io-chrome top' },
      React.createElement('div', { className: 'l' },
        React.createElement(InoculateWordmark, { size: 32, dark: false })
      ),
      React.createElement('div', { className: 'm' }),
      React.createElement('div', { className: 'r' },
        React.createElement('span', null, 'CLOCK ', React.createElement('b', null, clock)),
        React.createElement('span', null, '07°N · 45°W')
      )
    ),

    /* SECTION 1: THE SPECIMEN */
    React.createElement('section', { className: 'io-specimen' },

      /* LEFT: ROLODEX */
      React.createElement('div', { className: 'io-roll' },
        React.createElement('h4', null, '↳ COLLECTION · ' + SPECIMENS.length),
        SPECIMENS.map(s =>
          React.createElement('div', {
            key: s.id,
            className: 'io-roll-item' + (s.id === activeId ? ' active' : ''),
            onClick: () => setActiveId(s.id)
          },
            React.createElement('div', { className: 'n' }, 'SOURCE ' + s.n),
            React.createElement('div', { className: 'nm' }, s.name)
          )
        )
      ),

      /* CENTER: STAGE */
      React.createElement('div', { className: 'io-stage' },

        React.createElement('div', { className: 'io-hero' },
          React.createElement('div', { className: 'eyebrow' },
            React.createElement('span', { className: 'dot' }),
            'SOURCE ' + spec.n + ' · ' + spec.subject
          ),
          React.createElement('h1', null,
            spec.name,
            React.createElement('br'),
            'being ',
            React.createElement('em', null, 'extracted.')
          ),
          React.createElement('p', null,
            React.createElement('b', null, 'Click any region to extract. '),
            "Each incision pulls a layer of design intent into a portable artifact your agent can read."
          )
        ),

        /* the specimen card — click to open fullscreen */
        React.createElement('div', { className: 'io-card-wrap' },
          React.createElement('div', {
            className: 'io-card',
            key: activeId,
            ref: cardRef,
            onClick: openFullscreen,
            style: { cursor: 'pointer' }
          },
            React.createElement('div', { className: 'io-pin tl' }),
            React.createElement('div', { className: 'io-pin tr' }),
            React.createElement('div', { className: 'io-pin bl' }),
            React.createElement('div', { className: 'io-pin br' }),

            React.createElement('div', { className: 'scr' },
              window.SiteMock[activeId] && window.SiteMock[activeId]()
            ),

            React.createElement('div', { className: 'io-card-hint' }, '↗  CLICK TO EXTRACT')
          )
        ),

        /* specimen tag — number + name only */
        React.createElement('div', { className: 'io-tag' },
          React.createElement('span', { className: 'num' }, spec.n),
          React.createElement('span', null, '· ', React.createElement('b', null, spec.name))
        ),

        /* continue cue, appears when extractions complete */
        React.createElement('div', {
          className: 'io-continue' + (isComplete ? ' show' : '')
        },
          React.createElement('button', {
            className: 'io-dm-trigger',
            onClick: () => { setModalSpecId(activeId); setShowModal(true); }
          }, '◉  VIEW DESIGN MARK →')
        )
      ),

      /* RIGHT: CASE FILE + TRAY */
      React.createElement('div', { className: 'io-case' },
        React.createElement('h4', null,
          '↳ CASE FILE',
          React.createElement('span', { className: 'ct' }, spec.n)
        ),
        React.createElement('div', null,
          React.createElement('div', { className: 'row' },
            React.createElement('span', { className: 'nm' }, 'source'),
            React.createElement('span', { className: 'vl' }, spec.name)
          ),
          React.createElement('div', { className: 'row' },
            React.createElement('span', { className: 'nm' }, 'subject'),
            React.createElement('span', { className: 'vl' }, spec.subject)
          ),
          React.createElement('div', { className: 'row' },
            React.createElement('span', { className: 'nm' }, 'captured'),
            React.createElement('span', { className: 'vl' }, spec.captured)
          ),
          React.createElement('div', { className: 'row' },
            React.createElement('span', { className: 'nm' }, 'method'),
            React.createElement('span', { className: 'vl' }, spec.method)
          ),
          React.createElement('div', { className: 'row' },
            React.createElement('span', { className: 'nm' }, 'shaders'),
            React.createElement('span', { className: 'vl signal' }, spec.shaders)
          )
        ),

        React.createElement('div', { className: 'io-dm-row' },
          React.createElement('h4', null,
            '↳ DESIGN MARK',
            extracted.length > 0 && React.createElement('span', { className: 'ct' }, extracted.length + ' ×')
          ),
          React.createElement('button', {
            className: 'io-dm-skip',
            onClick: () => { setModalSpecId(activeId); setShowModal(true); }
          }, 'VIEW →')
        ),

        extractLog.length === 0
          ? React.createElement('div', { className: 'io-tray-empty' },
              React.createElement('b', null, 'EMPTY.'),
              ' Click any region of the subject to begin extraction. Layers will arrive here.'
            )
          : extractLog.filter(e => e.specimen === spec.n).map(e =>
              React.createElement('div', { className: 'io-extract', key: e.id },
                React.createElement('div', { className: 'eh' },
                  React.createElement('span', { className: 'etag' }, '↳ ' + e.label),
                  React.createElement('span', { className: 'estamp' }, e.stamp)
                ),
                React.createElement('div', {
                  className: 'ejson',
                  dangerouslySetInnerHTML: { __html: e.payload }
                })
              )
            ),

        isComplete && React.createElement('div', { className: 'io-complete' },
          React.createElement('b', null, '✓ DESIGN MARK COMPLETE'),
          React.createElement('br'),
          extracted.length + ' LAYERS · SCROLL ↓ TO CONTINUE'
        )
      )
    ),

    /* SECTION 2: THE NARRATIVE (wire) */
    React.createElement(Narrative, {
      onOpenMark: () => { setModalSpecId(activeId); setShowModal(true); },
      activeSpec: spec
    }),

    /* WAITLIST */
    React.createElement(window.WaitlistStrip, null),

    /* FULLSCREEN OVERLAY */
    fullscreenId && React.createElement(FullscreenOverlay, {
      specId: fullscreenId,
      extractsBySpecimen: extractsBySpecimen,
      onIncise: (zoneId) => incise(zoneId, fullscreenId),
      onClose: () => {
        const id = fullscreenId;
        const extr = extractsBySpecimen[id] || [];
        setFullscreenId(null);
        if (extr.length >= 5) {
          setModalSpecId(id);
          setTimeout(() => setShowModal(true), 440);
        }
      },
      origin: fullscreenOrigin
    }),

    /* DESIGN MARK MODAL */
    showModal && modalSpecId && React.createElement(DesignMarkModal, {
      spec: SPECIMENS.find(s => s.id === modalSpecId),
      onClose: () => setShowModal(false)
    })
  );
}

function FullscreenOverlay({ specId, extractsBySpecimen, onIncise, onClose, origin }) {
  const spec = SPECIMENS.find(s => s.id === specId);
  const zones = ZONE_LAYOUTS[specId] || [];
  const extracted = extractsBySpecimen[specId] || [];
  const imgSrc = 'assets/screenshots/' + (SCREENSHOT_MAP[specId] || 'framer') + '.png';
  const overlayRef = React.useRef(null);
  const chromeRef = React.useRef(null);
  const scrollRef = React.useRef(null);
  const closing = React.useRef(false);

  React.useEffect(() => {
    document.body.style.overflow = 'hidden';
    const from = origin || 'inset(40% 30% 40% 30%)';

    /* 1 — outer shell: clip-path expand with spring overshoot */
    if (overlayRef.current) {
      overlayRef.current.animate(
        [
          { clipPath: from, opacity: 0 },
          { clipPath: 'inset(-1% -1% -1% -1%)', opacity: 1, offset: 0.7 },
          { clipPath: 'inset(0% 0% 0% 0%)', opacity: 1 }
        ],
        { duration: 640, easing: 'cubic-bezier(.22, 1, .36, 1)', fill: 'forwards' }
      );
    }

    /* 2 — scroll area: starts slightly scaled in, zooms out to natural */
    if (scrollRef.current) {
      scrollRef.current.animate(
        [{ transform: 'scale(1.06)', opacity: 0 }, { transform: 'scale(1)', opacity: 1 }],
        { duration: 520, delay: 60, easing: 'cubic-bezier(.22,1,.36,1)', fill: 'forwards' }
      );
    }

    /* 3 — chrome bar slides down from top */
    if (chromeRef.current) {
      chromeRef.current.animate(
        [{ transform: 'translateY(-100%)', opacity: 0 }, { transform: 'translateY(0)', opacity: 1 }],
        { duration: 380, delay: 160, easing: 'cubic-bezier(.22,1,.36,1)', fill: 'forwards' }
      );
    }

    return () => { document.body.style.overflow = ''; };
  }, []);

  function handleClose() {
    if (closing.current) return;
    closing.current = true;
    const to = origin || 'inset(40% 30% 40% 30%)';

    /* content scales away while overlay collapses */
    if (scrollRef.current) {
      scrollRef.current.animate(
        [{ transform: 'scale(1)' }, { transform: 'scale(1.04)', opacity: 0 }],
        { duration: 280, easing: 'ease-in', fill: 'forwards' }
      );
    }
    if (chromeRef.current) {
      chromeRef.current.animate(
        [{ opacity: 1 }, { opacity: 0 }],
        { duration: 160, easing: 'ease-in', fill: 'forwards' }
      );
    }
    if (overlayRef.current) {
      const a = overlayRef.current.animate(
        [
          { clipPath: 'inset(0% 0% 0% 0%)', opacity: 1 },
          { clipPath: to, opacity: 0 }
        ],
        { duration: 380, delay: 40, easing: 'cubic-bezier(.76, 0, .7, .7)', fill: 'forwards' }
      );
      a.onfinish = onClose;
    } else {
      onClose();
    }
  }

  return React.createElement('div', {
    className: 'io-fullscreen',
    ref: overlayRef,
    onClick: handleClose
  },
    React.createElement('div', { className: 'io-fs-chrome', ref: chromeRef, onClick: e => e.stopPropagation() },
      React.createElement('div', { className: 'io-fs-chrome-l' },
        React.createElement('span', null, 'SOURCE ', React.createElement('b', null, spec.n)),
        React.createElement('span', null, spec.name),
        React.createElement('span', { className: 'io-fs-hint' }, 'CLICK REGIONS TO EXTRACT · ESC TO CLOSE')
      ),
      React.createElement('button', { className: 'io-fs-close', onClick: handleClose }, '✕ CLOSE')
    ),
    React.createElement('div', { className: 'io-fs-scroll', ref: scrollRef, onClick: e => e.stopPropagation() },
      React.createElement('div', { className: 'io-fs-img-wrap' },
        React.createElement('img', { src: imgSrc, alt: spec.name, className: 'io-fs-img', draggable: false }),
        zones.map(z =>
          React.createElement('div', {
            key: z.id,
            className: 'io-fs-zone' + (extracted.includes(z.id) ? ' locked' : ''),
            style: { top: z.top, left: z.left, width: z.width, height: z.height },
            'data-tag-pos': z.tagPos,
            onClick: (e) => { e.stopPropagation(); onIncise(z.id); }
          },
            React.createElement('span', { className: 'fztag fztag-' + z.tagPos }, '✚ ' + z.label)
          )
        )
      )
    )
  );
}

const CLONE_JOB_FILES = {
  'spec-014': 'assets/clones/framer.json',
  'spec-011': 'assets/clones/linear.json',
  'spec-009': 'assets/clones/stripe.json',
  'spec-007': 'assets/clones/vercel.json',
  'spec-005': 'assets/clones/notion.json',
  'spec-002': 'assets/clones/raycast.json'
};

function DesignMarkModal({ spec, onClose }) {
  const [copied, setCopied] = React.useState(false);
  const [raw, setRaw] = React.useState(null);
  const [loading, setLoading] = React.useState(true);
  const [highlighted, setHighlighted] = React.useState('');

  React.useEffect(() => {
    setLoading(true);
    setRaw(null);
    const path = CLONE_JOB_FILES[spec.id];
    fetch(path)
      .then(r => r.json())
      .then(data => {
        const str = JSON.stringify(data, null, 2);
        setRaw(str);
        setHighlighted(syntaxHighlightJson(data));
        setLoading(false);
      })
      .catch(() => { setRaw('// failed to load'); setLoading(false); });
  }, [spec.id]);

  function copy() {
    if (!raw) return;
    const fallback = () => {
      const ta = document.createElement('textarea');
      ta.value = raw;
      document.body.appendChild(ta);
      ta.select();
      document.execCommand('copy');
      document.body.removeChild(ta);
    };
    (navigator.clipboard ? navigator.clipboard.writeText(raw).catch(fallback) : Promise.resolve(fallback()));
    setCopied(true);
    setTimeout(() => setCopied(false), 2000);
  }

  return React.createElement('div', {
    className: 'io-dm-backdrop',
    onClick: e => { if (e.target === e.currentTarget) onClose(); }
  },
    React.createElement('div', { className: 'io-dm-dialog' },
      React.createElement('div', { className: 'io-dm-chrome' },
        React.createElement('div', { className: 'io-dm-chrome-l' },
          React.createElement('span', null, 'CLONE JOB · ', React.createElement('b', null, spec.n)),
          React.createElement('span', null, spec.name)
        )
      ),
      React.createElement('div', { className: 'io-dm-scroll' },
        loading
          ? React.createElement('div', { className: 'io-dm-loading' }, 'LOADING CLONE JOB…')
          : React.createElement('pre', {
              className: 'io-dm-pre',
              dangerouslySetInnerHTML: { __html: highlighted }
            })
      ),
      React.createElement('div', { className: 'io-dm-footer' },
        React.createElement('span', null, 'inoculate add ' + spec.name),
        React.createElement('div', { className: 'io-dm-actions' },
          React.createElement('button', {
            className: 'io-dm-copy' + (copied ? ' copied' : ''),
            onClick: copy,
            disabled: loading
          }, copied ? '✓ COPIED' : 'COPY JSON'),
          React.createElement('button', { className: 'io-dm-close-btn', onClick: onClose }, '✕ CLOSE')
        )
      )
    )
  );
}

/* ── Design Identity Card — station 04 rebrand panel ── */
function DesignIdentityCard({ spec }) {
  const marks = window.DESIGN_MARKS || REAL_MARKS;
  const mark = marks[spec.id] || marks['spec-014'];
  const colors = (mark.designTokens || {}).colorSemantics || {};
  const typo = (mark.designTokens || {}).typographySystem || '';
  const comp = mark.compositionProfile || {};
  const motion = mark.motionConstitution || {};

  const swatches = Object.entries(colors).slice(0, 4);
  const [typeFace, typeScale] = typo.split(';').map(s => s.trim());
  const alwaysAnimate = (motion.alwaysAnimate || []).join(' · ');

  return React.createElement('div', { className: 'rb-mark-panel dm-id-card' },
    React.createElement('div', { className: 'rb-mark-chrome' },
      React.createElement('div', { className: 'rb-mark-chrome-l' },
        React.createElement('span', null, 'DESIGN MARK · ', React.createElement('b', null, spec.n)),
        React.createElement('span', null, spec.name)
      )
    ),
    React.createElement('div', { className: 'dm-id-body' },
      /* Palette */
      React.createElement('div', { className: 'dm-id-section' },
        React.createElement('div', { className: 'dm-id-label' }, 'PALETTE'),
        React.createElement('div', { className: 'dm-id-swatches' },
          swatches.map(([k, v]) =>
            React.createElement('div', { key: k, className: 'dm-id-swatch' },
              React.createElement('div', { className: 'dm-id-swatch-block', style: { background: v } }),
              React.createElement('div', { className: 'dm-id-swatch-name' }, k),
              React.createElement('div', { className: 'dm-id-swatch-val' }, v)
            )
          )
        )
      ),
      /* Typography */
      React.createElement('div', { className: 'dm-id-section' },
        React.createElement('div', { className: 'dm-id-label' }, 'TYPOGRAPHY'),
        React.createElement('div', { className: 'dm-id-typo-face' }, typeFace),
        typeScale && React.createElement('div', { className: 'dm-id-typo-scale' }, typeScale)
      ),
      /* Composition + Motion */
      React.createElement('div', { className: 'dm-id-section dm-id-bottom' },
        React.createElement('div', { className: 'dm-id-col' },
          React.createElement('div', { className: 'dm-id-label' }, 'COMPOSITION'),
          React.createElement('div', { className: 'dm-id-stat' },
            React.createElement('span', null, comp.layoutPersonality),
            React.createElement('span', null, 'density ' + comp.density),
            React.createElement('span', null, comp.pacing + ' pacing'),
            React.createElement('span', null, 'asymmetry ' + comp.asymmetry)
          )
        ),
        React.createElement('div', { className: 'dm-id-col' },
          React.createElement('div', { className: 'dm-id-label' }, 'MOTION'),
          React.createElement('div', { className: 'dm-id-stat' },
            React.createElement('span', null, motion.alwaysAnimate ? 'always: ' + alwaysAnimate : ''),
            React.createElement('span', { className: 'dm-id-motion-stmt' }, motion.constitutionStatement)
          )
        )
      )
    )
  );
}

/* ── Inline join form — station 06 ── */
function InlineJoinForm() {
  const [open, setOpen] = React.useState(false);
  const [done, setDone] = React.useState(false);
  const [email, setEmail] = React.useState('');
  const [submitting, setSubmitting] = React.useState(false);
  const inputRef = React.useRef(null);

  function handleOpen() {
    setOpen(true);
    setTimeout(() => inputRef.current && inputRef.current.focus(), 350);
  }

  function handleSubmit(e) {
    e.preventDefault();
    if (!email.trim() || submitting) return;
    setSubmitting(true);
    fetch('https://formspree.io/f/xvzyvvej', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' },
      body: JSON.stringify({ email: email.trim() })
    }).finally(() => setDone(true));
  }

  if (done) {
    return React.createElement('div', { className: 'join-success' }, 'joined waitlist.');
  }

  return React.createElement('form', {
    className: 'join-pill' + (open ? ' join-pill--open' : ''),
    onSubmit: open ? handleSubmit : e => { e.preventDefault(); handleOpen(); }
  },
    React.createElement('input', {
      ref: inputRef,
      type: 'email',
      className: 'join-pill-input',
      placeholder: 'your@email.com',
      value: email,
      onChange: e => setEmail(e.target.value),
      tabIndex: open ? 0 : -1,
      'aria-hidden': !open
    }),
    React.createElement('button', {
      type: 'submit',
      className: 'join-pill-btn',
      disabled: submitting
    }, open ? (submitting ? '…' : '→') : 'JOIN WAITLIST →')
  );
}

/* ─────────────────────────────────────────────
   NARRATIVE — horizontal scroll fed by vertical scroll
   ───────────────────────────────────────────── */
function Narrative({ onOpenMark, activeSpec }) {
  const stageRef = React.useRef(null);
  const trackRef = React.useRef(null);
  const [station, setStation] = React.useState(0);

  React.useEffect(() => {
    function onScroll() {
      if (!stageRef.current || !trackRef.current) return;
      const r = stageRef.current.getBoundingClientRect();
      const vh = window.innerHeight - 44;
      const totalHeight = r.height - vh;
      const scrolled = Math.max(0, -r.top);
      const p = Math.max(0, Math.min(1, scrolled / Math.max(1, totalHeight)));
      const idx = Math.min(STATIONS.length - 1, Math.round(p * (STATIONS.length - 1)));
      setStation(idx);
      const shift = p * (STATIONS.length - 1) * 100;
      trackRef.current.style.transform = `translateX(-${shift}vw)`;
    }
    window.addEventListener('scroll', onScroll, { passive: true });
    onScroll();
    return () => window.removeEventListener('scroll', onScroll);
  }, []);

  const trackWidth = (STATIONS.length * 100) + 'vw';

  return React.createElement('section', { className: 'io-narrative', ref: stageRef },
    React.createElement('div', { className: 'io-narrative-sticky' },

      React.createElement('div', { className: 'io-narrative-prog' },
        React.createElement('span', null, 'NARRATIVE · ', React.createElement('b', null, String(station + 1).padStart(2, '0') + ' / ' + String(STATIONS.length).padStart(2, '0'))),
        React.createElement('div', { className: 'rail' },
          React.createElement('div', { className: 'fl', style: { width: ((station / (STATIONS.length - 1)) * 100) + '%' } }),
          React.createElement('div', { className: 'ticks' },
            STATIONS.map((s, i) =>
              React.createElement('span', { key: i, className: 'tick' + (i <= station ? ' passed' : '') })
            )
          )
        ),
        React.createElement('span', null, '↳ ', React.createElement('b', { className: 'signal' }, STATIONS[station].label))
      ),

      React.createElement('div', { className: 'io-narrative-track', ref: trackRef, style: { width: trackWidth } },

        /* STATION 01 · WHAT IS A DESIGN MARK */
        React.createElement('div', { className: 'io-station' },
          React.createElement('div', { className: 'io-station-header' },
            React.createElement('span', { className: 'num' }, '01'),
            React.createElement('span', null, '↳ ', React.createElement('b', null, STATIONS[0].label))
          ),
          React.createElement('div', { className: 'io-station-body st-define' },
            React.createElement('div', null,
              React.createElement('h2', null,
                'You just made a ',
                React.createElement('em', null, 'Design Mark.')
              ),
              React.createElement('p', null,
                React.createElement('b', null, 'A Design Mark is a structured description of what a site IS.'),
                ' Not a theme. Not tokens. A position. Color semantics, motion constitution, anti-defaults, taste vector. Every region you clicked extracted one layer.'
              ),
              React.createElement('p', null,
                'Your AI agent reads it. Generated frontend stops looking like every other AI-built site on the internet.'
              )
            ),
            React.createElement(BeforeAfter, null)
          )
        ),

        /* STATION 02 · HOW IT WORKS */
        React.createElement('div', { className: 'io-station' },
          React.createElement('div', { className: 'io-station-header' },
            React.createElement('span', { className: 'num' }, '02'),
            React.createElement('span', null, '↳ ', React.createElement('b', null, STATIONS[1].label))
          ),
          React.createElement('div', { className: 'io-station-body st-how' },
            React.createElement('h2', null, 'Capture. Classify. ', React.createElement('em', null, 'Write.')),
            React.createElement('div', { className: 'steps' },
              React.createElement('div', { className: 'st-step' },
                React.createElement('span', { className: 'num' }, '01'),
                React.createElement('div', null,
                  React.createElement('h3', null, 'CAPTURE'),
                  React.createElement('p', null, 'Headless browser intercepts every WebGL call, every CSS property, every uniform trajectory across 60 scroll steps.')
                )
              ),
              React.createElement('div', { className: 'st-step' },
                React.createElement('span', { className: 'num' }, '02'),
                React.createElement('div', null,
                  React.createElement('h3', null, 'CLASSIFY'),
                  React.createElement('p', null, 'IDF-weighted scoring surfaces site-specific code. R² classification routes each motion into one of four archetypes. Library noise is rejected.')
                )
              ),
              React.createElement('div', { className: 'st-step' },
                React.createElement('span', { className: 'num' }, '03'),
                React.createElement('div', null,
                  React.createElement('h3', null, 'WRITE'),
                  React.createElement('p', null, 'The output is a recursive JSON artifact. Drop it at your project root. Your agent reads it as constraint, not suggestion.')
                )
              )
            )
          )
        ),

        /* STATION 03 · WHAT WE BUILT — animated CLI */
        React.createElement('div', { className: 'io-station' },
          React.createElement('div', { className: 'io-station-header' },
            React.createElement('span', { className: 'num' }, '03'),
            React.createElement('span', null, '↳ ', React.createElement('b', null, STATIONS[2].label))
          ),
          React.createElement('div', { className: 'io-station-body st-cli' },
            React.createElement('div', { className: 'st-cli-left' },
              React.createElement('h2', null, 'One command.', React.createElement('br'), React.createElement('em', null, 'Design Mark.')),
              React.createElement('p', { className: 'tagline' },
                'Point at any site you admire. Inoculate captures its motion, color, type, and anti-defaults — then writes a portable artifact your agent can read as hard constraint.'
              ),
              React.createElement('div', { className: 'cli-stats' },
                React.createElement('div', { className: 'cstat' },
                  React.createElement('span', { className: 'cstat-n' }, 'any'),
                  React.createElement('span', { className: 'cstat-l' }, 'SITE YOU ADMIRE')
                ),
                React.createElement('div', { className: 'cstat' },
                  React.createElement('span', { className: 'cstat-n' }, '4'),
                  React.createElement('span', { className: 'cstat-l' }, 'EXTRACTION METHODS')
                ),
                React.createElement('div', { className: 'cstat' },
                  React.createElement('span', { className: 'cstat-n' }, '16'),
                  React.createElement('span', { className: 'cstat-l' }, 'ARTIFACT KEYS')
                )
              )
            ),
            React.createElement('div', { className: 'st-cli-right' },
              React.createElement(CliTerminal, { isActive: station === 2 })
            )
          )
        ),

        /* STATION 04 · REBRAND */
        React.createElement('div', { className: 'io-station io-station-rebrand' },
          React.createElement('div', { className: 'io-station-header' },
            React.createElement('span', { className: 'num' }, '04'),
            React.createElement('span', null, '↳ ', React.createElement('b', null, STATIONS[3].label))
          ),
          React.createElement('div', { className: 'io-station-body st-rebrand' },
            /* LEFT — copy + CTA */
            React.createElement('div', { className: 'st-rebrand-left' },
              React.createElement('h2', null, 'Clone it. Make it ', React.createElement('em', null, 'yours.')),
              React.createElement('p', null,
                React.createElement('b', null, 'One command.'),
                ' inoculate captures any site and writes its design mark to your project — taste vector, palette, motion constitution, anti-defaults.'
              ),
              React.createElement('p', null,
                'Then you step in. Delete what doesn\'t belong. Adjust values. Iterate until the mark is distinct enough to be yours. You or your agent — both work.'
              ),
              React.createElement('button', {
                className: 'rb-add-btn',
                onClick: onOpenMark
              },
                React.createElement('span', { className: 'rb-prompt' }, '$ '),
                'inoculate add ',
                React.createElement('span', { className: 'rb-url' }, '[site]'),
                React.createElement('span', { className: 'rb-arrow' }, ' →')
              ),
            ),
            /* RIGHT — design identity card (active specimen) */
            React.createElement(DesignIdentityCard, { spec: activeSpec || SPECIMENS[0] })
          )
        ),

        /* STATION 05 · MANIFESTO */
        React.createElement('div', { className: 'io-station' },
          React.createElement('div', { className: 'io-station-header' },
            React.createElement('span', { className: 'num' }, '05'),
            React.createElement('span', null, '↳ ', React.createElement('b', null, STATIONS[4].label))
          ),
          React.createElement('div', { className: 'io-station-body st-mani' },
            React.createElement('div', { className: 'st-mani-text' },
              'Prompts don\'t have ',
              React.createElement('em', null, 'taste'),
              '. Designed sites do. The gap between them is the ',
              React.createElement('em', null, 'extraction layer'),
              '.',
              React.createElement('span', { className: 'sig' }, '— Founder')
            )
          )
        ),

        /* STATION 06 · CTA */
        React.createElement('div', { className: 'io-station' },
          React.createElement('div', { className: 'io-station-header' },
            React.createElement('span', { className: 'num' }, '06'),
            React.createElement('span', null, '↳ ', React.createElement('b', null, STATIONS[5].label))
          ),
          React.createElement('div', { className: 'io-station-body st-cta' },
            React.createElement('h2', null, 'Request ', React.createElement('em', null, 'early access.')),
            React.createElement('p', null, "Closed beta opens summer 2026. Drop an email below — we'll reach out."),
            React.createElement(InlineJoinForm, null)
          )
        )
      )
    )
  );
}

ReactDOM.createRoot(document.getElementById('app')).render(
  React.createElement(Site, null)
);
