/* ============================================================================
 * SELECTION CONTROLS — COMPONENT PLAYGROUND  (bespoke)
 * ----------------------------------------------------------------------------
 * Selection Controls don't fit the shared variant×size×state engine: there is
 * no size axis, two independent boolean axes (selected, disabled), locked
 * glyphs (check / x), and dual-element switch geometry. So this is a dedicated
 * page — but it reuses the shared playground CHROME (playground.css) verbatim
 * so it sits visually beside its siblings, and it inherits the same .pg-back
 * link, banner, header and 9-section spine.
 *
 * The component is NEVER re-drawn. render() pulls the published component from
 * window.VendooDesignSystem_a81b7b.SelectionControls. Every value below traces
 * to a Vendoo token (tokens.css); wherever the component hardcodes a literal
 * (the switch's disabled rgba track, the literal "white" check, the 20/52/32
 * geometry) the page FLAGS the gap instead of pretending a token exists.
 * ========================================================================== */
(function () {
  const { useState, useLayoutEffect, useMemo, useRef } = React;
  const NS = window.VendooDesignSystem_a81b7b || {};
  const SelectionControls = NS.SelectionControls;

  /* ── color math (swatches + WCAG contrast) ──────────────────────────── */
  function parseColor(str) {
    if (!str) return null;
    str = str.trim();
    if (str[0] === "#") {
      let h = str.slice(1);
      if (h.length === 3) h = h.split("").map((c) => c + c).join("");
      if (h.length >= 6) return { r: parseInt(h.slice(0, 2), 16), g: parseInt(h.slice(2, 4), 16), b: parseInt(h.slice(4, 6), 16), a: h.length === 8 ? parseInt(h.slice(6, 8), 16) / 255 : 1 };
      return null;
    }
    const m = str.match(/rgba?\(([^)]+)\)/i);
    if (m) { const p = m[1].split(/[,\/]/).map((x) => x.trim()); return { r: +p[0], g: +p[1], b: +p[2], a: p[3] != null ? +p[3] : 1 }; }
    return null;
  }
  function over(top, bottom) { const a = top.a; return { r: top.r * a + bottom.r * (1 - a), g: top.g * a + bottom.g * (1 - a), b: top.b * a + bottom.b * (1 - a), a: 1 }; }
  function stack(cols) { let base = { ...cols[0], a: 1 }; for (let i = 1; i < cols.length; i++) if (cols[i]) base = over(cols[i], base); return base; }
  function relLum(c) { const f = (v) => { v /= 255; return v <= 0.03928 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4); }; return 0.2126 * f(c.r) + 0.7152 * f(c.g) + 0.0722 * f(c.b); }
  function ratio(a, b) { const l1 = relLum(a), l2 = relLum(b); const hi = Math.max(l1, l2), lo = Math.min(l1, l2); return (hi + 0.05) / (lo + 0.05); }
  function toCss(c) { return `rgb(${Math.round(c.r)}, ${Math.round(c.g)}, ${Math.round(c.b)})`; }

  /* ── enumerations ───────────────────────────────────────────────────── */
  const TYPES = [
    { key: "checkbox", name: "Checkbox", api: "Type=Checkbox", geo: "24 × 24 target · 20 box · r4", use: "multi-select" },
    { key: "radio", name: "Radio", api: "Type=Radio", geo: "24 × 24 target · 20 circle · full", use: "single-select" },
    { key: "switch", name: "Switch", api: "Type=Switch", geo: "52 × 32 track · 24 thumb · full", use: "immediate toggle" },
  ];
  const SELECTED = [{ key: false, name: "Unselected", api: "Selected=False" }, { key: true, name: "Selected", api: "Selected=True" }];
  const SELECTION_STATES = [
    { sel: false, dis: false, name: "Enabled · off", api: "Enabled · False" },
    { sel: true, dis: false, name: "Enabled · on", api: "Enabled · True" },
    { sel: false, dis: true, name: "Disabled · off", api: "Disabled · False" },
    { sel: true, dis: true, name: "Disabled · on", api: "Disabled · True" },
  ];
  const INTERACTIONS = [
    { key: "rest", name: "Rest", api: "no overlay" },
    { key: "hover", name: "Hover", api: "onSurface 8%" },
    { key: "focus", name: "Focus", api: "ring · primary" },
    { key: "pressed", name: "Pressed", api: "onSurface 10%" },
  ];
  const SWITCH_LABEL = { false: "off", true: "on" };

  /* ── the REAL control + reconstructed state-layer / focus overlay ──────
   * The bundle component renders only selected × disabled. Hover / focus /
   * pressed are SPECIFIED on the touch target it composes into (component
   * page note) but not painted by the component itself — so we reconstruct
   * them here with the documented tokens, clearly as scaffolding. ───────── */
  function Control({ type, selected, disabled, interaction, onClick }) {
    const isSwitch = type === "switch";
    // touch-target footprint per the component spec
    const tw = isSwitch ? 52 : 24, th = isSwitch ? 32 : 24;
    const showLayer = !disabled && (interaction === "hover" || interaction === "pressed");
    const showRing = !disabled && interaction === "focus";
    const layerBg = interaction === "hover"
      ? "var(--state-layers-onSurface-opacity-0_08)"
      : "var(--state-layers-onSurface-opacity-0_10)";
    const ringRadius = type === "checkbox" ? "var(--radius-xs)" : "var(--radius-full)";
    return (
      <span className="sc-target" style={{ width: tw, height: th }}>
        {showLayer ? (
          <span className="sc-target__layer" style={{ width: tw, height: th, borderRadius: isSwitch ? "var(--radius-full)" : "var(--radius-full)", background: layerBg }} />
        ) : null}
        {showRing ? (
          <span className="sc-target__ring" style={{ width: tw + 6, height: th + 6, borderRadius: isSwitch ? "var(--radius-full)" : ringRadius }} />
        ) : null}
        <SelectionControls type={type} selected={selected} disabled={disabled} onClick={onClick || undefined} />
      </span>
    );
  }

  /* ── one composed list row (realistic usage demo) ───────────────────── */
  function DemoRow({ cfg, theme, onToggle }) {
    const offLabel = !cfg.selected;
    return (
      <div className="sc-row" style={{ minWidth: 300 }}>
        {cfg.showIcon ? <span className="sc-row__icon"><v-icon name={cfg.icon}></v-icon></span> : null}
        {cfg.showLabel ? (
          <span
            className={"sc-row__label" + (offLabel ? " is-off" : "") + (cfg.disabled ? " is-disabled" : "")}
            onClick={cfg.disabled ? undefined : onToggle}
            style={{ cursor: cfg.disabled ? "default" : "pointer" }}
          >
            {cfg.label}
          </span>
        ) : null}
        <Control type={cfg.type} selected={cfg.selected} disabled={cfg.disabled} interaction={cfg.interaction} onClick={onToggle} />
      </div>
    );
  }

  /* ── small chrome controls (match engine look) ──────────────────────── */
  function Seg({ options, value, onChange }) {
    return (
      <div className="pg-optrow">
        {options.map((o) => (
          <button key={String(o.value)} type="button" aria-pressed={value === o.value} onClick={() => onChange(o.value)}>{o.label}</button>
        ))}
      </div>
    );
  }
  function ThemeSeg({ value, onChange, options }) {
    return (
      <div className="pg-seg" role="group">
        {options.map((o) => <button key={o.value} type="button" aria-pressed={value === o.value} onClick={() => onChange(o.value)}>{o.label}</button>)}
      </div>
    );
  }
  function Switch({ on, onClick }) { return <button type="button" className="pg-sw" role="switch" aria-checked={on} onClick={onClick}></button>; }
  function IconPicker({ value, onChange, disabled }) {
    const names = window.vIconNames || [];
    return (
      <select className="pg-pick" value={value} disabled={disabled} onChange={(e) => onChange(e.target.value)}>
        {names.map((n) => <option key={n} value={n}>{n}</option>)}
      </select>
    );
  }

  /* ── specimen frame ─────────────────────────────────────────────────── */
  function Frame({ nm, pr, children }) {
    return (
      <div className="pg-frame">
        <div className="pg-fstage">{children}</div>
        <div className="pg-fcap"><span className="nm">{nm}</span><span className="pr">{pr}</span></div>
      </div>
    );
  }

  /* ── section shell ──────────────────────────────────────────────────── */
  function Section({ num, title, slot, desc, children }) {
    return (
      <section className="pg-section">
        <div className="pg-sechead"><span className="num">{num}</span><h2>{title}</h2>{slot ? <span className="pg-slot">{slot}</span> : null}</div>
        {desc ? <p className="pg-secdesc" dangerouslySetInnerHTML={{ __html: desc }} /> : null}
        {children}
      </section>
    );
  }

  /* ── token model — resolves to NAMES for the current config ───────────
   * Returns groups of rows. Each row: role · token(or null) · note · flag.
   * Where the component hardcodes a literal, token is null + flag set. ──── */
  function tokenGroups(cfg) {
    const t = cfg.type, sel = cfg.selected, dis = cfg.disabled, isSwitch = t === "switch";

    // container / track
    const container = [];
    if (isSwitch) {
      container.push({
        role: "Track fill",
        token: dis ? null : (sel ? "--sys-primary" : "--sys-surface-variant"),
        note: dis ? (sel ? "on-surface 12% literal" : "surface-variant 12% literal") : null,
        flag: dis,
      });
      container.push({
        role: "Track outline",
        token: sel ? null : (dis ? null : "--sys-outline"),
        note: sel ? "none when on" : (dis ? "on-surface 10% literal · inset 2px" : "inset 2px"),
        flag: dis && !sel,
      });
    } else {
      container.push({
        role: "Container fill",
        token: sel ? "--sys-primary" : null,
        note: sel ? null : "transparent · border only",
      });
      container.push({
        role: "Border",
        token: sel ? null : "--sys-outline",
        note: sel ? "none when selected" : "2px",
      });
    }

    // icon / thumb
    const glyph = [];
    if (isSwitch) {
      glyph.push({ role: "Thumb fill", token: dis ? (sel ? "--sys-surface" : "--sys-on-surface") : (sel ? "--sys-on-primary" : "--sys-outline"), note: !dis && sel ? "component uses literal white" : null });
      glyph.push({ role: "Glyph", token: null, note: sel ? "check · locked" : "x · locked" });
      glyph.push({ role: "Glyph color", token: sel ? "--sys-primary" : "--sys-surface-variant", note: dis && sel ? "→ --sys-outline" : null });
    } else {
      glyph.push({ role: "Check glyph", token: sel ? null : null, note: sel ? "check · locked" : "none when unselected" });
      glyph.push({ role: "Check color", token: sel ? "--sys-on-primary" : null, note: sel ? "component uses literal white" : "—", flag: sel });
    }

    // state layer (interaction)
    const ia = cfg.interaction;
    const layer = [
      {
        role: "State layer",
        token: dis ? null : (ia === "hover" ? "--state-layers-onSurface-opacity-0_08" : (ia === "pressed" ? "--state-layers-onSurface-opacity-0_10" : null)),
        note: dis ? "none · disabled" : (ia === "hover" ? "8% · over target" : ia === "pressed" ? "10% · over target" : "none at rest"),
      },
      { role: "Focus ring", token: ia === "focus" && !dis ? "--sys-primary" : null, note: ia === "focus" && !dis ? "2px · DS focus indicator" : "—" },
      { role: "Disabled content", token: dis ? "--state-disabled-content" : null, note: dis ? "0.38 multiplier" : "—" },
    ];

    // surface + sizing + type
    const surface = [{ role: "Preview surface", token: "--sys-surface-container-lowest", note: "stage fill" }];
    const sizing = [
      { role: "Glyph size", token: "--sys-size-icon-small", note: "16px" },
      isSwitch
        ? { role: "Thumb size", token: "--sys-size-icon-default", note: "24px" }
        : { role: "Touch target", token: null, note: "24px · no named token", flag: true },
      { role: "Corner radius", token: t === "checkbox" ? "--radius-xs" : "--radius-full", note: t === "checkbox" ? "4px box" : (isSwitch ? "track + thumb" : "circle") },
      { role: "Min hit area", token: "--sys-size-touch-target-minimum", note: "48px · owned by row", flag: true },
    ];
    const type = [{ role: "Paired label", token: "--type-body-large", note: "composition · not a control prop" }];

    return [
      { group: "Surface context", rows: surface },
      { group: (isSwitch ? "Track · " : "Container · ") + (sel ? "selected" : "unselected") + (dis ? " · disabled" : ""), rows: container },
      { group: isSwitch ? "Thumb + glyph" : "Glyph", rows: glyph },
      { group: "Interaction · " + ia, rows: layer },
      { group: "Sizing · " + t, rows: sizing },
      { group: "Typography", rows: type },
    ];
  }

  function TokenTable({ groups, resolved }) {
    const isColor = (v) => v && (v[0] === "#" || /^rgba?\(/i.test(v));
    return (
      <div className="pg-inspector">
        <table className="pg-toktable">
          <thead><tr><th style={{ width: "26%" }}>Role</th><th style={{ width: "40%" }}>Token</th><th>Resolves to</th></tr></thead>
          <tbody>
            {groups.map((g) => (
              <React.Fragment key={g.group}>
                <tr className="grouprow"><td colSpan={3}>{g.group}</td></tr>
                {g.rows.map((r, i) => {
                  const colorVal = r.token && isColor(resolved[r.token]);
                  return (
                    <tr key={i}>
                      <td className="role">{r.role}</td>
                      <td>
                        {r.token
                          ? <span className="tok">{r.token}</span>
                          : (r.flag
                            ? <span className="sc-flag"><v-icon name="info"></v-icon>no token</span>
                            : <span className="tok tok--plain">—</span>)}
                      </td>
                      <td className="val">
                        <div className="pg-swrow">
                          {colorVal ? <span className="pg-swatch" style={{ background: resolved[r.token] }}></span> : (r.token ? <span className="pg-swatch empty"></span> : null)}
                          <span className="note">{r.note ? <span dangerouslySetInnerHTML={{ __html: r.note }} /> : (colorVal ? "" : "—")}</span>
                        </div>
                      </td>
                    </tr>
                  );
                })}
              </React.Fragment>
            ))}
          </tbody>
        </table>
      </div>
    );
  }

  /* ── anatomy per type ───────────────────────────────────────────────── */
  const ANATOMY = {
    checkbox: {
      heightPx: 24, ring: "var(--radius-xs)",
      rows: [
        { k: "Touch target", v: "24 × 24", t: "no named token", flag: true },
        { k: "Inner box", v: "20 × 20", t: "no named token", flag: true },
        { k: "Box radius", v: "4px", t: "--radius-xs" },
        { k: "Border (unselected)", v: "2px", t: "--sys-outline" },
        { k: "Check glyph", v: "16px", t: "--sys-size-icon-small" },
        { k: "Disabled opacity", v: "0.38", t: "--state-disabled-content" },
        { k: "Min hit area", v: "48px", t: "--sys-size-touch-target-minimum" },
      ],
    },
    radio: {
      heightPx: 24, ring: "var(--radius-full)",
      rows: [
        { k: "Touch target", v: "24 × 24", t: "no named token", flag: true },
        { k: "Inner circle", v: "20 × 20", t: "no named token", flag: true },
        { k: "Circle radius", v: "full", t: "--radius-full" },
        { k: "Border (unselected)", v: "2px", t: "--sys-outline" },
        { k: "Check glyph", v: "16px", t: "--sys-size-icon-small" },
        { k: "Disabled opacity", v: "0.38", t: "--state-disabled-content" },
        { k: "Min hit area", v: "48px", t: "--sys-size-touch-target-minimum" },
      ],
    },
    switch: {
      heightPx: 32, ring: "var(--radius-full)",
      rows: [
        { k: "Track", v: "52 × 32", t: "no named token", flag: true },
        { k: "Thumb", v: "24 × 24", t: "--sys-size-icon-default" },
        { k: "Thumb travel", v: "4 → 24px", t: "no named token", flag: true },
        { k: "Track radius", v: "full", t: "--radius-full" },
        { k: "Outline (off)", v: "inset 2px", t: "--sys-outline" },
        { k: "Glyph", v: "16px", t: "--sys-size-icon-small" },
        { k: "Disabled opacity", v: "0.38", t: "--state-disabled-content" },
      ],
    },
  };

  function Anatomy({ cfg }) {
    const a = ANATOMY[cfg.type];
    return (
      <div className="pg-anatomy">
        <div className="pg-anastage">
          <div className="pg-anabox" style={{ position: "relative", padding: "52px 76px 44px" }}>
            <span className="pg-guide" style={{ right: 34, top: 52, width: 1, height: a.heightPx }}></span>
            <span className="pg-dim" style={{ right: 8, top: "calc(52px + " + (a.heightPx / 2) + "px)", transform: "translateY(-50%)" }}>{a.rows[0].v}</span>
            <span className="pg-dim" style={{ left: 76, top: 18 }}>{a.rows[1].k.toLowerCase()} · {a.rows[1].v}</span>
            <span className="pg-dim" style={{ left: 76, bottom: 14 }}>glyph {ANATOMY[cfg.type].rows.find((r) => r.t === "--sys-size-icon-small").v}</span>
            <div style={{ transform: "scale(2.4)", transformOrigin: "center" }}>
              <Control type={cfg.type} selected={true} disabled={false} interaction="rest" />
            </div>
          </div>
        </div>
        <div className="pg-measure">
          {a.rows.map((r) => (
            <div className="m" key={r.k}>
              <span className="k">{r.k}</span>
              <span className="v">{r.v}</span>
              <span className="t">{r.flag ? <span className="sc-flag"><v-icon name="info"></v-icon>{r.t}</span> : <span className="tok">{r.t}</span>}</span>
            </div>
          ))}
        </div>
      </div>
    );
  }

  /* ── accessibility — contrast for the current meaningful pair ─────────
   * Selection controls are GRAPHICAL objects → WCAG non-text contrast 3:1
   * (not the 4.5:1 used for label text). The pair chosen depends on config. */
  function contrastPair(cfg) {
    const t = cfg.type, sel = cfg.selected, dis = cfg.disabled;
    if (dis) {
      // disabled controls are exempt from contrast minimums (WCAG 1.4.11)
      return { fgToken: "--sys-on-surface", fgAlpha: 0.38, bgTokens: ["--sys-surface-container-lowest"], expected: "exempt",
        note: "Disabled controls are <b>exempt</b> from WCAG 1.4.11 — content sits at opacity <b>0.38</b> over the surface by the locked disabled pattern.",
        fgLbl: "Disabled content", bgLbl: "Surface" };
    }
    if (sel) {
      // filled container vs its glyph — the active boundary that must read
      return { fgToken: "--sys-on-primary", fgAlpha: 1, bgTokens: ["--sys-primary"], expected: null,
        note: "Selected fill vs. the white check glyph it carries. As a graphical object the target is <b>3:1</b>.",
        fgLbl: "Check glyph", bgLbl: "--sys-primary fill" };
    }
    // unselected: the 2px outline boundary vs the surface behind it
    return { fgToken: "--sys-outline", fgAlpha: 1, bgTokens: ["--sys-surface-container-lowest"], expected: null,
      note: "Unselected boundary: the 2px <b>--sys-outline</b> border vs. the surface. Graphical-object target is <b>3:1</b>.",
      fgLbl: "Outline border", bgLbl: "Surface" };
  }

  function A11y({ cfg, resolved, theme }) {
    const cp = contrastPair(cfg);
    const AA = 3, AAA = 4.5;
    const bgCols = cp.bgTokens.map((t) => parseColor(resolved[t])).filter(Boolean);
    const fgRaw = parseColor(resolved[cp.fgToken]);
    let result = null;
    if (bgCols.length && fgRaw) {
      const effBg = stack(bgCols);
      const fg = { ...fgRaw, a: cp.fgAlpha != null ? cp.fgAlpha : fgRaw.a };
      const effFg = fg.a < 1 ? over(fg, effBg) : fg;
      result = { r: ratio(effFg, effBg), effBg, effFg };
    }
    const badge = (() => {
      if (!result) return null;
      if (cp.expected === "exempt") return { cls: "warn", icon: "info", text: "Exempt · disabled" };
      if (result.r >= AAA) return { cls: "pass", icon: "check", text: "Passes 3:1 + 4.5:1" };
      if (result.r >= AA) return { cls: "pass", icon: "check", text: "Passes 3:1 (graphical)" };
      return { cls: "fail", icon: "info", text: "Below 3:1" };
    })();

    const ROLE = { checkbox: 'role="checkbox"', radio: 'role="radio"', switch: 'role="switch"' };
    const notes = [
      { icon: "info", html: 'The bundle renders a plain <span class="tok">&lt;div onClick&gt;</span> — it carries <b>no</b> <span class="tok">' + ROLE[cfg.type] + '</span>, <span class="tok">aria-checked</span>, <span class="tok">tabindex</span> or key handler. <b>Flagged gap:</b> wire these on the host (or compose inside List Item) so it is announced and operable.' },
      { icon: "review", html: 'Selecting must update <span class="tok">aria-checked</span> = <b>' + (cfg.selected ? "true" : "false") + '</b>. A switch may also use <span class="tok">aria-checked</span> with <span class="tok">role="switch"</span>.' },
      { icon: "sparkle", html: 'Focus draws the shared <b>focus indicator</b> — <span class="tok">--sys-primary</span> at a 2px ring around the target. Set <b>Interaction → Focus</b> to preview it.' },
      { icon: "lock", html: 'The visible target is <b>24×24</b> (switch 52×32) — below the <span class="tok">--sys-size-touch-target-minimum</span> of 48. The ≥48 hit area must come from the <b>row</b> it sits in (see the composed demo above).' },
      { icon: "edit", html: 'The control has no built-in label. Associate one with <span class="tok">aria-labelledby</span> or a wrapping <span class="tok">&lt;label&gt;</span> — the paired label here is composition, not a prop.' },
    ];

    return (
      <div className="pg-a11y">
        <div className="pg-card">
          <h3>Contrast · current pair</h3>
          <div className="pg-ratio"><span className="big">{result ? result.r.toFixed(2) : "—"}</span><span className="unit">: 1</span></div>
          {badge ? <div className={"pg-badge " + badge.cls}><v-icon name={badge.icon}></v-icon>{badge.text}</div> : null}
          <div className="pg-pair">
            <div className="chip">
              <div className="sw" style={{ background: result ? toCss(result.effFg) : "transparent" }}></div>
              <div className="lb">{cp.fgLbl}{cp.fgAlpha < 1 ? " · 0.38" : ""}</div>
              <div className="tk">{cp.fgToken}</div>
            </div>
            <div className="chip">
              <div className="sw" style={{ background: result ? toCss(result.effBg) : "transparent" }}></div>
              <div className="lb">{cp.bgLbl}{theme === "dark" ? " · dark" : ""}</div>
              <div className="tk">{cp.bgTokens[cp.bgTokens.length - 1]}</div>
            </div>
          </div>
          <p style={{ fontSize: 12, color: "var(--pg-faint)", lineHeight: 1.5, margin: "14px 0 0" }} dangerouslySetInnerHTML={{ __html: cp.note }} />
          <p style={{ fontSize: 12, color: "var(--pg-faint)", lineHeight: 1.5, margin: "8px 0 0" }}>Selection controls are graphical objects — WCAG AA <b>non-text contrast</b> is <b>3:1</b>. Switch the preview to <b>dark</b> or flip <b>selected</b> to recompute.</p>
        </div>
        <div className="pg-card">
          <h3>Role · keyboard · labeling</h3>
          <div className="pg-notes">
            {notes.map((n, i) => (
              <div className="pg-note" key={i}><v-icon name={n.icon}></v-icon><div className="nbody" dangerouslySetInnerHTML={{ __html: n.html }} /></div>
            ))}
          </div>
        </div>
      </div>
    );
  }

  /* ── reproduce-config prompt ────────────────────────────────────────── */
  function PromptBlock({ cfg, theme }) {
    const lines = [
      "Render the Vendoo Selection Controls component using only Vendoo design system tokens:",
      "",
      "• type: " + cfg.type,
      "• selected: " + cfg.selected,
      "• disabled: " + cfg.disabled,
      "• interaction (documented): " + cfg.interaction,
      "• preview surface: " + (theme === "dark" ? "dark (--sys-* dark family)" : "light (--sys-surface)"),
      "",
      "Composition (not component props):",
      "• paired label: " + (cfg.showLabel ? "\u201C" + cfg.label + "\u201D" : "none"),
      "• row leading icon: " + (cfg.showIcon ? cfg.icon : "none"),
      "",
      "The control's glyphs are locked (check / x); it has no size, label, or icon prop.",
      "Pull SelectionControls from window.VendooDesignSystem_a81b7b — do not re-draw it.",
      "Provide the \u226548px hit area, role/aria-checked, tabindex and key handler on the host row.",
    ];
    const text = lines.join("\n");
    const [copied, setCopied] = useState(false);
    const copy = () => { const done = () => { setCopied(true); setTimeout(() => setCopied(false), 1600); }; if (navigator.clipboard && navigator.clipboard.writeText) navigator.clipboard.writeText(text).then(done, done); else done(); };
    const html = text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/(• [^:]+: )(.*)/g, (m, k, v) => k + '<span class="hl">' + v + "</span>");
    return (
      <div className="pg-prompt">
        <div className="head"><span className="lbl">Reproduce this configuration</span><span className="spacer"></span>
          <button className="pg-copybtn" type="button" onClick={copy}><v-icon name={copied ? "check" : "copy"}></v-icon>{copied ? "Copied" : "Copy prompt"}</button>
        </div>
        <pre dangerouslySetInnerHTML={{ __html: html }} />
      </div>
    );
  }

  /* ── controls panel — the COMPLETE API + flagged gaps + composition ──── */
  function Controls({ cfg, set, toggle }) {
    return (
      <div className="pg-controls">
        <div className="pg-grp">
          <div className="h"><span className="name">Type</span><span className="api">type</span></div>
          <Seg value={cfg.type} onChange={(v) => set("type", v)} options={TYPES.map((t) => ({ value: t.key, label: t.name }))} />
        </div>
        <div className="pg-grp">
          <div className="h"><span className="name">Selected</span><span className="api">selected: boolean</span></div>
          <Seg value={cfg.selected} onChange={(v) => set("selected", v)} options={[{ value: false, label: "False" }, { value: true, label: "True" }]} />
        </div>
        <div className="pg-grp">
          <div className="h"><span className="name">State</span><span className="api">disabled: boolean</span></div>
          <Seg value={cfg.disabled} onChange={(v) => set("disabled", v)} options={[{ value: false, label: "Enabled" }, { value: true, label: "Disabled" }]} />
        </div>
        <div className="pg-grp">
          <div className="h"><span className="name">Interaction</span><span className="api">documented</span></div>
          <p className="sub">Not painted by the component — specified on the target it composes into. Reconstructed here from tokens.</p>
          <Seg value={cfg.interaction} onChange={(v) => set("interaction", v)} options={INTERACTIONS.map((i) => ({ value: i.key, label: i.name }))} />
        </div>
        <div className="pg-grp">
          <div className="h"><span className="name">onClick</span><span className="api">() =&gt; void</span></div>
          <div className="pg-row">
            <span className="lhs"><v-icon name="controls"></v-icon>Interactive — click the preview or label to toggle</span>
            <span className="rhs"><Switch on={!cfg.disabled} onClick={() => set("disabled", !cfg.disabled)} /></span>
          </div>
        </div>

        {/* composition — paired label + leading icon (NOT component props) */}
        <div className="pg-grp">
          <div className="h"><span className="name">Paired label</span><span className="api">composition</span></div>
          <div className="pg-row">
            <span className="lhs"><v-icon name="edit"></v-icon>{cfg.showLabel ? "Shown" : "Hidden"}</span>
            <span className="rhs"><Switch on={cfg.showLabel} onClick={() => set("showLabel", !cfg.showLabel)} /></span>
          </div>
          <div className="pg-row">
            <input className="pg-txt" value={cfg.label} maxLength={40} disabled={!cfg.showLabel} onChange={(e) => set("label", e.target.value)} />
          </div>
        </div>
        <div className="pg-grp">
          <div className="h"><span className="name">Row leading icon</span><span className="api">composition</span></div>
          <div className="pg-row">
            <span className="lhs"><v-icon name={cfg.icon}></v-icon>{cfg.showIcon ? cfg.icon : "Hidden"}</span>
            <span className="rhs">
              <IconPicker value={cfg.icon} disabled={!cfg.showIcon} onChange={(v) => set("icon", v)} />
              <Switch on={cfg.showIcon} onClick={() => set("showIcon", !cfg.showIcon)} />
            </span>
          </div>
        </div>

        {/* flagged gaps — props that DON'T exist on this component */}
        <div className="pg-grp is-note">
          <div className="gap"><v-icon name="info"></v-icon><p><b>size</b> — not a prop. Geometry is fixed: 24×24 box/circle, 52×32 switch. Density is constant.</p></div>
        </div>
        <div className="pg-grp is-note">
          <div className="gap"><v-icon name="info"></v-icon><p><b>icon</b> / <b>leading-trailing icon</b> — not a prop. Glyphs are locked: <b>check</b> when selected, <b>x</b> on the off switch. The leading icon above belongs to the row, not the control.</p></div>
        </div>
      </div>
    );
  }

  /* ── Tweaks (playground presentation — distinct from component config) ─ */
  const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
    "stageSurface": "lowest",
    "specimenZoom": 220,
    "gridDots": true,
    "density": "regular"
  }/*EDITMODE-END*/;
  const STAGE_SURFACE_TOKEN = { lowest: "--sys-surface-container-lowest", surface: "--sys-surface", dim: "--sys-surface-dim" };

  function App() {
    const [t, setTweak] = useTweaks(TWEAK_DEFAULTS);
    const [cfg, setCfg] = useState({
      type: "checkbox", selected: true, disabled: false, interaction: "rest",
      showLabel: true, label: "Email me order updates", showIcon: true, icon: "bell",
    });
    const [theme, setTheme] = useState("light");
    const [resolved, setResolved] = useState({});
    const probeRef = useRef(null);

    const set = (k, v) => setCfg((c) => ({ ...c, [k]: v }));
    const toggle = () => { if (!cfg.disabled) set("selected", !cfg.selected); };
    const groups = useMemo(() => tokenGroups(cfg), [cfg]);

    useLayoutEffect(() => {
      const probe = probeRef.current;
      if (!probe) return;
      probe.className = "pg-probe" + (theme === "dark" ? " pg-theme-dark" : "");
      const need = new Set();
      groups.forEach((g) => g.rows.forEach((r) => r.token && need.add(r.token)));
      const cp = contrastPair(cfg);
      need.add(cp.fgToken); cp.bgTokens.forEach((x) => need.add(x));
      const cs = getComputedStyle(probe);
      const map = {}; need.forEach((x) => { map[x] = cs.getPropertyValue(x).trim(); });
      setResolved(map);
    }, [cfg, theme, groups]);

    const stageSurfaceVar = `var(${STAGE_SURFACE_TOKEN[t.stageSurface] || STAGE_SURFACE_TOKEN.lowest})`;
    const zoom = t.specimenZoom / 100;

    if (!SelectionControls) {
      return <div className="pg-wrap"><p style={{ padding: 40, color: "var(--sys-error)" }}>Could not load <code>SelectionControls</code> from the design-system bundle.</p></div>;
    }

    return (
      <div className="pg-wrap" data-density={t.density}>
        <span ref={probeRef} className="pg-probe" aria-hidden="true" style={{ position: "fixed", left: -9999, top: 0, width: 0, height: 0, pointerEvents: "none", opacity: 0 }} />

        <a className="pg-back" href="Playground Index.html"><v-icon name="arrow_left"></v-icon><span>All playgrounds</span></a>

        <div className="pg-banner">
          <span className="bdot"></span>
          <span className="btext"><b>Pulled from the published design system.</b> The live specimen is <code>window.VendooDesignSystem_a81b7b.SelectionControls</code> — never re-drawn. Every value traces to a token; literals the component hardcodes are flagged, not faked.</span>
        </div>

        {/* 1 · HEADER */}
        <header className="pg-header">
          <div className="pg-eyebrow">Component · Playground</div>
          <div className="pg-titlerow">
            <h1 className="pg-title">Selection Controls</h1>
            <span className="pg-status"><span className="ver">v1.0</span><span className="dot"></span>Ready</span>
          </div>
          <p className="pg-lede">Checkbox, radio and switch in their full selected × enabled/disabled matrix. Checkboxes handle multi-select, radios handle mutually exclusive choices, and switches toggle a single setting that takes effect immediately.</p>
          <div className="pg-props">
            <span className="chip"><b>type</b> · checkbox / radio / switch</span>
            <span className="chip"><b>selected</b> · boolean</span>
            <span className="chip"><b>disabled</b> · boolean</span>
            <span className="chip"><b>onClick</b> · () =&gt; void</span>
          </div>
        </header>

        {/* 2 · LIVE PREVIEW + 3 · CONTROLS */}
        <Section num="02 / 03" title="Live preview + controls" slot="component · controls"
          desc="The real component on a neutral surface, centered. Toggle the surface light or dark — it re-renders on every control change, and the preview is interactive (click the control or its label). Controls expose the complete API; props that don't exist are flagged.">
          <div className="pg-live">
            <div className="pg-stagewrap">
              <div className="pg-stagebar">
                <span className="grouplbl">surface</span>
                <ThemeSeg value={theme} onChange={setTheme} options={[{ value: "light", label: "Light" }, { value: "dark", label: "Dark" }]} />
              </div>
              <div className={"pg-stage" + (theme === "dark" ? " pg-theme-dark" : "")} data-grid={t.gridDots ? "on" : "off"} style={{ "--pg-stage-surface": stageSurfaceVar }}>
                <div className="pg-zoom" style={{ transform: `scale(${zoom})` }}>
                  {cfg.showLabel || cfg.showIcon
                    ? <DemoRow cfg={cfg} theme={theme} onToggle={toggle} />
                    : <Control type={cfg.type} selected={cfg.selected} disabled={cfg.disabled} interaction={cfg.interaction} onClick={toggle} />}
                </div>
              </div>
              <div className="pg-vpmeta">
                <span>type={cfg.type} · selected={String(cfg.selected)} · disabled={String(cfg.disabled)}</span>
                <span className={theme === "dark" ? "pg-theme-dark-readout" : ""}>{theme === "dark" ? "--sys-* dark family" : "--sys-surface (light)"}</span>
              </div>
            </div>
            <Controls cfg={cfg} set={set} toggle={toggle} />
          </div>
        </Section>

        {/* 4 · STATES MATRIX */}
        <Section num="04" title="States matrix" slot="selected × disabled · interaction"
          desc="Every supported state at once for the current type. The top row is the component's real axes — <b>selected × disabled</b> (4 combinations it actually renders). The bottom row reconstructs the documented <b>interaction</b> states from their tokens (the component itself paints no state layer).">
          <div className="pg-frames cols4" style={{ marginBottom: 18 }}>
            {SELECTION_STATES.map((s) => (
              <Frame key={s.name} nm={s.name} pr={"Type=" + cfg.type + " · " + s.api}>
                <div style={{ transform: "scale(1.6)" }}><Control type={cfg.type} selected={s.sel} disabled={s.dis} interaction="rest" /></div>
              </Frame>
            ))}
          </div>
          <div className="pg-frames cols4">
            {INTERACTIONS.map((ia) => (
              <Frame key={ia.key} nm={ia.name} pr={"State layer · " + ia.api}>
                <div style={{ transform: "scale(1.6)" }}><Control type={cfg.type} selected={cfg.selected} disabled={false} interaction={ia.key} /></div>
              </Frame>
            ))}
          </div>
        </Section>

        {/* 5 · VARIANT GRID */}
        <Section num="05" title="Variant grid" slot="types × selected"
          desc="All three types across the only real second axis — <b>selected</b>. There is no size variant (geometry is fixed), so the column axis is Unselected / Selected rather than size; each row notes its footprint.">
          <div className="pg-frames grid">
            <div></div>
            {SELECTED.map((s) => <div className="pg-colhead" key={String(s.key)}>{s.name}</div>)}
            {TYPES.map((tp) => (
              <React.Fragment key={tp.key}>
                <div className="pg-rowhead">{tp.name}<small>{tp.geo}</small></div>
                {SELECTED.map((s) => (
                  <Frame key={tp.key + String(s.key)} nm={tp.name + " · " + s.name} pr={tp.api + " · " + s.api}>
                    <div style={{ transform: "scale(1.5)" }}><Control type={tp.key} selected={s.key} disabled={false} interaction="rest" /></div>
                  </Frame>
                ))}
              </React.Fragment>
            ))}
          </div>
        </Section>

        {/* 6 · TOKEN INSPECTOR */}
        <Section num="06" title="Token inspector" slot="tokens(config)"
          desc="The semantic tokens the current configuration resolves to — surface, container/track, glyph, state-layer opacity, icon size and the paired type style. Names only; swatches show the resolved color (including the preview theme) but no hex is printed. Hardcoded literals are flagged as gaps.">
          <TokenTable groups={groups} resolved={resolved} />
        </Section>

        {/* 7 · ANATOMY */}
        <Section num="07" title="Anatomy & spec" slot="anatomy[type]"
          desc="Footprint, inner geometry, glyph and minimum hit area for the current type, as measured callouts. Where a measurement maps to a token it is named; where the component uses a raw literal it is flagged rather than dressed up as a token.">
          <Anatomy cfg={cfg} />
        </Section>

        {/* 8 · ACCESSIBILITY */}
        <Section num="08" title="Accessibility" slot="a11y"
          desc="Non-text contrast for the current foreground / background pair (composited with the active state layer), plus the role / keyboard / labeling gaps a host must close around this control.">
          <A11y cfg={cfg} resolved={resolved} theme={theme} />
        </Section>

        {/* 9 · PROMPT */}
        <Section num="↪" title="Hand this state back" slot="prompt(config)"
          desc="A copy-paste prompt that reproduces the exact configuration above — paste it back to regenerate this specific state later.">
          <PromptBlock cfg={cfg} theme={theme} />
        </Section>

        {/* Tweaks — playground presentation only */}
        <TweaksPanel title="Tweaks">
          <TweakSection label="Specimen stage" />
          <TweakRadio label="Surface" value={t.stageSurface} options={["lowest", "surface", "dim"]} onChange={(v) => setTweak("stageSurface", v)} />
          <TweakToggle label="Grid dots" value={t.gridDots} onChange={(v) => setTweak("gridDots", v)} />
          <TweakSlider label="Preview zoom" value={t.specimenZoom} min={100} max={320} step={10} unit="%" onChange={(v) => setTweak("specimenZoom", v)} />
          <TweakSection label="Chrome" />
          <TweakRadio label="Density" value={t.density} options={["compact", "regular", "comfy"]} onChange={(v) => setTweak("density", v)} />
        </TweaksPanel>
      </div>
    );
  }

  ReactDOM.createRoot(document.getElementById("app")).render(<App />);
})();
