{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "frame12",
  "title": "FRAME/12 Complete Kit",
  "description": "All FRAME/12 styles, hooks, components, and primitive adapters.",
  "dependencies": [
    "@radix-ui/react-select",
    "@radix-ui/react-dropdown-menu"
  ],
  "files": [
    {
      "path": "styles/frame12.css",
      "content": "/* FRAME/12 Design System — Tokens, Panel Grammar, Screentone, and Motion on Twos.\n   Works standalone without Tailwind. All rules are scoped to .f12-* classes. */\n\n:where(:root) {\n  --font-f-display: \"Dela Gothic One\", \"Arial Black\", \"Helvetica Neue\", sans-serif;\n  --font-f-body: \"Zen Kaku Gothic New\", \"Hiragino Sans\", \"Helvetica Neue\", Arial, sans-serif;\n  --font-f-mono: \"M PLUS 1 Code\", ui-monospace, \"SF Mono\", Menlo, monospace;\n\n  --f-gutter-pair: 12px;\n  --f-gutter-scene: 20px;\n  --f-gutter-change: 32px;\n\n  --f-shadow-sheet: 0 1px 0 rgba(0, 0, 0, 0.05), 0 18px 40px -26px rgba(0, 0, 0, 0.5);\n  --f-shadow-peg: inset 0 1px 2px rgba(0, 0, 0, 0.25);\n  --f-backdrop: rgba(18, 18, 18, 0.55);\n  --f-diff: #ffffff;\n}\n\n:where(:root),\n:root[data-theme=\"light\"],\n.f12-theme-light {\n  --f-desk: #e2e3e5;\n  --f-sheet: #ffffff;\n  --f-panel: #ffffff;\n  --f-ink: #121212;\n  --f-ink-2: #4b4b4b;\n  --f-rule: #121212;\n  --f-tone: #121212;\n  --f-grid: #e3e3e3;\n  --f-marker: #ffd60a;\n  --f-marker-ink: #121212;\n  --f-hole: #e2e3e5;\n  color-scheme: light;\n}\n\n@media (prefers-color-scheme: dark) {\n  :root:not([data-theme=\"light\"]):not(.f12-theme-light) {\n    --f-desk: #000000;\n    --f-sheet: #050505;\n    --f-panel: #19191a;\n    --f-ink: #f1f0ea;\n    --f-ink-2: #b9b8b1;\n    --f-rule: #f1f0ea;\n    --f-tone: #f1f0ea;\n    --f-grid: #2c2c2d;\n    --f-marker: #ffd60a;\n    --f-marker-ink: #121212;\n    --f-hole: #000000;\n    color-scheme: dark;\n  }\n}\n\n:root[data-theme=\"dark\"],\n.f12-theme-dark {\n  --f-desk: #000000;\n  --f-sheet: #050505;\n  --f-panel: #19191a;\n  --f-ink: #f1f0ea;\n  --f-ink-2: #b9b8b1;\n  --f-rule: #f1f0ea;\n  --f-tone: #f1f0ea;\n  --f-grid: #2c2c2d;\n  --f-marker: #ffd60a;\n  --f-marker-ink: #121212;\n  --f-hole: #000000;\n  color-scheme: dark;\n}\n\n/* ===================================================================== Scoped Base & Reset */\n.f12-dash,\n.f12-sheet,\n.f12-scene,\n.f12-panel,\n.f12-pair,\n.f12-rng,\n.f12-metric,\n.f12-chart,\n.f12-ints,\n.f12-btn,\n.f12-field,\n.f12-input,\n.f12-dialog,\n.f12-select,\n.f12-select-content,\n.f12-tooltip-wrap,\n.f12-menu-wrap,\n.f12-menu,\n.f12-table-wrap,\n.f12-balloon,\n.f12-balloon-standalone {\n  box-sizing: border-box;\n}\n\n.f12-dash *,\n.f12-dash *::before,\n.f12-dash *::after,\n.f12-sheet *,\n.f12-sheet *::before,\n.f12-sheet *::after,\n.f12-panel *,\n.f12-panel *::before,\n.f12-panel *::after,\n.f12-dialog *,\n.f12-select *,\n.f12-select-content *,\n.f12-menu *,\n.f12-table-wrap * {\n  box-sizing: border-box;\n}\n\n.f12-sr-only {\n  position: absolute;\n  width: 1px;\n  height: 1px;\n  padding: 0;\n  margin: -1px;\n  overflow: hidden;\n  clip: rect(0 0 0 0);\n  white-space: nowrap;\n  border: 0;\n}\n\n:where(.f12-frame button, .f12-sheet button, .f12-dialog button, button[class*=\"f12-\"]) {\n  font: inherit;\n  color: inherit;\n}\n\n.f12-frame :focus-visible,\n.f12-sheet :focus-visible,\n.f12-dialog :focus-visible,\n[class*=\"f12-\"]:focus-visible {\n  outline: 3px solid var(--f-ink);\n  outline-offset: 2px;\n}\n\n/* ===================================================================== Sheet & Pegs */\n.f12-dash {\n  container-type: inline-size;\n  position: relative;\n}\n.f12-dash h2,\n.f12-dash h3,\n.f12-dash p,\n.f12-dash ul {\n  margin: 0;\n}\n.f12-dash ul {\n  list-style: none;\n  padding: 0;\n}\n\n.f12-frame {\n  background: var(--f-desk);\n  color: var(--f-ink);\n  font-family: var(--font-f-body);\n  padding: 20px;\n  border-radius: 4px;\n}\n\n.f12-sheet {\n  position: relative;\n  background: var(--f-sheet);\n  color: var(--f-ink);\n  font-family: var(--font-f-body);\n  padding: 44px 28px 28px;\n  display: flex;\n  flex-direction: column;\n  gap: var(--f-gutter-change); /* 32px = scene change */\n  box-shadow: var(--f-shadow-sheet);\n}\n\n.f12-pegs {\n  position: absolute;\n  top: 12px;\n  left: 50%;\n  transform: translateX(-50%);\n  display: flex;\n  gap: 26px;\n  align-items: center;\n}\n.f12-peg {\n  display: block;\n  background: var(--f-hole);\n  border: 1px solid var(--f-grid);\n  box-shadow: var(--f-shadow-peg);\n}\n.f12-peg.round {\n  width: 11px;\n  height: 11px;\n  border-radius: 50%;\n}\n.f12-peg.slot {\n  width: 26px;\n  height: 8px;\n  border-radius: 4px;\n}\n\n.f12-hd {\n  display: flex;\n  flex-wrap: wrap;\n  gap: 16px 24px;\n  align-items: flex-end;\n  justify-content: space-between;\n}\n.f12-eyebrow {\n  display: flex;\n  flex-wrap: wrap;\n  align-items: center;\n  gap: 10px;\n  font-family: var(--font-f-mono);\n  font-size: 11px;\n  letter-spacing: 0.12em;\n  text-transform: uppercase;\n  color: var(--f-ink-2);\n}\n.f12-title {\n  font-family: var(--font-f-display);\n  font-weight: 400;\n  font-size: clamp(30px, 5.2cqi, 46px);\n  line-height: 1.02;\n  margin-top: 10px;\n  letter-spacing: 0.005em;\n  text-wrap: balance;\n}\n.f12-sub {\n  font-family: var(--font-f-mono);\n  font-size: 12px;\n  color: var(--f-ink-2);\n  margin-top: 8px;\n  letter-spacing: 0.04em;\n}\n\n/* ===================================================================== Scene & Gutter Grammar\n   12px = pair, 20px = same scene, 32px = scene change */\n.f12-scene {\n  display: grid;\n  grid-template-columns: minmax(0, 2fr) minmax(0, 1fr);\n  gap: var(--f-gutter-scene);\n  min-width: 0;\n}\n.f12-scene.f12-scene-split {\n  grid-template-columns: minmax(0, 2fr) minmax(0, 1fr);\n}\n.f12-scene.f12-scene-stack {\n  grid-template-columns: minmax(0, 1fr);\n}\n.f12-scene.f12-scene-equal {\n  grid-template-columns: repeat(2, minmax(0, 1fr));\n}\n.f12-scene.f12-scene-three {\n  grid-template-columns: repeat(3, minmax(0, 1fr));\n}\n.f12-scene.f12-scene-pair {\n  gap: var(--f-gutter-pair);\n}\n.f12-scene.f12-scene-scene {\n  gap: var(--f-gutter-scene);\n}\n.f12-scene.f12-scene-change {\n  gap: var(--f-gutter-change);\n}\n\n.f12-pair {\n  display: flex;\n  flex-direction: column;\n  gap: var(--f-gutter-pair);\n  min-width: 0;\n}\n.f12-pair > .f12-panel {\n  flex: 1;\n}\n\n/* ===================================================================== Panel */\n.f12-panel {\n  position: relative;\n  min-width: 0;\n  display: flex;\n  flex-direction: column;\n  color: var(--f-ink);\n  font-family: var(--font-f-body);\n}\n.f12-panel-frame {\n  position: absolute;\n  inset: 0;\n  width: 100%;\n  height: 100%;\n  overflow: visible;\n  pointer-events: none;\n}\n.f12-panel-frame polygon {\n  fill: var(--f-panel);\n  stroke: var(--f-rule);\n  stroke-width: 2.5;\n  stroke-linejoin: miter;\n}\n.f12-panel-body {\n  flex: 1;\n  min-width: 0;\n  display: flex;\n  flex-direction: column;\n  position: relative;\n  padding: 24px 22px 22px;\n}\n.f12-panel.f12-slant-bottom > .f12-panel-body {\n  padding-bottom: 36px;\n}\n.f12-panel.f12-slant-top > .f12-panel-body {\n  padding-top: 36px;\n}\n.f12-cut {\n  position: absolute;\n  top: -8px;\n  left: 16px;\n  z-index: 1;\n  padding: 0 6px;\n  line-height: 16px;\n  font-family: var(--font-f-mono);\n  font-size: 11px;\n  font-weight: 500;\n  letter-spacing: 0.12em;\n  background: var(--f-sheet);\n  color: var(--f-ink);\n}\n.f12-panel.f12-slant-top > .f12-cut {\n  top: 8px;\n}\n\n/* ===================================================================== Tag & Badge */\n.f12-tag {\n  display: inline-block;\n  font-family: var(--font-f-mono);\n  font-size: 11px;\n  color: var(--f-marker-ink);\n  background: var(--f-marker);\n  padding: 1px 6px;\n  letter-spacing: 0.08em;\n  text-transform: uppercase;\n}\n\n.f12-badge {\n  position: relative;\n  display: inline-flex;\n  align-items: center;\n  white-space: nowrap;\n  font-family: var(--font-f-mono);\n  font-size: 10px;\n  font-weight: 700;\n  letter-spacing: 0.12em;\n  text-transform: uppercase;\n  padding: 2px 7px;\n  background: var(--f-marker);\n  color: var(--f-marker-ink);\n  border: 2px solid var(--f-rule);\n}\n.f12-badge-t {\n  position: relative;\n  z-index: 1;\n}\n.f12-burst {\n  position: absolute;\n  left: 50%;\n  top: 50%;\n  width: 150%;\n  height: auto;\n  transform: translate(-50%, -50%);\n  opacity: 0;\n  pointer-events: none;\n}\n.f12-burst line {\n  stroke: var(--f-ink);\n  stroke-width: 2;\n  stroke-linecap: square;\n}\n\n/* ===================================================================== SegmentedControl (RangeTabs) */\n.f12-rng {\n  position: relative;\n  display: inline-flex;\n  flex: none;\n  isolation: isolate;\n  border: 2.5px solid var(--f-rule);\n  background: var(--f-panel);\n}\n.f12-rng-ind {\n  position: absolute;\n  top: 0;\n  bottom: 0;\n  left: 0;\n  z-index: 1;\n  background: var(--f-diff);\n  mix-blend-mode: difference;\n  pointer-events: none;\n}\n.f12-rng-btn {\n  cursor: pointer;\n  background: none;\n  border: 0;\n  display: grid;\n  justify-items: center;\n  padding: 6px 16px 5px;\n  color: var(--f-ink);\n  min-width: 64px;\n}\n.f12-rng-btn + .f12-rng-btn {\n  border-left: 2px solid var(--f-rule);\n}\n.f12-rng:not(:has(.f12-rng-ind)) .f12-rng-btn[aria-pressed=\"true\"] {\n  background: var(--f-ink);\n  color: var(--f-panel);\n}\n.f12-rng-n {\n  font-family: var(--font-f-display);\n  font-size: 18px;\n  line-height: 1;\n}\n.f12-rng-u {\n  font-family: var(--font-f-mono);\n  font-size: 10px;\n  letter-spacing: 0.14em;\n  text-transform: uppercase;\n}\n.f12-rng-btn:focus-visible {\n  outline: 3px solid var(--f-marker);\n  outline-offset: -6px;\n}\n\n/* ===================================================================== Button & Input */\n.f12-btn {\n  display: inline-flex;\n  align-items: center;\n  justify-content: center;\n  gap: 8px;\n  cursor: pointer;\n  font-family: var(--font-f-mono);\n  font-weight: 700;\n  letter-spacing: 0.08em;\n  text-transform: uppercase;\n  border: 2.5px solid var(--f-rule);\n  background: var(--f-panel);\n  color: var(--f-ink);\n  padding: 8px 16px;\n  font-size: 12px;\n  line-height: 1.2;\n}\n.f12-btn-sm {\n  padding: 5px 10px;\n  font-size: 11px;\n}\n.f12-btn-md {\n  padding: 8px 16px;\n  font-size: 12px;\n}\n.f12-btn-lg {\n  padding: 12px 22px;\n  font-size: 13px;\n}\n.f12-btn-primary {\n  background: var(--f-ink);\n  color: var(--f-panel);\n}\n.f12-btn-secondary {\n  background: var(--f-panel);\n  color: var(--f-ink);\n}\n.f12-btn-marker {\n  background: var(--f-marker);\n  color: var(--f-marker-ink);\n}\n.f12-btn:hover:not(:disabled) {\n  box-shadow: 3px 3px 0 var(--f-rule);\n}\n.f12-btn:active:not(:disabled) {\n  box-shadow: none;\n}\n.f12-btn:focus-visible {\n  outline: 3px solid var(--f-ink);\n  outline-offset: 2px;\n}\n.f12-btn:disabled {\n  cursor: not-allowed;\n  border-style: dashed;\n  color: var(--f-ink-2);\n  background: var(--f-panel);\n}\n\n.f12-field {\n  display: flex;\n  flex-direction: column;\n  gap: 6px;\n  font-family: var(--font-f-body);\n  color: var(--f-ink);\n}\n.f12-label {\n  font-family: var(--font-f-mono);\n  font-size: 11px;\n  font-weight: 500;\n  letter-spacing: 0.14em;\n  text-transform: uppercase;\n  color: var(--f-ink-2);\n}\n.f12-input {\n  width: 100%;\n  padding: 9px 12px;\n  font-family: var(--font-f-body);\n  font-size: 14px;\n  line-height: 1.4;\n  color: var(--f-ink);\n  background: var(--f-panel);\n  border: 2.5px solid var(--f-rule);\n  border-radius: 0;\n}\n.f12-input::placeholder {\n  color: var(--f-ink-2);\n}\n.f12-input:focus-visible {\n  outline: 3px solid var(--f-ink);\n  outline-offset: 2px;\n}\n.f12-hint {\n  font-family: var(--font-f-mono);\n  font-size: 11px;\n  color: var(--f-ink-2);\n  margin: 0;\n}\n.f12-error {\n  display: inline-flex;\n  align-items: center;\n  gap: 6px;\n  font-family: var(--font-f-mono);\n  font-size: 11px;\n  color: var(--f-ink);\n  margin: 0;\n}\n.f12-error-flag {\n  background: var(--f-marker);\n  color: var(--f-marker-ink);\n  padding: 0 4px;\n  font-weight: 700;\n}\n\n/* ===================================================================== Metric, Delta & Spark */\n.f12-metric {\n  display: flex;\n  flex-direction: column;\n  flex: 1;\n}\n.f12-m-label {\n  font-family: var(--font-f-mono);\n  font-size: 11px;\n  font-weight: 500;\n  letter-spacing: 0.14em;\n  text-transform: uppercase;\n  color: var(--f-ink-2);\n  margin: 0;\n}\n.f12-m-value {\n  font-family: var(--font-f-display);\n  font-weight: 400;\n  font-size: 34px;\n  line-height: 1.22;\n  padding-bottom: 2px;\n  margin: 10px 0 0;\n  font-variant-numeric: tabular-nums;\n  letter-spacing: 0.01em;\n  color: var(--f-ink);\n}\n.f12-metric.big .f12-m-value {\n  font-size: clamp(36px, 6cqi, 56px);\n  line-height: 1.1;\n  font-variant-numeric: proportional-nums;\n}\n.f12-delta {\n  display: flex;\n  align-items: baseline;\n  gap: 6px;\n  flex-wrap: wrap;\n  font-variant-numeric: tabular-nums;\n  font-family: var(--font-f-mono);\n  font-size: 12px;\n  margin: 14px 0 0;\n  letter-spacing: 0.02em;\n  color: var(--f-ink);\n}\n.f12-delta-sym {\n  font-size: 10px;\n}\n.f12-delta.up .f12-delta-sym,\n.f12-delta.down .f12-delta-sym {\n  color: var(--f-marker-ink);\n  background: var(--f-marker);\n  padding: 0 3px;\n}\n.f12-delta-ref {\n  color: var(--f-ink-2);\n}\n.f12-m-note {\n  font-size: 13px;\n  color: var(--f-ink-2);\n  margin: 6px 0 0;\n  max-width: 30ch;\n}\n\n.f12-spark {\n  display: flex;\n  flex-direction: column;\n  gap: 6px;\n  margin-top: auto;\n  padding-top: 16px;\n}\n.f12-spark svg {\n  display: block;\n  width: 100%;\n  border-bottom: 2px solid var(--f-rule);\n  overflow: visible;\n}\n.f12-spark-l {\n  font-family: var(--font-f-mono);\n  font-size: 10px;\n  letter-spacing: 0.14em;\n  text-transform: uppercase;\n  color: var(--f-ink-2);\n  margin: 0;\n}\n.f12-spark-bar {\n  stroke: var(--f-ink);\n  stroke-width: 1;\n}\n\n/* ===================================================================== Chart, Balloon & Data Table */\n.f12-c01-hd {\n  display: flex;\n  flex-wrap: wrap;\n  justify-content: space-between;\n  align-items: flex-end;\n  gap: 12px 24px;\n  margin-bottom: 4px;\n}\n.f12-legend,\n.f12-legend-hint {\n  display: flex;\n  flex-wrap: wrap;\n  gap: 4px 16px;\n  font-family: var(--font-f-mono);\n  font-size: 11px;\n  letter-spacing: 0.04em;\n  color: var(--f-ink-2);\n  margin: 0;\n  padding: 0;\n  list-style: none;\n}\n.f12-legend li {\n  display: flex;\n  align-items: center;\n  gap: 6px;\n}\n.f12-legend-hint {\n  max-width: 26ch;\n}\n.f12-sw {\n  display: inline-block;\n  width: 14px;\n  height: 0;\n  border-top-width: 2px;\n  border-top-style: solid;\n  flex: none;\n}\n.f12-sw-total {\n  border-color: var(--f-ink);\n  border-top-width: 2.5px;\n}\n.f12-sw-focus {\n  border-color: var(--f-ink);\n  border-top-style: dashed;\n}\n\n.f12-chart {\n  position: relative;\n  width: 100%;\n  touch-action: pan-y;\n}\n.f12-chart-svg {\n  display: block;\n  width: 100%;\n  overflow: visible;\n}\n.f12-chart-svg:focus-visible {\n  outline: 3px solid var(--f-ink);\n  outline-offset: 4px;\n}\n.f12-chart text {\n  fill: var(--f-ink-2);\n  font-family: var(--font-f-mono);\n  font-size: 10.5px;\n  font-variant-numeric: tabular-nums;\n}\n.f12-grid {\n  stroke: var(--f-grid);\n}\n.f12-baseline {\n  stroke: var(--f-rule);\n  stroke-width: 2;\n}\n.f12-sheet-ticks line {\n  stroke: var(--f-rule);\n  stroke-width: 1;\n}\n.f12-tone-dot {\n  fill: var(--f-tone);\n}\n.f12-l-total {\n  stroke: var(--f-ink);\n  stroke-width: 2.5;\n  stroke-linejoin: round;\n  stroke-linecap: round;\n}\n.f12-l-focus {\n  stroke: var(--f-ink);\n  stroke-width: 2;\n  stroke-dasharray: 6 4;\n  stroke-linejoin: round;\n}\n.f12-tail {\n  fill: var(--f-panel);\n  stroke: var(--f-rule);\n  stroke-width: 2;\n  stroke-linejoin: miter;\n}\n.f12-g-tag {\n  fill: var(--f-marker);\n}\n.f12-peak-dot {\n  fill: var(--f-marker);\n  stroke: var(--f-rule);\n  stroke-width: 2;\n}\n.f12-balloon {\n  position: absolute;\n  z-index: 2;\n  display: inline-flex;\n  align-items: center;\n  min-height: 28px;\n  max-width: calc(100% - 60px);\n  min-width: 0;\n  padding: 3px 12px;\n  background: var(--f-panel);\n  color: var(--f-ink);\n  border: 2px solid var(--f-rule);\n  border-radius: 14px;\n  font-family: var(--font-f-mono);\n  font-size: 12px;\n  font-weight: 500;\n  letter-spacing: 0.02em;\n  font-variant-numeric: tabular-nums;\n  overflow-wrap: anywhere;\n  word-break: break-word;\n}\n.f12-balloon-gap {\n  position: absolute;\n  bottom: -2px;\n  width: 10px;\n  height: 3px;\n  background: var(--f-panel);\n}\n.f12-balloon-standalone {\n  position: relative;\n  display: inline-flex;\n  flex-direction: column;\n  align-items: center;\n  max-width: 100%;\n  min-width: 0;\n}\n.f12-balloon-standalone .f12-balloon {\n  position: relative;\n  max-width: 100%;\n  min-height: 28px;\n}\n.f12-balloon-standalone-svg {\n  display: block;\n  overflow: visible;\n  margin-top: -1px;\n}\n\n.f12-cross line {\n  stroke: var(--f-ink);\n  stroke-width: 1;\n}\n.f12-cross-dot {\n  fill: var(--f-marker);\n  stroke: var(--f-rule);\n  stroke-width: 2;\n}\n.f12-cross-dot2 {\n  fill: var(--f-panel);\n  stroke: var(--f-rule);\n  stroke-width: 2;\n}\n.f12-tip {\n  position: absolute;\n  z-index: 3;\n  pointer-events: none;\n  display: grid;\n  gap: 2px;\n  min-width: 160px;\n  padding: 8px 10px;\n  font-size: 12px;\n  font-variant-numeric: tabular-nums;\n  background: var(--f-panel);\n  border: 2px solid var(--f-rule);\n  color: var(--f-ink);\n  font-family: var(--font-f-mono);\n  box-shadow: 4px 4px 0 var(--f-rule);\n}\n.f12-tip span {\n  display: flex;\n  align-items: center;\n  gap: 6px;\n}\n\n.f12-tbl {\n  margin-top: 10px;\n  font-family: var(--font-f-mono);\n  font-size: 12px;\n  color: var(--f-ink);\n}\n.f12-tbl summary {\n  cursor: pointer;\n  width: max-content;\n  padding: 4px 0;\n  text-decoration: underline;\n  text-underline-offset: 3px;\n}\n.f12-tbl-scroll {\n  max-height: 240px;\n  overflow: auto;\n  margin-top: 6px;\n}\n.f12-tbl table {\n  border-collapse: collapse;\n  width: 100%;\n  font-variant-numeric: tabular-nums;\n}\n.f12-tbl th,\n.f12-tbl td {\n  text-align: left;\n  padding: 5px 10px 5px 0;\n  white-space: nowrap;\n}\n.f12-tbl th {\n  color: var(--f-ink-2);\n  font-weight: 500;\n  border-bottom: 2px solid var(--f-rule);\n}\n.f12-tbl td {\n  border-bottom: 1px solid var(--f-grid);\n}\n\n/* ===================================================================== ToneBarList (Interventions) */\n.f12-ints-hd {\n  display: flex;\n  flex-wrap: wrap;\n  justify-content: space-between;\n  align-items: baseline;\n  gap: 6px 16px;\n  margin-bottom: 14px;\n}\n.f12-ints-sub {\n  font-family: var(--font-f-mono);\n  font-size: 11px;\n  color: var(--f-ink-2);\n  letter-spacing: 0.04em;\n  margin: 0;\n}\n.f12-ints-list {\n  display: grid;\n  list-style: none;\n  padding: 0;\n  margin: 0;\n}\n.f12-ints-list li + li {\n  border-top: 1px solid var(--f-grid);\n}\n.f12-int-row {\n  all: unset;\n  box-sizing: border-box;\n  cursor: pointer;\n  display: grid;\n  width: 100%;\n  align-items: center;\n  grid-template-columns: minmax(0, 1.1fr) minmax(0, 2fr) auto;\n  gap: 16px;\n  padding: 12px 8px;\n  color: var(--f-ink);\n}\n.f12-int-row:hover .f12-int-name {\n  text-decoration: underline;\n  text-underline-offset: 3px;\n}\n.f12-int-row:focus-visible {\n  outline: 3px solid var(--f-ink);\n  outline-offset: -3px;\n}\n.f12-int-name {\n  display: flex;\n  align-items: center;\n  gap: 10px;\n  min-width: 0;\n  flex-wrap: wrap;\n  font-size: 15px;\n  font-weight: 700;\n}\n.f12-int-bar {\n  position: relative;\n  display: block;\n  height: 16px;\n  border: 2px solid var(--f-rule);\n}\n.f12-int-fill {\n  position: absolute;\n  inset: 0 auto 0 0;\n  background-image: radial-gradient(circle, var(--f-tone) 1.1px, transparent 1.4px);\n  background-size: 5px 5px;\n  border-right: 2px solid var(--f-rule);\n}\n.f12-int-row[aria-pressed=\"true\"] {\n  background: var(--f-ink);\n  color: var(--f-panel);\n}\n.f12-int-row[aria-pressed=\"true\"] .f12-int-bar {\n  border-color: var(--f-panel);\n}\n.f12-int-row[aria-pressed=\"true\"] .f12-int-fill {\n  background: var(--f-marker);\n  border-right-color: var(--f-panel);\n}\n.f12-int-row[aria-pressed=\"true\"] .f12-int-share {\n  color: var(--f-panel);\n}\n.f12-int-row[aria-pressed=\"true\"] .f12-badge {\n  border-color: var(--f-panel);\n}\n.f12-int-val {\n  display: flex;\n  gap: 10px;\n  justify-content: flex-end;\n  font-variant-numeric: tabular-nums;\n  white-space: nowrap;\n  font-family: var(--font-f-mono);\n  font-size: 13px;\n  font-weight: 500;\n}\n.f12-int-share {\n  min-width: 3ch;\n  text-align: right;\n  color: var(--f-ink-2);\n}\n\n/* ===================================================================== Adapters: Dialog, Select, Tooltip, DropdownMenu, Table */\n\n/* Dialog */\ndialog.f12-dialog {\n  background: var(--f-panel);\n  color: var(--f-ink);\n  border: 2.5px solid var(--f-rule);\n  box-shadow: 6px 6px 0 var(--f-rule);\n  padding: 24px 22px 22px;\n  max-width: 480px;\n  width: calc(100% - 32px);\n  font-family: var(--font-f-body);\n}\ndialog.f12-dialog:modal {\n  overscroll-behavior: contain;\n}\ndialog.f12-dialog::backdrop {\n  overflow: hidden;\n  overscroll-behavior: contain;\n  background-color: var(--f-backdrop);\n  background-image: radial-gradient(circle, var(--f-ink) 1px, transparent 1.5px);\n  background-size: 6px 6px;\n}\n.f12-dialog-header {\n  display: flex;\n  flex-direction: column;\n  gap: 6px;\n  margin-bottom: 16px;\n}\n.f12-dialog-title {\n  font-family: var(--font-f-display);\n  font-weight: 400;\n  font-size: 24px;\n  line-height: 1.1;\n  color: var(--f-ink);\n  margin: 0;\n}\n.f12-dialog-description {\n  font-size: 14px;\n  color: var(--f-ink-2);\n  margin: 0;\n}\n.f12-dialog-footer {\n  display: flex;\n  justify-content: flex-end;\n  gap: var(--f-gutter-pair);\n  margin-top: 20px;\n}\n\n/* Select */\n.f12-select {\n  position: relative;\n  display: inline-flex;\n  flex-direction: column;\n  gap: 6px;\n  min-width: 180px;\n  font-family: var(--font-f-body);\n}\n.f12-select-trigger {\n  display: flex;\n  align-items: center;\n  justify-content: space-between;\n  gap: var(--f-gutter-pair);\n  width: 100%;\n  padding: 8px 12px;\n  background: var(--f-panel);\n  color: var(--f-ink);\n  border: 2.5px solid var(--f-rule);\n  font-family: var(--font-f-mono);\n  font-size: 12px;\n  font-weight: 500;\n  cursor: pointer;\n  text-align: left;\n}\n.f12-select-trigger:focus-visible {\n  outline: 3px solid var(--f-ink);\n  outline-offset: 2px;\n}\n.f12-select-caret {\n  display: inline-block;\n  padding: 1px 4px;\n  font-size: 10px;\n  background: var(--f-marker);\n  color: var(--f-marker-ink);\n  border: 1.5px solid var(--f-rule);\n  line-height: 1;\n}\n.f12-select-content {\n  z-index: 50;\n  min-width: var(--radix-select-trigger-width, 180px);\n  max-height: var(--radix-select-content-available-height, 300px);\n  overflow-y: auto;\n  background: var(--f-panel);\n  color: var(--f-ink);\n  border: 2.5px solid var(--f-rule);\n  box-shadow: 4px 4px 0 var(--f-rule);\n  list-style: none;\n  margin: 0;\n  padding: 0;\n}\n.f12-select-viewport {\n  padding: 0;\n}\n.f12-select-item {\n  display: flex;\n  align-items: center;\n  justify-content: space-between;\n  width: 100%;\n  padding: 8px 12px;\n  background: var(--f-panel);\n  color: var(--f-ink);\n  border: 0;\n  border-bottom: 1px solid var(--f-grid);\n  font-family: var(--font-f-mono);\n  font-size: 12px;\n  cursor: pointer;\n  text-align: left;\n  user-select: none;\n}\n.f12-select-item:last-child {\n  border-bottom: 0;\n}\n.f12-select-item:hover,\n.f12-select-item[data-highlighted],\n.f12-select-item[aria-selected=\"true\"],\n.f12-select-item[data-state=\"checked\"] {\n  background: var(--f-ink);\n  color: var(--f-panel);\n  outline: none;\n}\n.f12-select-item:focus-visible {\n  outline: 3px solid var(--f-ink);\n  outline-offset: -3px;\n}\n.f12-select-item[data-disabled] {\n  opacity: 0.5;\n  cursor: not-allowed;\n}\n.f12-select-check {\n  background: var(--f-marker);\n  color: var(--f-marker-ink);\n  padding: 0 4px;\n  font-size: 10px;\n  font-weight: 700;\n}\n.f12-select-label {\n  padding: 6px 12px 4px;\n  font-family: var(--font-f-mono);\n  font-size: 10px;\n  font-weight: 700;\n  letter-spacing: 0.14em;\n  text-transform: uppercase;\n  color: var(--f-ink-2);\n}\n.f12-select-sep {\n  height: 1px;\n  background: var(--f-grid);\n  margin: 4px 0;\n}\n\n/* Tooltip */\n.f12-tooltip-wrap {\n  position: relative;\n  display: inline-flex;\n  align-items: center;\n}\n.f12-tooltip {\n  position: absolute;\n  bottom: calc(100% + 8px);\n  left: 50%;\n  transform: translateX(-50%);\n  z-index: 50;\n  white-space: nowrap;\n  padding: 5px 10px;\n  background: var(--f-panel);\n  color: var(--f-ink);\n  border: 2px solid var(--f-rule);\n  box-shadow: 3px 3px 0 var(--f-rule);\n  font-family: var(--font-f-mono);\n  font-size: 11px;\n  pointer-events: none;\n}\n\n/* DropdownMenu */\n.f12-menu-wrap {\n  position: relative;\n  display: inline-block;\n}\n.f12-menu {\n  z-index: 50;\n  min-width: 180px;\n  background: var(--f-panel);\n  color: var(--f-ink);\n  border: 2.5px solid var(--f-rule);\n  box-shadow: 4px 4px 0 var(--f-rule);\n  padding: 4px 0;\n}\n.f12-menu-label {\n  padding: 6px 12px 4px;\n  font-family: var(--font-f-mono);\n  font-size: 10px;\n  font-weight: 700;\n  letter-spacing: 0.14em;\n  text-transform: uppercase;\n  color: var(--f-ink-2);\n}\n.f12-menu-sep {\n  height: 1px;\n  background: var(--f-grid);\n  margin: 4px 0;\n}\n.f12-menu-item {\n  display: flex;\n  align-items: center;\n  justify-content: space-between;\n  width: 100%;\n  padding: 7px 12px;\n  background: var(--f-panel);\n  color: var(--f-ink);\n  border: 0;\n  font-family: var(--font-f-body);\n  font-size: 13px;\n  cursor: pointer;\n  text-align: left;\n  user-select: none;\n}\n.f12-menu-item:hover,\n.f12-menu-item[data-highlighted],\n.f12-menu-item:focus-visible {\n  background: var(--f-ink);\n  color: var(--f-panel);\n  outline: none;\n}\n.f12-menu-item[data-disabled] {\n  opacity: 0.5;\n  cursor: not-allowed;\n}\n\n/* Table */\n.f12-table-wrap {\n  width: 100%;\n  overflow-x: auto;\n}\n.f12-table {\n  width: 100%;\n  border-collapse: collapse;\n  font-family: var(--font-f-body);\n  font-size: 13px;\n  color: var(--f-ink);\n  font-variant-numeric: tabular-nums;\n}\n.f12-table caption {\n  caption-side: bottom;\n  padding-top: 8px;\n  text-align: left;\n  font-family: var(--font-f-mono);\n  font-size: 11px;\n  color: var(--f-ink-2);\n}\n.f12-table th,\n.f12-table td {\n  text-align: left;\n  padding: 8px 12px 8px 0;\n  border-bottom: 1px solid var(--f-grid);\n}\n.f12-table thead th {\n  font-family: var(--font-f-mono);\n  font-size: 11px;\n  font-weight: 500;\n  letter-spacing: 0.14em;\n  text-transform: uppercase;\n  color: var(--f-ink-2);\n  border-bottom: 2.5px solid var(--f-rule);\n}\n.f12-table tfoot td,\n.f12-table tfoot th {\n  font-family: var(--font-f-mono);\n  font-weight: 700;\n  border-top: 2px solid var(--f-rule);\n  border-bottom: 0;\n}\n\n/* ===================================================================== Responsive Container Rules */\n@media (max-width: 760px) {\n  .f12-frame {\n    padding: 6px;\n  }\n}\n\n@container (max-width: 760px) {\n  .f12-frame {\n    padding: 6px;\n  }\n  .f12-sheet {\n    padding: 40px 14px 18px;\n    gap: 24px;\n  }\n  .f12-scene,\n  .f12-scene.f12-scene-split,\n  .f12-scene.f12-scene-equal,\n  .f12-scene.f12-scene-three {\n    grid-template-columns: minmax(0, 1fr);\n  }\n  .f12-rng-btn {\n    padding: 6px 10px 5px;\n    min-width: 52px;\n  }\n  .f12-panel-body {\n    padding: 22px 14px 18px;\n  }\n  .f12-int-row {\n    grid-template-columns: minmax(0, 1fr) auto;\n    grid-template-areas: \"name val\" \"bar bar\";\n    gap: 8px 12px;\n  }\n  .f12-int-name {\n    grid-area: name;\n  }\n  .f12-int-val {\n    grid-area: val;\n  }\n  .f12-int-bar {\n    grid-area: bar;\n  }\n  .f12-m-value {\n    font-size: 30px;\n  }\n}\n\n/* ===================================================================== Motion Grammar\n   smooth  = continuous easing\n   stepped = poses held on twos: 12 drawings/s, each pose 83.33ms\n   cut     = instant, editorial hard cut */\n.f12-m-smooth .f12-rng-ind {\n  transition: transform 260ms cubic-bezier(0.2, 0.8, 0.2, 1), width 260ms cubic-bezier(0.2, 0.8, 0.2, 1);\n}\n.f12-m-stepped .f12-rng-ind {\n  transition: transform 250ms steps(3, end), width 250ms steps(3, end);\n}\n\n.f12-m-smooth .f12-enter {\n  animation: f12EnterSmooth 260ms cubic-bezier(0.2, 0.8, 0.2, 1);\n}\n@keyframes f12EnterSmooth {\n  from {\n    opacity: 0;\n    transform: translateY(6px);\n  }\n  to {\n    opacity: 1;\n    transform: none;\n  }\n}\n.f12-m-stepped .f12-enter {\n  animation: f12EnterStep 250ms;\n  animation-timing-function: step-end;\n}\n@keyframes f12EnterStep {\n  0% {\n    opacity: 0.35;\n    transform: translateY(10px);\n  }\n  33% {\n    opacity: 0.8;\n    transform: translateY(4px);\n  }\n  66% {\n    opacity: 1;\n    transform: translateY(1px);\n  }\n  100% {\n    opacity: 1;\n    transform: none;\n  }\n}\n\n.f12-m-smooth .f12-pop {\n  animation: f12PopSmooth 240ms cubic-bezier(0.2, 0.9, 0.3, 1.25);\n}\n@keyframes f12PopSmooth {\n  from {\n    opacity: 0;\n    transform: scale(0.85);\n  }\n  to {\n    opacity: 1;\n    transform: none;\n  }\n}\n.f12-m-stepped .f12-pop {\n  animation: f12PopStep 333ms;\n  animation-timing-function: step-end;\n}\n@keyframes f12PopStep {\n  0% {\n    transform: scale(0.5);\n  }\n  25% {\n    transform: scale(1.22);\n  }\n  50% {\n    transform: scale(0.94);\n  }\n  75% {\n    transform: scale(1);\n  }\n  100% {\n    transform: none;\n  }\n}\n.f12-m-stepped .f12-pop .f12-burst {\n  animation: f12BurstStep 250ms;\n  animation-timing-function: step-end;\n}\n@keyframes f12BurstStep {\n  0% {\n    opacity: 1;\n    transform: translate(-50%, -50%) scale(0.85);\n  }\n  33% {\n    opacity: 1;\n    transform: translate(-50%, -50%) scale(1.08);\n  }\n  66%,\n  100% {\n    opacity: 0;\n  }\n}\n.f12-m-smooth .f12-pop .f12-burst {\n  animation: f12BurstSmooth 320ms ease-out;\n}\n@keyframes f12BurstSmooth {\n  from {\n    opacity: 0.9;\n    transform: translate(-50%, -50%) scale(0.85);\n  }\n  to {\n    opacity: 0;\n    transform: translate(-50%, -50%) scale(1.15);\n  }\n}\n\n@media (prefers-reduced-motion: reduce) {\n  .f12-dash *,\n  .f12-dash *::before,\n  .f12-dash *::after,\n  .f12-sheet *,\n  .f12-sheet *::before,\n  .f12-sheet *::after {\n    animation: none !important;\n    transition: none !important;\n  }\n}\n\n/* ===================================================================== Forced Colors (High Contrast) */\n@media (forced-colors: active) {\n  .f12-panel-frame polygon {\n    fill: Canvas;\n    stroke: CanvasText;\n  }\n  .f12-tag,\n  .f12-badge {\n    border: 1px solid CanvasText;\n  }\n  .f12-l-total,\n  .f12-l-focus,\n  .f12-spark-bar,\n  .f12-tail,\n  .f12-baseline,\n  .f12-sheet-ticks line {\n    stroke: CanvasText;\n  }\n  .f12-grid {\n    stroke: GrayText;\n  }\n  .f12-tone-dot,\n  .f12-peak-dot,\n  .f12-cross-dot {\n    fill: CanvasText;\n    stroke: CanvasText;\n  }\n  .f12-int-fill {\n    background: Highlight;\n    forced-color-adjust: none;\n  }\n  .f12-rng-ind {\n    mix-blend-mode: normal;\n    background: transparent;\n    border: 2px solid Highlight;\n  }\n  .f12-rng-btn[aria-pressed=\"true\"],\n  .f12-int-row[aria-pressed=\"true\"],\n  .f12-select-item[data-state=\"checked\"] {\n    outline: 2px solid Highlight;\n    outline-offset: -2px;\n  }\n  .f12-frame :focus-visible,\n  .f12-sheet :focus-visible,\n  .f12-dialog :focus-visible,\n  [class*=\"f12-\"]:focus-visible {\n    outline: 3px solid Highlight;\n  }\n}\n",
      "type": "registry:file",
      "target": "styles/frame12.css"
    },
    {
      "path": "styles/frame12-tailwind.css",
      "content": "/* Optional Tailwind v4 @theme mapping for FRAME/12 tokens and gutter grammar.\n   Import alongside frame12.css when using Tailwind CSS v4. */\n\n@import \"./frame12.css\";\n\n@theme inline {\n  --color-f-desk: var(--f-desk);\n  --color-f-sheet: var(--f-sheet);\n  --color-f-panel: var(--f-panel);\n  --color-f-ink: var(--f-ink);\n  --color-f-ink-2: var(--f-ink-2);\n  --color-f-rule: var(--f-rule);\n  --color-f-tone: var(--f-tone);\n  --color-f-grid: var(--f-grid);\n  --color-f-marker: var(--f-marker);\n  --color-f-marker-ink: var(--f-marker-ink);\n  --color-f-hole: var(--f-hole);\n\n  --font-f12-display: var(--font-f-display);\n  --font-f12-body: var(--font-f-body);\n  --font-f12-mono: var(--font-f-mono);\n\n  --spacing-gutter-pair: var(--f-gutter-pair);\n  --spacing-gutter-scene: var(--f-gutter-scene);\n  --spacing-gutter-change: var(--f-gutter-change);\n}\n",
      "type": "registry:file",
      "target": "styles/frame12-tailwind.css"
    },
    {
      "path": "hooks/use-on-twos.ts",
      "content": "'use client';\n\nimport * as React from 'react';\n\nexport type MotionMode = 'stepped' | 'smooth' | 'cut';\n\nexport const FRAME_MS = 1000 / 12; // animating \"on twos\": 12 drawings per second (83.33ms per pose)\n\nconst easeOut = (t: number): number => 1 - Math.pow(1 - t, 3);\n\nconst useIsoLayoutEffect = typeof window !== 'undefined' ? React.useLayoutEffect : React.useEffect;\n\nexport function useSize(ref: { readonly current: HTMLElement | null }): { w: number; h: number } {\n  const [size, setSize] = React.useState<{ w: number; h: number }>({ w: 0, h: 0 });\n\n  useIsoLayoutEffect(() => {\n    const el = ref.current;\n    if (!el) return;\n    // Layout size (offsetWidth/Height), not the transformed box, so scaled previews draw correctly.\n    const measure = () => {\n      const w = el.offsetWidth;\n      const h = el.offsetHeight;\n      setSize((s) => (s.w === w && s.h === h ? s : { w, h }));\n    };\n    measure();\n    if (typeof ResizeObserver === 'undefined') return;\n    const ro = new ResizeObserver(measure);\n    ro.observe(el);\n    return () => ro.disconnect();\n  }, [ref]);\n\n  return size;\n}\n\nconst REDUCED_MOTION_QUERY = '(prefers-reduced-motion: reduce)';\n\nfunction subscribeReducedMotion(onStoreChange: () => void): () => void {\n  if (typeof window === 'undefined' || typeof window.matchMedia !== 'function') {\n    return () => {};\n  }\n  const q = window.matchMedia(REDUCED_MOTION_QUERY);\n  if (q.addEventListener) {\n    q.addEventListener('change', onStoreChange);\n    return () => q.removeEventListener('change', onStoreChange);\n  }\n  q.addListener(onStoreChange);\n  return () => q.removeListener(onStoreChange);\n}\n\nfunction getReducedMotionSnapshot(): boolean {\n  if (typeof window === 'undefined' || typeof window.matchMedia !== 'function') {\n    return false;\n  }\n  return window.matchMedia(REDUCED_MOTION_QUERY).matches;\n}\n\nfunction getReducedMotionServerSnapshot(): boolean {\n  return false;\n}\n\nexport function useReducedMotion(): boolean {\n  return React.useSyncExternalStore(\n    subscribeReducedMotion,\n    getReducedMotionSnapshot,\n    getReducedMotionServerSnapshot,\n  );\n}\n\n/**\n * Progress 0..1 that replays whenever `key` changes.\n *\n * Stepped mode samples the cubic-out easing curve at 12 poses per second\n * (`FRAME_MS = 1000 / 12 = 83.33ms` per pose), like an animation exposure sheet\n * (\"on twos\"). Pose 1 (`k = 1`, `t = 1 / frames`) is displayed immediately at\n * `elapsed = 0` (`Math.floor(el / FRAME_MS) + 1`) so the element visibly steps\n * on the exact interaction frame rather than sitting at 0 for 83.33ms, and each\n * subsequent pose is held for a full 83.33ms interval until `frames` poses complete.\n *\n * Only changes to `key` trigger a new tween; changing `duration` or `motion`\n * alone keeps the current resting state. Honors `prefers-reduced-motion: reduce`.\n */\nexport function useOnTwos(\n  key: unknown,\n  duration = 600,\n  motion: MotionMode = 'stepped',\n): number {\n  const reduced = useReducedMotion();\n  const effectiveMotion: MotionMode = reduced ? 'cut' : motion;\n  const [p, setP] = React.useState<number>(1);\n  const prevKeyRef = React.useRef<unknown>(key);\n  const frames = Math.max(2, Math.round(duration / FRAME_MS));\n  const initialP =\n    effectiveMotion === 'cut' ? 1 : effectiveMotion === 'stepped' ? easeOut(1 / frames) : 0;\n\n  useIsoLayoutEffect(() => {\n    if (effectiveMotion === 'cut') {\n      prevKeyRef.current = key;\n      setP(1);\n      return;\n    }\n    if (Object.is(prevKeyRef.current, key)) {\n      setP(1);\n      return;\n    }\n    prevKeyRef.current = key;\n    const start = performance.now();\n    const totalFrames = Math.max(2, Math.round(duration / FRAME_MS));\n    let raf = 0;\n    let last = -1;\n    const tick = (now: number) => {\n      const el = now - start;\n      let t: number;\n      if (effectiveMotion === 'stepped') {\n        const k = Math.min(totalFrames, Math.floor(el / FRAME_MS) + 1);\n        t = k / totalFrames;\n      } else {\n        t = Math.min(1, el / duration);\n      }\n      const v = easeOut(t);\n      if (v !== last) {\n        last = v;\n        setP(v);\n      }\n      if (t < 1) raf = requestAnimationFrame(tick);\n    };\n    setP(effectiveMotion === 'stepped' ? easeOut(1 / totalFrames) : 0);\n    raf = requestAnimationFrame(tick);\n    return () => cancelAnimationFrame(raf);\n  }, [key, duration, effectiveMotion]);\n\n  const isNewKey = !Object.is(prevKeyRef.current, key);\n  return isNewKey ? initialP : p;\n}\n\nexport const useTween = useOnTwos;\n\nexport function useCountUp(\n  value: number,\n  motion: MotionMode = 'stepped',\n  duration = 600,\n): number {\n  const prev = React.useRef<number>(value);\n  const from = React.useRef<number>(value);\n  const displayedRef = React.useRef<number>(value);\n  if (!Object.is(prev.current, value)) {\n    from.current = displayedRef.current;\n    prev.current = value;\n  }\n  const p = useOnTwos(value, duration, motion);\n  const current = from.current + (value - from.current) * p;\n  displayedRef.current = current;\n  return current;\n}\n\n/**\n * Becomes true after the first change of `key`, so entrance animations\n * never run on first paint (the page is complete at rest).\n */\nexport function useChanged(key: unknown): boolean {\n  const first = React.useRef<unknown>(key);\n  const [changed, setChanged] = React.useState<boolean>(false);\n  React.useEffect(() => {\n    if (key !== first.current) setChanged(true);\n  }, [key]);\n  return changed;\n}\n",
      "type": "registry:hook",
      "target": "hooks/use-on-twos.ts"
    },
    {
      "path": "ui/index.ts",
      "content": "export { Sheet, Pegs, type SheetProps } from './sheet';\nexport { Scene, GUTTERS, type SceneGutter, type SceneLayout, type SceneProps } from './scene';\nexport { Panel, type PanelShape, type PanelProps } from './panel';\nexport { PanelPair, type PanelPairProps } from './panel-pair';\nexport {\n  SegmentedControl,\n  type SegmentedOption,\n  type SegmentedControlProps,\n} from './segmented-control';\nexport { Button, type ButtonVariant, type ButtonSize, type ButtonProps } from './button';\nexport { Input, type InputProps } from './input';\nexport { Badge, Burst, type BadgeProps } from './badge';\nexport { Tag, type TagProps } from './tag';\nexport {\n  Metric,\n  Delta,\n  fmtPct,\n  fmtPPAbs,\n  fmtMoney,\n  type DeltaProps,\n  type MetricProps,\n  type MetricHeadingLevel,\n} from './metric';\nexport { Balloon, type BalloonProps } from './balloon';\nexport {\n  ToneAreaChart,\n  defaultFormatValue,\n  defaultFormatShort,\n  fmtCurrency,\n  fmtCurrencyShort,\n  type ToneAreaDatum,\n  type ToneAreaAnnotation,\n  type ToneAreaChartProps,\n} from './tone-area-chart';\nexport {\n  ToneBarList,\n  type ToneBarItem,\n  type ToneBarListProps,\n} from './tone-bar-list';\nexport { ToneSpark, type ToneSparkProps } from './tone-spark';\nexport {\n  Dialog,\n  DialogTrigger,\n  DialogContent,\n  DialogHeader,\n  DialogTitle,\n  DialogDescription,\n  DialogFooter,\n  DialogClose,\n  type DialogProps,\n  type DialogTriggerProps,\n  type DialogContentProps,\n} from './dialog';\nexport {\n  Select,\n  SelectTrigger,\n  SelectValue,\n  SelectContent,\n  SelectItem,\n  SelectGroup,\n  SelectLabel,\n  SelectSeparator,\n  type SelectProps,\n  type SelectTriggerProps,\n  type SelectValueProps,\n  type SelectContentProps,\n  type SelectItemProps,\n  type SelectGroupProps,\n  type SelectLabelProps,\n  type SelectSeparatorProps,\n} from './select';\nexport {\n  TooltipProvider,\n  Tooltip,\n  TooltipTrigger,\n  TooltipContent,\n  type TooltipProps,\n  type TooltipTriggerProps,\n} from './tooltip';\nexport {\n  DropdownMenu,\n  DropdownMenuTrigger,\n  DropdownMenuContent,\n  DropdownMenuLabel,\n  DropdownMenuSeparator,\n  DropdownMenuItem,\n  DropdownMenuGroup,\n  type DropdownMenuProps,\n  type DropdownMenuTriggerProps,\n  type DropdownMenuContentProps,\n  type DropdownMenuLabelProps,\n  type DropdownMenuSeparatorProps,\n  type DropdownMenuItemProps,\n  type DropdownMenuGroupProps,\n} from './dropdown-menu';\nexport {\n  Table,\n  TableHeader,\n  TableBody,\n  TableFooter,\n  TableRow,\n  TableHead,\n  TableCell,\n  TableCaption,\n} from './table';\n",
      "type": "registry:ui",
      "target": "components/frame12/index.ts"
    },
    {
      "path": "ui/sheet.tsx",
      "content": "'use client';\n\nimport * as React from 'react';\nimport { type MotionMode, useReducedMotion } from '@/hooks/use-on-twos';\n\nexport interface SheetProps extends React.HTMLAttributes<HTMLDivElement> {\n  pegs?: boolean;\n  motion?: MotionMode;\n  theme?: 'light' | 'dark';\n  sheetClassName?: string;\n  children?: React.ReactNode;\n}\n\nexport function Pegs() {\n  return (\n    <div className=\"f12-pegs\" aria-hidden=\"true\">\n      <span className=\"f12-peg slot\" />\n      <span className=\"f12-peg round\" />\n      <span className=\"f12-peg slot\" />\n    </div>\n  );\n}\n\nexport const Sheet = React.forwardRef<HTMLDivElement, SheetProps>(function Sheet(\n  {\n    pegs = true,\n    motion = 'stepped',\n    theme,\n    className = '',\n    sheetClassName = '',\n    children,\n    ...rest\n  },\n  ref,\n) {\n  const reduced = useReducedMotion();\n  const effectiveMotion: MotionMode = reduced ? 'cut' : motion;\n  const themeClass = theme ? ` f12-theme-${theme}` : '';\n  const outerClass = `f12-dash f12-frame f12-m-${effectiveMotion}${themeClass}${className ? ` ${className}` : ''}`;\n  const innerClass = `f12-sheet${sheetClassName ? ` ${sheetClassName}` : ''}`;\n\n  return (\n    <div ref={ref} className={outerClass} data-theme={theme} {...rest}>\n      <div className={innerClass}>\n        {pegs && <Pegs />}\n        {children}\n      </div>\n    </div>\n  );\n});\n",
      "type": "registry:ui",
      "target": "components/frame12/sheet.tsx"
    },
    {
      "path": "ui/scene.tsx",
      "content": "'use client';\n\nimport * as React from 'react';\n\nexport type SceneGutter = 'pair' | 'scene' | 'change';\nexport type SceneLayout = 'split' | 'stack' | 'equal' | 'three';\n\nexport const GUTTERS: Record<SceneGutter, number> = {\n  pair: 12,\n  scene: 20,\n  change: 32,\n};\n\nexport interface SceneProps extends React.HTMLAttributes<HTMLDivElement> {\n  gutter?: SceneGutter;\n  layout?: SceneLayout;\n  children?: React.ReactNode;\n}\n\nexport const Scene = React.forwardRef<HTMLDivElement, SceneProps>(function Scene(\n  { gutter = 'scene', layout = 'split', className = '', children, ...rest },\n  ref,\n) {\n  const safeGutter: SceneGutter =\n    gutter === 'pair' || gutter === 'scene' || gutter === 'change' ? gutter : 'scene';\n  const safeLayout: SceneLayout =\n    layout === 'split' || layout === 'stack' || layout === 'equal' || layout === 'three'\n      ? layout\n      : 'split';\n\n  const classes = `f12-scene f12-scene-${safeLayout} f12-scene-${safeGutter}${className ? ` ${className}` : ''}`;\n\n  return (\n    <div\n      ref={ref}\n      className={classes}\n      data-gutter={GUTTERS[safeGutter]}\n      data-layout={safeLayout}\n      {...rest}\n    >\n      {children}\n    </div>\n  );\n});\n",
      "type": "registry:ui",
      "target": "components/frame12/scene.tsx"
    },
    {
      "path": "ui/panel.tsx",
      "content": "'use client';\n\nimport * as React from 'react';\nimport { useSize } from '@/hooks/use-on-twos';\n\nexport type PanelShape = 'rect' | 'slant-bottom' | 'slant-top';\n\nexport interface PanelProps extends React.HTMLAttributes<HTMLElement> {\n  cut?: string;\n  shape?: PanelShape;\n  label?: string;\n  children?: React.ReactNode;\n}\n\nexport const Panel = React.forwardRef<HTMLElement, PanelProps>(function Panel(\n  { cut, shape = 'rect', className = '', label, children, ...rest },\n  forwardedRef,\n) {\n  const innerRef = React.useRef<HTMLElement | null>(null);\n  const setRefs = React.useCallback(\n    (node: HTMLElement | null) => {\n      innerRef.current = node;\n      if (typeof forwardedRef === 'function') {\n        forwardedRef(node);\n      } else if (forwardedRef) {\n        (forwardedRef as React.MutableRefObject<HTMLElement | null>).current = node;\n      }\n    },\n    [forwardedRef],\n  );\n\n  const { w, h } = useSize(innerRef);\n  const s = 1.25; // half of 2.5px stroke\n  const d = 16; // slant rise in px\n  let pts: string;\n  if (shape === 'slant-bottom') {\n    pts = `${s},${s} ${w - s},${s} ${w - s},${h - s - d} ${s},${h - s}`;\n  } else if (shape === 'slant-top') {\n    pts = `${s},${s + d} ${w - s},${s} ${w - s},${h - s} ${s},${h - s}`;\n  } else {\n    pts = `${s},${s} ${w - s},${s} ${w - s},${h - s} ${s},${h - s}`;\n  }\n\n  const ssrPts =\n    shape === 'slant-bottom'\n      ? '0.35,0.35 99.65,0.35 99.65,93.2 0.35,99.65'\n      : shape === 'slant-top'\n        ? '0.35,6.8 99.65,0.35 99.65,99.65 0.35,99.65'\n        : '0.35,0.35 99.65,0.35 99.65,99.65 0.35,99.65';\n\n  return (\n    <section\n      ref={setRefs}\n      className={`f12-panel f12-${shape}${className ? ` ${className}` : ''}`}\n      aria-label={label}\n      {...rest}\n    >\n      {w > 0 ? (\n        <svg className=\"f12-panel-frame\" width={w} height={h} aria-hidden=\"true\">\n          <polygon points={pts} />\n        </svg>\n      ) : (\n        <svg\n          className=\"f12-panel-frame\"\n          viewBox=\"0 0 100 100\"\n          preserveAspectRatio=\"none\"\n          aria-hidden=\"true\"\n        >\n          <polygon vectorEffect=\"non-scaling-stroke\" points={ssrPts} />\n        </svg>\n      )}\n      {cut && (\n        <span className=\"f12-cut\" aria-hidden=\"true\">\n          {cut}\n        </span>\n      )}\n      <div className=\"f12-panel-body\">{children}</div>\n    </section>\n  );\n});\n",
      "type": "registry:ui",
      "target": "components/frame12/panel.tsx"
    },
    {
      "path": "ui/panel-pair.tsx",
      "content": "'use client';\n\nimport * as React from 'react';\nimport { Panel, type PanelProps } from './panel';\n\nexport interface PanelPairProps extends React.HTMLAttributes<HTMLDivElement> {\n  top?: Omit<PanelProps, 'shape'>;\n  bottom?: Omit<PanelProps, 'shape'>;\n  topCut?: string;\n  bottomCut?: string;\n  topLabel?: string;\n  bottomLabel?: string;\n  children?: React.ReactNode;\n}\n\nexport const PanelPair = React.forwardRef<HTMLDivElement, PanelPairProps>(function PanelPair(\n  {\n    top,\n    bottom,\n    topCut,\n    bottomCut,\n    topLabel,\n    bottomLabel,\n    className = '',\n    children,\n    ...rest\n  },\n  ref,\n) {\n  const classes = `f12-pair${className ? ` ${className}` : ''}`;\n\n  if (top && bottom) {\n    return (\n      <div ref={ref} className={classes} {...rest}>\n        <Panel {...top} shape=\"slant-bottom\" />\n        <Panel {...bottom} shape=\"slant-top\" />\n      </div>\n    );\n  }\n\n  const items = React.Children.toArray(children);\n  if (process.env.NODE_ENV !== 'production' && items.length > 2) {\n    console.warn(\n      `[FRAME/12 PanelPair] Expected at most 2 children (top and bottom panels), received ${items.length}. Extra children will not be rendered.`,\n    );\n  }\n  const first = items[0];\n  const second = items[1];\n\n  const renderSlot = (\n    node: React.ReactNode,\n    shape: 'slant-bottom' | 'slant-top',\n    fallbackCut?: string,\n    fallbackLabel?: string,\n  ) => {\n    if (React.isValidElement<PanelProps>(node) && node.type === Panel) {\n      return React.cloneElement(node, {\n        shape: node.props.shape && node.props.shape !== 'rect' ? node.props.shape : shape,\n        cut: node.props.cut ?? fallbackCut,\n        label: node.props.label ?? fallbackLabel,\n      });\n    }\n    return (\n      <Panel shape={shape} cut={fallbackCut} label={fallbackLabel}>\n        {node}\n      </Panel>\n    );\n  };\n\n  return (\n    <div ref={ref} className={classes} {...rest}>\n      {first !== undefined && renderSlot(first, 'slant-bottom', topCut, topLabel)}\n      {second !== undefined && renderSlot(second, 'slant-top', bottomCut, bottomLabel)}\n    </div>\n  );\n});\n",
      "type": "registry:ui",
      "target": "components/frame12/panel-pair.tsx"
    },
    {
      "path": "ui/segmented-control.tsx",
      "content": "'use client';\n\nimport * as React from 'react';\n\nexport interface SegmentedOption<T extends string | number = string | number> {\n  value: T;\n  label: string;\n  unit?: string;\n}\n\nexport interface SegmentedControlProps<T extends string | number = string | number> {\n  options: Array<SegmentedOption<T>>;\n  value: T;\n  onChange: (value: T) => void;\n  ariaLabel?: string;\n  idPrefix?: string;\n  className?: string;\n}\n\nconst useIsoLayoutEffect = typeof window !== 'undefined' ? React.useLayoutEffect : React.useEffect;\n\nexport function SegmentedControl<T extends string | number = string | number>({\n  options,\n  value,\n  onChange,\n  ariaLabel = 'Options',\n  idPrefix,\n  className = '',\n}: SegmentedControlProps<T>) {\n  const autoId = React.useId().replace(/:/g, '');\n  const resolvedPrefix = idPrefix ?? `seg-${autoId}`;\n  const wrap = React.useRef<HTMLDivElement | null>(null);\n  const [ind, setInd] = React.useState<{ x: number; w: number } | null>(null);\n\n  useIsoLayoutEffect(() => {\n    const el = wrap.current?.querySelector<HTMLElement>('[aria-pressed=\"true\"]');\n    if (!el) return;\n    const x = el.offsetLeft + el.clientLeft;\n    const w = el.clientWidth;\n    setInd((s) => (s && s.x === x && s.w === w ? s : { x, w }));\n  });\n\n  // Re-measure when fonts finish loading or the control resizes.\n  const [, bump] = React.useState(0);\n  React.useEffect(() => {\n    const el = wrap.current;\n    if (!el || typeof ResizeObserver === 'undefined') return;\n    const ro = new ResizeObserver(() => bump((n) => n + 1));\n    ro.observe(el);\n    return () => ro.disconnect();\n  }, []);\n\n  return (\n    <div\n      className={`f12-rng${className ? ` ${className}` : ''}`}\n      ref={wrap}\n      role=\"group\"\n      aria-label={ariaLabel}\n    >\n      {ind && (\n        <span\n          className=\"f12-rng-ind\"\n          aria-hidden=\"true\"\n          style={{ transform: `translateX(${ind.x}px)`, width: ind.w }}\n        />\n      )}\n      {options.map((opt) => (\n        <button\n          key={String(opt.value)}\n          id={`${resolvedPrefix}-${opt.value}`}\n          type=\"button\"\n          className=\"f12-rng-btn\"\n          aria-pressed={value === opt.value}\n          onClick={() => onChange(opt.value)}\n        >\n          <span className=\"f12-rng-n\">{opt.label}</span>\n          {opt.unit && <span className=\"f12-rng-u\">{opt.unit}</span>}\n        </button>\n      ))}\n    </div>\n  );\n}\n",
      "type": "registry:ui",
      "target": "components/frame12/segmented-control.tsx"
    },
    {
      "path": "ui/button.tsx",
      "content": "'use client';\n\nimport * as React from 'react';\n\nexport type ButtonVariant = 'primary' | 'secondary' | 'marker';\nexport type ButtonSize = 'sm' | 'md' | 'lg';\n\nexport interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n  variant?: ButtonVariant;\n  size?: ButtonSize;\n}\n\nexport const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(function Button(\n  { variant = 'secondary', size = 'md', type = 'button', className = '', children, ...rest },\n  ref,\n) {\n  const classes = `f12-btn f12-btn-${variant} f12-btn-${size}${className ? ` ${className}` : ''}`;\n  return (\n    <button ref={ref} type={type} className={classes} {...rest}>\n      {children}\n    </button>\n  );\n});\n",
      "type": "registry:ui",
      "target": "components/frame12/button.tsx"
    },
    {
      "path": "ui/input.tsx",
      "content": "'use client';\n\nimport * as React from 'react';\n\nexport interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {\n  label: string;\n  hint?: string;\n  error?: string;\n  fieldClassName?: string;\n}\n\nexport const Input = React.forwardRef<HTMLInputElement, InputProps>(function Input(\n  {\n    id,\n    label,\n    hint,\n    error,\n    className = '',\n    fieldClassName = '',\n    'aria-describedby': userDescribedBy,\n    'aria-invalid': userAriaInvalid,\n    ...rest\n  },\n  ref,\n) {\n  const autoId = React.useId();\n  const inputId = id || `f12-input-${autoId.replace(/:/g, '')}`;\n  const hintId = hint ? `${inputId}-hint` : undefined;\n  const errorId = error ? `${inputId}-error` : undefined;\n  const describedBy =\n    [userDescribedBy, hintId, errorId].filter(Boolean).join(' ') || undefined;\n\n  return (\n    <div className={`f12-field${fieldClassName ? ` ${fieldClassName}` : ''}`}>\n      <label htmlFor={inputId} className=\"f12-label\">\n        {label}\n      </label>\n      <input\n        ref={ref}\n        id={inputId}\n        className={`f12-input${className ? ` ${className}` : ''}`}\n        aria-describedby={describedBy}\n        aria-invalid={error ? true : userAriaInvalid}\n        {...rest}\n      />\n      {hint && (\n        <p id={hintId} className=\"f12-hint\">\n          {hint}\n        </p>\n      )}\n      {error && (\n        <p id={errorId} className=\"f12-error\" role=\"alert\">\n          <span className=\"f12-error-flag\" aria-hidden=\"true\">\n            !\n          </span>\n          <span>{error}</span>\n        </p>\n      )}\n    </div>\n  );\n});\n",
      "type": "registry:ui",
      "target": "components/frame12/input.tsx"
    },
    {
      "path": "ui/badge.tsx",
      "content": "'use client';\n\nimport * as React from 'react';\n\nexport interface BadgeProps extends React.HTMLAttributes<HTMLSpanElement> {\n  pop?: boolean;\n  burst?: boolean;\n  children?: React.ReactNode;\n}\n\nexport function Burst() {\n  const lines: React.ReactElement[] = [];\n  for (let i = 0; i < 14; i++) {\n    const a = (i / 14) * Math.PI * 2;\n    const r1 = 15 + (i % 2) * 3;\n    const r2 = 25 + (i % 3) * 3;\n    lines.push(\n      <line\n        key={i}\n        x1={30 + Math.cos(a) * r1 * 1.9}\n        y1={14 + Math.sin(a) * r1 * 0.75}\n        x2={30 + Math.cos(a) * r2 * 1.9}\n        y2={14 + Math.sin(a) * r2 * 0.75}\n      />,\n    );\n  }\n  return (\n    <svg className=\"f12-burst\" viewBox=\"-20 -12 100 52\" aria-hidden=\"true\">\n      {lines}\n    </svg>\n  );\n}\n\nexport const Badge = React.forwardRef<HTMLSpanElement, BadgeProps>(function Badge(\n  { pop = false, burst = true, className = '', children, ...rest },\n  ref,\n) {\n  return (\n    <span\n      ref={ref}\n      className={`f12-badge${pop ? ' f12-pop pop' : ''}${className ? ` ${className}` : ''}`}\n      {...rest}\n    >\n      {burst && <Burst />}\n      <span className=\"f12-badge-t\">{children}</span>\n    </span>\n  );\n});\n",
      "type": "registry:ui",
      "target": "components/frame12/badge.tsx"
    },
    {
      "path": "ui/tag.tsx",
      "content": "'use client';\n\nimport * as React from 'react';\n\nexport interface TagProps extends React.HTMLAttributes<HTMLSpanElement> {\n  children?: React.ReactNode;\n}\n\nexport const Tag = React.forwardRef<HTMLSpanElement, TagProps>(function Tag(\n  { className = '', children, ...rest },\n  ref,\n) {\n  return (\n    <span ref={ref} className={`f12-tag${className ? ` ${className}` : ''}`} {...rest}>\n      {children}\n    </span>\n  );\n});\n",
      "type": "registry:ui",
      "target": "components/frame12/tag.tsx"
    },
    {
      "path": "ui/metric.tsx",
      "content": "'use client';\n\nimport * as React from 'react';\nimport { type MotionMode, useCountUp } from '@/hooks/use-on-twos';\n\nexport const fmtPct = (v: number): string => (Math.abs(v) * 100).toFixed(1) + '%';\nexport const fmtPPAbs = (v: number): string => Math.abs(v).toFixed(2) + ' pp';\nexport const fmtMoney = (v: number): string => '$' + Math.round(v).toLocaleString('en-US');\n\nexport interface DeltaProps {\n  value: number;\n  kind?: 'pct' | 'pp';\n  comparisonLabel?: string;\n  range?: number | string;\n}\n\nexport function Delta({ value, kind = 'pct', comparisonLabel, range }: DeltaProps) {\n  const flat = kind === 'pp' ? Math.abs(value) < 0.005 : Math.abs(value) < 0.0005;\n  const up = value > 0;\n  const text = flat\n    ? kind === 'pp'\n      ? '0.00 pp change'\n      : '0.0% change'\n    : kind === 'pp'\n      ? fmtPPAbs(value)\n      : fmtPct(value);\n  const dir = flat ? 'flat' : up ? 'up' : 'down';\n  const sym = flat ? '=' : up ? '▲' : '▼';\n  const refLabel = comparisonLabel ?? (range != null ? `vs prior ${range} days` : undefined);\n\n  return (\n    <p className={`f12-delta ${dir}`}>\n      <span className=\"f12-delta-sym\" aria-hidden=\"true\">\n        {sym}\n      </span>\n      <span className=\"f12-sr-only\">{flat ? '' : up ? 'Up ' : 'Down '}</span>\n      {text}\n      {refLabel && <span className=\"f12-delta-ref\"> {refLabel}</span>}\n    </p>\n  );\n}\n\nexport type MetricHeadingLevel = 'h2' | 'h3' | 'h4' | 'div' | 'p';\n\nexport interface MetricProps {\n  label: string;\n  value: number;\n  format?: (value: number) => string;\n  delta?: number;\n  deltaKind?: 'pct' | 'pp';\n  comparisonLabel?: string;\n  range?: number | string;\n  note?: string;\n  big?: boolean;\n  motion?: MotionMode;\n  spark?: React.ReactNode;\n  headingLevel?: MetricHeadingLevel;\n  className?: string;\n}\n\nexport function Metric({\n  label,\n  value,\n  format = fmtMoney,\n  delta,\n  deltaKind = 'pct',\n  comparisonLabel,\n  range,\n  note,\n  big = false,\n  motion = 'stepped',\n  spark,\n  headingLevel: HeadingTag = 'h2',\n  className = '',\n}: MetricProps) {\n  const shown = useCountUp(value, motion);\n\n  return (\n    <div className={`f12-metric${big ? ' big' : ''}${className ? ` ${className}` : ''}`}>\n      <HeadingTag className=\"f12-m-label\">{label}</HeadingTag>\n      <p className=\"f12-m-value\" aria-live=\"polite\">\n        <span className=\"f12-sr-only\">{format(value)}</span>\n        <span aria-hidden=\"true\">{format(shown)}</span>\n      </p>\n      {delta != null && (\n        <Delta value={delta} kind={deltaKind} comparisonLabel={comparisonLabel} range={range} />\n      )}\n      {note && <p className=\"f12-m-note\">{note}</p>}\n      {spark}\n    </div>\n  );\n}\n",
      "type": "registry:ui",
      "target": "components/frame12/metric.tsx"
    },
    {
      "path": "ui/balloon.tsx",
      "content": "'use client';\n\nimport * as React from 'react';\n\nexport interface BalloonProps extends React.HTMLAttributes<HTMLDivElement> {\n  /** Tail horizontal offset in pixels relative to the balloon center (-36 to +36) */\n  tailOffset?: number;\n  /** Whether to show the marker-yellow target dot at the tip of the tail */\n  showDot?: boolean;\n  children?: React.ReactNode;\n}\n\n/**\n * Standalone speech-balloon annotation with mitered tail and seam cover.\n * Uses the same geometry as ToneAreaChart's peak callout.\n */\nexport function Balloon({\n  tailOffset = 0,\n  showDot = true,\n  className = '',\n  children,\n  ...rest\n}: BalloonProps) {\n  const clamped = Math.max(-36, Math.min(36, tailOffset));\n  const svgW = 120;\n  const svgH = 26;\n  const tailX = svgW / 2 + clamped * 0.4;\n  const px = svgW / 2 + clamped;\n  const py = svgH - 5;\n\n  return (\n    <div className={`f12-balloon-standalone${className ? ` ${className}` : ''}`} {...rest}>\n      <div className=\"f12-balloon\">\n        <span\n          className=\"f12-balloon-gap\"\n          aria-hidden=\"true\"\n          style={{ left: `calc(50% + ${clamped * 0.4 - 5}px)` }}\n        />\n        {children}\n      </div>\n      <svg\n        width={svgW}\n        height={svgH}\n        className=\"f12-balloon-standalone-svg\"\n        aria-hidden=\"true\"\n      >\n        <path\n          className=\"f12-tail\"\n          d={`M${tailX - 6},0 L${px - (px - tailX) * 0.15},${py - 7} L${tailX + 6},0`}\n        />\n        {showDot && <circle className=\"f12-peak-dot\" cx={px} cy={py} r=\"4\" />}\n      </svg>\n    </div>\n  );\n}\n",
      "type": "registry:ui",
      "target": "components/frame12/balloon.tsx"
    },
    {
      "path": "ui/tone-area-chart.tsx",
      "content": "'use client';\n\nimport * as React from 'react';\nimport { type MotionMode, useOnTwos, useSize } from '@/hooks/use-on-twos';\n\nexport interface ToneAreaDatum {\n  label: string;\n  longLabel?: string;\n  value: number;\n  compareValue?: number;\n}\n\nexport interface ToneAreaAnnotation {\n  index: number;\n  text: string;\n}\n\nexport interface ToneAreaChartProps {\n  data: ToneAreaDatum[];\n  seriesLabel?: string;\n  compareLabel?: string;\n  labelColumnHeader?: string;\n  formatValue?: (v: number) => string;\n  formatShort?: (v: number) => string;\n  annotation?: ToneAreaAnnotation | null;\n  motion?: MotionMode;\n  height?: number;\n  tableSummary?: string;\n  showTable?: boolean;\n  ariaLabel?: string;\n  className?: string;\n}\n\nexport function defaultFormatValue(v: number): string {\n  const safe = Number.isFinite(v) ? v : 0;\n  return Math.round(safe).toLocaleString('en-US');\n}\n\nexport function defaultFormatShort(v: number): string {\n  const safe = Number.isFinite(v) ? v : 0;\n  if (Math.abs(safe) >= 1000) {\n    const k = safe / 1000;\n    return (Number.isInteger(k) ? k.toFixed(0) : k.toFixed(1)) + 'k';\n  }\n  return String(Math.round(safe));\n}\n\nexport function fmtCurrency(v: number): string {\n  const safe = Number.isFinite(v) ? v : 0;\n  const sign = safe < 0 ? '-' : '';\n  return sign + '$' + Math.round(Math.abs(safe)).toLocaleString('en-US');\n}\n\nexport function fmtCurrencyShort(v: number): string {\n  const safe = Number.isFinite(v) ? v : 0;\n  const sign = safe < 0 ? '-' : '';\n  const abs = Math.abs(safe);\n  if (abs >= 1000) {\n    const k = abs / 1000;\n    return sign + '$' + (Number.isInteger(k) ? k.toFixed(0) : k.toFixed(1)) + 'k';\n  }\n  return sign + '$' + Math.round(abs);\n}\n\nfunction niceStep(span: number, count: number): number {\n  if (!Number.isFinite(span) || span <= 0) return 1;\n  const raw = span / count;\n  const mag = Math.pow(10, Math.floor(Math.log10(raw)));\n  const n = raw / mag;\n  const step = n <= 1 ? 1 : n <= 2 ? 2 : n <= 2.5 ? 2.5 : n <= 5 ? 5 : 10;\n  return step * mag;\n}\n\nconst TONE_BAND_RADII = [1.25, 1.05, 0.85, 0.62] as const;\n\nconst useIsoLayoutEffect = typeof window !== 'undefined' ? React.useLayoutEffect : React.useEffect;\n\nexport function ToneAreaChart({\n  data,\n  seriesLabel = 'Value',\n  compareLabel,\n  labelColumnHeader = 'Label',\n  formatValue = defaultFormatValue,\n  formatShort = defaultFormatShort,\n  annotation,\n  motion = 'stepped',\n  height = 260,\n  tableSummary = 'Show data table',\n  showTable = true,\n  ariaLabel,\n  className = '',\n}: ToneAreaChartProps) {\n  const wrap = React.useRef<HTMLDivElement | null>(null);\n  const { w } = useSize(wrap);\n  const rawId = React.useId();\n  const uid = React.useMemo(() => 'c-' + rawId.replace(/:/g, ''), [rawId]);\n\n  const safeData = React.useMemo<ToneAreaDatum[]>(\n    () =>\n      data.map((d) => ({\n        ...d,\n        value: Number.isFinite(d.value) ? d.value : 0,\n        compareValue:\n          d.compareValue != null && Number.isFinite(d.compareValue) ? d.compareValue : undefined,\n      })),\n    [data],\n  );\n\n  const n = safeData.length;\n  const hasCompare = Boolean(compareLabel) && safeData.some((d) => d.compareValue != null);\n  const tweenKey = `${n}|${safeData[0]?.label ?? ''}|${safeData[n - 1]?.value ?? ''}|${compareLabel ?? ''}`;\n  const p = useOnTwos(tweenKey, 750, motion);\n  const [hover, setHover] = React.useState<number | null>(null);\n  const balloon = React.useRef<HTMLDivElement | null>(null);\n  const [bw, setBw] = React.useState<number>(0);\n\n  const pad = { l: 46, r: 14, t: 46, b: 28 };\n  const isMeasured = w > 0;\n  const W = isMeasured ? w : 680;\n  const H = height;\n  const iw = Math.max(1, W - pad.l - pad.r);\n  const ih = Math.max(1, H - pad.t - pad.b);\n\n  const allValues: number[] = [];\n  for (const d of safeData) {\n    allValues.push(d.value);\n    if (hasCompare && d.compareValue != null) {\n      allValues.push(d.compareValue);\n    }\n  }\n  const rawMax = allValues.length > 0 ? Math.max(...allValues) : 0;\n  const rawMin = allValues.length > 0 ? Math.min(...allValues) : 0;\n  const domainMax = Math.max(0, rawMax);\n  const domainMin = Math.min(0, rawMin);\n  const span = Math.max(1, domainMax - domainMin);\n  const step = niceStep(span, 4);\n  const top = domainMax > 0 ? Math.ceil(domainMax / step) * step : domainMin === 0 ? step : 0;\n  const bottom = domainMin < 0 ? -Math.ceil(Math.abs(domainMin) / step) * step : 0;\n  const totalSpan = Math.max(step, top - bottom);\n\n  const x = (i: number) => pad.l + (n <= 1 ? iw / 2 : (i / (n - 1)) * iw);\n  const y = (v: number) => pad.t + ih - ((v - bottom) / totalSpan) * ih;\n  const zeroY = y(0);\n\n  const line = (get: (d: ToneAreaDatum) => number) =>\n    safeData.map((d, i) => `${i ? 'L' : 'M'}${x(i).toFixed(1)},${y(get(d)).toFixed(1)}`).join('');\n\n  const totalPath = n > 0 ? line((d) => d.value) : '';\n  const areaPath =\n    n > 0\n      ? `${totalPath}L${x(n - 1).toFixed(1)},${zeroY.toFixed(1)}L${x(0).toFixed(1)},${zeroY.toFixed(1)}Z`\n      : '';\n  const focusPath = hasCompare && n > 0 ? line((d) => d.compareValue ?? 0) : null;\n\n  const ticks: number[] = [];\n  for (let v = bottom; v <= top + 1e-6; v += step) {\n    ticks.push(Math.abs(v) < 1e-9 ? 0 : v);\n  }\n\n  const pxPerDay = n > 1 ? iw / (n - 1) : iw;\n  const baseEvery = n <= 7 ? 1 : n <= 30 ? 7 : 14;\n  const labelEvery = Math.max(baseEvery, Math.ceil(84 / pxPerDay / baseEvery) * baseEvery);\n  const xLabels: number[] = [];\n  for (let i = n - 1; i >= 0; i -= labelEvery) xLabels.push(i);\n\n  const resolvedAnnotation = React.useMemo<ToneAreaAnnotation | null>(() => {\n    if (annotation === null || n === 0) return null;\n    if (annotation !== undefined) {\n      const idx = Math.max(0, Math.min(n - 1, annotation.index));\n      return { index: idx, text: annotation.text };\n    }\n    let peakI = 0;\n    for (let i = 1; i < n; i++) {\n      if (safeData[i].value > safeData[peakI].value) peakI = i;\n    }\n    const pk = safeData[peakI];\n    return {\n      index: peakI,\n      text: `Peak ${pk.label} · ${formatValue(pk.value)}`,\n    };\n  }, [annotation, safeData, formatValue, n]);\n\n  const peakI = resolvedAnnotation ? resolvedAnnotation.index : 0;\n  const peakPoint = safeData[peakI];\n  const px = peakPoint ? x(peakI) : 0;\n  const py = peakPoint ? y(peakPoint.value) : 0;\n\n  useIsoLayoutEffect(() => {\n    if (balloon.current) setBw(balloon.current.offsetWidth);\n  });\n\n  const onMove = (e: React.PointerEvent<SVGSVGElement>) => {\n    if (!wrap.current || n === 0) return;\n    const r = wrap.current.getBoundingClientRect();\n    const mx = e.clientX - r.left;\n    const i = n <= 1 ? 0 : Math.round(((mx - pad.l) / iw) * (n - 1));\n    setHover(Math.max(0, Math.min(n - 1, i)));\n  };\n\n  const onKey = (e: React.KeyboardEvent<SVGSVGElement>) => {\n    if (n === 0) return;\n    if (e.key === 'ArrowRight') {\n      setHover((h) => Math.min(n - 1, h == null ? n - 1 : h + 1));\n      e.preventDefault();\n    } else if (e.key === 'ArrowLeft') {\n      setHover((h) => Math.max(0, h == null ? n - 1 : h - 1));\n      e.preventDefault();\n    } else if (e.key === 'Escape') {\n      setHover(null);\n    }\n  };\n\n  const clipW = pad.l + iw * p + 2;\n  const hd = hover != null && safeData[hover] ? safeData[hover] : null;\n  const bLeft = W ? Math.max(pad.l, Math.min(px - bw / 2, W - pad.r - bw)) : 0;\n  const tailX = Math.min(Math.max(px, bLeft + 14), Math.max(bLeft + 14, bLeft + bw - 14));\n  const bTop = 6;\n  const bH = 28;\n  const showPeak = p >= 0.999 && hover == null && resolvedAnnotation != null;\n\n  const computedAriaLabel =\n    ariaLabel ??\n    `${seriesLabel}, ${n} points.${\n      peakPoint\n        ? ` Peak ${peakPoint.longLabel ?? peakPoint.label}, ${formatValue(peakPoint.value)}.`\n        : ''\n    }`;\n\n  return (\n    <div className={`f12-tone-area-chart${className ? ` ${className}` : ''}`}>\n      <div className=\"f12-chart\" ref={wrap} style={{ height: H }}>\n        {n > 0 && (\n          <svg\n            width={isMeasured ? W : '100%'}\n            height={H}\n            viewBox={`0 0 ${W} ${H}`}\n            preserveAspectRatio={isMeasured ? undefined : 'none'}\n            className=\"f12-chart-svg\"\n            role=\"img\"\n            aria-label={computedAriaLabel}\n            tabIndex={0}\n            onPointerMove={onMove}\n            onPointerLeave={() => setHover(null)}\n            onKeyDown={onKey}\n            onBlur={() => setHover(null)}\n          >\n            <defs>\n              <clipPath id={`${uid}-clip`}>\n                <rect x=\"0\" y=\"0\" width={clipW} height={H} />\n              </clipPath>\n              {TONE_BAND_RADII.map((radius, b) => (\n                <React.Fragment key={b}>\n                  <pattern\n                    id={`${uid}-tone-${b}`}\n                    width=\"5\"\n                    height=\"5\"\n                    patternUnits=\"userSpaceOnUse\"\n                    patternTransform=\"rotate(45)\"\n                  >\n                    <circle cx=\"2.5\" cy=\"2.5\" r={radius} className=\"f12-tone-dot\" />\n                  </pattern>\n                  <clipPath id={`${uid}-band-${b}`}>\n                    <rect\n                      x=\"0\"\n                      y={pad.t + (ih * b) / TONE_BAND_RADII.length}\n                      width={W}\n                      height={ih / TONE_BAND_RADII.length + 0.5}\n                    />\n                  </clipPath>\n                </React.Fragment>\n              ))}\n            </defs>\n\n            {ticks.map((v) => (\n              <g key={v} className=\"f12-ytick\">\n                <line\n                  x1={pad.l}\n                  x2={W - pad.r}\n                  y1={y(v)}\n                  y2={y(v)}\n                  className={v === 0 ? 'f12-baseline' : 'f12-grid'}\n                />\n                <text x={pad.l - 8} y={y(v)} dy=\"0.35em\" textAnchor=\"end\">\n                  {formatShort(v)}\n                </text>\n              </g>\n            ))}\n\n            <g className=\"f12-sheet-ticks\" aria-hidden=\"true\">\n              {safeData.map(\n                (_, i) =>\n                  (n <= 30 || i % 3 === 0) && (\n                    <line\n                      key={i}\n                      x1={x(i)}\n                      x2={x(i)}\n                      y1={y(bottom)}\n                      y2={y(bottom) + (xLabels.includes(i) ? 7 : 3.5)}\n                    />\n                  ),\n              )}\n            </g>\n\n            {xLabels.map((i) => (\n              <text\n                key={i}\n                className=\"f12-xlab\"\n                x={x(i)}\n                y={H - 8}\n                textAnchor={i === n - 1 ? 'end' : i === 0 ? 'start' : 'middle'}\n              >\n                {safeData[i].label}\n              </text>\n            ))}\n\n            <g clipPath={`url(#${uid}-clip)`}>\n              {TONE_BAND_RADII.map((_, b) => (\n                <path\n                  key={b}\n                  d={areaPath}\n                  fill={`url(#${uid}-tone-${b})`}\n                  clipPath={`url(#${uid}-band-${b})`}\n                />\n              ))}\n              <path d={totalPath} className=\"f12-l-total\" fill=\"none\" />\n              {focusPath && <path d={focusPath} className=\"f12-l-focus\" fill=\"none\" />}\n            </g>\n\n            {showPeak && resolvedAnnotation && (\n              <>\n                {isMeasured && (\n                  <path\n                    className=\"f12-tail\"\n                    d={`M${tailX - 6},${bTop + bH - 1} L${px - (px - tailX) * 0.15},${py - 7} L${tailX + 6},${bTop + bH - 1}`}\n                  />\n                )}\n                <circle className=\"f12-peak-dot\" cx={px} cy={py} r=\"4\" />\n              </>\n            )}\n\n            {hd && hover != null && (\n              <g className=\"f12-cross\" aria-hidden=\"true\">\n                <line x1={x(hover)} x2={x(hover)} y1={pad.t - 4} y2={y(bottom)} />\n                <circle cx={x(hover)} cy={y(hd.value)} r=\"4.5\" className=\"f12-cross-dot\" />\n                {hasCompare && hd.compareValue != null && (\n                  <circle cx={x(hover)} cy={y(hd.compareValue)} r=\"4\" className=\"f12-cross-dot2\" />\n                )}\n              </g>\n            )}\n          </svg>\n        )}\n\n        {showPeak && resolvedAnnotation && (\n          <div\n            ref={balloon}\n            className=\"f12-balloon\"\n            style={\n              isMeasured\n                ? { left: bLeft, top: bTop, minHeight: bH }\n                : {\n                    left: `${Math.max(10, Math.min(80, (px / W) * 100))}%`,\n                    transform: 'translateX(-50%)',\n                    top: bTop,\n                    minHeight: bH,\n                  }\n            }\n            aria-hidden=\"true\"\n          >\n            {isMeasured && <span className=\"f12-balloon-gap\" style={{ left: tailX - bLeft - 5 }} />}\n            {resolvedAnnotation.text}\n          </div>\n        )}\n\n        {hd && hover != null && (\n          <div\n            className=\"f12-tip\"\n            role=\"status\"\n            style={{ left: Math.min(Math.max(x(hover) - 80, 4), Math.max(4, W - 164)), top: 4 }}\n          >\n            <strong>{hd.longLabel ?? hd.label}</strong>\n            <span>\n              <i className=\"f12-sw f12-sw-total\" aria-hidden=\"true\" />\n              {seriesLabel} {formatValue(hd.value)}\n            </span>\n            {hasCompare && hd.compareValue != null && (\n              <span>\n                <i className=\"f12-sw f12-sw-focus\" aria-hidden=\"true\" />\n                {compareLabel} {formatValue(hd.compareValue)}\n              </span>\n            )}\n          </div>\n        )}\n      </div>\n\n      {showTable && (\n        <details className=\"f12-tbl\">\n          <summary>{tableSummary}</summary>\n          <div className=\"f12-tbl-scroll\">\n            <table>\n              <thead>\n                <tr>\n                  <th scope=\"col\">{labelColumnHeader}</th>\n                  <th scope=\"col\">{seriesLabel}</th>\n                  {hasCompare && <th scope=\"col\">{compareLabel}</th>}\n                </tr>\n              </thead>\n              <tbody>\n                {safeData\n                  .slice()\n                  .reverse()\n                  .map((d, idx) => (\n                    <tr key={`${d.label}-${idx}`}>\n                      <td>{d.longLabel ?? d.label}</td>\n                      <td>{formatValue(d.value)}</td>\n                      {hasCompare && <td>{formatValue(d.compareValue ?? 0)}</td>}\n                    </tr>\n                  ))}\n              </tbody>\n            </table>\n          </div>\n        </details>\n      )}\n    </div>\n  );\n}\n",
      "type": "registry:ui",
      "target": "components/frame12/tone-area-chart.tsx"
    },
    {
      "path": "ui/tone-bar-list.tsx",
      "content": "'use client';\n\nimport * as React from 'react';\nimport { type MotionMode } from '@/hooks/use-on-twos';\nimport { Badge } from './badge';\n\nexport interface ToneBarItem {\n  id: string;\n  name: string;\n  value: number;\n  formattedValue?: string;\n  share?: number;\n  badge?: string;\n}\n\nexport interface ToneBarListProps {\n  title?: string;\n  subtitle?: string;\n  items: ToneBarItem[];\n  selectedId?: string | null;\n  onSelect?: (id: string | null) => void;\n  motion?: MotionMode;\n  changed?: boolean;\n  idPrefix?: string;\n  className?: string;\n}\n\nexport function ToneBarList({\n  title,\n  subtitle,\n  items,\n  selectedId = null,\n  onSelect,\n  changed = false,\n  idPrefix,\n  className = '',\n}: ToneBarListProps) {\n  const autoId = React.useId().replace(/:/g, '');\n  const resolvedPrefix = idPrefix ?? `f12-${autoId}`;\n  const max = Math.max(1, ...items.map((r) => (Number.isFinite(r.value) ? r.value : 0)));\n  const listKey = items.map((r) => `${r.id}:${r.value}`).join('|');\n\n  return (\n    <div className={`f12-ints${className ? ` ${className}` : ''}`}>\n      {(title || subtitle) && (\n        <div className=\"f12-ints-hd\">\n          {title && <h3 className=\"f12-m-label\">{title}</h3>}\n          {subtitle && <p className=\"f12-ints-sub\">{subtitle}</p>}\n        </div>\n      )}\n      <ul className={`f12-ints-list${changed ? ' f12-enter enter' : ''}`} key={listKey}>\n        {items.map((r) => {\n          const on = selectedId === r.id;\n          const safeVal = Number.isFinite(r.value) ? r.value : 0;\n          const formatted = r.formattedValue ?? '$' + Math.round(safeVal).toLocaleString('en-US');\n          return (\n            <li key={r.id}>\n              <button\n                type=\"button\"\n                id={resolvedPrefix ? `int-${resolvedPrefix}-${r.id}` : `int-${r.id}`}\n                className=\"f12-int-row\"\n                aria-pressed={on}\n                onClick={() => onSelect?.(on ? null : r.id)}\n              >\n                <span className=\"f12-int-name\">\n                  {r.name}\n                  {r.badge && (\n                    <Badge pop={changed} burst>\n                      {r.badge}\n                    </Badge>\n                  )}\n                </span>\n                <span className=\"f12-int-bar\" aria-hidden=\"true\">\n                  <span\n                    className=\"f12-int-fill\"\n                    style={{ width: `${Math.max(0, (safeVal / max) * 100)}%` }}\n                  />\n                </span>\n                <span className=\"f12-int-val\">\n                  {formatted}\n                  {r.share != null && (\n                    <span className=\"f12-int-share\">{(r.share * 100).toFixed(0)}%</span>\n                  )}\n                </span>\n              </button>\n            </li>\n          );\n        })}\n      </ul>\n    </div>\n  );\n}\n",
      "type": "registry:ui",
      "target": "components/frame12/tone-bar-list.tsx"
    },
    {
      "path": "ui/tone-spark.tsx",
      "content": "'use client';\n\nimport * as React from 'react';\nimport { type MotionMode, useOnTwos, useSize } from '@/hooks/use-on-twos';\n\nexport interface ToneSparkProps {\n  values: number[];\n  label: string;\n  ariaLabel?: string;\n  rangeKey?: string | number;\n  motion?: MotionMode;\n  height?: number;\n  className?: string;\n}\n\nexport function ToneSpark({\n  values,\n  label,\n  ariaLabel,\n  rangeKey,\n  motion = 'stepped',\n  height = 40,\n  className = '',\n}: ToneSparkProps) {\n  const ref = React.useRef<HTMLDivElement | null>(null);\n  const { w } = useSize(ref);\n  const p = useOnTwos(rangeKey ?? values.length, 600, motion);\n  const rawId = React.useId();\n  const uid = React.useMemo(() => 's-' + rawId.replace(/:/g, ''), [rawId]);\n\n  const safeValues = React.useMemo(\n    () => values.map((v) => (Number.isFinite(v) ? Math.max(0, v) : 0)),\n    [values],\n  );\n  const H = height;\n  const max = Math.max(1, ...safeValues);\n  const n = safeValues.length;\n  const gap = n > 40 ? 1 : 2;\n  const isMeasured = w > 0;\n  const W = isMeasured ? w : 280;\n  const bw = n > 0 ? Math.max(1, (W - gap * (n - 1)) / n) : 0;\n  const shownCount = Math.ceil(n * p);\n  const computedAriaLabel = ariaLabel ?? `${label}, last ${n} days, one bar per day`;\n\n  return (\n    <div className={`f12-spark${className ? ` ${className}` : ''}`} ref={ref}>\n      <p className=\"f12-spark-l\">{label}</p>\n      {n > 0 && (\n        <svg\n          width={isMeasured ? W : '100%'}\n          height={H}\n          viewBox={`0 0 ${W} ${H}`}\n          preserveAspectRatio={isMeasured ? undefined : 'none'}\n          role=\"img\"\n          aria-label={computedAriaLabel}\n        >\n          <defs>\n            <pattern\n              id={`${uid}-st`}\n              width=\"4\"\n              height=\"4\"\n              patternUnits=\"userSpaceOnUse\"\n              patternTransform=\"rotate(45)\"\n            >\n              <circle cx=\"2\" cy=\"2\" r=\"1.05\" className=\"f12-tone-dot\" />\n            </pattern>\n          </defs>\n          {safeValues.map((v, i) =>\n            i < shownCount ? (\n              <rect\n                key={i}\n                className=\"f12-spark-bar\"\n                vectorEffect=\"non-scaling-stroke\"\n                fill={`url(#${uid}-st)`}\n                x={i * (bw + gap)}\n                y={H - (v / max) * H}\n                width={bw}\n                height={(v / max) * H}\n              />\n            ) : null,\n          )}\n        </svg>\n      )}\n    </div>\n  );\n}\n",
      "type": "registry:ui",
      "target": "components/frame12/tone-spark.tsx"
    },
    {
      "path": "ui/dialog.tsx",
      "content": "'use client';\n\nimport * as React from 'react';\nimport { Button, type ButtonProps } from './button';\n\nconst useIsoLayoutEffect = typeof window !== 'undefined' ? React.useLayoutEffect : React.useEffect;\n\nconst openDialogStack: HTMLDialogElement[] = [];\nlet dialogObserver: MutationObserver | null = null;\n\nfunction pushOpenDialog(el: HTMLDialogElement) {\n  const idx = openDialogStack.indexOf(el);\n  if (idx !== -1) openDialogStack.splice(idx, 1);\n  openDialogStack.push(el);\n}\n\nfunction removeOpenDialog(el: HTMLDialogElement) {\n  const idx = openDialogStack.indexOf(el);\n  if (idx !== -1) openDialogStack.splice(idx, 1);\n}\n\nfunction processDialogMutations(records: MutationRecord[]) {\n  for (const rec of records) {\n    if (rec.type === 'attributes' && rec.attributeName === 'open') {\n      const target = rec.target;\n      if (typeof HTMLDialogElement !== 'undefined' && target instanceof HTMLDialogElement) {\n        if (target.open && target.isConnected) {\n          pushOpenDialog(target);\n        } else {\n          removeOpenDialog(target);\n        }\n      }\n    }\n  }\n}\n\nfunction ensureDialogObserver() {\n  if (dialogObserver || typeof document === 'undefined' || typeof MutationObserver === 'undefined') {\n    return;\n  }\n  for (const d of document.querySelectorAll<HTMLDialogElement>('dialog[open]')) {\n    pushOpenDialog(d);\n  }\n  dialogObserver = new MutationObserver(processDialogMutations);\n  if (document.documentElement) {\n    dialogObserver.observe(document.documentElement, {\n      subtree: true,\n      attributes: true,\n      attributeFilter: ['open'],\n    });\n  }\n}\n\nfunction isModalDialog(d: HTMLDialogElement): boolean {\n  if (!d.isConnected || !d.open) return false;\n  try {\n    if (d.matches(':modal')) return true;\n    // In environments where showModal() is supported, non-modal .show() dialogs do not match :modal\n    if (typeof d.showModal === 'function' && document.querySelector('dialog:modal')) {\n      return false;\n    }\n  } catch {\n    // Fallback if :modal selector is unsupported\n  }\n  return true;\n}\n\nfunction getTopmostOpenDialog(): HTMLDialogElement | undefined {\n  ensureDialogObserver();\n  if (dialogObserver) {\n    processDialogMutations(dialogObserver.takeRecords());\n  }\n  for (let i = openDialogStack.length - 1; i >= 0; i--) {\n    const d = openDialogStack[i];\n    if (isModalDialog(d)) return d;\n    if (!d.isConnected || !d.open) {\n      openDialogStack.splice(i, 1);\n    }\n  }\n  const fallback = document.querySelectorAll<HTMLDialogElement>('dialog[open]');\n  for (let i = fallback.length - 1; i >= 0; i--) {\n    if (isModalDialog(fallback[i])) return fallback[i];\n  }\n  return undefined;\n}\n\nfunction mergeRefs<T>(\n  ...refs: Array<React.Ref<T> | undefined>\n): React.RefCallback<T> {\n  return (value: T) => {\n    for (const ref of refs) {\n      if (typeof ref === 'function') {\n        ref(value);\n      } else if (ref != null) {\n        (ref as React.MutableRefObject<T | null>).current = value;\n      }\n    }\n  };\n}\n\ninterface DialogContextValue {\n  open: boolean;\n  setOpen: (next: boolean) => void;\n  titleId: string;\n  descId: string;\n  hasDescription: boolean;\n  setHasDescription: (present: boolean) => void;\n  dialogRef: React.RefObject<HTMLDialogElement | null>;\n}\n\nconst DialogContext = React.createContext<DialogContextValue | null>(null);\n\nfunction useDialogContext() {\n  const ctx = React.useContext(DialogContext);\n  if (!ctx) throw new Error('Dialog subcomponents must be used within <Dialog>');\n  return ctx;\n}\n\nexport interface DialogProps {\n  open?: boolean;\n  defaultOpen?: boolean;\n  onOpenChange?: (open: boolean) => void;\n  children?: React.ReactNode;\n}\n\nexport function Dialog({\n  open: controlledOpen,\n  defaultOpen = false,\n  onOpenChange,\n  children,\n}: DialogProps) {\n  const [uncontrolledOpen, setUncontrolledOpen] = React.useState<boolean>(defaultOpen);\n  const [hasDescription, setHasDescription] = React.useState<boolean>(false);\n  const isControlled = controlledOpen !== undefined;\n  const open = isControlled ? controlledOpen : uncontrolledOpen;\n  const openRef = React.useRef<boolean>(open);\n  openRef.current = open;\n  const onOpenChangeRef = React.useRef(onOpenChange);\n  onOpenChangeRef.current = onOpenChange;\n\n  const dialogRef = React.useRef<HTMLDialogElement | null>(null);\n  const rawId = React.useId().replace(/:/g, '');\n  const titleId = `f12-dlg-title-${rawId}`;\n  const descId = `f12-dlg-desc-${rawId}`;\n\n  const setOpen = React.useCallback(\n    (next: boolean) => {\n      if (openRef.current === next) return;\n      openRef.current = next;\n      if (!isControlled) setUncontrolledOpen(next);\n      onOpenChangeRef.current?.(next);\n    },\n    [isControlled],\n  );\n\n  React.useEffect(() => {\n    ensureDialogObserver();\n    const el = dialogRef.current;\n    if (!el) return;\n    if (open && !el.open) {\n      if (typeof el.showModal === 'function') el.showModal();\n      else el.setAttribute('open', '');\n      pushOpenDialog(el);\n    } else if (open && el.open) {\n      pushOpenDialog(el);\n    } else if (!open && el.open) {\n      removeOpenDialog(el);\n      if (typeof el.close === 'function') el.close();\n      else el.removeAttribute('open');\n    } else {\n      removeOpenDialog(el);\n    }\n  }, [open]);\n\n  return (\n    <DialogContext.Provider\n      value={{\n        open,\n        setOpen,\n        titleId,\n        descId,\n        hasDescription,\n        setHasDescription,\n        dialogRef,\n      }}\n    >\n      {children}\n    </DialogContext.Provider>\n  );\n}\n\nexport interface DialogTriggerProps extends ButtonProps {\n  asChild?: boolean;\n}\n\nfunction getElementRef(element: React.ReactElement): React.Ref<unknown> | undefined {\n  const propsObj = (element.props || {}) as Record<string, unknown>;\n  let getter = Object.getOwnPropertyDescriptor(propsObj, 'ref')?.get;\n  let mayWarn =\n    getter && 'isReactWarning' in getter && (getter as { isReactWarning?: boolean }).isReactWarning;\n  if (mayWarn) {\n    return (element as unknown as { ref?: React.Ref<unknown> }).ref;\n  }\n  getter = Object.getOwnPropertyDescriptor(element, 'ref')?.get;\n  mayWarn =\n    getter && 'isReactWarning' in getter && (getter as { isReactWarning?: boolean }).isReactWarning;\n  if (mayWarn) {\n    return (propsObj as { ref?: React.Ref<unknown> }).ref;\n  }\n  return (\n    (propsObj as { ref?: React.Ref<unknown> }).ref ||\n    (element as unknown as { ref?: React.Ref<unknown> }).ref\n  );\n}\n\nexport const DialogTrigger = React.forwardRef<HTMLButtonElement, DialogTriggerProps>(\n  function DialogTrigger(\n    { asChild = false, onClick, className = '', children, ...rest },\n    forwardedRef,\n  ) {\n    const { setOpen } = useDialogContext();\n    const childRef = React.isValidElement(children) ? getElementRef(children) : undefined;\n    const composedRef = React.useMemo(\n      () => mergeRefs(forwardedRef, childRef),\n      [forwardedRef, childRef],\n    );\n    if (asChild && React.isValidElement(children)) {\n      const child = children as React.ReactElement<Record<string, unknown>>;\n      const childProps = child.props || {};\n      const mergedClassName =\n        [childProps.className, className].filter(Boolean).join(' ') || undefined;\n      return React.cloneElement(child, {\n        ...rest,\n        ...childProps,\n        className: mergedClassName,\n        ref: composedRef,\n        onClick: (e: React.MouseEvent<HTMLButtonElement>) => {\n          onClick?.(e);\n          if (typeof childProps.onClick === 'function') {\n            (childProps.onClick as (ev: React.MouseEvent<HTMLButtonElement>) => void)(e);\n          }\n          if (!e.defaultPrevented) {\n            setOpen(true);\n          }\n        },\n      });\n    }\n    return (\n      <Button\n        ref={forwardedRef}\n        className={className}\n        onClick={(e) => {\n          onClick?.(e);\n          if (!e.defaultPrevented) {\n            setOpen(true);\n          }\n        }}\n        {...rest}\n      >\n        {children}\n      </Button>\n    );\n  },\n);\n\nexport interface DialogContentProps extends React.DialogHTMLAttributes<HTMLDialogElement> {\n  cut?: string;\n}\n\nexport const DialogContent = React.forwardRef<HTMLDialogElement, DialogContentProps>(\n  function DialogContent(\n    {\n      cut,\n      className = '',\n      onPointerDown,\n      onPointerUp,\n      onCancel,\n      onKeyDown,\n      'aria-describedby': userDescribedBy,\n      children,\n      ...rest\n    },\n    forwardedRef,\n  ) {\n    const { setOpen, titleId, descId, hasDescription, dialogRef } = useDialogContext();\n    const pressedOutside = React.useRef<boolean>(false);\n    const childPopupOpenOnEscapeRef = React.useRef<boolean>(false);\n\n    React.useEffect(() => {\n      const el = dialogRef.current;\n      if (!el) return;\n      const onClose = () => {\n        removeOpenDialog(el);\n        setOpen(false);\n      };\n      // Capture Escape keydown at document capture phase BEFORE Radix DismissableLayer\n      // unmounts the open listbox/menu, so we know whether Escape was consumed by a child popup.\n      const onDocKeyDownCapture = (e: KeyboardEvent) => {\n        if (e.key !== 'Escape') return;\n        if (el.querySelector('[role=\"listbox\"], [role=\"menu\"]')) {\n          childPopupOpenOnEscapeRef.current = true;\n          setTimeout(() => {\n            childPopupOpenOnEscapeRef.current = false;\n          }, 0);\n        }\n      };\n      const onDocKeyDown = (e: KeyboardEvent) => {\n        if (e.key !== 'Escape' || !el.open) return;\n        if (getTopmostOpenDialog() !== el) {\n          return;\n        }\n        if (\n          e.defaultPrevented ||\n          childPopupOpenOnEscapeRef.current ||\n          el.querySelector('[role=\"listbox\"], [role=\"menu\"]')\n        ) {\n          return;\n        }\n        e.preventDefault();\n        const cancelEvent = new Event('cancel', { bubbles: false, cancelable: true });\n        const shouldClose = el.dispatchEvent(cancelEvent);\n        if (!shouldClose || cancelEvent.defaultPrevented) {\n          return;\n        }\n        removeOpenDialog(el);\n        el.close();\n        setOpen(false);\n      };\n      el.addEventListener('close', onClose);\n      document.addEventListener('keydown', onDocKeyDownCapture, true);\n      document.addEventListener('keydown', onDocKeyDown);\n      return () => {\n        if (!el.open || !el.isConnected) {\n          removeOpenDialog(el);\n        }\n        el.removeEventListener('close', onClose);\n        document.removeEventListener('keydown', onDocKeyDownCapture, true);\n        document.removeEventListener('keydown', onDocKeyDown);\n      };\n    }, [dialogRef, setOpen]);\n\n    // Fallback for browsers where <dialog closedby=\"any\"> is not yet supported:\n    // test pointer coordinates against the dialog bounding box on pointerdown + pointerup.\n    const isOutside = (e: React.PointerEvent<HTMLDialogElement>, dialog: HTMLDialogElement) => {\n      const r = dialog.getBoundingClientRect();\n      return (\n        e.clientX < r.left || e.clientX > r.right || e.clientY < r.top || e.clientY > r.bottom\n      );\n    };\n\n    const resolvedDescribedBy = userDescribedBy ?? (hasDescription ? descId : undefined);\n    const composedDialogRef = React.useMemo(\n      () => mergeRefs(dialogRef, forwardedRef),\n      [dialogRef, forwardedRef],\n    );\n\n    return (\n      <dialog\n        ref={composedDialogRef}\n        className={`f12-dialog${className ? ` ${className}` : ''}`}\n        aria-labelledby={titleId}\n        aria-describedby={resolvedDescribedBy}\n        onKeyDown={(e) => {\n          onKeyDown?.(e);\n          if (e.key === 'Escape' && childPopupOpenOnEscapeRef.current) {\n            e.preventDefault();\n          }\n        }}\n        onCancel={(e) => {\n          onCancel?.(e);\n          if (\n            childPopupOpenOnEscapeRef.current ||\n            dialogRef.current?.querySelector('[role=\"listbox\"], [role=\"menu\"]')\n          ) {\n            e.preventDefault();\n            childPopupOpenOnEscapeRef.current = false;\n          }\n        }}\n        onPointerDown={(e) => {\n          onPointerDown?.(e);\n          if (e.defaultPrevented) return;\n          const el = dialogRef.current;\n          if (!el || el.querySelector('[role=\"listbox\"], [role=\"menu\"]')) {\n            pressedOutside.current = false;\n            return;\n          }\n          pressedOutside.current = e.target === el && isOutside(e, el);\n        }}\n        onPointerUp={(e) => {\n          onPointerUp?.(e);\n          if (e.defaultPrevented) {\n            pressedOutside.current = false;\n            return;\n          }\n          const el = dialogRef.current;\n          if (el && pressedOutside.current && e.target === el && isOutside(e, el)) {\n            el.close();\n            setOpen(false);\n          }\n          pressedOutside.current = false;\n        }}\n        {...rest}\n      >\n        {cut && (\n          <span className=\"f12-cut\" aria-hidden=\"true\">\n            {cut}\n          </span>\n        )}\n        {children}\n      </dialog>\n    );\n  },\n);\n\nexport function DialogHeader({\n  className = '',\n  children,\n  ...rest\n}: React.HTMLAttributes<HTMLDivElement>) {\n  return (\n    <div className={`f12-dialog-header${className ? ` ${className}` : ''}`} {...rest}>\n      {children}\n    </div>\n  );\n}\n\nexport function DialogTitle({\n  className = '',\n  children,\n  ...rest\n}: React.HTMLAttributes<HTMLHeadingElement>) {\n  const { titleId } = useDialogContext();\n  return (\n    <h2 id={titleId} className={`f12-dialog-title${className ? ` ${className}` : ''}`} {...rest}>\n      {children}\n    </h2>\n  );\n}\n\nexport function DialogDescription({\n  className = '',\n  children,\n  ...rest\n}: React.HTMLAttributes<HTMLParagraphElement>) {\n  const { descId, setHasDescription } = useDialogContext();\n  useIsoLayoutEffect(() => {\n    setHasDescription(true);\n    return () => setHasDescription(false);\n  }, [setHasDescription]);\n\n  return (\n    <p\n      id={descId}\n      className={`f12-dialog-description${className ? ` ${className}` : ''}`}\n      {...rest}\n    >\n      {children}\n    </p>\n  );\n}\n\nexport function DialogFooter({\n  className = '',\n  children,\n  ...rest\n}: React.HTMLAttributes<HTMLDivElement>) {\n  return (\n    <div className={`f12-dialog-footer${className ? ` ${className}` : ''}`} {...rest}>\n      {children}\n    </div>\n  );\n}\n\nexport function DialogClose({ onClick, children, ...rest }: ButtonProps) {\n  const { setOpen } = useDialogContext();\n  return (\n    <Button\n      onClick={(e) => {\n        onClick?.(e);\n        if (!e.defaultPrevented) {\n          setOpen(false);\n        }\n      }}\n      {...rest}\n    >\n      {children}\n    </Button>\n  );\n}\n",
      "type": "registry:ui",
      "target": "components/frame12/dialog.tsx"
    },
    {
      "path": "ui/select.tsx",
      "content": "'use client';\n\nimport * as React from 'react';\nimport * as SelectPrimitive from '@radix-ui/react-select';\n\ninterface SelectFieldContextValue {\n  triggerId: string;\n  containerEl: HTMLDivElement | null;\n}\n\nconst SelectFieldContext = React.createContext<SelectFieldContextValue | null>(null);\n\nexport interface SelectProps\n  extends React.ComponentPropsWithoutRef<typeof SelectPrimitive.Root> {\n  label?: string;\n  id?: string;\n  className?: string;\n}\n\nexport function Select({\n  value,\n  defaultValue,\n  onValueChange,\n  open,\n  defaultOpen,\n  onOpenChange,\n  dir,\n  name,\n  autoComplete,\n  disabled,\n  required,\n  form,\n  label,\n  id,\n  className = '',\n  children,\n}: SelectProps) {\n  const [containerEl, setContainerEl] = React.useState<HTMLDivElement | null>(null);\n  const rawId = React.useId().replace(/:/g, '');\n  const triggerId = id || `f12-select-${rawId}`;\n\n  const ctxValue = React.useMemo(\n    () => ({ triggerId, containerEl }),\n    [triggerId, containerEl],\n  );\n\n  return (\n    <SelectFieldContext.Provider value={ctxValue}>\n      <div ref={setContainerEl} className={`f12-select${className ? ` ${className}` : ''}`}>\n        {label && (\n          <label htmlFor={triggerId} className=\"f12-label\">\n            {label}\n          </label>\n        )}\n        <SelectPrimitive.Root\n          value={value}\n          defaultValue={defaultValue}\n          onValueChange={onValueChange}\n          open={open}\n          defaultOpen={defaultOpen}\n          onOpenChange={onOpenChange}\n          dir={dir}\n          name={name}\n          autoComplete={autoComplete}\n          disabled={disabled}\n          required={required}\n          form={form}\n        >\n          {children}\n        </SelectPrimitive.Root>\n      </div>\n    </SelectFieldContext.Provider>\n  );\n}\n\nexport interface SelectTriggerProps\n  extends Omit<React.ComponentPropsWithoutRef<typeof SelectPrimitive.Trigger>, 'asChild'> {\n  ariaLabel?: string;\n}\n\nexport const SelectTrigger = React.forwardRef<HTMLButtonElement, SelectTriggerProps>(\n  function SelectTrigger(\n    { ariaLabel, id, className = '', children, ...rest },\n    forwardedRef,\n  ) {\n    const field = React.useContext(SelectFieldContext);\n    const resolvedId = id ?? field?.triggerId;\n    const { asChild: _asChild, ...triggerProps } =\n      rest as React.ComponentPropsWithoutRef<typeof SelectPrimitive.Trigger>;\n    return (\n      <SelectPrimitive.Trigger\n        ref={forwardedRef}\n        id={resolvedId}\n        aria-label={ariaLabel}\n        className={`f12-select-trigger${className ? ` ${className}` : ''}`}\n        {...triggerProps}\n      >\n        {children}\n        <SelectPrimitive.Icon className=\"f12-select-caret\" aria-hidden=\"true\">\n          ▼\n        </SelectPrimitive.Icon>\n      </SelectPrimitive.Trigger>\n    );\n  },\n);\n\nexport type SelectValueProps = React.ComponentPropsWithoutRef<typeof SelectPrimitive.Value>;\n\nexport const SelectValue = React.forwardRef<HTMLSpanElement, SelectValueProps>(\n  function SelectValue({ placeholder = 'Select…', ...rest }, forwardedRef) {\n    return (\n      <SelectPrimitive.Value\n        ref={forwardedRef}\n        placeholder={placeholder}\n        {...rest}\n      />\n    );\n  },\n);\n\nexport type SelectContentProps = React.ComponentPropsWithoutRef<typeof SelectPrimitive.Content>;\n\nexport const SelectContent = React.forwardRef<HTMLDivElement, SelectContentProps>(\n  function SelectContent(\n    { className = '', position = 'popper', sideOffset = 4, children, ...rest },\n    forwardedRef,\n  ) {\n    const field = React.useContext(SelectFieldContext);\n    const portalContainer =\n      (field?.containerEl?.closest(\n        'dialog, .f12-frame, .f12-sheet, .f12-theme-dark, .f12-theme-light, [data-theme]',\n      ) as HTMLElement | null) ?? undefined;\n\n    return (\n      <SelectPrimitive.Portal container={portalContainer}>\n        <SelectPrimitive.Content\n          ref={forwardedRef}\n          position={position}\n          sideOffset={sideOffset}\n          className={`f12-select-content${className ? ` ${className}` : ''}`}\n          {...rest}\n        >\n          <SelectPrimitive.Viewport className=\"f12-select-viewport\">\n            {children}\n          </SelectPrimitive.Viewport>\n        </SelectPrimitive.Content>\n      </SelectPrimitive.Portal>\n    );\n  },\n);\n\nexport type SelectItemProps = Omit<\n  React.ComponentPropsWithoutRef<typeof SelectPrimitive.Item>,\n  'asChild'\n>;\n\nexport const SelectItem = React.forwardRef<HTMLDivElement, SelectItemProps>(\n  function SelectItem({ className = '', children, ...rest }, forwardedRef) {\n    const { asChild: _asChild, ...itemProps } =\n      rest as React.ComponentPropsWithoutRef<typeof SelectPrimitive.Item>;\n    return (\n      <SelectPrimitive.Item\n        ref={forwardedRef}\n        className={`f12-select-item${className ? ` ${className}` : ''}`}\n        {...itemProps}\n      >\n        <SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>\n        <SelectPrimitive.ItemIndicator className=\"f12-select-check\" aria-hidden=\"true\">\n          ✓\n        </SelectPrimitive.ItemIndicator>\n      </SelectPrimitive.Item>\n    );\n  },\n);\n\nexport type SelectGroupProps = React.ComponentPropsWithoutRef<typeof SelectPrimitive.Group>;\n\nexport const SelectGroup = React.forwardRef<HTMLDivElement, SelectGroupProps>(\n  function SelectGroup({ className = '', children, ...rest }, forwardedRef) {\n    return (\n      <SelectPrimitive.Group\n        ref={forwardedRef}\n        className={`f12-select-group${className ? ` ${className}` : ''}`}\n        {...rest}\n      >\n        {children}\n      </SelectPrimitive.Group>\n    );\n  },\n);\n\nexport type SelectLabelProps = React.ComponentPropsWithoutRef<typeof SelectPrimitive.Label>;\n\nexport const SelectLabel = React.forwardRef<HTMLDivElement, SelectLabelProps>(\n  function SelectLabel({ className = '', children, ...rest }, forwardedRef) {\n    return (\n      <SelectPrimitive.Label\n        ref={forwardedRef}\n        className={`f12-select-label${className ? ` ${className}` : ''}`}\n        {...rest}\n      >\n        {children}\n      </SelectPrimitive.Label>\n    );\n  },\n);\n\nexport type SelectSeparatorProps = React.ComponentPropsWithoutRef<typeof SelectPrimitive.Separator>;\n\nexport const SelectSeparator = React.forwardRef<HTMLDivElement, SelectSeparatorProps>(\n  function SelectSeparator({ className = '', ...rest }, forwardedRef) {\n    return (\n      <SelectPrimitive.Separator\n        ref={forwardedRef}\n        className={`f12-select-sep${className ? ` ${className}` : ''}`}\n        {...rest}\n      />\n    );\n  },\n);\n",
      "type": "registry:ui",
      "target": "components/frame12/select.tsx"
    },
    {
      "path": "ui/tooltip.tsx",
      "content": "'use client';\n\nimport * as React from 'react';\n\nconst useIsoLayoutEffect = typeof window !== 'undefined' ? React.useLayoutEffect : React.useEffect;\n\ninterface TooltipContextValue {\n  open: boolean;\n  setOpen: (next: boolean) => void;\n  tooltipId: string;\n  setCustomId: (id: string | undefined) => void;\n}\n\nconst TooltipContext = React.createContext<TooltipContextValue | null>(null);\n\nfunction useTooltipContext() {\n  const ctx = React.useContext(TooltipContext);\n  if (!ctx) throw new Error('Tooltip subcomponents must be used within <Tooltip>');\n  return ctx;\n}\n\nexport function TooltipProvider({ children }: { children?: React.ReactNode }) {\n  return <>{children}</>;\n}\n\nexport interface TooltipProps {\n  open?: boolean;\n  defaultOpen?: boolean;\n  onOpenChange?: (open: boolean) => void;\n  children?: React.ReactNode;\n}\n\nexport function Tooltip({\n  open: controlledOpen,\n  defaultOpen = false,\n  onOpenChange,\n  children,\n}: TooltipProps) {\n  const [uncontrolledOpen, setUncontrolledOpen] = React.useState<boolean>(defaultOpen);\n  const [customId, setCustomId] = React.useState<string | undefined>(undefined);\n  const isControlled = controlledOpen !== undefined;\n  const open = isControlled ? controlledOpen : uncontrolledOpen;\n  const rawId = React.useId().replace(/:/g, '');\n  const tooltipId = customId ?? `f12-tip-${rawId}`;\n\n  const setOpen = React.useCallback(\n    (next: boolean) => {\n      if (!isControlled) setUncontrolledOpen(next);\n      onOpenChange?.(next);\n    },\n    [isControlled, onOpenChange],\n  );\n\n  return (\n    <TooltipContext.Provider value={{ open, setOpen, tooltipId, setCustomId }}>\n      <span\n        className=\"f12-tooltip-wrap\"\n        onPointerEnter={() => setOpen(true)}\n        onPointerLeave={() => setOpen(false)}\n        onFocus={() => setOpen(true)}\n        onBlur={() => setOpen(false)}\n        onKeyDown={(e) => {\n          if (e.key === 'Escape') setOpen(false);\n        }}\n      >\n        {children}\n      </span>\n    </TooltipContext.Provider>\n  );\n}\n\nexport interface TooltipTriggerProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n  asChild?: boolean;\n}\n\nfunction mergeRefs<T>(\n  ...refs: Array<React.Ref<T> | undefined>\n): React.RefCallback<T> {\n  return (value: T) => {\n    for (const ref of refs) {\n      if (typeof ref === 'function') {\n        ref(value);\n      } else if (ref != null) {\n        (ref as React.MutableRefObject<T | null>).current = value;\n      }\n    }\n  };\n}\n\nfunction getElementRef(element: React.ReactElement): React.Ref<unknown> | undefined {\n  const propsObj = (element.props || {}) as Record<string, unknown>;\n  let getter = Object.getOwnPropertyDescriptor(propsObj, 'ref')?.get;\n  let mayWarn =\n    getter && 'isReactWarning' in getter && (getter as { isReactWarning?: boolean }).isReactWarning;\n  if (mayWarn) {\n    return (element as unknown as { ref?: React.Ref<unknown> }).ref;\n  }\n  getter = Object.getOwnPropertyDescriptor(element, 'ref')?.get;\n  mayWarn =\n    getter && 'isReactWarning' in getter && (getter as { isReactWarning?: boolean }).isReactWarning;\n  if (mayWarn) {\n    return (propsObj as { ref?: React.Ref<unknown> }).ref;\n  }\n  return (\n    (propsObj as { ref?: React.Ref<unknown> }).ref ||\n    (element as unknown as { ref?: React.Ref<unknown> }).ref\n  );\n}\n\nexport const TooltipTrigger = React.forwardRef<HTMLButtonElement, TooltipTriggerProps>(\n  function TooltipTrigger(\n    {\n      asChild = false,\n      className = '',\n      'aria-describedby': triggerDescribedBy,\n      children,\n      ...rest\n    },\n    forwardedRef,\n  ) {\n    const { open, tooltipId } = useTooltipContext();\n    const childRef = React.isValidElement(children) ? getElementRef(children) : undefined;\n    const composedRef = React.useMemo(\n      () => mergeRefs(forwardedRef, childRef),\n      [forwardedRef, childRef],\n    );\n    if (asChild && React.isValidElement(children)) {\n      const child = children as React.ReactElement<Record<string, unknown>>;\n      const childProps = child.props || {};\n      const mergedClassName = [childProps.className, className].filter(Boolean).join(' ') || undefined;\n      const mergedDescribedBy =\n        [\n          triggerDescribedBy,\n          childProps['aria-describedby'] as string | undefined,\n          open ? tooltipId : undefined,\n        ]\n          .filter(Boolean)\n          .join(' ') || undefined;\n\n      const mergedProps: Record<string, unknown> = {\n        ...rest,\n        ...childProps,\n        className: mergedClassName,\n        'aria-describedby': mergedDescribedBy,\n        ref: composedRef,\n      };\n\n      for (const evt of new Set([...Object.keys(rest), ...Object.keys(childProps)])) {\n        if (!/^on[A-Z]/.test(evt)) continue;\n        const parentHandler = (rest as Record<string, unknown>)[evt];\n        const childHandler = childProps[evt];\n        if (typeof parentHandler === 'function' && typeof childHandler === 'function') {\n          mergedProps[evt] = (...args: unknown[]) => {\n            (parentHandler as (...a: unknown[]) => void)(...args);\n            (childHandler as (...a: unknown[]) => void)(...args);\n          };\n        } else if (typeof parentHandler === 'function') {\n          mergedProps[evt] = parentHandler;\n        } else if (typeof childHandler === 'function') {\n          mergedProps[evt] = childHandler;\n        }\n      }\n\n      return React.cloneElement(child, mergedProps);\n    }\n    const buttonDescribedBy =\n      [triggerDescribedBy, open ? tooltipId : undefined].filter(Boolean).join(' ') || undefined;\n    return (\n      <button\n        ref={forwardedRef}\n        type=\"button\"\n        className={`f12-btn f12-btn-secondary f12-btn-sm${className ? ` ${className}` : ''}`}\n        aria-describedby={buttonDescribedBy}\n        {...rest}\n      >\n        {children}\n      </button>\n    );\n  },\n);\n\nexport function TooltipContent({\n  id: userProvidedId,\n  className = '',\n  children,\n  ...rest\n}: React.HTMLAttributes<HTMLSpanElement>) {\n  const { open, tooltipId, setCustomId } = useTooltipContext();\n  useIsoLayoutEffect(() => {\n    setCustomId(userProvidedId);\n    return () => setCustomId(undefined);\n  }, [userProvidedId, setCustomId]);\n  if (!open) return null;\n  return (\n    <span\n      id={userProvidedId ?? tooltipId}\n      role=\"tooltip\"\n      className={`f12-tooltip${className ? ` ${className}` : ''}`}\n      {...rest}\n    >\n      {children}\n    </span>\n  );\n}\n",
      "type": "registry:ui",
      "target": "components/frame12/tooltip.tsx"
    },
    {
      "path": "ui/dropdown-menu.tsx",
      "content": "'use client';\n\nimport * as React from 'react';\nimport * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu';\nimport { Button, type ButtonProps } from './button';\n\ninterface DropdownMenuFieldContextValue {\n  containerEl: HTMLDivElement | null;\n}\n\nconst DropdownMenuFieldContext = React.createContext<DropdownMenuFieldContextValue | null>(null);\n\nexport type DropdownMenuProps = React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Root>;\n\nexport function DropdownMenu({\n  open,\n  defaultOpen,\n  onOpenChange,\n  modal = false,\n  dir,\n  children,\n}: DropdownMenuProps) {\n  const [containerEl, setContainerEl] = React.useState<HTMLDivElement | null>(null);\n  const ctxValue = React.useMemo(() => ({ containerEl }), [containerEl]);\n\n  return (\n    <DropdownMenuFieldContext.Provider value={ctxValue}>\n      <div ref={setContainerEl} className=\"f12-menu-wrap\">\n        <DropdownMenuPrimitive.Root\n          open={open}\n          defaultOpen={defaultOpen}\n          onOpenChange={onOpenChange}\n          modal={modal}\n          dir={dir}\n        >\n          {children}\n        </DropdownMenuPrimitive.Root>\n      </div>\n    </DropdownMenuFieldContext.Provider>\n  );\n}\n\nexport interface DropdownMenuTriggerProps extends ButtonProps {\n  asChild?: boolean;\n}\n\nexport const DropdownMenuTrigger = React.forwardRef<HTMLButtonElement, DropdownMenuTriggerProps>(\n  function DropdownMenuTrigger(\n    { asChild = false, variant = 'secondary', size = 'md', className = '', children, ...rest },\n    forwardedRef,\n  ) {\n    if (asChild && React.isValidElement(children)) {\n      return (\n        <DropdownMenuPrimitive.Trigger\n          ref={forwardedRef}\n          asChild\n          className={className || undefined}\n          {...rest}\n        >\n          {children}\n        </DropdownMenuPrimitive.Trigger>\n      );\n    }\n    return (\n      <DropdownMenuPrimitive.Trigger asChild>\n        <Button ref={forwardedRef} variant={variant} size={size} className={className} {...rest}>\n          {children}\n        </Button>\n      </DropdownMenuPrimitive.Trigger>\n    );\n  },\n);\n\nexport type DropdownMenuContentProps = React.ComponentPropsWithoutRef<\n  typeof DropdownMenuPrimitive.Content\n>;\n\nexport const DropdownMenuContent = React.forwardRef<HTMLDivElement, DropdownMenuContentProps>(\n  function DropdownMenuContent(\n    { className = '', sideOffset = 4, align = 'start', children, ...rest },\n    forwardedRef,\n  ) {\n    const field = React.useContext(DropdownMenuFieldContext);\n    const portalContainer =\n      (field?.containerEl?.closest(\n        'dialog, .f12-frame, .f12-sheet, .f12-theme-dark, .f12-theme-light, [data-theme]',\n      ) as HTMLElement | null) ?? undefined;\n\n    return (\n      <DropdownMenuPrimitive.Portal container={portalContainer}>\n        <DropdownMenuPrimitive.Content\n          ref={forwardedRef}\n          sideOffset={sideOffset}\n          align={align}\n          className={`f12-menu${className ? ` ${className}` : ''}`}\n          {...rest}\n        >\n          {children}\n        </DropdownMenuPrimitive.Content>\n      </DropdownMenuPrimitive.Portal>\n    );\n  },\n);\n\nexport type DropdownMenuLabelProps = React.ComponentPropsWithoutRef<\n  typeof DropdownMenuPrimitive.Label\n>;\n\nexport const DropdownMenuLabel = React.forwardRef<HTMLDivElement, DropdownMenuLabelProps>(\n  function DropdownMenuLabel({ className = '', children, ...rest }, forwardedRef) {\n    return (\n      <DropdownMenuPrimitive.Label\n        ref={forwardedRef}\n        className={`f12-menu-label${className ? ` ${className}` : ''}`}\n        {...rest}\n      >\n        {children}\n      </DropdownMenuPrimitive.Label>\n    );\n  },\n);\n\nexport type DropdownMenuSeparatorProps = React.ComponentPropsWithoutRef<\n  typeof DropdownMenuPrimitive.Separator\n>;\n\nexport const DropdownMenuSeparator = React.forwardRef<HTMLDivElement, DropdownMenuSeparatorProps>(\n  function DropdownMenuSeparator({ className = '', ...rest }, forwardedRef) {\n    return (\n      <DropdownMenuPrimitive.Separator\n        ref={forwardedRef}\n        className={`f12-menu-sep${className ? ` ${className}` : ''}`}\n        {...rest}\n      />\n    );\n  },\n);\n\nexport type DropdownMenuItemProps = React.ComponentPropsWithoutRef<\n  typeof DropdownMenuPrimitive.Item\n>;\n\nexport const DropdownMenuItem = React.forwardRef<HTMLDivElement, DropdownMenuItemProps>(\n  function DropdownMenuItem({ className = '', children, ...rest }, forwardedRef) {\n    return (\n      <DropdownMenuPrimitive.Item\n        ref={forwardedRef}\n        className={`f12-menu-item${className ? ` ${className}` : ''}`}\n        {...rest}\n      >\n        {children}\n      </DropdownMenuPrimitive.Item>\n    );\n  },\n);\n\nexport type DropdownMenuGroupProps = React.ComponentPropsWithoutRef<\n  typeof DropdownMenuPrimitive.Group\n>;\n\nexport const DropdownMenuGroup = React.forwardRef<HTMLDivElement, DropdownMenuGroupProps>(\n  function DropdownMenuGroup({ className = '', children, ...rest }, forwardedRef) {\n    return (\n      <DropdownMenuPrimitive.Group\n        ref={forwardedRef}\n        className={`f12-menu-group${className ? ` ${className}` : ''}`}\n        {...rest}\n      >\n        {children}\n      </DropdownMenuPrimitive.Group>\n    );\n  },\n);\n",
      "type": "registry:ui",
      "target": "components/frame12/dropdown-menu.tsx"
    },
    {
      "path": "ui/table.tsx",
      "content": "'use client';\n\nimport * as React from 'react';\n\nexport function Table({\n  className = '',\n  children,\n  ...rest\n}: React.TableHTMLAttributes<HTMLTableElement>) {\n  return (\n    <div className=\"f12-table-wrap\">\n      <table className={`f12-table${className ? ` ${className}` : ''}`} {...rest}>\n        {children}\n      </table>\n    </div>\n  );\n}\n\nexport function TableHeader({\n  className = '',\n  children,\n  ...rest\n}: React.HTMLAttributes<HTMLTableSectionElement>) {\n  return (\n    <thead className={className} {...rest}>\n      {children}\n    </thead>\n  );\n}\n\nexport function TableBody({\n  className = '',\n  children,\n  ...rest\n}: React.HTMLAttributes<HTMLTableSectionElement>) {\n  return (\n    <tbody className={className} {...rest}>\n      {children}\n    </tbody>\n  );\n}\n\nexport function TableFooter({\n  className = '',\n  children,\n  ...rest\n}: React.HTMLAttributes<HTMLTableSectionElement>) {\n  return (\n    <tfoot className={className} {...rest}>\n      {children}\n    </tfoot>\n  );\n}\n\nexport function TableRow({\n  className = '',\n  children,\n  ...rest\n}: React.HTMLAttributes<HTMLTableRowElement>) {\n  return (\n    <tr className={className} {...rest}>\n      {children}\n    </tr>\n  );\n}\n\nexport function TableHead({\n  scope = 'col',\n  className = '',\n  children,\n  ...rest\n}: React.ThHTMLAttributes<HTMLTableCellElement>) {\n  return (\n    <th scope={scope} className={className} {...rest}>\n      {children}\n    </th>\n  );\n}\n\nexport function TableCell({\n  className = '',\n  children,\n  ...rest\n}: React.TdHTMLAttributes<HTMLTableCellElement>) {\n  return (\n    <td className={className} {...rest}>\n      {children}\n    </td>\n  );\n}\n\nexport function TableCaption({\n  className = '',\n  children,\n  ...rest\n}: React.HTMLAttributes<HTMLTableCaptionElement>) {\n  return (\n    <caption className={className} {...rest}>\n      {children}\n    </caption>\n  );\n}\n",
      "type": "registry:ui",
      "target": "components/frame12/table.tsx"
    }
  ],
  "type": "registry:block"
}