{
  "schemaVersion": 1,
  "version": "0.3.0",
  "core": "0.3.0",
  "items": [
    {
      "name": "modal",
      "version": "0.3.0",
      "kind": "component",
      "title": "Modal",
      "description": "Base UI Dialog (focus trap, Esc, scroll-lock, a11y) skinned as an Echo device panel. Enter uses motion.summon; exit is a GSAP tween that completes before unmount via useGsapPresence + actionsRef. sound.transition on open.",
      "items": []
    },
    {
      "name": "menu",
      "version": "0.3.0",
      "kind": "component",
      "title": "Menu",
      "description": "Base UI Menu (typeahead, roving focus, submenu timing, checkbox/radio item semantics) skinned as an Echo floating panel — the Select's molded cap trigger and the same lit dot for what is on. Two sounds: transition when the panel arrives, select when an item commits. Exports ContextMenu from the same item for the right-click case. Compound API.",
      "items": []
    },
    {
      "name": "sheet",
      "version": "0.3.0",
      "kind": "component",
      "title": "Sheet",
      "description": "A molded chassis panel that slides in from an edge — the console side panel and the mobile nav. Built on Base UI's Drawer, so it carries swipe-to-dismiss and a backdrop that tracks the swipe rather than a Dialog translated sideways. sound.transition on open. Compound API.",
      "items": []
    },
    {
      "name": "alert-dialog",
      "version": "0.3.0",
      "kind": "component",
      "title": "AlertDialog",
      "description": "A destructive confirm. Modal covers the structure; this is the semantics — role=alertdialog, a required description, and no dismissal by clicking away, so the question has to be answered. Its own sound: caution (the one rough waveform) on open, error on a destructive confirm. Severity reads as the deep end of the accent ramp, never an imported red.",
      "items": []
    },
    {
      "name": "size",
      "version": "0.3.0",
      "kind": "component",
      "title": "SizeProvider",
      "description": "One size scale for everything with a height: sm, md and lg are the control heights (32, 44 and 60px at default density), so a button, a field and a select of the same size line up in a row. Wrap a toolbar, a filter bar or a card footer in SizeProvider and every control inside takes that size; a size passed to a control wins. Controls read it with useControlSize.",
      "items": []
    },
    {
      "name": "scope",
      "version": "0.3.0",
      "kind": "component",
      "title": "Scope",
      "description": "Part of the page speaking with its own vocabulary. accent gives what's inside a colour of its own for identity (a category, a filter pad, a person, a creature): the theme engine run on your colour, so its lit caps, glow and LEDs are derived and contrast-checked like your main accent, and every component inside picks them up. It's for telling things apart, never for state. molding=\"soft\" rounds the caps inside and fills them out with a pillow of light. It draws nothing and takes no space.",
      "items": []
    },
    {
      "name": "hardware-button",
      "version": "0.3.0",
      "kind": "component",
      "title": "HardwareButton",
      "description": "A molded cap in a recessed well with real press travel and sound. primary/neutral/ghost; sm/md/lg on the one control scale (32/44/60px outer, so it lines up with a Field of the same size); fullWidth, icon slots, loading, engraved. It presses like a key switch (useCapPhysics), with the clicks on the mechanism; plastic color from createEchoTheme.",
      "items": [
        "size"
      ]
    },
    {
      "name": "popover",
      "version": "0.3.0",
      "kind": "component",
      "title": "Popover",
      "description": "Base UI Popover (anchoring, focus, dismiss, a11y) skinned as an Echo panel. Same useGsapPresence bridge as Modal (summon enter, GSAP exit before unmount), sound.select on open.",
      "items": []
    },
    {
      "name": "tooltip",
      "version": "0.3.0",
      "kind": "component",
      "title": "Tooltip",
      "description": "Base UI Tooltip (hover/focus, delay, a11y) skinned as a compact molded chip. Same useGsapPresence bridge as Modal/Popover; no sound.",
      "items": []
    },
    {
      "name": "select",
      "version": "0.3.0",
      "kind": "component",
      "title": "Select",
      "description": "Base UI Select (typeahead, keyboard, a11y) skinned as an Echo dropdown — a molded cap trigger and a floating panel with a lit dot on the selected option. CSS fade in and out (Base UI Select cannot hold a node for a GSAP exit); sound.select on change.",
      "items": [
        "size"
      ]
    },
    {
      "name": "command",
      "version": "0.3.0",
      "kind": "component",
      "title": "Command",
      "description": "The command palette as a dot-matrix readout: the query line is the LcdChip's recessed screen well, in the LCD voice, with an emissive caret and a scanline wash. Base UI Autocomplete for the input, filtering and listbox semantics; Base UI Dialog for the frame, because a palette is summoned to the middle of the screen rather than anchored to anything. Cmd/Ctrl+K by default; matches on hidden keywords as well as labels.",
      "items": []
    },
    {
      "name": "tabs",
      "version": "0.3.0",
      "kind": "component",
      "title": "Tabs",
      "description": "Base UI Tabs (roving focus, arrow-key nav, a11y) marked with the library's one \"you are here\": a 2px lit rail slides under the open tab, over a hairline baseline. Labels stay on the chassis. sound.select on change. Compound API.",
      "items": [
        "size"
      ]
    },
    {
      "name": "accordion",
      "version": "0.3.0",
      "kind": "component",
      "title": "Accordion",
      "description": "Base UI Accordion (keyboard, a11y, height measurement) skinned as molded device panels that expand. Click sound on toggle; height animates via CSS. Compound API.",
      "items": []
    },
    {
      "name": "switch",
      "version": "0.3.0",
      "kind": "component",
      "title": "Switch",
      "description": "Base UI Switch (role=switch, keyboard, a11y) with a hardware-toggle skin — a molded thumb sliding in a recessed track — and a click sound on toggle.",
      "items": []
    },
    {
      "name": "checkbox",
      "version": "0.3.0",
      "kind": "component",
      "title": "Checkbox",
      "description": "Base UI Checkbox (keyboard, indeterminate, a11y) with a molded box skin that fills accent and shows a check when set. Select sound on change.",
      "items": []
    },
    {
      "name": "slider",
      "version": "0.3.0",
      "kind": "component",
      "title": "Slider",
      "description": "Base UI Slider (keyboard, drag, track-press, a11y) with a recessed rail + molded knob and a scrubbing tick sound on each step — very hardware.",
      "items": []
    },
    {
      "name": "segmented",
      "version": "0.3.0",
      "kind": "component",
      "title": "Segmented",
      "description": "A hardware segmented selector — molded uppercase segments in a recessed well, the active one on the lit primary cap. A radiogroup value selector (roving focus, arrow-key select, select sound), distinct from Tabs which switches content panels. Composes var(--echo-*).",
      "items": [
        "size"
      ]
    },
    {
      "name": "field",
      "version": "0.3.0",
      "kind": "component",
      "title": "Field",
      "description": "A text input sunk into a recessed well. The inner edge lights in the accent on focus; a mono eyebrow label and an optional machine (mono) value voice. Composes var(--echo-*).",
      "items": [
        "size"
      ]
    },
    {
      "name": "date-field",
      "version": "0.3.0",
      "kind": "component",
      "title": "DateField",
      "description": "A date typed into wheels, day, month and year in the order the locale writes them, each a row of small flaps that turn over to the value. Field's recessed well and lit edge, on the same size scale. The value is an ISO date, so no time zone can move a day.",
      "items": [
        "size",
        "field"
      ]
    },
    {
      "name": "calendar",
      "version": "0.3.0",
      "kind": "component",
      "title": "Calendar",
      "description": "A month on a device screen. The days are its lit segments: the chosen day lit with the one lit accent, today on a lit rail, a day that can't be chosen struck through. Two keys page the months, and the month slides the way it went.",
      "items": [
        "date-field",
        "hardware-button",
        "size"
      ]
    },
    {
      "name": "date-picker",
      "version": "0.3.0",
      "kind": "component",
      "title": "DatePicker",
      "description": "A DateField with a calendar key in its well. Type the date, or open a Calendar under the field and choose it; the flaps turn over to the day you chose. The value is an ISO date.",
      "items": [
        "date-field",
        "calendar",
        "popover",
        "hardware-button"
      ]
    },
    {
      "name": "file-upload",
      "version": "0.3.0",
      "kind": "component",
      "title": "FileUpload",
      "description": "A recessed tray you press to choose files or drop them on; its inner edge lights while files are over it. Each file becomes a row with a Progress strip while it goes up, and a key to cancel, retry or remove it. It has no upload code: your handler uploads, and reports progress.",
      "items": [
        "field",
        "hardware-button",
        "progress",
        "size"
      ]
    },
    {
      "name": "textarea",
      "version": "0.3.0",
      "kind": "component",
      "title": "Textarea",
      "description": "Field's recessed well, multi-line and autosizing. The height is measured from the browser's own layout rather than counted from newlines, so it stays right when lines wrap and when the container resizes. Same well, same focus glow, same eyebrow label as Field.",
      "items": []
    },
    {
      "name": "badge",
      "version": "0.3.0",
      "kind": "component",
      "title": "Badge",
      "description": "A small molded/LCD status label. neutral (plastic), accent (the lit primary cap), lcd (glowing screen text), outline. Static; consumes var(--echo-*).",
      "items": []
    },
    {
      "name": "kbd",
      "version": "0.3.0",
      "kind": "component",
      "title": "Kbd",
      "description": "A molded keycap for keyboard hints — a tiny cap that never presses. Uses the <kbd> element.",
      "items": []
    },
    {
      "name": "divider",
      "version": "0.3.0",
      "kind": "component",
      "title": "Divider",
      "description": "A panel seam — a hairline with a faint light lip. Horizontal or vertical; role=separator.",
      "items": []
    },
    {
      "name": "stat-tile",
      "version": "0.3.0",
      "kind": "component",
      "title": "StatTile",
      "description": "A recessed LCD readout: a glowing value over a machine label, seated in a dark well. Static; consumes var(--echo-*).",
      "items": [
        "roll"
      ]
    },
    {
      "name": "chart",
      "version": "0.3.0",
      "kind": "component",
      "title": "Chart",
      "description": "StatTile's dot-matrix language applied to a series: a column per sample, cells lit from the bottom, in the same recessed screen well LcdChip and Progress use. Values quantise to whole cells by construction — steppiness is the data model, not a style. No axes, no gridlines, no tooltips, no smoothing: it is a readout, not a charting library.",
      "items": []
    },
    {
      "name": "app-shell",
      "version": "0.3.0",
      "kind": "component",
      "title": "AppShell",
      "description": "The app frame: a molded chassis rail lit from the key angle, a sticky sidebar, and the content between them. Slots, not props — the shell owns the layout, you own the contents. Ships the skip link by construction rather than as an option, and derives the sidebar's sticky offset from the rail's height so the two cannot drift. Below 900px the sidebar column is removed rather than stacked; pair it with a Sheet.",
      "items": []
    },
    {
      "name": "panel",
      "version": "0.3.0",
      "kind": "component",
      "title": "Panel",
      "description": "The two halves of the device material law as a container: raised molded plastic (things you touch) or a recessed dark screen (things you read). Consumes var(--echo-*).",
      "items": []
    },
    {
      "name": "progress",
      "version": "0.3.0",
      "kind": "component",
      "title": "Progress",
      "description": "A discrete LED cell meter in a recessed strip — filled cells are lit accent LEDs with a bloom. Steppy by construction; consumes var(--echo-*).",
      "items": []
    },
    {
      "name": "loader",
      "version": "0.3.0",
      "kind": "component",
      "title": "Loader",
      "description": "Three accent LEDs breathing in sequence — the device thinking. role=status; reduced motion holds the dots steady. Consumes var(--echo-*).",
      "items": []
    },
    {
      "name": "status-dot",
      "version": "0.3.0",
      "kind": "component",
      "title": "StatusDot",
      "description": "A tiny LED socket, filled and blooming or hollow and dead. State is carried by fill-vs-hollow and by a 5.25:1 luminance step, not by hue, so it survives protan/deuteran/tritan and greyscale. Requires `label` or `decorative`. Consumes var(--echo-*).",
      "items": []
    },
    {
      "name": "toast",
      "version": "0.3.0",
      "kind": "component",
      "title": "Toast",
      "description": "A raised glass notification slab with a status LED, and the toaster that announces it. Mount <Toaster> once around the app and call toast() from useToast(): the toaster's live region is on the page before anything is said, so every toast is announced. Built on Base UI's Toast. Consumes var(--echo-*).",
      "items": []
    },
    {
      "name": "status-island",
      "version": "0.3.0",
      "kind": "component",
      "title": "StatusIsland",
      "description": "Work that runs in the background, kept in one small floating slab: at rest a pill with a lit socket and a readout; pressed, it blooms open the way every Echo panel arrives, wider first and then taller, into the detail and what you can do about it. It announces when the work starts, finishes or fails, never every percent. For uploads, exports, timers, recordings and anything \"writing…\".",
      "items": [
        "status-dot",
        "lcd-chip",
        "progress",
        "size"
      ]
    },
    {
      "name": "receipt",
      "version": "0.3.0",
      "kind": "component",
      "title": "Receipt",
      "description": "The device prints: a summary feeds out of a slot in the chassis a line at a time, each with a small tick, in dark ink on the paper colour, and waits to be torn off. For order confirmations, payments, invoices, weekly recaps and the summary of what an automated run did. It prints when it arrives after the page has loaded; one that's there from the start is simply there.",
      "items": [
        "hardware-button"
      ]
    },
    {
      "name": "ticket",
      "version": "0.3.0",
      "kind": "component",
      "title": "Ticket",
      "description": "A paper pass: what it's for on the main part, the code on a stub across a perforation. Use it and the stub tears off along the perforation and drops away, leaving the torn edge and \"Used\". For event tickets, boarding passes, coupons, invites and gift cards. The same paper and ink as Receipt; on a narrow screen the stub goes under the main part.",
      "items": [
        "hardware-button",
        "receipt"
      ]
    },
    {
      "name": "now-playing",
      "version": "0.3.0",
      "kind": "component",
      "title": "NowPlaying",
      "description": "A small player: a screen with where it's from, what's playing and the time in lit segments, a strip to scrub along, and the transport keys under it, play the lit one. For music, podcasts, voice messages and recordings. Every part is an Echo part (SegmentDisplay, Slider, HardwareButtons in a ButtonGroup); you own the audio, this is the device you control it with.",
      "items": [
        "segment-display",
        "slider",
        "hardware-button",
        "toolbar",
        "scope"
      ]
    },
    {
      "name": "lcd-chip",
      "version": "0.3.0",
      "kind": "component",
      "title": "LcdChip",
      "description": "An inline recessed LCD readout: a glowing accent value next to a machine label, sunk into a dark well. The chip form of StatTile — use it inline in a row of controls; use StatTile when the readout is a dashboard cell.",
      "items": [
        "roll"
      ]
    },
    {
      "name": "segment-display",
      "version": "0.3.0",
      "kind": "component",
      "title": "SegmentDisplay",
      "description": "A seven-segment readout drawn the way a real one looks: the segments a reading doesn't light stay faintly visible under the glass, and zeros that only pad a reading out print dim instead of vanishing. For the one number a screen is about: a frequency, a clock, an amount, a counter.",
      "items": [
        "roll",
        "scope"
      ]
    },
    {
      "name": "date-tile",
      "version": "0.3.0",
      "kind": "component",
      "title": "DateTile",
      "description": "The page of a desk calendar: the weekday and month engraved small on a raised tile, the day huge on the screen set into it. Change the date and the day turns over to the new one. sm sits in a list row (an event, a booking, an invoice due), md on a card, lg on its own. One date for assistive tech, said in full.",
      "items": [
        "segment-display",
        "panel",
        "scope"
      ]
    },
    {
      "name": "annunciator",
      "version": "0.3.0",
      "kind": "component",
      "title": "Annunciator",
      "description": "The row of fixed marks printed on a device's screen glass (REC, SYNC, MUTE, a battery), each dark until what it names is happening, then lit. Every mark is always there, so the eye learns where each sits and reads the row at a glance: a status bar, a media player, a recorder. Screen readers hear which are on, in words.",
      "items": [
        "scope"
      ]
    },
    {
      "name": "led-key",
      "version": "0.3.0",
      "kind": "component",
      "title": "LedKey",
      "description": "A molded pill key with an indicator LED that breathes while lit. The latching sibling of HardwareButton: use it when the key's own state is part of the answer (armed, monitoring, recording), not for a command that fires and forgets.",
      "items": [
        "size"
      ]
    },
    {
      "name": "engraved-plate",
      "version": "0.3.0",
      "kind": "component",
      "title": "EngravedPlate",
      "description": "A paper-coloured metal plate with text cut into it and rivets at the edges — the one non-emissive readout in the library. Use it for a fact fixed to the device (a serial, a balance, a rating); use LcdChip for a value that updates while you watch.",
      "items": []
    },
    {
      "name": "textures",
      "version": "0.3.0",
      "kind": "component",
      "title": "Textures",
      "description": "The grain law as composable overlays: Dither (ordered Bayer), Noise (film grain), Halftone, Scanlines, plus GrainField (the brand surface) and Textured (the default stack). Nothing in Echo is ever a flat fill — and a dither or grain pass is the cure for the banding that large soft gradients show on the dark chassis. All tiles are generated as inline SVG data-URIs, so there are no asset files to copy. Every overlay is aria-hidden and pointer-events: none.",
      "items": []
    },
    {
      "name": "shader-field",
      "version": "0.3.0",
      "kind": "component",
      "title": "ShaderField",
      "description": "The live brand field: a WebGL domain-warped fbm gradient sampled from the accent ramp, blooming toward the cursor, with animated grain and TPDF debanding. Reads the accent ramp from the CSS it sits in (or from a pinned theme mirror), so it relights with the seed like every other surface. Reduced motion draws one static frame; no WebGL falls back to the wrapper's CSS gradient; the GL context is released on unmount.",
      "items": []
    },
    {
      "name": "radio-group",
      "version": "0.3.0",
      "kind": "component",
      "title": "RadioGroup",
      "description": "One choice from a small set: each option is a recessed hole beside its label, and the chosen one lights a pip inside its hole. Base UI owns roving focus, arrow-key selection, and form semantics; Echo owns the material. Compound API: RadioGroup with RadioGroup.Item children.",
      "items": []
    },
    {
      "name": "otp-field",
      "version": "0.3.0",
      "kind": "component",
      "title": "OTP field",
      "description": "The one-time code a sign-in asks for, as a row of lit digit windows — the Field's recessed well cut into six screens, in the LCD voice. Built on Base UI's OTP Field: a pasted code fills the row, arrow keys and Backspace walk it, and the phone can offer the code from an SMS. Composes var(--echo-*).",
      "items": [
        "size"
      ]
    },
    {
      "name": "number-field",
      "version": "0.3.0",
      "kind": "component",
      "title": "NumberField",
      "description": "A machined readout between two molded step caps — and the label above it is a scrub handle you drag left and right to dial the value. Base UI owns typing, arrow keys, alt/shift step sizes, clamping, and form semantics. Scrubbing is what makes this worth wrapping instead of using a plain number input.",
      "items": [
        "roll",
        "size"
      ]
    },
    {
      "name": "avatar",
      "version": "0.3.0",
      "kind": "component",
      "title": "Avatar",
      "description": "A person or device as a molded disc — the image seated in a well, or initials engraved into the plastic when there is no image or the image fails to load. The failure case is the whole point: a bare <img> with a broken URL leaves a hole, this falls back.",
      "items": []
    },
    {
      "name": "tag",
      "version": "0.3.0",
      "kind": "component",
      "title": "Tag",
      "description": "A label the user applied — a category, a person, a filter — optionally removable. Distinct from Badge, which reports state the system knows. The material says which is which: a Badge is printed onto the chassis, a Tag is a small plate that can be peeled off.",
      "items": []
    },
    {
      "name": "count-badge",
      "version": "0.3.0",
      "kind": "component",
      "title": "CountBadge",
      "description": "A number worth noticing — the lit sibling of Badge. Badge names a state; CountBadge counts a thing. It disappears at zero unless told otherwise, caps its face at max while still announcing the true count, and stays round at one digit.",
      "items": []
    },
    {
      "name": "skeleton",
      "version": "0.3.0",
      "kind": "component",
      "title": "Skeleton",
      "description": "The shape of content that has not arrived: a recess in the chassis with a slow sheen crossing it. Every skeleton is aria-hidden by default — the wait is announced once, by the region that owns it, via the label prop. Reduced motion holds the sheen still rather than looping forever.",
      "items": []
    },
    {
      "name": "banner",
      "version": "0.3.0",
      "kind": "component",
      "title": "Banner",
      "description": "A persistent inline message strip. Toast is transient and reports what just happened; Banner stays and describes a condition still true. Built as a piece of the device: a molded strip, a status LED in a recessed well, and an LCD tag that names the tone. Severity is carried by the LED's shape and the tag's words rather than by red/amber/green — Echo has one accent, and inventing hues the seed does not own would break on a reseed.",
      "items": []
    },
    {
      "name": "empty-state",
      "version": "0.3.0",
      "kind": "component",
      "title": "EmptyState",
      "description": "Nothing here, and what to do about it. Rendered as a quiet recess: the screen is on and working, there is simply nothing in it yet. The action slot is part of the API on purpose — an empty state without a way forward is a dead end.",
      "items": []
    },
    {
      "name": "creature",
      "version": "0.3.0",
      "kind": "component",
      "title": "Creature",
      "description": "A small companion that lives in the interface and only reports what's happening: idle, busy, done, an error, asleep. As a vector it breathes, drifts, blinks and watches the pointer, and a new mood carries on from wherever it is; as dots it lives on a screen and moves in steps. It's Echo by default; bring your own character as a few paths (a body, eye whites, pupils) or rows of text, and Echo supplies the materials so it relights with the theme.",
      "items": [
        "scope"
      ]
    },
    {
      "name": "perch",
      "version": "0.3.0",
      "kind": "component",
      "title": "Perch",
      "description": "A creature on the top edge of whatever you put in it: sitting there watching, or hiding behind the edge and peeking up when you come near. It reacts through its mood like every Creature, and never covers what it sits on: the space it needs above the edge is kept for it. For onboarding, an empty state's card, a success moment, a product's assistant.",
      "items": [
        "creature"
      ]
    },
    {
      "name": "table",
      "version": "0.3.0",
      "kind": "component",
      "title": "Table",
      "description": "Rows of data in a recessed screen well. A real <table> with a real <caption>, compound parts for a table you lay out yourself, and a data mode for one you don't: given columns and rows it sorts (LED pips and aria-sort), selects (Checkbox, with a select-all that can read 'some'), filters, keeps its header at the top, windows thousands of rows, and shows loading and empty rows. Rows that move slide to their new place.",
      "items": [
        "checkbox"
      ]
    },
    {
      "name": "description-list",
      "version": "0.3.0",
      "kind": "component",
      "title": "DescriptionList",
      "description": "Things and their values: order details, account settings, a device's specs, a system's status at a glance. plain sets the terms as machine labels over their values, with the one separator between rows; screen puts the whole list on a dark screen with the values in the readout face, like the glance list on a phone's home screen.",
      "items": [
        "scope"
      ]
    },
    {
      "name": "shortcut-map",
      "version": "0.3.0",
      "kind": "component",
      "title": "ShortcutMap",
      "description": "The \"Keyboard shortcuts\" sheet a desktop app opens with ?: the list of what each shortcut does, and above it the keyboard drawn in Kbd caps. Point at a shortcut and its keys light on the board; press keys on your own keyboard and the drawn ones go down with them. The list is the content; the board is a picture of it.",
      "items": [
        "kbd"
      ]
    },
    {
      "name": "widget-grid",
      "version": "0.3.0",
      "kind": "component",
      "title": "WidgetGrid",
      "description": "Widgets at fixed footprints (1×1, 2×1, 2×2, 4×2) on a grid people arrange for themselves: a dashboard, a home screen, a panel of gauges. Each widget is your own content; the grid gives it a place. Arrange it and each widget gets a Move key and, if you allow it, a Remove key: drag a widget by its Move key and the others slide out of its way, or use the arrow keys and the new place is said.",
      "items": [
        "hardware-button"
      ]
    },
    {
      "name": "breadcrumb",
      "version": "0.3.0",
      "kind": "component",
      "title": "Breadcrumb",
      "description": "Where you are in the hierarchy, as an engraved trail. A labelled nav around an ordered list; the last item is the current page, so it is not a link and carries aria-current. Separators are hidden from assistive tech — the list structure is the real separator.",
      "items": []
    },
    {
      "name": "pagination",
      "version": "0.3.0",
      "kind": "component",
      "title": "Pagination",
      "description": "A row of molded number caps with the current page lit, inside a labelled nav. The window keeps the first and last page always reachable, never elides a single page behind a gap, and never changes width as you page through — a control that reflows under the cursor is how you misclick. The arithmetic is exported as paginationRange if you need it elsewhere.",
      "items": []
    },
    {
      "name": "steps",
      "version": "0.3.0",
      "kind": "component",
      "title": "Steps",
      "description": "How far through a sequence you are, as LED stations wired together: done stations stay lit but dim, the current one blooms, upcoming ones are dead plastic. An ordered list inside a labelled group, with aria-current on the current station and the done state stated in text — a colour is not a message.",
      "items": []
    },
    {
      "name": "card",
      "version": "0.3.0",
      "kind": "component",
      "title": "Card",
      "description": "A Panel with an anatomy, so every card is spaced the same way: media flush to the edges, a header (title, description, one action), a body, and a footer whose controls are sm, pinned to the bottom so a row of cards lines its actions up. A Card alone in a list item fills it, so a Grid of cards as a list is one height a row. With href or onClick the whole card is pressable: the title becomes the link or button stretched over the card, it presses a pixel into the surface and sends Panel's ripple, and its own action and footer controls stay separate targets. Closed: slots are props, spacing is size.",
      "items": [
        "panel",
        "size"
      ]
    },
    {
      "name": "item",
      "version": "0.3.0",
      "kind": "component",
      "title": "Item",
      "description": "The row every list is made of: media to recognise it by, a title and a line under it, and what trails it. Consecutive Items are ruled by a hairline. The title and description wrap onto more lines when they need them, so a plan's features read whole; truncate keeps each to one line. href or onClick makes the whole row one target. swipeActions sit behind the row: swipe it toward the start and they slide into view, and Tab reaches each one, sliding the row open the same way.",
      "items": []
    },
    {
      "name": "layout",
      "version": "0.3.0",
      "kind": "component",
      "title": "Stack & Grid",
      "description": "The two layouts a screen is made of, with gaps on the space scale: Stack is a column or a wrapping row, Grid is as many columns as fit (minItemWidth) or a fixed number. Closed: a gap is a step, not a length, so two cards laid out by two people are spaced the same way.",
      "items": []
    },
    {
      "name": "collapsible",
      "version": "0.3.0",
      "kind": "component",
      "title": "Collapsible",
      "description": "One disclosure on its own: a ruled row with a title and a chevron that opens a panel. For \"show more\", advanced settings or a single FAQ row, without Accordion's group rules. Built on Base UI Collapsible; closed content stays findable with the browser's find-in-page, which opens it.",
      "items": []
    },
    {
      "name": "scroll-area",
      "version": "0.3.0",
      "kind": "component",
      "title": "ScrollArea",
      "description": "A region that scrolls inside itself, with the scrollbar in the device's material: a thin groove and a molded thumb that fattens under the hand, and shade at an edge wherever the content continues. Native scrolling (wheel, touch, keyboard, find-in-page) is untouched. Built on Base UI ScrollArea.",
      "items": []
    },
    {
      "name": "link",
      "version": "0.3.0",
      "kind": "component",
      "title": "Link",
      "description": "Inline text that goes somewhere. The words stay in the text colour and the accent is the underline, because accent-coloured text on the chassis is under AA. external opens a new tab and says so; render takes your router's link so navigation stays the router's.",
      "items": []
    },
    {
      "name": "toggle",
      "version": "0.3.0",
      "kind": "component",
      "title": "Toggle",
      "description": "The quiet key of a toolbar: bold, italic, grid or list, a filter. On is the cap held down in its well, not a light (that's LedKey). ToggleGroup puts Toggles in one long well with arrow-key focus: multiple lets any number be on, without it at most one. For exactly one of a few, always one, use Segmented. Built on Base UI Toggle and ToggleGroup.",
      "items": [
        "size",
        "toolbar"
      ]
    },
    {
      "name": "toolbar",
      "version": "0.3.0",
      "kind": "component",
      "title": "Toolbar",
      "description": "Several caps sharing one long well, like keys on one bar. ButtonGroup is the look alone: HardwareButtons that belong together, each its own tab stop. Toolbar adds a toolbar's behaviour: one tab stop for the whole bar and the arrow keys between its controls (Base UI Toolbar), sm controls by default, ToolbarGroup to keep a few in their own well, ToolbarSeparator between groups. Toggles and ToggleGroups inside join its arrow-key order by themselves.",
      "items": [
        "hardware-button",
        "size"
      ]
    },
    {
      "name": "range-slider",
      "version": "0.3.0",
      "kind": "component",
      "title": "RangeSlider",
      "description": "Two knobs on one rail for a span (a price range, a time window), with the rail lit between them. Slider's rail and knobs, with Slider's mass: the value moves at once and each knob catches up on a spring. They never cross; minGap keeps them apart. Each knob is its own slider for assistive tech, named from label.",
      "items": [
        "slider"
      ]
    },
    {
      "name": "knob",
      "version": "0.3.0",
      "kind": "component",
      "title": "Knob",
      "description": "A molded rotary cap in its well with an engraved pointer and a scale that lights up to the value. Drag it up (or around), turn it with the wheel once focused, or use the keys; it clicks at every step, settles onto each detent on a spring, and gives a little past either end. A slider for assistive tech: role=\"slider\" named by label, with every slider key.",
      "items": []
    },
    {
      "name": "tuner",
      "version": "0.3.0",
      "kind": "component",
      "title": "Tuner",
      "description": "A number picked the way a radio is tuned: a scale printed on the screen slides under a fixed, lit needle, and a seven-segment reading follows it. Drag it with your hand, flick it and it coasts onto a step, and every tick that passes the needle clicks. It fits a big range into a small width, since the range scrolls instead of being squeezed. A slider for assistive tech, with every slider key.",
      "items": [
        "segment-display",
        "scope"
      ]
    },
    {
      "name": "keypad",
      "version": "0.3.0",
      "kind": "component",
      "title": "Keypad",
      "description": "A payment terminal's keys under its screen. An amount fills from the right the way a till does (1, 2, 4, 0 reads 12.40) with its unused digits dim; a PIN lights a socket per digit and never shows them; a code shows its digits in cells. Type on a real keyboard and the key on screen goes down with your finger. It replaces the phone's own keyboard, so none pops up over it.",
      "items": [
        "hardware-button",
        "segment-display",
        "status-dot",
        "scope"
      ]
    },
    {
      "name": "filter-tray",
      "version": "0.3.0",
      "kind": "component",
      "title": "FilterTray",
      "description": "Chunky filter pads in one long well, with the action at its end. A pad that's on is a lit cap; the action carries the count. Apply, and the lit pads fold into the action (Morph) and it becomes one key saying how many are on, their names engraved on the tray's floor beside it; press it and they come back out. For the filter bar of a shop, a map or a feed.",
      "items": [
        "hardware-button",
        "morph",
        "size",
        "scope"
      ]
    },
    {
      "name": "week-strip",
      "version": "0.3.0",
      "kind": "component",
      "title": "WeekStrip",
      "description": "A week you tap through, the way the top of a phone's calendar works: seven days in a Segmented, each with its weekday and date, the chosen one lit, the light travelling there as a drop. Today carries a lit rail; a day with something on it has a pip. The keys at either end go a week back or forward, keeping the weekday.",
      "items": [
        "hardware-button",
        "segmented",
        "date-tile"
      ]
    },
    {
      "name": "switch-bank",
      "version": "0.3.0",
      "kind": "component",
      "title": "SwitchBank",
      "description": "Settings that come in a grid (notifications by event and channel, permissions by role and resource, a schedule by day) as a bank of Switches in a Table, one where each row meets each column. A Checkbox in each column header flips the whole column and shows a dash when it's mixed. A real table, so every Switch is read with its row and column.",
      "items": [
        "table",
        "switch",
        "checkbox"
      ]
    },
    {
      "name": "jog-wheel",
      "version": "0.3.0",
      "kind": "component",
      "title": "JogWheel",
      "description": "A knob with no ends: turn it and it moves a value by steps, as far as you like, like a video editor's jog wheel. Turn slowly for a step per click; spin it and the steps grow with the speed, so a long way is a quick flick. Knob's own cap, well and pointer, larger, with a ring engraved on the cap to see it turn. A spin button for assistive tech: arrows step, Shift or Page Up/Down take ten.",
      "items": [
        "knob"
      ]
    },
    {
      "name": "quick-tile",
      "version": "0.3.0",
      "kind": "component",
      "title": "QuickTile",
      "description": "A quick-settings tile, as in a phone's control centre: a big molded key with a glyph, a name and a line of state. Press it to switch the thing on or off; on, it's the lit cap and its socket glows. It presses like every Echo key. A switch for assistive tech, with the state line as its description; details open from a separate key, never from holding the tile down.",
      "items": [
        "status-dot",
        "hardware-button"
      ]
    },
    {
      "name": "fill-slider",
      "version": "0.3.0",
      "kind": "component",
      "title": "FillSlider",
      "description": "The tall slider of a control centre: a tube in the chassis that fills with lit plastic from the bottom, like Meter's, and follows your finger anywhere on it. For brightness, volume, a level you set by eye. Base UI's slider, vertical, with every slider key; the top of the fill is the handle, so there's no knob to aim for.",
      "items": []
    },
    {
      "name": "patch-bay",
      "version": "0.3.0",
      "kind": "component",
      "title": "PatchBay",
      "description": "Connecting things to things, the way a studio patches its gear: sockets down one side for what you have, sockets down the other for where it goes, and a cable between each connected pair. For mapping an import's columns to fields, routing events to channels, inputs to outputs. Each source has a Select that says where it goes, and that's the real control; the cables draw what the Selects say, and with a pointer you can drag one from socket to socket.",
      "items": [
        "select",
        "status-dot"
      ]
    },
    {
      "name": "meter",
      "version": "0.3.0",
      "kind": "component",
      "title": "Meter",
      "description": "A measurement within a known range (storage, battery, signal, a score), not a task's progress. A recessed tube with the primary plastic poured to the value; when the value changes the level travels there on a spring and settles with a small slosh. marks engrave levels on the tube without a second colour. Built on Base UI Meter: role=\"meter\" with the formatted value as aria-valuetext.",
      "items": []
    },
    {
      "name": "level-meter",
      "version": "0.3.0",
      "kind": "component",
      "title": "LevelMeter",
      "description": "A live level (a microphone, a mix bus) as LED cells with real ballistics: it rises at once, falls back slowly, and holds its peak for a moment. Feed it a level as often as you like; it draws on animation frames without re-rendering and stops once it has settled. For assistive tech a meter whose value is rounded to tenths and updated at most once a second.",
      "items": []
    },
    {
      "name": "combobox",
      "version": "0.3.0",
      "kind": "component",
      "title": "Combobox",
      "description": "A Select you can type into, for a list long enough to search: people, countries, labels. Field's well holds the text; the list drops in Select's plastic with the same flowing highlight. multiple keeps each choice as a tag that buds into the well; creatable offers to add what was typed. Built on Base UI Combobox, which owns filtering, the listbox and every announcement.",
      "items": [
        "size",
        "select",
        "tag"
      ]
    },
    {
      "name": "tags-input",
      "version": "0.3.0",
      "kind": "component",
      "title": "TagsInput",
      "description": "Free-form tags typed into Field's well: addresses, keywords, labels. Enter or a comma turns the text into a tag that buds into the well; Backspace in an empty input takes the last back; a paste with commas becomes several. For a fixed list to choose from, use Combobox with multiple.",
      "items": [
        "size",
        "tag",
        "combobox"
      ]
    },
    {
      "name": "fieldset",
      "version": "0.3.0",
      "kind": "component",
      "title": "Fieldset",
      "description": "A named group of fields (a shipping address, notification settings): a legend in the section voice, an optional description, and the fields under it. disabled turns off every control inside. Built on Base UI Fieldset.",
      "items": []
    },
    {
      "name": "checkbox-group",
      "version": "0.3.0",
      "kind": "component",
      "title": "CheckboxGroup",
      "description": "A named set of checkboxes sharing one value, the list of what's checked. Each option is a row, the checkbox and its words, the whole row a target. parent adds a checkbox that checks or clears them all and shows a dash when only some are on. Built on Base UI CheckboxGroup with Echo's Checkbox.",
      "items": [
        "checkbox"
      ]
    },
    {
      "name": "form",
      "version": "0.3.0",
      "kind": "component",
      "title": "Form",
      "description": "A form that fails well. Give it errors (field name → message) and pass the same message to each field's error. When a submit comes back with errors, a summary opens at the top: how many things need fixing, each a link that takes focus to its field, and the summary takes focus so it's heard first. A native form (noValidate: you validate in onSubmit), whose values arrive as an object.",
      "items": []
    },
    {
      "name": "hold-button",
      "version": "0.3.0",
      "kind": "component",
      "title": "HoldButton",
      "description": "Confirm by holding: the primary plastic fills the cap while you press, drains if you let go early, and the action happens when it's full. For the moments a second tap would be too easy. Space and Enter hold it too; a single press that can't hold (assistive tech) arms it instead, and a second press confirms. ConfirmButton is the two-press alternative.",
      "items": [
        "hardware-button",
        "size"
      ]
    },
    {
      "name": "choice-cards",
      "version": "0.3.0",
      "kind": "component",
      "title": "ChoiceCards",
      "description": "Choosing between things that need more than a word (a plan, a template, an account): each option is a card and the whole card is the choice. The chosen one lights a rail along its edge and its pip; nothing else changes colour. One choice is a radio group; multiple is a group of checkboxes. Built on Base UI RadioGroup and CheckboxGroup.",
      "items": [
        "panel"
      ]
    },
    {
      "name": "side-nav",
      "version": "0.3.0",
      "kind": "component",
      "title": "SideNav",
      "description": "The navigation down the side of an app: groups under machine-voice headings, items with an icon and a count, nested items that fold away (and open by themselves around the current page), and one lit rail that travels to where you are as a drop. collapsed folds it to its icons. Closed and data-driven; renderLink hands links to your router.",
      "items": []
    },
    {
      "name": "tab-bar",
      "version": "0.3.0",
      "kind": "component",
      "title": "TabBar",
      "description": "A phone app's bottom navigation as a dock: a molded slab floating clear of the screen's edges, a recessed track along it, and one raised cap seated under the destination you're on. Every destination has an LED socket; the current one's is lit, and its icon with it. Go somewhere else and the cap lifts, travels there on a spring and settles back in. A count on any with news, clear of the home indicator. Four or five destinations; more belong in SideNav.",
      "items": []
    },
    {
      "name": "notification-center",
      "version": "0.3.0",
      "kind": "component",
      "title": "NotificationCenter",
      "description": "An inbox of what happened: a bell key with the unread count, opening a panel of notifications as Items, newest first, each with an LED lit while unread. Opening one marks it read; \"Mark all read\" clears them. Where a toast goes after it's gone.",
      "items": [
        "hardware-button",
        "popover",
        "count-badge",
        "item"
      ]
    },
    {
      "name": "pull-to-refresh",
      "version": "0.3.0",
      "kind": "component",
      "title": "PullToRefresh",
      "description": "A scrolling list you pull down from the top to reload: the content follows your finger with a rubber band, a molded key turns as you pull and clicks at the detent, and the list holds there with the Loader's lights until onRefresh settles. A real Refresh button and one status make it work without the gesture.",
      "items": [
        "loader"
      ]
    },
    {
      "name": "console",
      "version": "0.3.0",
      "kind": "block",
      "title": "Console screen",
      "description": "A device dashboard as a front panel: AppShell, six StatTile readouts, an LED level matrix in a Panel, status lights, a takes Table and Pagination. Proves density and data at scale — whether the material language still holds when nothing on the screen has room.",
      "items": [
        "app-shell",
        "panel",
        "table",
        "stat-tile",
        "lcd-chip",
        "status-dot",
        "chart",
        "badge",
        "menu",
        "segmented",
        "engraved-plate",
        "pagination"
      ]
    },
    {
      "name": "chat",
      "version": "0.3.0",
      "kind": "block",
      "title": "Chat screen",
      "description": "One conversation as a front panel: an Avatar and StatusDot header, a message log, a Loader typing indicator, and a Textarea composer with one lit Send cap. Proves that the material language survives running text — incoming messages get no container, yours sit in the composer's recessed well, and the only raised object is Send.",
      "items": [
        "avatar",
        "textarea",
        "hardware-button",
        "loader",
        "status-dot",
        "kbd"
      ]
    },
    {
      "name": "morph",
      "version": "0.3.0",
      "kind": "component",
      "title": "Morph",
      "description": "Wrap your own HardwareButtons and render whatever state you like: when the buttons inside change, the old ones flow into the new ones as one liquid body. One becoming several divides at the waist, several becoming one folds, and the same number move and resize in place. At rest there is nothing but your buttons; the body is drawn only while the shape changes, in the cap's own material. Give a button data-morph=\"name\" and it is the same button in every state that has that name; filled caps (HardwareButton fill) are drawn as levels.",
      "items": [
        "hardware-button"
      ]
    },
    {
      "name": "done-button",
      "version": "0.3.0",
      "kind": "component",
      "title": "DoneButton",
      "description": "\"Mark as done\" divides into a lit \"Done\" and an \"Undo\". The state and its way back sit where the hand already is; Undo folds them back into the whole.",
      "items": [
        "hardware-button",
        "morph"
      ]
    },
    {
      "name": "confirm-button",
      "version": "0.3.0",
      "kind": "component",
      "title": "ConfirmButton",
      "description": "A destructive action that asks for its second press where the hand already is. \"Delete\" divides into \"Cancel\" and a lit \"Delete\"; Delete confirms, and the parts fold into a button saying what happened, which flows back to its first label a moment later. A lighter answer than a dialog for an action on one thing.",
      "items": [
        "hardware-button",
        "morph"
      ]
    },
    {
      "name": "action-fan",
      "version": "0.3.0",
      "kind": "component",
      "title": "ActionFan",
      "description": "One action opens into its choices, which bud from it one after another; the × folds them back. Choosing one does it and folds the fan. For two to four choices that belong to one verb — share, export, add.",
      "items": [
        "hardware-button",
        "morph"
      ]
    },
    {
      "name": "save-button",
      "version": "0.3.0",
      "kind": "component",
      "title": "SaveButton",
      "description": "The button becomes its own progress, then its own answer: Save narrows into a busy cap while your save runs, widens into a lit Saved, and flows back. One HardwareButton changing shape in a Morph — no dots swapped in, no width jump.",
      "items": [
        "hardware-button",
        "morph"
      ]
    },
    {
      "name": "timer",
      "version": "0.3.0",
      "kind": "component",
      "title": "Timer",
      "description": "A timer that is one button. It opens into its durations; the others run into the one you pick, which fills with the primary plastic and drains as the time runs, then rings three times and folds back. Press the running cap to pause; × or Escape folds it.",
      "items": [
        "hardware-button",
        "morph"
      ]
    },
    {
      "name": "stopwatch",
      "version": "0.3.0",
      "kind": "component",
      "title": "Stopwatch",
      "description": "Start becomes the running time (lit) and a Lap button beside it; each lap is a drop that leaves Lap and lands in the lap count. Pause dims the time and Lap flows into Reset, which folds everything back into Start.",
      "items": [
        "hardware-button",
        "morph",
        "count-badge",
        "bud-off"
      ]
    },
    {
      "name": "voice-note",
      "version": "0.3.0",
      "kind": "component",
      "title": "VoiceNote",
      "description": "Record a voice note in one button. The microphone opens into Stop and the take, whose bars follow your voice while Stop swells with it. Stop, and Stop is swallowed by the take, which becomes a note you can play: it fills with the primary plastic as it plays. × deletes it and everything folds back into the microphone.",
      "items": [
        "hardware-button",
        "morph"
      ]
    },
    {
      "name": "add-to-bag",
      "version": "0.3.0",
      "kind": "component",
      "title": "AddToBag",
      "description": "Press it and a drop buds out of the button and lands in the count beside it, which swells and goes up — the eye follows the thing you added to where it went. A HardwareButton and a CountBadge, joined by useBudOff.",
      "items": [
        "hardware-button",
        "count-badge",
        "bud-off"
      ]
    },
    {
      "name": "bud-off",
      "version": "0.3.0",
      "kind": "component",
      "title": "useBudOff",
      "description": "A drop of the primary plastic buds out of one element, flies to another and is swallowed by it, which swells as it lands — so the eye follows cause to effect. Its front leads and its tail lags, so it draws out on its own. Returns a function, budOff(from, to, options): from is the element the drop buds out of, to the one it lands in, and the options are below. budOff returns a function that calls the drop off before it lands: it's gone and onArrive never runs, for when what it was flying to is reset first.",
      "items": []
    },
    {
      "name": "pull-cord",
      "version": "0.3.0",
      "kind": "component",
      "title": "PullCord",
      "description": "A switch you pull. A real Echo Switch sits at the top and a cord hangs from it with a cap on its end; pull the cap and the cord stretches, clicks at the detent, and the switch changes when you let go past it. A short pull springs back. The Switch is the control — its state, name, focus, keyboard and form value — and the cord is a way to operate it by hand. Anything inside can read --echo-pull-on to light up.",
      "items": [
        "switch"
      ]
    },
    {
      "name": "roll",
      "version": "0.3.0",
      "kind": "component",
      "title": "useRoll",
      "description": "A readout that rolls to a new value instead of swapping it: each digit steps through the ones in between, all together, fast when it's far and slowest on the last step. It's the drum SplitFlap turns on, and what roll does on LcdChip, StatTile and NumberField. useRoll(text, options) returns the text to draw, which is in between values while it rolls, so draw it aria-hidden and give the real value to assistive technology.",
      "items": []
    },
    {
      "name": "split-flap",
      "version": "0.3.0",
      "kind": "component",
      "title": "SplitFlap",
      "description": "A readout that turns over like a departures board: each character flips through the ones between where it is and where it's going, flap by flap — fast when it's far, slowest on the last one — and each flap ticks. The flaps are the neutral cap's plastic in a recessed well.",
      "items": [
        "roll"
      ]
    },
    {
      "name": "light-source",
      "version": "0.3.0",
      "kind": "component",
      "title": "LightSource",
      "description": "Your pointer becomes the light the caps inside it are lit by: each HardwareButton's shine turns toward it and its shadow falls away from it, the nearest most. When the pointer leaves, the light drifts back to the room's key light. It lights what you put in it and adds nothing of its own.",
      "items": [
        "hardware-button"
      ]
    },
    {
      "name": "magnetic",
      "version": "0.3.0",
      "kind": "component",
      "title": "Magnetic",
      "description": "The HardwareButtons inside it feel your hand before you touch them: each leans toward the pointer and comes up a little, the nearest most, and springs home when you move away. It moves the button as a whole, never the cap, so pressing still presses.",
      "items": [
        "hardware-button"
      ]
    },
    {
      "name": "throw-stack",
      "version": "0.3.0",
      "kind": "component",
      "title": "ThrowStack",
      "description": "A stack of cards you can throw: drag the top one and flick it, and it keeps the speed you gave it, spins from where you held it (grabbed low, it swings the other way), flies off and tucks back in underneath. A short drag springs back. The cards are Echo Panels.",
      "items": [
        "panel"
      ]
    },
    {
      "name": "ripple",
      "version": "0.3.0",
      "kind": "component",
      "title": "Ripple",
      "description": "A surface of dots that answers a press like water: a wave runs out from where you pressed, and pressing longer presses deeper and sends a bigger one. The dots dip under the pointer as it passes. Put controls on it; a key press on one of them sends a wave from it too. It's Panel's pressable wave with the dots always out; to make an ordinary Panel give like this, use <Panel pressable>.",
      "items": [
        "panel"
      ]
    }
  ]
}
