`), not the host page's own React root, so the two trees don't collide:
+
+```jsx
+const { Accordion } = window.AudiDashUI;
+ReactDOM.createRoot(document.getElementById('ds-root')).render(
);
+```
+
+## Tokens
+
+23 CSS custom properties from @audi-dash/ui. Names are
+preserved verbatim from upstream. They are declared inside `_ds_bundle.css` (this DS ships one compiled stylesheet rather than separate token files).
+
+- **typography** (1): `--font-stack`
+- **other** (22): `--red`, `--r-tile`, `--r-pill`, …
+
+## Components
+
+### general
+- `Accordion`
+- `ActionButton`
+- `Feld`
+- `Fig`
+- `IconButton`
+- `ImagePlaceholder`
+- `Pill`
+- `Popup`
+- `PopupMenuItem`
+- `ProgressBar`
+- `ProgressRing`
+- `RowList`
+- `Seg`
+- `StatGrid`
+- `StatusRow`
+- `SwipeRow`
+- `Switch`
+- `TabBar`
+- `Tile`
+
+### accordion
+- `LeafRow`
diff --git a/design/_ds/audi-dashboard-ui-27d66fd4-ed86-43b2-b8bf-61e281a5a1a5/_adherence.oxlintrc.json b/design/_ds/audi-dashboard-ui-27d66fd4-ed86-43b2-b8bf-61e281a5a1a5/_adherence.oxlintrc.json
new file mode 100644
index 0000000..9f6bcc6
--- /dev/null
+++ b/design/_ds/audi-dashboard-ui-27d66fd4-ed86-43b2-b8bf-61e281a5a1a5/_adherence.oxlintrc.json
@@ -0,0 +1,290 @@
+{
+ "plugins": [
+ "react",
+ "import"
+ ],
+ "rules": {
+ "react/forbid-elements": [
+ "warn",
+ {
+ "forbid": []
+ }
+ ],
+ "no-restricted-imports": [
+ "warn",
+ {
+ "patterns": [
+ {
+ "group": [
+ "components/accordion/LeafRow/**",
+ "components/general/Accordion/**",
+ "components/general/ActionButton/**",
+ "components/general/Feld/**",
+ "components/general/Fig/**",
+ "components/general/IconButton/**",
+ "components/general/ImagePlaceholder/**",
+ "components/general/Pill/**",
+ "components/general/Popup/**",
+ "components/general/PopupMenuItem/**",
+ "components/general/ProgressBar/**",
+ "components/general/ProgressRing/**",
+ "components/general/RowList/**",
+ "components/general/Seg/**",
+ "components/general/StatGrid/**",
+ "components/general/StatusRow/**",
+ "components/general/SwipeRow/**",
+ "components/general/Switch/**",
+ "components/general/TabBar/**",
+ "components/general/Tile/**"
+ ],
+ "message": "Import design-system components from 'index.js', not component internals."
+ }
+ ]
+ }
+ ],
+ "no-restricted-syntax": [
+ "warn",
+ {
+ "selector": "Literal[value=/#[0-9a-fA-F]{3,8}\\b/]",
+ "message": "Raw hex color — use a design-system color token via var()."
+ },
+ {
+ "selector": "Literal[value=/\\b\\d+px\\b/]",
+ "message": "Raw px value — use a design-system spacing token via var()."
+ },
+ {
+ "selector": "JSXOpeningElement[name.name='Accordion'] > JSXAttribute > JSXIdentifier[name!=/^(?:title|summary|open|defaultOpen|onOpenChange|level|children|className|key|ref|className|style|children)$/]",
+ "message": "
doesn't accept that prop. Declared props: title, summary, open, defaultOpen, onOpenChange, level, children, className."
+ },
+ {
+ "selector": "JSXOpeningElement[name.name='ActionButton'] > JSXAttribute > JSXIdentifier[name!=/^(?:children|onClick|variant|disabled|type|className|key|ref|className|style|children)$/]",
+ "message": " doesn't accept that prop. Declared props: children, onClick, variant, disabled, type, className."
+ },
+ {
+ "selector": "JSXOpeningElement[name.name='ActionButton'] > JSXAttribute[name.name='variant'] > Literal[value!=/^(?:default|destructive)$/]",
+ "message": " variant must be one of 'default' | 'destructive'."
+ },
+ {
+ "selector": "JSXOpeningElement[name.name='ActionButton'] > JSXAttribute[name.name='type'] > Literal[value!=/^(?:button|submit)$/]",
+ "message": " type must be one of 'button' | 'submit'."
+ },
+ {
+ "selector": "JSXOpeningElement[name.name='Feld'] > JSXAttribute > JSXIdentifier[name!=/^(?:label|value|children|unit|last|className|key|ref|className|style|children)$/]",
+ "message": " doesn't accept that prop. Declared props: label, value, children, unit, last, className."
+ },
+ {
+ "selector": "JSXOpeningElement[name.name='Fig'] > JSXAttribute > JSXIdentifier[name!=/^(?:value|unit|size|className|key|ref|className|style|children)$/]",
+ "message": " doesn't accept that prop. Declared props: value, unit, size, className."
+ },
+ {
+ "selector": "JSXOpeningElement[name.name='IconButton'] > JSXAttribute > JSXIdentifier[name!=/^(?:onClick|children|disabled|className|key|ref|className|style|children)$/]",
+ "message": " doesn't accept that prop. Declared props: onClick, children, disabled, className."
+ },
+ {
+ "selector": "JSXOpeningElement[name.name='ImagePlaceholder'] > JSXAttribute > JSXIdentifier[name!=/^(?:src|alt|label|hint|icon|size|className|key|ref|className|style|children)$/]",
+ "message": " doesn't accept that prop. Declared props: src, alt, label, hint, icon, size, className."
+ },
+ {
+ "selector": "JSXOpeningElement[name.name='ImagePlaceholder'] > JSXAttribute[name.name='size'] > Literal[value!=/^(?:default|mini|round)$/]",
+ "message": " size must be one of 'default' | 'mini' | 'round'."
+ },
+ {
+ "selector": "JSXOpeningElement[name.name='LeafRow'] > JSXAttribute > JSXIdentifier[name!=/^(?:title|subTitle|value|subValue|onClick|className|key|ref|className|style|children)$/]",
+ "message": " doesn't accept that prop. Declared props: title, subTitle, value, subValue, onClick, className."
+ },
+ {
+ "selector": "JSXOpeningElement[name.name='Pill'] > JSXAttribute > JSXIdentifier[name!=/^(?:children|variant|className|key|ref|className|style|children)$/]",
+ "message": " doesn't accept that prop. Declared props: children, variant, className."
+ },
+ {
+ "selector": "JSXOpeningElement[name.name='Pill'] > JSXAttribute[name.name='variant'] > Literal[value!=/^(?:default|work)$/]",
+ "message": " variant must be one of 'default' | 'work'."
+ },
+ {
+ "selector": "JSXOpeningElement[name.name='Popup'] > JSXAttribute > JSXIdentifier[name!=/^(?:open|onClose|variant|anchor|children|className|portalTarget|key|ref|className|style|children)$/]",
+ "message": " doesn't accept that prop. Declared props: open, onClose, variant, anchor, children, className, portalTarget."
+ },
+ {
+ "selector": "JSXOpeningElement[name.name='Popup'] > JSXAttribute[name.name='variant'] > Literal[value!=/^(?:menu|form)$/]",
+ "message": " variant must be one of 'menu' | 'form'."
+ },
+ {
+ "selector": "JSXOpeningElement[name.name='PopupMenuItem'] > JSXAttribute > JSXIdentifier[name!=/^(?:onClick|destructive|children|key|ref|className|style|children)$/]",
+ "message": " doesn't accept that prop. Declared props: onClick, destructive, children."
+ },
+ {
+ "selector": "JSXOpeningElement[name.name='ProgressBar'] > JSXAttribute > JSXIdentifier[name!=/^(?:percent|segments|showLegend|className|key|ref|className|style|children)$/]",
+ "message": " doesn't accept that prop. Declared props: percent, segments, showLegend, className."
+ },
+ {
+ "selector": "JSXOpeningElement[name.name='ProgressRing'] > JSXAttribute > JSXIdentifier[name!=/^(?:percent|value|unit|label|size|className|key|ref|className|style|children)$/]",
+ "message": " doesn't accept that prop. Declared props: percent, value, unit, label, size, className."
+ },
+ {
+ "selector": "JSXOpeningElement[name.name='RowList'] > JSXAttribute > JSXIdentifier[name!=/^(?:items|className|key|ref|className|style|children)$/]",
+ "message": " doesn't accept that prop. Declared props: items, className."
+ },
+ {
+ "selector": "JSXOpeningElement[name.name='Seg'] > JSXAttribute > JSXIdentifier[name!=/^(?:options|value|onChange|className|key|ref|className|style|children)$/]",
+ "message": " doesn't accept that prop. Declared props: options, value, onChange, className."
+ },
+ {
+ "selector": "JSXOpeningElement[name.name='StatGrid'] > JSXAttribute > JSXIdentifier[name!=/^(?:items|columns|className|key|ref|className|style|children)$/]",
+ "message": " doesn't accept that prop. Declared props: items, columns, className."
+ },
+ {
+ "selector": "JSXOpeningElement[name.name='StatusRow'] > JSXAttribute > JSXIdentifier[name!=/^(?:status|title|subtitle|onClick|className|key|ref|className|style|children)$/]",
+ "message": " doesn't accept that prop. Declared props: status, title, subtitle, onClick, className."
+ },
+ {
+ "selector": "JSXOpeningElement[name.name='StatusRow'] > JSXAttribute[name.name='status'] > Literal[value!=/^(?:ok|warn|bad)$/]",
+ "message": " status must be one of 'ok' | 'warn' | 'bad'."
+ },
+ {
+ "selector": "JSXOpeningElement[name.name='SwipeRow'] > JSXAttribute > JSXIdentifier[name!=/^(?:children|onDelete|deleteLabel|swiped|onSwipedChange|className|key|ref|className|style|children)$/]",
+ "message": " doesn't accept that prop. Declared props: children, onDelete, deleteLabel, swiped, onSwipedChange, className."
+ },
+ {
+ "selector": "JSXOpeningElement[name.name='Switch'] > JSXAttribute > JSXIdentifier[name!=/^(?:checked|onChange|disabled|id|className|key|ref|className|style|children)$/]",
+ "message": " doesn't accept that prop. Declared props: checked, onChange, disabled, id, className."
+ },
+ {
+ "selector": "JSXOpeningElement[name.name='TabBar'] > JSXAttribute > JSXIdentifier[name!=/^(?:items|activeKey|onChange|iconOnly|className|key|ref|className|style|children)$/]",
+ "message": " doesn't accept that prop. Declared props: items, activeKey, onChange, iconOnly, className."
+ },
+ {
+ "selector": "JSXOpeningElement[name.name='Tile'] > JSXAttribute > JSXIdentifier[name!=/^(?:variant|chevron|onClick|className|children|key|ref|className|style|children)$/]",
+ "message": " doesn't accept that prop. Declared props: variant, chevron, onClick, className, children."
+ },
+ {
+ "selector": "JSXOpeningElement[name.name='Tile'] > JSXAttribute[name.name='variant'] > Literal[value!=/^(?:default|button|flat)$/]",
+ "message": " variant must be one of 'default' | 'button' | 'flat'."
+ }
+ ]
+ },
+ "overrides": [
+ {
+ "files": [
+ "**/index.js"
+ ],
+ "rules": {
+ "no-restricted-imports": "off"
+ }
+ }
+ ],
+ "x-omelette": {
+ "components": {
+ "Accordion": {
+ "replaces": []
+ },
+ "ActionButton": {
+ "replaces": []
+ },
+ "Feld": {
+ "replaces": []
+ },
+ "Fig": {
+ "replaces": []
+ },
+ "IconButton": {
+ "replaces": []
+ },
+ "ImagePlaceholder": {
+ "replaces": []
+ },
+ "LeafRow": {
+ "replaces": []
+ },
+ "Pill": {
+ "replaces": []
+ },
+ "Popup": {
+ "replaces": []
+ },
+ "PopupMenuItem": {
+ "replaces": []
+ },
+ "ProgressBar": {
+ "replaces": []
+ },
+ "ProgressRing": {
+ "replaces": []
+ },
+ "RowList": {
+ "replaces": []
+ },
+ "Seg": {
+ "replaces": []
+ },
+ "StatGrid": {
+ "replaces": []
+ },
+ "StatusRow": {
+ "replaces": []
+ },
+ "SwipeRow": {
+ "replaces": []
+ },
+ "Switch": {
+ "replaces": []
+ },
+ "TabBar": {
+ "replaces": []
+ },
+ "Tile": {
+ "replaces": []
+ }
+ },
+ "tokens": [
+ "--bad",
+ "--canvas",
+ "--fg",
+ "--fg2",
+ "--fg3",
+ "--font-stack",
+ "--line",
+ "--line-strong",
+ "--ok",
+ "--r-func",
+ "--r-pill",
+ "--r-tile",
+ "--rahmen-hg",
+ "--red",
+ "--shade",
+ "--sp-1",
+ "--sp-2",
+ "--sp-3",
+ "--sp-4",
+ "--sp-5",
+ "--tile",
+ "--tile-2",
+ "--warn"
+ ],
+ "tokenKinds": {
+ "--red": "color",
+ "--r-tile": "spacing",
+ "--r-pill": "spacing",
+ "--r-func": "spacing",
+ "--rahmen-hg": "color",
+ "--sp-1": "spacing",
+ "--sp-2": "spacing",
+ "--sp-3": "spacing",
+ "--sp-4": "spacing",
+ "--sp-5": "spacing",
+ "--canvas": "color",
+ "--tile": "color",
+ "--tile-2": "color",
+ "--line": "color",
+ "--line-strong": "color",
+ "--fg": "color",
+ "--fg2": "color",
+ "--fg3": "color",
+ "--ok": "color",
+ "--warn": "color",
+ "--bad": "color",
+ "--shade": "color",
+ "--font-stack": "font"
+ },
+ "fontFamilies": []
+ }
+}
\ No newline at end of file
diff --git a/design/_ds/audi-dashboard-ui-27d66fd4-ed86-43b2-b8bf-61e281a5a1a5/_ds_bundle.css b/design/_ds/audi-dashboard-ui-27d66fd4-ed86-43b2-b8bf-61e281a5a1a5/_ds_bundle.css
new file mode 100644
index 0000000..5ba5e7d
--- /dev/null
+++ b/design/_ds/audi-dashboard-ui-27d66fd4-ed86-43b2-b8bf-61e281a5a1a5/_ds_bundle.css
@@ -0,0 +1,733 @@
+/* src/tokens/tokens.css */
+:root {
+ --red: #F50537;
+ --r-tile: 20px;
+ --r-pill: 999px;
+ --r-func: 8px;
+ --rahmen-hg: #111;
+ --sp-1: 4px;
+ --sp-2: 8px;
+ --sp-3: 12px;
+ --sp-4: 16px;
+ --sp-5: 22px;
+ --canvas: #161b23;
+ --tile: #1f2733;
+ --tile-2: #2a3341;
+ --line: rgba(255, 255, 255, .10);
+ --line-strong: rgba(255, 255, 255, .20);
+ --fg: #FFFFFF;
+ --fg2: #9aa1ad;
+ --fg3: #657081;
+ --ok: #15da15;
+ --warn: #ffaa00;
+ --bad: #fd2c4e;
+ --shade: rgba(255, 255, 255, .05);
+ --font-stack:
+ Helvetica,
+ Arial,
+ sans-serif;
+}
+[data-theme=tag] {
+ --canvas: #FFFFFF;
+ --tile: #f2f2f2;
+ --tile-2: #e5e5e5;
+ --line: rgba(0, 0, 0, .10);
+ --line-strong: rgba(0, 0, 0, .22);
+ --fg: #000000;
+ --fg2: #4c4c4c;
+ --fg3: #666666;
+ --ok: #0DA20D;
+ --warn: #ffaa00;
+ --bad: #eb0d3f;
+ --shade: rgba(0, 0, 0, .04);
+}
+.ads-root {
+ font-family: var(--font-stack);
+ font-variant-numeric: tabular-nums;
+ color: var(--fg);
+ background: var(--canvas);
+}
+.ads-eyebrow {
+ font-size: 10px;
+ letter-spacing: .2em;
+ text-transform: uppercase;
+ color: var(--fg3);
+ display: block;
+}
+.ads-title {
+ font-size: 23px;
+ letter-spacing: -.015em;
+ line-height: 1.15;
+ color: var(--fg);
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+.ads-label {
+ font-size: 10px;
+ letter-spacing: .2em;
+ text-transform: uppercase;
+ color: var(--fg3);
+ display: block;
+}
+.ads-sport {
+ font-style: italic;
+ letter-spacing: .005em;
+}
+
+/* src/components/Pill/Pill.css */
+.ads-pill {
+ display: inline-flex;
+ align-items: center;
+ font-size: 10px;
+ letter-spacing: .14em;
+ text-transform: uppercase;
+ color: var(--fg2);
+ border: 1px solid var(--line-strong);
+ border-radius: var(--r-pill);
+ padding: 6px 12px;
+}
+.ads-pill--work {
+ color: var(--red);
+ border-color: var(--red);
+}
+
+/* src/components/IconButton/IconButton.css */
+.ads-icon-button {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ width: 34px;
+ height: 34px;
+ border: none;
+ border-radius: 50%;
+ background: none;
+ color: var(--fg3);
+ cursor: pointer;
+ padding: 0;
+}
+.ads-icon-button svg {
+ width: 18px;
+ height: 18px;
+}
+.ads-icon-button:hover:not(:disabled) {
+ background: var(--tile-2);
+ color: var(--fg);
+}
+.ads-icon-button:disabled {
+ opacity: .4;
+ cursor: default;
+}
+
+/* src/components/Fig/Fig.css */
+.ads-fig {
+ font-weight: 300;
+ letter-spacing: -.02em;
+ line-height: .95;
+ color: var(--fg);
+}
+.ads-fig__unit {
+ font-size: .32em;
+ font-weight: 400;
+ letter-spacing: normal;
+ color: var(--fg2);
+ margin-left: .32em;
+}
+
+/* src/components/StatusRow/StatusRow.css */
+.ads-status {
+ display: flex;
+ align-items: center;
+ gap: var(--sp-3);
+ width: 100%;
+ background: none;
+ border: none;
+ padding: 0;
+ text-align: left;
+ font-family: inherit;
+ cursor: default;
+}
+button.ads-status {
+ cursor: pointer;
+}
+.ads-dot {
+ width: 11px;
+ height: 11px;
+ border-radius: 50%;
+ flex: 0 0 auto;
+}
+.ads-dot--ok {
+ background: var(--ok);
+}
+.ads-dot--warn {
+ background: var(--warn);
+}
+.ads-dot--bad {
+ background: var(--bad);
+}
+.ads-status__text {
+ display: flex;
+ flex-direction: column;
+}
+.ads-status__t {
+ font-size: 14px;
+ color: var(--fg);
+}
+.ads-status__s {
+ font-size: 11px;
+ color: var(--fg3);
+}
+
+/* src/components/ActionButton/ActionButton.css */
+.ads-action {
+ display: block;
+ width: 100%;
+ font-family: inherit;
+ font-size: 11px;
+ letter-spacing: .14em;
+ text-transform: uppercase;
+ color: var(--fg);
+ background: none;
+ border: 1px solid var(--line-strong);
+ border-radius: var(--r-pill);
+ padding: 14px;
+ cursor: pointer;
+}
+.ads-action:hover:not(:disabled) {
+ border-color: var(--red);
+}
+.ads-action:disabled {
+ opacity: .4;
+ cursor: default;
+}
+.ads-action--destructive {
+ color: var(--bad);
+ border-color: var(--bad);
+}
+.ads-action--destructive:hover:not(:disabled) {
+ background: var(--bad);
+ color: var(--fg);
+ border-color: var(--bad);
+}
+
+/* src/components/Switch/Switch.css */
+.ads-switch {
+ position: relative;
+ display: inline-block;
+ flex-shrink: 0;
+ width: 46px;
+ height: 27px;
+}
+.ads-switch input {
+ position: absolute;
+ inset: 0;
+ opacity: 0;
+ margin: 0;
+ cursor: pointer;
+ min-width: 0;
+}
+.ads-switch__track {
+ position: absolute;
+ inset: 0;
+ background: var(--tile-2);
+ border: 1px solid var(--line);
+ border-radius: var(--r-pill);
+ transition: background .18s;
+ pointer-events: none;
+}
+.ads-switch__track::before {
+ content: "";
+ position: absolute;
+ left: 2px;
+ top: 1px;
+ width: 23px;
+ height: 23px;
+ background: #fff;
+ border-radius: 50%;
+ transition: transform .18s;
+}
+.ads-switch input:checked + .ads-switch__track {
+ background: var(--red);
+ border-color: var(--red);
+}
+.ads-switch input:checked + .ads-switch__track::before {
+ transform: translateX(19px);
+}
+.ads-switch input:disabled + .ads-switch__track {
+ opacity: .4;
+}
+
+/* src/components/Seg/Seg.css */
+.ads-seg {
+ display: flex;
+ gap: var(--sp-2);
+}
+.ads-seg button {
+ flex: 1;
+ border: 1px solid var(--line-strong);
+ background: none;
+ color: var(--fg2);
+ font-family: inherit;
+ font-size: 11px;
+ letter-spacing: .12em;
+ text-transform: uppercase;
+ padding: 11px 8px;
+ border-radius: var(--r-pill);
+ cursor: pointer;
+}
+.ads-seg button.ads-seg__on {
+ border-color: var(--red);
+ color: var(--fg);
+}
+
+/* src/components/RowList/RowList.css */
+.ads-rows {
+ margin: 0;
+}
+.ads-row {
+ display: flex;
+ justify-content: space-between;
+ align-items: baseline;
+ gap: var(--sp-3);
+ padding: 13px 0;
+ border-bottom: 1px solid var(--line);
+}
+.ads-row:last-child {
+ border-bottom: 0;
+}
+.ads-row dt {
+ font-size: 13px;
+ color: var(--fg2);
+}
+.ads-row dd {
+ margin: 0;
+ font-size: 14px;
+ color: var(--fg);
+ text-align: right;
+}
+.ads-row dd small {
+ display: block;
+ font-size: 11px;
+ color: var(--fg3);
+}
+
+/* src/components/Accordion/LeafRow.css */
+.ads-leaf {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: var(--sp-3);
+ width: 100%;
+ background: none;
+ border: none;
+ font-family: inherit;
+ text-align: left;
+ padding: 12px 0 12px 44px;
+ cursor: default;
+ border-bottom: 1px solid var(--line);
+}
+button.ads-leaf {
+ cursor: pointer;
+}
+.ads-leaf__k {
+ font-size: 13.5px;
+ color: var(--fg);
+ display: flex;
+ flex-direction: column;
+}
+.ads-leaf__k small {
+ font-size: 11px;
+ color: var(--fg3);
+}
+.ads-leaf__v {
+ font-size: 13px;
+ color: var(--fg2);
+ text-align: right;
+ display: flex;
+ flex-direction: column;
+}
+.ads-leaf__v small {
+ font-size: 11px;
+ color: var(--fg3);
+}
+.ads-chev {
+ width: 6px;
+ height: 10px;
+ color: var(--fg3);
+ flex: 0 0 auto;
+}
+
+/* src/components/Tile/Tile.css */
+.ads-tile {
+ background: var(--tile);
+ border-radius: var(--r-tile);
+ padding: var(--sp-5);
+ margin-bottom: var(--sp-3);
+}
+.ads-tile--flat {
+ background: none;
+ padding: 0;
+}
+button.ads-tile--button {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ width: 100%;
+ border: none;
+ font-family: inherit;
+ text-align: left;
+ cursor: pointer;
+ position: relative;
+}
+button.ads-tile--button:hover {
+ background: var(--tile-2);
+}
+.ads-tile__content {
+ flex: 1;
+}
+.ads-tile__go {
+ width: 6px;
+ height: 10px;
+ color: var(--fg3);
+ flex: 0 0 auto;
+ margin-left: var(--sp-3);
+}
+
+/* src/components/Feld/Feld.css */
+.ads-feld {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ gap: var(--sp-4);
+ padding: 12px 0;
+ border-bottom: 1px solid var(--line);
+}
+.ads-feld--last {
+ border-bottom: 0;
+}
+.ads-feld label {
+ font-size: 13px;
+ color: var(--fg2);
+}
+.ads-feld input,
+.ads-feld select {
+ background: var(--tile-2);
+ border: 1px solid var(--line);
+ color: var(--fg);
+ font-family: inherit;
+ font-size: 13.5px;
+ padding: 8px 11px;
+ border-radius: var(--r-func);
+ text-align: right;
+ min-width: 132px;
+}
+.ads-mit-einheit {
+ display: inline-flex;
+ align-items: center;
+ gap: var(--sp-2);
+}
+.ads-mit-einheit input {
+ min-width: 92px;
+ text-align: right;
+}
+.ads-mit-einheit span:last-child {
+ font-size: 13px;
+ color: var(--fg2);
+}
+
+/* src/components/ProgressRing/ProgressRing.css */
+.ads-ring {
+ position: relative;
+ display: inline-block;
+}
+.ads-ring svg {
+ transform: rotate(-90deg);
+}
+.ads-ring__track {
+ fill: none;
+ stroke: var(--line);
+ stroke-width: 10;
+}
+.ads-ring__arc {
+ fill: none;
+ stroke: var(--red);
+ stroke-width: 10;
+ stroke-linecap: round;
+ transition: stroke-dashoffset .3s;
+}
+.ads-ring__mid {
+ position: absolute;
+ inset: 0;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ text-align: center;
+}
+
+/* src/components/ProgressBar/ProgressBar.css */
+.ads-balken {
+ height: 4px;
+ border-radius: var(--r-pill);
+ background: var(--line);
+ overflow: hidden;
+}
+.ads-balken i {
+ display: block;
+ height: 100%;
+ background: var(--fg);
+ border-radius: var(--r-pill);
+}
+.ads-bar {
+ display: flex;
+ height: 4px;
+ border-radius: var(--r-pill);
+ overflow: hidden;
+ gap: 2px;
+}
+.ads-bar i {
+ display: block;
+ border-radius: var(--r-pill);
+}
+.ads-legend {
+ display: flex;
+ flex-wrap: wrap;
+ gap: var(--sp-3);
+ margin-top: var(--sp-2);
+ font-size: 11px;
+ color: var(--fg2);
+}
+.ads-legend span {
+ display: inline-flex;
+ align-items: center;
+ gap: 6px;
+}
+.ads-legend i {
+ width: 8px;
+ height: 8px;
+ border-radius: 50%;
+ display: inline-block;
+}
+
+/* src/components/StatGrid/StatGrid.css */
+.ads-quad {
+ display: grid;
+ gap: var(--sp-4);
+}
+.ads-quad__n {
+ display: block;
+}
+.ads-quad__l {
+ display: block;
+ margin-top: 4px;
+ font-size: 9px;
+ letter-spacing: .12em;
+ text-transform: uppercase;
+ color: var(--fg3);
+}
+
+/* src/components/Accordion/Accordion.css */
+.ads-acc-h {
+ display: flex;
+ align-items: center;
+ gap: var(--sp-2);
+ width: 100%;
+ background: none;
+ border: none;
+ font-family: inherit;
+ text-align: left;
+ padding: 12px 0;
+ cursor: pointer;
+ border-bottom: 1px solid var(--line);
+}
+.ads-acc-h__k {
+ flex: 1;
+ font-size: 15px;
+ color: var(--fg);
+}
+.ads-acc-h__v {
+ font-size: 11.5px;
+ color: var(--fg2);
+ text-align: right;
+}
+.ads-mark {
+ width: 6px;
+ height: 10px;
+ border-right: 1.4px solid var(--fg3);
+ border-bottom: 1.4px solid var(--fg3);
+ transform: rotate(-45deg) scaleY(1);
+ transition: transform .15s, border-color .15s;
+}
+.ads-acc-h[aria-expanded=true] .ads-mark {
+ border-color: var(--red);
+ transform: rotate(45deg) scaleY(1);
+}
+.ads-acc-b {
+ display: none;
+}
+.ads-acc-b--on {
+ display: block;
+}
+.ads-accordion--lvl2 {
+ margin-left: 22px;
+}
+.ads-accordion--lvl2 .ads-acc-h__k {
+ font-size: 13px;
+}
+
+/* src/components/SwipeRow/SwipeRow.css */
+.ads-swipe-wrap {
+ position: relative;
+ overflow: hidden;
+}
+.ads-swipe-delete {
+ position: absolute;
+ inset: 0 0 0 auto;
+ width: 84px;
+ background: var(--bad);
+ color: #fff;
+ border: none;
+ font-family: inherit;
+ font-size: 11px;
+ letter-spacing: .08em;
+ text-transform: uppercase;
+ cursor: pointer;
+}
+.ads-swipe-content {
+ position: relative;
+ background: var(--tile);
+ touch-action: pan-y;
+ transition: transform .18s;
+}
+
+/* src/components/TabBar/TabBar.css */
+.ads-tabbar {
+ display: grid;
+ border-top: 1px solid var(--line);
+}
+.ads-tab {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: 4px;
+ padding: 10px 0 8px;
+ background: none;
+ border: none;
+ border-top: 2px solid transparent;
+ margin-top: -1px;
+ color: var(--fg3);
+ font-family: inherit;
+ cursor: pointer;
+}
+.ads-tab--on {
+ border-top-color: var(--red);
+ color: var(--fg);
+}
+.ads-tab__icon svg {
+ width: 21px;
+ height: 21px;
+}
+.ads-tabbar--ohne .ads-tab__icon svg {
+ width: 26px;
+ height: 26px;
+}
+.ads-tab__label {
+ font-size: 9px;
+ letter-spacing: .08em;
+ text-transform: uppercase;
+}
+
+/* src/components/Popup/Popup.css */
+.ads-popup-catcher {
+ position: fixed;
+ inset: 0;
+ z-index: 1000;
+ background: none;
+ border: none;
+}
+.ads-popup {
+ position: fixed;
+ z-index: 1001;
+ background: var(--tile-2);
+ border-radius: 14px;
+ padding: var(--sp-4);
+}
+.ads-popup--menu {
+ display: flex;
+ flex-direction: column;
+ min-width: 180px;
+}
+.ads-popup--form {
+ min-width: 260px;
+}
+.ads-popup-item {
+ display: block;
+ width: 100%;
+ text-align: left;
+ background: none;
+ border: none;
+ color: var(--fg);
+ font-family: inherit;
+ font-size: 13.5px;
+ padding: 10px 4px;
+ cursor: pointer;
+}
+.ads-popup-item--destructive {
+ color: var(--bad);
+}
+
+/* src/components/ImagePlaceholder/ImagePlaceholder.css */
+.ads-bildbox {
+ position: relative;
+ width: 100%;
+ aspect-ratio: 4 / 3;
+ border-radius: 12px;
+ overflow: hidden;
+}
+.ads-bildbox img {
+ display: block;
+ width: 100%;
+ height: 100%;
+ object-fit: cover;
+}
+.ads-bildbox--mini {
+ width: 78px;
+ height: 78px;
+ aspect-ratio: auto;
+ border-radius: 12px;
+}
+.ads-bildbox--round {
+ border-radius: 50%;
+}
+.ads-platzhalter {
+ width: 100%;
+ height: 100%;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ gap: 6px;
+ border: 1px dashed var(--line-strong);
+ border-radius: inherit;
+ color: var(--fg3);
+ text-align: center;
+ padding: var(--sp-2);
+}
+.ads-platzhalter__icon svg {
+ width: 26px;
+ height: 26px;
+ color: var(--fg3);
+}
+.ads-platzhalter__label {
+ font-size: 10.5px;
+ letter-spacing: .02em;
+ color: var(--fg3);
+}
+.ads-platzhalter__hint {
+ font-family: ui-monospace, monospace;
+ font-size: 9px;
+ color: var(--fg3);
+}
+
+/* src/styles.css */
+/*# sourceMappingURL=styles.css.map */
\ No newline at end of file
diff --git a/design/_ds/audi-dashboard-ui-27d66fd4-ed86-43b2-b8bf-61e281a5a1a5/_ds_bundle.js b/design/_ds/audi-dashboard-ui-27d66fd4-ed86-43b2-b8bf-61e281a5a1a5/_ds_bundle.js
new file mode 100644
index 0000000..3cc2679
--- /dev/null
+++ b/design/_ds/audi-dashboard-ui-27d66fd4-ed86-43b2-b8bf-61e281a5a1a5/_ds_bundle.js
@@ -0,0 +1,563 @@
+/* @ds-bundle: {"namespace":"AudiDashUI","components":[{"name":"Accordion","sourcePath":"components/general/Accordion/Accordion.jsx"},{"name":"ActionButton","sourcePath":"components/general/ActionButton/ActionButton.jsx"},{"name":"Feld","sourcePath":"components/general/Feld/Feld.jsx"},{"name":"Fig","sourcePath":"components/general/Fig/Fig.jsx"},{"name":"IconButton","sourcePath":"components/general/IconButton/IconButton.jsx"},{"name":"ImagePlaceholder","sourcePath":"components/general/ImagePlaceholder/ImagePlaceholder.jsx"},{"name":"LeafRow","sourcePath":"components/accordion/LeafRow/LeafRow.jsx"},{"name":"Pill","sourcePath":"components/general/Pill/Pill.jsx"},{"name":"Popup","sourcePath":"components/general/Popup/Popup.jsx"},{"name":"PopupMenuItem","sourcePath":"components/general/PopupMenuItem/PopupMenuItem.jsx"},{"name":"ProgressBar","sourcePath":"components/general/ProgressBar/ProgressBar.jsx"},{"name":"ProgressRing","sourcePath":"components/general/ProgressRing/ProgressRing.jsx"},{"name":"RowList","sourcePath":"components/general/RowList/RowList.jsx"},{"name":"Seg","sourcePath":"components/general/Seg/Seg.jsx"},{"name":"StatGrid","sourcePath":"components/general/StatGrid/StatGrid.jsx"},{"name":"StatusRow","sourcePath":"components/general/StatusRow/StatusRow.jsx"},{"name":"SwipeRow","sourcePath":"components/general/SwipeRow/SwipeRow.jsx"},{"name":"Switch","sourcePath":"components/general/Switch/Switch.jsx"},{"name":"TabBar","sourcePath":"components/general/TabBar/TabBar.jsx"},{"name":"Tile","sourcePath":"components/general/Tile/Tile.jsx"}],"sourceHashes":{"components/general/Accordion/Accordion.jsx":"e451421cbbee","components/general/Accordion/Accordion.d.ts":"0b821f95d8ec","components/general/Accordion/Accordion.prompt.md":"7b4714a7568d","components/general/ActionButton/ActionButton.jsx":"555676a71f72","components/general/ActionButton/ActionButton.d.ts":"faef681772e0","components/general/ActionButton/ActionButton.prompt.md":"1e8fad2d73f9","components/general/Feld/Feld.jsx":"fec8fe89e3b8","components/general/Feld/Feld.d.ts":"263528b0d195","components/general/Feld/Feld.prompt.md":"274cbafb13e5","components/general/Fig/Fig.jsx":"5870842c3cc9","components/general/Fig/Fig.d.ts":"a326dd89b7fd","components/general/Fig/Fig.prompt.md":"c60284795308","components/general/IconButton/IconButton.jsx":"fcd5ddfd2b26","components/general/IconButton/IconButton.d.ts":"e7a8c88afc00","components/general/IconButton/IconButton.prompt.md":"f311ce3928f4","components/general/ImagePlaceholder/ImagePlaceholder.jsx":"8ddcd8dab0a0","components/general/ImagePlaceholder/ImagePlaceholder.d.ts":"d6364f15e9c0","components/general/ImagePlaceholder/ImagePlaceholder.prompt.md":"43ca50be5f77","components/accordion/LeafRow/LeafRow.jsx":"ce900d42927c","components/accordion/LeafRow/LeafRow.d.ts":"85468f327f7a","components/accordion/LeafRow/LeafRow.prompt.md":"237acb37d8e6","components/general/Pill/Pill.jsx":"210d8cf6596a","components/general/Pill/Pill.d.ts":"530c874d26b6","components/general/Pill/Pill.prompt.md":"14374bc5a758","components/general/Popup/Popup.jsx":"bede56d5c4aa","components/general/Popup/Popup.d.ts":"469d967b7416","components/general/Popup/Popup.prompt.md":"6195801e8172","components/general/PopupMenuItem/PopupMenuItem.jsx":"0429937f4520","components/general/PopupMenuItem/PopupMenuItem.d.ts":"d98857eaf3c3","components/general/PopupMenuItem/PopupMenuItem.prompt.md":"8f18bd7e059b","components/general/ProgressBar/ProgressBar.jsx":"9ca1d1ea172a","components/general/ProgressBar/ProgressBar.d.ts":"baaa06ad6859","components/general/ProgressBar/ProgressBar.prompt.md":"039685a8659f","components/general/ProgressRing/ProgressRing.jsx":"78d41740d78b","components/general/ProgressRing/ProgressRing.d.ts":"15839d274511","components/general/ProgressRing/ProgressRing.prompt.md":"32b3e060530f","components/general/RowList/RowList.jsx":"62af0e4a633e","components/general/RowList/RowList.d.ts":"6f76bdb3711d","components/general/RowList/RowList.prompt.md":"2abce7b8d541","components/general/Seg/Seg.jsx":"0ad3d0f3e130","components/general/Seg/Seg.d.ts":"549442e8afad","components/general/Seg/Seg.prompt.md":"a1432f2825f6","components/general/StatGrid/StatGrid.jsx":"218bbd339935","components/general/StatGrid/StatGrid.d.ts":"a1b9d892b1a6","components/general/StatGrid/StatGrid.prompt.md":"0f1df1271fb0","components/general/StatusRow/StatusRow.jsx":"de77b6665985","components/general/StatusRow/StatusRow.d.ts":"3fe225d397b1","components/general/StatusRow/StatusRow.prompt.md":"cd33af1c2e77","components/general/SwipeRow/SwipeRow.jsx":"27451f62cae8","components/general/SwipeRow/SwipeRow.d.ts":"496e2058917a","components/general/SwipeRow/SwipeRow.prompt.md":"d191d8adba8c","components/general/Switch/Switch.jsx":"33ba18bc52cc","components/general/Switch/Switch.d.ts":"e5b2427866a1","components/general/Switch/Switch.prompt.md":"81f49ffeb8a6","components/general/TabBar/TabBar.jsx":"b74b7d431989","components/general/TabBar/TabBar.d.ts":"2e79e7e870c7","components/general/TabBar/TabBar.prompt.md":"dd8948507175","components/general/Tile/Tile.jsx":"b526964c5c96","components/general/Tile/Tile.d.ts":"b37ce97e2658","components/general/Tile/Tile.prompt.md":"e7cc32b1303d"},"inlinedExternals":[],"builtBy":"cc-design-sync"} */
+"use strict";
+var AudiDashUI = (() => {
+ var __create = Object.create;
+ var __defProp = Object.defineProperty;
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
+ var __getOwnPropNames = Object.getOwnPropertyNames;
+ var __getProtoOf = Object.getPrototypeOf;
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
+ var __esm = (fn, res, err) => function __init() {
+ if (err) throw err[0];
+ try {
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
+ } catch (e) {
+ throw err = [e], e;
+ }
+ };
+ var __commonJS = (cb, mod) => function __require() {
+ try {
+ return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
+ } catch (e) {
+ throw mod = 0, e;
+ }
+ };
+ var __export = (target, all) => {
+ for (var name in all)
+ __defProp(target, name, { get: all[name], enumerable: true });
+ };
+ var __copyProps = (to, from, except, desc) => {
+ if (from && typeof from === "object" || typeof from === "function") {
+ for (let key of __getOwnPropNames(from))
+ if (!__hasOwnProp.call(to, key) && key !== except)
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
+ }
+ return to;
+ };
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
+ // If the importer is in node compatibility mode or this is not an ESM
+ // file that has been converted to a CommonJS file using a Babel-
+ // compatible transform (i.e. "__esModule" has not been set), then set
+ // "default" to the CommonJS "module.exports" for node compatibility.
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
+ mod
+ ));
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
+
+ //
+ var init_define_import_meta_env = __esm({
+ ""() {
+ }
+ });
+
+ // shim:react-shim
+ var require_react_shim = __commonJS({
+ "shim:react-shim"(exports, module) {
+ init_define_import_meta_env();
+ var R = window.React;
+ function np(p, k) {
+ var o = {};
+ for (var x in p) if (x !== "children") o[x] = p[x];
+ if (k !== void 0) o.key = k;
+ return o;
+ }
+ function jsx20(t, p, k) {
+ var c = p && p.children;
+ return c === void 0 ? R.createElement(t, np(p, k)) : R.createElement(t, np(p, k), c);
+ }
+ function jsxs16(t, p, k) {
+ return R.createElement.apply(R, [t, np(p, k)].concat(p.children));
+ }
+ module.exports = R;
+ module.exports.jsx = jsx20;
+ module.exports.jsxs = jsxs16;
+ module.exports.jsxDEV = function(t, p, k, s) {
+ return (s ? jsxs16 : jsx20)(t, p, k);
+ };
+ module.exports.Fragment = R.Fragment;
+ }
+ });
+
+ // shim:react-dom-shim
+ var require_react_dom_shim = __commonJS({
+ "shim:react-dom-shim"(exports, module) {
+ init_define_import_meta_env();
+ var D = window.ReactDOM;
+ var n = function() {
+ };
+ module.exports = Object.assign({ preload: n, preinit: n, preconnect: n, prefetchDNS: n, preloadModule: n, preinitModule: n }, D);
+ }
+ });
+
+ // dist/index.js
+ var index_exports = {};
+ __export(index_exports, {
+ Accordion: () => Accordion,
+ ActionButton: () => ActionButton,
+ Feld: () => Feld,
+ Fig: () => Fig,
+ IconButton: () => IconButton,
+ ImagePlaceholder: () => ImagePlaceholder,
+ LeafRow: () => LeafRow,
+ Pill: () => Pill,
+ Popup: () => Popup,
+ PopupMenuItem: () => PopupMenuItem,
+ ProgressBar: () => ProgressBar,
+ ProgressRing: () => ProgressRing,
+ RowList: () => RowList,
+ Seg: () => Seg,
+ StatGrid: () => StatGrid,
+ StatusRow: () => StatusRow,
+ SwipeRow: () => SwipeRow,
+ Switch: () => Switch,
+ TabBar: () => TabBar,
+ Tile: () => Tile
+ });
+ init_define_import_meta_env();
+ var import_jsx_runtime = __toESM(require_react_shim(), 1);
+ var import_jsx_runtime2 = __toESM(require_react_shim(), 1);
+ var import_jsx_runtime3 = __toESM(require_react_shim(), 1);
+ var import_jsx_runtime4 = __toESM(require_react_shim(), 1);
+ var import_jsx_runtime5 = __toESM(require_react_shim(), 1);
+ var import_jsx_runtime6 = __toESM(require_react_shim(), 1);
+ var import_jsx_runtime7 = __toESM(require_react_shim(), 1);
+ var import_jsx_runtime8 = __toESM(require_react_shim(), 1);
+ var import_jsx_runtime9 = __toESM(require_react_shim(), 1);
+ var import_jsx_runtime10 = __toESM(require_react_shim(), 1);
+ var import_jsx_runtime11 = __toESM(require_react_shim(), 1);
+ var import_jsx_runtime12 = __toESM(require_react_shim(), 1);
+ var import_jsx_runtime13 = __toESM(require_react_shim(), 1);
+ var React = __toESM(require_react_shim(), 1);
+ var import_jsx_runtime14 = __toESM(require_react_shim(), 1);
+ var import_jsx_runtime15 = __toESM(require_react_shim(), 1);
+ var React2 = __toESM(require_react_shim(), 1);
+ var import_jsx_runtime16 = __toESM(require_react_shim(), 1);
+ var import_jsx_runtime17 = __toESM(require_react_shim(), 1);
+ var import_react_dom = __toESM(require_react_dom_shim(), 1);
+ var import_jsx_runtime18 = __toESM(require_react_shim(), 1);
+ var React3 = __toESM(require_react_shim(), 1);
+ var import_jsx_runtime19 = __toESM(require_react_shim(), 1);
+ function Pill({ children, variant = "default", className }) {
+ const classes = ["ads-pill"];
+ if (variant === "work") classes.push("ads-pill--work");
+ if (className) classes.push(className);
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: classes.join(" "), children });
+ }
+ function IconButton({
+ onClick,
+ children,
+ disabled,
+ className,
+ ...rest
+ }) {
+ const classes = ["ads-icon-button"];
+ if (className) classes.push(className);
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
+ "button",
+ {
+ type: "button",
+ className: classes.join(" "),
+ onClick,
+ disabled,
+ ...rest,
+ children
+ }
+ );
+ }
+ function Fig({ value, unit, size, className }) {
+ const classes = ["ads-fig"];
+ if (className) classes.push(className);
+ const style = size !== void 0 ? { fontSize: typeof size === "number" ? `${size}px` : size } : void 0;
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: classes.join(" "), style, children: [
+ value,
+ unit !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "ads-fig__unit", children: unit })
+ ] });
+ }
+ function StatusRow({ status, title, subtitle, onClick, className }) {
+ const classes = ["ads-status"];
+ if (className) classes.push(className);
+ const Tag = onClick ? "button" : "div";
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
+ Tag,
+ {
+ type: onClick ? "button" : void 0,
+ className: classes.join(" "),
+ onClick,
+ children: [
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: `ads-dot ads-dot--${status}`, "aria-hidden": true }),
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: "ads-status__text", children: [
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "ads-status__t", children: title }),
+ subtitle !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "ads-status__s", children: subtitle })
+ ] })
+ ]
+ }
+ );
+ }
+ function ActionButton({
+ children,
+ onClick,
+ variant = "default",
+ disabled,
+ type = "button",
+ className
+ }) {
+ const classes = ["ads-action"];
+ if (variant === "destructive") classes.push("ads-action--destructive");
+ if (className) classes.push(className);
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { type, className: classes.join(" "), onClick, disabled, children });
+ }
+ function Switch({
+ checked,
+ onChange,
+ disabled,
+ id,
+ className,
+ ...rest
+ }) {
+ const classes = ["ads-switch"];
+ if (className) classes.push(className);
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: classes.join(" "), children: [
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
+ "input",
+ {
+ type: "checkbox",
+ role: "switch",
+ id,
+ checked,
+ disabled,
+ onChange: (e) => onChange(e.target.checked),
+ ...rest
+ }
+ ),
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "ads-switch__track", "aria-hidden": true })
+ ] });
+ }
+ function Seg({
+ options,
+ value,
+ onChange,
+ className
+ }) {
+ const classes = ["ads-seg"];
+ if (className) classes.push(className);
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: classes.join(" "), children: options.map((opt) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
+ "button",
+ {
+ type: "button",
+ className: opt.value === value ? "ads-seg__on" : void 0,
+ onClick: () => onChange(opt.value),
+ children: opt.label
+ },
+ opt.value
+ )) });
+ }
+ function RowList({ items, className }) {
+ const classes = ["ads-rows"];
+ if (className) classes.push(className);
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("dl", { className: classes.join(" "), children: items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "ads-row", children: [
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("dt", { children: item.label }),
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("dd", { children: [
+ item.value,
+ item.subValue !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("small", { children: item.subValue })
+ ] })
+ ] }, item.key)) });
+ }
+ function Tile({ variant = "default", chevron, onClick, className, children }) {
+ const classes = ["ads-tile"];
+ if (variant === "flat") classes.push("ads-tile--flat");
+ if (variant === "button") classes.push("ads-tile--button");
+ if (className) classes.push(className);
+ if (variant === "button") {
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("button", { type: "button", className: classes.join(" "), onClick, children: [
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "ads-tile__content", children }),
+ chevron && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("svg", { className: "ads-tile__go", viewBox: "0 0 6 10", "aria-hidden": true, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("path", { d: "M1 1l4 4-4 4", fill: "none", stroke: "currentColor", strokeWidth: "1.4" }) })
+ ] });
+ }
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: classes.join(" "), children });
+ }
+ function Feld({ label, value, children, unit, last, className }) {
+ const classes = ["ads-feld"];
+ if (last) classes.push("ads-feld--last");
+ if (className) classes.push(className);
+ const control = children ? unit ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: "ads-mit-einheit", children: [
+ children,
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { children: unit })
+ ] }) : children : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { children: value });
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: classes.join(" "), children: [
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("label", { children: label }),
+ control
+ ] });
+ }
+ var RADIUS = 64;
+ var CIRCUMFERENCE = 2 * Math.PI * RADIUS;
+ function ProgressRing({
+ percent,
+ value,
+ unit,
+ label,
+ size = 150,
+ className
+ }) {
+ const clamped = Math.max(0, Math.min(100, percent));
+ const offset = CIRCUMFERENCE * (1 - clamped / 100);
+ const classes = ["ads-ring"];
+ if (className) classes.push(className);
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: classes.join(" "), style: { width: size, height: size }, children: [
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("svg", { viewBox: "0 0 150 150", width: size, height: size, children: [
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("circle", { cx: "75", cy: "75", r: RADIUS, className: "ads-ring__track" }),
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
+ "circle",
+ {
+ cx: "75",
+ cy: "75",
+ r: RADIUS,
+ className: "ads-ring__arc",
+ strokeDasharray: CIRCUMFERENCE,
+ strokeDashoffset: offset
+ }
+ )
+ ] }),
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { className: "ads-ring__mid", children: [
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Fig, { value: value ?? Math.round(clamped), unit }),
+ label !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "ads-label", children: label })
+ ] })
+ ] });
+ }
+ function ProgressBar({ percent, segments, showLegend, className }) {
+ const classes = ["ads-progress-bar"];
+ if (className) classes.push(className);
+ if (segments && segments.length > 0) {
+ const total = segments.reduce((sum, s) => sum + s.value, 0) || 1;
+ const legend = showLegend ?? segments.length > 1;
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: classes.join(" "), children: [
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "ads-bar", children: segments.map((seg, i) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
+ "i",
+ {
+ style: { flex: seg.value / total, background: seg.color ?? "var(--fg)" }
+ },
+ i
+ )) }),
+ legend && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "ads-legend", children: segments.map((seg, i) => /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { children: [
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("i", { style: { background: seg.color ?? "var(--fg)" } }),
+ seg.label
+ ] }, i)) })
+ ] });
+ }
+ const clamped = Math.max(0, Math.min(100, percent ?? 0));
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: classes.join(" "), children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "ads-balken", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("i", { style: { width: `${clamped}%` } }) }) });
+ }
+ function StatGrid({ items, columns = 4, className }) {
+ const classes = ["ads-quad"];
+ if (className) classes.push(className);
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: classes.join(" "), style: { gridTemplateColumns: `repeat(${columns}, 1fr)` }, children: items.map((item, i) => /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { children: [
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Fig, { className: "ads-quad__n", value: item.value, unit: item.unit, size: 17 }),
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "ads-quad__l", children: item.caption })
+ ] }, i)) });
+ }
+ function Accordion({
+ title,
+ summary,
+ open,
+ defaultOpen = false,
+ onOpenChange,
+ level = 1,
+ children,
+ className
+ }) {
+ const [internalOpen, setInternalOpen] = React.useState(defaultOpen);
+ const isControlled = open !== void 0;
+ const isOpen = isControlled ? open : internalOpen;
+ const toggle = () => {
+ const next = !isOpen;
+ if (!isControlled) setInternalOpen(next);
+ onOpenChange?.(next);
+ };
+ const classes = ["ads-accordion"];
+ if (level === 2) classes.push("ads-accordion--lvl2");
+ if (className) classes.push(className);
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: classes.join(" "), children: [
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("button", { type: "button", className: "ads-acc-h", onClick: toggle, "aria-expanded": isOpen, children: [
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "ads-acc-h__k", children: title }),
+ summary !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "ads-acc-h__v", children: summary }),
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "ads-mark", "aria-hidden": true })
+ ] }),
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: isOpen ? "ads-acc-b ads-acc-b--on" : "ads-acc-b", children })
+ ] });
+ }
+ function LeafRow({ title, subTitle, value, subValue, onClick, className }) {
+ const classes = ["ads-leaf"];
+ if (className) classes.push(className);
+ const Tag = onClick ? "button" : "div";
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(Tag, { type: onClick ? "button" : void 0, className: classes.join(" "), onClick, children: [
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("span", { className: "ads-leaf__k", children: [
+ title,
+ subTitle !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("small", { children: subTitle })
+ ] }),
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("span", { className: "ads-leaf__v", children: [
+ value,
+ subValue !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("small", { children: subValue })
+ ] }),
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("svg", { className: "ads-chev", viewBox: "0 0 6 10", "aria-hidden": true, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("path", { d: "M1 1l4 4-4 4", fill: "none", stroke: "currentColor", strokeWidth: "1.4" }) })
+ ] });
+ }
+ var SWIPE_THRESHOLD = -40;
+ var SWIPE_OPEN = -84;
+ var listeners = /* @__PURE__ */ new Set();
+ function closeAllExcept(keep) {
+ for (const close of listeners) {
+ if (close !== keep) close();
+ }
+ }
+ function SwipeRow({
+ children,
+ onDelete,
+ deleteLabel = "Delete",
+ swiped,
+ onSwipedChange,
+ className
+ }) {
+ const [internalSwiped, setInternalSwiped] = React2.useState(false);
+ const isControlled = swiped !== void 0;
+ const isSwiped = isControlled ? swiped : internalSwiped;
+ const setSwiped = React2.useCallback(
+ (next) => {
+ if (!isControlled) setInternalSwiped(next);
+ onSwipedChange?.(next);
+ },
+ [isControlled, onSwipedChange]
+ );
+ const close = React2.useCallback(() => setSwiped(false), [setSwiped]);
+ React2.useEffect(() => {
+ listeners.add(close);
+ return () => {
+ listeners.delete(close);
+ };
+ }, [close]);
+ const dragStartX = React2.useRef(null);
+ const onPointerDown = (e) => {
+ dragStartX.current = e.clientX;
+ };
+ const onPointerMove = (e) => {
+ if (dragStartX.current === null) return;
+ const delta = e.clientX - dragStartX.current;
+ if (delta < SWIPE_THRESHOLD) {
+ closeAllExcept(close);
+ setSwiped(true);
+ dragStartX.current = null;
+ } else if (delta > -SWIPE_THRESHOLD) {
+ setSwiped(false);
+ }
+ };
+ const onPointerUp = () => {
+ dragStartX.current = null;
+ };
+ const classes = ["ads-swipe-wrap"];
+ if (className) classes.push(className);
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: classes.join(" "), children: [
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("button", { type: "button", className: "ads-swipe-delete", onClick: onDelete, children: deleteLabel }),
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
+ "div",
+ {
+ className: isSwiped ? "ads-swipe-content ads-swiped" : "ads-swipe-content",
+ style: { transform: isSwiped ? `translateX(${SWIPE_OPEN}px)` : void 0 },
+ onPointerDown,
+ onPointerMove,
+ onPointerUp,
+ onPointerCancel: onPointerUp,
+ children
+ }
+ )
+ ] });
+ }
+ function TabBar({ items, activeKey, onChange, iconOnly, className }) {
+ const classes = ["ads-tabbar"];
+ if (iconOnly) classes.push("ads-tabbar--ohne");
+ if (className) classes.push(className);
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
+ "nav",
+ {
+ className: classes.join(" "),
+ style: { gridTemplateColumns: `repeat(${items.length}, 1fr)` },
+ children: items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
+ "button",
+ {
+ type: "button",
+ className: item.key === activeKey ? "ads-tab ads-tab--on" : "ads-tab",
+ onClick: () => onChange(item.key),
+ children: [
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "ads-tab__icon", children: item.icon }),
+ !iconOnly && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "ads-tab__label", children: item.label })
+ ]
+ },
+ item.key
+ ))
+ }
+ );
+ }
+ function Popup({
+ open,
+ onClose,
+ variant = "menu",
+ anchor = "center",
+ children,
+ className,
+ portalTarget
+ }) {
+ if (!open) return null;
+ const classes = ["ads-popup", `ads-popup--${variant}`];
+ if (className) classes.push(className);
+ const style = anchor === "center" ? { top: "50%", left: "50%", transform: "translate(-50%, -50%)" } : { ...anchor };
+ const content = /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "ads-popup-catcher", onClick: onClose }),
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: classes.join(" "), style, children })
+ ] });
+ const target = portalTarget ?? (typeof document !== "undefined" ? document.body : null);
+ return target ? (0, import_react_dom.createPortal)(content, target) : content;
+ }
+ function PopupMenuItem({ onClick, destructive, children }) {
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
+ "button",
+ {
+ type: "button",
+ className: destructive ? "ads-popup-item ads-popup-item--destructive" : "ads-popup-item",
+ onClick,
+ children
+ }
+ );
+ }
+ var DEFAULT_ICON = /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("svg", { viewBox: "0 0 24 24", width: "26", height: "26", "aria-hidden": true, children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
+ "path",
+ {
+ fill: "currentColor",
+ fillRule: "evenodd",
+ d: "M4 5a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V5Zm2 0v14h12V5H6Zm3 3a1.5 1.5 0 1 1 0 3 1.5 1.5 0 0 1 0-3Zm-1 8 3-3 2 2 3-4 3 5H8Z",
+ clipRule: "evenodd"
+ }
+ ) });
+ function ImagePlaceholder({
+ src,
+ alt,
+ label,
+ hint,
+ icon,
+ size = "default",
+ className
+ }) {
+ const [failed, setFailed] = React3.useState(false);
+ const classes = ["ads-bildbox"];
+ if (size === "mini") classes.push("ads-bildbox--mini");
+ if (size === "round") classes.push("ads-bildbox--round");
+ if (className) classes.push(className);
+ const showPlaceholder = !src || failed;
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: classes.join(" "), children: [
+ !showPlaceholder && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("img", { src, alt, onError: () => setFailed(true) }),
+ showPlaceholder && /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "ads-platzhalter", children: [
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "ads-platzhalter__icon", children: icon ?? DEFAULT_ICON }),
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "ads-platzhalter__label", children: label }),
+ hint !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "ads-platzhalter__hint", children: hint })
+ ] })
+ ] });
+ }
+ return __toCommonJS(index_exports);
+})();
+window.AudiDashUI=AudiDashUI.__dsMainNs?Object.assign({},AudiDashUI,AudiDashUI.__dsMainNs,{__dsMainNs:undefined}):AudiDashUI;
diff --git a/design/_ds/audi-dashboard-ui-27d66fd4-ed86-43b2-b8bf-61e281a5a1a5/_ds_manifest.json b/design/_ds/audi-dashboard-ui-27d66fd4-ed86-43b2-b8bf-61e281a5a1a5/_ds_manifest.json
new file mode 100644
index 0000000..a1dedf9
--- /dev/null
+++ b/design/_ds/audi-dashboard-ui-27d66fd4-ed86-43b2-b8bf-61e281a5a1a5/_ds_manifest.json
@@ -0,0 +1 @@
+{"namespace":"AudiDashUI","components":[{"name":"Accordion","sourcePath":"components/general/Accordion/Accordion.jsx"},{"name":"ActionButton","sourcePath":"components/general/ActionButton/ActionButton.jsx"},{"name":"Feld","sourcePath":"components/general/Feld/Feld.jsx"},{"name":"Fig","sourcePath":"components/general/Fig/Fig.jsx"},{"name":"IconButton","sourcePath":"components/general/IconButton/IconButton.jsx"},{"name":"ImagePlaceholder","sourcePath":"components/general/ImagePlaceholder/ImagePlaceholder.jsx"},{"name":"LeafRow","sourcePath":"components/accordion/LeafRow/LeafRow.jsx"},{"name":"Pill","sourcePath":"components/general/Pill/Pill.jsx"},{"name":"Popup","sourcePath":"components/general/Popup/Popup.jsx"},{"name":"PopupMenuItem","sourcePath":"components/general/PopupMenuItem/PopupMenuItem.jsx"},{"name":"ProgressBar","sourcePath":"components/general/ProgressBar/ProgressBar.jsx"},{"name":"ProgressRing","sourcePath":"components/general/ProgressRing/ProgressRing.jsx"},{"name":"RowList","sourcePath":"components/general/RowList/RowList.jsx"},{"name":"Seg","sourcePath":"components/general/Seg/Seg.jsx"},{"name":"StatGrid","sourcePath":"components/general/StatGrid/StatGrid.jsx"},{"name":"StatusRow","sourcePath":"components/general/StatusRow/StatusRow.jsx"},{"name":"SwipeRow","sourcePath":"components/general/SwipeRow/SwipeRow.jsx"},{"name":"Switch","sourcePath":"components/general/Switch/Switch.jsx"},{"name":"TabBar","sourcePath":"components/general/TabBar/TabBar.jsx"},{"name":"Tile","sourcePath":"components/general/Tile/Tile.jsx"}],"startingPoints":[],"cards":[{"path":"components/accordion/LeafRow/LeafRow.html","group":"accordion"},{"path":"components/general/Accordion/Accordion.html","group":"general","viewport":"900x700"},{"path":"components/general/ActionButton/ActionButton.html","group":"general"},{"path":"components/general/Feld/Feld.html","group":"general","viewport":"900x700"},{"path":"components/general/Fig/Fig.html","group":"general"},{"path":"components/general/IconButton/IconButton.html","group":"general"},{"path":"components/general/ImagePlaceholder/ImagePlaceholder.html","group":"general"},{"path":"components/general/Pill/Pill.html","group":"general"},{"path":"components/general/Popup/Popup.html","group":"general","viewport":"340x300"},{"path":"components/general/PopupMenuItem/PopupMenuItem.html","group":"general"},{"path":"components/general/ProgressBar/ProgressBar.html","group":"general"},{"path":"components/general/ProgressRing/ProgressRing.html","group":"general"},{"path":"components/general/RowList/RowList.html","group":"general"},{"path":"components/general/Seg/Seg.html","group":"general"},{"path":"components/general/StatGrid/StatGrid.html","group":"general","viewport":"900x700"},{"path":"components/general/StatusRow/StatusRow.html","group":"general"},{"path":"components/general/SwipeRow/SwipeRow.html","group":"general"},{"path":"components/general/Switch/Switch.html","group":"general"},{"path":"components/general/TabBar/TabBar.html","group":"general","viewport":"900x700"},{"path":"components/general/Tile/Tile.html","group":"general"}],"templates":[],"hasThumbnailHtml":false,"globalCssPaths":["_ds_bundle.css","styles.css"],"tokens":[{"name":"--red","value":"#F50537","kind":"color","definedIn":"_ds_bundle.css"},{"name":"--r-tile","value":"20px","kind":"spacing","definedIn":"_ds_bundle.css"},{"name":"--r-pill","value":"999px","kind":"spacing","definedIn":"_ds_bundle.css"},{"name":"--r-func","value":"8px","kind":"spacing","definedIn":"_ds_bundle.css"},{"name":"--rahmen-hg","value":"#111","kind":"color","definedIn":"_ds_bundle.css"},{"name":"--sp-1","value":"4px","kind":"spacing","definedIn":"_ds_bundle.css"},{"name":"--sp-2","value":"8px","kind":"spacing","definedIn":"_ds_bundle.css"},{"name":"--sp-3","value":"12px","kind":"spacing","definedIn":"_ds_bundle.css"},{"name":"--sp-4","value":"16px","kind":"spacing","definedIn":"_ds_bundle.css"},{"name":"--sp-5","value":"22px","kind":"spacing","definedIn":"_ds_bundle.css"},{"name":"--canvas","value":"#161b23","kind":"color","definedIn":"_ds_bundle.css"},{"name":"--tile","value":"#1f2733","kind":"color","definedIn":"_ds_bundle.css"},{"name":"--tile-2","value":"#2a3341","kind":"color","definedIn":"_ds_bundle.css"},{"name":"--line","value":"rgba(255, 255, 255, .10)","kind":"color","definedIn":"_ds_bundle.css"},{"name":"--line-strong","value":"rgba(255, 255, 255, .20)","kind":"color","definedIn":"_ds_bundle.css"},{"name":"--fg","value":"#FFFFFF","kind":"color","definedIn":"_ds_bundle.css"},{"name":"--fg2","value":"#9aa1ad","kind":"color","definedIn":"_ds_bundle.css"},{"name":"--fg3","value":"#657081","kind":"color","definedIn":"_ds_bundle.css"},{"name":"--ok","value":"#15da15","kind":"color","definedIn":"_ds_bundle.css"},{"name":"--warn","value":"#ffaa00","kind":"color","definedIn":"_ds_bundle.css"},{"name":"--bad","value":"#fd2c4e","kind":"color","definedIn":"_ds_bundle.css"},{"name":"--shade","value":"rgba(255, 255, 255, .05)","kind":"color","definedIn":"_ds_bundle.css"},{"name":"--font-stack","value":"Helvetica,\n Arial,\n sans-serif","kind":"font","definedIn":"_ds_bundle.css"},{"name":"--canvas","value":"#FFFFFF","kind":"color","definedIn":"_ds_bundle.css","scope":"[data-theme=tag]"},{"name":"--tile","value":"#f2f2f2","kind":"color","definedIn":"_ds_bundle.css","scope":"[data-theme=tag]"},{"name":"--tile-2","value":"#e5e5e5","kind":"color","definedIn":"_ds_bundle.css","scope":"[data-theme=tag]"},{"name":"--line","value":"rgba(0, 0, 0, .10)","kind":"color","definedIn":"_ds_bundle.css","scope":"[data-theme=tag]"},{"name":"--line-strong","value":"rgba(0, 0, 0, .22)","kind":"color","definedIn":"_ds_bundle.css","scope":"[data-theme=tag]"},{"name":"--fg","value":"#000000","kind":"color","definedIn":"_ds_bundle.css","scope":"[data-theme=tag]"},{"name":"--fg2","value":"#4c4c4c","kind":"color","definedIn":"_ds_bundle.css","scope":"[data-theme=tag]"},{"name":"--fg3","value":"#666666","kind":"color","definedIn":"_ds_bundle.css","scope":"[data-theme=tag]"},{"name":"--ok","value":"#0DA20D","kind":"color","definedIn":"_ds_bundle.css","scope":"[data-theme=tag]"},{"name":"--warn","value":"#ffaa00","kind":"color","definedIn":"_ds_bundle.css","scope":"[data-theme=tag]"},{"name":"--bad","value":"#eb0d3f","kind":"color","definedIn":"_ds_bundle.css","scope":"[data-theme=tag]"},{"name":"--shade","value":"rgba(0, 0, 0, .04)","kind":"color","definedIn":"_ds_bundle.css","scope":"[data-theme=tag]"}],"themes":[{"selector":"[data-theme=tag]","label":"Tag"}],"fonts":[],"brandFonts":[],"source":"design-sync-cli"}
\ No newline at end of file
diff --git a/design/_ds/audi-dashboard-ui-27d66fd4-ed86-43b2-b8bf-61e281a5a1a5/styles.css b/design/_ds/audi-dashboard-ui-27d66fd4-ed86-43b2-b8bf-61e281a5a1a5/styles.css
new file mode 100644
index 0000000..8f6b11b
--- /dev/null
+++ b/design/_ds/audi-dashboard-ui-27d66fd4-ed86-43b2-b8bf-61e281a5a1a5/styles.css
@@ -0,0 +1 @@
+@import "./_ds_bundle.css";
diff --git a/design/assets/audi-rings-black.svg b/design/assets/audi-rings-black.svg
new file mode 100644
index 0000000..1c3b009
--- /dev/null
+++ b/design/assets/audi-rings-black.svg
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/design/assets/audi-rings-white.svg b/design/assets/audi-rings-white.svg
new file mode 100644
index 0000000..83a5ca6
--- /dev/null
+++ b/design/assets/audi-rings-white.svg
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/design/assets/audi-sport.svg b/design/assets/audi-sport.svg
new file mode 100644
index 0000000..07e5f71
--- /dev/null
+++ b/design/assets/audi-sport.svg
@@ -0,0 +1 @@
+AS_RGB_pos_red
\ No newline at end of file
diff --git a/design/assets/badge-rs6-negative.svg b/design/assets/badge-rs6-negative.svg
new file mode 100644
index 0000000..506b1a5
--- /dev/null
+++ b/design/assets/badge-rs6-negative.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/design/assets/badge-rs6-positive.svg b/design/assets/badge-rs6-positive.svg
new file mode 100644
index 0000000..11142fd
--- /dev/null
+++ b/design/assets/badge-rs6-positive.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/design/assets/fonts/AudiType-Normal.ttf b/design/assets/fonts/AudiType-Normal.ttf
new file mode 100644
index 0000000..d026f30
Binary files /dev/null and b/design/assets/fonts/AudiType-Normal.ttf differ
diff --git a/design/assets/fonts/AudiType-WideLight.ttf b/design/assets/fonts/AudiType-WideLight.ttf
new file mode 100644
index 0000000..5bf7368
Binary files /dev/null and b/design/assets/fonts/AudiType-WideLight.ttf differ
diff --git a/design/assets/fonts/AudiType-WideNormal.ttf b/design/assets/fonts/AudiType-WideNormal.ttf
new file mode 100644
index 0000000..85a8a32
Binary files /dev/null and b/design/assets/fonts/AudiType-WideNormal.ttf differ
diff --git a/design/assets/fonts/AudiTypeVF.ttf b/design/assets/fonts/AudiTypeVF.ttf
new file mode 100644
index 0000000..266a488
Binary files /dev/null and b/design/assets/fonts/AudiTypeVF.ttf differ
diff --git a/design/assets/icons.js b/design/assets/icons.js
new file mode 100644
index 0000000..b4e5eca
--- /dev/null
+++ b/design/assets/icons.js
@@ -0,0 +1 @@
+window.DM360_ICONS = {"add":" ","arrow-left":" ","camera":" ","car-insurance":" ","car-settings":" ","car":" ","caution":" ","code":" ","commute":" ","compass":" ","connect-key":" ","consumption":" ","cubic-capacity":" ","dashboard":" ","document-taxation":" ","download":" ","fuel-range":" ","gas-station":" ","lock":" ","mileage":" ","over-the-air-car":" ","parking":" ","photo":" ","plan-route":" ","poi-home":" ","service-package":" ","settings":" ","time":" ","tire":" ","top-speed":" "};
diff --git a/design/assets/icons.json b/design/assets/icons.json
new file mode 100644
index 0000000..0d8a1ed
--- /dev/null
+++ b/design/assets/icons.json
@@ -0,0 +1 @@
+{"add":" ","arrow-left":" ","camera":" ","car-insurance":" ","car-settings":" ","car":" ","caution":" ","code":" ","commute":" ","compass":" ","connect-key":" ","consumption":" ","cubic-capacity":" ","dashboard":" ","document-taxation":" ","download":" ","fuel-range":" ","gas-station":" ","lock":" ","mileage":" ","over-the-air-car":" ","parking":" ","photo":" ","plan-route":" ","poi-home":" ","service-package":" ","settings":" ","time":" ","tire":" ","top-speed":" "}
\ No newline at end of file
diff --git a/design/assets/icons/add.svg b/design/assets/icons/add.svg
new file mode 100644
index 0000000..b334344
--- /dev/null
+++ b/design/assets/icons/add.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/design/assets/icons/arrow-left.svg b/design/assets/icons/arrow-left.svg
new file mode 100644
index 0000000..8b13354
--- /dev/null
+++ b/design/assets/icons/arrow-left.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/design/assets/icons/camera.svg b/design/assets/icons/camera.svg
new file mode 100644
index 0000000..c1133ef
--- /dev/null
+++ b/design/assets/icons/camera.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/design/assets/icons/car-insurance.svg b/design/assets/icons/car-insurance.svg
new file mode 100644
index 0000000..b17dbb9
--- /dev/null
+++ b/design/assets/icons/car-insurance.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/design/assets/icons/car-settings.svg b/design/assets/icons/car-settings.svg
new file mode 100644
index 0000000..9def5d6
--- /dev/null
+++ b/design/assets/icons/car-settings.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/design/assets/icons/car.svg b/design/assets/icons/car.svg
new file mode 100644
index 0000000..33571db
--- /dev/null
+++ b/design/assets/icons/car.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/design/assets/icons/caution.svg b/design/assets/icons/caution.svg
new file mode 100644
index 0000000..f548a7b
--- /dev/null
+++ b/design/assets/icons/caution.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/design/assets/icons/code.svg b/design/assets/icons/code.svg
new file mode 100644
index 0000000..d8e5085
--- /dev/null
+++ b/design/assets/icons/code.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/design/assets/icons/commute.svg b/design/assets/icons/commute.svg
new file mode 100644
index 0000000..6d53023
--- /dev/null
+++ b/design/assets/icons/commute.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/design/assets/icons/compass.svg b/design/assets/icons/compass.svg
new file mode 100644
index 0000000..7711d68
--- /dev/null
+++ b/design/assets/icons/compass.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/design/assets/icons/connect-key.svg b/design/assets/icons/connect-key.svg
new file mode 100644
index 0000000..41e72a8
--- /dev/null
+++ b/design/assets/icons/connect-key.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/design/assets/icons/consumption.svg b/design/assets/icons/consumption.svg
new file mode 100644
index 0000000..fc29823
--- /dev/null
+++ b/design/assets/icons/consumption.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/design/assets/icons/cubic-capacity.svg b/design/assets/icons/cubic-capacity.svg
new file mode 100644
index 0000000..b7be893
--- /dev/null
+++ b/design/assets/icons/cubic-capacity.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/design/assets/icons/dashboard.svg b/design/assets/icons/dashboard.svg
new file mode 100644
index 0000000..e6f7a78
--- /dev/null
+++ b/design/assets/icons/dashboard.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/design/assets/icons/document-taxation.svg b/design/assets/icons/document-taxation.svg
new file mode 100644
index 0000000..57d35f4
--- /dev/null
+++ b/design/assets/icons/document-taxation.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/design/assets/icons/download.svg b/design/assets/icons/download.svg
new file mode 100644
index 0000000..1f3b7f3
--- /dev/null
+++ b/design/assets/icons/download.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/design/assets/icons/fuel-range.svg b/design/assets/icons/fuel-range.svg
new file mode 100644
index 0000000..ce5a0d7
--- /dev/null
+++ b/design/assets/icons/fuel-range.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/design/assets/icons/gas-station.svg b/design/assets/icons/gas-station.svg
new file mode 100644
index 0000000..ecb7117
--- /dev/null
+++ b/design/assets/icons/gas-station.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/design/assets/icons/lock.svg b/design/assets/icons/lock.svg
new file mode 100644
index 0000000..ffde04c
--- /dev/null
+++ b/design/assets/icons/lock.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/design/assets/icons/mileage.svg b/design/assets/icons/mileage.svg
new file mode 100644
index 0000000..ebc5efc
--- /dev/null
+++ b/design/assets/icons/mileage.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/design/assets/icons/over-the-air-car.svg b/design/assets/icons/over-the-air-car.svg
new file mode 100644
index 0000000..2fbdd47
--- /dev/null
+++ b/design/assets/icons/over-the-air-car.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/design/assets/icons/parking.svg b/design/assets/icons/parking.svg
new file mode 100644
index 0000000..e4b4f3f
--- /dev/null
+++ b/design/assets/icons/parking.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/design/assets/icons/photo.svg b/design/assets/icons/photo.svg
new file mode 100644
index 0000000..dd24633
--- /dev/null
+++ b/design/assets/icons/photo.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/design/assets/icons/plan-route.svg b/design/assets/icons/plan-route.svg
new file mode 100644
index 0000000..da3ac1c
--- /dev/null
+++ b/design/assets/icons/plan-route.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/design/assets/icons/poi-home.svg b/design/assets/icons/poi-home.svg
new file mode 100644
index 0000000..b787f73
--- /dev/null
+++ b/design/assets/icons/poi-home.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/design/assets/icons/service-package.svg b/design/assets/icons/service-package.svg
new file mode 100644
index 0000000..71fa040
--- /dev/null
+++ b/design/assets/icons/service-package.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/design/assets/icons/settings.svg b/design/assets/icons/settings.svg
new file mode 100644
index 0000000..28d14e8
--- /dev/null
+++ b/design/assets/icons/settings.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/design/assets/icons/time.svg b/design/assets/icons/time.svg
new file mode 100644
index 0000000..5bfcda8
--- /dev/null
+++ b/design/assets/icons/time.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/design/assets/icons/tire.svg b/design/assets/icons/tire.svg
new file mode 100644
index 0000000..3f2adac
--- /dev/null
+++ b/design/assets/icons/tire.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/design/assets/icons/top-speed.svg b/design/assets/icons/top-speed.svg
new file mode 100644
index 0000000..82f546f
--- /dev/null
+++ b/design/assets/icons/top-speed.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/design/assets/shell.svg b/design/assets/shell.svg
new file mode 100644
index 0000000..846e6c4
--- /dev/null
+++ b/design/assets/shell.svg
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/design/support.js b/design/support.js
new file mode 100644
index 0000000..cb009b6
--- /dev/null
+++ b/design/support.js
@@ -0,0 +1,1911 @@
+// GENERATED from dc-runtime/src/*.ts — do not edit. Rebuild with `cd dc-runtime && bun run build`.
+"use strict";
+(() => {
+ var __defProp = Object.defineProperty;
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
+
+ // src/react.ts
+ function getReact() {
+ const R = window.React;
+ if (!R) throw new Error("dc-runtime: window.React is not available yet");
+ return R;
+ }
+ function getReactDOM() {
+ const RD = window.ReactDOM;
+ if (!RD) throw new Error("dc-runtime: window.ReactDOM is not available yet");
+ return RD;
+ }
+ var h = ((...args) => getReact().createElement(
+ ...args
+ ));
+
+ // src/parse.ts
+ function parseDcDocument(doc) {
+ const dc = doc.querySelector("x-dc");
+ if (!dc) return null;
+ const scriptEl = doc.querySelector("script[data-dc-script]");
+ const { props, preview } = parseDataProps(
+ scriptEl?.getAttribute("data-props") ?? null
+ );
+ return {
+ template: dc.innerHTML,
+ js: scriptEl ? scriptEl.textContent || "" : "",
+ props,
+ preview
+ };
+ }
+ function parseDcText(src) {
+ const openMatch = /]*)?>/.exec(src);
+ if (!openMatch) return null;
+ const close = src.lastIndexOf(" ");
+ if (close === -1 || close < openMatch.index) return null;
+ const template = src.slice(openMatch.index + openMatch[0].length, close);
+ const doc = new DOMParser().parseFromString(src, "text/html");
+ const scriptEl = doc.querySelector("script[data-dc-script]");
+ const { props, preview } = parseDataProps(
+ scriptEl?.getAttribute("data-props") ?? null
+ );
+ return {
+ template,
+ js: scriptEl ? scriptEl.textContent || "" : "",
+ props,
+ preview
+ };
+ }
+ function parseDataProps(raw) {
+ if (!raw) return { props: null, preview: null };
+ let parsed;
+ try {
+ parsed = JSON.parse(raw);
+ } catch {
+ return { props: null, preview: null };
+ }
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
+ return { props: null, preview: null };
+ }
+ const obj = parsed;
+ const preview = obj.$preview && typeof obj.$preview === "object" ? obj.$preview : null;
+ const rest = {};
+ for (const k of Object.keys(obj)) {
+ if (k[0] !== "$") rest[k] = obj[k];
+ }
+ return { props: Object.keys(rest).length ? rest : null, preview };
+ }
+ function dcNameFromPath(pathname) {
+ let p = pathname || "";
+ try {
+ p = decodeURIComponent(p);
+ } catch {
+ }
+ const base = p.split("/").pop() || "Root";
+ return base.replace(/\.dc\.html$/, "").replace(/\.html?$/, "") || "Root";
+ }
+
+ // src/boot.ts
+ var BASE_CSS = `
+ .sc-placeholder{background:color-mix(in srgb,currentColor 8%,transparent);
+ border:1px solid color-mix(in srgb,currentColor 50%,transparent);
+ border-radius:2px;box-sizing:border-box;overflow:hidden}
+ @keyframes sc-shine{0%{background-position:100% 50%}100%{background-position:0% 50%}}
+ html.sc-dc-streaming .sc-placeholder,
+ html.sc-dc-streaming .sc-interp.sc-missing{position:relative;
+ background:color-mix(in srgb,currentColor 5%,transparent);
+ border-color:transparent}
+ html.sc-dc-streaming .sc-placeholder::before,
+ html.sc-dc-streaming .sc-interp.sc-missing::before{content:'';
+ position:absolute;inset:0;pointer-events:none;
+ background:linear-gradient(90deg,rgba(217,119,87,0) 25%,rgba(247,225,211,.95) 37%,rgba(217,119,87,0) 63%);
+ background-size:400% 100%;animation:sc-shine 1.4s ease infinite}
+ html.sc-dc-streaming .sc-placeholder:nth-child(n+9 of .sc-placeholder)::before,
+ html.sc-dc-streaming .sc-interp.sc-missing:nth-child(n+9 of .sc-interp.sc-missing)::before{animation:none;
+ background:color-mix(in srgb,currentColor 8%,transparent)}
+ .sc-placeholder-error{padding:4px 8px;font:11px/1.4 ui-monospace,monospace;
+ color:color-mix(in srgb,currentColor 70%,transparent);word-break:break-word}
+ .sc-interp.sc-missing{display:inline-block;width:2em;height:1em;overflow:hidden;
+ vertical-align:text-bottom;background:rgba(255,255,255,.3);border:1px solid rgba(0,0,0,.5);
+ border-radius:2px;box-sizing:border-box;color:transparent;
+ user-select:none}
+ .sc-interp.sc-unresolved{font-family:ui-monospace,monospace;font-size:.85em;
+ color:color-mix(in srgb,currentColor 50%,transparent);
+ background:color-mix(in srgb,currentColor 10%,transparent);border-radius:3px;
+ padding:0 3px}
+ .sc-host.sc-has-error{position:relative}
+ .sc-logic-error{position:absolute;top:8px;left:8px;z-index:2147483647;max-width:60ch;
+ padding:6px 10px;background:#b00020;color:#fff;font:12px/1.4 ui-monospace,monospace;
+ border-radius:4px;white-space:pre-wrap;pointer-events:none}
+ /* Mirrors PRINT_BASELINE_CSS in apps/web deck-stage-export.ts \u2014 keep both
+ in sync until dc-runtime regains a build step. */
+ @media print {
+ @page { margin: 0.5cm; }
+ figure, table { break-inside: avoid; }
+ #dc-root, #dc-root > .sc-host { height: auto; }
+ *, *::before, *::after {
+ print-color-adjust: exact; -webkit-print-color-adjust: exact;
+ backdrop-filter: none !important; -webkit-backdrop-filter: none !important;
+ animation-delay: -99s !important; animation-duration: .001s !important;
+ animation-iteration-count: 1 !important; animation-fill-mode: both !important;
+ animation-play-state: running !important; transition-duration: 0s !important;
+ }
+ }
+ `;
+ var FULL_PAGE_CSS = "html,body{height:100%;margin:0}#dc-root,#dc-root>.sc-host{height:100%}";
+ function rootNameForDocument(doc, loc) {
+ let bootPath = loc.pathname || "";
+ if (!/\.dc\.html?$/i.test(safeDecode(bootPath))) {
+ try {
+ bootPath = new URL(doc.baseURI || "/").pathname;
+ } catch {
+ }
+ }
+ return dcNameFromPath(bootPath);
+ }
+ function safeDecode(s) {
+ try {
+ return decodeURIComponent(s);
+ } catch {
+ return s;
+ }
+ }
+ function boot(runtime, doc = document) {
+ const parsed = parseDcDocument(doc);
+ if (!parsed) return null;
+ const React = getReact();
+ const rootName = rootNameForDocument(doc, location);
+ runtime.markFetched(rootName);
+ runtime.setRootName(rootName);
+ runtime.adoptParsed(rootName, parsed);
+ if (!window.__resources) {
+ fetch(location.href).then((res) => res.ok ? res.text() : "").then((t) => {
+ const raw = t ? parseDcText(t) : null;
+ if (raw?.template) runtime.updateHtml(rootName, raw.template);
+ }).catch(() => {
+ });
+ }
+ const dc = doc.querySelector("x-dc");
+ const hostEl = doc.createElement("div");
+ hostEl.id = "dc-root";
+ dc.replaceWith(hostEl);
+ if (!parsed.preview) {
+ const s = doc.createElement("style");
+ s.textContent = FULL_PAGE_CSS;
+ doc.head.appendChild(s);
+ }
+ const Root = runtime.getDC(rootName);
+ const entry = runtime.registry.get(rootName);
+ function StandaloneRoot() {
+ const [, setTick] = React.useState(0);
+ React.useEffect(() => {
+ const sub = () => setTick((n) => n + 1);
+ entry.subs.add(sub);
+ return () => {
+ entry.subs.delete(sub);
+ };
+ }, []);
+ const defaults = React.useMemo(() => {
+ const d = {};
+ for (const k in entry.propsMeta || {}) {
+ const v = entry.propsMeta?.[k]?.default;
+ if (v !== void 0) d[k] = v;
+ }
+ return d;
+ }, [entry.propsMeta]);
+ return h(Root, { ...defaults, ...entry.propOverrides || {} });
+ }
+ const ReactDOM = getReactDOM();
+ if (ReactDOM.createRoot)
+ ReactDOM.createRoot(hostEl).render(h(StandaloneRoot));
+ else ReactDOM.render(h(StandaloneRoot), hostEl);
+ return rootName;
+ }
+
+ // src/expr.ts
+ var IDENT_RE = /^[A-Za-z_$][A-Za-z0-9_$]*/;
+ var NUMBER_RE = /^-?\d+(\.\d+)?$/;
+ function resolve(vals, src) {
+ const expr = String(src).trim();
+ if (!expr) return void 0;
+ if (expr[0] === "(" && expr[expr.length - 1] === ")" && parensWrapWhole(expr)) {
+ return resolve(vals, expr.slice(1, -1));
+ }
+ const eq = findTopLevelEquality(expr);
+ if (eq) {
+ const lv = resolve(vals, expr.slice(0, eq.index));
+ const rv = resolve(vals, expr.slice(eq.index + eq.op.length));
+ switch (eq.op) {
+ case "===":
+ return lv === rv;
+ case "!==":
+ return lv !== rv;
+ case "==":
+ return lv == rv;
+ default:
+ return lv != rv;
+ }
+ }
+ if (expr[0] === "!") return !resolve(vals, expr.slice(1));
+ if (expr === "true") return true;
+ if (expr === "false") return false;
+ if (expr === "null") return null;
+ if (expr === "undefined") return void 0;
+ if (NUMBER_RE.test(expr)) return Number(expr);
+ if (expr.length >= 2 && (expr[0] === '"' || expr[0] === "'") && expr[expr.length - 1] === expr[0]) {
+ return expr.slice(1, -1);
+ }
+ return resolvePath(vals, expr);
+ }
+ function parensWrapWhole(expr) {
+ let depth = 0;
+ for (let i = 0; i < expr.length - 1; i++) {
+ if (expr[i] === "(") depth++;
+ else if (expr[i] === ")") {
+ depth--;
+ if (depth === 0) return false;
+ }
+ }
+ return true;
+ }
+ function findTopLevelEquality(expr) {
+ let depth = 0;
+ for (let i = 0; i < expr.length; i++) {
+ const c = expr[i];
+ if (c === "[" || c === "(") depth++;
+ else if (c === "]" || c === ")") depth--;
+ else if (depth === 0 && (c === "=" || c === "!") && expr[i + 1] === "=") {
+ if (i > 0 && (expr[i - 1] === "=" || expr[i - 1] === "!")) continue;
+ if (!expr.slice(0, i).trim()) continue;
+ const op = expr[i + 2] === "=" ? c + "==" : c + "=";
+ return { index: i, op };
+ }
+ }
+ return null;
+ }
+ function resolvePath(vals, expr) {
+ const head = expr.match(IDENT_RE);
+ if (!head) return void 0;
+ let cur = vals == null ? void 0 : vals[head[0]];
+ let i = head[0].length;
+ while (i < expr.length) {
+ if (expr[i] === ".") {
+ const m = expr.slice(i + 1).match(IDENT_RE) || expr.slice(i + 1).match(/^\d+/);
+ if (!m) return void 0;
+ cur = cur == null ? void 0 : cur[m[0]];
+ i += 1 + m[0].length;
+ } else if (expr[i] === "[") {
+ let depth = 1;
+ let j = i + 1;
+ while (j < expr.length && depth > 0) {
+ if (expr[j] === "[") depth++;
+ else if (expr[j] === "]") {
+ depth--;
+ if (depth === 0) break;
+ }
+ j++;
+ }
+ if (depth !== 0) return void 0;
+ const key = resolve(vals, expr.slice(i + 1, j));
+ cur = cur == null ? void 0 : cur[key];
+ i = j + 1;
+ } else {
+ return void 0;
+ }
+ }
+ return cur;
+ }
+
+ // src/encode.ts
+ var CAMEL_ATTR = "sc-camel-";
+ var INLINE_TEXT_TAGS = new Set(
+ "a abbr b bdi bdo br cite code del dfn em i ins kbd mark q s samp small span strike strong sub sup u var wbr".split(
+ " "
+ )
+ );
+ var RAW_WRAP = {
+ select: "sc-raw-select",
+ table: "sc-raw-table",
+ tbody: "sc-raw-tbody",
+ thead: "sc-raw-thead",
+ tfoot: "sc-raw-tfoot",
+ tr: "sc-raw-tr",
+ td: "sc-raw-td",
+ th: "sc-raw-th",
+ caption: "sc-raw-caption"
+ };
+ var RAW_UNWRAP = Object.fromEntries(
+ Object.entries(RAW_WRAP).map(([k, v]) => [v, k])
+ );
+ var EVENT_MAP = {
+ onclick: "onClick",
+ onchange: "onChange",
+ oninput: "onInput",
+ onsubmit: "onSubmit",
+ onkeydown: "onKeyDown",
+ onkeyup: "onKeyUp",
+ onkeypress: "onKeyPress",
+ onmousedown: "onMouseDown",
+ onmouseup: "onMouseUp",
+ onmouseenter: "onMouseEnter",
+ onmouseleave: "onMouseLeave",
+ onfocus: "onFocus",
+ onblur: "onBlur",
+ ondoubleclick: "onDoubleClick",
+ oncontextmenu: "onContextMenu",
+ onmousemove: "onMouseMove",
+ onmouseover: "onMouseOver",
+ onmouseout: "onMouseOut",
+ onpointerdown: "onPointerDown",
+ onpointerup: "onPointerUp",
+ onpointermove: "onPointerMove",
+ onpointerenter: "onPointerEnter",
+ onpointerleave: "onPointerLeave",
+ onpointercancel: "onPointerCancel",
+ onpointerover: "onPointerOver",
+ onpointerout: "onPointerOut",
+ ongotpointercapture: "onGotPointerCapture",
+ onlostpointercapture: "onLostPointerCapture",
+ ontouchstart: "onTouchStart",
+ ontouchend: "onTouchEnd",
+ ontouchmove: "onTouchMove",
+ ontouchcancel: "onTouchCancel",
+ ondragstart: "onDragStart",
+ ondragend: "onDragEnd",
+ ondragenter: "onDragEnter",
+ ondragleave: "onDragLeave",
+ ondragover: "onDragOver",
+ onanimationstart: "onAnimationStart",
+ onanimationend: "onAnimationEnd",
+ onanimationiteration: "onAnimationIteration",
+ ontransitionend: "onTransitionEnd"
+ };
+ var ATTRS = `(?:[^>"']|"[^"]*"|'[^']*')*`;
+ var IMPORT_SELF_CLOSE_RE = new RegExp(
+ "<(x-import|dc-import)(" + ATTRS + ")/>",
+ "gi"
+ );
+ var CAMEL_ATTR_RE = /(\s)([a-z]+[A-Z][A-Za-z0-9]*)(\s*=)/g;
+ function encodeCamelAttrs(html) {
+ return html.replace(
+ CAMEL_ATTR_RE,
+ (_, sp, name, eq) => sp + CAMEL_ATTR + name.replace(/[A-Z]/g, (c) => "-" + c.toLowerCase()) + eq
+ );
+ }
+ function encodeCase(html) {
+ html = html.replace(
+ IMPORT_SELF_CLOSE_RE,
+ (_, t, a) => "<" + t + a + ">" + t + ">"
+ );
+ html = html.replace(/)/gi, "/gi, " ");
+ html = encodeCamelAttrs(html);
+ for (const [real, alias] of Object.entries(RAW_WRAP)) {
+ html = html.replace(
+ new RegExp("(?)" + real + "(?=[\\s>])", "gi"),
+ "$1" + alias
+ );
+ }
+ return html;
+ }
+ function kebabToCamel(s) {
+ return s.replace(/-([a-z])/g, (_, c) => c.toUpperCase());
+ }
+ function cssToObj(css) {
+ const o = {};
+ for (const decl of css.split(";")) {
+ const i = decl.indexOf(":");
+ if (i < 0) continue;
+ const prop = decl.slice(0, i).trim();
+ o[prop.startsWith("--") ? prop : kebabToCamel(prop)] = decl.slice(i + 1).trim();
+ }
+ return o;
+ }
+ function compileAttr(raw) {
+ const whole = raw.match(/^\s*\{\{([\s\S]+?)\}\}\s*$/);
+ if (whole) {
+ const path = whole[1];
+ return (vals) => resolve(vals, path);
+ }
+ if (raw.includes("{{")) {
+ const parts = raw.split(/\{\{([\s\S]+?)\}\}/g);
+ return (vals) => parts.map((s, i) => i & 1 ? resolve(vals, s) ?? "" : s).join("");
+ }
+ return () => raw;
+ }
+
+ // src/compile.ts
+ function collectProps(node, kind, host) {
+ const propGetters = [];
+ const pseudoClasses = [];
+ let hintSize = null;
+ for (const { name, value } of [...node.attributes]) {
+ if (name === "sc-name" || name === "data-dc-tpl") continue;
+ let key = name;
+ if (key.startsWith(CAMEL_ATTR))
+ key = kebabToCamel(key.slice(CAMEL_ATTR.length));
+ if (key === "hint-size") {
+ hintSize = value;
+ continue;
+ }
+ if (key.startsWith("style-")) {
+ pseudoClasses.push(host.pseudoClass(key.slice(6), value));
+ continue;
+ }
+ if (kind !== "dom") {
+ if (key.includes("-") && !(kind === "x-import" && (key.startsWith("aria-") || key.startsWith("data-"))))
+ key = kebabToCamel(key);
+ } else {
+ if (key === "class") key = "className";
+ else if (key === "for") key = "htmlFor";
+ else if (key.startsWith("on"))
+ key = EVENT_MAP[key] || "on" + key[2].toUpperCase() + key.slice(3);
+ }
+ propGetters.push([key, compileAttr(value)]);
+ }
+ return { propGetters, pseudoClasses, hintSize };
+ }
+ var HOST_STYLE_PROPS = /* @__PURE__ */ new Set([
+ "position",
+ "left",
+ "right",
+ "top",
+ "bottom",
+ "inset",
+ "width",
+ "height",
+ "z-index",
+ "transform"
+ ]);
+ function hostPositionStyle(style) {
+ const all = typeof style === "string" ? cssToObj(style) : style != null && typeof style === "object" ? style : null;
+ if (!all) return void 0;
+ const out = {};
+ for (const [k, v] of Object.entries(all)) {
+ const kebab = k.replace(/[A-Z]/g, (c) => "-" + c.toLowerCase());
+ if (HOST_STYLE_PROPS.has(kebab)) out[k] = v;
+ }
+ return Object.keys(out).length ? out : void 0;
+ }
+ function compileTemplate(html, host) {
+ const tpl = document.createElement("template");
+ //! nosemgrep: direct-inner-html-assignment
+ tpl.innerHTML = encodeCase(html);
+ let tplN = 0;
+ (function stamp(node) {
+ if (node.nodeType === Node.ELEMENT_NODE) {
+ node.setAttribute("data-dc-tpl", String(tplN++));
+ }
+ for (const c of node.childNodes) stamp(c);
+ })(tpl.content);
+ const builders = walkChildren(tpl.content, host);
+ const render = ((vals, ctx) => builders.map((b, i) => b(vals || {}, ctx, i)));
+ render.__annotated = tpl.innerHTML;
+ return render;
+ }
+ function walkChildren(node, host) {
+ return [...node.childNodes].map((c) => walk(c, host)).filter((b) => b != null);
+ }
+ var SLIDE_ID_VALUE_RE = /^[0-9a-f]{8}$/;
+ var DECK_CONTROL_FLOW_RE = /^(sc-if|sc-for|sc-else|dc-import|x-import)$/;
+ var DECK_AUX_RE = /^(template|script|style|sc-helmet|helmet)$/;
+ function isDeckMountTag(el) {
+ if (el.localName === "deck-stage") return true;
+ return el.localName === "x-import" && (el.getAttribute("component-from-global-scope") || "") === "deck-stage";
+ }
+ function walkDeckChildren(el, host) {
+ const pairs = [...el.childNodes].map((c) => ({ c, b: walk(c, host) })).filter((p) => p.b !== null);
+ const kids = pairs.map((p) => p.b);
+ const seen = /* @__PURE__ */ new Set();
+ const wsSeen = /* @__PURE__ */ new Map();
+ const keys = [];
+ const nextSlideId = new Array(pairs.length);
+ {
+ let upcoming = null;
+ for (let j = pairs.length - 1; j >= 0; j--) {
+ const n = pairs[j].c;
+ if (n.nodeType === Node.ELEMENT_NODE) {
+ const t = n.localName;
+ upcoming = !DECK_AUX_RE.test(t) && !DECK_CONTROL_FLOW_RE.test(t) ? n.getAttribute("data-om-slide-id") : null;
+ }
+ nextSlideId[j] = upcoming;
+ }
+ }
+ for (let j = 0; j < pairs.length; j++) {
+ const { c } = pairs[j];
+ if (c.nodeType === Node.TEXT_NODE) {
+ if ((c.nodeValue ?? "").trim() === "") {
+ const base = nextSlideId[j] ? "omid-ws:" + nextSlideId[j] : "omid-ws:aux";
+ const n = wsSeen.get(base) ?? 0;
+ wsSeen.set(base, n + 1);
+ keys.push(n === 0 ? base : base + ":" + n);
+ continue;
+ }
+ return { kids, keys: null };
+ }
+ if (c.nodeType !== Node.ELEMENT_NODE) {
+ keys.push(j);
+ continue;
+ }
+ const child = c;
+ const tag = child.localName;
+ if (DECK_AUX_RE.test(tag)) {
+ keys.push(j);
+ continue;
+ }
+ if (DECK_CONTROL_FLOW_RE.test(tag)) return { kids, keys: null };
+ const v = child.getAttribute("data-om-slide-id");
+ if (!v || !SLIDE_ID_VALUE_RE.test(v) || seen.has(v)) {
+ return { kids, keys: null };
+ }
+ seen.add(v);
+ keys.push("omid:" + v);
+ }
+ return { kids, keys };
+ }
+ function renderDeckKids(kids, kidKeys, vals, ctx) {
+ return kids.map((b, j) => {
+ const k = kidKeys ? kidKeys[j] : j;
+ const out = b(vals, ctx, k);
+ return kidKeys != null && typeof out === "string" ? h(getReact().Fragment, { key: k }, out) : out;
+ });
+ }
+ function walk(node, host) {
+ if (node.nodeType === Node.TEXT_NODE) return walkText(node);
+ if (node.nodeType !== Node.ELEMENT_NODE) return null;
+ const el = node;
+ const tag = el.tagName.toLowerCase();
+ if (tag === "sc-for") return walkFor(el, host);
+ if (tag === "sc-if") return walkIf(el, host);
+ if (tag === "x-import") return walkXImport(el, host);
+ if (tag === "sc-helmet") return host.helmet(el);
+ if (tag === "dc-import") return walkComponent(el, host);
+ return walkElement(el, host);
+ }
+ var warnedHoles = /* @__PURE__ */ new Set();
+ function warnUnresolved(ctx, what) {
+ const key = (ctx?.__name || "?") + "\0" + what;
+ if (warnedHoles.has(key)) return;
+ warnedHoles.add(key);
+ console.warn("[dc-runtime] " + (ctx?.__name || "template") + ": " + what);
+ }
+ function walkText(node) {
+ const txt = node.nodeValue ?? "";
+ if (!txt.includes("{{")) {
+ if (!txt.trim() && !txt.includes(" ")) return null;
+ return () => txt;
+ }
+ const parts = txt.split(/\{\{([\s\S]+?)\}\}/g);
+ return (vals, ctx, key) => h(
+ getReact().Fragment,
+ { key },
+ ...parts.map((p, i) => {
+ if (!(i & 1)) return p;
+ const v = resolve(vals, p);
+ if (v === void 0) {
+ if (!ctx?.__streamingNow) {
+ if (document.body?.hasAttribute("data-dc-editor-on")) {
+ return h(
+ "span",
+ { key: i, className: "sc-interp sc-unresolved" },
+ "{{ " + p.trim() + " }}"
+ );
+ }
+ warnUnresolved(
+ ctx,
+ "{{ " + p.trim() + " }} never resolved \u2014 rendered as empty"
+ );
+ return null;
+ }
+ return h(
+ "span",
+ { key: i, className: "sc-interp sc-missing" },
+ p.trim()
+ );
+ }
+ if (getReact().isValidElement(v) || Array.isArray(v)) {
+ return h(getReact().Fragment, { key: i }, v);
+ }
+ if (v === null || typeof v === "boolean") return null;
+ return h("span", { key: i, className: "sc-interp" }, String(v));
+ })
+ );
+ }
+ function walkFor(el, host) {
+ const listGet = compileAttr(el.getAttribute("list") || "");
+ const asName = el.getAttribute("as") || "item";
+ const hintN = parseInt(el.getAttribute("hint-placeholder-count") || "0", 10);
+ const kids = walkChildren(el, host);
+ const listSrc = el.getAttribute("list") || "";
+ return (vals, ctx, key) => {
+ let list = listGet(vals);
+ if (!Array.isArray(list)) {
+ if (!ctx?.__streamingNow) {
+ if (list !== void 0 && list !== null) {
+ warnUnresolved(
+ ctx,
+ 'sc-for list="' + listSrc + '" is not an array (' + typeof list + ")"
+ );
+ }
+ list = [];
+ } else {
+ list = hintN > 0 ? Array(hintN).fill(void 0) : [];
+ }
+ }
+ return h(
+ getReact().Fragment,
+ { key },
+ list.map((item, i) => {
+ const sub = { ...vals, [asName]: item, $index: i };
+ return h(
+ getReact().Fragment,
+ { key: i },
+ kids.map((b, j) => b(sub, ctx, j))
+ );
+ })
+ );
+ };
+ }
+ function walkIf(el, host) {
+ const valGet = compileAttr(el.getAttribute("value") || "");
+ const hintRaw = el.getAttribute("hint-placeholder-val");
+ const hintGet = hintRaw != null ? compileAttr(hintRaw) : null;
+ const kids = walkChildren(el, host);
+ return (vals, ctx, key) => {
+ let v = valGet(vals);
+ if (v === void 0 && hintGet && ctx?.__streamingNow) v = hintGet(vals);
+ return v ? h(
+ getReact().Fragment,
+ { key },
+ kids.map((b, j) => b(vals, ctx, j))
+ ) : null;
+ };
+ }
+ function walkComponent(el, host) {
+ const name = el.getAttribute("name") || el.getAttribute("component") || "";
+ el.removeAttribute("name");
+ el.removeAttribute("component");
+ const tplId = el.getAttribute("data-dc-tpl");
+ const styleRaw = el.getAttribute("style");
+ el.removeAttribute("style");
+ const styleGet = styleRaw != null ? compileAttr(styleRaw) : null;
+ const { propGetters, hintSize } = collectProps(el, "dc-import", host);
+ const kids = walkChildren(el, host);
+ return (vals, ctx, key) => {
+ const props = {
+ key,
+ __hintSize: hintSize,
+ __tplId: tplId,
+ __hostStyle: styleGet ? hostPositionStyle(styleGet(vals)) : void 0
+ };
+ for (const [k, g] of propGetters) {
+ const v = g(vals);
+ if (k === "dcProps") {
+ if (v && typeof v === "object") Object.assign(props, v);
+ continue;
+ }
+ props[k] = v;
+ }
+ if (kids.length) props.children = kids.map((b, j) => b(vals, ctx, j));
+ return h(host.component(name), props);
+ };
+ }
+ function walkXImport(el, host) {
+ const globalNameGet = compileAttr(
+ el.getAttribute("component-from-global-scope") || ""
+ );
+ const exportNameGet = compileAttr(
+ el.getAttribute("component") || el.getAttribute("name") || ""
+ );
+ const fromRaw = el.getAttribute("from") || (el.getAttribute("component-from-global-scope") ? "" : el.getAttribute("src") || el.getAttribute("import") || "");
+ const urls = fromRaw.trim() ? fromRaw.trim().split(/\s+/) : [];
+ const url = urls.length ? urls[urls.length - 1] : "";
+ const kindOf = (u) => /\.(jsx|tsx)(\?|#|$)/i.test(u) ? "jsx" : "js";
+ const tplId = el.getAttribute("data-dc-tpl");
+ const styleRaw = el.getAttribute("style");
+ el.removeAttribute("style");
+ const styleGet = styleRaw != null ? compileAttr(styleRaw) : null;
+ const wrap = tplId != null || styleGet != null;
+ const { propGetters, hintSize } = collectProps(el, "x-import", host);
+ const hasContent = el.children.length > 0 || !!(el.textContent || "").trim();
+ const deckKeyed = hasContent && isDeckMountTag(el) ? walkDeckChildren(el, host) : null;
+ const kids = deckKeyed ? deckKeyed.kids : hasContent ? walkChildren(el, host) : [];
+ const kidKeys = deckKeyed?.keys ?? null;
+ const urlBindable = fromRaw.includes("{{");
+ if (urls.length && !urlBindable) {
+ let prev;
+ for (const u of urls) prev = host.loadExternal(kindOf(u), u, prev);
+ }
+ const evalName = (g, vals) => {
+ const v = g(vals);
+ const s = v == null ? "" : String(v);
+ return s.includes("{{") ? "" : s;
+ };
+ return (vals, ctx, key) => {
+ const globalName = evalName(globalNameGet, vals);
+ const name = globalName || evalName(exportNameGet, vals);
+ const C = !name || urlBindable ? null : globalName ? host.resolveExternalGlobal(url, globalName) : host.resolveExternal(url, name);
+ const hostStyle = styleGet ? hostPositionStyle(styleGet(vals)) : void 0;
+ const wrapper = wrap ? {
+ key,
+ className: "sc-host-x",
+ "data-dc-tpl": tplId,
+ style: hostStyle || { display: "contents" }
+ } : null;
+ if (!C) {
+ const error = urlBindable ? "x-import `from` cannot contain {{ \u2026 }} \u2014 module URLs are resolved at parse time; use a literal URL" : host.resolveExternalError(url, name);
+ const ph = host.placeholder({
+ key: wrapper ? void 0 : key,
+ name,
+ hintSize,
+ error
+ });
+ return wrapper ? h("div", wrapper, ph) : ph;
+ }
+ const props = wrapper ? {} : { key };
+ let unresolvedHole = false;
+ for (const [k, g] of propGetters) {
+ if (k === "component" || k === "componentFromGlobalScope" || k === "from") {
+ continue;
+ }
+ const v = g(vals);
+ if (v === void 0) unresolvedHole = true;
+ if (k === "dcProps") {
+ if (v && typeof v === "object") Object.assign(props, v);
+ continue;
+ }
+ props[k] = v;
+ }
+ if (unresolvedHole && ctx?.__htmlStreamingNow) {
+ const ph = host.placeholder({
+ key: wrapper ? void 0 : key,
+ name,
+ hintSize,
+ error: null
+ });
+ return wrapper ? h("div", wrapper, ph) : ph;
+ }
+ if (kids.length) {
+ props.children = renderDeckKids(kids, kidKeys, vals, ctx);
+ }
+ return wrapper ? h("div", wrapper, h(C, props)) : h(C, props);
+ };
+ }
+ function contentKey(el) {
+ const clone = el.cloneNode(true);
+ for (const d of clone.querySelectorAll("*")) {
+ while (d.attributes.length) d.removeAttribute(d.attributes[0].name);
+ }
+ const s = clone.innerHTML;
+ let h2 = 5381;
+ for (let i = 0; i < s.length; i++) h2 = (h2 << 5) + h2 + s.charCodeAt(i) | 0;
+ return s.length + "." + (h2 >>> 0).toString(36);
+ }
+ var NEVER_CONTENT_KEYED = new Set(
+ "script style textarea option title select canvas iframe video audio".split(
+ " "
+ )
+ );
+ var NOT_INLINE_SELECTOR = ":not(" + [...INLINE_TEXT_TAGS].join(",") + ")";
+ function walkElement(el, host) {
+ const realTag = RAW_UNWRAP[el.localName] || el.localName;
+ const tplId = el.getAttribute("data-dc-tpl");
+ const inlineOnly = el.childNodes.length > 0 && !NEVER_CONTENT_KEYED.has(realTag) && el.querySelector(NOT_INLINE_SELECTOR) === null;
+ const keySuffix = inlineOnly ? "|" + contentKey(el) : "";
+ const { propGetters, pseudoClasses } = collectProps(el, "dom", host);
+ const deckKeyed = isDeckMountTag(el) ? walkDeckChildren(el, host) : null;
+ const kids = deckKeyed ? deckKeyed.kids : walkChildren(el, host);
+ const kidKeys = deckKeyed?.keys ?? null;
+ return (vals, ctx, key) => {
+ const props = {
+ key: key + keySuffix,
+ "data-dc-tpl": tplId
+ };
+ for (const [k, g] of propGetters) {
+ let v = g(vals);
+ if (k === "style" && typeof v === "string") v = cssToObj(v);
+ if ((k === "value" || k === "checked") && v === void 0) {
+ v = k === "checked" ? false : "";
+ }
+ props[k] = v;
+ }
+ if (pseudoClasses.length) {
+ props.className = [props.className, ...pseudoClasses].filter(Boolean).join(" ");
+ }
+ return h(realTag, props, ...renderDeckKids(kids, kidKeys, vals, ctx));
+ };
+ }
+
+ // src/logic.ts
+ var StreamableLogic = class {
+ constructor(props) {
+ __publicField(this, "props");
+ __publicField(this, "state", {});
+ /** Back-pointer to the wrapper component, installed after construction. */
+ __publicField(this, "__host");
+ this.props = props || {};
+ }
+ setState(update, cb) {
+ this.__host && this.__host.__setLogicState(update, cb);
+ }
+ forceUpdate() {
+ this.__host && this.__host.forceUpdate();
+ }
+ componentDidMount() {
+ }
+ componentDidUpdate(_prevProps) {
+ }
+ componentWillUnmount() {
+ }
+ /** The flat object the template renders against (merged over props). */
+ renderVals() {
+ return {};
+ }
+ };
+ function evalDcLogic(src) {
+ //! nosemgrep: eval-and-function-constructor
+ const fn = new Function(
+ "DCLogic",
+ "StreamableLogic",
+ "React",
+ src + '\n;return (typeof Component!=="undefined"&&Component)||undefined;'
+ );
+ return fn(StreamableLogic, StreamableLogic, getReact());
+ }
+
+ // src/component.ts
+ function shallowEqual(a, b) {
+ if (!b) return false;
+ const ak = Object.keys(a).filter((k) => k !== "children");
+ const bk = Object.keys(b).filter((k) => k !== "children");
+ if (ak.length !== bk.length) return false;
+ for (const k of ak) if (a[k] !== b[k]) return false;
+ return true;
+ }
+ function Placeholder({
+ name,
+ hintSize,
+ streaming,
+ error
+ }) {
+ const [w, hgt] = (hintSize || "100%,60px").split(",");
+ return h(
+ "div",
+ {
+ className: "sc-placeholder" + (streaming ? " sc-streaming" : ""),
+ style: { width: w.trim(), height: hgt && hgt.trim() },
+ title: name
+ },
+ error ? h(
+ "div",
+ { className: "sc-placeholder-error" },
+ (name ? name + ": " : "") + error
+ ) : null
+ );
+ }
+ function hintToMin(hint) {
+ if (!hint) return void 0;
+ const [w, hgt] = hint.split(",");
+ return { minWidth: w.trim(), minHeight: hgt && hgt.trim() };
+ }
+ function createComponentFactory(registry, ensureFetched) {
+ const React = getReact();
+ const AncestorContext = React.createContext([]);
+ class StreamableComponent extends React.Component {
+ constructor(props) {
+ super(props);
+ __publicField(this, "__name");
+ __publicField(this, "__sub");
+ __publicField(this, "__needsDidMount", false);
+ /** Snapshot of the registry's streaming flags taken at render time —
+ * builders read it off the RenderCtx (this) to pick placeholder vs
+ * render-nothing for unresolved values. */
+ __publicField(this, "__streamingNow", false);
+ __publicField(this, "__htmlStreamingNow", false);
+ /** When a construct throws, remember the (class, registry.ver, props)
+ * triple so render-time reconcile doesn't re-attempt it on every parent
+ * re-render. A registry bump (new class, template, external module
+ * resolving via bumpAll) changes `ver` and breaks the memo so an
+ * env-dependent constructor can self-heal. */
+ __publicField(this, "__failedLogic", null);
+ __publicField(this, "__failedUserProps", null);
+ __publicField(this, "__failedVer", -1);
+ /** Per-instance constructor error — kept here (not on the registry entry)
+ * so one instance's successful construct can't hide a sibling's failure,
+ * and a construct can never wipe an eval error `updateJs` recorded on
+ * `r.logicError`. */
+ __publicField(this, "__ctorError", null);
+ __publicField(this, "logic");
+ this.__name = props.__name;
+ this.state = { __v: 0, __err: null };
+ this.__sub = () => {
+ if (this.state.__err) this.setState({ __err: null });
+ this.forceUpdate();
+ };
+ this.__makeLogic(registry.get(this.__name).Logic, null);
+ ensureFetched(this.__name);
+ }
+ /** Error-boundary hook: a render crash anywhere in this DC's subtree
+ * (its own template, an x-import'd component, a child DC without its
+ * own deeper boundary) lands here instead of unmounting the page. */
+ static getDerivedStateFromError(e) {
+ return { __err: e instanceof Error && e.message ? e.message : String(e) };
+ }
+ componentDidCatch(e, info) {
+ console.error(
+ "[dc-runtime] render error in <" + this.__name + ">:",
+ e,
+ info?.componentStack || ""
+ );
+ }
+ /** Instantiate the logic class (or the no-op base) and adopt `prevState`
+ * over its initial state — used both at mount and on hot-swap. */
+ __makeLogic(Logic, prevState) {
+ const L = Logic || StreamableLogic;
+ try {
+ this.logic = new L(this.__userProps());
+ this.__failedLogic = null;
+ this.__failedUserProps = null;
+ this.__ctorError = null;
+ } catch (e) {
+ console.error(e);
+ this.__failedLogic = Logic;
+ this.__failedUserProps = this.__userProps();
+ this.__failedVer = registry.get(this.__name).ver;
+ this.__ctorError = this.__name + ": " + (e instanceof Error && e.message ? e.message : String(e));
+ this.logic = new StreamableLogic(
+ this.__userProps()
+ );
+ }
+ this.logic.__host = this;
+ if (prevState)
+ this.logic.state = { ...this.logic.state || {}, ...prevState };
+ }
+ /** The props the author's logic + template see — internal __-prefixed
+ * wiring stripped. */
+ __userProps() {
+ const { __name, __hintSize, __tplId, __hostStyle, ...rest } = this.props;
+ return rest;
+ }
+ __setLogicState(update, cb) {
+ const prev = this.logic.state;
+ const patch = typeof update === "function" ? update(prev) : update;
+ this.logic.state = { ...prev, ...patch };
+ this.setState((s) => ({ __v: s.__v + 1 }), cb);
+ }
+ /** Swap the logic instance when the registry's Logic class changed
+ * (streaming completion, hot reload). State carries over; didMount
+ * re-fires after the swap commits so refs exist. */
+ __reconcileLogic() {
+ const r = registry.get(this.__name);
+ const Next = r.Logic;
+ const Cur = this.logic.constructor;
+ if (Next === Cur || !Next && Cur === StreamableLogic || Next === this.__failedLogic && r.ver === this.__failedVer && shallowEqual(this.__userProps(), this.__failedUserProps)) {
+ return;
+ }
+ if (!this.__needsDidMount) {
+ try {
+ this.logic.componentWillUnmount();
+ } catch (e) {
+ console.error(e);
+ }
+ }
+ this.__makeLogic(Next, this.logic.state);
+ this.__needsDidMount = true;
+ }
+ componentDidMount() {
+ registry.get(this.__name).subs.add(this.__sub);
+ try {
+ this.logic.componentDidMount();
+ } catch (e) {
+ console.error(e);
+ }
+ }
+ componentDidUpdate(prevProps) {
+ this.logic.props = this.__userProps();
+ if (this.__needsDidMount) {
+ if (this.state.__err || !registry.get(this.__name).tpl) return;
+ this.__needsDidMount = false;
+ try {
+ this.logic.componentDidMount();
+ } catch (e) {
+ console.error(e);
+ }
+ } else {
+ try {
+ this.logic.componentDidUpdate(prevProps);
+ } catch (e) {
+ console.error(e);
+ }
+ }
+ }
+ componentWillUnmount() {
+ registry.get(this.__name).subs.delete(this.__sub);
+ if (!this.__needsDidMount) {
+ try {
+ this.logic.componentWillUnmount();
+ } catch (e) {
+ console.error(e);
+ }
+ }
+ }
+ render() {
+ const r = registry.get(this.__name);
+ const cls = "sc-host" + (r.htmlStreaming ? " sc-streaming-html" : "") + (r.jsStreaming ? " sc-streaming-js" : "");
+ const hintStyle = r.htmlStreaming ? hintToMin(this.props.__hintSize) : void 0;
+ const hostStyle = this.props.__hostStyle || hintStyle ? { ...hintStyle || {}, ...this.props.__hostStyle || {} } : void 0;
+ const hostBase = {
+ className: cls,
+ style: hostStyle,
+ "data-sc-name": this.__name,
+ "data-dc-tpl": this.props.__tplId
+ };
+ const chain = Array.isArray(this.context) ? this.context : [];
+ if (chain.includes(this.__name)) {
+ const cycle = [
+ ...chain.slice(chain.indexOf(this.__name)),
+ this.__name
+ ].join(" \u2192 ");
+ return h(
+ "div",
+ { ...hostBase, className: cls + " sc-has-error" },
+ h(Placeholder, {
+ name: this.__name,
+ hintSize: this.props.__hintSize,
+ error: "circular import: " + cycle
+ })
+ );
+ }
+ if (this.state.__err) {
+ return h(
+ "div",
+ { ...hostBase, className: cls + " sc-has-error" },
+ h(
+ "div",
+ { className: "sc-logic-error", "data-omelette-chrome": "" },
+ this.__name + ": " + this.state.__err
+ ),
+ h(Placeholder, {
+ name: this.__name,
+ hintSize: this.props.__hintSize,
+ error: this.state.__err
+ })
+ );
+ }
+ this.__reconcileLogic();
+ if (!r.tpl) {
+ return h(
+ "div",
+ hostBase,
+ h(Placeholder, { name: this.__name, hintSize: this.props.__hintSize })
+ );
+ }
+ const userProps = this.__userProps();
+ this.logic.props = userProps;
+ let vals = userProps;
+ let renderErr = r.logicError || this.__ctorError;
+ try {
+ vals = { ...userProps, ...this.logic.renderVals() || {} };
+ } catch (e) {
+ console.error(e);
+ renderErr = this.__name + ".renderVals(): " + (e instanceof Error && e.message ? e.message : String(e));
+ }
+ this.__streamingNow = !!(r.htmlStreaming || r.jsStreaming);
+ this.__htmlStreamingNow = !!r.htmlStreaming;
+ return h(
+ "div",
+ { ...hostBase, className: cls + (renderErr ? " sc-has-error" : "") },
+ renderErr && h(
+ "div",
+ { className: "sc-logic-error", "data-omelette-chrome": "" },
+ renderErr
+ ),
+ h(
+ AncestorContext.Provider,
+ { value: [...chain, this.__name] },
+ r.tpl(vals, this)
+ )
+ );
+ }
+ }
+ __publicField(StreamableComponent, "contextType", AncestorContext);
+ const named = /* @__PURE__ */ new Map();
+ function getDC(name) {
+ const hit = named.get(name);
+ if (hit) return hit;
+ function Dispatcher(p) {
+ const [, setTick] = React.useState(0);
+ React.useEffect(() => {
+ const sub = () => setTick((n) => n + 1);
+ registry.get(name).subs.add(sub);
+ return () => {
+ registry.get(name).subs.delete(sub);
+ };
+ }, []);
+ ensureFetched(name);
+ return h(StreamableComponent, { ...p, __name: name });
+ }
+ Dispatcher.displayName = name;
+ named.set(name, Dispatcher);
+ return Dispatcher;
+ }
+ return {
+ getDC,
+ StreamableComponent
+ };
+ }
+
+ // src/bundled.ts
+ function bundledBlob(url) {
+ const blobs = window.__resourceBlobs;
+ const b = blobs ? blobs[url.split("#")[0]] : void 0;
+ return b instanceof Blob ? b : null;
+ }
+
+ // src/cdn.ts
+ var REACT_URL = "https://unpkg.com/react@18.3.1/umd/react.production.min.js";
+ var REACT_SRI = "sha384-DGyLxAyjq0f9SPpVevD6IgztCFlnMF6oW/XQGmfe+IsZ8TqEiDrcHkMLKI6fiB/Z";
+ var REACT_DOM_URL = "https://unpkg.com/react-dom@18.3.1/umd/react-dom.production.min.js";
+ var REACT_DOM_SRI = "sha384-gTGxhz21lVGYNMcdJOyq01Edg0jhn/c22nsx0kyqP0TxaV5WVdsSH1fSDUf5YJj1";
+ var BABEL_URL = "https://unpkg.com/@babel/standalone@7.29.0/babel.min.js";
+ var BABEL_SRI = "sha384-m08KidiNqLdpJqLq95G/LEi8Qvjl/xUYll3QILypMoQ65QorJ9Lvtp2RXYGBFj1y";
+ function cdnScriptFor(url, sri) {
+ const res = window.__resources;
+ const v = res ? res[url] : void 0;
+ return typeof v === "string" && v ? { src: v } : { src: url, integrity: sri };
+ }
+
+ // src/external.ts
+ var isCustomElementName = (n) => !n.includes(".") && n.includes("-");
+ function isRenderableType(g) {
+ if (typeof g === "function") return !isElementClass(g);
+ return typeof g === "object" && g !== null && typeof g.$$typeof === "symbol";
+ }
+ function resolveDottedPath(root, name) {
+ let cur = root;
+ for (const seg of name.split(".")) {
+ if (cur == null) return void 0;
+ cur = cur[seg];
+ }
+ return cur;
+ }
+ var GLOBAL_POLL_INTERVAL_MS = 50;
+ var GLOBAL_POLL_TIMEOUT_MS = 3e4;
+ function createExternalModules(onResolved) {
+ const cache = /* @__PURE__ */ new Map();
+ let babelLoading = null;
+ const reportedMissing = /* @__PURE__ */ new Map();
+ const polling = /* @__PURE__ */ new Set();
+ function ensureBabel() {
+ if (window.Babel) return Promise.resolve();
+ if (babelLoading) return babelLoading;
+ const babel = cdnScriptFor(BABEL_URL, BABEL_SRI);
+ babelLoading = new Promise((res, rej) => {
+ const s = document.createElement("script");
+ s.src = babel.src;
+ if (babel.integrity) {
+ s.integrity = babel.integrity;
+ s.crossOrigin = "anonymous";
+ }
+ s.onload = () => res();
+ s.onerror = rej;
+ document.head.appendChild(s);
+ });
+ return babelLoading;
+ }
+ const pending = /* @__PURE__ */ new Map();
+ function load(kind, url, after) {
+ const existing = pending.get(url);
+ if (existing) return existing;
+ cache.set(url, null);
+ console.info("[dc-runtime] x-import: loading", url, "(" + kind + ")");
+ const ready = Promise.all([
+ kind === "jsx" ? ensureBabel() : Promise.resolve(),
+ after ?? Promise.resolve()
+ ]);
+ const p = ready.then(() => {
+ const pre = bundledBlob(url);
+ if (pre) return pre.text();
+ return fetch(url).then((r) => {
+ if (!r.ok) throw new Error("HTTP " + r.status);
+ return r.text();
+ });
+ }).then((src) => {
+ const code = kind === "jsx" ? window.Babel.transform(src, {
+ filename: url,
+ presets: ["react", "typescript"]
+ }).code : src;
+ const module = { exports: {} };
+ const before = new Set(Object.keys(window));
+ //! nosemgrep: eval-and-function-constructor
+ new Function("React", "module", "exports", "require", code)(
+ getReact(),
+ module,
+ module.exports,
+ () => ({})
+ );
+ const globals = {};
+ for (const k of Object.keys(window)) {
+ if (!before.has(k) && typeof window[k] === "function") {
+ globals[k] = window[k];
+ }
+ }
+ cache.set(url, { mod: module.exports, globals });
+ console.info(
+ "[dc-runtime] x-import: loaded",
+ url,
+ "\u2014 exports:",
+ Object.keys(module.exports),
+ "window globals:",
+ Object.keys(globals)
+ );
+ onResolved();
+ }).catch((e) => {
+ cache.set(url, {
+ mod: {},
+ globals: {},
+ error: "failed to load: " + (e instanceof Error && e.message ? e.message : String(e))
+ });
+ console.error(
+ "[dc-runtime] x-import: FAILED to load",
+ url,
+ "(" + kind + ")",
+ e
+ );
+ onResolved();
+ });
+ pending.set(url, p);
+ return p;
+ }
+ function resolve2(url, name) {
+ const entry = cache.get(url);
+ if (!entry) return null;
+ const { mod, globals } = entry;
+ const C = mod && mod[name] || globals && globals[name] || typeof window !== "undefined" && window[name] || mod && mod.default;
+ if (typeof C === "function") return C;
+ const key = url + "\0" + name;
+ if (!reportedMissing.has(key)) {
+ reportedMissing.set(
+ key,
+ entry.error || 'no export named "' + name + '" (has: ' + Object.keys(mod).join(", ") + ")"
+ );
+ console.error(
+ "[dc-runtime] x-import: module",
+ url,
+ "loaded but has no component named",
+ JSON.stringify(name),
+ "\u2014 available exports:",
+ Object.keys(mod),
+ "window globals:",
+ Object.keys(globals),
+ ". The module must `module.exports = {" + name + "}` or set `window." + name + "`."
+ );
+ }
+ return null;
+ }
+ function waitForGlobal(name) {
+ if (polling.has(name)) return;
+ polling.add(name);
+ const started = Date.now();
+ const isCE = isCustomElementName(name);
+ const tick = () => {
+ const found = isCE ? customElements.get(name) : isRenderableType(resolveDottedPath(window, name));
+ if (found) {
+ polling.delete(name);
+ onResolved();
+ return;
+ }
+ if (Date.now() - started >= GLOBAL_POLL_TIMEOUT_MS) {
+ console.warn(
+ "[dc-runtime] x-import: global",
+ JSON.stringify(name),
+ "never appeared on window after " + GLOBAL_POLL_TIMEOUT_MS + "ms"
+ );
+ return;
+ }
+ setTimeout(tick, GLOBAL_POLL_INTERVAL_MS);
+ };
+ setTimeout(tick, GLOBAL_POLL_INTERVAL_MS);
+ }
+ function resolveGlobal(url, name) {
+ const isCE = isCustomElementName(name);
+ if (!url) {
+ if (isCE) {
+ if (customElements.get(name)) return name;
+ waitForGlobal(name);
+ return null;
+ }
+ const g2 = resolveDottedPath(window, name);
+ if (isRenderableType(g2)) return g2;
+ waitForGlobal(name);
+ return null;
+ }
+ const entry = cache.get(url);
+ if (!entry) return null;
+ if (isCE && customElements.get(name)) return name;
+ const g = entry.globals[name] ?? resolveDottedPath(window, name);
+ if (isRenderableType(g)) return g;
+ if (name.includes(".")) return null;
+ const key = url + "\0global\0" + name;
+ if (!reportedMissing.has(key)) {
+ reportedMissing.set(key, null);
+ if (isCE && !customElements.get(name)) {
+ console.warn(
+ "[dc-runtime] x-import:",
+ url,
+ "loaded but no custom element",
+ JSON.stringify(name),
+ "is registered and window." + name + " is not a function \u2014 rendering <" + name + "> as an unknown element."
+ );
+ }
+ }
+ return name;
+ }
+ function getError(url, name) {
+ const entry = cache.get(url);
+ if (entry?.error) return entry.error;
+ return reportedMissing.get(url + "\0" + name) || null;
+ }
+ return { load, resolve: resolve2, resolveGlobal, getError };
+ }
+ function isElementClass(g) {
+ try {
+ return typeof g === "function" && typeof HTMLElement !== "undefined" && g.prototype instanceof HTMLElement;
+ } catch {
+ return false;
+ }
+ }
+
+ // src/atomics.ts
+ var ATOMIC_CSS = (
+ // layout
+ ".fx{display:flex}.col{display:flex;flex-direction:column}.grid{display:grid}.ac{align-items:center}.jc{justify-content:center}.jb{justify-content:space-between}.f1{flex:1}.noshrink{flex-shrink:0}.wrap{flex-wrap:wrap}.fw5{font-weight:500}.fw6{font-weight:600}.fw7{font-weight:700}.fw8{font-weight:800}.fs11{font-size:11px}.fs12{font-size:12px}.fs13{font-size:13px}.fs14{font-size:14px}.fs15{font-size:15px}.fs16{font-size:16px}.fs20{font-size:20px}.fs22{font-size:22px}.upper{text-transform:uppercase}.tc{text-align:center}.nowrap{white-space:nowrap}.gap8{gap:8px}.gap10{gap:10px}.gap12{gap:12px}.gap16{gap:16px}.gap24{gap:24px}.m0{margin:0}.mt8{margin-top:8px}.mt12{margin-top:12px}.mt16{margin-top:16px}.mb8{margin-bottom:8px}.mb12{margin-bottom:12px}.mb16{margin-bottom:16px}.posrel{position:relative}.posabs{position:absolute}.round{border-radius:50%}.ohide{overflow:hidden}.bbox{box-sizing:border-box}.pointer{cursor:pointer}.w100{width:100%}.b0{border:none}"
+ );
+
+ // src/helmet.ts
+ var DESIGN_DOC_MODE_RE = / ]*\bname\s*=\s*["']design_doc_mode["'][^>]*\b(?:content|value)\s*=\s*["'](\w+)["']/i;
+ var CANVAS_BG_LIGHT = "#f0eee6";
+ var CANVAS_BG_DARK = "#2e2c26";
+ function createHelmetManager(doc, isStreaming) {
+ const mounted = /* @__PURE__ */ new Set();
+ const live = /* @__PURE__ */ new Map();
+ let designDocMode = null;
+ let canvasStyleEl = null;
+ let appTheme = "light";
+ try {
+ const ds = doc.documentElement.dataset.theme;
+ appTheme = ds === "dark" || ds === "light" ? ds : new URLSearchParams(doc.defaultView?.location.search ?? "").get(
+ "theme"
+ ) === "dark" ? "dark" : "light";
+ } catch {
+ }
+ function applyCanvasBg() {
+ if (!canvasStyleEl) return;
+ const bg = appTheme === "dark" ? CANVAS_BG_DARK : CANVAS_BG_LIGHT;
+ canvasStyleEl.textContent = `html,body{background:${bg}}#dc-root>.sc-host{position:relative}`;
+ }
+ function postDesignMode(mode) {
+ if (window.parent === window) return;
+ try {
+ window.parent.postMessage({ type: "__dc_design_mode", mode }, "*");
+ } catch {
+ }
+ }
+ function setDesignDocMode(mode) {
+ if (mode === designDocMode) return;
+ designDocMode = mode;
+ postDesignMode(mode);
+ if (mode === "canvas") {
+ doc.documentElement.setAttribute("data-dc-canvas", "");
+ canvasStyleEl = doc.createElement("style");
+ canvasStyleEl.setAttribute("data-dc-canvas", "");
+ applyCanvasBg();
+ doc.head.appendChild(canvasStyleEl);
+ } else {
+ doc.documentElement.removeAttribute("data-dc-canvas");
+ canvasStyleEl?.remove();
+ canvasStyleEl = null;
+ }
+ }
+ window.addEventListener("message", (e) => {
+ const type = e.data && e.data.type;
+ if (type === "__dc_theme") {
+ const t = e.data.theme;
+ if (t === "light" || t === "dark") {
+ appTheme = t;
+ applyCanvasBg();
+ }
+ return;
+ }
+ if (!designDocMode || type !== "__dc_probe") return;
+ postDesignMode(designDocMode);
+ });
+ function compile(node) {
+ const raw = [...node.children];
+ const helmetClosed = node.nextSibling != null || node.parentNode?.nextSibling != null;
+ if (node.hasAttribute("data-dc-atomics") && !mounted.has("__dc-atomics")) {
+ mounted.add("__dc-atomics");
+ const el = doc.createElement("style");
+ el.id = "__dc-atomics";
+ el.textContent = ATOMIC_CSS;
+ doc.head.appendChild(el);
+ }
+ return (_vals, ctx) => {
+ const name = ctx && ctx.__name || "";
+ const streaming = !!(name && isStreaming(name));
+ for (let i = 0; i < raw.length; i++) {
+ const child = raw[i];
+ const tag = child.tagName;
+ const mayBePartial = streaming && !helmetClosed && i === raw.length - 1;
+ if (tag === "SCRIPT") {
+ if (mayBePartial) continue;
+ const key = "SCRIPT|" + (child.getAttribute("src") || child.textContent || "");
+ if (mounted.has(key)) continue;
+ mounted.add(key);
+ const el = doc.createElement("script");
+ for (const { name: an, value } of [...child.attributes])
+ el.setAttribute(an, value);
+ if (child.textContent) el.textContent = child.textContent;
+ doc.head.appendChild(el);
+ } else if (tag === "LINK" || tag === "META") {
+ if (mayBePartial) continue;
+ const key = tag + "|" + (child.getAttribute("href") || child.getAttribute("src") || child.outerHTML);
+ if (mounted.has(key)) continue;
+ mounted.add(key);
+ if (tag === "LINK") {
+ const rel = (child.getAttribute("rel") || "").toLowerCase().split(/\s+/);
+ const href = (child.getAttribute("href") || "").trim();
+ const res = window.__resources;
+ const pre = res && rel.includes("stylesheet") && !rel.includes("alternate") ? res[href] : void 0;
+ const blob = typeof pre === "string" && pre ? bundledBlob(pre) : null;
+ if (blob) {
+ const el = doc.createElement("style");
+ if (child.hasAttribute("disabled")) {
+ el.setAttribute("media", "not all");
+ } else if (child.getAttribute("media")) {
+ el.setAttribute("media", child.getAttribute("media"));
+ }
+ if (child.getAttribute("title"))
+ el.setAttribute("title", child.getAttribute("title"));
+ void blob.text().then((css) => {
+ el.textContent = css;
+ });
+ doc.head.appendChild(el);
+ continue;
+ }
+ }
+ doc.head.appendChild(child.cloneNode(true));
+ } else {
+ const key = name + "|" + i;
+ let el = live.get(key);
+ if (!el || el.tagName !== tag) {
+ if (el) el.remove();
+ el = doc.createElement(tag.toLowerCase());
+ live.set(key, el);
+ doc.head.appendChild(el);
+ }
+ for (const { name: an, value } of [...child.attributes]) {
+ if (el.getAttribute(an) !== value) el.setAttribute(an, value);
+ }
+ if (el.textContent !== child.textContent)
+ el.textContent = child.textContent;
+ }
+ }
+ return null;
+ };
+ }
+ return { compile, setDesignDocMode };
+ }
+
+ // src/pseudo.ts
+ function scanUnquotedUrl(css, i) {
+ if (css[i] !== "u" && css[i] !== "U" || css.slice(i, i + 4).toLowerCase() !== "url(" || /[a-z0-9_-]/i.test(css[i - 1] ?? "")) {
+ return -1;
+ }
+ let j = i + 4;
+ while (j < css.length && /\s/.test(css[j])) j++;
+ if (css[j] === '"' || css[j] === "'") return -1;
+ while (j < css.length && css[j] !== ")") {
+ if (css[j] === "\\") j++;
+ j++;
+ }
+ return j < css.length ? j + 1 : css.length;
+ }
+ function stripComments(css) {
+ let out = "";
+ let quote = "";
+ for (let i = 0; i < css.length; i++) {
+ const c = css[i];
+ if (quote) {
+ if (c === "\\") {
+ out += c + (css[i + 1] ?? "");
+ i++;
+ continue;
+ }
+ if (c === quote) quote = "";
+ out += c;
+ } else if (c === "'" || c === '"') {
+ quote = c;
+ out += c;
+ } else if (c === "/" && css[i + 1] === "*") {
+ const end = css.indexOf("*/", i + 2);
+ i = end === -1 ? css.length : end + 1;
+ out += " ";
+ } else {
+ const end = scanUnquotedUrl(css, i);
+ if (end === -1) out += c;
+ else {
+ out += css.slice(i, end);
+ i = end - 1;
+ }
+ }
+ }
+ return out;
+ }
+ function importantify(css) {
+ css = stripComments(css);
+ const decls = [];
+ let start = 0;
+ let depth = 0;
+ let quote = "";
+ for (let i = 0; i < css.length; i++) {
+ const c = css[i];
+ if (quote) {
+ if (c === "\\") i++;
+ else if (c === quote) quote = "";
+ } else if (c === "'" || c === '"') quote = c;
+ else if (c === "(") depth++;
+ else if (c === ")") depth = Math.max(0, depth - 1);
+ else if (c === ";" && depth === 0) {
+ decls.push(css.slice(start, i));
+ start = i + 1;
+ } else {
+ const end = scanUnquotedUrl(css, i);
+ if (end !== -1) i = end - 1;
+ }
+ }
+ decls.push(css.slice(start));
+ return decls.map((d) => d.trim()).filter(Boolean).map((d) => /!\s*important$/i.test(d) ? d : d + " !important").join(";");
+ }
+ function createPseudoSheet(doc) {
+ let el = null;
+ const cache = /* @__PURE__ */ new Map();
+ let n = 0;
+ return (pseudo, css) => {
+ const k = pseudo + "|" + css;
+ const hit = cache.get(k);
+ if (hit) return hit;
+ if (!el) {
+ el = doc.createElement("style");
+ doc.head.appendChild(el);
+ }
+ const cls = "scp" + (n++).toString(36);
+ const isPseudoElement = pseudo === "before" || pseudo === "after";
+ const sel = isPseudoElement ? "." + cls + "::" + pseudo : "." + cls + ":" + pseudo;
+ el.sheet.insertRule(
+ sel + "{" + (isPseudoElement ? css : importantify(css)) + "}",
+ el.sheet.cssRules.length
+ );
+ cache.set(k, cls);
+ return cls;
+ };
+ }
+
+ // src/registry.ts
+ function createRegistry() {
+ const entries = /* @__PURE__ */ Object.create(null);
+ function get(name) {
+ return entries[name] || (entries[name] = {
+ html: "",
+ tpl: null,
+ Logic: null,
+ jsStreaming: false,
+ htmlStreaming: false,
+ ver: 0,
+ subs: /* @__PURE__ */ new Set(),
+ fetched: false
+ });
+ }
+ function bump(name) {
+ const r = get(name);
+ r.ver++;
+ for (const fn of r.subs) fn();
+ }
+ return {
+ entries,
+ get,
+ bump,
+ bumpAll() {
+ for (const n in entries) bump(n);
+ }
+ };
+ }
+
+ // src/runtime.ts
+ var COMPONENT_DIR = ".";
+ function createRuntime(doc = document) {
+ const registry = createRegistry();
+ const pseudoClass = createPseudoSheet(doc);
+ const helmet = createHelmetManager(
+ doc,
+ (name) => registry.get(name).htmlStreaming
+ );
+ const external = createExternalModules(() => registry.bumpAll());
+ const factory = createComponentFactory(registry, ensureFetched);
+ const host = {
+ component: (name) => factory.getDC(name),
+ placeholder: (props) => h(Placeholder, props),
+ helmet: (node) => helmet.compile(node),
+ loadExternal: (kind, url, after) => external.load(kind, url, after),
+ resolveExternal: (url, name) => external.resolve(url, name),
+ resolveExternalGlobal: (url, name) => external.resolveGlobal(url, name),
+ resolveExternalError: (url, name) => external.getError(url, name),
+ pseudoClass
+ };
+ function ensureFetched(name) {
+ const r = registry.get(name);
+ if (r.fetched) return;
+ r.fetched = true;
+ const url = COMPONENT_DIR + "/" + encodeURIComponent(name) + ".dc.html";
+ const res = window.__resources;
+ const pre = res ? res[url] : void 0;
+ const target = typeof pre === "string" && pre ? pre : url;
+ const blob = bundledBlob(target);
+ (blob ? blob.text() : fetch(target).then((res2) => {
+ if (!res2.ok) {
+ console.error(
+ '[dc-runtime] sibling fetch for "' + name + '" failed:',
+ url,
+ "returned",
+ res2.status,
+ "\u2014 the reference renders as an empty placeholder."
+ );
+ return "";
+ }
+ return res2.text();
+ })).then((t) => {
+ if (!t) return;
+ const parsed = parseDcText(t);
+ if (!parsed) {
+ console.error(
+ '[dc-runtime] sibling fetch for "' + name + '":',
+ url,
+ "has no block \u2014 not a Design Component."
+ );
+ return;
+ }
+ if (parsed.props) r.propsMeta = parsed.props;
+ if (parsed.preview) r.preview = parsed.preview;
+ if (parsed.template && !r.html) updateHtml(name, parsed.template);
+ if (parsed.js && !r.Logic) updateJs(name, parsed.js);
+ }).catch(
+ (e) => console.error(
+ '[dc-runtime] sibling fetch for "' + name + '" threw:',
+ url,
+ e
+ )
+ );
+ }
+ let rootName = null;
+ function updateHtml(name, html) {
+ const r = registry.get(name);
+ r.html = html;
+ if (name === rootName) {
+ const mode = DESIGN_DOC_MODE_RE.exec(html)?.[1] ?? null;
+ if (mode || !r.htmlStreaming) helmet.setDesignDocMode(mode);
+ }
+ try {
+ r.tpl = compileTemplate(html, host);
+ } catch (e) {
+ console.error("[dc-runtime] template compile FAILED for", name, e);
+ }
+ registry.bump(name);
+ }
+ function updateJs(name, src) {
+ const r = registry.get(name);
+ const seq = r.jsSeq = (r.jsSeq || 0) + 1;
+ try {
+ const Cls = evalDcLogic(src);
+ if (r.jsSeq !== seq) return;
+ if (typeof Cls !== "function") {
+ r.logicError = name + ".dc.html: