{
  "_meta": {
    "purpose": "Machine-readable index of the SeedTrust design system. Read this before UI work.",
    "generatedFrom": [
      "src/data/designSystemCatalog.js",
      "src/data/designTokens.js",
      "src/index.css"
    ],
    "regenerate": "npm run design-system:manifest (runs on build and in the pre-commit hook; the dev server serves it live)",
    "verify": "npm run design-system:check",
    "howToUse": [
      "components: what exists, what each is for, where its source file is, its use/avoid guidance, and the behaviors that bind it. Its page is routes.component with {portal} and {component} filled in.",
      "tokens.sections: every custom property in src/index.css as name: value, resolved for the admin portal. tokens.portalOverrides.user: what the user portal changes (status colors). tokens.daisyThemes: each portal's DaisyUI theme, which drives btn-*, badge-*, alert-* classes. Inside components use the Tailwind utility (bg-blue, text-status-warning), not raw var(--name).",
      "guidelines.principles: qualities a redesign must keep. guidelines.behaviors: interaction rules that span components; each names the components it binds, and each component lists its behaviors. Entries with standard: \"prototype\" are about the mockup being reviewable, not the product. Rendered at /ui/{portal}/guidelines.",
      "since and because on any entry record when and why a call was made. Keep them when editing the entry.",
      "To add a rule, edit the catalog: a principle, a behavior naming the components it binds, or a component guidance entry. Do not create a markdown rules file."
    ]
  },
  "project": {
    "name": "SeedTrust Mockups",
    "company": "Seedtrust",
    "product": "SeedTrust Portal",
    "baseDesignSystemPath": "/ui",
    "baseDesignSystemUrl": "https://seedtrust.orchidux.com/ui"
  },
  "portals": [
    {
      "id": "admin",
      "label": "Admin",
      "daisyTheme": "seedtrust-admin",
      "description": "Internal SeedTrust operations foundation for disbursement, communications, reporting, and card workflows."
    },
    {
      "id": "user",
      "label": "User",
      "daisyTheme": "seedtrust-user",
      "description": "Agency and case-manager portal foundation for external credit-card charge workflows."
    }
  ],
  "routes": {
    "siteUrl": "https://seedtrust.orchidux.com",
    "home": "/ui",
    "portal": "/ui/{portal}",
    "components": "/ui/{portal}/components",
    "component": "/ui/{portal}/components/{component}",
    "foundation": "/ui/{portal}/foundations/{topic}",
    "tokens": "/ui/{portal}/tokens",
    "guidelines": "/ui/{portal}/guidelines",
    "manifest": "/ui/manifest.json"
  },
  "components": [
    {
      "id": "accordion",
      "label": "Accordion",
      "description": "Collapsible grouped sections for review workflows and progressive disclosure.",
      "portals": [
        "admin",
        "user"
      ],
      "source": "src/components/Accordion.jsx",
      "behaviors": [
        "motion-explains",
        "keyboard-focus"
      ]
    },
    {
      "id": "alert",
      "label": "Alert",
      "description": "Status and notification banners for neutral, info, success, warning, and danger states.",
      "portals": [
        "admin",
        "user"
      ],
      "source": "src/components/Alert.jsx",
      "guidance": {
        "use": [
          "Solid DaisyUI status backgrounds with the neutral, info, success, warning, and danger/error variants."
        ],
        "avoid": [
          "Tinted or outlined alert treatments."
        ]
      },
      "behaviors": [
        "error-scope",
        "failure-copy",
        "action-sequence",
        "every-state-designed",
        "motion-explains",
        "not-color-alone",
        "mocked-never-real",
        "reachable-failure"
      ]
    },
    {
      "id": "autocomplete",
      "label": "Autocomplete",
      "description": "Type-ahead selection input for local option sets.",
      "portals": [
        "admin",
        "user"
      ],
      "source": "src/components/Autocomplete.jsx",
      "guidance": {
        "use": [
          "Pass label for the visible label, helperText for guidance, and hasError with the error message prop for validation."
        ],
        "avoid": [
          "placeholder as the only label."
        ]
      },
      "behaviors": [
        "forms-keep-context",
        "error-scope",
        "every-state-designed",
        "keyboard-focus",
        "not-color-alone"
      ]
    },
    {
      "id": "avatar",
      "label": "Avatar",
      "description": "Identity avatar with initials and image examples across supported sizes.",
      "portals": [
        "admin",
        "user"
      ],
      "source": "src/components/Avatar.jsx"
    },
    {
      "id": "badge",
      "label": "Badge",
      "description": "Compact labels for status, metadata, and workflow state.",
      "portals": [
        "admin",
        "user"
      ],
      "source": "src/components/Badge.jsx",
      "guidance": {
        "use": [
          "Case and disbursement status uses the status-* tokens: status-warning, status-review, status-danger, status-success, status-info, status-positive, status-neutral. Their rendered values follow the active portal foundation."
        ],
        "avoid": [
          "Brand or semantic colors for a status that has a status-* token."
        ]
      },
      "behaviors": [
        "not-color-alone"
      ]
    },
    {
      "id": "breadcrumbs",
      "label": "Breadcrumbs",
      "description": "Subtle page hierarchy trail for operational screens.",
      "portals": [
        "admin",
        "user"
      ],
      "source": "src/components/Breadcrumbs.jsx",
      "guidance": {
        "use": [
          "Subtle and production-like: 0.9rem or smaller, muted previous links, accent current crumb."
        ],
        "avoid": [
          "Oversized label treatment."
        ],
        "since": "2026-08-20"
      },
      "behaviors": [
        "keyboard-focus"
      ]
    },
    {
      "id": "button",
      "label": "Button",
      "description": "Primary, secondary, link, ghost, icon, disabled, and loading action states.",
      "portals": [
        "admin",
        "user"
      ],
      "source": "src/components/Button.jsx",
      "behaviors": [
        "money-actions-confirmed",
        "action-sequence",
        "every-state-designed",
        "keyboard-focus",
        "mocked-never-real",
        "reachable-failure"
      ]
    },
    {
      "id": "card",
      "label": "Card",
      "description": "Framed content container for repeated items, compact panels, and contained tools.",
      "portals": [
        "admin",
        "user"
      ],
      "source": "src/components/Card.jsx",
      "guidance": {
        "use": [
          "Card is a general content container. Metrics go through Stat."
        ],
        "avoid": [
          "Card type=\"stats\" for new work; it is a legacy compatibility path that delegates to Stat."
        ],
        "since": "2026-08-20"
      },
      "behaviors": [
        "overlay-trigger-context",
        "trigger-surfaces",
        "motion-explains"
      ]
    },
    {
      "id": "chat-bubble",
      "label": "Chat Bubble",
      "description": "Conversation message bubbles with direction, header, time, and footer metadata.",
      "portals": [
        "admin",
        "user"
      ],
      "source": "src/components/ChatBubble.jsx"
    },
    {
      "id": "checkbox",
      "label": "Checkbox",
      "description": "Binary selection control with labels, helper text, error, and disabled states.",
      "portals": [
        "admin",
        "user"
      ],
      "source": "src/components/Checkbox.jsx",
      "behaviors": [
        "every-state-designed",
        "selection-scope",
        "keyboard-focus"
      ]
    },
    {
      "id": "collapse",
      "label": "Collapse",
      "description": "Independent disclosure primitive for expanding and collapsing supporting content.",
      "portals": [
        "admin",
        "user"
      ],
      "source": "src/components/Collapse.jsx",
      "behaviors": [
        "motion-explains",
        "keyboard-focus"
      ]
    },
    {
      "id": "combobox",
      "label": "Combobox",
      "description": "Searchable single-select control for larger option sets.",
      "portals": [
        "admin",
        "user"
      ],
      "source": "src/components/Combobox.jsx",
      "guidance": {
        "use": [
          "Pass label for the visible label, helperText for guidance, and hasError with the error message prop for validation."
        ],
        "avoid": [
          "placeholder as the only label."
        ]
      },
      "behaviors": [
        "forms-keep-context",
        "error-scope",
        "every-state-designed",
        "keyboard-focus",
        "not-color-alone"
      ]
    },
    {
      "id": "content-card",
      "label": "Content Card",
      "description": "SeedTrust content wrapper for titled panels and page sections.",
      "portals": [
        "admin",
        "user"
      ],
      "source": "src/components/ContentCard.jsx",
      "behaviors": [
        "overlay-trigger-context",
        "trigger-surfaces"
      ]
    },
    {
      "id": "credit-card",
      "label": "Credit Card",
      "description": "Recognizable SeedTrust card-face visual for card and budget workflows.",
      "portals": [
        "admin",
        "user"
      ],
      "source": "src/components/CreditCard.jsx",
      "guidance": {
        "use": [
          "Real card proportions, rounded card corners, masked numbers by default, no cardholder or person names.",
          "Revealed details in prototypes stay visibly authorization-gated."
        ],
        "avoid": [
          "Chip blocks, bottom-right network labels, or decorative credit-card icons on the card face.",
          "Decorative marks that cross or reduce readability of the number, expiry, security code, issuer, or status text.",
          "Implying production reveal behavior without audit logging."
        ],
        "since": "2026-08-20",
        "because": "The card face is the one recognizable SeedTrust visual; decoration was competing with the details staff need to read."
      },
      "behaviors": [
        "money-actions-confirmed",
        "mocked-never-real"
      ]
    },
    {
      "id": "datepicker",
      "label": "Datepicker",
      "description": "Date input with calendar picker, helper, error, filled, and disabled states.",
      "portals": [
        "admin",
        "user"
      ],
      "source": "src/components/Datepicker.jsx",
      "guidance": {
        "use": [
          "Pass label for the visible label, helperText for guidance, and hasError with the error message prop for validation."
        ],
        "avoid": [
          "placeholder as the only label."
        ]
      },
      "behaviors": [
        "forms-keep-context",
        "error-scope",
        "every-state-designed",
        "keyboard-focus",
        "not-color-alone"
      ]
    },
    {
      "id": "dock",
      "label": "Dock",
      "description": "Compact bottom navigation for small-screen portal destinations.",
      "portals": [
        "admin",
        "user"
      ],
      "source": "src/components/Dock.jsx",
      "behaviors": [
        "keyboard-focus"
      ]
    },
    {
      "id": "drag-drop-upload",
      "label": "Drag Drop Upload",
      "description": "Drop-zone upload surface for one or more files with constraints.",
      "portals": [
        "admin",
        "user"
      ],
      "source": "src/components/DragDropUpload.jsx"
    },
    {
      "id": "dropdown",
      "label": "Dropdown",
      "description": "Button-triggered menu and split-button action patterns.",
      "portals": [
        "admin",
        "user"
      ],
      "source": "src/components/DropdownButton.jsx",
      "guidance": {
        "use": [
          "Dropdown owns button-triggered dropdown and split-button patterns."
        ],
        "avoid": [
          "DropdownButton for new UI; it is a legacy alias kept for existing imports."
        ],
        "since": "2026-08-20"
      },
      "behaviors": [
        "money-actions-confirmed",
        "action-sequence",
        "every-state-designed",
        "motion-explains",
        "keyboard-focus",
        "reachable-failure"
      ]
    },
    {
      "id": "empty-state",
      "label": "Empty State",
      "description": "Empty, no-result, and onboarding states with optional action affordances.",
      "portals": [
        "admin",
        "user"
      ],
      "source": "src/components/EmptyState.jsx",
      "behaviors": [
        "failure-copy",
        "every-state-designed"
      ]
    },
    {
      "id": "fieldset",
      "label": "Fieldset",
      "description": "Grouped form fields with legend and supporting description.",
      "portals": [
        "admin",
        "user"
      ],
      "source": "src/components/Fieldset.jsx",
      "behaviors": [
        "forms-keep-context"
      ]
    },
    {
      "id": "file-upload",
      "label": "File Upload",
      "description": "Single-file picker built from DaisyUI input, button, and join semantics, with helper, error, required, disabled, and append-button states.",
      "portals": [
        "admin",
        "user"
      ],
      "source": "src/components/FileUpload.jsx",
      "guidance": {
        "use": [
          "Pass label for the visible label, helperText for guidance, and hasError with the error message prop for validation."
        ],
        "avoid": [
          "placeholder as the only label."
        ]
      },
      "behaviors": [
        "forms-keep-context",
        "error-scope",
        "every-state-designed",
        "keyboard-focus",
        "not-color-alone"
      ]
    },
    {
      "id": "form-field",
      "label": "Form Field",
      "description": "Field wrapper for labels, controls, help text, and validation messages.",
      "portals": [
        "admin",
        "user"
      ],
      "source": "src/components/FormField.jsx",
      "behaviors": [
        "forms-keep-context"
      ]
    },
    {
      "id": "header",
      "label": "Header",
      "description": "Portal-aware top navigation for admin and user foundations.",
      "portals": [
        "admin",
        "user"
      ],
      "source": "src/components/Header.jsx",
      "guidance": {
        "use": [
          "In the user foundation, follow the production Agency/Case Manager top navigation from the Flask base_agency.html shell: navy left navigation, darker account block, 0.9rem nav labels, active rounded pills.",
          "In the admin foundation, Header is the operational admin bar."
        ],
        "avoid": [
          "HeaderAdmin or HeaderClient for new UI; they are compatibility internals."
        ],
        "since": "2026-08-20"
      },
      "behaviors": [
        "keyboard-focus"
      ]
    },
    {
      "id": "hover-3d",
      "label": "Hover 3D",
      "description": "Subtle three-dimensional hover treatment for the SeedTrust credit-card example.",
      "portals": [
        "admin",
        "user"
      ],
      "source": "src/components/Hover3D.jsx",
      "guidance": {
        "use": [
          "Showcase the SeedTrust CreditCard example only."
        ],
        "avoid": [
          "Receipt or generic card examples in the Hover3D showcase."
        ],
        "since": "2026-08-20"
      },
      "behaviors": [
        "motion-explains"
      ]
    },
    {
      "id": "indicator",
      "label": "Indicator",
      "description": "Small positional indicators for counts, status, and unread markers.",
      "portals": [
        "admin",
        "user"
      ],
      "source": "src/components/Indicator.jsx",
      "behaviors": [
        "not-color-alone"
      ]
    },
    {
      "id": "icon-button",
      "label": "Icon Button",
      "description": "Icon-only DaisyUI button wrapper in filled, outlined, neutral, and ghost types, all brand and state colors, four sizes.",
      "portals": [
        "admin",
        "user"
      ],
      "source": "src/components/IconButton.jsx",
      "guidance": {
        "use": [
          "Give every icon button a name: an aria-label, or a Tooltip that names the action. The icon alone is not a label."
        ],
        "avoid": []
      },
      "behaviors": [
        "action-sequence",
        "every-state-designed",
        "keyboard-focus",
        "reachable-failure"
      ]
    },
    {
      "id": "input",
      "label": "Input",
      "description": "Text input with labels, icons, add-ons, helper text, error, filled, and disabled states.",
      "portals": [
        "admin",
        "user"
      ],
      "source": "src/components/Input.jsx",
      "guidance": {
        "use": [
          "Pass label for the visible label, helperText for guidance, and hasError with the error message prop for validation."
        ],
        "avoid": [
          "placeholder as the only label."
        ]
      },
      "behaviors": [
        "forms-keep-context",
        "error-scope",
        "every-state-designed",
        "keyboard-focus",
        "not-color-alone"
      ]
    },
    {
      "id": "join",
      "label": "Join",
      "description": "Grouped buttons and controls using DaisyUI join patterns.",
      "portals": [
        "admin",
        "user"
      ],
      "source": "src/components/Join.jsx",
      "guidance": {
        "use": [
          "Join owns grouped button and control patterns; DaisyUI grouped controls route through it."
        ],
        "avoid": [
          "Adding or showcasing a ButtonGroup."
        ],
        "since": "2026-08-20"
      },
      "behaviors": [
        "action-sequence",
        "every-state-designed",
        "keyboard-focus",
        "reachable-failure"
      ]
    },
    {
      "id": "kbd",
      "label": "Kbd",
      "description": "Keyboard shortcut and keypress notation.",
      "portals": [
        "admin",
        "user"
      ],
      "source": "src/components/Kbd.jsx"
    },
    {
      "id": "list",
      "label": "List",
      "description": "Structured list and list-item patterns for compact collections.",
      "portals": [
        "admin",
        "user"
      ],
      "source": "src/components/List.jsx",
      "behaviors": [
        "overlay-trigger-context",
        "trigger-surfaces"
      ]
    },
    {
      "id": "loading",
      "label": "Loading",
      "description": "Loading indicators for pending async work and progressive states.",
      "portals": [
        "admin",
        "user"
      ],
      "source": "src/components/Loading.jsx",
      "behaviors": [
        "action-sequence",
        "every-state-designed"
      ]
    },
    {
      "id": "modal",
      "label": "Modal",
      "description": "Dialog surface for compact forms, confirmations, and focused tasks.",
      "portals": [
        "admin",
        "user"
      ],
      "source": "src/components/Modal.jsx",
      "behaviors": [
        "money-actions-confirmed",
        "overlay-trigger-context",
        "error-scope",
        "failure-copy",
        "every-state-designed",
        "motion-explains",
        "keyboard-focus",
        "mocked-never-real",
        "reachable-failure"
      ]
    },
    {
      "id": "multi-select",
      "label": "Multi Select",
      "description": "Multiple-value searchable selection control.",
      "portals": [
        "admin",
        "user"
      ],
      "source": "src/components/MultiSelect.jsx",
      "guidance": {
        "use": [
          "Pass label for the visible label, helperText for guidance, and hasError with the error message prop for validation."
        ],
        "avoid": [
          "placeholder as the only label."
        ]
      },
      "behaviors": [
        "forms-keep-context",
        "error-scope",
        "every-state-designed",
        "keyboard-focus",
        "not-color-alone"
      ]
    },
    {
      "id": "otp",
      "label": "OTP",
      "description": "One-time passcode entry control for fixed-length codes.",
      "portals": [
        "admin",
        "user"
      ],
      "source": "src/components/OTP.jsx",
      "guidance": {
        "use": [
          "Pass label for the visible label, helperText for guidance, and hasError with the error message prop for validation."
        ],
        "avoid": [
          "placeholder as the only label."
        ]
      },
      "behaviors": [
        "forms-keep-context",
        "error-scope",
        "every-state-designed",
        "keyboard-focus",
        "not-color-alone"
      ]
    },
    {
      "id": "phone-input",
      "label": "Phone Input",
      "description": "Phone number field with a country-code selector built from DaisyUI input, button, and join semantics.",
      "portals": [
        "admin",
        "user"
      ],
      "source": "src/components/PhoneInput.jsx",
      "guidance": {
        "use": [
          "Pass label for the visible label, helperText for guidance, and hasError with the error message prop for validation."
        ],
        "avoid": [
          "placeholder as the only label."
        ]
      },
      "behaviors": [
        "forms-keep-context",
        "error-scope",
        "every-state-designed",
        "keyboard-focus",
        "not-color-alone"
      ]
    },
    {
      "id": "pagination",
      "label": "Pagination",
      "description": "Numbered collection navigation with disabled and ellipsis states.",
      "portals": [
        "admin",
        "user"
      ],
      "source": "src/components/Pagination.jsx",
      "behaviors": [
        "tables-paginate-fifteen",
        "selection-scope",
        "selection-context",
        "keyboard-focus",
        "three-pages-of-fixtures",
        "stable-identities"
      ]
    },
    {
      "id": "progress-bar",
      "label": "Progress Bar",
      "description": "Linear progress indicator for completion, upload, and review state.",
      "portals": [
        "admin",
        "user"
      ],
      "source": "src/components/Progress.jsx",
      "behaviors": [
        "action-sequence",
        "not-color-alone"
      ]
    },
    {
      "id": "progress-circular",
      "label": "Progress Circular",
      "description": "Circular progress indicator for compact status and completion summaries.",
      "portals": [
        "admin",
        "user"
      ],
      "source": "src/components/CircularProgress.jsx",
      "behaviors": [
        "not-color-alone"
      ]
    },
    {
      "id": "radio",
      "label": "Radio",
      "description": "Single-choice option group with descriptions, helper, error, and disabled states.",
      "portals": [
        "admin",
        "user"
      ],
      "source": "src/components/Radio.jsx",
      "behaviors": [
        "every-state-designed",
        "keyboard-focus"
      ]
    },
    {
      "id": "select",
      "label": "Select",
      "description": "Dropdown select with labels, icons, add-ons, helper, error, and disabled states.",
      "portals": [
        "admin",
        "user"
      ],
      "source": "src/components/Select.jsx",
      "guidance": {
        "use": [
          "Pass label for the visible label, helperText for guidance, and hasError with the error message prop for validation."
        ],
        "avoid": [
          "placeholder as the only label."
        ]
      },
      "behaviors": [
        "forms-keep-context",
        "error-scope",
        "every-state-designed",
        "keyboard-focus",
        "not-color-alone"
      ]
    },
    {
      "id": "sidebar",
      "label": "Sidebar",
      "description": "Portal-aware side navigation for admin and user foundations.",
      "portals": [
        "admin",
        "user"
      ],
      "source": "src/components/Sidebar.jsx",
      "guidance": {
        "use": [
          "In the user foundation, follow the production Intended Parent portal from the Flask base_ip_gc.html and partials/sidebar_ip.html shell: rounded-right two-zone sidebar, \"Hi there\" greeting, active cases, messages, profile, resources, videos, and funding navigation with nested Fund My Account links."
        ],
        "avoid": [
          "AdminSidebar or ClientSidebar for new UI; they are compatibility internals."
        ],
        "since": "2026-08-20"
      },
      "behaviors": [
        "keyboard-focus"
      ]
    },
    {
      "id": "stat",
      "label": "Stat",
      "description": "Metric and KPI card patterns for operational summaries.",
      "portals": [
        "admin",
        "user"
      ],
      "source": "src/components/Stat.jsx",
      "guidance": {
        "use": [
          "Stat owns metric and KPI cards."
        ],
        "avoid": [
          "Documenting or building a stats card as a Card variant; Card type=\"stats\" is only a legacy path that delegates here."
        ],
        "since": "2026-08-20"
      },
      "behaviors": [
        "trigger-surfaces"
      ]
    },
    {
      "id": "steps",
      "label": "Steps",
      "description": "Progression indicator for sequenced workflows.",
      "portals": [
        "admin",
        "user"
      ],
      "source": "src/components/Steps.jsx",
      "behaviors": [
        "keyboard-focus",
        "not-color-alone"
      ]
    },
    {
      "id": "switch",
      "label": "Switch",
      "description": "On/off toggle with labels, helper text, error, and disabled states.",
      "portals": [
        "admin",
        "user"
      ],
      "source": "src/components/Switch.jsx",
      "behaviors": [
        "every-state-designed",
        "keyboard-focus",
        "not-color-alone"
      ]
    },
    {
      "id": "table",
      "label": "Table",
      "description": "Data table with selectable rows, sorting, cells, controls, and pagination examples.",
      "portals": [
        "admin",
        "user"
      ],
      "source": "src/components/Table.jsx",
      "guidance": {
        "use": [
          "Buttons and selects inside table cells are one size smaller than their standalone size.",
          "Full-page transaction and work-queue tables paginate at 15 rows with a Showing X-Y of N footer and numbered Prev/Next."
        ],
        "avoid": [
          "Standalone control sizes inside cells."
        ],
        "since": "2026-08-21"
      },
      "behaviors": [
        "tables-paginate-fifteen",
        "overlay-trigger-context",
        "trigger-surfaces",
        "error-scope",
        "every-state-designed",
        "selection-scope",
        "selection-context",
        "motion-explains",
        "keyboard-focus",
        "three-pages-of-fixtures",
        "stable-identities"
      ]
    },
    {
      "id": "tabs",
      "label": "Tabs",
      "description": "Tab navigation with pills, line, icons, disabled, and multi-tab variants.",
      "portals": [
        "admin",
        "user"
      ],
      "source": "src/components/Tabs.jsx",
      "behaviors": [
        "keyboard-focus"
      ]
    },
    {
      "id": "textarea",
      "label": "Textarea",
      "description": "Multi-line text input with helper, error, filled, and disabled states.",
      "portals": [
        "admin",
        "user"
      ],
      "source": "src/components/Textarea.jsx",
      "guidance": {
        "use": [
          "Pass label for the visible label, helperText for guidance, and hasError with the error message prop for validation."
        ],
        "avoid": [
          "placeholder as the only label."
        ]
      },
      "behaviors": [
        "forms-keep-context",
        "error-scope",
        "every-state-designed",
        "keyboard-focus",
        "not-color-alone"
      ]
    },
    {
      "id": "toast",
      "label": "Toast",
      "description": "Transient notification feedback with placement, variants, and optional action.",
      "portals": [
        "admin",
        "user"
      ],
      "source": "src/components/Toast.jsx",
      "behaviors": [
        "error-scope",
        "failure-copy",
        "action-sequence",
        "every-state-designed",
        "motion-explains",
        "not-color-alone",
        "mocked-never-real",
        "reachable-failure"
      ]
    },
    {
      "id": "tooltip",
      "label": "Tooltip",
      "description": "Hover and focus helper text rendered outside clipping containers.",
      "portals": [
        "admin",
        "user"
      ],
      "source": "src/components/Tooltip.jsx",
      "behaviors": [
        "motion-explains",
        "keyboard-focus"
      ]
    },
    {
      "id": "wysiwyg",
      "label": "Wysiwyg",
      "description": "Rich-text editor surface for formatted long-form content.",
      "portals": [
        "admin",
        "user"
      ],
      "source": "src/components/Wysiwyg.jsx",
      "guidance": {
        "use": [
          "Pass label for the visible label, helperText for guidance, and hasError with the error message prop for validation."
        ],
        "avoid": [
          "placeholder as the only label."
        ]
      },
      "behaviors": [
        "forms-keep-context",
        "error-scope",
        "every-state-designed",
        "keyboard-focus",
        "not-color-alone"
      ]
    }
  ],
  "foundations": [
    {
      "id": "colors",
      "label": "Colors",
      "description": "Neutral, brand, semantic, and status palettes for each portal foundation."
    },
    {
      "id": "typography",
      "label": "Typography",
      "description": "Bootstrap/Helvetica-style system stack, type sizes, weights, and letter spacing."
    },
    {
      "id": "spacing",
      "label": "Spacing",
      "description": "Spacing scale used for layout, component gaps, and page rhythm."
    },
    {
      "id": "border-radius",
      "label": "Border Radius",
      "description": "Corner radius scale for controls, cards, and overlays."
    },
    {
      "id": "icon-sizes",
      "label": "Icon Sizes",
      "description": "Icon sizing tokens for controls, navigation, and metadata."
    },
    {
      "id": "opacity",
      "label": "Opacity",
      "description": "Opacity values for disabled, hover, and emphasis states."
    },
    {
      "id": "shadows",
      "label": "Shadows",
      "description": "Elevation shadows for cards, overlays, and floating action surfaces."
    }
  ],
  "tokens": {
    "source": "src/index.css",
    "usage": "Use the Tailwind utility for a token (bg-blue, text-status-warning) or var(--<name>) in CSS; never a literal value. sections are resolved for the admin portal; portalOverrides lists what the user portal changes; daisyThemes carries each portal's DaisyUI theme (primary, secondary, accent, base, status colors, radius) for btn-*, badge-*, alert-* classes.",
    "sections": [
      {
        "id": "colors",
        "label": "Colors",
        "description": "Neutral, brand, semantic, status, focus, and surface colors resolved for the active portal. Status colors change per portal.",
        "groups": [
          {
            "id": "neutral",
            "label": "Neutral",
            "tokens": {
              "color-neutral-0": "#FFFFFF",
              "color-neutral-5": "#F2F2F2",
              "color-neutral-10": "#E5E5E5",
              "color-neutral-20": "#D5D5D5",
              "color-neutral-40": "#BFBFBF",
              "color-neutral-60": "#9E9E9E",
              "color-neutral-80": "#858585",
              "color-neutral-100": "#333333"
            }
          },
          {
            "id": "brand",
            "label": "Brand",
            "tokens": {
              "color-blue": "#4466A2",
              "color-blue-light": "#92AAD1",
              "color-blue-dark": "#335185",
              "color-green": "#3F806A",
              "color-green-light": "#8FBFAD",
              "color-green-dark": "#2D5C4C",
              "color-sky": "#3398FE",
              "color-sky-light": "#E8F2FF",
              "color-sky-dark": "#1A7DE0"
            }
          },
          {
            "id": "semantic",
            "label": "Semantic",
            "tokens": {
              "color-danger": "#DC3545",
              "color-danger-light": "#FEEAEE",
              "color-danger-dark": "#C82333",
              "color-danger-darkest": "#721C24",
              "color-success": "#28A745",
              "color-success-light": "#D4EDDA",
              "color-success-dark": "#218838",
              "color-success-darkest": "#155724",
              "color-warning": "#FFC107",
              "color-warning-light": "#FFF3CD",
              "color-warning-dark": "#F2B607",
              "color-warning-darkest": "#856404",
              "color-info": "#17A2B8",
              "color-info-light": "#D1ECF1",
              "color-info-dark": "#148496",
              "color-info-darkest": "#0C5460"
            }
          },
          {
            "id": "status",
            "label": "Status",
            "tokens": {
              "color-status-neutral": "#9E9E9E",
              "color-status-warning": "#FFC107",
              "color-status-review": "#FD7E14",
              "color-status-danger": "#DC3545",
              "color-status-success": "#28A745",
              "color-status-info": "#17A2B8",
              "color-status-positive": "#D4EDDA"
            }
          },
          {
            "id": "focus",
            "label": "Focus",
            "tokens": {
              "color-focus-ring": "#80BDFF",
              "color-focus-ring-danger": "#DC354540",
              "color-focus-shadow": "#007BFF40"
            }
          },
          {
            "id": "surface",
            "label": "Surface",
            "tokens": {
              "color-body-bg": "#F4F5F7"
            }
          }
        ]
      },
      {
        "id": "typography",
        "label": "Typography",
        "description": "Font family, size, line height, weight, and letter spacing.",
        "groups": [
          {
            "id": "font-family",
            "label": "Font Family",
            "tokens": {
              "font-family-body": "-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, \"Noto Sans\", \"Liberation Sans\", sans-serif",
              "font-family-heading": "-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, \"Noto Sans\", \"Liberation Sans\", sans-serif",
              "font-family-mono": "SFMono-Regular, Menlo, Monaco, Consolas, \"Liberation Mono\", \"Courier New\", monospace"
            }
          },
          {
            "id": "font-size",
            "label": "Font Size",
            "tokens": {
              "font-size-sm": "12px",
              "font-size-base": "16px",
              "font-size-lg": "16px",
              "font-size-xl": "20px",
              "font-size-2xl": "26px",
              "font-size-3xl": "32px",
              "font-size-4xl": "40px"
            }
          },
          {
            "id": "line-height",
            "label": "Line Height",
            "tokens": {
              "line-height-sm": "18px",
              "line-height-base": "22px",
              "line-height-lg": "24px",
              "line-height-xl": "30px",
              "line-height-2xl": "31px",
              "line-height-3xl": "38px",
              "line-height-4xl": "48px"
            }
          },
          {
            "id": "font-weight",
            "label": "Font Weight",
            "tokens": {
              "font-weight-normal": "400",
              "font-weight-medium": "500",
              "font-weight-semibold": "600",
              "font-weight-bold": "700"
            }
          },
          {
            "id": "letter-spacing",
            "label": "Letter Spacing",
            "tokens": {
              "letter-spacing-tighter": "-0.7px",
              "letter-spacing-tight": "-0.35px",
              "letter-spacing-normal": "0px",
              "letter-spacing-wide": "0.35px",
              "letter-spacing-wider": "0.7px",
              "letter-spacing-widest": "1.4px"
            }
          }
        ]
      },
      {
        "id": "spacing",
        "label": "Spacing",
        "description": "Spacing scale for layout, gaps, and component composition.",
        "groups": [
          {
            "id": "spacing",
            "label": "All Spacing Tokens",
            "tokens": {
              "spacing-3xs": "2px",
              "spacing-2xs": "4px",
              "spacing-xs": "8px",
              "spacing-sm": "12px",
              "spacing-md": "16px",
              "spacing-lg": "24px",
              "spacing-xl": "32px",
              "spacing-2xl": "48px",
              "spacing-3xl": "64px",
              "spacing-4xl": "96px"
            }
          }
        ]
      },
      {
        "id": "border-radius",
        "label": "Border Radius",
        "description": "Corner radius scale for controls, cards, overlays, and rounded surfaces.",
        "groups": [
          {
            "id": "radius",
            "label": "All Radius Tokens",
            "tokens": {
              "radius-none": "0px",
              "radius-sm": "3px",
              "radius-md": "4px",
              "radius-lg": "5px",
              "radius-full": "9999px"
            }
          }
        ]
      },
      {
        "id": "border-width",
        "label": "Border Width",
        "description": "Border widths for outlines and separators.",
        "groups": [
          {
            "id": "border-width",
            "label": "All Border Width Tokens",
            "tokens": {
              "border-width-0": "0px",
              "border-width-1": "1px",
              "border-width-2": "2px"
            }
          }
        ]
      },
      {
        "id": "sizing",
        "label": "Sizing",
        "description": "Avatar, icon, control height, and form control sizes.",
        "groups": [
          {
            "id": "avatar",
            "label": "Avatar Sizes",
            "tokens": {
              "avatar-xs": "16px",
              "avatar-sm": "24px",
              "avatar-md": "32px",
              "avatar-lg": "40px",
              "avatar-xl": "48px",
              "avatar-2xl": "64px",
              "avatar-3xl": "128px"
            }
          },
          {
            "id": "icon",
            "label": "Icon Sizes",
            "tokens": {
              "icon-xs": "12px",
              "icon-sm": "16px",
              "icon-md": "20px",
              "icon-lg": "24px",
              "icon-xl": "32px",
              "icon-2xl": "48px"
            }
          },
          {
            "id": "height",
            "label": "Control Heights",
            "tokens": {
              "height-2xs": "4px",
              "height-xs": "8px",
              "height-sm": "12px",
              "height-md": "16px",
              "height-lg": "24px",
              "height-xl": "32px",
              "height-2xl": "48px",
              "height-3xl": "64px",
              "height-4xl": "96px"
            }
          },
          {
            "id": "control",
            "label": "Form Controls",
            "tokens": {
              "checkbox-size": "20px",
              "radio-size": "20px",
              "switch-width": "35px",
              "switch-height": "22px"
            }
          }
        ]
      },
      {
        "id": "layout",
        "label": "Layout",
        "description": "Breakpoints, containers, columns, and gutters.",
        "groups": [
          {
            "id": "breakpoint",
            "label": "Breakpoints",
            "tokens": {
              "breakpoint-xs": "320px",
              "breakpoint-sm": "576px",
              "breakpoint-md": "768px",
              "breakpoint-lg": "992px",
              "breakpoint-xl": "1200px",
              "breakpoint-2xl": "1400px"
            }
          },
          {
            "id": "container",
            "label": "Containers",
            "tokens": {
              "container-sm": "540px",
              "container-md": "720px",
              "container-lg": "960px",
              "container-xl": "1140px",
              "container-2xl": "1320px"
            }
          },
          {
            "id": "grid",
            "label": "Columns and Gutters",
            "tokens": {
              "columns": "12",
              "gutter-sm": "15px",
              "gutter-default": "30px"
            }
          }
        ]
      },
      {
        "id": "opacity",
        "label": "Opacity",
        "description": "Opacity scale for disabled, hover, and emphasis treatments.",
        "groups": [
          {
            "id": "opacity",
            "label": "All Opacity Tokens",
            "tokens": {
              "opacity-0": "0",
              "opacity-10": "0.1",
              "opacity-25": "0.25",
              "opacity-50": "0.5",
              "opacity-60": "0.6",
              "opacity-75": "0.75",
              "opacity-90": "0.9",
              "opacity-100": "1"
            }
          }
        ]
      },
      {
        "id": "shadows",
        "label": "Shadows",
        "description": "Elevation shadows composed from the drop-shadow part tokens.",
        "groups": [
          {
            "id": "composed",
            "label": "Shadows",
            "tokens": {
              "shadow-sm": "0px 2px 4px 0px rgba(0, 0, 0, 0.075)",
              "shadow-md": "0px 8px 16px 0px rgba(0, 0, 0, 0.15)",
              "shadow-lg": "0px 16px 48px 0px rgba(0, 0, 0, 0.176)"
            }
          },
          {
            "id": "parts",
            "label": "Shadow Parts",
            "tokens": {
              "drop-shadow-sm-offset-x": "0px",
              "drop-shadow-sm-offset-y": "2px",
              "drop-shadow-sm-blur": "4px",
              "drop-shadow-sm-spread": "0px",
              "drop-shadow-sm-color": "rgba(0, 0, 0, 0.075)",
              "drop-shadow-md-offset-x": "0px",
              "drop-shadow-md-offset-y": "8px",
              "drop-shadow-md-blur": "16px",
              "drop-shadow-md-spread": "0px",
              "drop-shadow-md-color": "rgba(0, 0, 0, 0.15)",
              "drop-shadow-lg-offset-x": "0px",
              "drop-shadow-lg-offset-y": "16px",
              "drop-shadow-lg-blur": "48px",
              "drop-shadow-lg-spread": "0px",
              "drop-shadow-lg-color": "rgba(0, 0, 0, 0.176)"
            }
          }
        ]
      },
      {
        "id": "z-index",
        "label": "Z-Index",
        "description": "Layering for dropdowns, sticky UI, modals, popovers, and tooltips.",
        "groups": [
          {
            "id": "z-index",
            "label": "All Z-Index Tokens",
            "tokens": {
              "z-dropdown": "1000",
              "z-sticky": "1020",
              "z-fixed": "1030",
              "z-modal-backdrop": "1040",
              "z-modal": "1050",
              "z-popover": "1060",
              "z-tooltip": "1070"
            }
          }
        ]
      }
    ],
    "portalOverrides": {
      "user": {
        "color-status-neutral": "#AAAAAA",
        "color-status-warning": "#F8BB73",
        "color-status-review": "#F97B9C",
        "color-status-danger": "#FD7272",
        "color-status-success": "#517E6B",
        "color-status-info": "#7ACBEB",
        "color-status-positive": "#BBE68F"
      }
    },
    "daisyThemes": {
      "admin": {
        "name": "seedtrust-admin",
        "tokens": {
          "color-base-100": "#FFFFFF",
          "color-base-200": "#F4F5F7",
          "color-base-300": "#E4E7EB",
          "color-base-content": "#333333",
          "color-primary": "#4466A2",
          "color-primary-content": "#FFFFFF",
          "color-secondary": "#3F806A",
          "color-secondary-content": "#FFFFFF",
          "color-accent": "#4466A2",
          "color-accent-content": "#FFFFFF",
          "color-neutral": "#9E9E9E",
          "color-neutral-content": "#FFFFFF",
          "color-info": "#17A2B8",
          "color-info-content": "#FFFFFF",
          "color-success": "#28A745",
          "color-success-content": "#FFFFFF",
          "color-warning": "#FFC107",
          "color-warning-content": "#333333",
          "color-error": "#DC3545",
          "color-error-content": "#FFFFFF",
          "radius-selector": "4px",
          "radius-field": "4px",
          "radius-box": "4px",
          "size-selector": "4px",
          "size-field": "4px",
          "border": "1px",
          "depth": "1",
          "noise": "0"
        }
      },
      "user": {
        "name": "seedtrust-user",
        "tokens": {
          "color-base-100": "#FFFFFF",
          "color-base-200": "#F8F9FE",
          "color-base-300": "#ECEEF4",
          "color-base-content": "#354052",
          "color-primary": "#33456A",
          "color-primary-content": "#FFFFFF",
          "color-secondary": "#517E6B",
          "color-secondary-content": "#FFFFFF",
          "color-accent": "#843077",
          "color-accent-content": "#FFFFFF",
          "color-neutral": "#8F9DAF",
          "color-neutral-content": "#FFFFFF",
          "color-info": "#7ACBEB",
          "color-info-content": "#354052",
          "color-success": "#517E6B",
          "color-success-content": "#FFFFFF",
          "color-warning": "#F8BB73",
          "color-warning-content": "#354052",
          "color-error": "#E3170A",
          "color-error-content": "#FFFFFF",
          "radius-selector": "4px",
          "radius-field": "4px",
          "radius-box": "4px",
          "size-selector": "4px",
          "size-field": "4px",
          "border": "1px",
          "depth": "1",
          "noise": "0"
        }
      }
    }
  },
  "guidelines": {
    "sections": [
      {
        "id": "principles",
        "label": "Principles",
        "description": "Qualities a redesign must keep."
      },
      {
        "id": "behaviors",
        "label": "Behaviors",
        "description": "Interaction rules that span components and can be checked."
      },
      {
        "id": "prototype-standards",
        "label": "Prototype standards",
        "description": "Rules about the mockup being reviewable, not about the product."
      },
      {
        "id": "for-agents",
        "label": "For agents",
        "description": "Where the machine-readable version lives and how to point an agent at it."
      }
    ],
    "principles": [
      {
        "id": "operational-escrow",
        "title": "Operational escrow software",
        "body": "Admin surfaces feel like the tools staff run money through: conservative, clear, audit-friendly, workflow-first. No marketing layouts, hero text, or decorative panels.",
        "portals": [
          "admin"
        ]
      },
      {
        "id": "money-first",
        "title": "Money movement first",
        "body": "Every screen leads with money movement, approval state, exception or risk, the owner, and the next action. Anything that does not change a decision comes after, or not at all.",
        "portals": [
          "admin",
          "user"
        ]
      },
      {
        "id": "screenshots-are-the-spec",
        "title": "Screenshots are the spec",
        "body": "When SeedTrust screenshots are the source, match them exactly: colors, spacing, typography, radius, icons, and page composition.",
        "portals": [
          "admin",
          "user"
        ],
        "since": "2026-08-20"
      },
      {
        "id": "two-foundations-one-system",
        "title": "Two foundations, one component set",
        "body": "Admin is the foundation for /admin/* routes. User is the foundation for Agency, Case Manager, client, and portal screens. The same components serve both; a component is split only when structure, behavior, or required states differ, never because colors differ.",
        "portals": [
          "admin",
          "user"
        ],
        "since": "2026-08-20"
      },
      {
        "id": "daisy-primitive-layer",
        "title": "DaisyUI is the primitive layer",
        "body": "DaisyUI v5 is the official primitive layer. Use the project wrapper first (Join, Dropdown, Stat, and the rest), DaisyUI primitives directly only when no wrapper fits, and the utility classes shown on Foundation rather than raw CSS variables inside components.",
        "portals": [
          "admin",
          "user"
        ],
        "since": "2026-08-20",
        "because": "The revived ad71918 component port standardized on DaisyUI-backed wrappers with the seedtrust-admin and seedtrust-user themes."
      },
      {
        "id": "admin-foundation-follows-flask",
        "title": "Admin foundation follows the Flask admin shell",
        "body": "The admin body background is the Flask admin DaisyUI seedtrust-classic base-200 token, and admin chrome stays consistent with it.",
        "portals": [
          "admin"
        ],
        "since": "2026-08-20"
      },
      {
        "id": "user-foundation-is-legacy-agency",
        "title": "User foundation is the legacy agency portal",
        "body": "Agency and Case Manager colors come from the legacy Flask agency portal styles, never the Next PWA palette. Navy carries shell, navigation, and main actions; purple carries links, pagination, and secondary case actions; green is approval and support; sky is informational status.",
        "portals": [
          "user"
        ],
        "since": "2026-08-20"
      },
      {
        "id": "neutral-surfaces",
        "title": "Neutral surfaces carry the structure",
        "body": "Neutral surfaces and the body background do most of the layout work. Semantic and status colors are reserved for meaning.",
        "portals": [
          "admin",
          "user"
        ]
      },
      {
        "id": "system-type",
        "title": "System type, no display fonts",
        "body": "The Bootstrap/Helvetica-style system stack from the project tokens, everywhere. No editorial or novelty type.",
        "portals": [
          "admin",
          "user"
        ]
      },
      {
        "id": "say-it-once",
        "title": "Say it once",
        "body": "Show a count, amount, or status in one place. Do not repeat it across banners, cards, badges, and helper text.",
        "portals": [
          "admin",
          "user"
        ]
      },
      {
        "id": "structure-encodes-meaning",
        "title": "Structure encodes meaning",
        "body": "Dividers, numbering, labels, grouping, and cards exist to clarify a relationship. None of them decorates empty space.",
        "portals": [
          "admin",
          "user"
        ]
      },
      {
        "id": "show-dont-explain",
        "title": "Show, don't explain",
        "body": "State, placement, affordance, and concise labels do the explaining. No banners, helper paragraphs, onboarding copy, or callouts unless the consequence is high-risk or the brief requires them.",
        "portals": [
          "admin",
          "user"
        ]
      },
      {
        "id": "plain-verbs",
        "title": "Plain verbs, consistent names",
        "body": "Actions are written from the user's side of the screen with plain verbs, and the same action carries the same name everywhere.",
        "portals": [
          "admin",
          "user"
        ]
      },
      {
        "id": "build-from-catalog",
        "title": "Build from the catalog",
        "body": "Use a project component when one exists; extend or compose before creating a local variant. Never hardcode a value when a token, utility class, or component prop exists.",
        "portals": [
          "admin",
          "user"
        ]
      }
    ],
    "behaviors": [
      {
        "id": "money-actions-confirmed",
        "title": "Money moves only after a visible confirmation",
        "body": "Irreversible or sensitive financial and approval actions are visibly confirmed before they run, and the confirmation names exactly what it affects: which records, how many, what amount, and what cannot be undone.",
        "components": [
          "modal",
          "button",
          "dropdown",
          "credit-card"
        ],
        "portals": [
          "admin",
          "user"
        ]
      },
      {
        "id": "tables-paginate-fifteen",
        "title": "Full-page tables paginate at 15 rows",
        "body": "Transaction and work-queue tables show 15 rows per page with a Showing X-Y of N footer and numbered Prev/Next pagination. A table that intentionally does not paginate documents the cap or reason in the handoff.",
        "components": [
          "table",
          "pagination"
        ],
        "portals": [
          "admin",
          "user"
        ],
        "since": "2026-08-27"
      },
      {
        "id": "overlay-trigger-context",
        "title": "Overlays keep their trigger in view",
        "body": "While a modal or drawer is open, the row, card, or item that opened it is marked active. When it closes, that item stays highlighted until the user moves on, and keyboard focus returns to it.",
        "components": [
          "modal",
          "table",
          "card",
          "content-card",
          "list"
        ],
        "portals": [
          "admin",
          "user"
        ]
      },
      {
        "id": "trigger-surfaces",
        "title": "Anything that opens something is a control",
        "body": "A row, card, cell, or text region that opens a modal, drawer, or detail view has hover, focus, and keyboard behavior, and is a semantic interactive element whenever feasible.",
        "components": [
          "table",
          "card",
          "content-card",
          "list",
          "stat"
        ],
        "portals": [
          "admin",
          "user"
        ]
      },
      {
        "id": "forms-keep-context",
        "title": "Forms keep context",
        "body": "Labels stay visible, the user's input survives a validation error, and errors appear only after the user has interacted with the field.",
        "components": [
          "input",
          "textarea",
          "select",
          "combobox",
          "autocomplete",
          "multi-select",
          "datepicker",
          "phone-input",
          "file-upload",
          "otp",
          "wysiwyg",
          "form-field",
          "fieldset"
        ],
        "portals": [
          "admin",
          "user"
        ]
      },
      {
        "id": "error-scope",
        "title": "Errors land at the narrowest useful scope",
        "body": "Field errors for validation. Row or form errors for a failed action. Page-level errors only for a failed primary load. A toast only for transient, nonblocking feedback; anything persistent or actionable stays visible in context.",
        "components": [
          "input",
          "textarea",
          "select",
          "combobox",
          "autocomplete",
          "multi-select",
          "datepicker",
          "phone-input",
          "file-upload",
          "otp",
          "wysiwyg",
          "alert",
          "toast",
          "table",
          "modal"
        ],
        "portals": [
          "admin",
          "user"
        ]
      },
      {
        "id": "failure-copy",
        "title": "Failures say what, so what, and what next",
        "body": "A failure states what failed, the consequence, and the next useful action in plain language, with a retry, correction, or return path. Raw provider or status-code messages never appear as interface copy.",
        "components": [
          "alert",
          "toast",
          "modal",
          "empty-state"
        ],
        "portals": [
          "admin",
          "user"
        ]
      },
      {
        "id": "action-sequence",
        "title": "Actions show their whole sequence",
        "body": "A consequential action moves through ready, pending, failure, recovery or retry, and success. Input is preserved throughout, and it is always clear whether the action took effect.",
        "components": [
          "button",
          "icon-button",
          "join",
          "dropdown",
          "alert",
          "toast",
          "loading",
          "progress-bar"
        ],
        "portals": [
          "admin",
          "user"
        ]
      },
      {
        "id": "every-state-designed",
        "title": "Every state is designed",
        "body": "Empty, loading, error, disabled, hover and focus, confirmation, and destructive states are part of the flow wherever they apply, not afterthoughts.",
        "components": [
          "input",
          "textarea",
          "select",
          "combobox",
          "autocomplete",
          "multi-select",
          "datepicker",
          "phone-input",
          "file-upload",
          "otp",
          "wysiwyg",
          "checkbox",
          "radio",
          "switch",
          "button",
          "icon-button",
          "join",
          "dropdown",
          "table",
          "modal",
          "loading",
          "empty-state",
          "alert",
          "toast"
        ],
        "portals": [
          "admin",
          "user"
        ]
      },
      {
        "id": "selection-scope",
        "title": "Selection scope is explicit",
        "body": "The header control selects the visible rows first; selecting every matching result is a separate, named action. Hidden rows are never selected silently, and a selection is never discarded silently.",
        "components": [
          "table",
          "checkbox",
          "pagination"
        ],
        "portals": [
          "admin",
          "user"
        ]
      },
      {
        "id": "selection-context",
        "title": "Selections survive their context, and say so",
        "body": "The selected count and its scope stay visible next to the bulk actions. Pagination, search, filter, sort, refresh, deletion, and partial failure each have a defined effect on the selection.",
        "components": [
          "table",
          "pagination"
        ],
        "portals": [
          "admin",
          "user"
        ]
      },
      {
        "id": "motion-explains",
        "title": "Motion explains, never decorates",
        "body": "Inserting or removing content animates the element and the resulting reflow as one move. Overlays animate in and out without shifting what is behind them. Motion is brief and nonblocking, the change reads without it, and reduced-motion gets an instant alternative.",
        "components": [
          "modal",
          "toast",
          "alert",
          "table",
          "card",
          "dropdown",
          "tooltip",
          "accordion",
          "collapse",
          "hover-3d"
        ],
        "portals": [
          "admin",
          "user"
        ]
      },
      {
        "id": "keyboard-focus",
        "title": "Every control works from the keyboard",
        "body": "Every interactive element is reachable by keyboard, in a sensible order, and shows a visible focus state.",
        "components": [
          "button",
          "icon-button",
          "join",
          "dropdown",
          "input",
          "textarea",
          "select",
          "combobox",
          "autocomplete",
          "multi-select",
          "datepicker",
          "phone-input",
          "file-upload",
          "otp",
          "wysiwyg",
          "checkbox",
          "radio",
          "switch",
          "tabs",
          "pagination",
          "modal",
          "table",
          "breadcrumbs",
          "tooltip",
          "accordion",
          "collapse",
          "steps",
          "dock",
          "sidebar",
          "header"
        ],
        "portals": [
          "admin",
          "user"
        ]
      },
      {
        "id": "not-color-alone",
        "title": "State never relies on color alone",
        "body": "Status and errors carry text or an icon alongside color, so they read in grayscale and to color-blind users.",
        "components": [
          "badge",
          "indicator",
          "alert",
          "toast",
          "input",
          "textarea",
          "select",
          "combobox",
          "autocomplete",
          "multi-select",
          "datepicker",
          "phone-input",
          "file-upload",
          "otp",
          "wysiwyg",
          "progress-bar",
          "progress-circular",
          "switch",
          "steps"
        ],
        "portals": [
          "admin",
          "user"
        ]
      },
      {
        "id": "mocked-never-real",
        "title": "Mocked behavior never looks real",
        "body": "Mocked backend behavior is never presented as real authentication, database, payments, card issuing, or approvals. Prototype-only reveals and confirmations stay visibly simulated.",
        "components": [
          "button",
          "modal",
          "credit-card",
          "alert",
          "toast"
        ],
        "portals": [
          "admin",
          "user"
        ],
        "standard": "prototype"
      },
      {
        "id": "three-pages-of-fixtures",
        "title": "Paginated collections show three pages",
        "body": "Fixture data covers page 1, page 2, and a partial last page; load-more covers the initial batch plus two more with a partial final batch. Sparse and single-page states exist as secondary fixtures, never as the only demonstration.",
        "components": [
          "table",
          "pagination"
        ],
        "portals": [
          "admin",
          "user"
        ],
        "standard": "prototype"
      },
      {
        "id": "stable-identities",
        "title": "Paging never loses an item",
        "body": "Items keep stable identities. Changing pages or appending results never duplicates, skips, reorders, or miscounts them.",
        "components": [
          "table",
          "pagination"
        ],
        "portals": [
          "admin",
          "user"
        ],
        "standard": "prototype"
      },
      {
        "id": "reachable-failure",
        "title": "Every consequential action has a reachable failure",
        "body": "At least one representative failure per consequential action, reachable on purpose through a scenario switch, a query parameter, a fixture, or a resettable success-then-failure cycle. Never random, and never production data.",
        "components": [
          "button",
          "icon-button",
          "join",
          "dropdown",
          "alert",
          "toast",
          "modal"
        ],
        "portals": [
          "admin",
          "user"
        ],
        "standard": "prototype"
      }
    ]
  }
}
