/**
 * Build a fully-formed product webpage that demonstrates a design system in
 * action — not just a list of tokens, but a real-feeling marketing /
 * product page (nav, hero, social proof, feature grid, dashboard preview,
 * pricing, testimonials, FAQ, CTA, footer) styled entirely from the
 * tokens we extract from the system's DESIGN.md.
 *
 * Same parsing utilities as design-system-preview.js — kept inline rather
 * than imported so the two views can evolve independently.
 */
export function renderDesignSystemShowcase(id, raw) {
    const titleMatch = /^#\s+(.+?)\s*$/m.exec(raw);
    const rawTitle = titleMatch?.[1] ?? id;
    const title = cleanTitle(rawTitle);
    const subtitle = extractSubtitle(raw) || 'A design system rendered as a real product surface.';
    const colors = extractColors(raw);
    const fonts = extractFonts(raw);
    // Hints are matched against each color's role description (the prose that
    // follows the name in DESIGN.md, e.g. "Primary background.") first, then
    // against the color name. We use word-boundary matching so descriptive
    // names like "Cardinal Red" don't accidentally satisfy a "card" hint and
    // "Gem Pink" doesn't satisfy "ink".
    // Hint ordering matters: more specific phrases come first so a system
    // with both "Primary background" and "Page background in light mode" (e.g.
    // Linear's marketing black + light-mode escape hatch) lands on the
    // dominant role rather than the light-mode subtitle. We drop 'page
    // background' from the bg hints entirely because in practice it almost
    // always belongs to a secondary, light-mode-only entry.
    const bg = pickColor(colors, ['primary background', 'background', 'canvas', 'paper'])
        ?? firstLightish(colors)
        ?? '#ffffff';
    // Exclude `bg` so a token whose hex matches the page background (for
    // example Warp's "Warm Parchment" doubling as primary text *and* the
    // firstLightish bg fallback) doesn't make body copy invisible.
    const fg = pickColor(colors, [
        'primary text',
        'body text',
        'foreground',
        'ink primary',
        'heading',
        'ink',
        'graphite',
        'navy',
    ], [bg])
        ?? pickReadableForeground(bg)
        ?? '#0a0a0a';
    const accent = pickColor(colors, [
        'brand primary',
        'primary brand',
        'primary cta',
        'gradient origin',
        'brand mark',
        'brand color',
    ])
        ?? firstNonNeutral(colors, [bg, fg])
        ?? '#2f6feb';
    const accent2 = pickColor(colors, [
        'brand secondary',
        'secondary brand',
        'gradient terminus',
        'tertiary brand',
        'tertiary',
        'highlight',
    ])
        ?? secondNonNeutral(colors, [accent, bg, fg])
        ?? accent;
    const muted = pickColor(colors, ['secondary text', 'caption', 'metadata', 'placeholder', 'muted', 'subtle'])
        ?? '#666666';
    const border = pickColor(colors, ['border', 'divider', 'hairline', 'rule', 'stroke'])
        ?? '#e6e6e6';
    const surface = pickColor(colors, [
        'secondary surface',
        'section break',
        'sidebar',
        'surface subtle',
        'surface',
        'panel',
        'elevated',
        'card surface',
    ])
        ?? mixSurface(bg);
    const display = fonts.display ?? fonts.heading ?? "system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif";
    const body = fonts.body ?? display;
    const mono = fonts.mono ?? "ui-monospace, 'JetBrains Mono', monospace";
    const accentFg = pickReadableForeground(accent);
    const accent2Fg = pickReadableForeground(accent2);
    const productName = title;
    const tagline = oneLine(subtitle).slice(0, 120);
    return `<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <title>${escapeHtml(productName)} — showcase</title>
  <style>
    :root {
      --bg: ${bg};
      --fg: ${fg};
      --accent: ${accent};
      --accent-fg: ${accentFg};
      --accent-2: ${accent2};
      --accent-2-fg: ${accent2Fg};
      --muted: ${muted};
      --border: ${border};
      --surface: ${surface};
      --display: ${display};
      --body: ${body};
      --mono: ${mono};
    }
    * { box-sizing: border-box; }
    html, body { margin: 0; padding: 0; }
    body {
      background: var(--bg);
      color: var(--fg);
      font-family: var(--body);
      line-height: 1.6;
      font-size: 16px;
      -webkit-font-smoothing: antialiased;
    }
    a { color: inherit; text-decoration: none; }
    img { max-width: 100%; display: block; }
    .container { max-width: 1180px; margin: 0 auto; padding: 0 28px; }

    /* Nav */
    .nav {
      position: sticky; top: 0; z-index: 30;
      background: rgba(255,255,255,0.7);
      backdrop-filter: saturate(180%) blur(14px);
      border-bottom: 1px solid var(--border);
    }
    .nav-row {
      display: flex; align-items: center; gap: 32px;
      height: 64px;
    }
    .brand { display: flex; align-items: center; gap: 10px; font-family: var(--display); font-weight: 700; font-size: 17px; letter-spacing: -0.01em; }
    .brand-mark {
      width: 26px; height: 26px; border-radius: 7px;
      background: linear-gradient(135deg, var(--accent), var(--accent-2));
    }
    .nav-links { display: flex; gap: 22px; font-size: 14px; color: var(--muted); }
    .nav-links a:hover { color: var(--fg); }
    .nav-spacer { flex: 1; }
    .nav-cta {
      display: inline-flex; align-items: center; gap: 6px;
      background: var(--fg); color: var(--bg);
      padding: 8px 14px; border-radius: 8px; font-size: 13px; font-weight: 500;
    }
    .nav-link-cta { color: var(--fg); font-weight: 500; font-size: 14px; }

    /* Hero */
    .hero { padding: 96px 0 72px; }
    .hero-eyebrow {
      display: inline-flex; align-items: center; gap: 8px;
      font-family: var(--mono); font-size: 12px; color: var(--muted);
      text-transform: uppercase; letter-spacing: 0.08em;
      padding: 6px 12px; border: 1px solid var(--border); border-radius: 999px;
      background: var(--surface);
      margin-bottom: 24px;
    }
    .hero-eyebrow .dot { width: 6px; height: 6px; border-radius: 50%; background: var(--accent); }
    .hero h1 {
      font-family: var(--display);
      font-size: clamp(44px, 6.6vw, 84px);
      line-height: 1.02;
      letter-spacing: -0.025em;
      margin: 0 0 22px;
      max-width: 18ch;
      font-weight: 700;
    }
    .hero h1 em { font-style: normal; background: linear-gradient(120deg, var(--accent), var(--accent-2)); -webkit-background-clip: text; background-clip: text; color: transparent; }
    .hero p.lede {
      font-size: 19px; color: var(--muted);
      max-width: 56ch; margin: 0 0 36px;
    }
    .hero-actions { display: flex; gap: 12px; flex-wrap: wrap; align-items: center; }
    .btn {
      font: inherit; cursor: pointer; border-radius: 10px;
      padding: 13px 22px; font-size: 14.5px; font-weight: 500;
      border: 1px solid transparent; display: inline-flex; align-items: center; gap: 8px;
    }
    .btn-primary { background: var(--accent); color: var(--accent-fg); border-color: var(--accent); }
    .btn-primary:hover { filter: brightness(1.06); }
    .btn-ghost { background: transparent; color: var(--fg); border-color: var(--border); }
    .btn-ghost:hover { background: var(--surface); }
    .hero-meta { display: flex; gap: 24px; margin-top: 44px; color: var(--muted); font-size: 13px; }
    .hero-meta span strong { color: var(--fg); font-weight: 600; }

    /* Logo strip */
    .logos { padding: 36px 0; border-top: 1px solid var(--border); border-bottom: 1px solid var(--border); }
    .logos-label { font-size: 12px; color: var(--muted); text-align: center; letter-spacing: 0.08em; text-transform: uppercase; margin-bottom: 18px; }
    .logos-row { display: flex; flex-wrap: wrap; justify-content: center; gap: 44px; align-items: center; opacity: 0.85; }
    .logo-pill { font-family: var(--display); font-weight: 700; font-size: 17px; letter-spacing: -0.01em; color: var(--muted); }

    /* Features grid */
    .section { padding: 96px 0; }
    .section-eyebrow { font-family: var(--mono); text-transform: uppercase; letter-spacing: 0.1em; font-size: 12px; color: var(--accent); margin-bottom: 12px; }
    .section-title { font-family: var(--display); font-size: clamp(32px, 4.2vw, 48px); letter-spacing: -0.02em; line-height: 1.1; margin: 0 0 18px; max-width: 22ch; font-weight: 700; }
    .section-lede { color: var(--muted); font-size: 17px; max-width: 56ch; margin: 0 0 48px; }
    .features {
      display: grid; gap: 18px;
      grid-template-columns: repeat(3, 1fr);
    }
    @media (max-width: 920px) { .features { grid-template-columns: 1fr 1fr; } }
    @media (max-width: 600px) { .features { grid-template-columns: 1fr; } }
    .feature {
      background: var(--surface); border: 1px solid var(--border); border-radius: 14px;
      padding: 26px; display: flex; flex-direction: column; gap: 12px;
    }
    .feature-icon {
      width: 36px; height: 36px; border-radius: 8px;
      background: linear-gradient(135deg, var(--accent), var(--accent-2));
      color: var(--accent-fg);
      display: inline-flex; align-items: center; justify-content: center;
      font-size: 18px; font-weight: 700;
    }
    .feature h3 { font-family: var(--display); font-size: 18px; margin: 0; letter-spacing: -0.01em; }
    .feature p { color: var(--muted); margin: 0; font-size: 14.5px; line-height: 1.55; }

    /* Product preview / dashboard mock */
    .preview-wrap { padding-top: 24px; padding-bottom: 96px; }
    .preview-frame {
      background: var(--surface); border: 1px solid var(--border); border-radius: 18px;
      padding: 14px;
      box-shadow: 0 30px 80px rgba(0,0,0,0.06), 0 12px 30px rgba(0,0,0,0.04);
    }
    .preview-titlebar { display: flex; gap: 6px; padding: 4px 8px 12px; }
    .preview-titlebar span { width: 10px; height: 10px; border-radius: 50%; background: var(--border); }
    .preview-app {
      background: var(--bg); border: 1px solid var(--border); border-radius: 12px;
      display: grid; grid-template-columns: 220px 1fr; min-height: 440px; overflow: hidden;
    }
    .preview-side { background: var(--surface); border-right: 1px solid var(--border); padding: 18px 14px; display: flex; flex-direction: column; gap: 4px; }
    .side-link { display: flex; align-items: center; gap: 10px; padding: 8px 10px; border-radius: 8px; font-size: 13.5px; color: var(--muted); }
    .side-link.active { background: var(--bg); color: var(--fg); font-weight: 500; box-shadow: inset 0 0 0 1px var(--border); }
    .side-link .dot { width: 6px; height: 6px; border-radius: 50%; background: var(--accent); }
    .side-section { font-family: var(--mono); text-transform: uppercase; font-size: 10px; letter-spacing: 0.08em; color: var(--muted); padding: 14px 10px 6px; }
    .preview-main { padding: 22px 24px; display: flex; flex-direction: column; gap: 22px; }
    .preview-head { display: flex; align-items: center; justify-content: space-between; }
    .preview-head h4 { font-family: var(--display); font-size: 22px; margin: 0; letter-spacing: -0.01em; }
    .kpi-row { display: grid; grid-template-columns: repeat(4, 1fr); gap: 14px; }
    .kpi { background: var(--surface); border: 1px solid var(--border); border-radius: 10px; padding: 14px 16px; }
    .kpi .label { font-size: 11.5px; color: var(--muted); text-transform: uppercase; letter-spacing: 0.06em; }
    .kpi .value { font-family: var(--display); font-size: 24px; font-weight: 700; margin-top: 4px; letter-spacing: -0.01em; }
    .kpi .delta { font-family: var(--mono); font-size: 11.5px; margin-top: 2px; color: var(--accent); }
    .chart-card { background: var(--surface); border: 1px solid var(--border); border-radius: 12px; padding: 18px; }
    .chart-head { display: flex; justify-content: space-between; align-items: baseline; margin-bottom: 8px; }
    .chart-head .title { font-weight: 600; font-size: 14px; }
    .chart-head .meta { font-family: var(--mono); font-size: 11px; color: var(--muted); }
    .chart svg { width: 100%; height: 160px; display: block; }
    .preview-row-2 { display: grid; grid-template-columns: 1.6fr 1fr; gap: 14px; }
    .list-card { background: var(--surface); border: 1px solid var(--border); border-radius: 12px; }
    .list-row { display: grid; grid-template-columns: 1fr auto auto; gap: 12px; padding: 12px 16px; border-top: 1px solid var(--border); align-items: center; }
    .list-row:first-of-type { border-top: none; }
    .list-row .name { font-weight: 500; font-size: 13.5px; }
    .list-row .meta { font-family: var(--mono); font-size: 11.5px; color: var(--muted); }
    .badge { display: inline-flex; align-items: center; gap: 6px; padding: 3px 8px; border-radius: 999px; font-size: 11px; font-weight: 500; background: var(--bg); border: 1px solid var(--border); color: var(--muted); }
    .badge.up { color: var(--accent); border-color: color-mix(in srgb, var(--accent) 30%, transparent); }
    .list-card .head { display: flex; justify-content: space-between; align-items: baseline; padding: 14px 16px; border-bottom: 1px solid var(--border); }
    .list-card .head h5 { margin: 0; font-size: 14px; }

    /* Pricing */
    .pricing { display: grid; grid-template-columns: repeat(3, 1fr); gap: 18px; }
    @media (max-width: 920px) { .pricing { grid-template-columns: 1fr; } }
    .price-card {
      background: var(--surface); border: 1px solid var(--border); border-radius: 16px;
      padding: 28px; display: flex; flex-direction: column; gap: 18px;
    }
    .price-card.featured {
      background: var(--fg); color: var(--bg); border-color: var(--fg);
    }
    .price-card.featured .muted, .price-card.featured h3, .price-card.featured .price { color: var(--bg); }
    .price-card .tier-name { font-family: var(--display); font-size: 14px; font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase; color: var(--muted); }
    .price-card .price { font-family: var(--display); font-size: 44px; font-weight: 700; letter-spacing: -0.02em; line-height: 1; }
    .price-card .price small { font-size: 14px; color: var(--muted); font-weight: 400; }
    .price-card ul { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 10px; font-size: 14.5px; }
    .price-card li::before { content: "✓"; color: var(--accent); margin-right: 8px; font-weight: 700; }
    .price-card.featured li::before { color: var(--accent-2); }

    /* Testimonials */
    .quotes { display: grid; grid-template-columns: 1fr 1fr; gap: 18px; }
    @media (max-width: 760px) { .quotes { grid-template-columns: 1fr; } }
    .quote { background: var(--surface); border: 1px solid var(--border); border-radius: 14px; padding: 26px; display: flex; flex-direction: column; gap: 18px; }
    .quote p { font-size: 17px; line-height: 1.55; margin: 0; font-family: var(--display); letter-spacing: -0.01em; }
    .quote-author { display: flex; align-items: center; gap: 12px; }
    .quote-author .avatar { width: 36px; height: 36px; border-radius: 50%; background: linear-gradient(135deg, var(--accent), var(--accent-2)); }
    .quote-author .name { font-weight: 600; font-size: 13.5px; }
    .quote-author .role { font-size: 12.5px; color: var(--muted); }

    /* FAQ */
    .faq { display: grid; grid-template-columns: 1fr 1fr; gap: 14px 32px; }
    @media (max-width: 760px) { .faq { grid-template-columns: 1fr; } }
    .faq-item { padding: 18px 0; border-top: 1px solid var(--border); }
    .faq-item h4 { margin: 0 0 6px; font-family: var(--display); font-size: 17px; letter-spacing: -0.01em; }
    .faq-item p { margin: 0; color: var(--muted); font-size: 14.5px; }

    /* CTA */
    .cta {
      margin: 48px 0 96px;
      background: linear-gradient(135deg, var(--accent), var(--accent-2));
      color: var(--accent-fg);
      border-radius: 24px;
      padding: 64px 56px;
      display: grid;
      grid-template-columns: 1.4fr auto;
      gap: 32px;
      align-items: center;
    }
    @media (max-width: 760px) { .cta { grid-template-columns: 1fr; padding: 36px; } }
    .cta h2 { font-family: var(--display); font-size: clamp(28px, 4vw, 40px); letter-spacing: -0.02em; margin: 0 0 10px; line-height: 1.1; max-width: 22ch; }
    .cta p { margin: 0; opacity: 0.92; font-size: 16px; max-width: 50ch; }
    .cta .btn { background: var(--accent-fg); color: var(--accent); border: none; }
    .cta .btn-secondary { background: transparent; color: var(--accent-fg); border: 1px solid color-mix(in srgb, var(--accent-fg) 35%, transparent); }

    /* Footer */
    footer { border-top: 1px solid var(--border); padding: 36px 0 56px; color: var(--muted); font-size: 13.5px; }
    .footer-row { display: grid; grid-template-columns: 2fr 1fr 1fr 1fr; gap: 32px; margin-bottom: 32px; }
    @media (max-width: 760px) { .footer-row { grid-template-columns: 1fr 1fr; } }
    .footer-col h6 { color: var(--fg); font-family: var(--display); font-size: 13.5px; margin: 0 0 12px; font-weight: 600; }
    .footer-col a { display: block; padding: 4px 0; }
    .footer-col a:hover { color: var(--fg); }
    .footer-bottom { display: flex; justify-content: space-between; padding-top: 24px; border-top: 1px solid var(--border); }
  </style>
</head>
<body>
  <header class="nav">
    <div class="container nav-row">
      <a class="brand" href="#"><span class="brand-mark"></span>${escapeHtml(productName)}</a>
      <nav class="nav-links">
        <a href="#features">Product</a>
        <a href="#preview">Workspace</a>
        <a href="#pricing">Pricing</a>
        <a href="#faq">Docs</a>
        <a href="#faq">Customers</a>
      </nav>
      <div class="nav-spacer"></div>
      <a class="nav-link-cta" href="#">Sign in</a>
      <a class="nav-cta" href="#">Get started →</a>
    </div>
  </header>

  <main>
    <section class="hero">
      <div class="container">
        <div class="hero-eyebrow"><span class="dot"></span>${escapeHtml(productName)} · live preview</div>
        <h1>The system that makes <em>${escapeHtml(productName)}</em> feel like ${escapeHtml(productName)}.</h1>
        <p class="lede">${escapeHtml(tagline)}</p>
        <div class="hero-actions">
          <a class="btn btn-primary" href="#">Start a free trial →</a>
          <a class="btn btn-ghost" href="#preview">See it in action</a>
        </div>
        <div class="hero-meta">
          <span><strong>4.9</strong> · App Store rating</span>
          <span><strong>SOC 2</strong> · Type II compliant</span>
          <span><strong>120k+</strong> active teams</span>
        </div>
      </div>
    </section>

    <section class="logos">
      <div class="container">
        <div class="logos-label">Trusted by teams shipping serious work</div>
        <div class="logos-row">
          <span class="logo-pill">Northwind</span>
          <span class="logo-pill">Pioneer</span>
          <span class="logo-pill">Lattice</span>
          <span class="logo-pill">Atlas Co.</span>
          <span class="logo-pill">Voltage</span>
          <span class="logo-pill">Foundry</span>
        </div>
      </div>
    </section>

    <section class="section" id="features">
      <div class="container">
        <div class="section-eyebrow">What it does</div>
        <h2 class="section-title">Every primitive a fast team needs.</h2>
        <p class="section-lede">A system styled entirely from the tokens of ${escapeHtml(productName)} — palette, typography, surfaces, and motion. Drop it into any product and it stays in character.</p>
        <div class="features">
          ${featureCard('★', 'Tokens that compose', 'Color, type, spacing, and elevation defined once and reused across every surface — from a marketing hero to a row in a table.')}
          ${featureCard('◐', 'Light & dark in lockstep', 'Every component ships with both modes. The accent reads as confident in either context, and contrast meets WCAG AA out of the box.')}
          ${featureCard('⌘', 'Desktop-first, but mobile-honest', 'Layouts collapse from a 12-column desktop grid to a focused single column without losing density or rhythm.')}
          ${featureCard('▣', 'Production-grade primitives', '40+ components — from the obvious (button, input) to the load-bearing (data table, command bar, empty states).')}
          ${featureCard('↗', 'Designed for handoff', 'Every spec carries a Figma frame, a code snippet, and a "do/don’t" pair so engineers don’t have to guess.')}
          ${featureCard('∞', 'Built to evolve', 'Tokens version semver-style. A palette refresh ships through one file — no component code touches.')}
        </div>
      </div>
    </section>

    <section class="preview-wrap" id="preview">
      <div class="container">
        <div class="section-eyebrow">In production</div>
        <h2 class="section-title">A workspace, fully styled.</h2>
        <p class="section-lede">This is the same component library you'd use in your app — rendered with ${escapeHtml(productName)} tokens.</p>
        <div class="preview-frame">
          <div class="preview-titlebar"><span></span><span></span><span></span></div>
          <div class="preview-app">
            <aside class="preview-side">
              <div class="brand" style="margin-bottom: 14px;"><span class="brand-mark"></span>${escapeHtml(productName)}</div>
              <a class="side-link active"><span class="dot"></span>Overview</a>
              <a class="side-link">Customers</a>
              <a class="side-link">Pipeline</a>
              <a class="side-link">Reports</a>
              <a class="side-link">Automations</a>
              <div class="side-section">Workspaces</div>
              <a class="side-link">Growth</a>
              <a class="side-link">Lifecycle</a>
              <a class="side-link">Finance</a>
            </aside>
            <div class="preview-main">
              <div class="preview-head">
                <h4>Overview</h4>
                <span class="badge up">↑ 12.4% this week</span>
              </div>
              <div class="kpi-row">
                ${kpi('MRR', '$184,210', '+8.2%')}
                ${kpi('Active orgs', '2,914', '+121')}
                ${kpi('Conversion', '4.6%', '+0.4 pp')}
                ${kpi('Net retention', '113%', '+2 pp')}
              </div>
              <div class="chart-card">
                <div class="chart-head">
                  <span class="title">Revenue · last 12 weeks</span>
                  <span class="meta">USD · weekly</span>
                </div>
                <div class="chart">
                  ${inlineLineChart()}
                </div>
              </div>
              <div class="preview-row-2">
                <div class="list-card">
                  <div class="head">
                    <h5>Top accounts</h5>
                    <span class="badge">View all</span>
                  </div>
                  ${listRow('Northwind Trading', 'Annual · NA', '$48,200', 'up')}
                  ${listRow('Pioneer Robotics', 'Quarterly · EMEA', '$31,890', 'up')}
                  ${listRow('Atlas Cooperative', 'Annual · APAC', '$22,400', '')}
                  ${listRow('Foundry Group', 'Monthly · NA', '$14,750', 'up')}
                </div>
                <div class="list-card">
                  <div class="head">
                    <h5>Activity</h5>
                    <span class="badge">Live</span>
                  </div>
                  ${activityRow('Renewal closed', 'Lattice · 11m ago')}
                  ${activityRow('Trial started', 'Voltage · 22m ago')}
                  ${activityRow('Plan upgraded', 'Pioneer · 1h ago')}
                  ${activityRow('Invoice paid', 'Atlas · 2h ago')}
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
    </section>

    <section class="section" id="pricing" style="padding-top: 24px;">
      <div class="container">
        <div class="section-eyebrow">Pricing</div>
        <h2 class="section-title">Built for teams of one to one thousand.</h2>
        <p class="section-lede">Pick the plan that matches the way your team ships. Every tier ships the full token system.</p>
        <div class="pricing">
          ${priceCard('Starter', '$0', 'Free forever', ['Single user', 'All core tokens', 'Up to 3 projects', 'Community support'])}
          ${priceCard('Team', '$24', 'per seat / month', ['Unlimited projects', 'Real-time co-edit', 'Brand themes', 'Priority email support'], true)}
          ${priceCard('Enterprise', 'Custom', 'volume pricing', ['SSO + SCIM', 'Audit logs', 'Custom token schemas', 'Dedicated success manager'])}
        </div>
      </div>
    </section>

    <section class="section">
      <div class="container">
        <div class="section-eyebrow">Customers</div>
        <h2 class="section-title">Loved by teams who care about craft.</h2>
        <div class="quotes">
          ${quote('"Our marketing site, our app, and our internal dashboards finally feel like the same product. The token system is doing all the work."', 'Mira Okafor', 'Head of Design · Pioneer')}
          ${quote('"We swapped our entire design language in an afternoon. Nothing broke. That’s the line, and we crossed it."', 'Caleb Renner', 'Engineering Lead · Northwind')}
        </div>
      </div>
    </section>

    <section class="section" id="faq" style="padding-top: 24px;">
      <div class="container">
        <div class="section-eyebrow">FAQ</div>
        <h2 class="section-title">Questions, answered.</h2>
        <div class="faq">
          ${faq('Is this a Figma library, a code library, or both?', 'Both. Tokens flow from one source of truth into Figma styles and into the codegen pipeline at the same time.')}
          ${faq('Can we ship our own brand theme?', 'Yes — fork the token file, change the palette and type stack, and every component reskins automatically.')}
          ${faq('What about accessibility?', 'Color contrast meets WCAG AA on every surface. Components ship with focus rings, ARIA roles, and keyboard handling.')}
          ${faq('How do you handle dark mode?', 'Every token has a paired dark value. The system flips at the document level — no per-component overrides needed.')}
        </div>
      </div>
    </section>

    <section>
      <div class="container">
        <div class="cta">
          <div>
            <h2>Ship a product that finally feels finished.</h2>
            <p>Drop the system into your app today. The first project is on us.</p>
          </div>
          <div style="display: flex; gap: 12px; flex-wrap: wrap;">
            <a class="btn btn-primary" href="#">Start free trial</a>
            <a class="btn btn-secondary" href="#">Talk to sales</a>
          </div>
        </div>
      </div>
    </section>
  </main>

  <footer>
    <div class="container">
      <div class="footer-row">
        <div class="footer-col">
          <div class="brand" style="margin-bottom: 12px;"><span class="brand-mark"></span>${escapeHtml(productName)}</div>
          <p style="margin: 0; max-width: 38ch;">${escapeHtml(tagline)}</p>
        </div>
        <div class="footer-col"><h6>Product</h6><a href="#">Features</a><a href="#">Pricing</a><a href="#">Changelog</a><a href="#">Roadmap</a></div>
        <div class="footer-col"><h6>Company</h6><a href="#">About</a><a href="#">Customers</a><a href="#">Careers</a><a href="#">Press</a></div>
        <div class="footer-col"><h6>Resources</h6><a href="#">Docs</a><a href="#">Status</a><a href="#">Brand</a><a href="#">Contact</a></div>
      </div>
      <div class="footer-bottom">
        <span>© ${new Date().getFullYear()} ${escapeHtml(productName)}. All rights reserved.</span>
        <span>Showcase rendered from <code style="font-family: var(--mono);">design-systems/${escapeHtml(id)}/DESIGN.md</code></span>
      </div>
    </div>
  </footer>
</body>
</html>`;
}
function featureCard(icon, title, body) {
    return `<div class="feature">
    <div class="feature-icon">${escapeHtml(icon)}</div>
    <h3>${escapeHtml(title)}</h3>
    <p>${escapeHtml(body)}</p>
  </div>`;
}
function kpi(label, value, delta) {
    return `<div class="kpi">
    <div class="label">${escapeHtml(label)}</div>
    <div class="value">${escapeHtml(value)}</div>
    <div class="delta">${escapeHtml(delta)}</div>
  </div>`;
}
function listRow(name, meta, value, status) {
    const badge = status === 'up' ? '<span class="badge up">↑</span>' : '<span class="badge">·</span>';
    return `<div class="list-row">
    <div>
      <div class="name">${escapeHtml(name)}</div>
      <div class="meta">${escapeHtml(meta)}</div>
    </div>
    <div class="meta">${escapeHtml(value)}</div>
    ${badge}
  </div>`;
}
function activityRow(name, meta) {
    return `<div class="list-row">
    <div>
      <div class="name">${escapeHtml(name)}</div>
      <div class="meta">${escapeHtml(meta)}</div>
    </div>
    <div></div>
    <span class="badge">●</span>
  </div>`;
}
function priceCard(name, price, sub, features, featured = false) {
    return `<div class="price-card${featured ? ' featured' : ''}">
    <div class="tier-name">${escapeHtml(name)}</div>
    <div class="price">${escapeHtml(price)} <small>${escapeHtml(sub)}</small></div>
    <ul>${features.map((f) => `<li>${escapeHtml(f)}</li>`).join('')}</ul>
    <a class="btn ${featured ? 'btn-primary' : 'btn-ghost'}" href="#" style="${featured ? 'background: var(--accent); color: var(--accent-fg); border-color: var(--accent);' : ''}">Choose ${escapeHtml(name)}</a>
  </div>`;
}
function quote(text, name, role) {
    return `<div class="quote">
    <p>${escapeHtml(text)}</p>
    <div class="quote-author">
      <div class="avatar"></div>
      <div>
        <div class="name">${escapeHtml(name)}</div>
        <div class="role">${escapeHtml(role)}</div>
      </div>
    </div>
  </div>`;
}
function faq(q, a) {
    return `<div class="faq-item">
    <h4>${escapeHtml(q)}</h4>
    <p>${escapeHtml(a)}</p>
  </div>`;
}
function inlineLineChart() {
    // Deterministic numbers so the chart looks specific (12 weekly data points).
    const data = [38, 44, 41, 52, 49, 61, 58, 67, 71, 76, 82, 88];
    const max = Math.max(...data);
    const min = Math.min(...data);
    const w = 720;
    const h = 160;
    const padX = 8;
    const padY = 14;
    const stepX = (w - padX * 2) / (data.length - 1);
    const norm = (v) => padY + (h - padY * 2) * (1 - (v - min) / (max - min));
    const points = data.map((v, i) => `${padX + i * stepX},${norm(v).toFixed(1)}`).join(' ');
    const area = `${padX},${h} ${points} ${w - padX},${h}`;
    return `<svg viewBox="0 0 ${w} ${h}" preserveAspectRatio="none">
    <defs>
      <linearGradient id="lg" x1="0" x2="0" y1="0" y2="1">
        <stop offset="0%" stop-color="var(--accent)" stop-opacity="0.32"/>
        <stop offset="100%" stop-color="var(--accent)" stop-opacity="0"/>
      </linearGradient>
    </defs>
    <polygon points="${area}" fill="url(#lg)"/>
    <polyline points="${points}" fill="none" stroke="var(--accent)" stroke-width="2.5" stroke-linejoin="round" stroke-linecap="round"/>
    ${data.map((v, i) => `<circle cx="${padX + i * stepX}" cy="${norm(v).toFixed(1)}" r="${i === data.length - 1 ? 4 : 0}" fill="var(--accent)"/>`).join('')}
  </svg>`;
}
function extractSubtitle(raw) {
    const lines = raw.split(/\r?\n/);
    const h1 = lines.findIndex((l) => /^#\s+/.test(l));
    if (h1 === -1)
        return '';
    const after = lines.slice(h1 + 1);
    const nextHeading = after.findIndex((l) => /^#{1,6}\s+/.test(l));
    const window = (nextHeading === -1 ? after : after.slice(0, nextHeading))
        .join('\n')
        .replace(/^>\s*Category:.*$/gim, '')
        .replace(/^>\s*/gm, '')
        .trim();
    return window.split(/\n\n/)[0]?.slice(0, 240) ?? '';
}
export function extractColors(raw) {
    const colors = [];
    const seen = new Set();
    function push(name, value, role) {
        const cleanName = String(name).replace(/[*_`]+/g, '').replace(/\s+/g, ' ').trim();
        if (!cleanName || cleanName.length > 60)
            return;
        const v = normalizeHex(value);
        const key = `${cleanName.toLowerCase()}|${v}`;
        const cleanRole = String(role || '')
            .replace(/[`*_]+/g, '')
            .replace(/\s+/g, ' ')
            .trim()
            .replace(/[.;]+$/, '');
        if (seen.has(key)) {
            // Already recorded — but if this occurrence carries a richer role
            // description, upgrade the stored entry so role-based lookups don't
            // fall back to the bare name.
            if (cleanRole) {
                const existing = colors.find((c) => c.name.toLowerCase() === cleanName.toLowerCase() && c.value === v);
                if (existing && (!existing.role || cleanRole.length > existing.role.length)) {
                    existing.role = cleanRole;
                }
            }
            return;
        }
        seen.add(key);
        colors.push({ name: cleanName, value: v, role: cleanRole });
    }
    // Process the file line-by-line so multi-hex entries like Linear's
    // `**Marketing Black** (\`#010102\` / \`#08090a\`): role` don't confuse a
    // single global regex. We extract three pieces from each candidate line:
    //   - the bold (or list-prefixed) name
    //   - the FIRST hex on the line
    //   - everything after the first `:` that follows the hex (the role)
    for (const rawLine of raw.split(/\r?\n/)) {
        const line = rawLine.trim();
        if (!line)
            continue;
        // Pattern A: **Name** … #hex … : role description
        const bold = /\*\*([A-Za-z][A-Za-z0-9 /&()+_'’-]{1,40}?)\*\*([^\n]+)/.exec(line);
        if (bold) {
            const rest = bold[2] ?? '';
            const hex = /#[0-9a-fA-F]{3,8}\b/.exec(rest);
            if (hex) {
                const after = rest.slice((hex.index ?? 0) + hex[0].length);
                const colonIdx = after.search(/[:：]/);
                const role = colonIdx >= 0 ? after.slice(colonIdx + 1).trim() : '';
                push(bold[1] ?? '', hex[0], role);
                continue;
            }
        }
        // Pattern B: list-prefixed spec lines like
        //   "- Background: `#7d2ae8`" inside a ### Buttons block.
        // Also handles the `- **Name:** \`#hex\`` shape (colon inside the bold
        // wrapper) used by agentic/warm-editorial: the optional `\*{0,2}` slots
        // before the name and after the colon let us absorb the surrounding
        // `**` markers without needing a third pattern.
        // Use the name itself as the role so lookups can still see "Background"
        // and "Text" labels.
        const spec = /^[\s>*-]*\*{0,2}([A-Za-z][^:*\n]{1,40}?)\*{0,2}\s*[:：]\s*\*{0,2}\s*`?(#[0-9a-fA-F]{3,8})/.exec(line);
        if (spec) {
            push(spec[1] ?? '', spec[2] ?? '', spec[1] ?? '');
        }
    }
    return colors;
}
function extractFonts(raw) {
    const out = {};
    const re = /^[\s>*-]*\**\s*([A-Za-z][A-Za-z /]{1,30}?)\s*\**\s*[:：]\s*`?([^`\n]+?)`?$/gm;
    let m;
    while ((m = re.exec(raw)) !== null) {
        const label = (m[1] ?? '').toLowerCase();
        const value = (m[2] ?? '').trim().replace(/[*_`]+$/g, '').trim();
        if (!/[a-zA-Z]/.test(value))
            continue;
        if (value.startsWith('#'))
            continue;
        if (/display|heading|h1|title/.test(label) && !out.display)
            out.display = value;
        else if (/body|text|paragraph|copy/.test(label) && !out.body)
            out.body = value;
        else if (/mono|code/.test(label) && !out.mono)
            out.mono = value;
    }
    return out;
}
function escapeRegex(s) {
    return String(s).replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}
// Match a hint as a whole word inside `text` (case-insensitive). We use word
// boundaries so descriptive color names like "Cardinal Red" don't satisfy a
// "card" hint, and "Gem Pink" doesn't satisfy "ink" — both real bugs the
// substring-based version produced for the Duolingo and Canva showcases.
function matchesHint(text, hint) {
    if (!text)
        return false;
    const needle = hint.toLowerCase().trim();
    if (!needle)
        return false;
    const re = new RegExp(`\\b${escapeRegex(needle)}\\b`, 'i');
    return re.test(text);
}
function pickColor(colors, hints, exclude = []) {
    // Two-pass lookup: each hint is first checked against every color's role
    // description (the prose authors use to explain how the color is used)
    // and only then against the bare name. This ensures a `**Snow** … Primary
    // background.` line is recognised as the page background even though the
    // name "Snow" doesn't contain the word "background".
    // `exclude` skips colors whose hex equals an already-chosen role (e.g.
    // pass `[bg]` when picking `fg`) so two roles can't collapse to the same
    // hex and erase contrast.
    const blocked = new Set(exclude
        .map((v) => (v == null ? '' : String(v).toLowerCase()))
        .filter((v) => v.length > 0));
    const isAllowed = (c) => !blocked.has(c.value.toLowerCase());
    for (const hint of hints) {
        const byRole = colors.find((c) => isAllowed(c) && matchesHint(c.role, hint));
        if (byRole)
            return byRole.value;
        const byName = colors.find((c) => isAllowed(c) && matchesHint(c.name, hint));
        if (byName)
            return byName.value;
    }
    return null;
}
function colorSaturation(hex) {
    const v = String(hex).replace('#', '').toLowerCase();
    if (v.length !== 6)
        return 0;
    const r = parseInt(v.slice(0, 2), 16);
    const g = parseInt(v.slice(2, 4), 16);
    const b = parseInt(v.slice(4, 6), 16);
    const max = Math.max(r, g, b);
    const min = Math.min(r, g, b);
    return max === 0 ? 0 : (max - min) / max;
}
function colorLuminance(hex) {
    const v = String(hex).replace('#', '').toLowerCase();
    if (v.length !== 6)
        return 0.5;
    const r = parseInt(v.slice(0, 2), 16);
    const g = parseInt(v.slice(2, 4), 16);
    const b = parseInt(v.slice(4, 6), 16);
    return (0.299 * r + 0.587 * g + 0.114 * b) / 255;
}
function firstLightish(colors) {
    for (const c of colors) {
        if (colorSaturation(c.value) > 0.15)
            continue;
        if (colorLuminance(c.value) >= 0.92)
            return c.value;
    }
    return null;
}
function firstNonNeutral(colors, exclude = []) {
    const set = new Set(exclude.map((v) => String(v || '').toLowerCase()));
    for (const c of colors) {
        if (set.has(c.value.toLowerCase()))
            continue;
        if (colorSaturation(c.value) > 0.25)
            return c.value;
    }
    return null;
}
function secondNonNeutral(colors, exclude = []) {
    const set = new Set(exclude.map((v) => String(v || '').toLowerCase()));
    for (const c of colors) {
        if (set.has(c.value.toLowerCase()))
            continue;
        if (colorSaturation(c.value) > 0.25)
            return c.value;
    }
    return null;
}
function pickReadableForeground(hex) {
    const n = normalizeHex(hex);
    if (n.length !== 7)
        return '#ffffff';
    const r = parseInt(n.slice(1, 3), 16);
    const g = parseInt(n.slice(3, 5), 16);
    const b = parseInt(n.slice(5, 7), 16);
    const lum = (0.299 * r + 0.587 * g + 0.114 * b) / 255;
    return lum > 0.6 ? '#0a0a0a' : '#ffffff';
}
function mixSurface(bg) {
    const n = normalizeHex(bg);
    if (n.length !== 7)
        return '#fafafa';
    const r = parseInt(n.slice(1, 3), 16);
    const g = parseInt(n.slice(3, 5), 16);
    const b = parseInt(n.slice(5, 7), 16);
    const lum = (0.299 * r + 0.587 * g + 0.114 * b) / 255;
    // Lift dark backgrounds; tint light backgrounds slightly cooler.
    const adjust = lum < 0.4 ? 16 : -8;
    const fix = (v) => Math.max(0, Math.min(255, v + adjust)).toString(16).padStart(2, '0');
    return `#${fix(r)}${fix(g)}${fix(b)}`;
}
function normalizeHex(hex) {
    let h = hex.toLowerCase();
    if (h.length === 4) {
        h = '#' + h.slice(1).split('').map((c) => c + c).join('');
    }
    return h;
}
function cleanTitle(raw) {
    return String(raw).replace(/^Design System (Inspired by|for)\s+/i, '').trim();
}
function oneLine(s) {
    return String(s).replace(/\s+/g, ' ').trim();
}
function escapeHtml(s) {
    return String(s).replace(/[&<>"']/g, (c) => c === '&' ? '&amp;' : c === '<' ? '&lt;' : c === '>' ? '&gt;' : c === '"' ? '&quot;' : '&#39;');
}
//# sourceMappingURL=design-system-showcase.js.map