{
  "$schema": "https://ui.shadcn.com/schema/registry.json",
  "name": "bld8",
  "homepage": "https://ui.bld8.dev",
  "items": [
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "bld8-styles",
      "type": "registry:ui",
      "title": "BLD8 styles and licences",
      "description": "BLD8 styles and licences with editable BLD8 source.",
      "author": "Jaison (https://bld8.dev)",
      "dependencies": [],
      "registryDependencies": [],
      "files": [
        {
          "path": "registry/bld8/styles.css",
          "content": "@import './tokens.css';\n@import './tailwind.css';\n/* These advanced controls share the same tokens, focus and motion as the core. */\n.bui-input[data-density=\"compact\"] { padding:.45rem .7rem; min-height:34px; font-size:.8125rem; }\n.bui-date-field { display:flex; align-items:center; gap:6px; min-width:0; }\n.bui-select-clear { display:grid; place-items:center; flex-shrink:0; border:0; width:32px; height:32px; color:var(--bui-muted); background:transparent; cursor:pointer; }\n.bui-select-clear:focus-visible { outline:2px solid var(--bui-focus); outline-offset:2px; }\n.bui-date-field>.bui-input { flex:1; min-width:0; }\n.bui-date-trigger { display:flex; align-items:center; gap:.65rem; text-align:start; cursor:pointer; }\n.bui-date-trigger>span { flex:1; overflow-wrap:anywhere; }\n.bui-date-trigger>span[data-placeholder] { color:var(--bui-muted); }\n.bui-combobox-clear { position:absolute; right:34px; top:0; bottom:0; border:0; background:transparent; color:var(--bui-muted); cursor:pointer; display:grid; place-items:center; width:32px; }\n.bui-combobox-input:has(.bui-combobox-clear)>.bui-input { padding-right:72px; }\n.bui-multi-input { display:flex; flex-wrap:wrap; align-items:center; gap:5px; background:var(--bui-bg); border:1px solid var(--bui-line); border-radius:var(--bui-radius); padding:6px 38px 6px 8px; min-height:42px; position:relative; }\n.bui-multi-input:focus-within { border-color:var(--bui-focus); outline:2px solid var(--bui-focus); outline-offset:2px; }\n.bui-multi-input[data-invalid] { border-color:var(--bui-danger); }\n.bui-chip { display:inline-flex; align-items:center; gap:6px; background:var(--bui-surface); color:var(--bui-ink); padding:3px 5px 3px 8px; border-radius:3px; font-size:.75rem; }\n.bui-chip button { display:grid; place-items:center; padding:3px; color:inherit; background:transparent; border:0; cursor:pointer; border-radius:2px; }\n.bui-chip-input { flex:1; min-width:95px; width:0; border:0; background:transparent; color:var(--bui-ink); font:inherit; outline:none; padding:4px; }\n.bui-multi-input:has(input:disabled) { opacity:.5; cursor:not-allowed; }\n.bui-command-search { display:flex; align-items:center; gap:10px; margin-bottom:12px; }\n.bui-command-list { max-height:min(380px,45dvh); overflow:auto; overscroll-behavior:contain; }\n.bui-command-item { gap:12px; padding:.85rem .75rem; }\n.bui-command-item>span:has(strong) { flex:1; min-width:0; }\n.bui-command-item strong { display:block; font-weight:500; }\n.bui-command-item small { display:block; color:var(--bui-muted); font-size:.6875rem; margin-top:2px; }\n.bui-command-symbol { width:32px; height:32px; display:grid; place-items:center; background:var(--bui-surface); border-radius:4px; flex-shrink:0; }\n.bui-command-category { color:var(--bui-muted); font-size:.625rem; }\n.bui-command-footer { display:flex; gap:20px; border-top:1px solid var(--bui-line); padding-top:12px; margin-top:12px; font-size:.6875rem; color:var(--bui-muted); }\n.bui-command-footer kbd { display:inline-grid; place-items:center; background:var(--bui-surface); border:1px solid var(--bui-line); border-radius:3px; min-width:20px; height:20px; font:inherit; margin-right:3px; }\n.bui-calendar { font-family:var(--bui-font); font-size:.8125rem; color:var(--bui-ink); position:relative; width:min(100%,294px); }\n.bui-calendar-months { position:relative; }\n.bui-calendar-caption { height:44px; display:flex; align-items:center; padding:0 6px; padding-right:76px; }\n.bui-calendar-label { font-weight:550; }\n.bui-calendar-nav { position:absolute; inset-block-start:4px; inset-inline-end:0; display:flex; gap:4px; }\n.bui-calendar-nav-button { width:32px; height:32px; display:grid; place-items:center; border:0; border-radius:4px; background:var(--bui-surface); color:var(--bui-ink); cursor:pointer; }\n.bui-calendar-chevron { width:16px; height:16px; fill:currentColor; }\n.bui-calendar-grid { width:100%; border-collapse:collapse; table-layout:fixed; }\n.bui-calendar-weekday { height:32px; color:var(--bui-muted); font-size:.6875rem; font-weight:400; }\n.bui-calendar-day { text-align:center; padding:1px 0; height:40px; }\n.bui-calendar-day-button { width:100%; height:38px; display:grid; place-items:center; font:inherit; color:inherit; background:transparent; border:0; border-radius:4px; cursor:pointer; transition:background var(--bui-duration) var(--bui-ease),color var(--bui-duration) var(--bui-ease); }\n.bui-calendar-today:not(.bui-calendar-selected) .bui-calendar-day-button { box-shadow:inset 0 0 0 1px var(--bui-line); font-weight:650; }\n.bui-calendar-selected .bui-calendar-day-button { background:var(--bui-primary); color:var(--bui-primary-ink); }\n.bui-calendar-range-middle { background:var(--bui-surface); }\n.bui-calendar-range-middle .bui-calendar-day-button { background:transparent; color:var(--bui-ink); }\n.bui-calendar-range-start { background:linear-gradient(to right,transparent 50%,var(--bui-surface) 50%); }\n.bui-calendar-range-end { background:linear-gradient(to left,transparent 50%,var(--bui-surface) 50%); }\n.bui-calendar-range-start.bui-calendar-range-end { background:transparent; }\n.bui-calendar-outside:not(.bui-calendar-selected) { color:var(--bui-muted); }\n.bui-calendar-disabled { opacity:.3; }\n.bui-calendar-disabled button, .bui-calendar-nav-button:disabled { cursor:not-allowed; }\n.bui-calendar-hidden { visibility:hidden; }\n.bui-popup.bui-calendar-popup { width:min(326px,calc(100vw - 24px)); padding:16px; }\n.bui-calendar-footer { display:flex; justify-content:space-between; gap:12px; align-items:center; padding-top:12px; border-top:1px solid var(--bui-line); margin-top:12px; }\n.bui-calendar-footer .bui-hint { font-size:.6875rem; }\n.bui-file-upload { display:grid; gap:12px; font-family:var(--bui-font); font-size:.875rem; }\n.bui-dropzone { display:flex; flex-direction:column; align-items:center; gap:10px; padding:28px 16px; text-align:center; background:var(--bui-surface); border:1px dashed var(--bui-line); border-radius:6px; transition:background var(--bui-duration) var(--bui-ease),border-color var(--bui-duration) var(--bui-ease); }\n.bui-dropzone[data-dragging] { border-color:var(--bui-focus); background:var(--bui-bg); }\n.bui-dropzone:focus-within { outline:2px solid var(--bui-focus); outline-offset:3px; }\n.bui-dropzone[data-disabled] { opacity:.5; }\n.bui-file-symbol { display:grid; place-items:center; width:44px; height:44px; border-radius:8px; background:var(--bui-bg); }\n.bui-file-errors { margin:8px 0 0; padding-inline-start:18px; font-size:.75rem; overflow-wrap:anywhere; }\n.bui-file-list { list-style:none; margin:0; padding:0; }\n.bui-file-list li { display:flex; align-items:center; gap:12px; padding:12px 0; border-bottom:1px solid var(--bui-line); }\n.bui-file-list li>div { flex:1; min-width:0; }\n.bui-file-list strong { display:block; font-size:.8125rem; font-weight:500; overflow-wrap:anywhere; }\n.bui-file-list .bui-progress { margin-top:8px; }\n.bui-file-footer { display:flex; justify-content:space-between; flex-wrap:wrap; gap:12px; align-items:center; }\n.bui-table-toolbar { flex-wrap:wrap; }\n.bui-table-filter { max-width:180px; min-width:0; }\n.bui-column-options { display:grid; gap:12px; margin-top:12px; }\n.bui-table-check { width:42px; }\n.bui-table-selection { display:flex; justify-content:space-between; align-items:center; flex-wrap:wrap; gap:10px; background:var(--bui-surface); padding:8px 12px; margin-bottom:12px; border-radius:4px; font-size:.75rem; }\n.bui-table-selection>div { display:flex; gap:6px; flex-wrap:wrap; }\n.bui-table-loading { display:grid; gap:8px; }\n.bui-data-table[data-density=\"compact\"] .bui-table th,.bui-data-table[data-density=\"compact\"] .bui-table td { padding:.55rem .75rem; font-size:.8125rem; }\n.bui-table tr[data-selected] { background:var(--bui-surface); }\n.bui-chip button:focus-visible,.bui-combobox-clear:focus-visible,.bui-combobox-trigger:focus-visible,.bui-calendar button:focus-visible { outline:2px solid var(--bui-focus); outline-offset:2px; }\n@media (hover:hover) and (pointer:fine) {\n  .bui-calendar-day-button:hover:not(:disabled) { box-shadow:inset 0 0 0 1px var(--bui-focus); }\n  .bui-chip button:hover { background:var(--bui-bg); }\n}\n[class^=\"bui-\"], [class*=\" bui-\"] { box-sizing: border-box; }\n.bui-choice, .bui-field, .bui-tabs, .bui-accordion, .bui-popup, .bui-dialog, .bui-toast, .bui-data-table { font-family: var(--bui-font); font-size: .875rem; line-height: 1.5; }\n.bui-button, .bui-tab, .bui-option, .bui-input, .bui-checkbox, .bui-switch, .bui-accordion-trigger { transition: background-color var(--bui-duration) var(--bui-ease), color var(--bui-duration) var(--bui-ease), border-color var(--bui-duration) var(--bui-ease), box-shadow var(--bui-duration) var(--bui-ease), transform var(--bui-duration-slow) var(--bui-ease); }\n:where([class^=\"bui-\"], [class*=\" bui-\"]):focus-visible { outline: 2px solid var(--bui-focus); outline-offset: 3px; }\n.bui-button:disabled, .bui-input:disabled, .bui-choice:has(input:disabled), .bui-radio-group:disabled { opacity: .48; cursor: not-allowed; }\n.bui-button svg { flex-shrink: 0; }\n.bui-icon-button { width: 44px; padding: 0; }\n.bui-field { display: flex; flex-direction: column; gap: .5rem; width: 100%; color: var(--bui-ink); }\n.bui-label { font-size: .8125rem; line-height: 1.5; font-weight: 600; color: var(--bui-ink); margin: 0; }\n.bui-hint, .bui-error { margin: 0; font-size: .75rem; line-height: 1.6; color: var(--bui-muted); }\n.bui-error { color: var(--bui-danger); }\n.bui-icon { display:inline-block; vertical-align:middle; flex-shrink:0; }\n.bui-input-group { display:flex; align-items:center; width:100%; min-width:0; min-height:44px; padding-inline:.75rem; background:var(--bui-bg); border:1px solid var(--bui-line); border-radius:var(--bui-radius); transition:border-color var(--bui-duration) var(--bui-ease); }\n.bui-input-group>.bui-input { flex:1; min-width:0; border:0; background:transparent; padding-inline:.65rem; outline:none; box-shadow:none; }\n.bui-input-group:focus-within { border-color:var(--bui-focus); }\n.bui-input-group:has(>.bui-input:focus-visible) { outline:2px solid var(--bui-focus); outline-offset:3px; }\n.bui-input-group[data-invalid],.bui-input-group:has(.bui-input[aria-invalid=\"true\"]) { border-color:var(--bui-danger); }\n.bui-input-group:has(.bui-input:disabled) { background:var(--bui-surface); }\n.bui-input-adornment { display:inline-flex; align-items:center; color:var(--bui-muted); font-size:.8125rem; flex-shrink:0; }\n.bui-input-adornment>.bui-icon-button { width:32px; min-height:36px; padding:0; }\n.bui-choice { display: flex; align-items: flex-start; gap: .7rem; min-height: 32px; color: var(--bui-ink); cursor: pointer; }\n.bui-choice small { display: block; font-size: .75rem; color: var(--bui-muted); margin-top: .25rem; }\n.bui-checkbox { appearance: none; position: relative; width: 18px; height: 18px; flex: 0 0 18px; border: 1px solid var(--bui-line); border-radius: 3px; margin: .125rem 0 0; background: var(--bui-bg); cursor: inherit; }\n.bui-checkbox:checked { background: var(--bui-accent); border-color: var(--bui-accent-border); }\n.bui-checkbox:checked::after { content: ''; position: absolute; width: 5px; height: 9px; border: solid #191919; border-width: 0 1.7px 1.7px 0; transform: rotate(45deg); left: 5px; top: 1px; }\n.bui-switch-row { justify-content: space-between; align-items: center; gap: 1.5rem; width: 100%; }\n.bui-switch { appearance: none; position: relative; flex: 0 0 36px; width: 36px; height: 22px; border: 1px solid var(--bui-line); background: var(--bui-raised); border-radius: 20px; margin: 0; cursor: inherit; }\n.bui-switch::after { content: ''; position: absolute; width: 16px; height: 16px; border-radius: 50%; left: 2px; top: 2px; background: var(--bui-muted); transition: transform var(--bui-duration-slow) var(--bui-ease), background-color var(--bui-duration) var(--bui-ease); }\n.bui-switch:checked { background: var(--bui-accent); border-color: var(--bui-accent-border); }\n.bui-switch:checked::after { transform: translateX(14px); background: #191919; }\n.bui-radio-group { border: 0; padding: 0; margin: 0; display: grid; gap: .65rem; }\n.bui-radio-group legend { margin-bottom: .75rem; }\n.bui-choice input[type=\"radio\"] { accent-color: var(--bui-focus); width: 17px; height: 17px; margin: 2px 0 0; }\n.bui-slider { width: 100%; height: 24px; margin: 0; accent-color: var(--bui-focus); }\n.bui-between { display: flex; align-items: center; justify-content: space-between; gap: 1rem; }\n.bui-between output { font: .75rem ui-monospace, monospace; color: var(--bui-muted); }\n.bui-badge { display: inline-flex; align-items: center; border: 1px solid var(--bui-line); border-radius: 4px; padding: .18rem .5rem; font: 500 .6875rem/1.5 var(--bui-font); }\n.bui-tone--neutral { color: var(--bui-ink); background: var(--bui-surface); }\n.bui-tone--accent { color: var(--bui-focus); background: var(--bui-soft); }\n.bui-tone--success { color: var(--bui-success); background: var(--bui-success-bg); }\n.bui-tone--warning { color: var(--bui-warning); background: var(--bui-warning-bg); }\n.bui-tone--danger { color: var(--bui-danger); background: var(--bui-danger-bg); }\n.bui-card { border: 0; border-radius: var(--bui-panel-radius); background: var(--bui-bg); color: var(--bui-ink); padding: 1.5rem; }\n.bui-avatar { width: 36px; height: 36px; background: var(--bui-soft); border: 1px solid var(--bui-line); color: var(--bui-focus); display: inline-flex; flex-shrink: 0; align-items: center; justify-content: center; overflow: hidden; border-radius: 50%; font: 600 .75rem var(--bui-font); }\n.bui-avatar--sm { width: 28px; height: 28px; font-size: .625rem; }\n.bui-avatar--lg { width: 48px; height: 48px; font-size: 1rem; }\n.bui-avatar img { width: 100%; height: 100%; object-fit: cover; }\n.bui-separator { width: 100%; height: 0; border: 0; border-top: 1px solid var(--bui-line); margin-block: 1rem; }\n.bui-spinner { display: inline-block; width: 16px; height: 16px; flex: 0 0 16px; border-radius: 50%; border: 1.5px solid currentColor; border-right-color: transparent; animation: bui-spin .8s linear infinite; }\n@keyframes bui-spin { to { transform: rotate(360deg); } }\n.bui-skeleton { display: block; background: var(--bui-raised); border-radius: 4px; }\n.bui-progress { width: 100%; height: 5px; border: 0; border-radius: 4px; overflow: hidden; background: var(--bui-raised); accent-color: var(--bui-focus); }\n.bui-progress::-webkit-progress-bar { background: var(--bui-raised); }\n.bui-progress::-webkit-progress-value { background: var(--bui-focus); border-radius: 4px; }\n.bui-progress::-moz-progress-bar { background: var(--bui-focus); }\n.bui-alert { padding: 1rem; border: 1px solid var(--bui-line); border-radius: 6px; font: .8125rem/1.6 var(--bui-font); }\n.bui-alert strong { display: block; font-weight: 600; margin-bottom: .2rem; }\n.bui-empty { text-align: center; padding: 2rem 1rem; font-family: var(--bui-font); color: var(--bui-ink); }\n.bui-empty-mark { display: inline-grid; place-items: center; height: 36px; width: 36px; border: 1px dashed var(--bui-line); border-radius: 8px; color: var(--bui-muted); margin-bottom: .8rem; }\n.bui-empty h3 { font-size: .9375rem; margin: 0 0 .5rem; font-weight: 500; }\n.bui-empty p { font-size: .8125rem; color: var(--bui-muted); margin: 0 0 1rem; }\n.bui-breadcrumb { display: flex; flex-wrap: wrap; gap: .7rem; list-style: none; padding: 0; margin: 0; font: .75rem var(--bui-font); color: var(--bui-muted); }\n.bui-breadcrumb li { display: flex; align-items: center; gap: .7rem; }\n.bui-breadcrumb a { color: inherit; text-underline-offset: 4px; }\n.bui-breadcrumb [aria-current] { color: var(--bui-ink); }\n.bui-pagination { display: flex; justify-content: flex-end; align-items: center; flex-wrap: wrap; gap: .8rem; padding-top: 1rem; }\n.bui-pagination > span { font: .75rem var(--bui-font); color: var(--bui-muted); }\n.bui-positioner { z-index: 90; outline: none; }\n.bui-popup { background: var(--bui-bg); color: var(--bui-ink); border: 1px solid var(--bui-line); border-radius: 8px; box-shadow: var(--bui-shadow); padding: .35rem; transform-origin: var(--transform-origin); transition: opacity var(--bui-duration) var(--bui-ease), transform var(--bui-duration) var(--bui-ease); max-height: var(--available-height); overflow-y: auto; }\n.bui-popup[data-starting-style], .bui-popup[data-ending-style] { opacity: 0; transform: translateY(-4px) scale(.98); }\n.bui-select-trigger { display: flex; justify-content: space-between; align-items: center; gap: .75rem; text-align: start; cursor: pointer; }\n.bui-select-popup { min-width: var(--anchor-width); }\n.bui-option { display: flex; align-items: center; justify-content: space-between; gap: 1.5rem; padding: .6rem .7rem; min-height: 36px; border-radius: 4px; cursor: default; outline: none; font-size: .8125rem; }\n.bui-option[data-highlighted] { background: var(--bui-soft); color: var(--bui-ink); }\n.bui-option[data-disabled] { opacity: .4; }\n.bui-combobox-input { position: relative; }\n.bui-combobox-input input { padding-right: 2.5rem; }\n.bui-combobox-trigger { position: absolute; inset-inline-end: 1px; top: 1px; bottom: 1px; width: 40px; display: grid; place-items: center; border: 0; color: var(--bui-muted); background: transparent; cursor: pointer; }\n.bui-combo-empty { color: var(--bui-muted); padding: .75rem; font-size: .8125rem; }\n.bui-combo-empty:empty { display: none; }\n.bui-tab-list { position: relative; padding: 4px 4px 0; display: flex; gap: .25rem; border-bottom: 1px solid var(--bui-line); overflow-x: auto; }\n.bui-tab { font: 500 .8125rem var(--bui-font); color: var(--bui-muted); border: 0; border-bottom: 2px solid transparent; padding: .8rem 1rem; background: transparent; cursor: pointer; white-space: nowrap; }\n.bui-tab[data-active] { color: var(--bui-ink); border-bottom-color: transparent; }\n.bui-tab:disabled { opacity: .5; cursor: not-allowed; }\n.bui-tab-panel { padding-block: 1.25rem; color: var(--bui-ink); outline-offset: 4px; }\n.bui-accordion { width: 100%; color: var(--bui-ink); }\n.bui-accordion-item { border-bottom: 1px solid var(--bui-line); }\n.bui-accordion-item:first-child { border-top: 1px solid var(--bui-line); }\n.bui-accordion-item h3 { margin: 0; }\n.bui-accordion-trigger { display: flex; width: 100%; align-items: center; justify-content: space-between; gap: 1.5rem; padding: 1rem 0; font: 500 .875rem var(--bui-font); color: inherit; background: transparent; border: 0; text-align: start; cursor: pointer; }\n.bui-accordion-trigger svg { flex-shrink: 0; transition: transform var(--bui-duration) var(--bui-ease); }\n.bui-accordion-trigger[data-panel-open] svg { transform: rotate(45deg); }\n.bui-accordion-panel { height: var(--accordion-panel-height); overflow: hidden; transition: height var(--bui-duration-slow) var(--bui-ease), opacity var(--bui-duration) var(--bui-ease); }\n.bui-accordion-panel[data-starting-style], .bui-accordion-panel[data-ending-style] { height: 0; opacity: 0; }\n.bui-accordion-panel > div { padding-bottom: 1.25rem; font-size: .8125rem; color: var(--bui-muted); line-height: 1.7; }\n.bui-backdrop { position: absolute; inset: 0; min-height: 100dvh; z-index: 80; background: #0005; transition: opacity var(--bui-duration) var(--bui-ease); }\n.bui-backdrop[data-starting-style], .bui-backdrop[data-ending-style] { opacity: 0; }\n.bui-dialog { position: fixed; z-index: 81; top: 50%; left: 50%; transform: translate(-50%,-50%); width: min(460px, calc(100vw - 2rem)); max-height: calc(100dvh - 2rem); overflow-y: auto; background: var(--bui-bg); color: var(--bui-ink); border: 1px solid var(--bui-line); border-radius: 12px; box-shadow: var(--bui-shadow); padding: 1.5rem; transition: opacity var(--bui-duration) var(--bui-ease), scale var(--bui-duration-slow) var(--bui-ease), translate var(--bui-duration-slow) var(--bui-ease); outline: none; }\n.bui-dialog[data-starting-style], .bui-dialog[data-ending-style] { opacity: 0; scale: .98; translate: 0 8px; }\n.bui-dialog-heading { display: flex; align-items: flex-start; gap: 1rem; justify-content: space-between; }\n.bui-dialog-heading .bui-icon-button { flex-shrink: 0; margin-top: -.5rem; margin-right: -.5rem; }\n.bui-dialog-title { font-family: var(--bui-heading); font-size: 1.25rem; line-height: 1.4; font-weight: 600; margin: 0; letter-spacing: -.04em; }\n.bui-dialog-description { margin: .5rem 0 0; color: var(--bui-muted); font-size: .8125rem; line-height: 1.7; }\n.bui-dialog-body { padding-top: 1.5rem; }\n.bui-sheet { top: 0; left: auto; right: 0; transform: none; height: 100dvh; max-height: 100dvh; width: min(420px, calc(100vw - 1rem)); border-radius: 0; border-width: 0 0 0 1px; transition: transform var(--bui-duration-slow) var(--bui-ease), opacity var(--bui-duration) var(--bui-ease); }\n.bui-sheet[data-starting-style], .bui-sheet[data-ending-style] { transform: translateX(100%); scale: 1; translate: none; }\n.bui-popover { width: min(300px, calc(100vw - 2rem)); padding: 1.25rem; }\n.bui-popover > div { margin-top: 1rem; }\n.bui-tooltip { background: var(--bui-ink); color: var(--bui-bg); max-width: min(260px, calc(100vw - 2rem)); padding: .4rem .65rem; border-radius: 4px; font: .75rem/1.5 var(--bui-font); }\n.bui-menu { min-width: 180px; }\n.bui-destructive { color: var(--bui-danger); }\n.bui-toast-viewport { position: fixed; z-index: 100; right: 1.25rem; bottom: 1.25rem; width: min(360px, calc(100vw - 2.5rem)); display: flex; flex-direction: column; gap: .5rem; outline: none; }\n.bui-toast { display: flex; align-items: flex-start; gap: .75rem; border: 1px solid var(--bui-line); border-left: 3px solid var(--bui-focus); background: var(--bui-bg); color: var(--bui-ink); border-radius: 6px; padding: 1rem; box-shadow: var(--bui-shadow); transition: opacity var(--bui-duration) var(--bui-ease), transform var(--bui-duration-slow) var(--bui-ease); }\n.bui-toast[data-starting-style], .bui-toast[data-ending-style] { opacity: 0; transform: translateY(10px); }\n.bui-toast-content { flex: 1; }\n.bui-toast-close { padding: 0; border: 0; background: transparent; color: var(--bui-muted); cursor: pointer; width: 24px; height: 24px; }\n.bui-table-toolbar { display: flex; align-items: center; gap: 1rem; margin-bottom: 1rem; }\n.bui-table-toolbar .bui-input { max-width: 280px; }\n.bui-table-toolbar .bui-hint { white-space: nowrap; }\n.bui-table-scroll { width: 100%; overflow-x: auto; border: 1px solid var(--bui-line); border-radius: 6px; }\n.bui-table { border-collapse: collapse; text-align: start; width: 100%; white-space: nowrap; }\n.bui-table th { background: var(--bui-surface); font-size: .75rem; font-weight: 500; color: var(--bui-muted); }\n.bui-table th, .bui-table td { padding: .85rem 1rem; border-bottom: 1px solid var(--bui-line); }\n.bui-table tr:last-child td { border-bottom: 0; }\n.bui-table th button { padding: 0; font: inherit; color: inherit; background: transparent; border: 0; cursor: pointer; display: inline-flex; align-items: center; gap: .75rem; }\n.bui-table th button:focus-visible { outline: 2px solid var(--bui-focus); outline-offset: 4px; }\n.bui-table tbody tr { transition: background-color var(--bui-duration) var(--bui-ease); }\n.bui-sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; clip: rect(0,0,0,0); overflow: hidden; white-space: nowrap; border: 0; }\n/* Keep the hit area still; movement belongs to the supporting detail. */\n.bui-button-content { display: inline-flex; justify-content: center; align-items: center; gap: inherit; transition: opacity var(--bui-duration-fast) var(--bui-ease); }\n.bui-button-spinner { position: absolute; inset: 0; display: grid; place-items: center; }\n.bui-button[aria-busy=\"true\"] { opacity: 1; cursor: progress; }\n.bui-button[aria-busy=\"true\"] .bui-button-content { opacity: 0; }\n.bui-button [data-bui-icon=\"arrow\"] { transition: transform var(--bui-duration-slow) var(--bui-ease); }\n.bui-button:active:not(:disabled) { transform: scale(.985); transition-duration: var(--bui-duration-fast); }\n.bui-input:disabled, .bui-accordion-trigger:disabled { cursor: not-allowed; }\n.bui-tab:focus-visible { outline-offset: -3px; }\n.bui-tab-indicator { position: absolute; left: 0; bottom: 0; height: 2px; width: var(--active-tab-width); transform: translateX(var(--active-tab-left)); border-radius: 2px; background: var(--bui-focus); pointer-events: none; transition: transform var(--bui-duration-slow) var(--bui-ease), width var(--bui-duration-slow) var(--bui-ease); }\n.bui-tab-panel:not([hidden]) { animation: bui-panel-enter var(--bui-duration) var(--bui-ease); }\n/* Remove the outgoing panel immediately so rapid tab changes never stack layouts. */\n.bui-tab-panel[data-ending-style] { display: none; animation: none; }\n@keyframes bui-panel-enter { from { opacity: 0; translate: 0 4px; } to { opacity: 1; translate: 0 0; } }\n.bui-select-trigger [data-bui-icon=\"chevron\"], .bui-combobox-trigger svg { transition: transform var(--bui-duration-slow) var(--bui-ease); }\n.bui-select-trigger[data-popup-open] [data-bui-icon=\"chevron\"], .bui-combobox-trigger[data-popup-open] svg { transform: rotate(180deg); }\n.bui-tooltip { transform-origin: var(--transform-origin); transition: opacity var(--bui-duration-fast) var(--bui-ease), transform var(--bui-duration) var(--bui-ease); }\n.bui-tooltip[data-starting-style], .bui-tooltip[data-ending-style] { opacity: 0; transform: translateY(3px); }\n.bui-popup[data-side=\"top\"][data-starting-style], .bui-popup[data-side=\"top\"][data-ending-style] { transform: translateY(4px) scale(.98); }\n.bui-popup[data-ending-style], .bui-tooltip[data-ending-style], .bui-dialog[data-ending-style], .bui-backdrop[data-ending-style], .bui-toast[data-ending-style] { transition-duration: var(--bui-duration-fast); transition-timing-function: var(--bui-ease-exit); }\n@media (hover: hover) and (pointer: fine) {\n  .bui-button--primary:hover:not(:disabled) { background: var(--bui-primary-hover); border-color: var(--bui-primary-hover); }\n  .bui-button--accent:hover:not(:disabled) { background: var(--bui-accent-hover); border-color: var(--bui-accent-hover); }\n  .bui-button--secondary:hover:not(:disabled), .bui-button--ghost:hover:not(:disabled) { background: var(--bui-surface); border-color: var(--bui-line); }\n  .bui-button:hover:not(:disabled) [data-bui-icon=\"arrow\"] { transform: translate(2px,-2px); }\n  .bui-tab:hover:not(:disabled), .bui-accordion-trigger:hover:not(:disabled) { color: var(--bui-focus); }\n  .bui-table tbody tr:hover { background: var(--bui-surface); }\n}\n@media (prefers-reduced-motion: reduce) {\n  [class^=\"bui-\"], [class*=\" bui-\"], [class^=\"bui-\"]::before, [class*=\" bui-\"]::before, [class^=\"bui-\"]::after, [class*=\" bui-\"]::after { animation: none !important; transition: none !important; }\n  .bui-button:active:not(:disabled), .bui-button:hover:not(:disabled) [data-bui-icon=\"arrow\"] { transform: none; }\n}\n@media (forced-colors: active) {\n  .bui-card { outline: 1px solid CanvasText; }\n  .bui-tab-indicator { background: Highlight; }\n  .bui-checkbox:checked::after { border-color: Highlight; }\n  .bui-switch:checked::after { background: Highlight; }\n  .bui-spinner { border-color: CanvasText; border-right-color: transparent; }\n}\n\n/* Base UI supplies lifecycle and swipe state. BLD8 supplies tokens and easing. */\n.bui-drawer-backdrop { background:#0005; opacity:calc(1 - var(--drawer-swipe-progress,0)); transition:opacity var(--bui-duration) var(--bui-ease); }\n.bui-drawer-backdrop[data-starting-style],.bui-drawer-backdrop[data-ending-style] { opacity:0; }\n.bui-drawer { line-height:1.5; max-width:100vw; outline:none; transition:transform var(--bui-duration-slow) var(--bui-ease); transform:translate3d(var(--drawer-swipe-movement-x,0px),var(--drawer-swipe-movement-y,0px),0); }\n.bui-drawer[data-side=\"bottom\"] { bottom:0; left:0; right:0; width:min(640px,100%); margin-inline:auto; max-height:85dvh; border-radius:12px 12px 0 0; padding-bottom:env(safe-area-inset-bottom); }\n.bui-drawer[data-side=\"left\"],.bui-drawer[data-side=\"right\"] { top:0; bottom:0; width:min(360px,calc(100vw - 32px)); padding-top:env(safe-area-inset-top); padding-bottom:env(safe-area-inset-bottom); }\n.bui-drawer[data-side=\"left\"] { left:0; border-radius:0 12px 12px 0; }\n.bui-drawer[data-side=\"right\"] { right:0; border-radius:12px 0 0 12px; }\n.bui-drawer[data-side=\"bottom\"]:is([data-starting-style],[data-ending-style]) { transform:translate3d(0,100%,0); }\n.bui-drawer[data-side=\"left\"]:is([data-starting-style],[data-ending-style]) { transform:translate3d(-100%,0,0); }\n.bui-drawer[data-side=\"right\"]:is([data-starting-style],[data-ending-style]) { transform:translate3d(100%,0,0); }\n.bui-drawer[data-swiping],.bui-drawer-backdrop[data-swiping] { transition-duration:0ms; }\n.bui-drawer-handle { flex-shrink:0; cursor:grab; touch-action:none; }\n.bui-drawer *, .bui-context-menu *, .bui-sidebar-layout * { box-sizing:border-box; }\n.bui-context-menu { max-height:var(--available-height); overflow-y:auto; transform-origin:var(--transform-origin); transition:opacity var(--bui-duration-fast) var(--bui-ease),transform var(--bui-duration) var(--bui-ease); outline:none; border:1px solid var(--bui-line); }\n.bui-context-menu:is([data-starting-style],[data-ending-style]) { opacity:0; transform:translateY(-3px) scale(.98); }\n.bui-context-item { transition:background-color var(--bui-duration-fast) var(--bui-ease),color var(--bui-duration-fast) var(--bui-ease); }\n.bui-sidebar { width:216px; transition:width var(--bui-duration-slow) var(--bui-ease); }\n.bui-sidebar[data-collapsed] { width:68px; }\n.bui-sidebar[data-collapsed] .bui-sidebar-label,.bui-sidebar[data-collapsed] .bui-sidebar-footer { display:none; }\n.bui-sidebar[data-collapsed] .bui-sidebar-header { justify-content:center; padding-inline:0; }\n.bui-sidebar-button { line-height:1.5; transition:background-color var(--bui-duration) var(--bui-ease),color var(--bui-duration) var(--bui-ease); }\n.bui-sidebar-mobile .bui-sidebar-nav { padding:0; }\n@media(hover:hover) and (pointer:fine) { .bui-sidebar-button:hover:not([data-active]):not(:disabled) { background:var(--bui-surface); } }\n@media(prefers-reduced-motion:reduce) { .bui-drawer,.bui-drawer-backdrop,.bui-context-menu,.bui-context-item,.bui-sidebar,.bui-sidebar-button { transition:none; } }\n@media(forced-colors:active) { .bui-sidebar,.bui-drawer { border:1px solid CanvasText; } .bui-sidebar-button[data-active],.bui-context-item[data-highlighted] { outline:2px solid Highlight; } }\n\n.bui-table th {position:relative}\n.bui-column-resize {position:absolute;inset-block:8px;inset-inline-end:0;width:10px;cursor:col-resize;touch-action:none;border-inline-end:2px solid transparent;z-index:2}\n.bui-column-resize:hover,.bui-column-resize:focus-visible {border-color:var(--bui-focus);background:var(--bui-raised)}\n.bui-table td {overflow-wrap:anywhere}\n\n.bui-table th {text-align:start}\n.bui-table [data-pinned] {position:sticky}\n.bui-table-scroll {container-type:inline-size;container-name:bld8-table}\n.bui-table-scroll-hint {display:none;margin:.5rem 0}\n@container bld8-table (max-width:600px) {.bui-table [data-pinned] {position:static}}\n@media(max-width:760px){.bui-table-scroll-hint {display:block}}\n",
          "target": "@ui/bld8/styles.css",
          "type": "registry:file"
        },
        {
          "path": "registry/bld8/tokens.css",
          "content": ":root, [data-ui-theme=\"light\"] {\n  color-scheme: light;\n  --bui-canvas: #f5f5f5; --bui-bg: #ffffff; --bui-surface: #f8f8f8; --bui-raised: #eeeeee;\n  --bui-ink: #171717; --bui-muted: #626262; --bui-line: #dedede;\n  --bui-primary: #171717; --bui-primary-hover: #333333; --bui-primary-ink: #ffffff;\n  --bui-accent: #ffe24a; --bui-accent-hover: #f2d32e; --bui-accent-ink: #171717; --bui-accent-border: #857021;\n  --bui-focus: #171717; --bui-soft: #fff7d1;\n  --bui-danger: #b42318; --bui-danger-bg: #fff1ef;\n  --bui-success: #23613b; --bui-success-bg: #edf7ef;\n  --bui-warning: #805500; --bui-warning-bg: #fff7df;\n  --bui-radius: 4px; --bui-panel-radius: 12px;\n  --bui-shadow: 0 3px 7px #19191906, 0 14px 40px #1919190d;\n  --bui-ease: cubic-bezier(.16,1,.3,1); --bui-ease-exit: cubic-bezier(.4,0,1,1);\n  --bui-duration-fast: 160ms; --bui-duration: 280ms; --bui-duration-slow: 440ms;\n  --bui-font: var(--font-body, Arial, sans-serif); --bui-heading: var(--font-display, Arial, sans-serif);\n}\n[data-ui-theme=\"dark\"] {\n  color-scheme: dark;\n  --bui-canvas: #141414; --bui-bg: #202020; --bui-surface: #262626; --bui-raised: #303030;\n  --bui-ink: #f7f7f7; --bui-muted: #b4b4b4; --bui-line: #404040;\n  --bui-primary: #f5f5f5; --bui-primary-hover: #dedede; --bui-primary-ink: #171717;\n  --bui-focus: #ffe24a; --bui-soft: #39321a;\n  --bui-danger: #ffb4a9; --bui-danger-bg: #3c2321;\n  --bui-success: #a5deb7; --bui-success-bg: #1e3527;\n  --bui-warning: #ebce8a; --bui-warning-bg: #3a311f;\n  --bui-shadow: 0 3px 7px #0002, 0 14px 40px #0003;\n}",
          "target": "@ui/bld8/tokens.css",
          "type": "registry:file"
        },
        {
          "path": "registry/bld8/tailwind.css",
          "content": "/*! tailwindcss v4.3.0 | MIT License | https://tailwindcss.com */\n@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-border-style:solid;--tw-leading:initial;--tw-font-weight:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000}}}@layer theme{:root,:host{--bui-spacing:.25rem;--bui-text-xs:.75rem;--bui-text-xs--line-height:calc(1 / .75);--bui-text-sm:.875rem;--bui-text-sm--line-height:calc(1.25 / .875);--bui-text-lg:1.125rem;--bui-text-lg--line-height:calc(1.75 / 1.125);--bui-font-weight-semibold:600;--bui-leading-relaxed:1.625}}@layer base,components;@layer utilities{.bui\\:pointer-events-auto{pointer-events:auto}.bui\\:pointer-events-none{pointer-events:none}.bui\\:fixed{position:fixed}.bui\\:relative{position:relative}.bui\\:inset-0{inset:calc(var(--bui-spacing) * 0)}.bui\\:z-80{z-index:80}.bui\\:z-90{z-index:90}.bui\\:z-\\[81\\]{z-index:81}.bui\\:m-0{margin:calc(var(--bui-spacing) * 0)}.bui\\:mx-auto{margin-inline:auto}.bui\\:my-1{margin-block:calc(var(--bui-spacing) * 1)}.bui\\:my-3{margin-block:calc(var(--bui-spacing) * 3)}.bui\\:mt-2{margin-top:calc(var(--bui-spacing) * 2)}.bui\\:mt-auto{margin-top:auto}.bui\\:mb-0{margin-bottom:calc(var(--bui-spacing) * 0)}.bui\\:ml-auto{margin-left:auto}.bui\\:flex{display:flex}.bui\\:grid{display:grid}.bui\\:size-4{width:calc(var(--bui-spacing) * 4);height:calc(var(--bui-spacing) * 4)}.bui\\:h-1{height:calc(var(--bui-spacing) * 1)}.bui\\:h-px{height:1px}.bui\\:min-h-0{min-height:calc(var(--bui-spacing) * 0)}.bui\\:min-h-10{min-height:calc(var(--bui-spacing) * 10)}.bui\\:min-h-11{min-height:calc(var(--bui-spacing) * 11)}.bui\\:min-h-full{min-height:100%}.bui\\:w-10{width:calc(var(--bui-spacing) * 10)}.bui\\:w-full{width:100%}.bui\\:max-w-\\[calc\\(100vw-24px\\)\\]{max-width:calc(100vw - 24px)}.bui\\:min-w-0{min-width:calc(var(--bui-spacing) * 0)}.bui\\:min-w-52{min-width:calc(var(--bui-spacing) * 52)}.bui\\:flex-1{flex:1}.bui\\:shrink-0{flex-shrink:0}.bui\\:cursor-default{cursor:default}.bui\\:cursor-pointer{cursor:pointer}.bui\\:flex-col{flex-direction:column}.bui\\:items-center{align-items:center}.bui\\:items-start{align-items:flex-start}.bui\\:justify-between{justify-content:space-between}.bui\\:gap-1{gap:calc(var(--bui-spacing) * 1)}.bui\\:gap-3{gap:calc(var(--bui-spacing) * 3)}.bui\\:gap-4{gap:calc(var(--bui-spacing) * 4)}.bui\\:gap-5{gap:calc(var(--bui-spacing) * 5)}.bui\\:gap-6{gap:calc(var(--bui-spacing) * 6)}.bui\\:truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.bui\\:overflow-hidden{overflow:hidden}.bui\\:overflow-y-auto{overflow-y:auto}.bui\\:overscroll-contain{overscroll-behavior:contain}.bui\\:rounded-control{border-radius:var(--bui-radius)}.bui\\:rounded-full{border-radius:3.40282e38px}.bui\\:rounded-panel{border-radius:var(--bui-panel-radius)}.bui\\:border-0{border-style:var(--tw-border-style);border-width:0}.bui\\:bg-background{background-color:var(--bui-bg)}.bui\\:bg-border{background-color:var(--bui-line)}.bui\\:bg-transparent{background-color:#0000}.bui\\:p-1\\.5{padding:calc(var(--bui-spacing) * 1.5)}.bui\\:p-3{padding:calc(var(--bui-spacing) * 3)}.bui\\:p-6{padding:calc(var(--bui-spacing) * 6)}.bui\\:px-2{padding-inline:calc(var(--bui-spacing) * 2)}.bui\\:px-3{padding-inline:calc(var(--bui-spacing) * 3)}.bui\\:px-6{padding-inline:calc(var(--bui-spacing) * 6)}.bui\\:py-2{padding-block:calc(var(--bui-spacing) * 2)}.bui\\:py-3{padding-block:calc(var(--bui-spacing) * 3)}.bui\\:pb-2{padding-bottom:calc(var(--bui-spacing) * 2)}.bui\\:pb-6{padding-bottom:calc(var(--bui-spacing) * 6)}.bui\\:text-left{text-align:left}.bui\\:font-body{font-family:var(--bui-font)}.bui\\:text-lg{font-size:var(--bui-text-lg);line-height:var(--tw-leading,var(--bui-text-lg--line-height))}.bui\\:text-sm{font-size:var(--bui-text-sm);line-height:var(--tw-leading,var(--bui-text-sm--line-height))}.bui\\:text-xs{font-size:var(--bui-text-xs);line-height:var(--tw-leading,var(--bui-text-xs--line-height))}.bui\\:leading-relaxed{--tw-leading:var(--bui-leading-relaxed);line-height:var(--bui-leading-relaxed)}.bui\\:font-semibold{--tw-font-weight:var(--bui-font-weight-semibold);font-weight:var(--bui-font-weight-semibold)}.bui\\:text-danger{color:var(--bui-danger)}.bui\\:text-foreground{color:var(--bui-ink)}.bui\\:text-muted{color:var(--bui-muted)}.bui\\:shadow-panel{--tw-shadow:var(--bui-shadow);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.bui\\:outline-none{--tw-outline-style:none;outline-style:none}.bui\\:select-none{-webkit-user-select:none;user-select:none}.bui\\:disabled\\:cursor-not-allowed:disabled{cursor:not-allowed}.bui\\:disabled\\:opacity-45:disabled{opacity:.45}.bui\\:data-active\\:bg-accent[data-active]{background-color:var(--bui-accent)}.bui\\:data-active\\:text-accent-foreground[data-active]{color:var(--bui-accent-ink)}.bui\\:data-disabled\\:pointer-events-none[data-disabled]{pointer-events:none}.bui\\:data-disabled\\:opacity-45[data-disabled]{opacity:.45}.bui\\:data-highlighted\\:bg-surface[data-highlighted]{background-color:var(--bui-surface)}}.bui-button{min-height:calc(var(--bui-spacing) * 11);cursor:pointer;justify-content:center;align-items:center;gap:calc(var(--bui-spacing) * 3);border-radius:var(--bui-radius);border-style:var(--tw-border-style);--tw-border-style:solid;padding-inline:calc(var(--bui-spacing) * 4);font-family:var(--bui-font);font-size:var(--bui-text-sm);line-height:var(--tw-leading,var(--bui-text-sm--line-height));--tw-leading:1.5;--tw-font-weight:var(--bui-font-weight-semibold);line-height:1.5;font-weight:var(--bui-font-weight-semibold);white-space:nowrap;border:1px solid #0000;padding-block:.6rem;text-decoration-line:none;display:inline-flex;position:relative}.bui-button--primary{border-color:var(--bui-primary);background-color:var(--bui-primary);color:var(--bui-primary-ink)}.bui-button--accent{border-color:var(--bui-accent);background-color:var(--bui-accent);color:var(--bui-accent-ink)}.bui-button--secondary{border-color:var(--bui-line);background-color:var(--bui-bg);color:var(--bui-ink);--tw-shadow:0 1px 2px var(--tw-shadow-color,#19191905);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.bui-button--ghost{color:var(--bui-ink);background-color:#0000}.bui-button--danger{border-color:var(--bui-danger);background-color:var(--bui-danger-bg);color:var(--bui-danger)}.bui-button--sm{min-height:calc(var(--bui-spacing) * 9);padding-inline:calc(var(--bui-spacing) * 3);padding-block:.35rem;font-size:.8125rem}.bui-button--lg{min-height:calc(var(--bui-spacing) * 12);padding-inline:calc(var(--bui-spacing) * 6)}.bui-input{min-height:calc(var(--bui-spacing) * 11);border-radius:var(--bui-radius);border-style:var(--tw-border-style);--tw-border-style:solid;border-style:solid;border-width:1px;border-color:var(--bui-line);background-color:var(--bui-bg);width:100%;font-family:var(--bui-font);font-size:var(--bui-text-sm);line-height:var(--tw-leading,var(--bui-text-sm--line-height));--tw-leading:1.5;color:var(--bui-ink);padding-block:.65rem;padding-inline:.8rem;line-height:1.5}.bui-input::placeholder{color:var(--bui-muted);opacity:.85}.bui-input:focus{border-color:var(--bui-focus)}.bui-input[aria-invalid=true]{border-color:var(--bui-danger)}.bui-textarea{min-height:calc(var(--bui-spacing) * 28);resize:vertical}@property --tw-border-style{syntax:\"*\";inherits:false;initial-value:solid}@property --tw-leading{syntax:\"*\";inherits:false}@property --tw-font-weight{syntax:\"*\";inherits:false}@property --tw-shadow{syntax:\"*\";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:\"*\";inherits:false}@property --tw-shadow-alpha{syntax:\"<percentage>\";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:\"*\";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:\"*\";inherits:false}@property --tw-inset-shadow-alpha{syntax:\"<percentage>\";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:\"*\";inherits:false}@property --tw-ring-shadow{syntax:\"*\";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:\"*\";inherits:false}@property --tw-inset-ring-shadow{syntax:\"*\";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:\"*\";inherits:false}@property --tw-ring-offset-width{syntax:\"<length>\";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:\"*\";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:\"*\";inherits:false;initial-value:0 0 #0000}",
          "target": "@ui/bld8/tailwind.css",
          "type": "registry:file"
        },
        {
          "path": "registry/bld8/licenses/LICENSE",
          "content": "MIT License\n\nCopyright (c) 2026 Jaison\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n",
          "target": "@ui/bld8/licenses/LICENSE",
          "type": "registry:file"
        },
        {
          "path": "registry/bld8/licenses/LUCIDE_LICENSE",
          "content": "ISC License\n\nCopyright (c) 2026 Lucide Icons and Contributors\n\nPermission to use, copy, modify, and/or distribute this software for any\npurpose with or without fee is hereby granted, provided that the above\ncopyright notice and this permission notice appear in all copies.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\nWITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\nMERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\nANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\nWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\nACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\nOR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n\n---\n\nThe following Lucide icons are derived from the Feather project:\n\nairplay, alert-circle, alert-octagon, alert-triangle, aperture, arrow-down-circle, arrow-down-left, arrow-down-right, arrow-down, arrow-left-circle, arrow-left, arrow-right-circle, arrow-right, arrow-up-circle, arrow-up-left, arrow-up-right, arrow-up, at-sign, calendar, cast, check, chevron-down, chevron-left, chevron-right, chevron-up, chevrons-down, chevrons-left, chevrons-right, chevrons-up, circle, clipboard, clock, code, columns, command, compass, corner-down-left, corner-down-right, corner-left-down, corner-left-up, corner-right-down, corner-right-up, corner-up-left, corner-up-right, crosshair, database, divide-circle, divide-square, dollar-sign, download, external-link, feather, frown, hash, headphones, help-circle, info, italic, key, layout, life-buoy, link-2, link, loader, lock, log-in, log-out, maximize, meh, minimize, minimize-2, minus-circle, minus-square, minus, monitor, moon, more-horizontal, more-vertical, move, music, navigation-2, navigation, octagon, pause-circle, percent, plus-circle, plus-square, plus, power, radio, rss, search, server, share, shopping-bag, sidebar, smartphone, smile, square, table-2, tablet, target, terminal, trash-2, trash, triangle, tv, type, upload, x-circle, x-octagon, x-square, x, zoom-in, zoom-out\n\nThe MIT License (MIT) (for the icons listed above)\n\nCopyright (c) 2013-present Cole Bemis\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n",
          "target": "@ui/bld8/licenses/LUCIDE_LICENSE",
          "type": "registry:file"
        },
        {
          "path": "registry/bld8/licenses/DAY_PICKER_LICENSE",
          "content": "The MIT License (MIT)\n\nCopyright (c) 2014-2026 Giampaolo Bellavite <io@gpbl.dev> and contributors\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n",
          "target": "@ui/bld8/licenses/DAY_PICKER_LICENSE",
          "type": "registry:file"
        },
        {
          "path": "registry/bld8/licenses/SHADCN_LICENSE",
          "content": "MIT License\n\nCopyright (c) 2023 shadcn\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n",
          "target": "@ui/bld8/licenses/SHADCN_LICENSE",
          "type": "registry:file"
        },
        {
          "path": "registry/bld8/licenses/THIRD_PARTY_NOTICES.md",
          "content": "# Third-party notices\r\n\r\nReact DayPicker 10.0.2 provides calendar selection and keyboard navigation.\r\nSource: https://github.com/gpbl/react-day-picker . Its full MIT notice is included\r\nin `DAY_PICKER_LICENSE`. date-fns and @date-fns/tz are transitive dependencies;\r\ntheir MIT notices accompany their installed npm distributions. BLD8 supplies its\r\nown token-based styling rather than copying another library's styled calendar.\r\n\r\nLucide React 1.55.0 supplies the standard icon family. Source:\r\nhttps://github.com/lucide-icons/lucide . Its ISC licence and the MIT notice for\r\nFeather-derived icons are reproduced in the included `LUCIDE_LICENSE` file.\r\nThe original BLD8 dotted arrow is separate artwork. Named Lucide components are\r\nordinary package dependencies; the icon directory's generated SVG downloads\r\nretain the full upstream licence notices.\r\n\r\nBase UI is used as an installed dependency for accessible interaction primitives. Source: https://github.com/mui/base-ui . Its licence is reproduced below. Base UI remains an installed dependency. Selected shadcn/ui Base UI composition patterns are adapted as described below.\r\n\r\nMIT License\r\n\r\nCopyright (c) 2019 Material-UI SAS\r\n\r\nPermission is hereby granted, free of charge, to any person obtaining a copy\r\nof this software and associated documentation files (the \"Software\"), to deal\r\nin the Software without restriction, including without limitation the rights\r\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\ncopies of the Software, and to permit persons to whom the Software is\r\nfurnished to do so, subject to the following conditions:\r\n\r\nThe above copyright notice and this permission notice shall be included in all\r\ncopies or substantial portions of the Software.\r\n\r\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r\nSOFTWARE.\r\n\r\nSelected composition patterns are adapted from shadcn/ui (MIT, copyright 2023 shadcn). Pinned upstream revision: 30a58d4498f270af1c1e981a7d78a15cf5740841. The full notice is in SHADCN_LICENSE. Drawer, context-menu and sidebar compositions and the button variant pattern retain BLD8 styling and focused APIs. Provenance and source hashes: docs/upstream.json in the repository.\r\n\r\nTailwind CSS 4.3.0 and its CLI are build dependencies (MIT). clsx, class-variance-authority and tailwind-merge are runtime dependencies (MIT). Their notices accompany installed npm distributions. Compiled utilities are included; consuming applications do not need Tailwind.\r\n",
          "target": "@ui/bld8/licenses/THIRD_PARTY_NOTICES.md",
          "type": "registry:file"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "bld8-calendar",
      "type": "registry:ui",
      "title": "BLD8 calendar source",
      "description": "BLD8 calendar source with editable BLD8 source.",
      "author": "Jaison (https://bld8.dev)",
      "dependencies": [
        "@base-ui/react@1.8.0",
        "lucide-react@1.55.0",
        "react-day-picker@10.0.2"
      ],
      "registryDependencies": [
        "https://ui.bld8.dev/r/bld8-styles.json",
        "https://ui.bld8.dev/r/bld8-core.json",
        "https://ui.bld8.dev/r/bld8-state.json"
      ],
      "files": [
        {
          "path": "registry/bld8/calendar.tsx",
          "content": "'use client';\nimport './styles.css';\nimport { useId, useRef, useState } from 'react';\nimport { DayPicker, type DateRange, type DayPickerLocale } from 'react-day-picker';\nimport { Popover } from '@base-ui/react/popover';\nimport { CalendarDays, X } from 'lucide-react';\nimport { Button, Icon, IconButton } from './core';\nimport { useControllableValue } from './state';\nexport type { DateRange, DayPickerLocale } from 'react-day-picker';\n\nexport interface CalendarBaseProps {\n  label?: string;\n  defaultMonth?: Date;\n  minDate?: Date;\n  maxDate?: Date;\n  disabled?: boolean;\n  locale?: DayPickerLocale;\n  weekStartsOn?: 0 | 1 | 2 | 3 | 4 | 5 | 6;\n  autoFocus?: boolean;\n}\nexport type CalendarProps = CalendarBaseProps & (\n  { mode?: 'single'; value?: Date; onValueChange?: (value: Date | undefined) => void } |\n  { mode: 'range'; value?: DateRange; onValueChange?: (value: DateRange | undefined) => void }\n);\nconst calendarClasses = {\n  root:'bui-calendar', months:'bui-calendar-months', month:'bui-calendar-month', month_caption:'bui-calendar-caption',\n  caption_label:'bui-calendar-label', nav:'bui-calendar-nav', button_previous:'bui-calendar-nav-button', button_next:'bui-calendar-nav-button',\n  chevron:'bui-calendar-chevron', month_grid:'bui-calendar-grid', weekday:'bui-calendar-weekday', day:'bui-calendar-day', day_button:'bui-calendar-day-button',\n  today:'bui-calendar-today', selected:'bui-calendar-selected', outside:'bui-calendar-outside', disabled:'bui-calendar-disabled',\n  range_start:'bui-calendar-range-start', range_end:'bui-calendar-range-end', range_middle:'bui-calendar-range-middle', hidden:'bui-calendar-hidden',\n};\nexport function Calendar({ label = 'Choose a date', defaultMonth, minDate, maxDate, disabled, locale, weekStartsOn = 1, autoFocus, ...selection }: CalendarProps) {\n  const common = { classNames:calendarClasses, 'aria-label':label, defaultMonth:defaultMonth ?? (selection.mode === 'range' ? selection.value?.from : selection.value),\n    startMonth:minDate, endMonth:maxDate, locale, weekStartsOn, autoFocus, showOutsideDays:true, fixedWeeks:true,\n    disabled:disabled ? true : [ ...(minDate ? [{before:minDate}] : []), ...(maxDate ? [{after:maxDate}] : []) ] };\n  return selection.mode === 'range'\n    ? <DayPicker {...common} mode=\"range\" selected={selection.value} onSelect={selection.onValueChange} excludeDisabled />\n    : <DayPicker {...common} mode=\"single\" selected={selection.value} onSelect={selection.onValueChange} />;\n}\n/** Date-only form values use local calendar fields, never UTC conversion. */\nexport function formatDateValue(value?: Date) {\n  return value && !Number.isNaN(value.getTime()) ? [value.getFullYear(), String(value.getMonth() + 1).padStart(2, '0'), String(value.getDate()).padStart(2, '0')].join('-') : '';\n}\nexport interface DatePickerProps extends Omit<CalendarBaseProps, 'label' | 'autoFocus'> {\n  label: string;\n  value?: Date | null;\n  defaultValue?: Date | null;\n  onValueChange?: (value: Date | null) => void;\n  name?: string;\n  placeholder?: string;\n  hint?: string;\n  error?: string;\n  formatLocale?: string;\n}\nexport function DatePicker({ label, value, defaultValue = null, onValueChange, name, placeholder = 'Choose a date', hint, error, formatLocale = 'en-AU', ...calendar }: DatePickerProps) {\n  const id = useId(); const [open, setOpen] = useState(false);\n  const trigger=useRef<HTMLButtonElement>(null);\n  const [selected, setSelected] = useControllableValue(value, defaultValue, onValueChange);\n  const display = selected ? new Intl.DateTimeFormat(formatLocale, {day:'numeric', month:'short', year:'numeric'}).format(selected) : placeholder;\n  return <div className=\"bui-field\">\n    <label htmlFor={id} className=\"bui-label\">{label}</label>\n    <div className=\"bui-date-field\">\n      <Popover.Root open={open} onOpenChange={setOpen}><Popover.Trigger ref={trigger} id={id} disabled={calendar.disabled} aria-invalid={!!error || undefined} aria-describedby={hint || error ? id + '-description' : undefined} className=\"bui-input bui-date-trigger\">\n        <Icon icon={CalendarDays} /><span data-placeholder={!selected || undefined}>{display}</span><Icon name=\"chevron\" />\n      </Popover.Trigger><Popover.Portal><Popover.Positioner className=\"bui-positioner\" sideOffset={8}><Popover.Popup className=\"bui-popup bui-calendar-popup\">\n        <Popover.Title className=\"bui-sr-only\">{label}</Popover.Title>\n        <Calendar {...calendar} label={label} value={selected ?? undefined} autoFocus onValueChange={date => {setSelected(date ?? null);setOpen(false);}} />\n      </Popover.Popup></Popover.Positioner></Popover.Portal></Popover.Root>\n      {selected && <IconButton icon={X} label={'Clear ' + label.toLowerCase()} size=\"sm\" variant=\"ghost\" disabled={calendar.disabled} onClick={() => {setSelected(null);trigger.current?.focus();}} />}\n    </div>\n    {name && <input type=\"hidden\" name={name} value={formatDateValue(selected ?? undefined)} />}\n    {(hint || error) && <p id={id + '-description'} className={error ? 'bui-error' : 'bui-hint'} role={error ? 'alert' : undefined}>{error || hint}</p>}\n  </div>;\n}\nexport interface DateRangePickerProps extends Omit<DatePickerProps, 'value' | 'defaultValue' | 'onValueChange'> {\n  value?: DateRange | null;\n  defaultValue?: DateRange | null;\n  onValueChange?: (value: DateRange | null) => void;\n}\nexport function DateRangePicker({ label, value, defaultValue = null, onValueChange, name, placeholder = 'Choose a date range', hint, error, formatLocale = 'en-AU', ...calendar }: DateRangePickerProps) {\n  const id = useId(); const [open, setOpen] = useState(false);\n  const trigger=useRef<HTMLButtonElement>(null);\n  const [selected, setSelected] = useControllableValue(value, defaultValue, onValueChange);\n  const format = (date:Date) => new Intl.DateTimeFormat(formatLocale, {day:'numeric',month:'short',year:'numeric'}).format(date);\n  const display = selected?.from ? format(selected.from) + (selected.to ? ' – ' + format(selected.to) : ' – Choose end date') : placeholder;\n  return <div className=\"bui-field\"><label htmlFor={id} className=\"bui-label\">{label}</label><div className=\"bui-date-field\">\n    <Popover.Root open={open} onOpenChange={setOpen}><Popover.Trigger ref={trigger} id={id} disabled={calendar.disabled} aria-invalid={!!error || undefined} aria-describedby={hint || error ? id + '-description' : undefined} className=\"bui-input bui-date-trigger\">\n      <Icon icon={CalendarDays} /><span data-placeholder={!selected?.from || undefined}>{display}</span><Icon name=\"chevron\" />\n    </Popover.Trigger><Popover.Portal><Popover.Positioner className=\"bui-positioner\" sideOffset={8}><Popover.Popup className=\"bui-popup bui-calendar-popup\">\n      <Popover.Title className=\"bui-sr-only\">{label}</Popover.Title>\n      <Calendar {...calendar} label={label} mode=\"range\" value={selected ?? undefined} autoFocus onValueChange={range => setSelected(range ?? null)} />\n      <div className=\"bui-calendar-footer\"><span className=\"bui-hint\" aria-live=\"polite\">{selected?.from && selected.to ? 'Range selected' : 'Choose start and end dates'}</span><Button size=\"sm\" disabled={!selected?.from || !selected.to} onClick={() => setOpen(false)}>Done</Button></div>\n    </Popover.Popup></Popover.Positioner></Popover.Portal></Popover.Root>\n    {selected && <IconButton icon={X} label={'Clear ' + label.toLowerCase()} size=\"sm\" variant=\"ghost\" disabled={calendar.disabled} onClick={() => {setSelected(null);trigger.current?.focus();}} />}\n  </div>\n    {name && <><input type=\"hidden\" name={name + '.from'} value={formatDateValue(selected?.from)} /><input type=\"hidden\" name={name + '.to'} value={formatDateValue(selected?.to)} /></>}\n    {(hint || error) && <p id={id + '-description'} className={error ? 'bui-error' : 'bui-hint'} role={error ? 'alert' : undefined}>{error || hint}</p>}\n  </div>;\n}\n",
          "target": "@ui/bld8/calendar.tsx",
          "type": "registry:ui"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "bld8-command",
      "type": "registry:ui",
      "title": "BLD8 command source",
      "description": "BLD8 command source with editable BLD8 source.",
      "author": "Jaison (https://bld8.dev)",
      "dependencies": [
        "@base-ui/react@1.8.0",
        "lucide-react@1.55.0"
      ],
      "registryDependencies": [
        "https://ui.bld8.dev/r/bld8-styles.json",
        "https://ui.bld8.dev/r/bld8-core.json",
        "https://ui.bld8.dev/r/bld8-overlays.json",
        "https://ui.bld8.dev/r/bld8-state.json"
      ],
      "files": [
        {
          "path": "registry/bld8/command.tsx",
          "content": "'use client';\nimport './styles.css';\nimport { useEffect, useRef, type ReactElement } from 'react';\nimport { Combobox } from '@base-ui/react/combobox';\nimport { Search, type LucideIcon } from 'lucide-react';\nimport { Icon } from './core';\nimport { Dialog } from './overlays';\nimport { useControllableValue } from './state';\n\nexport interface CommandItem {\n  id: string;\n  label: string;\n  description?: string;\n  category?: string;\n  keywords?: string[];\n  icon?: LucideIcon;\n  disabled?: boolean;\n  onSelect: () => void;\n}\nexport interface CommandPaletteProps {\n  items: CommandItem[];\n  trigger?: ReactElement;\n  title?: string;\n  placeholder?: string;\n  open?: boolean;\n  defaultOpen?: boolean;\n  onOpenChange?: (open: boolean) => void;\n  /** Register Ctrl/Command+K once per application. Disabled by default. */\n  shortcut?: boolean;\n}\nexport function CommandPalette({ items, trigger, title = 'Quick actions', placeholder = 'Search pages and actions…', open, defaultOpen = false, onOpenChange, shortcut = false }: CommandPaletteProps) {\n  const [isOpen, setOpen] = useControllableValue(open, defaultOpen, onOpenChange);\n  const input=useRef<HTMLInputElement>(null);\n  useEffect(() => {\n    if (!shortcut) return;\n    const handle = (event: KeyboardEvent) => {\n      if (event.key.toLowerCase() === 'k' && (event.metaKey || event.ctrlKey) && !event.altKey && !event.repeat && !event.isComposing) {\n        event.preventDefault(); setOpen(!isOpen);\n      }\n    };\n    document.addEventListener('keydown', handle);\n    return () => document.removeEventListener('keydown', handle);\n  }, [shortcut, isOpen, setOpen]);\n  return <Combobox.Root<CommandItem> inline open={isOpen} onOpenChange={setOpen} items={items} value={null} autoHighlight\n    itemToStringLabel={item => item.label} isItemEqualToValue={(a, b) => a.id === b.id}\n    filter={(item, query) => [item.label, item.description, item.category, ...(item.keywords ?? [])].join(' ').toLocaleLowerCase().includes(query.trim().toLocaleLowerCase())}\n    onValueChange={item => { if (item && !item.disabled) { setOpen(false); item.onSelect(); } }}>\n    <Dialog initialFocus={input} trigger={trigger} title={title} description=\"Use arrow keys to navigate, Enter to choose and Escape to close.\" open={isOpen} onOpenChange={setOpen}>\n      <div className=\"bui-command\">\n        <div className=\"bui-command-search\"><Icon icon={Search} /><Combobox.Input ref={input} aria-label={title + ' search'} placeholder={placeholder} className=\"bui-input\" /></div>\n        <Combobox.Empty className=\"bui-combo-empty\">No matching actions. Try another search.</Combobox.Empty>\n        <Combobox.List className=\"bui-command-list\">{(item: CommandItem) => <Combobox.Item key={item.id} value={item} disabled={item.disabled} className=\"bui-option bui-command-item\">\n          {item.icon && <span className=\"bui-command-symbol\"><Icon icon={item.icon} /></span>}\n          <span><strong>{item.label}</strong>{item.description && <small>{item.description}</small>}</span>\n          {item.category && <span className=\"bui-command-category\">{item.category}</span>}\n        </Combobox.Item>}</Combobox.List>\n        <div className=\"bui-command-footer\"><span><kbd>↑</kbd><kbd>↓</kbd> Navigate</span><span><kbd>↵</kbd> Open</span></div>\n      </div>\n    </Dialog>\n  </Combobox.Root>;\n}\n",
          "target": "@ui/bld8/command.tsx",
          "type": "registry:ui"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "bld8-context-menu",
      "type": "registry:ui",
      "title": "BLD8 context-menu source",
      "description": "BLD8 context-menu source with editable BLD8 source.",
      "author": "Jaison (https://bld8.dev)",
      "dependencies": [
        "@base-ui/react@1.8.0",
        "lucide-react@1.55.0"
      ],
      "registryDependencies": [
        "https://ui.bld8.dev/r/bld8-styles.json",
        "https://ui.bld8.dev/r/bld8-utils.json"
      ],
      "files": [
        {
          "path": "registry/bld8/context-menu.tsx",
          "content": "'use client';\nimport './styles.css';\r\n// Adapted from shadcn/ui's Base UI composition. See SHADCN_LICENSE and docs/upstream.json.\r\nimport { ContextMenu as Primitive } from '@base-ui/react/context-menu';\r\nimport { Check, ChevronRight, Circle } from 'lucide-react';\r\nimport { cn } from './utils';\r\n\r\nexport const ContextMenu = Primitive.Root;\r\nexport const ContextMenuGroup = Primitive.Group;\r\nexport const ContextMenuRadioGroup = Primitive.RadioGroup;\r\nexport const ContextMenuSub = Primitive.SubmenuRoot;\r\nexport function ContextMenuTrigger(props:Primitive.Trigger.Props) {\r\n  return <Primitive.Trigger tabIndex={0} {...props} />;\r\n}\r\ntype Styled<P> = Omit<P,'className'> & {className?:string};\r\nexport function ContextMenuContent({className,side='right',align='start',sideOffset=4,...props}:Styled<Primitive.Popup.Props> & Pick<Primitive.Positioner.Props,'side'|'align'|'sideOffset'>) {\r\n  return <Primitive.Portal><Primitive.Positioner className=\"bui:fixed bui:z-90\" sideOffset={sideOffset} side={side} align={align}>\r\n    <Primitive.Popup {...props} className={cn('bui-context-menu bui:min-w-52 bui:max-w-[calc(100vw-24px)] bui:rounded-panel bui:bg-background bui:p-1.5 bui:font-body bui:text-sm bui:text-foreground bui:shadow-panel',className)} />\r\n  </Primitive.Positioner></Primitive.Portal>;\r\n}\r\nconst itemClass='bui-context-item bui:relative bui:flex bui:min-h-10 bui:items-center bui:gap-3 bui:rounded-control bui:px-3 bui:py-2 bui:cursor-default bui:outline-none bui:select-none bui:data-highlighted:bg-surface bui:data-disabled:opacity-45 bui:data-disabled:pointer-events-none';\r\nexport function ContextMenuItem({className,destructive=false,...props}:Styled<Primitive.Item.Props>&{destructive?:boolean}) {\r\n  return <Primitive.Item {...props} className={cn(itemClass,destructive && 'bui:text-danger',className)} />;\r\n}\r\nexport function ContextMenuCheckboxItem({className,children,...props}:Styled<Primitive.CheckboxItem.Props>) {\r\n  return <Primitive.CheckboxItem {...props} className={cn(itemClass,className)}>\r\n    <span className=\"bui:flex bui:size-4 bui:shrink-0\"><Primitive.CheckboxItemIndicator><Check size={16} strokeWidth={1.75} /></Primitive.CheckboxItemIndicator></span>{children}\r\n  </Primitive.CheckboxItem>;\r\n}\r\nexport function ContextMenuRadioItem({className,children,...props}:Styled<Primitive.RadioItem.Props>) {\r\n  return <Primitive.RadioItem {...props} className={cn(itemClass,className)}>\r\n    <span className=\"bui:flex bui:size-4 bui:shrink-0\"><Primitive.RadioItemIndicator><Circle size={12} fill=\"currentColor\" /></Primitive.RadioItemIndicator></span>{children}\r\n  </Primitive.RadioItem>;\r\n}\r\nexport function ContextMenuSubTrigger({className,children,...props}:Styled<Primitive.SubmenuTrigger.Props>) {\r\n  return <Primitive.SubmenuTrigger {...props} className={cn(itemClass,className)}>{children}<ChevronRight size={16} strokeWidth={1.75} className=\"bui:ml-auto\" /></Primitive.SubmenuTrigger>;\r\n}\r\nexport function ContextMenuSeparator({className,...props}:Styled<Primitive.Separator.Props>) {\r\n  return <Primitive.Separator {...props} className={cn('bui:my-1 bui:h-px bui:border-0 bui:bg-border',className)} />;\r\n}\r\nexport function ContextMenuLabel({className,...props}:Styled<Primitive.GroupLabel.Props>) {\r\n  return <Primitive.GroupLabel {...props} className={cn('bui:px-3 bui:py-2 bui:text-xs bui:text-muted',className)} />;\r\n}\r\n",
          "target": "@ui/bld8/context-menu.tsx",
          "type": "registry:ui"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "bld8-controls",
      "type": "registry:ui",
      "title": "BLD8 controls source",
      "description": "BLD8 controls source with editable BLD8 source.",
      "author": "Jaison (https://bld8.dev)",
      "dependencies": [
        "@base-ui/react@1.8.0"
      ],
      "registryDependencies": [
        "https://ui.bld8.dev/r/bld8-styles.json",
        "https://ui.bld8.dev/r/bld8-core.json",
        "https://ui.bld8.dev/r/bld8-state.json"
      ],
      "files": [
        {
          "path": "registry/bld8/controls.tsx",
          "content": "'use client';\nimport './styles.css';\nimport { useId, useRef, type ReactNode } from 'react';\nimport { Select as PrimitiveSelect } from '@base-ui/react/select';\nimport { Combobox as PrimitiveCombobox } from '@base-ui/react/combobox';\nimport { Tabs as PrimitiveTabs } from '@base-ui/react/tabs';\nimport { Accordion as PrimitiveAccordion } from '@base-ui/react/accordion';\nimport { Icon, type Option } from './core';\nimport { useControllableValue } from './state';\n\nexport interface SelectProps { label: string; options: Option[]; value?: string | null; defaultValue?: string; onValueChange?: (value: string | null) => void; placeholder?: string; name?: string; disabled?: boolean; required?: boolean; clearable?: boolean }\nexport function Select({ label, options, placeholder = 'Select an option', value, defaultValue, onValueChange, clearable, ...props }: SelectProps) {\n  const id = useId();\n  const trigger=useRef<HTMLButtonElement>(null);\n  const [selected, setSelected] = useControllableValue<string | null>(value, defaultValue ?? null, onValueChange);\n  return <div className=\"bui-field\"><label className=\"bui-label\" htmlFor={id}>{label}</label><div className=\"bui-date-field\"><PrimitiveSelect.Root items={options} value={selected} onValueChange={setSelected} {...props}><PrimitiveSelect.Trigger ref={trigger} id={id} className=\"bui-input bui-select-trigger\"><PrimitiveSelect.Value placeholder={placeholder} /><PrimitiveSelect.Icon><Icon name=\"chevron\" /></PrimitiveSelect.Icon></PrimitiveSelect.Trigger><PrimitiveSelect.Portal><PrimitiveSelect.Positioner sideOffset={6} alignItemWithTrigger={false} className=\"bui-positioner\"><PrimitiveSelect.Popup className=\"bui-popup bui-select-popup\"><PrimitiveSelect.List>{options.map(option => <PrimitiveSelect.Item key={option.value} value={option.value} disabled={option.disabled} className=\"bui-option\"><PrimitiveSelect.ItemText>{option.label}</PrimitiveSelect.ItemText><PrimitiveSelect.ItemIndicator><Icon name=\"check\" /></PrimitiveSelect.ItemIndicator></PrimitiveSelect.Item>)}</PrimitiveSelect.List></PrimitiveSelect.Popup></PrimitiveSelect.Positioner></PrimitiveSelect.Portal></PrimitiveSelect.Root>{clearable && selected !== null && <button type=\"button\" className=\"bui-select-clear\" disabled={props.disabled} aria-label={'Clear ' + label.toLowerCase()} onClick={() => {setSelected(null);trigger.current?.focus();}}><Icon name=\"close\" /></button>}</div></div>;\n}\nexport interface ComboboxProps { label: string; items: string[]; value?: string | null; defaultValue?: string; onValueChange?: (value: string | null) => void; placeholder?: string; name?: string; disabled?: boolean; required?: boolean; clearable?: boolean }\nexport function Combobox({ label, placeholder = 'Search options…', clearable, ...props }: ComboboxProps) {\n  const id = useId();\n  return <div className=\"bui-field\"><label className=\"bui-label\" htmlFor={id}>{label}</label><PrimitiveCombobox.Root {...props}><PrimitiveCombobox.InputGroup className=\"bui-combobox-input\"><PrimitiveCombobox.Input id={id} placeholder={placeholder} className=\"bui-input\" />{clearable && <PrimitiveCombobox.Clear aria-label={'Clear ' + label.toLowerCase()} className=\"bui-combobox-clear\"><Icon name=\"close\" /></PrimitiveCombobox.Clear>}<PrimitiveCombobox.Trigger aria-label={'Show ' + label.toLowerCase() + ' options'} className=\"bui-combobox-trigger\"><Icon name=\"chevron\" /></PrimitiveCombobox.Trigger></PrimitiveCombobox.InputGroup><PrimitiveCombobox.Portal><PrimitiveCombobox.Positioner sideOffset={6} className=\"bui-positioner\"><PrimitiveCombobox.Popup className=\"bui-popup bui-select-popup\"><PrimitiveCombobox.Empty className=\"bui-combo-empty\">No matching options.</PrimitiveCombobox.Empty><PrimitiveCombobox.List>{(item: string) => <PrimitiveCombobox.Item key={item} value={item} className=\"bui-option\">{item}<PrimitiveCombobox.ItemIndicator><Icon name=\"check\" /></PrimitiveCombobox.ItemIndicator></PrimitiveCombobox.Item>}</PrimitiveCombobox.List></PrimitiveCombobox.Popup></PrimitiveCombobox.Positioner></PrimitiveCombobox.Portal></PrimitiveCombobox.Root></div>;\n}\nexport function Tabs({ label, items, value, defaultValue, onValueChange }: { label: string; items: { value: string; label: string; content: ReactNode; disabled?: boolean }[]; value?: string; defaultValue?: string; onValueChange?: (value: string) => void }) {\n  return <PrimitiveTabs.Root className=\"bui-tabs\" value={value} defaultValue={defaultValue ?? items[0]?.value} onValueChange={next => { if (typeof next === 'string') onValueChange?.(next); }}><PrimitiveTabs.List className=\"bui-tab-list\" aria-label={label}>{items.map(item => <PrimitiveTabs.Tab key={item.value} value={item.value} disabled={item.disabled} className=\"bui-tab\">{item.label}</PrimitiveTabs.Tab>)}<PrimitiveTabs.Indicator className=\"bui-tab-indicator\" /></PrimitiveTabs.List>{items.map(item => <PrimitiveTabs.Panel key={item.value} value={item.value} className=\"bui-tab-panel\">{item.content}</PrimitiveTabs.Panel>)}</PrimitiveTabs.Root>;\n}\nexport function Accordion({ items, multiple = false, defaultValue, value, onValueChange }: { items: { value: string; title: string; content: ReactNode; disabled?: boolean }[]; multiple?: boolean; defaultValue?: string[]; value?: string[]; onValueChange?: (value: string[]) => void }) {\n  return <PrimitiveAccordion.Root className=\"bui-accordion\" multiple={multiple} defaultValue={defaultValue} value={value} onValueChange={onValueChange}>{items.map(item => <PrimitiveAccordion.Item value={item.value} key={item.value} disabled={item.disabled} className=\"bui-accordion-item\"><PrimitiveAccordion.Header><PrimitiveAccordion.Trigger className=\"bui-accordion-trigger\">{item.title}<Icon name=\"plus\" /></PrimitiveAccordion.Trigger></PrimitiveAccordion.Header><PrimitiveAccordion.Panel className=\"bui-accordion-panel\"><div>{item.content}</div></PrimitiveAccordion.Panel></PrimitiveAccordion.Item>)}</PrimitiveAccordion.Root>;\n}\n",
          "target": "@ui/bld8/controls.tsx",
          "type": "registry:ui"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "bld8-core",
      "type": "registry:ui",
      "title": "BLD8 core source",
      "description": "BLD8 core source with editable BLD8 source.",
      "author": "Jaison (https://bld8.dev)",
      "dependencies": [
        "lucide-react@1.55.0"
      ],
      "registryDependencies": [
        "https://ui.bld8.dev/r/bld8-styles.json",
        "https://ui.bld8.dev/r/bld8-icons.json",
        "https://ui.bld8.dev/r/bld8-utils.json",
        "https://ui.bld8.dev/r/bld8-variants.json"
      ],
      "files": [
        {
          "path": "registry/bld8/core.tsx",
          "content": "'use client';\nimport './styles.css';\nimport { createContext, useContext, useId, useState, type ComponentProps, type CSSProperties, type ReactNode } from 'react';\nimport type { LucideIcon } from 'lucide-react';\nimport { Icon } from './icons';\nimport { cn } from './utils';\nimport { buttonVariants } from './variants';\nexport { Icon, type IconProps, type IconName } from './icons';\n\nexport function cx(...values: (string | false | undefined)[]) { return values.filter(Boolean).join(' '); }\nexport type ButtonProps = ComponentProps<'button'> & { variant?: 'primary' | 'accent' | 'secondary' | 'ghost' | 'danger'; size?: 'sm' | 'md' | 'lg'; loading?: boolean; leadingIcon?:LucideIcon; trailingIcon?:LucideIcon };\nexport function Button({ variant = 'primary', size = 'md', loading, disabled, className, children, type = 'button', leadingIcon, trailingIcon, ...props }: ButtonProps) {\n  return <button {...props} type={type} disabled={disabled || loading} aria-busy={loading || undefined} className={cn(buttonVariants({variant,size}),className)}><span className=\"bui-button-content\">{leadingIcon && <Icon icon={leadingIcon} size={size === 'sm' ? 16 : 18} />}{children}{trailingIcon && <Icon icon={trailingIcon} size={size === 'sm' ? 16 : 18} />}</span>{loading && <span className=\"bui-button-spinner\"><Spinner /></span>}</button>;\n}\nexport function IconButton({ label, icon, children, ...props }: ButtonProps & { label: string; icon?:LucideIcon }) { return <Button {...props} aria-label={label} className={cx('bui-icon-button', props.className)}>{children ?? (icon && <Icon icon={icon} />)}</Button>; }\nconst FieldContext = createContext<{ id: string; description?: string; invalid: boolean; required?: boolean } | null>(null);\nexport function Field({ label, hint, error, id: suppliedId, children, required }: { label: string; hint?: string; error?: string; id?: string; children: ReactNode; required?: boolean }) {\n  const generated = useId(); const id = suppliedId || generated;\n  const description = [hint && id + '-hint', error && id + '-error'].filter(Boolean).join(' ') || undefined;\n  return <FieldContext.Provider value={{ id, description, invalid: !!error, required }}><div className=\"bui-field\"><label className=\"bui-label\" htmlFor={id}>{label}{required && <span aria-hidden=\"true\"> *</span>}</label>{children}{hint && <p id={id + '-hint'} className=\"bui-hint\">{hint}</p>}{error && <p id={id + '-error'} className=\"bui-error\" role=\"alert\">{error}</p>}</div></FieldContext.Provider>;\n}\nexport function Input({ className, density = 'comfortable', ...props }: ComponentProps<'input'> & { density?: 'comfortable' | 'compact' }) {\n  const field = useContext(FieldContext);\n  return <input id={field?.id} aria-describedby={field?.description} aria-invalid={field?.invalid || undefined} required={field?.required} {...props} data-density={density} className={cx('bui-input', className)} />;\n}\nexport function Textarea({ className, ...props }: ComponentProps<'textarea'>) {\n  const field = useContext(FieldContext);\n  return <textarea id={field?.id} aria-describedby={field?.description} aria-invalid={field?.invalid || undefined} required={field?.required} rows={4} {...props} className={cx('bui-input', 'bui-textarea', className)} />;\n}\nexport function InputGroup({leading,trailing,className,children,...props}:ComponentProps<'div'> & {leading?:ReactNode;trailing?:ReactNode}) {\n  const field=useContext(FieldContext);\n  return <div {...props} data-invalid={field?.invalid || undefined} className={cx('bui-input-group',className)}>{leading && <span className=\"bui-input-adornment\">{leading}</span>}{children}{trailing && <span className=\"bui-input-adornment\">{trailing}</span>}</div>;\n}\nexport function Checkbox({ label, description, className, ...props }: Omit<ComponentProps<'input'>, 'type'> & { label: string; description?: string }) {\n  const hintId = useId();\n  return <label className={cx('bui-choice', className)}><input {...props} type=\"checkbox\" className=\"bui-checkbox\" aria-describedby={description ? hintId : props['aria-describedby']} /><span>{label}{description && <small id={hintId}>{description}</small>}</span></label>;\n}\nexport function Switch({ label, description, className, ...props }: Omit<ComponentProps<'input'>, 'type' | 'role'> & { label: string; description?: string }) {\n  const hintId = useId();\n  return <label className={cx('bui-choice', 'bui-switch-row', className)}><span>{label}{description && <small id={hintId}>{description}</small>}</span><input {...props} type=\"checkbox\" role=\"switch\" className=\"bui-switch\" aria-describedby={description ? hintId : props['aria-describedby']} /></label>;\n}\nexport interface Option { value: string; label: string; disabled?: boolean }\nexport function RadioGroup({ label, options, name, value, defaultValue, onValueChange, disabled }: { label: string; options: Option[]; name?: string; value?: string; defaultValue?: string; onValueChange?: (value: string) => void; disabled?: boolean }) {\n  const id = useId();\n  return <fieldset className=\"bui-radio-group\" disabled={disabled}><legend className=\"bui-label\">{label}</legend>{options.map(option => <label className=\"bui-choice\" key={option.value}><input type=\"radio\" name={name || id} value={option.value} checked={value === undefined ? undefined : value === option.value} defaultChecked={value === undefined ? defaultValue === option.value : undefined} disabled={option.disabled} onChange={() => onValueChange?.(option.value)} />{option.label}</label>)}</fieldset>;\n}\nexport function Slider({ label, ...props }: Omit<ComponentProps<'input'>, 'type'> & { label: string }) {\n  const id = useId(); const [internal, setInternal] = useState(props.defaultValue ?? 50);\n  return <div className=\"bui-field\"><div className=\"bui-between\"><label className=\"bui-label\" htmlFor={props.id || id}>{label}</label><output htmlFor={props.id || id}>{props.value ?? internal}</output></div><input {...props} id={props.id || id} className={cx('bui-slider', props.className)} type=\"range\" onChange={event => { setInternal(event.target.value); props.onChange?.(event); }} /></div>;\n}\nexport function Badge({ tone = 'neutral', className, ...props }: ComponentProps<'span'> & { tone?: 'neutral' | 'accent' | 'success' | 'warning' | 'danger' }) { return <span {...props} className={cx('bui-badge', 'bui-tone--' + tone, className)} />; }\nexport function Card({ className, ...props }: ComponentProps<'div'>) { return <div {...props} className={cx('bui-card', className)} />; }\nexport function Avatar({ name, src, size = 'md' }: { name: string; src?: string; size?: 'sm' | 'md' | 'lg' }) {\n  const [failed, setFailed] = useState<string | null>(null);\n  return <span className={'bui-avatar bui-avatar--' + size} role=\"img\" aria-label={name}>{src && failed !== src ? <img src={src} alt=\"\" onError={() => setFailed(src)} /> : name.trim().split(/\\s+/).map(part => part[0]).slice(0,2).join('')}</span>;\n}\nexport function Separator({ className, ...props }: ComponentProps<'hr'>) { return <hr {...props} className={cx('bui-separator', className)} />; }\nexport function Spinner({ label }: { label?: string }) { return <span className=\"bui-spinner\" role={label ? 'status' : undefined} aria-label={label} aria-hidden={label ? undefined : true} />; }\nexport function Skeleton({ width = '100%', height = '1rem', className }: { width?: CSSProperties['width']; height?: CSSProperties['height']; className?: string }) { return <span className={cx('bui-skeleton', className)} style={{ width, height }} aria-hidden=\"true\" />; }\nexport function Progress({ label, value, max = 100 }: { label: string; value: number | null; max?: number }) { return <div className=\"bui-field\"><div className=\"bui-between\"><span className=\"bui-label\">{label}</span><span className=\"bui-hint\">{value === null ? 'In progress' : Math.round(value / max * 100) + '%'}</span></div><progress className=\"bui-progress\" aria-label={label} max={max} value={value === null ? undefined : value} /></div>; }\nexport function Alert({ title, children, tone = 'neutral', live = false }: { title: string; children?: ReactNode; tone?: 'neutral' | 'success' | 'warning' | 'danger'; live?: boolean }) { return <div className={'bui-alert bui-tone--' + tone} role={live ? (tone === 'danger' ? 'alert' : 'status') : undefined}><strong>{title}</strong>{children && <div>{children}</div>}</div>; }\nexport function EmptyState({ title, children, action }: { title: string; children?: ReactNode; action?: ReactNode }) { return <div className=\"bui-empty\"><span className=\"bui-empty-mark\" aria-hidden=\"true\"><Icon name=\"plus\" /></span><h3>{title}</h3><p>{children}</p>{action}</div>; }\nexport function Breadcrumb({ items, label = 'Breadcrumb' }: { items: { label: string; href?: string }[]; label?: string }) { return <nav aria-label={label}><ol className=\"bui-breadcrumb\">{items.map((item,index) => <li key={index}>{index > 0 && <span aria-hidden=\"true\">/</span>}{item.href && index < items.length - 1 ? <a href={item.href}>{item.label}</a> : <span aria-current={index === items.length - 1 ? 'page' : undefined}>{item.label}</span>}</li>)}</ol></nav>; }\nexport function Pagination({ page, totalPages, onPageChange, label = 'Pagination' }: { page: number; totalPages: number; onPageChange: (page: number) => void; label?: string }) { return <nav aria-label={label} className=\"bui-pagination\"><Button variant=\"secondary\" size=\"sm\" disabled={page <= 1} onClick={() => onPageChange(page - 1)}>Previous</Button><span aria-live=\"polite\">Page {page} of {Math.max(totalPages,1)}</span><Button variant=\"secondary\" size=\"sm\" disabled={page >= totalPages} onClick={() => onPageChange(page + 1)}>Next</Button></nav>; }\n",
          "target": "@ui/bld8/core.tsx",
          "type": "registry:ui"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "bld8-data-table",
      "type": "registry:ui",
      "title": "BLD8 data-table source",
      "description": "BLD8 data-table source with editable BLD8 source.",
      "author": "Jaison (https://bld8.dev)",
      "dependencies": [
        "lucide-react@1.55.0"
      ],
      "registryDependencies": [
        "https://ui.bld8.dev/r/bld8-styles.json",
        "https://ui.bld8.dev/r/bld8-core.json",
        "https://ui.bld8.dev/r/bld8-overlays.json",
        "https://ui.bld8.dev/r/bld8-state.json"
      ],
      "files": [
        {
          "path": "registry/bld8/data-table.tsx",
          "content": "'use client';\nimport './styles.css';\nimport { useId, useMemo, useRef, useEffect, useState, type CSSProperties, type ReactNode } from 'react';\nimport { ArrowDown, ArrowUp, ArrowUpDown, SlidersHorizontal } from 'lucide-react';\nimport { Alert, Button, Checkbox, EmptyState, Icon, Input, Pagination, Skeleton } from './core';\nimport { Popover } from './overlays';\nimport { useControllableValue } from './state';\n\nexport interface Column<T> {\n  key: string;\n  header: string;\n  cell: (row: T) => ReactNode;\n  sortValue?: (row: T) => string | number;\n  exportValue?: (row: T) => string | number;\n  hideable?: boolean;\n  width?:number; minWidth?:number; pinned?:'start'|'end';\n}\nexport interface TableFilter<T> { key:string; label:string; options:{value:string;label:string}[]; value:(row:T)=>string }\nexport interface TableQuery { search:string; filters:Record<string,string>; sort:{key:string;descending:boolean}|null; page:number; pageSize:number }\nexport const defaultTableQuery:TableQuery={search:'',filters:{},sort:null,page:1,pageSize:5};\nexport interface DataTableProps<T> {\n  caption: string; rows: T[]; columns: Column<T>[]; rowKey: (row: T) => string;\n  searchText?: (row: T) => string; pageSize?: number;\n  filters?: TableFilter<T>[];\n  columnVisibility?: boolean;\n  visibleColumnKeys?: string[];\n  defaultVisibleColumnKeys?: string[];\n  onVisibleColumnKeysChange?: (keys:string[])=>void;\n  selectable?: boolean;\n  rowLabel?: (row:T)=>string;\n  selectedKeys?: string[];\n  defaultSelectedKeys?: string[];\n  onSelectedKeysChange?: (keys:string[])=>void;\n  renderBulkActions?: (selectedRows:T[])=>ReactNode;\n  density?: 'comfortable' | 'compact';\n  loading?: boolean;\n  error?: string;\n  onRetry?: ()=>void;\n  server?:{query:TableQuery; onQueryChange:(query:TableQuery)=>void; totalRows:number};\n  renderSelectedActions?:(keys:string[])=>ReactNode;\n  resizableColumns?:boolean;\n}\n/** Export explicit scalar values. Formula-leading strings are escaped for spreadsheets. */\nexport function createTableCSV<T>(rows:T[], columns:Column<T>[]) {\n  const safe = (value:string|number) => {\n    let text = String(value); if (typeof value === 'string' && /^(?:[\\s\\uFEFF]*[=+@-]|[\\t\\r\\n])/.test(text)) text = \"'\" + text;\n    return '\"' + text.replace(/\"/g,'\"\"') + '\"';\n  };\n  const exportable = columns.filter(column => column.exportValue || column.sortValue);\n  return [exportable.map(column => safe(column.header)).join(','), ...rows.map(row => exportable.map(column => safe((column.exportValue ?? column.sortValue)!(row))).join(','))].join('\\r\\n');\n}\nfunction SelectionCheckbox({label, checked, mixed, onChange}:{label:string;checked:boolean;mixed?:boolean;onChange:()=>void}) {\n  const ref=useRef<HTMLInputElement>(null);\n  useEffect(() => {if(ref.current) ref.current.indeterminate=!!mixed;},[mixed]);\n  return <input ref={ref} type=\"checkbox\" className=\"bui-checkbox\" aria-label={label} aria-checked={mixed ? 'mixed' : checked} checked={checked} onChange={onChange} />;\n}\nexport function DataTable<T>({ caption, rows, columns, rowKey, searchText, pageSize = 5, filters = [], columnVisibility = false,\n  visibleColumnKeys, defaultVisibleColumnKeys, onVisibleColumnKeysChange, selectable = false, rowLabel = rowKey,\n  selectedKeys, defaultSelectedKeys = [], onSelectedKeysChange, renderBulkActions, density = 'comfortable', loading, error, onRetry, server, renderSelectedActions, resizableColumns=false }: DataTableProps<T>) {\n  const id=useId();\n  const [local,setLocal]=useState<TableQuery>({...defaultTableQuery,pageSize});\n  const state=server?.query ?? {...local,pageSize};\n  const query=state.search, page=state.page, facets=state.filters, sort=state.sort;\n  const changeQuery=(patch:Partial<TableQuery>)=>{const next={...state,...patch};if(server)server.onQueryChange(next);else setLocal(next);};\n  const [widths,setWidths]=useState<Record<string,number>>({});\n  const [selected,setSelected]=useControllableValue(selectedKeys,defaultSelectedKeys,onSelectedKeysChange);\n  const [shown,setShown]=useControllableValue(visibleColumnKeys,defaultVisibleColumnKeys ?? columns.map(column=>column.key),onVisibleColumnKeysChange);\n  const activeColumns=columns.filter(column=>column.hideable===false || shown.includes(column.key));\n  const displayedColumns=activeColumns.length ? activeColumns : columns.slice(0,1);\n  const selectedSet=new Set(selected); const selectedRows=rows.filter(row=>selectedSet.has(rowKey(row)));\n  const visible=useMemo(() => {\n    if(server)return rows;\n    const result=rows.filter(row=>(!searchText || searchText(row).toLocaleLowerCase().includes(query.toLocaleLowerCase())) && filters.every(filter=>!facets[filter.key] || filter.value(row)===facets[filter.key]));\n    const column=columns.find(item=>item.key===sort?.key);\n    if(column?.sortValue) { const get=column.sortValue; result.sort((a,b)=>{const av=get(a),bv=get(b);const order=typeof av==='number' && typeof bv==='number' ? av-bv : String(av).localeCompare(String(bv),undefined,{numeric:true});return sort?.descending ? -order : order;}); }\n    return result;\n  },[rows,columns,searchText,query,sort,filters,facets,server]);\n  const size=Number.isFinite(state.pageSize) ? Math.max(1,Math.floor(state.pageSize)) : 5;\n  const total=server ? Math.max(0,server.totalRows) : visible.length;\n  const pages=Math.max(1,Math.ceil(total/size)); const activePage=Math.min(page,pages);\n  const pageRows=server ? rows : visible.slice((activePage-1)*size,activePage*size);\n  const pageSelected=pageRows.filter(row=>selectedSet.has(rowKey(row))).length;\n  const toggle=(keys:string[])=>{const next=new Set(selected);const all=keys.every(key=>next.has(key));keys.forEach(key=>all ? next.delete(key) : next.add(key));setSelected([...next]);};\n  const width=(column:Column<T>)=>widths[column.key] ?? column.width ?? 180;\n  const columnStyle=(column:Column<T>):CSSProperties=>{\n    const index=displayedColumns.indexOf(column);\n    const offset=column.pinned==='start' ? displayedColumns.slice(0,index).filter(item=>item.pinned==='start').reduce((sum,item)=>sum+width(item),selectable?48:0) : displayedColumns.slice(index+1).filter(item=>item.pinned==='end').reduce((sum,item)=>sum+width(item),0);\n    return {width:resizableColumns || column.pinned ? width(column):column.width,minWidth:column.minWidth ?? 100,...(column.pinned ? {insetInlineStart:column.pinned==='start'?offset:undefined,insetInlineEnd:column.pinned==='end'?offset:undefined,zIndex:1,background:'var(--bui-bg)'}:{})};\n  };\n  const resize=(column:Column<T>,value:number)=>setWidths(current=>({...current,[column.key]:Math.min(600,Math.max(column.minWidth ?? 100,value))}));\n  return <div className=\"bui-data-table\" data-density={density} aria-busy={loading || undefined}>\n    {(searchText || server || filters.length>0 || columnVisibility) && <div className=\"bui-table-toolbar\">\n      {(searchText || server) && <Input type=\"search\" aria-label={'Search ' + caption.toLowerCase()} placeholder=\"Filter records…\" value={query} onChange={event=>{changeQuery({search:event.target.value,page:1});}} />}\n      {filters.map(filter=><label className=\"bui-table-filter\" key={filter.key} htmlFor={id+filter.key}><span className=\"bui-sr-only\">{filter.label}</span><select id={id+filter.key} className=\"bui-input\" disabled={loading} value={facets[filter.key] ?? ''} onChange={event=>{changeQuery({filters:{...facets,[filter.key]:event.target.value},page:1});}}><option value=\"\">All {filter.label.toLowerCase()}</option>{filter.options.map(option=><option key={option.value} value={option.value}>{option.label}</option>)}</select></label>)}\n      <span className=\"bui-hint\" aria-live=\"polite\">{total} results</span>\n      {columnVisibility && <Popover title=\"Visible columns\" trigger={<Button variant=\"secondary\" size=\"sm\" leadingIcon={SlidersHorizontal}>Columns</Button>}><div className=\"bui-column-options\">{columns.map(column=><Checkbox key={column.key} label={column.header} checked={displayedColumns.some(item=>item.key===column.key)} disabled={column.hideable===false || (displayedColumns.length===1 && displayedColumns[0].key===column.key)} onChange={event=>setShown(event.target.checked ? [...shown,column.key] : shown.filter(key=>key!==column.key))} />)}</div></Popover>}\n    </div>}\n    {selectable && selected.length>0 && <div className=\"bui-table-selection\"><span role=\"status\">{selected.length} selected</span><div>{renderSelectedActions ? renderSelectedActions(selected) : renderBulkActions?.(selectedRows)}<Button size=\"sm\" variant=\"ghost\" onClick={()=>setSelected([])}>Clear selection</Button></div></div>}\n    {error ? <Alert title=\"Unable to load records\" tone=\"danger\" live>{error}{onRetry && <Button size=\"sm\" variant=\"secondary\" onClick={onRetry}>Retry</Button>}</Alert> : loading ? <div className=\"bui-table-loading\"><span role=\"status\" className=\"bui-hint\">Loading {caption.toLowerCase()}…</span>{[0,1,2].map(index=><Skeleton key={index} height=\"3rem\" />)}</div> : <>\n      <div className=\"bui-table-scroll\" tabIndex={0} role=\"region\" aria-label={caption + ' table'}><table className=\"bui-table\" style={resizableColumns?{tableLayout:'fixed',minWidth:displayedColumns.reduce((sum,column)=>sum+width(column),selectable?48:0)}:undefined}><caption className=\"bui-sr-only\">{caption}</caption><thead><tr>\n        {selectable && <th scope=\"col\" className=\"bui-table-check\"><SelectionCheckbox label=\"Select current page\" checked={pageRows.length>0 && pageSelected===pageRows.length} mixed={pageSelected>0 && pageSelected<pageRows.length} onChange={()=>toggle(pageRows.map(rowKey))} /></th>}\n        {displayedColumns.map(column=><th scope=\"col\" key={column.key} data-pinned={column.pinned} style={columnStyle(column)} aria-sort={column.sortValue ? sort?.key===column.key ? sort.descending ? 'descending' : 'ascending' : 'none' : undefined}>{column.sortValue ? <button type=\"button\" onClick={()=>{changeQuery({sort:sort?.key===column.key && sort.descending ? null : {key:column.key,descending:sort?.key===column.key && !sort.descending},page:1});}}>{column.header}<Icon icon={sort?.key===column.key ? sort.descending ? ArrowDown : ArrowUp : ArrowUpDown} size={14} /></button> : column.header}{resizableColumns && <span className=\"bui-column-resize\" role=\"separator\" tabIndex={0} aria-label={'Resize '+column.header} aria-orientation=\"vertical\" aria-valuemin={column.minWidth ?? 100} aria-valuemax={600} aria-valuenow={width(column)} onKeyDown={event=>{if(event.key==='ArrowLeft'||event.key==='ArrowRight'){event.preventDefault();resize(column,width(column)+(event.key==='ArrowRight'?10:-10));}if(event.key==='Home'){event.preventDefault();resize(column,column.minWidth ?? 100);}}} onPointerDown={event=>{event.preventDefault();const start=event.clientX,initial=width(column);const target=event.currentTarget;target.setPointerCapture(event.pointerId);const move=(move:PointerEvent)=>resize(column,initial+move.clientX-start);const stop=()=>{target.removeEventListener('pointermove',move);target.removeEventListener('pointerup',stop);target.removeEventListener('pointercancel',stop);};target.addEventListener('pointermove',move);target.addEventListener('pointerup',stop);target.addEventListener('pointercancel',stop);}} />}</th>)}\n      </tr></thead><tbody>{pageRows.map(row=><tr key={rowKey(row)} data-selected={selectable && selectedSet.has(rowKey(row)) || undefined}>\n        {selectable && <td className=\"bui-table-check\"><SelectionCheckbox label={'Select ' + rowLabel(row)} checked={selectedSet.has(rowKey(row))} onChange={()=>toggle([rowKey(row)])} /></td>}\n        {displayedColumns.map(column=><td key={column.key} data-pinned={column.pinned} style={columnStyle(column)}>{column.cell(row)}</td>)}\n      </tr>)}</tbody></table></div>\n      {visible.length===0 && <EmptyState title={!query && !Object.values(facets).some(Boolean) ? 'No records yet' : 'No matching records'} action={query || Object.values(facets).some(Boolean) ? <Button variant=\"secondary\" size=\"sm\" onClick={()=>{changeQuery({search:'',filters:{},page:1});}}>Clear filter</Button> : undefined}>{!query && !Object.values(facets).some(Boolean) ? 'Records will appear here when they are added.' : 'Try another search or filter.'}</EmptyState>}\n      {resizableColumns && <p className=\"bui-table-scroll-hint bui-hint\">Scroll horizontally to see every column.</p>}\n      <Pagination page={activePage} totalPages={pages} onPageChange={page=>changeQuery({page})} />\n    </>}\n  </div>;\n}\n",
          "target": "@ui/bld8/data-table.tsx",
          "type": "registry:ui"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "bld8-drawer",
      "type": "registry:ui",
      "title": "BLD8 drawer source",
      "description": "BLD8 drawer source with editable BLD8 source.",
      "author": "Jaison (https://bld8.dev)",
      "dependencies": [
        "@base-ui/react@1.8.0"
      ],
      "registryDependencies": [
        "https://ui.bld8.dev/r/bld8-styles.json",
        "https://ui.bld8.dev/r/bld8-core.json",
        "https://ui.bld8.dev/r/bld8-utils.json"
      ],
      "files": [
        {
          "path": "registry/bld8/drawer.tsx",
          "content": "'use client';\nimport './styles.css';\n// Adapted from shadcn/ui's Base UI composition. See SHADCN_LICENSE and docs/upstream.json.\nimport type { ReactElement, ReactNode, RefObject } from 'react';\nimport { Drawer as Primitive } from '@base-ui/react/drawer';\nimport { Button, Icon } from './core';\nimport { cn } from './utils';\n\nexport interface DrawerProps {\n  trigger?: ReactElement;\n  title: string;\n  description?: string;\n  children: ReactNode;\n  side?: 'bottom' | 'left' | 'right';\n  open?: boolean;\n  defaultOpen?: boolean;\n  onOpenChange?: (open: boolean) => void;\n  initialFocus?: RefObject<HTMLElement | null>;\n  finalFocus?: RefObject<HTMLElement | null>;\n  className?: string;\n}\n/** A modal drawer with Base UI focus management and swipe dismissal. */\nexport function Drawer({trigger,title,description,children,side='bottom',initialFocus,finalFocus,className,...props}:DrawerProps) {\n  return <Primitive.Root {...props} swipeDirection={side==='bottom' ? 'down' : side}>\n    {trigger && <Primitive.Trigger render={trigger} />}\n    <Primitive.Portal>\n      <Primitive.Backdrop className=\"bui-drawer-backdrop bui:fixed bui:inset-0 bui:z-80\" />\n      <Primitive.Viewport className=\"bui-drawer-viewport bui:fixed bui:inset-0 bui:z-[81] bui:pointer-events-none\">\n        <Primitive.Popup initialFocus={initialFocus} finalFocus={finalFocus} data-side={side} className={cn('bui-drawer bui:pointer-events-auto bui:fixed bui:flex bui:flex-col bui:bg-background bui:text-foreground bui:font-body bui:shadow-panel',className)}>\n          {side==='bottom' && <div className=\"bui-drawer-handle bui:mx-auto bui:my-3 bui:h-1 bui:w-10 bui:rounded-full bui:bg-border\" aria-hidden=\"true\" />}\n          <div className=\"bui:flex bui:items-start bui:justify-between bui:gap-4 bui:p-6\">\n            <div><Primitive.Title className=\"bui:font-semibold bui:text-lg bui:m-0\">{title}</Primitive.Title>{description && <Primitive.Description className=\"bui:mt-2 bui:mb-0 bui:text-sm bui:leading-relaxed bui:text-muted\">{description}</Primitive.Description>}</div>\n            <Primitive.Close render={<Button variant=\"ghost\" className=\"bui-icon-button\" aria-label=\"Close drawer\"><Icon name=\"close\" /></Button>} />\n          </div>\n          <Primitive.Content className=\"bui:min-h-0 bui:overflow-y-auto bui:overscroll-contain bui:px-6 bui:pb-6\">{children}</Primitive.Content>\n        </Primitive.Popup>\n      </Primitive.Viewport>\n    </Primitive.Portal>\n  </Primitive.Root>;\n}\nexport function DrawerClose({children='Done'}:{children?:ReactNode}) {\n  return <Primitive.Close render={<Button>{children}</Button>} />;\n}\n",
          "target": "@ui/bld8/drawer.tsx",
          "type": "registry:ui"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "bld8-file-upload",
      "type": "registry:ui",
      "title": "BLD8 file-upload source",
      "description": "BLD8 file-upload source with editable BLD8 source.",
      "author": "Jaison (https://bld8.dev)",
      "dependencies": [
        "lucide-react@1.55.0"
      ],
      "registryDependencies": [
        "https://ui.bld8.dev/r/bld8-styles.json",
        "https://ui.bld8.dev/r/bld8-core.json",
        "https://ui.bld8.dev/r/bld8-state.json"
      ],
      "files": [
        {
          "path": "registry/bld8/file-upload.tsx",
          "content": "'use client';\nimport './styles.css';\nimport { useEffect, useId, useRef, useState } from 'react';\nimport { File, Upload, X } from 'lucide-react';\nimport { Alert, Button, Icon, IconButton, Progress } from './core';\nimport { useControllableValue } from './state';\n\nexport interface UploadContext { signal: AbortSignal; onProgress: (file: globalThis.File, percent: number) => void }\nexport interface FileUploadProps {\n  label: string;\n  value?: globalThis.File[];\n  defaultValue?: globalThis.File[];\n  onValueChange?: (files: globalThis.File[]) => void;\n  accept?: string;\n  maxFiles?: number;\n  maxSize?: number;\n  disabled?: boolean;\n  hint?: string;\n  /** Supply your upload service. No request is made without this callback. */\n  onUpload?: (files: globalThis.File[], context: UploadContext) => Promise<void>;\n}\n// Selection identity is metadata-based, not a claim of content-level deduplication.\nconst fileKey = (file:globalThis.File) => file.name + ':' + file.size + ':' + file.type;\nfunction bytes(value:number) { return value < 1024 ? value + ' B' : value < 1024 * 1024 ? (value / 1024).toFixed(1) + ' KB' : (value / 1024 / 1024).toFixed(1) + ' MB'; }\nfunction accepts(file:globalThis.File, accept:string) {\n  return !accept || accept.split(',').some(raw => {\n    const rule = raw.trim().toLowerCase(); const type = file.type.toLowerCase();\n    return rule.startsWith('.') ? file.name.toLowerCase().endsWith(rule) : rule.endsWith('/*') ? type.startsWith(rule.slice(0, -1)) : type === rule;\n  });\n}\nexport function FileUpload({ label, value, defaultValue = [], onValueChange, accept = '', maxFiles = 5, maxSize = 10 * 1024 * 1024, disabled, hint, onUpload }: FileUploadProps) {\n  const id = useId(); const input = useRef<HTMLInputElement>(null); const controller = useRef<AbortController | null>(null);\n  const browse=useRef<HTMLButtonElement>(null);\n  const run = useRef(0); const [files, setFiles] = useControllableValue(value, defaultValue, onValueChange);\n  const [dragging, setDragging] = useState(false); const [errors, setErrors] = useState<string[]>([]);\n  const [busy, setBusy] = useState(false); const [status, setStatus] = useState(''); const [progress, setProgress] = useState<Record<string,number>>({});\n  const fileLimit = Number.isFinite(maxFiles) ? Math.max(1, Math.floor(maxFiles)) : 5;\n  const sizeLimit = Number.isFinite(maxSize) ? Math.max(1, maxSize) : 10 * 1024 * 1024;\n  useEffect(() => () => { run.current++; controller.current?.abort(); }, []);\n  const add = (incoming:globalThis.File[]) => {\n    if (disabled || busy) return;\n    const next = [...files]; const rejected:string[] = [];\n    for (const file of incoming) {\n      if (next.some(item => fileKey(item) === fileKey(file))) { rejected.push(file.name + ': already selected.'); continue; }\n      if (!accepts(file, accept)) { rejected.push(file.name + ': unsupported file type.'); continue; }\n      if (file.size > sizeLimit) { rejected.push(file.name + ': exceeds ' + bytes(sizeLimit) + '.'); continue; }\n      if (next.length >= fileLimit) { rejected.push(file.name + ': limit of ' + fileLimit + ' files reached.'); continue; }\n      next.push(file);\n    }\n    setFiles(next); setErrors(rejected); setProgress({}); setStatus(next.length + ' files selected.');\n  };\n  async function upload() {\n    if (!onUpload || !files.length || busy || disabled) return;\n    const current = ++run.current; const abort = new AbortController(); controller.current = abort;\n    setBusy(true); setErrors([]); setProgress({}); setStatus('Uploading files…');\n    try {\n      await onUpload([...files], {signal:abort.signal, onProgress:(file, percent) => {\n        if (run.current === current && !abort.signal.aborted && Number.isFinite(percent)) setProgress(previous => ({...previous, [fileKey(file)]:Math.max(0, Math.min(100, percent))}));\n      }});\n      if (run.current !== current || abort.signal.aborted) return;\n      setProgress(Object.fromEntries(files.map(file => [fileKey(file),100]))); setStatus('Upload complete.');\n    } catch (error) {\n      if (run.current === current && !abort.signal.aborted) { setErrors([error instanceof Error ? error.message : 'Upload failed. Try again.']); setStatus(''); }\n    } finally { if (run.current === current) {setBusy(false);controller.current = null;} }\n  }\n  return <div className=\"bui-file-upload\">\n    <label htmlFor={id} className=\"bui-label\">{label}</label>\n    <div className=\"bui-dropzone\" data-dragging={dragging || undefined} data-disabled={disabled || busy || undefined}\n      onDragOver={event => {event.preventDefault();if(!disabled && !busy) {event.dataTransfer.dropEffect='copy';setDragging(true);}}}\n      onDragLeave={event => {if(!event.currentTarget.contains(event.relatedTarget as Node)) setDragging(false);}}\n      onDrop={event => {event.preventDefault();setDragging(false);add(Array.from(event.dataTransfer.files));}}>\n      <span className=\"bui-file-symbol\"><Icon icon={Upload} size={24} /></span><strong>Drop files here</strong>\n      <p className=\"bui-hint\">{hint ?? (accept || 'Any file type') + ' · Up to ' + fileLimit + ' files · ' + bytes(sizeLimit) + ' each'}</p>\n      <input ref={input} id={id} type=\"file\" multiple={fileLimit > 1} accept={accept} disabled={disabled || busy} className=\"bui-sr-only\" aria-describedby={id + '-help'} onChange={event => {add(Array.from(event.target.files ?? []));event.target.value='';}} />\n      <Button ref={browse} variant=\"secondary\" size=\"sm\" disabled={disabled || busy} onClick={() => input.current?.click()}>Browse files</Button>\n      <span id={id + '-help'} className=\"bui-sr-only\">{accept || 'Any file type'}. Maximum {fileLimit} files, {bytes(sizeLimit)} per file. Drag and drop or browse.</span>\n    </div>\n    {errors.length > 0 && <Alert title=\"Check the files\" tone=\"danger\" live><ul className=\"bui-file-errors\">{errors.map((error,index) => <li key={index}>{error}</li>)}</ul></Alert>}\n    {files.length > 0 && <ul className=\"bui-file-list\" aria-label={label + ' selected files'}>{files.map(file => <li key={fileKey(file)}>\n      <Icon icon={File} /><div><strong>{file.name}</strong><span className=\"bui-hint\">{bytes(file.size)}</span>{progress[fileKey(file)] !== undefined && <Progress label={'Upload ' + file.name} value={progress[fileKey(file)]} />}</div>\n      <IconButton icon={X} label={'Remove ' + file.name} variant=\"ghost\" size=\"sm\" disabled={disabled || busy} onClick={() => {setFiles(files.filter(item => fileKey(item) !== fileKey(file)));setErrors([]);setStatus(file.name + ' removed.');browse.current?.focus();}} />\n    </li>)}</ul>}\n    <div className=\"bui-file-footer\"><span role=\"status\" className=\"bui-hint\">{status}</span>{onUpload && (busy ? <Button variant=\"secondary\" size=\"sm\" onClick={() => {run.current++;controller.current?.abort();controller.current=null;setBusy(false);setProgress({});setStatus('Upload cancelled.');}}>Cancel upload</Button> : <Button size=\"sm\" disabled={disabled || !files.length} onClick={upload}>Upload {files.length || ''} {files.length === 1 ? 'file' : 'files'}</Button>)}</div>\n  </div>;\n}\n",
          "target": "@ui/bld8/file-upload.tsx",
          "type": "registry:ui"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "bld8-form",
      "type": "registry:ui",
      "title": "BLD8 form source",
      "description": "BLD8 form source with editable BLD8 source.",
      "author": "Jaison (https://bld8.dev)",
      "dependencies": [],
      "registryDependencies": [
        "https://ui.bld8.dev/r/bld8-styles.json",
        "https://ui.bld8.dev/r/bld8-core.json"
      ],
      "files": [
        {
          "path": "registry/bld8/form.tsx",
          "content": "'use client';\nimport './styles.css';\nimport { useEffect, useRef, useState, type ComponentProps, type FormEvent } from 'react';\nimport { Alert } from './core';\n\nexport type FormErrors<T> = Partial<Record<keyof T, string>>;\nexport interface FormResult<T> { values?:T; fieldErrors?:FormErrors<T>; error?:string }\nexport interface FormOptions<T> {\n  initialValues:T;\n  validate?:(values:T, context:{signal:AbortSignal})=>FormErrors<T>|Promise<FormErrors<T>>;\n  onSubmit:(values:T, context:{signal:AbortSignal})=>Promise<FormResult<T>|void>;\n  onSuccess?:(values:T)=>void;\n}\n/** A small form state adapter. Validation and persistence stay with the application. */\nexport function useForm<T extends object>({initialValues,validate,onSubmit,onSuccess}:FormOptions<T>) {\n  const [values,setValues]=useState(initialValues);const [baseline,setBaseline]=useState(initialValues);\n  const [errors,setErrors]=useState<FormErrors<T>>({});const [error,setError]=useState('');\n  const [pending,setPending]=useState(false);const [saved,setSaved]=useState(false);\n  const formRef=useRef<HTMLFormElement>(null);const request=useRef<AbortController|null>(null);\n  const dirty=JSON.stringify(values)!==JSON.stringify(baseline);\n  useEffect(()=>()=>request.current?.abort(),[]);\n  function focusError(next:FormErrors<T>) {const name=Object.keys(next).find(key=>next[key as keyof T]);if(name) requestAnimationFrame(()=>formRef.current?.querySelector<HTMLElement>(`[name=\"${CSS.escape(name)}\"]`)?.focus());}\n  function setField<K extends keyof T>(key:K,value:T[K]) {if(request.current)return;setValues(current=>({...current,[key]:value}));setErrors(current=>({...current,[key]:undefined}));setError('');setSaved(false);}\n  function reset(next:T=baseline) {request.current?.abort();request.current=null;setPending(false);setValues(next);setBaseline(next);setErrors({});setError('');setSaved(false);}\n  async function submit(event?:FormEvent) {\n    event?.preventDefault();if(request.current)return false;\n    const controller=new AbortController();request.current=controller;setPending(true);setError('');setSaved(false);\n    try {\n      const invalid=await validate?.(values,{signal:controller.signal}) ?? {};\n      if(controller.signal.aborted)return false;\n      setErrors(invalid);if(Object.values(invalid).some(Boolean)){focusError(invalid);return false;}\n      const result=await onSubmit(values,{signal:controller.signal});\n      if(controller.signal.aborted)return false;\n      if(result?.error || Object.values(result?.fieldErrors ?? {}).some(Boolean)){setErrors(result?.fieldErrors ?? {});setError(result?.error ?? 'Check the highlighted fields.');focusError(result?.fieldErrors ?? {});return false;}\n      const next=result?.values ?? values;setValues(next);setBaseline(next);setSaved(true);onSuccess?.(next);return true;\n    } catch(cause) {if(!controller.signal.aborted)setError(cause instanceof Error?cause.message:'Unable to save. Try again.');return false;}\n    finally {if(request.current===controller){request.current=null;setPending(false);}}\n  }\n  return {values,errors,error,pending,saved,dirty,setField,reset,submit,formRef};\n}\nexport function useUnsavedChanges(dirty:boolean) {\n  useEffect(()=>{if(!dirty)return;const warn=(event:BeforeUnloadEvent)=>{event.preventDefault();event.returnValue='';};window.addEventListener('beforeunload',warn);return()=>window.removeEventListener('beforeunload',warn);},[dirty]);\n}\nexport function FormErrorSummary({error,errors}:{error?:string;errors?:Record<string,string|undefined>}) {\n  const messages=Object.values(errors ?? {}).filter(Boolean);\n  return error || messages.length ? <Alert title={error || 'Check the highlighted fields.'} tone=\"danger\" live>{messages.length>0 && <ul>{messages.map((message,index)=><li key={index}>{message}</li>)}</ul>}</Alert> : null;\n}\nexport function Form<T extends object>({form,children,...props}:Omit<ComponentProps<'form'>,'onSubmit'|'ref'> & {form:ReturnType<typeof useForm<T>>}) {\n  return <form {...props} ref={form.formRef} noValidate aria-busy={form.pending || undefined} onSubmit={form.submit}>{children}</form>;\n}\n",
          "target": "@ui/bld8/form.tsx",
          "type": "registry:ui"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "bld8-icons",
      "type": "registry:ui",
      "title": "BLD8 icons source",
      "description": "BLD8 icons source with editable BLD8 source.",
      "author": "Jaison (https://bld8.dev)",
      "dependencies": [
        "lucide-react@1.55.0"
      ],
      "registryDependencies": [
        "https://ui.bld8.dev/r/bld8-styles.json"
      ],
      "files": [
        {
          "path": "registry/bld8/icons.tsx",
          "content": "'use client';\nimport './styles.css';\nimport { Check, X, ChevronDown, Plus, Search, Copy, Sun, Moon, type LucideIcon, type LucideProps } from 'lucide-react';\n\nconst familiar = { check:Check, close:X, chevron:ChevronDown, plus:Plus, search:Search, copy:Copy, sun:Sun, moon:Moon };\nexport type IconName = 'arrow' | keyof typeof familiar;\nexport type IconProps = LucideProps & { name?:IconName; icon?:LucideIcon; label?:string };\n\n/** Named Lucide imports keep application icons explicit and tree-shakable. */\nexport function Icon({name='arrow',icon:Custom,size=18,strokeWidth=1.75,nonScalingStroke,label,className,...props}:IconProps) {\n  const accessibleLabel = label || props['aria-label'];\n  const common = {role:accessibleLabel ? 'img' as const : undefined,'aria-hidden':accessibleLabel ? undefined : true,'aria-label':accessibleLabel,focusable:false as const,className:['bui-icon',className].filter(Boolean).join(' '),...props};\n  const Glyph = Custom || (name === 'arrow' ? undefined : familiar[name]);\n  if (Glyph) return <Glyph size={size} strokeWidth={strokeWidth} nonScalingStroke={nonScalingStroke} data-bui-icon={Custom ? Custom.displayName || 'custom' : name} {...common} />;\n  return <svg width={size} height={size} viewBox=\"0 0 24 24\" fill=\"none\" data-bui-icon=\"arrow\" {...common}>{[[10,6],[14,6],[18,6],[14,10],[18,10],[10,14],[18,14],[6,18]].map(([x,y]) => <circle key={x + ',' + y} cx={x} cy={y} r=\"1.25\" fill=\"currentColor\" />)}</svg>;\n}\n",
          "target": "@ui/bld8/icons.tsx",
          "type": "registry:ui"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "bld8-index",
      "type": "registry:ui",
      "title": "BLD8 index source",
      "description": "BLD8 index source with editable BLD8 source.",
      "author": "Jaison (https://bld8.dev)",
      "dependencies": [],
      "registryDependencies": [
        "https://ui.bld8.dev/r/bld8-styles.json",
        "https://ui.bld8.dev/r/bld8-core.json",
        "https://ui.bld8.dev/r/bld8-controls.json",
        "https://ui.bld8.dev/r/bld8-overlays.json",
        "https://ui.bld8.dev/r/bld8-data-table.json",
        "https://ui.bld8.dev/r/bld8-multi-select.json",
        "https://ui.bld8.dev/r/bld8-command.json",
        "https://ui.bld8.dev/r/bld8-calendar.json",
        "https://ui.bld8.dev/r/bld8-file-upload.json",
        "https://ui.bld8.dev/r/bld8-utils.json",
        "https://ui.bld8.dev/r/bld8-variants.json",
        "https://ui.bld8.dev/r/bld8-drawer.json",
        "https://ui.bld8.dev/r/bld8-context-menu.json",
        "https://ui.bld8.dev/r/bld8-sidebar.json",
        "https://ui.bld8.dev/r/bld8-form.json"
      ],
      "files": [
        {
          "path": "registry/bld8/index.ts",
          "content": "'use client';\nexport * from './core';\nexport * from './controls';\nexport * from './overlays';\nexport * from './data-table';\nexport * from './multi-select';\nexport * from './command';\nexport * from './calendar';\nexport * from './file-upload';\nexport * from './utils';\nexport * from './variants';\nexport * from './drawer';\nexport * from './context-menu';\nexport * from './sidebar';\nexport * from './form';\n",
          "target": "@ui/bld8/index.ts",
          "type": "registry:ui"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "bld8-multi-select",
      "type": "registry:ui",
      "title": "BLD8 multi-select source",
      "description": "BLD8 multi-select source with editable BLD8 source.",
      "author": "Jaison (https://bld8.dev)",
      "dependencies": [
        "@base-ui/react@1.8.0"
      ],
      "registryDependencies": [
        "https://ui.bld8.dev/r/bld8-styles.json",
        "https://ui.bld8.dev/r/bld8-core.json",
        "https://ui.bld8.dev/r/bld8-state.json"
      ],
      "files": [
        {
          "path": "registry/bld8/multi-select.tsx",
          "content": "'use client';\nimport './styles.css';\nimport { useId } from 'react';\nimport { Combobox } from '@base-ui/react/combobox';\nimport { Icon, type Option } from './core';\nimport { useControllableValue } from './state';\n\nexport interface MultiSelectProps {\n  label: string;\n  options: Option[];\n  value?: string[];\n  defaultValue?: string[];\n  onValueChange?: (value: string[]) => void;\n  placeholder?: string;\n  hint?: string;\n  error?: string;\n  name?: string;\n  disabled?: boolean;\n  required?: boolean;\n}\n\nexport function MultiSelect({ label, options, value, defaultValue = [], onValueChange, placeholder = 'Choose options…', hint, error, ...props }: MultiSelectProps) {\n  const id = useId();\n  const [selected, setSelected] = useControllableValue(value, defaultValue, onValueChange);\n  const labelFor = (value: string) => options.find(option => option.value === value)?.label ?? value;\n  const descriptions = [hint && id + '-hint', error && id + '-error'].filter(Boolean).join(' ') || undefined;\n  return <div className=\"bui-field\">\n    <label htmlFor={id} className=\"bui-label\">{label}{props.required && <span aria-hidden=\"true\"> *</span>}</label>\n    <Combobox.Root multiple items={options.map(option => option.value)} value={selected} onValueChange={setSelected} itemToStringLabel={labelFor} {...props}>\n      <Combobox.Chips className=\"bui-multi-input\" data-invalid={!!error || undefined}>\n        <Combobox.Value>{(values: string[]) => values.map(value => <Combobox.Chip key={value} className=\"bui-chip\">\n          {labelFor(value)}<Combobox.ChipRemove aria-label={'Remove ' + labelFor(value)}><Icon name=\"close\" size={14} /></Combobox.ChipRemove>\n        </Combobox.Chip>)}</Combobox.Value>\n        <Combobox.Input id={id} aria-describedby={descriptions} aria-invalid={!!error || undefined} placeholder={selected.length ? 'Add another…' : placeholder} className=\"bui-chip-input\" />\n        <Combobox.Trigger className=\"bui-combobox-trigger\" aria-label={'Show ' + label.toLowerCase() + ' options'}><Icon name=\"chevron\" /></Combobox.Trigger>\n      </Combobox.Chips>\n      <Combobox.Portal><Combobox.Positioner className=\"bui-positioner\" sideOffset={6}><Combobox.Popup className=\"bui-popup bui-select-popup\">\n        <Combobox.Empty className=\"bui-combo-empty\">No matching options.</Combobox.Empty>\n        <Combobox.List>{(value: string) => <Combobox.Item key={value} value={value} disabled={options.find(option => option.value === value)?.disabled} className=\"bui-option\">\n          {labelFor(value)}<Combobox.ItemIndicator><Icon name=\"check\" /></Combobox.ItemIndicator>\n        </Combobox.Item>}</Combobox.List>\n      </Combobox.Popup></Combobox.Positioner></Combobox.Portal>\n    </Combobox.Root>\n    {hint && <p id={id + '-hint'} className=\"bui-hint\">{hint}</p>}\n    {error && <p id={id + '-error'} className=\"bui-error\" role=\"alert\">{error}</p>}\n  </div>;\n}\n",
          "target": "@ui/bld8/multi-select.tsx",
          "type": "registry:ui"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "bld8-overlays",
      "type": "registry:ui",
      "title": "BLD8 overlays source",
      "description": "BLD8 overlays source with editable BLD8 source.",
      "author": "Jaison (https://bld8.dev)",
      "dependencies": [
        "@base-ui/react@1.8.0"
      ],
      "registryDependencies": [
        "https://ui.bld8.dev/r/bld8-styles.json",
        "https://ui.bld8.dev/r/bld8-core.json"
      ],
      "files": [
        {
          "path": "registry/bld8/overlays.tsx",
          "content": "'use client';\nimport './styles.css';\nimport { useId, useState, type ReactElement, type ReactNode, type RefObject } from 'react';\nimport { Dialog as PrimitiveDialog } from '@base-ui/react/dialog';\nimport { Popover as PrimitivePopover } from '@base-ui/react/popover';\nimport { Tooltip as PrimitiveTooltip } from '@base-ui/react/tooltip';\nimport { Menu as PrimitiveMenu } from '@base-ui/react/menu';\nimport { Toast as PrimitiveToast } from '@base-ui/react/toast';\nimport { Button, Icon, cx } from './core';\n\nexport interface DialogProps { trigger?: ReactElement; title: string; description?: string; children: ReactNode; open?: boolean; defaultOpen?: boolean; onOpenChange?: (open: boolean) => void; initialFocus?:RefObject<HTMLElement|null>; finalFocus?:RefObject<HTMLElement|null> }\nfunction DialogFrame({ trigger, title, description, children, sheet, initialFocus, finalFocus, ...props }: DialogProps & { sheet?: boolean }) {\n  return <PrimitiveDialog.Root {...props}>{trigger && <PrimitiveDialog.Trigger render={trigger} />}<PrimitiveDialog.Portal><PrimitiveDialog.Backdrop className=\"bui-backdrop\" /><PrimitiveDialog.Popup initialFocus={initialFocus} finalFocus={finalFocus} className={cx('bui-dialog', sheet && 'bui-sheet')}><div className=\"bui-dialog-heading\"><div><PrimitiveDialog.Title className=\"bui-dialog-title\">{title}</PrimitiveDialog.Title>{description && <PrimitiveDialog.Description className=\"bui-dialog-description\">{description}</PrimitiveDialog.Description>}</div><PrimitiveDialog.Close render={<Button variant=\"ghost\" className=\"bui-icon-button\" aria-label=\"Close dialog\"><Icon name=\"close\" /></Button>} /></div><div className=\"bui-dialog-body\">{children}</div></PrimitiveDialog.Popup></PrimitiveDialog.Portal></PrimitiveDialog.Root>;\n}\nexport function Dialog(props: DialogProps) { return <DialogFrame {...props} />; }\nexport function Sheet(props: DialogProps) { return <DialogFrame {...props} sheet />; }\nexport function DialogClose({ children = 'Cancel' }: { children?: ReactNode }) { return <PrimitiveDialog.Close render={<Button variant=\"secondary\">{children}</Button>} />; }\nexport function Popover({ trigger, title, children }: { trigger: ReactElement; title: string; children: ReactNode }) {\n  return <PrimitivePopover.Root><PrimitivePopover.Trigger render={trigger} /><PrimitivePopover.Portal><PrimitivePopover.Positioner className=\"bui-positioner\" sideOffset={8}><PrimitivePopover.Popup className=\"bui-popup bui-popover\"><PrimitivePopover.Title className=\"bui-label\">{title}</PrimitivePopover.Title><div>{children}</div></PrimitivePopover.Popup></PrimitivePopover.Positioner></PrimitivePopover.Portal></PrimitivePopover.Root>;\n}\nexport function Tooltip({ content, children }: { content: string; children: ReactElement }) {\n  const id = useId(); const [open, setOpen] = useState(false); return <PrimitiveTooltip.Root open={open} onOpenChange={setOpen}><PrimitiveTooltip.Trigger render={children} delay={350} aria-describedby={open ? id : undefined} /><PrimitiveTooltip.Portal><PrimitiveTooltip.Positioner className=\"bui-positioner\" sideOffset={8}><PrimitiveTooltip.Popup className=\"bui-tooltip\" id={id} role=\"tooltip\">{content}</PrimitiveTooltip.Popup></PrimitiveTooltip.Positioner></PrimitiveTooltip.Portal></PrimitiveTooltip.Root>;\n}\nexport interface MenuItem { label: string; onSelect?: () => void; disabled?: boolean; destructive?: boolean }\nexport function DropdownMenu({ trigger, items }: { trigger: ReactElement; items: MenuItem[] }) { return <PrimitiveMenu.Root><PrimitiveMenu.Trigger render={trigger} /><PrimitiveMenu.Portal><PrimitiveMenu.Positioner className=\"bui-positioner\" align=\"end\" sideOffset={8}><PrimitiveMenu.Popup className=\"bui-popup bui-menu\">{items.map(item => <PrimitiveMenu.Item key={item.label} disabled={item.disabled} onClick={item.onSelect} className={cx('bui-option', item.destructive && 'bui-destructive')}>{item.label}</PrimitiveMenu.Item>)}</PrimitiveMenu.Popup></PrimitiveMenu.Positioner></PrimitiveMenu.Portal></PrimitiveMenu.Root>; }\nfunction ToastViewport() {\n  const { toasts } = PrimitiveToast.useToastManager();\n  return <PrimitiveToast.Portal><PrimitiveToast.Viewport className=\"bui-toast-viewport\">{toasts.map(toast => <PrimitiveToast.Root key={toast.id} toast={toast} className=\"bui-toast\"><PrimitiveToast.Content className=\"bui-toast-content\"><PrimitiveToast.Title className=\"bui-label\" /><PrimitiveToast.Description className=\"bui-hint\" /></PrimitiveToast.Content><PrimitiveToast.Close className=\"bui-toast-close\" aria-label=\"Dismiss notification\" aria-hidden={false}><Icon name=\"close\" /></PrimitiveToast.Close></PrimitiveToast.Root>)}</PrimitiveToast.Viewport></PrimitiveToast.Portal>;\n}\nexport function UIProvider({ children }: { children: ReactNode }) { return <PrimitiveTooltip.Provider><PrimitiveToast.Provider timeout={5000} limit={3}>{children}<ToastViewport /></PrimitiveToast.Provider></PrimitiveTooltip.Provider>; }\nexport const useToast = PrimitiveToast.useToastManager;\n",
          "target": "@ui/bld8/overlays.tsx",
          "type": "registry:ui"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "bld8-sidebar",
      "type": "registry:ui",
      "title": "BLD8 sidebar source",
      "description": "BLD8 sidebar source with editable BLD8 source.",
      "author": "Jaison (https://bld8.dev)",
      "dependencies": [
        "lucide-react@1.55.0"
      ],
      "registryDependencies": [
        "https://ui.bld8.dev/r/bld8-styles.json",
        "https://ui.bld8.dev/r/bld8-core.json",
        "https://ui.bld8.dev/r/bld8-drawer.json",
        "https://ui.bld8.dev/r/bld8-overlays.json",
        "https://ui.bld8.dev/r/bld8-state.json",
        "https://ui.bld8.dev/r/bld8-utils.json"
      ],
      "files": [
        {
          "path": "registry/bld8/sidebar.tsx",
          "content": "'use client';\nimport './styles.css';\n// Adapted from shadcn/ui's provider / desktop-collapse / mobile-overlay pattern.\n// No cookies or global keyboard shortcut. See SHADCN_LICENSE and docs/upstream.json.\nimport { createContext, useContext, useEffect, useId, useRef, useState, type ComponentProps, type ReactNode } from 'react';\nimport { PanelLeft, type LucideIcon } from 'lucide-react';\nimport { Button } from './core';\nimport { Drawer } from './drawer';\nimport { Tooltip } from './overlays';\nimport { useControllableValue } from './state';\nimport { cn } from './utils';\n\ninterface SidebarState {open:boolean;setOpen:(open:boolean)=>void;mobile:boolean;mobileOpen:boolean;setMobileOpen:(open:boolean)=>void;id:string;triggerRef:React.RefObject<HTMLButtonElement|null>}\nconst SidebarContext=createContext<SidebarState|null>(null);\nexport function useSidebar() {\n  const value=useContext(SidebarContext);\n  if(!value) throw new Error('Sidebar components need a SidebarProvider.');\n  return value;\n}\nexport interface SidebarProviderProps extends ComponentProps<'div'> {\n  open?:boolean; defaultOpen?:boolean; onOpenChange?:(open:boolean)=>void;\n}\nexport function SidebarProvider({open:controlled,defaultOpen=true,onOpenChange,children,className,...props}:SidebarProviderProps) {\n  const [open,setOpen]=useControllableValue(controlled,defaultOpen,onOpenChange);\n  const [mobile,setMobile]=useState(false);const [mobileOpen,setMobileOpen]=useState(false);\n  const id=useId();const triggerRef=useRef<HTMLButtonElement>(null);const container=useRef<HTMLDivElement>(null);\n  useEffect(()=>{\n    const element=container.current;if(!element)return;\n    // Container width also handles embedded previews and narrow application panes.\n    const observer=new ResizeObserver(([entry])=>{const narrow=entry.contentRect.width<640;setMobile(narrow);if(!narrow)setMobileOpen(false);});\n    observer.observe(element);return ()=>observer.disconnect();\n  },[]);\n  return <SidebarContext.Provider value={{open,setOpen,mobile,mobileOpen,setMobileOpen,id,triggerRef}}>\n    <div {...props} ref={container} data-collapsed={!open || undefined} data-mobile={mobile || undefined} className={cn('bui-sidebar-layout bui:flex bui:w-full bui:min-w-0 bui:gap-5',className)}>{children}</div>\n  </SidebarContext.Provider>;\n}\nexport function Sidebar({children,label='Workspace navigation',className,...props}:ComponentProps<'nav'>&{label?:string}) {\n  const {open,mobile,mobileOpen,setMobileOpen,id,triggerRef}=useSidebar();\n  const navigation=<nav {...props} id={id} aria-label={label} className={cn('bui-sidebar-nav bui:flex bui:min-h-full bui:flex-col bui:gap-6 bui:p-3',className)}>{children}</nav>;\n  if(mobile)return <Drawer title={label} side=\"left\" open={mobileOpen} onOpenChange={setMobileOpen} finalFocus={triggerRef} className=\"bui-sidebar-mobile\">{navigation}</Drawer>;\n  return <aside data-collapsed={!open || undefined} className=\"bui-sidebar bui:shrink-0 bui:overflow-hidden bui:rounded-panel bui:bg-background\">{navigation}</aside>;\n}\nexport function SidebarTrigger({onClick,...props}:Omit<ComponentProps<typeof Button>,'children'>) {\n  const {open,setOpen,mobile,mobileOpen,setMobileOpen,id,triggerRef}=useSidebar();\n  return <Button variant=\"ghost\" {...props} ref={triggerRef} aria-controls={id} aria-expanded={mobile?mobileOpen:open} aria-label={mobile?'Open navigation':open?'Collapse navigation':'Expand navigation'} onClick={event=>{onClick?.(event);if(!event.defaultPrevented)mobile?setMobileOpen(!mobileOpen):setOpen(!open);}} className={cn('bui-icon-button',props.className)}><PanelLeft size={18} strokeWidth={1.75} aria-hidden=\"true\" /></Button>;\n}\nexport function SidebarInset({className,...props}:ComponentProps<'div'>) {\n  return <div {...props} className={cn('bui:min-w-0 bui:flex-1',className)} />;\n}\nexport function SidebarHeader({className,...props}:ComponentProps<'div'>) {\n  return <div {...props} className={cn('bui-sidebar-header bui:flex bui:min-h-11 bui:items-center bui:gap-3 bui:px-2 bui:text-sm bui:font-semibold',className)} />;\n}\nexport function SidebarFooter({className,...props}:ComponentProps<'div'>) {\n  return <div {...props} className={cn('bui-sidebar-footer bui:mt-auto bui:px-2 bui:py-3 bui:text-xs bui:text-muted',className)} />;\n}\nexport function SidebarGroup({children,label}:{children:ReactNode;label?:string}) {\n  const id=useId();\n  return <div className=\"bui:grid bui:gap-1\" role=\"group\" aria-labelledby={label?id:undefined}>\n    {label && <p id={id} className=\"bui-sidebar-label bui:m-0 bui:px-3 bui:pb-2 bui:text-xs bui:text-muted\">{label}</p>}{children}\n  </div>;\n}\nexport function SidebarMenuButton({label,icon:Symbol,active=false,onClick,...props}:Omit<ComponentProps<'button'>,'children'>&{label:string;icon:LucideIcon;active?:boolean}) {\n  const {mobile,open,setMobileOpen}=useSidebar();\n  const button=<button type=\"button\" {...props} aria-label={label} aria-current={active?'page':undefined} data-active={active || undefined} onClick={event=>{onClick?.(event);if(!event.defaultPrevented && mobile)setMobileOpen(false);}} className={cn('bui-sidebar-button bui:flex bui:min-h-11 bui:w-full bui:items-center bui:gap-3 bui:rounded-control bui:border-0 bui:bg-transparent bui:px-3 bui:py-2 bui:text-left bui:font-body bui:text-sm bui:text-foreground bui:cursor-pointer bui:data-active:bg-accent bui:data-active:text-accent-foreground bui:disabled:opacity-45 bui:disabled:cursor-not-allowed',props.className)}>\n    <Symbol size={18} strokeWidth={1.75} aria-hidden=\"true\" className=\"bui:shrink-0\" /><span className=\"bui-sidebar-label bui:truncate\">{label}</span>\n  </button>;\n  return !mobile&&!open ? <Tooltip content={label}>{button}</Tooltip> : button;\n}\n",
          "target": "@ui/bld8/sidebar.tsx",
          "type": "registry:ui"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "bld8-state",
      "type": "registry:ui",
      "title": "BLD8 state source",
      "description": "BLD8 state source with editable BLD8 source.",
      "author": "Jaison (https://bld8.dev)",
      "dependencies": [],
      "registryDependencies": [
        "https://ui.bld8.dev/r/bld8-styles.json"
      ],
      "files": [
        {
          "path": "registry/bld8/state.ts",
          "content": "import { useState } from 'react';\n\n/** A controlled value never falls back to internal state when it is empty. */\nexport function useControllableValue<T>(value: T | undefined, defaultValue: T, onChange?: (value: T) => void) {\n  const [internal, setInternal] = useState(defaultValue);\n  const current = value === undefined ? internal : value;\n  const update = (next: T) => {\n    if (value === undefined) setInternal(next);\n    onChange?.(next);\n  };\n  return [current, update] as const;\n}\n",
          "target": "@ui/bld8/state.ts",
          "type": "registry:ui"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "bld8-utils",
      "type": "registry:ui",
      "title": "BLD8 utils source",
      "description": "BLD8 utils source with editable BLD8 source.",
      "author": "Jaison (https://bld8.dev)",
      "dependencies": [
        "clsx@2.1.1",
        "tailwind-merge@3.7.0"
      ],
      "registryDependencies": [
        "https://ui.bld8.dev/r/bld8-styles.json"
      ],
      "files": [
        {
          "path": "registry/bld8/utils.ts",
          "content": "import { clsx, type ClassValue } from 'clsx';\nimport { extendTailwindMerge } from 'tailwind-merge';\nconst merge = extendTailwindMerge({ prefix:'bui' });\n/** Merge BLD8 utilities; preserve compatibility and consumer CSS classes. */\nexport function cn(...values:ClassValue[]) { return merge(clsx(values)); }\n",
          "target": "@ui/bld8/utils.ts",
          "type": "registry:ui"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "bld8-variants",
      "type": "registry:ui",
      "title": "BLD8 variants source",
      "description": "BLD8 variants source with editable BLD8 source.",
      "author": "Jaison (https://bld8.dev)",
      "dependencies": [
        "class-variance-authority@0.7.1"
      ],
      "registryDependencies": [
        "https://ui.bld8.dev/r/bld8-styles.json"
      ],
      "files": [
        {
          "path": "registry/bld8/variants.ts",
          "content": "// CVA composition follows shadcn's MIT Button pattern; see SHADCN_LICENSE.\nimport { cva } from 'class-variance-authority';\nexport const buttonVariants = cva('bui-button bui:shrink-0 bui:select-none', {\n  variants:{\n    variant:{primary:'bui-button--primary',accent:'bui-button--accent',secondary:'bui-button--secondary',ghost:'bui-button--ghost',danger:'bui-button--danger'},\n    size:{sm:'bui-button--sm',md:'bui-button--md',lg:'bui-button--lg'},\n  },\n  defaultVariants:{variant:'primary',size:'md'},\n});\n",
          "target": "@ui/bld8/variants.ts",
          "type": "registry:ui"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "bld8-block-account-settings",
      "type": "registry:ui",
      "title": "BLD8 account-settings source",
      "description": "BLD8 account-settings source with editable BLD8 source.",
      "author": "Jaison (https://bld8.dev)",
      "dependencies": [],
      "registryDependencies": [
        "https://ui.bld8.dev/r/bld8-styles.json",
        "https://ui.bld8.dev/r/bld8-index.json",
        "https://ui.bld8.dev/r/bld8-block-styles.json"
      ],
      "files": [
        {
          "path": "registry/bld8/blocks/account-settings.tsx",
          "content": "'use client';\nimport './styles.css';\nimport { useState, type FormEvent } from 'react';\nimport { Avatar, Button, Field, Input, Switch } from '../index';\n\nexport interface AccountValues { name: string; email: string; digest: boolean }\nexport function AccountSettings({ initialValues = { name: 'Alex Morgan', email: 'alex@example.com', digest: true }, onSave }: { initialValues?: AccountValues; onSave?: (values: AccountValues) => Promise<void> }) {\n  const [values, setValues] = useState(initialValues);\n  const [errors, setErrors] = useState<{ name?: string; email?: string }>({});\n  const [saving, setSaving] = useState(false);\n  const [message, setMessage] = useState('');\n  function update(patch: Partial<AccountValues>) { setValues(current => ({ ...current, ...patch })); setMessage(''); }\n  async function save(event: FormEvent) {\n    event.preventDefault();\n    const next = { name: values.name.trim() ? undefined : 'Enter your name.', email: /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(values.email.trim()) ? undefined : 'Enter a valid email address.' };\n    setErrors(next); if (next.name || next.email) return;\n    setSaving(true);\n    try { if (onSave) await onSave({ ...values, name: values.name.trim(), email: values.email.trim() }); setMessage(onSave ? 'Changes saved.' : 'Saved for this session.'); }\n    catch { setMessage('Changes could not be saved. Please try again.'); }\n    finally { setSaving(false); }\n  }\n  return <section className=\"bblocks-panel\" aria-label=\"Account settings\">\n    <div className=\"bblocks-heading\"><div><p className=\"bblocks-kicker\">PERSONAL SPACE</p><h2>Your profile.</h2><p className=\"bblocks-muted\">The details that make it yours.</p></div><Avatar name={values.name || 'Profile'} size=\"lg\" /></div>\n    <form onSubmit={save} noValidate className=\"bblocks-stack\">\n      <div className=\"bblocks-form-grid\"><Field label=\"Display name\" error={errors.name} required><Input value={values.name} autoComplete=\"name\" onChange={e => update({name:e.target.value})} /></Field><Field label=\"Email address\" error={errors.email} required><Input type=\"email\" value={values.email} autoComplete=\"email\" onChange={e => update({email:e.target.value})} /></Field></div>\n      <div className=\"bblocks-rule\"><Switch label=\"Weekly summary\" description=\"A quiet update about your workspace.\" checked={values.digest} onChange={e => update({digest:e.target.checked})} /></div>\n      <div className=\"bblocks-heading\"><p className=\"bblocks-note\">{onSave ? 'Save your profile changes.' : 'Sample profile. Changes stay in this session.'}</p><Button type=\"submit\" loading={saving}>Save profile</Button></div>\n    </form><p role=\"status\" className=\"bblocks-status\">{message}</p>\n  </section>;\n}\n",
          "target": "@ui/bld8/blocks/account-settings.tsx",
          "type": "registry:ui"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "bld8-block-index",
      "type": "registry:ui",
      "title": "BLD8 index source",
      "description": "BLD8 index source with editable BLD8 source.",
      "author": "Jaison (https://bld8.dev)",
      "dependencies": [],
      "registryDependencies": [
        "https://ui.bld8.dev/r/bld8-styles.json",
        "https://ui.bld8.dev/r/bld8-block-sign-in.json",
        "https://ui.bld8.dev/r/bld8-block-account-settings.json",
        "https://ui.bld8.dev/r/bld8-block-metrics.json",
        "https://ui.bld8.dev/r/bld8-block-workspace.json",
        "https://ui.bld8.dev/r/bld8-block-team.json",
        "https://ui.bld8.dev/r/bld8-block-project-board.json",
        "https://ui.bld8.dev/r/bld8-block-templates.json",
        "https://ui.bld8.dev/r/bld8-block-project-planner.json",
        "https://ui.bld8.dev/r/bld8-block-resource-manager.json",
        "https://ui.bld8.dev/r/bld8-block-operations-template.json",
        "https://ui.bld8.dev/r/bld8-block-outline-projects.json",
        "https://ui.bld8.dev/r/bld8-block-outline-repository.json",
        "https://ui.bld8.dev/r/bld8-block-styles.json"
      ],
      "files": [
        {
          "path": "registry/bld8/blocks/index.ts",
          "content": "'use client';\nexport * from './sign-in';\nexport * from './account-settings';\nexport * from './metrics';\nexport * from './workspace';\nexport * from './team';\nexport * from './project-board';\nexport * from './templates';\nexport * from './project-planner';\nexport * from './resource-manager';\nexport * from './operations-template';\nexport * from './outline-projects';\nexport * from './outline-repository';\n",
          "target": "@ui/bld8/blocks/index.ts",
          "type": "registry:ui"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "bld8-block-metrics",
      "type": "registry:ui",
      "title": "BLD8 metrics source",
      "description": "BLD8 metrics source with editable BLD8 source.",
      "author": "Jaison (https://bld8.dev)",
      "dependencies": [],
      "registryDependencies": [
        "https://ui.bld8.dev/r/bld8-styles.json",
        "https://ui.bld8.dev/r/bld8-index.json",
        "https://ui.bld8.dev/r/bld8-block-styles.json"
      ],
      "files": [
        {
          "path": "registry/bld8/blocks/metrics.tsx",
          "content": "'use client';\nimport './styles.css';\nimport { useState } from 'react';\nimport { Badge, Button } from '../index';\n\nconst periods = {\n  week: { label:'This week', visits:'8,420', projects:'24', completion:'86%', bars:[42,58,48,76,65,92,80], labels:['Mon','Tue','Wed','Thu','Fri','Sat','Sun'] },\n  month: { label:'This month', visits:'32,680', projects:'91', completion:'89%', bars:[35,54,61,48,78,88,96], labels:['01','05','09','13','17','21','25'] },\n};\nexport function MetricsOverview() {\n  const [period, setPeriod] = useState<keyof typeof periods>('week');\n  const current = periods[period];\n  return <section className=\"bblocks-metrics\" aria-label=\"Metrics overview\">\n    <div className=\"bblocks-heading\"><div><p className=\"bblocks-kicker\">THE BIG PICTURE</p><h2>A good rhythm.</h2></div><div className=\"bblocks-segment\" role=\"group\" aria-label=\"Metrics period\">{(Object.keys(periods) as (keyof typeof periods)[]).map(key => <Button key={key} size=\"sm\" variant={period === key ? 'primary' : 'ghost'} aria-pressed={period === key} onClick={() => setPeriod(key)}>{periods[key].label}</Button>)}</div></div>\n    <div className=\"bblocks-stats\">{[['Visits',current.visits,'+12%'],['Active projects',current.projects,'+4'],['Completion',current.completion,'+3%']].map(([label,value,change]) => <div className=\"bblocks-stat\" key={label}><span>{label}</span><strong>{value}</strong><Badge tone=\"success\">{change}</Badge></div>)}</div>\n    <figure className=\"bblocks-panel bblocks-chart\"><figcaption><span>Workspace activity</span><span className=\"bblocks-muted\">{current.label} · sample data</span></figcaption><div className=\"bblocks-bars\" role=\"img\" aria-label={`${current.label} sample activity: ${current.bars.map((value,i) => `${current.labels[i]} ${value}`).join(', ')}`}>{current.bars.map((height,index) => <div key={index}><span style={{height:height + '%'}} /><small>{current.labels[index]}</small></div>)}</div></figure>\n  </section>;\n}\n",
          "target": "@ui/bld8/blocks/metrics.tsx",
          "type": "registry:ui"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "bld8-block-operations-template",
      "type": "registry:ui",
      "title": "BLD8 operations-template source",
      "description": "BLD8 operations-template source with editable BLD8 source.",
      "author": "Jaison (https://bld8.dev)",
      "dependencies": [
        "lucide-react@1.55.0"
      ],
      "registryDependencies": [
        "https://ui.bld8.dev/r/bld8-styles.json",
        "https://ui.bld8.dev/r/bld8-block-outline-projects.json",
        "https://ui.bld8.dev/r/bld8-block-outline-repository.json",
        "https://ui.bld8.dev/r/bld8-block-resource-manager.json",
        "https://ui.bld8.dev/r/bld8-block-account-settings.json",
        "https://ui.bld8.dev/r/bld8-index.json",
        "https://ui.bld8.dev/r/bld8-block-styles.json"
      ],
      "files": [
        {
          "path": "registry/bld8/blocks/operations-template.tsx",
          "content": "'use client';\nimport './styles.css';\nimport { useEffect, useRef, useState } from 'react';\nimport { CalendarDays, FolderOpen, Search, Settings2, Sparkle } from 'lucide-react';\nimport { Alert, Badge, Button, CommandPalette, ContextMenu, ContextMenuTrigger, ContextMenuContent, ContextMenuItem, SidebarProvider, Sidebar, SidebarHeader, SidebarGroup, SidebarMenuButton, SidebarFooter, SidebarInset, SidebarTrigger } from '../index';\nimport { OutlineProjects } from './outline-projects';\nimport { createOutlineRepository, type OutlineRepository } from './outline-repository';\nimport type { ResourceRecord } from './resource-manager';\nimport type { AccountValues } from './account-settings';\nimport { ResourceManager } from './resource-manager';\nimport { AccountSettings } from './account-settings';\n\nconst views=[{id:'Planning',icon:CalendarDays},{id:'Resources',icon:FolderOpen},{id:'Settings',icon:Settings2}] as const;\nexport function OperationsTemplate({repository:provided}:{repository?:OutlineRepository}={}) {\n  const [repository,setRepository]=useState<OutlineRepository|null>(provided ?? null);\n  const [storageError,setStorageError]=useState('');\n  const [preferences,setPreferences]=useState<{resources?:ResourceRecord[];profile?:AccountValues}|null>(null);\n  useEffect(()=>{try{setRepository(provided ?? createOutlineRepository(window.localStorage));const raw=window.localStorage.getItem('bld8-outline-preferences-v1');const value=raw?JSON.parse(raw):{};setPreferences({resources:Array.isArray(value.resources)?value.resources:undefined,profile:value.profile && typeof value.profile.name==='string' && typeof value.profile.email==='string' && typeof value.profile.digest==='boolean'?value.profile:undefined});}catch{setStorageError('Browser storage is unavailable. Enable storage for this site and reload to use the saved workspace.');setPreferences({});}},[provided]);\n  const preferenceRef=useRef(preferences);preferenceRef.current=preferences;\n  function savePreferences(patch:Partial<NonNullable<typeof preferences>>){const next={...preferenceRef.current,...patch};window.localStorage.setItem('bld8-outline-preferences-v1',JSON.stringify(next));preferenceRef.current=next;setPreferences(next);}\n\n  const [view,setView]=useState('Planning');const heading=useRef<HTMLHeadingElement>(null);\n  function navigate(next:string) {setView(next);requestAnimationFrame(()=>heading.current?.focus());}\n  return <div className=\"bblocks-operations\">\n    <header className=\"bblocks-operations-header\"><span className=\"bblocks-wordmark\"><span aria-hidden=\"true\">✳</span> Outline</span><Badge tone=\"accent\">Example application</Badge><CommandPalette title=\"Outline navigation\" trigger={<Button variant=\"secondary\" size=\"sm\" leadingIcon={Search}>Find a view</Button>} items={views.map(item=>({id:item.id,label:'Open '+item.id.toLowerCase(),category:'Navigate',icon:item.icon,onSelect:()=>navigate(item.id)}))} /></header>\n    <SidebarProvider className=\"bblocks-operations-layout\">\n      <Sidebar label=\"Outline views\">\n        <SidebarHeader><Sparkle size={18} strokeWidth={1.75} aria-hidden=\"true\" /><span className=\"bui-sidebar-label\">Your workspace</span></SidebarHeader>\n        <SidebarGroup label=\"WORKSPACE\">{views.map(item=><SidebarMenuButton key={item.id} icon={item.icon} label={item.id} active={view===item.id} onClick={()=>setView(item.id)} />)}</SidebarGroup>\n        <SidebarFooter>Small steps. Room to think.</SidebarFooter>\n      </Sidebar>\n      <SidebarInset>\n        <div className=\"bblocks-operations-toolbar\"><SidebarTrigger /><span className=\"bblocks-muted\">{view}</span></div>\n        <ContextMenu><ContextMenuTrigger className=\"bblocks-operations-intro\" aria-label=\"Workspace quick navigation\">\n          <p className=\"bblocks-kicker\">SMALL PLANS. USEFUL DETAILS.</p><h2 ref={heading} tabIndex={-1}>{view==='Planning' ? 'Make room for the next idea.' : view==='Resources' ? 'Keep the references close.' : 'A few details, made yours.'}</h2><p className=\"bblocks-muted\">Projects, references and preferences. Saved in this browser; no account required.</p>\n        </ContextMenuTrigger><ContextMenuContent aria-label=\"Workspace quick navigation\">{views.map(item=><ContextMenuItem key={item.id} onClick={()=>navigate(item.id)}><item.icon size={16} aria-hidden=\"true\" />Open {item.id.toLowerCase()}</ContextMenuItem>)}</ContextMenuContent></ContextMenu>\n        {storageError && <Alert title=\"Storage needs attention\" tone=\"warning\">{storageError}</Alert>}\n        <div hidden={view!=='Planning'}>{repository?<OutlineProjects repository={repository} />:<p role=\"status\">Opening the workspace…</p>}</div>\n        <div hidden={view!=='Resources'}>{preferences && <ResourceManager initialRecords={preferences.resources} onRecordsChange={resources=>{try{savePreferences({resources});setStorageError('');}catch{setStorageError('Resource changes are only in memory: browser storage could not be updated.');}}} />}</div>\n        <div hidden={view!=='Settings'}>{preferences && <AccountSettings initialValues={preferences.profile} onSave={async profile=>{savePreferences({profile});setStorageError('');}} />}</div>\n      </SidebarInset>\n    </SidebarProvider>\n    <footer className=\"bblocks-note\">Outline / BLD8 UI · MIT · Both collections free. Local browser storage · File metadata only · Connect the repository adapter to your own API.</footer>\n  </div>;\n}\n",
          "target": "@ui/bld8/blocks/operations-template.tsx",
          "type": "registry:ui"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "bld8-block-outline-projects",
      "type": "registry:ui",
      "title": "BLD8 outline-projects source",
      "description": "BLD8 outline-projects source with editable BLD8 source.",
      "author": "Jaison (https://bld8.dev)",
      "dependencies": [
        "lucide-react@1.55.0"
      ],
      "registryDependencies": [
        "https://ui.bld8.dev/r/bld8-styles.json",
        "https://ui.bld8.dev/r/bld8-block-outline-repository.json",
        "https://ui.bld8.dev/r/bld8-index.json",
        "https://ui.bld8.dev/r/bld8-block-styles.json"
      ],
      "files": [
        {
          "path": "registry/bld8/blocks/outline-projects.tsx",
          "content": "'use client';\nimport './styles.css';\nimport { useEffect, useRef, useState } from 'react';\nimport { Archive, Check, Download, Pencil, Plus, Trash2 } from 'lucide-react';\nimport { Alert, Badge, Button, DataTable, Dialog, Field, Form, FormErrorSummary, Input, Textarea, createTableCSV, defaultTableQuery, useForm, useUnsavedChanges, type Column, type TableQuery } from '../index';\nimport { OutlineValidationError, validateOutline, type OutlineProject, type OutlineRepository, type OutlineValues } from './outline-repository';\n\nconst empty:OutlineValues={name:'',due:'',notes:'',status:'Planned'};\nfunction ProjectEditor({project,repository,onSaved,onClose}:{project:OutlineProject|null;repository:OutlineRepository;onSaved:()=>void;onClose:()=>void}) {\n  const [discard,setDiscard]=useState(false);\n  const form=useForm<OutlineValues>({\n    initialValues:project?{name:project.name,due:project.due,notes:project.notes,status:project.status}:empty,\n    validate:validateOutline,\n    onSubmit:async(values,{signal})=>{try{const saved=await repository.save(values,project,signal);return {values:saved};}catch(error){if(error instanceof OutlineValidationError)return {fieldErrors:error.fields};throw error;}},\n    onSuccess:onSaved,\n  });\n  useUnsavedChanges(form.dirty);\n  const close=()=>{if(form.pending)return;if(form.dirty)setDiscard(true);else onClose();};\n  return <Dialog title={project?'Edit project':'Plan a project'} description=\"A name, a review date and the context worth keeping.\" open onOpenChange={open=>{if(!open)close();}}>\n    <Form form={form} className=\"bblocks-stack\">\n      <FormErrorSummary error={form.error} />\n      <Field label=\"Project name\" required error={form.errors.name}><Input name=\"name\" value={form.values.name} onChange={event=>form.setField('name',event.target.value)} disabled={form.pending} autoComplete=\"off\" maxLength={80} /></Field>\n      <div className=\"bblocks-form-grid\"><Field label=\"Review date\" required error={form.errors.due}><Input name=\"due\" type=\"date\" value={form.values.due} onChange={event=>form.setField('due',event.target.value)} disabled={form.pending} /></Field><label className=\"bui-field\"><span className=\"bui-label\">Status</span><select name=\"status\" className=\"bui-input\" value={form.values.status} onChange={event=>form.setField('status',event.target.value as OutlineValues['status'])} disabled={form.pending}>{['Planned','Ready','Archived'].map(value=><option key={value}>{value}</option>)}</select></label></div>\n      <Field label=\"Notes to self\" hint=\"Keep the useful context close.\" error={form.errors.notes}><Textarea name=\"notes\" value={form.values.notes} maxLength={1000} onChange={event=>form.setField('notes',event.target.value)} disabled={form.pending} /></Field>\n      {discard && <Alert title=\"Discard this draft?\" tone=\"warning\"><p>Your unsaved changes will be lost.</p><div className=\"bblocks-inline-actions\"><Button variant=\"danger\" size=\"sm\" onClick={onClose}>Discard changes</Button><Button variant=\"secondary\" size=\"sm\" onClick={()=>setDiscard(false)}>Keep editing</Button></div></Alert>}\n      <div className=\"bblocks-heading\"><span className=\"bblocks-note\">{form.pending?'Saving…':form.dirty?'Unsaved changes':'Ready when you are.'}</span><div className=\"bblocks-inline-actions\"><Button variant=\"secondary\" onClick={close} disabled={form.pending}>Cancel</Button><Button type=\"submit\" loading={form.pending}>{project?'Save project':'Add project'}</Button></div></div>\n    </Form>\n  </Dialog>;\n}\nexport function OutlineProjects({repository}:{repository:OutlineRepository}) {\n  const [query,setQuery]=useState<TableQuery>({...defaultTableQuery});const [rows,setRows]=useState<OutlineProject[]>([]);const [total,setTotal]=useState(0);\n  const [loading,setLoading]=useState(true);const [error,setError]=useState('');const [revision,setRevision]=useState(0);\n  const [selected,setSelected]=useState<string[]>([]);const [editor,setEditor]=useState<{project:OutlineProject|null}|null>(null);\n  const [deleting,setDeleting]=useState<OutlineProject|null>(null);const [mutation,setMutation]=useState(false);const [message,setMessage]=useState('');const [actionError,setActionError]=useState('');\n  const [density,setDensity]=useState<'comfortable'|'compact'>('comfortable');\n  const origin=useRef<HTMLElement|null>(null);const operation=useRef<AbortController|null>(null);\n  useEffect(()=>()=>operation.current?.abort(),[]);\n  useEffect(()=>{const controller=new AbortController();setLoading(true);setError('');repository.list(query,controller.signal).then(result=>{if(controller.signal.aborted)return;const last=Math.max(1,Math.ceil(result.total/query.pageSize));if(query.page>last){setQuery(current=>({...current,page:last}));return;}setRows(result.rows);setTotal(result.total);}).catch(error=>{if(!controller.signal.aborted)setError(error instanceof Error?error.message:'Unable to load projects.');}).finally(()=>{if(!controller.signal.aborted)setLoading(false);});return()=>controller.abort();},[query,revision,repository]);\n  useEffect(()=>{const refresh=()=>setRevision(value=>value+1);window.addEventListener('storage',refresh);return()=>window.removeEventListener('storage',refresh);},[]);\n  function openEditor(project:OutlineProject|null){origin.current=document.activeElement as HTMLElement;setEditor({project});}\n  function closeEditor(){setEditor(null);requestAnimationFrame(()=>origin.current?.focus());}\n  async function mutate(action:(signal:AbortSignal)=>Promise<void>,success:string){if(operation.current)return;const controller=new AbortController();operation.current=controller;setMutation(true);setActionError('');try{await action(controller.signal);if(controller.signal.aborted)return;setSelected([]);setDeleting(null);setMessage(success);setRevision(value=>value+1);}catch(error){if(!controller.signal.aborted)setActionError(error instanceof Error?error.message:'Changes could not be saved.');}finally{if(operation.current===controller){operation.current=null;setMutation(false);}}}\n  const columns:Column<OutlineProject>[]=[\n    {key:'name',header:'Project',hideable:false,pinned:'start',width:240,minWidth:160,sortValue:row=>row.name,cell:row=><Button variant=\"ghost\" size=\"sm\" className=\"bblocks-project-name\" onClick={()=>openEditor(row)}>{row.name}</Button>},\n    {key:'due',header:'Review date',width:160,sortValue:row=>row.due,cell:row=><time dateTime={row.due}>{row.due}</time>},\n    {key:'status',header:'Status',width:140,sortValue:row=>row.status,cell:row=><Badge tone={row.status==='Ready'?'success':'neutral'}>{row.status}</Badge>},\n    {key:'actions',header:'Actions',width:160,cell:row=><div className=\"bblocks-inline-actions\"><Button size=\"sm\" variant=\"ghost\" aria-label={'Edit '+row.name} leadingIcon={Pencil} onClick={()=>openEditor(row)}>Edit</Button><Button size=\"sm\" variant=\"ghost\" aria-label={'Delete '+row.name} onClick={()=>{setActionError('');setDeleting(row);}}><Trash2 size={16} aria-hidden=\"true\" /></Button></div>},\n  ];\n  function download(){const url=URL.createObjectURL(new Blob(['\\uFEFF'+createTableCSV(rows,columns)],{type:'text/csv;charset=utf-8;'}));const link=document.createElement('a');link.href=url;link.download='outline-current-page.csv';link.click();setTimeout(()=>URL.revokeObjectURL(url),1000);setMessage('Current page exported.');}\n  return <section className=\"bblocks-panel\" aria-label=\"Outline projects\"><div className=\"bblocks-heading\"><div><p className=\"bblocks-kicker\">PROJECTS / {total.toString().padStart(2,'0')}</p><h2>A little room to plan.</h2><p className=\"bblocks-muted\">The next step, and the details behind it.</p></div><Button leadingIcon={Plus} onClick={()=>openEditor(null)}>Plan project</Button></div>\n    <div className=\"bblocks-heading bblocks-table-options\"><label className=\"bui-field\"><span className=\"bui-sr-only\">Table density</span><select aria-label=\"Table density\" className=\"bui-input\" value={density} onChange={event=>setDensity(event.target.value as typeof density)}><option value=\"comfortable\">Comfortable</option><option value=\"compact\">Compact</option></select></label><Button leadingIcon={Download} size=\"sm\" variant=\"ghost\" onClick={download} disabled={loading || !!error || !rows.length}>Export current page</Button></div>\n    {actionError && !deleting && <Alert title=\"Unable to save changes\" tone=\"danger\" live>{actionError}</Alert>}\n    <DataTable caption=\"Outline projects\" rows={rows} columns={columns} rowKey={row=>row.id} rowLabel={row=>row.name} server={{query,onQueryChange:setQuery,totalRows:total}} loading={loading} error={error} onRetry={()=>setRevision(value=>value+1)} columnVisibility resizableColumns density={density} selectable selectedKeys={selected} onSelectedKeysChange={setSelected} filters={[{key:'status',label:'Statuses',options:['Planned','Ready','Archived'].map(value=>({value,label:value})),value:row=>row.status}]} renderSelectedActions={keys=><><Button size=\"sm\" leadingIcon={Check} loading={mutation} onClick={()=>mutate(signal=>repository.setStatus(keys,'Ready',signal),keys.length+' projects marked ready.')}>Mark ready</Button><Button size=\"sm\" variant=\"secondary\" leadingIcon={Archive} disabled={mutation} onClick={()=>mutate(signal=>repository.setStatus(keys,'Archived',signal),keys.length+' projects archived.')}>Archive</Button></>} />\n    <p role=\"status\" className=\"bblocks-status\">{message}</p>\n    {editor && <ProjectEditor project={editor.project} repository={repository} onClose={closeEditor} onSaved={()=>{setMessage(editor.project?'Project saved.':'Project added.');setQuery(current=>({...current,page:1}));setRevision(value=>value+1);closeEditor();}} />}\n    {deleting && <Dialog title=\"Delete project?\" description={'Delete '+deleting.name+' permanently from this workspace.'} open onOpenChange={open=>{if(!open&&!mutation)setDeleting(null);}}>{actionError && <Alert title=\"Unable to delete project\" tone=\"danger\" live>{actionError}</Alert>}<div className=\"bblocks-inline-actions\"><Button variant=\"secondary\" disabled={mutation} onClick={()=>setDeleting(null)}>Keep project</Button><Button variant=\"danger\" loading={mutation} onClick={()=>mutate(signal=>repository.remove(deleting,signal),'Project deleted.')}>Delete project</Button></div></Dialog>}\n  </section>;\n}\n",
          "target": "@ui/bld8/blocks/outline-projects.tsx",
          "type": "registry:ui"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "bld8-block-outline-repository",
      "type": "registry:ui",
      "title": "BLD8 outline-repository source",
      "description": "BLD8 outline-repository source with editable BLD8 source.",
      "author": "Jaison (https://bld8.dev)",
      "dependencies": [],
      "registryDependencies": [
        "https://ui.bld8.dev/r/bld8-styles.json",
        "https://ui.bld8.dev/r/bld8-index.json",
        "https://ui.bld8.dev/r/bld8-block-styles.json"
      ],
      "files": [
        {
          "path": "registry/bld8/blocks/outline-repository.ts",
          "content": "import type { FormErrors, TableQuery } from '../index';\n\nexport interface OutlineValues {name:string; due:string; notes:string; status:'Planned'|'Ready'|'Archived'}\nexport interface OutlineProject extends OutlineValues {id:string;version:number}\nexport interface OutlinePage {rows:OutlineProject[];total:number}\nexport interface OutlineRepository {\n  list:(query:TableQuery,signal:AbortSignal)=>Promise<OutlinePage>;\n  save:(values:OutlineValues,previous:OutlineProject|null,signal:AbortSignal)=>Promise<OutlineProject>;\n  setStatus:(ids:string[],status:OutlineValues['status'],signal:AbortSignal)=>Promise<void>;\n  remove:(project:OutlineProject,signal:AbortSignal)=>Promise<void>;\n}\nexport class OutlineValidationError extends Error {\n  constructor(public fields:FormErrors<OutlineValues>){super('Check the highlighted fields.');}\n}\nexport const outlineSeed:OutlineProject[]=[\n  ['keyboard','Keyboard review','2026-10-20','Planned'],['interface','Interface studies','2026-10-24','Planned'],\n  ['forms','Form patterns','2026-10-28','Ready'],['navigation','Navigation audit','2026-11-02','Planned'],\n  ['tokens','Theme tokens','2026-11-06','Ready'],['docs','Usage guide','2026-11-10','Planned'],\n  ['motion','Motion studies','2026-11-14','Planned'],['mobile','Mobile checks','2026-11-18','Ready'],\n].map(([id,name,due,status])=>({id,name,due,status:status as OutlineValues['status'],notes:'',version:1}));\nexport function validateOutline(values:OutlineValues):FormErrors<OutlineValues> {\n  const fields:FormErrors<OutlineValues>={};\n  if(values.name.trim().length<3)fields.name='Use at least three characters.';\n  if(values.name.trim().length>80)fields.name='Keep the name within 80 characters.';\n  const parsed=Date.parse(values.due+'T12:00:00Z');\n  if(!/^\\d{4}-\\d{2}-\\d{2}$/.test(values.due) || Number.isNaN(parsed) || new Date(parsed).toISOString().slice(0,10)!==values.due)fields.due='Choose a valid review date.';\n  if(values.notes.length>1000)fields.notes='Keep notes within 1,000 characters.';\n  if(!['Planned','Ready','Archived'].includes(values.status))fields.status='Choose a valid status.';\n  return fields;\n}\nfunction readProjects(storage:Storage,key:string):OutlineProject[] {\n  const raw=storage.getItem(key);if(!raw)return outlineSeed.map(row=>({...row}));\n  const value:unknown=JSON.parse(raw);\n  if(!Array.isArray(value) || !value.every(row=>row && typeof row.id==='string' && typeof row.name==='string' && typeof row.notes==='string' && typeof row.due==='string' && ['Planned','Ready','Archived'].includes(row.status) && Number.isInteger(row.version)))throw new Error('Saved project data could not be read. Export or clear this site’s storage before starting again.');\n  return value;\n}\n/** Browser-backed reference adapter. Replace this contract with your HTTP service. */\nexport function createOutlineRepository(storage:Storage,key='bld8-outline-projects-v1'):OutlineRepository {\n  const read=()=>readProjects(storage,key);\n  const write=(rows:OutlineProject[])=>{try{storage.setItem(key,JSON.stringify(rows));}catch{throw new Error('Browser storage is unavailable or full. Your changes have not been saved. Try again.');}};\n  const check=(signal:AbortSignal)=>signal.throwIfAborted();\n  return {\n    async list(query,signal){\n      check(signal);let rows=read().filter(row=>(row.name+' '+row.notes).toLocaleLowerCase().includes(query.search.toLocaleLowerCase()) && (!query.filters.status || row.status===query.filters.status));\n      const sort=query.sort;if(sort && ['name','due','status'].includes(sort.key)){const key=sort.key as 'name'|'due'|'status';rows.sort((a,b)=>a[key].localeCompare(b[key],undefined,{numeric:true})*(sort.descending?-1:1));}\n      const total=rows.length;rows=rows.slice((query.page-1)*query.pageSize,query.page*query.pageSize);check(signal);return {rows,total};\n    },\n    async save(values,previous,signal){\n      check(signal);const fields=validateOutline(values);const rows=read();\n      if(rows.some(row=>row.id!==previous?.id && row.name.toLocaleLowerCase()===values.name.trim().toLocaleLowerCase()))fields.name='A project with this name already exists.';\n      if(Object.values(fields).some(Boolean))throw new OutlineValidationError(fields);\n      const existing=previous?rows.find(row=>row.id===previous.id):null;\n      if(previous && existing?.version!==previous.version)throw new Error('This project changed in another tab. Close and reopen it before saving. Your draft is still here.');\n      const project={...values,name:values.name.trim(),notes:values.notes.trim(),id:previous?.id ?? crypto.randomUUID(),version:(previous?.version ?? 0)+1};\n      check(signal);write(previous?rows.map(row=>row.id===previous.id?project:row):[project,...rows]);return project;\n    },\n    async setStatus(ids,status,signal){check(signal);write(read().map(row=>ids.includes(row.id)?{...row,status,version:row.version+1}:row));},\n    async remove(project,signal){check(signal);const rows=read();if(rows.find(row=>row.id===project.id)?.version!==project.version)throw new Error('This project changed. Refresh the list before deleting it.');write(rows.filter(row=>row.id!==project.id));},\n  };\n}\n",
          "target": "@ui/bld8/blocks/outline-repository.ts",
          "type": "registry:ui"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "bld8-block-project-board",
      "type": "registry:ui",
      "title": "BLD8 project-board source",
      "description": "BLD8 project-board source with editable BLD8 source.",
      "author": "Jaison (https://bld8.dev)",
      "dependencies": [],
      "registryDependencies": [
        "https://ui.bld8.dev/r/bld8-styles.json",
        "https://ui.bld8.dev/r/bld8-index.json",
        "https://ui.bld8.dev/r/bld8-block-styles.json"
      ],
      "files": [
        {
          "path": "registry/bld8/blocks/project-board.tsx",
          "content": "'use client';\nimport './styles.css';\nimport { useState, type FormEvent } from 'react';\nimport { Badge, Button, Dialog, Field, Input, Select } from '../index';\n\nconst stages = ['Planned','In progress','Done'] as const;\ntype Stage = typeof stages[number];\nexport interface BoardTask { id:string; title:string; category:string; stage:Stage }\nconst sample: BoardTask[] = [\n  {id:'1',title:'Review keyboard navigation',category:'Accessibility',stage:'Planned'},\n  {id:'2',title:'Refine the empty state',category:'Interface',stage:'Planned'},\n  {id:'3',title:'Build the settings form',category:'Engineering',stage:'In progress'},\n  {id:'4',title:'Set the spacing scale',category:'Foundations',stage:'Done'},\n];\nexport function ProjectBoard({ initialTasks = sample }: { initialTasks?: BoardTask[] }) {\n  const [tasks,setTasks] = useState(initialTasks);\n  const [open,setOpen] = useState(false);\n  const [title,setTitle] = useState('');\n  const [error,setError] = useState('');\n  const [message,setMessage] = useState('');\n  function add(event: FormEvent) {\n    event.preventDefault(); if (!title.trim()) {setError('Enter a task title.');return;}\n    setTasks(current => [...current,{id:crypto.randomUUID(),title:title.trim(),category:'Workspace',stage:'Planned'}]);\n    setOpen(false);setTitle('');setError('');setMessage('Task added for this session.');\n  }\n  function move(id:string,stage:Stage) { setTasks(current => current.map(task => task.id === id ? {...task,stage} : task)); setMessage(`Task moved to ${stage.toLowerCase()}.`); }\n  return <section className=\"bblocks-board\" aria-label=\"Project board\"><div className=\"bblocks-heading\"><div><p className=\"bblocks-kicker\">A LITTLE MOMENTUM</p><h2>From idea to done.</h2><p className=\"bblocks-muted\">Sample tasks. Change a status or add your own.</p></div><Dialog title=\"Add a task\" description=\"Create a task for this session.\" open={open} onOpenChange={setOpen} trigger={<Button>New task</Button>}><form onSubmit={add} noValidate className=\"bblocks-stack\"><Field label=\"Task title\" error={error} required><Input value={title} onChange={e => setTitle(e.target.value)} /></Field><Button type=\"submit\">Add task</Button></form></Dialog></div><div className=\"bblocks-columns\">{stages.map(stage => <section className=\"bblocks-lane\" key={stage} aria-label={stage + ' tasks'}><div className=\"bblocks-heading\"><h3>{stage}</h3><Badge>{tasks.filter(task => task.stage === stage).length}</Badge></div>{tasks.filter(task => task.stage === stage).map(task => <article className=\"bblocks-task\" key={task.id}><span className=\"bblocks-kicker\">{task.category}</span><h4>{task.title}</h4><Select label={'Status for ' + task.title} value={task.stage} options={stages.map(value => ({value,label:value}))} onValueChange={value => move(task.id,value as Stage)} /></article>)}{!tasks.some(task => task.stage === stage) && <p className=\"bblocks-note\">A little room for the next task.</p>}</section>)}</div><p className=\"bblocks-status\" role=\"status\">{message}</p></section>;\n}\n",
          "target": "@ui/bld8/blocks/project-board.tsx",
          "type": "registry:ui"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "bld8-block-project-planner",
      "type": "registry:ui",
      "title": "BLD8 project-planner source",
      "description": "BLD8 project-planner source with editable BLD8 source.",
      "author": "Jaison (https://bld8.dev)",
      "dependencies": [
        "lucide-react@1.55.0"
      ],
      "registryDependencies": [
        "https://ui.bld8.dev/r/bld8-styles.json",
        "https://ui.bld8.dev/r/bld8-index.json",
        "https://ui.bld8.dev/r/bld8-block-styles.json"
      ],
      "files": [
        {
          "path": "registry/bld8/blocks/project-planner.tsx",
          "content": "'use client';\nimport './styles.css';\nimport { useState, type FormEvent } from 'react';\nimport { CalendarDays, Check, Plus } from 'lucide-react';\nimport { Alert, Badge, Button, DataTable, DatePicker, Dialog, Field, FileUpload, Icon, Input, MultiSelect, formatDateValue, type Column } from '../index';\n\nexport interface PlannedProject { id:string; name:string; due:string; disciplines:string[]; status:'Planned'|'Ready'; attachmentCount:number }\nexport interface ProjectDraft { name:string; due:Date; disciplines:string[]; attachments:File[] }\nexport interface ProjectPlannerProps { initialProjects?:PlannedProject[]; onCreate?:(draft:ProjectDraft)=>Promise<PlannedProject>; onProjectsChange?:(projects:PlannedProject[])=>void }\nconst disciplines=['Design','Engineering','Research','Documentation'].map(label=>({value:label.toLowerCase(),label}));\nconst initial:PlannedProject[]=[\n  {id:'1',name:'Keyboard review',due:'2026-10-20',disciplines:['engineering'],status:'Planned',attachmentCount:2},\n  {id:'2',name:'Interface studies',due:'2026-10-24',disciplines:['design','research'],status:'Planned',attachmentCount:1},\n  {id:'3',name:'Form patterns',due:'2026-10-28',disciplines:['engineering','documentation'],status:'Ready',attachmentCount:0},\n];\nconst columns:Column<PlannedProject>[]=[\n  {key:'name',header:'Project',hideable:false,sortValue:row=>row.name,cell:row=><strong>{row.name}</strong>},\n  {key:'due',header:'Review date',sortValue:row=>row.due,cell:row=><span className=\"bblocks-date\"><Icon icon={CalendarDays} size={14} /><time dateTime={row.due}>{row.due.split('-').reverse().join('/')}</time></span>},\n  {key:'disciplines',header:'Disciplines',cell:row=><span className=\"bblocks-tags\">{row.disciplines.map(value=><Badge key={value}>{disciplines.find(option=>option.value===value)?.label ?? value}</Badge>)}</span>},\n  {key:'status',header:'Status',sortValue:row=>row.status,cell:row=><Badge tone={row.status==='Ready' ? 'success' : 'neutral'}>{row.status}</Badge>},\n];\nexport function ProjectPlanner({initialProjects=initial,onCreate,onProjectsChange}:ProjectPlannerProps) {\n  const [projects,setProjects]=useState(initialProjects); const [selected,setSelected]=useState<string[]>([]);\n  const [open,setOpen]=useState(false); const [name,setName]=useState(''); const [due,setDue]=useState<Date|null>(null);\n  const [tags,setTags]=useState<string[]>(['design']); const [files,setFiles]=useState<File[]>([]);\n  const [error,setError]=useState(''); const [busy,setBusy]=useState(false); const [message,setMessage]=useState('');\n  const change=(next:PlannedProject[])=>{setProjects(next);onProjectsChange?.(next);};\n  async function create(event:FormEvent) {\n    event.preventDefault(); if(!name.trim()) {setError('Enter a project name.');return;} if(!due) {setError('Choose a review date.');return;}\n    if(!tags.length) {setError('Choose at least one discipline.');return;} setError('');setBusy(true);\n    try {\n      const project=onCreate ? await onCreate({name:name.trim(),due,disciplines:tags,attachments:files}) : {id:crypto.randomUUID(),name:name.trim(),due:formatDateValue(due),disciplines:tags,status:'Planned' as const,attachmentCount:files.length};\n      change([...projects,project]);setName('');setDue(null);setTags(['design']);setFiles([]);setOpen(false);setMessage(onCreate ? 'Project added.' : 'Project metadata added for this session. Attachments were not uploaded.');\n    } catch(cause) {setError(cause instanceof Error ? cause.message : 'Unable to create the project. Try again.');} finally {setBusy(false);}\n  }\n  return <section className=\"bblocks-panel\" aria-label=\"Project planner\">\n    <div className=\"bblocks-heading\"><div><p className=\"bblocks-kicker\">THE NEXT USEFUL STEP</p><h2>A little room to plan.</h2><p className=\"bblocks-muted\">Projects, disciplines and review dates in one place.</p></div><Dialog title=\"Plan a project\" description=\"Give the work a name and a review date.\" open={open} onOpenChange={next=>{if(!busy)setOpen(next);}} trigger={<Button leadingIcon={Plus}>Plan project</Button>}>\n      <form className=\"bblocks-stack\" noValidate onSubmit={create}>\n        <Field label=\"Project name\" required error={error && !name.trim() ? error : undefined}><Input value={name} onChange={event=>{setName(event.target.value);setError('');}} disabled={busy} autoComplete=\"off\" /></Field>\n        <DatePicker label=\"Review date\" value={due} onValueChange={setDue} disabled={busy} error={error && name.trim() && !due ? error : undefined} />\n        <MultiSelect label=\"Disciplines\" options={disciplines} value={tags} onValueChange={setTags} disabled={busy} error={error && name.trim() && due && !tags.length ? error : undefined} />\n        {error && name.trim() && due && tags.length>0 && <Alert title=\"Unable to add project\" tone=\"danger\" live>{error}</Alert>}\n        <FileUpload label=\"Reference files\" value={files} onValueChange={setFiles} accept=\".pdf,.txt,.png,.jpg\" maxFiles={3} maxSize={5*1024*1024} disabled={busy} />\n        <p className=\"bblocks-note\">{onCreate ? 'Your create callback handles persistence and attached files.' : 'This preview stores metadata in memory. Files are not uploaded or saved.'}</p>\n        <Button type=\"submit\" loading={busy}>Add project</Button>\n      </form>\n    </Dialog></div>\n    <div className=\"bblocks-planner-summary\"><span><strong>{projects.length}</strong> projects</span><span><strong>{projects.filter(project=>project.status==='Ready').length}</strong> ready for review</span><span><strong>{new Set(projects.flatMap(project=>project.disciplines)).size}</strong> disciplines</span></div>\n    <DataTable caption=\"Planned projects\" rows={projects} columns={columns} rowKey={row=>row.id} rowLabel={row=>row.name} searchText={row=>row.name+' '+row.disciplines.join(' ')} columnVisibility selectable selectedKeys={selected} onSelectedKeysChange={setSelected} filters={[{key:'status',label:'Statuses',options:[{value:'Planned',label:'Planned'},{value:'Ready',label:'Ready'}],value:row=>row.status}]} renderBulkActions={chosen=><Button size=\"sm\" leadingIcon={Check} onClick={()=>{change(projects.map(project=>chosen.some(row=>row.id===project.id) ? {...project,status:'Ready'} : project));setSelected([]);setMessage(chosen.length+' projects marked ready.');}}>Mark ready</Button>} />\n    <p role=\"status\" className=\"bblocks-status\">{message}</p>\n  </section>;\n}\n",
          "target": "@ui/bld8/blocks/project-planner.tsx",
          "type": "registry:ui"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "bld8-block-resource-manager",
      "type": "registry:ui",
      "title": "BLD8 resource-manager source",
      "description": "BLD8 resource-manager source with editable BLD8 source.",
      "author": "Jaison (https://bld8.dev)",
      "dependencies": [
        "lucide-react@1.55.0"
      ],
      "registryDependencies": [
        "https://ui.bld8.dev/r/bld8-styles.json",
        "https://ui.bld8.dev/r/bld8-index.json",
        "https://ui.bld8.dev/r/bld8-block-styles.json"
      ],
      "files": [
        {
          "path": "registry/bld8/blocks/resource-manager.tsx",
          "content": "'use client';\nimport './styles.css';\nimport { useState, type FormEvent } from 'react';\nimport { Archive, Download, FileText, Plus, Undo2 } from 'lucide-react';\nimport { Alert, Badge, Button, DataTable, Dialog, FileUpload, Icon, createTableCSV, type Column } from '../index';\n\nexport interface ResourceRecord {id:string;name:string;type:string;size:number;status:'Active'|'Archived'}\nexport interface ResourceManagerProps { initialRecords?:ResourceRecord[]; onImport?:(files:File[])=>Promise<ResourceRecord[]>; onRecordsChange?:(records:ResourceRecord[])=>void }\nconst initial:ResourceRecord[]=[\n  {id:'1',name:'Interface brief.pdf',type:'PDF',size:148200,status:'Active'},\n  {id:'2',name:'Research notes.txt',type:'TXT',size:4200,status:'Active'},\n  {id:'3',name:'Navigation sketches.png',type:'PNG',size:824000,status:'Active'},\n  {id:'4',name:'Old checklist.txt',type:'TXT',size:2080,status:'Archived'},\n];\nconst columns:Column<ResourceRecord>[]=[\n  {key:'name',header:'File',hideable:false,sortValue:row=>row.name,cell:row=><span className=\"bblocks-date\"><Icon icon={FileText} /><strong>{row.name}</strong></span>},\n  {key:'type',header:'Type',sortValue:row=>row.type,cell:row=><Badge>{row.type}</Badge>},\n  {key:'size',header:'Size',sortValue:row=>row.size,cell:row=><span>{(row.size/1024).toFixed(1)} KB</span>},\n  {key:'status',header:'Status',sortValue:row=>row.status,cell:row=><Badge tone={row.status==='Active' ? 'success' : 'neutral'}>{row.status}</Badge>},\n];\nfunction download(rows:ResourceRecord[]) {\n  const blob=new Blob(['\\uFEFF'+createTableCSV(rows,columns)],{type:'text/csv;charset=utf-8;'}); const url=URL.createObjectURL(blob);\n  const link=document.createElement('a');link.href=url;link.download='resource-metadata.csv';link.click();setTimeout(()=>URL.revokeObjectURL(url),1000);\n}\nexport function ResourceManager({initialRecords=initial,onImport,onRecordsChange}:ResourceManagerProps) {\n  const [records,setRecords]=useState(initialRecords);const [selected,setSelected]=useState<string[]>([]);const [files,setFiles]=useState<File[]>([]);\n  const [open,setOpen]=useState(false);const [busy,setBusy]=useState(false);const [error,setError]=useState('');const [message,setMessage]=useState('');\n  const [undo,setUndo]=useState<{id:string;status:ResourceRecord['status']}[]>([]);\n  const change=(next:ResourceRecord[])=>{setRecords(next);onRecordsChange?.(next);};\n  async function add(event:FormEvent) {\n    event.preventDefault();if(!files.length) {setError('Choose at least one file.');return;} setError('');setBusy(true);\n    try {\n      const added=onImport ? await onImport(files) : files.map(file=>({id:crypto.randomUUID(),name:file.name,type:file.name.split('.').pop()?.toUpperCase() ?? 'FILE',size:file.size,status:'Active' as const}));\n      change([...records,...added]);setFiles([]);setOpen(false);setMessage(onImport ? added.length+' resources imported.' : added.length+' metadata records added. File contents were not stored or uploaded.');\n    } catch(cause) {setError(cause instanceof Error ? cause.message : 'Import failed. Try again.');} finally {setBusy(false);}\n  }\n  return <section className=\"bblocks-panel\" aria-label=\"Resource library\"><div className=\"bblocks-heading\"><div><p className=\"bblocks-kicker\">THE MATERIAL, IN REACH</p><h2>A home for the references.</h2><p className=\"bblocks-muted\">Filter records, export metadata and archive with a way back.</p></div><Dialog title=\"Add resources\" description=\"Select files to add their metadata to the library.\" open={open} onOpenChange={next=>{if(!busy)setOpen(next);}} trigger={<Button leadingIcon={Plus}>Add resources</Button>}>\n    <form className=\"bblocks-stack\" onSubmit={add}><FileUpload label=\"Resource files\" value={files} onValueChange={setFiles} accept=\".pdf,.txt,.png,.jpg\" maxFiles={5} maxSize={10*1024*1024} disabled={busy} />{error && <Alert title=\"Unable to add resources\" tone=\"danger\" live>{error}</Alert>}<p className=\"bblocks-note\">{onImport ? 'Your import callback owns file storage.' : 'This local example saves metadata only. File contents never leave your browser.'}</p><Button type=\"submit\" loading={busy}>Add to library</Button></form>\n  </Dialog></div>\n    <DataTable caption=\"Resources\" rows={records} columns={columns} rowKey={row=>row.id} rowLabel={row=>row.name} searchText={row=>row.name+' '+row.type} pageSize={4} selectable selectedKeys={selected} onSelectedKeysChange={setSelected} columnVisibility density=\"compact\" filters={[{key:'status',label:'Statuses',options:[{value:'Active',label:'Active'},{value:'Archived',label:'Archived'}],value:row=>row.status},{key:'type',label:'Types',options:['PDF','TXT','PNG','JPG'].map(value=>({value,label:value})),value:row=>row.type}]} renderBulkActions={chosen=><><Button leadingIcon={Download} variant=\"secondary\" size=\"sm\" onClick={()=>{download(chosen);setMessage(chosen.length+' metadata records exported.');}}>Export CSV</Button><Button leadingIcon={Archive} size=\"sm\" onClick={()=>{setUndo(chosen.map(row=>({id:row.id,status:row.status})));change(records.map(row=>chosen.some(item=>item.id===row.id) ? {...row,status:'Archived'} : row));setSelected([]);setMessage(chosen.length+' resources archived.');}}>Archive</Button></>} />\n    <div className=\"bblocks-resource-footer\"><p role=\"status\" className=\"bblocks-status\">{message}</p>{undo.length>0 && <Button variant=\"ghost\" size=\"sm\" leadingIcon={Undo2} onClick={()=>{change(records.map(row=>{const previous=undo.find(item=>item.id===row.id);return previous ? {...row,status:previous.status} : row;}));setUndo([]);setMessage('Archive undone.');}}>Undo archive</Button>}</div>\n    <p className=\"bblocks-note\">Illustrative file metadata. No file hosting or storage service is included.</p>\n  </section>;\n}\n",
          "target": "@ui/bld8/blocks/resource-manager.tsx",
          "type": "registry:ui"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "bld8-block-sign-in",
      "type": "registry:ui",
      "title": "BLD8 sign-in source",
      "description": "BLD8 sign-in source with editable BLD8 source.",
      "author": "Jaison (https://bld8.dev)",
      "dependencies": [],
      "registryDependencies": [
        "https://ui.bld8.dev/r/bld8-styles.json",
        "https://ui.bld8.dev/r/bld8-index.json",
        "https://ui.bld8.dev/r/bld8-block-styles.json"
      ],
      "files": [
        {
          "path": "registry/bld8/blocks/sign-in.tsx",
          "content": "'use client';\nimport './styles.css';\nimport { useState, type FormEvent } from 'react';\nimport { Button, Field, Input, Icon } from '../index';\n\nexport function SignInForm({ onSignIn }: { onSignIn?: (email: string, password: string) => Promise<void> }) {\n  const [email, setEmail] = useState('');\n  const [password, setPassword] = useState('');\n  const [errors, setErrors] = useState<{ email?: string; password?: string }>({});\n  const [busy, setBusy] = useState(false);\n  const [message, setMessage] = useState('');\n  async function submit(event: FormEvent) {\n    event.preventDefault();\n    const next = { email: /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(email.trim()) ? undefined : 'Enter a valid email address.', password: password.length >= 8 ? undefined : 'Use at least 8 characters.' };\n    setErrors(next); setMessage('');\n    if (next.email || next.password) return;\n    setBusy(true);\n    try {\n      if (onSignIn) await onSignIn(email.trim(), password);\n      setMessage(onSignIn ? 'Sign-in request completed.' : 'Form validated. Connect your authentication service to sign in.');\n      setPassword('');\n    } catch { setMessage('Unable to sign in. Please try again.'); }\n    finally { setBusy(false); }\n  }\n  return <section className=\"bblocks-auth bblocks-panel\" aria-label=\"Sign-in form\">\n    <span className=\"bblocks-symbol\" aria-hidden=\"true\"><Icon name=\"plus\" /></span>\n    <p className=\"bblocks-kicker\">YOUR WORKSPACE</p><h2>Welcome back.</h2><p className=\"bblocks-muted\">A little space to do your best work.</p>\n    <form className=\"bblocks-stack\" onSubmit={submit} noValidate>\n      <Field label=\"Email\" error={errors.email} required><Input type=\"email\" autoComplete=\"username\" value={email} placeholder=\"you@example.com\" onChange={e => setEmail(e.target.value)} /></Field>\n      <Field label=\"Password\" error={errors.password} required><Input type=\"password\" autoComplete=\"current-password\" value={password} onChange={e => setPassword(e.target.value)} /></Field>\n      <Button type=\"submit\" loading={busy}>Continue <Icon /></Button>\n    </form>\n    <p className=\"bblocks-status\" role=\"status\">{message}</p>\n    {!onSignIn && <p className=\"bblocks-note\">Demo form. No account is created and no credentials are sent.</p>}\n  </section>;\n}\n",
          "target": "@ui/bld8/blocks/sign-in.tsx",
          "type": "registry:ui"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "bld8-block-team",
      "type": "registry:ui",
      "title": "BLD8 team source",
      "description": "BLD8 team source with editable BLD8 source.",
      "author": "Jaison (https://bld8.dev)",
      "dependencies": [],
      "registryDependencies": [
        "https://ui.bld8.dev/r/bld8-styles.json",
        "https://ui.bld8.dev/r/bld8-index.json",
        "https://ui.bld8.dev/r/bld8-block-styles.json"
      ],
      "files": [
        {
          "path": "registry/bld8/blocks/team.tsx",
          "content": "'use client';\nimport './styles.css';\nimport { useState, type FormEvent } from 'react';\nimport { Avatar, Badge, Button, DataTable, Dialog, Field, Input, Select, type Column } from '../index';\n\nexport interface TeamMember { id:string; name:string; email:string; role:string; status:'Active' | 'Invited' }\nconst sample: TeamMember[] = [\n  {id:'1',name:'Maya Chen',email:'maya@example.com',role:'Admin',status:'Active'},\n  {id:'2',name:'Oliver Reed',email:'oliver@example.com',role:'Editor',status:'Active'},\n  {id:'3',name:'Sam Rivera',email:'sam@example.com',role:'Editor',status:'Active'},\n  {id:'4',name:'Avery Brooks',email:'avery@example.com',role:'Viewer',status:'Active'},\n];\nexport function TeamDirectory({ initialMembers = sample }: { initialMembers?: TeamMember[] }) {\n  const [members,setMembers] = useState(initialMembers);\n  const [open,setOpen] = useState(false);\n  const [email,setEmail] = useState('');\n  const [role,setRole] = useState('Editor');\n  const [error,setError] = useState('');\n  const [message,setMessage] = useState('');\n  const columns: Column<TeamMember>[] = [\n    {key:'name',header:'Person',sortValue:row => row.name,cell:row => <div className=\"bblocks-person\"><Avatar name={row.name} /><div><strong>{row.name}</strong><small>{row.email}</small></div></div>},\n    {key:'role',header:'Role',sortValue:row => row.role,cell:row => row.role},\n    {key:'status',header:'Status',cell:row => <Badge tone={row.status === 'Active' ? 'success' : 'accent'}>{row.status}</Badge>},\n  ];\n  function invite(event: FormEvent) {\n    event.preventDefault(); const address = email.trim();\n    if (!/^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(address)) { setError('Enter a valid email address.'); return; }\n    if (members.some(member => member.email.toLowerCase() === address.toLowerCase())) { setError('This email is already in the workspace.'); return; }\n    setMembers(current => [...current,{id:crypto.randomUUID(),name:address.split('@')[0],email:address,role,status:'Invited'}]);\n    setOpen(false); setEmail(''); setError(''); setMessage('Invitation added to this demo. No email was sent.');\n  }\n  return <section className=\"bblocks-panel\" aria-label=\"Team directory\"><div className=\"bblocks-heading\"><div><p className=\"bblocks-kicker\">PEOPLE & ACCESS</p><h2>Better, together.</h2><p className=\"bblocks-muted\">{members.length} people in this sample workspace.</p></div><Dialog open={open} onOpenChange={next => {setOpen(next);setError('');}} title=\"Invite a teammate\" description=\"Add a person to this sample workspace. No invitation email is sent.\" trigger={<Button>Invite person</Button>}><form className=\"bblocks-stack\" onSubmit={invite} noValidate><Field label=\"Invite email\" error={error} required><Input type=\"email\" value={email} onChange={e => setEmail(e.target.value)} /></Field><Select label=\"Workspace role\" options={['Admin','Editor','Viewer'].map(value => ({value,label:value}))} value={role} onValueChange={value => { if (value) setRole(value); }} /><Button type=\"submit\">Add invitation</Button></form></Dialog></div><DataTable caption=\"Team members\" rows={members} columns={columns} rowKey={row => row.id} searchText={row => row.name + ' ' + row.email + ' ' + row.role} pageSize={5} /><p className=\"bblocks-status\" role=\"status\">{message}</p></section>;\n}\n",
          "target": "@ui/bld8/blocks/team.tsx",
          "type": "registry:ui"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "bld8-block-templates",
      "type": "registry:ui",
      "title": "BLD8 templates source",
      "description": "BLD8 templates source with editable BLD8 source.",
      "author": "Jaison (https://bld8.dev)",
      "dependencies": [],
      "registryDependencies": [
        "https://ui.bld8.dev/r/bld8-styles.json",
        "https://ui.bld8.dev/r/bld8-block-account-settings.json",
        "https://ui.bld8.dev/r/bld8-block-sign-in.json",
        "https://ui.bld8.dev/r/bld8-block-project-board.json",
        "https://ui.bld8.dev/r/bld8-block-team.json",
        "https://ui.bld8.dev/r/bld8-block-workspace.json",
        "https://ui.bld8.dev/r/bld8-index.json",
        "https://ui.bld8.dev/r/bld8-block-styles.json"
      ],
      "files": [
        {
          "path": "registry/bld8/blocks/templates.tsx",
          "content": "'use client';\nimport './styles.css';\nimport { useId, useState } from 'react';\nimport { Badge, Button, Dialog, Icon } from '../index';\nimport { AccountSettings } from './account-settings';\nimport { SignInForm } from './sign-in';\nimport { ProjectBoard } from './project-board';\nimport { TeamDirectory } from './team';\nimport { WorkspaceOverview } from './workspace';\n\nexport function StudioTemplate() {\n  const [view,setView] = useState('Overview');\n  return <div className=\"bblocks-studio\"><aside className=\"bblocks-studio-sidebar\"><a href=\"#\" onClick={event => {event.preventDefault();setView('Overview');}} className=\"bblocks-wordmark\"><span aria-hidden=\"true\">✳</span> Studio</a><p className=\"bblocks-kicker\">YOUR WORKSPACE</p><nav aria-label=\"Studio sections\">{['Overview','Projects','People','Settings'].map(label => <Button key={label} variant={label === view ? 'primary' : 'ghost'} aria-pressed={label === view} onClick={() => setView(label)}>{label}</Button>)}</nav><p className=\"bblocks-note\">A working interface starter.<br />All data is illustrative.</p></aside><div className=\"bblocks-studio-main\"><div className=\"bblocks-studio-top\"><span>{view}</span><Badge tone=\"accent\">Sample workspace</Badge></div>{view === 'Overview' && <WorkspaceOverview />}{view === 'Projects' && <ProjectBoard />}{view === 'People' && <TeamDirectory />}{view === 'Settings' && <AccountSettings />}</div></div>;\n}\nexport function LaunchTemplate() {\n  const prefix = useId();\n  return <div className=\"bblocks-launch\"><header><a className=\"bblocks-wordmark\" href={'#' + prefix + '-top'}><span aria-hidden=\"true\">✳</span> Gather</a><a href={'#' + prefix + '-details'}>The details <Icon /></a></header><section className=\"bblocks-launch-hero\" id={prefix + '-top'}><div><p className=\"bblocks-kicker\">LESS NOISE. MORE ROOM.</p><h2>A calmer place<br />for your next idea.</h2><p>Bring the work, people and small decisions into one clear workspace.</p><Dialog title=\"Try the sign-in form\" description=\"This starter includes an interface, not an authentication service.\" trigger={<Button>Try the demo <Icon /></Button>}><SignInForm /></Dialog><span className=\"bblocks-note\">An illustrative product, built with BLD8 UI.</span></div><div className=\"bblocks-launch-sketch\" aria-hidden=\"true\"><div><span className=\"bblocks-kicker\">THE WEEK, AT A GLANCE</span><strong>A little progress.</strong><div className=\"bblocks-sketch-row\"><span>Navigation study</span><Badge tone=\"accent\">In progress</Badge></div><div className=\"bblocks-sketch-row\"><span>First ideas</span><Badge tone=\"success\">Done</Badge></div><div className=\"bblocks-sketch-row\"><span>Next conversation</span><Badge>Planned</Badge></div></div></div></section><section className=\"bblocks-launch-features\" id={prefix + '-details'}>{[['01','Keep the work in view.','A clear overview without the clutter.'],['02','Make room for people.','A shared space with considered controls.'],['03','Let the details settle.','Typography, spacing and motion in a common rhythm.']].map(([number,title,copy]) => <article key={number}><span className=\"bblocks-kicker\">{number} / THE DETAILS</span><h3>{title}</h3><p>{copy}</p></article>)}</section><footer>Gather / an interface starter <span>Made with BLD8 UI</span></footer></div>;\n}\n",
          "target": "@ui/bld8/blocks/templates.tsx",
          "type": "registry:ui"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "bld8-block-workspace",
      "type": "registry:ui",
      "title": "BLD8 workspace source",
      "description": "BLD8 workspace source with editable BLD8 source.",
      "author": "Jaison (https://bld8.dev)",
      "dependencies": [],
      "registryDependencies": [
        "https://ui.bld8.dev/r/bld8-styles.json",
        "https://ui.bld8.dev/r/bld8-block-metrics.json",
        "https://ui.bld8.dev/r/bld8-index.json",
        "https://ui.bld8.dev/r/bld8-block-styles.json"
      ],
      "files": [
        {
          "path": "registry/bld8/blocks/workspace.tsx",
          "content": "'use client';\nimport './styles.css';\nimport { useState } from 'react';\nimport { Avatar, Badge, Button } from '../index';\nimport { MetricsOverview } from './metrics';\n\nconst activity = [\n  { name:'Maya Chen', action:'updated the navigation study', time:'12 min ago', kind:'Updates' },\n  { name:'Oliver Reed', action:'recorded a typography decision', time:'38 min ago', kind:'Decisions' },\n  { name:'Sam Rivera', action:'shared the first dashboard draft', time:'1 hour ago', kind:'Updates' },\n];\nexport function WorkspaceOverview() {\n  const [filter,setFilter] = useState('All');\n  const items = activity.filter(item => filter === 'All' || item.kind === filter);\n  return <div className=\"bblocks-stack\"><MetricsOverview /><section className=\"bblocks-panel\" aria-label=\"Workspace activity\"><div className=\"bblocks-heading\"><div><p className=\"bblocks-kicker\">IN THE WORKSPACE</p><h2>Small steps, together.</h2></div><Badge>Sample data</Badge></div><div className=\"bblocks-segment\" role=\"group\" aria-label=\"Activity filter\">{['All','Updates','Decisions'].map(label => <Button key={label} size=\"sm\" variant={filter === label ? 'primary' : 'ghost'} aria-pressed={filter === label} onClick={() => setFilter(label)}>{label}</Button>)}</div><ul className=\"bblocks-activity\">{items.map(item => <li key={item.name}><Avatar name={item.name} /><div><strong>{item.name}</strong><p>{item.action}</p></div><time>{item.time}</time></li>)}</ul><p className=\"bblocks-note\" role=\"status\">{items.length} activity {items.length === 1 ? 'item' : 'items'}. Illustrative records, not live analytics.</p></section></div>;\n}\n",
          "target": "@ui/bld8/blocks/workspace.tsx",
          "type": "registry:ui"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "bld8-block-styles",
      "type": "registry:ui",
      "title": "BLD8 block styles",
      "description": "BLD8 block styles with editable BLD8 source.",
      "author": "Jaison (https://bld8.dev)",
      "dependencies": [],
      "registryDependencies": [
        "https://ui.bld8.dev/r/bld8-styles.json"
      ],
      "files": [
        {
          "path": "registry/bld8/blocks/styles.css",
          "content": ".bblocks-root { container-type:inline-size; container-name:bld8-preview; }\n.bblocks-panel { background:var(--bui-bg); border-radius:var(--bui-panel-radius); padding:clamp(1.25rem,3vw,2rem); }\n.bblocks-stack { display:flex; flex-direction:column; gap:1.5rem; min-width:0; }\n.bblocks-heading { display:flex; justify-content:space-between; align-items:center; gap:1.25rem; margin-bottom:1.5rem; }\n.bblocks-heading:last-child { margin-bottom:0; }\n.bblocks-heading h2,.bblocks-auth h2 { margin:.5rem 0; font-size:clamp(1.5rem,2.6vw,2rem); letter-spacing:-.05em; line-height:1.2; }\n.bblocks-kicker { font:10px/1.5 Consolas,monospace; letter-spacing:.1em; color:var(--bui-muted); }\n.bblocks-muted { color:var(--bui-muted); font-size:.8125rem; }\n.bblocks-note { color:var(--bui-muted); font-size:.6875rem; line-height:1.7; }\n.bblocks-status { min-height:1.7em; color:var(--bui-muted); font-size:.75rem; margin:.75rem 0 0; }\n.bblocks-auth { max-width:420px; margin:auto; }\n.bblocks-auth form { margin-top:2rem; }\n.bblocks-auth .bui-button { width:100%; }\n.bblocks-symbol { display:grid; place-items:center; width:40px; height:40px; background:var(--bui-accent); color:var(--bui-accent-ink); border-radius:6px; margin-bottom:2rem; }\n.bblocks-form-grid { display:grid; grid-template-columns:1fr 1fr; gap:1.25rem; }\n.bblocks-rule { border-block:1px solid var(--bui-line); padding:1.5rem 0; }\n.bblocks-segment { display:flex; gap:4px; flex-wrap:wrap; }\n.bblocks-stats { display:grid; grid-template-columns:repeat(3,minmax(0,1fr)); gap:1rem; margin:1.5rem 0; }\n.bblocks-stat { padding:1.5rem; background:var(--bui-bg); border-radius:var(--bui-panel-radius); }\n.bblocks-stat>span:first-child { font-size:.75rem; color:var(--bui-muted); display:block; }\n.bblocks-stat>strong { display:block; font-size:clamp(1.8rem,3vw,2.5rem); font-weight:550; line-height:1.2; letter-spacing:-.06em; margin:1rem 0; }\n.bblocks-chart { margin:0; }\n.bblocks-chart figcaption { display:flex; justify-content:space-between; flex-wrap:wrap; gap:.5rem; font-size:.8125rem; }\n.bblocks-bars { display:flex; gap:clamp(.5rem,2vw,1.5rem); height:160px; margin-top:2rem; padding-bottom:24px; }\n.bblocks-bars>div { flex:1; display:flex; flex-direction:column; justify-content:flex-end; position:relative; }\n.bblocks-bars span { display:block; background:var(--bui-primary); border-radius:4px 4px 0 0; transition:height var(--bui-duration-slow) var(--bui-ease); }\n.bblocks-bars>div:nth-last-child(2) span { background:var(--bui-accent); }\n.bblocks-bars small { position:absolute; top:calc(100% + 6px); width:100%; text-align:center; font-size:.625rem; color:var(--bui-muted); }\n.bblocks-activity { list-style:none; margin:1.25rem 0; padding:0; }\n.bblocks-activity li { display:flex; gap:1rem; align-items:center; padding:1rem 0; border-top:1px solid var(--bui-line); }\n.bblocks-activity strong { font-size:.8125rem; font-weight:550; }\n.bblocks-activity p { margin:.2rem 0 0; font-size:.75rem; color:var(--bui-muted); }\n.bblocks-activity time { margin-left:auto; font-size:.625rem; color:var(--bui-muted); white-space:nowrap; }\n.bblocks-person { display:flex; align-items:center; gap:.75rem; }\n.bblocks-person strong { font-size:.8125rem; font-weight:500; }\n.bblocks-person small { display:block; font-size:.6875rem; color:var(--bui-muted); }\n.bblocks-columns { display:grid; grid-template-columns:repeat(3,minmax(0,1fr)); gap:1rem; }\n.bblocks-lane { background:var(--bui-surface); border-radius:8px; padding:1rem; min-width:0; }\n.bblocks-lane h3 { font-size:.8125rem; letter-spacing:-.02em; }\n.bblocks-lane>.bblocks-heading { margin-bottom:1rem; }\n.bblocks-task { background:var(--bui-bg); border-radius:6px; padding:1rem; margin-bottom:.75rem; }\n.bblocks-task h4 { font-size:.875rem; font-weight:550; line-height:1.5; margin:.5rem 0 1rem; letter-spacing:-.02em; }\n.bblocks-task .bui-label { font-size:.625rem; }\n.bblocks-task .bui-select-trigger { font-size:.6875rem; }\n.bblocks-studio { display:grid; grid-template-columns:180px minmax(0,1fr); background:var(--bui-canvas); border-radius:10px; overflow:hidden; }\n.bblocks-studio-sidebar { background:var(--bui-bg); padding:1.5rem 1rem; }\n.bblocks-studio-sidebar>.bblocks-kicker { margin:3rem .5rem 1rem; }\n.bblocks-studio-sidebar nav { display:flex; flex-direction:column; gap:.4rem; }\n.bblocks-studio-sidebar nav button { justify-content:flex-start; }\n.bblocks-studio-sidebar>.bblocks-note { margin:3rem .5rem 1rem; }\n.bblocks-wordmark { display:inline-flex; align-items:center; gap:.65rem; font-weight:650; font-size:1.125rem; text-decoration:none; letter-spacing:-.04em; }\n.bblocks-wordmark>span { color:var(--bui-ink); background:var(--bui-accent); display:grid; place-items:center; width:28px; height:28px; border-radius:4px; }\n.bblocks-studio-main { padding:1.5rem; min-width:0; }\n.bblocks-studio-top { display:flex; justify-content:space-between; align-items:center; padding-bottom:1.25rem; margin-bottom:2rem; border-bottom:1px solid var(--bui-line); font-size:.8125rem; }\n.bblocks-launch { background:var(--bui-canvas); padding:clamp(1.25rem,4vw,3rem); border-radius:10px; }\n.bblocks-launch>header { display:flex; justify-content:space-between; gap:1rem; align-items:center; }\n.bblocks-launch>header>a:last-child { font-size:.75rem; display:inline-flex; align-items:center; gap:.5rem; text-decoration:none; }\n.bblocks-launch-hero { display:grid; grid-template-columns:1.1fr 1fr; align-items:center; gap:2rem; padding:4rem 0; }\n.bblocks-launch-hero h2 { font-size:clamp(2rem,4vw,3.5rem); line-height:1.08; letter-spacing:-.06em; margin:1.5rem 0; }\n.bblocks-launch-hero p:not(.bblocks-kicker) { font-size:.875rem; color:var(--bui-muted); max-width:340px; margin:1.5rem 0; }\n.bblocks-launch-hero .bblocks-note { display:block; margin-top:1rem; }\n.bblocks-launch-sketch { padding:1.25rem; background:var(--bui-accent); border-radius:8px; color:var(--bui-accent-ink); }\n.bblocks-launch-sketch>div { background:var(--bui-bg); color:var(--bui-ink); padding:1.5rem; border-radius:6px; }\n.bblocks-launch-sketch strong { display:block; font-size:1.75rem; font-weight:550; letter-spacing:-.05em; margin:1rem 0 1.5rem; }\n.bblocks-sketch-row { display:flex; justify-content:space-between; gap:.5rem; align-items:center; border-top:1px solid var(--bui-line); padding:.75rem 0; font-size:.6875rem; }\n.bblocks-launch-features { display:grid; grid-template-columns:repeat(3,minmax(0,1fr)); gap:1.5rem; padding:2rem 0; border-top:1px solid var(--bui-line); }\n.bblocks-launch-features h3 { font-size:1rem; margin:1rem 0 .5rem; }\n.bblocks-launch-features p { color:var(--bui-muted); font-size:.75rem; }\n.bblocks-launch>footer { display:flex; justify-content:space-between; flex-wrap:wrap; gap:1rem; border-top:1px solid var(--bui-line); padding-top:1.5rem; font-size:.625rem; color:var(--bui-muted); }\n@media(max-width:680px) {\n  .bblocks-heading { flex-wrap:wrap; align-items:flex-start; }\n  .bblocks-form-grid,.bblocks-columns { grid-template-columns:1fr; }\n  .bblocks-stat { padding:1rem; }\n  .bblocks-stat>strong { font-size:1.6rem; }\n  .bblocks-studio { grid-template-columns:1fr; }\n  .bblocks-studio-sidebar { padding:1rem; }\n  .bblocks-studio-sidebar nav { flex-direction:row; flex-wrap:wrap; margin-top:1rem; }\n  .bblocks-studio-sidebar>.bblocks-kicker,.bblocks-studio-sidebar>.bblocks-note { display:none; }\n  .bblocks-studio-main { padding:1rem; }\n  .bblocks-launch-hero,.bblocks-launch-features { grid-template-columns:1fr; }\n  .bblocks-launch-hero { padding:2.5rem 0; }\n  .bblocks-activity time { display:none; }\n}\n@media(max-width:400px) { .bblocks-stats { gap:.5rem; }.bblocks-stat { padding:.75rem; }.bblocks-stat>strong { font-size:1.4rem; } }\n@container bld8-preview (max-width:680px) {\n  .bblocks-heading { flex-wrap:wrap; align-items:flex-start; }\n  .bblocks-form-grid,.bblocks-columns { grid-template-columns:1fr; }\n  .bblocks-stat { padding:1rem; }.bblocks-stat>strong { font-size:1.6rem; }\n  .bblocks-studio { grid-template-columns:1fr; }.bblocks-studio-sidebar { padding:1rem; }\n  .bblocks-studio-sidebar nav { flex-direction:row; flex-wrap:wrap; margin-top:1rem; }\n  .bblocks-studio-sidebar>.bblocks-kicker,.bblocks-studio-sidebar>.bblocks-note { display:none; }.bblocks-studio-main { padding:1rem; }\n  .bblocks-launch-hero,.bblocks-launch-features { grid-template-columns:1fr; }.bblocks-launch-hero { padding:2.5rem 0; }.bblocks-activity time { display:none; }\n}\n@media(prefers-reduced-motion:reduce) { .bblocks-bars span { transition:none; } }\n.bblocks-date { display:inline-flex; align-items:center; gap:8px; }\n.bblocks-tags { display:inline-flex; gap:4px; flex-wrap:wrap; }\n.bblocks-planner-summary { display:flex; flex-wrap:wrap; gap:24px; padding:16px 0; margin-bottom:16px; border-block:1px solid var(--bui-line); color:var(--bui-muted); font-size:.75rem; }\n.bblocks-planner-summary strong { color:var(--bui-ink); font-size:1rem; margin-right:6px; }\n.bblocks-resource-footer { display:flex; align-items:center; justify-content:space-between; flex-wrap:wrap; gap:8px; margin-block:12px; }\n.bblocks-operations { background:var(--bui-canvas); padding:clamp(16px,4vw,36px); border-radius:10px; }\n.bblocks-operations-header { display:flex; align-items:center; gap:16px; flex-wrap:wrap; padding-bottom:24px; border-bottom:1px solid var(--bui-line); }\n.bblocks-operations-header>.bui-button { margin-left:auto; }\n.bblocks-operations-intro { padding:36px 0 24px; }\n.bblocks-operations-intro h2 { font-size:clamp(1.75rem,4vw,2.5rem); font-weight:500; line-height:1.2; letter-spacing:-.05em; margin:12px 0; outline:none; }\n.bblocks-operations-nav { display:flex; gap:6px; flex-wrap:wrap; margin-bottom:20px; }\n.bblocks-operations>footer { margin-top:24px; }\n@container bld8-preview (max-width:550px) { .bblocks-panel>.bblocks-heading { flex-direction:column; align-items:flex-start; } .bblocks-operations-header>.bui-badge { display:none; } }\n.bblocks-operations-layout { margin-top:24px; align-items:stretch; }\n.bblocks-operations-toolbar { display:flex; align-items:center; gap:12px; font-size:.75rem; }\n.bblocks-operations-layout .bblocks-operations-intro { padding:20px 0 24px; }\n\n.bblocks-inline-actions {display:flex;gap:8px;align-items:center;flex-wrap:wrap}\n.bblocks-project-name {white-space:normal;text-align:start;justify-content:flex-start;max-width:100%}\n\n.bblocks-table-options>.bui-field {width:180px;max-width:100%;flex:0 0 auto}\n.bblocks-project-name {padding-inline:0}\n",
          "target": "@ui/bld8/blocks/styles.css",
          "type": "registry:file"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "button",
      "type": "registry:ui",
      "title": "BLD8 button",
      "description": "BLD8 button with editable BLD8 source.",
      "author": "Jaison (https://bld8.dev)",
      "dependencies": [],
      "registryDependencies": [
        "https://ui.bld8.dev/r/bld8-core.json"
      ],
      "files": [
        {
          "path": "registry/bld8/button.tsx",
          "content": "'use client';\nexport * from './core';\n",
          "target": "@ui/bld8/button.tsx",
          "type": "registry:ui"
        }
      ],
      "docs": "React 19 is required. Source is installed inside your configured UI directory under bld8/. Styles are imported by the components. Wrap overlays in UIProvider from bld8/overlays and set body { position: relative; }. Keep the included licences. Compiled utilities cover the shipped components; use ordinary CSS or your own Tailwind build for new utility classes."
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "icon-button",
      "type": "registry:ui",
      "title": "BLD8 icon-button",
      "description": "BLD8 icon-button with editable BLD8 source.",
      "author": "Jaison (https://bld8.dev)",
      "dependencies": [],
      "registryDependencies": [
        "https://ui.bld8.dev/r/bld8-core.json"
      ],
      "files": [
        {
          "path": "registry/bld8/icon-button.tsx",
          "content": "'use client';\nexport * from './core';\n",
          "target": "@ui/bld8/icon-button.tsx",
          "type": "registry:ui"
        }
      ],
      "docs": "React 19 is required. Source is installed inside your configured UI directory under bld8/. Styles are imported by the components. Wrap overlays in UIProvider from bld8/overlays and set body { position: relative; }. Keep the included licences. Compiled utilities cover the shipped components; use ordinary CSS or your own Tailwind build for new utility classes."
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "input",
      "type": "registry:ui",
      "title": "BLD8 input",
      "description": "BLD8 input with editable BLD8 source.",
      "author": "Jaison (https://bld8.dev)",
      "dependencies": [],
      "registryDependencies": [
        "https://ui.bld8.dev/r/bld8-core.json"
      ],
      "files": [
        {
          "path": "registry/bld8/input.tsx",
          "content": "'use client';\nexport * from './core';\n",
          "target": "@ui/bld8/input.tsx",
          "type": "registry:ui"
        }
      ],
      "docs": "React 19 is required. Source is installed inside your configured UI directory under bld8/. Styles are imported by the components. Wrap overlays in UIProvider from bld8/overlays and set body { position: relative; }. Keep the included licences. Compiled utilities cover the shipped components; use ordinary CSS or your own Tailwind build for new utility classes."
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "textarea",
      "type": "registry:ui",
      "title": "BLD8 textarea",
      "description": "BLD8 textarea with editable BLD8 source.",
      "author": "Jaison (https://bld8.dev)",
      "dependencies": [],
      "registryDependencies": [
        "https://ui.bld8.dev/r/bld8-core.json"
      ],
      "files": [
        {
          "path": "registry/bld8/textarea.tsx",
          "content": "'use client';\nexport * from './core';\n",
          "target": "@ui/bld8/textarea.tsx",
          "type": "registry:ui"
        }
      ],
      "docs": "React 19 is required. Source is installed inside your configured UI directory under bld8/. Styles are imported by the components. Wrap overlays in UIProvider from bld8/overlays and set body { position: relative; }. Keep the included licences. Compiled utilities cover the shipped components; use ordinary CSS or your own Tailwind build for new utility classes."
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "checkbox",
      "type": "registry:ui",
      "title": "BLD8 checkbox",
      "description": "BLD8 checkbox with editable BLD8 source.",
      "author": "Jaison (https://bld8.dev)",
      "dependencies": [],
      "registryDependencies": [
        "https://ui.bld8.dev/r/bld8-core.json"
      ],
      "files": [
        {
          "path": "registry/bld8/checkbox.tsx",
          "content": "'use client';\nexport * from './core';\n",
          "target": "@ui/bld8/checkbox.tsx",
          "type": "registry:ui"
        }
      ],
      "docs": "React 19 is required. Source is installed inside your configured UI directory under bld8/. Styles are imported by the components. Wrap overlays in UIProvider from bld8/overlays and set body { position: relative; }. Keep the included licences. Compiled utilities cover the shipped components; use ordinary CSS or your own Tailwind build for new utility classes."
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "switch",
      "type": "registry:ui",
      "title": "BLD8 switch",
      "description": "BLD8 switch with editable BLD8 source.",
      "author": "Jaison (https://bld8.dev)",
      "dependencies": [],
      "registryDependencies": [
        "https://ui.bld8.dev/r/bld8-core.json"
      ],
      "files": [
        {
          "path": "registry/bld8/switch.tsx",
          "content": "'use client';\nexport * from './core';\n",
          "target": "@ui/bld8/switch.tsx",
          "type": "registry:ui"
        }
      ],
      "docs": "React 19 is required. Source is installed inside your configured UI directory under bld8/. Styles are imported by the components. Wrap overlays in UIProvider from bld8/overlays and set body { position: relative; }. Keep the included licences. Compiled utilities cover the shipped components; use ordinary CSS or your own Tailwind build for new utility classes."
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "radio",
      "type": "registry:ui",
      "title": "BLD8 radio",
      "description": "BLD8 radio with editable BLD8 source.",
      "author": "Jaison (https://bld8.dev)",
      "dependencies": [],
      "registryDependencies": [
        "https://ui.bld8.dev/r/bld8-core.json"
      ],
      "files": [
        {
          "path": "registry/bld8/radio.tsx",
          "content": "'use client';\nexport * from './core';\n",
          "target": "@ui/bld8/radio.tsx",
          "type": "registry:ui"
        }
      ],
      "docs": "React 19 is required. Source is installed inside your configured UI directory under bld8/. Styles are imported by the components. Wrap overlays in UIProvider from bld8/overlays and set body { position: relative; }. Keep the included licences. Compiled utilities cover the shipped components; use ordinary CSS or your own Tailwind build for new utility classes."
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "slider",
      "type": "registry:ui",
      "title": "BLD8 slider",
      "description": "BLD8 slider with editable BLD8 source.",
      "author": "Jaison (https://bld8.dev)",
      "dependencies": [],
      "registryDependencies": [
        "https://ui.bld8.dev/r/bld8-core.json"
      ],
      "files": [
        {
          "path": "registry/bld8/slider.tsx",
          "content": "'use client';\nexport * from './core';\n",
          "target": "@ui/bld8/slider.tsx",
          "type": "registry:ui"
        }
      ],
      "docs": "React 19 is required. Source is installed inside your configured UI directory under bld8/. Styles are imported by the components. Wrap overlays in UIProvider from bld8/overlays and set body { position: relative; }. Keep the included licences. Compiled utilities cover the shipped components; use ordinary CSS or your own Tailwind build for new utility classes."
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "badge",
      "type": "registry:ui",
      "title": "BLD8 badge",
      "description": "BLD8 badge with editable BLD8 source.",
      "author": "Jaison (https://bld8.dev)",
      "dependencies": [],
      "registryDependencies": [
        "https://ui.bld8.dev/r/bld8-core.json"
      ],
      "files": [
        {
          "path": "registry/bld8/badge.tsx",
          "content": "'use client';\nexport * from './core';\n",
          "target": "@ui/bld8/badge.tsx",
          "type": "registry:ui"
        }
      ],
      "docs": "React 19 is required. Source is installed inside your configured UI directory under bld8/. Styles are imported by the components. Wrap overlays in UIProvider from bld8/overlays and set body { position: relative; }. Keep the included licences. Compiled utilities cover the shipped components; use ordinary CSS or your own Tailwind build for new utility classes."
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "alert",
      "type": "registry:ui",
      "title": "BLD8 alert",
      "description": "BLD8 alert with editable BLD8 source.",
      "author": "Jaison (https://bld8.dev)",
      "dependencies": [],
      "registryDependencies": [
        "https://ui.bld8.dev/r/bld8-core.json"
      ],
      "files": [
        {
          "path": "registry/bld8/alert.tsx",
          "content": "'use client';\nexport * from './core';\n",
          "target": "@ui/bld8/alert.tsx",
          "type": "registry:ui"
        }
      ],
      "docs": "React 19 is required. Source is installed inside your configured UI directory under bld8/. Styles are imported by the components. Wrap overlays in UIProvider from bld8/overlays and set body { position: relative; }. Keep the included licences. Compiled utilities cover the shipped components; use ordinary CSS or your own Tailwind build for new utility classes."
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "progress",
      "type": "registry:ui",
      "title": "BLD8 progress",
      "description": "BLD8 progress with editable BLD8 source.",
      "author": "Jaison (https://bld8.dev)",
      "dependencies": [],
      "registryDependencies": [
        "https://ui.bld8.dev/r/bld8-core.json"
      ],
      "files": [
        {
          "path": "registry/bld8/progress.tsx",
          "content": "'use client';\nexport * from './core';\n",
          "target": "@ui/bld8/progress.tsx",
          "type": "registry:ui"
        }
      ],
      "docs": "React 19 is required. Source is installed inside your configured UI directory under bld8/. Styles are imported by the components. Wrap overlays in UIProvider from bld8/overlays and set body { position: relative; }. Keep the included licences. Compiled utilities cover the shipped components; use ordinary CSS or your own Tailwind build for new utility classes."
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "loading",
      "type": "registry:ui",
      "title": "BLD8 loading",
      "description": "BLD8 loading with editable BLD8 source.",
      "author": "Jaison (https://bld8.dev)",
      "dependencies": [],
      "registryDependencies": [
        "https://ui.bld8.dev/r/bld8-core.json"
      ],
      "files": [
        {
          "path": "registry/bld8/loading.tsx",
          "content": "'use client';\nexport * from './core';\n",
          "target": "@ui/bld8/loading.tsx",
          "type": "registry:ui"
        }
      ],
      "docs": "React 19 is required. Source is installed inside your configured UI directory under bld8/. Styles are imported by the components. Wrap overlays in UIProvider from bld8/overlays and set body { position: relative; }. Keep the included licences. Compiled utilities cover the shipped components; use ordinary CSS or your own Tailwind build for new utility classes."
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "empty",
      "type": "registry:ui",
      "title": "BLD8 empty",
      "description": "BLD8 empty with editable BLD8 source.",
      "author": "Jaison (https://bld8.dev)",
      "dependencies": [],
      "registryDependencies": [
        "https://ui.bld8.dev/r/bld8-core.json"
      ],
      "files": [
        {
          "path": "registry/bld8/empty.tsx",
          "content": "'use client';\nexport * from './core';\n",
          "target": "@ui/bld8/empty.tsx",
          "type": "registry:ui"
        }
      ],
      "docs": "React 19 is required. Source is installed inside your configured UI directory under bld8/. Styles are imported by the components. Wrap overlays in UIProvider from bld8/overlays and set body { position: relative; }. Keep the included licences. Compiled utilities cover the shipped components; use ordinary CSS or your own Tailwind build for new utility classes."
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "avatar",
      "type": "registry:ui",
      "title": "BLD8 avatar",
      "description": "BLD8 avatar with editable BLD8 source.",
      "author": "Jaison (https://bld8.dev)",
      "dependencies": [],
      "registryDependencies": [
        "https://ui.bld8.dev/r/bld8-core.json"
      ],
      "files": [
        {
          "path": "registry/bld8/avatar.tsx",
          "content": "'use client';\nexport * from './core';\n",
          "target": "@ui/bld8/avatar.tsx",
          "type": "registry:ui"
        }
      ],
      "docs": "React 19 is required. Source is installed inside your configured UI directory under bld8/. Styles are imported by the components. Wrap overlays in UIProvider from bld8/overlays and set body { position: relative; }. Keep the included licences. Compiled utilities cover the shipped components; use ordinary CSS or your own Tailwind build for new utility classes."
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "card",
      "type": "registry:ui",
      "title": "BLD8 card",
      "description": "BLD8 card with editable BLD8 source.",
      "author": "Jaison (https://bld8.dev)",
      "dependencies": [],
      "registryDependencies": [
        "https://ui.bld8.dev/r/bld8-core.json"
      ],
      "files": [
        {
          "path": "registry/bld8/card.tsx",
          "content": "'use client';\nexport * from './core';\n",
          "target": "@ui/bld8/card.tsx",
          "type": "registry:ui"
        }
      ],
      "docs": "React 19 is required. Source is installed inside your configured UI directory under bld8/. Styles are imported by the components. Wrap overlays in UIProvider from bld8/overlays and set body { position: relative; }. Keep the included licences. Compiled utilities cover the shipped components; use ordinary CSS or your own Tailwind build for new utility classes."
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "breadcrumb",
      "type": "registry:ui",
      "title": "BLD8 breadcrumb",
      "description": "BLD8 breadcrumb with editable BLD8 source.",
      "author": "Jaison (https://bld8.dev)",
      "dependencies": [],
      "registryDependencies": [
        "https://ui.bld8.dev/r/bld8-core.json"
      ],
      "files": [
        {
          "path": "registry/bld8/breadcrumb.tsx",
          "content": "'use client';\nexport * from './core';\n",
          "target": "@ui/bld8/breadcrumb.tsx",
          "type": "registry:ui"
        }
      ],
      "docs": "React 19 is required. Source is installed inside your configured UI directory under bld8/. Styles are imported by the components. Wrap overlays in UIProvider from bld8/overlays and set body { position: relative; }. Keep the included licences. Compiled utilities cover the shipped components; use ordinary CSS or your own Tailwind build for new utility classes."
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "pagination",
      "type": "registry:ui",
      "title": "BLD8 pagination",
      "description": "BLD8 pagination with editable BLD8 source.",
      "author": "Jaison (https://bld8.dev)",
      "dependencies": [],
      "registryDependencies": [
        "https://ui.bld8.dev/r/bld8-core.json"
      ],
      "files": [
        {
          "path": "registry/bld8/pagination.tsx",
          "content": "'use client';\nexport * from './core';\n",
          "target": "@ui/bld8/pagination.tsx",
          "type": "registry:ui"
        }
      ],
      "docs": "React 19 is required. Source is installed inside your configured UI directory under bld8/. Styles are imported by the components. Wrap overlays in UIProvider from bld8/overlays and set body { position: relative; }. Keep the included licences. Compiled utilities cover the shipped components; use ordinary CSS or your own Tailwind build for new utility classes."
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "input-group",
      "type": "registry:ui",
      "title": "BLD8 input-group",
      "description": "BLD8 input-group with editable BLD8 source.",
      "author": "Jaison (https://bld8.dev)",
      "dependencies": [],
      "registryDependencies": [
        "https://ui.bld8.dev/r/bld8-core.json"
      ],
      "files": [
        {
          "path": "registry/bld8/input-group.tsx",
          "content": "'use client';\nexport * from './core';\n",
          "target": "@ui/bld8/input-group.tsx",
          "type": "registry:ui"
        }
      ],
      "docs": "React 19 is required. Source is installed inside your configured UI directory under bld8/. Styles are imported by the components. Wrap overlays in UIProvider from bld8/overlays and set body { position: relative; }. Keep the included licences. Compiled utilities cover the shipped components; use ordinary CSS or your own Tailwind build for new utility classes."
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "select",
      "type": "registry:ui",
      "title": "BLD8 select",
      "description": "BLD8 select with editable BLD8 source.",
      "author": "Jaison (https://bld8.dev)",
      "dependencies": [],
      "registryDependencies": [
        "https://ui.bld8.dev/r/bld8-controls.json"
      ],
      "files": [
        {
          "path": "registry/bld8/select.tsx",
          "content": "'use client';\nexport * from './controls';\n",
          "target": "@ui/bld8/select.tsx",
          "type": "registry:ui"
        }
      ],
      "docs": "React 19 is required. Source is installed inside your configured UI directory under bld8/. Styles are imported by the components. Wrap overlays in UIProvider from bld8/overlays and set body { position: relative; }. Keep the included licences. Compiled utilities cover the shipped components; use ordinary CSS or your own Tailwind build for new utility classes."
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "combobox",
      "type": "registry:ui",
      "title": "BLD8 combobox",
      "description": "BLD8 combobox with editable BLD8 source.",
      "author": "Jaison (https://bld8.dev)",
      "dependencies": [],
      "registryDependencies": [
        "https://ui.bld8.dev/r/bld8-controls.json"
      ],
      "files": [
        {
          "path": "registry/bld8/combobox.tsx",
          "content": "'use client';\nexport * from './controls';\n",
          "target": "@ui/bld8/combobox.tsx",
          "type": "registry:ui"
        }
      ],
      "docs": "React 19 is required. Source is installed inside your configured UI directory under bld8/. Styles are imported by the components. Wrap overlays in UIProvider from bld8/overlays and set body { position: relative; }. Keep the included licences. Compiled utilities cover the shipped components; use ordinary CSS or your own Tailwind build for new utility classes."
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "tabs",
      "type": "registry:ui",
      "title": "BLD8 tabs",
      "description": "BLD8 tabs with editable BLD8 source.",
      "author": "Jaison (https://bld8.dev)",
      "dependencies": [],
      "registryDependencies": [
        "https://ui.bld8.dev/r/bld8-controls.json"
      ],
      "files": [
        {
          "path": "registry/bld8/tabs.tsx",
          "content": "'use client';\nexport * from './controls';\n",
          "target": "@ui/bld8/tabs.tsx",
          "type": "registry:ui"
        }
      ],
      "docs": "React 19 is required. Source is installed inside your configured UI directory under bld8/. Styles are imported by the components. Wrap overlays in UIProvider from bld8/overlays and set body { position: relative; }. Keep the included licences. Compiled utilities cover the shipped components; use ordinary CSS or your own Tailwind build for new utility classes."
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "accordion",
      "type": "registry:ui",
      "title": "BLD8 accordion",
      "description": "BLD8 accordion with editable BLD8 source.",
      "author": "Jaison (https://bld8.dev)",
      "dependencies": [],
      "registryDependencies": [
        "https://ui.bld8.dev/r/bld8-controls.json"
      ],
      "files": [
        {
          "path": "registry/bld8/accordion.tsx",
          "content": "'use client';\nexport * from './controls';\n",
          "target": "@ui/bld8/accordion.tsx",
          "type": "registry:ui"
        }
      ],
      "docs": "React 19 is required. Source is installed inside your configured UI directory under bld8/. Styles are imported by the components. Wrap overlays in UIProvider from bld8/overlays and set body { position: relative; }. Keep the included licences. Compiled utilities cover the shipped components; use ordinary CSS or your own Tailwind build for new utility classes."
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "dialog",
      "type": "registry:ui",
      "title": "BLD8 dialog",
      "description": "BLD8 dialog with editable BLD8 source.",
      "author": "Jaison (https://bld8.dev)",
      "dependencies": [],
      "registryDependencies": [
        "https://ui.bld8.dev/r/bld8-overlays.json"
      ],
      "files": [
        {
          "path": "registry/bld8/dialog.tsx",
          "content": "'use client';\nexport * from './overlays';\n",
          "target": "@ui/bld8/dialog.tsx",
          "type": "registry:ui"
        }
      ],
      "docs": "React 19 is required. Source is installed inside your configured UI directory under bld8/. Styles are imported by the components. Wrap overlays in UIProvider from bld8/overlays and set body { position: relative; }. Keep the included licences. Compiled utilities cover the shipped components; use ordinary CSS or your own Tailwind build for new utility classes."
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "sheet",
      "type": "registry:ui",
      "title": "BLD8 sheet",
      "description": "BLD8 sheet with editable BLD8 source.",
      "author": "Jaison (https://bld8.dev)",
      "dependencies": [],
      "registryDependencies": [
        "https://ui.bld8.dev/r/bld8-overlays.json"
      ],
      "files": [
        {
          "path": "registry/bld8/sheet.tsx",
          "content": "'use client';\nexport * from './overlays';\n",
          "target": "@ui/bld8/sheet.tsx",
          "type": "registry:ui"
        }
      ],
      "docs": "React 19 is required. Source is installed inside your configured UI directory under bld8/. Styles are imported by the components. Wrap overlays in UIProvider from bld8/overlays and set body { position: relative; }. Keep the included licences. Compiled utilities cover the shipped components; use ordinary CSS or your own Tailwind build for new utility classes."
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "popover",
      "type": "registry:ui",
      "title": "BLD8 popover",
      "description": "BLD8 popover with editable BLD8 source.",
      "author": "Jaison (https://bld8.dev)",
      "dependencies": [],
      "registryDependencies": [
        "https://ui.bld8.dev/r/bld8-overlays.json"
      ],
      "files": [
        {
          "path": "registry/bld8/popover.tsx",
          "content": "'use client';\nexport * from './overlays';\n",
          "target": "@ui/bld8/popover.tsx",
          "type": "registry:ui"
        }
      ],
      "docs": "React 19 is required. Source is installed inside your configured UI directory under bld8/. Styles are imported by the components. Wrap overlays in UIProvider from bld8/overlays and set body { position: relative; }. Keep the included licences. Compiled utilities cover the shipped components; use ordinary CSS or your own Tailwind build for new utility classes."
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "tooltip",
      "type": "registry:ui",
      "title": "BLD8 tooltip",
      "description": "BLD8 tooltip with editable BLD8 source.",
      "author": "Jaison (https://bld8.dev)",
      "dependencies": [],
      "registryDependencies": [
        "https://ui.bld8.dev/r/bld8-overlays.json"
      ],
      "files": [
        {
          "path": "registry/bld8/tooltip.tsx",
          "content": "'use client';\nexport * from './overlays';\n",
          "target": "@ui/bld8/tooltip.tsx",
          "type": "registry:ui"
        }
      ],
      "docs": "React 19 is required. Source is installed inside your configured UI directory under bld8/. Styles are imported by the components. Wrap overlays in UIProvider from bld8/overlays and set body { position: relative; }. Keep the included licences. Compiled utilities cover the shipped components; use ordinary CSS or your own Tailwind build for new utility classes."
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "dropdown",
      "type": "registry:ui",
      "title": "BLD8 dropdown",
      "description": "BLD8 dropdown with editable BLD8 source.",
      "author": "Jaison (https://bld8.dev)",
      "dependencies": [],
      "registryDependencies": [
        "https://ui.bld8.dev/r/bld8-overlays.json"
      ],
      "files": [
        {
          "path": "registry/bld8/dropdown.tsx",
          "content": "'use client';\nexport * from './overlays';\n",
          "target": "@ui/bld8/dropdown.tsx",
          "type": "registry:ui"
        }
      ],
      "docs": "React 19 is required. Source is installed inside your configured UI directory under bld8/. Styles are imported by the components. Wrap overlays in UIProvider from bld8/overlays and set body { position: relative; }. Keep the included licences. Compiled utilities cover the shipped components; use ordinary CSS or your own Tailwind build for new utility classes."
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "toast",
      "type": "registry:ui",
      "title": "BLD8 toast",
      "description": "BLD8 toast with editable BLD8 source.",
      "author": "Jaison (https://bld8.dev)",
      "dependencies": [],
      "registryDependencies": [
        "https://ui.bld8.dev/r/bld8-overlays.json"
      ],
      "files": [
        {
          "path": "registry/bld8/toast.tsx",
          "content": "'use client';\nexport * from './overlays';\n",
          "target": "@ui/bld8/toast.tsx",
          "type": "registry:ui"
        }
      ],
      "docs": "React 19 is required. Source is installed inside your configured UI directory under bld8/. Styles are imported by the components. Wrap overlays in UIProvider from bld8/overlays and set body { position: relative; }. Keep the included licences. Compiled utilities cover the shipped components; use ordinary CSS or your own Tailwind build for new utility classes."
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "table",
      "type": "registry:ui",
      "title": "BLD8 table",
      "description": "BLD8 table with editable BLD8 source.",
      "author": "Jaison (https://bld8.dev)",
      "dependencies": [],
      "registryDependencies": [
        "https://ui.bld8.dev/r/bld8-data-table.json"
      ],
      "files": [
        {
          "path": "registry/bld8/table.tsx",
          "content": "'use client';\nexport * from './data-table';\n",
          "target": "@ui/bld8/table.tsx",
          "type": "registry:ui"
        }
      ],
      "docs": "React 19 is required. Source is installed inside your configured UI directory under bld8/. Styles are imported by the components. Wrap overlays in UIProvider from bld8/overlays and set body { position: relative; }. Keep the included licences. Compiled utilities cover the shipped components; use ordinary CSS or your own Tailwind build for new utility classes."
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "advanced-table",
      "type": "registry:ui",
      "title": "BLD8 advanced-table",
      "description": "BLD8 advanced-table with editable BLD8 source.",
      "author": "Jaison (https://bld8.dev)",
      "dependencies": [],
      "registryDependencies": [
        "https://ui.bld8.dev/r/bld8-data-table.json"
      ],
      "files": [
        {
          "path": "registry/bld8/advanced-table.tsx",
          "content": "'use client';\nexport * from './data-table';\n",
          "target": "@ui/bld8/advanced-table.tsx",
          "type": "registry:ui"
        }
      ],
      "docs": "React 19 is required. Source is installed inside your configured UI directory under bld8/. Styles are imported by the components. Wrap overlays in UIProvider from bld8/overlays and set body { position: relative; }. Keep the included licences. Compiled utilities cover the shipped components; use ordinary CSS or your own Tailwind build for new utility classes."
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "calendar",
      "type": "registry:ui",
      "title": "BLD8 calendar",
      "description": "BLD8 calendar with editable BLD8 source.",
      "author": "Jaison (https://bld8.dev)",
      "dependencies": [],
      "registryDependencies": [
        "https://ui.bld8.dev/r/bld8-calendar.json"
      ],
      "files": [],
      "docs": "React 19 is required. Source is installed inside your configured UI directory under bld8/. Styles are imported by the components. Wrap overlays in UIProvider from bld8/overlays and set body { position: relative; }. Keep the included licences. Compiled utilities cover the shipped components; use ordinary CSS or your own Tailwind build for new utility classes."
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "date-picker",
      "type": "registry:ui",
      "title": "BLD8 date-picker",
      "description": "BLD8 date-picker with editable BLD8 source.",
      "author": "Jaison (https://bld8.dev)",
      "dependencies": [],
      "registryDependencies": [
        "https://ui.bld8.dev/r/bld8-calendar.json"
      ],
      "files": [
        {
          "path": "registry/bld8/date-picker.tsx",
          "content": "'use client';\nexport * from './calendar';\n",
          "target": "@ui/bld8/date-picker.tsx",
          "type": "registry:ui"
        }
      ],
      "docs": "React 19 is required. Source is installed inside your configured UI directory under bld8/. Styles are imported by the components. Wrap overlays in UIProvider from bld8/overlays and set body { position: relative; }. Keep the included licences. Compiled utilities cover the shipped components; use ordinary CSS or your own Tailwind build for new utility classes."
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "date-range",
      "type": "registry:ui",
      "title": "BLD8 date-range",
      "description": "BLD8 date-range with editable BLD8 source.",
      "author": "Jaison (https://bld8.dev)",
      "dependencies": [],
      "registryDependencies": [
        "https://ui.bld8.dev/r/bld8-calendar.json"
      ],
      "files": [
        {
          "path": "registry/bld8/date-range.tsx",
          "content": "'use client';\nexport * from './calendar';\n",
          "target": "@ui/bld8/date-range.tsx",
          "type": "registry:ui"
        }
      ],
      "docs": "React 19 is required. Source is installed inside your configured UI directory under bld8/. Styles are imported by the components. Wrap overlays in UIProvider from bld8/overlays and set body { position: relative; }. Keep the included licences. Compiled utilities cover the shipped components; use ordinary CSS or your own Tailwind build for new utility classes."
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "icon",
      "type": "registry:ui",
      "title": "BLD8 icon",
      "description": "BLD8 icon with editable BLD8 source.",
      "author": "Jaison (https://bld8.dev)",
      "dependencies": [],
      "registryDependencies": [
        "https://ui.bld8.dev/r/bld8-icons.json"
      ],
      "files": [
        {
          "path": "registry/bld8/icon.tsx",
          "content": "'use client';\nexport * from './icons';\n",
          "target": "@ui/bld8/icon.tsx",
          "type": "registry:ui"
        }
      ],
      "docs": "React 19 is required. Source is installed inside your configured UI directory under bld8/. Styles are imported by the components. Wrap overlays in UIProvider from bld8/overlays and set body { position: relative; }. Keep the included licences. Compiled utilities cover the shipped components; use ordinary CSS or your own Tailwind build for new utility classes."
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "multi-select",
      "type": "registry:ui",
      "title": "BLD8 multi-select",
      "description": "BLD8 multi-select with editable BLD8 source.",
      "author": "Jaison (https://bld8.dev)",
      "dependencies": [],
      "registryDependencies": [
        "https://ui.bld8.dev/r/bld8-multi-select.json"
      ],
      "files": [],
      "docs": "React 19 is required. Source is installed inside your configured UI directory under bld8/. Styles are imported by the components. Wrap overlays in UIProvider from bld8/overlays and set body { position: relative; }. Keep the included licences. Compiled utilities cover the shipped components; use ordinary CSS or your own Tailwind build for new utility classes."
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "command",
      "type": "registry:ui",
      "title": "BLD8 command",
      "description": "BLD8 command with editable BLD8 source.",
      "author": "Jaison (https://bld8.dev)",
      "dependencies": [],
      "registryDependencies": [
        "https://ui.bld8.dev/r/bld8-command.json"
      ],
      "files": [],
      "docs": "React 19 is required. Source is installed inside your configured UI directory under bld8/. Styles are imported by the components. Wrap overlays in UIProvider from bld8/overlays and set body { position: relative; }. Keep the included licences. Compiled utilities cover the shipped components; use ordinary CSS or your own Tailwind build for new utility classes."
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "file-upload",
      "type": "registry:ui",
      "title": "BLD8 file-upload",
      "description": "BLD8 file-upload with editable BLD8 source.",
      "author": "Jaison (https://bld8.dev)",
      "dependencies": [],
      "registryDependencies": [
        "https://ui.bld8.dev/r/bld8-file-upload.json"
      ],
      "files": [],
      "docs": "React 19 is required. Source is installed inside your configured UI directory under bld8/. Styles are imported by the components. Wrap overlays in UIProvider from bld8/overlays and set body { position: relative; }. Keep the included licences. Compiled utilities cover the shipped components; use ordinary CSS or your own Tailwind build for new utility classes."
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "drawer",
      "type": "registry:ui",
      "title": "BLD8 drawer",
      "description": "BLD8 drawer with editable BLD8 source.",
      "author": "Jaison (https://bld8.dev)",
      "dependencies": [],
      "registryDependencies": [
        "https://ui.bld8.dev/r/bld8-drawer.json"
      ],
      "files": [],
      "docs": "React 19 is required. Source is installed inside your configured UI directory under bld8/. Styles are imported by the components. Wrap overlays in UIProvider from bld8/overlays and set body { position: relative; }. Keep the included licences. Compiled utilities cover the shipped components; use ordinary CSS or your own Tailwind build for new utility classes."
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "context-menu",
      "type": "registry:ui",
      "title": "BLD8 context-menu",
      "description": "BLD8 context-menu with editable BLD8 source.",
      "author": "Jaison (https://bld8.dev)",
      "dependencies": [],
      "registryDependencies": [
        "https://ui.bld8.dev/r/bld8-context-menu.json"
      ],
      "files": [],
      "docs": "React 19 is required. Source is installed inside your configured UI directory under bld8/. Styles are imported by the components. Wrap overlays in UIProvider from bld8/overlays and set body { position: relative; }. Keep the included licences. Compiled utilities cover the shipped components; use ordinary CSS or your own Tailwind build for new utility classes."
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "sidebar",
      "type": "registry:ui",
      "title": "BLD8 sidebar",
      "description": "BLD8 sidebar with editable BLD8 source.",
      "author": "Jaison (https://bld8.dev)",
      "dependencies": [],
      "registryDependencies": [
        "https://ui.bld8.dev/r/bld8-sidebar.json"
      ],
      "files": [],
      "docs": "React 19 is required. Source is installed inside your configured UI directory under bld8/. Styles are imported by the components. Wrap overlays in UIProvider from bld8/overlays and set body { position: relative; }. Keep the included licences. Compiled utilities cover the shipped components; use ordinary CSS or your own Tailwind build for new utility classes."
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "form",
      "type": "registry:ui",
      "title": "BLD8 form",
      "description": "BLD8 form with editable BLD8 source.",
      "author": "Jaison (https://bld8.dev)",
      "dependencies": [],
      "registryDependencies": [
        "https://ui.bld8.dev/r/bld8-form.json"
      ],
      "files": [],
      "docs": "React 19 is required. Source is installed inside your configured UI directory under bld8/. Styles are imported by the components. Wrap overlays in UIProvider from bld8/overlays and set body { position: relative; }. Keep the included licences. Compiled utilities cover the shipped components; use ordinary CSS or your own Tailwind build for new utility classes."
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "project-planner",
      "type": "registry:block",
      "title": "Project planner",
      "description": "Project planner with editable BLD8 source.",
      "author": "Jaison (https://bld8.dev)",
      "dependencies": [],
      "registryDependencies": [
        "https://ui.bld8.dev/r/bld8-block-project-planner.json"
      ],
      "files": [],
      "docs": "React 19 is required. Source is installed inside your configured UI directory under bld8/. Styles are imported by the components. Wrap overlays in UIProvider from bld8/overlays and set body { position: relative; }. Keep the included licences. Compiled utilities cover the shipped components; use ordinary CSS or your own Tailwind build for new utility classes."
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "resources",
      "type": "registry:block",
      "title": "Resource library",
      "description": "Resource library with editable BLD8 source.",
      "author": "Jaison (https://bld8.dev)",
      "dependencies": [],
      "registryDependencies": [
        "https://ui.bld8.dev/r/bld8-block-resource-manager.json"
      ],
      "files": [],
      "docs": "React 19 is required. Source is installed inside your configured UI directory under bld8/. Styles are imported by the components. Wrap overlays in UIProvider from bld8/overlays and set body { position: relative; }. Keep the included licences. Compiled utilities cover the shipped components; use ordinary CSS or your own Tailwind build for new utility classes."
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "sign-in",
      "type": "registry:block",
      "title": "Sign-in form",
      "description": "Sign-in form with editable BLD8 source.",
      "author": "Jaison (https://bld8.dev)",
      "dependencies": [],
      "registryDependencies": [
        "https://ui.bld8.dev/r/bld8-block-sign-in.json"
      ],
      "files": [],
      "docs": "React 19 is required. Source is installed inside your configured UI directory under bld8/. Styles are imported by the components. Wrap overlays in UIProvider from bld8/overlays and set body { position: relative; }. Keep the included licences. Compiled utilities cover the shipped components; use ordinary CSS or your own Tailwind build for new utility classes."
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "account-settings",
      "type": "registry:block",
      "title": "Account settings",
      "description": "Account settings with editable BLD8 source.",
      "author": "Jaison (https://bld8.dev)",
      "dependencies": [],
      "registryDependencies": [
        "https://ui.bld8.dev/r/bld8-block-account-settings.json"
      ],
      "files": [],
      "docs": "React 19 is required. Source is installed inside your configured UI directory under bld8/. Styles are imported by the components. Wrap overlays in UIProvider from bld8/overlays and set body { position: relative; }. Keep the included licences. Compiled utilities cover the shipped components; use ordinary CSS or your own Tailwind build for new utility classes."
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "metrics",
      "type": "registry:block",
      "title": "Metrics overview",
      "description": "Metrics overview with editable BLD8 source.",
      "author": "Jaison (https://bld8.dev)",
      "dependencies": [],
      "registryDependencies": [
        "https://ui.bld8.dev/r/bld8-block-metrics.json"
      ],
      "files": [],
      "docs": "React 19 is required. Source is installed inside your configured UI directory under bld8/. Styles are imported by the components. Wrap overlays in UIProvider from bld8/overlays and set body { position: relative; }. Keep the included licences. Compiled utilities cover the shipped components; use ordinary CSS or your own Tailwind build for new utility classes."
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "workspace",
      "type": "registry:block",
      "title": "Workspace overview",
      "description": "Workspace overview with editable BLD8 source.",
      "author": "Jaison (https://bld8.dev)",
      "dependencies": [],
      "registryDependencies": [
        "https://ui.bld8.dev/r/bld8-block-workspace.json"
      ],
      "files": [],
      "docs": "React 19 is required. Source is installed inside your configured UI directory under bld8/. Styles are imported by the components. Wrap overlays in UIProvider from bld8/overlays and set body { position: relative; }. Keep the included licences. Compiled utilities cover the shipped components; use ordinary CSS or your own Tailwind build for new utility classes."
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "team",
      "type": "registry:block",
      "title": "Team directory",
      "description": "Team directory with editable BLD8 source.",
      "author": "Jaison (https://bld8.dev)",
      "dependencies": [],
      "registryDependencies": [
        "https://ui.bld8.dev/r/bld8-block-team.json"
      ],
      "files": [],
      "docs": "React 19 is required. Source is installed inside your configured UI directory under bld8/. Styles are imported by the components. Wrap overlays in UIProvider from bld8/overlays and set body { position: relative; }. Keep the included licences. Compiled utilities cover the shipped components; use ordinary CSS or your own Tailwind build for new utility classes."
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "project-board",
      "type": "registry:block",
      "title": "Project board",
      "description": "Project board with editable BLD8 source.",
      "author": "Jaison (https://bld8.dev)",
      "dependencies": [],
      "registryDependencies": [
        "https://ui.bld8.dev/r/bld8-block-project-board.json"
      ],
      "files": [],
      "docs": "React 19 is required. Source is installed inside your configured UI directory under bld8/. Styles are imported by the components. Wrap overlays in UIProvider from bld8/overlays and set body { position: relative; }. Keep the included licences. Compiled utilities cover the shipped components; use ordinary CSS or your own Tailwind build for new utility classes."
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "outline",
      "type": "registry:block",
      "title": "Outline workspace",
      "description": "Outline workspace with editable BLD8 source.",
      "author": "Jaison (https://bld8.dev)",
      "dependencies": [],
      "registryDependencies": [
        "https://ui.bld8.dev/r/bld8-block-operations-template.json"
      ],
      "files": [],
      "docs": "React 19 is required. Source is installed inside your configured UI directory under bld8/. Styles are imported by the components. Wrap overlays in UIProvider from bld8/overlays and set body { position: relative; }. Keep the included licences. Compiled utilities cover the shipped components; use ordinary CSS or your own Tailwind build for new utility classes."
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "studio",
      "type": "registry:block",
      "title": "Studio workspace",
      "description": "Studio workspace with editable BLD8 source.",
      "author": "Jaison (https://bld8.dev)",
      "dependencies": [],
      "registryDependencies": [
        "https://ui.bld8.dev/r/bld8-block-templates.json"
      ],
      "files": [],
      "docs": "React 19 is required. Source is installed inside your configured UI directory under bld8/. Styles are imported by the components. Wrap overlays in UIProvider from bld8/overlays and set body { position: relative; }. Keep the included licences. Compiled utilities cover the shipped components; use ordinary CSS or your own Tailwind build for new utility classes."
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "launch",
      "type": "registry:block",
      "title": "Gather landing page",
      "description": "Gather landing page with editable BLD8 source.",
      "author": "Jaison (https://bld8.dev)",
      "dependencies": [],
      "registryDependencies": [
        "https://ui.bld8.dev/r/bld8-block-templates.json"
      ],
      "files": [],
      "docs": "React 19 is required. Source is installed inside your configured UI directory under bld8/. Styles are imported by the components. Wrap overlays in UIProvider from bld8/overlays and set body { position: relative; }. Keep the included licences. Compiled utilities cover the shipped components; use ordinary CSS or your own Tailwind build for new utility classes."
    }
  ]
}