@0001-labs/design-system-1 0.3.0-alpha.19 → 0.3.0-alpha.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/DS1/0-face/app-banner.ts +1 -1
- package/DS1/0-face/bento.ts +84 -0
- package/DS1/0-face/calendar.ts +2 -2
- package/DS1/1-root/bento.css +97 -0
- package/DS1/1-root/card.css +6 -1
- package/DS1/1-root/cjk.css +1 -1
- package/DS1/1-root/controls.css +1 -0
- package/DS1/1-root/fonts.css +1 -1
- package/DS1/1-root/one.css +1 -1
- package/DS1/1-root/one.semantic.css +1 -1
- package/DS1/3-unit/calendar-base.ts +31 -22
- package/DS1/3-unit/ds-bento.ts +67 -0
- package/DS1/3-unit/ds-calendar.ts +477 -22
- package/DS1/3-unit/styles/ds-bento.css +66 -0
- package/DS1/3-unit/styles/ds-calendar.css +119 -1
- package/DS1/index.ts +1 -1
- package/dist/0-face/app-banner.js +1 -1
- package/dist/0-face/bento.d.ts +41 -0
- package/dist/0-face/bento.d.ts.map +1 -0
- package/dist/0-face/bento.js +77 -0
- package/dist/0-face/calendar.js +2 -2
- package/dist/3-unit/calendar-base.d.ts +17 -12
- package/dist/3-unit/calendar-base.d.ts.map +1 -1
- package/dist/3-unit/calendar-base.js +21 -16
- package/dist/3-unit/ds-bento.d.ts +31 -0
- package/dist/3-unit/ds-bento.d.ts.map +1 -0
- package/dist/3-unit/ds-bento.js +47 -0
- package/dist/3-unit/ds-calendar-large.d.ts +3 -4
- package/dist/3-unit/ds-calendar-large.d.ts.map +1 -1
- package/dist/3-unit/ds-calendar.d.ts +139 -12
- package/dist/3-unit/ds-calendar.d.ts.map +1 -1
- package/dist/3-unit/ds-calendar.js +464 -23
- package/dist/design-system-1.bundle.js +1125 -1095
- package/dist/design-system-1.bundle.js.map +1 -1
- package/dist/design-system-1.bundle.min.js +2484 -2457
- package/dist/design-system-1.bundle.min.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/DS1/3-unit/ds-date-picker.ts +0 -540
- package/DS1/3-unit/styles/ds-date-picker.css +0 -124
- package/dist/3-unit/ds-date-picker.d.ts +0 -203
- package/dist/3-unit/ds-date-picker.d.ts.map +0 -1
- package/dist/3-unit/ds-date-picker.js +0 -499
|
@@ -6644,7 +6644,7 @@ _ColorInput.styles = [r$3(component_metrics_default), i$4`
|
|
|
6644
6644
|
define("ds-color", ColorInput);
|
|
6645
6645
|
//#endregion
|
|
6646
6646
|
//#region DS1/1-root/card.css?inline
|
|
6647
|
-
var card_default = "/* Shape is a surface preference. Keep these base lengths unscaled: each\n * component resolves them with its own --ds-sf in component-metrics.css. */\n[data-ds-shape=\"square\"],\n:host([data-ds-shape=\"square\"]) {\n --ds-corner-size: 0px;\n --ds-corner-shape: round;\n --ds-button-inset: 0.5px;\n}\n\n[data-ds-shape=\"rounded\"],\n:host([data-ds-shape=\"rounded\"]) {\n --ds-corner-size: 4px;\n --ds-corner-shape: round;\n --ds-button-inset: 2.5px;\n}\n\n[data-ds-shape=\"circular\"],\n:host([data-ds-shape=\"circular\"]) {\n --ds-corner-size: 999px;\n --ds-corner-shape: round;\n --ds-button-inset: 5px;\n}\n\n/* A squircle needs twice an arc's radius for the same apparent corner.\n * Circular controls keep true semicircles even in a squircle browser. */\n@supports (corner-shape: squircle) {\n [data-ds-shape=\"rounded\"],\n :host([data-ds-shape=\"rounded\"]) {\n --ds-corner-size: 8px;\n --ds-corner-shape: squircle;\n }\n}\n\n/* Resolve dimensions where a component is drawn. Inherited calc() values have\n * already used their ancestor's scale. Base tokens stay unscaled and inherit;\n * resolved tokens can still be overridden directly on a component.\n * data-ds-surface gives ordinary layout elements the same scaled measures.\n */\n:root,\n:host,\n:where([data-ds-surface]) {\n --ds-unit: calc(var(--ds-1, 20px) * var(--ds-sf, 1));\n --ds-control-height: calc(var(--ds-control-size, var(--ds-08, 16px)) * var(--ds-sf, 1));\n --ds-row-height: calc(var(--ds-row-size, var(--ds-1, 20px)) * var(--ds-sf, 1));\n --ds-type-size-default: calc(var(--ds-text-size, 14px) * var(--ds-sf, 1));\n --ds-type-size-small: calc(var(--ds-small-text-size, 10px) * var(--ds-sf, 1));\n --ds-type-size-heading: calc(var(--ds-heading-text-size, 13px) * var(--ds-sf, 1));\n --ds-type-size-display: calc(var(--ds-display-text-size, 20px) * var(--ds-sf, 1));\n --ds-type-lineheight-default: calc(var(--ds-text-leading, 16px) * var(--ds-sf, 1));\n --ds-type-letterspacing-default: calc(var(--ds-text-tracking, -0.3px) * var(--ds-sf, 1));\n --ds-radius: calc(var(--ds-corner-size, 4px) * var(--ds-sf, 1));\n --ds-radius-card: calc(var(--ds-card-corner-size, 4px) * var(--ds-sf, 1));\n}\n\n/*\n * A card, as plain classes on native elements.\n *\n * A card holds one thing on a fill of its own: its name in the muted ink on\n * one square, a title in the display size on lines of a square and a half, writing,\n * and a picture of it (`ds-card__media`) a square below, which can run off\n * the card's foot and end edge and be cut there, never framed. Its size is\n * given in whole squares, its padding one square, its corners a card's\n * (`--ds-radius-card`). A card that opens something is one press target, an\n * `<a class=\"ds-card\" href>`: the pointer tints it, keyboard focus rings it\n * 2px inside and its picture rises a little. Ordinary writing still sits\n * straight on the paper; a card is for a thing shown among others, as in a\n * slide. The `ds-card` element draws the same parts.\n *\n * ds-card the card; `data-tone` names a palette colour\n * for its fill (the colour's pastel, dim in dark\n * mode, from palette.css, which one.css imports),\n * `ink` for the ink with the paper's words\n * ds-card--outlined a 1px line and no fill\n * ds-card__label its name, muted, on one square\n * ds-card__title the title, display size, a square and a half a line\n * ds-card__body writing, one square a line\n * ds-card__media the picture, a square below the words\n * ds-card__media--center standing in the card's middle\n * ds-card__media--bleed running on past the padding to the end edge\n *\n * Tokens: `--ds-card-width` and `--ds-card-height` (whole squares; the\n * content's size by default), `--ds-card-padding` (one square), and\n * `--ds-card-fill`, `--ds-card-ink` and `--ds-card-muted`.\n */\n\n.ds-card {\n --ds-card-fill: var(--ds-fill);\n --ds-card-ink: var(--ds-text-color);\n --ds-card-muted: var(--ds-text-color-muted);\n --ds-card-padding: var(--ds-unit);\n position: relative;\n box-sizing: border-box;\n display: flex;\n flex-direction: column;\n align-items: stretch;\n width: var(--ds-card-width, auto);\n height: var(--ds-card-height, auto);\n min-width: 0;\n margin: 0;\n padding
|
|
6647
|
+
var card_default = "/* Shape is a surface preference. Keep these base lengths unscaled: each\n * component resolves them with its own --ds-sf in component-metrics.css. */\n[data-ds-shape=\"square\"],\n:host([data-ds-shape=\"square\"]) {\n --ds-corner-size: 0px;\n --ds-corner-shape: round;\n --ds-button-inset: 0.5px;\n}\n\n[data-ds-shape=\"rounded\"],\n:host([data-ds-shape=\"rounded\"]) {\n --ds-corner-size: 4px;\n --ds-corner-shape: round;\n --ds-button-inset: 2.5px;\n}\n\n[data-ds-shape=\"circular\"],\n:host([data-ds-shape=\"circular\"]) {\n --ds-corner-size: 999px;\n --ds-corner-shape: round;\n --ds-button-inset: 5px;\n}\n\n/* A squircle needs twice an arc's radius for the same apparent corner.\n * Circular controls keep true semicircles even in a squircle browser. */\n@supports (corner-shape: squircle) {\n [data-ds-shape=\"rounded\"],\n :host([data-ds-shape=\"rounded\"]) {\n --ds-corner-size: 8px;\n --ds-corner-shape: squircle;\n }\n}\n\n/* Resolve dimensions where a component is drawn. Inherited calc() values have\n * already used their ancestor's scale. Base tokens stay unscaled and inherit;\n * resolved tokens can still be overridden directly on a component.\n * data-ds-surface gives ordinary layout elements the same scaled measures.\n */\n:root,\n:host,\n:where([data-ds-surface]) {\n --ds-unit: calc(var(--ds-1, 20px) * var(--ds-sf, 1));\n --ds-control-height: calc(var(--ds-control-size, var(--ds-08, 16px)) * var(--ds-sf, 1));\n --ds-row-height: calc(var(--ds-row-size, var(--ds-1, 20px)) * var(--ds-sf, 1));\n --ds-type-size-default: calc(var(--ds-text-size, 14px) * var(--ds-sf, 1));\n --ds-type-size-small: calc(var(--ds-small-text-size, 10px) * var(--ds-sf, 1));\n --ds-type-size-heading: calc(var(--ds-heading-text-size, 13px) * var(--ds-sf, 1));\n --ds-type-size-display: calc(var(--ds-display-text-size, 20px) * var(--ds-sf, 1));\n --ds-type-lineheight-default: calc(var(--ds-text-leading, 16px) * var(--ds-sf, 1));\n --ds-type-letterspacing-default: calc(var(--ds-text-tracking, -0.3px) * var(--ds-sf, 1));\n --ds-radius: calc(var(--ds-corner-size, 4px) * var(--ds-sf, 1));\n --ds-radius-card: calc(var(--ds-card-corner-size, 4px) * var(--ds-sf, 1));\n}\n\n/*\n * A card, as plain classes on native elements.\n *\n * A card holds one thing on a fill of its own: its name in the muted ink on\n * one square, a title in the display size on lines of a square and a half, writing,\n * and a picture of it (`ds-card__media`) a square below, which can run off\n * the card's foot and end edge and be cut there, never framed. Its size is\n * given in whole squares, its padding one square, its corners a card's\n * (`--ds-radius-card`). A card that opens something is one press target, an\n * `<a class=\"ds-card\" href>`: the pointer tints it, keyboard focus rings it\n * 2px inside and its picture rises a little. Ordinary writing still sits\n * straight on the paper; a card is for a thing shown among others, as in a\n * slide. The `ds-card` element draws the same parts.\n *\n * ds-card the card; `data-tone` names a palette colour\n * for its fill (the colour's pastel, dim in dark\n * mode, from palette.css, which one.css imports),\n * `ink` for the ink with the paper's words\n * ds-card--outlined a 1px line and no fill\n * ds-card__label its name, muted, on one square\n * ds-card__title the title, display size, a square and a half a line\n * ds-card__body writing, one square a line\n * ds-card__media the picture, a square below the words\n * ds-card__media--center standing in the card's middle\n * ds-card__media--bleed running on past the padding to the end edge\n *\n * Tokens: `--ds-card-width` and `--ds-card-height` (whole squares; the\n * content's size by default), `--ds-card-padding` (one square), and\n * `--ds-card-fill`, `--ds-card-ink` and `--ds-card-muted`.\n */\n\n.ds-card {\n --ds-card-fill: var(--ds-fill);\n --ds-card-ink: var(--ds-text-color);\n --ds-card-muted: var(--ds-text-color-muted);\n --ds-card-padding: var(--ds-unit);\n position: relative;\n box-sizing: border-box;\n display: flex;\n flex-direction: column;\n align-items: stretch;\n width: var(--ds-card-width, auto);\n height: var(--ds-card-height, auto);\n min-width: 0;\n margin: 0;\n /* In a squares bento the surface reaches a quarter square towards its neighbours (`--ds-bento-inset-*`, 0 elsewhere), and the padding grows by as much so what it holds stays on the squares. */\n padding:\n calc(var(--ds-card-padding) + var(--ds-bento-inset-top, 0px))\n calc(var(--ds-card-padding) + var(--ds-bento-inset-end, 0px))\n var(--ds-bento-inset-bottom, 0px)\n calc(var(--ds-card-padding) + var(--ds-bento-inset-start, 0px));\n overflow: hidden;\n border-radius: var(--ds-radius-card);\n background: var(--ds-card-fill);\n color: var(--ds-card-ink);\n font-family: var(--ds-typeface-regular);\n font-size: var(--ds-type-size-default);\n text-decoration: none;\n -webkit-tap-highlight-color: transparent;\n}\n\n.ds-card[hidden] {\n display: none;\n}\n\n.ds-card--outlined {\n --ds-card-fill: transparent;\n box-shadow: inset 0 0 0 1px var(--ds-border-color);\n}\n\n.ds-card[data-tone=\"apple-green\"] { --ds-card-fill: var(--one-apple-green-pastel); }\n.ds-card[data-tone=\"chartreuse\"] { --ds-card-fill: var(--one-chartreuse-pastel); }\n.ds-card[data-tone=\"every-green\"] { --ds-card-fill: var(--one-every-green-pastel); }\n.ds-card[data-tone=\"yellow\"] { --ds-card-fill: var(--one-yellow-pastel); }\n.ds-card[data-tone=\"orange\"] { --ds-card-fill: var(--one-orange-pastel); }\n.ds-card[data-tone=\"tuned-red\"] { --ds-card-fill: var(--one-tuned-red-pastel); }\n.ds-card[data-tone=\"pink\"] { --ds-card-fill: var(--one-pink-pastel); }\n.ds-card[data-tone=\"sharp-blue\"] { --ds-card-fill: var(--one-sharp-blue-pastel); }\n.ds-card[data-tone=\"winning-blue\"] { --ds-card-fill: var(--one-winning-blue-pastel); }\n.ds-card[data-tone=\"hysteric-blue\"] { --ds-card-fill: var(--one-hysteric-blue-pastel); }\n.ds-card[data-tone=\"purple\"] { --ds-card-fill: var(--one-purple-pastel); }\n.ds-card[data-tone=\"metal-green\"] { --ds-card-fill: var(--one-metal-green-pastel); }\n.ds-card[data-tone=\"drip-yellow\"] { --ds-card-fill: var(--one-drip-yellow-pastel); }\n.ds-card[data-tone=\"sand\"] { --ds-card-fill: var(--one-sand-pastel); }\n.ds-card[data-tone=\"old-gold\"] { --ds-card-fill: var(--one-old-gold-pastel); }\n.ds-card[data-tone=\"red-for-blood\"] { --ds-card-fill: var(--one-red-for-blood-pastel); }\n.ds-card[data-tone=\"dark-red-variant\"] { --ds-card-fill: var(--one-dark-red-variant-pastel); }\n.ds-card[data-tone=\"signal-red\"] { --ds-card-fill: var(--one-signal-red-pastel); }\n.ds-card[data-tone=\"ink\"] {\n --ds-card-fill: var(--ds-black);\n --ds-card-ink: var(--ds-white);\n --ds-card-muted: color-mix(in srgb, var(--ds-white) 60%, transparent);\n box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--ds-white) 8%, transparent);\n}\n\n/* Words: each line on the lower sixteen of its square. They keep their room\n in a card of a set height; only the picture is cut at the foot. */\n.ds-card__label,\n.ds-card__title,\n.ds-card__body {\n flex: none;\n}\n\n.ds-card__label {\n margin: 0;\n padding-top: calc(4px * var(--ds-sf, 1));\n color: var(--ds-card-muted);\n font: inherit;\n line-height: var(--ds-type-lineheight-default, calc(16px * var(--ds-sf, 1)));\n}\n\n.ds-card__title {\n margin: 0;\n color: var(--ds-card-ink);\n font-family: var(--ds-typeface-medium);\n font-size: var(--ds-type-size-display);\n font-weight: var(--ds-type-weight-bold);\n /* A title that wraps keeps its lines together: a square and a half each. */\n line-height: calc(1.5 * var(--ds-unit));\n letter-spacing: calc(var(--ds-display-text-tracking, -0.4px) * var(--ds-sf, 1));\n text-wrap: balance;\n}\n\n.ds-card__body {\n margin: 0;\n line-height: var(--ds-unit);\n}\n\n.ds-card__media {\n display: flex;\n flex: none;\n align-items: flex-start;\n justify-content: flex-start;\n min-width: 0;\n margin-top: var(--ds-unit);\n}\n\n.ds-card__media--center {\n justify-content: center;\n margin-inline: calc(-1 * var(--ds-card-padding));\n}\n\n.ds-card__media--bleed {\n margin-inline-end: calc(-1 * var(--ds-card-padding));\n}\n\n.ds-card__media > * {\n flex: none;\n}\n\n/* A card that opens something. */\na.ds-card,\n.ds-card[data-interactive] {\n cursor: pointer;\n}\n\na.ds-card::after,\n.ds-card[data-interactive]::after {\n content: \"\";\n position: absolute;\n inset: 0;\n border-radius: inherit;\n background: transparent;\n pointer-events: none;\n}\n\na.ds-card:focus-visible,\n.ds-card[data-interactive]:focus-visible {\n outline: 2px solid var(--ds-focus-ring);\n outline-offset: -2px;\n}\n\n@media (hover: hover) {\n a.ds-card:hover::after,\n .ds-card[data-interactive]:hover::after {\n background: color-mix(in srgb, var(--ds-card-ink) 4%, transparent);\n }\n}\n\na.ds-card:active::after,\n.ds-card[data-interactive]:active::after {\n background: color-mix(in srgb, var(--ds-card-ink) 8%, transparent);\n}\n\n@media (hover: hover) and (prefers-reduced-motion: no-preference) {\n a.ds-card > .ds-card__media,\n .ds-card[data-interactive] > .ds-card__media {\n transition: transform 240ms cubic-bezier(0.23, 1, 0.32, 1);\n }\n\n a.ds-card:hover > .ds-card__media,\n .ds-card[data-interactive]:hover > .ds-card__media {\n transform: translateY(calc(-0.25 * var(--ds-unit)));\n }\n}\n";
|
|
6648
6648
|
//#endregion
|
|
6649
6649
|
//#region DS1/2-core/styles/ds-card.css?inline
|
|
6650
6650
|
var ds_card_default = "/* ds-card.css */\n/* The element places the card; 1-root/card.css draws it. The host takes the\n card's size, so a card is measured where it stands, in a slide too. */\n\n:host {\n display: flex;\n box-sizing: border-box;\n width: var(--ds-card-width, auto);\n height: var(--ds-card-height, auto);\n min-width: 0;\n}\n\n:host([hidden]) {\n display: none !important;\n}\n\n:host([disabled]) {\n opacity: 0.5;\n pointer-events: none;\n}\n\n.ds-card {\n flex: 1;\n width: auto;\n height: auto;\n}\n\n[hidden] {\n display: none !important;\n}\n\n::slotted([slot=\"media\"]) {\n flex: none;\n}\n";
|
|
@@ -8800,7 +8800,7 @@ function ensureSmartAppBanner(options) {
|
|
|
8800
8800
|
const meta = document.createElement("meta");
|
|
8801
8801
|
meta.name = "apple-itunes-app";
|
|
8802
8802
|
meta.content = [`app-id=${options.appId}`, options.open ? `app-argument=${options.open}` : ""].filter(Boolean).join(", ");
|
|
8803
|
-
document.head.
|
|
8803
|
+
document.head.appendChild(meta);
|
|
8804
8804
|
}
|
|
8805
8805
|
/**
|
|
8806
8806
|
* Opens the app: the deep link first, then the App Store when the page is
|
|
@@ -8828,7 +8828,7 @@ function openApp(options, wait = 1500) {
|
|
|
8828
8828
|
}
|
|
8829
8829
|
//#endregion
|
|
8830
8830
|
//#region DS1/1-root/controls.css?inline
|
|
8831
|
-
var controls_default = "/* Shape is a surface preference. Keep these base lengths unscaled: each\n * component resolves them with its own --ds-sf in component-metrics.css. */\n[data-ds-shape=\"square\"],\n:host([data-ds-shape=\"square\"]) {\n --ds-corner-size: 0px;\n --ds-corner-shape: round;\n --ds-button-inset: 0.5px;\n}\n\n[data-ds-shape=\"rounded\"],\n:host([data-ds-shape=\"rounded\"]) {\n --ds-corner-size: 4px;\n --ds-corner-shape: round;\n --ds-button-inset: 2.5px;\n}\n\n[data-ds-shape=\"circular\"],\n:host([data-ds-shape=\"circular\"]) {\n --ds-corner-size: 999px;\n --ds-corner-shape: round;\n --ds-button-inset: 5px;\n}\n\n/* A squircle needs twice an arc's radius for the same apparent corner.\n * Circular controls keep true semicircles even in a squircle browser. */\n@supports (corner-shape: squircle) {\n [data-ds-shape=\"rounded\"],\n :host([data-ds-shape=\"rounded\"]) {\n --ds-corner-size: 8px;\n --ds-corner-shape: squircle;\n }\n}\n\n/* Resolve dimensions where a component is drawn. Inherited calc() values have\n * already used their ancestor's scale. Base tokens stay unscaled and inherit;\n * resolved tokens can still be overridden directly on a component.\n * data-ds-surface gives ordinary layout elements the same scaled measures.\n */\n:root,\n:host,\n:where([data-ds-surface]) {\n --ds-unit: calc(var(--ds-1, 20px) * var(--ds-sf, 1));\n --ds-control-height: calc(var(--ds-control-size, var(--ds-08, 16px)) * var(--ds-sf, 1));\n --ds-row-height: calc(var(--ds-row-size, var(--ds-1, 20px)) * var(--ds-sf, 1));\n --ds-type-size-default: calc(var(--ds-text-size, 14px) * var(--ds-sf, 1));\n --ds-type-size-small: calc(var(--ds-small-text-size, 10px) * var(--ds-sf, 1));\n --ds-type-size-heading: calc(var(--ds-heading-text-size, 13px) * var(--ds-sf, 1));\n --ds-type-size-display: calc(var(--ds-display-text-size, 20px) * var(--ds-sf, 1));\n --ds-type-lineheight-default: calc(var(--ds-text-leading, 16px) * var(--ds-sf, 1));\n --ds-type-letterspacing-default: calc(var(--ds-text-tracking, -0.3px) * var(--ds-sf, 1));\n --ds-radius: calc(var(--ds-corner-size, 4px) * var(--ds-sf, 1));\n --ds-radius-card: calc(var(--ds-card-corner-size, 4px) * var(--ds-sf, 1));\n}\n/*\n * A table: words straight on the paper, one square a row. No box and no\n * column lines: each row stands on a hairline at its foot, its words set on\n * that line like a caption: the sixteen of words against the 1px line, three\n * spare above, a 20px pitch, as Ezo sets every row.\n * Column headers keep the text's weight in the title grey; the first column\n * of a body row is a row header in the text colour. Nothing is filled with\n * the accent except a cell someone has selected.\n *\n * `.ds-table` dresses a native <table>; `<ds-table>` draws the same table\n * from data. Put a wide table in `.ds-table-scroll` to scroll it sideways,\n * and give the table `data-sticky` to keep its first column in place.\n *\n * <th data-numeric>, <td data-numeric> numbers, set to the column's end\n * <tfoot> totals, under a line of their own\n * <th colspan=\"2\"> a column group, in a header row\n * <th scope=\"rowgroup\"> a row group, a heading row in grey\n * <td aria-selected=\"true\"> a selected cell\n *\n * `data-sheet` makes it a spreadsheet: every cell four squares by one (80 by\n * 20), its 1px lines at its end and foot so the words have 79 by 19, set 4px\n * in on the sixteen, as an Ezo item's are. Column letters and the row numbers\n * (`.ds-table__letters`, `.ds-table__number`, two squares wide) stay in place\n * while the sheet scrolls both ways inside `.ds-table-scroll`; give the table\n * `--ds-table-columns` (the number of data columns) and the scroll a height\n * with `--ds-table-height`.\n */\n\n.ds-table {\n --ds-table-row: var(--ds-row-height, calc(20px * var(--ds-sf, 1)));\n --ds-table-gap: calc(var(--ds-table-row) / 2);\n --ds-table-rule: var(--ds-border-color, light-dark(#d8d8d8, #3d3d3d));\n --ds-table-paper: var(--ds-background, Canvas);\n width: 100%;\n border-collapse: collapse;\n border-spacing: 0;\n color: var(--ds-text-color, inherit);\n font-family: var(--ds-typeface-regular, inherit);\n font-feature-settings: var(--ds-font-features, normal);\n font-size: var(--ds-type-size-default, 14px);\n letter-spacing: var(--ds-type-letterspacing-default, normal);\n}\n\n.ds-table :is(th, td) {\n box-sizing: border-box;\n height: var(--ds-table-row);\n padding: 0 var(--ds-table-gap) 0 0;\n border: 0;\n border-bottom: 1px solid var(--ds-table-rule);\n background: transparent;\n line-height: var(--ds-type-lineheight-default);\n text-align: start;\n vertical-align: bottom;\n font-weight: inherit;\n white-space: nowrap;\n}\n\n.ds-table :is(th, td):last-child {\n padding-inline-end: 0;\n}\n\n.ds-table thead th,\n.ds-table th[scope=\"rowgroup\"] {\n color: var(--ds-title-color, light-dark(#797979, #9a9a9a));\n}\n\n.ds-table tbody th:not([scope=\"rowgroup\"]) {\n color: inherit;\n}\n\n.ds-table [data-numeric] {\n text-align: end;\n font-variant-numeric: tabular-nums;\n}\n\n/* Totals: the rule above them is the last body row's; theirs closes the table. */\n.ds-table tfoot :is(th, td) {\n color: inherit;\n}\n\n.ds-table [aria-selected=\"true\"] {\n background: var(--ds-accent-color, Highlight);\n color: var(--ds-button-text-color-on-accent, inherit);\n}\n\n.ds-table :is(th, td):has(> :is(a, button):only-child) {\n cursor: pointer;\n}\n\n.ds-table caption {\n box-sizing: border-box;\n height: var(--ds-table-row);\n padding-top: calc(var(--ds-table-row) - var(--ds-type-lineheight-default));\n line-height: var(--ds-type-lineheight-default);\n text-align: start;\n color: var(--ds-title-color, light-dark(#797979, #9a9a9a));\n}\n\n.ds-table-scroll {\n max-width: 100%;\n overflow-x: auto;\n overscroll-behavior-x: contain;\n}\n\n.ds-table-scroll > .ds-table {\n width: max-content;\n min-width: 100%;\n}\n\n.ds-table[data-sticky] :is(th, td):first-child {\n position: sticky;\n inset-inline-start: 0;\n z-index: 1;\n background: var(--ds-table-paper);\n}\n\n.ds-table[data-sticky] [aria-selected=\"true\"]:first-child {\n background: var(--ds-accent-color, Highlight);\n}\n\n/* Keep the row whose details are open visible, including its sticky first cell.\n Cell selection remains independent and keeps its accent. */\n.ds-table tbody > tr[data-open]:not([data-open=\"false\"]) > :is(th, td):not([aria-selected=\"true\"]) {\n background: var(--ds-row-fill-current, var(--ds-fill-hover));\n}\n@media (forced-colors: active) {\n .ds-table tbody > tr[data-open]:not([data-open=\"false\"]) > :is(th, td):not([aria-selected=\"true\"]) {\n background: Highlight;\n color: HighlightText;\n }\n}\n\n/* A spreadsheet: cells four squares by one, on lines, lettered and numbered. */\n.ds-table[data-sheet] {\n --ds-table-cell: calc(4 * var(--ds-table-row));\n --ds-table-index: calc(2 * var(--ds-table-row));\n --ds-table-text: calc(4px * var(--ds-sf, 1));\n table-layout: fixed;\n width: calc(var(--ds-table-index) + var(--ds-table-columns, 8) * var(--ds-table-cell));\n min-width: 0;\n border-collapse: separate;\n border-spacing: 0;\n}\n.ds-table-scroll > .ds-table[data-sheet] {\n width: calc(var(--ds-table-index) + var(--ds-table-columns, 8) * var(--ds-table-cell));\n min-width: 0;\n}\n.ds-table[data-sheet] :is(th, td) {\n width: var(--ds-table-cell);\n max-width: var(--ds-table-cell);\n height: var(--ds-table-row);\n padding: 0 var(--ds-table-text);\n border-bottom: 1px solid var(--ds-table-rule);\n border-inline-end: 1px solid var(--ds-table-rule);\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.ds-table[data-sheet] :is(th, td):last-child {\n padding-inline-end: var(--ds-table-text);\n}\n.ds-table[data-sheet] .ds-table__number {\n width: var(--ds-table-index);\n max-width: var(--ds-table-index);\n position: sticky;\n inset-inline-start: 0;\n z-index: 1;\n background: var(--ds-table-paper);\n color: var(--ds-title-color, light-dark(#797979, #9a9a9a));\n text-align: center;\n font-variant-numeric: tabular-nums;\n}\n.ds-table[data-sheet] thead :is(th, td) {\n position: sticky;\n top: 0;\n z-index: 2;\n background: var(--ds-table-paper);\n}\n.ds-table[data-sheet] thead tr + tr :is(th, td) {\n top: var(--ds-table-row);\n}\n.ds-table[data-sheet] thead .ds-table__number {\n z-index: 3;\n}\n.ds-table[data-sheet] .ds-table__letters td {\n color: var(--ds-title-color, light-dark(#797979, #9a9a9a));\n text-align: center;\n}\n.ds-table[data-sheet] tbody td:not([data-numeric]) {\n color: inherit;\n}\n.ds-table[data-sheet] [aria-selected=\"true\"] {\n background: transparent;\n color: inherit;\n box-shadow: inset 0 0 0 2px var(--ds-focus-ring, Highlight);\n}\n.ds-table-scroll:has(> .ds-table[data-sheet]) {\n max-height: var(--ds-table-height, none);\n overflow: auto;\n overscroll-behavior: contain;\n}\n/*\n * Text on the grid, as plain classes on native text.\n *\n * Interface copy on a page without Lit: a label, a message, a title. Each line\n * is one square (`--ds-unit`), so a paragraph of any length stands on whole\n * squares, and a display title takes two. The `ds-text` element draws the same\n * words when they come from a translation key.\n *\n * one.css and controls.css both import this file, so a page that loads either\n * of them, or both, has one definition of these classes.\n *\n * ds-text 14 on a one-square line, the text colour\n * ds-text--small 10\n * ds-text--heading 13, medium\n * ds-text--display 20 on two squares, medium\n * ds-text--strong medium\n * ds-text--muted, --title, --danger tones\n */\n\n.ds-text {\n margin: 0;\n color: var(--ds-text-color);\n font-family: var(--ds-typeface-regular);\n font-feature-settings: var(--ds-font-features);\n font-size: var(--ds-type-size-default);\n font-weight: var(--ds-type-weight-default);\n line-height: var(--ds-unit);\n letter-spacing: var(--ds-type-letterspacing-default);\n}\n\n.ds-text--small {\n font-size: var(--ds-type-size-small);\n}\n\n.ds-text--heading {\n font-family: var(--ds-typeface-medium);\n font-size: var(--ds-type-size-heading);\n font-weight: var(--ds-type-weight-bold);\n}\n\n.ds-text--display {\n font-family: var(--ds-typeface-medium);\n font-size: var(--ds-type-size-display);\n font-weight: var(--ds-type-weight-bold);\n line-height: calc(2 * var(--ds-unit));\n letter-spacing: calc(var(--ds-display-text-tracking, -0.4px) * var(--ds-sf, 1));\n}\n\n.ds-text--strong {\n font-family: var(--ds-typeface-medium);\n font-weight: var(--ds-type-weight-bold);\n}\n\n.ds-text--muted {\n color: var(--ds-text-color-muted);\n}\n\n.ds-text--title {\n color: var(--ds-title-color);\n}\n\n.ds-text--danger {\n color: var(--ds-danger-color);\n}\n\n.ds-text--warning {\n color: var(--ds-warning-color);\n}\n/*\n * An empty state, as plain classes on native elements.\n *\n * It says that a place has nothing in it yet and what to do about it: a title,\n * a line of text and, when there is one, the action that fills it. The words\n * sit on the paper with no box, no illustration and no colour; every line is\n * one square, so the whole stands on whole squares. The `ds-empty` element\n * draws the same parts from a translation key, with the shared words' \"Nothing\n * here yet\" as its title when none is given.\n *\n * ds-empty the block, at most sixteen squares wide\n * ds-empty__icon an icon from the library, on its own square, muted\n * ds-empty__title one line in the medium face\n * ds-empty__text lines of one square, muted\n * ds-empty__actions buttons or links on one row, one square below\n * ds-empty--centered centred in the space it stands in\n * ds-empty--done all done: the check on a mark in the success\n * green, the title in that green\n *\n * Tokens: `--ds-empty-measure` (the widest it grows, sixteen squares) and\n * `--ds-empty-padding` (the room above and below, none by default).\n */\n\n.ds-empty {\n box-sizing: border-box;\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n width: 100%;\n max-width: var(--ds-empty-measure, calc(16 * var(--ds-unit)));\n margin: 0;\n padding-block: var(--ds-empty-padding, 0);\n color: var(--ds-text-color);\n font-family: var(--ds-typeface-regular);\n font-feature-settings: var(--ds-font-features);\n font-size: var(--ds-type-size-default);\n font-weight: var(--ds-type-weight-default);\n line-height: var(--ds-unit);\n letter-spacing: var(--ds-type-letterspacing-default);\n text-transform: none;\n}\n\n.ds-empty__icon {\n display: flex;\n align-items: center;\n height: var(--ds-unit);\n color: var(--ds-text-color-muted);\n}\n\n.ds-empty__title,\n.ds-empty__text {\n margin: 0;\n font: inherit;\n letter-spacing: inherit;\n}\n\n.ds-empty__title {\n font-family: var(--ds-typeface-medium);\n font-weight: var(--ds-type-weight-bold);\n}\n\n.ds-empty__text {\n color: var(--ds-text-color-muted);\n}\n\n.ds-empty__actions {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 0 calc(var(--ds-unit) / 2);\n min-height: var(--ds-row-height);\n margin-top: var(--ds-unit);\n}\n\n.ds-empty--centered {\n align-items: center;\n margin-inline: auto;\n text-align: center;\n}\n\n.ds-empty--centered .ds-empty__actions {\n justify-content: center;\n}\n\n/* Done: a place empty because everything in it is finished (every receipt\n found, nothing left to review). The icon, the check by default, stands on a\n round mark one control high in the success green, on the sixteen, and the\n title takes the same green; the line under it stays muted. */\n.ds-empty--done .ds-empty__icon {\n box-sizing: border-box;\n justify-content: center;\n width: var(--ds-control-height);\n height: var(--ds-control-height);\n margin-top: calc(var(--ds-unit) - var(--ds-control-height));\n border-radius: 50%;\n background: var(--ds-success-color);\n color: light-dark(var(--ds-white), var(--ds-black));\n --ds-icon-color: currentColor;\n}\n\n.ds-empty--done .ds-empty__title {\n color: var(--ds-success-color);\n}\n/*\n * An inline notice, as plain classes on native elements.\n *\n * A notice stands in the flow of the page, where its words apply: a failure\n * beside the form that failed, a warning above the list it is about. It is not\n * positioned and takes no box or shadow. A square mark, one control high and\n * filled in the tone's colour, carries the tone; the words sit on the paper\n * beside it, each line one square, with the actions on the row below and the\n * dismiss button at the end of the first line. Danger turns the words into\n * the danger colour. The `ds-notice` element draws the same parts.\n *\n * ds-notice the block: mark, words, dismiss\n * ds-notice__mark the square mark; holds an icon in its ink\n * ds-notice__title one line in the medium face\n * ds-notice__text lines of one square\n * ds-notice__actions buttons or links on one row\n * ds-notice__dismiss an icon button at the end of the first line\n * ds-notice--success, --warning, --danger tones; neutral without one\n * ds-notice--banner a strip across the top of its positioning\n * context instead: one square high, filled in\n * the tone's colour, everything on one line\n * ds-notice--app a row at the top of the page leading to the\n * site's iPhone app: its picture\n * (ds-notice__picture, two squares), its name\n * and one line about it, Open\n * (a.ds-notice__open) and the close; three\n * squares high with a hairline at its foot.\n * startAppBanners() from 0-face/app-banner.ts\n * shows it only where it belongs\n *\n * Give the block role=\"status\", or role=\"alert\" for danger, so assistive\n * technology reads it when it appears.\n *\n * Tokens: `--ds-notice-mark`, `--ds-notice-mark-ink` and `--ds-notice-ink`,\n * which the tones set.\n */\n\n.ds-notice {\n --ds-notice-mark: var(--ds-fill);\n --ds-notice-mark-ink: var(--ds-text-color);\n --ds-notice-ink: var(--ds-text-color);\n box-sizing: border-box;\n display: grid;\n grid-template-columns: var(--ds-unit) minmax(0, 1fr) auto;\n align-items: start;\n margin: 0;\n color: var(--ds-notice-ink);\n font-family: var(--ds-typeface-regular);\n font-feature-settings: var(--ds-font-features);\n font-size: var(--ds-type-size-default);\n font-weight: var(--ds-type-weight-default);\n line-height: var(--ds-unit);\n letter-spacing: var(--ds-type-letterspacing-default);\n text-transform: none;\n}\n\n.ds-notice--success {\n --ds-notice-mark: var(--ds-apple-green);\n --ds-notice-mark-ink: var(--ds-black);\n}\n\n.ds-notice--warning {\n --ds-notice-mark: var(--ds-orange);\n --ds-notice-mark-ink: var(--ds-black);\n}\n\n.ds-notice--danger {\n --ds-notice-mark: var(--ds-danger-color);\n --ds-notice-mark-ink: light-dark(var(--ds-white), var(--ds-black));\n --ds-notice-ink: var(--ds-danger-color);\n}\n\n/* The mark stands on the first line, one control high in a one-square cell. */\n.ds-notice__mark {\n box-sizing: border-box;\n grid-column: 1;\n grid-row: 1;\n display: flex;\n align-items: center;\n justify-content: center;\n width: var(--ds-control-height);\n height: var(--ds-control-height);\n margin-block: calc((var(--ds-unit) - var(--ds-control-height)) / 2);\n overflow: hidden;\n background: var(--ds-notice-mark);\n color: var(--ds-notice-mark-ink);\n --ds-icon-color: var(--ds-notice-mark-ink);\n}\n\n.ds-notice__title,\n.ds-notice__text,\n.ds-notice__actions {\n grid-column: 2;\n min-width: 0;\n margin: 0;\n}\n\n.ds-notice__title,\n.ds-notice__text {\n font: inherit;\n letter-spacing: inherit;\n overflow-wrap: anywhere;\n}\n\n.ds-notice__title {\n font-family: var(--ds-typeface-medium);\n font-weight: var(--ds-type-weight-bold);\n}\n\n.ds-notice__actions {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 0 calc(var(--ds-unit) / 2);\n min-height: var(--ds-row-height);\n}\n\n/* The dismiss button closes the first line: a one-square cell at the end.\n Two classes, so the button's own reset of its margin does not undo it. */\n.ds-notice .ds-notice__dismiss {\n grid-column: 3;\n grid-row: 1;\n margin-block: calc((var(--ds-unit) - var(--ds-control-height)) / 2);\n margin-inline-start: calc(var(--ds-unit) - var(--ds-control-height));\n}\n\n/* A banner: the same parts on one line, one square high, across the top of\n the nearest positioned ancestor (or the page), on a fill of the tone's\n colour. It takes no room in the flow; leave a square for it where words\n stand under it. The actions stand at the end of the line, half a square\n apart; danger words keep the text colour on the danger fill. */\n.ds-notice--banner {\n position: absolute;\n top: 0;\n inset-inline: 0;\n z-index: 9999;\n display: flex;\n align-items: center;\n gap: calc(var(--ds-unit) / 2);\n height: var(--ds-unit);\n padding-inline: var(--ds-unit);\n background: color-mix(in srgb, var(--ds-notice-mark) 40%, transparent);\n --ds-notice-ink: var(--ds-text-color);\n}\n\n.ds-notice--banner .ds-notice__mark {\n flex: none;\n margin-block: 0;\n}\n\n.ds-notice--banner .ds-notice__title,\n.ds-notice--banner .ds-notice__text {\n min-width: 0;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.ds-notice--banner .ds-notice__text {\n flex: 1;\n}\n\n.ds-notice--banner .ds-notice__actions {\n flex: none;\n min-height: 0;\n}\n\n.ds-notice--banner .ds-notice__dismiss {\n margin-block: 0;\n margin-inline-start: 0;\n}\n\n/* The app banner: a row at the top of the page, in the flow, three squares\n high: half a square above and below two squares of content, a hairline at\n its foot. The app's picture fills two squares with a picture's corners; the\n name and the line about it take a square each, on the sixteen; Open and the\n close stand on the sixteen of the square in the middle of the two. */\n.ds-notice--app {\n grid-template-columns: calc(2 * var(--ds-unit)) minmax(0, 1fr) auto var(--ds-unit);\n grid-template-rows: var(--ds-unit) var(--ds-unit);\n column-gap: calc(var(--ds-unit) / 2);\n align-items: end;\n padding: calc(var(--ds-unit) / 2) var(--ds-unit);\n background: var(--ds-paper);\n box-shadow: inset 0 -1px 0 var(--ds-border-color);\n line-height: var(--ds-type-lineheight-default);\n}\n\n.ds-notice--app[hidden] {\n display: none;\n}\n\n.ds-notice__picture {\n box-sizing: border-box;\n grid-column: 1;\n grid-row: 1 / 3;\n align-self: stretch;\n overflow: hidden;\n border-radius: var(--ds-radius);\n background: var(--ds-fill);\n outline: 1px solid var(--ds-border-color);\n outline-offset: -1px;\n}\n\n.ds-notice__picture img {\n display: block;\n width: 100%;\n height: 100%;\n object-fit: cover;\n}\n\n.ds-notice--app .ds-notice__title,\n.ds-notice--app .ds-notice__text {\n grid-column: 2;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.ds-notice--app .ds-notice__title { grid-row: 1; }\n\n.ds-notice--app .ds-notice__text {\n grid-row: 2;\n color: var(--ds-text-color-muted);\n}\n\n/* Open and the close: their square starts half a square into the two, its\n control on the lower sixteen of it. */\n.ds-notice--app .ds-notice__open,\n.ds-notice--app .ds-notice__dismiss {\n grid-row: 1 / 3;\n align-self: start;\n margin: calc(1.5 * var(--ds-unit) - var(--ds-control-height)) 0 0;\n}\n\n.ds-notice--app .ds-notice__open {\n grid-column: 3;\n text-decoration: none;\n}\n\n.ds-notice--app .ds-notice__dismiss {\n grid-column: 4;\n justify-self: end;\n}\n/*\n * Overlay: everything that stands over the page, one component with a type.\n * A `modal` stands in the centre (controls.css and the element's frame); this\n * sheet draws the others, for the `ds-overlay` element (`type=\"sheet\"`,\n * `\"drawer\"` with `side`, `\"screen\"`, which mark its native dialog\n * `data-ds-type` and `data-ds-edge`) and the native frame\n * (`dialog.ds-overlay.ds-overlay--sheet`, `--drawer` with `--start`,\n * `--screen`); controls.css imports it. A popover is placed by the element.\n *\n * - A sheet is as wide as the screen up to 32 squares and centred beyond\n * that, as high as its content up to two squares below the top, with no\n * line at its foot; its one line, at the top, is drawn inside its first\n * square (`--ds-overlay-line`), so it stands on whole squares. A handle two squares wide stands in the middle of its\n * first square and stays there while the content scrolls.\n * - A drawer is the screen's height and 16 squares wide (`--ds-overlay-width`),\n * leaving at least two squares of the page beside it; its one line is on\n * the side that faces the page. `end` is the right in a left-to-right page.\n * - Each keeps the square of padding inside the screen's safe area\n * (`env(safe-area-inset-*)`, with `viewport-fit=cover` on the page).\n * - Each slides in from its edge and back out to it, in transform alone,\n * while the backdrop fades; with reduced motion it fades in place. Dragging\n * it towards its edge (0-face/overlay-swipe.ts) moves it with the finger and\n * fades the backdrop as it goes.\n * - The page behind a modal native sheet or drawer does not scroll.\n */\n\n:is(ds-overlay > dialog[data-ds-edge=\"bottom\"], dialog.ds-overlay.ds-overlay--sheet),\n:is(ds-overlay > dialog[data-ds-edge=\"end\"], dialog.ds-overlay.ds-overlay--drawer:not(.ds-overlay--start)),\n:is(ds-overlay > dialog[data-ds-edge=\"start\"], dialog.ds-overlay.ds-overlay--drawer.ds-overlay--start) {\n --ds-overlay-gap: var(--ds-unit);\n --ds-overlay-inner: var(--ds-overlay-padding, var(--ds-unit));\n /* The line it faces the page with is drawn inside its first square. */\n --ds-overlay-within: max(0px, var(--ds-overlay-inner) - var(--ds-overlay-line, 1px));\n --ds-overlay-motion: var(--ds-overlay-enter, 380ms);\n --ds-overlay-curve: var(--ds-overlay-easing, cubic-bezier(0.32, 0.72, 0, 1));\n margin: 0;\n gap: var(--ds-overlay-gap);\n transform: var(--ds-overlay-held);\n transition:\n transform var(--ds-overlay-motion) var(--ds-overlay-curve),\n opacity var(--ds-overlay-motion) var(--ds-overlay-curve),\n overlay var(--ds-overlay-motion) allow-discrete,\n display var(--ds-overlay-motion) allow-discrete;\n}\n\n/* Content that supplies its own room. */\n:is(ds-overlay > dialog[data-ds-edge], dialog.ds-overlay:is(.ds-overlay--sheet, .ds-overlay--drawer))[data-ds-overlay-flush] {\n --ds-overlay-inner: 0px;\n --ds-overlay-gap: 0px;\n}\n\n:is(ds-overlay > dialog[data-ds-edge=\"bottom\"], dialog.ds-overlay.ds-overlay--sheet) {\n --ds-overlay-held: translateY(var(--ds-overlay-drag, 0px));\n --ds-overlay-away: translateY(100%);\n inset: auto 0 0;\n width: var(--ds-overlay-width, 100%);\n max-width: min(100%, var(--ds-overlay-sheet-width, calc(32 * var(--ds-unit))));\n height: var(--ds-overlay-height, fit-content);\n max-height: calc(100dvh - var(--ds-overlay-sheet-gap, calc(2 * var(--ds-unit))) - env(safe-area-inset-top, 0px));\n margin: 0 auto;\n padding:\n var(--ds-overlay-within)\n calc(var(--ds-overlay-inner) + env(safe-area-inset-right, 0px))\n calc(var(--ds-overlay-inner) + env(safe-area-inset-bottom, 0px))\n calc(var(--ds-overlay-inner) + env(safe-area-inset-left, 0px));\n border-bottom: 0;\n}\n\n/* The handle: two squares wide, in the middle of the first square, above the\n * content as it scrolls. It takes no room: the content starts where it would. */\n:is(ds-overlay > dialog[data-ds-edge=\"bottom\"], dialog.ds-overlay.ds-overlay--sheet)::before {\n --ds-overlay-handle-height: calc(4px * var(--ds-sf, 1));\n content: \"\";\n display: var(--ds-overlay-handle, block);\n position: sticky;\n z-index: 1;\n /* A sticky offset counts from the content edge, under the sheet's top padding: take that\n padding off, so the handle is held where it already stands, in the first square. */\n top: calc((var(--ds-unit) - var(--ds-overlay-handle-height)) / 2 - var(--ds-overlay-line, 1px) - var(--ds-overlay-within));\n flex: 0 0 auto;\n align-self: center;\n width: calc(2 * var(--ds-unit));\n height: var(--ds-overlay-handle-height);\n margin-top: calc(var(--ds-overlay-inner) * -1 + (var(--ds-unit) - var(--ds-overlay-handle-height)) / 2);\n margin-bottom: calc(var(--ds-overlay-inner) - var(--ds-overlay-gap) - var(--ds-overlay-handle-height) - (var(--ds-unit) - var(--ds-overlay-handle-height)) / 2);\n border-radius: calc(var(--ds-overlay-handle-height) / 2);\n background: var(--ds-overlay-handle-color, var(--ds-border-color));\n pointer-events: none;\n}\n\n:is(ds-overlay > dialog[data-ds-edge=\"end\"], dialog.ds-overlay.ds-overlay--drawer:not(.ds-overlay--start)),\n:is(ds-overlay > dialog[data-ds-edge=\"start\"], dialog.ds-overlay.ds-overlay--drawer.ds-overlay--start) {\n --ds-overlay-held: translateX(var(--ds-overlay-drag, 0px));\n width: calc(var(--ds-overlay-width, calc(16 * var(--ds-unit))) + var(--ds-overlay-safe-side, 0px));\n max-width: calc(100vw - 2 * var(--ds-unit));\n height: 100dvh;\n max-height: none;\n border-top: 0;\n border-bottom: 0;\n}\n\n/* At the right: the end of a left-to-right page, the start of a right-to-left one. */\n:is(ds-overlay > dialog[data-ds-edge=\"end\"], dialog.ds-overlay.ds-overlay--drawer:not(.ds-overlay--start)):not(:dir(rtl)),\n:is(ds-overlay > dialog[data-ds-edge=\"start\"], dialog.ds-overlay.ds-overlay--drawer.ds-overlay--start):dir(rtl) {\n --ds-overlay-away: translateX(100%);\n --ds-overlay-safe-side: env(safe-area-inset-right, 0px);\n inset: 0 0 0 auto;\n padding:\n calc(var(--ds-overlay-inner) + env(safe-area-inset-top, 0px))\n calc(var(--ds-overlay-inner) + env(safe-area-inset-right, 0px))\n calc(var(--ds-overlay-inner) + env(safe-area-inset-bottom, 0px))\n var(--ds-overlay-within);\n border-right: 0;\n}\n\n:is(ds-overlay > dialog[data-ds-edge=\"start\"], dialog.ds-overlay.ds-overlay--drawer.ds-overlay--start):not(:dir(rtl)),\n:is(ds-overlay > dialog[data-ds-edge=\"end\"], dialog.ds-overlay.ds-overlay--drawer:not(.ds-overlay--start)):dir(rtl) {\n --ds-overlay-away: translateX(-100%);\n --ds-overlay-safe-side: env(safe-area-inset-left, 0px);\n inset: 0 auto 0 0;\n padding:\n calc(var(--ds-overlay-inner) + env(safe-area-inset-top, 0px))\n var(--ds-overlay-within)\n calc(var(--ds-overlay-inner) + env(safe-area-inset-bottom, 0px))\n calc(var(--ds-overlay-inner) + env(safe-area-inset-left, 0px));\n border-left: 0;\n}\n\n/* The page behind a native sheet or drawer holds still while it is open, as\n * the element holds it (the element saves and restores the scroll itself). */\n:root:has(dialog.ds-overlay:is(.ds-overlay--sheet, .ds-overlay--drawer):modal) {\n overflow: hidden;\n overscroll-behavior: none;\n}\n\n/* Out to its edge, a little quicker than it came; and in from it. */\n:is(ds-overlay > dialog[data-ds-edge], dialog.ds-overlay:is(.ds-overlay--sheet, .ds-overlay--drawer)):not([open]) {\n --ds-overlay-motion: var(--ds-overlay-exit, 260ms);\n transform: var(--ds-overlay-away);\n}\n\n@starting-style {\n :is(ds-overlay > dialog[data-ds-edge], dialog.ds-overlay:is(.ds-overlay--sheet, .ds-overlay--drawer))[open] {\n transform: var(--ds-overlay-away);\n }\n}\n\n:is(ds-overlay > dialog[data-ds-edge], dialog.ds-overlay:is(.ds-overlay--sheet, .ds-overlay--drawer))::backdrop {\n opacity: calc(1 - var(--ds-overlay-progress, 0));\n transition:\n opacity var(--ds-overlay-motion, 380ms) ease,\n overlay var(--ds-overlay-motion, 380ms) allow-discrete,\n display var(--ds-overlay-motion, 380ms) allow-discrete;\n}\n\n:is(ds-overlay > dialog[data-ds-edge], dialog.ds-overlay:is(.ds-overlay--sheet, .ds-overlay--drawer)):not([open])::backdrop {\n opacity: 0;\n}\n\n@starting-style {\n :is(ds-overlay > dialog[data-ds-edge], dialog.ds-overlay:is(.ds-overlay--sheet, .ds-overlay--drawer))[open]::backdrop {\n opacity: 0;\n }\n}\n\n/* While a finger holds it, it follows the finger alone. */\n:is(ds-overlay > dialog[data-ds-edge], dialog.ds-overlay:is(.ds-overlay--sheet, .ds-overlay--drawer))[data-ds-overlay-dragging],\n:is(ds-overlay > dialog[data-ds-edge], dialog.ds-overlay:is(.ds-overlay--sheet, .ds-overlay--drawer))[data-ds-overlay-dragging]::backdrop {\n transition: none;\n}\n\n/* Reduced motion: no slide. It fades where it stands, a dragged one too. */\n@media (prefers-reduced-motion: reduce) {\n :is(ds-overlay > dialog[data-ds-edge], dialog.ds-overlay:is(.ds-overlay--sheet, .ds-overlay--drawer)) {\n --ds-overlay-motion: 150ms;\n transition:\n opacity var(--ds-overlay-motion) ease,\n overlay var(--ds-overlay-motion) allow-discrete,\n display var(--ds-overlay-motion) allow-discrete;\n }\n\n :is(ds-overlay > dialog[data-ds-edge], dialog.ds-overlay:is(.ds-overlay--sheet, .ds-overlay--drawer)):not([open]) {\n --ds-overlay-motion: 150ms;\n transform: var(--ds-overlay-held);\n opacity: 0;\n }\n\n @starting-style {\n :is(ds-overlay > dialog[data-ds-edge], dialog.ds-overlay:is(.ds-overlay--sheet, .ds-overlay--drawer))[open] {\n transform: var(--ds-overlay-held);\n opacity: 0;\n }\n }\n}\n\n/*\n * The screen: an overlay over the whole screen, for navigation folded away on\n * a narrow screen (`ds-header`, `ds-page drawer`, `attachOverlay()`).\n *\n * The panel is the dialog frame (`dialog.ds-overlay`) laid over the whole\n * screen, on the page's own paper, a square of room on every side. Its first\n * row holds the close button where the menu button stood; what the page\n * folded away (its navigation and actions) follows, every link one square\n * high. The page script `0-face/attach-overlay.ts` opens it: it moves the folded parts\n * into the panel and back, keeps focus inside, closes on Escape, on a link and\n * when the screen widens, and holds the page's scroll while it is open.\n * `ds-header` and `ds-page drawer` use the same script and these rules.\n *\n * ds-overlay--screen on a <dialog class=\"ds-overlay\">, the panel\n * ds-overlay__bar the first row: the close button at its end\n * ds-overlay__close the close button, an icon button\n * ds-overlay__toggle the button that opens it: it carries\n * two icons, the first shown while closed and the\n * second (close) while open\n *\n * Tokens: `--ds-overlay-paper` (the page's paper by default).\n */\n\n:is(ds-overlay > dialog[data-ds-type=\"screen\"], dialog.ds-overlay.ds-overlay--screen) {\n --ds-overlay-width: 100vw;\n width: 100vw;\n max-width: none;\n height: 100dvh;\n max-height: none;\n margin: 0;\n padding: var(--ds-unit);\n gap: 0;\n border: 0;\n background: var(--ds-overlay-paper, var(--background, Canvas));\n overflow-y: auto;\n}\n\n:is(ds-overlay > dialog[data-ds-type=\"screen\"], dialog.ds-overlay.ds-overlay--screen)[open] {\n display: flex;\n flex-direction: column;\n align-items: stretch;\n gap: var(--ds-unit);\n}\n\n/* Content that supplies its own room, as the documentation's navigation does. */\n:is(ds-overlay > dialog[data-ds-type=\"screen\"], dialog.ds-overlay.ds-overlay--screen)[data-ds-overlay-flush] {\n padding: 0;\n gap: 0;\n}\n\n:is(ds-overlay > dialog[data-ds-type=\"screen\"], dialog.ds-overlay.ds-overlay--screen)::backdrop {\n background: transparent;\n}\n\n/* It arrives by fading in and settling half a square, and leaves at once. */\n@media (prefers-reduced-motion: no-preference) {\n :is(ds-overlay > dialog[data-ds-type=\"screen\"], dialog.ds-overlay.ds-overlay--screen)[open] {\n transition: opacity 160ms ease-out, transform 160ms ease-out;\n }\n\n @starting-style {\n :is(ds-overlay > dialog[data-ds-type=\"screen\"], dialog.ds-overlay.ds-overlay--screen)[open] {\n opacity: 0;\n transform: translateY(calc(var(--ds-unit) / -2));\n }\n }\n}\n\n.ds-overlay__bar {\n display: flex;\n align-items: center;\n justify-content: flex-end;\n min-height: var(--ds-row-height);\n}\n\n/* Centred in the last square of the row, as the menu button is. Two classes,\n so the button's own margin does not undo it. */\n.ds-overlay__bar > .ds-overlay__close {\n margin-inline-end: calc((var(--ds-unit) - var(--ds-control-height)) / 2);\n}\n\n/* The toggle shows its first icon while closed and its second while open; the\n close button, a copy of it, shows the second. */\n.ds-overlay__toggle:not([aria-expanded=\"true\"]) > :nth-child(2),\n.ds-overlay__toggle[aria-expanded=\"true\"] > :first-child:not(:only-child),\n.ds-overlay__close > :first-child:not(:only-child) {\n display: none;\n}\n/*\n * A site header, as plain classes on native elements.\n *\n * One row of one square, a square of room around it: the brand at the start\n * in twelve squares (as a page's navigation column is, so the links stand\n * over the work), the navigation two squares after it, the actions at the end. Every link is\n * one square high, a square apart, in the text's ink; the page you are on\n * (`aria-current=\"page\"`) stands on a hairline of the full ink, the others\n * show a faint one under the pointer. Below thirty squares of width the\n * navigation and the actions fold into a drawer: the menu button takes their\n * place at the end of the row, and `0-face/header.ts` opens them over the page.\n * The `ds-header` element draws the same parts.\n *\n * ds-header the row, a <header>\n * ds-header__brand the mark or name, a link home; a picture in it is one square high\n * ds-header__nav the links, a <nav>\n * ds-header__actions buttons or links at the end\n * ds-header__toggle the menu button: `.ds-button.ds-button--icon.ds-overlay__toggle`\n * with a menu icon and a close icon, shown only on a narrow screen\n * ds-header--sticky stays at the top of the page as it scrolls, on the paper\n *\n * Tokens: `--ds-header-brand` (the brand's width, at least twelve squares),\n * `--ds-header-paper` (the sticky header's paper) and `--ds-header-line` (the\n * hairline under a sticky header, none by default).\n */\n\n.ds-header {\n box-sizing: border-box;\n container-type: inline-size;\n display: flex;\n align-items: center;\n gap: calc(2 * var(--ds-unit));\n min-width: 0;\n margin: 0;\n padding: var(--ds-unit);\n color: var(--ds-text-color);\n font-family: var(--ds-typeface-regular);\n font-feature-settings: var(--ds-font-features);\n font-size: var(--ds-type-size-default);\n font-weight: var(--ds-type-weight-default);\n line-height: var(--ds-unit);\n letter-spacing: var(--ds-type-letterspacing-default);\n text-transform: none;\n}\n\n.ds-header--sticky {\n position: sticky;\n top: 0;\n z-index: 1;\n background: var(--ds-header-paper, var(--background, Canvas));\n box-shadow: inset 0 -1px var(--ds-header-line, transparent);\n}\n\n.ds-header__brand {\n box-sizing: border-box;\n display: inline-flex;\n flex: 0 0 auto;\n min-width: var(--ds-header-brand, calc(12 * var(--ds-unit)));\n align-items: center;\n gap: calc(var(--ds-unit) / 2);\n height: var(--ds-unit);\n color: inherit;\n font-family: var(--ds-typeface-medium);\n font-weight: var(--ds-type-weight-bold);\n text-decoration: none;\n white-space: nowrap;\n}\n\n.ds-header__brand :is(img, svg) {\n display: block;\n width: auto;\n height: var(--ds-unit);\n}\n\n.ds-header__nav,\n.ds-header__actions {\n display: flex;\n align-items: center;\n gap: var(--ds-unit);\n min-width: 0;\n margin: 0;\n padding: 0;\n}\n\n.ds-header__nav {\n flex: 1 1 auto;\n flex-wrap: wrap;\n row-gap: 0;\n}\n\n.ds-header__actions {\n flex: 0 0 auto;\n justify-content: flex-end;\n gap: calc(var(--ds-unit) / 2);\n margin-inline-start: auto;\n}\n\n/* A link in the navigation: the text's ink on a one-square line. */\n.ds-header__nav a {\n display: block;\n height: var(--ds-unit);\n color: inherit;\n text-decoration-line: underline;\n text-decoration-thickness: 1px;\n text-decoration-color: transparent;\n text-underline-offset: calc(2px * var(--ds-sf));\n white-space: nowrap;\n}\n\n.ds-header__nav a:hover {\n text-decoration-color: color-mix(in srgb, currentColor 40%, transparent);\n}\n\n.ds-header__nav a[aria-current]:not([aria-current=\"false\"]) {\n text-decoration-color: currentColor;\n}\n\n.ds-header__nav a:focus-visible,\n.ds-header__brand:focus-visible {\n outline: 2px solid var(--ds-focus-ring);\n outline-offset: 1px;\n}\n\n/* The menu button stands at the end of the row, and only on a narrow screen.\n Two classes, so the button's own display and margin do not undo it. */\n.ds-header > .ds-header__toggle {\n display: none;\n margin-inline-start: auto;\n /* Centred in the last square of the row, where the close button stands too. */\n margin-inline-end: calc((var(--ds-unit) - var(--ds-control-height)) / 2);\n}\n\n@container (max-width: 599px) {\n .ds-header > :is(.ds-header__nav, .ds-header__actions) {\n display: none;\n }\n\n .ds-header > .ds-header__toggle {\n display: inline-flex;\n }\n\n .ds-header > .ds-header__brand {\n min-width: 0;\n }\n}\n\n/* In the drawer the navigation is a column of one-square links, and the\n actions a row one square below it. */\n.ds-overlay--screen :is(.ds-header__nav, .ds-header__actions) {\n flex: 0 0 auto;\n flex-direction: column;\n align-items: flex-start;\n flex-wrap: nowrap;\n gap: 0;\n margin: 0;\n}\n\n.ds-overlay--screen .ds-header__actions {\n flex-direction: row;\n flex-wrap: wrap;\n gap: calc(var(--ds-unit) / 2);\n}\n/*\n * A site footer, as plain classes on native elements.\n *\n * The brand and its line at the start, twelve squares wide; the columns of\n * links beside it, eight squares each, two squares apart; then, two squares\n * below, the legal line at the start and the preferences (language and theme,\n * as `ds-cycle` or native buttons) at the end. Every line is one square, the\n * column headings in the title grey, the links in the text's ink with a faint\n * hairline under the pointer. A hairline runs along its top. Columns that do\n * not fit beside the brand go below it, and on a narrow screen everything\n * stands in one column. The `ds-footer` element draws the same parts from data.\n *\n * ds-footer the block, a <footer>\n * ds-footer__brand the mark and its line\n * ds-footer__mark the mark or name, a link home; a picture in it is one square high\n * ds-footer__tagline a line about the site, muted\n * ds-footer__columns the columns, a <nav> or <div>\n * ds-footer__column one column: a heading and its links\n * ds-footer__heading the column's heading, one line in the title grey\n * ds-footer__links the links, a <ul> with one link per <li>\n * ds-footer__base the last row, two squares below\n * ds-footer__legal in it, the copyright and legal line, muted\n * ds-footer__preferences in it, the language and theme controls, at its end\n *\n * Tokens: `--ds-footer-line` (the hairline along the top).\n */\n\n.ds-footer {\n box-sizing: border-box;\n container-type: inline-size;\n display: flex;\n flex-wrap: wrap;\n align-items: flex-start;\n gap: calc(2 * var(--ds-unit));\n min-width: 0;\n margin: 0;\n padding: calc(2 * var(--ds-unit)) var(--ds-unit) var(--ds-unit);\n box-shadow: inset 0 1px var(--ds-footer-line, var(--ds-border-color));\n color: var(--ds-text-color);\n font-family: var(--ds-typeface-regular);\n font-feature-settings: var(--ds-font-features);\n font-size: var(--ds-type-size-default);\n font-weight: var(--ds-type-weight-default);\n line-height: var(--ds-unit);\n letter-spacing: var(--ds-type-letterspacing-default);\n text-transform: none;\n}\n\n.ds-footer :is(p, h2, h3, h4, ul) {\n margin: 0;\n font: inherit;\n letter-spacing: inherit;\n}\n\n.ds-footer__brand {\n display: flex;\n flex: 0 0 calc(12 * var(--ds-unit));\n flex-direction: column;\n max-width: 100%;\n min-width: 0;\n}\n\n.ds-footer__mark {\n display: inline-flex;\n align-items: center;\n gap: calc(var(--ds-unit) / 2);\n align-self: flex-start;\n height: var(--ds-unit);\n color: inherit;\n font-family: var(--ds-typeface-medium);\n font-weight: var(--ds-type-weight-bold);\n text-decoration: none;\n}\n\n.ds-footer__mark :is(img, svg) {\n display: block;\n width: auto;\n height: var(--ds-unit);\n}\n\n.ds-footer__tagline,\n.ds-footer__legal {\n color: var(--ds-text-color-muted);\n}\n\n.ds-footer__columns {\n display: flex;\n /* Never narrower than one column: below that the columns go under the brand. */\n flex: 1 1 calc(8 * var(--ds-unit));\n flex-wrap: wrap;\n gap: var(--ds-unit) calc(2 * var(--ds-unit));\n min-width: min(100%, calc(8 * var(--ds-unit)));\n}\n\n.ds-footer__column {\n display: flex;\n flex: 0 0 calc(8 * var(--ds-unit));\n flex-direction: column;\n max-width: 100%;\n min-width: 0;\n}\n\n.ds-footer .ds-footer__heading {\n color: var(--ds-title-color);\n}\n\n.ds-footer .ds-footer__links {\n padding: 0;\n list-style: none;\n}\n\n.ds-footer__links li {\n margin: 0;\n padding: 0;\n}\n\n.ds-footer__links a {\n display: inline-block;\n max-width: 100%;\n overflow: hidden;\n color: inherit;\n text-decoration-line: underline;\n text-decoration-thickness: 1px;\n text-decoration-color: transparent;\n text-overflow: ellipsis;\n text-underline-offset: calc(2px * var(--ds-sf));\n vertical-align: top;\n white-space: nowrap;\n}\n\n.ds-footer__links a:hover {\n text-decoration-color: color-mix(in srgb, currentColor 40%, transparent);\n}\n\n.ds-footer__links a[aria-current]:not([aria-current=\"false\"]) {\n text-decoration-color: currentColor;\n}\n\n:is(.ds-footer__links a, .ds-footer__mark):focus-visible {\n outline: 2px solid var(--ds-focus-ring);\n outline-offset: 1px;\n}\n\n/* The last row, two squares below: the legal line at the start, the\n preferences at the end; on a narrow screen the preferences go first. */\n.ds-footer__base {\n display: flex;\n flex: 0 0 100%;\n flex-wrap: wrap;\n align-items: flex-start;\n gap: var(--ds-unit) calc(2 * var(--ds-unit));\n min-width: 0;\n}\n\n.ds-footer__legal {\n flex: 1 1 auto;\n min-width: 0;\n}\n\n.ds-footer__preferences {\n display: flex;\n flex: 0 0 auto;\n flex-wrap: wrap;\n align-items: center;\n gap: 0 calc(var(--ds-unit) / 2);\n min-height: var(--ds-unit);\n margin-inline-start: auto;\n}\n\n@container (max-width: 599px) {\n .ds-footer__brand,\n .ds-footer__columns {\n flex-basis: 100%;\n }\n\n .ds-footer__base {\n flex-direction: column;\n }\n\n .ds-footer__preferences {\n order: -1;\n margin-inline-start: 0;\n }\n}\n/*\n * A document page: terms, a privacy policy, a legal notice, a help article.\n *\n * The contents stand at the start, twelve squares wide, and stay in view as\n * the writing scrolls past; the writing, two squares after them, is a reading\n * column of at most thirty-two squares, native headings and paragraphs marked\n * `data-ds-prose` (prose.css draws them). Where the two do not fit side by\n * side the contents stand above the writing. Every line is one square; the\n * contents' links are in the text's ink, the section in view (`aria-current`)\n * on a hairline of the full ink, a third level half a square in. The\n * `ds-document` element builds the contents from the headings and marks the\n * one in view.\n *\n * ds-document the page's two columns\n * ds-document__toc the contents, a <nav>, as tall as the writing\n * ds-document__contents inside it, what stays in view: the title and the list\n * ds-document__toc-title \"Contents\", one line in the title grey\n * ds-document__toc-list the links, an <ol> with one link per <li>\n * ds-document__toc-sub an <li> for a third-level heading\n * ds-document__body the writing, marked data-ds-prose\n *\n * A definition table (`ds-definitions` on a <dl>) sets terms beside what they\n * mean, as a legal notice such as 特定商取引法に基づく表記 does: the term eight\n * squares wide in the muted ink, its definition beside it, each pair on a\n * hairline at its foot with half a square above and below, as a prose table's\n * rows are. Pairs may stand in a <div> each. Below twenty-four squares the\n * definition goes under its term. It works inside or outside prose.\n *\n * Tokens: `--ds-document-top` (where the contents stop below the top of the\n * view, one square; add a sticky header's height), `--ds-definitions-term`\n * (the term column, eight squares).\n */\n\n.ds-document {\n box-sizing: border-box;\n display: flex;\n flex-wrap: wrap;\n align-items: stretch;\n gap: var(--ds-unit) calc(2 * var(--ds-unit));\n min-width: 0;\n color: var(--ds-text-color);\n font-family: var(--ds-typeface-regular);\n font-feature-settings: var(--ds-font-features);\n font-size: var(--ds-type-size-default);\n font-weight: var(--ds-type-weight-default);\n line-height: var(--ds-unit);\n letter-spacing: var(--ds-type-letterspacing-default);\n}\n\n/* The contents column stretches to the writing's height when the two stand\n side by side, so what is inside it can stay in view; standing above the\n writing it is only as tall as itself, and nothing sticks. */\n.ds-document__toc {\n flex: 0 0 calc(12 * var(--ds-unit));\n max-width: 100%;\n min-width: 0;\n}\n\n.ds-document__contents {\n position: sticky;\n top: var(--ds-document-top, var(--ds-unit));\n}\n\n.ds-document__toc-title {\n margin: 0;\n color: var(--ds-title-color);\n font: inherit;\n letter-spacing: inherit;\n}\n\n.ds-document__toc-list,\n.ds-document__toc-list ol {\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.ds-document__toc-list li {\n margin: 0;\n padding: 0;\n}\n\n.ds-document__toc-list .ds-document__toc-sub {\n padding-inline-start: calc(var(--ds-unit) / 2);\n}\n\n.ds-document__toc-list a {\n display: block;\n overflow: hidden;\n color: inherit;\n text-decoration-line: underline;\n text-decoration-thickness: 1px;\n text-decoration-color: transparent;\n text-overflow: ellipsis;\n text-underline-offset: calc(2px * var(--ds-sf));\n white-space: nowrap;\n}\n\n.ds-document__toc-list a:hover {\n text-decoration-color: color-mix(in srgb, currentColor 40%, transparent);\n}\n\n.ds-document__toc-list a[aria-current]:not([aria-current=\"false\"]) {\n text-decoration-color: currentColor;\n}\n\n.ds-document__toc-list a:focus-visible {\n outline: 2px solid var(--ds-focus-ring);\n outline-offset: -1px;\n}\n\n/* The writing: at least twenty squares beside the contents, else below them. */\n.ds-document__body {\n flex: 1 1 0;\n min-width: min(100%, calc(20 * var(--ds-unit)));\n max-width: calc(32 * var(--ds-unit));\n}\n\n/* A heading the contents jump to stops where the contents do. */\n.ds-document__body :is(h1, h2, h3, h4, h5, h6) {\n scroll-margin-top: var(--ds-document-top, var(--ds-unit));\n}\n\n/* A definition table. */\n\n.ds-definitions {\n box-sizing: border-box;\n container-type: inline-size;\n display: grid;\n grid-template-columns: minmax(0, var(--ds-definitions-term, calc(8 * var(--ds-unit)))) minmax(0, 1fr);\n margin: 0;\n padding: 0;\n color: var(--ds-text-color);\n font-family: var(--ds-typeface-regular);\n font-size: var(--ds-type-size-default);\n line-height: var(--ds-unit);\n letter-spacing: var(--ds-type-letterspacing-default);\n}\n\n.ds-definitions > div {\n display: contents;\n}\n\n.ds-definitions :is(dt, dd) {\n box-sizing: border-box;\n min-width: 0;\n margin: 0;\n padding-block: calc(var(--ds-unit) / 2);\n box-shadow: inset 0 -1px var(--ds-border-color);\n font: inherit;\n letter-spacing: inherit;\n line-height: var(--ds-unit);\n overflow-wrap: anywhere;\n}\n\n.ds-definitions dt {\n grid-column: 1;\n padding-inline-end: calc(var(--ds-unit) / 2);\n color: var(--ds-text-color-muted);\n}\n\n.ds-definitions dd {\n grid-column: 2;\n}\n\n@container (max-width: 479px) {\n .ds-definitions dt,\n .ds-definitions dd {\n grid-column: 1 / -1;\n }\n\n .ds-definitions dt {\n padding-block-end: 0;\n padding-inline-end: 0;\n box-shadow: none;\n }\n\n .ds-definitions dd {\n padding-block-start: 0;\n }\n}\n/*\n * A carousel, as plain classes on native elements.\n *\n * A carousel is a row of slides that snaps sideways, one slide to a stop,\n * with a row of controls one square high under it: optional previous and\n * next buttons and a dot for each slide. Slides are the track's width, or\n * whole squares wide, a whole number of squares apart (one by default). The\n * controls stand one square below the track, on the grid from its start.\n * The `ds-carousel` element draws the same parts, and\n * `0-face/carousel.ts` gives the native markup its behaviour.\n *\n * ds-carousel the region: track, controls, status;\n * `data-slides=\"auto\"` for slides of their\n * own width, `data-bleed` `end` or `both`,\n * `data-snap=\"none\"` to slide freely\n * ds-carousel__track the scroller; every child is a slide\n * ds-carousel__controls the row of buttons and dots\n * ds-carousel__previous, __next, icon buttons, on `.ds-button.ds-button--icon`\n * __pause\n * ds-carousel__status the polite announcement, kept out of sight\n *\n * The dots are `ds-progress--dots` from progress.css.\n *\n * A strip of slides of their own width can run on past its box to the\n * window's end edge, or to both edges, while its first slide keeps to the\n * box's start, so it lines up with the page's column; `--ds-carousel-before`\n * and `--ds-carousel-after` are the room to the edges, which the script\n * measures.\n *\n * Tokens: `--ds-carousel-slide` (a slide's width, the track's by default)\n * and `--ds-carousel-gap` (between slides, one square by default).\n */\n\n.ds-carousel {\n box-sizing: border-box;\n display: grid;\n grid-template-columns: minmax(0, 1fr);\n row-gap: var(--ds-unit);\n position: relative;\n min-width: 0;\n margin: 0;\n}\n\n.ds-carousel__track {\n box-sizing: border-box;\n display: grid;\n grid-auto-flow: column;\n grid-auto-columns: var(--ds-carousel-slide, 100%);\n column-gap: var(--ds-carousel-gap, var(--ds-unit));\n min-width: 0;\n margin: 0;\n padding: 0;\n list-style: none;\n overflow-x: auto;\n overflow-y: hidden;\n overscroll-behavior-x: contain;\n scroll-snap-type: x mandatory;\n scrollbar-width: none;\n}\n\n.ds-carousel__track::-webkit-scrollbar {\n display: none;\n}\n\n/* Slides of their own width, several in view. */\n.ds-carousel[data-slides=\"auto\"] > .ds-carousel__track {\n grid-auto-columns: max-content;\n}\n\n.ds-carousel[data-snap=\"none\"] > .ds-carousel__track {\n scroll-snap-type: none;\n}\n\n/* To the window's end edge: the track reaches out over the room after the\n box and keeps a gap at its end, so the last slide stops short of the edge. */\n.ds-carousel[data-bleed=\"end\"] > .ds-carousel__track {\n margin-inline-end: calc(-1 * var(--ds-carousel-after, 0px));\n padding-inline-end: var(--ds-carousel-gap, var(--ds-unit));\n}\n\n/* To both edges: the track reaches out both ways, and the first slide, and\n each one it stops at, still stands on the box's start. */\n.ds-carousel[data-bleed=\"both\"] > .ds-carousel__track {\n margin-inline: calc(-1 * var(--ds-carousel-before, 0px)) calc(-1 * var(--ds-carousel-after, 0px));\n padding-inline: var(--ds-carousel-before, 0px) var(--ds-carousel-gap, var(--ds-unit));\n scroll-padding-inline-start: var(--ds-carousel-before, 0px);\n}\n\n.ds-carousel__track:focus-visible {\n outline: 2px solid var(--ds-focus-ring);\n outline-offset: 1px;\n}\n\n.ds-carousel__track > * {\n box-sizing: border-box;\n min-width: 0;\n margin: 0;\n scroll-snap-align: start;\n}\n\n/* One slide to a stop; a strip of several in view may pass a few. */\n.ds-carousel:not([data-slides=\"auto\"]) > .ds-carousel__track > * {\n scroll-snap-stop: always;\n}\n\n.ds-carousel__controls {\n display: flex;\n align-items: center;\n height: var(--ds-row-height);\n min-width: 0;\n}\n\n/* The buttons take a one-square cell each, as the dots do. Two classes, so\n the button's own reset of its margin does not undo it. */\n.ds-carousel .ds-carousel__previous,\n.ds-carousel .ds-carousel__next,\n.ds-carousel .ds-carousel__pause {\n flex: none;\n margin: calc((var(--ds-unit) - var(--ds-control-height)) / 2);\n}\n\n/* Previous points back along the reading direction. */\n.ds-carousel:dir(rtl) :is(.ds-carousel__previous, .ds-carousel__next) > * {\n transform: scaleX(-1);\n}\n\n.ds-carousel__status {\n position: absolute;\n width: 1px;\n height: 1px;\n overflow: hidden;\n clip-path: inset(50%);\n white-space: nowrap;\n}\n/*\n * A card, as plain classes on native elements.\n *\n * A card holds one thing on a fill of its own: its name in the muted ink on\n * one square, a title in the display size on lines of a square and a half, writing,\n * and a picture of it (`ds-card__media`) a square below, which can run off\n * the card's foot and end edge and be cut there, never framed. Its size is\n * given in whole squares, its padding one square, its corners a card's\n * (`--ds-radius-card`). A card that opens something is one press target, an\n * `<a class=\"ds-card\" href>`: the pointer tints it, keyboard focus rings it\n * 2px inside and its picture rises a little. Ordinary writing still sits\n * straight on the paper; a card is for a thing shown among others, as in a\n * slide. The `ds-card` element draws the same parts.\n *\n * ds-card the card; `data-tone` names a palette colour\n * for its fill (the colour's pastel, dim in dark\n * mode, from palette.css, which one.css imports),\n * `ink` for the ink with the paper's words\n * ds-card--outlined a 1px line and no fill\n * ds-card__label its name, muted, on one square\n * ds-card__title the title, display size, a square and a half a line\n * ds-card__body writing, one square a line\n * ds-card__media the picture, a square below the words\n * ds-card__media--center standing in the card's middle\n * ds-card__media--bleed running on past the padding to the end edge\n *\n * Tokens: `--ds-card-width` and `--ds-card-height` (whole squares; the\n * content's size by default), `--ds-card-padding` (one square), and\n * `--ds-card-fill`, `--ds-card-ink` and `--ds-card-muted`.\n */\n\n.ds-card {\n --ds-card-fill: var(--ds-fill);\n --ds-card-ink: var(--ds-text-color);\n --ds-card-muted: var(--ds-text-color-muted);\n --ds-card-padding: var(--ds-unit);\n position: relative;\n box-sizing: border-box;\n display: flex;\n flex-direction: column;\n align-items: stretch;\n width: var(--ds-card-width, auto);\n height: var(--ds-card-height, auto);\n min-width: 0;\n margin: 0;\n padding: var(--ds-card-padding) var(--ds-card-padding) 0;\n overflow: hidden;\n border-radius: var(--ds-radius-card);\n background: var(--ds-card-fill);\n color: var(--ds-card-ink);\n font-family: var(--ds-typeface-regular);\n font-size: var(--ds-type-size-default);\n text-decoration: none;\n -webkit-tap-highlight-color: transparent;\n}\n\n.ds-card[hidden] {\n display: none;\n}\n\n.ds-card--outlined {\n --ds-card-fill: transparent;\n box-shadow: inset 0 0 0 1px var(--ds-border-color);\n}\n\n.ds-card[data-tone=\"apple-green\"] { --ds-card-fill: var(--one-apple-green-pastel); }\n.ds-card[data-tone=\"chartreuse\"] { --ds-card-fill: var(--one-chartreuse-pastel); }\n.ds-card[data-tone=\"every-green\"] { --ds-card-fill: var(--one-every-green-pastel); }\n.ds-card[data-tone=\"yellow\"] { --ds-card-fill: var(--one-yellow-pastel); }\n.ds-card[data-tone=\"orange\"] { --ds-card-fill: var(--one-orange-pastel); }\n.ds-card[data-tone=\"tuned-red\"] { --ds-card-fill: var(--one-tuned-red-pastel); }\n.ds-card[data-tone=\"pink\"] { --ds-card-fill: var(--one-pink-pastel); }\n.ds-card[data-tone=\"sharp-blue\"] { --ds-card-fill: var(--one-sharp-blue-pastel); }\n.ds-card[data-tone=\"winning-blue\"] { --ds-card-fill: var(--one-winning-blue-pastel); }\n.ds-card[data-tone=\"hysteric-blue\"] { --ds-card-fill: var(--one-hysteric-blue-pastel); }\n.ds-card[data-tone=\"purple\"] { --ds-card-fill: var(--one-purple-pastel); }\n.ds-card[data-tone=\"metal-green\"] { --ds-card-fill: var(--one-metal-green-pastel); }\n.ds-card[data-tone=\"drip-yellow\"] { --ds-card-fill: var(--one-drip-yellow-pastel); }\n.ds-card[data-tone=\"sand\"] { --ds-card-fill: var(--one-sand-pastel); }\n.ds-card[data-tone=\"old-gold\"] { --ds-card-fill: var(--one-old-gold-pastel); }\n.ds-card[data-tone=\"red-for-blood\"] { --ds-card-fill: var(--one-red-for-blood-pastel); }\n.ds-card[data-tone=\"dark-red-variant\"] { --ds-card-fill: var(--one-dark-red-variant-pastel); }\n.ds-card[data-tone=\"signal-red\"] { --ds-card-fill: var(--one-signal-red-pastel); }\n.ds-card[data-tone=\"ink\"] {\n --ds-card-fill: var(--ds-black);\n --ds-card-ink: var(--ds-white);\n --ds-card-muted: color-mix(in srgb, var(--ds-white) 60%, transparent);\n box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--ds-white) 8%, transparent);\n}\n\n/* Words: each line on the lower sixteen of its square. They keep their room\n in a card of a set height; only the picture is cut at the foot. */\n.ds-card__label,\n.ds-card__title,\n.ds-card__body {\n flex: none;\n}\n\n.ds-card__label {\n margin: 0;\n padding-top: calc(4px * var(--ds-sf, 1));\n color: var(--ds-card-muted);\n font: inherit;\n line-height: var(--ds-type-lineheight-default, calc(16px * var(--ds-sf, 1)));\n}\n\n.ds-card__title {\n margin: 0;\n color: var(--ds-card-ink);\n font-family: var(--ds-typeface-medium);\n font-size: var(--ds-type-size-display);\n font-weight: var(--ds-type-weight-bold);\n /* A title that wraps keeps its lines together: a square and a half each. */\n line-height: calc(1.5 * var(--ds-unit));\n letter-spacing: calc(var(--ds-display-text-tracking, -0.4px) * var(--ds-sf, 1));\n text-wrap: balance;\n}\n\n.ds-card__body {\n margin: 0;\n line-height: var(--ds-unit);\n}\n\n.ds-card__media {\n display: flex;\n flex: none;\n align-items: flex-start;\n justify-content: flex-start;\n min-width: 0;\n margin-top: var(--ds-unit);\n}\n\n.ds-card__media--center {\n justify-content: center;\n margin-inline: calc(-1 * var(--ds-card-padding));\n}\n\n.ds-card__media--bleed {\n margin-inline-end: calc(-1 * var(--ds-card-padding));\n}\n\n.ds-card__media > * {\n flex: none;\n}\n\n/* A card that opens something. */\na.ds-card,\n.ds-card[data-interactive] {\n cursor: pointer;\n}\n\na.ds-card::after,\n.ds-card[data-interactive]::after {\n content: \"\";\n position: absolute;\n inset: 0;\n border-radius: inherit;\n background: transparent;\n pointer-events: none;\n}\n\na.ds-card:focus-visible,\n.ds-card[data-interactive]:focus-visible {\n outline: 2px solid var(--ds-focus-ring);\n outline-offset: -2px;\n}\n\n@media (hover: hover) {\n a.ds-card:hover::after,\n .ds-card[data-interactive]:hover::after {\n background: color-mix(in srgb, var(--ds-card-ink) 4%, transparent);\n }\n}\n\na.ds-card:active::after,\n.ds-card[data-interactive]:active::after {\n background: color-mix(in srgb, var(--ds-card-ink) 8%, transparent);\n}\n\n@media (hover: hover) and (prefers-reduced-motion: no-preference) {\n a.ds-card > .ds-card__media,\n .ds-card[data-interactive] > .ds-card__media {\n transition: transform 240ms cubic-bezier(0.23, 1, 0.32, 1);\n }\n\n a.ds-card:hover > .ds-card__media,\n .ds-card[data-interactive]:hover > .ds-card__media {\n transform: translateY(calc(-0.25 * var(--ds-unit)));\n }\n}\n/*\n * Figures, as plain classes on native elements: a stat and a group of stats.\n * The `ds-stat` element draws the same parts; controls.css imports this\n * file. A value against its range, steps and page dots are `progress.css`.\n *\n * Everything sits on the paper with no box, every line is one square and\n * widths come in whole squares. Colour is kept for a state: the danger colour\n * for a figure that is over.\n *\n * A stat: a label, a figure and a line for its change or caption.\n *\n * ds-stat the block, as wide as its column\n * ds-stat__label one line, muted; an icon may lead it on its own square\n * ds-stat__icon the square an icon from the library stands on\n * ds-stat__figure the figure in tabular numerals, 20 on two squares\n * ds-stat__digit one digit in a cell of one width, for a face without tabular numerals\n * ds-stat__caption one line, muted, under the figure\n * ds-stat__change the change at the start of the caption, in the text colour;\n * --danger or --warning where the page knows which way is bad\n * ds-stat--danger, --warning the figure in that colour\n * ds-stats a group of stats on whole squares: columns eight\n * squares wide, one square between them and between rows\n *\n * Tokens: `--ds-stat-size` (the figure's type size before the scale, 20px)\n * and `--ds-stat-lines` (the squares its line takes, 2), `--ds-stat-typeface`\n * (the medium face), `--ds-stat-digit` (a digit cell's width, 1ch),\n * `--ds-stat-change-color`, and `--ds-stats-width` (a column's width in\n * squares, 8).\n *\n */\n\n/* ---- Stat ------------------------------------------------------------ */\n\n.ds-stat {\n box-sizing: border-box;\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n min-width: 0;\n margin: 0;\n color: var(--ds-text-color);\n font-family: var(--ds-typeface-regular);\n font-feature-settings: var(--ds-font-features);\n font-size: var(--ds-type-size-default);\n font-weight: var(--ds-type-weight-default);\n line-height: var(--ds-unit);\n letter-spacing: var(--ds-type-letterspacing-default);\n text-transform: none;\n}\n\n.ds-stat__label,\n.ds-stat__figure,\n.ds-stat__caption {\n box-sizing: border-box;\n max-width: 100%;\n margin: 0;\n font: inherit;\n letter-spacing: inherit;\n}\n\n.ds-stat__label,\n.ds-stat__caption {\n display: flex;\n align-items: flex-start;\n min-height: var(--ds-unit);\n color: var(--ds-text-color-muted);\n overflow-wrap: anywhere;\n}\n\n.ds-stat__icon {\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n width: var(--ds-unit);\n height: var(--ds-unit);\n}\n\n.ds-stat__figure {\n display: block;\n overflow: hidden;\n font-family: var(--ds-stat-typeface, var(--ds-typeface-medium));\n font-size: calc(var(--ds-stat-size, var(--ds-display-text-size, 20px)) * var(--ds-sf, 1));\n font-weight: var(--ds-type-weight-bold);\n font-variant-numeric: tabular-nums;\n line-height: calc(var(--ds-stat-lines, 2) * var(--ds-unit));\n min-height: calc(var(--ds-stat-lines, 2) * var(--ds-unit));\n letter-spacing: calc(var(--ds-display-text-tracking, -0.4px) * var(--ds-sf, 1));\n white-space: nowrap;\n text-overflow: ellipsis;\n}\n\n.ds-stat__digit {\n display: inline-block;\n width: var(--ds-stat-digit, 1ch);\n text-align: center;\n}\n\n.ds-stat--danger .ds-stat__figure {\n color: var(--ds-danger-color);\n}\n\n.ds-stat--warning .ds-stat__figure {\n color: var(--ds-warning-color);\n}\n\n.ds-stat__change {\n display: inline-flex;\n flex: none;\n align-items: center;\n height: var(--ds-unit);\n margin-inline-end: calc(4px * var(--ds-sf, 1));\n color: var(--ds-stat-change-color, var(--ds-text-color));\n font-variant-numeric: tabular-nums;\n white-space: nowrap;\n}\n\n.ds-stat__change--danger {\n --ds-stat-change-color: var(--ds-danger-color);\n}\n\n.ds-stat__change--warning {\n --ds-stat-change-color: var(--ds-warning-color);\n}\n\n.ds-stats {\n box-sizing: border-box;\n display: grid;\n grid-template-columns: repeat(auto-fill, min(100%, calc(var(--ds-stats-width, 8) * var(--ds-unit))));\n gap: var(--ds-unit);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.ds-stats > li {\n min-width: 0;\n margin: 0;\n}\n/*\n * Progress, as plain classes on native elements: a value against its range,\n * a sequence of steps, or a dot for each page. The `ds-progress` element\n * draws the same parts; controls.css imports this file.\n *\n * Everything sits on the paper with no box, every line is one square and\n * widths come in whole squares. Colour is kept for a state: the danger colour\n * for a value that is over or a step that failed, the ink for the current\n * step and the current dot.\n *\n * A value against its range, one square high (HTML's <progress>):\n *\n * ds-progress the row; role=\"meter\" with aria-valuenow, -min, -max and -valuetext\n * ds-progress__fill the bar, half a square high, drawn to --ds-progress-value (0 to 1)\n * ds-progress--squares the range in squares instead, each one square\n * ds-progress__square one square of the range; --on when it is filled\n * ds-progress--over past the end: filled whole in the danger colour\n *\n * Tokens: `--ds-progress-value`, `--ds-progress-color` (the ink by default)\n * and `--ds-progress-track` (the grey fill).\n *\n * A sequence of steps, one square high, each step on whole squares:\n *\n * ds-progress--steps with ds-progress, on an <ol>; the steps on one row, joined by a line\n * ds-progress--vertical one step to a row, each with room for its body under it\n * ds-progress__step an <li>; aria-current=\"step\" on the current one\n * ds-progress__step--done, --current, --failed states; upcoming without one\n * ds-progress__link a step that goes somewhere: an <a href> around its mark and label\n * ds-progress__mark the number (or the done or failed icon), one control high\n * ds-progress__label the step's name on one line\n * ds-progress__state the state in words for assistive technology, hidden (\"Done\")\n * ds-progress__body what belongs under a step in a vertical sequence\n *\n * A dot for each page, one square each:\n *\n * ds-progress--dots with ds-progress, a group of dots (role=\"group\")\n * ds-progress__dot a button; `data-state` is `past`, `current` (with\n * `aria-current=\"true\"`), `next`, `future`, or `end` for a\n * last dot marked as an end\n *\n * Tokens: the dot colours `--ds-progress-dot-past` and `-future` (the muted\n * text colour by default), `-current`, `-next` and `-end` (the text colour),\n * set on the dots or any element around them. Past, current and next dots are\n * filled; future dots and the end marker are rings.\n */\n\n/* ---- A value against its range: the bar, or the range in squares ---- */\n\n.ds-progress {\n box-sizing: border-box;\n position: relative;\n display: block;\n width: 100%;\n height: var(--ds-unit);\n margin: 0;\n}\n\n/* The range and its bar are a band half a square high across the middle of\n the row, as a chart's ratio is drawn. */\n.ds-progress:not(.ds-progress--squares, .ds-progress--steps, .ds-progress--dots)::before,\n.ds-progress__fill {\n position: absolute;\n inset-inline: 0;\n top: calc(var(--ds-unit) / 4);\n height: calc(var(--ds-unit) / 2);\n}\n\n.ds-progress:not(.ds-progress--squares, .ds-progress--steps, .ds-progress--dots)::before {\n content: \"\";\n background: var(--ds-progress-track, var(--ds-fill));\n}\n\n.ds-progress__fill {\n display: block;\n background: var(--ds-progress-color, var(--ds-text-color));\n transform: scaleX(var(--ds-progress-value, 0));\n transform-origin: left center;\n transition: transform 0.4s cubic-bezier(0.2, 0.8, 0.2, 1);\n}\n\n.ds-progress__fill:dir(rtl) {\n transform-origin: right center;\n}\n\n.ds-progress--over .ds-progress__fill {\n background: var(--ds-danger-color);\n transform: none;\n}\n\n.ds-progress--squares {\n display: flex;\n width: max-content;\n max-width: 100%;\n overflow: hidden;\n}\n\n.ds-progress__square {\n flex: none;\n width: calc(var(--ds-unit) - 1px);\n height: calc(var(--ds-unit) - 1px);\n margin-inline-end: 1px;\n background: var(--ds-progress-track, var(--ds-fill));\n}\n\n.ds-progress__square--on {\n background: var(--ds-progress-color, var(--ds-text-color));\n}\n\n.ds-progress--over .ds-progress__square {\n background: var(--ds-danger-color);\n}\n\n@media (prefers-reduced-motion: reduce) {\n .ds-progress__fill {\n transition: none;\n }\n}\n\n/* ---- A sequence of steps --------------------------------------------- */\n\n.ds-progress--steps {\n box-sizing: border-box;\n position: static;\n display: flex;\n width: auto;\n height: auto;\n flex-wrap: wrap;\n align-items: flex-start;\n min-width: 0;\n margin: 0;\n padding: 0;\n list-style: none;\n color: var(--ds-text-color);\n font-family: var(--ds-typeface-regular);\n font-feature-settings: var(--ds-font-features);\n font-size: var(--ds-type-size-default);\n font-weight: var(--ds-type-weight-default);\n line-height: var(--ds-unit);\n letter-spacing: var(--ds-type-letterspacing-default);\n text-transform: none;\n}\n\n/* Each step rounds its width up to whole squares where the browser can size\n to content in calc; elsewhere it hugs its words. */\n.ds-progress__step {\n --ds-progress-mark: transparent;\n --ds-progress-mark-ink: var(--ds-text-color-muted);\n --ds-progress-mark-line: var(--ds-border-color);\n box-sizing: border-box;\n position: relative;\n display: flex;\n align-items: flex-start;\n min-width: 0;\n max-width: 100%;\n width: max-content;\n width: calc-size(max-content, round(up, size, var(--ds-unit)));\n min-height: var(--ds-unit);\n margin: 0;\n color: var(--ds-text-color-muted);\n}\n\n/* A line joins a step to the next: at least one square, across whatever the\n step's rounding leaves, a quarter of a square short of each end. */\n.ds-progress__step:not(:last-child)::after {\n content: \"\";\n flex: 1 0 var(--ds-unit);\n height: var(--ds-unit);\n background: linear-gradient(var(--ds-border-color), var(--ds-border-color)) center / calc(100% - var(--ds-unit) / 2) 1px no-repeat;\n}\n\n.ds-progress__step--done {\n --ds-progress-mark: var(--ds-fill);\n --ds-progress-mark-ink: var(--ds-text-color);\n --ds-progress-mark-line: transparent;\n color: var(--ds-text-color);\n}\n\n.ds-progress__step--current {\n --ds-progress-mark: var(--ds-text-color);\n --ds-progress-mark-ink: var(--ds-paper);\n --ds-progress-mark-line: transparent;\n color: var(--ds-text-color);\n}\n\n.ds-progress__step--failed {\n --ds-progress-mark: var(--ds-danger-color);\n --ds-progress-mark-ink: light-dark(var(--ds-white), var(--ds-black));\n --ds-progress-mark-line: transparent;\n color: var(--ds-danger-color);\n}\n\n.ds-progress__link {\n display: flex;\n align-items: flex-start;\n min-width: 0;\n color: inherit;\n text-decoration: none;\n border-radius: var(--ds-radius);\n}\n\n.ds-progress__link:hover .ds-progress__label {\n text-decoration: underline;\n text-decoration-thickness: 1px;\n text-underline-offset: calc(3px * var(--ds-sf, 1));\n}\n\n.ds-progress__link:focus-visible {\n outline: 2px solid var(--ds-focus-ring);\n outline-offset: -2px;\n}\n\n.ds-progress__mark {\n box-sizing: border-box;\n display: flex;\n flex: none;\n align-items: center;\n justify-content: center;\n width: var(--ds-control-height);\n height: var(--ds-control-height);\n margin: calc((var(--ds-unit) - var(--ds-control-height)) / 2);\n overflow: hidden;\n background: var(--ds-progress-mark);\n box-shadow: inset 0 0 0 1px var(--ds-progress-mark-line);\n color: var(--ds-progress-mark-ink);\n --ds-icon-color: var(--ds-progress-mark-ink);\n font-family: var(--ds-typeface-medium);\n font-size: var(--ds-type-size-small);\n font-weight: var(--ds-type-weight-bold);\n font-variant-numeric: tabular-nums;\n line-height: var(--ds-control-height);\n letter-spacing: 0;\n}\n\n.ds-progress__label {\n min-width: 0;\n padding-inline-end: calc(4px * var(--ds-sf, 1));\n overflow: hidden;\n white-space: nowrap;\n text-overflow: ellipsis;\n}\n\n.ds-progress__step--current .ds-progress__label {\n font-family: var(--ds-typeface-medium);\n font-weight: var(--ds-type-weight-bold);\n}\n\n.ds-progress__state {\n position: absolute;\n width: 1px;\n height: 1px;\n overflow: hidden;\n clip-path: inset(50%);\n white-space: nowrap;\n}\n\n.ds-progress--vertical {\n flex-direction: column;\n flex-wrap: nowrap;\n}\n\n.ds-progress--vertical .ds-progress__step {\n flex-wrap: wrap;\n width: 100%;\n}\n\n.ds-progress--vertical .ds-progress__step::after {\n content: none;\n}\n\n/* Its content stands in a column, so an inline element in it (text drawn by\n an element, say) takes its own lines rather than a line box's descent. */\n.ds-progress__body {\n box-sizing: border-box;\n display: flex;\n flex-direction: column;\n flex: 1 0 100%;\n min-width: 0;\n padding-inline-start: var(--ds-unit);\n color: var(--ds-text-color);\n}\n\n/* ---- A dot for each page ------------------------------------------- */\n\n.ds-progress--dots {\n position: static;\n display: inline-flex;\n width: auto;\n flex: none;\n align-items: center;\n height: var(--ds-row-height);\n margin: 0;\n padding: 0;\n}\n\n.ds-progress__dot {\n --ds-progress-dot-color: var(--ds-progress-dot-future, var(--ds-text-color-muted));\n appearance: none;\n box-sizing: border-box;\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n width: var(--ds-unit);\n height: var(--ds-unit);\n margin: 0;\n padding: 0;\n border: 0;\n border-radius: var(--ds-radius);\n background: transparent;\n color: inherit;\n cursor: pointer;\n -webkit-tap-highlight-color: transparent;\n}\n\n/* The dot itself: 4px, scaled with the surface, a fifth of the square. */\n.ds-progress__dot::before {\n content: \"\";\n box-sizing: border-box;\n width: calc(4px * var(--ds-sf, 1));\n height: calc(4px * var(--ds-sf, 1));\n border-radius: 50%;\n background: transparent;\n box-shadow: inset 0 0 0 1px var(--ds-progress-dot-color);\n transition: transform 160ms ease-out;\n}\n\n.ds-progress__dot[data-state=\"past\"] { --ds-progress-dot-color: var(--ds-progress-dot-past, var(--ds-text-color-muted)); }\n.ds-progress__dot[data-state=\"next\"] { --ds-progress-dot-color: var(--ds-progress-dot-next, var(--ds-text-color)); }\n.ds-progress__dot[data-state=\"end\"] { --ds-progress-dot-color: var(--ds-progress-dot-end, var(--ds-text-color)); }\n.ds-progress__dot[aria-current=\"true\"] { --ds-progress-dot-color: var(--ds-progress-dot-current, var(--ds-text-color)); }\n\n.ds-progress__dot:is([data-state=\"past\"], [data-state=\"next\"], [aria-current=\"true\"])::before {\n background: var(--ds-progress-dot-color);\n}\n\n/* The current dot is half again as large. */\n.ds-progress__dot[aria-current=\"true\"]::before {\n transform: scale(1.5);\n}\n\n.ds-progress__dot:hover:not([aria-current=\"true\"])::before {\n transform: scale(1.25);\n}\n\n.ds-progress__dot:focus-visible {\n outline: 2px solid var(--ds-focus-ring);\n outline-offset: -2px;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .ds-progress__dot::before {\n transition: none;\n }\n}\n/*\n * Rows, as plain classes on native elements: the `ds-row` and `ds-sidebar`\n * elements' look without the elements.\n *\n * A row is one square high, and what it holds stands on the lower sixteen of\n * the square with the spare four above, as Ezo sets every row: a line of\n * words on a 16px line box, a 16px icon and a 16px control all end on the\n * row's bottom line, so the capitals (7px below the top line, baseline 3px\n * above the next) are centred on an icon beside them. On an `<a href>` or a\n * `<button>` the whole row is one press target, a row, a tile or a card: the pointer over it, the\n * press and the focus ring cover the row, and its content keeps the row's\n * layout. A row that also holds controls of its own (a quick action, a link\n * in another cell) is any element, a `<li>`, a `<div>` or a `<tr>`, with one\n * `ds-row__target` inside: that link or button takes the press anywhere on\n * the row, and every other control inside stays separately pressable.\n *\n * ds-row a row one square high; a press target on <a> or <button>\n * ds-row__target the row's press target, when the row holds other controls\n * ds-row--auto as high as its content, at least one square\n * ds-row--stacked the content stacked, each line one square (a tile, a card)\n * ds-row--nav a navigation row: the sidebar's two-pixel corners\n * aria-current=\"page\" the destination being shown, filled and in the medium weight\n * aria-disabled=\"true\" or `disabled` on a button: dimmed, not pressable\n *\n * A sidebar of nested things (the `ds-sidebar tree` element without Lit) is a\n * `role=\"tree\"` list of `role=\"treeitem\"` rows, flat, each with its\n * `aria-level`, one square further in per level. `0-face/sidebar.ts`\n * (`connectSidebar`) gives it the keyboard of the tree pattern.\n *\n * ds-sidebar the tree (`role=\"tree\"`)\n * ds-sidebar__item a row (`role=\"treeitem\"`, `aria-level`, `aria-expanded` on a parent, `aria-selected`)\n * ds-sidebar__disclosure the arrow on its own square, turned down when the row is open; empty on a leaf\n * ds-sidebar__label the words, cut short with an ellipsis\n * ds-sidebar__meta small muted words at the row's end\n *\n * An icon (`.ds-icon`) in a tree row takes a square of its own. Tokens:\n * `--ds-row-padding` (the words' distance from the row's edges, 4px),\n * `--ds-row-fill-hover`, `--ds-row-fill-press`, `--ds-row-fill-current` and\n * `--ds-row-current-weight` (component-tokens.css, shared with the\n * element), `--ds-sidebar-disclosure` (the arrow's drawing, the library's\n * `right` icon) and `--ds-sidebar-indent` (a row's depth in squares, read\n * from `aria-level` up to twelve levels).\n */\n\n:where(.ds-row):not(tr) {\n box-sizing: border-box;\n display: flex;\n flex-direction: row;\n align-items: flex-end;\n gap: calc(4px * var(--ds-sf));\n min-width: 0;\n height: var(--ds-row-height);\n margin: 0;\n line-height: var(--ds-type-lineheight-default);\n}\n\n:where(.ds-row--auto):not(tr) {\n height: auto;\n min-height: var(--ds-row-height);\n}\n\n:where(.ds-row--stacked):not(tr) {\n flex-direction: column;\n align-items: flex-start;\n justify-content: flex-start;\n gap: 0;\n height: auto;\n}\n\n/* The press target: the row itself, or the one target inside it. */\na.ds-row,\nbutton.ds-row,\n.ds-row__target {\n appearance: none;\n box-sizing: border-box;\n margin: 0;\n border: 0;\n background: none;\n color: inherit;\n font: inherit;\n letter-spacing: inherit;\n text-align: start;\n text-decoration: none;\n text-transform: none;\n cursor: pointer;\n outline: none;\n -webkit-tap-highlight-color: transparent;\n}\n\n/* The font inherited above would bring the page's line into the row: the words go back on the\n sixteen, as every row's (a stacked tile keeps its square lines below). */\na.ds-row,\nbutton.ds-row {\n position: relative;\n width: 100%;\n line-height: var(--ds-type-lineheight-default);\n padding: 0 var(--ds-row-padding, calc(4px * var(--ds-sf)));\n border-radius: var(--ds-row-radius, 0);\n}\n\n.ds-row__target {\n padding: 0;\n}\n\n/* Each line of a tile one square, over the inherited font of a native link or button:\n a tile's lines wrap, so they stay on whole squares rather than the sixteen. */\n.ds-row.ds-row--stacked {\n line-height: var(--ds-row-height);\n}\n\n/* A row with a target inside: the target's layers cover the row. */\n.ds-row:has(.ds-row__target) {\n position: relative;\n isolation: isolate;\n}\n:where(.ds-row:has(.ds-row__target)):not(tr) {\n padding-inline: var(--ds-row-padding, calc(4px * var(--ds-sf)));\n}\n.ds-row__target::before,\n.ds-row__target::after {\n content: \"\";\n position: absolute;\n inset: 0;\n border-radius: var(--ds-row-radius, 0);\n}\n.ds-row__target::before { z-index: 1; }\n.ds-row__target::after { z-index: -1; }\n.ds-row:has(.ds-row__target) :where(a[href], button, input, select, textarea, label, summary, [tabindex]):not(.ds-row__target) {\n position: relative;\n z-index: 2;\n}\n\n/*\n * The pointer, the press, the current destination and the focus ring are one layer under the\n * row's content (Joachim, 19 October 2026). On a one-square row it is a square high and sits two\n * pixels around what the row holds: from two above the lower sixteen to two below the row's foot,\n * and two past the content at each side, its corners the icon tiles' 4px and those two more, so a\n * 16px icon stands in it with two all round. It is drawn over the row, never moving its words or\n * icons off the grid. An open row (`data-open`) wears the same layer. A taller row (a stacked\n * tile, `auto`) is filled whole.\n * Tokens: `--ds-row-fill-radius` (6px), `--ds-row-fill-overhang` (2px).\n */\na.ds-row,\nbutton.ds-row {\n isolation: isolate;\n}\na.ds-row::after,\nbutton.ds-row::after {\n content: \"\";\n position: absolute;\n z-index: -1;\n pointer-events: none;\n}\na.ds-row::after,\nbutton.ds-row::after,\n.ds-row__target::after {\n --ds-row-overhang: var(--ds-row-fill-overhang, calc(2px * var(--ds-sf)));\n inset:\n calc(var(--ds-row-height) - var(--ds-control-height) - var(--ds-row-overhang))\n calc(var(--ds-row-padding, calc(4px * var(--ds-sf))) - var(--ds-row-overhang))\n calc(0px - var(--ds-row-overhang));\n border-radius: var(--ds-row-radius, var(--ds-row-fill-radius, calc(6px * var(--ds-sf))));\n}\n:is(a, button).ds-row:is(.ds-row--stacked, .ds-row--auto)::after,\n:is(.ds-row--stacked, .ds-row--auto) .ds-row__target::after {\n inset: 0;\n}\na.ds-row[href]:hover::after,\nbutton.ds-row:hover:not(:disabled)::after,\n.ds-row__target:is(a[href], button:not(:disabled)):hover::after {\n background: var(--ds-row-fill-hover, var(--ds-fill));\n}\na.ds-row[href]:active::after,\nbutton.ds-row:active:not(:disabled)::after,\n.ds-row__target:is(a[href], button:not(:disabled)):active::after {\n background: var(--ds-row-fill-press, var(--ds-fill-hover));\n}\n.ds-row:is(a, button)[aria-current]:not([aria-current=\"false\"])::after,\n.ds-row__target[aria-current]:not([aria-current=\"false\"])::after {\n background: var(--ds-row-fill-current, var(--ds-fill-hover));\n}\n.ds-row:is(a, button)[aria-current]:not([aria-current=\"false\"]),\n.ds-row:has(.ds-row__target[aria-current]:not([aria-current=\"false\"])) {\n --ds-type-weight-default: var(--ds-row-current-weight, 500);\n font-weight: var(--ds-row-current-weight, 500);\n}\na.ds-row:focus-visible::after,\nbutton.ds-row:focus-visible::after,\n.ds-row__target:focus-visible::after {\n outline: 2px solid var(--ds-focus-ring);\n outline-offset: -2px;\n}\na.ds-row:not([href]),\na.ds-row[aria-disabled=\"true\"],\nbutton.ds-row:disabled,\nbutton.ds-row[aria-disabled=\"true\"],\n.ds-row:has(.ds-row__target:is(:disabled, [aria-disabled=\"true\"], a:not([href]))) {\n cursor: default;\n opacity: 0.5;\n}\n.ds-row__target:is(:disabled, [aria-disabled=\"true\"], a:not([href])) {\n cursor: default;\n}\na.ds-row[aria-disabled=\"true\"]:hover::after,\nbutton.ds-row[aria-disabled=\"true\"]:hover::after {\n background: none;\n}\n\n.ds-row--nav {\n --ds-row-radius: calc(2px * var(--ds-sf));\n}\n\n/* A sidebar of nested things: the tree. */\n\n.ds-sidebar {\n box-sizing: border-box;\n display: flex;\n flex-direction: column;\n min-width: 0;\n margin: 0;\n padding: 0;\n list-style: none;\n color: var(--ds-text-color);\n font-family: var(--ds-typeface-regular);\n font-feature-settings: var(--ds-font-features);\n font-size: var(--ds-type-size-default);\n font-weight: var(--ds-type-weight-default);\n line-height: var(--ds-type-lineheight-default);\n letter-spacing: var(--ds-type-letterspacing-default);\n}\n\n.ds-sidebar__item {\n box-sizing: border-box;\n display: flex;\n align-items: flex-end;\n height: var(--ds-row-height);\n min-width: 0;\n margin: 0;\n padding-block: 0;\n padding-inline: calc(var(--ds-sidebar-indent, 0) * var(--ds-unit)) var(--ds-row-padding, calc(4px * var(--ds-sf)));\n white-space: nowrap;\n cursor: pointer;\n user-select: none;\n outline: none;\n -webkit-tap-highlight-color: transparent;\n}\n.ds-sidebar__item[hidden] { display: none; }\n.ds-sidebar__item[aria-level=\"2\"] { --ds-sidebar-indent: 1; }\n.ds-sidebar__item[aria-level=\"3\"] { --ds-sidebar-indent: 2; }\n.ds-sidebar__item[aria-level=\"4\"] { --ds-sidebar-indent: 3; }\n.ds-sidebar__item[aria-level=\"5\"] { --ds-sidebar-indent: 4; }\n.ds-sidebar__item[aria-level=\"6\"] { --ds-sidebar-indent: 5; }\n.ds-sidebar__item[aria-level=\"7\"] { --ds-sidebar-indent: 6; }\n.ds-sidebar__item[aria-level=\"8\"] { --ds-sidebar-indent: 7; }\n.ds-sidebar__item[aria-level=\"9\"] { --ds-sidebar-indent: 8; }\n.ds-sidebar__item[aria-level=\"10\"] { --ds-sidebar-indent: 9; }\n.ds-sidebar__item[aria-level=\"11\"] { --ds-sidebar-indent: 10; }\n.ds-sidebar__item[aria-level=\"12\"] { --ds-sidebar-indent: 11; }\n.ds-sidebar__item:hover:not([aria-disabled=\"true\"]) { background: var(--ds-row-fill-hover, var(--ds-fill)); }\n.ds-sidebar__item:active:not([aria-disabled=\"true\"]) { background: var(--ds-row-fill-press, var(--ds-fill-hover)); }\n.ds-sidebar__item[aria-selected=\"true\"] {\n --ds-type-weight-default: var(--ds-row-current-weight, 500);\n background: var(--ds-row-fill-current, var(--ds-fill-hover));\n font-weight: var(--ds-row-current-weight, 500);\n}\n.ds-sidebar__item:focus-visible {\n outline: 2px solid var(--ds-focus-ring);\n outline-offset: -2px;\n}\n.ds-sidebar__item[aria-disabled=\"true\"] {\n cursor: default;\n opacity: 0.5;\n}\n\n/* The arrow and an icon each stand on a whole square, drawn on the row's sixteen (two\n pixels below the square's middle); a leaf keeps the arrow's square empty. */\n.ds-sidebar__disclosure,\n.ds-sidebar__item > .ds-icon {\n flex: 0 0 var(--ds-unit);\n width: var(--ds-unit);\n height: var(--ds-unit);\n -webkit-mask-size: var(--ds-icon-box, calc(14px * var(--ds-sf)));\n mask-size: var(--ds-icon-box, calc(14px * var(--ds-sf)));\n -webkit-mask-position: center calc(50% + 2px * var(--ds-sf));\n mask-position: center calc(50% + 2px * var(--ds-sf));\n}\n.ds-sidebar__disclosure {\n --ds-icon-box: calc(14px * var(--ds-sf));\n display: inline-block;\n color: var(--ds-text-color-muted);\n background-color: currentColor;\n -webkit-mask: var(--ds-sidebar-disclosure, url(\"data:image/svg+xml,%3Csvg xmlns='http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg' viewBox='0 0 16 16'%3E%3Cpath d='M13.1566 8.60594H0V9.61651L13.1562 9.61791L10.249 12.5251L10.9558 13.219L15.0636 9.11123L10.9524 5L10.245 5.70734L13.1566 8.60594Z'/%3E%3C/svg%3E\")) center calc(50% + 2px * var(--ds-sf)) / var(--ds-icon-box) no-repeat;\n mask: var(--ds-sidebar-disclosure, url(\"data:image/svg+xml,%3Csvg xmlns='http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg' viewBox='0 0 16 16'%3E%3Cpath d='M13.1566 8.60594H0V9.61651L13.1562 9.61791L10.249 12.5251L10.9558 13.219L15.0636 9.11123L10.9524 5L10.245 5.70734L13.1566 8.60594Z'/%3E%3C/svg%3E\")) center calc(50% + 2px * var(--ds-sf)) / var(--ds-icon-box) no-repeat;\n transform: rotate(0deg);\n transition: transform 120ms ease-out;\n}\n.ds-sidebar__item:not([aria-expanded]) > .ds-sidebar__disclosure {\n visibility: hidden;\n}\n.ds-sidebar__item[aria-expanded=\"true\"] > .ds-sidebar__disclosure {\n transform: rotate(90deg);\n}\n.ds-sidebar__label {\n flex: 1 1 auto;\n min-width: 0;\n padding-inline-start: calc(4px * var(--ds-sf));\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.ds-sidebar__meta {\n flex: none;\n padding-inline-start: calc(4px * var(--ds-sf));\n color: var(--ds-text-color-muted);\n font-size: var(--ds-type-size-small);\n font-variant-numeric: tabular-nums;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .ds-sidebar__disclosure { transition: none; }\n}\n\n@media (forced-colors: active) {\n .ds-row:is(a, button)[aria-current]:not([aria-current=\"false\"]),\n .ds-row__target[aria-current]:not([aria-current=\"false\"])::after,\n .ds-sidebar__item[aria-selected=\"true\"] {\n outline: 1px solid Highlight;\n outline-offset: -1px;\n }\n .ds-sidebar__disclosure {\n background-color: CanvasText;\n }\n}\n\n/* A controlled detail view: the caller marks its open row, and clears it on close.\n Navigation's current state and the text weight remain independent. */\n.ds-row[data-open]:not([data-open=\"false\"]) {\n position: relative;\n isolation: isolate;\n}\n.ds-row[data-open]:not([data-open=\"false\"])::after {\n content: \"\";\n position: absolute;\n z-index: -1;\n pointer-events: none;\n --ds-row-overhang: var(--ds-row-fill-overhang, calc(2px * var(--ds-sf)));\n inset: calc(var(--ds-row-height) - var(--ds-control-height) - var(--ds-row-overhang))\n calc(var(--ds-row-padding, calc(4px * var(--ds-sf))) - var(--ds-row-overhang))\n calc(0px - var(--ds-row-overhang));\n border-radius: var(--ds-row-radius, var(--ds-row-fill-radius, calc(6px * var(--ds-sf))));\n background: var(--ds-row-fill-current, var(--ds-fill-hover));\n}\n/* A plain row (no press target inside) has no padding of its own: its words and icons stand on\n the row's edges, so the layer reaches two past them, as a flush row's does. */\n.ds-row[data-open]:not([data-open=\"false\"]):not(a, button, .ds-row--stacked, .ds-row--auto, :has(.ds-row__target))::after {\n inset: calc(var(--ds-row-height) - var(--ds-control-height) - var(--ds-row-overhang))\n calc(0px - var(--ds-row-overhang))\n calc(0px - var(--ds-row-overhang));\n}\n.ds-row[data-open]:is(.ds-row--stacked, .ds-row--auto)::after { inset: 0; }\n@media (forced-colors: active) {\n .ds-row[data-open]:not([data-open=\"false\"])::after { outline: 1px solid Highlight; outline-offset: -1px; }\n}\n/*\n * `.ds-context` is the `ds-context` element's look on a native menu, for a page\n * without Lit or a menu a library draws: Ezo's gap face. The rows carry the\n * colour and the menu only cuts the outer silhouette, so the page shows\n * through a pixel between rows and two between groups. The rows are black\n * with white words in both themes, as Ezo's menus always were (the slate in\n * dark, darker than the page). Every row is 19px with the pixel under it, a square's pitch, its words\n * on the sixteen and an icon at its end. A Select's menu is the light face,\n * `.ds-menu`; a Context's is this dark one.\n *\n * ds-context the menu (`role=\"menu\"`); its rows are its buttons,\n * links and menu items, or `ds-context__item`\n * ds-context__item a row; `--danger` (or `data-danger`) in red\n * ds-context__label a heading row, muted\n * ds-context__shortcut a shortcut at the row's end, muted\n * ds-context__separator a group gap (or an `hr`, or `role=\"separator\"`):\n * never a line; first, last or doubled it is quiet\n * [data-ds-refused] a refused change: the row turns red\n *\n * The page places and opens it (a popover at the pointer, say) and owns its\n * keys; the faces of hover, focus, disabled and the wait of a pending menu\n * (`aria-busy=\"true\"`) are here. Tokens as the element's: --ds-context-fill,\n * --ds-context-ink, --ds-context-hover, --ds-context-danger,\n * --ds-context-refused, --ds-context-radius.\n */\n\n.ds-context {\n --ds-context-row: calc(var(--ds-row-height) - 1px);\n /* Black in both themes, as Ezo's menus always were: in dark the slate, darker than the page. */\n --ds-context-fill: light-dark(var(--ds-black, #2a2a2a), var(--ds-slate, #1e1e1e));\n --ds-context-ink: var(--ds-white, #ffffff);\n --ds-context-hover: color-mix(in srgb, var(--ds-context-fill) 78%, var(--ds-context-ink));\n --ds-context-danger: var(--ds-tuned-red);\n --ds-context-refused: var(--ds-tuned-red);\n box-sizing: border-box;\n display: flex;\n flex-direction: column;\n gap: 1px;\n width: var(--ds-menu-width, max-content);\n min-width: calc(4 * var(--ds-unit));\n max-height: var(--ds-menu-max-height, calc(16 * var(--ds-unit)));\n overflow-y: auto;\n margin: 0;\n padding: 0;\n border: 0;\n background: transparent;\n box-shadow: none;\n clip-path: inset(0 round var(--ds-context-radius, var(--ds-radius, 4px)));\n color: var(--ds-context-ink);\n font-family: var(--ds-typeface-regular);\n font-feature-settings: var(--ds-font-features);\n font-size: var(--ds-type-size-default);\n font-weight: var(--ds-type-weight-default);\n line-height: var(--ds-type-lineheight-default);\n letter-spacing: var(--ds-type-letterspacing-default);\n list-style: none;\n}\n\n.ds-context > [role=\"group\"] {\n display: contents;\n}\n\n/* A row: whatever the page or library styles its buttons with, one row on the sixteen. */\n.ds-context :is(.ds-context__item, :is(.ds-context, .ds-context > [role=\"group\"]) > :is(button, a, li, [role^=\"menuitem\"]):not(.ds-context__label, .ds-context__separator, [role=\"separator\"])) {\n box-sizing: border-box !important;\n display: flex !important;\n flex: 0 0 auto !important;\n align-items: flex-end !important;\n justify-content: space-between !important;\n gap: calc(4px * var(--ds-sf));\n width: 100%;\n height: var(--ds-context-row) !important;\n min-height: var(--ds-context-row) !important;\n max-height: var(--ds-context-row) !important;\n margin: 0 !important;\n padding: 0 calc(4px * var(--ds-sf)) !important;\n border: 0 !important;\n border-radius: 0 !important;\n background: var(--ds-context-fill) !important;\n color: var(--ds-context-ink) !important;\n font: inherit;\n line-height: var(--ds-type-lineheight-default) !important;\n letter-spacing: inherit;\n text-align: start;\n text-decoration: none;\n white-space: nowrap;\n cursor: pointer;\n outline: none;\n appearance: none;\n -webkit-tap-highlight-color: transparent;\n}\n\n.ds-context :is(.ds-context__item, :is(.ds-context, .ds-context > [role=\"group\"]) > :is(button, a, li, [role^=\"menuitem\"])):is(:hover, :focus-visible, [data-highlighted]):not(:disabled, [aria-disabled=\"true\"], [data-disabled]) {\n background: var(--ds-context-hover) !important;\n}\n\n.ds-context :is(.ds-context__item, :is(.ds-context, .ds-context > [role=\"group\"]) > :is(button, a, li, [role^=\"menuitem\"])):focus-visible {\n box-shadow: inset 0 0 0 2px var(--ds-focus-ring);\n}\n\n.ds-context :is(.ds-context__item, :is(.ds-context, .ds-context > [role=\"group\"]) > :is(button, a, li, [role^=\"menuitem\"])):is(:disabled, [aria-disabled=\"true\"], [data-disabled]) {\n cursor: default;\n opacity: 0.5;\n}\n\n.ds-context[aria-busy=\"true\"] > * {\n cursor: wait !important;\n}\n\n/* Danger is red, on either fill. */\n.ds-context :is(.ds-context__item, :is(.ds-context, .ds-context > [role=\"group\"]) > :is(button, a, li, [role^=\"menuitem\"])):is(.ds-context__item--danger, [data-danger], [data-variant=\"destructive\"]) {\n color: var(--ds-context-danger) !important;\n}\n\n/* A refused change: its row turns red a moment. */\n.ds-context :is(.ds-context__item, :is(.ds-context, .ds-context > [role=\"group\"]) > :is(button, a, li, [role^=\"menuitem\"]))[data-ds-refused] {\n background: var(--ds-context-refused) !important;\n}\n\n/* Groups are a gap, never a line: the separator takes nothing but the gap after it. */\n.ds-context > :is(hr, .ds-context__separator, [role=\"separator\"]) {\n flex: 0 0 0 !important;\n height: 0 !important;\n margin: 0 !important;\n padding: 0 !important;\n border: 0 !important;\n background: none !important;\n}\n\n/* A group left empty leaves no gap. */\n.ds-context > :is(hr, .ds-context__separator, [role=\"separator\"]):is(:first-child, :last-child),\n.ds-context > :is(hr, .ds-context__separator, [role=\"separator\"]) + :is(hr, .ds-context__separator, [role=\"separator\"]) {\n display: none !important;\n}\n\n.ds-context :is(.ds-context__label, [data-ds-menu-label]) {\n box-sizing: border-box;\n height: var(--ds-context-row);\n /* The spare three above the sixteen. */\n padding: calc(var(--ds-context-row) - var(--ds-type-lineheight-default)) calc(4px * var(--ds-sf)) 0;\n background: var(--ds-context-fill);\n color: color-mix(in srgb, var(--ds-context-ink) 60%, var(--ds-context-fill));\n line-height: var(--ds-type-lineheight-default);\n white-space: nowrap;\n}\n\n.ds-context__shortcut {\n margin-left: auto;\n color: color-mix(in srgb, var(--ds-context-ink) 60%, var(--ds-context-fill));\n}\n\n/*\n * Native controls in shared dress.\n *\n * DS one keeps a few components as plain classes on native elements. shared does\n * the same for everything a person types into or picks from: text fields,\n * selects and checkboxes stay `<input>` and `<select>`, so labels, form\n * semantics and React's controlled inputs work as they always have.\n *\n * `.ds-button` is the `ds-button` element's look on a native `<button>`,\n * for a button inside a drag handle. The drag library recognises only native\n * controls: inside a handle it would lift the row on Space where a\n * `ds-button` was meant to be pressed. Both read the same custom properties.\n * On an `<a href>` it is a link drawn as a button (see `a.ds-button` below).\n */\n\n.ds-button {\n appearance: none;\n box-sizing: border-box;\n display: inline-flex;\n /* At the foot of a line, so the 16px face takes the lower sixteen of the square. */\n vertical-align: bottom;\n flex: 0 0 auto;\n width: var(--ds-button-width, max-content);\n align-items: center;\n justify-content: var(--ds-button-align, flex-start);\n gap: var(--ds-button-gap, calc(4px * var(--ds-sf)));\n height: var(--ds-button-height, var(--ds-control-height));\n margin: 0;\n padding: var(--ds-button-padding, 0);\n border: 0;\n border-radius: var(--ds-radius);\n background: var(--ds-button-background, transparent);\n color: var(--ds-button-color, var(--ds-button-text-color));\n font-family: var(--ds-typeface-regular);\n font-feature-settings: var(--ds-font-features);\n font-size: var(--ds-type-size-default);\n line-height: var(--ds-type-lineheight-default);\n letter-spacing: var(--ds-type-letterspacing-default);\n white-space: nowrap;\n cursor: pointer;\n -webkit-tap-highlight-color: transparent;\n}\n\n.ds-button--icon {\n justify-content: center;\n width: var(--ds-button-height, var(--ds-control-height));\n padding: 0;\n color: var(--ds-button-color, var(--ds-text-color-muted));\n}\n\n.ds-button--icon:hover:not(:disabled, [aria-disabled=\"true\"]) {\n --ds-button-color: var(--ds-text-color);\n}\n\n.ds-button:focus-visible {\n outline: 2px solid var(--ds-focus-ring);\n outline-offset: 1px;\n}\n\n.ds-button:disabled,\n.ds-button[aria-disabled=\"true\"] {\n cursor: default;\n opacity: 0.5;\n}\n\n/*\n * one.css carries older button rules that dim a button on hover and nudge it\n * on press. The shared button does neither: these match their specificity, so\n * controls.css, loaded after one.css, wins.\n */\n.ds-button:hover:not(:disabled, [aria-disabled=\"true\"]) {\n filter: none;\n}\n\n.ds-button:active:not(:disabled, [aria-disabled=\"true\"]) {\n transform: none;\n}\n\n/*\n * `a.ds-button` is a link drawn as a button. The browser keeps the link:\n * middle-click, a new tab, Copy link and Enter. It never takes the link's\n * underline or colours, in any state, so every face (primary, secondary,\n * icon, tabs) looks as it does on a `<button>`. A disabled link has no `href`\n * and carries `aria-disabled=\"true\"` and `role=\"link\"`.\n */\na.ds-button,\na.ds-button:is(:hover, :focus, :active) {\n text-decoration: none;\n}\n\na.ds-button:is(:link, :visited) {\n color: var(--ds-button-color, var(--ds-button-text-color));\n}\n\na.ds-button.ds-button--icon:is(:link, :visited) {\n color: var(--ds-button-color, var(--ds-text-color-muted));\n}\n\na.ds-button[aria-disabled=\"true\"] {\n pointer-events: none;\n}\n\n/*\n * `.ds-link` is a link in running text: the text's ink, underlined by a\n * hairline 2px below the letters (as a toast's actions are), which turns to the full ink under\n * the pointer. A visited link is drawn in the muted ink. Words keep their\n * sentence case. Tokens: `--ds-link-color`, `--ds-link-visited-color`,\n * `--ds-link-line-color`, `--ds-link-hover-line-color`.\n */\n.ds-link {\n color: var(--ds-link-color, currentColor);\n text-decoration-line: underline;\n text-decoration-thickness: 1px;\n text-decoration-color: var(--ds-link-line-color, color-mix(in srgb, currentColor 40%, transparent));\n text-underline-offset: calc(2px * var(--ds-sf));\n cursor: pointer;\n}\n\n.ds-link:visited {\n color: var(--ds-link-visited-color, var(--ds-text-color-muted));\n}\n\n.ds-link:hover {\n text-decoration-color: var(--ds-link-hover-line-color, currentColor);\n}\n\n/* Quiet navigation and related-component lists: no underline in any state. */\n.ds-link.ds-link--plain {\n text-decoration: none;\n}\n\n.ds-link:focus-visible {\n outline: 2px solid var(--ds-focus-ring);\n outline-offset: 1px;\n}\n\n.ds-link[aria-disabled=\"true\"] {\n cursor: default;\n opacity: 0.5;\n pointer-events: none;\n}\n\n.ds-input,\n.ds-select {\n box-sizing: border-box;\n min-width: 0;\n height: var(--ds-input-height, var(--ds-control-height));\n margin: 0;\n padding: 0 calc(4px * var(--ds-sf));\n border: 0;\n border-radius: var(--ds-radius);\n background: var(--ds-fill);\n color: var(--ds-text-color);\n font-family: var(--ds-typeface-regular);\n font-feature-settings: var(--ds-font-features);\n font-size: var(--ds-type-size-default);\n line-height: var(--ds-type-lineheight-default);\n letter-spacing: var(--ds-type-letterspacing-default);\n outline: none;\n}\n\n.ds-input::placeholder {\n color: var(--ds-title-color);\n}\n\n.ds-input:focus-visible,\n.ds-select:focus-visible,\n.ds-checkbox:focus-visible,\n.ds-radio:focus-visible,\n.ds-switch:focus-visible {\n outline: 2px solid var(--ds-focus-ring);\n outline-offset: 1px;\n}\n\n.ds-input:disabled,\n.ds-select:disabled,\n.ds-checkbox:disabled,\n.ds-radio:disabled,\n.ds-switch:disabled {\n cursor: default;\n opacity: 0.5;\n}\n\n.ds-select {\n appearance: none;\n padding-right: calc(16px * var(--ds-sf));\n background-image:\n linear-gradient(45deg, transparent 50%, currentColor 50%),\n linear-gradient(135deg, currentColor 50%, transparent 50%);\n background-position:\n calc(100% - 9px) 50%,\n calc(100% - 6px) 50%;\n background-size:\n 3px 3px,\n 3px 3px;\n background-repeat: no-repeat;\n cursor: pointer;\n}\n\n/* A multiline field, `ds-input` on a <textarea>, spans whole rows: --ds-textarea-rows sets how many, three by default. */\ntextarea.ds-input {\n display: block;\n height: var(--ds-textarea-height, calc(var(--ds-textarea-rows, 3) * var(--ds-row-height)));\n min-height: var(--ds-row-height);\n padding: var(--ds-textarea-padding, calc(4px * var(--ds-sf)));\n border-radius: var(--ds-textarea-radius, calc(4px * var(--ds-sf)));\n resize: vertical;\n}\n\n/*\n * `.ds-checkbox` and `.ds-radio` are the `ds-checkbox` and `ds-radio` elements'\n * faces on a native `<input>`: one square on the field's ground with a 1px\n * line. The checkbox has the corners of a control and fills with the accent,\n * the check (`x-icon/check.svg`) in its ink; the radio is a circle with a dot\n * half a square across in the text colour.\n */\n.ds-checkbox,\n.ds-radio {\n appearance: none;\n box-sizing: border-box;\n display: inline-grid;\n flex: 0 0 auto;\n place-items: center;\n vertical-align: middle;\n width: var(--ds-row-height);\n height: var(--ds-row-height);\n margin: 0;\n padding: 0;\n border: 1px solid var(--ds-border-color);\n background: var(--ds-input-background);\n cursor: pointer;\n}\n\n.ds-checkbox {\n --ds-checkbox-mark: url(\"data:image/svg+xml,%3Csvg%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%20fill%3D%22none%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%3Cpath%20d%3D%22M6.68649%2011.884L12.443%206.13601L11.736%205.42715L6.68835%2010.4827L4.26399%208.0501L3.55696%208.74525L6.68649%2011.884Z%22%20fill%3D%22currentColor%22%2F%3E%0A%3C%2Fsvg%3E\");\n border-radius: var(--ds-radius);\n corner-shape: var(--ds-corner-shape, round);\n color: var(--ds-button-text-color-on-accent);\n}\n\n.ds-checkbox:is(:checked, :indeterminate) {\n background: var(--ds-accent-color);\n}\n\n.ds-checkbox::before,\n.ds-radio::before {\n content: \"\";\n opacity: 0;\n background: currentColor;\n}\n\n.ds-checkbox::before {\n width: calc(0.8 * var(--ds-row-height));\n height: calc(0.8 * var(--ds-row-height));\n mask: var(--ds-checkbox-mark) center / contain no-repeat;\n}\n\n.ds-checkbox:indeterminate::before {\n width: calc(var(--ds-row-height) / 2);\n height: calc(2px * var(--ds-sf));\n mask: none;\n}\n\n.ds-radio {\n border-radius: 50%;\n color: var(--ds-text-color);\n}\n\n.ds-radio::before {\n width: calc(var(--ds-row-height) / 2);\n height: calc(var(--ds-row-height) / 2);\n border-radius: 50%;\n}\n\n.ds-checkbox:is(:checked, :indeterminate)::before,\n.ds-radio:checked::before {\n opacity: 1;\n}\n\n/*\n * `.ds-switch` is the `ds-switch` element's look on a native\n * `<button role=\"switch\" aria-checked>`: two control heights wide, its thumb\n * one control high less a 2px inset, travelling one control height.\n * `.ds-switch--rounded` is the round variant with a white thumb.\n */\n\n.ds-switch {\n --ds-choice-unit: var(--ds-control-height);\n appearance: none;\n box-sizing: border-box;\n position: relative;\n display: inline-block;\n flex: 0 0 auto;\n vertical-align: middle;\n width: calc(2 * var(--ds-choice-unit));\n height: var(--ds-choice-unit);\n margin: 0;\n padding: calc(2px * var(--ds-sf));\n border: 0;\n border-radius: var(--ds-radius);\n background: var(--ds-fill);\n color: var(--ds-text-color-muted);\n cursor: pointer;\n touch-action: manipulation;\n}\n\n.ds-switch::after {\n content: \"\";\n display: block;\n width: calc(var(--ds-choice-unit) - 4px * var(--ds-sf));\n height: 100%;\n border-radius: var(--ds-radius);\n background: currentColor;\n transform: translateX(0);\n transition: transform 140ms ease;\n}\n\n.ds-switch[aria-checked=\"true\"] {\n background: var(--ds-accent-color);\n color: var(--ds-button-text-color-on-accent);\n}\n\n.ds-switch[aria-checked=\"true\"]::after {\n transform: translateX(var(--ds-choice-unit));\n}\n\n.ds-switch--rounded {\n border-radius: var(--ds-choice-unit);\n color: var(--ds-white);\n}\n\n.ds-switch--rounded::after {\n border-radius: 50%;\n background: var(--ds-white);\n}\n\n.ds-switch--rounded[aria-checked=\"true\"] {\n background: var(--ds-switch-track-on);\n}\n\n@media (prefers-reduced-motion: reduce) {\n .ds-switch::after {\n transition: none;\n }\n}\n\n/*\n * `.ds-range` draws a native `<input type=\"range\">`: one control high,\n * standing on the lower sixteen of its square (the spare four above it as a\n * margin, so it takes one square alone and in a row), eight squares wide.\n * The track is a 1px line across the middle of the control, the thumb one\n * control high and half a control wide with the shared corners, in the ink.\n * The browser keeps the value, the keys, the form data and the events.\n *\n * Tokens: `--ds-range-width` (eight squares), `--ds-range-track` (the line,\n * the title grey), `--ds-range-thumb` (the ink) and `--ds-range-thumb-width`.\n * WebKit and Blink draw the parts as `::-webkit-slider-*`, Firefox as\n * `::-moz-range-*`; both get the same track and thumb.\n */\n\n.ds-range {\n -webkit-appearance: none;\n appearance: none;\n box-sizing: border-box;\n display: inline-block;\n vertical-align: bottom;\n width: var(--ds-range-width, calc(8 * var(--ds-unit)));\n min-width: 0;\n height: var(--ds-control-height);\n margin: calc(var(--ds-row-height) - var(--ds-control-height)) 0 0;\n padding: 0;\n border: 0;\n border-radius: var(--ds-radius);\n background: transparent;\n color: var(--ds-range-thumb, var(--ds-text-color));\n font: inherit;\n cursor: pointer;\n touch-action: pan-y;\n -webkit-tap-highlight-color: transparent;\n}\n\n.ds-range::-webkit-slider-runnable-track {\n box-sizing: border-box;\n height: var(--ds-control-height);\n border: 0;\n background: linear-gradient(var(--ds-range-track, var(--ds-title-color)) 0 0) 0 calc(var(--ds-control-height) / 2) / 100% 1px no-repeat;\n}\n\n.ds-range::-moz-range-track {\n box-sizing: border-box;\n height: var(--ds-control-height);\n border: 0;\n background: linear-gradient(var(--ds-range-track, var(--ds-title-color)) 0 0) 0 calc(var(--ds-control-height) / 2) / 100% 1px no-repeat;\n}\n\n.ds-range::-moz-range-progress {\n background: transparent;\n}\n\n.ds-range::-webkit-slider-thumb {\n -webkit-appearance: none;\n appearance: none;\n box-sizing: border-box;\n width: var(--ds-range-thumb-width, calc(var(--ds-control-height) / 2));\n height: var(--ds-control-height);\n border: 0;\n border-radius: var(--ds-radius);\n background: currentColor;\n}\n\n.ds-range::-moz-range-thumb {\n box-sizing: border-box;\n width: var(--ds-range-thumb-width, calc(var(--ds-control-height) / 2));\n height: var(--ds-control-height);\n border: 0;\n border-radius: var(--ds-radius);\n background: currentColor;\n}\n\n.ds-range:focus-visible {\n outline: 2px solid var(--ds-focus-ring);\n outline-offset: 1px;\n}\n\n.ds-range:disabled {\n cursor: default;\n opacity: 0.5;\n}\n\n/*\n * `.ds-tabs` is the `ds-tabs` element's row on native buttons. As an option\n * group (role=\"group\", a segmented control) its `.ds-button` choices are\n * grey and the chosen one, aria-pressed, aria-selected or aria-current, is in\n * the accent, as the primary and secondary buttons are.\n */\n\n.ds-tabs {\n box-sizing: border-box;\n display: flex;\n flex-direction: row;\n align-items: center;\n gap: calc(4px * var(--ds-sf));\n min-width: 0;\n height: var(--ds-row-height);\n}\n\n.ds-tabs--fill > * {\n flex: 1 1 0;\n justify-content: center;\n}\n\n.ds-tabs[role=\"group\"] > .ds-button {\n --ds-button-height: var(--ds-row-height);\n --ds-button-padding: 0 calc(4px * var(--ds-sf));\n --ds-button-background: var(--ds-button-background-color-secondary);\n min-width: 0;\n}\n\n.ds-tabs[role=\"group\"] > .ds-button:hover:not(:disabled, [aria-disabled=\"true\"]) {\n --ds-button-background: var(--ds-fill-hover);\n}\n\n.ds-tabs[role=\"group\"] > .ds-button:is([aria-pressed=\"true\"], [aria-selected=\"true\"], [aria-current]:not([aria-current=\"false\"])) {\n --ds-button-background: var(--ds-button-background-color-primary);\n --ds-button-color: var(--ds-button-text-color-on-accent);\n}\n\n/*\n * `.ds-overlay` is the `ds-overlay` element's frame on a native `<dialog>`, a\n * modal by default: twenty squares wide, a square of padding, square corners,\n * a hairline and the paper. `ds-overlay--sheet`, `ds-overlay--drawer` (with\n * `ds-overlay--start` for the start side) and `ds-overlay--screen` are its\n * other types (overlay.css). Its header, title, description, footer and close button are marked\n * with data-ds-overlay, as inside the element.\n */\n\ndialog.ds-overlay {\n box-sizing: border-box;\n position: fixed;\n inset: 0;\n width: var(--ds-overlay-width, calc(20 * var(--ds-unit)));\n max-width: var(--ds-overlay-max-width, calc(100vw - 2 * var(--ds-unit)));\n max-height: var(--ds-overlay-max-height, calc(100dvh - 2 * var(--ds-unit)));\n height: var(--ds-overlay-height, fit-content);\n margin: auto;\n padding: var(--ds-overlay-padding, var(--ds-unit));\n border: var(--ds-overlay-border, 1px solid var(--ds-border-color));\n border-radius: 0;\n background: var(--ds-overlay-paper, var(--ds-paper));\n color: var(--ds-text-color);\n box-shadow: none;\n overflow: auto;\n overscroll-behavior: contain;\n font-family: var(--ds-typeface-regular);\n font-feature-settings: var(--ds-font-features);\n font-size: var(--ds-type-size-default);\n font-weight: var(--ds-type-weight-default);\n line-height: var(--ds-type-lineheight-default);\n letter-spacing: var(--ds-type-letterspacing-default);\n}\n\ndialog.ds-overlay[open] {\n display: flex;\n flex-direction: column;\n gap: var(--ds-unit);\n}\n\ndialog.ds-overlay::backdrop {\n background: color-mix(in srgb, var(--ds-black) 40%, transparent);\n}\n\n.ds-overlay [data-ds-overlay=\"header\"] {\n display: flex;\n flex-direction: column;\n}\n\n/* The header keeps the last square of its row for the close button, only when it has one. */\ndialog.ds-overlay:has(> [data-ds-overlay=\"close\"]) [data-ds-overlay=\"header\"] {\n padding-inline-end: var(--ds-unit);\n}\n\n/* The title on its square's lower sixteen, as every row's words. */\n.ds-overlay [data-ds-overlay=\"title\"] {\n display: flex;\n align-items: flex-end;\n min-height: var(--ds-row-height);\n margin: 0;\n color: var(--ds-text-color);\n font: inherit;\n font-weight: var(--ds-type-weight-bold);\n line-height: var(--ds-type-lineheight-default);\n}\n\n.ds-overlay [data-ds-overlay=\"description\"] {\n margin: 0;\n color: var(--ds-text-color-muted);\n font: inherit;\n}\n\n.ds-overlay [data-ds-overlay=\"footer\"] {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n justify-content: flex-end;\n gap: calc(var(--ds-unit) / 2);\n min-height: var(--ds-row-height);\n}\n\n.ds-overlay [data-ds-overlay=\"close\"] {\n position: absolute;\n top: var(--ds-unit);\n right: var(--ds-unit);\n}\n\n/* A field in the frame, as a prompt has: its label one row high, the field\n * one row high beneath it and as wide as the frame, two squares in all. */\n.ds-overlay [data-ds-overlay=\"field\"] {\n display: flex;\n flex-direction: column;\n}\n\n.ds-overlay [data-ds-overlay=\"label\"] {\n min-height: var(--ds-row-height);\n line-height: var(--ds-row-height);\n}\n\n.ds-overlay [data-ds-overlay=\"field\"] > .ds-input {\n --ds-input-height: var(--ds-row-height);\n width: 100%;\n}\n\n/*\n * `.ds-button--primary` and `--secondary` are the element's variants on a\n * native button: a form's submit button stays native so Enter in a field\n * submits the form. `--danger` is its `danger` attribute.\n */\n\n.ds-button--primary,\n.ds-button--secondary {\n --ds-button-padding: 0 calc(4px * var(--ds-sf));\n}\n\n.ds-button--primary {\n --ds-button-background: var(--ds-button-background-color-primary);\n --ds-button-color: var(--ds-button-text-color-on-accent);\n}\n\n.ds-button--secondary {\n --ds-button-background: var(--ds-button-background-color-secondary);\n}\n\n.ds-button--secondary:hover:not(:disabled, [aria-disabled=\"true\"]) {\n --ds-button-background: var(--ds-fill-hover);\n}\n\n/* `.ds-button--danger` is the element's `danger`: a destructive action's words\n * in the danger colour, on the secondary face or none. */\n.ds-button--danger {\n --ds-button-color: var(--ds-danger-color, var(--ds-tuned-red));\n}\n\n.ds-button--fixed {\n width: var(--ds-button-width, calc(4 * var(--ds-unit)));\n}\n\n.ds-button--wide {\n justify-content: center;\n width: 100%;\n}\n\n/*\n * `.ds-menu` is the `ds-menu` element's look on a menu a library draws:\n * the context menu's items come from Radix, which owns their roles, focus and\n * keys, so they stay Radix's and take shared's paper, rows and type.\n * On whole squares, as the element: the line and the padding inside it make\n * half a square on each side, entries are one square each with nothing\n * between them, a separator is one square with its line, and there is no\n * shadow. n entries make a menu n + 1 squares high.\n */\n\n.ds-menu {\n box-sizing: border-box;\n display: flex;\n flex-direction: column;\n gap: 0;\n min-width: calc(8 * var(--ds-unit));\n max-width: calc(12 * var(--ds-unit));\n max-height: var(--ds-menu-max-height, calc(16 * var(--ds-unit)));\n overflow-y: auto;\n padding: calc(var(--ds-unit) / 2 - 1px);\n border: 1px solid var(--ds-border-color);\n border-radius: var(--ds-radius-card);\n background: var(--ds-paper);\n color: var(--ds-text-color);\n box-shadow: none;\n font-family: var(--ds-typeface-regular);\n font-feature-settings: var(--ds-font-features);\n font-size: var(--ds-type-size-default);\n font-weight: var(--ds-type-weight-default);\n line-height: var(--ds-type-lineheight-default);\n letter-spacing: var(--ds-type-letterspacing-default);\n}\n\n.ds-menu__item {\n position: relative;\n box-sizing: border-box;\n display: flex;\n align-items: center;\n gap: calc(4px * var(--ds-sf));\n width: 100%;\n min-height: var(--ds-row-height);\n padding: calc(2px * var(--ds-sf)) calc(6px * var(--ds-sf));\n border-radius: calc(4px * var(--ds-sf));\n color: var(--ds-text-color);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n cursor: default;\n user-select: none;\n outline: none;\n}\n\n/* An entry a library draws as its own button or link is one square high too,\n * whatever that library's button styles say. */\n.ds-menu > :is(button, a, [role=\"option\"], [role^=\"menuitem\"]),\n.ds-menu > [role=\"group\"] > :is(button, a, [role=\"option\"], [role^=\"menuitem\"]) {\n box-sizing: border-box !important;\n flex: 0 0 auto !important;\n height: var(--ds-row-height) !important;\n min-height: var(--ds-row-height) !important;\n max-height: var(--ds-row-height) !important;\n margin-block: 0 !important;\n padding-block: 0 !important;\n line-height: var(--ds-type-lineheight-default) !important;\n}\n\n/* A menu item may be a native button: it keeps the row's look, not a button's. */\n:where(button).ds-menu__item {\n appearance: none;\n margin: 0;\n border: 0;\n background: transparent;\n font: inherit;\n letter-spacing: inherit;\n text-align: start;\n}\n\n.ds-menu__item--inset {\n padding-left: calc(var(--ds-unit) + calc(4px * var(--ds-sf)));\n}\n\n.ds-menu__item:hover,\n.ds-menu__item:focus-visible,\n.ds-menu__item[data-highlighted] {\n background: var(--ds-fill);\n}\n\n.ds-menu__item[data-variant=\"destructive\"] {\n color: var(--ds-danger-color, var(--ds-tuned-red));\n}\n\n.ds-menu__item[data-disabled],\n.ds-menu__item[aria-disabled=\"true\"] {\n opacity: 0.5;\n pointer-events: none;\n}\n\n.ds-menu__indicator {\n position: absolute;\n left: calc(6px * var(--ds-sf));\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: calc(12px * var(--ds-sf));\n height: calc(12px * var(--ds-sf));\n pointer-events: none;\n}\n\n.ds-menu__indicator svg {\n width: 100%;\n height: 100%;\n}\n\n.ds-menu__chevron {\n width: calc(12px * var(--ds-sf));\n height: calc(12px * var(--ds-sf));\n margin-left: auto;\n color: var(--ds-text-color-muted);\n}\n\n.ds-menu__label {\n box-sizing: border-box;\n min-height: var(--ds-row-height);\n padding: calc(2px * var(--ds-sf)) calc(6px * var(--ds-sf));\n color: var(--ds-title-color);\n font-size: var(--ds-type-size-small);\n}\n\n.ds-menu__separator {\n flex: 0 0 auto;\n height: 1px;\n /* One square with its line. */\n margin: calc(var(--ds-unit) / 2 - 1px) calc(6px * var(--ds-sf)) calc(var(--ds-unit) / 2);\n background: var(--ds-border-color);\n}\n\n.ds-menu__shortcut {\n margin-left: auto;\n padding-left: var(--ds-unit);\n color: var(--ds-title-color);\n font-size: var(--ds-type-size-small);\n}\n\n/*\n * Pieces the components draw, as classes on native elements: a field's label\n * row, an avatar, a badge, a toggle button, an icon and a file drop zone. Each\n * reads the same tokens as its element, so a page without Lit draws the same\n * look.\n */\n\n/*\n * `.ds-field` is the label row `ds-input` draws, around any native control:\n * the label (`.ds-field__label`) on a one-square line above it, then a hint\n * (`.ds-field__hint`) in the muted ink and an error (`.ds-field__error`) in\n * the danger colour, each on one-square lines. Every row is at least one\n * square high and a control lower than that stands centred on it, so the\n * field keeps to whole squares. `.ds-field--beside` sets the label beside the\n * control, in a column `--ds-field-label-width` wide (four squares), with the\n * hint and the error under the control. An empty hint or error takes no room,\n * so the error can stay in the page as a live region.\n */\n\n.ds-field {\n box-sizing: border-box;\n display: grid;\n grid-template-columns: minmax(0, 1fr);\n grid-auto-rows: minmax(var(--ds-row-height), auto);\n align-items: center;\n justify-items: start;\n min-width: 0;\n margin: 0;\n color: var(--ds-text-color);\n font-family: var(--ds-typeface-regular);\n font-feature-settings: var(--ds-font-features);\n font-size: var(--ds-type-size-default);\n font-weight: var(--ds-type-weight-default);\n line-height: var(--ds-unit);\n letter-spacing: var(--ds-type-letterspacing-default);\n}\n\n.ds-field > :is(.ds-input, .ds-select) {\n justify-self: stretch;\n}\n\n.ds-field__label,\n.ds-field__hint,\n.ds-field__error {\n display: block;\n min-width: 0;\n margin: 0;\n font: inherit;\n letter-spacing: inherit;\n}\n\n.ds-field__label {\n color: var(--ds-field-label-color, var(--ds-text-color));\n}\n\n.ds-field__hint {\n color: var(--ds-text-color-muted);\n}\n\n.ds-field__error {\n color: var(--ds-danger-color);\n}\n\n.ds-field__hint:empty,\n.ds-field__error:empty {\n display: none;\n}\n\n.ds-field--beside {\n grid-template-columns: var(--ds-field-label-width, calc(4 * var(--ds-unit))) minmax(0, 1fr);\n}\n\n.ds-field--beside > * {\n grid-column: 2;\n}\n\n.ds-field--beside > .ds-field__label {\n grid-column: 1;\n grid-row: 1;\n align-self: start;\n}\n\n/*\n * `.ds-avatar` is the `ds-avatar` element's mark: round and one control high,\n * an initial in small type on the neutral fill, or an `<img alt=\"\">` after the\n * initial, covering it. While the picture loads the initial shows; remove a\n * picture that fails (`onerror`), as the element does, or the browser draws\n * its broken-image mark. `--large` is two squares with type a square high,\n * `--pair` fits two characters between the hairline edges, `--square` gives it\n * a picture's corners, `--outlined` draws the hairline in its ink and\n * `--pending` greys out someone who has not accepted yet.\n * `--ds-avatar-background` fills it with a colour and `--ds-avatar-color`\n * letters it: on a fill, pick the black or white ink that reads on it\n * (`--ds-black`, `--ds-white`).\n */\n\n.ds-avatar {\n --ds-avatar-size: var(--ds-control-height);\n --ds-avatar-pair-type-size: var(--ds-type-size-small);\n box-sizing: border-box;\n position: relative;\n display: inline-grid;\n place-items: center;\n flex: 0 0 auto;\n vertical-align: middle;\n width: var(--ds-avatar-size);\n height: var(--ds-avatar-size);\n overflow: hidden;\n border-radius: 50%;\n corner-shape: round;\n background: var(--ds-avatar-background, var(--ds-fill));\n color: var(--ds-avatar-color, var(--ds-text-color));\n font: var(--ds-type-weight-default) var(--ds-type-size-small) / 1 var(--ds-typeface-regular);\n letter-spacing: normal;\n text-align: center;\n white-space: nowrap;\n user-select: none;\n -webkit-user-select: none;\n}\n\n.ds-avatar > img {\n position: absolute;\n inset: 0;\n display: block;\n width: 100%;\n height: 100%;\n object-fit: cover;\n}\n\n.ds-avatar--large {\n --ds-avatar-size: calc(2 * var(--ds-unit));\n --ds-avatar-pair-type-size: var(--ds-type-size-default);\n font-size: var(--ds-unit);\n}\n\n.ds-avatar--pair {\n font-size: min(var(--ds-avatar-pair-type-size), calc((var(--ds-avatar-size) - 2px) / 2));\n}\n\n.ds-avatar--square {\n border-radius: var(--ds-avatar-radius, var(--ds-radius));\n corner-shape: var(--ds-corner-shape, round);\n}\n\n.ds-avatar--outlined::after {\n content: \"\";\n position: absolute;\n inset: 0;\n border: 1px solid var(--ds-avatar-outline, currentColor);\n border-radius: inherit;\n pointer-events: none;\n}\n\n.ds-avatar--pending {\n background: var(--ds-fill);\n color: var(--ds-text-color-muted);\n}\n\n.ds-avatar--pending > img {\n filter: grayscale(1);\n opacity: 0.5;\n}\n\n/*\n * `.ds-badge` is the `ds-badge` element's status label: one square high on the\n * neutral fill, its words padded 4px and cut short with an ellipsis, never a\n * button. Where the browser can size to content in calc (calc-size), its width\n * rounds up to whole squares as the element's does; elsewhere it hugs the\n * words. An icon inside is a `.ds-icon` before the words. `--icon` shows the\n * icon alone, one square wide, and keeps the words for assistive technology:\n * put them in an element of their own. `--ds-badge-background` and\n * `--ds-badge-color` give a status a meaningful colour.\n */\n\n.ds-badge {\n box-sizing: border-box;\n display: inline-block;\n flex: 0 0 auto;\n vertical-align: middle;\n width: max-content;\n width: calc-size(max-content, round(up, size, var(--ds-unit)));\n min-width: var(--ds-row-height);\n max-width: 100%;\n height: var(--ds-row-height);\n padding: 0 calc(4px * var(--ds-sf));\n overflow: hidden;\n background: var(--ds-badge-background, var(--ds-fill));\n color: var(--ds-badge-color, var(--ds-text-color));\n font-family: var(--ds-typeface-regular);\n font-feature-settings: var(--ds-font-features);\n font-size: var(--ds-type-size-default);\n font-weight: var(--ds-type-weight-default);\n line-height: var(--ds-row-height);\n letter-spacing: var(--ds-type-letterspacing-default);\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.ds-badge > .ds-icon {\n vertical-align: top;\n margin-top: calc((var(--ds-row-height) - var(--ds-icon-box, var(--ds-control-height))) / 2);\n margin-right: calc(4px * var(--ds-sf));\n}\n\n.ds-badge--icon {\n position: relative;\n width: var(--ds-row-height);\n padding: 0;\n text-align: center;\n}\n\n.ds-badge--icon > .ds-icon {\n margin-right: 0;\n}\n\n.ds-badge--icon > :not(.ds-icon) {\n position: absolute;\n width: 1px;\n height: 1px;\n overflow: hidden;\n clip-path: inset(50%);\n white-space: nowrap;\n}\n\n/*\n * `.ds-toggle` makes a `.ds-button` a toggle button, `<button aria-pressed>`:\n * the secondary button's grey while it is off, the primary button's accent\n * while it is on, as a chosen segment of `.ds-tabs[role=\"group\"]` is. Its\n * words stay the same in both states; the page toggles `aria-pressed`.\n * A setting that is on or off is a `.ds-switch`; one of several choices is a\n * `.ds-tabs[role=\"group\"]`.\n */\n\n.ds-toggle {\n --ds-button-padding: 0 calc(4px * var(--ds-sf));\n --ds-button-background: var(--ds-button-background-color-secondary);\n}\n\n.ds-toggle:hover:not(:disabled, [aria-disabled=\"true\"]) {\n --ds-button-background: var(--ds-fill-hover);\n}\n\n.ds-toggle[aria-pressed=\"true\"],\n.ds-toggle[aria-pressed=\"true\"]:hover:not(:disabled, [aria-disabled=\"true\"]) {\n --ds-button-background: var(--ds-button-background-color-primary);\n --ds-button-color: var(--ds-button-text-color-on-accent);\n}\n\n/*\n * `.ds-icon` is the `ds-icon` element's drawing without the element: a\n * Design system 1 icon file as a mask, painted in the text colour\n * (`--ds-icon-color`), 14px by default, 12px with `--small` and 16px with\n * `--large`, times the scale. `--ds-icon` names the file, as Sync 1's `icons`\n * export copies it: `style=\"--ds-icon: url(icons/close.svg)\"` (a path from the\n * page) or a rule per icon in the page's stylesheet. The mask takes only the\n * drawing's shape, so an icon with colours of its own is an `<img>`. These\n * rules have no specificity: a page that drew its own `.ds-icon` keeps its\n * rule until it removes it.\n */\n\n:where(.ds-icon) {\n --ds-icon-box: calc(var(--ds-icon-size, 14px) * var(--ds-sf));\n display: inline-block;\n flex: 0 0 auto;\n width: var(--ds-icon-box);\n height: calc(var(--ds-icon-box) / var(--ds-icon-ratio, 1));\n color: var(--ds-icon-color, currentColor);\n background-color: currentColor;\n -webkit-mask: var(--ds-icon) center / contain no-repeat;\n mask: var(--ds-icon) center / contain no-repeat;\n}\n\n:where(.ds-icon--small) {\n --ds-icon-size: 12px;\n}\n\n:where(.ds-icon--large) {\n --ds-icon-size: 16px;\n}\n\n/*\n * `.ds-drop` is `ds-file-picker`'s area on a `<label>` around a native\n * `<input type=\"file\">`: the secondary button's face, as wide as its row and\n * eight squares high (`--compact`: four), its words centred in a square of\n * padding. The input covers the zone unseen, so a click, the keyboard and a\n * dropped file all reach it, and the browser keeps labels, forms, `required`,\n * `multiple` and reset. Keyboard focus draws the focus ring. A page that also\n * handles drops on a larger surface sets `data-dragging` on the zone while\n * files are dragged over it, for the ring and the hover fill. A `.ds-button`\n * on a `<span>` inside draws a button face among the words.\n *\n * The same native input directly inside a `label.ds-button` is the file\n * picker's button: the button's face, one square high.\n */\n\n.ds-drop {\n box-sizing: border-box;\n position: relative;\n display: flex;\n flex-wrap: wrap;\n align-content: center;\n align-items: center;\n justify-content: center;\n gap: calc(var(--ds-unit) / 2);\n width: 100%;\n min-width: 0;\n height: calc(8 * var(--ds-unit));\n margin: 0;\n padding: var(--ds-unit);\n overflow: hidden;\n border-radius: var(--ds-radius);\n corner-shape: var(--ds-corner-shape, round);\n background: var(--ds-button-background-color-secondary);\n color: var(--ds-button-text-color);\n font-family: var(--ds-typeface-regular);\n font-feature-settings: var(--ds-font-features);\n font-size: var(--ds-type-size-default);\n font-weight: var(--ds-type-weight-default);\n line-height: var(--ds-type-lineheight-default);\n letter-spacing: var(--ds-type-letterspacing-default);\n text-align: center;\n cursor: pointer;\n user-select: none;\n -webkit-user-select: none;\n -webkit-tap-highlight-color: transparent;\n}\n\n.ds-drop--compact {\n height: calc(4 * var(--ds-unit));\n}\n\nlabel.ds-button:has(> input[type=\"file\"]) {\n --ds-button-height: var(--ds-row-height);\n position: relative;\n overflow: hidden;\n}\n\n:is(.ds-drop, label.ds-button) > input[type=\"file\"]:not([hidden]) {\n position: absolute;\n inset: 0;\n box-sizing: border-box;\n display: block;\n width: 100%;\n height: 100%;\n min-width: 0;\n margin: 0;\n padding: 0;\n border: 0;\n opacity: 0;\n cursor: pointer;\n}\n\n:is(.ds-drop, label.ds-button) > input[type=\"file\"]::file-selector-button {\n cursor: pointer;\n}\n\n.ds-drop:hover:not(:has(> input:disabled)),\n.ds-drop[data-dragging]:not(:has(> input:disabled)) {\n background: var(--ds-fill-hover);\n}\n\n.ds-drop:has(> input:focus-visible),\n.ds-drop[data-dragging]:not(:has(> input:disabled)),\nlabel.ds-button:has(> input[type=\"file\"]:focus-visible) {\n outline: 2px solid var(--ds-focus-ring);\n outline-offset: 1px;\n}\n\n.ds-drop:has(> input:disabled),\nlabel.ds-button:has(> input[type=\"file\"]:disabled) {\n cursor: default;\n opacity: 0.5;\n}\n\n:is(.ds-drop, label.ds-button) > input[type=\"file\"]:disabled {\n cursor: default;\n}\n";
|
|
8831
|
+
var controls_default = "/* Shape is a surface preference. Keep these base lengths unscaled: each\n * component resolves them with its own --ds-sf in component-metrics.css. */\n[data-ds-shape=\"square\"],\n:host([data-ds-shape=\"square\"]) {\n --ds-corner-size: 0px;\n --ds-corner-shape: round;\n --ds-button-inset: 0.5px;\n}\n\n[data-ds-shape=\"rounded\"],\n:host([data-ds-shape=\"rounded\"]) {\n --ds-corner-size: 4px;\n --ds-corner-shape: round;\n --ds-button-inset: 2.5px;\n}\n\n[data-ds-shape=\"circular\"],\n:host([data-ds-shape=\"circular\"]) {\n --ds-corner-size: 999px;\n --ds-corner-shape: round;\n --ds-button-inset: 5px;\n}\n\n/* A squircle needs twice an arc's radius for the same apparent corner.\n * Circular controls keep true semicircles even in a squircle browser. */\n@supports (corner-shape: squircle) {\n [data-ds-shape=\"rounded\"],\n :host([data-ds-shape=\"rounded\"]) {\n --ds-corner-size: 8px;\n --ds-corner-shape: squircle;\n }\n}\n\n/* Resolve dimensions where a component is drawn. Inherited calc() values have\n * already used their ancestor's scale. Base tokens stay unscaled and inherit;\n * resolved tokens can still be overridden directly on a component.\n * data-ds-surface gives ordinary layout elements the same scaled measures.\n */\n:root,\n:host,\n:where([data-ds-surface]) {\n --ds-unit: calc(var(--ds-1, 20px) * var(--ds-sf, 1));\n --ds-control-height: calc(var(--ds-control-size, var(--ds-08, 16px)) * var(--ds-sf, 1));\n --ds-row-height: calc(var(--ds-row-size, var(--ds-1, 20px)) * var(--ds-sf, 1));\n --ds-type-size-default: calc(var(--ds-text-size, 14px) * var(--ds-sf, 1));\n --ds-type-size-small: calc(var(--ds-small-text-size, 10px) * var(--ds-sf, 1));\n --ds-type-size-heading: calc(var(--ds-heading-text-size, 13px) * var(--ds-sf, 1));\n --ds-type-size-display: calc(var(--ds-display-text-size, 20px) * var(--ds-sf, 1));\n --ds-type-lineheight-default: calc(var(--ds-text-leading, 16px) * var(--ds-sf, 1));\n --ds-type-letterspacing-default: calc(var(--ds-text-tracking, -0.3px) * var(--ds-sf, 1));\n --ds-radius: calc(var(--ds-corner-size, 4px) * var(--ds-sf, 1));\n --ds-radius-card: calc(var(--ds-card-corner-size, 4px) * var(--ds-sf, 1));\n}\n/*\n * A table: words straight on the paper, one square a row. No box and no\n * column lines: each row stands on a hairline at its foot, its words set on\n * that line like a caption: the sixteen of words against the 1px line, three\n * spare above, a 20px pitch, as Ezo sets every row.\n * Column headers keep the text's weight in the title grey; the first column\n * of a body row is a row header in the text colour. Nothing is filled with\n * the accent except a cell someone has selected.\n *\n * `.ds-table` dresses a native <table>; `<ds-table>` draws the same table\n * from data. Put a wide table in `.ds-table-scroll` to scroll it sideways,\n * and give the table `data-sticky` to keep its first column in place.\n *\n * <th data-numeric>, <td data-numeric> numbers, set to the column's end\n * <tfoot> totals, under a line of their own\n * <th colspan=\"2\"> a column group, in a header row\n * <th scope=\"rowgroup\"> a row group, a heading row in grey\n * <td aria-selected=\"true\"> a selected cell\n *\n * `data-sheet` makes it a spreadsheet: every cell four squares by one (80 by\n * 20), its 1px lines at its end and foot so the words have 79 by 19, set 4px\n * in on the sixteen, as an Ezo item's are. Column letters and the row numbers\n * (`.ds-table__letters`, `.ds-table__number`, two squares wide) stay in place\n * while the sheet scrolls both ways inside `.ds-table-scroll`; give the table\n * `--ds-table-columns` (the number of data columns) and the scroll a height\n * with `--ds-table-height`.\n */\n\n.ds-table {\n --ds-table-row: var(--ds-row-height, calc(20px * var(--ds-sf, 1)));\n --ds-table-gap: calc(var(--ds-table-row) / 2);\n --ds-table-rule: var(--ds-border-color, light-dark(#d8d8d8, #3d3d3d));\n --ds-table-paper: var(--ds-background, Canvas);\n width: 100%;\n border-collapse: collapse;\n border-spacing: 0;\n color: var(--ds-text-color, inherit);\n font-family: var(--ds-typeface-regular, inherit);\n font-feature-settings: var(--ds-font-features, normal);\n font-size: var(--ds-type-size-default, 14px);\n letter-spacing: var(--ds-type-letterspacing-default, normal);\n}\n\n.ds-table :is(th, td) {\n box-sizing: border-box;\n height: var(--ds-table-row);\n padding: 0 var(--ds-table-gap) 0 0;\n border: 0;\n border-bottom: 1px solid var(--ds-table-rule);\n background: transparent;\n line-height: var(--ds-type-lineheight-default);\n text-align: start;\n vertical-align: bottom;\n font-weight: inherit;\n white-space: nowrap;\n}\n\n.ds-table :is(th, td):last-child {\n padding-inline-end: 0;\n}\n\n.ds-table thead th,\n.ds-table th[scope=\"rowgroup\"] {\n color: var(--ds-title-color, light-dark(#797979, #9a9a9a));\n}\n\n.ds-table tbody th:not([scope=\"rowgroup\"]) {\n color: inherit;\n}\n\n.ds-table [data-numeric] {\n text-align: end;\n font-variant-numeric: tabular-nums;\n}\n\n/* Totals: the rule above them is the last body row's; theirs closes the table. */\n.ds-table tfoot :is(th, td) {\n color: inherit;\n}\n\n.ds-table [aria-selected=\"true\"] {\n background: var(--ds-accent-color, Highlight);\n color: var(--ds-button-text-color-on-accent, inherit);\n}\n\n.ds-table :is(th, td):has(> :is(a, button):only-child) {\n cursor: pointer;\n}\n\n.ds-table caption {\n box-sizing: border-box;\n height: var(--ds-table-row);\n padding-top: calc(var(--ds-table-row) - var(--ds-type-lineheight-default));\n line-height: var(--ds-type-lineheight-default);\n text-align: start;\n color: var(--ds-title-color, light-dark(#797979, #9a9a9a));\n}\n\n.ds-table-scroll {\n max-width: 100%;\n overflow-x: auto;\n overscroll-behavior-x: contain;\n}\n\n.ds-table-scroll > .ds-table {\n width: max-content;\n min-width: 100%;\n}\n\n.ds-table[data-sticky] :is(th, td):first-child {\n position: sticky;\n inset-inline-start: 0;\n z-index: 1;\n background: var(--ds-table-paper);\n}\n\n.ds-table[data-sticky] [aria-selected=\"true\"]:first-child {\n background: var(--ds-accent-color, Highlight);\n}\n\n/* Keep the row whose details are open visible, including its sticky first cell.\n Cell selection remains independent and keeps its accent. */\n.ds-table tbody > tr[data-open]:not([data-open=\"false\"]) > :is(th, td):not([aria-selected=\"true\"]) {\n background: var(--ds-row-fill-current, var(--ds-fill-hover));\n}\n@media (forced-colors: active) {\n .ds-table tbody > tr[data-open]:not([data-open=\"false\"]) > :is(th, td):not([aria-selected=\"true\"]) {\n background: Highlight;\n color: HighlightText;\n }\n}\n\n/* A spreadsheet: cells four squares by one, on lines, lettered and numbered. */\n.ds-table[data-sheet] {\n --ds-table-cell: calc(4 * var(--ds-table-row));\n --ds-table-index: calc(2 * var(--ds-table-row));\n --ds-table-text: calc(4px * var(--ds-sf, 1));\n table-layout: fixed;\n width: calc(var(--ds-table-index) + var(--ds-table-columns, 8) * var(--ds-table-cell));\n min-width: 0;\n border-collapse: separate;\n border-spacing: 0;\n}\n.ds-table-scroll > .ds-table[data-sheet] {\n width: calc(var(--ds-table-index) + var(--ds-table-columns, 8) * var(--ds-table-cell));\n min-width: 0;\n}\n.ds-table[data-sheet] :is(th, td) {\n width: var(--ds-table-cell);\n max-width: var(--ds-table-cell);\n height: var(--ds-table-row);\n padding: 0 var(--ds-table-text);\n border-bottom: 1px solid var(--ds-table-rule);\n border-inline-end: 1px solid var(--ds-table-rule);\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.ds-table[data-sheet] :is(th, td):last-child {\n padding-inline-end: var(--ds-table-text);\n}\n.ds-table[data-sheet] .ds-table__number {\n width: var(--ds-table-index);\n max-width: var(--ds-table-index);\n position: sticky;\n inset-inline-start: 0;\n z-index: 1;\n background: var(--ds-table-paper);\n color: var(--ds-title-color, light-dark(#797979, #9a9a9a));\n text-align: center;\n font-variant-numeric: tabular-nums;\n}\n.ds-table[data-sheet] thead :is(th, td) {\n position: sticky;\n top: 0;\n z-index: 2;\n background: var(--ds-table-paper);\n}\n.ds-table[data-sheet] thead tr + tr :is(th, td) {\n top: var(--ds-table-row);\n}\n.ds-table[data-sheet] thead .ds-table__number {\n z-index: 3;\n}\n.ds-table[data-sheet] .ds-table__letters td {\n color: var(--ds-title-color, light-dark(#797979, #9a9a9a));\n text-align: center;\n}\n.ds-table[data-sheet] tbody td:not([data-numeric]) {\n color: inherit;\n}\n.ds-table[data-sheet] [aria-selected=\"true\"] {\n background: transparent;\n color: inherit;\n box-shadow: inset 0 0 0 2px var(--ds-focus-ring, Highlight);\n}\n.ds-table-scroll:has(> .ds-table[data-sheet]) {\n max-height: var(--ds-table-height, none);\n overflow: auto;\n overscroll-behavior: contain;\n}\n/*\n * Text on the grid, as plain classes on native text.\n *\n * Interface copy on a page without Lit: a label, a message, a title. Each line\n * is one square (`--ds-unit`), so a paragraph of any length stands on whole\n * squares, and a display title takes two. The `ds-text` element draws the same\n * words when they come from a translation key.\n *\n * one.css and controls.css both import this file, so a page that loads either\n * of them, or both, has one definition of these classes.\n *\n * ds-text 14 on a one-square line, the text colour\n * ds-text--small 10\n * ds-text--heading 13, medium\n * ds-text--display 20 on two squares, medium\n * ds-text--strong medium\n * ds-text--muted, --title, --danger tones\n */\n\n.ds-text {\n margin: 0;\n color: var(--ds-text-color);\n font-family: var(--ds-typeface-regular);\n font-feature-settings: var(--ds-font-features);\n font-size: var(--ds-type-size-default);\n font-weight: var(--ds-type-weight-default);\n line-height: var(--ds-unit);\n letter-spacing: var(--ds-type-letterspacing-default);\n}\n\n.ds-text--small {\n font-size: var(--ds-type-size-small);\n}\n\n.ds-text--heading {\n font-family: var(--ds-typeface-medium);\n font-size: var(--ds-type-size-heading);\n font-weight: var(--ds-type-weight-bold);\n}\n\n.ds-text--display {\n font-family: var(--ds-typeface-medium);\n font-size: var(--ds-type-size-display);\n font-weight: var(--ds-type-weight-bold);\n line-height: calc(2 * var(--ds-unit));\n letter-spacing: calc(var(--ds-display-text-tracking, -0.4px) * var(--ds-sf, 1));\n}\n\n.ds-text--strong {\n font-family: var(--ds-typeface-medium);\n font-weight: var(--ds-type-weight-bold);\n}\n\n.ds-text--muted {\n color: var(--ds-text-color-muted);\n}\n\n.ds-text--title {\n color: var(--ds-title-color);\n}\n\n.ds-text--danger {\n color: var(--ds-danger-color);\n}\n\n.ds-text--warning {\n color: var(--ds-warning-color);\n}\n/*\n * An empty state, as plain classes on native elements.\n *\n * It says that a place has nothing in it yet and what to do about it: a title,\n * a line of text and, when there is one, the action that fills it. The words\n * sit on the paper with no box, no illustration and no colour; every line is\n * one square, so the whole stands on whole squares. The `ds-empty` element\n * draws the same parts from a translation key, with the shared words' \"Nothing\n * here yet\" as its title when none is given.\n *\n * ds-empty the block, at most sixteen squares wide\n * ds-empty__icon an icon from the library, on its own square, muted\n * ds-empty__title one line in the medium face\n * ds-empty__text lines of one square, muted\n * ds-empty__actions buttons or links on one row, one square below\n * ds-empty--centered centred in the space it stands in\n * ds-empty--done all done: the check on a mark in the success\n * green, the title in that green\n *\n * Tokens: `--ds-empty-measure` (the widest it grows, sixteen squares) and\n * `--ds-empty-padding` (the room above and below, none by default).\n */\n\n.ds-empty {\n box-sizing: border-box;\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n width: 100%;\n max-width: var(--ds-empty-measure, calc(16 * var(--ds-unit)));\n margin: 0;\n padding-block: var(--ds-empty-padding, 0);\n color: var(--ds-text-color);\n font-family: var(--ds-typeface-regular);\n font-feature-settings: var(--ds-font-features);\n font-size: var(--ds-type-size-default);\n font-weight: var(--ds-type-weight-default);\n line-height: var(--ds-unit);\n letter-spacing: var(--ds-type-letterspacing-default);\n text-transform: none;\n}\n\n.ds-empty__icon {\n display: flex;\n align-items: center;\n height: var(--ds-unit);\n color: var(--ds-text-color-muted);\n}\n\n.ds-empty__title,\n.ds-empty__text {\n margin: 0;\n font: inherit;\n letter-spacing: inherit;\n}\n\n.ds-empty__title {\n font-family: var(--ds-typeface-medium);\n font-weight: var(--ds-type-weight-bold);\n}\n\n.ds-empty__text {\n color: var(--ds-text-color-muted);\n}\n\n.ds-empty__actions {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 0 calc(var(--ds-unit) / 2);\n min-height: var(--ds-row-height);\n margin-top: var(--ds-unit);\n}\n\n.ds-empty--centered {\n align-items: center;\n margin-inline: auto;\n text-align: center;\n}\n\n.ds-empty--centered .ds-empty__actions {\n justify-content: center;\n}\n\n/* Done: a place empty because everything in it is finished (every receipt\n found, nothing left to review). The icon, the check by default, stands on a\n round mark one control high in the success green, on the sixteen, and the\n title takes the same green; the line under it stays muted. */\n.ds-empty--done .ds-empty__icon {\n box-sizing: border-box;\n justify-content: center;\n width: var(--ds-control-height);\n height: var(--ds-control-height);\n margin-top: calc(var(--ds-unit) - var(--ds-control-height));\n border-radius: 50%;\n background: var(--ds-success-color);\n color: light-dark(var(--ds-white), var(--ds-black));\n --ds-icon-color: currentColor;\n}\n\n.ds-empty--done .ds-empty__title {\n color: var(--ds-success-color);\n}\n/*\n * An inline notice, as plain classes on native elements.\n *\n * A notice stands in the flow of the page, where its words apply: a failure\n * beside the form that failed, a warning above the list it is about. It is not\n * positioned and takes no box or shadow. A square mark, one control high and\n * filled in the tone's colour, carries the tone; the words sit on the paper\n * beside it, each line one square, with the actions on the row below and the\n * dismiss button at the end of the first line. Danger turns the words into\n * the danger colour. The `ds-notice` element draws the same parts.\n *\n * ds-notice the block: mark, words, dismiss\n * ds-notice__mark the square mark; holds an icon in its ink\n * ds-notice__title one line in the medium face\n * ds-notice__text lines of one square\n * ds-notice__actions buttons or links on one row\n * ds-notice__dismiss an icon button at the end of the first line\n * ds-notice--success, --warning, --danger tones; neutral without one\n * ds-notice--banner a strip across the top of its positioning\n * context instead: one square high, filled in\n * the tone's colour, everything on one line\n * ds-notice--app a row at the top of the page leading to the\n * site's iPhone app: its picture\n * (ds-notice__picture, two squares), its name\n * and one line about it, Open\n * (a.ds-notice__open) and the close; three\n * squares high with a hairline at its foot.\n * startAppBanners() from 0-face/app-banner.ts\n * shows it only where it belongs\n *\n * Give the block role=\"status\", or role=\"alert\" for danger, so assistive\n * technology reads it when it appears.\n *\n * Tokens: `--ds-notice-mark`, `--ds-notice-mark-ink` and `--ds-notice-ink`,\n * which the tones set.\n */\n\n.ds-notice {\n --ds-notice-mark: var(--ds-fill);\n --ds-notice-mark-ink: var(--ds-text-color);\n --ds-notice-ink: var(--ds-text-color);\n box-sizing: border-box;\n display: grid;\n grid-template-columns: var(--ds-unit) minmax(0, 1fr) auto;\n align-items: start;\n margin: 0;\n color: var(--ds-notice-ink);\n font-family: var(--ds-typeface-regular);\n font-feature-settings: var(--ds-font-features);\n font-size: var(--ds-type-size-default);\n font-weight: var(--ds-type-weight-default);\n line-height: var(--ds-unit);\n letter-spacing: var(--ds-type-letterspacing-default);\n text-transform: none;\n}\n\n.ds-notice--success {\n --ds-notice-mark: var(--ds-apple-green);\n --ds-notice-mark-ink: var(--ds-black);\n}\n\n.ds-notice--warning {\n --ds-notice-mark: var(--ds-orange);\n --ds-notice-mark-ink: var(--ds-black);\n}\n\n.ds-notice--danger {\n --ds-notice-mark: var(--ds-danger-color);\n --ds-notice-mark-ink: light-dark(var(--ds-white), var(--ds-black));\n --ds-notice-ink: var(--ds-danger-color);\n}\n\n/* The mark stands on the first line, one control high in a one-square cell. */\n.ds-notice__mark {\n box-sizing: border-box;\n grid-column: 1;\n grid-row: 1;\n display: flex;\n align-items: center;\n justify-content: center;\n width: var(--ds-control-height);\n height: var(--ds-control-height);\n margin-block: calc((var(--ds-unit) - var(--ds-control-height)) / 2);\n overflow: hidden;\n background: var(--ds-notice-mark);\n color: var(--ds-notice-mark-ink);\n --ds-icon-color: var(--ds-notice-mark-ink);\n}\n\n.ds-notice__title,\n.ds-notice__text,\n.ds-notice__actions {\n grid-column: 2;\n min-width: 0;\n margin: 0;\n}\n\n.ds-notice__title,\n.ds-notice__text {\n font: inherit;\n letter-spacing: inherit;\n overflow-wrap: anywhere;\n}\n\n.ds-notice__title {\n font-family: var(--ds-typeface-medium);\n font-weight: var(--ds-type-weight-bold);\n}\n\n.ds-notice__actions {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 0 calc(var(--ds-unit) / 2);\n min-height: var(--ds-row-height);\n}\n\n/* The dismiss button closes the first line: a one-square cell at the end.\n Two classes, so the button's own reset of its margin does not undo it. */\n.ds-notice .ds-notice__dismiss {\n grid-column: 3;\n grid-row: 1;\n margin-block: calc((var(--ds-unit) - var(--ds-control-height)) / 2);\n margin-inline-start: calc(var(--ds-unit) - var(--ds-control-height));\n}\n\n/* A banner: the same parts on one line, one square high, across the top of\n the nearest positioned ancestor (or the page), on a fill of the tone's\n colour. It takes no room in the flow; leave a square for it where words\n stand under it. The actions stand at the end of the line, half a square\n apart; danger words keep the text colour on the danger fill. */\n.ds-notice--banner {\n position: absolute;\n top: 0;\n inset-inline: 0;\n z-index: 9999;\n display: flex;\n align-items: center;\n gap: calc(var(--ds-unit) / 2);\n height: var(--ds-unit);\n padding-inline: var(--ds-unit);\n background: color-mix(in srgb, var(--ds-notice-mark) 40%, transparent);\n --ds-notice-ink: var(--ds-text-color);\n}\n\n.ds-notice--banner .ds-notice__mark {\n flex: none;\n margin-block: 0;\n}\n\n.ds-notice--banner .ds-notice__title,\n.ds-notice--banner .ds-notice__text {\n min-width: 0;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.ds-notice--banner .ds-notice__text {\n flex: 1;\n}\n\n.ds-notice--banner .ds-notice__actions {\n flex: none;\n min-height: 0;\n}\n\n.ds-notice--banner .ds-notice__dismiss {\n margin-block: 0;\n margin-inline-start: 0;\n}\n\n/* The app banner: a row at the top of the page, in the flow, three squares\n high: half a square above and below two squares of content, a hairline at\n its foot. The app's picture fills two squares with a picture's corners; the\n name and the line about it take a square each, on the sixteen; Open and the\n close stand on the sixteen of the square in the middle of the two. */\n.ds-notice--app {\n grid-template-columns: calc(2 * var(--ds-unit)) minmax(0, 1fr) auto var(--ds-unit);\n grid-template-rows: var(--ds-unit) var(--ds-unit);\n column-gap: calc(var(--ds-unit) / 2);\n align-items: end;\n padding: calc(var(--ds-unit) / 2) var(--ds-unit);\n background: var(--ds-paper);\n box-shadow: inset 0 -1px 0 var(--ds-border-color);\n line-height: var(--ds-type-lineheight-default);\n}\n\n.ds-notice--app[hidden] {\n display: none;\n}\n\n.ds-notice__picture {\n box-sizing: border-box;\n grid-column: 1;\n grid-row: 1 / 3;\n align-self: stretch;\n overflow: hidden;\n border-radius: var(--ds-radius);\n background: var(--ds-fill);\n outline: 1px solid var(--ds-border-color);\n outline-offset: -1px;\n}\n\n.ds-notice__picture img {\n display: block;\n width: 100%;\n height: 100%;\n object-fit: cover;\n}\n\n.ds-notice--app .ds-notice__title,\n.ds-notice--app .ds-notice__text {\n grid-column: 2;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.ds-notice--app .ds-notice__title { grid-row: 1; }\n\n.ds-notice--app .ds-notice__text {\n grid-row: 2;\n color: var(--ds-text-color-muted);\n}\n\n/* Open and the close: their square starts half a square into the two, its\n control on the lower sixteen of it. */\n.ds-notice--app .ds-notice__open,\n.ds-notice--app .ds-notice__dismiss {\n grid-row: 1 / 3;\n align-self: start;\n margin: calc(1.5 * var(--ds-unit) - var(--ds-control-height)) 0 0;\n}\n\n.ds-notice--app .ds-notice__open {\n grid-column: 3;\n text-decoration: none;\n}\n\n.ds-notice--app .ds-notice__dismiss {\n grid-column: 4;\n justify-self: end;\n}\n/*\n * Overlay: everything that stands over the page, one component with a type.\n * A `modal` stands in the centre (controls.css and the element's frame); this\n * sheet draws the others, for the `ds-overlay` element (`type=\"sheet\"`,\n * `\"drawer\"` with `side`, `\"screen\"`, which mark its native dialog\n * `data-ds-type` and `data-ds-edge`) and the native frame\n * (`dialog.ds-overlay.ds-overlay--sheet`, `--drawer` with `--start`,\n * `--screen`); controls.css imports it. A popover is placed by the element.\n *\n * - A sheet is as wide as the screen up to 32 squares and centred beyond\n * that, as high as its content up to two squares below the top, with no\n * line at its foot; its one line, at the top, is drawn inside its first\n * square (`--ds-overlay-line`), so it stands on whole squares. A handle two squares wide stands in the middle of its\n * first square and stays there while the content scrolls.\n * - A drawer is the screen's height and 16 squares wide (`--ds-overlay-width`),\n * leaving at least two squares of the page beside it; its one line is on\n * the side that faces the page. `end` is the right in a left-to-right page.\n * - Each keeps the square of padding inside the screen's safe area\n * (`env(safe-area-inset-*)`, with `viewport-fit=cover` on the page).\n * - Each slides in from its edge and back out to it, in transform alone,\n * while the backdrop fades; with reduced motion it fades in place. Dragging\n * it towards its edge (0-face/overlay-swipe.ts) moves it with the finger and\n * fades the backdrop as it goes.\n * - The page behind a modal native sheet or drawer does not scroll.\n */\n\n:is(ds-overlay > dialog[data-ds-edge=\"bottom\"], dialog.ds-overlay.ds-overlay--sheet),\n:is(ds-overlay > dialog[data-ds-edge=\"end\"], dialog.ds-overlay.ds-overlay--drawer:not(.ds-overlay--start)),\n:is(ds-overlay > dialog[data-ds-edge=\"start\"], dialog.ds-overlay.ds-overlay--drawer.ds-overlay--start) {\n --ds-overlay-gap: var(--ds-unit);\n --ds-overlay-inner: var(--ds-overlay-padding, var(--ds-unit));\n /* The line it faces the page with is drawn inside its first square. */\n --ds-overlay-within: max(0px, var(--ds-overlay-inner) - var(--ds-overlay-line, 1px));\n --ds-overlay-motion: var(--ds-overlay-enter, 380ms);\n --ds-overlay-curve: var(--ds-overlay-easing, cubic-bezier(0.32, 0.72, 0, 1));\n margin: 0;\n gap: var(--ds-overlay-gap);\n transform: var(--ds-overlay-held);\n transition:\n transform var(--ds-overlay-motion) var(--ds-overlay-curve),\n opacity var(--ds-overlay-motion) var(--ds-overlay-curve),\n overlay var(--ds-overlay-motion) allow-discrete,\n display var(--ds-overlay-motion) allow-discrete;\n}\n\n/* Content that supplies its own room. */\n:is(ds-overlay > dialog[data-ds-edge], dialog.ds-overlay:is(.ds-overlay--sheet, .ds-overlay--drawer))[data-ds-overlay-flush] {\n --ds-overlay-inner: 0px;\n --ds-overlay-gap: 0px;\n}\n\n:is(ds-overlay > dialog[data-ds-edge=\"bottom\"], dialog.ds-overlay.ds-overlay--sheet) {\n --ds-overlay-held: translateY(var(--ds-overlay-drag, 0px));\n --ds-overlay-away: translateY(100%);\n inset: auto 0 0;\n width: var(--ds-overlay-width, 100%);\n max-width: min(100%, var(--ds-overlay-sheet-width, calc(32 * var(--ds-unit))));\n height: var(--ds-overlay-height, fit-content);\n max-height: calc(100dvh - var(--ds-overlay-sheet-gap, calc(2 * var(--ds-unit))) - env(safe-area-inset-top, 0px));\n margin: 0 auto;\n padding:\n var(--ds-overlay-within)\n calc(var(--ds-overlay-inner) + env(safe-area-inset-right, 0px))\n calc(var(--ds-overlay-inner) + env(safe-area-inset-bottom, 0px))\n calc(var(--ds-overlay-inner) + env(safe-area-inset-left, 0px));\n border-bottom: 0;\n}\n\n/* The handle: two squares wide, in the middle of the first square, above the\n * content as it scrolls. It takes no room: the content starts where it would. */\n:is(ds-overlay > dialog[data-ds-edge=\"bottom\"], dialog.ds-overlay.ds-overlay--sheet)::before {\n --ds-overlay-handle-height: calc(4px * var(--ds-sf, 1));\n content: \"\";\n display: var(--ds-overlay-handle, block);\n position: sticky;\n z-index: 1;\n /* A sticky offset counts from the content edge, under the sheet's top padding: take that\n padding off, so the handle is held where it already stands, in the first square. */\n top: calc((var(--ds-unit) - var(--ds-overlay-handle-height)) / 2 - var(--ds-overlay-line, 1px) - var(--ds-overlay-within));\n flex: 0 0 auto;\n align-self: center;\n width: calc(2 * var(--ds-unit));\n height: var(--ds-overlay-handle-height);\n margin-top: calc(var(--ds-overlay-inner) * -1 + (var(--ds-unit) - var(--ds-overlay-handle-height)) / 2);\n margin-bottom: calc(var(--ds-overlay-inner) - var(--ds-overlay-gap) - var(--ds-overlay-handle-height) - (var(--ds-unit) - var(--ds-overlay-handle-height)) / 2);\n border-radius: calc(var(--ds-overlay-handle-height) / 2);\n background: var(--ds-overlay-handle-color, var(--ds-border-color));\n pointer-events: none;\n}\n\n:is(ds-overlay > dialog[data-ds-edge=\"end\"], dialog.ds-overlay.ds-overlay--drawer:not(.ds-overlay--start)),\n:is(ds-overlay > dialog[data-ds-edge=\"start\"], dialog.ds-overlay.ds-overlay--drawer.ds-overlay--start) {\n --ds-overlay-held: translateX(var(--ds-overlay-drag, 0px));\n width: calc(var(--ds-overlay-width, calc(16 * var(--ds-unit))) + var(--ds-overlay-safe-side, 0px));\n max-width: calc(100vw - 2 * var(--ds-unit));\n height: 100dvh;\n max-height: none;\n border-top: 0;\n border-bottom: 0;\n}\n\n/* At the right: the end of a left-to-right page, the start of a right-to-left one. */\n:is(ds-overlay > dialog[data-ds-edge=\"end\"], dialog.ds-overlay.ds-overlay--drawer:not(.ds-overlay--start)):not(:dir(rtl)),\n:is(ds-overlay > dialog[data-ds-edge=\"start\"], dialog.ds-overlay.ds-overlay--drawer.ds-overlay--start):dir(rtl) {\n --ds-overlay-away: translateX(100%);\n --ds-overlay-safe-side: env(safe-area-inset-right, 0px);\n inset: 0 0 0 auto;\n padding:\n calc(var(--ds-overlay-inner) + env(safe-area-inset-top, 0px))\n calc(var(--ds-overlay-inner) + env(safe-area-inset-right, 0px))\n calc(var(--ds-overlay-inner) + env(safe-area-inset-bottom, 0px))\n var(--ds-overlay-within);\n border-right: 0;\n}\n\n:is(ds-overlay > dialog[data-ds-edge=\"start\"], dialog.ds-overlay.ds-overlay--drawer.ds-overlay--start):not(:dir(rtl)),\n:is(ds-overlay > dialog[data-ds-edge=\"end\"], dialog.ds-overlay.ds-overlay--drawer:not(.ds-overlay--start)):dir(rtl) {\n --ds-overlay-away: translateX(-100%);\n --ds-overlay-safe-side: env(safe-area-inset-left, 0px);\n inset: 0 auto 0 0;\n padding:\n calc(var(--ds-overlay-inner) + env(safe-area-inset-top, 0px))\n var(--ds-overlay-within)\n calc(var(--ds-overlay-inner) + env(safe-area-inset-bottom, 0px))\n calc(var(--ds-overlay-inner) + env(safe-area-inset-left, 0px));\n border-left: 0;\n}\n\n/* The page behind a native sheet or drawer holds still while it is open, as\n * the element holds it (the element saves and restores the scroll itself). */\n:root:has(dialog.ds-overlay:is(.ds-overlay--sheet, .ds-overlay--drawer):modal) {\n overflow: hidden;\n overscroll-behavior: none;\n}\n\n/* Out to its edge, a little quicker than it came; and in from it. */\n:is(ds-overlay > dialog[data-ds-edge], dialog.ds-overlay:is(.ds-overlay--sheet, .ds-overlay--drawer)):not([open]) {\n --ds-overlay-motion: var(--ds-overlay-exit, 260ms);\n transform: var(--ds-overlay-away);\n}\n\n@starting-style {\n :is(ds-overlay > dialog[data-ds-edge], dialog.ds-overlay:is(.ds-overlay--sheet, .ds-overlay--drawer))[open] {\n transform: var(--ds-overlay-away);\n }\n}\n\n:is(ds-overlay > dialog[data-ds-edge], dialog.ds-overlay:is(.ds-overlay--sheet, .ds-overlay--drawer))::backdrop {\n opacity: calc(1 - var(--ds-overlay-progress, 0));\n transition:\n opacity var(--ds-overlay-motion, 380ms) ease,\n overlay var(--ds-overlay-motion, 380ms) allow-discrete,\n display var(--ds-overlay-motion, 380ms) allow-discrete;\n}\n\n:is(ds-overlay > dialog[data-ds-edge], dialog.ds-overlay:is(.ds-overlay--sheet, .ds-overlay--drawer)):not([open])::backdrop {\n opacity: 0;\n}\n\n@starting-style {\n :is(ds-overlay > dialog[data-ds-edge], dialog.ds-overlay:is(.ds-overlay--sheet, .ds-overlay--drawer))[open]::backdrop {\n opacity: 0;\n }\n}\n\n/* While a finger holds it, it follows the finger alone. */\n:is(ds-overlay > dialog[data-ds-edge], dialog.ds-overlay:is(.ds-overlay--sheet, .ds-overlay--drawer))[data-ds-overlay-dragging],\n:is(ds-overlay > dialog[data-ds-edge], dialog.ds-overlay:is(.ds-overlay--sheet, .ds-overlay--drawer))[data-ds-overlay-dragging]::backdrop {\n transition: none;\n}\n\n/* Reduced motion: no slide. It fades where it stands, a dragged one too. */\n@media (prefers-reduced-motion: reduce) {\n :is(ds-overlay > dialog[data-ds-edge], dialog.ds-overlay:is(.ds-overlay--sheet, .ds-overlay--drawer)) {\n --ds-overlay-motion: 150ms;\n transition:\n opacity var(--ds-overlay-motion) ease,\n overlay var(--ds-overlay-motion) allow-discrete,\n display var(--ds-overlay-motion) allow-discrete;\n }\n\n :is(ds-overlay > dialog[data-ds-edge], dialog.ds-overlay:is(.ds-overlay--sheet, .ds-overlay--drawer)):not([open]) {\n --ds-overlay-motion: 150ms;\n transform: var(--ds-overlay-held);\n opacity: 0;\n }\n\n @starting-style {\n :is(ds-overlay > dialog[data-ds-edge], dialog.ds-overlay:is(.ds-overlay--sheet, .ds-overlay--drawer))[open] {\n transform: var(--ds-overlay-held);\n opacity: 0;\n }\n }\n}\n\n/*\n * The screen: an overlay over the whole screen, for navigation folded away on\n * a narrow screen (`ds-header`, `ds-page drawer`, `attachOverlay()`).\n *\n * The panel is the dialog frame (`dialog.ds-overlay`) laid over the whole\n * screen, on the page's own paper, a square of room on every side. Its first\n * row holds the close button where the menu button stood; what the page\n * folded away (its navigation and actions) follows, every link one square\n * high. The page script `0-face/attach-overlay.ts` opens it: it moves the folded parts\n * into the panel and back, keeps focus inside, closes on Escape, on a link and\n * when the screen widens, and holds the page's scroll while it is open.\n * `ds-header` and `ds-page drawer` use the same script and these rules.\n *\n * ds-overlay--screen on a <dialog class=\"ds-overlay\">, the panel\n * ds-overlay__bar the first row: the close button at its end\n * ds-overlay__close the close button, an icon button\n * ds-overlay__toggle the button that opens it: it carries\n * two icons, the first shown while closed and the\n * second (close) while open\n *\n * Tokens: `--ds-overlay-paper` (the page's paper by default).\n */\n\n:is(ds-overlay > dialog[data-ds-type=\"screen\"], dialog.ds-overlay.ds-overlay--screen) {\n --ds-overlay-width: 100vw;\n width: 100vw;\n max-width: none;\n height: 100dvh;\n max-height: none;\n margin: 0;\n padding: var(--ds-unit);\n gap: 0;\n border: 0;\n background: var(--ds-overlay-paper, var(--background, Canvas));\n overflow-y: auto;\n}\n\n:is(ds-overlay > dialog[data-ds-type=\"screen\"], dialog.ds-overlay.ds-overlay--screen)[open] {\n display: flex;\n flex-direction: column;\n align-items: stretch;\n gap: var(--ds-unit);\n}\n\n/* Content that supplies its own room, as the documentation's navigation does. */\n:is(ds-overlay > dialog[data-ds-type=\"screen\"], dialog.ds-overlay.ds-overlay--screen)[data-ds-overlay-flush] {\n padding: 0;\n gap: 0;\n}\n\n:is(ds-overlay > dialog[data-ds-type=\"screen\"], dialog.ds-overlay.ds-overlay--screen)::backdrop {\n background: transparent;\n}\n\n/* It arrives by fading in and settling half a square, and leaves at once. */\n@media (prefers-reduced-motion: no-preference) {\n :is(ds-overlay > dialog[data-ds-type=\"screen\"], dialog.ds-overlay.ds-overlay--screen)[open] {\n transition: opacity 160ms ease-out, transform 160ms ease-out;\n }\n\n @starting-style {\n :is(ds-overlay > dialog[data-ds-type=\"screen\"], dialog.ds-overlay.ds-overlay--screen)[open] {\n opacity: 0;\n transform: translateY(calc(var(--ds-unit) / -2));\n }\n }\n}\n\n.ds-overlay__bar {\n display: flex;\n align-items: center;\n justify-content: flex-end;\n min-height: var(--ds-row-height);\n}\n\n/* Centred in the last square of the row, as the menu button is. Two classes,\n so the button's own margin does not undo it. */\n.ds-overlay__bar > .ds-overlay__close {\n margin-inline-end: calc((var(--ds-unit) - var(--ds-control-height)) / 2);\n}\n\n/* The toggle shows its first icon while closed and its second while open; the\n close button, a copy of it, shows the second. */\n.ds-overlay__toggle:not([aria-expanded=\"true\"]) > :nth-child(2),\n.ds-overlay__toggle[aria-expanded=\"true\"] > :first-child:not(:only-child),\n.ds-overlay__close > :first-child:not(:only-child) {\n display: none;\n}\n/*\n * A site header, as plain classes on native elements.\n *\n * One row of one square, a square of room around it: the brand at the start\n * in twelve squares (as a page's navigation column is, so the links stand\n * over the work), the navigation two squares after it, the actions at the end. Every link is\n * one square high, a square apart, in the text's ink; the page you are on\n * (`aria-current=\"page\"`) stands on a hairline of the full ink, the others\n * show a faint one under the pointer. Below thirty squares of width the\n * navigation and the actions fold into a drawer: the menu button takes their\n * place at the end of the row, and `0-face/header.ts` opens them over the page.\n * The `ds-header` element draws the same parts.\n *\n * ds-header the row, a <header>\n * ds-header__brand the mark or name, a link home; a picture in it is one square high\n * ds-header__nav the links, a <nav>\n * ds-header__actions buttons or links at the end\n * ds-header__toggle the menu button: `.ds-button.ds-button--icon.ds-overlay__toggle`\n * with a menu icon and a close icon, shown only on a narrow screen\n * ds-header--sticky stays at the top of the page as it scrolls, on the paper\n *\n * Tokens: `--ds-header-brand` (the brand's width, at least twelve squares),\n * `--ds-header-paper` (the sticky header's paper) and `--ds-header-line` (the\n * hairline under a sticky header, none by default).\n */\n\n.ds-header {\n box-sizing: border-box;\n container-type: inline-size;\n display: flex;\n align-items: center;\n gap: calc(2 * var(--ds-unit));\n min-width: 0;\n margin: 0;\n padding: var(--ds-unit);\n color: var(--ds-text-color);\n font-family: var(--ds-typeface-regular);\n font-feature-settings: var(--ds-font-features);\n font-size: var(--ds-type-size-default);\n font-weight: var(--ds-type-weight-default);\n line-height: var(--ds-unit);\n letter-spacing: var(--ds-type-letterspacing-default);\n text-transform: none;\n}\n\n.ds-header--sticky {\n position: sticky;\n top: 0;\n z-index: 1;\n background: var(--ds-header-paper, var(--background, Canvas));\n box-shadow: inset 0 -1px var(--ds-header-line, transparent);\n}\n\n.ds-header__brand {\n box-sizing: border-box;\n display: inline-flex;\n flex: 0 0 auto;\n min-width: var(--ds-header-brand, calc(12 * var(--ds-unit)));\n align-items: center;\n gap: calc(var(--ds-unit) / 2);\n height: var(--ds-unit);\n color: inherit;\n font-family: var(--ds-typeface-medium);\n font-weight: var(--ds-type-weight-bold);\n text-decoration: none;\n white-space: nowrap;\n}\n\n.ds-header__brand :is(img, svg) {\n display: block;\n width: auto;\n height: var(--ds-unit);\n}\n\n.ds-header__nav,\n.ds-header__actions {\n display: flex;\n align-items: center;\n gap: var(--ds-unit);\n min-width: 0;\n margin: 0;\n padding: 0;\n}\n\n.ds-header__nav {\n flex: 1 1 auto;\n flex-wrap: wrap;\n row-gap: 0;\n}\n\n.ds-header__actions {\n flex: 0 0 auto;\n justify-content: flex-end;\n gap: calc(var(--ds-unit) / 2);\n margin-inline-start: auto;\n}\n\n/* A link in the navigation: the text's ink on a one-square line. */\n.ds-header__nav a {\n display: block;\n height: var(--ds-unit);\n color: inherit;\n text-decoration-line: underline;\n text-decoration-thickness: 1px;\n text-decoration-color: transparent;\n text-underline-offset: calc(2px * var(--ds-sf));\n white-space: nowrap;\n}\n\n.ds-header__nav a:hover {\n text-decoration-color: color-mix(in srgb, currentColor 40%, transparent);\n}\n\n.ds-header__nav a[aria-current]:not([aria-current=\"false\"]) {\n text-decoration-color: currentColor;\n}\n\n.ds-header__nav a:focus-visible,\n.ds-header__brand:focus-visible {\n outline: 2px solid var(--ds-focus-ring);\n outline-offset: 1px;\n}\n\n/* The menu button stands at the end of the row, and only on a narrow screen.\n Two classes, so the button's own display and margin do not undo it. */\n.ds-header > .ds-header__toggle {\n display: none;\n margin-inline-start: auto;\n /* Centred in the last square of the row, where the close button stands too. */\n margin-inline-end: calc((var(--ds-unit) - var(--ds-control-height)) / 2);\n}\n\n@container (max-width: 599px) {\n .ds-header > :is(.ds-header__nav, .ds-header__actions) {\n display: none;\n }\n\n .ds-header > .ds-header__toggle {\n display: inline-flex;\n }\n\n .ds-header > .ds-header__brand {\n min-width: 0;\n }\n}\n\n/* In the drawer the navigation is a column of one-square links, and the\n actions a row one square below it. */\n.ds-overlay--screen :is(.ds-header__nav, .ds-header__actions) {\n flex: 0 0 auto;\n flex-direction: column;\n align-items: flex-start;\n flex-wrap: nowrap;\n gap: 0;\n margin: 0;\n}\n\n.ds-overlay--screen .ds-header__actions {\n flex-direction: row;\n flex-wrap: wrap;\n gap: calc(var(--ds-unit) / 2);\n}\n/*\n * A site footer, as plain classes on native elements.\n *\n * The brand and its line at the start, twelve squares wide; the columns of\n * links beside it, eight squares each, two squares apart; then, two squares\n * below, the legal line at the start and the preferences (language and theme,\n * as `ds-cycle` or native buttons) at the end. Every line is one square, the\n * column headings in the title grey, the links in the text's ink with a faint\n * hairline under the pointer. A hairline runs along its top. Columns that do\n * not fit beside the brand go below it, and on a narrow screen everything\n * stands in one column. The `ds-footer` element draws the same parts from data.\n *\n * ds-footer the block, a <footer>\n * ds-footer__brand the mark and its line\n * ds-footer__mark the mark or name, a link home; a picture in it is one square high\n * ds-footer__tagline a line about the site, muted\n * ds-footer__columns the columns, a <nav> or <div>\n * ds-footer__column one column: a heading and its links\n * ds-footer__heading the column's heading, one line in the title grey\n * ds-footer__links the links, a <ul> with one link per <li>\n * ds-footer__base the last row, two squares below\n * ds-footer__legal in it, the copyright and legal line, muted\n * ds-footer__preferences in it, the language and theme controls, at its end\n *\n * Tokens: `--ds-footer-line` (the hairline along the top).\n */\n\n.ds-footer {\n box-sizing: border-box;\n container-type: inline-size;\n display: flex;\n flex-wrap: wrap;\n align-items: flex-start;\n gap: calc(2 * var(--ds-unit));\n min-width: 0;\n margin: 0;\n padding: calc(2 * var(--ds-unit)) var(--ds-unit) var(--ds-unit);\n box-shadow: inset 0 1px var(--ds-footer-line, var(--ds-border-color));\n color: var(--ds-text-color);\n font-family: var(--ds-typeface-regular);\n font-feature-settings: var(--ds-font-features);\n font-size: var(--ds-type-size-default);\n font-weight: var(--ds-type-weight-default);\n line-height: var(--ds-unit);\n letter-spacing: var(--ds-type-letterspacing-default);\n text-transform: none;\n}\n\n.ds-footer :is(p, h2, h3, h4, ul) {\n margin: 0;\n font: inherit;\n letter-spacing: inherit;\n}\n\n.ds-footer__brand {\n display: flex;\n flex: 0 0 calc(12 * var(--ds-unit));\n flex-direction: column;\n max-width: 100%;\n min-width: 0;\n}\n\n.ds-footer__mark {\n display: inline-flex;\n align-items: center;\n gap: calc(var(--ds-unit) / 2);\n align-self: flex-start;\n height: var(--ds-unit);\n color: inherit;\n font-family: var(--ds-typeface-medium);\n font-weight: var(--ds-type-weight-bold);\n text-decoration: none;\n}\n\n.ds-footer__mark :is(img, svg) {\n display: block;\n width: auto;\n height: var(--ds-unit);\n}\n\n.ds-footer__tagline,\n.ds-footer__legal {\n color: var(--ds-text-color-muted);\n}\n\n.ds-footer__columns {\n display: flex;\n /* Never narrower than one column: below that the columns go under the brand. */\n flex: 1 1 calc(8 * var(--ds-unit));\n flex-wrap: wrap;\n gap: var(--ds-unit) calc(2 * var(--ds-unit));\n min-width: min(100%, calc(8 * var(--ds-unit)));\n}\n\n.ds-footer__column {\n display: flex;\n flex: 0 0 calc(8 * var(--ds-unit));\n flex-direction: column;\n max-width: 100%;\n min-width: 0;\n}\n\n.ds-footer .ds-footer__heading {\n color: var(--ds-title-color);\n}\n\n.ds-footer .ds-footer__links {\n padding: 0;\n list-style: none;\n}\n\n.ds-footer__links li {\n margin: 0;\n padding: 0;\n}\n\n.ds-footer__links a {\n display: inline-block;\n max-width: 100%;\n overflow: hidden;\n color: inherit;\n text-decoration-line: underline;\n text-decoration-thickness: 1px;\n text-decoration-color: transparent;\n text-overflow: ellipsis;\n text-underline-offset: calc(2px * var(--ds-sf));\n vertical-align: top;\n white-space: nowrap;\n}\n\n.ds-footer__links a:hover {\n text-decoration-color: color-mix(in srgb, currentColor 40%, transparent);\n}\n\n.ds-footer__links a[aria-current]:not([aria-current=\"false\"]) {\n text-decoration-color: currentColor;\n}\n\n:is(.ds-footer__links a, .ds-footer__mark):focus-visible {\n outline: 2px solid var(--ds-focus-ring);\n outline-offset: 1px;\n}\n\n/* The last row, two squares below: the legal line at the start, the\n preferences at the end; on a narrow screen the preferences go first. */\n.ds-footer__base {\n display: flex;\n flex: 0 0 100%;\n flex-wrap: wrap;\n align-items: flex-start;\n gap: var(--ds-unit) calc(2 * var(--ds-unit));\n min-width: 0;\n}\n\n.ds-footer__legal {\n flex: 1 1 auto;\n min-width: 0;\n}\n\n.ds-footer__preferences {\n display: flex;\n flex: 0 0 auto;\n flex-wrap: wrap;\n align-items: center;\n gap: 0 calc(var(--ds-unit) / 2);\n min-height: var(--ds-unit);\n margin-inline-start: auto;\n}\n\n@container (max-width: 599px) {\n .ds-footer__brand,\n .ds-footer__columns {\n flex-basis: 100%;\n }\n\n .ds-footer__base {\n flex-direction: column;\n }\n\n .ds-footer__preferences {\n order: -1;\n margin-inline-start: 0;\n }\n}\n/*\n * A document page: terms, a privacy policy, a legal notice, a help article.\n *\n * The contents stand at the start, twelve squares wide, and stay in view as\n * the writing scrolls past; the writing, two squares after them, is a reading\n * column of at most thirty-two squares, native headings and paragraphs marked\n * `data-ds-prose` (prose.css draws them). Where the two do not fit side by\n * side the contents stand above the writing. Every line is one square; the\n * contents' links are in the text's ink, the section in view (`aria-current`)\n * on a hairline of the full ink, a third level half a square in. The\n * `ds-document` element builds the contents from the headings and marks the\n * one in view.\n *\n * ds-document the page's two columns\n * ds-document__toc the contents, a <nav>, as tall as the writing\n * ds-document__contents inside it, what stays in view: the title and the list\n * ds-document__toc-title \"Contents\", one line in the title grey\n * ds-document__toc-list the links, an <ol> with one link per <li>\n * ds-document__toc-sub an <li> for a third-level heading\n * ds-document__body the writing, marked data-ds-prose\n *\n * A definition table (`ds-definitions` on a <dl>) sets terms beside what they\n * mean, as a legal notice such as 特定商取引法に基づく表記 does: the term eight\n * squares wide in the muted ink, its definition beside it, each pair on a\n * hairline at its foot with half a square above and below, as a prose table's\n * rows are. Pairs may stand in a <div> each. Below twenty-four squares the\n * definition goes under its term. It works inside or outside prose.\n *\n * Tokens: `--ds-document-top` (where the contents stop below the top of the\n * view, one square; add a sticky header's height), `--ds-definitions-term`\n * (the term column, eight squares).\n */\n\n.ds-document {\n box-sizing: border-box;\n display: flex;\n flex-wrap: wrap;\n align-items: stretch;\n gap: var(--ds-unit) calc(2 * var(--ds-unit));\n min-width: 0;\n color: var(--ds-text-color);\n font-family: var(--ds-typeface-regular);\n font-feature-settings: var(--ds-font-features);\n font-size: var(--ds-type-size-default);\n font-weight: var(--ds-type-weight-default);\n line-height: var(--ds-unit);\n letter-spacing: var(--ds-type-letterspacing-default);\n}\n\n/* The contents column stretches to the writing's height when the two stand\n side by side, so what is inside it can stay in view; standing above the\n writing it is only as tall as itself, and nothing sticks. */\n.ds-document__toc {\n flex: 0 0 calc(12 * var(--ds-unit));\n max-width: 100%;\n min-width: 0;\n}\n\n.ds-document__contents {\n position: sticky;\n top: var(--ds-document-top, var(--ds-unit));\n}\n\n.ds-document__toc-title {\n margin: 0;\n color: var(--ds-title-color);\n font: inherit;\n letter-spacing: inherit;\n}\n\n.ds-document__toc-list,\n.ds-document__toc-list ol {\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.ds-document__toc-list li {\n margin: 0;\n padding: 0;\n}\n\n.ds-document__toc-list .ds-document__toc-sub {\n padding-inline-start: calc(var(--ds-unit) / 2);\n}\n\n.ds-document__toc-list a {\n display: block;\n overflow: hidden;\n color: inherit;\n text-decoration-line: underline;\n text-decoration-thickness: 1px;\n text-decoration-color: transparent;\n text-overflow: ellipsis;\n text-underline-offset: calc(2px * var(--ds-sf));\n white-space: nowrap;\n}\n\n.ds-document__toc-list a:hover {\n text-decoration-color: color-mix(in srgb, currentColor 40%, transparent);\n}\n\n.ds-document__toc-list a[aria-current]:not([aria-current=\"false\"]) {\n text-decoration-color: currentColor;\n}\n\n.ds-document__toc-list a:focus-visible {\n outline: 2px solid var(--ds-focus-ring);\n outline-offset: -1px;\n}\n\n/* The writing: at least twenty squares beside the contents, else below them. */\n.ds-document__body {\n flex: 1 1 0;\n min-width: min(100%, calc(20 * var(--ds-unit)));\n max-width: calc(32 * var(--ds-unit));\n}\n\n/* A heading the contents jump to stops where the contents do. */\n.ds-document__body :is(h1, h2, h3, h4, h5, h6) {\n scroll-margin-top: var(--ds-document-top, var(--ds-unit));\n}\n\n/* A definition table. */\n\n.ds-definitions {\n box-sizing: border-box;\n container-type: inline-size;\n display: grid;\n grid-template-columns: minmax(0, var(--ds-definitions-term, calc(8 * var(--ds-unit)))) minmax(0, 1fr);\n margin: 0;\n padding: 0;\n color: var(--ds-text-color);\n font-family: var(--ds-typeface-regular);\n font-size: var(--ds-type-size-default);\n line-height: var(--ds-unit);\n letter-spacing: var(--ds-type-letterspacing-default);\n}\n\n.ds-definitions > div {\n display: contents;\n}\n\n.ds-definitions :is(dt, dd) {\n box-sizing: border-box;\n min-width: 0;\n margin: 0;\n padding-block: calc(var(--ds-unit) / 2);\n box-shadow: inset 0 -1px var(--ds-border-color);\n font: inherit;\n letter-spacing: inherit;\n line-height: var(--ds-unit);\n overflow-wrap: anywhere;\n}\n\n.ds-definitions dt {\n grid-column: 1;\n padding-inline-end: calc(var(--ds-unit) / 2);\n color: var(--ds-text-color-muted);\n}\n\n.ds-definitions dd {\n grid-column: 2;\n}\n\n@container (max-width: 479px) {\n .ds-definitions dt,\n .ds-definitions dd {\n grid-column: 1 / -1;\n }\n\n .ds-definitions dt {\n padding-block-end: 0;\n padding-inline-end: 0;\n box-shadow: none;\n }\n\n .ds-definitions dd {\n padding-block-start: 0;\n }\n}\n/*\n * A bento, as plain classes on native elements: tiles of different sizes\n * standing half a square (10px) apart, each a card (`.ds-card`, or any box)\n * that holds one thing. The `ds-bento` element draws the same.\n *\n * Flow (the default): columns that share the width (`--ds-bento-columns`,\n * three), a tile one column wide or more (`data-span`, or\n * `--ds-bento-span`) and one row high or more (`data-rows`, or\n * `--ds-bento-rows`); a row is as high as its tallest tile, at least\n * `--ds-bento-row` (ten squares by default). Below thirty squares of width\n * the bento is one column.\n *\n * Squares (`data-squares`): the bento is exactly `--ds-bento-columns` squares wide\n * and every tile is placed on whole squares (`data-place=\"x y w h\"`,\n * counted from 0). Tiles are placed a square apart, and a tile's surface\n * reaches a quarter square towards each tile beside it, so they stand half a\n * square apart while what they hold stays on the squares, and the bento's\n * own edges stay on the page's. `placeBento()` (0-face/bento.ts) reads the\n * places and sets the reach; the element does it itself.\n *\n * data-span=\"2\" a tile two columns wide (to 6)\n * data-rows=\"2\" a tile two rows high (to 6)\n * data-place=\"0 0 15 7\" a tile's square, width and height in squares\n *\n * Tokens: `--ds-bento-gap` (half a square), `--ds-bento-columns`,\n * `--ds-bento-row`, and on a tile `--ds-bento-span`, `--ds-bento-rows`.\n */\n\n.ds-bento {\n --ds-bento-gap: calc(var(--ds-unit) / 2);\n box-sizing: border-box;\n display: grid;\n grid-template-columns: repeat(var(--ds-bento-columns, 3), minmax(0, 1fr));\n grid-auto-rows: minmax(var(--ds-bento-row, calc(10 * var(--ds-unit))), auto);\n grid-auto-flow: row dense;\n gap: var(--ds-bento-gap);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n.ds-bento[hidden] { display: none; }\n\n.ds-bento > * {\n --ds-card-width: auto;\n --ds-card-height: auto;\n box-sizing: border-box;\n min-width: 0;\n min-height: 0;\n grid-column: span var(--ds-bento-span, 1);\n grid-row: span var(--ds-bento-rows, 1);\n}\n.ds-bento > [data-span=\"2\"] { --ds-bento-span: 2; }\n.ds-bento > [data-span=\"3\"] { --ds-bento-span: 3; }\n.ds-bento > [data-span=\"4\"] { --ds-bento-span: 4; }\n.ds-bento > [data-span=\"5\"] { --ds-bento-span: 5; }\n.ds-bento > [data-span=\"6\"] { --ds-bento-span: 6; }\n.ds-bento > [data-rows=\"2\"] { --ds-bento-rows: 2; }\n.ds-bento > [data-rows=\"3\"] { --ds-bento-rows: 3; }\n.ds-bento > [data-rows=\"4\"] { --ds-bento-rows: 4; }\n.ds-bento > [data-rows=\"5\"] { --ds-bento-rows: 5; }\n.ds-bento > [data-rows=\"6\"] { --ds-bento-rows: 6; }\n\n@media (max-width: 600px) {\n .ds-bento:not([data-squares]) { grid-template-columns: minmax(0, 1fr); }\n .ds-bento:not([data-squares]) > * { grid-column: auto; }\n}\n\n/* Squares: every tile on whole squares, a square apart, its surface a quarter square nearer each neighbour. */\n.ds-bento[data-squares] {\n --ds-bento-reach: calc(var(--ds-unit) / 4);\n /* Exactly its squares wide: each column one square. */\n width: calc(var(--ds-bento-columns, 48) * var(--ds-unit));\n max-width: none;\n grid-template-columns: repeat(var(--ds-bento-columns, 48), var(--ds-unit));\n grid-auto-rows: var(--ds-unit);\n grid-auto-flow: row;\n gap: 0;\n}\n.ds-bento[data-squares] > * {\n --ds-bento-inset-top: calc(var(--ds-bento-reach) * var(--ds-bento-top, 0));\n --ds-bento-inset-end: calc(var(--ds-bento-reach) * var(--ds-bento-end, 0));\n --ds-bento-inset-bottom: calc(var(--ds-bento-reach) * var(--ds-bento-bottom, 0));\n --ds-bento-inset-start: calc(var(--ds-bento-reach) * var(--ds-bento-start, 0));\n grid-column: calc(var(--ds-bento-x, 0) + 1) / span var(--ds-bento-w, 4);\n grid-row: calc(var(--ds-bento-y, 0) + 1) / span var(--ds-bento-h, 4);\n margin: calc(-1 * var(--ds-bento-inset-top)) calc(-1 * var(--ds-bento-inset-end)) calc(-1 * var(--ds-bento-inset-bottom)) calc(-1 * var(--ds-bento-inset-start));\n}\n/* A card grows its own padding by the reach (card.css); any other tile is padded here, a square inside. */\n.ds-bento[data-squares] > :not(.ds-card, ds-card) {\n padding:\n calc(var(--ds-unit) + var(--ds-bento-inset-top))\n calc(var(--ds-unit) + var(--ds-bento-inset-end))\n calc(var(--ds-unit) + var(--ds-bento-inset-bottom))\n calc(var(--ds-unit) + var(--ds-bento-inset-start));\n}\n/*\n * A carousel, as plain classes on native elements.\n *\n * A carousel is a row of slides that snaps sideways, one slide to a stop,\n * with a row of controls one square high under it: optional previous and\n * next buttons and a dot for each slide. Slides are the track's width, or\n * whole squares wide, a whole number of squares apart (one by default). The\n * controls stand one square below the track, on the grid from its start.\n * The `ds-carousel` element draws the same parts, and\n * `0-face/carousel.ts` gives the native markup its behaviour.\n *\n * ds-carousel the region: track, controls, status;\n * `data-slides=\"auto\"` for slides of their\n * own width, `data-bleed` `end` or `both`,\n * `data-snap=\"none\"` to slide freely\n * ds-carousel__track the scroller; every child is a slide\n * ds-carousel__controls the row of buttons and dots\n * ds-carousel__previous, __next, icon buttons, on `.ds-button.ds-button--icon`\n * __pause\n * ds-carousel__status the polite announcement, kept out of sight\n *\n * The dots are `ds-progress--dots` from progress.css.\n *\n * A strip of slides of their own width can run on past its box to the\n * window's end edge, or to both edges, while its first slide keeps to the\n * box's start, so it lines up with the page's column; `--ds-carousel-before`\n * and `--ds-carousel-after` are the room to the edges, which the script\n * measures.\n *\n * Tokens: `--ds-carousel-slide` (a slide's width, the track's by default)\n * and `--ds-carousel-gap` (between slides, one square by default).\n */\n\n.ds-carousel {\n box-sizing: border-box;\n display: grid;\n grid-template-columns: minmax(0, 1fr);\n row-gap: var(--ds-unit);\n position: relative;\n min-width: 0;\n margin: 0;\n}\n\n.ds-carousel__track {\n box-sizing: border-box;\n display: grid;\n grid-auto-flow: column;\n grid-auto-columns: var(--ds-carousel-slide, 100%);\n column-gap: var(--ds-carousel-gap, var(--ds-unit));\n min-width: 0;\n margin: 0;\n padding: 0;\n list-style: none;\n overflow-x: auto;\n overflow-y: hidden;\n overscroll-behavior-x: contain;\n scroll-snap-type: x mandatory;\n scrollbar-width: none;\n}\n\n.ds-carousel__track::-webkit-scrollbar {\n display: none;\n}\n\n/* Slides of their own width, several in view. */\n.ds-carousel[data-slides=\"auto\"] > .ds-carousel__track {\n grid-auto-columns: max-content;\n}\n\n.ds-carousel[data-snap=\"none\"] > .ds-carousel__track {\n scroll-snap-type: none;\n}\n\n/* To the window's end edge: the track reaches out over the room after the\n box and keeps a gap at its end, so the last slide stops short of the edge. */\n.ds-carousel[data-bleed=\"end\"] > .ds-carousel__track {\n margin-inline-end: calc(-1 * var(--ds-carousel-after, 0px));\n padding-inline-end: var(--ds-carousel-gap, var(--ds-unit));\n}\n\n/* To both edges: the track reaches out both ways, and the first slide, and\n each one it stops at, still stands on the box's start. */\n.ds-carousel[data-bleed=\"both\"] > .ds-carousel__track {\n margin-inline: calc(-1 * var(--ds-carousel-before, 0px)) calc(-1 * var(--ds-carousel-after, 0px));\n padding-inline: var(--ds-carousel-before, 0px) var(--ds-carousel-gap, var(--ds-unit));\n scroll-padding-inline-start: var(--ds-carousel-before, 0px);\n}\n\n.ds-carousel__track:focus-visible {\n outline: 2px solid var(--ds-focus-ring);\n outline-offset: 1px;\n}\n\n.ds-carousel__track > * {\n box-sizing: border-box;\n min-width: 0;\n margin: 0;\n scroll-snap-align: start;\n}\n\n/* One slide to a stop; a strip of several in view may pass a few. */\n.ds-carousel:not([data-slides=\"auto\"]) > .ds-carousel__track > * {\n scroll-snap-stop: always;\n}\n\n.ds-carousel__controls {\n display: flex;\n align-items: center;\n height: var(--ds-row-height);\n min-width: 0;\n}\n\n/* The buttons take a one-square cell each, as the dots do. Two classes, so\n the button's own reset of its margin does not undo it. */\n.ds-carousel .ds-carousel__previous,\n.ds-carousel .ds-carousel__next,\n.ds-carousel .ds-carousel__pause {\n flex: none;\n margin: calc((var(--ds-unit) - var(--ds-control-height)) / 2);\n}\n\n/* Previous points back along the reading direction. */\n.ds-carousel:dir(rtl) :is(.ds-carousel__previous, .ds-carousel__next) > * {\n transform: scaleX(-1);\n}\n\n.ds-carousel__status {\n position: absolute;\n width: 1px;\n height: 1px;\n overflow: hidden;\n clip-path: inset(50%);\n white-space: nowrap;\n}\n/*\n * A card, as plain classes on native elements.\n *\n * A card holds one thing on a fill of its own: its name in the muted ink on\n * one square, a title in the display size on lines of a square and a half, writing,\n * and a picture of it (`ds-card__media`) a square below, which can run off\n * the card's foot and end edge and be cut there, never framed. Its size is\n * given in whole squares, its padding one square, its corners a card's\n * (`--ds-radius-card`). A card that opens something is one press target, an\n * `<a class=\"ds-card\" href>`: the pointer tints it, keyboard focus rings it\n * 2px inside and its picture rises a little. Ordinary writing still sits\n * straight on the paper; a card is for a thing shown among others, as in a\n * slide. The `ds-card` element draws the same parts.\n *\n * ds-card the card; `data-tone` names a palette colour\n * for its fill (the colour's pastel, dim in dark\n * mode, from palette.css, which one.css imports),\n * `ink` for the ink with the paper's words\n * ds-card--outlined a 1px line and no fill\n * ds-card__label its name, muted, on one square\n * ds-card__title the title, display size, a square and a half a line\n * ds-card__body writing, one square a line\n * ds-card__media the picture, a square below the words\n * ds-card__media--center standing in the card's middle\n * ds-card__media--bleed running on past the padding to the end edge\n *\n * Tokens: `--ds-card-width` and `--ds-card-height` (whole squares; the\n * content's size by default), `--ds-card-padding` (one square), and\n * `--ds-card-fill`, `--ds-card-ink` and `--ds-card-muted`.\n */\n\n.ds-card {\n --ds-card-fill: var(--ds-fill);\n --ds-card-ink: var(--ds-text-color);\n --ds-card-muted: var(--ds-text-color-muted);\n --ds-card-padding: var(--ds-unit);\n position: relative;\n box-sizing: border-box;\n display: flex;\n flex-direction: column;\n align-items: stretch;\n width: var(--ds-card-width, auto);\n height: var(--ds-card-height, auto);\n min-width: 0;\n margin: 0;\n /* In a squares bento the surface reaches a quarter square towards its neighbours (`--ds-bento-inset-*`, 0 elsewhere), and the padding grows by as much so what it holds stays on the squares. */\n padding:\n calc(var(--ds-card-padding) + var(--ds-bento-inset-top, 0px))\n calc(var(--ds-card-padding) + var(--ds-bento-inset-end, 0px))\n var(--ds-bento-inset-bottom, 0px)\n calc(var(--ds-card-padding) + var(--ds-bento-inset-start, 0px));\n overflow: hidden;\n border-radius: var(--ds-radius-card);\n background: var(--ds-card-fill);\n color: var(--ds-card-ink);\n font-family: var(--ds-typeface-regular);\n font-size: var(--ds-type-size-default);\n text-decoration: none;\n -webkit-tap-highlight-color: transparent;\n}\n\n.ds-card[hidden] {\n display: none;\n}\n\n.ds-card--outlined {\n --ds-card-fill: transparent;\n box-shadow: inset 0 0 0 1px var(--ds-border-color);\n}\n\n.ds-card[data-tone=\"apple-green\"] { --ds-card-fill: var(--one-apple-green-pastel); }\n.ds-card[data-tone=\"chartreuse\"] { --ds-card-fill: var(--one-chartreuse-pastel); }\n.ds-card[data-tone=\"every-green\"] { --ds-card-fill: var(--one-every-green-pastel); }\n.ds-card[data-tone=\"yellow\"] { --ds-card-fill: var(--one-yellow-pastel); }\n.ds-card[data-tone=\"orange\"] { --ds-card-fill: var(--one-orange-pastel); }\n.ds-card[data-tone=\"tuned-red\"] { --ds-card-fill: var(--one-tuned-red-pastel); }\n.ds-card[data-tone=\"pink\"] { --ds-card-fill: var(--one-pink-pastel); }\n.ds-card[data-tone=\"sharp-blue\"] { --ds-card-fill: var(--one-sharp-blue-pastel); }\n.ds-card[data-tone=\"winning-blue\"] { --ds-card-fill: var(--one-winning-blue-pastel); }\n.ds-card[data-tone=\"hysteric-blue\"] { --ds-card-fill: var(--one-hysteric-blue-pastel); }\n.ds-card[data-tone=\"purple\"] { --ds-card-fill: var(--one-purple-pastel); }\n.ds-card[data-tone=\"metal-green\"] { --ds-card-fill: var(--one-metal-green-pastel); }\n.ds-card[data-tone=\"drip-yellow\"] { --ds-card-fill: var(--one-drip-yellow-pastel); }\n.ds-card[data-tone=\"sand\"] { --ds-card-fill: var(--one-sand-pastel); }\n.ds-card[data-tone=\"old-gold\"] { --ds-card-fill: var(--one-old-gold-pastel); }\n.ds-card[data-tone=\"red-for-blood\"] { --ds-card-fill: var(--one-red-for-blood-pastel); }\n.ds-card[data-tone=\"dark-red-variant\"] { --ds-card-fill: var(--one-dark-red-variant-pastel); }\n.ds-card[data-tone=\"signal-red\"] { --ds-card-fill: var(--one-signal-red-pastel); }\n.ds-card[data-tone=\"ink\"] {\n --ds-card-fill: var(--ds-black);\n --ds-card-ink: var(--ds-white);\n --ds-card-muted: color-mix(in srgb, var(--ds-white) 60%, transparent);\n box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--ds-white) 8%, transparent);\n}\n\n/* Words: each line on the lower sixteen of its square. They keep their room\n in a card of a set height; only the picture is cut at the foot. */\n.ds-card__label,\n.ds-card__title,\n.ds-card__body {\n flex: none;\n}\n\n.ds-card__label {\n margin: 0;\n padding-top: calc(4px * var(--ds-sf, 1));\n color: var(--ds-card-muted);\n font: inherit;\n line-height: var(--ds-type-lineheight-default, calc(16px * var(--ds-sf, 1)));\n}\n\n.ds-card__title {\n margin: 0;\n color: var(--ds-card-ink);\n font-family: var(--ds-typeface-medium);\n font-size: var(--ds-type-size-display);\n font-weight: var(--ds-type-weight-bold);\n /* A title that wraps keeps its lines together: a square and a half each. */\n line-height: calc(1.5 * var(--ds-unit));\n letter-spacing: calc(var(--ds-display-text-tracking, -0.4px) * var(--ds-sf, 1));\n text-wrap: balance;\n}\n\n.ds-card__body {\n margin: 0;\n line-height: var(--ds-unit);\n}\n\n.ds-card__media {\n display: flex;\n flex: none;\n align-items: flex-start;\n justify-content: flex-start;\n min-width: 0;\n margin-top: var(--ds-unit);\n}\n\n.ds-card__media--center {\n justify-content: center;\n margin-inline: calc(-1 * var(--ds-card-padding));\n}\n\n.ds-card__media--bleed {\n margin-inline-end: calc(-1 * var(--ds-card-padding));\n}\n\n.ds-card__media > * {\n flex: none;\n}\n\n/* A card that opens something. */\na.ds-card,\n.ds-card[data-interactive] {\n cursor: pointer;\n}\n\na.ds-card::after,\n.ds-card[data-interactive]::after {\n content: \"\";\n position: absolute;\n inset: 0;\n border-radius: inherit;\n background: transparent;\n pointer-events: none;\n}\n\na.ds-card:focus-visible,\n.ds-card[data-interactive]:focus-visible {\n outline: 2px solid var(--ds-focus-ring);\n outline-offset: -2px;\n}\n\n@media (hover: hover) {\n a.ds-card:hover::after,\n .ds-card[data-interactive]:hover::after {\n background: color-mix(in srgb, var(--ds-card-ink) 4%, transparent);\n }\n}\n\na.ds-card:active::after,\n.ds-card[data-interactive]:active::after {\n background: color-mix(in srgb, var(--ds-card-ink) 8%, transparent);\n}\n\n@media (hover: hover) and (prefers-reduced-motion: no-preference) {\n a.ds-card > .ds-card__media,\n .ds-card[data-interactive] > .ds-card__media {\n transition: transform 240ms cubic-bezier(0.23, 1, 0.32, 1);\n }\n\n a.ds-card:hover > .ds-card__media,\n .ds-card[data-interactive]:hover > .ds-card__media {\n transform: translateY(calc(-0.25 * var(--ds-unit)));\n }\n}\n/*\n * Figures, as plain classes on native elements: a stat and a group of stats.\n * The `ds-stat` element draws the same parts; controls.css imports this\n * file. A value against its range, steps and page dots are `progress.css`.\n *\n * Everything sits on the paper with no box, every line is one square and\n * widths come in whole squares. Colour is kept for a state: the danger colour\n * for a figure that is over.\n *\n * A stat: a label, a figure and a line for its change or caption.\n *\n * ds-stat the block, as wide as its column\n * ds-stat__label one line, muted; an icon may lead it on its own square\n * ds-stat__icon the square an icon from the library stands on\n * ds-stat__figure the figure in tabular numerals, 20 on two squares\n * ds-stat__digit one digit in a cell of one width, for a face without tabular numerals\n * ds-stat__caption one line, muted, under the figure\n * ds-stat__change the change at the start of the caption, in the text colour;\n * --danger or --warning where the page knows which way is bad\n * ds-stat--danger, --warning the figure in that colour\n * ds-stats a group of stats on whole squares: columns eight\n * squares wide, one square between them and between rows\n *\n * Tokens: `--ds-stat-size` (the figure's type size before the scale, 20px)\n * and `--ds-stat-lines` (the squares its line takes, 2), `--ds-stat-typeface`\n * (the medium face), `--ds-stat-digit` (a digit cell's width, 1ch),\n * `--ds-stat-change-color`, and `--ds-stats-width` (a column's width in\n * squares, 8).\n *\n */\n\n/* ---- Stat ------------------------------------------------------------ */\n\n.ds-stat {\n box-sizing: border-box;\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n min-width: 0;\n margin: 0;\n color: var(--ds-text-color);\n font-family: var(--ds-typeface-regular);\n font-feature-settings: var(--ds-font-features);\n font-size: var(--ds-type-size-default);\n font-weight: var(--ds-type-weight-default);\n line-height: var(--ds-unit);\n letter-spacing: var(--ds-type-letterspacing-default);\n text-transform: none;\n}\n\n.ds-stat__label,\n.ds-stat__figure,\n.ds-stat__caption {\n box-sizing: border-box;\n max-width: 100%;\n margin: 0;\n font: inherit;\n letter-spacing: inherit;\n}\n\n.ds-stat__label,\n.ds-stat__caption {\n display: flex;\n align-items: flex-start;\n min-height: var(--ds-unit);\n color: var(--ds-text-color-muted);\n overflow-wrap: anywhere;\n}\n\n.ds-stat__icon {\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n width: var(--ds-unit);\n height: var(--ds-unit);\n}\n\n.ds-stat__figure {\n display: block;\n overflow: hidden;\n font-family: var(--ds-stat-typeface, var(--ds-typeface-medium));\n font-size: calc(var(--ds-stat-size, var(--ds-display-text-size, 20px)) * var(--ds-sf, 1));\n font-weight: var(--ds-type-weight-bold);\n font-variant-numeric: tabular-nums;\n line-height: calc(var(--ds-stat-lines, 2) * var(--ds-unit));\n min-height: calc(var(--ds-stat-lines, 2) * var(--ds-unit));\n letter-spacing: calc(var(--ds-display-text-tracking, -0.4px) * var(--ds-sf, 1));\n white-space: nowrap;\n text-overflow: ellipsis;\n}\n\n.ds-stat__digit {\n display: inline-block;\n width: var(--ds-stat-digit, 1ch);\n text-align: center;\n}\n\n.ds-stat--danger .ds-stat__figure {\n color: var(--ds-danger-color);\n}\n\n.ds-stat--warning .ds-stat__figure {\n color: var(--ds-warning-color);\n}\n\n.ds-stat__change {\n display: inline-flex;\n flex: none;\n align-items: center;\n height: var(--ds-unit);\n margin-inline-end: calc(4px * var(--ds-sf, 1));\n color: var(--ds-stat-change-color, var(--ds-text-color));\n font-variant-numeric: tabular-nums;\n white-space: nowrap;\n}\n\n.ds-stat__change--danger {\n --ds-stat-change-color: var(--ds-danger-color);\n}\n\n.ds-stat__change--warning {\n --ds-stat-change-color: var(--ds-warning-color);\n}\n\n.ds-stats {\n box-sizing: border-box;\n display: grid;\n grid-template-columns: repeat(auto-fill, min(100%, calc(var(--ds-stats-width, 8) * var(--ds-unit))));\n gap: var(--ds-unit);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.ds-stats > li {\n min-width: 0;\n margin: 0;\n}\n/*\n * Progress, as plain classes on native elements: a value against its range,\n * a sequence of steps, or a dot for each page. The `ds-progress` element\n * draws the same parts; controls.css imports this file.\n *\n * Everything sits on the paper with no box, every line is one square and\n * widths come in whole squares. Colour is kept for a state: the danger colour\n * for a value that is over or a step that failed, the ink for the current\n * step and the current dot.\n *\n * A value against its range, one square high (HTML's <progress>):\n *\n * ds-progress the row; role=\"meter\" with aria-valuenow, -min, -max and -valuetext\n * ds-progress__fill the bar, half a square high, drawn to --ds-progress-value (0 to 1)\n * ds-progress--squares the range in squares instead, each one square\n * ds-progress__square one square of the range; --on when it is filled\n * ds-progress--over past the end: filled whole in the danger colour\n *\n * Tokens: `--ds-progress-value`, `--ds-progress-color` (the ink by default)\n * and `--ds-progress-track` (the grey fill).\n *\n * A sequence of steps, one square high, each step on whole squares:\n *\n * ds-progress--steps with ds-progress, on an <ol>; the steps on one row, joined by a line\n * ds-progress--vertical one step to a row, each with room for its body under it\n * ds-progress__step an <li>; aria-current=\"step\" on the current one\n * ds-progress__step--done, --current, --failed states; upcoming without one\n * ds-progress__link a step that goes somewhere: an <a href> around its mark and label\n * ds-progress__mark the number (or the done or failed icon), one control high\n * ds-progress__label the step's name on one line\n * ds-progress__state the state in words for assistive technology, hidden (\"Done\")\n * ds-progress__body what belongs under a step in a vertical sequence\n *\n * A dot for each page, one square each:\n *\n * ds-progress--dots with ds-progress, a group of dots (role=\"group\")\n * ds-progress__dot a button; `data-state` is `past`, `current` (with\n * `aria-current=\"true\"`), `next`, `future`, or `end` for a\n * last dot marked as an end\n *\n * Tokens: the dot colours `--ds-progress-dot-past` and `-future` (the muted\n * text colour by default), `-current`, `-next` and `-end` (the text colour),\n * set on the dots or any element around them. Past, current and next dots are\n * filled; future dots and the end marker are rings.\n */\n\n/* ---- A value against its range: the bar, or the range in squares ---- */\n\n.ds-progress {\n box-sizing: border-box;\n position: relative;\n display: block;\n width: 100%;\n height: var(--ds-unit);\n margin: 0;\n}\n\n/* The range and its bar are a band half a square high across the middle of\n the row, as a chart's ratio is drawn. */\n.ds-progress:not(.ds-progress--squares, .ds-progress--steps, .ds-progress--dots)::before,\n.ds-progress__fill {\n position: absolute;\n inset-inline: 0;\n top: calc(var(--ds-unit) / 4);\n height: calc(var(--ds-unit) / 2);\n}\n\n.ds-progress:not(.ds-progress--squares, .ds-progress--steps, .ds-progress--dots)::before {\n content: \"\";\n background: var(--ds-progress-track, var(--ds-fill));\n}\n\n.ds-progress__fill {\n display: block;\n background: var(--ds-progress-color, var(--ds-text-color));\n transform: scaleX(var(--ds-progress-value, 0));\n transform-origin: left center;\n transition: transform 0.4s cubic-bezier(0.2, 0.8, 0.2, 1);\n}\n\n.ds-progress__fill:dir(rtl) {\n transform-origin: right center;\n}\n\n.ds-progress--over .ds-progress__fill {\n background: var(--ds-danger-color);\n transform: none;\n}\n\n.ds-progress--squares {\n display: flex;\n width: max-content;\n max-width: 100%;\n overflow: hidden;\n}\n\n.ds-progress__square {\n flex: none;\n width: calc(var(--ds-unit) - 1px);\n height: calc(var(--ds-unit) - 1px);\n margin-inline-end: 1px;\n background: var(--ds-progress-track, var(--ds-fill));\n}\n\n.ds-progress__square--on {\n background: var(--ds-progress-color, var(--ds-text-color));\n}\n\n.ds-progress--over .ds-progress__square {\n background: var(--ds-danger-color);\n}\n\n@media (prefers-reduced-motion: reduce) {\n .ds-progress__fill {\n transition: none;\n }\n}\n\n/* ---- A sequence of steps --------------------------------------------- */\n\n.ds-progress--steps {\n box-sizing: border-box;\n position: static;\n display: flex;\n width: auto;\n height: auto;\n flex-wrap: wrap;\n align-items: flex-start;\n min-width: 0;\n margin: 0;\n padding: 0;\n list-style: none;\n color: var(--ds-text-color);\n font-family: var(--ds-typeface-regular);\n font-feature-settings: var(--ds-font-features);\n font-size: var(--ds-type-size-default);\n font-weight: var(--ds-type-weight-default);\n line-height: var(--ds-unit);\n letter-spacing: var(--ds-type-letterspacing-default);\n text-transform: none;\n}\n\n/* Each step rounds its width up to whole squares where the browser can size\n to content in calc; elsewhere it hugs its words. */\n.ds-progress__step {\n --ds-progress-mark: transparent;\n --ds-progress-mark-ink: var(--ds-text-color-muted);\n --ds-progress-mark-line: var(--ds-border-color);\n box-sizing: border-box;\n position: relative;\n display: flex;\n align-items: flex-start;\n min-width: 0;\n max-width: 100%;\n width: max-content;\n width: calc-size(max-content, round(up, size, var(--ds-unit)));\n min-height: var(--ds-unit);\n margin: 0;\n color: var(--ds-text-color-muted);\n}\n\n/* A line joins a step to the next: at least one square, across whatever the\n step's rounding leaves, a quarter of a square short of each end. */\n.ds-progress__step:not(:last-child)::after {\n content: \"\";\n flex: 1 0 var(--ds-unit);\n height: var(--ds-unit);\n background: linear-gradient(var(--ds-border-color), var(--ds-border-color)) center / calc(100% - var(--ds-unit) / 2) 1px no-repeat;\n}\n\n.ds-progress__step--done {\n --ds-progress-mark: var(--ds-fill);\n --ds-progress-mark-ink: var(--ds-text-color);\n --ds-progress-mark-line: transparent;\n color: var(--ds-text-color);\n}\n\n.ds-progress__step--current {\n --ds-progress-mark: var(--ds-text-color);\n --ds-progress-mark-ink: var(--ds-paper);\n --ds-progress-mark-line: transparent;\n color: var(--ds-text-color);\n}\n\n.ds-progress__step--failed {\n --ds-progress-mark: var(--ds-danger-color);\n --ds-progress-mark-ink: light-dark(var(--ds-white), var(--ds-black));\n --ds-progress-mark-line: transparent;\n color: var(--ds-danger-color);\n}\n\n.ds-progress__link {\n display: flex;\n align-items: flex-start;\n min-width: 0;\n color: inherit;\n text-decoration: none;\n border-radius: var(--ds-radius);\n}\n\n.ds-progress__link:hover .ds-progress__label {\n text-decoration: underline;\n text-decoration-thickness: 1px;\n text-underline-offset: calc(3px * var(--ds-sf, 1));\n}\n\n.ds-progress__link:focus-visible {\n outline: 2px solid var(--ds-focus-ring);\n outline-offset: -2px;\n}\n\n.ds-progress__mark {\n box-sizing: border-box;\n display: flex;\n flex: none;\n align-items: center;\n justify-content: center;\n width: var(--ds-control-height);\n height: var(--ds-control-height);\n margin: calc((var(--ds-unit) - var(--ds-control-height)) / 2);\n overflow: hidden;\n background: var(--ds-progress-mark);\n box-shadow: inset 0 0 0 1px var(--ds-progress-mark-line);\n color: var(--ds-progress-mark-ink);\n --ds-icon-color: var(--ds-progress-mark-ink);\n font-family: var(--ds-typeface-medium);\n font-size: var(--ds-type-size-small);\n font-weight: var(--ds-type-weight-bold);\n font-variant-numeric: tabular-nums;\n line-height: var(--ds-control-height);\n letter-spacing: 0;\n}\n\n.ds-progress__label {\n min-width: 0;\n padding-inline-end: calc(4px * var(--ds-sf, 1));\n overflow: hidden;\n white-space: nowrap;\n text-overflow: ellipsis;\n}\n\n.ds-progress__step--current .ds-progress__label {\n font-family: var(--ds-typeface-medium);\n font-weight: var(--ds-type-weight-bold);\n}\n\n.ds-progress__state {\n position: absolute;\n width: 1px;\n height: 1px;\n overflow: hidden;\n clip-path: inset(50%);\n white-space: nowrap;\n}\n\n.ds-progress--vertical {\n flex-direction: column;\n flex-wrap: nowrap;\n}\n\n.ds-progress--vertical .ds-progress__step {\n flex-wrap: wrap;\n width: 100%;\n}\n\n.ds-progress--vertical .ds-progress__step::after {\n content: none;\n}\n\n/* Its content stands in a column, so an inline element in it (text drawn by\n an element, say) takes its own lines rather than a line box's descent. */\n.ds-progress__body {\n box-sizing: border-box;\n display: flex;\n flex-direction: column;\n flex: 1 0 100%;\n min-width: 0;\n padding-inline-start: var(--ds-unit);\n color: var(--ds-text-color);\n}\n\n/* ---- A dot for each page ------------------------------------------- */\n\n.ds-progress--dots {\n position: static;\n display: inline-flex;\n width: auto;\n flex: none;\n align-items: center;\n height: var(--ds-row-height);\n margin: 0;\n padding: 0;\n}\n\n.ds-progress__dot {\n --ds-progress-dot-color: var(--ds-progress-dot-future, var(--ds-text-color-muted));\n appearance: none;\n box-sizing: border-box;\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n width: var(--ds-unit);\n height: var(--ds-unit);\n margin: 0;\n padding: 0;\n border: 0;\n border-radius: var(--ds-radius);\n background: transparent;\n color: inherit;\n cursor: pointer;\n -webkit-tap-highlight-color: transparent;\n}\n\n/* The dot itself: 4px, scaled with the surface, a fifth of the square. */\n.ds-progress__dot::before {\n content: \"\";\n box-sizing: border-box;\n width: calc(4px * var(--ds-sf, 1));\n height: calc(4px * var(--ds-sf, 1));\n border-radius: 50%;\n background: transparent;\n box-shadow: inset 0 0 0 1px var(--ds-progress-dot-color);\n transition: transform 160ms ease-out;\n}\n\n.ds-progress__dot[data-state=\"past\"] { --ds-progress-dot-color: var(--ds-progress-dot-past, var(--ds-text-color-muted)); }\n.ds-progress__dot[data-state=\"next\"] { --ds-progress-dot-color: var(--ds-progress-dot-next, var(--ds-text-color)); }\n.ds-progress__dot[data-state=\"end\"] { --ds-progress-dot-color: var(--ds-progress-dot-end, var(--ds-text-color)); }\n.ds-progress__dot[aria-current=\"true\"] { --ds-progress-dot-color: var(--ds-progress-dot-current, var(--ds-text-color)); }\n\n.ds-progress__dot:is([data-state=\"past\"], [data-state=\"next\"], [aria-current=\"true\"])::before {\n background: var(--ds-progress-dot-color);\n}\n\n/* The current dot is half again as large. */\n.ds-progress__dot[aria-current=\"true\"]::before {\n transform: scale(1.5);\n}\n\n.ds-progress__dot:hover:not([aria-current=\"true\"])::before {\n transform: scale(1.25);\n}\n\n.ds-progress__dot:focus-visible {\n outline: 2px solid var(--ds-focus-ring);\n outline-offset: -2px;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .ds-progress__dot::before {\n transition: none;\n }\n}\n/*\n * Rows, as plain classes on native elements: the `ds-row` and `ds-sidebar`\n * elements' look without the elements.\n *\n * A row is one square high, and what it holds stands on the lower sixteen of\n * the square with the spare four above, as Ezo sets every row: a line of\n * words on a 16px line box, a 16px icon and a 16px control all end on the\n * row's bottom line, so the capitals (7px below the top line, baseline 3px\n * above the next) are centred on an icon beside them. On an `<a href>` or a\n * `<button>` the whole row is one press target, a row, a tile or a card: the pointer over it, the\n * press and the focus ring cover the row, and its content keeps the row's\n * layout. A row that also holds controls of its own (a quick action, a link\n * in another cell) is any element, a `<li>`, a `<div>` or a `<tr>`, with one\n * `ds-row__target` inside: that link or button takes the press anywhere on\n * the row, and every other control inside stays separately pressable.\n *\n * ds-row a row one square high; a press target on <a> or <button>\n * ds-row__target the row's press target, when the row holds other controls\n * ds-row--auto as high as its content, at least one square\n * ds-row--stacked the content stacked, each line one square (a tile, a card)\n * ds-row--nav a navigation row: the sidebar's two-pixel corners\n * aria-current=\"page\" the destination being shown, filled and in the medium weight\n * aria-disabled=\"true\" or `disabled` on a button: dimmed, not pressable\n *\n * A sidebar of nested things (the `ds-sidebar tree` element without Lit) is a\n * `role=\"tree\"` list of `role=\"treeitem\"` rows, flat, each with its\n * `aria-level`, one square further in per level. `0-face/sidebar.ts`\n * (`connectSidebar`) gives it the keyboard of the tree pattern.\n *\n * ds-sidebar the tree (`role=\"tree\"`)\n * ds-sidebar__item a row (`role=\"treeitem\"`, `aria-level`, `aria-expanded` on a parent, `aria-selected`)\n * ds-sidebar__disclosure the arrow on its own square, turned down when the row is open; empty on a leaf\n * ds-sidebar__label the words, cut short with an ellipsis\n * ds-sidebar__meta small muted words at the row's end\n *\n * An icon (`.ds-icon`) in a tree row takes a square of its own. Tokens:\n * `--ds-row-padding` (the words' distance from the row's edges, 4px),\n * `--ds-row-fill-hover`, `--ds-row-fill-press`, `--ds-row-fill-current` and\n * `--ds-row-current-weight` (component-tokens.css, shared with the\n * element), `--ds-sidebar-disclosure` (the arrow's drawing, the library's\n * `right` icon) and `--ds-sidebar-indent` (a row's depth in squares, read\n * from `aria-level` up to twelve levels).\n */\n\n:where(.ds-row):not(tr) {\n box-sizing: border-box;\n display: flex;\n flex-direction: row;\n align-items: flex-end;\n gap: calc(4px * var(--ds-sf));\n min-width: 0;\n height: var(--ds-row-height);\n margin: 0;\n line-height: var(--ds-type-lineheight-default);\n}\n\n:where(.ds-row--auto):not(tr) {\n height: auto;\n min-height: var(--ds-row-height);\n}\n\n:where(.ds-row--stacked):not(tr) {\n flex-direction: column;\n align-items: flex-start;\n justify-content: flex-start;\n gap: 0;\n height: auto;\n}\n\n/* The press target: the row itself, or the one target inside it. */\na.ds-row,\nbutton.ds-row,\n.ds-row__target {\n appearance: none;\n box-sizing: border-box;\n margin: 0;\n border: 0;\n background: none;\n color: inherit;\n font: inherit;\n letter-spacing: inherit;\n text-align: start;\n text-decoration: none;\n text-transform: none;\n cursor: pointer;\n outline: none;\n -webkit-tap-highlight-color: transparent;\n}\n\n/* The font inherited above would bring the page's line into the row: the words go back on the\n sixteen, as every row's (a stacked tile keeps its square lines below). */\na.ds-row,\nbutton.ds-row {\n position: relative;\n width: 100%;\n line-height: var(--ds-type-lineheight-default);\n padding: 0 var(--ds-row-padding, calc(4px * var(--ds-sf)));\n border-radius: var(--ds-row-radius, 0);\n}\n\n.ds-row__target {\n padding: 0;\n}\n\n/* Each line of a tile one square, over the inherited font of a native link or button:\n a tile's lines wrap, so they stay on whole squares rather than the sixteen. */\n.ds-row.ds-row--stacked {\n line-height: var(--ds-row-height);\n}\n\n/* A row with a target inside: the target's layers cover the row. */\n.ds-row:has(.ds-row__target) {\n position: relative;\n isolation: isolate;\n}\n:where(.ds-row:has(.ds-row__target)):not(tr) {\n padding-inline: var(--ds-row-padding, calc(4px * var(--ds-sf)));\n}\n.ds-row__target::before,\n.ds-row__target::after {\n content: \"\";\n position: absolute;\n inset: 0;\n border-radius: var(--ds-row-radius, 0);\n}\n.ds-row__target::before { z-index: 1; }\n.ds-row__target::after { z-index: -1; }\n.ds-row:has(.ds-row__target) :where(a[href], button, input, select, textarea, label, summary, [tabindex]):not(.ds-row__target) {\n position: relative;\n z-index: 2;\n}\n\n/*\n * The pointer, the press, the current destination and the focus ring are one layer under the\n * row's content (Joachim, 19 October 2026). On a one-square row it is a square high and sits two\n * pixels around what the row holds: from two above the lower sixteen to two below the row's foot,\n * and two past the content at each side, its corners the icon tiles' 4px and those two more, so a\n * 16px icon stands in it with two all round. It is drawn over the row, never moving its words or\n * icons off the grid. An open row (`data-open`) wears the same layer. A taller row (a stacked\n * tile, `auto`) is filled whole.\n * Tokens: `--ds-row-fill-radius` (6px), `--ds-row-fill-overhang` (2px).\n */\na.ds-row,\nbutton.ds-row {\n isolation: isolate;\n}\na.ds-row::after,\nbutton.ds-row::after {\n content: \"\";\n position: absolute;\n z-index: -1;\n pointer-events: none;\n}\na.ds-row::after,\nbutton.ds-row::after,\n.ds-row__target::after {\n --ds-row-overhang: var(--ds-row-fill-overhang, calc(2px * var(--ds-sf)));\n inset:\n calc(var(--ds-row-height) - var(--ds-control-height) - var(--ds-row-overhang))\n calc(var(--ds-row-padding, calc(4px * var(--ds-sf))) - var(--ds-row-overhang))\n calc(0px - var(--ds-row-overhang));\n border-radius: var(--ds-row-radius, var(--ds-row-fill-radius, calc(6px * var(--ds-sf))));\n}\n:is(a, button).ds-row:is(.ds-row--stacked, .ds-row--auto)::after,\n:is(.ds-row--stacked, .ds-row--auto) .ds-row__target::after {\n inset: 0;\n}\na.ds-row[href]:hover::after,\nbutton.ds-row:hover:not(:disabled)::after,\n.ds-row__target:is(a[href], button:not(:disabled)):hover::after {\n background: var(--ds-row-fill-hover, var(--ds-fill));\n}\na.ds-row[href]:active::after,\nbutton.ds-row:active:not(:disabled)::after,\n.ds-row__target:is(a[href], button:not(:disabled)):active::after {\n background: var(--ds-row-fill-press, var(--ds-fill-hover));\n}\n.ds-row:is(a, button)[aria-current]:not([aria-current=\"false\"])::after,\n.ds-row__target[aria-current]:not([aria-current=\"false\"])::after {\n background: var(--ds-row-fill-current, var(--ds-fill-hover));\n}\n.ds-row:is(a, button)[aria-current]:not([aria-current=\"false\"]),\n.ds-row:has(.ds-row__target[aria-current]:not([aria-current=\"false\"])) {\n --ds-type-weight-default: var(--ds-row-current-weight, 500);\n font-weight: var(--ds-row-current-weight, 500);\n}\na.ds-row:focus-visible::after,\nbutton.ds-row:focus-visible::after,\n.ds-row__target:focus-visible::after {\n outline: 2px solid var(--ds-focus-ring);\n outline-offset: -2px;\n}\na.ds-row:not([href]),\na.ds-row[aria-disabled=\"true\"],\nbutton.ds-row:disabled,\nbutton.ds-row[aria-disabled=\"true\"],\n.ds-row:has(.ds-row__target:is(:disabled, [aria-disabled=\"true\"], a:not([href]))) {\n cursor: default;\n opacity: 0.5;\n}\n.ds-row__target:is(:disabled, [aria-disabled=\"true\"], a:not([href])) {\n cursor: default;\n}\na.ds-row[aria-disabled=\"true\"]:hover::after,\nbutton.ds-row[aria-disabled=\"true\"]:hover::after {\n background: none;\n}\n\n.ds-row--nav {\n --ds-row-radius: calc(2px * var(--ds-sf));\n}\n\n/* A sidebar of nested things: the tree. */\n\n.ds-sidebar {\n box-sizing: border-box;\n display: flex;\n flex-direction: column;\n min-width: 0;\n margin: 0;\n padding: 0;\n list-style: none;\n color: var(--ds-text-color);\n font-family: var(--ds-typeface-regular);\n font-feature-settings: var(--ds-font-features);\n font-size: var(--ds-type-size-default);\n font-weight: var(--ds-type-weight-default);\n line-height: var(--ds-type-lineheight-default);\n letter-spacing: var(--ds-type-letterspacing-default);\n}\n\n.ds-sidebar__item {\n box-sizing: border-box;\n display: flex;\n align-items: flex-end;\n height: var(--ds-row-height);\n min-width: 0;\n margin: 0;\n padding-block: 0;\n padding-inline: calc(var(--ds-sidebar-indent, 0) * var(--ds-unit)) var(--ds-row-padding, calc(4px * var(--ds-sf)));\n white-space: nowrap;\n cursor: pointer;\n user-select: none;\n outline: none;\n -webkit-tap-highlight-color: transparent;\n}\n.ds-sidebar__item[hidden] { display: none; }\n.ds-sidebar__item[aria-level=\"2\"] { --ds-sidebar-indent: 1; }\n.ds-sidebar__item[aria-level=\"3\"] { --ds-sidebar-indent: 2; }\n.ds-sidebar__item[aria-level=\"4\"] { --ds-sidebar-indent: 3; }\n.ds-sidebar__item[aria-level=\"5\"] { --ds-sidebar-indent: 4; }\n.ds-sidebar__item[aria-level=\"6\"] { --ds-sidebar-indent: 5; }\n.ds-sidebar__item[aria-level=\"7\"] { --ds-sidebar-indent: 6; }\n.ds-sidebar__item[aria-level=\"8\"] { --ds-sidebar-indent: 7; }\n.ds-sidebar__item[aria-level=\"9\"] { --ds-sidebar-indent: 8; }\n.ds-sidebar__item[aria-level=\"10\"] { --ds-sidebar-indent: 9; }\n.ds-sidebar__item[aria-level=\"11\"] { --ds-sidebar-indent: 10; }\n.ds-sidebar__item[aria-level=\"12\"] { --ds-sidebar-indent: 11; }\n.ds-sidebar__item:hover:not([aria-disabled=\"true\"]) { background: var(--ds-row-fill-hover, var(--ds-fill)); }\n.ds-sidebar__item:active:not([aria-disabled=\"true\"]) { background: var(--ds-row-fill-press, var(--ds-fill-hover)); }\n.ds-sidebar__item[aria-selected=\"true\"] {\n --ds-type-weight-default: var(--ds-row-current-weight, 500);\n background: var(--ds-row-fill-current, var(--ds-fill-hover));\n font-weight: var(--ds-row-current-weight, 500);\n}\n.ds-sidebar__item:focus-visible {\n outline: 2px solid var(--ds-focus-ring);\n outline-offset: -2px;\n}\n.ds-sidebar__item[aria-disabled=\"true\"] {\n cursor: default;\n opacity: 0.5;\n}\n\n/* The arrow and an icon each stand on a whole square, drawn on the row's sixteen (two\n pixels below the square's middle); a leaf keeps the arrow's square empty. */\n.ds-sidebar__disclosure,\n.ds-sidebar__item > .ds-icon {\n flex: 0 0 var(--ds-unit);\n width: var(--ds-unit);\n height: var(--ds-unit);\n -webkit-mask-size: var(--ds-icon-box, calc(14px * var(--ds-sf)));\n mask-size: var(--ds-icon-box, calc(14px * var(--ds-sf)));\n -webkit-mask-position: center calc(50% + 2px * var(--ds-sf));\n mask-position: center calc(50% + 2px * var(--ds-sf));\n}\n.ds-sidebar__disclosure {\n --ds-icon-box: calc(14px * var(--ds-sf));\n display: inline-block;\n color: var(--ds-text-color-muted);\n background-color: currentColor;\n -webkit-mask: var(--ds-sidebar-disclosure, url(\"data:image/svg+xml,%3Csvg xmlns='http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg' viewBox='0 0 16 16'%3E%3Cpath d='M13.1566 8.60594H0V9.61651L13.1562 9.61791L10.249 12.5251L10.9558 13.219L15.0636 9.11123L10.9524 5L10.245 5.70734L13.1566 8.60594Z'/%3E%3C/svg%3E\")) center calc(50% + 2px * var(--ds-sf)) / var(--ds-icon-box) no-repeat;\n mask: var(--ds-sidebar-disclosure, url(\"data:image/svg+xml,%3Csvg xmlns='http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg' viewBox='0 0 16 16'%3E%3Cpath d='M13.1566 8.60594H0V9.61651L13.1562 9.61791L10.249 12.5251L10.9558 13.219L15.0636 9.11123L10.9524 5L10.245 5.70734L13.1566 8.60594Z'/%3E%3C/svg%3E\")) center calc(50% + 2px * var(--ds-sf)) / var(--ds-icon-box) no-repeat;\n transform: rotate(0deg);\n transition: transform 120ms ease-out;\n}\n.ds-sidebar__item:not([aria-expanded]) > .ds-sidebar__disclosure {\n visibility: hidden;\n}\n.ds-sidebar__item[aria-expanded=\"true\"] > .ds-sidebar__disclosure {\n transform: rotate(90deg);\n}\n.ds-sidebar__label {\n flex: 1 1 auto;\n min-width: 0;\n padding-inline-start: calc(4px * var(--ds-sf));\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.ds-sidebar__meta {\n flex: none;\n padding-inline-start: calc(4px * var(--ds-sf));\n color: var(--ds-text-color-muted);\n font-size: var(--ds-type-size-small);\n font-variant-numeric: tabular-nums;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .ds-sidebar__disclosure { transition: none; }\n}\n\n@media (forced-colors: active) {\n .ds-row:is(a, button)[aria-current]:not([aria-current=\"false\"]),\n .ds-row__target[aria-current]:not([aria-current=\"false\"])::after,\n .ds-sidebar__item[aria-selected=\"true\"] {\n outline: 1px solid Highlight;\n outline-offset: -1px;\n }\n .ds-sidebar__disclosure {\n background-color: CanvasText;\n }\n}\n\n/* A controlled detail view: the caller marks its open row, and clears it on close.\n Navigation's current state and the text weight remain independent. */\n.ds-row[data-open]:not([data-open=\"false\"]) {\n position: relative;\n isolation: isolate;\n}\n.ds-row[data-open]:not([data-open=\"false\"])::after {\n content: \"\";\n position: absolute;\n z-index: -1;\n pointer-events: none;\n --ds-row-overhang: var(--ds-row-fill-overhang, calc(2px * var(--ds-sf)));\n inset: calc(var(--ds-row-height) - var(--ds-control-height) - var(--ds-row-overhang))\n calc(var(--ds-row-padding, calc(4px * var(--ds-sf))) - var(--ds-row-overhang))\n calc(0px - var(--ds-row-overhang));\n border-radius: var(--ds-row-radius, var(--ds-row-fill-radius, calc(6px * var(--ds-sf))));\n background: var(--ds-row-fill-current, var(--ds-fill-hover));\n}\n/* A plain row (no press target inside) has no padding of its own: its words and icons stand on\n the row's edges, so the layer reaches two past them, as a flush row's does. */\n.ds-row[data-open]:not([data-open=\"false\"]):not(a, button, .ds-row--stacked, .ds-row--auto, :has(.ds-row__target))::after {\n inset: calc(var(--ds-row-height) - var(--ds-control-height) - var(--ds-row-overhang))\n calc(0px - var(--ds-row-overhang))\n calc(0px - var(--ds-row-overhang));\n}\n.ds-row[data-open]:is(.ds-row--stacked, .ds-row--auto)::after { inset: 0; }\n@media (forced-colors: active) {\n .ds-row[data-open]:not([data-open=\"false\"])::after { outline: 1px solid Highlight; outline-offset: -1px; }\n}\n/*\n * `.ds-context` is the `ds-context` element's look on a native menu, for a page\n * without Lit or a menu a library draws: Ezo's gap face. The rows carry the\n * colour and the menu only cuts the outer silhouette, so the page shows\n * through a pixel between rows and two between groups. The rows are black\n * with white words in both themes, as Ezo's menus always were (the slate in\n * dark, darker than the page). Every row is 19px with the pixel under it, a square's pitch, its words\n * on the sixteen and an icon at its end. A Select's menu is the light face,\n * `.ds-menu`; a Context's is this dark one.\n *\n * ds-context the menu (`role=\"menu\"`); its rows are its buttons,\n * links and menu items, or `ds-context__item`\n * ds-context__item a row; `--danger` (or `data-danger`) in red\n * ds-context__label a heading row, muted\n * ds-context__shortcut a shortcut at the row's end, muted\n * ds-context__separator a group gap (or an `hr`, or `role=\"separator\"`):\n * never a line; first, last or doubled it is quiet\n * [data-ds-refused] a refused change: the row turns red\n *\n * The page places and opens it (a popover at the pointer, say) and owns its\n * keys; the faces of hover, focus, disabled and the wait of a pending menu\n * (`aria-busy=\"true\"`) are here. Tokens as the element's: --ds-context-fill,\n * --ds-context-ink, --ds-context-hover, --ds-context-danger,\n * --ds-context-refused, --ds-context-radius.\n */\n\n.ds-context {\n --ds-context-row: calc(var(--ds-row-height) - 1px);\n /* Black in both themes, as Ezo's menus always were: in dark the slate, darker than the page. */\n --ds-context-fill: light-dark(var(--ds-black, #2a2a2a), var(--ds-slate, #1e1e1e));\n --ds-context-ink: var(--ds-white, #ffffff);\n --ds-context-hover: color-mix(in srgb, var(--ds-context-fill) 78%, var(--ds-context-ink));\n --ds-context-danger: var(--ds-tuned-red);\n --ds-context-refused: var(--ds-tuned-red);\n box-sizing: border-box;\n display: flex;\n flex-direction: column;\n gap: 1px;\n width: var(--ds-menu-width, max-content);\n min-width: calc(4 * var(--ds-unit));\n max-height: var(--ds-menu-max-height, calc(16 * var(--ds-unit)));\n overflow-y: auto;\n margin: 0;\n padding: 0;\n border: 0;\n background: transparent;\n box-shadow: none;\n clip-path: inset(0 round var(--ds-context-radius, var(--ds-radius, 4px)));\n color: var(--ds-context-ink);\n font-family: var(--ds-typeface-regular);\n font-feature-settings: var(--ds-font-features);\n font-size: var(--ds-type-size-default);\n font-weight: var(--ds-type-weight-default);\n line-height: var(--ds-type-lineheight-default);\n letter-spacing: var(--ds-type-letterspacing-default);\n list-style: none;\n}\n\n.ds-context > [role=\"group\"] {\n display: contents;\n}\n\n/* A row: whatever the page or library styles its buttons with, one row on the sixteen. */\n.ds-context :is(.ds-context__item, :is(.ds-context, .ds-context > [role=\"group\"]) > :is(button, a, li, [role^=\"menuitem\"]):not(.ds-context__label, .ds-context__separator, [role=\"separator\"])) {\n box-sizing: border-box !important;\n display: flex !important;\n flex: 0 0 auto !important;\n align-items: flex-end !important;\n justify-content: space-between !important;\n gap: calc(4px * var(--ds-sf));\n width: 100%;\n height: var(--ds-context-row) !important;\n min-height: var(--ds-context-row) !important;\n max-height: var(--ds-context-row) !important;\n margin: 0 !important;\n padding: 0 calc(4px * var(--ds-sf)) !important;\n border: 0 !important;\n border-radius: 0 !important;\n background: var(--ds-context-fill) !important;\n color: var(--ds-context-ink) !important;\n font: inherit;\n line-height: var(--ds-type-lineheight-default) !important;\n letter-spacing: inherit;\n text-align: start;\n text-decoration: none;\n white-space: nowrap;\n cursor: pointer;\n outline: none;\n appearance: none;\n -webkit-tap-highlight-color: transparent;\n}\n\n.ds-context :is(.ds-context__item, :is(.ds-context, .ds-context > [role=\"group\"]) > :is(button, a, li, [role^=\"menuitem\"])):is(:hover, :focus-visible, [data-highlighted]):not(:disabled, [aria-disabled=\"true\"], [data-disabled]) {\n background: var(--ds-context-hover) !important;\n}\n\n.ds-context :is(.ds-context__item, :is(.ds-context, .ds-context > [role=\"group\"]) > :is(button, a, li, [role^=\"menuitem\"])):focus-visible {\n box-shadow: inset 0 0 0 2px var(--ds-focus-ring);\n}\n\n.ds-context :is(.ds-context__item, :is(.ds-context, .ds-context > [role=\"group\"]) > :is(button, a, li, [role^=\"menuitem\"])):is(:disabled, [aria-disabled=\"true\"], [data-disabled]) {\n cursor: default;\n opacity: 0.5;\n}\n\n.ds-context[aria-busy=\"true\"] > * {\n cursor: wait !important;\n}\n\n/* Danger is red, on either fill. */\n.ds-context :is(.ds-context__item, :is(.ds-context, .ds-context > [role=\"group\"]) > :is(button, a, li, [role^=\"menuitem\"])):is(.ds-context__item--danger, [data-danger], [data-variant=\"destructive\"]) {\n color: var(--ds-context-danger) !important;\n}\n\n/* A refused change: its row turns red a moment. */\n.ds-context :is(.ds-context__item, :is(.ds-context, .ds-context > [role=\"group\"]) > :is(button, a, li, [role^=\"menuitem\"]))[data-ds-refused] {\n background: var(--ds-context-refused) !important;\n}\n\n/* Groups are a gap, never a line: the separator takes nothing but the gap after it. */\n.ds-context > :is(hr, .ds-context__separator, [role=\"separator\"]) {\n flex: 0 0 0 !important;\n height: 0 !important;\n margin: 0 !important;\n padding: 0 !important;\n border: 0 !important;\n background: none !important;\n}\n\n/* A group left empty leaves no gap. */\n.ds-context > :is(hr, .ds-context__separator, [role=\"separator\"]):is(:first-child, :last-child),\n.ds-context > :is(hr, .ds-context__separator, [role=\"separator\"]) + :is(hr, .ds-context__separator, [role=\"separator\"]) {\n display: none !important;\n}\n\n.ds-context :is(.ds-context__label, [data-ds-menu-label]) {\n box-sizing: border-box;\n height: var(--ds-context-row);\n /* The spare three above the sixteen. */\n padding: calc(var(--ds-context-row) - var(--ds-type-lineheight-default)) calc(4px * var(--ds-sf)) 0;\n background: var(--ds-context-fill);\n color: color-mix(in srgb, var(--ds-context-ink) 60%, var(--ds-context-fill));\n line-height: var(--ds-type-lineheight-default);\n white-space: nowrap;\n}\n\n.ds-context__shortcut {\n margin-left: auto;\n color: color-mix(in srgb, var(--ds-context-ink) 60%, var(--ds-context-fill));\n}\n\n/*\n * Native controls in shared dress.\n *\n * DS one keeps a few components as plain classes on native elements. shared does\n * the same for everything a person types into or picks from: text fields,\n * selects and checkboxes stay `<input>` and `<select>`, so labels, form\n * semantics and React's controlled inputs work as they always have.\n *\n * `.ds-button` is the `ds-button` element's look on a native `<button>`,\n * for a button inside a drag handle. The drag library recognises only native\n * controls: inside a handle it would lift the row on Space where a\n * `ds-button` was meant to be pressed. Both read the same custom properties.\n * On an `<a href>` it is a link drawn as a button (see `a.ds-button` below).\n */\n\n.ds-button {\n appearance: none;\n box-sizing: border-box;\n display: inline-flex;\n /* At the foot of a line, so the 16px face takes the lower sixteen of the square. */\n vertical-align: bottom;\n flex: 0 0 auto;\n width: var(--ds-button-width, max-content);\n align-items: center;\n justify-content: var(--ds-button-align, flex-start);\n gap: var(--ds-button-gap, calc(4px * var(--ds-sf)));\n height: var(--ds-button-height, var(--ds-control-height));\n margin: 0;\n padding: var(--ds-button-padding, 0);\n border: 0;\n border-radius: var(--ds-radius);\n background: var(--ds-button-background, transparent);\n color: var(--ds-button-color, var(--ds-button-text-color));\n font-family: var(--ds-typeface-regular);\n font-feature-settings: var(--ds-font-features);\n font-size: var(--ds-type-size-default);\n line-height: var(--ds-type-lineheight-default);\n letter-spacing: var(--ds-type-letterspacing-default);\n white-space: nowrap;\n cursor: pointer;\n -webkit-tap-highlight-color: transparent;\n}\n\n.ds-button--icon {\n justify-content: center;\n width: var(--ds-button-height, var(--ds-control-height));\n padding: 0;\n color: var(--ds-button-color, var(--ds-text-color-muted));\n}\n\n.ds-button--icon:hover:not(:disabled, [aria-disabled=\"true\"]) {\n --ds-button-color: var(--ds-text-color);\n}\n\n.ds-button:focus-visible {\n outline: 2px solid var(--ds-focus-ring);\n outline-offset: 1px;\n}\n\n.ds-button:disabled,\n.ds-button[aria-disabled=\"true\"] {\n cursor: default;\n opacity: 0.5;\n}\n\n/*\n * one.css carries older button rules that dim a button on hover and nudge it\n * on press. The shared button does neither: these match their specificity, so\n * controls.css, loaded after one.css, wins.\n */\n.ds-button:hover:not(:disabled, [aria-disabled=\"true\"]) {\n filter: none;\n}\n\n.ds-button:active:not(:disabled, [aria-disabled=\"true\"]) {\n transform: none;\n}\n\n/*\n * `a.ds-button` is a link drawn as a button. The browser keeps the link:\n * middle-click, a new tab, Copy link and Enter. It never takes the link's\n * underline or colours, in any state, so every face (primary, secondary,\n * icon, tabs) looks as it does on a `<button>`. A disabled link has no `href`\n * and carries `aria-disabled=\"true\"` and `role=\"link\"`.\n */\na.ds-button,\na.ds-button:is(:hover, :focus, :active) {\n text-decoration: none;\n}\n\na.ds-button:is(:link, :visited) {\n color: var(--ds-button-color, var(--ds-button-text-color));\n}\n\na.ds-button.ds-button--icon:is(:link, :visited) {\n color: var(--ds-button-color, var(--ds-text-color-muted));\n}\n\na.ds-button[aria-disabled=\"true\"] {\n pointer-events: none;\n}\n\n/*\n * `.ds-link` is a link in running text: the text's ink, underlined by a\n * hairline 2px below the letters (as a toast's actions are), which turns to the full ink under\n * the pointer. A visited link is drawn in the muted ink. Words keep their\n * sentence case. Tokens: `--ds-link-color`, `--ds-link-visited-color`,\n * `--ds-link-line-color`, `--ds-link-hover-line-color`.\n */\n.ds-link {\n color: var(--ds-link-color, currentColor);\n text-decoration-line: underline;\n text-decoration-thickness: 1px;\n text-decoration-color: var(--ds-link-line-color, color-mix(in srgb, currentColor 40%, transparent));\n text-underline-offset: calc(2px * var(--ds-sf));\n cursor: pointer;\n}\n\n.ds-link:visited {\n color: var(--ds-link-visited-color, var(--ds-text-color-muted));\n}\n\n.ds-link:hover {\n text-decoration-color: var(--ds-link-hover-line-color, currentColor);\n}\n\n/* Quiet navigation and related-component lists: no underline in any state. */\n.ds-link.ds-link--plain {\n text-decoration: none;\n}\n\n.ds-link:focus-visible {\n outline: 2px solid var(--ds-focus-ring);\n outline-offset: 1px;\n}\n\n.ds-link[aria-disabled=\"true\"] {\n cursor: default;\n opacity: 0.5;\n pointer-events: none;\n}\n\n.ds-input,\n.ds-select {\n box-sizing: border-box;\n min-width: 0;\n height: var(--ds-input-height, var(--ds-control-height));\n margin: 0;\n padding: 0 calc(4px * var(--ds-sf));\n border: 0;\n border-radius: var(--ds-radius);\n background: var(--ds-fill);\n color: var(--ds-text-color);\n font-family: var(--ds-typeface-regular);\n font-feature-settings: var(--ds-font-features);\n font-size: var(--ds-type-size-default);\n line-height: var(--ds-type-lineheight-default);\n letter-spacing: var(--ds-type-letterspacing-default);\n outline: none;\n}\n\n.ds-input::placeholder {\n color: var(--ds-title-color);\n}\n\n.ds-input:focus-visible,\n.ds-select:focus-visible,\n.ds-checkbox:focus-visible,\n.ds-radio:focus-visible,\n.ds-switch:focus-visible {\n outline: 2px solid var(--ds-focus-ring);\n outline-offset: 1px;\n}\n\n.ds-input:disabled,\n.ds-select:disabled,\n.ds-checkbox:disabled,\n.ds-radio:disabled,\n.ds-switch:disabled {\n cursor: default;\n opacity: 0.5;\n}\n\n.ds-select {\n appearance: none;\n padding-right: calc(16px * var(--ds-sf));\n background-image:\n linear-gradient(45deg, transparent 50%, currentColor 50%),\n linear-gradient(135deg, currentColor 50%, transparent 50%);\n background-position:\n calc(100% - 9px) 50%,\n calc(100% - 6px) 50%;\n background-size:\n 3px 3px,\n 3px 3px;\n background-repeat: no-repeat;\n cursor: pointer;\n}\n\n/* A multiline field, `ds-input` on a <textarea>, spans whole rows: --ds-textarea-rows sets how many, three by default. */\ntextarea.ds-input {\n display: block;\n height: var(--ds-textarea-height, calc(var(--ds-textarea-rows, 3) * var(--ds-row-height)));\n min-height: var(--ds-row-height);\n padding: var(--ds-textarea-padding, calc(4px * var(--ds-sf)));\n border-radius: var(--ds-textarea-radius, calc(4px * var(--ds-sf)));\n resize: vertical;\n}\n\n/*\n * `.ds-checkbox` and `.ds-radio` are the `ds-checkbox` and `ds-radio` elements'\n * faces on a native `<input>`: one square on the field's ground with a 1px\n * line. The checkbox has the corners of a control and fills with the accent,\n * the check (`x-icon/check.svg`) in its ink; the radio is a circle with a dot\n * half a square across in the text colour.\n */\n.ds-checkbox,\n.ds-radio {\n appearance: none;\n box-sizing: border-box;\n display: inline-grid;\n flex: 0 0 auto;\n place-items: center;\n vertical-align: middle;\n width: var(--ds-row-height);\n height: var(--ds-row-height);\n margin: 0;\n padding: 0;\n border: 1px solid var(--ds-border-color);\n background: var(--ds-input-background);\n cursor: pointer;\n}\n\n.ds-checkbox {\n --ds-checkbox-mark: url(\"data:image/svg+xml,%3Csvg%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%20fill%3D%22none%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%3Cpath%20d%3D%22M6.68649%2011.884L12.443%206.13601L11.736%205.42715L6.68835%2010.4827L4.26399%208.0501L3.55696%208.74525L6.68649%2011.884Z%22%20fill%3D%22currentColor%22%2F%3E%0A%3C%2Fsvg%3E\");\n border-radius: var(--ds-radius);\n corner-shape: var(--ds-corner-shape, round);\n color: var(--ds-button-text-color-on-accent);\n}\n\n.ds-checkbox:is(:checked, :indeterminate) {\n background: var(--ds-accent-color);\n}\n\n.ds-checkbox::before,\n.ds-radio::before {\n content: \"\";\n opacity: 0;\n background: currentColor;\n}\n\n.ds-checkbox::before {\n width: calc(0.8 * var(--ds-row-height));\n height: calc(0.8 * var(--ds-row-height));\n mask: var(--ds-checkbox-mark) center / contain no-repeat;\n}\n\n.ds-checkbox:indeterminate::before {\n width: calc(var(--ds-row-height) / 2);\n height: calc(2px * var(--ds-sf));\n mask: none;\n}\n\n.ds-radio {\n border-radius: 50%;\n color: var(--ds-text-color);\n}\n\n.ds-radio::before {\n width: calc(var(--ds-row-height) / 2);\n height: calc(var(--ds-row-height) / 2);\n border-radius: 50%;\n}\n\n.ds-checkbox:is(:checked, :indeterminate)::before,\n.ds-radio:checked::before {\n opacity: 1;\n}\n\n/*\n * `.ds-switch` is the `ds-switch` element's look on a native\n * `<button role=\"switch\" aria-checked>`: two control heights wide, its thumb\n * one control high less a 2px inset, travelling one control height.\n * `.ds-switch--rounded` is the round variant with a white thumb.\n */\n\n.ds-switch {\n --ds-choice-unit: var(--ds-control-height);\n appearance: none;\n box-sizing: border-box;\n position: relative;\n display: inline-block;\n flex: 0 0 auto;\n vertical-align: middle;\n width: calc(2 * var(--ds-choice-unit));\n height: var(--ds-choice-unit);\n margin: 0;\n padding: calc(2px * var(--ds-sf));\n border: 0;\n border-radius: var(--ds-radius);\n background: var(--ds-fill);\n color: var(--ds-text-color-muted);\n cursor: pointer;\n touch-action: manipulation;\n}\n\n.ds-switch::after {\n content: \"\";\n display: block;\n width: calc(var(--ds-choice-unit) - 4px * var(--ds-sf));\n height: 100%;\n border-radius: var(--ds-radius);\n background: currentColor;\n transform: translateX(0);\n transition: transform 140ms ease;\n}\n\n.ds-switch[aria-checked=\"true\"] {\n background: var(--ds-accent-color);\n color: var(--ds-button-text-color-on-accent);\n}\n\n.ds-switch[aria-checked=\"true\"]::after {\n transform: translateX(var(--ds-choice-unit));\n}\n\n.ds-switch--rounded {\n border-radius: var(--ds-choice-unit);\n color: var(--ds-white);\n}\n\n.ds-switch--rounded::after {\n border-radius: 50%;\n background: var(--ds-white);\n}\n\n.ds-switch--rounded[aria-checked=\"true\"] {\n background: var(--ds-switch-track-on);\n}\n\n@media (prefers-reduced-motion: reduce) {\n .ds-switch::after {\n transition: none;\n }\n}\n\n/*\n * `.ds-range` draws a native `<input type=\"range\">`: one control high,\n * standing on the lower sixteen of its square (the spare four above it as a\n * margin, so it takes one square alone and in a row), eight squares wide.\n * The track is a 1px line across the middle of the control, the thumb one\n * control high and half a control wide with the shared corners, in the ink.\n * The browser keeps the value, the keys, the form data and the events.\n *\n * Tokens: `--ds-range-width` (eight squares), `--ds-range-track` (the line,\n * the title grey), `--ds-range-thumb` (the ink) and `--ds-range-thumb-width`.\n * WebKit and Blink draw the parts as `::-webkit-slider-*`, Firefox as\n * `::-moz-range-*`; both get the same track and thumb.\n */\n\n.ds-range {\n -webkit-appearance: none;\n appearance: none;\n box-sizing: border-box;\n display: inline-block;\n vertical-align: bottom;\n width: var(--ds-range-width, calc(8 * var(--ds-unit)));\n min-width: 0;\n height: var(--ds-control-height);\n margin: calc(var(--ds-row-height) - var(--ds-control-height)) 0 0;\n padding: 0;\n border: 0;\n border-radius: var(--ds-radius);\n background: transparent;\n color: var(--ds-range-thumb, var(--ds-text-color));\n font: inherit;\n cursor: pointer;\n touch-action: pan-y;\n -webkit-tap-highlight-color: transparent;\n}\n\n.ds-range::-webkit-slider-runnable-track {\n box-sizing: border-box;\n height: var(--ds-control-height);\n border: 0;\n background: linear-gradient(var(--ds-range-track, var(--ds-title-color)) 0 0) 0 calc(var(--ds-control-height) / 2) / 100% 1px no-repeat;\n}\n\n.ds-range::-moz-range-track {\n box-sizing: border-box;\n height: var(--ds-control-height);\n border: 0;\n background: linear-gradient(var(--ds-range-track, var(--ds-title-color)) 0 0) 0 calc(var(--ds-control-height) / 2) / 100% 1px no-repeat;\n}\n\n.ds-range::-moz-range-progress {\n background: transparent;\n}\n\n.ds-range::-webkit-slider-thumb {\n -webkit-appearance: none;\n appearance: none;\n box-sizing: border-box;\n width: var(--ds-range-thumb-width, calc(var(--ds-control-height) / 2));\n height: var(--ds-control-height);\n border: 0;\n border-radius: var(--ds-radius);\n background: currentColor;\n}\n\n.ds-range::-moz-range-thumb {\n box-sizing: border-box;\n width: var(--ds-range-thumb-width, calc(var(--ds-control-height) / 2));\n height: var(--ds-control-height);\n border: 0;\n border-radius: var(--ds-radius);\n background: currentColor;\n}\n\n.ds-range:focus-visible {\n outline: 2px solid var(--ds-focus-ring);\n outline-offset: 1px;\n}\n\n.ds-range:disabled {\n cursor: default;\n opacity: 0.5;\n}\n\n/*\n * `.ds-tabs` is the `ds-tabs` element's row on native buttons. As an option\n * group (role=\"group\", a segmented control) its `.ds-button` choices are\n * grey and the chosen one, aria-pressed, aria-selected or aria-current, is in\n * the accent, as the primary and secondary buttons are.\n */\n\n.ds-tabs {\n box-sizing: border-box;\n display: flex;\n flex-direction: row;\n align-items: center;\n gap: calc(4px * var(--ds-sf));\n min-width: 0;\n height: var(--ds-row-height);\n}\n\n.ds-tabs--fill > * {\n flex: 1 1 0;\n justify-content: center;\n}\n\n.ds-tabs[role=\"group\"] > .ds-button {\n --ds-button-height: var(--ds-row-height);\n --ds-button-padding: 0 calc(4px * var(--ds-sf));\n --ds-button-background: var(--ds-button-background-color-secondary);\n min-width: 0;\n}\n\n.ds-tabs[role=\"group\"] > .ds-button:hover:not(:disabled, [aria-disabled=\"true\"]) {\n --ds-button-background: var(--ds-fill-hover);\n}\n\n.ds-tabs[role=\"group\"] > .ds-button:is([aria-pressed=\"true\"], [aria-selected=\"true\"], [aria-current]:not([aria-current=\"false\"])) {\n --ds-button-background: var(--ds-button-background-color-primary);\n --ds-button-color: var(--ds-button-text-color-on-accent);\n}\n\n/*\n * `.ds-overlay` is the `ds-overlay` element's frame on a native `<dialog>`, a\n * modal by default: twenty squares wide, a square of padding, square corners,\n * a hairline and the paper. `ds-overlay--sheet`, `ds-overlay--drawer` (with\n * `ds-overlay--start` for the start side) and `ds-overlay--screen` are its\n * other types (overlay.css). Its header, title, description, footer and close button are marked\n * with data-ds-overlay, as inside the element.\n */\n\ndialog.ds-overlay {\n box-sizing: border-box;\n position: fixed;\n inset: 0;\n width: var(--ds-overlay-width, calc(20 * var(--ds-unit)));\n max-width: var(--ds-overlay-max-width, calc(100vw - 2 * var(--ds-unit)));\n max-height: var(--ds-overlay-max-height, calc(100dvh - 2 * var(--ds-unit)));\n height: var(--ds-overlay-height, fit-content);\n margin: auto;\n padding: var(--ds-overlay-padding, var(--ds-unit));\n border: var(--ds-overlay-border, 1px solid var(--ds-border-color));\n border-radius: 0;\n background: var(--ds-overlay-paper, var(--ds-paper));\n color: var(--ds-text-color);\n box-shadow: none;\n overflow: auto;\n overscroll-behavior: contain;\n font-family: var(--ds-typeface-regular);\n font-feature-settings: var(--ds-font-features);\n font-size: var(--ds-type-size-default);\n font-weight: var(--ds-type-weight-default);\n line-height: var(--ds-type-lineheight-default);\n letter-spacing: var(--ds-type-letterspacing-default);\n}\n\ndialog.ds-overlay[open] {\n display: flex;\n flex-direction: column;\n gap: var(--ds-unit);\n}\n\ndialog.ds-overlay::backdrop {\n background: color-mix(in srgb, var(--ds-black) 40%, transparent);\n}\n\n.ds-overlay [data-ds-overlay=\"header\"] {\n display: flex;\n flex-direction: column;\n}\n\n/* The header keeps the last square of its row for the close button, only when it has one. */\ndialog.ds-overlay:has(> [data-ds-overlay=\"close\"]) [data-ds-overlay=\"header\"] {\n padding-inline-end: var(--ds-unit);\n}\n\n/* The title on its square's lower sixteen, as every row's words. */\n.ds-overlay [data-ds-overlay=\"title\"] {\n display: flex;\n align-items: flex-end;\n min-height: var(--ds-row-height);\n margin: 0;\n color: var(--ds-text-color);\n font: inherit;\n font-weight: var(--ds-type-weight-bold);\n line-height: var(--ds-type-lineheight-default);\n}\n\n.ds-overlay [data-ds-overlay=\"description\"] {\n margin: 0;\n color: var(--ds-text-color-muted);\n font: inherit;\n}\n\n.ds-overlay [data-ds-overlay=\"footer\"] {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n justify-content: flex-end;\n gap: calc(var(--ds-unit) / 2);\n min-height: var(--ds-row-height);\n}\n\n.ds-overlay [data-ds-overlay=\"close\"] {\n position: absolute;\n top: var(--ds-unit);\n right: var(--ds-unit);\n}\n\n/* A field in the frame, as a prompt has: its label one row high, the field\n * one row high beneath it and as wide as the frame, two squares in all. */\n.ds-overlay [data-ds-overlay=\"field\"] {\n display: flex;\n flex-direction: column;\n}\n\n.ds-overlay [data-ds-overlay=\"label\"] {\n min-height: var(--ds-row-height);\n line-height: var(--ds-row-height);\n}\n\n.ds-overlay [data-ds-overlay=\"field\"] > .ds-input {\n --ds-input-height: var(--ds-row-height);\n width: 100%;\n}\n\n/*\n * `.ds-button--primary` and `--secondary` are the element's variants on a\n * native button: a form's submit button stays native so Enter in a field\n * submits the form. `--danger` is its `danger` attribute.\n */\n\n.ds-button--primary,\n.ds-button--secondary {\n --ds-button-padding: 0 calc(4px * var(--ds-sf));\n}\n\n.ds-button--primary {\n --ds-button-background: var(--ds-button-background-color-primary);\n --ds-button-color: var(--ds-button-text-color-on-accent);\n}\n\n.ds-button--secondary {\n --ds-button-background: var(--ds-button-background-color-secondary);\n}\n\n.ds-button--secondary:hover:not(:disabled, [aria-disabled=\"true\"]) {\n --ds-button-background: var(--ds-fill-hover);\n}\n\n/* `.ds-button--danger` is the element's `danger`: a destructive action's words\n * in the danger colour, on the secondary face or none. */\n.ds-button--danger {\n --ds-button-color: var(--ds-danger-color, var(--ds-tuned-red));\n}\n\n.ds-button--fixed {\n width: var(--ds-button-width, calc(4 * var(--ds-unit)));\n}\n\n.ds-button--wide {\n justify-content: center;\n width: 100%;\n}\n\n/*\n * `.ds-menu` is the `ds-menu` element's look on a menu a library draws:\n * the context menu's items come from Radix, which owns their roles, focus and\n * keys, so they stay Radix's and take shared's paper, rows and type.\n * On whole squares, as the element: the line and the padding inside it make\n * half a square on each side, entries are one square each with nothing\n * between them, a separator is one square with its line, and there is no\n * shadow. n entries make a menu n + 1 squares high.\n */\n\n.ds-menu {\n box-sizing: border-box;\n display: flex;\n flex-direction: column;\n gap: 0;\n min-width: calc(8 * var(--ds-unit));\n max-width: calc(12 * var(--ds-unit));\n max-height: var(--ds-menu-max-height, calc(16 * var(--ds-unit)));\n overflow-y: auto;\n padding: calc(var(--ds-unit) / 2 - 1px);\n border: 1px solid var(--ds-border-color);\n border-radius: var(--ds-radius-card);\n background: var(--ds-paper);\n color: var(--ds-text-color);\n box-shadow: none;\n font-family: var(--ds-typeface-regular);\n font-feature-settings: var(--ds-font-features);\n font-size: var(--ds-type-size-default);\n font-weight: var(--ds-type-weight-default);\n line-height: var(--ds-type-lineheight-default);\n letter-spacing: var(--ds-type-letterspacing-default);\n}\n\n.ds-menu__item {\n position: relative;\n box-sizing: border-box;\n display: flex;\n align-items: center;\n gap: calc(4px * var(--ds-sf));\n width: 100%;\n min-height: var(--ds-row-height);\n padding: calc(2px * var(--ds-sf)) calc(6px * var(--ds-sf));\n border-radius: calc(4px * var(--ds-sf));\n color: var(--ds-text-color);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n cursor: default;\n user-select: none;\n outline: none;\n}\n\n/* An entry a library draws as its own button or link is one square high too,\n * whatever that library's button styles say. */\n.ds-menu > :is(button, a, [role=\"option\"], [role^=\"menuitem\"]),\n.ds-menu > [role=\"group\"] > :is(button, a, [role=\"option\"], [role^=\"menuitem\"]) {\n box-sizing: border-box !important;\n flex: 0 0 auto !important;\n height: var(--ds-row-height) !important;\n min-height: var(--ds-row-height) !important;\n max-height: var(--ds-row-height) !important;\n margin-block: 0 !important;\n padding-block: 0 !important;\n line-height: var(--ds-type-lineheight-default) !important;\n}\n\n/* A menu item may be a native button: it keeps the row's look, not a button's. */\n:where(button).ds-menu__item {\n appearance: none;\n margin: 0;\n border: 0;\n background: transparent;\n font: inherit;\n letter-spacing: inherit;\n text-align: start;\n}\n\n.ds-menu__item--inset {\n padding-left: calc(var(--ds-unit) + calc(4px * var(--ds-sf)));\n}\n\n.ds-menu__item:hover,\n.ds-menu__item:focus-visible,\n.ds-menu__item[data-highlighted] {\n background: var(--ds-fill);\n}\n\n.ds-menu__item[data-variant=\"destructive\"] {\n color: var(--ds-danger-color, var(--ds-tuned-red));\n}\n\n.ds-menu__item[data-disabled],\n.ds-menu__item[aria-disabled=\"true\"] {\n opacity: 0.5;\n pointer-events: none;\n}\n\n.ds-menu__indicator {\n position: absolute;\n left: calc(6px * var(--ds-sf));\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: calc(12px * var(--ds-sf));\n height: calc(12px * var(--ds-sf));\n pointer-events: none;\n}\n\n.ds-menu__indicator svg {\n width: 100%;\n height: 100%;\n}\n\n.ds-menu__chevron {\n width: calc(12px * var(--ds-sf));\n height: calc(12px * var(--ds-sf));\n margin-left: auto;\n color: var(--ds-text-color-muted);\n}\n\n.ds-menu__label {\n box-sizing: border-box;\n min-height: var(--ds-row-height);\n padding: calc(2px * var(--ds-sf)) calc(6px * var(--ds-sf));\n color: var(--ds-title-color);\n font-size: var(--ds-type-size-small);\n}\n\n.ds-menu__separator {\n flex: 0 0 auto;\n height: 1px;\n /* One square with its line. */\n margin: calc(var(--ds-unit) / 2 - 1px) calc(6px * var(--ds-sf)) calc(var(--ds-unit) / 2);\n background: var(--ds-border-color);\n}\n\n.ds-menu__shortcut {\n margin-left: auto;\n padding-left: var(--ds-unit);\n color: var(--ds-title-color);\n font-size: var(--ds-type-size-small);\n}\n\n/*\n * Pieces the components draw, as classes on native elements: a field's label\n * row, an avatar, a badge, a toggle button, an icon and a file drop zone. Each\n * reads the same tokens as its element, so a page without Lit draws the same\n * look.\n */\n\n/*\n * `.ds-field` is the label row `ds-input` draws, around any native control:\n * the label (`.ds-field__label`) on a one-square line above it, then a hint\n * (`.ds-field__hint`) in the muted ink and an error (`.ds-field__error`) in\n * the danger colour, each on one-square lines. Every row is at least one\n * square high and a control lower than that stands centred on it, so the\n * field keeps to whole squares. `.ds-field--beside` sets the label beside the\n * control, in a column `--ds-field-label-width` wide (four squares), with the\n * hint and the error under the control. An empty hint or error takes no room,\n * so the error can stay in the page as a live region.\n */\n\n.ds-field {\n box-sizing: border-box;\n display: grid;\n grid-template-columns: minmax(0, 1fr);\n grid-auto-rows: minmax(var(--ds-row-height), auto);\n align-items: center;\n justify-items: start;\n min-width: 0;\n margin: 0;\n color: var(--ds-text-color);\n font-family: var(--ds-typeface-regular);\n font-feature-settings: var(--ds-font-features);\n font-size: var(--ds-type-size-default);\n font-weight: var(--ds-type-weight-default);\n line-height: var(--ds-unit);\n letter-spacing: var(--ds-type-letterspacing-default);\n}\n\n.ds-field > :is(.ds-input, .ds-select) {\n justify-self: stretch;\n}\n\n.ds-field__label,\n.ds-field__hint,\n.ds-field__error {\n display: block;\n min-width: 0;\n margin: 0;\n font: inherit;\n letter-spacing: inherit;\n}\n\n.ds-field__label {\n color: var(--ds-field-label-color, var(--ds-text-color));\n}\n\n.ds-field__hint {\n color: var(--ds-text-color-muted);\n}\n\n.ds-field__error {\n color: var(--ds-danger-color);\n}\n\n.ds-field__hint:empty,\n.ds-field__error:empty {\n display: none;\n}\n\n.ds-field--beside {\n grid-template-columns: var(--ds-field-label-width, calc(4 * var(--ds-unit))) minmax(0, 1fr);\n}\n\n.ds-field--beside > * {\n grid-column: 2;\n}\n\n.ds-field--beside > .ds-field__label {\n grid-column: 1;\n grid-row: 1;\n align-self: start;\n}\n\n/*\n * `.ds-avatar` is the `ds-avatar` element's mark: round and one control high,\n * an initial in small type on the neutral fill, or an `<img alt=\"\">` after the\n * initial, covering it. While the picture loads the initial shows; remove a\n * picture that fails (`onerror`), as the element does, or the browser draws\n * its broken-image mark. `--large` is two squares with type a square high,\n * `--pair` fits two characters between the hairline edges, `--square` gives it\n * a picture's corners, `--outlined` draws the hairline in its ink and\n * `--pending` greys out someone who has not accepted yet.\n * `--ds-avatar-background` fills it with a colour and `--ds-avatar-color`\n * letters it: on a fill, pick the black or white ink that reads on it\n * (`--ds-black`, `--ds-white`).\n */\n\n.ds-avatar {\n --ds-avatar-size: var(--ds-control-height);\n --ds-avatar-pair-type-size: var(--ds-type-size-small);\n box-sizing: border-box;\n position: relative;\n display: inline-grid;\n place-items: center;\n flex: 0 0 auto;\n vertical-align: middle;\n width: var(--ds-avatar-size);\n height: var(--ds-avatar-size);\n overflow: hidden;\n border-radius: 50%;\n corner-shape: round;\n background: var(--ds-avatar-background, var(--ds-fill));\n color: var(--ds-avatar-color, var(--ds-text-color));\n font: var(--ds-type-weight-default) var(--ds-type-size-small) / 1 var(--ds-typeface-regular);\n letter-spacing: normal;\n text-align: center;\n white-space: nowrap;\n user-select: none;\n -webkit-user-select: none;\n}\n\n.ds-avatar > img {\n position: absolute;\n inset: 0;\n display: block;\n width: 100%;\n height: 100%;\n object-fit: cover;\n}\n\n.ds-avatar--large {\n --ds-avatar-size: calc(2 * var(--ds-unit));\n --ds-avatar-pair-type-size: var(--ds-type-size-default);\n font-size: var(--ds-unit);\n}\n\n.ds-avatar--pair {\n font-size: min(var(--ds-avatar-pair-type-size), calc((var(--ds-avatar-size) - 2px) / 2));\n}\n\n.ds-avatar--square {\n border-radius: var(--ds-avatar-radius, var(--ds-radius));\n corner-shape: var(--ds-corner-shape, round);\n}\n\n.ds-avatar--outlined::after {\n content: \"\";\n position: absolute;\n inset: 0;\n border: 1px solid var(--ds-avatar-outline, currentColor);\n border-radius: inherit;\n pointer-events: none;\n}\n\n.ds-avatar--pending {\n background: var(--ds-fill);\n color: var(--ds-text-color-muted);\n}\n\n.ds-avatar--pending > img {\n filter: grayscale(1);\n opacity: 0.5;\n}\n\n/*\n * `.ds-badge` is the `ds-badge` element's status label: one square high on the\n * neutral fill, its words padded 4px and cut short with an ellipsis, never a\n * button. Where the browser can size to content in calc (calc-size), its width\n * rounds up to whole squares as the element's does; elsewhere it hugs the\n * words. An icon inside is a `.ds-icon` before the words. `--icon` shows the\n * icon alone, one square wide, and keeps the words for assistive technology:\n * put them in an element of their own. `--ds-badge-background` and\n * `--ds-badge-color` give a status a meaningful colour.\n */\n\n.ds-badge {\n box-sizing: border-box;\n display: inline-block;\n flex: 0 0 auto;\n vertical-align: middle;\n width: max-content;\n width: calc-size(max-content, round(up, size, var(--ds-unit)));\n min-width: var(--ds-row-height);\n max-width: 100%;\n height: var(--ds-row-height);\n padding: 0 calc(4px * var(--ds-sf));\n overflow: hidden;\n background: var(--ds-badge-background, var(--ds-fill));\n color: var(--ds-badge-color, var(--ds-text-color));\n font-family: var(--ds-typeface-regular);\n font-feature-settings: var(--ds-font-features);\n font-size: var(--ds-type-size-default);\n font-weight: var(--ds-type-weight-default);\n line-height: var(--ds-row-height);\n letter-spacing: var(--ds-type-letterspacing-default);\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.ds-badge > .ds-icon {\n vertical-align: top;\n margin-top: calc((var(--ds-row-height) - var(--ds-icon-box, var(--ds-control-height))) / 2);\n margin-right: calc(4px * var(--ds-sf));\n}\n\n.ds-badge--icon {\n position: relative;\n width: var(--ds-row-height);\n padding: 0;\n text-align: center;\n}\n\n.ds-badge--icon > .ds-icon {\n margin-right: 0;\n}\n\n.ds-badge--icon > :not(.ds-icon) {\n position: absolute;\n width: 1px;\n height: 1px;\n overflow: hidden;\n clip-path: inset(50%);\n white-space: nowrap;\n}\n\n/*\n * `.ds-toggle` makes a `.ds-button` a toggle button, `<button aria-pressed>`:\n * the secondary button's grey while it is off, the primary button's accent\n * while it is on, as a chosen segment of `.ds-tabs[role=\"group\"]` is. Its\n * words stay the same in both states; the page toggles `aria-pressed`.\n * A setting that is on or off is a `.ds-switch`; one of several choices is a\n * `.ds-tabs[role=\"group\"]`.\n */\n\n.ds-toggle {\n --ds-button-padding: 0 calc(4px * var(--ds-sf));\n --ds-button-background: var(--ds-button-background-color-secondary);\n}\n\n.ds-toggle:hover:not(:disabled, [aria-disabled=\"true\"]) {\n --ds-button-background: var(--ds-fill-hover);\n}\n\n.ds-toggle[aria-pressed=\"true\"],\n.ds-toggle[aria-pressed=\"true\"]:hover:not(:disabled, [aria-disabled=\"true\"]) {\n --ds-button-background: var(--ds-button-background-color-primary);\n --ds-button-color: var(--ds-button-text-color-on-accent);\n}\n\n/*\n * `.ds-icon` is the `ds-icon` element's drawing without the element: a\n * Design system 1 icon file as a mask, painted in the text colour\n * (`--ds-icon-color`), 14px by default, 12px with `--small` and 16px with\n * `--large`, times the scale. `--ds-icon` names the file, as Sync 1's `icons`\n * export copies it: `style=\"--ds-icon: url(icons/close.svg)\"` (a path from the\n * page) or a rule per icon in the page's stylesheet. The mask takes only the\n * drawing's shape, so an icon with colours of its own is an `<img>`. These\n * rules have no specificity: a page that drew its own `.ds-icon` keeps its\n * rule until it removes it.\n */\n\n:where(.ds-icon) {\n --ds-icon-box: calc(var(--ds-icon-size, 14px) * var(--ds-sf));\n display: inline-block;\n flex: 0 0 auto;\n width: var(--ds-icon-box);\n height: calc(var(--ds-icon-box) / var(--ds-icon-ratio, 1));\n color: var(--ds-icon-color, currentColor);\n background-color: currentColor;\n -webkit-mask: var(--ds-icon) center / contain no-repeat;\n mask: var(--ds-icon) center / contain no-repeat;\n}\n\n:where(.ds-icon--small) {\n --ds-icon-size: 12px;\n}\n\n:where(.ds-icon--large) {\n --ds-icon-size: 16px;\n}\n\n/*\n * `.ds-drop` is `ds-file-picker`'s area on a `<label>` around a native\n * `<input type=\"file\">`: the secondary button's face, as wide as its row and\n * eight squares high (`--compact`: four), its words centred in a square of\n * padding. The input covers the zone unseen, so a click, the keyboard and a\n * dropped file all reach it, and the browser keeps labels, forms, `required`,\n * `multiple` and reset. Keyboard focus draws the focus ring. A page that also\n * handles drops on a larger surface sets `data-dragging` on the zone while\n * files are dragged over it, for the ring and the hover fill. A `.ds-button`\n * on a `<span>` inside draws a button face among the words.\n *\n * The same native input directly inside a `label.ds-button` is the file\n * picker's button: the button's face, one square high.\n */\n\n.ds-drop {\n box-sizing: border-box;\n position: relative;\n display: flex;\n flex-wrap: wrap;\n align-content: center;\n align-items: center;\n justify-content: center;\n gap: calc(var(--ds-unit) / 2);\n width: 100%;\n min-width: 0;\n height: calc(8 * var(--ds-unit));\n margin: 0;\n padding: var(--ds-unit);\n overflow: hidden;\n border-radius: var(--ds-radius);\n corner-shape: var(--ds-corner-shape, round);\n background: var(--ds-button-background-color-secondary);\n color: var(--ds-button-text-color);\n font-family: var(--ds-typeface-regular);\n font-feature-settings: var(--ds-font-features);\n font-size: var(--ds-type-size-default);\n font-weight: var(--ds-type-weight-default);\n line-height: var(--ds-type-lineheight-default);\n letter-spacing: var(--ds-type-letterspacing-default);\n text-align: center;\n cursor: pointer;\n user-select: none;\n -webkit-user-select: none;\n -webkit-tap-highlight-color: transparent;\n}\n\n.ds-drop--compact {\n height: calc(4 * var(--ds-unit));\n}\n\nlabel.ds-button:has(> input[type=\"file\"]) {\n --ds-button-height: var(--ds-row-height);\n position: relative;\n overflow: hidden;\n}\n\n:is(.ds-drop, label.ds-button) > input[type=\"file\"]:not([hidden]) {\n position: absolute;\n inset: 0;\n box-sizing: border-box;\n display: block;\n width: 100%;\n height: 100%;\n min-width: 0;\n margin: 0;\n padding: 0;\n border: 0;\n opacity: 0;\n cursor: pointer;\n}\n\n:is(.ds-drop, label.ds-button) > input[type=\"file\"]::file-selector-button {\n cursor: pointer;\n}\n\n.ds-drop:hover:not(:has(> input:disabled)),\n.ds-drop[data-dragging]:not(:has(> input:disabled)) {\n background: var(--ds-fill-hover);\n}\n\n.ds-drop:has(> input:focus-visible),\n.ds-drop[data-dragging]:not(:has(> input:disabled)),\nlabel.ds-button:has(> input[type=\"file\"]:focus-visible) {\n outline: 2px solid var(--ds-focus-ring);\n outline-offset: 1px;\n}\n\n.ds-drop:has(> input:disabled),\nlabel.ds-button:has(> input[type=\"file\"]:disabled) {\n cursor: default;\n opacity: 0.5;\n}\n\n:is(.ds-drop, label.ds-button) > input[type=\"file\"]:disabled {\n cursor: default;\n}\n";
|
|
8832
8832
|
//#endregion
|
|
8833
8833
|
//#region DS1/2-core/styles/ds-notice.css?inline
|
|
8834
8834
|
var ds_notice_default = "/* ds-notice.css */\n/* The element only places the block; 1-root/notice.css draws it and\n controls.css its dismiss button. */\n\n:host {\n display: block;\n min-width: 0;\n}\n\n:host([hidden]),\n[hidden] {\n display: none !important;\n}\n\n/* The banner is placed by the host; its block then fills the host. */\n:host([banner]),\n:host([form=\"banner\"]) {\n position: absolute;\n top: 0;\n inset-inline: 0;\n z-index: 9999;\n}\n:host([banner]) .ds-notice--banner,\n:host([form=\"banner\"]) .ds-notice--banner {\n position: static;\n}\n\n/* The app banner stands in the flow, at the top of the page. */\n:host([form=\"app\"]) {\n display: block;\n}\n\n/* Slotted words take the notice's lines rather than their own margins. */\n::slotted([slot=\"heading\"]),\n::slotted(:not([slot])) {\n margin: 0;\n}\n\n/* The app's own picture in the icon slot fills its two squares. */\n::slotted(img[slot=\"icon\"]) {\n display: block;\n width: 100%;\n height: 100%;\n object-fit: cover;\n}\n";
|
|
@@ -10741,7 +10741,7 @@ var CalendarBase = class extends i$2 {
|
|
|
10741
10741
|
this.relabel = () => this.requestUpdate();
|
|
10742
10742
|
this.value = "";
|
|
10743
10743
|
this.selectable = false;
|
|
10744
|
-
this.
|
|
10744
|
+
this.endPending = false;
|
|
10745
10745
|
this.literal = false;
|
|
10746
10746
|
this.events = [];
|
|
10747
10747
|
}
|
|
@@ -10758,6 +10758,7 @@ var CalendarBase = class extends i$2 {
|
|
|
10758
10758
|
willUpdate(changed) {
|
|
10759
10759
|
super.willUpdate(changed);
|
|
10760
10760
|
if (changed.has("value") && this.value && !readRange(this.value).start) this.value = "";
|
|
10761
|
+
if (changed.has("value") && this.value !== this.pressedValue) this.endPending = false;
|
|
10761
10762
|
}
|
|
10762
10763
|
/** Shared words, filled in: `words("Week {week}", { week: 42 })`. */
|
|
10763
10764
|
words(key, params) {
|
|
@@ -10788,21 +10789,18 @@ var CalendarBase = class extends i$2 {
|
|
|
10788
10789
|
/** The chosen days: the first and the last of a range, or the one day twice. */
|
|
10789
10790
|
get chosen() {
|
|
10790
10791
|
const { start, end } = readRange(this.value);
|
|
10791
|
-
return
|
|
10792
|
-
start,
|
|
10793
|
-
end
|
|
10794
|
-
} : {
|
|
10792
|
+
return {
|
|
10795
10793
|
start,
|
|
10796
|
-
end: start
|
|
10794
|
+
end: end || start
|
|
10797
10795
|
};
|
|
10798
10796
|
}
|
|
10799
10797
|
/** How a day stands to the selection: an end of it, inside it, or neither; with the end still to come, the pointer previews it. */
|
|
10800
10798
|
selection(day) {
|
|
10801
10799
|
let { start, end } = this.chosen;
|
|
10802
|
-
if (this.
|
|
10800
|
+
if (this.endPending && start && this.hoverDay) end = this.hoverDay;
|
|
10803
10801
|
if (end && end < start) [start, end] = [end, start];
|
|
10804
10802
|
const selected = day === start || day === end;
|
|
10805
|
-
const spans = Boolean(
|
|
10803
|
+
const spans = Boolean(start && end && start !== end);
|
|
10806
10804
|
return {
|
|
10807
10805
|
selected,
|
|
10808
10806
|
inside: spans && day > start && day < end,
|
|
@@ -10834,7 +10832,10 @@ var CalendarBase = class extends i$2 {
|
|
|
10834
10832
|
}
|
|
10835
10833
|
/**
|
|
10836
10834
|
* A person pressed a day: `day-press` fires, and unless it is cancelled a
|
|
10837
|
-
* selectable calendar takes the day and fires `change`.
|
|
10835
|
+
* selectable calendar takes the day and fires `change`. There is one way to
|
|
10836
|
+
* pick: the first press chooses a day, which is the value; the next ends a
|
|
10837
|
+
* range from it, before or after (the same day again keeps the one day);
|
|
10838
|
+
* the press after that starts again.
|
|
10838
10839
|
*/
|
|
10839
10840
|
press(day) {
|
|
10840
10841
|
const pressed = new CustomEvent("day-press", {
|
|
@@ -10848,15 +10849,15 @@ var CalendarBase = class extends i$2 {
|
|
|
10848
10849
|
});
|
|
10849
10850
|
if (!this.dispatchEvent(pressed) || !this.selectable || !this.allowed(day)) return;
|
|
10850
10851
|
const previous = this.value || "";
|
|
10851
|
-
|
|
10852
|
-
|
|
10853
|
-
|
|
10854
|
-
if (start && !end) value = day < start ? `${day}/${start}` : `${start}/${day}`;
|
|
10855
|
-
}
|
|
10852
|
+
const { start: first } = readRange(previous);
|
|
10853
|
+
const ending = this.endPending && Boolean(first);
|
|
10854
|
+
const value = !ending || day === first ? day : day < first ? `${day}/${first}` : `${first}/${day}`;
|
|
10856
10855
|
this.focusDay = day;
|
|
10857
|
-
|
|
10858
|
-
this.value = value;
|
|
10856
|
+
this.endPending = !ending;
|
|
10859
10857
|
this.hoverDay = void 0;
|
|
10858
|
+
this.pressedValue = value;
|
|
10859
|
+
if (value === previous && !ending) return;
|
|
10860
|
+
this.value = value;
|
|
10860
10861
|
const { start, end } = readRange(value);
|
|
10861
10862
|
this.dispatchEvent(new CustomEvent("change", {
|
|
10862
10863
|
bubbles: true,
|
|
@@ -10865,7 +10866,7 @@ var CalendarBase = class extends i$2 {
|
|
|
10865
10866
|
value,
|
|
10866
10867
|
previous,
|
|
10867
10868
|
start,
|
|
10868
|
-
end:
|
|
10869
|
+
end: ending ? end || start : ""
|
|
10869
10870
|
}
|
|
10870
10871
|
}));
|
|
10871
10872
|
}
|
|
@@ -10915,10 +10916,6 @@ _CalendarBase.properties = {
|
|
|
10915
10916
|
type: Boolean,
|
|
10916
10917
|
reflect: true
|
|
10917
10918
|
},
|
|
10918
|
-
range: {
|
|
10919
|
-
type: Boolean,
|
|
10920
|
-
reflect: true
|
|
10921
|
-
},
|
|
10922
10919
|
label: { type: String },
|
|
10923
10920
|
literal: {
|
|
10924
10921
|
type: Boolean,
|
|
@@ -10926,21 +10923,64 @@ _CalendarBase.properties = {
|
|
|
10926
10923
|
},
|
|
10927
10924
|
events: { attribute: false },
|
|
10928
10925
|
focusDay: { state: true },
|
|
10929
|
-
hoverDay: { state: true }
|
|
10926
|
+
hoverDay: { state: true },
|
|
10927
|
+
endPending: { state: true }
|
|
10930
10928
|
};
|
|
10931
10929
|
//#endregion
|
|
10932
10930
|
//#region DS1/3-unit/styles/ds-calendar.css?inline
|
|
10933
|
-
var ds_calendar_default = "/* ds-calendar.css\n * A month on whole squares. A day is --ds-calendar-day-squares wide (four,\n * one when compact) and, beside its date's square, holds --ds-calendar-lines\n * one-square lines of events and one square to spare. Every line of words\n * stands on the lower sixteen of its square. The boxes are hairlines centred\n * on the grid lines; today is a red disc nine tenths of a square across. */\n\n:host {\n --ds-calendar-day: calc(var(--ds-unit) * var(--ds-calendar-day-squares, 4));\n --ds-calendar-day-height: calc(var(--ds-unit) * (var(--ds-calendar-lines, 2) + 2));\n --ds-calendar-line: 1px solid var(--ds-border-color);\n --ds-calendar-today: var(--ds-red-for-blood);\n --ds-calendar-today-ink: var(--ds-white, #fff);\n --ds-calendar-selected: var(--ds-sharp-blue);\n --ds-calendar-selected-ink: var(--ds-white, #fff);\n --ds-calendar-band: color-mix(in srgb, var(--ds-calendar-selected) 16%, var(--ds-paper));\n --ds-calendar-mark: calc(var(--ds-unit) * 0.9);\n --ds-calendar-pad: calc(4px * var(--ds-sf, 1));\n box-sizing: border-box;\n display: inline-block;\n vertical-align: top;\n color: var(--ds-text-color);\n font-family: var(--ds-typeface-regular);\n font-feature-settings: var(--ds-font-features);\n font-size: var(--ds-type-size-default);\n font-weight: var(--ds-type-weight-default);\n line-height: var(--ds-type-lineheight-default);\n letter-spacing: var(--ds-type-letterspacing-default);\n}\n:host([hidden]) { display: none !important; }\n/* A compact day is square: one square, or two where the month has room. Its marks grow with it. */\n:host([compact]) {\n --ds-calendar-day-height: var(--ds-calendar-day);\n --ds-calendar-mark: calc(var(--ds-unit) * (var(--ds-calendar-day-squares, 1) * 0.75 + 0.15));\n}\n\n.calendar { width: calc(7 * var(--ds-calendar-day)); }\n\n/* The title and the arrows: one square, one square above the days (none when compact). */\n.header {\n box-sizing: border-box;\n display: flex;\n align-items: flex-end;\n gap: var(--ds-calendar-pad);\n height: var(--ds-unit);\n margin-block-end: var(--ds-unit);\n}\n:host([compact]) .header { margin-block-end: 0; }\n.title {\n flex: 1 1 auto;\n min-width: 0;\n overflow: hidden;\n font-family: var(--ds-typeface-medium, var(--ds-typeface-regular));\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.controls {\n display: flex;\n flex: 0 0 auto;\n align-items: flex-end;\n gap: 0;\n}\n/* Each arrow is a chevron on its own square, one control high at the square's foot,\n * in the title grey; the pointer fills it with the system's corners and inks it. */\n.nav {\n flex: 0 0 auto;\n width: var(--ds-unit);\n height: var(--ds-control-height);\n border-radius: var(--ds-radius);\n color: var(--ds-title-color);\n}\n.nav:hover:not(:disabled) { background: var(--ds-fill); color: var(--ds-text-color); }\n:host(:dir(rtl)) .nav > ds-icon { transform: scaleX(-1); }\n\n.grid { outline: none; }\n.weekdays,\n.week {\n display: grid;\n grid-template-columns: repeat(7, var(--ds-calendar-day));\n}\n\n/* The weekday names: a block line in the title grey, at the start of a wide day, centred on a compact one. */\n.weekday {\n box-sizing: border-box;\n height: var(--ds-unit);\n padding: calc(4px * var(--ds-sf, 1)) var(--ds-calendar-pad) 0;\n overflow: hidden;\n color: var(--ds-title-color);\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n:host([compact]) .weekday { padding-inline: 0; text-align: center; }\n\n/* A day's box: hairlines on the grid lines, top and start; the last column\n * and the last week close it at the end and the foot. */\n.day {\n position: relative;\n box-sizing: border-box;\n min-width: 0;\n height: var(--ds-calendar-day-height);\n outline: none;\n}\n.day::after {\n position: absolute;\n inset: -0.5px;\n border-block-start: var(--ds-calendar-line);\n border-inline-start: var(--ds-calendar-line);\n content: \"\";\n pointer-events: none;\n}\n.day:nth-child(7)::after { border-inline-end: var(--ds-calendar-line); }\n.week:last-child .day::after { border-block-end: var(--ds-calendar-line); }\n:host([compact]) .day::after { content: none; }\n\n.day[data-day] { cursor: default; }\n:host([selectable]) .day[data-day]:not([aria-disabled=\"true\"]) { cursor: pointer; }\n:host([selectable]:not([compact])) .day[data-day]:not([aria-disabled=\"true\"]):hover { background: var(--ds-row-fill-hover, var(--ds-fill)); }\n.day:focus-visible { outline: 2px solid var(--ds-focus-ring); outline-offset: -2px; }\n:host([compact]) .day:focus-visible { outline: none; }\n:host([compact]) .day:focus-visible .date { outline: 2px solid var(--ds-focus-ring); outline-offset: -1px; }\n\n/* The date: on the first square, at the end of a wide day, in the title grey. */\n.date-line {\n box-sizing: border-box;\n display: flex;\n align-items: flex-end;\n justify-content: flex-end;\n gap: var(--ds-calendar-pad);\n height: var(--ds-unit);\n padding-inline: var(--ds-calendar-pad);\n}\n.date {\n color: var(--ds-title-color);\n font-variant-numeric: tabular-nums;\n}\n.week-number {\n margin-inline-end: auto;\n color: var(--ds-title-color);\n font-family: var(--ds-typeface-compressed);\n}\n\n/* A compact day: the date centred in its square, in the ink; with events,\n * the empty days fall back to the title grey and the busy ones keep the ink. */\n:host([compact]) .date-line { justify-content: center; padding: 0; }\n:host([compact]) .date { color: var(--ds-text-color); }\n:host([compact][data-events]) .day:not([data-busy]) .date { color: var(--ds-title-color); }\n:host([compact][selectable]) .day[data-day]:not([aria-disabled=\"true\"], [data-today], [data-selected]):hover .date { background: var(--ds-fill); }\n\n/* Today and the selected day: a disc nine tenths of a square, centred on the date's square. */\n.day:is([data-today], [data-selected]) .date-line { align-items: center; padding-inline-end: calc(var(--ds-unit) * 0.05); }\n:host([compact]) .day:is([data-today], [data-selected]) .date-line { padding: 0; }\n.date {\n box-sizing: border-box;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: var(--ds-calendar-mark);\n height: var(--ds-calendar-mark);\n border-radius: 999px;\n}\n.day:not([data-today], [data-selected]) .date { min-width: 0; height: auto; }\n:host([compact]) .day .date { min-width: var(--ds-calendar-mark); height: var(--ds-calendar-mark); }\n.day[data-today] .date { background: var(--ds-calendar-today); color: var(--ds-calendar-today-ink); letter-spacing: 0; }\n/* The selected day, and each end of a range: a square with the system's corners in the selection's blue. */\n.day[data-selected] .date { border-radius: var(--ds-radius); background: var(--ds-calendar-selected); color: var(--ds-calendar-selected-ink); letter-spacing: 0; }\n\n.day[aria-disabled=\"true\"] .date { color: var(--ds-title-color); opacity: 0.5; }\n\n/* Events: one square each, stacked edge to edge on the day's lines, drawn one pixel short. */\n.events {\n display: flex;\n flex-direction: column;\n}\n.event,\n.more {\n box-sizing: border-box;\n display: flex;\n align-items: flex-end;\n gap: var(--ds-calendar-pad);\n height: calc(var(--ds-unit) - 1px);\n margin: 0.5px;\n padding-inline: var(--ds-calendar-pad);\n overflow: hidden;\n white-space: nowrap;\n}\n.event {\n background: var(--ds-calendar-event-fill, var(--ds-fill));\n color: var(--ds-calendar-event-ink, var(--ds-text-color));\n cursor: pointer;\n}\n.event .name { min-width: 0; overflow: hidden; text-overflow: ellipsis; }\n.event .time { flex: 0 0 auto; opacity: 0.6; font-variant-numeric: tabular-nums; }\n.more { color: var(--ds-title-color); cursor: pointer; }\n.more:hover { color: var(--ds-text-color); }\n\n/* A day whose hidden events are unfolded lays them over the days below. */\n.day[data-open] { z-index: 1; }\n.day[data-open] .events {\n position: absolute;\n inset-block-start: var(--ds-unit);\n inset-inline: 0;\n background: var(--ds-paper);\n box-shadow: 0 0 0 1px var(--ds-border-color);\n}\n\n@media (prefers-reduced-motion: no-preference) {\n .event, .more { transition: opacity 120ms ease; }\n}\n\n/* A compact day's date stands in the middle of its square once the square is two or more wide. */\n:host([compact][data-roomy]) .date-line { align-items: center; height: var(--ds-calendar-day-height); }\n\n/* The days of the months before and after, in the title grey. */\n.day[data-outside] .date { color: var(--ds-title-color); }\n:host([compact]) .day[data-outside] .date { color: var(--ds-title-color); }\n\n/* A range: the days between its ends on a band of the selection's blue; the band runs into each end's square. */\n.day[data-inside] { background: var(--ds-calendar-band); }\n:host(:not([compact])) .day:is([data-first], [data-last]) { background: var(--ds-calendar-band); }\n:host([compact]) .day[data-first] { background: linear-gradient(to right, transparent 50%, var(--ds-calendar-band) 50%); }\n:host([compact]) .day[data-last] { background: linear-gradient(to left, transparent 50%, var(--ds-calendar-band) 50%); }\n:host([compact]:dir(rtl)) .day[data-first] { background: linear-gradient(to left, transparent 50%, var(--ds-calendar-band) 50%); }\n:host([compact]:dir(rtl)) .day[data-last] { background: linear-gradient(to right, transparent 50%, var(--ds-calendar-band) 50%); }\n:host([compact][selectable]) .day[data-inside]:hover .date { background: transparent; }\n\n/* Today, as words in the title grey beside the arrows. */\n.today-button {\n height: var(--ds-control-height);\n padding-inline: calc(4px * var(--ds-sf, 1));\n border: 0;\n background: transparent;\n color: var(--ds-title-color);\n}\n.today-button:hover { background: var(--ds-fill); color: var(--ds-text-color); }\n\n/* In a compact month the pointer's day and the chosen day take squares with the system's corners; today keeps its disc. */\n:host([compact]) .date { border-radius: var(--ds-radius); }\n:host([compact]) .day[data-today]:not([data-selected]) .date { border-radius: 999px; }\n";
|
|
10931
|
+
var ds_calendar_default = "/* ds-calendar.css\n * A month on whole squares. A day is --ds-calendar-day-squares wide (four,\n * one when compact) and, beside its date's square, holds --ds-calendar-lines\n * one-square lines of events and one square to spare. Every line of words\n * stands on the lower sixteen of its square. The boxes are hairlines centred\n * on the grid lines; today is a red disc nine tenths of a square across.\n *\n * A picker is the select's face: one control high at the foot of its square,\n * ten squares wide by default, the calendar icon at its start and the down\n * arrow at its end. Its month opens on the menu's frame, half a square from\n * the field: a 1px line, half a square inside it, no shadow, so eight squares\n * wide. Inside, on whole squares: the first and last day to type (each with\n * its time below when times are on), one square spare, the compact month one\n * square a day, then Include time and Clear, each one square, set off by\n * one-square separators with a line through them. */\n\n:host {\n --ds-calendar-day: calc(var(--ds-unit) * var(--ds-calendar-day-squares, 4));\n --ds-calendar-day-height: calc(var(--ds-unit) * (var(--ds-calendar-lines, 2) + 2));\n --ds-calendar-line: 1px solid var(--ds-border-color);\n --ds-calendar-today: var(--ds-red-for-blood);\n --ds-calendar-today-ink: var(--ds-white, #fff);\n --ds-calendar-selected: var(--ds-sharp-blue);\n --ds-calendar-selected-ink: var(--ds-white, #fff);\n --ds-calendar-band: color-mix(in srgb, var(--ds-calendar-selected) 16%, var(--ds-paper));\n --ds-calendar-mark: calc(var(--ds-unit) * 0.9);\n --ds-calendar-pad: calc(4px * var(--ds-sf, 1));\n box-sizing: border-box;\n display: inline-block;\n vertical-align: top;\n color: var(--ds-text-color);\n font-family: var(--ds-typeface-regular);\n font-feature-settings: var(--ds-font-features);\n font-size: var(--ds-type-size-default);\n font-weight: var(--ds-type-weight-default);\n line-height: var(--ds-type-lineheight-default);\n letter-spacing: var(--ds-type-letterspacing-default);\n}\n:host([hidden]) { display: none !important; }\n/* A compact day is square: one square, or two where the month has room. Its marks grow with it. */\n:host([compact]) {\n --ds-calendar-day-height: var(--ds-calendar-day);\n --ds-calendar-mark: calc(var(--ds-unit) * (var(--ds-calendar-day-squares, 1) * 0.75 + 0.15));\n}\n\n.calendar { width: calc(7 * var(--ds-calendar-day)); }\n\n/* The title and the arrows: one square, one square above the days (none when compact). */\n.header {\n box-sizing: border-box;\n display: flex;\n align-items: flex-end;\n gap: var(--ds-calendar-pad);\n height: var(--ds-unit);\n margin-block-end: var(--ds-unit);\n}\n:host([compact]) .header { margin-block-end: 0; }\n.title {\n flex: 1 1 auto;\n min-width: 0;\n overflow: hidden;\n font-family: var(--ds-typeface-medium, var(--ds-typeface-regular));\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.controls {\n display: flex;\n flex: 0 0 auto;\n align-items: flex-end;\n gap: 0;\n}\n/* Each arrow is a chevron on its own square, one control high at the square's foot,\n * in the title grey; the pointer fills it with the system's corners and inks it. */\n.nav {\n flex: 0 0 auto;\n width: var(--ds-unit);\n height: var(--ds-control-height);\n border-radius: var(--ds-radius);\n color: var(--ds-title-color);\n}\n.nav:hover:not(:disabled) { background: var(--ds-fill); color: var(--ds-text-color); }\n:host(:dir(rtl)) .nav > ds-icon { transform: scaleX(-1); }\n\n.grid { outline: none; }\n.weekdays,\n.week {\n display: grid;\n grid-template-columns: repeat(7, var(--ds-calendar-day));\n}\n\n/* The weekday names: a block line in the title grey, at the start of a wide day, centred on a compact one. */\n.weekday {\n box-sizing: border-box;\n height: var(--ds-unit);\n padding: calc(4px * var(--ds-sf, 1)) var(--ds-calendar-pad) 0;\n overflow: hidden;\n color: var(--ds-title-color);\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n:host([compact]) .weekday { padding-inline: 0; text-align: center; }\n\n/* A day's box: hairlines on the grid lines, top and start; the last column\n * and the last week close it at the end and the foot. */\n.day {\n position: relative;\n box-sizing: border-box;\n min-width: 0;\n height: var(--ds-calendar-day-height);\n outline: none;\n}\n.day::after {\n position: absolute;\n inset: -0.5px;\n border-block-start: var(--ds-calendar-line);\n border-inline-start: var(--ds-calendar-line);\n content: \"\";\n pointer-events: none;\n}\n.day:nth-child(7)::after { border-inline-end: var(--ds-calendar-line); }\n.week:last-child .day::after { border-block-end: var(--ds-calendar-line); }\n:host([compact]) .day::after { content: none; }\n\n.day[data-day] { cursor: default; }\n:host([selectable]) .day[data-day]:not([aria-disabled=\"true\"]) { cursor: pointer; }\n:host([selectable]:not([compact])) .day[data-day]:not([aria-disabled=\"true\"]):hover { background: var(--ds-row-fill-hover, var(--ds-fill)); }\n.day:focus-visible { outline: 2px solid var(--ds-focus-ring); outline-offset: -2px; }\n:host([compact]) .day:focus-visible { outline: none; }\n:host([compact]) .day:focus-visible .date { outline: 2px solid var(--ds-focus-ring); outline-offset: -1px; }\n\n/* The date: on the first square, at the end of a wide day, in the title grey. */\n.date-line {\n box-sizing: border-box;\n display: flex;\n align-items: flex-end;\n justify-content: flex-end;\n gap: var(--ds-calendar-pad);\n height: var(--ds-unit);\n padding-inline: var(--ds-calendar-pad);\n}\n.date {\n color: var(--ds-title-color);\n font-variant-numeric: tabular-nums;\n}\n.week-number {\n margin-inline-end: auto;\n color: var(--ds-title-color);\n font-family: var(--ds-typeface-compressed);\n}\n\n/* A compact day: the date centred in its square, in the ink; with events,\n * the empty days fall back to the title grey and the busy ones keep the ink. */\n:host([compact]) .date-line { justify-content: center; padding: 0; }\n:host([compact]) .date { color: var(--ds-text-color); }\n:host([compact][data-events]) .day:not([data-busy]) .date { color: var(--ds-title-color); }\n:host([compact][selectable]) .day[data-day]:not([aria-disabled=\"true\"], [data-today], [data-selected]):hover .date { background: var(--ds-fill); }\n\n/* Today and the selected day: a disc nine tenths of a square, centred on the date's square. */\n.day:is([data-today], [data-selected]) .date-line { align-items: center; padding-inline-end: calc(var(--ds-unit) * 0.05); }\n:host([compact]) .day:is([data-today], [data-selected]) .date-line { padding: 0; }\n.date {\n box-sizing: border-box;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: var(--ds-calendar-mark);\n height: var(--ds-calendar-mark);\n border-radius: 999px;\n}\n.day:not([data-today], [data-selected]) .date { min-width: 0; height: auto; }\n:host([compact]) .day .date { min-width: var(--ds-calendar-mark); height: var(--ds-calendar-mark); }\n.day[data-today] .date { background: var(--ds-calendar-today); color: var(--ds-calendar-today-ink); letter-spacing: 0; }\n/* The selected day, and each end of a range: a square with the system's corners in the selection's blue. */\n.day[data-selected] .date { border-radius: var(--ds-radius); background: var(--ds-calendar-selected); color: var(--ds-calendar-selected-ink); letter-spacing: 0; }\n\n.day[aria-disabled=\"true\"] .date { color: var(--ds-title-color); opacity: 0.5; }\n\n/* Events: one square each, stacked edge to edge on the day's lines, drawn one pixel short. */\n.events {\n display: flex;\n flex-direction: column;\n}\n.event,\n.more {\n box-sizing: border-box;\n display: flex;\n align-items: flex-end;\n gap: var(--ds-calendar-pad);\n height: calc(var(--ds-unit) - 1px);\n margin: 0.5px;\n padding-inline: var(--ds-calendar-pad);\n overflow: hidden;\n white-space: nowrap;\n}\n.event {\n background: var(--ds-calendar-event-fill, var(--ds-fill));\n color: var(--ds-calendar-event-ink, var(--ds-text-color));\n cursor: pointer;\n}\n.event .name { min-width: 0; overflow: hidden; text-overflow: ellipsis; }\n.event .time { flex: 0 0 auto; opacity: 0.6; font-variant-numeric: tabular-nums; }\n.more { color: var(--ds-title-color); cursor: pointer; }\n.more:hover { color: var(--ds-text-color); }\n\n/* A day whose hidden events are unfolded lays them over the days below. */\n.day[data-open] { z-index: 1; }\n.day[data-open] .events {\n position: absolute;\n inset-block-start: var(--ds-unit);\n inset-inline: 0;\n background: var(--ds-paper);\n box-shadow: 0 0 0 1px var(--ds-border-color);\n}\n\n@media (prefers-reduced-motion: no-preference) {\n .event, .more { transition: opacity 120ms ease; }\n}\n\n/* A compact day's date stands in the middle of its square once the square is two or more wide. */\n:host([compact][data-roomy]) .date-line { align-items: center; height: var(--ds-calendar-day-height); }\n\n/* The days of the months before and after, in the title grey. */\n.day[data-outside] .date { color: var(--ds-title-color); }\n:host([compact]) .day[data-outside] .date { color: var(--ds-title-color); }\n\n/* A range: the days between its ends on a band of the selection's blue; the band runs into each end's square. */\n.day[data-inside] { background: var(--ds-calendar-band); }\n:host(:not([compact])) .day:is([data-first], [data-last]) { background: var(--ds-calendar-band); }\n:host([compact]) .day[data-first] { background: linear-gradient(to right, transparent 50%, var(--ds-calendar-band) 50%); }\n:host([compact]) .day[data-last] { background: linear-gradient(to left, transparent 50%, var(--ds-calendar-band) 50%); }\n:host([compact]:dir(rtl)) .day[data-first] { background: linear-gradient(to left, transparent 50%, var(--ds-calendar-band) 50%); }\n:host([compact]:dir(rtl)) .day[data-last] { background: linear-gradient(to right, transparent 50%, var(--ds-calendar-band) 50%); }\n:host([compact][selectable]) .day[data-inside]:hover .date { background: transparent; }\n\n/* Today, as words in the title grey beside the arrows. */\n.today-button {\n height: var(--ds-control-height);\n padding-inline: calc(4px * var(--ds-sf, 1));\n border: 0;\n background: transparent;\n color: var(--ds-title-color);\n}\n.today-button:hover { background: var(--ds-fill); color: var(--ds-text-color); }\n\n/* In a compact month the pointer's day and the chosen day take squares with the system's corners; today keeps its disc. */\n:host([compact]) .date { border-radius: var(--ds-radius); }\n:host([compact]) .day[data-today]:not([data-selected]) .date { border-radius: 999px; }\n\n/* The picker: a field that opens the small month. */\n:host([picker]) {\n --ds-calendar-picker-width: calc(10 * var(--ds-unit));\n display: inline-flex;\n align-items: flex-end;\n vertical-align: bottom;\n height: var(--ds-unit);\n}\n\n.trigger {\n display: inline-flex;\n align-items: flex-end;\n gap: calc(4px * var(--ds-sf, 1));\n width: var(--ds-calendar-picker-width);\n padding-inline: 0 calc(4px * var(--ds-sf, 1));\n text-align: start;\n cursor: pointer;\n}\n.trigger:disabled { cursor: default; }\n.trigger .icon,\n.trigger .arrow { flex: 0 0 auto; }\n.trigger .text {\n flex: 1 1 auto;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.trigger[data-empty] .text { color: var(--ds-title-color); }\n.trigger[aria-expanded=\"true\"] .arrow { transform: rotate(180deg); }\n\n/* The month's panel, on the menu's frame. */\n.popover {\n position: fixed;\n inset: auto;\n box-sizing: border-box;\n margin: 0;\n padding: calc(var(--ds-unit) / 2 - 1px);\n border: 1px solid var(--ds-border-color);\n border-radius: var(--ds-radius-card);\n background: var(--ds-paper);\n color: var(--ds-text-color);\n box-shadow: none;\n overflow: visible;\n}\n.popover:not(:popover-open) { display: none; }\n\n/* The days to type: a row of one square for each end, its time on the row below; one square spare after. */\n.fields { margin-block-end: var(--ds-unit); }\n.field-row {\n display: flex;\n align-items: flex-end;\n gap: calc(var(--ds-unit) / 2);\n height: var(--ds-unit);\n}\n.field { flex: 1 1 auto; min-width: 0; }\n.clock { flex: 1 1 auto; min-width: 0; }\n.fields, .options { width: calc(7 * var(--ds-unit)); }\n\n/* Include time and Clear, each one square, the words on the sixteen. */\n.option {\n box-sizing: border-box;\n display: flex;\n align-items: flex-end;\n justify-content: space-between;\n gap: var(--ds-unit);\n width: 100%;\n height: var(--ds-unit);\n margin: 0;\n padding: 0 calc(4px * var(--ds-sf, 1));\n border: 0;\n border-radius: var(--ds-radius);\n background: transparent;\n color: var(--ds-text-color);\n font: inherit;\n letter-spacing: inherit;\n text-align: start;\n cursor: pointer;\n}\n.option:hover:not(:disabled) { background: var(--ds-row-fill-hover, var(--ds-fill)); }\n.option:focus-visible { outline: 2px solid var(--ds-focus-ring); outline-offset: -2px; }\n.option:disabled { color: var(--ds-title-color); cursor: default; }\n.option .ds-switch { flex: 0 0 auto; }\n\n/* A separator: one square with a 1px line through its middle. */\n.separator {\n position: relative;\n height: var(--ds-unit);\n}\n.separator::after {\n position: absolute;\n inset-inline: 0;\n top: calc(50% - 0.5px);\n height: 1px;\n background: var(--ds-border-color);\n content: \"\";\n}\n\n@media (prefers-reduced-motion: no-preference) {\n .popover:popover-open {\n animation: ds-calendar-picker-in 140ms cubic-bezier(0.22, 1, 0.36, 1);\n }\n .trigger .arrow { transition: transform 140ms ease; }\n}\n@keyframes ds-calendar-picker-in {\n from { opacity: 0; transform: translateY(calc(-4px * var(--ds-sf, 1))); }\n to { opacity: 1; transform: none; }\n}\n";
|
|
10934
10932
|
//#endregion
|
|
10935
10933
|
//#region DS1/3-unit/ds-calendar.ts
|
|
10936
10934
|
var _Calendar;
|
|
10937
10935
|
var whole$1 = (value, least, most, fallback) => typeof value === "number" && Number.isFinite(value) ? Math.max(least, Math.min(most, Math.floor(value))) : fallback;
|
|
10936
|
+
var TIME = /^([01]\d|2[0-3]):([0-5]\d)$/;
|
|
10937
|
+
/** Reads a value: `2026-10-21`, `2026-10-21T14:30`, or two of them joined by `/`. */
|
|
10938
|
+
function readDateValue(value) {
|
|
10939
|
+
const read = (part) => {
|
|
10940
|
+
const [day = "", time = ""] = (part ?? "").trim().split("T");
|
|
10941
|
+
if (!isDay(day)) return void 0;
|
|
10942
|
+
const clock = time.slice(0, 5);
|
|
10943
|
+
return {
|
|
10944
|
+
day,
|
|
10945
|
+
time: TIME.test(clock) ? clock : ""
|
|
10946
|
+
};
|
|
10947
|
+
};
|
|
10948
|
+
const [first, second] = (value ?? "").split("/");
|
|
10949
|
+
let start = read(first), end = read(second);
|
|
10950
|
+
if (start && end && `${end.day}T${end.time}` < `${start.day}T${start.time}`) [start, end] = [end, start];
|
|
10951
|
+
return {
|
|
10952
|
+
start,
|
|
10953
|
+
end
|
|
10954
|
+
};
|
|
10955
|
+
}
|
|
10956
|
+
/**
|
|
10957
|
+
* Writes a value from its ends, the times only with `time`. An end that is
|
|
10958
|
+
* the same moment as the start leaves the value one day.
|
|
10959
|
+
*/
|
|
10960
|
+
function writeDateValue(start, end, options) {
|
|
10961
|
+
if (!start) return "";
|
|
10962
|
+
const part = (side) => options.time && side.time ? `${side.day}T${side.time}` : side.day;
|
|
10963
|
+
return end && part(end) !== part(start) ? `${part(start)}/${part(end)}` : part(start);
|
|
10964
|
+
}
|
|
10965
|
+
/** Reads what a person typed: a day written `YYYY-MM-DD`, or a date the browser can read ("Oct 21, 2026"). */
|
|
10966
|
+
function parseTypedDay(text) {
|
|
10967
|
+
const trimmed = text.trim();
|
|
10968
|
+
if (isDay(trimmed)) return trimmed;
|
|
10969
|
+
const moment = Date.parse(trimmed);
|
|
10970
|
+
return Number.isFinite(moment) ? dayOf(new Date(moment)) : null;
|
|
10971
|
+
}
|
|
10972
|
+
var openPickers = /* @__PURE__ */ new Set();
|
|
10938
10973
|
/**
|
|
10939
10974
|
* @element ds-calendar
|
|
10940
10975
|
* @prop {string} month - The month shown, `YYYY-MM` (or a day in it). The
|
|
10941
10976
|
* selected day's month, or today's, when left out; the arrows change it.
|
|
10942
|
-
* @prop {string} value - The selected day, `YYYY-MM-DD
|
|
10943
|
-
*
|
|
10977
|
+
* @prop {string} value - The selected day, `YYYY-MM-DD`, or a range,
|
|
10978
|
+
* `YYYY-MM-DD/YYYY-MM-DD`; in a picker either end may carry a time
|
|
10979
|
+
* (`2026-10-21T09:00`).
|
|
10980
|
+
* @prop {boolean} selectable - Pressing a day selects it and fires `change`:
|
|
10981
|
+
* the first press one day, the next the end of a range from it.
|
|
10982
|
+
* @prop {boolean} picker - A field one control high that opens the small
|
|
10983
|
+
* month below it, with the days to type, Include time and Clear.
|
|
10944
10984
|
* @prop {boolean} compact - One square per day, no events written out: the
|
|
10945
10985
|
* small month.
|
|
10946
10986
|
* @prop {number} dayWidth - Squares per day (`day-width`): 4 by default, 1
|
|
@@ -10951,8 +10991,6 @@ var whole$1 = (value, least, most, fallback) => typeof value === "number" && Num
|
|
|
10951
10991
|
* @prop {boolean} fixed - Always draw six weeks, so the month keeps its height.
|
|
10952
10992
|
* @prop {boolean} outsideDays - Draw the days of the months before and after
|
|
10953
10993
|
* in the title grey (`outside-days`); pressing one moves there.
|
|
10954
|
-
* @prop {boolean} range - A selectable calendar chooses a first and a last
|
|
10955
|
-
* day; `value` is then `YYYY-MM-DD/YYYY-MM-DD`.
|
|
10956
10994
|
* @prop {boolean} noHeader - Leave out the title and arrows (`no-header`).
|
|
10957
10995
|
* @prop {boolean} noToday - Leave out the Today button (`no-today`).
|
|
10958
10996
|
* @prop {string} min - The first day a person may choose.
|
|
@@ -10960,24 +10998,42 @@ var whole$1 = (value, least, most, fallback) => typeof value === "number" && Num
|
|
|
10960
10998
|
* @prop {string} weekStart - The week's first day (`week-start`), 0–6 from
|
|
10961
10999
|
* Sunday or its English name; the language's own by default.
|
|
10962
11000
|
* @prop {string} today - The day drawn as today; the reader's own by default.
|
|
11001
|
+
* @prop {string} label - The grid's name, or a picker's: a translation key,
|
|
11002
|
+
* or literal words with `literal`.
|
|
11003
|
+
* @prop {string} name - The form field's name.
|
|
11004
|
+
* @prop {string} placeholder - A picker's words before a day is chosen; the
|
|
11005
|
+
* shared "Choose a date" by default.
|
|
11006
|
+
* @prop {string} length - How a picker writes a day: `short`, `medium` (the
|
|
11007
|
+
* default) or `long`.
|
|
11008
|
+
* @prop {boolean} time - A picker chooses a time with each day (Include time).
|
|
11009
|
+
* @prop {boolean} required - A form needs a value; a picker leaves Clear out.
|
|
11010
|
+
* @prop {boolean} disabled - A picker cannot be opened.
|
|
11011
|
+
* @prop {boolean} open - A picker's month is open.
|
|
10963
11012
|
* @prop {CalendarEvent[]} events - What happens on the days (property only).
|
|
10964
11013
|
*
|
|
10965
11014
|
* @fires day-press - A day was pressed or chosen with Enter or Space;
|
|
10966
11015
|
* `{ day, events }`. Cancelable: cancelled, a selectable calendar keeps its value.
|
|
10967
|
-
* @fires change - A person selected a day
|
|
11016
|
+
* @fires change - A person selected a day or ended a range;
|
|
11017
|
+
* `{ value, previous, start, end }`, `end` empty while it is still to come.
|
|
11018
|
+
* @fires input - A picker's value changed, the same moment as `change`.
|
|
10968
11019
|
* @fires event-press - An event was pressed; `{ event, day }`.
|
|
10969
11020
|
* @fires navigate - A person moved to another month; `{ month }`.
|
|
11021
|
+
* @fires ds-calendar-toggle - A picker's month opened or closed; `{ open }`.
|
|
10970
11022
|
*
|
|
10971
11023
|
* @example
|
|
10972
11024
|
* <ds-calendar month="2026-10" week-numbers></ds-calendar>
|
|
10973
|
-
* <ds-calendar compact selectable value="2026-10-18"></ds-calendar>
|
|
10974
|
-
* <ds-calendar
|
|
11025
|
+
* <ds-calendar compact selectable value="2026-10-18/2026-10-24"></ds-calendar>
|
|
11026
|
+
* <ds-calendar picker label="When" literal name="when" value="2026-10-21/2026-10-24"></ds-calendar>
|
|
10975
11027
|
*/
|
|
10976
11028
|
var Calendar = class extends CalendarBase {
|
|
10977
11029
|
constructor() {
|
|
10978
11030
|
super();
|
|
10979
11031
|
this.weeksRun = "rows";
|
|
10980
11032
|
this.byDay = /* @__PURE__ */ new Map();
|
|
11033
|
+
this.internals = typeof this.attachInternals === "function" ? this.attachInternals() : null;
|
|
11034
|
+
this.initial = "";
|
|
11035
|
+
this.shown = false;
|
|
11036
|
+
this.focusMonth = false;
|
|
10981
11037
|
this.onKeyDown = (event) => {
|
|
10982
11038
|
const cell = event.target.closest("[data-day]");
|
|
10983
11039
|
if (!cell) return;
|
|
@@ -10987,9 +11043,9 @@ var Calendar = class extends CalendarBase {
|
|
|
10987
11043
|
this.press(day);
|
|
10988
11044
|
return;
|
|
10989
11045
|
}
|
|
10990
|
-
if (event.key === "Escape" && this.
|
|
11046
|
+
if (event.key === "Escape" && this.unfolded) {
|
|
10991
11047
|
event.stopPropagation();
|
|
10992
|
-
this.
|
|
11048
|
+
this.unfolded = void 0;
|
|
10993
11049
|
return;
|
|
10994
11050
|
}
|
|
10995
11051
|
const target = this.keyTarget(event, day);
|
|
@@ -11005,7 +11061,7 @@ var Calendar = class extends CalendarBase {
|
|
|
11005
11061
|
if (!cell) return;
|
|
11006
11062
|
const day = cell.dataset.day;
|
|
11007
11063
|
if (find("[data-more]")) {
|
|
11008
|
-
this.
|
|
11064
|
+
this.unfolded = this.unfolded === day ? void 0 : day;
|
|
11009
11065
|
return;
|
|
11010
11066
|
}
|
|
11011
11067
|
const chip = find("[data-event]");
|
|
@@ -11019,14 +11075,93 @@ var Calendar = class extends CalendarBase {
|
|
|
11019
11075
|
if (!sameMonth(day, this.shownMonth)) this.showMonth(day, true);
|
|
11020
11076
|
};
|
|
11021
11077
|
this.onPointerOver = (event) => {
|
|
11022
|
-
if (!this.
|
|
11023
|
-
const { start, end } = readRange(this.value);
|
|
11024
|
-
if (!start || end) return;
|
|
11078
|
+
if (!this.endPending || !this.selectable) return;
|
|
11025
11079
|
const day = event.composedPath().find((node) => node instanceof HTMLElement && node.dataset?.day)?.dataset.day;
|
|
11026
11080
|
if (day !== this.hoverDay && (!day || this.allowed(day))) this.hoverDay = day;
|
|
11027
11081
|
};
|
|
11028
11082
|
this.onFocusOut = (event) => {
|
|
11029
|
-
if (this.
|
|
11083
|
+
if (this.unfolded && !(event.relatedTarget instanceof Node && this.renderRoot.contains(event.relatedTarget))) this.unfolded = void 0;
|
|
11084
|
+
};
|
|
11085
|
+
this.place = () => {
|
|
11086
|
+
const panel = this.panel, trigger = this.trigger;
|
|
11087
|
+
if (!this.shown || !panel || !trigger) return;
|
|
11088
|
+
const rect = trigger.getBoundingClientRect();
|
|
11089
|
+
const view = this.ownerDocument.defaultView;
|
|
11090
|
+
const viewport = view.visualViewport;
|
|
11091
|
+
const left = viewport?.offsetLeft ?? 0, top = viewport?.offsetTop ?? 0;
|
|
11092
|
+
const width = viewport?.width ?? view.innerWidth, height = viewport?.height ?? view.innerHeight;
|
|
11093
|
+
const box = panel.getBoundingClientRect();
|
|
11094
|
+
const gap = (parseFloat(getComputedStyle(panel).paddingTop) || 9) + 1;
|
|
11095
|
+
const square = Math.max(rect.height, gap * 2);
|
|
11096
|
+
const foot = rect.bottom, head = rect.bottom - square;
|
|
11097
|
+
const below = top + height - foot - 2 * gap, above = head - top - 2 * gap;
|
|
11098
|
+
const up = below < box.height && above > below;
|
|
11099
|
+
const x = getComputedStyle(this).direction === "rtl" ? rect.right - box.width : rect.left;
|
|
11100
|
+
panel.style.left = `${Math.max(left + gap, Math.min(x, left + width - gap - box.width))}px`;
|
|
11101
|
+
panel.style.top = `${Math.max(top + gap, up ? head - gap - box.height : foot + gap)}px`;
|
|
11102
|
+
};
|
|
11103
|
+
this.onOutside = (event) => {
|
|
11104
|
+
if (!event.composedPath().includes(this)) this.open = false;
|
|
11105
|
+
};
|
|
11106
|
+
this.toggle = () => {
|
|
11107
|
+
if (this.disabled) return;
|
|
11108
|
+
this.focusMonth = false;
|
|
11109
|
+
this.open = !this.open;
|
|
11110
|
+
};
|
|
11111
|
+
this.onTriggerKey = (event) => {
|
|
11112
|
+
if (this.disabled) return;
|
|
11113
|
+
if (event.key === "ArrowDown" || event.key === "ArrowUp" || (event.key === "Enter" || event.key === " ") && !this.open) {
|
|
11114
|
+
event.preventDefault();
|
|
11115
|
+
this.focusMonth = true;
|
|
11116
|
+
if (this.open) this.focusPickerDay();
|
|
11117
|
+
else this.open = true;
|
|
11118
|
+
}
|
|
11119
|
+
};
|
|
11120
|
+
this.onPanelKey = (event) => {
|
|
11121
|
+
if (event.key === "Escape" && !event.defaultPrevented) {
|
|
11122
|
+
event.preventDefault();
|
|
11123
|
+
event.stopPropagation();
|
|
11124
|
+
this.open = false;
|
|
11125
|
+
}
|
|
11126
|
+
};
|
|
11127
|
+
this.onPanelFocusOut = (event) => {
|
|
11128
|
+
const next = event.relatedTarget;
|
|
11129
|
+
if (this.open && next instanceof Node && !this.contains(next) && !this.renderRoot.contains(next)) this.open = false;
|
|
11130
|
+
};
|
|
11131
|
+
this.picked = (event) => {
|
|
11132
|
+
event.stopPropagation();
|
|
11133
|
+
const { start, end } = this.ends;
|
|
11134
|
+
const first = {
|
|
11135
|
+
day: event.detail.start,
|
|
11136
|
+
time: start?.time || (this.time ? "09:00" : "")
|
|
11137
|
+
};
|
|
11138
|
+
if (!event.detail.end) {
|
|
11139
|
+
this.write(first, void 0);
|
|
11140
|
+
return;
|
|
11141
|
+
}
|
|
11142
|
+
const last = {
|
|
11143
|
+
day: event.detail.end,
|
|
11144
|
+
time: end?.time || (this.time ? "10:00" : "")
|
|
11145
|
+
};
|
|
11146
|
+
this.write(first, last);
|
|
11147
|
+
if (!this.time) this.open = false;
|
|
11148
|
+
};
|
|
11149
|
+
this.setTime = () => {
|
|
11150
|
+
this.time = !this.time;
|
|
11151
|
+
const { start, end } = this.ends;
|
|
11152
|
+
const timed = (side, clock) => side ? {
|
|
11153
|
+
...side,
|
|
11154
|
+
time: this.time ? side.time || clock : ""
|
|
11155
|
+
} : void 0;
|
|
11156
|
+
this.write(timed(start, "09:00"), timed(end ?? (this.time ? start : void 0), "10:00"));
|
|
11157
|
+
};
|
|
11158
|
+
this.passPress = (event) => {
|
|
11159
|
+
const control = event.currentTarget.querySelector(".ds-switch");
|
|
11160
|
+
if (control && !event.composedPath().includes(control)) control.click();
|
|
11161
|
+
};
|
|
11162
|
+
this.clear = () => {
|
|
11163
|
+
this.commit("");
|
|
11164
|
+
this.open = false;
|
|
11030
11165
|
};
|
|
11031
11166
|
this.compact = false;
|
|
11032
11167
|
this.weekNumbers = false;
|
|
@@ -11034,6 +11169,25 @@ var Calendar = class extends CalendarBase {
|
|
|
11034
11169
|
this.outsideDays = false;
|
|
11035
11170
|
this.noHeader = false;
|
|
11036
11171
|
this.noToday = false;
|
|
11172
|
+
this.picker = false;
|
|
11173
|
+
this.time = false;
|
|
11174
|
+
this.required = false;
|
|
11175
|
+
this.disabled = false;
|
|
11176
|
+
this.open = false;
|
|
11177
|
+
}
|
|
11178
|
+
disconnectedCallback() {
|
|
11179
|
+
this.hide(false);
|
|
11180
|
+
super.disconnectedCallback();
|
|
11181
|
+
}
|
|
11182
|
+
firstUpdated() {
|
|
11183
|
+
this.initial = this.value;
|
|
11184
|
+
}
|
|
11185
|
+
/** The form was reset: back to the value it started with. */
|
|
11186
|
+
formResetCallback() {
|
|
11187
|
+
this.value = this.initial;
|
|
11188
|
+
}
|
|
11189
|
+
formDisabledCallback(disabled) {
|
|
11190
|
+
this.disabled = disabled;
|
|
11037
11191
|
}
|
|
11038
11192
|
/** The first of the month shown. */
|
|
11039
11193
|
get shownMonth() {
|
|
@@ -11054,13 +11208,29 @@ var Calendar = class extends CalendarBase {
|
|
|
11054
11208
|
this.style.setProperty("--ds-calendar-lines", String(this.eventLines));
|
|
11055
11209
|
this.toggleAttribute("data-events", (this.events ?? []).length > 0);
|
|
11056
11210
|
this.toggleAttribute("data-roomy", this.squaresPerDay >= 2);
|
|
11211
|
+
if (this.picker && changed.has("value") && this.value) {
|
|
11212
|
+
const { start, end } = this.ends;
|
|
11213
|
+
if (!start) this.value = "";
|
|
11214
|
+
else if (start.time || end?.time) this.time = true;
|
|
11215
|
+
}
|
|
11216
|
+
if (changed.has("disabled") && this.disabled) this.open = false;
|
|
11217
|
+
}
|
|
11218
|
+
updated(changed) {
|
|
11219
|
+
super.updated(changed);
|
|
11220
|
+
if (changed.has("value") || changed.has("required")) {
|
|
11221
|
+
this.internals?.setFormValue(this.value || null);
|
|
11222
|
+
if (this.required && !this.value) this.internals?.setValidity({ valueMissing: true }, this.pickerWords(void 0, "Choose a date"), this.trigger ?? void 0);
|
|
11223
|
+
else this.internals?.setValidity({});
|
|
11224
|
+
}
|
|
11225
|
+
if (changed.has("open") || changed.has("picker")) if (this.open && this.picker) this.show();
|
|
11226
|
+
else this.hide(changed.get("open") === true);
|
|
11057
11227
|
}
|
|
11058
11228
|
/** Shows another month and says so with `navigate`. */
|
|
11059
11229
|
showMonth(month, announce = false) {
|
|
11060
11230
|
const first = readMonth(month);
|
|
11061
11231
|
if (!first || first === this.shownMonth) return;
|
|
11062
11232
|
this.month = first.slice(0, 7);
|
|
11063
|
-
this.
|
|
11233
|
+
this.unfolded = void 0;
|
|
11064
11234
|
if (announce) this.announceMonth(first);
|
|
11065
11235
|
}
|
|
11066
11236
|
/** The month before, as the previous arrow does. */
|
|
@@ -11118,7 +11288,7 @@ var Calendar = class extends CalendarBase {
|
|
|
11118
11288
|
const isToday = day === this.todayDay;
|
|
11119
11289
|
const { selected, inside, first, last } = this.selection(day);
|
|
11120
11290
|
const allowed = this.allowed(day);
|
|
11121
|
-
const unfolded = this.
|
|
11291
|
+
const unfolded = this.unfolded === day;
|
|
11122
11292
|
const shown = unfolded || events.length <= lines ? events : events.slice(0, Math.max(0, lines - 1));
|
|
11123
11293
|
const hidden = events.length - shown.length;
|
|
11124
11294
|
return b$1`<div
|
|
@@ -11160,6 +11330,7 @@ var Calendar = class extends CalendarBase {
|
|
|
11160
11330
|
</div>`;
|
|
11161
11331
|
}
|
|
11162
11332
|
render() {
|
|
11333
|
+
if (this.picker) return this.renderPicker();
|
|
11163
11334
|
const month = this.shownMonth;
|
|
11164
11335
|
const first = this.firstDay;
|
|
11165
11336
|
const weeks = monthWeeks(month, first, this.fixed);
|
|
@@ -11173,7 +11344,7 @@ var Calendar = class extends CalendarBase {
|
|
|
11173
11344
|
part="grid"
|
|
11174
11345
|
role="grid"
|
|
11175
11346
|
aria-label=${this.nameOr(monthTitle(month))}
|
|
11176
|
-
aria-multiselectable=${this.selectable ?
|
|
11347
|
+
aria-multiselectable=${this.selectable ? "true" : A}
|
|
11177
11348
|
@keydown=${this.onKeyDown}
|
|
11178
11349
|
@click=${this.onClick}
|
|
11179
11350
|
>
|
|
@@ -11184,355 +11355,276 @@ var Calendar = class extends CalendarBase {
|
|
|
11184
11355
|
</div>
|
|
11185
11356
|
</div>`;
|
|
11186
11357
|
}
|
|
11187
|
-
|
|
11188
|
-
|
|
11189
|
-
|
|
11190
|
-
...CalendarBase.properties,
|
|
11191
|
-
month: {
|
|
11192
|
-
type: String,
|
|
11193
|
-
reflect: true
|
|
11194
|
-
},
|
|
11195
|
-
compact: {
|
|
11196
|
-
type: Boolean,
|
|
11197
|
-
reflect: true
|
|
11198
|
-
},
|
|
11199
|
-
dayWidth: {
|
|
11200
|
-
type: Number,
|
|
11201
|
-
attribute: "day-width"
|
|
11202
|
-
},
|
|
11203
|
-
lines: { type: Number },
|
|
11204
|
-
weekNumbers: {
|
|
11205
|
-
type: Boolean,
|
|
11206
|
-
attribute: "week-numbers",
|
|
11207
|
-
reflect: true
|
|
11208
|
-
},
|
|
11209
|
-
fixed: {
|
|
11210
|
-
type: Boolean,
|
|
11211
|
-
reflect: true
|
|
11212
|
-
},
|
|
11213
|
-
outsideDays: {
|
|
11214
|
-
type: Boolean,
|
|
11215
|
-
attribute: "outside-days",
|
|
11216
|
-
reflect: true
|
|
11217
|
-
},
|
|
11218
|
-
noHeader: {
|
|
11219
|
-
type: Boolean,
|
|
11220
|
-
attribute: "no-header",
|
|
11221
|
-
reflect: true
|
|
11222
|
-
},
|
|
11223
|
-
noToday: {
|
|
11224
|
-
type: Boolean,
|
|
11225
|
-
attribute: "no-today",
|
|
11226
|
-
reflect: true
|
|
11227
|
-
},
|
|
11228
|
-
open: { state: true }
|
|
11229
|
-
};
|
|
11230
|
-
_Calendar.styles = [
|
|
11231
|
-
r$3(component_metrics_default),
|
|
11232
|
-
r$3(controls_default),
|
|
11233
|
-
r$3(ds_calendar_default)
|
|
11234
|
-
];
|
|
11235
|
-
define("ds-calendar", Calendar);
|
|
11236
|
-
//#endregion
|
|
11237
|
-
//#region DS1/3-unit/styles/ds-calendar-large.css?inline
|
|
11238
|
-
var ds_calendar_large_default = "/* ds-calendar-large.css\n * The grid drawn --ds-calendar-scale times (one and a half by default): a\n * cell is a square of 30px, its lines 1.5px, its words the heading size\n * times the scale (19.5px). Weeks run in columns and the days down them; the\n * frame's corners are four tenths of a cell. Today is a red disc nine tenths\n * of a cell across, the selected day an ink square of the same size. */\n\n:host {\n --ds-calendar-cell: calc(var(--ds-unit) * var(--ds-calendar-scale, 1.5));\n --ds-calendar-stroke: calc(1px * var(--ds-calendar-scale, 1.5));\n --ds-calendar-ink: var(--ds-text-color);\n --ds-calendar-event-fill: var(--ds-apple-green);\n --ds-calendar-today: var(--ds-red-for-blood);\n --ds-calendar-today-ink: var(--ds-white, #fff);\n --ds-calendar-mark: calc(var(--ds-calendar-cell) * 0.9);\n --ds-calendar-corner: calc(var(--ds-calendar-cell) * 0.4);\n --ds-calendar-rail: calc(var(--ds-calendar-cell) * 2);\n box-sizing: border-box;\n display: block;\n min-width: 0;\n color: var(--ds-text-color);\n font-family: var(--ds-typeface-regular);\n font-feature-settings: var(--ds-font-features);\n font-size: calc(var(--ds-type-size-heading) * var(--ds-calendar-scale, 1.5));\n font-weight: var(--ds-type-weight-default);\n line-height: 1;\n letter-spacing: var(--ds-type-letterspacing-default);\n}\n:host([hidden]) { display: none !important; }\n\n.calendar { min-width: 0; }\n\n/* The title and the arrows: one cell high, over the months. */\n.header {\n display: flex;\n align-items: flex-end;\n gap: calc(4px * var(--ds-sf, 1));\n height: var(--ds-calendar-cell);\n margin-inline-start: calc(var(--ds-calendar-rail) + var(--ds-unit) / 2);\n font-size: var(--ds-type-size-default);\n line-height: var(--ds-type-lineheight-default);\n}\n.title {\n flex: 1 1 auto;\n min-width: 0;\n overflow: hidden;\n font-size: calc(var(--ds-type-size-heading) * var(--ds-calendar-scale, 1.5));\n line-height: var(--ds-calendar-cell);\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.controls { display: flex; flex: 0 0 auto; align-items: flex-end; gap: 0; }\n/* Each arrow is a chevron on its own square, as in a month. */\n.nav { flex: 0 0 auto; width: var(--ds-unit); height: var(--ds-control-height); border-radius: var(--ds-radius); color: var(--ds-title-color); }\n.nav:hover:not(:disabled) { background: var(--ds-fill); color: var(--ds-text-color); }\n:host(:dir(rtl)) .nav > ds-icon { transform: scaleX(-1); }\n\n.body {\n display: grid;\n grid-template-columns: var(--ds-calendar-rail) minmax(0, 1fr);\n column-gap: calc(var(--ds-unit) / 2);\n}\n\n/* The weekdays down the start, outside the scroll: every other one named. */\n.rail {\n display: grid;\n grid-template-rows: repeat(7, var(--ds-calendar-cell));\n padding-block-start: var(--ds-calendar-cell);\n color: var(--ds-title-color);\n font-size: var(--ds-type-size-default);\n line-height: var(--ds-type-lineheight-default);\n}\n.weekday {\n display: flex;\n align-items: center;\n justify-content: flex-end;\n white-space: nowrap;\n}\n\n.scroller {\n overflow-x: auto;\n overflow-y: hidden;\n scrollbar-width: none;\n overscroll-behavior-x: contain;\n}\n.scroller::-webkit-scrollbar { display: none; }\n\n/* The months over their weeks, one cell high, their names on its foot. */\n.months {\n display: grid;\n grid-template-columns: repeat(var(--ds-calendar-weeks), var(--ds-calendar-cell));\n height: var(--ds-calendar-cell);\n}\n.month {\n display: flex;\n align-items: flex-end;\n min-width: 0;\n padding: 0 var(--ds-calendar-stroke) calc(3px * var(--ds-calendar-scale, 1.5));\n overflow: hidden;\n white-space: nowrap;\n}\n\n/* The frame: a line all round with rounded corners; the cells draw the lines inside. */\n.frame {\n box-sizing: border-box;\n width: max-content;\n border: var(--ds-calendar-stroke) solid var(--ds-calendar-ink);\n border-radius: var(--ds-calendar-corner);\n overflow: hidden;\n}\n.grid {\n display: grid;\n grid-template-columns: repeat(var(--ds-calendar-weeks), var(--ds-calendar-cell));\n grid-template-rows: repeat(7, var(--ds-calendar-cell));\n}\n.row { display: contents; }\n.hidden {\n position: absolute;\n width: 1px;\n height: 1px;\n overflow: hidden;\n clip-path: inset(50%);\n white-space: nowrap;\n}\n\n.cell {\n box-sizing: border-box;\n display: flex;\n align-items: center;\n justify-content: center;\n width: var(--ds-calendar-cell);\n height: var(--ds-calendar-cell);\n border-block-start: var(--ds-calendar-stroke) solid var(--ds-calendar-ink);\n border-inline-start: var(--ds-calendar-stroke) solid var(--ds-calendar-ink);\n background: var(--ds-calendar-cell-fill, transparent);\n font-variant-numeric: tabular-nums;\n outline: none;\n}\n.cell[data-first-row] { border-block-start-width: 0; }\n.cell[data-first-column] { border-inline-start-width: 0; }\n.cell[data-filled] { color: var(--ds-slate); }\n:host([selectable]) .cell:not([aria-disabled=\"true\"]) { cursor: pointer; }\n:host([selectable]) .cell:not([aria-disabled=\"true\"], [data-filled]):hover { background: var(--ds-row-fill-hover, var(--ds-fill)); }\n.cell:focus-visible { outline: 2px solid var(--ds-focus-ring); outline-offset: -3px; }\n.cell[aria-disabled=\"true\"] { color: var(--ds-title-color); }\n\n.date {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: var(--ds-calendar-mark);\n height: var(--ds-calendar-mark);\n letter-spacing: 0;\n}\n.cell[data-today] .date { border-radius: 999px; background: var(--ds-calendar-today); color: var(--ds-calendar-today-ink); }\n.cell[data-selected] .date { background: var(--ds-calendar-ink); color: var(--ds-paper); }\n.cell[data-inside]:not([data-filled]) { background: color-mix(in srgb, var(--ds-calendar-ink) 12%, var(--ds-paper)); }\n.cell[data-today][data-selected] .date { border-radius: 999px; box-shadow: inset 0 0 0 var(--ds-calendar-stroke) var(--ds-calendar-today); }\n\n/* On a narrow screen the weekdays take one letter and one square. */\n@media (max-width: 720px) {\n :host { --ds-calendar-rail: var(--ds-unit); }\n .rail .weekday:not(:empty) { font-size: 0; }\n .rail .weekday:not(:empty)::after { content: attr(data-narrow); font-size: var(--ds-type-size-default); }\n}\n\n/* Activity keeps the day grid, with quiet separated squares and event colours. */\n:host([activity]) .frame { border: 0; border-radius: 0; }\n:host([activity]) .cell { position: relative; border: 0; background: none; }\n:host([activity]) .cell::before {\n content: \"\";\n position: absolute;\n inset: calc(2px * var(--ds-sf, 1));\n border-radius: calc(2px * var(--ds-sf, 1));\n background: var(--ds-calendar-cell-fill, var(--ds-fill));\n}\n:host([activity]) .date { display: none; }\n:host([activity]) .cell[data-selected]::before { outline: 1px solid var(--ds-calendar-ink); }\n";
|
|
11239
|
-
//#endregion
|
|
11240
|
-
//#region DS1/3-unit/ds-calendar-large.ts
|
|
11241
|
-
var _CalendarLarge;
|
|
11242
|
-
/** The fill for a day: one colour, or bands side by side. */
|
|
11243
|
-
function fillOf(events) {
|
|
11244
|
-
if (!events.length) return void 0;
|
|
11245
|
-
const colours = [...new Set(events.map((event) => event.color || "var(--ds-calendar-event-fill)"))];
|
|
11246
|
-
if (colours.length === 1) return colours[0];
|
|
11247
|
-
const share = 100 / colours.length;
|
|
11248
|
-
return `linear-gradient(90deg, ${colours.map((colour, index) => `${colour} ${index * share}% ${(index + 1) * share}%`).join(", ")})`;
|
|
11249
|
-
}
|
|
11250
|
-
/**
|
|
11251
|
-
* @element ds-calendar-large
|
|
11252
|
-
* @prop {string} start - The first month drawn, `YYYY-MM`; the month before
|
|
11253
|
-
* today's by default.
|
|
11254
|
-
* @prop {number} months - How many months are drawn: 6 by default.
|
|
11255
|
-
* @prop {number} scale - How many times the grid it is drawn: 1.5 by default.
|
|
11256
|
-
* @prop {string} value - The selected day, `YYYY-MM-DD`.
|
|
11257
|
-
* @prop {boolean} selectable - Pressing a day selects it and fires `change`.
|
|
11258
|
-
* @prop {boolean} noHeader - Leave out the title and arrows (`no-header`).
|
|
11259
|
-
* @prop {string} min - The first day a person may choose.
|
|
11260
|
-
* @prop {string} max - The last day a person may choose.
|
|
11261
|
-
* @prop {string} weekStart - The week's first day (`week-start`); the
|
|
11262
|
-
* language's own by default.
|
|
11263
|
-
* @prop {string} today - The day drawn as today; the reader's own by default.
|
|
11264
|
-
* @prop {CalendarEvent[]} events - What happens on the days (property only).
|
|
11265
|
-
*
|
|
11266
|
-
* @fires day-press - A day was pressed or chosen with Enter or Space; `{ day, events }`.
|
|
11267
|
-
* @fires change - A person selected a day; `{ value, previous }`.
|
|
11268
|
-
* @fires navigate - The months drawn moved on or back; `{ month }`, the first one.
|
|
11269
|
-
*
|
|
11270
|
-
* @example
|
|
11271
|
-
* <ds-calendar-large start="2026-09" months="6"></ds-calendar-large>
|
|
11272
|
-
*/
|
|
11273
|
-
var CalendarLarge = class extends CalendarBase {
|
|
11274
|
-
constructor() {
|
|
11275
|
-
super();
|
|
11276
|
-
this.weeksRun = "columns";
|
|
11277
|
-
this.byDay = /* @__PURE__ */ new Map();
|
|
11278
|
-
this.placed = false;
|
|
11279
|
-
this.frame = 0;
|
|
11280
|
-
this.onScroll = () => {
|
|
11281
|
-
cancelAnimationFrame(this.frame);
|
|
11282
|
-
this.frame = requestAnimationFrame(() => {
|
|
11283
|
-
const scroller = this.scroller;
|
|
11284
|
-
const cell = scroller?.querySelector(".cell")?.getBoundingClientRect().width;
|
|
11285
|
-
if (!scroller || !cell) return;
|
|
11286
|
-
const column = Math.min(this.weekStarts.length - 1, Math.max(0, Math.round(Math.abs(scroller.scrollLeft) / cell)));
|
|
11287
|
-
this.visible = startOfMonth(addDays(this.weekStarts[column], 3));
|
|
11288
|
-
});
|
|
11289
|
-
};
|
|
11290
|
-
this.onKeyDown = (event) => {
|
|
11291
|
-
const cell = event.target.closest("[data-day]");
|
|
11292
|
-
if (!cell) return;
|
|
11293
|
-
const day = cell.dataset.day;
|
|
11294
|
-
if (event.key === "Enter" || event.key === " ") {
|
|
11295
|
-
event.preventDefault();
|
|
11296
|
-
this.press(day);
|
|
11297
|
-
return;
|
|
11298
|
-
}
|
|
11299
|
-
const target = this.keyTarget(event, day);
|
|
11300
|
-
if (!target) return;
|
|
11301
|
-
event.preventDefault();
|
|
11302
|
-
if (target < this.weekStarts[0] || target > this.lastDay) {
|
|
11303
|
-
const by = target < this.weekStarts[0] ? -1 : 1;
|
|
11304
|
-
const first = addMonths(this.firstMonth, by);
|
|
11305
|
-
this.start = first.slice(0, 7);
|
|
11306
|
-
this.announceMonth(first);
|
|
11307
|
-
}
|
|
11308
|
-
this.focusCell(target);
|
|
11309
|
-
};
|
|
11310
|
-
this.onClick = (event) => {
|
|
11311
|
-
const cell = event.composedPath().find((node) => node instanceof HTMLElement && node.dataset?.day);
|
|
11312
|
-
if (!cell) return;
|
|
11313
|
-
const day = cell.dataset.day;
|
|
11314
|
-
this.focusDay = day;
|
|
11315
|
-
this.press(day);
|
|
11316
|
-
};
|
|
11317
|
-
this.noHeader = false;
|
|
11318
|
-
this.activity = false;
|
|
11319
|
-
}
|
|
11320
|
-
/** The first of the first month drawn. */
|
|
11321
|
-
get firstMonth() {
|
|
11322
|
-
return readMonth(this.start) ?? addMonths(startOfMonth(this.todayDay), -1);
|
|
11323
|
-
}
|
|
11324
|
-
get monthCount() {
|
|
11325
|
-
const count = this.months;
|
|
11326
|
-
return typeof count === "number" && Number.isFinite(count) ? Math.max(1, Math.min(36, Math.floor(count))) : 6;
|
|
11358
|
+
pickerWords(value, fallback) {
|
|
11359
|
+
if (value && this.literal) return value;
|
|
11360
|
+
return getText(value || fallback) || value || fallback;
|
|
11327
11361
|
}
|
|
11328
|
-
|
|
11329
|
-
|
|
11330
|
-
const first = this.firstMonth;
|
|
11331
|
-
const from = addDays(first, -((weekdayOf(first) - this.firstDay + 7) % 7));
|
|
11332
|
-
const last = addDays(addMonths(first, this.monthCount), -1);
|
|
11333
|
-
const weeks = [];
|
|
11334
|
-
for (let day = from; day <= last; day = addDays(day, 7)) weeks.push(day);
|
|
11335
|
-
return weeks;
|
|
11362
|
+
get trigger() {
|
|
11363
|
+
return this.renderRoot.querySelector(".trigger");
|
|
11336
11364
|
}
|
|
11337
|
-
get
|
|
11338
|
-
return
|
|
11365
|
+
get panel() {
|
|
11366
|
+
return this.renderRoot.querySelector(".popover");
|
|
11339
11367
|
}
|
|
11340
|
-
|
|
11341
|
-
|
|
11368
|
+
/** The small month inside the picker. */
|
|
11369
|
+
get smallMonth() {
|
|
11370
|
+
return this.renderRoot.querySelector("ds-calendar");
|
|
11342
11371
|
}
|
|
11343
|
-
|
|
11344
|
-
|
|
11345
|
-
const scale = typeof this.scale === "number" && Number.isFinite(this.scale) && this.scale > 0 ? this.scale : this.activity ? 1 : 1.5;
|
|
11346
|
-
this.style.setProperty("--ds-calendar-scale", String(scale));
|
|
11372
|
+
get ends() {
|
|
11373
|
+
return readDateValue(this.value);
|
|
11347
11374
|
}
|
|
11348
|
-
|
|
11349
|
-
|
|
11350
|
-
this.
|
|
11351
|
-
|
|
11375
|
+
/** Opens a picker's month. */
|
|
11376
|
+
show() {
|
|
11377
|
+
if (this.shown || !this.picker || this.disabled || !this.isConnected) return;
|
|
11378
|
+
const panel = this.panel;
|
|
11379
|
+
if (!panel) return;
|
|
11380
|
+
for (const other of openPickers) if (other !== this) other.open = false;
|
|
11381
|
+
openPickers.add(this);
|
|
11382
|
+
this.shown = true;
|
|
11383
|
+
this.open = true;
|
|
11384
|
+
const month = this.smallMonth;
|
|
11385
|
+
if (month) {
|
|
11386
|
+
month.month = (this.ends.start?.day || this.today || this.todayDay).slice(0, 7);
|
|
11387
|
+
month.endPending = false;
|
|
11388
|
+
}
|
|
11389
|
+
panel.showPopover?.();
|
|
11390
|
+
this.place();
|
|
11391
|
+
if (month) month.updateComplete.then(this.place);
|
|
11392
|
+
this.ownerDocument.addEventListener("pointerdown", this.onOutside, true);
|
|
11393
|
+
this.ownerDocument.addEventListener("scroll", this.place, true);
|
|
11394
|
+
window.addEventListener("resize", this.place);
|
|
11395
|
+
this.dispatchEvent(new CustomEvent("ds-calendar-toggle", {
|
|
11396
|
+
bubbles: true,
|
|
11397
|
+
composed: true,
|
|
11398
|
+
detail: { open: true }
|
|
11399
|
+
}));
|
|
11400
|
+
if (this.focusMonth) this.focusPickerDay();
|
|
11352
11401
|
}
|
|
11353
|
-
|
|
11354
|
-
|
|
11355
|
-
|
|
11402
|
+
/** Closes a picker's month, giving focus back to the field when it was inside. */
|
|
11403
|
+
hide(restore = true) {
|
|
11404
|
+
if (!this.shown) return;
|
|
11405
|
+
this.shown = false;
|
|
11406
|
+
openPickers.delete(this);
|
|
11407
|
+
const panel = this.panel;
|
|
11408
|
+
const within = panel?.matches(":focus-within");
|
|
11409
|
+
if (panel?.matches(":popover-open")) panel.hidePopover?.();
|
|
11410
|
+
this.ownerDocument.removeEventListener("pointerdown", this.onOutside, true);
|
|
11411
|
+
this.ownerDocument.removeEventListener("scroll", this.place, true);
|
|
11412
|
+
window.removeEventListener("resize", this.place);
|
|
11413
|
+
this.open = false;
|
|
11414
|
+
if (restore && within) this.trigger?.focus({ preventScroll: true });
|
|
11415
|
+
this.dispatchEvent(new CustomEvent("ds-calendar-toggle", {
|
|
11416
|
+
bubbles: true,
|
|
11417
|
+
composed: true,
|
|
11418
|
+
detail: { open: false }
|
|
11419
|
+
}));
|
|
11356
11420
|
}
|
|
11357
|
-
|
|
11358
|
-
|
|
11421
|
+
async focusPickerDay() {
|
|
11422
|
+
const month = this.smallMonth;
|
|
11423
|
+
if (!month) return;
|
|
11424
|
+
await month.updateComplete;
|
|
11425
|
+
month.renderRoot.querySelector("[data-day][tabindex=\"0\"]")?.focus({ preventScroll: true });
|
|
11359
11426
|
}
|
|
11360
|
-
|
|
11361
|
-
|
|
11427
|
+
/** Takes a new value and says so. */
|
|
11428
|
+
commit(value) {
|
|
11429
|
+
const previous = this.value || "";
|
|
11430
|
+
if (value === previous) return;
|
|
11431
|
+
this.value = value;
|
|
11432
|
+
const { start, end } = readDateValue(value);
|
|
11433
|
+
const detail = {
|
|
11434
|
+
value,
|
|
11435
|
+
previous,
|
|
11436
|
+
start: start?.day ?? "",
|
|
11437
|
+
end: end?.day ?? start?.day ?? ""
|
|
11438
|
+
};
|
|
11439
|
+
this.dispatchEvent(new CustomEvent("input", {
|
|
11440
|
+
bubbles: true,
|
|
11441
|
+
composed: true,
|
|
11442
|
+
detail
|
|
11443
|
+
}));
|
|
11444
|
+
this.dispatchEvent(new CustomEvent("change", {
|
|
11445
|
+
bubbles: true,
|
|
11446
|
+
composed: true,
|
|
11447
|
+
detail
|
|
11448
|
+
}));
|
|
11362
11449
|
}
|
|
11363
|
-
|
|
11364
|
-
|
|
11365
|
-
const scroller = this.scroller;
|
|
11366
|
-
const column = this.columnOf(day);
|
|
11367
|
-
if (!scroller || column < 0) return;
|
|
11368
|
-
const cell = scroller.querySelector(".cell")?.getBoundingClientRect().width ?? 30;
|
|
11369
|
-
const reduce = matchMedia?.("(prefers-reduced-motion: reduce)").matches;
|
|
11370
|
-
const rtl = getComputedStyle(this).direction === "rtl";
|
|
11371
|
-
scroller.scrollTo({
|
|
11372
|
-
left: (rtl ? -1 : 1) * column * cell,
|
|
11373
|
-
behavior: smooth && !reduce ? "smooth" : "auto"
|
|
11374
|
-
});
|
|
11375
|
-
this.visible = startOfMonth(day);
|
|
11450
|
+
write(start, end) {
|
|
11451
|
+
this.commit(writeDateValue(start, end, { time: this.time }));
|
|
11376
11452
|
}
|
|
11377
|
-
/**
|
|
11378
|
-
|
|
11379
|
-
const
|
|
11380
|
-
const
|
|
11381
|
-
|
|
11382
|
-
|
|
11383
|
-
this.start
|
|
11384
|
-
this.announceMonth(addMonths(first, by));
|
|
11385
|
-
this.updateComplete.then(() => this.scrollToDay(target, false));
|
|
11453
|
+
/** A day typed in a field, read when the person leaves it or presses Enter. */
|
|
11454
|
+
typed(side, input) {
|
|
11455
|
+
const { start, end } = this.ends;
|
|
11456
|
+
const text = input.value.trim();
|
|
11457
|
+
if (!text) {
|
|
11458
|
+
if (side === "start") this.commit("");
|
|
11459
|
+
else this.write(start, void 0);
|
|
11386
11460
|
return;
|
|
11387
11461
|
}
|
|
11388
|
-
|
|
11462
|
+
const day = parseTypedDay(text);
|
|
11463
|
+
if (!day) {
|
|
11464
|
+
input.value = this.fieldText(side === "start" ? start : end);
|
|
11465
|
+
return;
|
|
11466
|
+
}
|
|
11467
|
+
const next = {
|
|
11468
|
+
day,
|
|
11469
|
+
time: (side === "start" ? start : end)?.time || (this.time ? side === "start" ? "09:00" : "10:00" : "")
|
|
11470
|
+
};
|
|
11471
|
+
if (side === "start") this.write(next, end);
|
|
11472
|
+
else this.write(start ?? next, next);
|
|
11473
|
+
const month = this.smallMonth;
|
|
11474
|
+
if (month) month.month = day.slice(0, 7);
|
|
11389
11475
|
}
|
|
11390
|
-
|
|
11391
|
-
|
|
11392
|
-
|
|
11476
|
+
timed(side, input) {
|
|
11477
|
+
const { start, end } = this.ends;
|
|
11478
|
+
const clock = TIME.test(input.value) ? input.value : "";
|
|
11479
|
+
if (side === "start" && start) this.write({
|
|
11480
|
+
...start,
|
|
11481
|
+
time: clock
|
|
11482
|
+
}, end);
|
|
11483
|
+
if (side === "end" && start) this.write(start, {
|
|
11484
|
+
day: (end ?? start).day,
|
|
11485
|
+
time: clock
|
|
11486
|
+
});
|
|
11393
11487
|
}
|
|
11394
|
-
|
|
11395
|
-
|
|
11396
|
-
|
|
11488
|
+
moment(side) {
|
|
11489
|
+
const [year, month, date] = side.day.split("-").map(Number);
|
|
11490
|
+
const [hours, minutes] = (side.time || "12:00").split(":").map(Number);
|
|
11491
|
+
return Date.UTC(year, month - 1, date, hours, minutes);
|
|
11397
11492
|
}
|
|
11398
|
-
|
|
11399
|
-
|
|
11400
|
-
|
|
11401
|
-
|
|
11402
|
-
|
|
11403
|
-
|
|
11404
|
-
this.announceMonth(first);
|
|
11405
|
-
this.updateComplete.then(() => this.scrollToDay(startOfMonth(today), false));
|
|
11406
|
-
} else this.scrollToDay(startOfMonth(today));
|
|
11407
|
-
this.focusDay = today;
|
|
11493
|
+
formatter(withTime) {
|
|
11494
|
+
return dateFormatter({
|
|
11495
|
+
dateStyle: this.length ?? "medium",
|
|
11496
|
+
...withTime ? { timeStyle: "short" } : {},
|
|
11497
|
+
timeZone: "UTC"
|
|
11498
|
+
});
|
|
11408
11499
|
}
|
|
11409
|
-
|
|
11410
|
-
|
|
11411
|
-
for (const day of [
|
|
11412
|
-
this.focusDay,
|
|
11413
|
-
this.chosen.start,
|
|
11414
|
-
this.todayDay
|
|
11415
|
-
]) if (day && day >= first && day <= last) return day;
|
|
11416
|
-
return this.firstMonth;
|
|
11500
|
+
fieldText(side) {
|
|
11501
|
+
return side ? this.formatter(false).format(this.moment(side)) : "";
|
|
11417
11502
|
}
|
|
11418
|
-
|
|
11419
|
-
|
|
11420
|
-
const
|
|
11421
|
-
|
|
11422
|
-
|
|
11423
|
-
|
|
11424
|
-
|
|
11425
|
-
@click=${() => which === "previous" ? this.previousMonth() : this.nextMonth()}
|
|
11426
|
-
><ds-icon type=${which === "previous" ? "chevron-left" : "chevron-right"} size="large" aria-hidden="true"></ds-icon></button>`;
|
|
11427
|
-
return b$1`<div class="header" part="header">
|
|
11428
|
-
<span class="title" aria-live="polite">${monthTitle(this.visible ?? this.firstMonth)}</span>
|
|
11429
|
-
<span class="controls">
|
|
11430
|
-
${arrow("previous")}
|
|
11431
|
-
<button class="ds-button ds-button--secondary" part="today" type="button" @click=${() => this.showToday()}>${this.words("Today")}</button>
|
|
11432
|
-
${arrow("next")}
|
|
11433
|
-
</span>
|
|
11434
|
-
</div>`;
|
|
11503
|
+
/** The face's words: one day, or a range written as the language writes one ("Oct 21 – 24, 2026"). */
|
|
11504
|
+
faceText() {
|
|
11505
|
+
const { start, end } = this.ends;
|
|
11506
|
+
if (!start) return this.pickerWords(this.placeholder, "Choose a date");
|
|
11507
|
+
const formatter = this.formatter(Boolean(start.time || end?.time));
|
|
11508
|
+
if (!end) return formatter.format(this.moment(start));
|
|
11509
|
+
return formatter.formatRange ? formatter.formatRange(this.moment(start), this.moment(end)) : `${formatter.format(this.moment(start))} – ${formatter.format(this.moment(end))}`;
|
|
11435
11510
|
}
|
|
11436
|
-
|
|
11437
|
-
const
|
|
11438
|
-
|
|
11439
|
-
|
|
11440
|
-
|
|
11441
|
-
|
|
11442
|
-
|
|
11443
|
-
|
|
11444
|
-
|
|
11445
|
-
|
|
11446
|
-
|
|
11447
|
-
|
|
11448
|
-
|
|
11449
|
-
|
|
11450
|
-
|
|
11451
|
-
|
|
11452
|
-
|
|
11453
|
-
|
|
11454
|
-
|
|
11455
|
-
|
|
11456
|
-
|
|
11457
|
-
|
|
11458
|
-
|
|
11459
|
-
|
|
11460
|
-
|
|
11461
|
-
|
|
11462
|
-
|
|
11463
|
-
|
|
11464
|
-
|
|
11511
|
+
renderEnd(side, value, name) {
|
|
11512
|
+
const label = side === "start" ? name : `${name}, ${this.pickerWords(void 0, "End date")}`;
|
|
11513
|
+
return b$1`<div class="field-row" part="field">
|
|
11514
|
+
<input
|
|
11515
|
+
class="ds-input field"
|
|
11516
|
+
type="text"
|
|
11517
|
+
autocomplete="off"
|
|
11518
|
+
aria-label=${label}
|
|
11519
|
+
placeholder=${side === "start" ? this.pickerWords(this.placeholder, "Choose a date") : this.pickerWords(void 0, "End date")}
|
|
11520
|
+
.value=${this.fieldText(value)}
|
|
11521
|
+
@change=${(event) => this.typed(side, event.target)}
|
|
11522
|
+
@keydown=${(event) => {
|
|
11523
|
+
if (event.key === "Enter") {
|
|
11524
|
+
event.preventDefault();
|
|
11525
|
+
this.typed(side, event.target);
|
|
11526
|
+
}
|
|
11527
|
+
}}
|
|
11528
|
+
/>
|
|
11529
|
+
</div>
|
|
11530
|
+
${this.time ? b$1`<div class="field-row" part="field">
|
|
11531
|
+
<input
|
|
11532
|
+
class="ds-input clock"
|
|
11533
|
+
type="time"
|
|
11534
|
+
aria-label=${`${label}, ${this.pickerWords(void 0, "Time")}`}
|
|
11535
|
+
.value=${value?.time ?? ""}
|
|
11536
|
+
?disabled=${!this.ends.start}
|
|
11537
|
+
@change=${(event) => this.timed(side, event.target)}
|
|
11538
|
+
/>
|
|
11539
|
+
</div>` : A}`;
|
|
11540
|
+
}
|
|
11541
|
+
renderPicker() {
|
|
11542
|
+
const { start, end } = this.ends;
|
|
11543
|
+
const text = this.faceText();
|
|
11544
|
+
const name = this.label ? this.pickerWords(this.label, this.label) : this.pickerWords(void 0, "Date");
|
|
11545
|
+
const days = start ? end ? `${start.day}/${end.day}` : start.day : "";
|
|
11546
|
+
return b$1`<button
|
|
11547
|
+
class="ds-select trigger"
|
|
11548
|
+
part="trigger"
|
|
11549
|
+
type="button"
|
|
11550
|
+
aria-haspopup="dialog"
|
|
11551
|
+
aria-expanded=${String(this.open)}
|
|
11552
|
+
aria-label=${start ? `${name}, ${text}` : name}
|
|
11553
|
+
?disabled=${this.disabled}
|
|
11554
|
+
?data-empty=${!start}
|
|
11555
|
+
@click=${this.toggle}
|
|
11556
|
+
@keydown=${this.onTriggerKey}
|
|
11557
|
+
>
|
|
11558
|
+
<ds-icon class="icon" type="calendar" aria-hidden="true"></ds-icon>
|
|
11559
|
+
<span class="text">${text}</span>
|
|
11560
|
+
<ds-icon class="arrow" type="down" aria-hidden="true"></ds-icon>
|
|
11561
|
+
</button>
|
|
11562
|
+
<div
|
|
11563
|
+
class="popover"
|
|
11564
|
+
part="popover"
|
|
11565
|
+
popover="manual"
|
|
11566
|
+
role="dialog"
|
|
11567
|
+
aria-label=${name}
|
|
11568
|
+
@keydown=${this.onPanelKey}
|
|
11569
|
+
@focusout=${this.onPanelFocusOut}
|
|
11570
|
+
>
|
|
11571
|
+
<div class="fields">
|
|
11572
|
+
${this.renderEnd("start", start, name)}
|
|
11573
|
+
${this.renderEnd("end", start ? end ?? start : void 0, name)}
|
|
11465
11574
|
</div>
|
|
11466
|
-
<
|
|
11467
|
-
|
|
11468
|
-
|
|
11469
|
-
|
|
11470
|
-
|
|
11471
|
-
|
|
11472
|
-
|
|
11473
|
-
|
|
11474
|
-
|
|
11475
|
-
|
|
11476
|
-
|
|
11477
|
-
|
|
11478
|
-
|
|
11479
|
-
|
|
11480
|
-
|
|
11481
|
-
|
|
11482
|
-
|
|
11483
|
-
const events = this.eventsOn(day);
|
|
11484
|
-
const isToday = day === today;
|
|
11485
|
-
const { selected, inside } = this.selection(day);
|
|
11486
|
-
const written = isToday || selected || events.length > 0 && ends.has(day);
|
|
11487
|
-
const fill = fillOf(events);
|
|
11488
|
-
return b$1`<div
|
|
11489
|
-
role="gridcell"
|
|
11490
|
-
class="cell"
|
|
11491
|
-
part=${[
|
|
11492
|
-
"cell",
|
|
11493
|
-
isToday ? "today" : "",
|
|
11494
|
-
selected ? "selected" : "",
|
|
11495
|
-
events.length ? "filled" : ""
|
|
11496
|
-
].filter(Boolean).join(" ")}
|
|
11497
|
-
data-day=${day}
|
|
11498
|
-
tabindex=${day === tab ? 0 : -1}
|
|
11499
|
-
aria-label=${this.cellLabel(day, events)}
|
|
11500
|
-
title=${this.activity ? this.cellLabel(day, events) : A}
|
|
11501
|
-
aria-selected=${this.selectable ? String(selected || inside) : A}
|
|
11502
|
-
aria-current=${isToday ? "date" : A}
|
|
11503
|
-
aria-disabled=${this.allowed(day) ? A : "true"}
|
|
11504
|
-
?data-today=${isToday}
|
|
11505
|
-
?data-selected=${selected}
|
|
11506
|
-
?data-inside=${inside}
|
|
11507
|
-
?data-filled=${events.length > 0}
|
|
11508
|
-
?data-first-row=${row === 0}
|
|
11509
|
-
?data-first-column=${column === 0}
|
|
11510
|
-
style=${`grid-row: ${row + 1}; grid-column: ${column + 1};${fill ? ` --ds-calendar-cell-fill: ${fill};` : ""}`}
|
|
11511
|
-
>${written ? b$1`<span class="date" aria-hidden="true">${dateNumber(day)}</span>` : A}</div>`;
|
|
11512
|
-
})}
|
|
11513
|
-
</div>`)}
|
|
11514
|
-
</div>
|
|
11575
|
+
<ds-calendar
|
|
11576
|
+
compact
|
|
11577
|
+
selectable
|
|
11578
|
+
fixed
|
|
11579
|
+
outside-days
|
|
11580
|
+
.value=${days}
|
|
11581
|
+
.min=${this.min}
|
|
11582
|
+
.max=${this.max}
|
|
11583
|
+
.weekStart=${this.weekStart}
|
|
11584
|
+
.today=${this.today}
|
|
11585
|
+
@change=${this.picked}
|
|
11586
|
+
></ds-calendar>
|
|
11587
|
+
<div class="options" part="options">
|
|
11588
|
+
<div class="separator" aria-hidden="true"></div>
|
|
11589
|
+
<div class="option" @click=${this.passPress}>
|
|
11590
|
+
<span>${this.pickerWords(void 0, "Include time")}</span>
|
|
11591
|
+
<button class="ds-switch" type="button" role="switch" aria-label=${this.pickerWords(void 0, "Include time")} aria-checked=${String(this.time)} @click=${this.setTime}></button>
|
|
11515
11592
|
</div>
|
|
11593
|
+
${this.required ? A : b$1`<div class="separator" aria-hidden="true"></div>
|
|
11594
|
+
<button class="option clear" part="clear" type="button" ?disabled=${!start} @click=${this.clear}>${this.pickerWords(void 0, "Clear")}</button>`}
|
|
11516
11595
|
</div>
|
|
11517
|
-
</div
|
|
11518
|
-
</div>`;
|
|
11519
|
-
}
|
|
11520
|
-
updated(changed) {
|
|
11521
|
-
super.updated(changed);
|
|
11522
|
-
if (this.placed && changed.has("start") && this.visible && !this.focusDay) this.scrollToDay(this.visible, false);
|
|
11596
|
+
</div>`;
|
|
11523
11597
|
}
|
|
11524
11598
|
};
|
|
11525
|
-
|
|
11526
|
-
|
|
11599
|
+
_Calendar = Calendar;
|
|
11600
|
+
_Calendar.formAssociated = true;
|
|
11601
|
+
_Calendar.properties = {
|
|
11527
11602
|
...CalendarBase.properties,
|
|
11528
|
-
|
|
11603
|
+
month: {
|
|
11529
11604
|
type: String,
|
|
11530
11605
|
reflect: true
|
|
11531
11606
|
},
|
|
11532
|
-
|
|
11533
|
-
|
|
11534
|
-
|
|
11607
|
+
compact: {
|
|
11608
|
+
type: Boolean,
|
|
11609
|
+
reflect: true
|
|
11610
|
+
},
|
|
11611
|
+
dayWidth: {
|
|
11612
|
+
type: Number,
|
|
11613
|
+
attribute: "day-width"
|
|
11614
|
+
},
|
|
11615
|
+
lines: { type: Number },
|
|
11616
|
+
weekNumbers: {
|
|
11617
|
+
type: Boolean,
|
|
11618
|
+
attribute: "week-numbers",
|
|
11619
|
+
reflect: true
|
|
11620
|
+
},
|
|
11621
|
+
fixed: {
|
|
11622
|
+
type: Boolean,
|
|
11623
|
+
reflect: true
|
|
11624
|
+
},
|
|
11625
|
+
outsideDays: {
|
|
11535
11626
|
type: Boolean,
|
|
11627
|
+
attribute: "outside-days",
|
|
11536
11628
|
reflect: true
|
|
11537
11629
|
},
|
|
11538
11630
|
noHeader: {
|
|
@@ -11540,530 +11632,578 @@ _CalendarLarge.properties = {
|
|
|
11540
11632
|
attribute: "no-header",
|
|
11541
11633
|
reflect: true
|
|
11542
11634
|
},
|
|
11543
|
-
|
|
11635
|
+
noToday: {
|
|
11636
|
+
type: Boolean,
|
|
11637
|
+
attribute: "no-today",
|
|
11638
|
+
reflect: true
|
|
11639
|
+
},
|
|
11640
|
+
picker: {
|
|
11641
|
+
type: Boolean,
|
|
11642
|
+
reflect: true
|
|
11643
|
+
},
|
|
11644
|
+
name: {
|
|
11645
|
+
type: String,
|
|
11646
|
+
reflect: true
|
|
11647
|
+
},
|
|
11648
|
+
placeholder: { type: String },
|
|
11649
|
+
length: { type: String },
|
|
11650
|
+
time: {
|
|
11651
|
+
type: Boolean,
|
|
11652
|
+
reflect: true
|
|
11653
|
+
},
|
|
11654
|
+
required: {
|
|
11655
|
+
type: Boolean,
|
|
11656
|
+
reflect: true
|
|
11657
|
+
},
|
|
11658
|
+
disabled: {
|
|
11659
|
+
type: Boolean,
|
|
11660
|
+
reflect: true
|
|
11661
|
+
},
|
|
11662
|
+
open: {
|
|
11663
|
+
type: Boolean,
|
|
11664
|
+
reflect: true
|
|
11665
|
+
},
|
|
11666
|
+
unfolded: { state: true }
|
|
11544
11667
|
};
|
|
11545
|
-
|
|
11668
|
+
_Calendar.styles = [
|
|
11546
11669
|
r$3(component_metrics_default),
|
|
11547
11670
|
r$3(controls_default),
|
|
11548
|
-
r$3(
|
|
11671
|
+
r$3(ds_calendar_default)
|
|
11549
11672
|
];
|
|
11550
|
-
define("ds-calendar
|
|
11551
|
-
//#endregion
|
|
11552
|
-
//#region DS1/1-root/carousel.css?inline
|
|
11553
|
-
var carousel_default = "/* Shape is a surface preference. Keep these base lengths unscaled: each\n * component resolves them with its own --ds-sf in component-metrics.css. */\n[data-ds-shape=\"square\"],\n:host([data-ds-shape=\"square\"]) {\n --ds-corner-size: 0px;\n --ds-corner-shape: round;\n --ds-button-inset: 0.5px;\n}\n\n[data-ds-shape=\"rounded\"],\n:host([data-ds-shape=\"rounded\"]) {\n --ds-corner-size: 4px;\n --ds-corner-shape: round;\n --ds-button-inset: 2.5px;\n}\n\n[data-ds-shape=\"circular\"],\n:host([data-ds-shape=\"circular\"]) {\n --ds-corner-size: 999px;\n --ds-corner-shape: round;\n --ds-button-inset: 5px;\n}\n\n/* A squircle needs twice an arc's radius for the same apparent corner.\n * Circular controls keep true semicircles even in a squircle browser. */\n@supports (corner-shape: squircle) {\n [data-ds-shape=\"rounded\"],\n :host([data-ds-shape=\"rounded\"]) {\n --ds-corner-size: 8px;\n --ds-corner-shape: squircle;\n }\n}\n\n/* Resolve dimensions where a component is drawn. Inherited calc() values have\n * already used their ancestor's scale. Base tokens stay unscaled and inherit;\n * resolved tokens can still be overridden directly on a component.\n * data-ds-surface gives ordinary layout elements the same scaled measures.\n */\n:root,\n:host,\n:where([data-ds-surface]) {\n --ds-unit: calc(var(--ds-1, 20px) * var(--ds-sf, 1));\n --ds-control-height: calc(var(--ds-control-size, var(--ds-08, 16px)) * var(--ds-sf, 1));\n --ds-row-height: calc(var(--ds-row-size, var(--ds-1, 20px)) * var(--ds-sf, 1));\n --ds-type-size-default: calc(var(--ds-text-size, 14px) * var(--ds-sf, 1));\n --ds-type-size-small: calc(var(--ds-small-text-size, 10px) * var(--ds-sf, 1));\n --ds-type-size-heading: calc(var(--ds-heading-text-size, 13px) * var(--ds-sf, 1));\n --ds-type-size-display: calc(var(--ds-display-text-size, 20px) * var(--ds-sf, 1));\n --ds-type-lineheight-default: calc(var(--ds-text-leading, 16px) * var(--ds-sf, 1));\n --ds-type-letterspacing-default: calc(var(--ds-text-tracking, -0.3px) * var(--ds-sf, 1));\n --ds-radius: calc(var(--ds-corner-size, 4px) * var(--ds-sf, 1));\n --ds-radius-card: calc(var(--ds-card-corner-size, 4px) * var(--ds-sf, 1));\n}\n\n/*\n * A carousel, as plain classes on native elements.\n *\n * A carousel is a row of slides that snaps sideways, one slide to a stop,\n * with a row of controls one square high under it: optional previous and\n * next buttons and a dot for each slide. Slides are the track's width, or\n * whole squares wide, a whole number of squares apart (one by default). The\n * controls stand one square below the track, on the grid from its start.\n * The `ds-carousel` element draws the same parts, and\n * `0-face/carousel.ts` gives the native markup its behaviour.\n *\n * ds-carousel the region: track, controls, status;\n * `data-slides=\"auto\"` for slides of their\n * own width, `data-bleed` `end` or `both`,\n * `data-snap=\"none\"` to slide freely\n * ds-carousel__track the scroller; every child is a slide\n * ds-carousel__controls the row of buttons and dots\n * ds-carousel__previous, __next, icon buttons, on `.ds-button.ds-button--icon`\n * __pause\n * ds-carousel__status the polite announcement, kept out of sight\n *\n * The dots are `ds-progress--dots` from progress.css.\n *\n * A strip of slides of their own width can run on past its box to the\n * window's end edge, or to both edges, while its first slide keeps to the\n * box's start, so it lines up with the page's column; `--ds-carousel-before`\n * and `--ds-carousel-after` are the room to the edges, which the script\n * measures.\n *\n * Tokens: `--ds-carousel-slide` (a slide's width, the track's by default)\n * and `--ds-carousel-gap` (between slides, one square by default).\n */\n\n.ds-carousel {\n box-sizing: border-box;\n display: grid;\n grid-template-columns: minmax(0, 1fr);\n row-gap: var(--ds-unit);\n position: relative;\n min-width: 0;\n margin: 0;\n}\n\n.ds-carousel__track {\n box-sizing: border-box;\n display: grid;\n grid-auto-flow: column;\n grid-auto-columns: var(--ds-carousel-slide, 100%);\n column-gap: var(--ds-carousel-gap, var(--ds-unit));\n min-width: 0;\n margin: 0;\n padding: 0;\n list-style: none;\n overflow-x: auto;\n overflow-y: hidden;\n overscroll-behavior-x: contain;\n scroll-snap-type: x mandatory;\n scrollbar-width: none;\n}\n\n.ds-carousel__track::-webkit-scrollbar {\n display: none;\n}\n\n/* Slides of their own width, several in view. */\n.ds-carousel[data-slides=\"auto\"] > .ds-carousel__track {\n grid-auto-columns: max-content;\n}\n\n.ds-carousel[data-snap=\"none\"] > .ds-carousel__track {\n scroll-snap-type: none;\n}\n\n/* To the window's end edge: the track reaches out over the room after the\n box and keeps a gap at its end, so the last slide stops short of the edge. */\n.ds-carousel[data-bleed=\"end\"] > .ds-carousel__track {\n margin-inline-end: calc(-1 * var(--ds-carousel-after, 0px));\n padding-inline-end: var(--ds-carousel-gap, var(--ds-unit));\n}\n\n/* To both edges: the track reaches out both ways, and the first slide, and\n each one it stops at, still stands on the box's start. */\n.ds-carousel[data-bleed=\"both\"] > .ds-carousel__track {\n margin-inline: calc(-1 * var(--ds-carousel-before, 0px)) calc(-1 * var(--ds-carousel-after, 0px));\n padding-inline: var(--ds-carousel-before, 0px) var(--ds-carousel-gap, var(--ds-unit));\n scroll-padding-inline-start: var(--ds-carousel-before, 0px);\n}\n\n.ds-carousel__track:focus-visible {\n outline: 2px solid var(--ds-focus-ring);\n outline-offset: 1px;\n}\n\n.ds-carousel__track > * {\n box-sizing: border-box;\n min-width: 0;\n margin: 0;\n scroll-snap-align: start;\n}\n\n/* One slide to a stop; a strip of several in view may pass a few. */\n.ds-carousel:not([data-slides=\"auto\"]) > .ds-carousel__track > * {\n scroll-snap-stop: always;\n}\n\n.ds-carousel__controls {\n display: flex;\n align-items: center;\n height: var(--ds-row-height);\n min-width: 0;\n}\n\n/* The buttons take a one-square cell each, as the dots do. Two classes, so\n the button's own reset of its margin does not undo it. */\n.ds-carousel .ds-carousel__previous,\n.ds-carousel .ds-carousel__next,\n.ds-carousel .ds-carousel__pause {\n flex: none;\n margin: calc((var(--ds-unit) - var(--ds-control-height)) / 2);\n}\n\n/* Previous points back along the reading direction. */\n.ds-carousel:dir(rtl) :is(.ds-carousel__previous, .ds-carousel__next) > * {\n transform: scaleX(-1);\n}\n\n.ds-carousel__status {\n position: absolute;\n width: 1px;\n height: 1px;\n overflow: hidden;\n clip-path: inset(50%);\n white-space: nowrap;\n}\n";
|
|
11673
|
+
define("ds-calendar", Calendar);
|
|
11554
11674
|
//#endregion
|
|
11555
|
-
//#region DS1/3-unit/styles/ds-
|
|
11556
|
-
var
|
|
11675
|
+
//#region DS1/3-unit/styles/ds-calendar-large.css?inline
|
|
11676
|
+
var ds_calendar_large_default = "/* ds-calendar-large.css\n * The grid drawn --ds-calendar-scale times (one and a half by default): a\n * cell is a square of 30px, its lines 1.5px, its words the heading size\n * times the scale (19.5px). Weeks run in columns and the days down them; the\n * frame's corners are four tenths of a cell. Today is a red disc nine tenths\n * of a cell across, the selected day an ink square of the same size. */\n\n:host {\n --ds-calendar-cell: calc(var(--ds-unit) * var(--ds-calendar-scale, 1.5));\n --ds-calendar-stroke: calc(1px * var(--ds-calendar-scale, 1.5));\n --ds-calendar-ink: var(--ds-text-color);\n --ds-calendar-event-fill: var(--ds-apple-green);\n --ds-calendar-today: var(--ds-red-for-blood);\n --ds-calendar-today-ink: var(--ds-white, #fff);\n --ds-calendar-mark: calc(var(--ds-calendar-cell) * 0.9);\n --ds-calendar-corner: calc(var(--ds-calendar-cell) * 0.4);\n --ds-calendar-rail: calc(var(--ds-calendar-cell) * 2);\n box-sizing: border-box;\n display: block;\n min-width: 0;\n color: var(--ds-text-color);\n font-family: var(--ds-typeface-regular);\n font-feature-settings: var(--ds-font-features);\n font-size: calc(var(--ds-type-size-heading) * var(--ds-calendar-scale, 1.5));\n font-weight: var(--ds-type-weight-default);\n line-height: 1;\n letter-spacing: var(--ds-type-letterspacing-default);\n}\n:host([hidden]) { display: none !important; }\n\n.calendar { min-width: 0; }\n\n/* The title and the arrows: one cell high, over the months. */\n.header {\n display: flex;\n align-items: flex-end;\n gap: calc(4px * var(--ds-sf, 1));\n height: var(--ds-calendar-cell);\n margin-inline-start: calc(var(--ds-calendar-rail) + var(--ds-unit) / 2);\n font-size: var(--ds-type-size-default);\n line-height: var(--ds-type-lineheight-default);\n}\n.title {\n flex: 1 1 auto;\n min-width: 0;\n overflow: hidden;\n font-size: calc(var(--ds-type-size-heading) * var(--ds-calendar-scale, 1.5));\n line-height: var(--ds-calendar-cell);\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.controls { display: flex; flex: 0 0 auto; align-items: flex-end; gap: 0; }\n/* Each arrow is a chevron on its own square, as in a month. */\n.nav { flex: 0 0 auto; width: var(--ds-unit); height: var(--ds-control-height); border-radius: var(--ds-radius); color: var(--ds-title-color); }\n.nav:hover:not(:disabled) { background: var(--ds-fill); color: var(--ds-text-color); }\n:host(:dir(rtl)) .nav > ds-icon { transform: scaleX(-1); }\n\n.body {\n display: grid;\n grid-template-columns: var(--ds-calendar-rail) minmax(0, 1fr);\n column-gap: calc(var(--ds-unit) / 2);\n}\n\n/* The weekdays down the start, outside the scroll: every other one named. */\n.rail {\n display: grid;\n grid-template-rows: repeat(7, var(--ds-calendar-cell));\n padding-block-start: var(--ds-calendar-cell);\n color: var(--ds-title-color);\n font-size: var(--ds-type-size-default);\n line-height: var(--ds-type-lineheight-default);\n}\n.weekday {\n display: flex;\n align-items: center;\n justify-content: flex-end;\n white-space: nowrap;\n}\n\n.scroller {\n overflow-x: auto;\n overflow-y: hidden;\n scrollbar-width: none;\n overscroll-behavior-x: contain;\n}\n.scroller::-webkit-scrollbar { display: none; }\n\n/* The months over their weeks, one cell high, their names on its foot. */\n.months {\n display: grid;\n grid-template-columns: repeat(var(--ds-calendar-weeks), var(--ds-calendar-cell));\n height: var(--ds-calendar-cell);\n}\n.month {\n display: flex;\n align-items: flex-end;\n min-width: 0;\n padding: 0 var(--ds-calendar-stroke) calc(3px * var(--ds-calendar-scale, 1.5));\n overflow: hidden;\n white-space: nowrap;\n}\n\n/* The frame: a line all round with rounded corners; the cells draw the lines inside. */\n.frame {\n box-sizing: border-box;\n width: max-content;\n border: var(--ds-calendar-stroke) solid var(--ds-calendar-ink);\n border-radius: var(--ds-calendar-corner);\n overflow: hidden;\n}\n.grid {\n display: grid;\n grid-template-columns: repeat(var(--ds-calendar-weeks), var(--ds-calendar-cell));\n grid-template-rows: repeat(7, var(--ds-calendar-cell));\n}\n.row { display: contents; }\n.hidden {\n position: absolute;\n width: 1px;\n height: 1px;\n overflow: hidden;\n clip-path: inset(50%);\n white-space: nowrap;\n}\n\n.cell {\n box-sizing: border-box;\n display: flex;\n align-items: center;\n justify-content: center;\n width: var(--ds-calendar-cell);\n height: var(--ds-calendar-cell);\n border-block-start: var(--ds-calendar-stroke) solid var(--ds-calendar-ink);\n border-inline-start: var(--ds-calendar-stroke) solid var(--ds-calendar-ink);\n background: var(--ds-calendar-cell-fill, transparent);\n font-variant-numeric: tabular-nums;\n outline: none;\n}\n.cell[data-first-row] { border-block-start-width: 0; }\n.cell[data-first-column] { border-inline-start-width: 0; }\n.cell[data-filled] { color: var(--ds-slate); }\n:host([selectable]) .cell:not([aria-disabled=\"true\"]) { cursor: pointer; }\n:host([selectable]) .cell:not([aria-disabled=\"true\"], [data-filled]):hover { background: var(--ds-row-fill-hover, var(--ds-fill)); }\n.cell:focus-visible { outline: 2px solid var(--ds-focus-ring); outline-offset: -3px; }\n.cell[aria-disabled=\"true\"] { color: var(--ds-title-color); }\n\n.date {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: var(--ds-calendar-mark);\n height: var(--ds-calendar-mark);\n letter-spacing: 0;\n}\n.cell[data-today] .date { border-radius: 999px; background: var(--ds-calendar-today); color: var(--ds-calendar-today-ink); }\n.cell[data-selected] .date { background: var(--ds-calendar-ink); color: var(--ds-paper); }\n.cell[data-inside]:not([data-filled]) { background: color-mix(in srgb, var(--ds-calendar-ink) 12%, var(--ds-paper)); }\n.cell[data-today][data-selected] .date { border-radius: 999px; box-shadow: inset 0 0 0 var(--ds-calendar-stroke) var(--ds-calendar-today); }\n\n/* On a narrow screen the weekdays take one letter and one square. */\n@media (max-width: 720px) {\n :host { --ds-calendar-rail: var(--ds-unit); }\n .rail .weekday:not(:empty) { font-size: 0; }\n .rail .weekday:not(:empty)::after { content: attr(data-narrow); font-size: var(--ds-type-size-default); }\n}\n\n/* Activity keeps the day grid, with quiet separated squares and event colours. */\n:host([activity]) .frame { border: 0; border-radius: 0; }\n:host([activity]) .cell { position: relative; border: 0; background: none; }\n:host([activity]) .cell::before {\n content: \"\";\n position: absolute;\n inset: calc(2px * var(--ds-sf, 1));\n border-radius: calc(2px * var(--ds-sf, 1));\n background: var(--ds-calendar-cell-fill, var(--ds-fill));\n}\n:host([activity]) .date { display: none; }\n:host([activity]) .cell[data-selected]::before { outline: 1px solid var(--ds-calendar-ink); }\n";
|
|
11557
11677
|
//#endregion
|
|
11558
|
-
//#region DS1/3-unit/ds-
|
|
11559
|
-
var
|
|
11560
|
-
/**
|
|
11561
|
-
|
|
11678
|
+
//#region DS1/3-unit/ds-calendar-large.ts
|
|
11679
|
+
var _CalendarLarge;
|
|
11680
|
+
/** The fill for a day: one colour, or bands side by side. */
|
|
11681
|
+
function fillOf(events) {
|
|
11682
|
+
if (!events.length) return void 0;
|
|
11683
|
+
const colours = [...new Set(events.map((event) => event.color || "var(--ds-calendar-event-fill)"))];
|
|
11684
|
+
if (colours.length === 1) return colours[0];
|
|
11685
|
+
const share = 100 / colours.length;
|
|
11686
|
+
return `linear-gradient(90deg, ${colours.map((colour, index) => `${colour} ${index * share}% ${(index + 1) * share}%`).join(", ")})`;
|
|
11687
|
+
}
|
|
11562
11688
|
/**
|
|
11563
|
-
* @element ds-
|
|
11564
|
-
* @prop {string}
|
|
11565
|
-
*
|
|
11566
|
-
* @prop {
|
|
11567
|
-
* @prop {number}
|
|
11568
|
-
* @prop {
|
|
11569
|
-
* @prop {boolean}
|
|
11570
|
-
* @prop {boolean}
|
|
11571
|
-
* @prop {
|
|
11572
|
-
*
|
|
11573
|
-
*
|
|
11574
|
-
*
|
|
11575
|
-
* @prop {string}
|
|
11576
|
-
*
|
|
11577
|
-
* box's start; `both` runs it to both edges.
|
|
11578
|
-
* @prop {boolean} loop - Hold the slides three times over, so the strip has no
|
|
11579
|
-
* end. The copies are hidden from assistive technology and never focused;
|
|
11580
|
-
* a looping carousel draws no dots.
|
|
11581
|
-
* @prop {string} autoplay - Move on a slide at a time by itself: empty for
|
|
11582
|
-
* every five seconds, or a number of milliseconds. Held while a person is
|
|
11583
|
-
* in the strip or cannot see it, never under reduced motion, and always
|
|
11584
|
-
* with a pause button.
|
|
11585
|
-
* @prop {boolean} free - Slide freely, without stopping at slides.
|
|
11586
|
-
*
|
|
11587
|
-
* @slot - The slides, one element each.
|
|
11588
|
-
*
|
|
11589
|
-
* @fires change - A person moved to another slide: by swiping, scrolling, a
|
|
11590
|
-
* dot or a button. `detail` is `{ index, previous }`. Setting `current` or
|
|
11591
|
-
* calling `goTo()` does not fire it.
|
|
11689
|
+
* @element ds-calendar-large
|
|
11690
|
+
* @prop {string} start - The first month drawn, `YYYY-MM`; the month before
|
|
11691
|
+
* today's by default.
|
|
11692
|
+
* @prop {number} months - How many months are drawn: 6 by default.
|
|
11693
|
+
* @prop {number} scale - How many times the grid it is drawn: 1.5 by default.
|
|
11694
|
+
* @prop {string} value - The selected day, `YYYY-MM-DD`.
|
|
11695
|
+
* @prop {boolean} selectable - Pressing a day selects it and fires `change`.
|
|
11696
|
+
* @prop {boolean} noHeader - Leave out the title and arrows (`no-header`).
|
|
11697
|
+
* @prop {string} min - The first day a person may choose.
|
|
11698
|
+
* @prop {string} max - The last day a person may choose.
|
|
11699
|
+
* @prop {string} weekStart - The week's first day (`week-start`); the
|
|
11700
|
+
* language's own by default.
|
|
11701
|
+
* @prop {string} today - The day drawn as today; the reader's own by default.
|
|
11702
|
+
* @prop {CalendarEvent[]} events - What happens on the days (property only).
|
|
11592
11703
|
*
|
|
11593
|
-
*
|
|
11594
|
-
*
|
|
11595
|
-
*
|
|
11596
|
-
* only with `autoplay`. `bleed`, `loop` and `autoplay` are read when the
|
|
11597
|
-
* element first draws; put a new element in its place to change them.
|
|
11704
|
+
* @fires day-press - A day was pressed or chosen with Enter or Space; `{ day, events }`.
|
|
11705
|
+
* @fires change - A person selected a day; `{ value, previous }`.
|
|
11706
|
+
* @fires navigate - The months drawn moved on or back; `{ month }`, the first one.
|
|
11598
11707
|
*
|
|
11599
11708
|
* @example
|
|
11600
|
-
* <ds-
|
|
11601
|
-
* <figure>…</figure>
|
|
11602
|
-
* <figure>…</figure>
|
|
11603
|
-
* </ds-carousel>
|
|
11709
|
+
* <ds-calendar-large start="2026-09" months="6"></ds-calendar-large>
|
|
11604
11710
|
*/
|
|
11605
|
-
var
|
|
11711
|
+
var CalendarLarge = class extends CalendarBase {
|
|
11606
11712
|
constructor() {
|
|
11607
11713
|
super();
|
|
11608
|
-
this.
|
|
11609
|
-
this.
|
|
11714
|
+
this.weeksRun = "columns";
|
|
11715
|
+
this.byDay = /* @__PURE__ */ new Map();
|
|
11716
|
+
this.placed = false;
|
|
11610
11717
|
this.frame = 0;
|
|
11611
|
-
this.
|
|
11612
|
-
this.relabel = () => {
|
|
11613
|
-
this.labelSlides();
|
|
11614
|
-
this.requestUpdate();
|
|
11615
|
-
};
|
|
11616
|
-
this.scrolled = () => {
|
|
11718
|
+
this.onScroll = () => {
|
|
11617
11719
|
cancelAnimationFrame(this.frame);
|
|
11618
|
-
if (this.loop) return;
|
|
11619
11720
|
this.frame = requestAnimationFrame(() => {
|
|
11620
|
-
|
|
11621
|
-
|
|
11622
|
-
|
|
11623
|
-
|
|
11624
|
-
|
|
11625
|
-
return;
|
|
11626
|
-
}
|
|
11627
|
-
const track = this.track;
|
|
11628
|
-
if (track) this.show(nearestSlide(track, this.slides, this.index));
|
|
11721
|
+
const scroller = this.scroller;
|
|
11722
|
+
const cell = scroller?.querySelector(".cell")?.getBoundingClientRect().width;
|
|
11723
|
+
if (!scroller || !cell) return;
|
|
11724
|
+
const column = Math.min(this.weekStarts.length - 1, Math.max(0, Math.round(Math.abs(scroller.scrollLeft) / cell)));
|
|
11725
|
+
this.visible = startOfMonth(addDays(this.weekStarts[column], 3));
|
|
11629
11726
|
});
|
|
11630
11727
|
};
|
|
11631
|
-
this.
|
|
11632
|
-
|
|
11633
|
-
|
|
11634
|
-
|
|
11635
|
-
event.
|
|
11728
|
+
this.onKeyDown = (event) => {
|
|
11729
|
+
const cell = event.target.closest("[data-day]");
|
|
11730
|
+
if (!cell) return;
|
|
11731
|
+
const day = cell.dataset.day;
|
|
11732
|
+
if (event.key === "Enter" || event.key === " ") {
|
|
11733
|
+
event.preventDefault();
|
|
11734
|
+
this.press(day);
|
|
11735
|
+
return;
|
|
11736
|
+
}
|
|
11737
|
+
const target = this.keyTarget(event, day);
|
|
11738
|
+
if (!target) return;
|
|
11636
11739
|
event.preventDefault();
|
|
11637
|
-
this.
|
|
11740
|
+
if (target < this.weekStarts[0] || target > this.lastDay) {
|
|
11741
|
+
const by = target < this.weekStarts[0] ? -1 : 1;
|
|
11742
|
+
const first = addMonths(this.firstMonth, by);
|
|
11743
|
+
this.start = first.slice(0, 7);
|
|
11744
|
+
this.announceMonth(first);
|
|
11745
|
+
}
|
|
11746
|
+
this.focusCell(target);
|
|
11638
11747
|
};
|
|
11639
|
-
this.
|
|
11640
|
-
|
|
11641
|
-
|
|
11642
|
-
|
|
11643
|
-
|
|
11644
|
-
|
|
11645
|
-
|
|
11646
|
-
this.
|
|
11647
|
-
this.
|
|
11648
|
-
this.count = 0;
|
|
11649
|
-
this.announcement = "";
|
|
11650
|
-
this.paused = false;
|
|
11748
|
+
this.onClick = (event) => {
|
|
11749
|
+
const cell = event.composedPath().find((node) => node instanceof HTMLElement && node.dataset?.day);
|
|
11750
|
+
if (!cell) return;
|
|
11751
|
+
const day = cell.dataset.day;
|
|
11752
|
+
this.focusDay = day;
|
|
11753
|
+
this.press(day);
|
|
11754
|
+
};
|
|
11755
|
+
this.noHeader = false;
|
|
11756
|
+
this.activity = false;
|
|
11651
11757
|
}
|
|
11652
|
-
/** The
|
|
11653
|
-
get
|
|
11654
|
-
return
|
|
11758
|
+
/** The first of the first month drawn. */
|
|
11759
|
+
get firstMonth() {
|
|
11760
|
+
return readMonth(this.start) ?? addMonths(startOfMonth(this.todayDay), -1);
|
|
11655
11761
|
}
|
|
11656
|
-
|
|
11657
|
-
|
|
11658
|
-
return
|
|
11762
|
+
get monthCount() {
|
|
11763
|
+
const count = this.months;
|
|
11764
|
+
return typeof count === "number" && Number.isFinite(count) ? Math.max(1, Math.min(36, Math.floor(count))) : 6;
|
|
11659
11765
|
}
|
|
11660
|
-
/**
|
|
11661
|
-
get
|
|
11662
|
-
|
|
11766
|
+
/** The first day of each week drawn, from the week holding the first month's first day. */
|
|
11767
|
+
get weekStarts() {
|
|
11768
|
+
const first = this.firstMonth;
|
|
11769
|
+
const from = addDays(first, -((weekdayOf(first) - this.firstDay + 7) % 7));
|
|
11770
|
+
const last = addDays(addMonths(first, this.monthCount), -1);
|
|
11771
|
+
const weeks = [];
|
|
11772
|
+
for (let day = from; day <= last; day = addDays(day, 7)) weeks.push(day);
|
|
11773
|
+
return weeks;
|
|
11663
11774
|
}
|
|
11664
|
-
get
|
|
11665
|
-
return this.
|
|
11775
|
+
get lastDay() {
|
|
11776
|
+
return addDays(this.weekStarts.at(-1), 6);
|
|
11666
11777
|
}
|
|
11667
|
-
|
|
11668
|
-
|
|
11669
|
-
const current = Number.isFinite(this.current) ? Math.floor(this.current) : 0;
|
|
11670
|
-
return Math.max(0, Math.min(this.count - 1, current));
|
|
11778
|
+
eventsOn(day) {
|
|
11779
|
+
return this.byDay.get(day) ?? [];
|
|
11671
11780
|
}
|
|
11672
|
-
|
|
11673
|
-
super.
|
|
11674
|
-
|
|
11675
|
-
|
|
11781
|
+
willUpdate(changed) {
|
|
11782
|
+
super.willUpdate(changed);
|
|
11783
|
+
const scale = typeof this.scale === "number" && Number.isFinite(this.scale) && this.scale > 0 ? this.scale : this.activity ? 1 : 1.5;
|
|
11784
|
+
this.style.setProperty("--ds-calendar-scale", String(scale));
|
|
11785
|
+
}
|
|
11786
|
+
firstUpdated() {
|
|
11787
|
+
const today = this.todayDay;
|
|
11788
|
+
this.scrollToDay(today >= this.weekStarts[0] && today <= this.lastDay ? startOfMonth(today) : this.firstMonth, false);
|
|
11789
|
+
this.placed = true;
|
|
11676
11790
|
}
|
|
11677
11791
|
disconnectedCallback() {
|
|
11678
|
-
window.removeEventListener("language-changed", this.relabel);
|
|
11679
|
-
window.removeEventListener("translations-loaded", this.relabel);
|
|
11680
11792
|
cancelAnimationFrame(this.frame);
|
|
11681
|
-
clearTimeout(this.settle);
|
|
11682
|
-
this.drive?.stop();
|
|
11683
|
-
this.drive = null;
|
|
11684
11793
|
super.disconnectedCallback();
|
|
11685
11794
|
}
|
|
11686
|
-
|
|
11687
|
-
|
|
11688
|
-
return params ? text.replace(/\{\{?(\w+)\}?\}/g, (whole, name) => name in params ? String(params[name]) : whole) : text;
|
|
11689
|
-
}
|
|
11690
|
-
/** Writes an attribute the page has not written, and remembers it as this element's. */
|
|
11691
|
-
write(element, name, value) {
|
|
11692
|
-
const mine = this.own.get(element) ?? /* @__PURE__ */ new Set();
|
|
11693
|
-
if (element.hasAttribute(name) && !mine.has(name)) return;
|
|
11694
|
-
mine.add(name);
|
|
11695
|
-
this.own.set(element, mine);
|
|
11696
|
-
if (element.getAttribute(name) !== value) element.setAttribute(name, value);
|
|
11697
|
-
}
|
|
11698
|
-
labelSlides() {
|
|
11699
|
-
const slides = this.slides;
|
|
11700
|
-
const labelled = (slide) => slide.hasAttribute("aria-labelledby");
|
|
11701
|
-
slides.forEach((slide, index) => {
|
|
11702
|
-
this.write(slide, "role", "group");
|
|
11703
|
-
this.write(slide, "aria-roledescription", this.words(void 0, "Slide"));
|
|
11704
|
-
if (!labelled(slide)) this.write(slide, "aria-label", this.words(void 0, "{index} of {count}", {
|
|
11705
|
-
index: index + 1,
|
|
11706
|
-
count: slides.length
|
|
11707
|
-
}));
|
|
11708
|
-
});
|
|
11709
|
-
this.count = slides.length;
|
|
11795
|
+
get scroller() {
|
|
11796
|
+
return this.renderRoot.querySelector(".scroller");
|
|
11710
11797
|
}
|
|
11711
|
-
|
|
11712
|
-
|
|
11713
|
-
if (!this.hasUpdated) this.labelSlides();
|
|
11714
|
-
this.write(this, "role", "region");
|
|
11715
|
-
this.write(this, "aria-roledescription", this.words(void 0, "Carousel"));
|
|
11716
|
-
if (!this.hasAttribute("aria-labelledby")) this.write(this, "aria-label", this.words(this.label, "Carousel"));
|
|
11717
|
-
const width = squares(typeof this.slideWidth === "string" && this.slideWidth !== "auto" ? Number(this.slideWidth) : typeof this.slideWidth === "number" ? this.slideWidth : void 0, 1);
|
|
11718
|
-
const gap = squares(this.gap, 0);
|
|
11719
|
-
if (this.strip) this.style.setProperty("--ds-carousel-slide", "max-content");
|
|
11720
|
-
else if (width) this.style.setProperty("--ds-carousel-slide", `calc(var(--ds-unit) * ${width})`);
|
|
11721
|
-
else this.style.removeProperty("--ds-carousel-slide");
|
|
11722
|
-
if (gap !== void 0) this.style.setProperty("--ds-carousel-gap", `calc(var(--ds-unit) * ${gap})`);
|
|
11723
|
-
else this.style.removeProperty("--ds-carousel-gap");
|
|
11798
|
+
columnOf(day) {
|
|
11799
|
+
return this.weekStarts.findIndex((start) => day >= start && day <= addDays(start, 6));
|
|
11724
11800
|
}
|
|
11725
|
-
|
|
11726
|
-
|
|
11727
|
-
const
|
|
11728
|
-
|
|
11729
|
-
|
|
11730
|
-
|
|
11731
|
-
|
|
11801
|
+
/** Scrolls the week holding `day` to the start of the view. */
|
|
11802
|
+
scrollToDay(day, smooth = true) {
|
|
11803
|
+
const scroller = this.scroller;
|
|
11804
|
+
const column = this.columnOf(day);
|
|
11805
|
+
if (!scroller || column < 0) return;
|
|
11806
|
+
const cell = scroller.querySelector(".cell")?.getBoundingClientRect().width ?? 30;
|
|
11807
|
+
const reduce = matchMedia?.("(prefers-reduced-motion: reduce)").matches;
|
|
11808
|
+
const rtl = getComputedStyle(this).direction === "rtl";
|
|
11809
|
+
scroller.scrollTo({
|
|
11810
|
+
left: (rtl ? -1 : 1) * column * cell,
|
|
11811
|
+
behavior: smooth && !reduce ? "smooth" : "auto"
|
|
11732
11812
|
});
|
|
11813
|
+
this.visible = startOfMonth(day);
|
|
11733
11814
|
}
|
|
11734
|
-
|
|
11735
|
-
|
|
11736
|
-
|
|
11737
|
-
|
|
11738
|
-
|
|
11739
|
-
|
|
11740
|
-
|
|
11741
|
-
|
|
11742
|
-
this.
|
|
11743
|
-
|
|
11744
|
-
|
|
11745
|
-
|
|
11746
|
-
goTo(index) {
|
|
11747
|
-
this.current = index;
|
|
11748
|
-
}
|
|
11749
|
-
/** Goes to the next slide, as the next button does. */
|
|
11750
|
-
next() {
|
|
11751
|
-
if (this.drive) this.drive.step(1);
|
|
11752
|
-
else this.move(this.index + 1);
|
|
11753
|
-
}
|
|
11754
|
-
/** Goes to the previous slide, as the previous button does. */
|
|
11755
|
-
previous() {
|
|
11756
|
-
if (this.drive) this.drive.step(-1);
|
|
11757
|
-
else this.move(this.index - 1);
|
|
11815
|
+
/** Moves the view a month back or on; past the months drawn, the months move with it. */
|
|
11816
|
+
step(by) {
|
|
11817
|
+
const target = addMonths(this.visible ?? this.firstMonth, by);
|
|
11818
|
+
const first = this.firstMonth;
|
|
11819
|
+
const end = addMonths(first, this.monthCount);
|
|
11820
|
+
if (target < first || target >= end) {
|
|
11821
|
+
this.start = addMonths(first, by).slice(0, 7);
|
|
11822
|
+
this.announceMonth(addMonths(first, by));
|
|
11823
|
+
this.updateComplete.then(() => this.scrollToDay(target, false));
|
|
11824
|
+
return;
|
|
11825
|
+
}
|
|
11826
|
+
this.scrollToDay(target);
|
|
11758
11827
|
}
|
|
11759
|
-
|
|
11760
|
-
|
|
11761
|
-
this.
|
|
11828
|
+
/** The month before, as the previous arrow does. */
|
|
11829
|
+
previousMonth() {
|
|
11830
|
+
this.step(-1);
|
|
11762
11831
|
}
|
|
11763
|
-
|
|
11764
|
-
|
|
11765
|
-
|
|
11766
|
-
if (!track || !slide || !scrollToSlide(track, slide, smooth)) return;
|
|
11767
|
-
this.pending = index;
|
|
11768
|
-
clearTimeout(this.settle);
|
|
11769
|
-
this.settle = setTimeout(() => {
|
|
11770
|
-
this.pending = void 0;
|
|
11771
|
-
}, 600);
|
|
11832
|
+
/** The month after, as the next arrow does. */
|
|
11833
|
+
nextMonth() {
|
|
11834
|
+
this.step(1);
|
|
11772
11835
|
}
|
|
11773
|
-
/**
|
|
11774
|
-
|
|
11775
|
-
const
|
|
11776
|
-
|
|
11777
|
-
|
|
11778
|
-
|
|
11779
|
-
|
|
11780
|
-
|
|
11781
|
-
|
|
11782
|
-
|
|
11783
|
-
});
|
|
11784
|
-
this.dispatchEvent(new CustomEvent("change", {
|
|
11785
|
-
bubbles: true,
|
|
11786
|
-
composed: true,
|
|
11787
|
-
detail: {
|
|
11788
|
-
index: target,
|
|
11789
|
-
previous
|
|
11790
|
-
}
|
|
11791
|
-
}));
|
|
11836
|
+
/** Brings today into view, moving the months drawn when it is outside them. */
|
|
11837
|
+
showToday() {
|
|
11838
|
+
const today = this.todayDay;
|
|
11839
|
+
if (today < this.weekStarts[0] || today > this.lastDay) {
|
|
11840
|
+
const first = addMonths(startOfMonth(today), -1);
|
|
11841
|
+
this.start = first.slice(0, 7);
|
|
11842
|
+
this.announceMonth(first);
|
|
11843
|
+
this.updateComplete.then(() => this.scrollToDay(startOfMonth(today), false));
|
|
11844
|
+
} else this.scrollToDay(startOfMonth(today));
|
|
11845
|
+
this.focusDay = today;
|
|
11792
11846
|
}
|
|
11793
|
-
|
|
11794
|
-
const
|
|
11795
|
-
|
|
11796
|
-
|
|
11847
|
+
get tabDay() {
|
|
11848
|
+
const first = this.weekStarts[0], last = this.lastDay;
|
|
11849
|
+
for (const day of [
|
|
11850
|
+
this.focusDay,
|
|
11851
|
+
this.chosen.start,
|
|
11852
|
+
this.todayDay
|
|
11853
|
+
]) if (day && day >= first && day <= last) return day;
|
|
11854
|
+
return this.firstMonth;
|
|
11797
11855
|
}
|
|
11798
|
-
|
|
11799
|
-
|
|
11800
|
-
const
|
|
11801
|
-
|
|
11802
|
-
class="ds-button ds-button--icon ds-carousel__${which}"
|
|
11856
|
+
renderHeader() {
|
|
11857
|
+
if (this.noHeader) return A;
|
|
11858
|
+
const arrow = (which) => b$1`<button
|
|
11859
|
+
class="ds-button ds-button--icon nav"
|
|
11803
11860
|
part=${which}
|
|
11804
11861
|
type="button"
|
|
11805
|
-
aria-label=${this.words(
|
|
11806
|
-
|
|
11807
|
-
|
|
11808
|
-
|
|
11809
|
-
|
|
11810
|
-
|
|
11811
|
-
|
|
11812
|
-
|
|
11813
|
-
|
|
11814
|
-
|
|
11815
|
-
|
|
11862
|
+
aria-label=${this.words(which === "previous" ? "Previous month" : "Next month")}
|
|
11863
|
+
@click=${() => which === "previous" ? this.previousMonth() : this.nextMonth()}
|
|
11864
|
+
><ds-icon type=${which === "previous" ? "chevron-left" : "chevron-right"} size="large" aria-hidden="true"></ds-icon></button>`;
|
|
11865
|
+
return b$1`<div class="header" part="header">
|
|
11866
|
+
<span class="title" aria-live="polite">${monthTitle(this.visible ?? this.firstMonth)}</span>
|
|
11867
|
+
<span class="controls">
|
|
11868
|
+
${arrow("previous")}
|
|
11869
|
+
<button class="ds-button ds-button--secondary" part="today" type="button" @click=${() => this.showToday()}>${this.words("Today")}</button>
|
|
11870
|
+
${arrow("next")}
|
|
11871
|
+
</span>
|
|
11872
|
+
</div>`;
|
|
11873
|
+
}
|
|
11874
|
+
render() {
|
|
11875
|
+
const weeks = this.weekStarts;
|
|
11876
|
+
const first = weeks[0], last = this.lastDay;
|
|
11877
|
+
this.byDay = eventsByDay(this.events ?? [], first, last);
|
|
11878
|
+
const short = weekdayNames(this.firstDay, "short");
|
|
11879
|
+
const narrow = weekdayNames(this.firstDay, "narrow");
|
|
11880
|
+
const long = weekdayNames(this.firstDay, "long");
|
|
11881
|
+
const today = this.todayDay;
|
|
11882
|
+
const tab = this.tabDay;
|
|
11883
|
+
const labels = [];
|
|
11884
|
+
for (let month = this.firstMonth, index = 0; index < this.monthCount; index++, month = addMonths(month, 1)) {
|
|
11885
|
+
const column = this.columnOf(month);
|
|
11886
|
+
const next = this.columnOf(addMonths(month, 1));
|
|
11887
|
+
labels.push({
|
|
11888
|
+
column,
|
|
11889
|
+
span: Math.max(1, (next < 0 ? weeks.length : next) - column),
|
|
11890
|
+
day: month
|
|
11891
|
+
});
|
|
11892
|
+
}
|
|
11893
|
+
const ends = /* @__PURE__ */ new Set();
|
|
11894
|
+
for (const event of this.events ?? []) {
|
|
11895
|
+
ends.add(event.start);
|
|
11896
|
+
if (event.end) ends.add(event.end);
|
|
11897
|
+
}
|
|
11898
|
+
return b$1`<div class="calendar" part="calendar" style=${`--ds-calendar-weeks: ${weeks.length}`}>
|
|
11899
|
+
${this.renderHeader()}
|
|
11900
|
+
<div class="body">
|
|
11901
|
+
<div class="rail" part="weekdays" aria-hidden="true">
|
|
11902
|
+
${short.map((name, row) => b$1`<span class="weekday" data-narrow=${narrow[row]}>${row % 2 === 1 ? name : ""}</span>`)}
|
|
11903
|
+
</div>
|
|
11904
|
+
<div class="scroller" part="scroller" @scroll=${this.onScroll}>
|
|
11905
|
+
<div class="months" aria-hidden="true">
|
|
11906
|
+
${labels.map(({ column, span, day }) => b$1`<span class="month" style=${`grid-column: ${column + 1} / span ${span}`}>${day.slice(5, 7) === "01" || day === this.firstMonth ? monthTitle(day, "short") : monthName(day, "short")}</span>`)}
|
|
11907
|
+
</div>
|
|
11908
|
+
<div class="frame" part="frame">
|
|
11909
|
+
<div
|
|
11910
|
+
class="grid"
|
|
11911
|
+
part="grid"
|
|
11912
|
+
role="grid"
|
|
11913
|
+
aria-label=${this.nameOr(`${monthTitle(this.firstMonth)} – ${monthTitle(addMonths(this.firstMonth, this.monthCount - 1))}`)}
|
|
11914
|
+
@keydown=${this.onKeyDown}
|
|
11915
|
+
@click=${this.onClick}
|
|
11916
|
+
>
|
|
11917
|
+
${short.map((_, row) => b$1`<div role="row" class="row">
|
|
11918
|
+
<span role="rowheader" class="hidden">${long[row]}</span>
|
|
11919
|
+
${weeks.map((start, column) => {
|
|
11920
|
+
const day = addDays(start, row);
|
|
11921
|
+
const events = this.eventsOn(day);
|
|
11922
|
+
const isToday = day === today;
|
|
11923
|
+
const { selected, inside } = this.selection(day);
|
|
11924
|
+
const written = isToday || selected || events.length > 0 && ends.has(day);
|
|
11925
|
+
const fill = fillOf(events);
|
|
11926
|
+
return b$1`<div
|
|
11927
|
+
role="gridcell"
|
|
11928
|
+
class="cell"
|
|
11929
|
+
part=${[
|
|
11930
|
+
"cell",
|
|
11931
|
+
isToday ? "today" : "",
|
|
11932
|
+
selected ? "selected" : "",
|
|
11933
|
+
events.length ? "filled" : ""
|
|
11934
|
+
].filter(Boolean).join(" ")}
|
|
11935
|
+
data-day=${day}
|
|
11936
|
+
tabindex=${day === tab ? 0 : -1}
|
|
11937
|
+
aria-label=${this.cellLabel(day, events)}
|
|
11938
|
+
title=${this.activity ? this.cellLabel(day, events) : A}
|
|
11939
|
+
aria-selected=${this.selectable ? String(selected || inside) : A}
|
|
11940
|
+
aria-current=${isToday ? "date" : A}
|
|
11941
|
+
aria-disabled=${this.allowed(day) ? A : "true"}
|
|
11942
|
+
?data-today=${isToday}
|
|
11943
|
+
?data-selected=${selected}
|
|
11944
|
+
?data-inside=${inside}
|
|
11945
|
+
?data-filled=${events.length > 0}
|
|
11946
|
+
?data-first-row=${row === 0}
|
|
11947
|
+
?data-first-column=${column === 0}
|
|
11948
|
+
style=${`grid-row: ${row + 1}; grid-column: ${column + 1};${fill ? ` --ds-calendar-cell-fill: ${fill};` : ""}`}
|
|
11949
|
+
>${written ? b$1`<span class="date" aria-hidden="true">${dateNumber(day)}</span>` : A}</div>`;
|
|
11950
|
+
})}
|
|
11951
|
+
</div>`)}
|
|
11952
|
+
</div>
|
|
11953
|
+
</div>
|
|
11954
|
+
</div>
|
|
11816
11955
|
</div>
|
|
11817
|
-
${controls && this.count > 1 ? b$1`<div class="ds-carousel__controls" part="controls">
|
|
11818
|
-
${moving ? b$1`<button
|
|
11819
|
-
class="ds-button ds-button--icon ds-carousel__pause"
|
|
11820
|
-
part="pause"
|
|
11821
|
-
type="button"
|
|
11822
|
-
aria-pressed=${String(this.paused)}
|
|
11823
|
-
aria-label=${this.words(void 0, this.paused ? "Play" : "Pause")}
|
|
11824
|
-
@click=${this.togglePause}
|
|
11825
|
-
><ds-icon type=${this.paused ? "play-alt" : "pause"} aria-hidden="true"></ds-icon></button>` : A}
|
|
11826
|
-
${this.buttons ? button("previous") : A}
|
|
11827
|
-
${dots ? b$1`<ds-progress part="dots" .dots=${this.count} .active=${index} ?end=${this.end} @select=${this.picked}></ds-progress>` : A}
|
|
11828
|
-
${this.buttons ? button("next") : A}
|
|
11829
|
-
</div>` : A}
|
|
11830
|
-
<span class="ds-carousel__status" part="status" aria-live="polite" aria-atomic="true">${this.announcement}</span>
|
|
11831
11956
|
</div>`;
|
|
11832
11957
|
}
|
|
11958
|
+
updated(changed) {
|
|
11959
|
+
super.updated(changed);
|
|
11960
|
+
if (this.placed && changed.has("start") && this.visible && !this.focusDay) this.scrollToDay(this.visible, false);
|
|
11961
|
+
}
|
|
11833
11962
|
};
|
|
11834
|
-
|
|
11835
|
-
|
|
11836
|
-
|
|
11837
|
-
|
|
11838
|
-
type: Boolean,
|
|
11839
|
-
reflect: true
|
|
11840
|
-
},
|
|
11841
|
-
current: {
|
|
11842
|
-
type: Number,
|
|
11843
|
-
reflect: true
|
|
11844
|
-
},
|
|
11845
|
-
buttons: {
|
|
11846
|
-
type: Boolean,
|
|
11847
|
-
reflect: true
|
|
11848
|
-
},
|
|
11849
|
-
noDots: {
|
|
11850
|
-
type: Boolean,
|
|
11851
|
-
reflect: true,
|
|
11852
|
-
attribute: "no-dots"
|
|
11853
|
-
},
|
|
11854
|
-
end: {
|
|
11855
|
-
type: Boolean,
|
|
11856
|
-
reflect: true
|
|
11857
|
-
},
|
|
11858
|
-
slideWidth: {
|
|
11859
|
-
attribute: "slide-width",
|
|
11860
|
-
reflect: true,
|
|
11861
|
-
converter: {
|
|
11862
|
-
fromAttribute: (value) => value === null ? void 0 : value === "auto" ? "auto" : Number(value),
|
|
11863
|
-
toAttribute: (value) => value === void 0 ? null : String(value)
|
|
11864
|
-
}
|
|
11865
|
-
},
|
|
11866
|
-
gap: { type: Number },
|
|
11867
|
-
bleed: {
|
|
11963
|
+
_CalendarLarge = CalendarLarge;
|
|
11964
|
+
_CalendarLarge.properties = {
|
|
11965
|
+
...CalendarBase.properties,
|
|
11966
|
+
start: {
|
|
11868
11967
|
type: String,
|
|
11869
11968
|
reflect: true
|
|
11870
11969
|
},
|
|
11871
|
-
|
|
11970
|
+
months: { type: Number },
|
|
11971
|
+
scale: { type: Number },
|
|
11972
|
+
activity: {
|
|
11872
11973
|
type: Boolean,
|
|
11873
11974
|
reflect: true
|
|
11874
11975
|
},
|
|
11875
|
-
|
|
11876
|
-
type: String,
|
|
11877
|
-
reflect: true
|
|
11878
|
-
},
|
|
11879
|
-
free: {
|
|
11976
|
+
noHeader: {
|
|
11880
11977
|
type: Boolean,
|
|
11978
|
+
attribute: "no-header",
|
|
11881
11979
|
reflect: true
|
|
11882
11980
|
},
|
|
11883
|
-
|
|
11884
|
-
announcement: { state: true },
|
|
11885
|
-
paused: { state: true }
|
|
11981
|
+
visible: { state: true }
|
|
11886
11982
|
};
|
|
11887
|
-
|
|
11983
|
+
_CalendarLarge.styles = [
|
|
11888
11984
|
r$3(component_metrics_default),
|
|
11889
11985
|
r$3(controls_default),
|
|
11890
|
-
r$3(
|
|
11891
|
-
r$3(ds_carousel_default)
|
|
11986
|
+
r$3(ds_calendar_large_default)
|
|
11892
11987
|
];
|
|
11893
|
-
define("ds-
|
|
11894
|
-
//#endregion
|
|
11895
|
-
//#region DS1/3-unit/styles/ds-date-picker.css?inline
|
|
11896
|
-
var ds_date_picker_default = "/* ds-date-picker.css\n * The field is the select's face: one control high at the foot of its\n * square, ten squares wide by default, the calendar icon at its start and\n * the down arrow at its end. The panel opens on the menu's frame, half a\n * square from the field: a 1px line, half a square inside it, no shadow, so\n * eight squares wide. Inside, on whole squares: the first and last day to\n * type (each with its time below when times are on), one square spare, the\n * compact month one square a day with 18px marks, then Include time and\n * Clear, each one square, set off by one-square separators with a line\n * through them. */\n\n:host {\n --ds-date-picker-width: calc(10 * var(--ds-unit));\n box-sizing: border-box;\n display: inline-flex;\n align-items: flex-end;\n vertical-align: bottom;\n height: var(--ds-unit);\n color: var(--ds-text-color);\n font-family: var(--ds-typeface-regular);\n font-size: var(--ds-type-size-default);\n line-height: var(--ds-type-lineheight-default);\n}\n:host([hidden]) { display: none !important; }\n\n.trigger {\n display: inline-flex;\n align-items: flex-end;\n gap: calc(4px * var(--ds-sf, 1));\n width: var(--ds-date-picker-width);\n padding-inline: 0 calc(4px * var(--ds-sf, 1));\n text-align: start;\n cursor: pointer;\n}\n.trigger:disabled { cursor: default; }\n.trigger .icon,\n.trigger .arrow { flex: 0 0 auto; }\n.trigger .text {\n flex: 1 1 auto;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.trigger[data-empty] .text { color: var(--ds-title-color); }\n.trigger[aria-expanded=\"true\"] .arrow { transform: rotate(180deg); }\n\n/* The panel, on the menu's frame. */\n.popover {\n position: fixed;\n inset: auto;\n box-sizing: border-box;\n margin: 0;\n padding: calc(var(--ds-unit) / 2 - 1px);\n border: 1px solid var(--ds-border-color);\n border-radius: var(--ds-radius-card);\n background: var(--ds-paper);\n color: var(--ds-text-color);\n box-shadow: none;\n overflow: visible;\n}\n.popover:not(:popover-open) { display: none; }\n\n/* The days to type: a row of one square for each end, its time on the row below; one square spare after. */\n.fields { margin-block-end: var(--ds-unit); }\n.field-row {\n display: flex;\n align-items: flex-end;\n gap: calc(var(--ds-unit) / 2);\n height: var(--ds-unit);\n}\n.field { flex: 1 1 auto; min-width: 0; }\n.clock { flex: 1 1 auto; min-width: 0; }\n.fields, .options { width: calc(7 * var(--ds-unit)); }\n\n/* The switches and Clear, each one square, the words on the sixteen. */\n.option {\n box-sizing: border-box;\n display: flex;\n align-items: flex-end;\n justify-content: space-between;\n gap: var(--ds-unit);\n width: 100%;\n height: var(--ds-unit);\n margin: 0;\n padding: 0 calc(4px * var(--ds-sf, 1));\n border: 0;\n border-radius: var(--ds-radius);\n background: transparent;\n color: var(--ds-text-color);\n font: inherit;\n letter-spacing: inherit;\n text-align: start;\n cursor: pointer;\n}\n.option:hover:not(:disabled) { background: var(--ds-row-fill-hover, var(--ds-fill)); }\n.option:focus-visible { outline: 2px solid var(--ds-focus-ring); outline-offset: -2px; }\n.option:disabled { color: var(--ds-title-color); cursor: default; }\n.option .ds-switch { flex: 0 0 auto; }\n\n/* A separator: one square with a 1px line through its middle. */\n.separator {\n position: relative;\n height: var(--ds-unit);\n}\n.separator::after {\n position: absolute;\n inset-inline: 0;\n top: calc(50% - 0.5px);\n height: 1px;\n background: var(--ds-border-color);\n content: \"\";\n}\n\n@media (prefers-reduced-motion: no-preference) {\n .popover:popover-open {\n animation: ds-date-picker-in 140ms cubic-bezier(0.22, 1, 0.36, 1);\n }\n .trigger .arrow { transition: transform 140ms ease; }\n}\n@keyframes ds-date-picker-in {\n from { opacity: 0; transform: translateY(calc(-4px * var(--ds-sf, 1))); }\n to { opacity: 1; transform: none; }\n}\n";
|
|
11988
|
+
define("ds-calendar-large", CalendarLarge);
|
|
11897
11989
|
//#endregion
|
|
11898
|
-
//#region DS1/
|
|
11899
|
-
|
|
11900
|
-
|
|
11901
|
-
|
|
11902
|
-
|
|
11903
|
-
const
|
|
11904
|
-
|
|
11905
|
-
|
|
11906
|
-
|
|
11990
|
+
//#region DS1/0-face/bento.ts
|
|
11991
|
+
/** Reads `data-place` ("x y w h"); `undefined` unless it is four whole numbers with a size. */
|
|
11992
|
+
function bentoPlace(value) {
|
|
11993
|
+
const parts = (value ?? "").trim().split(/[\s,]+/).map(Number);
|
|
11994
|
+
if (parts.length !== 4 || parts.some((part) => !Number.isInteger(part) || part < 0)) return void 0;
|
|
11995
|
+
const [x, y, w, h] = parts;
|
|
11996
|
+
return w > 0 && h > 0 ? [
|
|
11997
|
+
x,
|
|
11998
|
+
y,
|
|
11999
|
+
w,
|
|
12000
|
+
h
|
|
12001
|
+
] : void 0;
|
|
12002
|
+
}
|
|
12003
|
+
var overlaps = (a0, a1, b0, b1) => a0 < b1 && b0 < a1;
|
|
12004
|
+
/** For each place, the sides that face another tile across a one-square gap. */
|
|
12005
|
+
function bentoReach(places) {
|
|
12006
|
+
return places.map(([x, y, w, h], index) => {
|
|
12007
|
+
const others = places.filter((_, other) => other !== index);
|
|
11907
12008
|
return {
|
|
11908
|
-
|
|
11909
|
-
|
|
12009
|
+
start: others.some(([ox, oy, ow, oh]) => ox + ow + 1 === x && overlaps(y, y + h, oy, oy + oh)),
|
|
12010
|
+
end: others.some(([ox, oy, , oh]) => x + w + 1 === ox && overlaps(y, y + h, oy, oy + oh)),
|
|
12011
|
+
top: others.some(([ox, oy, ow, oh]) => oy + oh + 1 === y && overlaps(x, x + w, ox, ox + ow)),
|
|
12012
|
+
bottom: others.some(([ox, oy, ow]) => y + h + 1 === oy && overlaps(x, x + w, ox, ox + ow))
|
|
11910
12013
|
};
|
|
11911
|
-
};
|
|
11912
|
-
const [first, second] = (value ?? "").split("/");
|
|
11913
|
-
let start = read(first), end = read(second);
|
|
11914
|
-
if (start && end && `${end.day}T${end.time}` < `${start.day}T${start.time}`) [start, end] = [end, start];
|
|
11915
|
-
return {
|
|
11916
|
-
start,
|
|
11917
|
-
end
|
|
11918
|
-
};
|
|
11919
|
-
}
|
|
11920
|
-
/**
|
|
11921
|
-
* Writes a value from its ends, the times only with `time`. An end that is
|
|
11922
|
-
* the same moment as the start leaves the value one day.
|
|
11923
|
-
*/
|
|
11924
|
-
function writeDateValue(start, end, options) {
|
|
11925
|
-
if (!start) return "";
|
|
11926
|
-
const part = (side) => options.time && side.time ? `${side.day}T${side.time}` : side.day;
|
|
11927
|
-
return end && part(end) !== part(start) ? `${part(start)}/${part(end)}` : part(start);
|
|
12014
|
+
});
|
|
11928
12015
|
}
|
|
11929
|
-
/**
|
|
11930
|
-
function
|
|
11931
|
-
const
|
|
11932
|
-
|
|
11933
|
-
|
|
11934
|
-
|
|
12016
|
+
/** Places one squares bento's tiles: their squares and their reach, as custom properties. */
|
|
12017
|
+
function placeBento(bento) {
|
|
12018
|
+
const placed = [...bento.children].filter((child) => child instanceof HTMLElement && !child.hidden).map((tile) => ({
|
|
12019
|
+
tile,
|
|
12020
|
+
place: bentoPlace(tile.dataset.place)
|
|
12021
|
+
})).filter((entry) => !!entry.place);
|
|
12022
|
+
const reach = bentoReach(placed.map((entry) => entry.place));
|
|
12023
|
+
placed.forEach(({ tile, place: [x, y, w, h] }, index) => {
|
|
12024
|
+
const sides = reach[index];
|
|
12025
|
+
tile.style.setProperty("--ds-bento-x", String(x));
|
|
12026
|
+
tile.style.setProperty("--ds-bento-y", String(y));
|
|
12027
|
+
tile.style.setProperty("--ds-bento-w", String(w));
|
|
12028
|
+
tile.style.setProperty("--ds-bento-h", String(h));
|
|
12029
|
+
for (const side of [
|
|
12030
|
+
"start",
|
|
12031
|
+
"top",
|
|
12032
|
+
"end",
|
|
12033
|
+
"bottom"
|
|
12034
|
+
]) tile.style.setProperty(`--ds-bento-${side}`, sides[side] ? "1" : "0");
|
|
12035
|
+
});
|
|
11935
12036
|
}
|
|
11936
|
-
|
|
12037
|
+
//#endregion
|
|
12038
|
+
//#region DS1/3-unit/styles/ds-bento.css?inline
|
|
12039
|
+
var ds_bento_default = "/* ds-bento.css */\n/* The element's bento: the same as 1-root/bento.css's .ds-bento, on the host and its slotted tiles. */\n\n:host {\n --ds-bento-gap: calc(var(--ds-unit) / 2);\n box-sizing: border-box;\n display: grid;\n grid-template-columns: repeat(var(--ds-bento-columns, 3), minmax(0, 1fr));\n grid-auto-rows: minmax(var(--ds-bento-row, calc(10 * var(--ds-unit))), auto);\n grid-auto-flow: row dense;\n gap: var(--ds-bento-gap);\n}\n:host([hidden]) { display: none !important; }\n\n::slotted(*) {\n --ds-card-width: auto;\n --ds-card-height: auto;\n box-sizing: border-box;\n min-width: 0;\n min-height: 0;\n grid-column: span var(--ds-bento-span, 1);\n grid-row: span var(--ds-bento-rows, 1);\n}\n::slotted([data-span=\"2\"]) { --ds-bento-span: 2; }\n::slotted([data-span=\"3\"]) { --ds-bento-span: 3; }\n::slotted([data-span=\"4\"]) { --ds-bento-span: 4; }\n::slotted([data-span=\"5\"]) { --ds-bento-span: 5; }\n::slotted([data-span=\"6\"]) { --ds-bento-span: 6; }\n::slotted([data-rows=\"2\"]) { --ds-bento-rows: 2; }\n::slotted([data-rows=\"3\"]) { --ds-bento-rows: 3; }\n::slotted([data-rows=\"4\"]) { --ds-bento-rows: 4; }\n::slotted([data-rows=\"5\"]) { --ds-bento-rows: 5; }\n::slotted([data-rows=\"6\"]) { --ds-bento-rows: 6; }\n\n@media (max-width: 600px) {\n :host(:not([squares])) { grid-template-columns: minmax(0, 1fr); }\n :host(:not([squares])) ::slotted(*) { grid-column: auto; }\n}\n\n:host([squares]) {\n --ds-bento-reach: calc(var(--ds-unit) / 4);\n /* Exactly its squares wide: each column one square. */\n width: calc(var(--ds-bento-columns, 48) * var(--ds-unit));\n max-width: none;\n grid-template-columns: repeat(var(--ds-bento-columns, 48), var(--ds-unit));\n grid-auto-rows: var(--ds-unit);\n grid-auto-flow: row;\n gap: 0;\n}\n:host([squares]) ::slotted(*) {\n --ds-bento-inset-top: calc(var(--ds-bento-reach) * var(--ds-bento-top, 0));\n --ds-bento-inset-end: calc(var(--ds-bento-reach) * var(--ds-bento-end, 0));\n --ds-bento-inset-bottom: calc(var(--ds-bento-reach) * var(--ds-bento-bottom, 0));\n --ds-bento-inset-start: calc(var(--ds-bento-reach) * var(--ds-bento-start, 0));\n grid-column: calc(var(--ds-bento-x, 0) + 1) / span var(--ds-bento-w, 4);\n grid-row: calc(var(--ds-bento-y, 0) + 1) / span var(--ds-bento-h, 4);\n margin: calc(-1 * var(--ds-bento-inset-top)) calc(-1 * var(--ds-bento-inset-end)) calc(-1 * var(--ds-bento-inset-bottom)) calc(-1 * var(--ds-bento-inset-start));\n}\n/* A card grows its own padding by the reach (card.css); any other tile is padded here, a square inside. */\n:host([squares]) ::slotted(:not(.ds-card, ds-card)) {\n padding:\n calc(var(--ds-unit) + var(--ds-bento-inset-top))\n calc(var(--ds-unit) + var(--ds-bento-inset-end))\n calc(var(--ds-unit) + var(--ds-bento-inset-bottom))\n calc(var(--ds-unit) + var(--ds-bento-inset-start));\n}\n";
|
|
12040
|
+
//#endregion
|
|
12041
|
+
//#region DS1/3-unit/ds-bento.ts
|
|
12042
|
+
var _Bento;
|
|
12043
|
+
var Bento = class extends i$2 {
|
|
12044
|
+
constructor() {
|
|
12045
|
+
super();
|
|
12046
|
+
this.squares = false;
|
|
12047
|
+
}
|
|
12048
|
+
connectedCallback() {
|
|
12049
|
+
super.connectedCallback();
|
|
12050
|
+
this.observer = new MutationObserver(() => this.place());
|
|
12051
|
+
this.observer.observe(this, {
|
|
12052
|
+
childList: true,
|
|
12053
|
+
subtree: true,
|
|
12054
|
+
attributes: true,
|
|
12055
|
+
attributeFilter: ["data-place", "hidden"]
|
|
12056
|
+
});
|
|
12057
|
+
}
|
|
12058
|
+
disconnectedCallback() {
|
|
12059
|
+
this.observer?.disconnect();
|
|
12060
|
+
super.disconnectedCallback();
|
|
12061
|
+
}
|
|
12062
|
+
updated() {
|
|
12063
|
+
if (this.columns) this.style.setProperty("--ds-bento-columns", String(this.columns));
|
|
12064
|
+
else this.style.removeProperty("--ds-bento-columns");
|
|
12065
|
+
this.place();
|
|
12066
|
+
}
|
|
12067
|
+
place() {
|
|
12068
|
+
if (this.squares) placeBento(this);
|
|
12069
|
+
}
|
|
12070
|
+
render() {
|
|
12071
|
+
return b$1`<slot @slotchange=${() => this.place()}></slot>`;
|
|
12072
|
+
}
|
|
12073
|
+
};
|
|
12074
|
+
_Bento = Bento;
|
|
12075
|
+
_Bento.properties = {
|
|
12076
|
+
columns: {
|
|
12077
|
+
type: Number,
|
|
12078
|
+
reflect: true
|
|
12079
|
+
},
|
|
12080
|
+
squares: {
|
|
12081
|
+
type: Boolean,
|
|
12082
|
+
reflect: true
|
|
12083
|
+
}
|
|
12084
|
+
};
|
|
12085
|
+
_Bento.styles = [r$3(component_metrics_default), r$3(ds_bento_default)];
|
|
12086
|
+
define("ds-bento", Bento);
|
|
12087
|
+
//#endregion
|
|
12088
|
+
//#region DS1/1-root/carousel.css?inline
|
|
12089
|
+
var carousel_default = "/* Shape is a surface preference. Keep these base lengths unscaled: each\n * component resolves them with its own --ds-sf in component-metrics.css. */\n[data-ds-shape=\"square\"],\n:host([data-ds-shape=\"square\"]) {\n --ds-corner-size: 0px;\n --ds-corner-shape: round;\n --ds-button-inset: 0.5px;\n}\n\n[data-ds-shape=\"rounded\"],\n:host([data-ds-shape=\"rounded\"]) {\n --ds-corner-size: 4px;\n --ds-corner-shape: round;\n --ds-button-inset: 2.5px;\n}\n\n[data-ds-shape=\"circular\"],\n:host([data-ds-shape=\"circular\"]) {\n --ds-corner-size: 999px;\n --ds-corner-shape: round;\n --ds-button-inset: 5px;\n}\n\n/* A squircle needs twice an arc's radius for the same apparent corner.\n * Circular controls keep true semicircles even in a squircle browser. */\n@supports (corner-shape: squircle) {\n [data-ds-shape=\"rounded\"],\n :host([data-ds-shape=\"rounded\"]) {\n --ds-corner-size: 8px;\n --ds-corner-shape: squircle;\n }\n}\n\n/* Resolve dimensions where a component is drawn. Inherited calc() values have\n * already used their ancestor's scale. Base tokens stay unscaled and inherit;\n * resolved tokens can still be overridden directly on a component.\n * data-ds-surface gives ordinary layout elements the same scaled measures.\n */\n:root,\n:host,\n:where([data-ds-surface]) {\n --ds-unit: calc(var(--ds-1, 20px) * var(--ds-sf, 1));\n --ds-control-height: calc(var(--ds-control-size, var(--ds-08, 16px)) * var(--ds-sf, 1));\n --ds-row-height: calc(var(--ds-row-size, var(--ds-1, 20px)) * var(--ds-sf, 1));\n --ds-type-size-default: calc(var(--ds-text-size, 14px) * var(--ds-sf, 1));\n --ds-type-size-small: calc(var(--ds-small-text-size, 10px) * var(--ds-sf, 1));\n --ds-type-size-heading: calc(var(--ds-heading-text-size, 13px) * var(--ds-sf, 1));\n --ds-type-size-display: calc(var(--ds-display-text-size, 20px) * var(--ds-sf, 1));\n --ds-type-lineheight-default: calc(var(--ds-text-leading, 16px) * var(--ds-sf, 1));\n --ds-type-letterspacing-default: calc(var(--ds-text-tracking, -0.3px) * var(--ds-sf, 1));\n --ds-radius: calc(var(--ds-corner-size, 4px) * var(--ds-sf, 1));\n --ds-radius-card: calc(var(--ds-card-corner-size, 4px) * var(--ds-sf, 1));\n}\n\n/*\n * A carousel, as plain classes on native elements.\n *\n * A carousel is a row of slides that snaps sideways, one slide to a stop,\n * with a row of controls one square high under it: optional previous and\n * next buttons and a dot for each slide. Slides are the track's width, or\n * whole squares wide, a whole number of squares apart (one by default). The\n * controls stand one square below the track, on the grid from its start.\n * The `ds-carousel` element draws the same parts, and\n * `0-face/carousel.ts` gives the native markup its behaviour.\n *\n * ds-carousel the region: track, controls, status;\n * `data-slides=\"auto\"` for slides of their\n * own width, `data-bleed` `end` or `both`,\n * `data-snap=\"none\"` to slide freely\n * ds-carousel__track the scroller; every child is a slide\n * ds-carousel__controls the row of buttons and dots\n * ds-carousel__previous, __next, icon buttons, on `.ds-button.ds-button--icon`\n * __pause\n * ds-carousel__status the polite announcement, kept out of sight\n *\n * The dots are `ds-progress--dots` from progress.css.\n *\n * A strip of slides of their own width can run on past its box to the\n * window's end edge, or to both edges, while its first slide keeps to the\n * box's start, so it lines up with the page's column; `--ds-carousel-before`\n * and `--ds-carousel-after` are the room to the edges, which the script\n * measures.\n *\n * Tokens: `--ds-carousel-slide` (a slide's width, the track's by default)\n * and `--ds-carousel-gap` (between slides, one square by default).\n */\n\n.ds-carousel {\n box-sizing: border-box;\n display: grid;\n grid-template-columns: minmax(0, 1fr);\n row-gap: var(--ds-unit);\n position: relative;\n min-width: 0;\n margin: 0;\n}\n\n.ds-carousel__track {\n box-sizing: border-box;\n display: grid;\n grid-auto-flow: column;\n grid-auto-columns: var(--ds-carousel-slide, 100%);\n column-gap: var(--ds-carousel-gap, var(--ds-unit));\n min-width: 0;\n margin: 0;\n padding: 0;\n list-style: none;\n overflow-x: auto;\n overflow-y: hidden;\n overscroll-behavior-x: contain;\n scroll-snap-type: x mandatory;\n scrollbar-width: none;\n}\n\n.ds-carousel__track::-webkit-scrollbar {\n display: none;\n}\n\n/* Slides of their own width, several in view. */\n.ds-carousel[data-slides=\"auto\"] > .ds-carousel__track {\n grid-auto-columns: max-content;\n}\n\n.ds-carousel[data-snap=\"none\"] > .ds-carousel__track {\n scroll-snap-type: none;\n}\n\n/* To the window's end edge: the track reaches out over the room after the\n box and keeps a gap at its end, so the last slide stops short of the edge. */\n.ds-carousel[data-bleed=\"end\"] > .ds-carousel__track {\n margin-inline-end: calc(-1 * var(--ds-carousel-after, 0px));\n padding-inline-end: var(--ds-carousel-gap, var(--ds-unit));\n}\n\n/* To both edges: the track reaches out both ways, and the first slide, and\n each one it stops at, still stands on the box's start. */\n.ds-carousel[data-bleed=\"both\"] > .ds-carousel__track {\n margin-inline: calc(-1 * var(--ds-carousel-before, 0px)) calc(-1 * var(--ds-carousel-after, 0px));\n padding-inline: var(--ds-carousel-before, 0px) var(--ds-carousel-gap, var(--ds-unit));\n scroll-padding-inline-start: var(--ds-carousel-before, 0px);\n}\n\n.ds-carousel__track:focus-visible {\n outline: 2px solid var(--ds-focus-ring);\n outline-offset: 1px;\n}\n\n.ds-carousel__track > * {\n box-sizing: border-box;\n min-width: 0;\n margin: 0;\n scroll-snap-align: start;\n}\n\n/* One slide to a stop; a strip of several in view may pass a few. */\n.ds-carousel:not([data-slides=\"auto\"]) > .ds-carousel__track > * {\n scroll-snap-stop: always;\n}\n\n.ds-carousel__controls {\n display: flex;\n align-items: center;\n height: var(--ds-row-height);\n min-width: 0;\n}\n\n/* The buttons take a one-square cell each, as the dots do. Two classes, so\n the button's own reset of its margin does not undo it. */\n.ds-carousel .ds-carousel__previous,\n.ds-carousel .ds-carousel__next,\n.ds-carousel .ds-carousel__pause {\n flex: none;\n margin: calc((var(--ds-unit) - var(--ds-control-height)) / 2);\n}\n\n/* Previous points back along the reading direction. */\n.ds-carousel:dir(rtl) :is(.ds-carousel__previous, .ds-carousel__next) > * {\n transform: scaleX(-1);\n}\n\n.ds-carousel__status {\n position: absolute;\n width: 1px;\n height: 1px;\n overflow: hidden;\n clip-path: inset(50%);\n white-space: nowrap;\n}\n";
|
|
12090
|
+
//#endregion
|
|
12091
|
+
//#region DS1/3-unit/styles/ds-carousel.css?inline
|
|
12092
|
+
var ds_carousel_default = "/* ds-carousel.css */\n/* The element only places the parts; 1-root/carousel.css draws them and\n controls.css the buttons. The slides are the element's children, so the\n track's rules for its children are said again for slotted ones. */\n\n:host {\n display: block;\n min-width: 0;\n}\n\n:host([hidden]) {\n display: none !important;\n}\n\n::slotted(*) {\n box-sizing: border-box;\n flex: none;\n min-width: 0;\n margin: 0;\n scroll-snap-align: start;\n}\n\n/* One slide to a stop; a strip of slides of their own width may pass a few. */\n:host(:not([slide-width=\"auto\"])) ::slotted(*) {\n scroll-snap-stop: always;\n}\n\n:host(:dir(rtl)) :is(.ds-carousel__previous, .ds-carousel__next) > ds-icon {\n transform: scaleX(-1);\n}\n";
|
|
12093
|
+
//#endregion
|
|
12094
|
+
//#region DS1/3-unit/ds-carousel.ts
|
|
12095
|
+
var _Carousel;
|
|
12096
|
+
/** A whole number of squares, or `undefined` for a value that is not one. */
|
|
12097
|
+
var squares = (value, least) => typeof value === "number" && Number.isFinite(value) && value >= least ? Math.floor(value) : void 0;
|
|
11937
12098
|
/**
|
|
11938
|
-
* @element ds-
|
|
11939
|
-
* @prop {string}
|
|
11940
|
-
*
|
|
11941
|
-
* @prop {
|
|
11942
|
-
* @prop {
|
|
11943
|
-
*
|
|
11944
|
-
* @prop {boolean}
|
|
11945
|
-
* @prop {
|
|
11946
|
-
*
|
|
11947
|
-
*
|
|
11948
|
-
*
|
|
11949
|
-
* @prop {
|
|
11950
|
-
* @prop {
|
|
11951
|
-
* `
|
|
11952
|
-
*
|
|
11953
|
-
* @prop {
|
|
11954
|
-
*
|
|
11955
|
-
*
|
|
11956
|
-
* @prop {string}
|
|
11957
|
-
*
|
|
11958
|
-
*
|
|
11959
|
-
*
|
|
12099
|
+
* @element ds-carousel
|
|
12100
|
+
* @prop {string} label - The region's name: a translation key, or literal
|
|
12101
|
+
* words. Name what the slides show ("Colours", "What people say").
|
|
12102
|
+
* @prop {boolean} literal - Show `label` as written, never looked up.
|
|
12103
|
+
* @prop {number} current - The slide in view, from 0. Setting it scrolls there.
|
|
12104
|
+
* @prop {boolean} buttons - Show previous and next buttons beside the dots.
|
|
12105
|
+
* @prop {boolean} noDots - Leave the dots out (`no-dots`).
|
|
12106
|
+
* @prop {boolean} end - Draw the last dot as an end marker.
|
|
12107
|
+
* @prop {number | "auto"} slideWidth - Each slide's width in whole squares
|
|
12108
|
+
* (`slide-width`); the carousel's own width when not set; `auto` for slides
|
|
12109
|
+
* of their own width, a strip of several in view.
|
|
12110
|
+
* @prop {number} gap - Squares between slides; one by default.
|
|
12111
|
+
* @prop {string} bleed - `none` (the default) keeps the strip in its box;
|
|
12112
|
+
* `end` runs it on to the window's end edge, the first slide still on the
|
|
12113
|
+
* box's start; `both` runs it to both edges.
|
|
12114
|
+
* @prop {boolean} loop - Hold the slides three times over, so the strip has no
|
|
12115
|
+
* end. The copies are hidden from assistive technology and never focused;
|
|
12116
|
+
* a looping carousel draws no dots.
|
|
12117
|
+
* @prop {string} autoplay - Move on a slide at a time by itself: empty for
|
|
12118
|
+
* every five seconds, or a number of milliseconds. Held while a person is
|
|
12119
|
+
* in the strip or cannot see it, never under reduced motion, and always
|
|
12120
|
+
* with a pause button.
|
|
12121
|
+
* @prop {boolean} free - Slide freely, without stopping at slides.
|
|
11960
12122
|
*
|
|
11961
|
-
* @
|
|
11962
|
-
*
|
|
11963
|
-
* @fires
|
|
12123
|
+
* @slot - The slides, one element each.
|
|
12124
|
+
*
|
|
12125
|
+
* @fires change - A person moved to another slide: by swiping, scrolling, a
|
|
12126
|
+
* dot or a button. `detail` is `{ index, previous }`. Setting `current` or
|
|
12127
|
+
* calling `goTo()` does not fire it.
|
|
12128
|
+
*
|
|
12129
|
+
* The element is a region described as a carousel, named by `label`; each
|
|
12130
|
+
* slide is a group labelled "2 of 5" unless the page labels it, and the
|
|
12131
|
+
* current slide is announced politely when it changes. It moves on its own
|
|
12132
|
+
* only with `autoplay`. `bleed`, `loop` and `autoplay` are read when the
|
|
12133
|
+
* element first draws; put a new element in its place to change them.
|
|
11964
12134
|
*
|
|
11965
12135
|
* @example
|
|
11966
|
-
* <ds-
|
|
12136
|
+
* <ds-carousel label="Colours" slide-width="12" buttons>
|
|
12137
|
+
* <figure>…</figure>
|
|
12138
|
+
* <figure>…</figure>
|
|
12139
|
+
* </ds-carousel>
|
|
11967
12140
|
*/
|
|
11968
|
-
var
|
|
11969
|
-
constructor() {
|
|
11970
|
-
super();
|
|
11971
|
-
this.
|
|
11972
|
-
this.
|
|
11973
|
-
this.
|
|
11974
|
-
this.
|
|
11975
|
-
this.relabel = () =>
|
|
11976
|
-
|
|
11977
|
-
|
|
11978
|
-
if (!this.shown || !panel || !trigger) return;
|
|
11979
|
-
const rect = trigger.getBoundingClientRect();
|
|
11980
|
-
const view = this.ownerDocument.defaultView;
|
|
11981
|
-
const viewport = view.visualViewport;
|
|
11982
|
-
const left = viewport?.offsetLeft ?? 0, top = viewport?.offsetTop ?? 0;
|
|
11983
|
-
const width = viewport?.width ?? view.innerWidth, height = viewport?.height ?? view.innerHeight;
|
|
11984
|
-
const box = panel.getBoundingClientRect();
|
|
11985
|
-
const gap = (parseFloat(getComputedStyle(panel).paddingTop) || 9) + 1;
|
|
11986
|
-
const square = Math.max(rect.height, gap * 2);
|
|
11987
|
-
const foot = rect.bottom, head = rect.bottom - square;
|
|
11988
|
-
const below = top + height - foot - 2 * gap, above = head - top - 2 * gap;
|
|
11989
|
-
const up = below < box.height && above > below;
|
|
11990
|
-
const x = getComputedStyle(this).direction === "rtl" ? rect.right - box.width : rect.left;
|
|
11991
|
-
panel.style.left = `${Math.max(left + gap, Math.min(x, left + width - gap - box.width))}px`;
|
|
11992
|
-
panel.style.top = `${Math.max(top + gap, up ? head - gap - box.height : foot + gap)}px`;
|
|
11993
|
-
};
|
|
11994
|
-
this.onOutside = (event) => {
|
|
11995
|
-
if (!event.composedPath().includes(this)) this.open = false;
|
|
11996
|
-
};
|
|
11997
|
-
this.toggle = () => {
|
|
11998
|
-
if (this.disabled) return;
|
|
11999
|
-
this.focusMonth = false;
|
|
12000
|
-
this.open = !this.open;
|
|
12001
|
-
};
|
|
12002
|
-
this.onTriggerKey = (event) => {
|
|
12003
|
-
if (this.disabled) return;
|
|
12004
|
-
if (event.key === "ArrowDown" || event.key === "ArrowUp" || (event.key === "Enter" || event.key === " ") && !this.open) {
|
|
12005
|
-
event.preventDefault();
|
|
12006
|
-
this.focusMonth = true;
|
|
12007
|
-
if (this.open) this.focusDay();
|
|
12008
|
-
else this.open = true;
|
|
12009
|
-
}
|
|
12141
|
+
var Carousel = class extends i$2 {
|
|
12142
|
+
constructor() {
|
|
12143
|
+
super();
|
|
12144
|
+
this.drive = null;
|
|
12145
|
+
this.own = /* @__PURE__ */ new Map();
|
|
12146
|
+
this.frame = 0;
|
|
12147
|
+
this.moving = false;
|
|
12148
|
+
this.relabel = () => {
|
|
12149
|
+
this.labelSlides();
|
|
12150
|
+
this.requestUpdate();
|
|
12010
12151
|
};
|
|
12011
|
-
this.
|
|
12012
|
-
|
|
12013
|
-
|
|
12014
|
-
|
|
12015
|
-
this.
|
|
12016
|
-
|
|
12152
|
+
this.scrolled = () => {
|
|
12153
|
+
cancelAnimationFrame(this.frame);
|
|
12154
|
+
if (this.loop) return;
|
|
12155
|
+
this.frame = requestAnimationFrame(() => {
|
|
12156
|
+
if (this.pending !== void 0) {
|
|
12157
|
+
clearTimeout(this.settle);
|
|
12158
|
+
this.settle = setTimeout(() => {
|
|
12159
|
+
this.pending = void 0;
|
|
12160
|
+
}, 150);
|
|
12161
|
+
return;
|
|
12162
|
+
}
|
|
12163
|
+
const track = this.track;
|
|
12164
|
+
if (track) this.show(nearestSlide(track, this.slides, this.index));
|
|
12165
|
+
});
|
|
12017
12166
|
};
|
|
12018
|
-
this.
|
|
12019
|
-
|
|
12020
|
-
if (this.open && next instanceof Node && !this.contains(next) && !this.renderRoot.contains(next)) this.open = false;
|
|
12167
|
+
this.ended = () => {
|
|
12168
|
+
this.pending = void 0;
|
|
12021
12169
|
};
|
|
12022
12170
|
this.picked = (event) => {
|
|
12023
12171
|
event.stopPropagation();
|
|
12024
|
-
|
|
12025
|
-
|
|
12026
|
-
day: event.detail.start,
|
|
12027
|
-
time: start?.time || (this.time ? "09:00" : "")
|
|
12028
|
-
};
|
|
12029
|
-
if (!event.detail.end) {
|
|
12030
|
-
this.awaitingEnd = true;
|
|
12031
|
-
this.write(first, void 0);
|
|
12032
|
-
return;
|
|
12033
|
-
}
|
|
12034
|
-
this.awaitingEnd = false;
|
|
12035
|
-
const last = {
|
|
12036
|
-
day: event.detail.end,
|
|
12037
|
-
time: end?.time || (this.time ? "10:00" : "")
|
|
12038
|
-
};
|
|
12039
|
-
this.write(first, last);
|
|
12040
|
-
if (!this.time) this.open = false;
|
|
12041
|
-
};
|
|
12042
|
-
this.setTime = () => {
|
|
12043
|
-
this.time = !this.time;
|
|
12044
|
-
const { start, end } = this.ends;
|
|
12045
|
-
const timed = (side, clock) => side ? {
|
|
12046
|
-
...side,
|
|
12047
|
-
time: this.time ? side.time || clock : ""
|
|
12048
|
-
} : void 0;
|
|
12049
|
-
this.write(timed(start, "09:00"), timed(end ?? (this.time ? start : void 0), "10:00"));
|
|
12050
|
-
};
|
|
12051
|
-
this.passPress = (event) => {
|
|
12052
|
-
const control = event.currentTarget.querySelector(".ds-switch");
|
|
12053
|
-
if (control && !event.composedPath().includes(control)) control.click();
|
|
12054
|
-
};
|
|
12055
|
-
this.clear = () => {
|
|
12056
|
-
this.commit("");
|
|
12057
|
-
this.open = false;
|
|
12172
|
+
event.preventDefault();
|
|
12173
|
+
this.move(event.detail.index);
|
|
12058
12174
|
};
|
|
12059
|
-
this.value = "";
|
|
12060
12175
|
this.literal = false;
|
|
12061
|
-
this.
|
|
12062
|
-
this.
|
|
12063
|
-
this.
|
|
12064
|
-
this.
|
|
12065
|
-
this.
|
|
12066
|
-
this.
|
|
12176
|
+
this.current = 0;
|
|
12177
|
+
this.buttons = false;
|
|
12178
|
+
this.noDots = false;
|
|
12179
|
+
this.end = false;
|
|
12180
|
+
this.bleed = "none";
|
|
12181
|
+
this.loop = false;
|
|
12182
|
+
this.autoplay = null;
|
|
12183
|
+
this.free = false;
|
|
12184
|
+
this.count = 0;
|
|
12185
|
+
this.announcement = "";
|
|
12186
|
+
this.paused = false;
|
|
12187
|
+
}
|
|
12188
|
+
/** The slides: the elements given to the carousel, without a loop's copies. */
|
|
12189
|
+
get slides() {
|
|
12190
|
+
return [...this.children].filter((child) => child instanceof HTMLElement && !child.hasAttribute("slot") && !child.hasAttribute("data-ds-carousel-copy"));
|
|
12191
|
+
}
|
|
12192
|
+
/** Milliseconds between autoplay steps; 0 for none. */
|
|
12193
|
+
get every() {
|
|
12194
|
+
return autoplayInterval(this.autoplay);
|
|
12195
|
+
}
|
|
12196
|
+
/** Slides of their own width: a strip. */
|
|
12197
|
+
get strip() {
|
|
12198
|
+
return this.slideWidth === "auto";
|
|
12199
|
+
}
|
|
12200
|
+
get track() {
|
|
12201
|
+
return this.renderRoot.querySelector(".ds-carousel__track");
|
|
12202
|
+
}
|
|
12203
|
+
/** The slide in view, inside the count. */
|
|
12204
|
+
get index() {
|
|
12205
|
+
const current = Number.isFinite(this.current) ? Math.floor(this.current) : 0;
|
|
12206
|
+
return Math.max(0, Math.min(this.count - 1, current));
|
|
12067
12207
|
}
|
|
12068
12208
|
connectedCallback() {
|
|
12069
12209
|
super.connectedCallback();
|
|
@@ -12073,330 +12213,220 @@ var DatePicker = class extends i$2 {
|
|
|
12073
12213
|
disconnectedCallback() {
|
|
12074
12214
|
window.removeEventListener("language-changed", this.relabel);
|
|
12075
12215
|
window.removeEventListener("translations-loaded", this.relabel);
|
|
12076
|
-
this.
|
|
12216
|
+
cancelAnimationFrame(this.frame);
|
|
12217
|
+
clearTimeout(this.settle);
|
|
12218
|
+
this.drive?.stop();
|
|
12219
|
+
this.drive = null;
|
|
12077
12220
|
super.disconnectedCallback();
|
|
12078
12221
|
}
|
|
12079
|
-
|
|
12080
|
-
|
|
12081
|
-
|
|
12082
|
-
/** The form was reset: back to the value it started with. */
|
|
12083
|
-
formResetCallback() {
|
|
12084
|
-
this.value = this.initial;
|
|
12085
|
-
}
|
|
12086
|
-
formDisabledCallback(disabled) {
|
|
12087
|
-
this.disabled = disabled;
|
|
12088
|
-
}
|
|
12089
|
-
words(value, fallback) {
|
|
12090
|
-
if (value && this.literal) return value;
|
|
12091
|
-
return getText(value || fallback) || value || fallback;
|
|
12092
|
-
}
|
|
12093
|
-
get trigger() {
|
|
12094
|
-
return this.renderRoot.querySelector(".trigger");
|
|
12095
|
-
}
|
|
12096
|
-
get panel() {
|
|
12097
|
-
return this.renderRoot.querySelector(".popover");
|
|
12098
|
-
}
|
|
12099
|
-
get calendar() {
|
|
12100
|
-
return this.renderRoot.querySelector("ds-calendar");
|
|
12101
|
-
}
|
|
12102
|
-
get ends() {
|
|
12103
|
-
return readDateValue(this.value);
|
|
12104
|
-
}
|
|
12105
|
-
willUpdate(changed) {
|
|
12106
|
-
super.willUpdate(changed);
|
|
12107
|
-
if (changed.has("value") && this.value) {
|
|
12108
|
-
const { start, end } = this.ends;
|
|
12109
|
-
if (!start) this.value = "";
|
|
12110
|
-
else if (start.time || end?.time) this.time = true;
|
|
12111
|
-
}
|
|
12112
|
-
if (changed.has("disabled") && this.disabled) this.open = false;
|
|
12113
|
-
}
|
|
12114
|
-
updated(changed) {
|
|
12115
|
-
super.updated(changed);
|
|
12116
|
-
if (changed.has("value") || changed.has("required")) {
|
|
12117
|
-
this.internals?.setFormValue(this.value || null);
|
|
12118
|
-
if (this.required && !this.value) this.internals?.setValidity({ valueMissing: true }, this.words(void 0, "Choose a date"), this.trigger ?? void 0);
|
|
12119
|
-
else this.internals?.setValidity({});
|
|
12120
|
-
}
|
|
12121
|
-
if (changed.has("open")) if (this.open) this.show();
|
|
12122
|
-
else this.hide(changed.get("open") === true);
|
|
12123
|
-
}
|
|
12124
|
-
/** Opens the panel. */
|
|
12125
|
-
show() {
|
|
12126
|
-
if (this.shown || this.disabled || !this.isConnected) return;
|
|
12127
|
-
const panel = this.panel;
|
|
12128
|
-
if (!panel) return;
|
|
12129
|
-
for (const other of openPickers) if (other !== this) other.open = false;
|
|
12130
|
-
openPickers.add(this);
|
|
12131
|
-
this.shown = true;
|
|
12132
|
-
this.open = true;
|
|
12133
|
-
this.awaitingEnd = false;
|
|
12134
|
-
const calendar = this.calendar;
|
|
12135
|
-
if (calendar) calendar.month = (this.ends.start?.day || this.today || today()).slice(0, 7);
|
|
12136
|
-
panel.showPopover?.();
|
|
12137
|
-
this.place();
|
|
12138
|
-
if (calendar) calendar.updateComplete.then(this.place);
|
|
12139
|
-
this.ownerDocument.addEventListener("pointerdown", this.onOutside, true);
|
|
12140
|
-
this.ownerDocument.addEventListener("scroll", this.place, true);
|
|
12141
|
-
window.addEventListener("resize", this.place);
|
|
12142
|
-
this.dispatchEvent(new CustomEvent("ds-date-picker-toggle", {
|
|
12143
|
-
bubbles: true,
|
|
12144
|
-
composed: true,
|
|
12145
|
-
detail: { open: true }
|
|
12146
|
-
}));
|
|
12147
|
-
if (this.focusMonth) this.focusDay();
|
|
12148
|
-
}
|
|
12149
|
-
/** Closes the panel, giving focus back to the field when it was inside. */
|
|
12150
|
-
hide(restore = true) {
|
|
12151
|
-
if (!this.shown) return;
|
|
12152
|
-
this.shown = false;
|
|
12153
|
-
openPickers.delete(this);
|
|
12154
|
-
this.awaitingEnd = false;
|
|
12155
|
-
const panel = this.panel;
|
|
12156
|
-
const within = panel?.matches(":focus-within");
|
|
12157
|
-
if (panel?.matches(":popover-open")) panel.hidePopover?.();
|
|
12158
|
-
this.ownerDocument.removeEventListener("pointerdown", this.onOutside, true);
|
|
12159
|
-
this.ownerDocument.removeEventListener("scroll", this.place, true);
|
|
12160
|
-
window.removeEventListener("resize", this.place);
|
|
12161
|
-
this.open = false;
|
|
12162
|
-
if (restore && within) this.trigger?.focus({ preventScroll: true });
|
|
12163
|
-
this.dispatchEvent(new CustomEvent("ds-date-picker-toggle", {
|
|
12164
|
-
bubbles: true,
|
|
12165
|
-
composed: true,
|
|
12166
|
-
detail: { open: false }
|
|
12167
|
-
}));
|
|
12168
|
-
}
|
|
12169
|
-
async focusDay() {
|
|
12170
|
-
const calendar = this.calendar;
|
|
12171
|
-
if (!calendar) return;
|
|
12172
|
-
await calendar.updateComplete;
|
|
12173
|
-
calendar.renderRoot.querySelector("[data-day][tabindex=\"0\"]")?.focus({ preventScroll: true });
|
|
12174
|
-
}
|
|
12175
|
-
/** Takes a new value and says so. */
|
|
12176
|
-
commit(value) {
|
|
12177
|
-
const previous = this.value || "";
|
|
12178
|
-
if (value === previous) return;
|
|
12179
|
-
this.value = value;
|
|
12180
|
-
const detail = {
|
|
12181
|
-
value,
|
|
12182
|
-
previous
|
|
12183
|
-
};
|
|
12184
|
-
this.dispatchEvent(new CustomEvent("input", {
|
|
12185
|
-
bubbles: true,
|
|
12186
|
-
composed: true,
|
|
12187
|
-
detail
|
|
12188
|
-
}));
|
|
12189
|
-
this.dispatchEvent(new CustomEvent("change", {
|
|
12190
|
-
bubbles: true,
|
|
12191
|
-
composed: true,
|
|
12192
|
-
detail
|
|
12193
|
-
}));
|
|
12194
|
-
}
|
|
12195
|
-
write(start, end) {
|
|
12196
|
-
this.commit(writeDateValue(start, end, { time: this.time }));
|
|
12222
|
+
words(value, fallback, params) {
|
|
12223
|
+
const text = value && this.literal ? value : getText(value || fallback, params) || value || fallback;
|
|
12224
|
+
return params ? text.replace(/\{\{?(\w+)\}?\}/g, (whole, name) => name in params ? String(params[name]) : whole) : text;
|
|
12197
12225
|
}
|
|
12198
|
-
/**
|
|
12199
|
-
|
|
12200
|
-
const
|
|
12201
|
-
|
|
12202
|
-
|
|
12203
|
-
|
|
12204
|
-
|
|
12205
|
-
return;
|
|
12206
|
-
}
|
|
12207
|
-
const day = parseTypedDay(text);
|
|
12208
|
-
if (!day) {
|
|
12209
|
-
input.value = this.fieldText(side === "start" ? start : end);
|
|
12210
|
-
return;
|
|
12211
|
-
}
|
|
12212
|
-
const next = {
|
|
12213
|
-
day,
|
|
12214
|
-
time: (side === "start" ? start : end)?.time || (this.time ? side === "start" ? "09:00" : "10:00" : "")
|
|
12215
|
-
};
|
|
12216
|
-
if (side === "start") this.write(next, end);
|
|
12217
|
-
else this.write(start ?? next, next);
|
|
12218
|
-
this.awaitingEnd = false;
|
|
12219
|
-
const calendar = this.calendar;
|
|
12220
|
-
if (calendar) calendar.month = day.slice(0, 7);
|
|
12226
|
+
/** Writes an attribute the page has not written, and remembers it as this element's. */
|
|
12227
|
+
write(element, name, value) {
|
|
12228
|
+
const mine = this.own.get(element) ?? /* @__PURE__ */ new Set();
|
|
12229
|
+
if (element.hasAttribute(name) && !mine.has(name)) return;
|
|
12230
|
+
mine.add(name);
|
|
12231
|
+
this.own.set(element, mine);
|
|
12232
|
+
if (element.getAttribute(name) !== value) element.setAttribute(name, value);
|
|
12221
12233
|
}
|
|
12222
|
-
|
|
12223
|
-
const
|
|
12224
|
-
const
|
|
12225
|
-
|
|
12226
|
-
|
|
12227
|
-
|
|
12228
|
-
|
|
12229
|
-
|
|
12230
|
-
|
|
12231
|
-
|
|
12234
|
+
labelSlides() {
|
|
12235
|
+
const slides = this.slides;
|
|
12236
|
+
const labelled = (slide) => slide.hasAttribute("aria-labelledby");
|
|
12237
|
+
slides.forEach((slide, index) => {
|
|
12238
|
+
this.write(slide, "role", "group");
|
|
12239
|
+
this.write(slide, "aria-roledescription", this.words(void 0, "Slide"));
|
|
12240
|
+
if (!labelled(slide)) this.write(slide, "aria-label", this.words(void 0, "{index} of {count}", {
|
|
12241
|
+
index: index + 1,
|
|
12242
|
+
count: slides.length
|
|
12243
|
+
}));
|
|
12232
12244
|
});
|
|
12245
|
+
this.count = slides.length;
|
|
12233
12246
|
}
|
|
12234
|
-
|
|
12235
|
-
|
|
12236
|
-
|
|
12237
|
-
|
|
12247
|
+
willUpdate(changed) {
|
|
12248
|
+
super.willUpdate(changed);
|
|
12249
|
+
if (!this.hasUpdated) this.labelSlides();
|
|
12250
|
+
this.write(this, "role", "region");
|
|
12251
|
+
this.write(this, "aria-roledescription", this.words(void 0, "Carousel"));
|
|
12252
|
+
if (!this.hasAttribute("aria-labelledby")) this.write(this, "aria-label", this.words(this.label, "Carousel"));
|
|
12253
|
+
const width = squares(typeof this.slideWidth === "string" && this.slideWidth !== "auto" ? Number(this.slideWidth) : typeof this.slideWidth === "number" ? this.slideWidth : void 0, 1);
|
|
12254
|
+
const gap = squares(this.gap, 0);
|
|
12255
|
+
if (this.strip) this.style.setProperty("--ds-carousel-slide", "max-content");
|
|
12256
|
+
else if (width) this.style.setProperty("--ds-carousel-slide", `calc(var(--ds-unit) * ${width})`);
|
|
12257
|
+
else this.style.removeProperty("--ds-carousel-slide");
|
|
12258
|
+
if (gap !== void 0) this.style.setProperty("--ds-carousel-gap", `calc(var(--ds-unit) * ${gap})`);
|
|
12259
|
+
else this.style.removeProperty("--ds-carousel-gap");
|
|
12238
12260
|
}
|
|
12239
|
-
|
|
12240
|
-
|
|
12241
|
-
|
|
12242
|
-
|
|
12243
|
-
|
|
12261
|
+
firstUpdated() {
|
|
12262
|
+
const track = this.track;
|
|
12263
|
+
const bleed = bleedOf(this.bleed);
|
|
12264
|
+
if (track && (bleed !== "none" || this.loop || this.every > 0)) this.drive = driveCarousel(this, track, this, {
|
|
12265
|
+
bleed,
|
|
12266
|
+
loop: this.loop,
|
|
12267
|
+
autoplay: this.every
|
|
12244
12268
|
});
|
|
12245
12269
|
}
|
|
12246
|
-
|
|
12247
|
-
|
|
12270
|
+
updated(changed) {
|
|
12271
|
+
super.updated(changed);
|
|
12272
|
+
if (this.loop) return;
|
|
12273
|
+
if (changed.has("current")) {
|
|
12274
|
+
if (this.moving) {
|
|
12275
|
+
this.moving = false;
|
|
12276
|
+
return;
|
|
12277
|
+
}
|
|
12278
|
+
this.travel(this.index, changed.get("current") !== void 0);
|
|
12279
|
+
} else if (changed.has("count") && !changed.get("count") && this.index > 0) this.travel(this.index, false);
|
|
12248
12280
|
}
|
|
12249
|
-
/**
|
|
12250
|
-
|
|
12251
|
-
|
|
12252
|
-
if (!start) return this.words(this.placeholder, "Choose a date");
|
|
12253
|
-
const formatter = this.formatter(Boolean(start.time || end?.time));
|
|
12254
|
-
if (!end) return formatter.format(this.moment(start));
|
|
12255
|
-
return formatter.formatRange ? formatter.formatRange(this.moment(start), this.moment(end)) : `${formatter.format(this.moment(start))} – ${formatter.format(this.moment(end))}`;
|
|
12281
|
+
/** Goes to a slide: smoothly, unless the reader asks for reduced motion. Fires no `change`. */
|
|
12282
|
+
goTo(index) {
|
|
12283
|
+
this.current = index;
|
|
12256
12284
|
}
|
|
12257
|
-
|
|
12258
|
-
|
|
12259
|
-
|
|
12260
|
-
|
|
12261
|
-
|
|
12262
|
-
|
|
12263
|
-
|
|
12264
|
-
|
|
12265
|
-
|
|
12266
|
-
|
|
12267
|
-
|
|
12268
|
-
|
|
12269
|
-
|
|
12270
|
-
|
|
12271
|
-
|
|
12285
|
+
/** Goes to the next slide, as the next button does. */
|
|
12286
|
+
next() {
|
|
12287
|
+
if (this.drive) this.drive.step(1);
|
|
12288
|
+
else this.move(this.index + 1);
|
|
12289
|
+
}
|
|
12290
|
+
/** Goes to the previous slide, as the previous button does. */
|
|
12291
|
+
previous() {
|
|
12292
|
+
if (this.drive) this.drive.step(-1);
|
|
12293
|
+
else this.move(this.index - 1);
|
|
12294
|
+
}
|
|
12295
|
+
togglePause() {
|
|
12296
|
+
this.paused = !this.paused;
|
|
12297
|
+
this.drive?.pause(this.paused);
|
|
12298
|
+
}
|
|
12299
|
+
travel(index, smooth) {
|
|
12300
|
+
const track = this.track;
|
|
12301
|
+
const slide = this.slides[index];
|
|
12302
|
+
if (!track || !slide || !scrollToSlide(track, slide, smooth)) return;
|
|
12303
|
+
this.pending = index;
|
|
12304
|
+
clearTimeout(this.settle);
|
|
12305
|
+
this.settle = setTimeout(() => {
|
|
12306
|
+
this.pending = void 0;
|
|
12307
|
+
}, 600);
|
|
12308
|
+
}
|
|
12309
|
+
/** A person moved to `index`: show it, say it, and fire `change`. */
|
|
12310
|
+
show(index) {
|
|
12311
|
+
const target = Math.max(0, Math.min(this.count - 1, index));
|
|
12312
|
+
const previous = this.index;
|
|
12313
|
+
if (target === previous || this.count === 0) return;
|
|
12314
|
+
this.moving = true;
|
|
12315
|
+
this.current = target;
|
|
12316
|
+
this.announcement = this.words(void 0, "{index} of {count}", {
|
|
12317
|
+
index: target + 1,
|
|
12318
|
+
count: this.count
|
|
12319
|
+
});
|
|
12320
|
+
this.dispatchEvent(new CustomEvent("change", {
|
|
12321
|
+
bubbles: true,
|
|
12322
|
+
composed: true,
|
|
12323
|
+
detail: {
|
|
12324
|
+
index: target,
|
|
12325
|
+
previous
|
|
12272
12326
|
}
|
|
12273
|
-
}
|
|
12274
|
-
|
|
12275
|
-
|
|
12276
|
-
|
|
12277
|
-
|
|
12278
|
-
|
|
12279
|
-
type="time"
|
|
12280
|
-
aria-label=${`${label}, ${this.words(void 0, "Time")}`}
|
|
12281
|
-
.value=${value?.time ?? ""}
|
|
12282
|
-
?disabled=${!this.ends.start}
|
|
12283
|
-
@change=${(event) => this.timed(side, event.target)}
|
|
12284
|
-
/>
|
|
12285
|
-
</div>` : A}`;
|
|
12327
|
+
}));
|
|
12328
|
+
}
|
|
12329
|
+
move(index) {
|
|
12330
|
+
const target = Math.max(0, Math.min(this.count - 1, index));
|
|
12331
|
+
this.travel(target, true);
|
|
12332
|
+
this.show(target);
|
|
12286
12333
|
}
|
|
12287
12334
|
render() {
|
|
12288
|
-
const
|
|
12289
|
-
const
|
|
12290
|
-
const
|
|
12291
|
-
|
|
12292
|
-
|
|
12293
|
-
|
|
12294
|
-
|
|
12295
|
-
|
|
12296
|
-
|
|
12297
|
-
|
|
12298
|
-
|
|
12299
|
-
|
|
12300
|
-
|
|
12301
|
-
|
|
12302
|
-
|
|
12303
|
-
>
|
|
12304
|
-
<
|
|
12305
|
-
|
|
12306
|
-
|
|
12307
|
-
|
|
12308
|
-
|
|
12309
|
-
|
|
12310
|
-
|
|
12311
|
-
|
|
12312
|
-
|
|
12313
|
-
|
|
12314
|
-
|
|
12315
|
-
|
|
12316
|
-
|
|
12317
|
-
|
|
12318
|
-
|
|
12319
|
-
|
|
12320
|
-
|
|
12321
|
-
<ds-calendar
|
|
12322
|
-
compact
|
|
12323
|
-
selectable
|
|
12324
|
-
range
|
|
12325
|
-
fixed
|
|
12326
|
-
outside-days
|
|
12327
|
-
.value=${days}
|
|
12328
|
-
.min=${this.min}
|
|
12329
|
-
.max=${this.max}
|
|
12330
|
-
.weekStart=${this.weekStart}
|
|
12331
|
-
.today=${this.today}
|
|
12332
|
-
@change=${this.picked}
|
|
12333
|
-
></ds-calendar>
|
|
12334
|
-
<div class="options" part="options">
|
|
12335
|
-
${this.noOptions ? A : b$1`<div class="separator" aria-hidden="true"></div>
|
|
12336
|
-
<div class="option" @click=${this.passPress}>
|
|
12337
|
-
<span>${this.words(void 0, "Include time")}</span>
|
|
12338
|
-
<button class="ds-switch" type="button" role="switch" aria-label=${this.words(void 0, "Include time")} aria-checked=${String(this.time)} @click=${this.setTime}></button>
|
|
12339
|
-
</div>`}
|
|
12340
|
-
${this.required ? A : b$1`<div class="separator" aria-hidden="true"></div>
|
|
12341
|
-
<button class="option clear" part="clear" type="button" ?disabled=${!start} @click=${this.clear}>${this.words(void 0, "Clear")}</button>`}
|
|
12342
|
-
</div>
|
|
12343
|
-
</div>`;
|
|
12335
|
+
const index = this.index;
|
|
12336
|
+
const driven = this.drive !== null || bleedOf(this.bleed) !== "none" || this.loop || this.every > 0;
|
|
12337
|
+
const button = (which) => b$1`<button
|
|
12338
|
+
class="ds-button ds-button--icon ds-carousel__${which}"
|
|
12339
|
+
part=${which}
|
|
12340
|
+
type="button"
|
|
12341
|
+
aria-label=${this.words(void 0, which === "previous" ? "Previous slide" : "Next slide")}
|
|
12342
|
+
?disabled=${!driven && (which === "previous" ? index <= 0 : index >= this.count - 1)}
|
|
12343
|
+
@click=${() => which === "previous" ? this.previous() : this.next()}
|
|
12344
|
+
><ds-icon type=${which === "previous" ? "left" : "right"} aria-hidden="true"></ds-icon></button>`;
|
|
12345
|
+
const moving = this.every > 0 && !prefersReducedMotion();
|
|
12346
|
+
const dots = !this.noDots && !this.loop;
|
|
12347
|
+
const controls = this.buttons || dots || moving;
|
|
12348
|
+
const bleed = bleedOf(this.bleed);
|
|
12349
|
+
return b$1`<div class="ds-carousel" part="carousel" data-slides=${this.strip ? "auto" : A} data-bleed=${bleed === "none" ? A : bleed} data-snap=${this.free ? "none" : A}>
|
|
12350
|
+
<div class="ds-carousel__track" part="track" @scroll=${this.scrolled} @scrollend=${this.ended}>
|
|
12351
|
+
<slot @slotchange=${() => this.labelSlides()}></slot>
|
|
12352
|
+
</div>
|
|
12353
|
+
${controls && this.count > 1 ? b$1`<div class="ds-carousel__controls" part="controls">
|
|
12354
|
+
${moving ? b$1`<button
|
|
12355
|
+
class="ds-button ds-button--icon ds-carousel__pause"
|
|
12356
|
+
part="pause"
|
|
12357
|
+
type="button"
|
|
12358
|
+
aria-pressed=${String(this.paused)}
|
|
12359
|
+
aria-label=${this.words(void 0, this.paused ? "Play" : "Pause")}
|
|
12360
|
+
@click=${this.togglePause}
|
|
12361
|
+
><ds-icon type=${this.paused ? "play-alt" : "pause"} aria-hidden="true"></ds-icon></button>` : A}
|
|
12362
|
+
${this.buttons ? button("previous") : A}
|
|
12363
|
+
${dots ? b$1`<ds-progress part="dots" .dots=${this.count} .active=${index} ?end=${this.end} @select=${this.picked}></ds-progress>` : A}
|
|
12364
|
+
${this.buttons ? button("next") : A}
|
|
12365
|
+
</div>` : A}
|
|
12366
|
+
<span class="ds-carousel__status" part="status" aria-live="polite" aria-atomic="true">${this.announcement}</span>
|
|
12367
|
+
</div>`;
|
|
12344
12368
|
}
|
|
12345
12369
|
};
|
|
12346
|
-
|
|
12347
|
-
|
|
12348
|
-
|
|
12349
|
-
|
|
12350
|
-
type:
|
|
12370
|
+
_Carousel = Carousel;
|
|
12371
|
+
_Carousel.properties = {
|
|
12372
|
+
label: { type: String },
|
|
12373
|
+
literal: {
|
|
12374
|
+
type: Boolean,
|
|
12351
12375
|
reflect: true
|
|
12352
12376
|
},
|
|
12353
|
-
|
|
12354
|
-
type:
|
|
12377
|
+
current: {
|
|
12378
|
+
type: Number,
|
|
12355
12379
|
reflect: true
|
|
12356
12380
|
},
|
|
12357
|
-
|
|
12358
|
-
literal: {
|
|
12381
|
+
buttons: {
|
|
12359
12382
|
type: Boolean,
|
|
12360
12383
|
reflect: true
|
|
12361
12384
|
},
|
|
12362
|
-
|
|
12363
|
-
length: { type: String },
|
|
12364
|
-
time: {
|
|
12385
|
+
noDots: {
|
|
12365
12386
|
type: Boolean,
|
|
12366
|
-
reflect: true
|
|
12387
|
+
reflect: true,
|
|
12388
|
+
attribute: "no-dots"
|
|
12367
12389
|
},
|
|
12368
|
-
|
|
12390
|
+
end: {
|
|
12369
12391
|
type: Boolean,
|
|
12370
|
-
attribute: "no-options",
|
|
12371
12392
|
reflect: true
|
|
12372
12393
|
},
|
|
12373
|
-
|
|
12374
|
-
|
|
12375
|
-
|
|
12394
|
+
slideWidth: {
|
|
12395
|
+
attribute: "slide-width",
|
|
12396
|
+
reflect: true,
|
|
12397
|
+
converter: {
|
|
12398
|
+
fromAttribute: (value) => value === null ? void 0 : value === "auto" ? "auto" : Number(value),
|
|
12399
|
+
toAttribute: (value) => value === void 0 ? null : String(value)
|
|
12400
|
+
}
|
|
12401
|
+
},
|
|
12402
|
+
gap: { type: Number },
|
|
12403
|
+
bleed: {
|
|
12376
12404
|
type: String,
|
|
12377
|
-
|
|
12405
|
+
reflect: true
|
|
12378
12406
|
},
|
|
12379
|
-
|
|
12380
|
-
required: {
|
|
12407
|
+
loop: {
|
|
12381
12408
|
type: Boolean,
|
|
12382
12409
|
reflect: true
|
|
12383
12410
|
},
|
|
12384
|
-
|
|
12385
|
-
type:
|
|
12411
|
+
autoplay: {
|
|
12412
|
+
type: String,
|
|
12386
12413
|
reflect: true
|
|
12387
12414
|
},
|
|
12388
|
-
|
|
12415
|
+
free: {
|
|
12389
12416
|
type: Boolean,
|
|
12390
12417
|
reflect: true
|
|
12391
12418
|
},
|
|
12392
|
-
|
|
12419
|
+
count: { state: true },
|
|
12420
|
+
announcement: { state: true },
|
|
12421
|
+
paused: { state: true }
|
|
12393
12422
|
};
|
|
12394
|
-
|
|
12423
|
+
_Carousel.styles = [
|
|
12395
12424
|
r$3(component_metrics_default),
|
|
12396
12425
|
r$3(controls_default),
|
|
12397
|
-
r$3(
|
|
12426
|
+
r$3(carousel_default),
|
|
12427
|
+
r$3(ds_carousel_default)
|
|
12398
12428
|
];
|
|
12399
|
-
define("ds-
|
|
12429
|
+
define("ds-carousel", Carousel);
|
|
12400
12430
|
//#endregion
|
|
12401
12431
|
//#region DS1/3-unit/ds-form.ts
|
|
12402
12432
|
var _Form;
|
|
@@ -16539,6 +16569,6 @@ _Image.properties = {
|
|
|
16539
16569
|
_Image.styles = r$3(ds_image_default);
|
|
16540
16570
|
define("ds-image", Image);
|
|
16541
16571
|
//#endregion
|
|
16542
|
-
export { Accordion, Avatar, AvatarGroup, Badge, Button, COMPONENT_VISIBILITY, CONTENTS_LABEL, Calendar, CalendarBase, CalendarLarge, Card, Carousel, ChartElement, Checkbox, ColorInput, Composer, Container, Context, Cycle, DEFAULT_LANGUAGE,
|
|
16572
|
+
export { Accordion, Avatar, AvatarGroup, Badge, Bento, Button, COMPONENT_VISIBILITY, CONTENTS_LABEL, Calendar, CalendarBase, CalendarLarge, Card, Carousel, ChartElement, Checkbox, ColorInput, Composer, Container, Context, Cycle, DEFAULT_LANGUAGE, DocumentPage, DsTable, EMPTY_HEADING, Empty, FALLBACK_LANGUAGE, FilePicker, Footer, Form, Gap, Grid, GridBars, GridChart, GridLineChart, GridRange, GridRatio, GridSpark, Header, Icon, Image, Input, LANGUAGES, LANGUAGE_METADATA, LOCALE_TAGS, LONG_PRESS_DELAY, List, MENU_LABEL, MESSAGE_ICONS, Matrix, Menu, Message, NOTICE_ICONS, Notice, Overlay, PAGE_LAYOUTS, Page, Panel, Progress, Radio, Row, SUPPORTED_LANGUAGES, Select, Series, Sidebar, Stat, Swatch, Switch, THEME_MODES, TOUCH_TOOLTIP_DURATION, Tabs, Tag, Text, Toaster, Token, TokenField, Tooltip, applike, applyScaling, ariaKeyShortcuts, avatarInk, calculateScalingFactor, columnLetter, componentVisibility, configureFormat, configureI18n, configureLanguageRouting, connectSidebar, createChart, currencyDigits, currencySymbol, currentLanguage, currentTheme, currentThemeMode, dateFormatter, detectMobileDevice, documentLevels, drawSparkline, englishText, fallbackLanguages, fillPlaceholders, followSystemTheme, footerPreferences, formatCompact, formatDate, formatDateTime, formatList, formatMoney, formatMoneyToParts, formatMonthDay, formatMonthDayTime, formatMonthYear, formatNumber, formatPercent, formatPrice, formatRelativeTime, formatTime, fromMinorUnits, getAvailableLanguages, getAvailableLanguagesSync, getBrowserLanguage, getDeviceInfo, getLanguageDisplayName, getLanguageRoutingOptions, getPriceCurrency, getPriceLabel, getScalingFactor, getText, getThemeMode, hasTranslation, headingId, hideTooltip, initDeviceDetection, initGridShortcut, initTooltips, isApplePlatform, isLanguage, isLanguageSlug, isModKey, isPublicComponent, isTranslationsFile, isTyping, keyWord, languageFromSlug, languageOrder, languageSlug, listFormatter, loadLanguage, loadSharedWords, loadTranslations, localeTag, matchesShortcut, measureStyle, toast as message, toast, modKey, nativeLanguageName, normalizeLanguage, numberFormatter, onShortcut, orderColumns, parseLanguagePath, parseShortcut, parseTypedDay, pickLanguages, placeholdersIn, preferenceStorageKey, provideIcons, readDateValue, readLanguageFile, readMonth, readRange, relativeTimeFormatter, relativeTimeUnit, resolveText, savePreferences, scale, scalingConfig, scalingFactor, setKeyWords, setLanguage, setScalingConfig, setTheme, setThemeMode, shortcutLabel, showTooltip, startScaling, stepStates, stripLanguagePrefix, textInLanguage, themeIconSvg, toDevicePixel, toLayoutStep, toMinorUnits, translate, treeStep, unscale, updateScalingFactor, validateTranslations, withLanguagePrefix, writeDateValue };
|
|
16543
16573
|
|
|
16544
16574
|
//# sourceMappingURL=design-system-1.bundle.js.map
|