anentrypoint-design 0.0.477 → 0.0.478

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.html CHANGED
@@ -7,7 +7,7 @@
7
7
 
8
8
  <meta name="description" content="the visual paradigm. layered surfaces, monospace labels, loud content inside quiet chrome. consumed by every 247420 surface.">
9
9
  <meta name="keywords" content="design-system, tokens, 247420, anentrypoint">
10
- <meta name="author" content="247420 / AnEntrypoint">
10
+ <meta name="author" content="247420 · a design system by AnEntrypoint">
11
11
  <meta name="robots" content="index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1">
12
12
  <meta name="generator" content="anentrypoint-design">
13
13
  <link rel="canonical" href="https://anentrypoint.github.io/design">
@@ -116,14 +116,21 @@ a.row:hover .ds-row-arrow { opacity: 1 }
116
116
  .ds-page-footer-links a { color: var(--fg-3) }
117
117
  .ds-page-footer-links a:hover { color: var(--fg) }
118
118
  </style>
119
- <script id="__site__" type="application/json">{"title":"design","slug":"index","siteName":"design","navItems":[["247420","https://247420.xyz"],["AnEntrypoint ->","https://github.com/AnEntrypoint"]],"theme":"auto","hero":{"heading":"design","subheading":"the 247420 design system","body":"14 kit surfaces, zero raw color literals, one importmap script tag to install. every panel, row, and form control in this system reads its color, radius, and spacing from a single token file — swap the tokens and every surface built on them changes with it.","badges":[{"label":"design-system"},{"label":"tokens"},{"label":"web"}],"ctas":[{"label":"GitHub","href":"https://github.com/AnEntrypoint/design","primary":true},{"label":"247420","href":"https://247420.xyz"}]},"sections":[],"examples":[{"label":"index shell","desc":"full navigation shell with tabs, filters, and row interactions.","href":"./index.html"},{"label":"homepage kit","desc":"hero + works layout and updated readable type scale.","href":"./ui_kits/homepage/"},{"label":"project page kit","desc":"overview, install, receipt, and changelog template.","href":"./ui_kits/project_page/"},{"label":"docs kit","desc":"technical documentation layout with sidebar and prose.","href":"./ui_kits/docs/"},{"label":"blog kit","desc":"long-form writing layout tuned for readability.","href":"./ui_kits/blog/"},{"label":"chat kit","desc":"message thread + composer with pill bubbles and room sidebar.","href":"./ui_kits/chat/"},{"label":"aicat kit","desc":"ai assistant with cat persona — ascii portrait + mood face.","href":"./ui_kits/aicat/"},{"label":"slide deck","desc":"16:9 deck stage with improved presenter controls text.","href":"./slides/"},{"label":"dashboard kit","desc":"kpis, tables, receipts, changelog — operations surface.","href":"./ui_kits/dashboard/"},{"label":"terminal kit","desc":"cli prompt, command lines, log viewer.","href":"./ui_kits/terminal/"},{"label":"settings kit","desc":"sectioned forms, toggles, segmented buttons, save bar.","href":"./ui_kits/settings/"},{"label":"signin kit","desc":"auth panel, providers, magic link.","href":"./ui_kits/signin/"},{"label":"search kit","desc":"query bar, faceted filters, ranked results.","href":"./ui_kits/search/"},{"label":"404 kit","desc":"empty-state hero with suggested routes.","href":"./ui_kits/error_404/"},{"label":"gallery kit","desc":"visual grid + lightbox over tonal cards.","href":"./ui_kits/gallery/"},{"label":"preview samples","desc":"design previews and component samples.","href":"./preview/buttons.html"}],"bodyHtml":"","sidebar":{"sections":[{"group":"open","items":[{"glyph":"+","label":"open","href":"./ui_kits/homepage/"}]},{"group":"bins","items":[{"label":"everything","href":"#all","active":true,"count":43},{"label":"pinned","href":"#kits","count":14},{"label":"shipped","href":"#previews","count":25},{"label":"drafts","href":"#decks","count":1}]},{"group":"labels","items":[{"label":"ui kits","href":"#kits","count":14},{"label":"decks","href":"#decks","count":1},{"label":"previews","href":"#previews","count":25},{"label":"docs","href":"#docs","count":3}]},{"group":"more","items":[{"label":"readme","href":"https://github.com/AnEntrypoint/design/blob/main/README.md"},{"label":"skill","href":"https://github.com/AnEntrypoint/design/blob/main/SKILL.md"},{"label":"tokens","href":"https://github.com/AnEntrypoint/design/blob/main/colors_and_type.css"},{"label":"source","href":"https://github.com/AnEntrypoint/design"}]}]},"marquee":{"items":["open source","design tokens","buildless components","zero raw color literals"],"sep":"/"},"panels":[{"id":"kits","title":"ui kits","count":"14 surfaces","items":[{"code":"","title":"homepage","sub":"marquee + works grid","meta":"open ->","href":"./ui_kits/homepage/"},{"code":"","title":"project page","sub":"hero receipt install changelog","meta":"open ->","href":"./ui_kits/project_page/"},{"code":"","title":"docs","sub":"long-form prose chrome","meta":"open ->","href":"./ui_kits/docs/"},{"code":"","title":"blog","sub":"dated index + reading view","meta":"open ->","href":"./ui_kits/blog/"},{"code":"","title":"chat","sub":"message thread + composer","meta":"open ->","href":"./ui_kits/chat/"},{"code":"","title":"aicat","sub":"ai assistant with cat persona","meta":"open ->","href":"./ui_kits/aicat/"},{"code":"","title":"file browser","sub":"rails by file type drop preview","meta":"open ->","href":"./ui_kits/file_browser/"},{"code":"","title":"dashboard","sub":"kpis tables receipts changelog","meta":"open ->","href":"./ui_kits/dashboard/"},{"code":"","title":"terminal","sub":"cli prompt command lines log view","meta":"open ->","href":"./ui_kits/terminal/"},{"code":"","title":"settings","sub":"sectioned forms toggles save bar","meta":"open ->","href":"./ui_kits/settings/"},{"code":"","title":"signin","sub":"auth providers magic link","meta":"open ->","href":"./ui_kits/signin/"},{"code":"","title":"search","sub":"topbar query faceted filters rows","meta":"open ->","href":"./ui_kits/search/"},{"code":"","title":"404","sub":"empty-state hero suggested routes","meta":"open ->","href":"./ui_kits/error_404/"},{"code":"","title":"gallery","sub":"visual grid tonal cards lightbox","meta":"open ->","href":"./ui_kits/gallery/"}]},{"id":"file_browser","title":"file browser","count":"primitives","items":[{"code":"fb","title":"file_browser kit","sub":"drop, list, preview, dialogs","meta":"open kit","href":"./ui_kits/file_browser/"},{"code":"fb","title":"FileRow","sub":"rail icon name meta","meta":"preview","href":"./preview/file-row.html"},{"code":"fb","title":"FileGrid","sub":"stack of rows in a panel","meta":"preview","href":"./preview/file-grid.html"},{"code":"fb","title":"DropZone","sub":"tonal upload target","meta":"preview","href":"./preview/dropzone.html"},{"code":"fb","title":"FileViewer","sub":"modal preview keyed head","meta":"preview","href":"./preview/file-viewer.html"},{"code":"fb","title":"FileToolbar","sub":"actions breadcrumb upload","meta":"preview","href":"./preview/file-toolbar.html"},{"code":"fb","title":"fsbrowse","sub":"Express + busboy backend","meta":"source","href":"https://github.com/AnEntrypoint/fsbrowse"}]},{"id":"desktop_os","title":"desktop os shell","count":"in-page wm","items":[{"code":"os","title":"createDesktopShell","sub":"menubar apps launcher taskbar window manager","meta":"shell.js","href":"https://github.com/AnEntrypoint/design/blob/main/src/desktop/shell.js"},{"code":"os","title":"icons set","sub":"svg glyphs for menubar + taskbar","meta":"icons.js","href":"https://github.com/AnEntrypoint/design/blob/main/src/desktop/icons.js"},{"code":"os","title":"theme.css","sub":"os chrome tokens menubar launcher wm","meta":"theme.css","href":"https://github.com/AnEntrypoint/design/blob/main/src/desktop/theme.css"},{"code":"os","title":"import path","sub":"anentrypoint-design/desktop","meta":"exports","href":"https://github.com/AnEntrypoint/design/blob/main/package.json"}]},{"id":"web_components","title":"web components","count":"1 element","items":[{"code":"wc","title":"\u003cds-chat>","sub":"auto-registers when the sdk loads in a browser","meta":"ds-chat.js","href":"https://github.com/AnEntrypoint/design/blob/main/src/web-components/ds-chat.js"},{"code":"wc","title":"registerChatElement","sub":"manual register helper","meta":"source","href":"https://github.com/AnEntrypoint/design/blob/main/src/index.js"}]},{"id":"api_exports","title":"public api","count":"sdk surface","items":[{"code":"api","title":"h / applyDiff","sub":"webjsx createElement + diff","meta":"index.js","href":"https://github.com/AnEntrypoint/design/blob/main/src/index.js"},{"code":"api","title":"installStyles / scope","sub":"ds-247420 css scope + bootstrap","meta":"styles.js","href":"https://github.com/AnEntrypoint/design/blob/main/src/styles.js"},{"code":"api","title":"loadCss","sub":"fetch the bundled css string","meta":"styles.js","href":"https://github.com/AnEntrypoint/design/blob/main/src/styles.js"},{"code":"api","title":"mount / mountKit","sub":"ds shell + ui_kit bootstrap","meta":"bootstrap.js","href":"https://github.com/AnEntrypoint/design/blob/main/src/bootstrap.js"},{"code":"api","title":"registerDeckStage / getDeckStage","sub":"16:9 deck stage api","meta":"deck-stage.js","href":"https://github.com/AnEntrypoint/design/blob/main/src/deck-stage.js"},{"code":"api","title":"renderMarkdown","sub":"marked v15 + dompurify lazy stack","meta":"markdown.js","href":"https://github.com/AnEntrypoint/design/blob/main/src/markdown.js"},{"code":"api","title":"ensurePrism / highlightAllUnder","sub":"prism core + per-language","meta":"highlight.js","href":"https://github.com/AnEntrypoint/design/blob/main/src/highlight.js"},{"code":"api","title":"renderPageHtml","sub":"static page html template","meta":"page-html.js","href":"https://github.com/AnEntrypoint/design/blob/main/src/page-html.js"},{"code":"api","title":"components / motion / debug","sub":"namespaces from the default export","meta":"components.js","href":"https://github.com/AnEntrypoint/design/blob/main/src/components.js"}]},{"id":"decks","title":"decks","count":1,"items":[{"code":"","title":"deck template","sub":"16:9 stage with auto-fit","meta":"open ->","href":"./slides/"}]},{"id":"docs","title":"docs","count":3,"items":[{"code":"md","title":"readme","sub":"overview, manifesto, conventions","meta":"open ->","href":"https://github.com/AnEntrypoint/design/blob/main/README.md"},{"code":"md","title":"skill","sub":"authoring rules for the agent","meta":"open ->","href":"https://github.com/AnEntrypoint/design/blob/main/SKILL.md"},{"code":"css","title":"tokens","sub":"colors, type, panel surface tokens","meta":"open ->","href":"https://github.com/AnEntrypoint/design/blob/main/colors_and_type.css"}]},{"id":"features","title":"why design","count":4,"items":[{"code":"","title":"layered surfaces","sub":"panel-on-panel rhythm; loud content sits inside quiet chrome.","meta":"panel-row.css","href":"https://github.com/AnEntrypoint/design/blob/main/src/css/app-shell/panel-row.css"},{"code":"","title":"monospace labels","sub":"mono only for codes/labels/CLI; sans for everything legible.","meta":"colors_and_type.css","href":"https://github.com/AnEntrypoint/design/blob/main/colors_and_type.css"},{"code":"","title":"indicator rails","sub":"color-coded inset rails for category separation, never borders.","meta":"panel-row.css","href":"https://github.com/AnEntrypoint/design/blob/main/src/css/app-shell/panel-row.css#L126"},{"code":"","title":"tokens-only","sub":"every surface, type ramp, accent driven by --panel-* / --fs-* tokens.","meta":"colors_and_type.css","href":"https://github.com/AnEntrypoint/design/blob/main/colors_and_type.css"}]},{"id":"previews","title":"previews","count":25,"items":[{"code":"","title":"buttons","sub":"preview · buttons.html","meta":"open ->","href":"./preview/buttons.html"},{"code":"","title":"colors core","sub":"preview · colors-core.html","meta":"open ->","href":"./preview/colors-core.html"},{"code":"","title":"colors lore","sub":"preview · colors-lore.html","meta":"open ->","href":"./preview/colors-lore.html"},{"code":"","title":"colors semantic","sub":"preview · colors-semantic.html","meta":"open ->","href":"./preview/colors-semantic.html"},{"code":"","title":"dateline","sub":"preview · dateline.html","meta":"open ->","href":"./preview/dateline.html"},{"code":"","title":"dropzone","sub":"preview · dropzone.html","meta":"open ->","href":"./preview/dropzone.html"},{"code":"","title":"file grid","sub":"preview · file-grid.html","meta":"open ->","href":"./preview/file-grid.html"},{"code":"","title":"file row","sub":"preview · file-row.html","meta":"open ->","href":"./preview/file-row.html"},{"code":"","title":"file toolbar","sub":"preview · file-toolbar.html","meta":"open ->","href":"./preview/file-toolbar.html"},{"code":"","title":"file viewer","sub":"preview · file-viewer.html","meta":"open ->","href":"./preview/file-viewer.html"},{"code":"","title":"header","sub":"preview · header.html","meta":"open ->","href":"./preview/header.html"},{"code":"","title":"icons unicode","sub":"preview · icons-unicode.html","meta":"open ->","href":"./preview/icons-unicode.html"},{"code":"","title":"index row","sub":"preview · index-row.html","meta":"open ->","href":"./preview/index-row.html"},{"code":"","title":"inputs","sub":"preview · inputs.html","meta":"open ->","href":"./preview/inputs.html"},{"code":"","title":"manifesto","sub":"preview · manifesto.html","meta":"open ->","href":"./preview/manifesto.html"},{"code":"","title":"rules","sub":"preview · rules.html","meta":"open ->","href":"./preview/rules.html"},{"code":"","title":"spacing","sub":"preview · spacing.html","meta":"open ->","href":"./preview/spacing.html"},{"code":"","title":"stamps","sub":"preview · stamps.html","meta":"open ->","href":"./preview/stamps.html"},{"code":"","title":"stamps lore","sub":"preview · stamps-lore.html","meta":"open ->","href":"./preview/stamps-lore.html"},{"code":"","title":"theme ink","sub":"preview · theme-ink.html","meta":"open ->","href":"./preview/theme-ink.html"},{"code":"","title":"type display","sub":"preview · type-display.html","meta":"open ->","href":"./preview/type-display.html"},{"code":"","title":"type mono","sub":"preview · type-mono.html","meta":"open ->","href":"./preview/type-mono.html"},{"code":"","title":"type prose","sub":"preview · type-prose.html","meta":"open ->","href":"./preview/type-prose.html"},{"code":"","title":"type scale","sub":"preview · type-scale.html","meta":"open ->","href":"./preview/type-scale.html"},{"code":"","title":"wordmarks","sub":"preview · wordmarks.html","meta":"open ->","href":"./preview/wordmarks.html"}]}],"quickstart":{"heading":"quick start","lines":[{"kind":"cmt","text":"# install via importmap (no bundler)"},{"kind":"cmd","text":"\u003cscript type='importmap'>{\"imports\":{\"anentrypoint-design\":\"https://unpkg.com/anentrypoint-design@latest/dist/247420.js\"}}\u003c/script>"},{"kind":"cmt","text":"# or clone the source"},{"kind":"cmd","text":"git clone https://github.com/AnEntrypoint/design.git"}]},"statusLeft":["main","utf-8","lf"],"statusRight":["anentrypoint-design@latest","14 kits"]}</script>
119
+ <script id="__site__" type="application/json">{"title":"design","slug":"index","siteName":"design","navItems":[["247420","https://247420.xyz"],["AnEntrypoint ->","https://github.com/AnEntrypoint"]],"theme":"auto","hero":{"heading":"design","subheading":"the 247420 design system","body":"14 kit surfaces, 25 previews, one deck, and a full desktop-OS shell — plus a web component and an SDK, all tokens-only, zero raw color literals, one importmap script tag to install. every panel, row, and form control in this system reads its color, radius, and spacing from a single token file — swap the tokens and every surface built on them changes with it.","badges":[{"label":"design-system"},{"label":"tokens"},{"label":"web"}],"ctas":[{"label":"GitHub","href":"https://github.com/AnEntrypoint/design","primary":true},{"label":"247420","href":"https://247420.xyz"}]},"sections":[],"examples":[],"bodyHtml":"","sidebar":{"sections":[{"group":"open","items":[{"glyph":"+","label":"open","href":"./ui_kits/homepage/"}]},{"group":"bins","items":[{"label":"everything","href":"#all","active":true,"count":45},{"label":"pinned","href":"#kits","count":14},{"label":"shipped","href":"#previews","count":25},{"label":"drafts","href":"#decks","count":1}]},{"group":"labels","items":[{"label":"ui kits","href":"#kits","count":14},{"label":"decks","href":"#decks","count":1},{"label":"previews","href":"#previews","count":25},{"label":"docs","href":"#docs","count":5}]},{"group":"more","items":[{"label":"readme","href":"https://github.com/AnEntrypoint/design/blob/main/README.md"},{"label":"skill","href":"https://github.com/AnEntrypoint/design/blob/main/SKILL.md"},{"label":"tokens","href":"https://github.com/AnEntrypoint/design/blob/main/colors_and_type.css"},{"label":"source","href":"https://github.com/AnEntrypoint/design"},{"label":"MIT license","href":"https://github.com/AnEntrypoint/design/blob/main/LICENSE"}]}]},"marquee":{"items":["open source","design tokens","buildless components","zero raw color literals"],"sep":"/"},"panels":[{"id":"kits","title":"ui kits","count":"14 surfaces","items":[{"code":"","title":"homepage","sub":"marquee + works grid","meta":"open ->","href":"./ui_kits/homepage/"},{"code":"","title":"project page","sub":"hero receipt install changelog","meta":"open ->","href":"./ui_kits/project_page/"},{"code":"","title":"docs","sub":"long-form prose chrome","meta":"open ->","href":"./ui_kits/docs/"},{"code":"","title":"blog","sub":"dated index + reading view","meta":"open ->","href":"./ui_kits/blog/"},{"code":"","title":"chat","sub":"message thread + composer","meta":"open ->","href":"./ui_kits/chat/"},{"code":"","title":"aicat","sub":"ai assistant with cat persona","meta":"open ->","href":"./ui_kits/aicat/"},{"code":"","title":"file browser","sub":"rails by file type drop preview","meta":"open ->","href":"./ui_kits/file_browser/"},{"code":"","title":"dashboard","sub":"kpis tables receipts changelog","meta":"open ->","href":"./ui_kits/dashboard/"},{"code":"","title":"terminal","sub":"cli prompt command lines log view","meta":"open ->","href":"./ui_kits/terminal/"},{"code":"","title":"settings","sub":"sectioned forms toggles save bar","meta":"open ->","href":"./ui_kits/settings/"},{"code":"","title":"signin","sub":"auth providers magic link","meta":"open ->","href":"./ui_kits/signin/"},{"code":"","title":"search","sub":"topbar query faceted filters rows","meta":"open ->","href":"./ui_kits/search/"},{"code":"","title":"404","sub":"empty-state hero suggested routes","meta":"open ->","href":"./ui_kits/error_404/"},{"code":"","title":"gallery","sub":"visual grid tonal cards lightbox","meta":"open ->","href":"./ui_kits/gallery/"}]},{"id":"file_browser","title":"file browser","count":"primitives","items":[{"code":"fb","title":"file_browser kit","sub":"drop, list, preview, dialogs","meta":"open ->","href":"./ui_kits/file_browser/"},{"code":"fb","title":"FileRow","sub":"rail icon name meta","meta":"open ->","href":"./preview/file-row.html"},{"code":"fb","title":"FileGrid","sub":"stack of rows in a panel","meta":"open ->","href":"./preview/file-grid.html"},{"code":"fb","title":"DropZone","sub":"tonal upload target","meta":"open ->","href":"./preview/dropzone.html"},{"code":"fb","title":"FileViewer","sub":"modal preview keyed head","meta":"open ->","href":"./preview/file-viewer.html"},{"code":"fb","title":"FileToolbar","sub":"actions breadcrumb upload","meta":"open ->","href":"./preview/file-toolbar.html"},{"code":"fb","title":"fsbrowse","sub":"Express + busboy backend","meta":"source","href":"https://github.com/AnEntrypoint/fsbrowse"}]},{"id":"desktop_os","title":"desktop os shell","count":"in-page wm","items":[{"code":"os","title":"createDesktopShell","sub":"menubar apps launcher taskbar window manager","meta":"shell.js","href":"https://github.com/AnEntrypoint/design/blob/main/src/desktop/shell.js"},{"code":"os","title":"icons set","sub":"svg glyphs for menubar + taskbar","meta":"icons.js","href":"https://github.com/AnEntrypoint/design/blob/main/src/desktop/icons.js"},{"code":"os","title":"theme.css","sub":"os chrome tokens menubar launcher wm","meta":"theme.css","href":"https://github.com/AnEntrypoint/design/blob/main/src/desktop/theme.css"},{"code":"os","title":"import path","sub":"anentrypoint-design/desktop","meta":"exports","href":"https://github.com/AnEntrypoint/design/blob/main/package.json"}]},{"id":"web_components","title":"web components","count":"1 element","items":[{"code":"wc","title":"\u003cds-chat>","sub":"auto-registers when the sdk loads in a browser","meta":"ds-chat.js","href":"https://github.com/AnEntrypoint/design/blob/main/src/web-components/ds-chat.js"},{"code":"wc","title":"registerChatElement","sub":"manual register helper","meta":"source","href":"https://github.com/AnEntrypoint/design/blob/main/src/index.js"}]},{"id":"api_exports","title":"public api","count":"sdk surface","items":[{"code":"api","title":"h / applyDiff","sub":"webjsx createElement + diff","meta":"index.js","href":"https://github.com/AnEntrypoint/design/blob/main/src/index.js"},{"code":"api","title":"installStyles / scope","sub":"ds-247420 css scope + bootstrap","meta":"styles.js","href":"https://github.com/AnEntrypoint/design/blob/main/src/styles.js"},{"code":"api","title":"loadCss","sub":"fetch the bundled css string","meta":"styles.js","href":"https://github.com/AnEntrypoint/design/blob/main/src/styles.js"},{"code":"api","title":"mount / mountKit","sub":"ds shell + ui_kit bootstrap","meta":"bootstrap.js","href":"https://github.com/AnEntrypoint/design/blob/main/src/bootstrap.js"},{"code":"api","title":"registerDeckStage / getDeckStage","sub":"16:9 deck stage api","meta":"deck-stage.js","href":"https://github.com/AnEntrypoint/design/blob/main/src/deck-stage.js"},{"code":"api","title":"renderMarkdown","sub":"marked v15 + dompurify lazy stack","meta":"markdown.js","href":"https://github.com/AnEntrypoint/design/blob/main/src/markdown.js"},{"code":"api","title":"ensurePrism / highlightAllUnder","sub":"prism core + per-language","meta":"highlight.js","href":"https://github.com/AnEntrypoint/design/blob/main/src/highlight.js"},{"code":"api","title":"renderPageHtml","sub":"static page html template","meta":"page-html.js","href":"https://github.com/AnEntrypoint/design/blob/main/src/page-html.js"},{"code":"api","title":"components / motion / debug","sub":"namespaces from the default export","meta":"components.js","href":"https://github.com/AnEntrypoint/design/blob/main/src/components.js"}]},{"id":"decks","title":"decks","count":1,"items":[{"code":"","title":"deck template","sub":"16:9 stage with auto-fit","meta":"open ->","href":"./slides/"}]},{"id":"docs","title":"docs","count":5,"items":[{"code":"md","title":"readme","sub":"overview, manifesto, conventions","meta":"open ->","href":"https://github.com/AnEntrypoint/design/blob/main/README.md"},{"code":"md","title":"skill","sub":"authoring rules for the agent","meta":"open ->","href":"https://github.com/AnEntrypoint/design/blob/main/SKILL.md"},{"code":"css","title":"tokens","sub":"colors, type, panel surface tokens","meta":"open ->","href":"https://github.com/AnEntrypoint/design/blob/main/colors_and_type.css"},{"code":"md","title":"component props","sub":"generated prop reference","meta":"open ->","href":"https://github.com/AnEntrypoint/design/blob/main/docs/component-props.md"},{"code":"md","title":"changelog","sub":"release history","meta":"open ->","href":"https://github.com/AnEntrypoint/design/blob/main/CHANGELOG.md"}]},{"id":"features","title":"why design","count":4,"items":[{"code":"","title":"layered surfaces","sub":"panel-on-panel rhythm; loud content sits inside quiet chrome.","meta":"panel-row.css","href":"https://github.com/AnEntrypoint/design/blob/main/src/css/app-shell/panel-row.css"},{"code":"","title":"monospace labels","sub":"mono only for codes/labels/CLI; sans for everything legible.","meta":"colors_and_type.css","href":"https://github.com/AnEntrypoint/design/blob/main/colors_and_type.css"},{"code":"","title":"indicator rails","sub":"color-coded inset rails for category separation, never borders.","meta":"panel-row.css","href":"https://github.com/AnEntrypoint/design/blob/main/src/css/app-shell/panel-row.css#L126"},{"code":"","title":"tokens-only","sub":"every surface, type ramp, accent driven by --panel-* / --fs-* tokens.","meta":"colors_and_type.css","href":"https://github.com/AnEntrypoint/design/blob/main/colors_and_type.css"}]},{"id":"previews","title":"previews","count":25,"items":[{"code":"","title":"buttons","sub":"preview · buttons.html","meta":"open ->","href":"./preview/buttons.html"},{"code":"","title":"colors core","sub":"preview · colors-core.html","meta":"open ->","href":"./preview/colors-core.html"},{"code":"","title":"colors lore","sub":"preview · colors-lore.html","meta":"open ->","href":"./preview/colors-lore.html"},{"code":"","title":"colors semantic","sub":"preview · colors-semantic.html","meta":"open ->","href":"./preview/colors-semantic.html"},{"code":"","title":"dateline","sub":"preview · dateline.html","meta":"open ->","href":"./preview/dateline.html"},{"code":"","title":"dropzone","sub":"preview · dropzone.html","meta":"open ->","href":"./preview/dropzone.html"},{"code":"","title":"file grid","sub":"preview · file-grid.html","meta":"open ->","href":"./preview/file-grid.html"},{"code":"","title":"file row","sub":"preview · file-row.html","meta":"open ->","href":"./preview/file-row.html"},{"code":"","title":"file toolbar","sub":"preview · file-toolbar.html","meta":"open ->","href":"./preview/file-toolbar.html"},{"code":"","title":"file viewer","sub":"preview · file-viewer.html","meta":"open ->","href":"./preview/file-viewer.html"},{"code":"","title":"header","sub":"preview · header.html","meta":"open ->","href":"./preview/header.html"},{"code":"","title":"icons unicode","sub":"preview · icons-unicode.html","meta":"open ->","href":"./preview/icons-unicode.html"},{"code":"","title":"index row","sub":"preview · index-row.html","meta":"open ->","href":"./preview/index-row.html"},{"code":"","title":"inputs","sub":"preview · inputs.html","meta":"open ->","href":"./preview/inputs.html"},{"code":"","title":"manifesto","sub":"preview · manifesto.html","meta":"open ->","href":"./preview/manifesto.html"},{"code":"","title":"rules","sub":"preview · rules.html","meta":"open ->","href":"./preview/rules.html"},{"code":"","title":"spacing","sub":"preview · spacing.html","meta":"open ->","href":"./preview/spacing.html"},{"code":"","title":"stamps","sub":"preview · stamps.html","meta":"open ->","href":"./preview/stamps.html"},{"code":"","title":"stamps lore","sub":"preview · stamps-lore.html","meta":"open ->","href":"./preview/stamps-lore.html"},{"code":"","title":"theme ink","sub":"preview · theme-ink.html","meta":"open ->","href":"./preview/theme-ink.html"},{"code":"","title":"type display","sub":"preview · type-display.html","meta":"open ->","href":"./preview/type-display.html"},{"code":"","title":"type mono","sub":"preview · type-mono.html","meta":"open ->","href":"./preview/type-mono.html"},{"code":"","title":"type prose","sub":"preview · type-prose.html","meta":"open ->","href":"./preview/type-prose.html"},{"code":"","title":"type scale","sub":"preview · type-scale.html","meta":"open ->","href":"./preview/type-scale.html"},{"code":"","title":"wordmarks","sub":"preview · wordmarks.html","meta":"open ->","href":"./preview/wordmarks.html"}]}],"quickstart":{"heading":"quick start","lines":[{"kind":"cmt","text":"# install via importmap (no bundler)"},{"kind":"cmd","text":"\u003cscript type='importmap'>{\"imports\":{\"anentrypoint-design\":\"https://unpkg.com/anentrypoint-design@latest/dist/247420.js\"}}\u003c/script>"},{"kind":"cmt","text":"# or clone the source"},{"kind":"cmd","text":"git clone https://github.com/AnEntrypoint/design.git"}]},"statusLeft":["main","utf-8","lf"],"statusRight":["anentrypoint-design@latest","14 kits"],"seoAuthor":"247420 · a design system by AnEntrypoint"}</script>
120
120
  <style>html,body{margin:0;padding:0}body{background:var(--bg,#F6F5F1);color:var(--fg,#131318);font-family:var(--ff-body,system-ui,sans-serif)}</style>
121
121
  </head>
122
122
  <body>
123
123
  <div id="app"></div>
124
124
  <script type="module">
125
125
  import { mount, components as C, h } from 'anentrypoint-design';
126
- const data = JSON.parse(document.getElementById('__site__').textContent);
126
+ let data;
127
+ try {
128
+ data = JSON.parse(document.getElementById('__site__').textContent);
129
+ } catch (e) {
130
+ console.error('[page-html] failed to parse #__site__ bootstrap data:', e);
131
+ document.getElementById('app').textContent = 'This page failed to load correctly. Please refresh, or contact support if the problem persists.';
132
+ throw e;
133
+ }
127
134
 
128
135
  function heroNode(hero) {
129
136
  if (!hero) return null;
@@ -150,11 +157,13 @@ function heroNode(hero) {
150
157
  );
151
158
  }
152
159
 
160
+ function __esc(s) { return String(s).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;'); }
161
+
153
162
  function sectionNode(sec, idx) {
154
163
  const features = sec.features || sec.items || [];
155
164
  const rows = features.map((f, i) => {
156
165
  const kids = [h('div', { key: 't', class: 'ds-feature-title' }, String(f.name || ''))];
157
- if (f.desc) kids.push(h('div', { key: 'd', class: 'ds-feature-desc', innerHTML: String(f.desc).replace(/`([^`]+)`/g, '<code>$1</code>') }));
166
+ if (f.desc) kids.push(h('div', { key: 'd', class: 'ds-feature-desc', innerHTML: __esc(String(f.desc)).replace(/`([^`]+)`/g, '<code>$1</code>') }));
158
167
  if (f.benefit) kids.push(h('div', { key: 'b', class: 'ds-feature-benefit' }, String(f.benefit)));
159
168
  return h('div', { key: i, class: 'ds-feature' }, ...kids);
160
169
  });
@@ -185,9 +194,64 @@ function examplesNode(examples) {
185
194
  });
186
195
  }
187
196
 
188
- function panelNode(panel, idx) {
189
- const items = Array.isArray(panel.items) ? panel.items : [];
190
- if (!items.length) return null;
197
+ // Category glyph per homepage panel id — the same line-icon vocabulary
198
+ // icons.js already provides, so kits/previews/decks/docs read as distinct
199
+ // categories at a glance instead of by text label alone. Falls back to no
200
+ // icon for panel ids outside this table (e.g. one-off feature panels).
201
+ const PANEL_ICON = {
202
+ kits: 'grid',
203
+ file_browser: 'folder',
204
+ desktop_os: 'square',
205
+ web_components: 'page',
206
+ api_exports: 'link',
207
+ decks: 'screen',
208
+ docs: 'file-text',
209
+ previews: 'eye',
210
+ features: 'info',
211
+ };
212
+
213
+ // Filter state for the kits search box above the "ui kits" panel. Reuses
214
+ // ui_kits/search's own query-bar pattern (plain module-level state object,
215
+ // mutated on input, driving a re-render) rather than inventing a second
216
+ // filtering mechanism -- this homepage already ships that kit, so the
217
+ // homepage's own kit listing gets the same affordance instead of being the
218
+ // one surface on the site without a way to search kits by name.
219
+ const kitsFilterState = { q: '' };
220
+
221
+ function panelNode(panel, idx, rerender) {
222
+ let items = Array.isArray(panel.items) ? panel.items : [];
223
+ const isKits = panel.id === 'kits';
224
+ const q = isKits ? kitsFilterState.q.trim().toLowerCase() : '';
225
+ if (isKits && q) {
226
+ items = items.filter((it) => {
227
+ const hay = (String(it.title || it.name || '') + ' ' + String(it.sub || it.desc || '')).toLowerCase();
228
+ return hay.includes(q);
229
+ });
230
+ }
231
+ const iconName = panel.id && PANEL_ICON[panel.id];
232
+ const titleText = panel.title || panel.name || '';
233
+ const titleNode = iconName && titleText
234
+ ? h('span', { class: 'ds-panel-title-glyph' }, C.Icon(iconName, { size: 15 }), h('span', {}, titleText))
235
+ : titleText;
236
+ const filterInput = isKits && rerender ? h('div', { class: 'ds-kits-filter' },
237
+ h('input', {
238
+ type: 'search', class: 'input ds-kits-filter-input',
239
+ placeholder: 'filter kits by name or description…',
240
+ value: kitsFilterState.q,
241
+ 'aria-label': 'filter ui kits',
242
+ oninput: (e) => { kitsFilterState.q = e.target.value; rerender(); },
243
+ })) : null;
244
+ if (!items.length) {
245
+ if (isKits && q) {
246
+ return h('div', { class: 'ds-kits-panel-wrap' }, filterInput,
247
+ C.Panel({ id: panel.id || null, title: titleNode, count: 0, children:
248
+ h('div', { class: 'ds-empty-state' },
249
+ h('div', { class: 'ds-empty-state-glyph' }, '( )'),
250
+ h('p', { class: 'ds-empty-state-msg' }, 'no kits match ', h('code', {}, '"' + kitsFilterState.q.trim() + '"')),
251
+ ) }));
252
+ }
253
+ return filterInput ? h('div', { class: 'ds-kits-panel-wrap' }, filterInput) : null;
254
+ }
191
255
  const rows = items.map((it, i) => {
192
256
  const code = it.code == null ? '' : String(it.code).trim();
193
257
  const kids = [];
@@ -197,7 +261,8 @@ function panelNode(panel, idx) {
197
261
  kids.push(h('span', { key: 'a', class: 'ds-row-arrow' }, it.meta || '->'));
198
262
  return h('a', { key: i, class: 'row', href: it.href || '#' }, ...kids);
199
263
  });
200
- return C.Panel({ id: panel.id || null, title: panel.title || panel.name || '', count: panel.count || items.length, children: rows });
264
+ const panelEl = C.Panel({ id: panel.id || null, title: titleNode, count: items.length, children: rows });
265
+ return filterInput ? h('div', { class: 'ds-kits-panel-wrap' }, filterInput, panelEl) : panelEl;
201
266
  }
202
267
 
203
268
  function marqueeNode(marquee) {
@@ -301,8 +366,14 @@ const bodyNode = data.bodyHtml ? C.Section({ children: h('div', { class: 'page-b
301
366
  function footerNode() {
302
367
  const year = new Date().getFullYear();
303
368
  const links = (data.navItems || []).filter(([, href]) => /^https?:/.test(String(href)));
369
+ // Names the actual maintaining entity, not just the project's numeric
370
+ // brand. This is a personal/community project (MIT, copyright holder
371
+ // "AnEntrypoint" per LICENSE) with no separate legal org behind it, so the
372
+ // footer says that plainly instead of leaving "247420" to stand in for an
373
+ // entity it isn't.
374
+ const entity = (data.seoAuthor || '247420 · a design system by AnEntrypoint').toLowerCase();
304
375
  return h('footer', { class: 'ds-page-footer' },
305
- h('span', { class: 'ds-page-footer-copy' }, String(year) + ' · ' + data.siteName),
376
+ h('span', { class: 'ds-page-footer-copy' }, String(year) + ' · ' + entity),
306
377
  links.length ? h('nav', { class: 'ds-page-footer-links', 'aria-label': 'footer' },
307
378
  ...links.map(([label, href], i) => h('a', { key: i, href }, String(label).replace(' ->', '')))
308
379
  ) : null,
@@ -320,40 +391,46 @@ function tierNode(tier, children) {
320
391
  return h('section', { key: tier.key, class: 'ds-tier ds-tier-' + tier.key, id: tier.key, 'aria-labelledby': labelId }, head, ...kids);
321
392
  }
322
393
 
323
- const panelsById = new Map((data.panels || []).map((p) => [p.id || p.title || p.name || '', p]));
324
- const takePanel = (id) => { const p = panelsById.get(id); if (p) panelsById.delete(id); return p ? panelNode(p) : null; };
325
-
326
394
  const TIERS = [
327
395
  { key: 'open', label: 'open', lede: 'browse and try the system running.', ids: ['kits', 'previews', 'decks'], extra: () => [examplesNode(data.examples)] },
328
396
  { key: 'ships', label: 'ships', lede: 'what the package contains.', ids: ['file_browser', 'desktop_os', 'web_components', 'api_exports'], extra: () => [] },
329
397
  { key: 'read', label: 'read', lede: 'understand the rules behind it.', ids: ['docs', 'features'], extra: () => [quickstartNode(data.quickstart)] },
330
398
  ];
331
399
 
332
- const tierNodes = TIERS.map((t) => {
333
- const kids = [...t.ids.map(takePanel), ...t.extra()].filter(Boolean);
334
- if (t.key === 'open' && kids.length) {
335
- const lead = kids[0];
336
- if (lead.props) lead.props.class = (lead.props.class || '') + ' ds-tier-lead';
337
- }
338
- return tierNode(t, kids);
339
- });
340
- const leftoverPanels = [...panelsById.values()].map(panelNode);
400
+ // Builds the whole main-content tree fresh each render so the kits filter
401
+ // (module-level kitsFilterState) can drive a real re-render via mount()'s
402
+ // own returned render callback -- same reactive shape mountKit() gives every
403
+ // other kit on the site, applied here to the static-page renderer.
404
+ function buildMainChildren(rerender) {
405
+ const panelsById = new Map((data.panels || []).map((p) => [p.id || p.title || p.name || '', p]));
406
+ const takePanel = (id) => { const p = panelsById.get(id); if (p) panelsById.delete(id); return p ? panelNode(p, 0, rerender) : null; };
341
407
 
342
- const mainChildren = [
343
- heroNode(data.hero),
344
- marqueeNode(data.marquee),
345
- ...data.sections.map(sectionNode),
346
- ...tierNodes,
347
- ...leftoverPanels,
348
- bodyNode,
349
- footerNode(),
350
- ].filter(Boolean);
408
+ const tierNodes = TIERS.map((t) => {
409
+ const kids = [...t.ids.map(takePanel), ...t.extra()].filter(Boolean);
410
+ if (t.key === 'open' && kids.length) {
411
+ const lead = kids[0];
412
+ if (lead.props) lead.props.class = (lead.props.class || '') + ' ds-tier-lead';
413
+ }
414
+ return tierNode(t, kids);
415
+ });
416
+ const leftoverPanels = [...panelsById.values()].map((p) => panelNode(p, 0, rerender));
417
+
418
+ return [
419
+ heroNode(data.hero),
420
+ marqueeNode(data.marquee),
421
+ ...data.sections.map(sectionNode),
422
+ ...tierNodes,
423
+ ...leftoverPanels,
424
+ bodyNode,
425
+ footerNode(),
426
+ ].filter(Boolean);
427
+ }
351
428
 
352
- mount(document.getElementById('app'), () => C.AppShell({
429
+ mount(document.getElementById('app'), (rerender) => C.AppShell({
353
430
  topbar: C.Topbar({ brand: data.siteName, items: data.navItems, active: data.title }),
354
431
  crumb: C.Crumb({ leaf: data.title }),
355
432
  side: sideNode(data.sidebar),
356
- main: h('div', { class: 'app-stage' }, ...mainChildren),
433
+ main: h('div', { class: 'app-stage' }, ...buildMainChildren(rerender)),
357
434
  status: C.Status({
358
435
  left: data.statusLeft || [data.siteName.toLowerCase(), data.slug],
359
436
  right: data.statusRight || ['live'],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "anentrypoint-design",
3
- "version": "0.0.477",
3
+ "version": "0.0.478",
4
4
  "description": "247420 design system SDK — webjsx + modified ripple-ui, single-file ESM bundle for reproducible use of the AnEntrypoint design.",
5
5
  "type": "module",
6
6
  "main": "./dist/247420.js",
@@ -99,13 +99,20 @@ export function Marquee({ items = [], sep = '/' }) {
99
99
  if (!items.length) return null;
100
100
  // Two identical runs make the -50% translate loop seamless. Each text and
101
101
  // separator is a keyed span so webjsx applyDiff never sees a primitive
102
- // sibling beside a keyed VElement.
102
+ // sibling beside a keyed VElement. Run 'a' is the real, assistive-tech-
103
+ // visible content; run 'b' is a purely visual duplicate for the seamless
104
+ // loop and must not be exposed to screen readers as doubled text, so it
105
+ // is wrapped in its own aria-hidden container (standard seamless-marquee
106
+ // technique).
103
107
  const run = (runKey) => items.flatMap((it, i) => [
104
108
  h('span', { class: 'ds-marquee-item', key: `${runKey}-i${i}` }, it),
105
109
  h('span', { class: 'ds-marquee-sep', key: `${runKey}-s${i}`, 'aria-hidden': 'true' }, sep),
106
110
  ]);
107
111
  return h('div', { class: 'ds-marquee', role: 'marquee' },
108
- h('div', { class: 'ds-marquee-track' }, ...run('a'), ...run('b'))
112
+ h('div', { class: 'ds-marquee-track' },
113
+ h('span', { class: 'ds-marquee-run ds-marquee-run-a' }, ...run('a')),
114
+ h('span', { class: 'ds-marquee-run ds-marquee-run-b', 'aria-hidden': 'true' }, ...run('b')),
115
+ )
109
116
  );
110
117
  }
111
118
 
@@ -90,7 +90,7 @@ export const themePage = makePage((ctx) => {
90
90
  return [
91
91
  PageHeader({ title: 'theme', lede: 'theme preference' }),
92
92
  section('current', Table({ headers: ['setting', 'value'], rows: [
93
- ['theme', (typeof window !== 'undefined' && document.body.getAttribute('data-theme')) || 'github-dark'],
93
+ ['theme', (typeof window !== 'undefined' && document.documentElement.getAttribute('data-theme')) || 'github-dark'],
94
94
  ['density', (typeof window !== 'undefined' && document.documentElement.getAttribute('data-density')) || 'compact'],
95
95
  ['accent', (typeof window !== 'undefined' && document.documentElement.getAttribute('data-accent')) || 'default'],
96
96
  ] })),
@@ -7,9 +7,14 @@ import * as webjsx from '../../../vendor/webjsx/index.js';
7
7
  import { trapTab } from '../overlay-primitives.js';
8
8
  import { Brand, Glyph } from './atoms.js';
9
9
  import { Icon } from './icons.js';
10
+ import { ThemeToggle } from '../theme-toggle.js';
10
11
  const h = webjsx.createElement;
11
12
 
12
- export function Topbar({ brand = '247420', leaf = '', items = [], active = '', onNav, search } = {}) {
13
+ // `themeToggle` defaults on: every Topbar consumer (homepage included) gets a
14
+ // real, working light/dark/auto control in the shell chrome instead of each
15
+ // call site having to remember to wire ThemeToggle() in by hand. Pass
16
+ // `themeToggle: false` to opt a shell out (e.g. a kit that renders its own).
17
+ export function Topbar({ brand = '247420', leaf = '', items = [], active = '', onNav, search, themeToggle = true } = {}) {
13
18
  return h('header', { class: 'app-topbar', role: 'banner' },
14
19
  Brand({ name: brand, leaf }),
15
20
  search ? h('label', { class: 'app-search' },
@@ -50,7 +55,8 @@ export function Topbar({ brand = '247420', leaf = '', items = [], active = '', o
50
55
  }
51
56
  }
52
57
  }, label);
53
- }))
58
+ })),
59
+ themeToggle ? h('div', { class: 'app-topbar-theme' }, ThemeToggle({ compact: true })) : null
54
60
  );
55
61
  }
56
62
 
@@ -208,9 +214,14 @@ export function AppShell({ topbar, crumb, side, main, status, narrow } = {}) {
208
214
  // brand + nav (topbar) and breadcrumb + right slot (crumb) share a single
209
215
  // band so the chrome reads as one bar, not two. Either prop alone still
210
216
  // renders on its own (consumers that pass only a topbar are unaffected).
217
+ // Landmark wrapper: topbar/crumb are opaque children with no semantics of
218
+ // their own, so screen-reader users landmark-navigating a page saw no
219
+ // "banner"/"navigation" region at all above <main>. <header role="banner">
220
+ // names the brand+nav band; the app-side-shell aside below already exists
221
+ // as a real <aside>, so this closes the missing landmark for the top band.
211
222
  const chrome = (topbar && crumb)
212
- ? h('div', { class: 'app-chrome' }, topbar, crumb)
213
- : (topbar || crumb || null);
223
+ ? h('header', { class: 'app-chrome', role: 'banner' }, topbar, crumb)
224
+ : (topbar || crumb) ? h('header', { class: 'app-chrome', role: 'banner' }, topbar || crumb) : null;
214
225
  return h('div', { class: 'app', ref: syncAppSide },
215
226
  h('a', { href: '#app-main', class: 'skip-link' }, 'skip to main content'),
216
227
  hasSide ? h('button', {
@@ -0,0 +1,103 @@
1
+ // copy-code.js -- vanilla-JS "copy" button injector for <pre><code> blocks.
2
+ //
3
+ // Standalone module, no dependencies, no framework assumptions: include it
4
+ // with a plain <script src="…/copy-code.js"></script> (or type="module") on
5
+ // any page rendering doc/code blocks and it wires itself up on
6
+ // DOMContentLoaded, finding every `pre > code` element and injecting a small
7
+ // button that copies the block's text to the clipboard.
8
+ //
9
+ // Self-invoking so a page can include it more than once without double-
10
+ // registering handlers or double-injecting buttons (guarded per-element via
11
+ // a data attribute).
12
+ (function () {
13
+ 'use strict';
14
+
15
+ const COPY_LABEL = 'copy';
16
+ const COPIED_LABEL = 'copied';
17
+ const FAILED_LABEL = 'copy failed';
18
+ const RESET_MS = 1500;
19
+ const MARK_ATTR = 'data-copy-code-wired';
20
+
21
+ function copyText(text) {
22
+ if (navigator.clipboard && navigator.clipboard.writeText) {
23
+ return navigator.clipboard.writeText(text);
24
+ }
25
+ // Fallback for non-secure contexts / browsers without navigator.clipboard.
26
+ return new Promise((resolve, reject) => {
27
+ try {
28
+ const ta = document.createElement('textarea');
29
+ ta.value = text;
30
+ ta.style.position = 'fixed';
31
+ ta.style.opacity = '0';
32
+ document.body.appendChild(ta);
33
+ ta.focus();
34
+ ta.select();
35
+ const ok = document.execCommand('copy');
36
+ document.body.removeChild(ta);
37
+ ok ? resolve() : reject(new Error('execCommand copy failed'));
38
+ } catch (err) {
39
+ reject(err);
40
+ }
41
+ });
42
+ }
43
+
44
+ function makeButton(codeEl) {
45
+ const btn = document.createElement('button');
46
+ btn.type = 'button';
47
+ btn.className = 'copy-code-btn';
48
+ btn.textContent = COPY_LABEL;
49
+ btn.setAttribute('aria-label', 'copy code to clipboard');
50
+
51
+ let resetTimer = null;
52
+ btn.addEventListener('click', () => {
53
+ copyText(codeEl.textContent || '').then(
54
+ () => setLabel(true),
55
+ () => setLabel(false)
56
+ );
57
+ });
58
+
59
+ function setLabel(ok) {
60
+ btn.textContent = ok ? COPIED_LABEL : FAILED_LABEL;
61
+ clearTimeout(resetTimer);
62
+ resetTimer = setTimeout(() => { btn.textContent = COPY_LABEL; }, RESET_MS);
63
+ }
64
+
65
+ return btn;
66
+ }
67
+
68
+ function wireBlock(codeEl) {
69
+ const pre = codeEl.parentElement;
70
+ if (!pre || pre.tagName !== 'PRE') return;
71
+ if (pre.hasAttribute(MARK_ATTR)) return;
72
+ pre.setAttribute(MARK_ATTR, '1');
73
+ // Position context for an absolutely-positioned button; harmless no-op
74
+ // if the page's own CSS already sets a position on <pre>.
75
+ if (!pre.style.position) pre.style.position = 'relative';
76
+ pre.appendChild(makeButton(codeEl));
77
+ }
78
+
79
+ function wireAll(root) {
80
+ (root || document).querySelectorAll('pre > code').forEach(wireBlock);
81
+ }
82
+
83
+ if (document.readyState === 'loading') {
84
+ document.addEventListener('DOMContentLoaded', () => wireAll(document));
85
+ } else {
86
+ wireAll(document);
87
+ }
88
+
89
+ // Minimal default styling, injected once, so the button is usable even on
90
+ // pages with no bespoke .copy-code-btn rule of their own. A page that wants
91
+ // its own look can simply define .copy-code-btn in its own stylesheet --
92
+ // this only runs if that class isn't already styled to be visible.
93
+ if (!document.getElementById('copy-code-btn-style')) {
94
+ const style = document.createElement('style');
95
+ style.id = 'copy-code-btn-style';
96
+ style.textContent =
97
+ '.copy-code-btn{position:absolute;top:.5em;right:.5em;font:inherit;' +
98
+ 'font-size:.75em;line-height:1;padding:.35em .6em;border:1px solid currentColor;' +
99
+ 'border-radius:4px;background:transparent;color:inherit;cursor:pointer;opacity:.6}' +
100
+ '.copy-code-btn:hover{opacity:1}';
101
+ document.head.appendChild(style);
102
+ }
103
+ })();
@@ -41,6 +41,12 @@
41
41
  .ds-demo-label { font-size: var(--fs-xs); font-weight: 500; margin: 0 0 var(--space-1); }
42
42
  .ds-demo-desc { font-size: var(--fs-tiny); color: var(--fg-3); margin: 0 0 var(--space-2); }
43
43
 
44
+ /* Per-preview backlink to the full token map/doc — names which token
45
+ families the specimen above it demonstrates, then links out to the
46
+ generated theme-map for the resolved values. */
47
+ .tokens-backlink { font-family: var(--ff-mono); font-size: var(--fs-xs); color: var(--fg-3); margin-top: 2px; }
48
+ .tokens-backlink a { color: inherit; }
49
+
44
50
  @media (max-width: 768px) {
45
51
  .ds-catalog { flex-direction: column; }
46
52
  .ds-catalog-side { width: 100%; height: auto; position: static; border-right: 0; border-bottom: var(--bw-hair) solid var(--rule); }
@@ -263,6 +263,12 @@
263
263
  display: grid; grid-template-columns: repeat(auto-fill, minmax(132px, 1fr));
264
264
  gap: var(--space-3); align-items: start;
265
265
  }
266
+ /* Mobile fallback: auto-fill can still pack 2 cramped columns down to ~320px
267
+ viewports; force a single column below the shared mobile breakpoint
268
+ (docs/responsive.md) so thumbnails and file rails always read as a list. */
269
+ @media (max-width: 480px) {
270
+ .ds-file-grid-thumb { grid-template-columns: 1fr; }
271
+ }
266
272
  .ds-file-cell {
267
273
  position: relative;
268
274
  background: var(--bg); border: var(--bw-hair) solid var(--rule); border-radius: var(--r-2);
@@ -88,6 +88,18 @@
88
88
  display: flex; gap: var(--space-2, 10px); flex-wrap: wrap;
89
89
  justify-content: flex-start; margin-top: var(--space-hair, 4px);
90
90
  }
91
+ /* Hero CTA labels are content-driven (e.g. "GitHub", proper nouns from
92
+ home.yaml) and the site's voice is deliberately all-lowercase everywhere
93
+ else. Force the rendered case here rather than hand-lowercasing every
94
+ proper-noun label at the content layer, so a future CTA label doesn't
95
+ silently reintroduce Title Case. */
96
+ .ds-hero-actions .btn { text-transform: lowercase; }
97
+ /* Filter input above the homepage's "ui kits" panel — reuses the same
98
+ .input token the search kit's own topbar query box uses, just placed
99
+ inline above the panel instead of in a topbar slot. */
100
+ .ds-kits-panel-wrap { display: flex; flex-direction: column; gap: var(--space-2, 10px); }
101
+ .ds-kits-filter { display: flex; }
102
+ .ds-kits-filter-input { width: 100%; max-width: 32ch; }
91
103
  /* Below this width the aside card's own internal rhythm (stat rows still
92
104
  stacked vertically at full width) is already correct for a narrow column —
93
105
  no separate breakpoint override needed now that .ds-hero is always a
@@ -167,6 +179,7 @@
167
179
  white-space: nowrap; will-change: transform;
168
180
  animation: ds-marquee-run 28s linear infinite;
169
181
  }
182
+ .ds-marquee-run { display: inline-flex; align-items: center; gap: var(--space-5); }
170
183
  .ds-marquee-item { display: inline-flex; align-items: center; gap: var(--space-5); }
171
184
  .ds-marquee-sep { color: var(--accent-ink); }
172
185
  .ds-marquee:hover .ds-marquee-track,
@@ -451,6 +451,11 @@
451
451
  .ds-btn-row-tight { gap: var(--space-1-75, 6px); }
452
452
  .ds-key-input { flex: 1 1 160px; min-width: 0; font-family: var(--ff-mono); }
453
453
  .ds-toggle-btn { min-width: 78px; }
454
+ /* Side-by-side checked/unchecked reference pair (settings kit theme panel) --
455
+ documents the visual difference between states in one static, non-live
456
+ spot rather than requiring a viewer to toggle a real control back and
457
+ forth to compare. */
458
+ .ds-toggle-state-sample { display: flex; align-items: center; gap: var(--space-1-5, 6px); }
454
459
  .ds-toggle-label { margin-left: var(--space-2, 8px); color: inherit; opacity: 0.7; }
455
460
  .ds-btn-warn { color: var(--warn); }
456
461
  /* Raw --mascot text measures 3.11:1 on paper (fails 4.5:1); --mascot-deep is
@@ -593,6 +598,14 @@
593
598
  display: flex; flex-direction: column; gap: 0;
594
599
  background: var(--ink); border-radius: var(--r-1);
595
600
  font-family: var(--ff-mono); font-size: var(--fs-micro); line-height: 1.65;
601
+ /* Responsive strategy for long logs: cap the scrollback height and scroll
602
+ vertically rather than growing the page indefinitely; long command/output
603
+ lines wrap (see .cli .cmd's overflow-wrap: anywhere below) instead of
604
+ scrolling horizontally, so wrapping is the chosen default over
605
+ horizontal scroll for this kit. */
606
+ max-height: 60vh;
607
+ overflow-y: auto;
608
+ overflow-wrap: anywhere;
596
609
  }
597
610
  /* .cli is authored in hero-content.css as a STANDALONE hero code block --
598
611
  20px/24px padding, --fs-lg type, --r-3 radius and its own --ink background
@@ -73,6 +73,13 @@
73
73
  margin: 0; font: inherit; font-size: inherit; font-weight: inherit;
74
74
  letter-spacing: inherit; text-transform: inherit; color: inherit;
75
75
  }
76
+ /* Category glyph beside a panel title (kits / previews / decks / docs on the
77
+ homepage) — same inline-svg vocabulary as icons.js, sized to sit on the
78
+ text baseline rather than dominating it. */
79
+ .ds-panel-title-glyph {
80
+ display: inline-flex; align-items: center; gap: var(--space-1-5, 6px);
81
+ }
82
+ .ds-panel-title-glyph .ds-icon { flex-shrink: 0; color: var(--fg-3); }
76
83
  .panel-body { padding: var(--space-2) var(--space-3) var(--space-3); }
77
84
  .panel-body > * { margin: 0; }
78
85
  /* One-line explanatory caption under a panel's title — e.g. distinguishing
@@ -113,6 +120,14 @@
113
120
  transition: background var(--dur-snap) var(--ease), box-shadow var(--dur-base) var(--ease-spring);
114
121
  }
115
122
  .row + .row { margin-top: 2px; }
123
+ /* Mobile tap-target floor: at compact/comfortable density on a touch
124
+ viewport the padding-only row height can fall under the 44px effective
125
+ tap target (WCAG 2.5.5), especially at [data-density="compact"] (0.75x).
126
+ Force a min-height on narrow/coarse-pointer viewports only, so the dense
127
+ desktop mono/list layout (file-row, index-row) is untouched above 640px. */
128
+ @media (max-width: 640px), (pointer: coarse) {
129
+ .row, a.row, button.row, .row[role="button"] { min-height: 44px; }
130
+ }
116
131
  /* Interactive rows (anchor/button wrappers) get a hairline lift on hover,
117
132
  matching the btn/panel elevation language — non-interactive rows (plain
118
133
  divs used as static list items) are unaffected since the selector needs a