← Accessible Components results

Accessible Components

nex agi Nex N2.5 mini GGUF · typescript

Initial view of Accessible Components

Reviews & generation details

Reviews

No human review yet. Unreviewed does not mean unsuccessful.

Generation context

Imported historical artifact. Its exact original instructions and lineage are not known.

Generation prompt · exact text unavailable

See the current prompt for reference. It may differ from the instructions used to generate this artifact.

Inspect original source 56,718 bytes · SHA-256 02e142bf1a5f
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>ARIA Components — Accessible Interaction Showcase</title>
<style>
/* ── css: tokens ── */
:root {
  --ink: #17202b;
  --muted: #65707f;
  --faint: #8a95a2;
  --line: #e6e9ec;
  --line-strong: #d6dce1;
  --surface: #ffffff;
  --canvas: #f7f8f7;
  --wash: #eef2f1;
  --accent: #236a62;
  --accent-deep: #195049;
  --accent-soft: #e6f1ee;
  --accent-warm: #e4a35e;
  --danger: #a24b4b;
  --shadow: 0 18px 50px rgba(30, 51, 48, .13);
  --radius: 14px;
  --radius-sm: 9px;
  --focus: 0 0 0 3px rgba(35, 106, 98, .26);
  --font: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  --mono: "SFMono-Regular", Consolas, "Liberation Mono", monospace;
  --container: 1180px;
  --side: 250px;
  --section-gap: clamp(56px, 7vw, 100px);
  --ease: cubic-bezier(.22, .61, .21, 1);
  --duration: 260ms;
}
* { box-sizing: border-box; }
html { scroll-behavior: smooth; scroll-padding-top: 32px; }
body { margin: 0; color: var(--ink); background: var(--canvas); font-family: var(--font); font-size: 15px; line-height: 1.55; -webkit-font-smoothing: antialiased; }
button, input { font: inherit; }
button, a { -webkit-tap-highlight-color: transparent; }
a { color: inherit; }
::selection { background: var(--accent-soft); color: var(--accent-deep); }
:focus { outline: none; }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; box-shadow: var(--focus); }
.skip-link { position: fixed; z-index: 100; top: 14px; left: 14px; padding: 10px 14px; border-radius: 8px; color: #fff; background: var(--accent-deep); transform: translateY(-160%); transition: transform 160ms var(--ease); }
.skip-link:focus-visible { transform: translateY(0); outline-color: #fff; box-shadow: 0 8px 24px rgba(25,80,73,.25); }
.shell { min-height: 100vh; display: grid; grid-template-columns: var(--side) minmax(0, 1fr); }
.sidebar { position: sticky; top: 0; align-self: start; height: 100vh; display: flex; flex-direction: column; padding: 38px 26px 26px; border-right: 1px solid var(--line); background: rgba(255,255,255,.72); backdrop-filter: blur(12px); }
.brand { display: flex; align-items: center; gap: 10px; font-size: 15px; font-weight: 750; letter-spacing: .01em; }
.brand-mark { position: relative; display: grid; place-items: center; width: 24px; height: 24px; border-radius: 7px; background: var(--accent-deep); box-shadow: inset 0 0 0 1px rgba(255,255,255,.16); }
.brand-mark span:first-child, .brand-mark span:last-child { position: absolute; width: 6px; height: 6px; border-radius: 50%; background: #fff; }
.brand-mark span:first-child { transform: translate(-4px, -4px); }
.brand-mark span:last-child { transform: translate(4px, 4px); }
.sidebar-meta { display: flex; flex-direction: column; gap: 5px; margin: 50px 0 34px; padding-left: 2px; }
.eyebrow { color: var(--accent); font-size: 10px; font-weight: 800; letter-spacing: .15em; text-transform: uppercase; }
.version { color: var(--faint); font-family: var(--mono); font-size: 10px; letter-spacing: .04em; }
.side-nav { display: flex; flex-direction: column; gap: 3px; }
.nav-label { margin: 0 0 9px 11px; color: var(--faint); font-size: 10px; font-weight: 750; letter-spacing: .14em; text-transform: uppercase; }
.nav-link { display: flex; justify-content: space-between; align-items: center; padding: 11px 11px; border-radius: 8px; color: var(--muted); text-decoration: none; font-size: 13px; transition: color 160ms var(--ease), background 160ms var(--ease); }
.nav-link span { color: var(--faint); font-size: 13px; transition: transform 160ms var(--ease), color 160ms var(--ease); }
.nav-link:hover, .nav-link:focus-visible { color: var(--accent-deep); background: var(--accent-soft); }
.nav-link:hover span, .nav-link:focus-visible span { color: var(--accent); transform: translate(2px, -2px); }
.side-footer { margin-top: auto; padding: 18px 11px 0; border-top: 1px solid var(--line); }
.health { display: flex; align-items: center; gap: 7px; color: var(--accent-deep); font-size: 12px; font-weight: 700; }
.health-dot { width: 7px; height: 7px; border-radius: 50%; background: #59a878; box-shadow: 0 0 0 4px rgba(89,168,120,.14); }
.side-footer p { margin: 9px 0 0; color: var(--faint); font-size: 11px; line-height: 1.45; }
.workspace { min-width: 0; }
.hero { display: grid; grid-template-columns: minmax(0, 1.2fr) minmax(320px, .8fr); align-items: center; gap: 50px; min-height: 510px; padding: 90px max(48px, calc((100vw - var(--container)) / 2)); background: linear-gradient(110deg, #fff 0%, #fbfcfb 58%, #f1f5f3 100%); }
.hero-kicker, .hero-copy { max-width: 650px; }
.hero-kicker { display: flex; align-items: center; gap: 9px; color: var(--accent-deep); font-size: 11px; font-weight: 750; letter-spacing: .13em; text-transform: uppercase; }
.pulse { width: 8px; height: 8px; border-radius: 50%; background: var(--accent-warm); box-shadow: 0 0 0 5px rgba(228,163,94,.16); }
.hero h1 { max-width: 660px; margin: 20px 0 20px; font-size: clamp(42px, 5.1vw, 74px); font-weight: 700; letter-spacing: -.055em; line-height: .98; }
.hero h1 em { color: var(--accent); font-style: normal; }
.hero-copy { max-width: 570px; margin: 0; color: var(--muted); font-size: clamp(15px, 1.4vw, 18px); line-height: 1.65; }
.hero-actions { display: flex; align-items: center; gap: 22px; margin-top: 32px; }
.text-link { display: inline-flex; align-items: center; gap: 9px; color: var(--accent-deep); font-weight: 700; text-decoration: none; }
.text-link span { color: var(--accent); transition: transform 160ms var(--ease); }
.text-link:hover span { transform: translateX(4px); }
.hero-note { display: flex; align-items: center; gap: 5px; color: var(--faint); font-family: var(--mono); font-size: 11px; }
.kbd { display: inline-flex; min-width: 22px; justify-content: center; align-items: center; height: 22px; padding: 0 6px; border: 1px solid var(--line-strong); border-bottom-width: 2px; border-radius: 5px; background: #fff; color: var(--muted); font-family: var(--mono); font-size: 10px; line-height: 1; box-shadow: 0 1px 1px rgba(20,30,33,.04); }
.hero-orbit { position: relative; display: grid; place-items: center; justify-self: center; width: min(100%, 410px); aspect-ratio: 1; }
.orbit-ring { position: absolute; border: 1px solid #d9e5e1; border-radius: 50%; opacity: .7; }
.ring-one { inset: 14%; }
.ring-two { inset: 29%; border-style: dashed; opacity: .55; }
.orbit-core { position: relative; z-index: 1; display: grid; place-items: center; width: 122px; height: 122px; border-radius: 50%; color: #fff; background: var(--accent-deep); box-shadow: 0 18px 45px rgba(25,80,73,.22); }
.orbit-core span { font-size: 38px; line-height: 1; transform: translateY(8px); }
.orbit-core small { position: absolute; bottom: 25px; color: rgba(255,255,255,.72); font-size: 9px; letter-spacing: .08em; line-height: 1.2; text-align: center; text-transform: uppercase; }
.main-heading { display: flex; align-items: end; justify-content: space-between; gap: 20px; padding: 48px max(48px, calc((100vw - var(--container)) / 2)) 38px; }
.main-heading .intro { margin: 8px 0 0; color: var(--muted); font-size: 14px; }
.pattern-badge { display: inline-flex; align-items: center; gap: 8px; padding: 8px 11px; border: 1px solid #cfe2dc; border-radius: 999px; color: var(--accent-deep); background: rgba(230,241,238,.55); font-size: 11px; font-weight: 700; }
.badge-check { display: grid; place-items: center; width: 17px; height: 17px; border-radius: 50%; color: #fff; background: var(--accent); font-size: 10px; }
.component-section { padding: 0 max(48px, calc((100vw - var(--container)) / 2)) var(--section-gap); scroll-margin-top: 24px; }
.section-topline { display: flex; justify-content: space-between; align-items: center; margin-bottom: 18px; }
.section-number { color: var(--accent); font-family: var(--mono); font-size: 11px; font-weight: 700; letter-spacing: .12em; }
.tag { padding: 5px 9px; border: 1px solid var(--line-strong); border-radius: 999px; color: var(--muted); font-size: 10px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; }
.tag-outline { color: var(--accent); background: var(--accent-soft); border-color: #cfe2dc; }
.section-intro { display: flex; align-items: end; justify-content: space-between; gap: 30px; margin-bottom: 21px; }
.section-intro h2 { margin: 0; font-size: 24px; font-weight: 700; letter-spacing: -.035em; }
.section-intro p { max-width: 500px; margin: 0 0 2px; color: var(--muted); font-size: 13px; line-height: 1.6; }
.demo-card { overflow: hidden; border: 1px solid var(--line); border-radius: var(--radius); background: var(--surface); box-shadow: 0 1px 2px rgba(29,45,47,.025), 0 14px 34px rgba(29,45,47,.035); }
.demo-card-header { display: flex; align-items: center; gap: 8px; min-height: 44px; padding: 0 20px; border-bottom: 1px solid var(--line); background: #fcfdfc; color: var(--muted); font-size: 11px; }
.demo-dot { width: 7px; height: 7px; border-radius: 50%; background: #65a98f; box-shadow: 0 0 0 4px rgba(101,169,143,.11); }
.demo-label { font-weight: 700; }
.demo-hint { margin-left: auto; color: var(--faint); font-size: 11px; }
.contract-caption { display: flex; align-items: center; gap: 9px; margin: 14px 2px 0; color: var(--muted); font-size: 11px; }
.contract-caption strong { color: var(--ink); font-size: 11px; }
.caption-icon { display: grid; place-items: center; width: 19px; height: 19px; border: 1px solid var(--line-strong); border-radius: 6px; color: var(--accent); background: #fff; font-size: 11px; }
.button { display: inline-flex; align-items: center; justify-content: center; gap: 9px; min-height: 40px; padding: 0 15px; border: 1px solid transparent; border-radius: 8px; cursor: pointer; font-size: 12px; font-weight: 700; transition: transform 150ms var(--ease), background 150ms var(--ease), border-color 150ms var(--ease), color 150ms var(--ease); }
.button:active { transform: translateY(1px); }
.button-primary { color: #fff; background: var(--accent-deep); box-shadow: 0 7px 16px rgba(25,80,73,.16); }
.button-primary:hover { background: var(--accent); }
.button-primary span { font-size: 14px; }
.button-secondary { color: var(--accent-deep); border-color: #d5e1de; background: #fff; }
.button-secondary:hover { border-color: var(--accent); background: var(--accent-soft); }
.text-input { width: 100%; min-height: 43px; padding: 0 13px; border: 1px solid var(--line-strong); border-radius: 8px; color: var(--ink); background: #fff; font-size: 13px; transition: border-color 150ms var(--ease), box-shadow 150ms var(--ease); }
.text-input::placeholder { color: #a1aaB1; }
.text-input:hover, .text-input:focus { border-color: #a9c4bd; }
.text-input:focus { border-color: var(--accent); box-shadow: var(--focus); }
/* Modal */
.dialog-backdrop { position: fixed; z-index: 50; inset: 0; display: grid; place-items: center; padding: 24px; background: rgba(19, 32, 37, .43); animation: fade-in 180ms var(--ease) both; }
.dialog-backdrop[hidden] { display: none; }
.modal-dialog { width: min(100%, 470px); padding: 27px; border: 1px solid rgba(255,255,255,.5); border-radius: 15px; background: #fff; box-shadow: var(--shadow); animation: dialog-in 220ms var(--ease) both; }
.dialog-backdrop[hidden] .modal-dialog { animation: none; }
@keyframes fade-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes dialog-in { from { opacity: 0; transform: translateY(12px) scale(.98); } to { opacity: 1; transform: translateY(0) scale(1); } }
.dialog-topline { display: flex; align-items: center; gap: 9px; margin-bottom: 18px; }
.dialog-icon { display: grid; place-items: center; width: 28px; height: 28px; border-radius: 8px; color: var(--accent); background: var(--accent-soft); }
.modal-dialog h3 { margin: 0 0 9px; font-size: 22px; letter-spacing: -.035em; }
.modal-dialog > p { margin: 0 0 21px; color: var(--muted); font-size: 13px; }
.field-label { display: block; margin-bottom: 7px; color: var(--ink); font-size: 11px; font-weight: 750; }
.dialog-actions { display: flex; justify-content: flex-end; gap: 9px; margin-top: 20px; }
/* Menu */
.menu-demo { position: relative; min-height: 184px; padding: 30px; background: linear-gradient(135deg, #fcfdfc, #f5f8f7); }
.menu-popover { position: absolute; z-index: 10; top: 81px; left: 30px; min-width: 245px; margin: 0; padding: 6px; border: 1px solid var(--line); border-radius: 10px; background: #fff; box-shadow: 0 15px 38px rgba(25,48,45,.13); list-style: none; }
.menu-popover[hidden] { display: none; }
.menu-popover button { display: flex; align-items: center; justify-content: space-between; width: 100%; padding: 10px 11px; border: 0; border-radius: 6px; color: var(--ink); background: transparent; cursor: pointer; text-align: left; font-size: 12px; }
.menu-popover button:hover, .menu-popover button[aria-current="true"] { color: var(--accent-deep); background: var(--accent-soft); }
.menu-item-symbol { color: var(--faint); }
.menu-result { display: flex; align-items: center; justify-content: space-between; gap: 20px; max-width: 250px; padding: 13px 15px; border-left: 2px solid var(--accent); background: #fff; box-shadow: 0 5px 18px rgba(29,45,47,.07); }
.result-label, .stat-label { display: block; color: var(--faint); font-size: 10px; font-weight: 650; text-transform: uppercase; letter-spacing: .08em; }
.menu-result strong { font-size: 12px; }
/* Tabs */
.tabs-demo { padding: 0 30px 28px; background: #fbfcfb; }
.tab-list { display: flex; gap: 27px; border-bottom: 1px solid var(--line); }
.tab { position: relative; padding: 15px 1px 13px; border: 0; color: var(--faint); background: transparent; cursor: pointer; font-size: 12px; font-weight: 700; }
.tab:hover { color: var(--accent-deep); }
.tab[aria-selected="true"] { color: var(--accent-deep); }
.tab[aria-selected="true"]::after { position: absolute; right: 0; bottom: -1px; left: 0; height: 2px; border-radius: 2px 2px 0 0; background: var(--accent); content: ""; }
.tab-index { margin-left: 7px; font-family: var(--mono); font-size: 9px; font-weight: 500; }
.tab[aria-selected="true"] .tab-index { color: var(--accent); }
.panel-content { padding: 25px 0 4px; }
.stat-row { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; }
.stat { padding: 14px 16px; border: 1px solid var(--line); border-radius: 9px; background: #fff; }
.stat strong { display: inline-block; margin: 10px 0 3px; font-size: 24px; letter-spacing: -.04em; }
.stat-trend { font-size: 10px; font-weight: 750; }
.stat-trend.up { color: #3f966d; }
.stat-trend.down { color: var(--accent-warm); }
.panel-prompt { display: flex; align-items: center; gap: 13px; margin: 20px 0 8px; padding: 15px 16px; border: 1px solid #d9e8e4; border-radius: 9px; background: var(--accent-soft); }
.panel-prompt strong { font-size: 12px; }
.panel-prompt p { margin: 2px 0 0; color: var(--muted); font-size: 11px; }
.prompt-icon { color: var(--accent); }
.panel-chart { height: 220px; padding: 18px 22px 12px; border: 1px solid var(--line); border-radius: 10px; background: #fff; }
.chart-axis { position: absolute; display: flex; justify-content: space-between; }
.chart-bars { display: flex; align-items: end; gap: clamp(8px, 2vw, 21px); height: 155px; margin: 30px 22px 0; border-bottom: 1px solid var(--line); background: repeating-linear-gradient(to top, transparent 0, transparent 37px, #f0f3f2 38px); }
.chart-bars span { position: relative; display: block; flex: 1; height: var(--bar-h); min-height: 18px; border-radius: 4px 4px 0 0; background: linear-gradient(to top, var(--accent) 0%, #78aba3 100%); }
.chart-bars span:nth-child(2n) { background: linear-gradient(to top, var(--accent-warm) 0%, #f1c188 100%); }
.chart-caption { margin-top: 10px; color: var(--muted); font-size: 10px; }
.mini-stats { display: flex; justify-content: space-between; padding: 15px 4px 0; color: var(--muted); font-size: 10px; }
.mini-stats strong { color: var(--ink); font-family: var(--mono); font-size: 11px; }
.activity-list { display: flex; flex-direction: column; gap: 2px; padding: 8px 16px; border-top: 1px solid var(--line); }
.activity-row { display: flex; align-items: center; gap: 12px; padding: 10px 0; border-bottom: 1px solid var(--line); }
.activity-avatar { display: grid; place-items: center; flex: 0 0 30px; height: 30px; border-radius: 8px; color: #fff; font-size: 9px; font-weight: 800; }
.activity-avatar.amber { background: #d89b58; } .activity-avatar.blue { background: #6692c7; } .activity-avatar.green { background: #6aa581; } .activity-avatar.coral { background: #c7796c; }
.activity-row strong { font-size: 11px; }
.activity-row p { margin: 2px 0 0; color: var(--muted); font-size: 10px; }
.activity-row time { margin-left: 4px; color: var(--faint); font-size: 9px; }
/* Combobox */
.combobox-demo { min-height: 198px; padding: 28px 30px; background: linear-gradient(135deg, #fcfdfc, #f5f8f7); }
.combobox-shell { position: relative; }
.combobox-shell .text-input { padding-right: 42px; }
.input-glyph { position: absolute; top: 12px; right: 14px; color: var(--faint); font-size: 22px; pointer-events: none; }
.combo-list { position: absolute; z-index: 12; top: 52px; right: 0; left: 0; max-height: 222px; margin: 5px 0 0; padding: 5px; overflow-y: auto; border: 1px solid var(--line); border-radius: 9px; background: #fff; box-shadow: 0 15px 38px rgba(25,48,45,.13); list-style: none; }
.combo-list li { padding: 9px 11px; border-radius: 6px; color: var(--ink); font-size: 12px; }
.combo-list li[aria-selected="true"] { color: var(--accent-deep); background: var(--accent-soft); }
.combo-list li[aria-selected="false"] { color: var(--muted); }
.combo-empty { color: var(--muted); font-size: 12px; }
.combo-status { display: flex; align-items: center; gap: 8px; margin: 12px 2px 0; color: var(--muted); font-size: 11px; }
.status-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--accent-warm); }
.combo-status strong { color: var(--accent-deep); font-weight: 700; }
/* Accordion */
.accordion { padding: 4px 20px 20px; background: #fbfcfb; }
.accordion-item + .accordion-item { border-top: 1px solid var(--line); }
.accordion-heading { margin: 0; }
.accordion-button { display: flex; align-items: center; justify-content: space-between; width: 100%; min-height: 59px; padding: 0 3px; border: 0; color: var(--ink); background: transparent; cursor: pointer; text-align: left; font-size: 13px; font-weight: 700; }
.accordion-button:hover { color: var(--accent-deep); }
.accordion-button:focus-visible { outline: 2px solid var(--accent); outline-offset: 4px; }
.accordion-icon { display: grid; place-items: center; width: 25px; height: 25px; border: 1px solid var(--line-strong); border-radius: 7px; color: var(--accent); background: #fff; font-size: 18px; line-height: 1; transition: transform 180ms var(--ease), background 180ms var(--ease); }
.accordion-button[aria-expanded="true"] .accordion-icon { color: #fff; background: var(--accent-deep); border-color: var(--accent-deep); }
.accordion-panel { overflow: hidden; }
.accordion-content { padding: 0 3px 21px 39px; color: var(--muted); font-size: 12px; line-height: 1.65; }
.accordion-content p { margin: 0; }
/* Closing */
.closing-strip { display: flex; align-items: end; justify-content: space-between; gap: 30px; margin: 0 max(48px, calc((100vw - var(--container)) / 2)) 70px; padding: 34px 38px; border: 1px solid var(--line); border-radius: var(--radius); background: var(--accent-deep); color: #fff; }
.closing-strip h2 { margin: 12px 0 7px; font-size: 27px; letter-spacing: -.04em; }
.closing-strip p { max-width: 600px; margin: 0; color: rgba(255,255,255,.7); font-size: 13px; }
.closing-strip .button { flex: 0 0 auto; color: var(--accent-deep); background: #fff; }
@media (max-width: 900px) {
  :root { --side: 210px; }
  .hero { grid-template-columns: 1fr; min-height: auto; padding-top: 64px; padding-bottom: 64px; }
  .hero-orbit { justify-self: start; width: min(100%, 300px); margin-top: 20px; }
  .main-heading, .component-section, .closing-strip { padding-right: 28px; padding-left: 28px; }
  .section-intro { display: block; }
  .section-intro p { margin-top: 12px; }
}
@media (max-width: 680px) {
  :root { --container: none; --side: 0; --section-gap: 56px; }
  body { font-size: 14px; }
  .shell { display: block; }
  .sidebar { position: relative; height: auto; padding: 22px 18px; border-right: 0; border-bottom: 1px solid var(--line); }
  .sidebar-meta { flex-direction: row; justify-content: space-between; margin: 22px 0 17px; }
  .side-nav { display: grid; grid-template-columns: repeat(5, 1fr); gap: 5px; }
  .nav-label { grid-column: 1 / -1; }
  .nav-link { justify-content: flex-start; padding: 9px 8px; font-size: 11px; }
  .nav-link span { display: none; }
  .side-footer { display: none; }
  .workspace { width: 100%; }
  .hero { min-height: auto; gap: 25px; padding: 48px 20px 50px; }
  .hero h1 { font-size: clamp(39px, 12vw, 56px); }
  .hero-orbit { width: 220px; }
  .orbit-core { width: 90px; height: 90px; }
  .orbit-core span { font-size: 29px; }
  .main-heading { display: block; padding: 40px 20px 28px; }
  .pattern-badge { margin-top: 22px; }
  .component-section { padding: 0 20px 56px; }
  .section-topline { margin-bottom: 14px; }
  .section-intro h2 { font-size: 22px; }
  .section-intro p { font-size: 12px; }
  .demo-card-header { padding: 0 14px; }
  .demo-hint { font-size: 10px; }
  .demo-card-header .demo-label { font-size: 10px; }
  .menu-demo, .combobox-demo { min-height: 165px; padding: 22px 16px; }
  .menu-popover { top: 65px; left: 16px; right: 16px; min-width: 0; }
  .menu-result { max-width: 100%; }
  .tabs-demo { padding: 0 12px 20px; }
  .tab-list { gap: 19px; overflow-x: auto; }
  .tab { flex: 0 0 auto; padding-right: 1px; }
  .stat-row { grid-template-columns: 1fr; gap: 8px; }
  .stat { display: flex; align-items: center; justify-content: space-between; padding: 12px; }
  .stat strong { margin: 0 0 0 11px; }
  .panel-prompt { padding: 12px; }
  .panel-chart { height: 175px; padding: 14px 14px 8px; }
  .chart-bars { margin-left: 14px; margin-right: 14px; }
  .mini-stats { gap: 10px; flex-wrap: wrap; }
  .combobox-list, .combo-list { position: fixed; top: auto; bottom: 10px; left: 10px; right: 10px; max-height: min(50vh, 260px); }
  .combo-status { margin-left: 2px; }
  .accordion { padding: 3px 14px 14px; }
  .accordion-content { padding-left: 3px; }
  .closing-strip { display: block; margin: 0 20px 48px; padding: 26px 20px; }
  .closing-strip .button { margin-top: 20px; }
}
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { scroll-behavior: auto !important; animation-duration: .01ms !important; animation-iteration-count: 1 !important; transition-duration: .01ms !important; }
}
</style>
</head>
<body>
<a class="skip-link" href="#main-content">Skip to main content</a>
<div class="shell">
  <aside class="sidebar" aria-label="Component navigation">
  <div class="brand">
    <span class="brand-mark" aria-hidden="true"><span></span><span></span></span>
    <span>Element Atlas</span>
  </div>
  <div class="sidebar-meta">
    <span class="eyebrow">Accessible UI kit</span>
    <span class="version">v1.0 · vanilla</span>
  </div>
  <nav class="side-nav" aria-label="Components">
    <p class="nav-label">Components</p>
    <a class="nav-link" href="#component-modal">Modal dialog <span>↗</span></a>
    <a class="nav-link" href="#dropdown-menu">Dropdown menu <span>↗</span></a>
    <a class="nav-link" href="#tabs">Tabs <span>↗</span></a>
    <a class="nav-link" href="#combobox">Combobox <span>↗</span></a>
    <a class="nav-link" href="#accordion">Accordion <span>↗</span></a>
  </nav>
  <div class="side-footer">
    <div class="health"><span class="health-dot" aria-hidden="true"></span> Keyboard ready</div>
    <p>Every control follows the ARIA APG pattern.</p>
  </div>
</aside>

  <div class="workspace">
    <header class="hero">
  <div>
    <div class="hero-kicker"><span class="pulse" aria-hidden="true"></span> Interaction patterns, responsibly built</div>
    <h1>Interfaces that feel natural <em>to everyone.</em></h1>
    <p class="hero-copy">A living design-system showcase for dialogs, menus, tabs, comboboxes, and accordions. Every example is built to be explored with a keyboard or assistive technology.</p>
    <div class="hero-actions">
      <a class="text-link" href="#component-modal">Start with the modal <span aria-hidden="true">→</span></a>
      <span class="hero-note"><span class="kbd">1</span><span class="kbd">2</span><span class="kbd">3</span> patterns to explore</span>
    </div>
  </div>
  <div class="hero-orbit" aria-hidden="true">
    <div class="orbit-ring ring-one"></div><div class="orbit-ring ring-two"></div>
    <div class="orbit-core"><span>◈</span><small>focus<br>first</small></div>
  </div>
</header>

    <main id="main-content" tabindex="-1">
  <div class="main-heading"><div><span class="eyebrow">Component reference</span><p class="intro">Five core patterns. One shared standard for clear, dependable interaction.</p></div><div class="pattern-badge"><span class="badge-check" aria-hidden="true">✓</span> APG aligned</div></div>

  <section id="component-modal" class="component-section" aria-labelledby="modal-dialog-heading">
    <div class="section-topline"><span class="section-number">01</span><span class="tag tag-outline">Overlay</span></div>
    <div class="section-intro"><h2 id="modal-dialog-heading">Modal dialog</h2><p>A contained decision with a clear next step. Focus is trapped, the background goes inert, and Escape returns you to where you began.</p></div>
    <div class="demo-card">
      <div class="demo-card-header"><span class="demo-dot" aria-hidden="true"></span><span class="demo-label">Live example</span><span class="demo-hint"><span class="kbd">Esc</span> to dismiss</span></div>
      <div class="modal-demo"><div><span class="demo-label-small">Invite a collaborator</span><p class="demo-copy">Give your teammate access to the shared workspace.</p></div><button id="open-modal" class="button button-primary" type="button">Invite teammate <span aria-hidden="true">↗</span></button></div>
      <div class="dialog-backdrop" id="modal-backdrop" hidden=""><div class="modal-dialog" id="modal-dialog" role="dialog" aria-modal="true" aria-labelledby="modal-title" aria-describedby="modal-description" data-dialog="">
        <div class="dialog-topline"><span class="dialog-icon" aria-hidden="true">✦</span><span class="eyebrow">Workspace access</span></div>
        <h3 id="modal-title">Invite a collaborator</h3>
        <p id="modal-description">Choose an email to send an invitation. Your teammate can join with a single click.</p>
        <label class="field-label" for="modal-email">Work email</label>
        <input id="modal-email" class="text-input" type="email" placeholder="name@company.com" autocomplete="email">
        <div class="dialog-actions"><button class="button button-secondary" type="button" data-modal-close="">Cancel</button><button class="button button-primary" type="button" data-modal-confirm="">Send invitation</button></div>
      </div></div>
    </div>
    <p class="contract-caption"><span class="caption-icon" aria-hidden="true">⌘</span> <strong>Keyboard contract</strong> · Tab cycles inside · Esc closes · focus returns to trigger</p>
  </section>

  <section id="dropdown-menu" class="component-section" aria-labelledby="dropdown-menu-heading">
    <div class="section-topline"><span class="section-number">02</span><span class="tag tag-outline">Navigation</span></div>
    <div class="section-intro"><h2 id="dropdown-menu-heading">Dropdown menu</h2><p>A compact command list with full arrow-key support. The button reflects its expanded state, and selection performs a visible action.</p></div>
    <div class="demo-card">
      <div class="demo-card-header"><span class="demo-dot" aria-hidden="true"></span><span class="demo-label">Live example</span><span class="demo-hint"><span class="kbd">↓</span> opens · <span class="kbd">Esc</span> closes</span></div>
      <div class="menu-demo">
        <button id="menu-button" class="button button-secondary" type="button" aria-haspopup="menu" aria-expanded="false" aria-controls="menu-items"><span class="menu-glyph" aria-hidden="true">☰</span> Choose a view <span class="chevron" aria-hidden="true">⌄</span></button>
        <ul id="menu-items" class="menu-popover" role="menu" aria-label="Choose a view" hidden="">
          <li role="none"><button id="menu-item-dashboard" role="menuitem" type="button" data-menu-value="dashboard">Dashboard <span class="menu-item-symbol" aria-hidden="true">◫</span></button></li>
          <li role="none"><button id="menu-item-reports" role="menuitem" type="button" data-menu-value="reports">Reports <span class="menu-item-symbol" aria-hidden="true">▤</span></button></li>
          <li role="none"><button id="menu-item-activity" role="menuitem" type="button" data-menu-value="activity">Activity <span class="menu-item-symbol" aria-hidden="true">◌</span></button></li>
          <li role="none"><button id="menu-item-settings" role="menuitem" type="button" data-menu-value="settings">Settings <span class="menu-item-symbol" aria-hidden="true">⚙</span></button></li>
        </ul>
        <div class="menu-result" id="menu-result" aria-live="polite"><span class="result-label">Selected view</span><strong id="menu-result-value">Dashboard</strong></div>
      </div>
    </div>
    <p class="contract-caption"><span class="caption-icon" aria-hidden="true">⌘</span> <strong>Keyboard contract</strong> · ↓ opens · ↑ ↓ navigate · Home / End jump · Esc closes</p>
  </section>

  <section id="tabs" class="component-section" aria-labelledby="tabs-heading">
    <div class="section-topline"><span class="section-number">03</span><span class="tag tag-outline">Navigation</span></div>
    <div class="section-intro"><h2 id="tabs-heading">Tabs</h2><p>Roving tabindex keeps one tab in the tab order. Arrow keys move the selection while hidden panels stay truly hidden.</p></div>
    <div class="demo-card">
      <div class="demo-card-header"><span class="demo-dot" aria-hidden="true"></span><span class="demo-label">Live example</span><span class="demo-hint"><span class="kbd">←</span> <span class="kbd">→</span> switch panels</span></div>
      <div class="tabs-demo">
        <div class="tab-list" role="tablist" aria-label="Project views" id="project-tabs">
          <button class="tab is-active" role="tab" id="tab-overview" aria-selected="true" aria-controls="panel-overview" tabindex="0" type="button">Overview <span class="tab-index" aria-hidden="true">01</span></button>
          <button class="tab" role="tab" id="tab-analytics" aria-selected="false" aria-controls="panel-analytics" tabindex="-1" type="button">Analytics <span class="tab-index" aria-hidden="true">02</span></button>
          <button class="tab" role="tab" id="tab-activity" aria-selected="false" aria-controls="panel-activity" tabindex="-1" type="button">Activity <span class="tab-index" aria-hidden="true">03</span></button>
        </div>
        <div id="panel-overview" role="tabpanel" aria-labelledby="tab-overview" tabindex="0"><div class="panel-content"><div class="stat-row"><div class="stat"><span class="stat-label">Active members</span><strong>1,284</strong><span class="stat-trend up">↗ 12%</span></div><div class="stat"><span class="stat-label">Tasks completed</span><strong>86</strong><span class="stat-trend up">↗ 8%</span></div><div class="stat"><span class="stat-label">On track</span><strong>94%</strong><span class="stat-trend down">↓ 2%</span></div></div><div class="panel-prompt"><span class="prompt-icon" aria-hidden="true">✦</span><div><strong>Good morning, Maya.</strong><p>Your sprint is moving in the right direction. Review the latest signals before your next standup.</p></div></div></div></div>
        <div id="panel-analytics" role="tabpanel" aria-labelledby="tab-analytics" tabindex="0" hidden=""><div class="panel-content"><div class="panel-chart"><div class="chart-bars"><span style="--bar-h: 38%"></span><span style="--bar-h: 62%"></span><span style="--bar-h: 48%"></span><span style="--bar-h: 82%"></span><span style="--bar-h: 66%"></span><span style="--bar-h: 94%"></span><span style="--bar-h: 74%"></span></div><div class="chart-caption">Weekly signups <span>·</span> last 7 days</div></div><div class="mini-stats"><span>Conversion <strong>32.4%</strong></span><span>Avg. session <strong>4m 18s</strong></span><span>Bounce <strong>18.2%</strong></span></div></div></div>
        <div id="panel-activity" role="tabpanel" aria-labelledby="tab-activity" tabindex="0" hidden=""><div class="panel-content"><div class="activity-list"><div class="activity-row"><span class="activity-avatar amber">JL</span><div><strong>Jules Lane</strong><p>Commented on “Onboarding flow” <time>2m ago</time></p></div></div><div class="activity-row"><span class="activity-avatar blue">AK</span><div><strong>Alex Kim</strong><p>Completed 3 tasks in the release checklist <time>18m ago</time></p></div></div><div class="activity-row"><span class="activity-avatar green">MT</span><div><strong>Marisol Torres</strong><p>Added 4 new comments to the Q3 plan <time>1h ago</time></p></div></div><div class="activity-row"><span class="activity-avatar coral">RS</span><div><strong>Ray Sun</strong><p>Moved “Empty state” to In review <time>3h ago</time></p></div></div></div></div>
      </div>
    </div>
    <p class="contract-caption"><span class="caption-icon" aria-hidden="true">⌘</span> <strong>Keyboard contract</strong> · ← → switch tabs · one tab in tab order · panels reveal on selection</p>
  </div></section>

  <section id="combobox" class="component-section" aria-labelledby="combobox-heading">
    <div class="section-topline"><span class="section-number">04</span><span class="tag tag-outline">Input</span></div>
    <div class="section-intro"><h2 id="combobox-heading">Combobox</h2><p>Type to filter a large option set. The highlighted option is announced through <code>aria-activedescendant</code> and remains out of the tab order.</p></div>
    <div class="demo-card">
      <div class="demo-card-header"><span class="demo-dot" aria-hidden="true"></span><span class="demo-label">Live example</span><span class="demo-hint"><span class="kbd">↑</span> <span class="kbd">↓</span> filter · <span class="kbd">Enter</span> select</span></div>
      <div class="combobox-demo"><label class="field-label" for="city-combobox">Select a city</label><div class="combobox-shell"><input id="city-combobox" class="text-input" type="text" role="combobox" aria-expanded="false" aria-controls="city-options" aria-activedescendant="" autocomplete="off" placeholder="Search 20 cities"><span class="input-glyph" aria-hidden="true">⌕</span></div><ul id="city-options" class="combo-list" role="listbox" aria-label="Cities" hidden=""></ul><p id="combo-status" class="combo-status" aria-live="polite"><span class="status-dot" aria-hidden="true"></span><span id="combo-status-text">Choose a destination</span></p></div>
    </div>
    <p class="contract-caption"><span class="caption-icon" aria-hidden="true">⌘</span> <strong>Keyboard contract</strong> · type to filter · ↑ ↓ highlight · Enter selects · Esc reverts</p>
  </section>

  <section id="accordion" class="component-section" aria-labelledby="accordion-heading">
    <div class="section-topline"><span class="section-number">05</span><span class="tag tag-outline">Content</span></div>
    <div class="section-intro"><h2 id="accordion-heading">Accordion</h2><p>Multiple regions can stay open at once. Height animates only while content is visible, then the region is hidden for assistive technology.</p></div>
    <div class="demo-card accordion-demo-card">
      <div class="demo-card-header"><span class="demo-dot" aria-hidden="true"></span><span class="demo-label">Live example</span><span class="demo-hint">Enter / Space toggles a region</span></div>
      <div class="accordion" id="principles-accordion">
        <div class="accordion-item"><h3 class="accordion-heading"><button id="accordion-button-1" class="accordion-button" type="button" aria-expanded="true" aria-controls="accordion-panel-1"><span class="accordion-title">What makes this accessible?</span><span class="accordion-icon" aria-hidden="true">−</span></button></h3><div id="accordion-panel-1" class="accordion-panel" role="region" aria-labelledby="accordion-button-1"><div class="accordion-content"><p>Every example uses native controls where possible, semantic structure where needed, and explicit relationships between labels, controls, and regions. State changes are reflected in the DOM and announced.</p></div></div></div>
        <div class="accordion-item"><h3 class="accordion-heading"><button id="accordion-button-2" class="accordion-button" type="button" aria-expanded="false" aria-controls="accordion-panel-2"><span class="accordion-title">How is focus managed?</span><span class="accordion-icon" aria-hidden="true">+</span></button></h3><div id="accordion-panel-2" class="accordion-panel" role="region" aria-labelledby="accordion-button-2"><div class="accordion-content"><p>Focus is intentional. Dialogs trap focus and return it, menus close predictably, and only the active tab sits in the tab order. A visible focus ring appears on every interactive element.</p></div></div></div>
        <div class="accordion-item"><h3 class="accordion-heading"><button id="accordion-button-3" class="accordion-button" type="button" aria-expanded="false" aria-controls="accordion-panel-3"><span class="accordion-title">What happens at 200% zoom?</span><span class="accordion-icon" aria-hidden="true">+</span></button></h3><div id="accordion-panel-3" class="accordion-panel" role="region" aria-labelledby="accordion-button-3"><div class="accordion-content"><p>The layout reflows into a single column, controls retain generous hit targets, and menus and panels never rely on visual placement alone. Content remains readable and operable at any supported browser zoom.</p></div></div></div>
        <div class="accordion-item"><h3 class="accordion-heading"><button id="accordion-button-4" class="accordion-button" type="button" aria-expanded="false" aria-controls="accordion-panel-4"><span class="accordion-title">Can the motion be reduced?</span><span class="accordion-icon" aria-hidden="true">+</span></button></h3><div id="accordion-panel-4" class="accordion-panel" role="region" aria-labelledby="accordion-button-4"><div class="accordion-content"><p>Yes. The showcase respects prefers-reduced-motion, shortening transitions and keeping every state change immediate without sacrificing visibility or accessibility.</p></div></div></div>
      </div>
    </div>
    <p class="contract-caption"><span class="caption-icon" aria-hidden="true">⌘</span> <strong>Keyboard contract</strong> · Enter / Space opens and closes · multiple regions may remain open</p>
  </section>

  <section class="closing-strip" aria-labelledby="closing-heading"><div><span class="eyebrow">Built for the long run</span><h2 id="closing-heading">Clear patterns make better products.</h2><p>Use these examples as a starting point for your own interface. The smallest details are where trust is built.</p></div><a class="button button-primary" href="#component-modal">Explore the pattern set <span aria-hidden="true">→</span></a></section>
</main>
  </div>
</div>
<script>
(function () {
'use strict';
var __mods = {};
var __cache = {};
var __map = {"src/main.ts":{"./accordion":"src/accordion.ts","./combobox":"src/combobox.ts","./dropdown":"src/dropdown.ts","./modal":"src/modal.ts","./tabs":"src/tabs.ts"},"src/modal.ts":{"./utils":"src/utils.ts"},"src/dropdown.ts":{"./utils":"src/utils.ts"},"src/tabs.ts":{"./utils":"src/utils.ts"},"src/combobox.ts":{"./utils":"src/utils.ts"},"src/accordion.ts":{"./utils":"src/utils.ts"}};
function __require(id) {
  if (__cache[id]) return __cache[id].exports;
  var module = __cache[id] = { exports: {} };
  var factory = __mods[id];
  if (!factory) throw new Error("Module not found: " + id);
  factory(module.exports, function (spec) {
    var target = (__map[id] && __map[id][spec]) || spec;
    return __require(target);
  }, module);
  return module.exports;
}

// ── module: src/main.ts ──
__mods["src/main.ts"] = function (exports, require, module) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.start = start;
const accordion_1 = require("./accordion");
const combobox_1 = require("./combobox");
const dropdown_1 = require("./dropdown");
const modal_1 = require("./modal");
const tabs_1 = require("./tabs");
function start() {
    (0, modal_1.createModal)();
    (0, dropdown_1.createDropdown)();
    (0, tabs_1.createTabs)();
    (0, combobox_1.createCombobox)();
    (0, accordion_1.createAccordion)();
}
start();
};

// ── module: src/utils.ts ──
__mods["src/utils.ts"] = function (exports, require, module) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.COMPONENTS = void 0;
exports.querySelectorOrThrow = querySelectorOrThrow;
exports.getFocusable = getFocusable;
exports.closeOverlay = closeOverlay;
exports.COMPONENTS = {
    modal: { open: "open", close: "close" },
};
function querySelectorOrThrow(scope, selector) {
    const found = scope.querySelector(selector);
    if (!found)
        throw new Error(`Missing ${selector}`);
    return found;
}
function getFocusable(scope) {
    return Array.from(scope.querySelectorAll('a[href], area[href], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"]), [contenteditable="true"]')).filter((element) => !element.hasAttribute("disabled") && element.offsetParent !== null);
}
function closeOverlay(root, restoreFocus = () => undefined) {
    root.hidden = true;
    document.body.classList.remove("modal-open");
    restoreFocus();
}
};

// ── module: src/modal.ts ──
__mods["src/modal.ts"] = function (exports, require, module) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createModal = createModal;
const utils_1 = require("./utils");
function createModal() {
    const button = (0, utils_1.querySelectorOrThrow)(document, "#open-modal");
    const backdrop = (0, utils_1.querySelectorOrThrow)(document, "#modal-backdrop");
    const dialog = (0, utils_1.querySelectorOrThrow)(backdrop, "[data-dialog]");
    const email = (0, utils_1.querySelectorOrThrow)(dialog, "#modal-email");
    const closeButtons = Array.from(dialog.querySelectorAll("[data-modal-close]"));
    const confirm = (0, utils_1.querySelectorOrThrow)(dialog, "[data-modal-confirm]");
    function openDialog() {
        const previousFocus = document.activeElement instanceof HTMLElement ? document.activeElement : null;
        backdrop.dataset.previousFocus = previousFocus?.id ?? "body";
        backdrop.hidden = false;
        document.body.classList.add("modal-open");
        const sections = Array.from(document.querySelectorAll(".sidebar, .hero, main .component-section"));
        sections.forEach((section) => section.setAttribute("inert", ""));
        email.focus();
    }
    function closeDialog() {
        backdrop.hidden = true;
        document.body.classList.remove("modal-open");
        Array.from(document.querySelectorAll("[inert]")).forEach((element) => element.removeAttribute("inert"));
        const previousId = backdrop.dataset.previousFocus;
        const previousFocus = previousId ? document.getElementById(previousId) : button;
        (previousFocus instanceof HTMLElement ? previousFocus : button).focus();
        backdrop.removeAttribute("data-previous-focus");
    }
    button.addEventListener("click", () => {
        backdrop.hidden ? openDialog() : closeDialog();
    });
    backdrop.addEventListener("click", (event) => {
        if (event.target === backdrop)
            closeDialog();
    });
    backdrop.addEventListener("keydown", (event) => {
        if (event.key === "Escape") {
            event.preventDefault();
            closeDialog();
            return;
        }
        if (event.key !== "Tab")
            return;
        const focusables = Array.from(dialog.querySelectorAll('button:not([disabled]), input:not([disabled]), [href], [tabindex]:not([tabindex="-1"])')).filter((element) => element.getClientRects().length > 0);
        if (!focusables.length)
            return;
        const first = focusables[0];
        const last = focusables[focusables.length - 1];
        if (event.shiftKey && document.activeElement === first) {
            event.preventDefault();
            last.focus();
        }
        else if (!event.shiftKey && document.activeElement === last) {
            event.preventDefault();
            first.focus();
        }
    });
    closeButtons.forEach((item) => item.addEventListener("click", () => closeDialog()));
    confirm.addEventListener("click", () => closeDialog());
    return closeDialog;
}
};

// ── module: src/dropdown.ts ──
__mods["src/dropdown.ts"] = function (exports, require, module) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createDropdown = createDropdown;
const utils_1 = require("./utils");
function createDropdown() {
    const button = (0, utils_1.querySelectorOrThrow)(document, "#menu-button");
    const menu = (0, utils_1.querySelectorOrThrow)(document, "#menu-items");
    const resultValue = (0, utils_1.querySelectorOrThrow)(document, "#menu-result-value");
    const items = Array.from(menu.querySelectorAll("[role='menuitem']"));
    let current = 0;
    function setOpen(open, initialIndex = -1) {
        menu.hidden = !open;
        button.setAttribute("aria-expanded", String(open));
        if (open && initialIndex >= 0)
            selectItem(initialIndex, false);
    }
    function selectItem(index, closeMenu = true) {
        current = (index + items.length) % items.length;
        items.forEach((item, itemIndex) => {
            item.removeAttribute("aria-current");
            if (itemIndex === current)
                item.setAttribute("aria-current", "true");
        });
        const label = items[current].dataset.menuValue?.replace("-", " ");
        if (label)
            resultValue.textContent = label.replace(/\b\w/g, (character) => character.toUpperCase());
        if (closeMenu) {
            setOpen(false);
            button.focus();
        }
    }
    button.addEventListener("click", () => {
        if (menu.hidden)
            setOpen(true, 0);
        else
            setOpen(false);
    });
    button.addEventListener("keydown", (event) => {
        if (event.key === "ArrowDown") {
            event.preventDefault();
            setOpen(true, 0);
        }
        else if (event.key === "Enter" || event.key === " ") {
            event.preventDefault();
            if (menu.hidden)
                setOpen(true, 0);
            else
                selectItem(current, false);
        }
    });
    menu.addEventListener("click", (event) => {
        const item = event.target.closest("[role='menuitem']");
        if (item)
            selectItem(items.indexOf(item), true);
    });
    menu.addEventListener("keydown", (event) => {
        if (event.key === "ArrowDown") {
            event.preventDefault();
            selectItem(current + 1, false);
        }
        else if (event.key === "ArrowUp") {
            event.preventDefault();
            selectItem(current - 1, false);
        }
        else if (event.key === "Home") {
            event.preventDefault();
            selectItem(0, false);
        }
        else if (event.key === "End") {
            event.preventDefault();
            selectItem(items.length - 1, false);
        }
        else if (event.key === "Escape") {
            event.preventDefault();
            setOpen(false);
            button.focus();
        }
        else if (event.key === "Tab") {
            setOpen(false);
        }
    });
    return () => setOpen(false);
}
};

// ── module: src/tabs.ts ──
__mods["src/tabs.ts"] = function (exports, require, module) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createTabs = createTabs;
const utils_1 = require("./utils");
function createTabs() {
    const tablist = (0, utils_1.querySelectorOrThrow)(document, "#project-tabs");
    const tabs = Array.from(tablist.querySelectorAll("[role='tab']"));
    const panels = tabs.map((tab) => (0, utils_1.querySelectorOrThrow)(document, `#${tab.getAttribute("aria-controls")}`));
    function activate(index, focus = true) {
        tabs.forEach((tab, tabIndex) => {
            const selected = tabIndex === index;
            tab.setAttribute("aria-selected", String(selected));
            tab.tabIndex = selected ? 0 : -1;
            tab.classList.toggle("is-active", selected);
            panels[tabIndex].hidden = !selected;
        });
        if (focus)
            tabs[index].focus();
    }
    tabs.forEach((tab, index) => {
        tab.addEventListener("click", () => activate(index));
        tab.addEventListener("keydown", (event) => {
            let nextIndex;
            if (event.key === "ArrowRight")
                nextIndex = (index + 1) % tabs.length;
            else if (event.key === "ArrowLeft")
                nextIndex = (index - 1 + tabs.length) % tabs.length;
            else if (event.key === "Home")
                nextIndex = 0;
            else if (event.key === "End")
                nextIndex = tabs.length - 1;
            if (nextIndex !== undefined) {
                event.preventDefault();
                activate(nextIndex);
            }
        });
    });
    return () => activate(0, false);
}
};

// ── module: src/combobox.ts ──
__mods["src/combobox.ts"] = function (exports, require, module) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createCombobox = createCombobox;
const utils_1 = require("./utils");
const CITIES = [
    "Amsterdam", "Auckland", "Bangkok", "Barcelona", "Berlin", "Boston", "Budapest",
    "Copenhagen", "Dublin", "Florence", "Hong Kong", "Lisbon", "London", "Los Angeles",
    "Melbourne", "Mexico City", "Montreal", "New York", "Osaka", "Porto", "San Francisco",
    "Singapore", "Stockholm", "Sydney", "Tokyo", "Toronto", "Vancouver", "Vienna", "Zurich",
];
function createCombobox() {
    const input = (0, utils_1.querySelectorOrThrow)(document, "#city-combobox");
    const listbox = (0, utils_1.querySelectorOrThrow)(document, "#city-options");
    const status = (0, utils_1.querySelectorOrThrow)(document, "#combo-status-text");
    let filtered = CITIES;
    let activeIndex = -1;
    let lastText = "";
    function render(query) {
        filtered = CITIES.filter((city) => city.toLowerCase().includes(query.toLowerCase()));
        listbox.replaceChildren();
        if (filtered.length === 0) {
            const empty = document.createElement("li");
            empty.className = "combo-empty";
            empty.setAttribute("role", "option");
            empty.id = "city-option-empty";
            empty.textContent = "No cities found";
            listbox.append(empty);
            activeIndex = -1;
        }
        else {
            filtered.forEach((city, index) => {
                const option = document.createElement("li");
                option.id = `city-option-${index}`;
                option.setAttribute("role", "option");
                option.setAttribute("aria-selected", index === activeIndex ? "true" : "false");
                option.textContent = city;
                listbox.append(option);
            });
            if (activeIndex < 0)
                activeIndex = 0;
        }
        const option = listbox.querySelector(`[id='city-option-${activeIndex}']`);
        option?.scrollIntoView({ block: "nearest" });
    }
    function openListbox(query) {
        input.value = query;
        lastText = query;
        render(query);
        input.setAttribute("aria-expanded", "true");
        input.setAttribute("aria-controls", "city-options");
        if (activeIndex >= 0)
            input.setAttribute("aria-activedescendant", `city-option-${activeIndex}`);
    }
    function closeListbox() {
        input.value = lastText;
        listbox.hidden = true;
        listbox.replaceChildren();
        activeIndex = -1;
        input.setAttribute("aria-expanded", "false");
        input.removeAttribute("aria-controls");
        input.removeAttribute("aria-activedescendant");
    }
    input.addEventListener("focus", () => {
        lastText = input.value;
        if (input.value)
            openListbox(input.value);
    });
    input.addEventListener("input", () => {
        activeIndex = -1;
        openListbox(input.value);
    });
    input.addEventListener("keydown", (event) => {
        if (input.getAttribute("aria-expanded") !== "true")
            return;
        if (event.key === "ArrowDown") {
            event.preventDefault();
            activeIndex = activeIndex < filtered.length - 1 ? activeIndex + 1 : 0;
            render(input.value);
            input.setAttribute("aria-activedescendant", `city-option-${activeIndex}`);
        }
        else if (event.key === "ArrowUp") {
            event.preventDefault();
            activeIndex = activeIndex > 0 ? activeIndex - 1 : filtered.length - 1;
            render(input.value);
            input.setAttribute("aria-activedescendant", `city-option-${activeIndex}`);
        }
        else if (event.key === "Enter") {
            event.preventDefault();
            if (activeIndex >= 0) {
                input.value = filtered[activeIndex];
                lastText = input.value;
                status.textContent = `Selected ${filtered[activeIndex]}`;
            }
            closeListbox();
            input.focus();
        }
        else if (event.key === "Escape") {
            event.preventDefault();
            closeListbox();
        }
        else if (event.key === "Home" || event.key === "End") {
            event.preventDefault();
            activeIndex = event.key === "Home" ? 0 : filtered.length - 1;
            render(input.value);
            input.setAttribute("aria-activedescendant", `city-option-${activeIndex}`);
        }
    });
    listbox.addEventListener("click", (event) => {
        const option = event.target.closest("[role='option']");
        if (!option)
            return;
        const index = Array.from(option.parentElement?.children ?? []).indexOf(option);
        if (index < 0)
            return;
        input.value = filtered[index];
        lastText = input.value;
        status.textContent = `Selected ${filtered[index]}`;
        closeListbox();
        input.focus();
    });
    input.addEventListener("blur", () => {
        window.setTimeout(() => closeListbox(), 0);
    });
    return () => closeListbox();
}
};

// ── module: src/accordion.ts ──
__mods["src/accordion.ts"] = function (exports, require, module) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createAccordion = createAccordion;
function createAccordion() {
    const items = Array.from(document.querySelectorAll(".accordion-item"));
    function setPanel(item, panel, open) {
        const button = item.querySelector(".accordion-button");
        if (!button)
            return;
        button.setAttribute("aria-expanded", String(open));
        const icon = item.querySelector(".accordion-icon");
        if (icon)
            icon.textContent = open ? "−" : "+";
        if (open) {
            panel.hidden = false;
            panel.style.height = "0px";
            const targetHeight = panel.scrollHeight;
            panel.style.height = `${targetHeight}px`;
            window.requestAnimationFrame(() => {
                panel.style.height = `${panel.scrollHeight}px`;
            });
            return;
        }
        panel.hidden = true;
        panel.style.height = "";
        panel.removeAttribute("style");
    }
    function toggle(item) {
        const panel = item.querySelector(".accordion-panel");
        if (!panel)
            return;
        setPanel(item, panel, panel.hidden !== true);
    }
    items.forEach((item) => item.querySelector(".accordion-button")?.addEventListener("click", () => toggle(item)));
    return () => undefined;
}
};

// ── entry ──
__require("src/main.ts");
})();
</script>
</body>
</html>