@livx.cc/bare-v3 0.1.0-alpha.10
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/README.md +39 -0
- package/dist/bare.css +1758 -0
- package/dist/bare.min.css +1 -0
- package/dist/manifest.json +457 -0
- package/dist/references/app-frame.md +9 -0
- package/dist/references/button.md +9 -0
- package/dist/references/card-structure.md +9 -0
- package/dist/references/command.md +9 -0
- package/dist/references/content.md +9 -0
- package/dist/references/control-structure.md +9 -0
- package/dist/references/conversation.md +9 -0
- package/dist/references/cross-screen.md +34 -0
- package/dist/references/data-display.md +9 -0
- package/dist/references/dialog.md +9 -0
- package/dist/references/disclosure.md +9 -0
- package/dist/references/feedback.md +9 -0
- package/dist/references/field.md +9 -0
- package/dist/references/form-composition.md +9 -0
- package/dist/references/foundation.md +9 -0
- package/dist/references/icons.md +14 -0
- package/dist/references/identity.md +9 -0
- package/dist/references/layout.md +9 -0
- package/dist/references/marketing.md +9 -0
- package/dist/references/mobile.md +9 -0
- package/dist/references/motion.md +44 -0
- package/dist/references/navigation.md +9 -0
- package/dist/references/page-layout.md +9 -0
- package/dist/references/reading.md +9 -0
- package/dist/references/row.md +9 -0
- package/dist/references/start.md +21 -0
- package/dist/references/status.md +9 -0
- package/dist/references/steps.md +9 -0
- package/dist/references/surface.md +9 -0
- package/dist/references/tabs.md +9 -0
- package/dist/references/type.md +9 -0
- package/dist/ui.js +598 -0
- package/package.json +47 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@layer bare.reset{:where(.b3-root),:where(.b3-root *){box-sizing:border-box}:where(.b3-root){font-family:var(--b3-font-body);background:var(--b3-color-canvas);color:var(--b3-color-text);color-scheme:light;margin:0;font-size:1rem;line-height:1.5}:where(.b3-root>body){margin:0}:where(.b3-root) :where(button,input,select,textarea){font:inherit}:where(.b3-root) :where(h1,h2,h3,p){margin:0}:where(.b3-root) :where(button,a,input,select,textarea,summary,[tabindex]):focus-visible{outline:3px solid var(--b3-color-focus);outline-offset:3px}:where(.b3-root) :where(img,svg){max-inline-size:100%}@media (prefers-reduced-motion:reduce){:where(.b3-root *),:where(.b3-root *):before,:where(.b3-root *):after{transition-duration:.01ms!important;animation-duration:.01ms!important;animation-iteration-count:1!important}}[data-b3-motion=reduce] *,[data-b3-motion=reduce] :before,[data-b3-motion=reduce] :after,[data-b3-motion=reduce] ::backdrop{scroll-behavior:auto!important;transition:none!important;animation:none!important}:where(.b3-root [hidden]):not([hidden=until-found]){display:none!important}:where(.b3-root) :where(input[type=checkbox],input[type=radio],input[type=range]){accent-color:var(--b3-color-accent)}}@layer bare.tokens{.b3-root{--b3-color-canvas:#f6f5f0;--b3-color-surface:#fff;--b3-color-text:#202923;--b3-color-muted:#59655d;--b3-color-border:#d5dbd3;--b3-color-accent:#245c42;--b3-color-on-accent:#fff;--b3-color-danger:#a62c35;--b3-color-focus:#276bdd;--b3-font-body:ui-sans-serif, system-ui, sans-serif;--b3-font-display:var(--b3-font-body);--b3-radius:.75rem;--b3-space:1rem;--b3-content:68rem}.b3-root[data-b3-theme=dark]{color-scheme:dark;--b3-color-canvas:#141c19;--b3-color-surface:#202c26;--b3-color-text:#edf3ec;--b3-color-muted:#a8b9ad;--b3-color-border:#415348;--b3-color-accent:#aadbb8;--b3-color-on-accent:#132b1b;--b3-color-danger:#ffadb1;--b3-color-focus:#9ac4ff}.b3-root{--b3-space-1:.25rem;--b3-space-2:.5rem;--b3-space-3:.75rem;--b3-space-4:1rem;--b3-space-6:1.5rem;--b3-space-8:2rem;--b3-space-12:3rem;--b3-radius-small:.375rem;--b3-radius-large:1.25rem;--b3-shadow:0 8px 32px #14231b14;--b3-shadow-raised:0 16px 56px #14231b24;--b3-color-success:#256443;--b3-color-warning:#805100;--b3-color-info:#275f99;--b3-duration:.16s}.b3-root[data-b3-theme=dark]{--b3-shadow:0 8px 32px #0004;--b3-shadow-raised:0 16px 56px #0007;--b3-color-success:#99d9ab;--b3-color-warning:#f2c76c;--b3-color-info:#a2cfff}}@layer bare.layout{.b3-shell{inline-size:min(100%, var(--b3-content));margin-inline:auto;padding:clamp(1rem,4vw,3rem)}.b3-stack{gap:var(--b3-space);flex-direction:column;min-inline-size:0;display:flex}.b3-stack:where(dialog:not([open])){display:none}.b3-scroll{overscroll-behavior:contain;scrollbar-gutter:stable;flex:auto;min-block-size:0;min-inline-size:0;overflow:auto}.b3-stack:has(>.b3-scroll)>:not(.b3-scroll){flex-shrink:0}.b3-cluster{align-items:center;gap:var(--b3-space);flex-wrap:wrap;min-inline-size:0;display:flex}.b3-inline{vertical-align:middle;align-items:center;gap:.5em;min-inline-size:0;max-inline-size:100%;display:inline-flex}.b3-inline>*{min-inline-size:0}.b3-grid{grid-template-columns:repeat(auto-fit, minmax(min(100%, var(--b3-grid-min,17rem)), 1fr));gap:var(--b3-space);display:grid}.b3-split{justify-content:space-between;align-items:center;gap:var(--b3-space);flex-wrap:wrap;display:flex}.b3-page{flex-direction:column;min-block-size:100svh;display:flex}.b3-page-body{flex:1;min-inline-size:0}.b3-app-layout{grid-template-columns:minmax(12rem,16rem) minmax(0,1fr);min-block-size:100svh;display:grid}.b3-sidebar{padding:var(--b3-space-6);border-inline-end:1px solid var(--b3-color-border);background:var(--b3-color-surface);min-inline-size:0}.b3-center{padding:var(--b3-space-6);place-items:center;display:grid}.b3-cover{min-block-size:min(42rem,85svh);padding-block:var(--b3-space-12);flex-direction:column;justify-content:center;display:flex}.b3-reel{gap:var(--b3-space);scroll-snap-type:x proximity;padding-block-end:var(--b3-space-2);display:flex;overflow-x:auto}.b3-reel>*{scroll-snap-align:start;flex:0 0 min(85%,20rem)}@media (width<=48rem){.b3-app-layout{grid-template-columns:minmax(0,1fr)}.b3-sidebar{border-inline-end:0;border-block-end:1px solid var(--b3-color-border)}}}@layer bare.components{.b3-title{font-family:var(--b3-font-display);letter-spacing:-.04em;overflow-wrap:anywhere;font-size:clamp(2rem,7vw,4rem);line-height:1.05}.b3-heading{font-family:var(--b3-font-display);letter-spacing:-.02em;font-size:1.375rem;line-height:1.25}.b3-muted{color:var(--b3-color-muted)}.b3-label{letter-spacing:.06em;text-transform:uppercase;font-size:.8125rem;font-weight:650}.b3-surface{background:var(--b3-color-surface);color:var(--b3-color-text);border:1px solid var(--b3-color-border);border-radius:var(--b3-radius);padding:clamp(1rem,3vw,2rem)}.b3-button{border-radius:var(--b3-radius);background:var(--b3-color-accent);min-block-size:2.75rem;color:var(--b3-color-on-accent);cursor:pointer;border:1px solid #0000;justify-content:center;align-items:center;gap:.5rem;padding:.625rem 1rem;font-weight:650;text-decoration:none;display:inline-flex}.b3-button[data-b3-emphasis=quiet]{color:var(--b3-color-text);border-color:var(--b3-color-border);background:0 0}.b3-button:disabled{opacity:.5;cursor:not-allowed}.b3-field{align-content:start;gap:.375rem;min-inline-size:0;display:grid}.b3-input{border:1px solid var(--b3-color-border);border-radius:var(--b3-radius);background:var(--b3-color-surface);min-block-size:2.75rem;inline-size:100%;min-inline-size:0;color:var(--b3-color-text);padding:.625rem .75rem}.b3-error{color:var(--b3-color-danger);font-size:.875rem}select.b3-input:not([multiple]):not([size]),select.b3-input[size="1"]:not([multiple]){appearance:none;background-image:linear-gradient(45deg,#0000 50%,currentColor 50%),linear-gradient(135deg,currentColor 50%,#0000 50%);background-position:right calc(1rem + 5px) center,right 1rem center;background-repeat:no-repeat;background-size:5px 5px;padding-inline-end:2.5rem}select.b3-input:not([multiple]):not([size]):dir(rtl),select.b3-input[size="1"]:not([multiple]):dir(rtl){background-position:1rem,calc(1rem + 5px)}@media (forced-colors:active){select.b3-input:not([multiple]):not([size]),select.b3-input[size="1"]:not([multiple]){appearance:auto;background-image:none}}.b3-row{border-block-end:1px solid var(--b3-color-border);align-items:center;gap:.75rem;padding-block:1rem;display:flex}.b3-badge{border:1px solid var(--b3-color-border);border-radius:100vmax;align-items:center;padding:.125rem .5rem;font-size:.75rem;font-weight:650;display:inline-flex}.b3-progress{block-size:.5rem;inline-size:100%;accent-color:var(--b3-color-accent)}.b3-button{transition:box-shadow var(--b3-duration), border-color var(--b3-duration)}@media (hover:hover){.b3-button:not(:disabled):hover{box-shadow:inset 0 0 0 100vmax #00000012}}.b3-button:not(:disabled):active{box-shadow:inset 0 0 0 100vmax #00000024}.b3-button[data-b3-emphasis=outline]{color:var(--b3-color-accent);background:0 0;border-color:currentColor}.b3-button[data-b3-emphasis=danger]{background:var(--b3-color-danger);color:var(--b3-color-canvas)}.b3-button[data-b3-size=small]{padding:.5rem .75rem;font-size:.875rem}.b3-button[data-b3-size=large]{min-block-size:3.25rem;padding:.875rem 1.5rem}.b3-button[aria-busy=true]{cursor:progress}.b3-icon{vertical-align:-.2em;flex:none;block-size:1.25em;inline-size:1.25em;display:inline-block}.b3-input:disabled{opacity:.6;cursor:not-allowed}.b3-input[readonly]{background:var(--b3-color-canvas)}.b3-input::placeholder{color:var(--b3-color-muted);opacity:.8}.b3-input-group{border:1px solid var(--b3-color-border);border-radius:var(--b3-radius);background:var(--b3-color-surface);align-items:stretch;min-inline-size:0;display:flex;overflow:clip}.b3-input-group>.b3-input{border:0;border-radius:0;flex:1}.b3-input-group:focus-within{outline:3px solid var(--b3-color-focus);outline-offset:3px}.b3-input-affix{color:var(--b3-color-muted);background:var(--b3-color-canvas);align-items:center;padding-inline:.75rem;display:flex}.b3-choice{cursor:pointer;align-items:start;gap:.75rem;padding-block:.5rem;display:flex}.b3-choice input{--b3-choice-control:1.125rem;inline-size:var(--b3-choice-control);block-size:var(--b3-choice-control);flex:none;margin:0;margin-block-start:max(0px, calc((1lh - var(--b3-choice-control)) / 2))}.b3-choice>.b3-switch{--b3-choice-control:1.625rem}.b3-switch{appearance:none;background:var(--b3-color-muted);border:2px solid var(--b3-color-muted);cursor:pointer;border-radius:2rem;position:relative;block-size:1.625rem!important;inline-size:2.75rem!important}.b3-switch:before{content:"";background:var(--b3-color-surface);border-radius:50%;block-size:1.125rem;inline-size:1.125rem;position:absolute;inset-block-start:.125rem;inset-inline-start:.125rem}.b3-switch:checked{background:var(--b3-color-accent);border-color:var(--b3-color-accent)}.b3-switch:checked:before{background:var(--b3-color-on-accent);inset-inline-start:calc(100% - 1.25rem)}.b3-switch:disabled{opacity:.5;cursor:not-allowed}.b3-card-header,.b3-card-footer{justify-content:space-between;align-items:center;gap:var(--b3-space);flex-wrap:wrap;display:flex}.b3-card-header{margin-block-end:var(--b3-space-4)}.b3-card-footer{border-block-start:1px solid var(--b3-color-border);margin-block-start:var(--b3-space-4);padding-block-start:var(--b3-space-4)}.b3-surface[data-b3-elevation=raised]{box-shadow:var(--b3-shadow)}.b3-divider{border:0;border-block-start:1px solid var(--b3-color-border);margin-block:var(--b3-space)}.b3-alert{--b3-status-color:var(--b3-color-info);border:1px solid var(--b3-status-color);border-radius:var(--b3-radius-small);color:var(--b3-color-text);background:color-mix(in srgb, var(--b3-status-color) 8%, var(--b3-color-surface));border-inline-start-width:4px;align-items:start;gap:.75rem;padding:1rem;display:flex}.b3-alert[data-b3-tone=success],.b3-badge[data-b3-tone=success]{--b3-status-color:var(--b3-color-success)}.b3-alert[data-b3-tone=warning],.b3-badge[data-b3-tone=warning]{--b3-status-color:var(--b3-color-warning)}.b3-alert[data-b3-tone=danger],.b3-badge[data-b3-tone=danger]{--b3-status-color:var(--b3-color-danger)}.b3-badge[data-b3-tone]{color:var(--b3-status-color,var(--b3-color-info));background:color-mix(in srgb, currentColor 7%, transparent);border-color:currentColor}.b3-toast-region{z-index:100;pointer-events:none;gap:.75rem;inline-size:min(24rem,100% - 2rem);display:grid;position:fixed;inset-block-end:1rem;inset-inline-end:1rem}.b3-toast{border:1px solid var(--b3-color-border);border-radius:var(--b3-radius);background:var(--b3-color-surface);color:var(--b3-color-text);box-shadow:var(--b3-shadow-raised);pointer-events:auto;align-items:start;gap:1rem;padding:1rem;display:flex}.b3-spinner{vertical-align:-.125em;border:2px solid;border-inline-end-color:#0000;border-radius:50%;flex:none;block-size:1.125em;inline-size:1.125em;animation:.8s linear infinite b3-spin;display:inline-block}@keyframes b3-spin{to{transform:rotate(360deg)}}.b3-skeleton{background:var(--b3-color-border);border-radius:var(--b3-radius-small);min-block-size:1rem;animation:1.8s ease-in-out infinite b3-pulse}@keyframes b3-pulse{50%{opacity:.45}}.b3-avatar{background:var(--b3-color-accent);block-size:2.5rem;inline-size:2.5rem;color:var(--b3-color-on-accent);border-radius:50%;flex:none;place-items:center;font-size:.875rem;font-weight:650;display:inline-grid;overflow:hidden}.b3-avatar>img{object-fit:cover;block-size:100%;inline-size:100%}.b3-avatar-stack{padding-inline-start:.5rem;display:flex}.b3-avatar-stack>.b3-avatar{border:2px solid var(--b3-color-surface);margin-inline-start:-.5rem}.b3-kbd{border:1px solid var(--b3-color-border);background:var(--b3-color-surface);color:var(--b3-color-muted);border-block-end-width:2px;border-radius:.25rem;padding:.15rem .35rem;font:.75rem ui-monospace,monospace}.b3-table-wrap{border:1px solid var(--b3-color-border);border-radius:var(--b3-radius);overflow-x:auto}.b3-table{border-collapse:collapse;text-align:start;font-variant-numeric:tabular-nums;inline-size:100%}.b3-table th{color:var(--b3-color-muted);background:var(--b3-color-canvas);font-size:.75rem;font-weight:650}.b3-table :is(th,td){border-block-end:1px solid var(--b3-color-border);text-align:start;vertical-align:middle;padding:.875rem 1rem}.b3-table tbody tr:last-child td{border-block-end:0}.b3-table[data-b3-density=compact] :is(th,td){padding:.5rem .75rem}.b3-table tbody tr[aria-selected=true]{background:color-mix(in srgb, var(--b3-color-accent) 10%, var(--b3-color-surface))}.b3-definition{grid-template-columns:minmax(7rem,1fr) minmax(0,2fr);gap:.75rem 1.5rem;margin:0;display:grid}.b3-definition dt{color:var(--b3-color-muted)}.b3-definition dd{overflow-wrap:anywhere;margin:0}.b3-stat{gap:.5rem;display:grid}.b3-stat-value{letter-spacing:-.045em;font-variant-numeric:tabular-nums;font-size:clamp(2rem,5vw,3rem);font-weight:650;line-height:1.1}.b3-nav{border-block-end:1px solid var(--b3-color-border);flex-wrap:wrap;align-items:center;gap:.5rem;padding:.75rem;display:flex}.b3-nav[data-b3-orientation=vertical]{border-block-end:0;flex-direction:column;align-items:stretch}.b3-nav-link{border-radius:var(--b3-radius-small);min-block-size:2.75rem;color:var(--b3-color-muted);align-items:center;gap:.5rem;padding:.625rem .875rem;text-decoration:none;display:flex}.b3-nav-link[aria-current=page]{background:color-mix(in srgb, var(--b3-color-accent) 10%, var(--b3-color-surface));color:var(--b3-color-accent);font-weight:650}.b3-nav-link:hover{background:var(--b3-color-surface);color:var(--b3-color-text)}.b3-breadcrumbs{color:var(--b3-color-muted);flex-wrap:wrap;align-items:center;gap:.5rem;margin:0;padding:0;font-size:.875rem;list-style:none;display:flex}.b3-breadcrumbs li+li:before{content:"/";color:var(--b3-color-border);margin-inline-end:.5rem}.b3-tablist{border-block-end:1px solid var(--b3-color-border);gap:.25rem;display:flex;overflow-x:auto}.b3-tab{appearance:none;color:var(--b3-color-muted);font:inherit;white-space:nowrap;cursor:pointer;background:0 0;border:0;border-block-end:2px solid #0000;min-block-size:2.75rem;padding:.75rem 1rem}.b3-tab[aria-selected=true]{color:var(--b3-color-accent);border-block-end-color:currentColor;font-weight:650}.b3-tab:disabled{opacity:.5;cursor:not-allowed}.b3-tabpanel{padding-block:var(--b3-space-4)}.b3-accordion{border-block-end:1px solid var(--b3-color-border)}.b3-accordion>summary{cursor:pointer;padding:1rem .25rem;font-weight:650}.b3-accordion>:not(summary){padding:0 .25rem 1rem}.b3-dropdown{display:inline-block;position:relative}.b3-dropdown>summary{list-style:none}.b3-dropdown>summary::-webkit-details-marker{display:none}.b3-dropdown-panel{z-index:20;border:1px solid var(--b3-color-border);border-radius:var(--b3-radius);background:var(--b3-color-surface);max-block-size:70svh;inline-size:max-content;min-inline-size:min(12rem,85vw);max-inline-size:min(22rem,85vw);color:var(--b3-color-text);box-shadow:var(--b3-shadow-raised);padding:.5rem;position:absolute;inset-block-start:calc(100% + .5rem);inset-inline-start:0;overflow-y:auto}.b3-dialog{overscroll-behavior:contain;border:1px solid var(--b3-color-border);border-radius:var(--b3-radius-large);background:var(--b3-color-surface);max-block-size:calc(100svh - 2rem);inline-size:min(32rem,100% - 2rem);color:var(--b3-color-text);box-shadow:var(--b3-shadow-raised);padding:1.5rem;overflow:auto}.b3-dialog::backdrop{background:#101b17a6}.b3-dialog[data-b3-placement=end]{border-radius:0;block-size:100svh;max-block-size:100svh;inline-size:min(28rem,100%);margin:0;margin-inline-start:auto}@media (prefers-reduced-motion:no-preference){.b3-dialog[open]{animation:.28s cubic-bezier(.16,1,.3,1) b3-dialog-enter}.b3-dialog[open][data-b3-placement=end]{animation-name:b3-drawer-enter}.b3-dialog::backdrop,.b3-sheet::backdrop{transition:opacity .16s ease-out}.b3-dialog[data-b3-closing]::backdrop,.b3-sheet[data-b3-closing]::backdrop{opacity:0}@keyframes b3-dialog-enter{0%{opacity:0;transform:translateY(8px)scale(.96)}}@keyframes b3-drawer-enter{0%{opacity:0;translate:var(--b3-drawer-offset,1rem)}}.b3-dialog[dir=rtl][data-b3-placement=end],[dir=rtl] .b3-dialog[data-b3-placement=end]{--b3-drawer-offset:-1rem}}.b3-tree{border-inline-start:1px solid var(--b3-color-border);padding-inline-start:1rem;list-style:none}.b3-tree summary{cursor:pointer;padding-block:.5rem}.b3-prose{overflow-wrap:anywhere;max-inline-size:65ch;line-height:1.75}.b3-prose :is(p,ul,ol,blockquote,pre){margin-block:1rem}.b3-prose :is(h2,h3,h4){margin-block:1.75rem .75rem;line-height:1.25}.b3-prose blockquote{border-inline-start:3px solid var(--b3-color-accent);color:var(--b3-color-muted);margin-inline:0;padding-inline-start:1rem}.b3-prose pre{background:var(--b3-color-surface);border:1px solid var(--b3-color-border);border-radius:var(--b3-radius-small);padding:1rem;overflow-x:auto}.b3-visually-hidden{clip-path:inset(50%);white-space:nowrap;block-size:1px;inline-size:1px;position:absolute;overflow:hidden}.b3-skip-link{z-index:1000;border-radius:var(--b3-radius-small);background:var(--b3-color-accent);max-inline-size:calc(100% - 1.5rem);color:var(--b3-color-on-accent);padding:.75rem 1rem;font-weight:650;position:fixed;inset-block-start:max(.75rem, env(safe-area-inset-top,0px));inset-inline-start:.75rem}.b3-skip-link:not(:focus){clip-path:inset(50%);white-space:nowrap;block-size:1px;inline-size:1px;padding:0;overflow:hidden}.b3-hero{grid-template-columns:repeat(2,minmax(0,1fr));align-items:center;gap:clamp(2rem,6vw,6rem);padding-block:clamp(3rem,8vw,7rem);display:grid}.b3-hero[data-b3-align=center]{text-align:center;grid-template-columns:minmax(0,1fr);justify-items:center}.b3-hero-copy{gap:1.5rem;max-inline-size:40rem;display:grid}.b3-feature{grid-template-columns:minmax(0,1fr) minmax(0,1fr);align-items:center;gap:clamp(1.5rem,5vw,5rem);padding-block:clamp(2rem,6vw,5rem);display:grid}.b3-feature[data-b3-reverse=true]>:first-child{order:2}.b3-feature-icon{border-radius:var(--b3-radius);background:var(--b3-color-accent);block-size:3rem;inline-size:3rem;color:var(--b3-color-on-accent);place-items:center;display:inline-grid}.b3-pricing{border:1px solid var(--b3-color-border);border-radius:var(--b3-radius-large);background:var(--b3-color-surface);color:var(--b3-color-text);flex-direction:column;gap:1.25rem;padding:clamp(1.25rem,3vw,2rem);display:flex}.b3-pricing[data-b3-featured=true]{border:2px solid var(--b3-color-accent);box-shadow:var(--b3-shadow)}.b3-pricing>.b3-button:last-child{margin-block-start:auto}.b3-price{font-variant-numeric:tabular-nums;align-items:baseline;gap:.375rem;display:flex}.b3-price>strong{letter-spacing:-.05em;font-size:3.25rem;line-height:1.1}.b3-checklist{gap:.75rem;margin:0;padding:0;list-style:none;display:grid}.b3-checklist>li{align-items:start;gap:.625rem;display:flex}.b3-checklist>li:before{content:"✓";color:var(--b3-color-accent);font-weight:700}.b3-quote{border-inline-start:3px solid var(--b3-color-accent);margin:0;padding:1.5rem}.b3-quote blockquote{margin:0 0 1rem;font-size:1.25rem;line-height:1.5}.b3-art{isolation:isolate;border-radius:var(--b3-radius-large);background:var(--b3-color-surface);position:relative;overflow:hidden}.b3-art:before{content:"";z-index:-1;pointer-events:none;position:absolute;inset:0}.b3-art[data-b3-art=dots]:before{background-image:radial-gradient(var(--b3-color-border) 1px,transparent 1px);background-size:16px 16px}.b3-art[data-b3-art=glow]:before{background:radial-gradient(ellipse at 20% 20%,color-mix(in srgb,var(--b3-color-accent) 20%,transparent),transparent 65%)}.b3-art[data-b3-art=wash]:before{background:linear-gradient(135deg,color-mix(in srgb,var(--b3-color-accent) 14%,transparent),transparent 70%)}@media (width<=48rem){.b3-hero,.b3-feature{grid-template-columns:minmax(0,1fr)}.b3-feature[data-b3-reverse=true]>:first-child{order:initial}}.b3-reading{grid-template-columns:minmax(0,1fr) minmax(12rem,16rem);grid-template-areas:"content outline";align-items:start;gap:clamp(2rem,5vw,5rem);display:grid}.b3-reading>:not(.b3-toc){grid-area:content;min-inline-size:0}.b3-toc{max-block-size:calc(100svh - var(--b3-outline-top,1rem) - 1rem);border-inline-start:1px solid var(--b3-color-border);grid-area:outline;padding-inline-start:1rem;font-size:.875rem;position:sticky;inset-block-start:var(--b3-outline-top,1rem);overflow-y:auto}.b3-toc ol{gap:.25rem;margin:.75rem 0 0;padding:0;list-style:none;display:grid}.b3-toc ol ol{margin:.25rem 0;padding-inline-start:1rem}.b3-toc-link{border-radius:var(--b3-radius-small);color:var(--b3-color-muted);overflow-wrap:anywhere;padding:.625rem .75rem;text-decoration:none;display:block}.b3-toc-link:hover{color:var(--b3-color-text);background:var(--b3-color-surface)}.b3-toc-link[aria-current=location]{color:var(--b3-color-accent);background:color-mix(in srgb, var(--b3-color-accent) 10%, var(--b3-color-surface));font-weight:650}@media (width<=48rem){.b3-reading{grid-template-columns:minmax(0,1fr);grid-template-areas:"outline""content";gap:2rem}.b3-toc{max-block-size:none;position:static}}.b3-command{inline-size:min(38rem,100% - 2rem);padding:0}.b3-command-search{border-block-end:1px solid var(--b3-color-border);align-items:center;gap:.75rem;padding:1rem;display:flex}.b3-command-search>input{flex:1;min-inline-size:0}.b3-command-list{overscroll-behavior:contain;max-block-size:50svh;padding:.5rem;overflow-y:auto}.b3-command-group+.b3-command-group{border-block-start:1px solid var(--b3-color-border);margin-block-start:.5rem;padding-block-start:.5rem}.b3-command-group>:first-child:not([role=option]){color:var(--b3-color-muted);padding:.5rem .75rem;font-size:.75rem;display:block}.b3-command-item{border-radius:var(--b3-radius-small);cursor:pointer;justify-content:space-between;align-items:center;gap:1rem;min-block-size:2.75rem;padding:.875rem .75rem;display:flex}.b3-command-item>:first-child{overflow-wrap:anywhere;min-inline-size:0}.b3-command-item[aria-selected=true]{background:var(--b3-color-accent);color:var(--b3-color-on-accent)}.b3-command-item[aria-selected=true] .b3-muted{color:inherit}.b3-command-item[aria-disabled=true]{opacity:.5;cursor:not-allowed}.b3-command-item:not([aria-disabled=true]):hover{outline:1px solid var(--b3-color-border);outline-offset:-1px}.b3-form-grid{grid-template-columns:repeat(auto-fit,minmax(min(100%,14rem),1fr));align-items:start;gap:1.25rem;display:grid}.b3-fieldset{border:0;min-inline-size:0;margin:0;padding:0}.b3-fieldset>legend{padding:0 0 .75rem;font-weight:650}.b3-help{color:var(--b3-color-muted);font-size:.875rem}.b3-help[data-b3-tone=success]{color:var(--b3-color-success)}.b3-help[data-b3-tone=warning]{color:var(--b3-color-warning)}.b3-input[data-b3-size=small]{padding:.5rem .75rem}.b3-input[data-b3-size=large]{min-block-size:3.25rem;padding:.875rem 1rem}.b3-input[data-b3-emphasis=subtle]{background-color:var(--b3-color-canvas);border-color:#0000}.b3-input[data-b3-emphasis=outline]{background-color:#0000;border-width:2px}.b3-input[data-b3-tone=success]{border-color:var(--b3-color-success)}.b3-input[data-b3-tone=warning]{border-color:var(--b3-color-warning)}.b3-input[aria-invalid=true]{border-color:var(--b3-color-danger)}textarea.b3-input{resize:vertical}select.b3-input[multiple]{min-block-size:8rem}.b3-input[type=file]{padding:.375rem}.b3-input::file-selector-button{font:inherit;border-radius:var(--b3-radius-small);background:var(--b3-color-accent);color:var(--b3-color-on-accent);cursor:pointer;border:0;margin-inline-end:.75rem;padding:.5rem .75rem}.b3-input[type=color]{inline-size:5rem;padding:.25rem}.b3-range{min-block-size:2.75rem;inline-size:100%;accent-color:var(--b3-color-accent);margin:0}.b3-choice-card{border:1px solid var(--b3-color-border);border-radius:var(--b3-radius);background:var(--b3-color-surface);color:var(--b3-color-text);cursor:pointer;align-items:start;gap:.75rem;padding:1rem;display:flex}.b3-choice-card>input{flex:none;block-size:1.125rem;inline-size:1.125rem;margin-block-start:.3rem}.b3-choice-card:has(input:checked){border-color:var(--b3-color-accent);background:color-mix(in srgb, var(--b3-color-accent) 7%, var(--b3-color-surface));box-shadow:inset 0 0 0 1px var(--b3-color-accent)}.b3-choice-card:has(input:focus-visible){outline:3px solid var(--b3-color-focus);outline-offset:3px}.b3-choice-card:has(input:disabled){opacity:.5;cursor:not-allowed}.b3-choice-card:has(input[aria-invalid=true]){border-color:var(--b3-color-danger)}.b3-range[aria-invalid=true]{accent-color:var(--b3-color-danger)}.b3-stepper{flex-wrap:wrap;gap:1rem 2rem;margin:0;padding:0;list-style:none;display:flex}.b3-step{color:var(--b3-color-muted);align-items:center;gap:.625rem;font-size:.875rem;display:flex}.b3-step-marker{border:1px solid var(--b3-color-border);font-variant-numeric:tabular-nums;border-radius:50%;flex:none;place-items:center;block-size:2rem;inline-size:2rem;display:grid}.b3-step[aria-current=step]{color:var(--b3-color-text);font-weight:650}.b3-step[aria-current=step] .b3-step-marker{background:var(--b3-color-accent);color:var(--b3-color-on-accent);border-color:var(--b3-color-accent)}.b3-step[data-b3-complete=true] .b3-step-marker{border-color:var(--b3-color-success);color:var(--b3-color-success)}.b3-conversation{gap:1.5rem;min-inline-size:0;margin:0;padding:0;list-style:none;display:grid}.b3-message{justify-self:start;gap:.375rem;min-inline-size:0;max-inline-size:min(85%,38rem);display:grid}.b3-message[data-b3-side=self]{justify-self:end}.b3-message-body{border:1px solid var(--b3-color-border);border-radius:var(--b3-radius);background:var(--b3-color-surface);color:var(--b3-color-text);white-space:pre-wrap;overflow-wrap:anywhere;padding:.875rem 1rem}.b3-message[data-b3-side=self]>.b3-message-body{background:var(--b3-color-accent);color:var(--b3-color-on-accent);border-color:#0000}.b3-message-meta{color:var(--b3-color-muted);flex-wrap:wrap;gap:.35rem .75rem;font-size:.8125rem;display:flex}.b3-message[data-b3-side=self]>.b3-message-meta{justify-content:end}.b3-mobile-app{--b3-touch:44px;min-block-size:100svh;max-inline-size:var(--b3-app-width,70rem);margin-inline:auto;padding-block-end:calc(5.5rem + env(safe-area-inset-bottom,0px))}.b3-mobile-app[data-b3-platform=android]{--b3-touch:48px}.b3-mobile-app :where(button,.b3-button,select,input:not([type=checkbox],[type=radio])){min-block-size:var(--b3-touch)}.b3-app-bar{padding:max(.75rem, env(safe-area-inset-top,0px)) 1.25rem .75rem;align-items:center;gap:.75rem;display:flex}.b3-app-bar>:last-child{margin-inline-start:auto}.b3-bottom-nav{z-index:10;max-inline-size:var(--b3-app-width,70rem);padding:.5rem 1rem max(.5rem, env(safe-area-inset-bottom,0px));background:var(--b3-color-surface);color:var(--b3-color-text);border-block-start:1px solid var(--b3-color-border);justify-content:space-around;gap:.5rem;margin-inline:auto;display:flex;position:fixed;inset-block-end:0;inset-inline:0}.b3-bottom-link{min-block-size:var(--b3-touch,44px);min-inline-size:0;color:var(--b3-color-muted);border-radius:1rem;flex-direction:column;flex:1;justify-content:center;align-items:center;gap:.15rem;padding:.25rem .5rem;font-size:.75rem;text-decoration:none;display:flex}.b3-bottom-link[aria-current=page]{color:var(--b3-color-accent);font-weight:700}[data-b3-platform=android] .b3-bottom-link[aria-current=page]{background:var(--b3-color-canvas)}.b3-mobile-list{border:1px solid var(--b3-color-border);background:var(--b3-color-surface);border-radius:1rem;margin:0;padding:0;list-style:none;overflow:hidden}.b3-mobile-list>li+li{border-block-start:1px solid var(--b3-color-border)}.b3-mobile-row{min-block-size:var(--b3-touch,44px);color:var(--b3-color-text);align-items:center;gap:1rem;padding:.875rem 1rem;text-decoration:none;display:flex}.b3-mobile-row>:last-child:not(:first-child){margin-inline-start:auto}.b3-sheet{inline-size:min(100%, var(--b3-overlay-width,32rem));max-inline-size:none;max-block-size:min(85dvh, calc(100dvh - env(safe-area-inset-top,0px) - 1rem));overscroll-behavior:contain;border:1px solid var(--b3-color-border);padding:1.5rem 1.5rem max(1.5rem, env(safe-area-inset-bottom,0px));background:var(--b3-color-surface);color:var(--b3-color-text);border-radius:1.5rem 1.5rem 0 0;margin:0 auto;inset:auto 0 0;overflow-y:auto}.b3-sheet::backdrop{background:#0007}.b3-sheet [data-b3-initial-focus]:focus{outline:none}.b3-sheet-handle{min-block-size:44px;inline-size:5rem;color:var(--b3-color-muted);touch-action:none;cursor:grab;background:0 0;border:0;border-radius:1rem;flex:none;align-self:center;place-items:center;margin-block:-1rem -.5rem;padding:0;display:grid}.b3-sheet-handle:before{content:"";background:currentColor;border-radius:1rem;block-size:.25rem;inline-size:2.25rem}.b3-sheet[data-b3-dragging]{animation:none}.b3-sheet[data-b3-dragging] .b3-sheet-handle{cursor:grabbing}[data-b3-platform=android] .b3-mobile-list{border-radius:1.5rem}@media (prefers-reduced-motion:no-preference){.b3-sheet[open]{animation:.32s cubic-bezier(.16,1,.3,1) b3-sheet-enter}@keyframes b3-sheet-enter{0%{opacity:0;transform:translateY(3rem)}to{opacity:1;transform:translateY(0)}}}.b3-root:has(dialog:modal){overflow:hidden}.b3-app-frame{block-size:var(--b3-frame-height,100dvh);min-block-size:0;max-inline-size:var(--b3-app-width,70rem);padding:env(safe-area-inset-top,0px) env(safe-area-inset-right,0px) env(safe-area-inset-bottom,0px) env(safe-area-inset-left,0px);grid-template-rows:auto minmax(0,1fr) auto;margin-inline:auto;display:grid;overflow:clip}.b3-app-frame>header{grid-row:1;min-inline-size:0}.b3-app-frame>main{overscroll-behavior:contain;grid-row:2;min-block-size:0;min-inline-size:0;overflow:auto}.b3-app-frame>:is(nav,footer){grid-row:3;min-inline-size:0;position:relative}.b3-app-frame>.b3-app-bar{padding-block-start:.75rem}.b3-app-frame .b3-bottom-nav{inline-size:100%;max-inline-size:none;padding-block-end:.5rem;position:static}}
|
|
@@ -0,0 +1,457 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": "0.1.0-alpha.10",
|
|
3
|
+
"cssSha256": "bf8e395a9479687a5244197fbed8f69667b845976251c467ce7bb6eb294d25ab",
|
|
4
|
+
"classes": [
|
|
5
|
+
"b3-accordion",
|
|
6
|
+
"b3-alert",
|
|
7
|
+
"b3-app-bar",
|
|
8
|
+
"b3-app-frame",
|
|
9
|
+
"b3-app-layout",
|
|
10
|
+
"b3-art",
|
|
11
|
+
"b3-avatar",
|
|
12
|
+
"b3-avatar-stack",
|
|
13
|
+
"b3-badge",
|
|
14
|
+
"b3-bottom-link",
|
|
15
|
+
"b3-bottom-nav",
|
|
16
|
+
"b3-breadcrumbs",
|
|
17
|
+
"b3-button",
|
|
18
|
+
"b3-card-footer",
|
|
19
|
+
"b3-card-header",
|
|
20
|
+
"b3-center",
|
|
21
|
+
"b3-checklist",
|
|
22
|
+
"b3-choice",
|
|
23
|
+
"b3-choice-card",
|
|
24
|
+
"b3-cluster",
|
|
25
|
+
"b3-command",
|
|
26
|
+
"b3-command-group",
|
|
27
|
+
"b3-command-item",
|
|
28
|
+
"b3-command-list",
|
|
29
|
+
"b3-command-search",
|
|
30
|
+
"b3-conversation",
|
|
31
|
+
"b3-cover",
|
|
32
|
+
"b3-definition",
|
|
33
|
+
"b3-dialog",
|
|
34
|
+
"b3-divider",
|
|
35
|
+
"b3-dropdown",
|
|
36
|
+
"b3-dropdown-panel",
|
|
37
|
+
"b3-error",
|
|
38
|
+
"b3-feature",
|
|
39
|
+
"b3-feature-icon",
|
|
40
|
+
"b3-field",
|
|
41
|
+
"b3-fieldset",
|
|
42
|
+
"b3-form-grid",
|
|
43
|
+
"b3-grid",
|
|
44
|
+
"b3-heading",
|
|
45
|
+
"b3-help",
|
|
46
|
+
"b3-hero",
|
|
47
|
+
"b3-hero-copy",
|
|
48
|
+
"b3-icon",
|
|
49
|
+
"b3-inline",
|
|
50
|
+
"b3-input",
|
|
51
|
+
"b3-input-affix",
|
|
52
|
+
"b3-input-group",
|
|
53
|
+
"b3-kbd",
|
|
54
|
+
"b3-label",
|
|
55
|
+
"b3-message",
|
|
56
|
+
"b3-message-body",
|
|
57
|
+
"b3-message-meta",
|
|
58
|
+
"b3-mobile-app",
|
|
59
|
+
"b3-mobile-list",
|
|
60
|
+
"b3-mobile-row",
|
|
61
|
+
"b3-muted",
|
|
62
|
+
"b3-nav",
|
|
63
|
+
"b3-nav-link",
|
|
64
|
+
"b3-page",
|
|
65
|
+
"b3-page-body",
|
|
66
|
+
"b3-price",
|
|
67
|
+
"b3-pricing",
|
|
68
|
+
"b3-progress",
|
|
69
|
+
"b3-prose",
|
|
70
|
+
"b3-quote",
|
|
71
|
+
"b3-range",
|
|
72
|
+
"b3-reading",
|
|
73
|
+
"b3-reel",
|
|
74
|
+
"b3-root",
|
|
75
|
+
"b3-row",
|
|
76
|
+
"b3-scroll",
|
|
77
|
+
"b3-sheet",
|
|
78
|
+
"b3-sheet-handle",
|
|
79
|
+
"b3-shell",
|
|
80
|
+
"b3-sidebar",
|
|
81
|
+
"b3-skeleton",
|
|
82
|
+
"b3-skip-link",
|
|
83
|
+
"b3-spinner",
|
|
84
|
+
"b3-split",
|
|
85
|
+
"b3-stack",
|
|
86
|
+
"b3-stat",
|
|
87
|
+
"b3-stat-value",
|
|
88
|
+
"b3-step",
|
|
89
|
+
"b3-step-marker",
|
|
90
|
+
"b3-stepper",
|
|
91
|
+
"b3-surface",
|
|
92
|
+
"b3-switch",
|
|
93
|
+
"b3-tab",
|
|
94
|
+
"b3-table",
|
|
95
|
+
"b3-table-wrap",
|
|
96
|
+
"b3-tablist",
|
|
97
|
+
"b3-tabpanel",
|
|
98
|
+
"b3-title",
|
|
99
|
+
"b3-toast",
|
|
100
|
+
"b3-toast-region",
|
|
101
|
+
"b3-toc",
|
|
102
|
+
"b3-toc-link",
|
|
103
|
+
"b3-tree",
|
|
104
|
+
"b3-visually-hidden"
|
|
105
|
+
],
|
|
106
|
+
"contracts": [
|
|
107
|
+
{
|
|
108
|
+
"id": "foundation",
|
|
109
|
+
"title": "Root and theme",
|
|
110
|
+
"classes": [
|
|
111
|
+
"b3-root"
|
|
112
|
+
],
|
|
113
|
+
"guidance": "Place b3-root on html to synchronize the document canvas and native controls. Set data-b3-theme=\"dark\" explicitly for dark mode. Nested roots reset tokens; set their theme explicitly. Override complete CSS values in --b3-* properties. Consumer CSS is unlayered and wins over library defaults. Scope custom palette overrides to each theme: unlayered :root token overrides beat layered library dark defaults. Use .b3-root:not([data-b3-theme=\"dark\"]) for light-only colors and .b3-root[data-b3-theme=\"dark\"] for dark overrides. Set foreground/background pairs together.",
|
|
114
|
+
"example": "<html class=\"b3-root\" data-b3-theme=\"dark\">"
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
"id": "layout",
|
|
118
|
+
"title": "Composition",
|
|
119
|
+
"classes": [
|
|
120
|
+
"b3-shell",
|
|
121
|
+
"b3-stack",
|
|
122
|
+
"b3-cluster",
|
|
123
|
+
"b3-grid",
|
|
124
|
+
"b3-split",
|
|
125
|
+
"b3-scroll",
|
|
126
|
+
"b3-inline"
|
|
127
|
+
],
|
|
128
|
+
"guidance": "Shell bounds the page. Stack is vertical, cluster wraps horizontal peers, grid fits columns, split separates two groups. Override --b3-space locally. Preserve meaningful DOM order. Default to phone and desktop support. Use intrinsic peer columns and wrapping before media queries; bound reading/forms separately from the page. Set --b3-content for shell width. Read cross-screen.md for composition choices and targeted verification. In a bounded b3-stack, b3-scroll makes one body independently scrollable while sibling heading/actions stay in flow. Supply a meaningful height or max-height; scrolling cannot occur without a bound. Name a keyboard-focusable scroll region with tabindex=0 and aria-labelledby. Reuse the same atom in panels, dialogs and sheets. Inline keeps a small icon/text or label/badge group together, vertically centers peers and lets the text itself wrap. Use cluster for independently wrapping peers; use inline when wrapping the icon away from its label would break the meaning. Set --b3-grid-min to the minimum useful peer width (e.g. 8rem for concise metrics); the same grid then fits columns without per-screen column counts.",
|
|
129
|
+
"example": "<main class=\"b3-shell b3-stack\"><header class=\"b3-split\">…</header></main>"
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
"id": "type",
|
|
133
|
+
"title": "Hierarchy",
|
|
134
|
+
"classes": [
|
|
135
|
+
"b3-title",
|
|
136
|
+
"b3-heading",
|
|
137
|
+
"b3-muted",
|
|
138
|
+
"b3-label"
|
|
139
|
+
],
|
|
140
|
+
"guidance": "Use a single visual title and native heading hierarchy. Muted is secondary readable text. Label styling is optional and does not create a form label. Use b3-heading for dialog and sheet headings; b3-title is page-scale and should not be nested in a narrow overlay.",
|
|
141
|
+
"example": "<h1 class=\"b3-title\">Today, intentionally.</h1>"
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
"id": "surface",
|
|
145
|
+
"title": "Surface",
|
|
146
|
+
"classes": [
|
|
147
|
+
"b3-surface"
|
|
148
|
+
],
|
|
149
|
+
"guidance": "Use surfaces to group meaningful content, not around every row. Use dividers or whitespace when a panel would add noise.",
|
|
150
|
+
"example": "<section class=\"b3-surface\" aria-labelledby=\"heading\"><h2 id=\"heading\">History</h2></section>"
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
"id": "button",
|
|
154
|
+
"title": "Action",
|
|
155
|
+
"classes": [
|
|
156
|
+
"b3-button"
|
|
157
|
+
],
|
|
158
|
+
"guidance": "Use native button for actions, anchor for navigation. data-b3-emphasis=\"quiet\" is a secondary action. Native disabled prevents activation. App owns click behavior. Icon-only actions need an accessible name. Emphasis: primary (default), quiet, outline, danger. Sizes small/default/large retain touch-height floors. aria-busy conveys loading but does not disable clicks; set disabled while duplicate submission must be prevented.",
|
|
159
|
+
"example": "<button class=\"b3-button\" type=\"submit\">Save entry</button>"
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
"id": "field",
|
|
163
|
+
"title": "Input and error",
|
|
164
|
+
"classes": [
|
|
165
|
+
"b3-field",
|
|
166
|
+
"b3-input",
|
|
167
|
+
"b3-error"
|
|
168
|
+
],
|
|
169
|
+
"guidance": "Associate label for/id. Use aria-invalid and aria-describedby for errors; explain a fix. Never depend on color alone. App owns validation. Native input/select/textarea behavior is retained. Single selects reserve an inline-end indicator lane that mirrors in RTL; multiple/listbox selects keep native presentation. Forced-colors mode restores the native indicator.",
|
|
170
|
+
"example": "<div class=\"b3-field\"><label for=\"name\">Name</label><input id=\"name\" class=\"b3-input\" aria-invalid=\"true\" aria-describedby=\"error\"><p id=\"error\" class=\"b3-error\">Enter a name.</p></div>"
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
"id": "row",
|
|
174
|
+
"title": "List row",
|
|
175
|
+
"classes": [
|
|
176
|
+
"b3-row"
|
|
177
|
+
],
|
|
178
|
+
"guidance": "Use li inside ul or ol when listing items. The row owns only spacing and a divider; app owns completion, selection, and ordering. Long content should wrap.",
|
|
179
|
+
"example": "<ul><li class=\"b3-row\">Read ten pages</li></ul>"
|
|
180
|
+
},
|
|
181
|
+
{
|
|
182
|
+
"id": "status",
|
|
183
|
+
"title": "Status and progress",
|
|
184
|
+
"classes": [
|
|
185
|
+
"b3-badge",
|
|
186
|
+
"b3-progress"
|
|
187
|
+
],
|
|
188
|
+
"guidance": "Badges need meaningful text. Use native progress with max/value and accessible label. Announce meaningful task changes via a separate status region; do not announce every timer tick. Badge supports data-b3-tone=success/warning/danger/info. Text must convey the status independently of color.",
|
|
189
|
+
"example": "<progress class=\"b3-progress\" aria-label=\"Daily goal\" max=\"8\" value=\"3\"></progress>"
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
"id": "page-layout",
|
|
193
|
+
"title": "Page composition",
|
|
194
|
+
"classes": [
|
|
195
|
+
"b3-page",
|
|
196
|
+
"b3-page-body",
|
|
197
|
+
"b3-app-layout",
|
|
198
|
+
"b3-sidebar",
|
|
199
|
+
"b3-center",
|
|
200
|
+
"b3-cover",
|
|
201
|
+
"b3-reel"
|
|
202
|
+
],
|
|
203
|
+
"guidance": "Page/body form a full-height document. App-layout supplies a sidebar and content region, stacking below 48rem. Center aligns its children. Cover gives a hero room; reel provides intentional horizontal scrolling. Preserve document order and label scrollable collections.",
|
|
204
|
+
"example": "<div class=\"b3-app-layout\"><aside class=\"b3-sidebar\">Navigation</aside><main class=\"b3-page\"><header>Page heading</header><div class=\"b3-page-body b3-shell\">Content</div><footer>Footer</footer></main></div>"
|
|
205
|
+
},
|
|
206
|
+
{
|
|
207
|
+
"id": "control-structure",
|
|
208
|
+
"title": "Form composition",
|
|
209
|
+
"classes": [
|
|
210
|
+
"b3-input-group",
|
|
211
|
+
"b3-input-affix",
|
|
212
|
+
"b3-choice",
|
|
213
|
+
"b3-switch"
|
|
214
|
+
],
|
|
215
|
+
"guidance": "Input groups combine an affix and native input without removing its label. Choice is a native checkbox/radio label layout. Switch must be input type=checkbox with an associated label; checked/disabled remain native. Enabled switches require a distinct track and thumb in both states and themes (at least 3:1 thumb-to-track and track-to-surrounding contrast for the default solid treatment). The off track uses muted, not the subtle border token. Never invent div controls. Choice aligns the control with the first label line, including labels with helper text, and removes native input margins.",
|
|
216
|
+
"example": "<label for=\"budget\">Budget in USD</label><div class=\"b3-input-group\"><span class=\"b3-input-affix\" aria-hidden=\"true\">$</span><input class=\"b3-input\" id=\"budget\" type=\"number\"></div><label class=\"b3-choice\"><input class=\"b3-switch\" type=\"checkbox\" checked><span>Email updates</span></label>"
|
|
217
|
+
},
|
|
218
|
+
{
|
|
219
|
+
"id": "card-structure",
|
|
220
|
+
"title": "Card anatomy",
|
|
221
|
+
"classes": [
|
|
222
|
+
"b3-card-header",
|
|
223
|
+
"b3-card-footer",
|
|
224
|
+
"b3-divider"
|
|
225
|
+
],
|
|
226
|
+
"guidance": "Optional surface slots separate heading/actions and footer. data-b3-elevation=raised adds a shadow. Divider uses hr. A card is not required around every block.",
|
|
227
|
+
"example": "<article class=\"b3-surface\" data-b3-elevation=\"raised\"><header class=\"b3-card-header\"><h2 class=\"b3-heading\">Project</h2></header><p>Project details</p><footer class=\"b3-card-footer\"><button class=\"b3-button\">Open project</button></footer></article>"
|
|
228
|
+
},
|
|
229
|
+
{
|
|
230
|
+
"id": "feedback",
|
|
231
|
+
"title": "Alerts, toast and loading",
|
|
232
|
+
"classes": [
|
|
233
|
+
"b3-alert",
|
|
234
|
+
"b3-toast-region",
|
|
235
|
+
"b3-toast",
|
|
236
|
+
"b3-spinner",
|
|
237
|
+
"b3-skeleton"
|
|
238
|
+
],
|
|
239
|
+
"guidance": "Alert data-b3-tone supports info, success, warning, danger. Include explanatory text; icons/color alone are insufficient. Add role=alert only for urgent dynamic messages. Toast region uses aria-live=polite and toast dismissal data-b3-dismiss with mount(). No automatic timers are imposed. Spinner/skeleton need a separate accessible loading description; decorative shapes use aria-hidden. Reduced motion uses root defaults.",
|
|
240
|
+
"example": "<div class=\"b3-alert\" data-b3-tone=\"warning\"><div><strong>Check your input</strong><p>Enter a valid email address.</p></div></div><div class=\"b3-toast-region\" aria-live=\"polite\"><div class=\"b3-toast\"><p>Changes saved.</p><button class=\"b3-button\" data-b3-dismiss>Dismiss</button></div></div>"
|
|
241
|
+
},
|
|
242
|
+
{
|
|
243
|
+
"id": "identity",
|
|
244
|
+
"title": "Avatars and icons",
|
|
245
|
+
"classes": [
|
|
246
|
+
"b3-icon",
|
|
247
|
+
"b3-avatar",
|
|
248
|
+
"b3-avatar-stack",
|
|
249
|
+
"b3-kbd"
|
|
250
|
+
],
|
|
251
|
+
"guidance": "Icon styles an inline SVG. Label icon-only actions; decorative icons use aria-hidden. Avatar renders initials or an image with meaningful alt text, not both spoken twice. Avatar-stack overlaps peers. kbd represents a real keyboard shortcut, not a working binding.",
|
|
252
|
+
"example": "<span class=\"b3-avatar\" aria-label=\"Alex Lee\">AL</span><kbd class=\"b3-kbd\">Enter</kbd><svg class=\"b3-icon\" aria-hidden=\"true\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"><path d=\"M5 12h14M12 5v14\"/></svg>"
|
|
253
|
+
},
|
|
254
|
+
{
|
|
255
|
+
"id": "data-display",
|
|
256
|
+
"title": "Tables, definitions and metrics",
|
|
257
|
+
"classes": [
|
|
258
|
+
"b3-table-wrap",
|
|
259
|
+
"b3-table",
|
|
260
|
+
"b3-definition",
|
|
261
|
+
"b3-stat",
|
|
262
|
+
"b3-stat-value"
|
|
263
|
+
],
|
|
264
|
+
"guidance": "Table-wrap provides intentional horizontal scroll. Use native table/caption/th scopes; data-b3-density=compact changes spacing. aria-selected is visual only: app owns selection and sorting. Definition uses dl/dt/dd. Stat groups label, value and explanation; format numbers in the app.",
|
|
265
|
+
"example": "<div class=\"b3-table-wrap\"><table class=\"b3-table\"><caption>Invoices</caption><thead><tr><th scope=\"col\">Client</th><th scope=\"col\">Amount</th></tr></thead><tbody><tr><td>Studio North</td><td>$4800</td></tr></tbody></table></div><dl class=\"b3-definition\"><dt>Status</dt><dd>Active</dd></dl>"
|
|
266
|
+
},
|
|
267
|
+
{
|
|
268
|
+
"id": "navigation",
|
|
269
|
+
"title": "Navigation and breadcrumbs",
|
|
270
|
+
"classes": [
|
|
271
|
+
"b3-nav",
|
|
272
|
+
"b3-nav-link",
|
|
273
|
+
"b3-breadcrumbs"
|
|
274
|
+
],
|
|
275
|
+
"guidance": "Use nav with accessible label; aria-current=page marks the active link. data-b3-orientation=vertical creates sidebar navigation. Breadcrumbs is an ol within labeled nav. Native links own navigation; no hidden routing system.",
|
|
276
|
+
"example": "<nav class=\"b3-nav\" aria-label=\"Main\"><a class=\"b3-nav-link\" href=\"/\" aria-current=\"page\">Overview</a><a class=\"b3-nav-link\" href=\"/projects\">Projects</a></nav>"
|
|
277
|
+
},
|
|
278
|
+
{
|
|
279
|
+
"id": "tabs",
|
|
280
|
+
"title": "Tabbed views",
|
|
281
|
+
"classes": [
|
|
282
|
+
"b3-tablist",
|
|
283
|
+
"b3-tab",
|
|
284
|
+
"b3-tabpanel"
|
|
285
|
+
],
|
|
286
|
+
"guidance": "Optional mount() wires [role=tablist][data-b3-tabs]. Use native buttons with role=tab, unique id, aria-controls, aria-selected and matching role=tabpanel with aria-labelledby. Inactive panels start hidden. Arrow keys, Home/End and RTL direction select and focus tabs; disabled tabs are skipped. Native Tab exits the tablist.",
|
|
287
|
+
"example": "<div class=\"b3-tablist\" role=\"tablist\" aria-label=\"Project\" data-b3-tabs><button class=\"b3-tab\" id=\"tab-a\" role=\"tab\" aria-controls=\"panel-a\" aria-selected=\"true\">Summary</button><button class=\"b3-tab\" id=\"tab-b\" role=\"tab\" aria-controls=\"panel-b\" aria-selected=\"false\" tabindex=\"-1\">Activity</button></div><section class=\"b3-tabpanel\" id=\"panel-a\" role=\"tabpanel\" aria-labelledby=\"tab-a\">Summary content</section><section class=\"b3-tabpanel\" id=\"panel-b\" role=\"tabpanel\" aria-labelledby=\"tab-b\" hidden>Activity content</section>"
|
|
288
|
+
},
|
|
289
|
+
{
|
|
290
|
+
"id": "disclosure",
|
|
291
|
+
"title": "Accordion, dropdown and hierarchy",
|
|
292
|
+
"classes": [
|
|
293
|
+
"b3-accordion",
|
|
294
|
+
"b3-dropdown",
|
|
295
|
+
"b3-dropdown-panel",
|
|
296
|
+
"b3-tree"
|
|
297
|
+
],
|
|
298
|
+
"guidance": "Accordion and dropdown use native details/summary. Dropdown is a disclosure containing ordinary links/buttons, not an ARIA menu. mount() adds outside-click and Escape dismissal. Tree is a nested list/details presentation, not a role=tree widget. Browser disclosure behavior supplies keyboard activation.",
|
|
299
|
+
"example": "<details class=\"b3-accordion\"><summary>More information</summary><p>Useful details.</p></details><details class=\"b3-dropdown\"><summary class=\"b3-button\">Actions</summary><div class=\"b3-dropdown-panel\"><a class=\"b3-nav-link\" href=\"#details\">View details</a></div></details>"
|
|
300
|
+
},
|
|
301
|
+
{
|
|
302
|
+
"id": "dialog",
|
|
303
|
+
"title": "Dialog and drawer",
|
|
304
|
+
"classes": [
|
|
305
|
+
"b3-dialog"
|
|
306
|
+
],
|
|
307
|
+
"guidance": "Use native dialog with aria-labelledby and explicit close button. mount() wires data-b3-open=dialog-id and data-b3-close. showModal() owns focus containment, Escape dismissal and return focus. data-b3-placement=end presents a drawer with the same native modal behavior. App owns submission and unsaved-change decisions. Set data-b3-backdrop=dismiss on read-only details, navigation drawers and reversible pickers. Forms default to no backdrop dismissal; preserve drafts or guard the cancel event when work could be lost. Backdrop dismissal requires a pointer press and release outside the panel, so dragging from inside does not close it. Backdrop and data-b3-close dispatch cancel before closing; preventDefault keeps the dialog open, matching native Escape. Never use outside dismissal as confirmation of a destructive action.",
|
|
308
|
+
"example": "<button class=\"b3-button\" data-b3-open=\"confirm\">Open dialog</button><dialog class=\"b3-dialog\" id=\"confirm\" aria-labelledby=\"confirm-title\"><h2 id=\"confirm-title\">Confirm changes</h2><p>Review before continuing.</p><button class=\"b3-button\" data-b3-close>Close</button></dialog>"
|
|
309
|
+
},
|
|
310
|
+
{
|
|
311
|
+
"id": "content",
|
|
312
|
+
"title": "Long-form content and accessibility",
|
|
313
|
+
"classes": [
|
|
314
|
+
"b3-prose",
|
|
315
|
+
"b3-visually-hidden",
|
|
316
|
+
"b3-skip-link"
|
|
317
|
+
],
|
|
318
|
+
"guidance": "Prose scopes readable article flow and supports headings, lists, quotes and code. Visually-hidden keeps accessible text available to assistive technology. Do not use it to conceal focusable controls. Native hidden hides inactive component states. Put a b3-skip-link anchor first in the body, targeting the main landmark ID. The destination needs tabindex=-1 for reliable native focus transfer. The link is visually clipped until focused, then fixed above the page. Do not apply permanently visually-hidden styling to focusable controls.",
|
|
319
|
+
"example": "<article class=\"b3-prose\"><h2>A useful heading</h2><p>Readable long-form content.</p><blockquote>A supporting observation.</blockquote></article><button class=\"b3-button\"><span aria-hidden=\"true\">+</span><span class=\"b3-visually-hidden\">Add item</span></button><a class=\"b3-skip-link\" href=\"#main-content\">Skip to content</a><main id=\"main-content\" tabindex=\"-1\">Content</main>"
|
|
320
|
+
},
|
|
321
|
+
{
|
|
322
|
+
"id": "marketing",
|
|
323
|
+
"title": "Product-page composition",
|
|
324
|
+
"classes": [
|
|
325
|
+
"b3-hero",
|
|
326
|
+
"b3-hero-copy",
|
|
327
|
+
"b3-feature",
|
|
328
|
+
"b3-feature-icon",
|
|
329
|
+
"b3-pricing",
|
|
330
|
+
"b3-price",
|
|
331
|
+
"b3-checklist",
|
|
332
|
+
"b3-quote",
|
|
333
|
+
"b3-art"
|
|
334
|
+
],
|
|
335
|
+
"guidance": "Hero and feature compose copy beside a visual; both stack below 48rem. Hero data-b3-align=center is a single centered column. Feature data-b3-reverse=true reverses visual order only on wide screens; keep reading order logical. Pricing featured state uses data-b3-featured=true. Price changes, billing period and selection belong to the app. Checklist marks are decorative; write meaningful list text. Quote uses figure/blockquote/figcaption with truthful attribution. Art data-b3-art=dots/glow/wash is static decoration behind content, adapts to theme roles and must not replace readable surfaces. Do not invent testimonials, payment success or integrations.",
|
|
336
|
+
"example": "<section class=\"b3-hero\"><div class=\"b3-hero-copy\"><h1 class=\"b3-title\">Make room for good work.</h1><p>A clear product promise.</p><a class=\"b3-button\" href=\"#pricing\">Explore plans</a></div><div class=\"b3-art\" data-b3-art=\"dots\">Product preview</div></section>"
|
|
337
|
+
},
|
|
338
|
+
{
|
|
339
|
+
"id": "reading",
|
|
340
|
+
"title": "Reading layout and document outline",
|
|
341
|
+
"classes": [
|
|
342
|
+
"b3-reading",
|
|
343
|
+
"b3-toc",
|
|
344
|
+
"b3-toc-link"
|
|
345
|
+
],
|
|
346
|
+
"guidance": "Reading contains exactly one article and one nav.b3-toc with an accessible label. Author ordinary #id links and unique heading IDs; nested ordered lists express heading levels. Set heading tabindex=-1 for native fragment focus and scroll-margin-block-start for any fixed header. Optional mount() tracks [data-b3-toc] links with aria-current=location from window scroll; it does not generate IDs, rewrite links, relocate content or manage routing. The outline is sticky beside the article above 48rem and precedes it below. --b3-outline-top controls sticky offset. This first version tracks window scrolling, not nested scroll containers. Dynamic heading/link changes require cleanup and remount.",
|
|
347
|
+
"example": "<div class=\"b3-reading\"><nav class=\"b3-toc\" data-b3-toc aria-label=\"On this page\"><ol><li><a class=\"b3-toc-link\" href=\"#purpose\">Purpose</a></li></ol></nav><article class=\"b3-prose\"><h2 id=\"purpose\" tabindex=\"-1\">Purpose</h2><p>A readable guide.</p></article></div>"
|
|
348
|
+
},
|
|
349
|
+
{
|
|
350
|
+
"id": "command",
|
|
351
|
+
"title": "Command palette",
|
|
352
|
+
"classes": [
|
|
353
|
+
"b3-command",
|
|
354
|
+
"b3-command-search",
|
|
355
|
+
"b3-command-list",
|
|
356
|
+
"b3-command-group",
|
|
357
|
+
"b3-command-item"
|
|
358
|
+
],
|
|
359
|
+
"guidance": "Use native dialog.b3-dialog.b3-command[data-b3-command], a labelled autofocus input with role=combobox, aria-autocomplete=list, aria-haspopup=listbox, aria-controls=list-id and aria-expanded=false. Listbox options need unique IDs, aria-selected=false and data-b3-value; optional data-b3-keywords adds synonyms. Never nest interactive elements inside options. Label role=group containers with aria-labelledby. mount() filters text, skips aria-disabled=true, retains input focus with aria-activedescendant, supports arrows/Enter and native Escape, and emits cancelable bubbling b3:command with detail.value and detail.item. App performs the action; default closes the dialog, preventDefault keeps it open. App owns shortcut registration and destination focus when navigating. data-b3-command-empty and data-b3-command-status provide empty/count feedback. Search resets on opening. Home/End and editing shortcuts retain browser behavior. Native dialog open-state observation resets the search and is disconnected on cleanup. Browser/device coverage remains to be qualified.",
|
|
360
|
+
"example": "<button class=\"b3-button\" data-b3-open=\"commands\">Find an action</button><dialog class=\"b3-dialog b3-command\" id=\"commands\" data-b3-command aria-label=\"Commands\"><div class=\"b3-command-search\"><input class=\"b3-input\" aria-label=\"Search commands\" role=\"combobox\" aria-autocomplete=\"list\" aria-haspopup=\"listbox\" aria-expanded=\"false\" aria-controls=\"actions\" autofocus><button class=\"b3-button\" data-b3-close>Close</button></div><div class=\"b3-command-list\" role=\"listbox\" id=\"actions\" aria-label=\"Actions\"><div class=\"b3-command-item\" role=\"option\" id=\"action-theme\" aria-selected=\"false\" data-b3-value=\"theme\">Switch appearance</div></div><p data-b3-command-empty hidden>No matching actions.</p><p data-b3-command-status role=\"status\"></p></dialog>"
|
|
361
|
+
},
|
|
362
|
+
{
|
|
363
|
+
"id": "form-composition",
|
|
364
|
+
"title": "Native form composition and input variants",
|
|
365
|
+
"classes": [
|
|
366
|
+
"b3-form-grid",
|
|
367
|
+
"b3-fieldset",
|
|
368
|
+
"b3-help",
|
|
369
|
+
"b3-range",
|
|
370
|
+
"b3-choice-card"
|
|
371
|
+
],
|
|
372
|
+
"guidance": "Group related controls with fieldset/legend; use b3-form-grid for responsive rows. Choice cards are labels containing a single native radio or checkbox and descriptive text; checked, focus-visible and disabled appearance follow the input. Use b3-help with aria-describedby; success/warning tones require meaningful text and never imply remote validation. Inputs support data-b3-size=small/large, data-b3-emphasis=subtle/outline and data-b3-tone=success/warning. aria-invalid=true always has error-border priority. b3-range styles the native range control; app owns its output. Native file, date, time, color and multi-select preserve browser behavior. File selection does not upload anything. Keep all controls labelled. For validation, link a focused error summary to each invalid field, preserve help references and user input, and clear errors when corrected. App owns validation/persistence; no hidden form submission handler.",
|
|
373
|
+
"example": "<fieldset class=\"b3-fieldset\"><legend>Workspace type</legend><div class=\"b3-form-grid\"><label class=\"b3-choice-card\"><input type=\"radio\" name=\"kind\" value=\"studio\"><span>Studio</span></label><label class=\"b3-choice-card\"><input type=\"radio\" name=\"kind\" value=\"team\"><span>Team</span></label></div></fieldset><div class=\"b3-field\"><label for=\"seats\">Seats</label><input class=\"b3-range\" id=\"seats\" type=\"range\" min=\"2\" max=\"20\" value=\"5\" aria-describedby=\"seats-help\"><p class=\"b3-help\" id=\"seats-help\">Include the owner.</p></div>"
|
|
374
|
+
},
|
|
375
|
+
{
|
|
376
|
+
"id": "steps",
|
|
377
|
+
"title": "Step progress",
|
|
378
|
+
"classes": [
|
|
379
|
+
"b3-stepper",
|
|
380
|
+
"b3-step",
|
|
381
|
+
"b3-step-marker"
|
|
382
|
+
],
|
|
383
|
+
"guidance": "Use an ordered list with a meaningful accessible label. Exactly one b3-step has aria-current=step while the flow is active. Completed steps use data-b3-complete=true and explicit completed text for assistive technology; markers may be aria-hidden if meaning is repeated in text. This is a progress display, not a tablist. App owns Back/Continue, validation, review, persistence and heading focus after transitions. Do not make future steps look clickable if they cannot be reached. Completed saved state may replace the indicator with a completion heading.",
|
|
384
|
+
"example": "<ol class=\"b3-stepper\" aria-label=\"Setup progress\"><li class=\"b3-step\" aria-current=\"step\"><span class=\"b3-step-marker\" aria-hidden=\"true\">1</span><span>Workspace</span></li><li class=\"b3-step\"><span class=\"b3-step-marker\" aria-hidden=\"true\">2</span><span>People</span></li><li class=\"b3-step\"><span class=\"b3-step-marker\" aria-hidden=\"true\">3</span><span>Review</span></li></ol>"
|
|
385
|
+
},
|
|
386
|
+
{
|
|
387
|
+
"id": "conversation",
|
|
388
|
+
"title": "Conversation messages",
|
|
389
|
+
"classes": [
|
|
390
|
+
"b3-conversation",
|
|
391
|
+
"b3-message",
|
|
392
|
+
"b3-message-body",
|
|
393
|
+
"b3-message-meta"
|
|
394
|
+
],
|
|
395
|
+
"guidance": "Use an ordered list for chronological messages with authored sender labels and time elements. data-b3-side=self mirrors alignment in RTL and uses on-accent text. Message bodies preserve line breaks and wrap long content. App owns delivery state, persistence, safe text rendering, scroll position and focus. Announce newly added messages through a separate concise status region; do not mark the full restored history live. Never imply a reply was delivered remotely when only local storage succeeded. Recording, attachments, streaming and retries are not provided by these presentation classes.",
|
|
396
|
+
"example": "<ol class=\"b3-conversation\" aria-label=\"Messages\"><li class=\"b3-message\" data-b3-side=\"self\"><p class=\"b3-message-body\">Happy to help.</p><div class=\"b3-message-meta\"><span>You</span><time datetime=\"2026-09-08T09:14:00Z\">09:14 UTC</time></div></li></ol>"
|
|
397
|
+
},
|
|
398
|
+
{
|
|
399
|
+
"id": "mobile",
|
|
400
|
+
"title": "Mobile app composition",
|
|
401
|
+
"classes": [
|
|
402
|
+
"b3-mobile-app",
|
|
403
|
+
"b3-app-bar",
|
|
404
|
+
"b3-bottom-nav",
|
|
405
|
+
"b3-bottom-link",
|
|
406
|
+
"b3-mobile-list",
|
|
407
|
+
"b3-mobile-row",
|
|
408
|
+
"b3-sheet",
|
|
409
|
+
"b3-sheet-handle"
|
|
410
|
+
],
|
|
411
|
+
"guidance": "For new apps with persistent navigation, read app-frame.md first: grid owns the navigation height rather than a fixed-padding estimate. Use b3-mobile-app on the app container with data-b3-platform=ios or android. Native anchors carry navigation; app owns URLs/history and aria-current=page. Bottom navigation stays available across primary destinations. Use dialog.b3-sheet with showModal(), a label and explicit cancel; app owns form state and focus restoration. Layout reserves env safe-area insets and targets 44/48 CSS pixels as a starting treatment, not proof of physical platform sizing. Test software keyboard, large text, orientation, real touch and device insets. Never draw fake OS status/gesture bars inside app content. Native runtime and platform fidelity require separate qualification. Default app width supports phone and desktop up to70rem; use intrinsic wrapping grids for content. Set --b3-app-width only for an intentional narrower surface. A platform treatment does not imply a phone-only layout. For a scrollable sheet use dialog.b3-sheet.b3-stack with a direct b3-scroll body and fixed siblings. For optional handle dragging add data-b3-drag=dismiss and button.b3-sheet-handle with data-b3-close and aria-label=\"Close sheet\". mount() handles drag-to-dismiss through the cancel event. Body gestures remain native scrolling. A handle click/keyboard activation also closes. No multiple detents or content-wide drag are implied. The mounted helper gives a labeled sheet heading initial focus unless the app declares an explicit autofocus target; handles remain keyboard reachable. The sheet owns outer padding and the bottom safe area: do not repeat these on its header/body/footer. Keep b3-scroll intrinsic sizing instead of overriding it with flex:1 or a zero flex basis. Sheets fit content up to 85dvh and a 32rem reading width by default; --b3-overlay-width is an explicit width escape hatch for denser content. Use a b3-stack footer for a full-width primary action, and group descriptive row text in a stack rather than competing columns. b3-mobile-app already reserves bottom space for its fixed navigation. Do not add a second matching bottom padding to a child panel. Use b3-app-bar or an explicit comfortable top inset; a safe-area value of zero is not ordinary content spacing.",
|
|
412
|
+
"example": "<div class=\"b3-mobile-app\" data-b3-platform=\"ios\"><header class=\"b3-app-bar\">Today</header><main><ul class=\"b3-mobile-list\"><li><a class=\"b3-mobile-row\" href=\"#detail\">Read a few pages</a></li></ul></main><nav class=\"b3-bottom-nav\" aria-label=\"Main\"><a class=\"b3-bottom-link\" href=\"#today\" aria-current=\"page\">Today</a></nav></div>"
|
|
413
|
+
},
|
|
414
|
+
{
|
|
415
|
+
"id": "app-frame",
|
|
416
|
+
"title": "Bounded app frame",
|
|
417
|
+
"classes": [
|
|
418
|
+
"b3-app-frame"
|
|
419
|
+
],
|
|
420
|
+
"guidance": "Combine b3-mobile-app b3-app-frame with direct header, main, and exactly one bottom region: nav OR a footer containing nav. Never put sibling nav and footer elements in the frame; both occupy its third grid row. Main scrolls; grid reserves the actual navigation height, including large labels. The frame alone owns device insets; its app bar/nav use ordinary padding. Set --b3-frame-height for a bounded embedded preview; otherwise the frame uses 100dvh. Do not add a fixed-nav padding estimate or change its navigation to position:fixed. Put transient undo feedback in a direct footer wrapper and anchor it above that footer, not a guessed bar height. Restore per-route scroll with main.scrollTop, not window.scrollY. Keep the DOM order meaningful and use intrinsic grids inside main for wider screens. Existing b3-mobile-app without this atom retains its original fixed-navigation behavior. The hosting platform owns any external chrome; do not reproduce a host footer or fake OS bars inside the app.",
|
|
421
|
+
"example": "<div class=\"b3-mobile-app b3-app-frame\" data-b3-platform=\"ios\"><header class=\"b3-app-bar\"><strong>Today</strong><button class=\"b3-button\">New plan</button></header><main class=\"b3-shell b3-stack\" tabindex=\"-1\" aria-label=\"Plans\"><h1 class=\"b3-title\">Make a little progress</h1><div class=\"b3-grid\"><article class=\"b3-surface\">Your first plan</article></div></main><nav class=\"b3-bottom-nav\" aria-label=\"Main\"><a class=\"b3-bottom-link\" href=\"#today\" aria-current=\"page\">Today</a><a class=\"b3-bottom-link\" href=\"#saved\">Saved</a></nav></div>"
|
|
422
|
+
}
|
|
423
|
+
],
|
|
424
|
+
"references": [
|
|
425
|
+
"foundation.md",
|
|
426
|
+
"layout.md",
|
|
427
|
+
"type.md",
|
|
428
|
+
"surface.md",
|
|
429
|
+
"button.md",
|
|
430
|
+
"field.md",
|
|
431
|
+
"row.md",
|
|
432
|
+
"status.md",
|
|
433
|
+
"page-layout.md",
|
|
434
|
+
"control-structure.md",
|
|
435
|
+
"card-structure.md",
|
|
436
|
+
"feedback.md",
|
|
437
|
+
"identity.md",
|
|
438
|
+
"data-display.md",
|
|
439
|
+
"navigation.md",
|
|
440
|
+
"tabs.md",
|
|
441
|
+
"disclosure.md",
|
|
442
|
+
"dialog.md",
|
|
443
|
+
"content.md",
|
|
444
|
+
"marketing.md",
|
|
445
|
+
"reading.md",
|
|
446
|
+
"command.md",
|
|
447
|
+
"form-composition.md",
|
|
448
|
+
"steps.md",
|
|
449
|
+
"conversation.md",
|
|
450
|
+
"mobile.md",
|
|
451
|
+
"app-frame.md",
|
|
452
|
+
"cross-screen.md",
|
|
453
|
+
"icons.md",
|
|
454
|
+
"motion.md",
|
|
455
|
+
"start.md"
|
|
456
|
+
]
|
|
457
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# Bounded app frame
|
|
2
|
+
|
|
3
|
+
Combine b3-mobile-app b3-app-frame with direct header, main, and exactly one bottom region: nav OR a footer containing nav. Never put sibling nav and footer elements in the frame; both occupy its third grid row. Main scrolls; grid reserves the actual navigation height, including large labels. The frame alone owns device insets; its app bar/nav use ordinary padding. Set --b3-frame-height for a bounded embedded preview; otherwise the frame uses 100dvh. Do not add a fixed-nav padding estimate or change its navigation to position:fixed. Put transient undo feedback in a direct footer wrapper and anchor it above that footer, not a guessed bar height. Restore per-route scroll with main.scrollTop, not window.scrollY. Keep the DOM order meaningful and use intrinsic grids inside main for wider screens. Existing b3-mobile-app without this atom retains its original fixed-navigation behavior. The hosting platform owns any external chrome; do not reproduce a host footer or fake OS bars inside the app.
|
|
4
|
+
|
|
5
|
+
Classes: b3-app-frame
|
|
6
|
+
|
|
7
|
+
```html
|
|
8
|
+
<div class="b3-mobile-app b3-app-frame" data-b3-platform="ios"><header class="b3-app-bar"><strong>Today</strong><button class="b3-button">New plan</button></header><main class="b3-shell b3-stack" tabindex="-1" aria-label="Plans"><h1 class="b3-title">Make a little progress</h1><div class="b3-grid"><article class="b3-surface">Your first plan</article></div></main><nav class="b3-bottom-nav" aria-label="Main"><a class="b3-bottom-link" href="#today" aria-current="page">Today</a><a class="b3-bottom-link" href="#saved">Saved</a></nav></div>
|
|
9
|
+
```
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# Action
|
|
2
|
+
|
|
3
|
+
Use native button for actions, anchor for navigation. data-b3-emphasis="quiet" is a secondary action. Native disabled prevents activation. App owns click behavior. Icon-only actions need an accessible name. Emphasis: primary (default), quiet, outline, danger. Sizes small/default/large retain touch-height floors. aria-busy conveys loading but does not disable clicks; set disabled while duplicate submission must be prevented.
|
|
4
|
+
|
|
5
|
+
Classes: b3-button
|
|
6
|
+
|
|
7
|
+
```html
|
|
8
|
+
<button class="b3-button" type="submit">Save entry</button>
|
|
9
|
+
```
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# Card anatomy
|
|
2
|
+
|
|
3
|
+
Optional surface slots separate heading/actions and footer. data-b3-elevation=raised adds a shadow. Divider uses hr. A card is not required around every block.
|
|
4
|
+
|
|
5
|
+
Classes: b3-card-header, b3-card-footer, b3-divider
|
|
6
|
+
|
|
7
|
+
```html
|
|
8
|
+
<article class="b3-surface" data-b3-elevation="raised"><header class="b3-card-header"><h2 class="b3-heading">Project</h2></header><p>Project details</p><footer class="b3-card-footer"><button class="b3-button">Open project</button></footer></article>
|
|
9
|
+
```
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# Command palette
|
|
2
|
+
|
|
3
|
+
Use native dialog.b3-dialog.b3-command[data-b3-command], a labelled autofocus input with role=combobox, aria-autocomplete=list, aria-haspopup=listbox, aria-controls=list-id and aria-expanded=false. Listbox options need unique IDs, aria-selected=false and data-b3-value; optional data-b3-keywords adds synonyms. Never nest interactive elements inside options. Label role=group containers with aria-labelledby. mount() filters text, skips aria-disabled=true, retains input focus with aria-activedescendant, supports arrows/Enter and native Escape, and emits cancelable bubbling b3:command with detail.value and detail.item. App performs the action; default closes the dialog, preventDefault keeps it open. App owns shortcut registration and destination focus when navigating. data-b3-command-empty and data-b3-command-status provide empty/count feedback. Search resets on opening. Home/End and editing shortcuts retain browser behavior. Native dialog open-state observation resets the search and is disconnected on cleanup. Browser/device coverage remains to be qualified.
|
|
4
|
+
|
|
5
|
+
Classes: b3-command, b3-command-search, b3-command-list, b3-command-group, b3-command-item
|
|
6
|
+
|
|
7
|
+
```html
|
|
8
|
+
<button class="b3-button" data-b3-open="commands">Find an action</button><dialog class="b3-dialog b3-command" id="commands" data-b3-command aria-label="Commands"><div class="b3-command-search"><input class="b3-input" aria-label="Search commands" role="combobox" aria-autocomplete="list" aria-haspopup="listbox" aria-expanded="false" aria-controls="actions" autofocus><button class="b3-button" data-b3-close>Close</button></div><div class="b3-command-list" role="listbox" id="actions" aria-label="Actions"><div class="b3-command-item" role="option" id="action-theme" aria-selected="false" data-b3-value="theme">Switch appearance</div></div><p data-b3-command-empty hidden>No matching actions.</p><p data-b3-command-status role="status"></p></dialog>
|
|
9
|
+
```
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# Long-form content and accessibility
|
|
2
|
+
|
|
3
|
+
Prose scopes readable article flow and supports headings, lists, quotes and code. Visually-hidden keeps accessible text available to assistive technology. Do not use it to conceal focusable controls. Native hidden hides inactive component states. Put a b3-skip-link anchor first in the body, targeting the main landmark ID. The destination needs tabindex=-1 for reliable native focus transfer. The link is visually clipped until focused, then fixed above the page. Do not apply permanently visually-hidden styling to focusable controls.
|
|
4
|
+
|
|
5
|
+
Classes: b3-prose, b3-visually-hidden, b3-skip-link
|
|
6
|
+
|
|
7
|
+
```html
|
|
8
|
+
<article class="b3-prose"><h2>A useful heading</h2><p>Readable long-form content.</p><blockquote>A supporting observation.</blockquote></article><button class="b3-button"><span aria-hidden="true">+</span><span class="b3-visually-hidden">Add item</span></button><a class="b3-skip-link" href="#main-content">Skip to content</a><main id="main-content" tabindex="-1">Content</main>
|
|
9
|
+
```
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# Form composition
|
|
2
|
+
|
|
3
|
+
Input groups combine an affix and native input without removing its label. Choice is a native checkbox/radio label layout. Switch must be input type=checkbox with an associated label; checked/disabled remain native. Enabled switches require a distinct track and thumb in both states and themes (at least 3:1 thumb-to-track and track-to-surrounding contrast for the default solid treatment). The off track uses muted, not the subtle border token. Never invent div controls. Choice aligns the control with the first label line, including labels with helper text, and removes native input margins.
|
|
4
|
+
|
|
5
|
+
Classes: b3-input-group, b3-input-affix, b3-choice, b3-switch
|
|
6
|
+
|
|
7
|
+
```html
|
|
8
|
+
<label for="budget">Budget in USD</label><div class="b3-input-group"><span class="b3-input-affix" aria-hidden="true">$</span><input class="b3-input" id="budget" type="number"></div><label class="b3-choice"><input class="b3-switch" type="checkbox" checked><span>Email updates</span></label>
|
|
9
|
+
```
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# Conversation messages
|
|
2
|
+
|
|
3
|
+
Use an ordered list for chronological messages with authored sender labels and time elements. data-b3-side=self mirrors alignment in RTL and uses on-accent text. Message bodies preserve line breaks and wrap long content. App owns delivery state, persistence, safe text rendering, scroll position and focus. Announce newly added messages through a separate concise status region; do not mark the full restored history live. Never imply a reply was delivered remotely when only local storage succeeded. Recording, attachments, streaming and retries are not provided by these presentation classes.
|
|
4
|
+
|
|
5
|
+
Classes: b3-conversation, b3-message, b3-message-body, b3-message-meta
|
|
6
|
+
|
|
7
|
+
```html
|
|
8
|
+
<ol class="b3-conversation" aria-label="Messages"><li class="b3-message" data-b3-side="self"><p class="b3-message-body">Happy to help.</p><div class="b3-message-meta"><span>You</span><time datetime="2026-09-08T09:14:00Z">09:14 UTC</time></div></li></ol>
|
|
9
|
+
```
|