tyrell-components 1.0.0-TC58 → 1.0.0-TC59

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.
Files changed (65) hide show
  1. package/css/tyrell-colors-static.css +14 -0
  2. package/css/tyrell-theme.css +1 -0
  3. package/css/tyrell.css +8 -6
  4. package/dist/tyrell-colors-static.css +1 -1
  5. package/dist/tyrell-theme.css +1 -1
  6. package/dist/tyrell.js +1 -1
  7. package/lib/base/ty-component.d.ts +8 -12
  8. package/lib/base/ty-component.js +38 -9
  9. package/lib/components/button.d.ts +10 -0
  10. package/lib/components/button.js +22 -1
  11. package/lib/components/calendar-month.d.ts +7 -1
  12. package/lib/components/calendar-month.js +32 -18
  13. package/lib/components/calendar-navigation.js +19 -6
  14. package/lib/components/calendar.d.ts +24 -5
  15. package/lib/components/calendar.js +83 -37
  16. package/lib/components/checkbox.d.ts +5 -0
  17. package/lib/components/checkbox.js +18 -5
  18. package/lib/components/copy.d.ts +2 -0
  19. package/lib/components/copy.js +15 -31
  20. package/lib/components/date-picker.d.ts +7 -26
  21. package/lib/components/date-picker.js +14 -84
  22. package/lib/components/file-upload.js +6 -2
  23. package/lib/components/input.d.ts +0 -9
  24. package/lib/components/input.js +17 -40
  25. package/lib/components/modal.js +59 -18
  26. package/lib/components/popup.js +56 -5
  27. package/lib/components/radio.d.ts +6 -0
  28. package/lib/components/radio.js +12 -28
  29. package/lib/components/select.d.ts +29 -11
  30. package/lib/components/select.js +43 -57
  31. package/lib/components/switch.d.ts +4 -0
  32. package/lib/components/switch.js +18 -5
  33. package/lib/components/tabs.js +1 -1
  34. package/lib/components/textarea.d.ts +1 -0
  35. package/lib/components/textarea.js +21 -8
  36. package/lib/index.d.ts +1 -0
  37. package/lib/index.js +1 -0
  38. package/lib/styles/button.js +1 -0
  39. package/lib/styles/calendar-month.js +1 -1
  40. package/lib/styles/calendar.js +3 -0
  41. package/lib/styles/checkbox.js +11 -5
  42. package/lib/styles/date-picker.js +5 -10
  43. package/lib/styles/input.js +5 -9
  44. package/lib/styles/option.d.ts +1 -1
  45. package/lib/styles/option.js +4 -0
  46. package/lib/styles/popup.d.ts +1 -1
  47. package/lib/styles/popup.js +2 -0
  48. package/lib/styles/radio.js +10 -4
  49. package/lib/styles/select-base.js +5 -10
  50. package/lib/styles/select.d.ts +1 -1
  51. package/lib/styles/select.js +4 -0
  52. package/lib/styles/switch.js +10 -5
  53. package/lib/styles/tag.js +2 -1
  54. package/lib/utils/calendar-utils.d.ts +49 -0
  55. package/lib/utils/calendar-utils.js +63 -6
  56. package/lib/utils/scroll-lock.d.ts +10 -4
  57. package/lib/utils/scroll-lock.js +102 -2
  58. package/lib/utils/validity.d.ts +27 -1
  59. package/lib/utils/validity.js +68 -16
  60. package/lib/version.d.ts +1 -1
  61. package/lib/version.js +1 -1
  62. package/package.json +1 -1
  63. package/dist/tyrell.js.map +0 -1
  64. package/lib/utils/error-flavor.d.ts +0 -8
  65. package/lib/utils/error-flavor.js +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"file":"tyrell.js","sources":["../src/types/common.ts","../src/utils/property-manager.ts","../src/utils/validity.ts","../src/utils/upgrade-properties.ts","../src/base/ty-component.ts","../src/utils/styles.ts","../src/styles/button.ts","../src/utils/flavor-sheet.ts","../src/utils/loader-registry.ts","../src/components/button.ts","../src/styles/icon.ts","../src/version.ts","../src/utils/icon-registry.ts","../src/components/icon.ts","../src/styles/tag.ts","../src/components/tag.ts","../src/styles/option.ts","../src/components/option.ts","../src/utils/error-flavor.ts","../src/styles/field-size.ts","../src/styles/input.ts","../src/utils/number-format.ts","../src/utils/locale.ts","../src/utils/icons.ts","../src/components/input.ts","../src/styles/checkbox.ts","../src/components/checkbox.ts","../src/styles/switch.ts","../src/components/switch.ts","../src/styles/radio.ts","../src/components/radio.ts","../src/styles/copy.ts","../src/components/copy.ts","../src/styles/file-upload.ts","../src/components/file-upload.ts","../src/styles/textarea.ts","../src/utils/custom-scrollbar.ts","../src/styles/custom-scrollbar.ts","../src/components/textarea.ts","../src/utils/positioning.ts","../src/styles/tooltip.ts","../src/components/tooltip.ts","../src/utils/scroll-lock.ts","../src/styles/popup.ts","../src/components/popup.ts","../src/styles/modal.ts","../src/components/modal.ts","../src/styles/select-base.ts","../src/styles/select.ts","../src/utils/mobile.ts","../src/components/select.ts","../src/components/selected-tags.ts","../src/styles/tabs.ts","../src/components/tabs.ts","../src/styles/tab.ts","../src/components/tab.ts","../src/styles/wizard.ts","../src/components/wizard.ts","../src/styles/step.ts","../src/components/step.ts","../src/styles/calendar-month.ts","../src/utils/calendar-utils.ts","../src/components/calendar-month.ts","../src/styles/calendar-navigation.ts","../src/components/calendar-navigation.ts","../src/styles/calendar.ts","../src/components/calendar.ts","../src/styles/date-picker.ts","../src/components/date-picker.ts","../src/styles/resize-observer.ts","../src/utils/resize-observer.ts","../src/components/resize-observer.ts","../src/styles/scroll-container.ts","../src/components/scroll-container.ts","../src/cdn.ts"],"sourcesContent":["/**\n * Ty Component Common Types\n */\n\n/**\n * Built-in semantic color flavor names. Append `+` for a stronger shade or `-`\n * for a softer shade — e.g. `primary`, `primary+`, `primary-`. Matches the\n * design system's `ty-bg-primary+` / `ty-text-primary-` class convention.\n */\n/* `secondary` was removed in TC37 — the built-in set is semantic-only.\n * An aesthetic second accent is one flavor-pack away (see CSS_GUIDE →\n * Custom Flavors); markup using flavor=\"secondary\" degrades to neutral. */\nexport const FLAVORS = [\n 'primary',\n 'success',\n 'danger',\n 'warning',\n 'neutral',\n] as const\n\nexport type FlavorBase = (typeof FLAVORS)[number]\n\n/**\n * A flavor with optional shade suffix: `primary | primary+ | primary-`.\n */\nexport type FlavorShaded<F extends string = FlavorBase> = F | `${F}+` | `${F}-`\n\n/**\n * Semantic color flavors used throughout Ty components.\n *\n * Built-in flavors get themed styles. Add `+` / `-` for a stronger / softer\n * shade. Any other string is also accepted — pass a custom flavor name and\n * theme it via `--ty-button-*` (or component-specific) CSS variables on the\n * host. The `(string & {})` keeps editor autocomplete on the literals while\n * leaving the type open.\n */\nexport type Flavor = FlavorShaded | (string & {})\n\n/** Component size variants */\nexport type Size = 'xs' | 'sm' | 'md' | 'lg' | 'xl'\n\n/** Default `size` for every field component — change here, not per component. */\nexport const DEFAULT_SIZE: Size = 'sm'\n\n/** Input types supported by ty-input */\nexport type InputType =\n | 'text'\n | 'password'\n | 'email'\n | 'url'\n | 'tel'\n | 'date'\n | 'time'\n | 'datetime-local'\n | 'number'\n | 'currency'\n | 'percent'\n | 'compact'\n | 'checkbox'\n\n/** Base properties shared by all Ty components */\nexport interface TyBaseElement extends HTMLElement {\n /** Semantic color flavor */\n flavor?: Flavor\n}\n\n/** Button appearance variant */\nexport type ButtonAppearance = 'solid' | 'outlined' | 'ghost'\n\n/** Button component interface */\nexport interface TyButtonElement extends TyBaseElement {\n /** Button size */\n size?: Size\n /** Visual appearance: solid (filled, default), outlined (border only), ghost (text only) */\n appearance?: ButtonAppearance\n /** Disabled state */\n disabled?: boolean\n /** Pill shape (fully rounded) */\n pill?: boolean\n /** Action (icon-only square) */\n action?: boolean\n /** Full-width */\n wide?: boolean\n /** Button type for forms */\n type?: 'button' | 'submit' | 'reset'\n}\n\n/** Icon size variants */\nexport type IconSize =\n | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' // Relative sizes\n | '12' | '14' | '16' | '18' | '20' | '24' | '32' | '48' | '64' | '80' | '96' // Fixed pixel sizes\n\n/** Icon animation tempo */\nexport type IconTempo = 'slow' | 'fast'\n\n/** Icon component interface */\nexport interface TyIconElement extends HTMLElement {\n /** Icon name to display */\n name?: string\n /** Icon size */\n size?: IconSize\n /** Spin animation */\n spin?: boolean\n /** Pulse animation */\n pulse?: boolean\n /** Animation tempo */\n tempo?: IconTempo\n}\n\n/** Tag component custom event detail */\nexport interface TyTagEventDetail {\n /** Target tag element */\n target: HTMLElement\n}\n\n/** Tag component interface */\nexport interface TyTagElement extends TyBaseElement {\n /** Tag value */\n value?: string\n /** Tag size */\n size?: Size\n /** Selected state */\n selected?: boolean\n /** Square corners instead of the default pill */\n noPill?: boolean\n /** Clickable state */\n clickable?: boolean\n /** Dismissible state */\n dismissible?: boolean\n /** Disabled state */\n disabled?: boolean\n}\n\n/** Option component interface - omit 'hidden' from HTMLElement to avoid conflict */\nexport interface TyOptionElement extends Omit<HTMLElement, 'hidden'> {\n /** Option value */\n value?: string\n /** Selected state */\n selected?: boolean\n /** Disabled state */\n disabled?: boolean\n /** Highlighted state (keyboard navigation) */\n highlighted?: boolean\n /** Hidden state - overrides HTMLElement's hidden */\n hidden?: boolean\n}\n\n/** Input component interface */\nexport interface TyInputElement extends TyBaseElement {\n /** Input type */\n type?: InputType\n /** Input value */\n value?: string\n /** Input name (for forms) */\n name?: string\n /** Placeholder text */\n placeholder?: string\n /** Label text */\n label?: string\n /** Disabled state */\n disabled?: boolean\n /** Required field */\n required?: boolean\n /** Error message */\n error?: string\n /** Input size */\n size?: Size\n /** Associated form */\n readonly form?: HTMLFormElement | null\n\n // Numeric formatting properties\n /** Currency code for currency type (e.g., 'USD', 'EUR', 'HRK') */\n currency?: string\n /** Locale for formatting (e.g., 'en-US', 'hr-HR') */\n locale?: string\n /** Number of decimal places */\n precision?: number | string\n\n /** Debounce in milliseconds before firing input/change events (0-5000ms) */\n debounce?: number | string\n}\n\n/** CSS style content */\nexport interface StyleContent {\n /** CSS text content */\n css: string\n /** Optional style ID for caching */\n id?: string\n}\n","/**\n * Property Manager - Unified property lifecycle for web components\n * \n * Handles property/attribute synchronization, validation, coercion, and change tracking.\n * All property updates flow through a single code path for consistency.\n */\n\n/**\n * Configuration for a single property\n */\nexport interface PropertyConfig {\n // Data type for coercion\n type: 'string' | 'boolean' | 'number' | 'object' | 'array'\n \n // Does changing this property require a render?\n visual?: boolean\n \n // Should this sync to form value?\n formValue?: boolean\n \n // Should this emit a change event?\n emitChange?: boolean\n \n // Default value\n default?: any\n \n // Custom validator function\n validate?: (value: any) => boolean\n \n // Custom coercion function\n coerce?: (value: any) => any\n \n // Property aliases: extra attribute names mapped to a fixed value\n aliases?: Record<string, any>\n}\n\n/**\n * Represents a property change\n */\nexport interface PropertyChange {\n name: string\n oldValue: any\n newValue: any\n source: 'attribute' | 'property' | 'internal'\n}\n\n/**\n * Manages component properties with unified lifecycle\n */\n/**\n * Boolean coercion for a property set from JS, HTML-style: '' (what React 19\n * and Vue hand a property for a bare attribute) is true; false, null,\n * undefined, 0, 'false' and '0' are false.\n */\nexport function coerceBoolean(value: unknown): boolean {\n if (typeof value === 'string') {\n const normalized = value.toLowerCase().trim()\n return normalized !== 'false' && normalized !== '0'\n }\n return Boolean(value)\n}\n\n/** A default may be a thunk, evaluated per element (e.g. \"the current month\"). */\nfunction defaultOf(config: PropertyConfig): any {\n return typeof config.default === 'function' ? config.default() : config.default\n}\n\nexport class PropertyManager<T = any> {\n private _props = new Map<string, any>()\n private _config: Record<string, PropertyConfig>\n \n constructor(config: Record<string, PropertyConfig>) {\n this._config = config\n this._initializeDefaults()\n }\n \n /**\n * Initialize properties with default values\n */\n private _initializeDefaults(): void {\n for (const [name, config] of Object.entries(this._config)) {\n if (config.default !== undefined) {\n this._props.set(name, defaultOf(config))\n }\n }\n }\n \n /**\n * Check if a property name exists in the configuration\n */\n hasConfig(name: string): boolean {\n return name in this._config\n }\n\n /**\n * Update a property value\n * Returns PropertyChange if value changed, null otherwise\n */\n updateProperty(\n name: string, \n value: any, \n source: 'attribute' | 'property' | 'internal' = 'property'\n ): PropertyChange | null {\n const config = this._config[name]\n if (!config) {\n console.warn(`[PropertyManager] Unknown property: ${name}`)\n return null\n }\n \n const oldValue = this._props.get(name)\n const coercedValue = this._coerceValue(name, value, config)\n\n if (!this._validateValue(name, coercedValue, config)) {\n console.warn(`[PropertyManager] Invalid value for ${name}:`, coercedValue)\n return null\n }\n\n if (this._valuesEqual(oldValue, coercedValue)) {\n return null\n }\n\n this._props.set(name, coercedValue)\n\n const change: PropertyChange = {\n name,\n oldValue,\n newValue: coercedValue,\n source\n }\n \n return change\n }\n \n /**\n * Coerce value to the correct type\n */\n private _coerceValue(name: string, value: any, config: PropertyConfig): any {\n if (config.coerce) {\n return config.coerce(value)\n }\n\n if (value === null || value === undefined) {\n return defaultOf(config) ?? null\n }\n\n switch (config.type) {\n case 'boolean':\n // HTML Standard: attribute present (even empty) = true, absent = false\n if (typeof value === 'string') {\n // Empty string = true (HTML boolean attribute: <input checked>)\n if (value === '') return true\n // Explicit false values\n const normalized = value.toLowerCase().trim()\n if (normalized === 'false' || normalized === '0') return false\n // Everything else is truthy\n return true\n }\n // Non-string: standard truthy/falsy\n return Boolean(value)\n \n case 'number':\n const num = Number(value)\n return isNaN(num) ? (defaultOf(config) ?? 0) : num\n \n case 'string':\n return String(value)\n \n case 'object':\n case 'array':\n if (typeof value === 'string') {\n try {\n return JSON.parse(value)\n } catch {\n console.warn(`[PropertyManager] Failed to parse ${name}:`, value)\n return defaultOf(config) ?? (config.type === 'array' ? [] : {})\n }\n }\n return value\n \n default:\n return value\n }\n }\n \n /**\n * Validate a property value\n */\n private _validateValue(name: string, value: any, config: PropertyConfig): boolean {\n if (config.validate) {\n return config.validate(value)\n }\n return true\n }\n \n /**\n * Check if two values are equal\n */\n private _valuesEqual(a: any, b: any): boolean {\n if (typeof a !== 'object' || typeof b !== 'object') {\n return a === b\n }\n\n if (a === null || b === null) {\n return a === b\n }\n \n // Deep equality for objects/arrays (simple implementation)\n // For production, consider using a proper deep equality library\n try {\n return JSON.stringify(a) === JSON.stringify(b)\n } catch {\n return false\n }\n }\n \n /**\n * Get a property value\n */\n get(name: string): any {\n return this._props.get(name)\n }\n \n /**\n * Get all properties as an object\n */\n getAll(): Record<string, any> {\n return Object.fromEntries(this._props)\n }\n \n /**\n * Get property configuration\n */\n getConfig(name: string): PropertyConfig | undefined {\n return this._config[name]\n }\n \n /**\n * Check if a property is visual (requires render)\n */\n isVisual(name: string): boolean {\n return this._config[name]?.visual ?? false\n }\n \n /**\n * Check if a property affects form value\n */\n isFormValue(name: string): boolean {\n return this._config[name]?.formValue ?? false\n }\n \n /**\n * Check if a property should emit change events\n */\n shouldEmitChange(name: string): boolean {\n return this._config[name]?.emitChange ?? false\n }\n \n /**\n * Handle property aliases (extra attribute names mapped to a fixed value)\n */\n handleAlias(aliasName: string, value: any): PropertyChange | null {\n for (const [propName, config] of Object.entries(this._config)) {\n if (config.aliases && aliasName in config.aliases) {\n // Removing the alias attribute restores the default — otherwise\n // dropping the alias would leave its value applied and the\n // property could never turn back on from markup (React 19, HTMX\n // swaps, plain removeAttribute).\n if (value === null) return this.updateProperty(propName, defaultOf(config), 'attribute')\n const aliasedValue = config.aliases[aliasName]\n return this.updateProperty(propName, aliasedValue, 'attribute')\n }\n }\n return null\n }\n}","/**\n * Constraint validation for form-associated ty components.\n *\n * Components report their own state (e.g. valueMissing) through set(); users\n * add a custom error through setCustomValidity(). Both are kept separately and\n * merged into ElementInternals, so a component re-validating on the next\n * keystroke doesn't wipe the user's custom error (same as native inputs).\n *\n * reportValidity() uses the component's own `error` display when it has one\n * (ty-input, ty-textarea, ty-radio-group, ty-file-upload) instead of the\n * browser's bubble, and clears that message again once the field is valid.\n * Whenever the browser fires `invalid` on such a field — a submit attempt,\n * form.reportValidity(), or checkValidity() on the field or its form — the\n * message goes into that error line (no bubble), so a plain <form> needs no\n * JS. For a check that shows nothing, read `field.validity.valid` or\n * `form.matches(':invalid')`. A submit (a submitter click, Enter in a\n * single-line field, form.requestSubmit()) and form.reportValidity() also\n * move focus to the first failing field — the first in form order, like a\n * native form, also when a later field shows a bubble. checkValidity() never\n * does. An `error` the author set is never overwritten or removed;\n * form.reset() clears every message the controller wrote.\n */\n\ntype Own = { flags: ValidityStateFlags; message?: string; anchor?: HTMLElement };\n\n/**\n * True while a form reports its validation: for the rest of the task in\n * which the user clicked a submitter or pressed Enter in a field that submits\n * implicitly, and during form.requestSubmit() / form.reportValidity(). Used\n * only to decide whether `invalid` moves focus (ours, or the browser's for a\n * bubble): checkValidity() fires the same event.\n */\nlet submitAttempt = false;\n/** A pointer interaction is under way: a blur now is part of a click elsewhere. */\nlet pointerPressed = false;\nlet touchRelease: ReturnType<typeof setTimeout> | undefined;\n/** Controllers whose blur reveal waits for the click to finish. */\nconst pendingReveals = new Set<ValidityController>();\nlet documentWatched = false;\n\n/** The click is over: show the reveals that waited for it. */\nfunction release(): void {\n clearTimeout(touchRelease);\n pointerPressed = false;\n if (pendingReveals.size === 0) return;\n // The set is read only in the next task, so a form.reset() run by the\n // click (a reset button) can still take its fields out.\n setTimeout(() => {\n const waiting = [...pendingReveals];\n pendingReveals.clear();\n waiting.forEach((c) => c.reveal());\n });\n}\n\nfunction watchDocument(): void {\n if (documentWatched) return;\n documentWatched = true;\n const mark = () => {\n submitAttempt = true;\n setTimeout(() => { submitAttempt = false; });\n };\n document.addEventListener('click', (e) => {\n // composedPath(): by the time it reaches the document, a click in a\n // shadow root (Lit, Stencil) is retargeted to that root's host.\n const control = e.composedPath().find(\n (n): n is HTMLButtonElement | HTMLInputElement => n instanceof HTMLButtonElement || n instanceof HTMLInputElement,\n );\n if (control?.form && (control.type === 'submit' || control.type === 'image')) mark();\n if (pointerPressed) release();\n }, true);\n document.addEventListener('keydown', (e) => {\n // Only a single-line input submits implicitly: not a textarea or\n // contenteditable, nor Enter confirming an IME composition. (ty-input's\n // Enter submits through requestSubmit() or a submitter click.)\n const target = e.composedPath()[0];\n if (e.key === 'Enter' && !e.isComposing && target instanceof HTMLInputElement && target.form) mark();\n }, true);\n // A script-run submit or report focuses the first failing field too.\n const proto = HTMLFormElement.prototype as any;\n for (const name of ['requestSubmit', 'reportValidity']) {\n const original = proto[name];\n if (typeof original !== 'function') continue;\n proto[name] = function (this: HTMLFormElement, ...args: unknown[]) {\n const was = submitAttempt;\n submitAttempt = true;\n try {\n return original.apply(this, args);\n } finally {\n submitAttempt = was;\n }\n };\n }\n\n // Revealing an error line on blur pushes the layout down. If the blur came\n // from pressing a button below the field, the button would move before\n // the click and the click would be lost — so wait until the click (and any\n // submit or reset) has run.\n document.addEventListener('pointerdown', () => {\n clearTimeout(touchRelease);\n pointerPressed = true;\n }, true);\n document.addEventListener('pointerup', (e) => {\n // A mouse clicks in the same task. A touch moves focus (the blur) only at\n // its compatibility mousedown, after pointerup, then clicks: wait for\n // that click (above). A long press or a drag never clicks.\n if (e.pointerType === 'mouse') release();\n else touchRelease = setTimeout(release, 1000);\n }, true);\n document.addEventListener('pointercancel', release, true);\n\n watchRoot(document);\n}\n\n/** Roots (the document, shadow roots) whose `invalid` events are watched. */\nconst watchedRoots = new WeakSet<Node>();\n\n/**\n * A submit attempt fires `invalid` on every failing control, then the\n * browser shows its bubble on the first one that didn't cancel the event and\n * focuses it. A field with an error line cancels its own, so with one first\n * in the form a later checkbox or native input would get the bubble and the\n * focus. Cancel the rest then: the first field focuses itself. `invalid`\n * doesn't leave a shadow root, so a form in one is watched at that root.\n */\nfunction watchRoot(root: Node): void {\n if (watchedRoots.has(root)) return;\n watchedRoots.add(root);\n root.addEventListener('invalid', (e) => {\n if (!submitAttempt) return;\n const target = e.target as HTMLInputElement;\n const first = target.form ? firstInvalid(target.form) : undefined;\n if (first && first !== target && hasErrorLine(first)) e.preventDefault();\n }, true);\n}\n\n/** `node` is a shadow-including descendant of `host` (or `host` itself). */\nfunction within(host: Node, node: Node): boolean {\n for (let n: Node | undefined = node; n; n = (n.getRootNode() as ShadowRoot).host) {\n if (host.contains(n)) return true;\n }\n return false;\n}\n\n/**\n * First control of the form that is currently invalid (tree order). Like the\n * browser picking where to report, it skips one that isn't rendered or is\n * visibility:hidden (e.g. in another ty-wizard step): it couldn't take focus.\n */\nfunction firstInvalid(form: HTMLFormElement): Element | undefined {\n return Array.from(form.elements).find((el) => {\n const c = el as HTMLInputElement & { checkVisibility?: (o?: object) => boolean };\n return c.willValidate && c.validity && !c.validity.valid &&\n c.checkVisibility?.({ visibilityProperty: true, checkVisibilityCSS: true }) !== false;\n });\n}\n\n/** Hosts of a ValidityController. */\nconst hosts = new WeakSet<Element>();\n\n/** A Ty field that shows its message in its own error line (no bubble). */\nfunction hasErrorLine(el: Element): boolean {\n return hosts.has(el) && 'error' in el;\n}\n\nexport class ValidityController {\n private own: Own = { flags: {} };\n private custom = '';\n /** The message this controller last wrote into `error`. */\n private written: string | null = null;\n\n constructor(private host: HTMLElement, private internals: ElementInternals) {\n watchDocument();\n hosts.add(host);\n // Any validation of this field (submit, reportValidity, checkValidity):\n // the message goes into its own error line instead of the browser bubble.\n // On a submit or form.reportValidity() the first failing field also takes\n // focus (the browser only focuses fields whose bubble it shows).\n host.addEventListener('invalid', (e) => {\n if (!hasErrorLine(host)) return;\n watchRoot(host.getRootNode());\n e.preventDefault();\n this.showError();\n if (!submitAttempt) return;\n const form = this.internals.form;\n if (!form || firstInvalid(form) === host) host.focus();\n });\n }\n\n /**\n * Show the current message, if any, in the error display (on blur after an\n * edit). During a pointer interaction it waits until after the click.\n */\n reveal(): void {\n if (pointerPressed) {\n pendingReveals.add(this);\n return;\n }\n if ('error' in this.host && !this.internals.validity.valid) this.showError();\n }\n\n /**\n * `error` still holds what this controller wrote (a reportValidity(), a\n * submit, a blur reveal), so it's ours to update and clear. Once the author\n * sets their own message, it's theirs.\n */\n private get errorFromReport(): boolean {\n return this.written !== null && this.host.getAttribute('error') === this.written;\n }\n\n private writeError(message: string | null): void {\n // Recorded first: the write re-renders the field, which re-validates.\n this.written = message;\n if (message === null) this.host.removeAttribute('error');\n else this.host.setAttribute('error', message);\n }\n\n /** Into `error`, unless the author's own message is there. */\n private showError(): void {\n if (this.host.getAttribute('error') && !this.errorFromReport) return;\n this.writeError(this.internals.validationMessage);\n }\n\n /**\n * form.reset(): drop the message this controller showed and any blur\n * reveal still waiting, so the field looks untouched again. An `error` the\n * author set stays.\n */\n reset(): void {\n pendingReveals.delete(this);\n if (this.errorFromReport) this.writeError(null);\n this.written = null;\n }\n\n /** The component's own validity (replaces the previous one). */\n set(flags: ValidityStateFlags, message?: string, anchor?: HTMLElement): void {\n this.own = { flags, message, anchor };\n this.sync();\n }\n\n setCustom(message: string): void {\n this.custom = message || '';\n this.sync();\n }\n\n report(): boolean {\n const valid = this.internals.checkValidity(); // fires 'invalid' when not\n if (valid) return true;\n if ('error' in this.host) {\n this.showError();\n this.host.focus();\n } else {\n this.internals.reportValidity(); // no error display: browser bubble\n }\n return false;\n }\n\n private sync(): void {\n const { flags, message } = this.own;\n // A re-render may have replaced the anchor since set(); setValidity()\n // throws for one that's no longer inside the host.\n const anchor = this.own.anchor && within(this.host, this.own.anchor) ? this.own.anchor : undefined;\n const invalid = Object.values(flags).some(Boolean);\n if (this.custom) {\n this.internals.setValidity({ ...flags, customError: true }, this.custom, anchor);\n } else if (invalid) {\n this.internals.setValidity(flags, message || 'Invalid value', anchor);\n } else {\n this.internals.setValidity({});\n }\n\n if (!this.errorFromReport) {\n this.written = null;\n return;\n }\n if (this.internals.validity.valid) {\n this.writeError(null);\n } else if (this.host.getAttribute('error') !== this.internals.validationMessage) {\n this.showError();\n }\n }\n}\n\ntype ProbeTag = 'input' | 'textarea' | 'select';\nconst probes: Partial<Record<ProbeTag, HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement>> = {};\n\n/**\n * The browser's own (localized) message for a rule: a detached native control\n * gets the same attributes and value and reports what it would say. `true`\n * sets a boolean attribute; '', false and null leave the attribute off. One\n * probe per tag, never in the document, stripped of every attribute before\n * each use. Works for required and min/max; length rules only report after a\n * user edit, so a probe can't word them (see lengthValidity()).\n */\nexport function nativeMessage(\n tag: ProbeTag,\n attrs: Record<string, string | boolean | null | undefined>,\n value = '',\n): string {\n const probe = (probes[tag] ??= document.createElement(tag));\n for (const name of probe.getAttributeNames()) probe.removeAttribute(name);\n for (const [name, v] of Object.entries(attrs)) {\n if (v === true) probe.setAttribute(name, '');\n else if (v) probe.setAttribute(name, v);\n }\n probe.value = value;\n return probe.validationMessage;\n}\n\n/**\n * nativeMessage() plus the probe's own flags, for rules whose attribute the\n * browser parses (min/max: ' 5 ' or '0x10' is no rule at all), so the flag\n * and its message can't disagree. Read `validity` right away: the probe is\n * reused by the next call.\n */\nexport function nativeValidity(\n tag: ProbeTag,\n attrs: Record<string, string | boolean | null | undefined>,\n value = '',\n): { validity: ValidityState; message: string } {\n const message = nativeMessage(tag, attrs, value);\n return { validity: probes[tag]!.validity, message };\n}\n\n/** Non-negative integer limit from an attribute string, or null when unset/invalid. */\nexport function toLimit(v: unknown): number | null {\n if (v === null || v === undefined || String(v).trim() === '') return null;\n const n = Number(v);\n return Number.isInteger(n) && n >= 0 ? n : null;\n}\n\n/** Replace {name} placeholders; unknown or null ones are left as-is. */\nfunction fillMessage(template: string, vars: Record<string, number | null>): string {\n return template.replace(/\\{(\\w+)\\}/g, (match, key) => vars[key] != null ? String(vars[key]) : match);\n}\n\n/**\n * minlength / maxlength for a text field (ty-input, ty-textarea): the failing\n * flags with their messages. `control` is the inner native control carrying\n * `minlength`; it only flags (and words, localized) a value the user typed,\n * so its message is used then. Otherwise Ty's wording, and the author's\n * too-short / too-long message always wins. Placeholders: {minlength}\n * {maxlength} {length}.\n */\nexport function lengthValidity(\n value: string,\n rules: { minlength: unknown; maxlength: unknown; tooShortMessage: string; tooLongMessage: string },\n control?: HTMLInputElement | HTMLTextAreaElement | null,\n): { tooShort?: string; tooLong?: string } {\n const length = value.length;\n const minLength = toLimit(rules.minlength);\n const maxLength = toLimit(rules.maxlength);\n const vars = { minlength: minLength, maxlength: maxLength, length };\n const result: { tooShort?: string; tooLong?: string } = {};\n if (minLength !== null && length < minLength) {\n result.tooShort = !rules.tooShortMessage && control?.validity.tooShort\n ? control.validationMessage\n : fillMessage(rules.tooShortMessage || 'Use at least {minlength} characters (now {length})', vars);\n }\n if (maxLength !== null && length > maxLength) {\n result.tooLong = fillMessage(rules.tooLongMessage || 'Use at most {maxlength} characters (now {length})', vars);\n }\n return result;\n}\n","const accessorCache = new WeakMap<Function, string[]>()\n\n/** Every settable accessor of the class chain, up to HTMLElement. */\nfunction settableAccessors(ctor: Function): string[] {\n let names = accessorCache.get(ctor)\n if (!names) {\n const set = new Set<string>()\n for (let proto = ctor.prototype; proto && proto !== HTMLElement.prototype; proto = Object.getPrototypeOf(proto)) {\n for (const [name, d] of Object.entries(Object.getOwnPropertyDescriptors(proto))) {\n if (d.set) set.add(name)\n }\n }\n names = [...set]\n accessorCache.set(ctor, names)\n }\n return names\n}\n\n/** Early values liftProperties() took off, waiting for upgradeProperties(). */\nconst lifted = new WeakMap<HTMLElement, [string, unknown][]>()\n\n/** Read and delete the own values that shadow settable accessors. */\nfunction takeOwn(el: HTMLElement): [string, unknown][] {\n const taken: [string, unknown][] = []\n for (const name of settableAccessors(el.constructor)) {\n if (!Object.prototype.hasOwnProperty.call(el, name)) continue\n taken.push([name, (el as any)[name]])\n delete (el as any)[name]\n }\n return taken\n}\n\n/**\n * For a component whose attributeChangedCallback assigns through its own\n * accessors: call it in the constructor. While an element upgrades, the\n * attribute callbacks run before connectedCallback and would overwrite the\n * early values (an own property takes the assignment); taken off here, they\n * reach the setters in upgradeProperties() instead, after the attributes.\n */\nexport function liftProperties(el: HTMLElement): void {\n const taken = takeOwn(el)\n if (taken.length) lifted.set(el, taken)\n}\n\n/**\n * Properties set before the element upgraded (a framework rendering it\n * before its definition loaded, a lazily defined element) are own data\n * properties that shadow the class accessors, so later assignments would\n * never reach a setter. Standard \"upgrade property\" pattern: read the own\n * value, delete it, assign it again through the accessor. Covers every\n * settable accessor on the prototype chain (value, checked, open, error,\n * minLength, …). TyComponent does this itself; a component extending\n * HTMLElement directly calls it at the start of connectedCallback.\n * A value its setter rejects is reported, not thrown: connectedCallback\n * goes on, as it would for an attribute with a bad value.\n */\nexport function upgradeProperties(el: HTMLElement): void {\n const early = [...(lifted.get(el) ?? []), ...takeOwn(el)]\n lifted.delete(el)\n for (const [name, value] of early) {\n if (value === undefined) continue\n try {\n ;(el as any)[name] = value\n } catch (e) {\n reportError(e)\n }\n }\n}\n","/**\n * TyComponent - Base class for all Ty web components\n * \n * Provides unified property/attribute lifecycle management:\n * - Single code path for all property updates\n * - Declarative property configuration\n * - Predictable rendering behavior\n * - Form association support\n * - Property change events via 'prop:change' (separate from user 'change' events)\n */\n\nimport { PropertyManager, PropertyConfig, PropertyChange } from '../utils/property-manager.js'\nimport { ValidityController } from '../utils/validity.js'\nimport { upgradeProperties } from '../utils/upgrade-properties.js'\n\nexport { upgradeProperties }\n\n/**\n * Base class for all Ty components with unified property lifecycle\n */\nexport abstract class TyComponent<T = any> extends HTMLElement {\n static formAssociated = true\n \n // Subclasses must define their property configuration\n protected static properties: Record<string, PropertyConfig> = {}\n \n protected props: PropertyManager<T>\n\n protected _internals: ElementInternals\n\n private _validity: ValidityController\n\n protected _connected = false\n\n protected _rendered = false\n\n /** The user edited the field since it was created or its form reset:\n * blur then shows its validation message (like native :user-invalid). */\n protected _userEdited = false\n\n constructor() {\n super()\n\n const ctor = this.constructor as typeof TyComponent\n this.props = new PropertyManager<T>(ctor.properties)\n\n this._internals = this.attachInternals()\n this._validity = new ValidityController(this, this._internals)\n \n // Setup shadow DOM (subclasses can override by checking if shadowRoot exists)\n if (!this.shadowRoot) {\n this.attachShadow({ mode: 'open' })\n }\n }\n \n /**\n * Define which attributes to observe\n * Auto-generated from property configuration\n * Returns kebab-case attribute names (e.g., 'minHeight' -> 'min-height')\n */\n static get observedAttributes(): string[] {\n const attrs: string[] = []\n for (const [name, config] of Object.entries(this.properties)) {\n attrs.push(name.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase())\n // Include alias names so attributeChangedCallback fires for them\n if (config.aliases) {\n for (const alias of Object.keys(config.aliases)) {\n attrs.push(alias)\n }\n }\n }\n return attrs\n }\n \n /**\n * Unified property setter\n * Use this in your property setters instead of direct field assignment\n */\n protected setProperty(name: string, value: any): void {\n const change = this.props.updateProperty(name, value, 'property')\n \n if (change) {\n this._syncPropertyToAttribute(change)\n this._handlePropertyChanges([change])\n }\n }\n \n /**\n * Unified property getter\n * Use this in your property getters\n */\n protected getProperty(name: string): any {\n return this.props.get(name)\n }\n \n /**\n * Sync property value to HTML attribute\n */\n private _syncPropertyToAttribute(change: PropertyChange): void {\n const { name, newValue } = change\n const config = this.props.getConfig(name)\n \n if (!config) return\n\n const attrName = this._toKebabCase(name)\n\n if (config.type === 'boolean') {\n if (newValue) {\n this.setAttribute(attrName, '')\n } else {\n this.removeAttribute(attrName)\n }\n } else if (newValue === null || newValue === undefined) {\n this.removeAttribute(attrName)\n } else if (typeof newValue === 'object') {\n this.setAttribute(attrName, JSON.stringify(newValue))\n } else {\n this.setAttribute(attrName, String(newValue))\n }\n }\n \n private _toKebabCase(str: string): string {\n return str.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase()\n }\n\n private _toCamelCase(str: string): string {\n return str.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase())\n }\n \n /**\n * Attribute changed callback - unified for all components\n */\n attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void {\n if (oldValue === newValue) return\n\n // Check if this is an alias (e.g., external-search)\n let change = this.props.handleAlias(name, newValue)\n\n if (!change) {\n // Properties may be registered with kebab-case (e.g., 'display-month')\n // or camelCase. Try the attribute name as-is first, then camelCase.\n const camelName = this._toCamelCase(name)\n const propName = this.props.hasConfig(name) ? name : camelName\n change = this.props.updateProperty(propName, newValue, 'attribute')\n }\n \n if (change) {\n this._handlePropertyChanges([change])\n }\n }\n \n /**\n * Connected callback - handle pre-set properties\n */\n connectedCallback(): void {\n // Native defaultValue/defaultChecked semantics: form.reset() restores the\n // ATTRIBUTE-declared state. Property changes reflect back to attributes\n // here (unlike native inputs), so the original attribute must be captured\n // once, at first connect, before any interaction overwrites it.\n if (!this._resetDefaults) {\n this._resetDefaults = new Map()\n const ctor = this.constructor as typeof TyComponent\n for (const [name, config] of Object.entries(ctor.properties)) {\n if (!config.formValue) continue\n const attr = this.getAttribute(this._toKebabCase(name))\n this._resetDefaults.set(name, attr ?? (typeof config.default === 'function' ? config.default() : config.default) ?? null)\n }\n }\n\n // Before _connected: the setters update state, render happens once below\n this._upgradeProperties()\n\n this._connected = true\n\n this.onConnect()\n\n if (!this._rendered) {\n this.render()\n this._rendered = true\n }\n }\n \n /**\n * Disconnected callback\n */\n disconnectedCallback(): void {\n this._connected = false\n this.onDisconnect()\n }\n \n /**\n * upgradeProperties(), plus declared properties without an accessor of\n * their own name (e.g. ty-input's `minlength`): those go straight to\n * setProperty().\n */\n private _upgradeProperties(): void {\n for (const name of Object.keys((this.constructor as typeof TyComponent).properties)) {\n if (!Object.prototype.hasOwnProperty.call(this, name)) continue\n const value = (this as any)[name]\n delete (this as any)[name]\n if (value === undefined) continue\n if (name in this) (this as any)[name] = value\n else this.setProperty(name, value)\n }\n upgradeProperties(this)\n }\n \n /**\n * THE CORE LIFECYCLE METHOD\n * All property changes flow through here\n * \n * Lifecycle order:\n * 1. Update internal state (onPropertiesChanged hook)\n * 2. Sync form value (if formValue property changed)\n * 3. Render (if visual property changed)\n * 4. Emit events (if emitChange property changed)\n */\n private _handlePropertyChanges(changes: PropertyChange[]): void {\n if (changes.length === 0) return\n \n // 1. Update internal state (subclass-specific)\n this.onPropertiesChanged(changes)\n \n // 2. Sync form value if needed\n const formValueChanged = changes.some(c => this.props.isFormValue(c.name))\n if (formValueChanged) {\n this.updateFormValue()\n }\n \n // 3. Render only if visual properties changed AND component is connected\n const visualChanged = changes.some(c => this.props.isVisual(c.name))\n if (visualChanged && this._connected) {\n this.render()\n }\n \n // 4. Emit change events if configured\n this._emitChangeEvents(changes)\n }\n \n /**\n * Emit property change events for properties that require it\n * Uses 'prop:change' event to avoid conflicts with user interaction 'change' events\n */\n private _emitChangeEvents(changes: PropertyChange[]): void {\n for (const change of changes) {\n if (this.props.shouldEmitChange(change.name)) {\n this.dispatchEvent(new CustomEvent('prop:change', {\n detail: {\n property: change.name,\n oldValue: change.oldValue,\n newValue: change.newValue\n },\n bubbles: true,\n composed: true\n }))\n }\n }\n }\n \n /**\n * Update form value via ElementInternals\n * Subclasses can override to customize form value\n */\n protected updateFormValue(): void {\n const formValue = this.getFormValue()\n this._internals.setFormValue(formValue)\n }\n \n /**\n * Get the form value for this component\n * Default: return 'value' property\n * Override for custom behavior\n */\n protected getFormValue(): File | string | FormData | null {\n return this.props.get('value') ?? null\n }\n \n /**\n * Render the component\n * Subclasses MUST implement this\n */\n protected abstract render(): void\n \n /**\n * Hook: Called when properties change\n * Subclasses can override to update internal state\n * \n * This is called BEFORE rendering, so you can update\n * internal state here and it will be reflected in the render\n */\n protected onPropertiesChanged(changes: PropertyChange[]): void {\n }\n \n /**\n * Hook: Called when component is connected\n * Use this instead of overriding connectedCallback\n */\n protected onConnect(): void {\n }\n \n /**\n * Hook: Called when component is disconnected\n * Use this for cleanup instead of overriding disconnectedCallback\n */\n protected onDisconnect(): void {\n }\n \n /**\n * Get the form element this component is associated with\n */\n get form(): HTMLFormElement | null {\n return this._internals.form\n }\n\n // --- Constraint validation (same API as native form controls) -------------\n\n /** Form-associated? Non-FACE internals throw on validity access. */\n private get _validates(): boolean {\n return (this.constructor as typeof TyComponent).formAssociated === true\n }\n\n /** Subclasses report their own validity here, not via _internals directly,\n * so a user's setCustomValidity() survives re-validation. */\n protected applyValidity(flags: ValidityStateFlags, message?: string, anchor?: HTMLElement): void {\n this._validity.set(flags, message, anchor)\n }\n\n /** Show the field's current validation message in its error display, if\n * it's invalid. Called on blur after the user edited the field. */\n protected revealValidity(): void {\n if (this._validates) this._validity.reveal()\n }\n\n get validity(): ValidityState | undefined {\n return this._validates ? this._internals.validity : undefined\n }\n\n get validationMessage(): string {\n return this._validates ? this._internals.validationMessage : ''\n }\n\n get willValidate(): boolean {\n return this._validates ? this._internals.willValidate : false\n }\n\n checkValidity(): boolean {\n return this._validates ? this._internals.checkValidity() : true\n }\n\n /** Like native, but shows the message in the component's `error` display\n * when it has one (and clears it once valid) instead of the browser bubble. */\n reportValidity(): boolean {\n return this._validates ? this._validity.report() : true\n }\n\n setCustomValidity(message: string): void {\n if (this._validates) this._validity.setCustom(message)\n }\n\n /**\n * a11y helper for components whose ARIA role lives on an inner shadow element\n * (checkbox/switch/radio). A wrapping <label> names the form-associated HOST,\n * not the inner role element — so mirror the host's associated label text onto\n * the role element as aria-label, giving it an accessible name.\n */\n protected applyLabelName(roleEl: HTMLElement): void {\n let text = Array.from(this._internals.labels ?? [])\n .map((l) => (l as HTMLElement).textContent?.trim())\n .filter(Boolean)\n .join(' ')\n if (!text) {\n // Non-form-associated controls (e.g. ty-radio) aren't labelable, so the\n // wrapping <label> never appears in internals.labels — read it directly,\n // stripping this element's own subtree from the text.\n const lbl = this.closest('label')\n if (lbl) {\n const clone = lbl.cloneNode(true) as HTMLElement\n clone.querySelectorAll(this.tagName.toLowerCase()).forEach((n) => n.remove())\n text = clone.textContent?.trim() ?? ''\n }\n }\n if (text) roleEl.setAttribute('aria-label', text)\n else roleEl.removeAttribute('aria-label')\n }\n\n private _handlingActivationClick = false\n\n /**\n * Guard for click-driven toggle handlers (checkbox/switch) on components\n * whose whole host is the click target AND that expect a wrapping\n * <label> to delegate to them. Some browsers still forward a label's own\n * synthetic click to the associated control even when the original click\n * already targeted that control directly, firing 'click' twice for one\n * user gesture. Both arrive synchronously in the same task, so a flag\n * cleared on the next microtask catches only the spurious duplicate —\n * two genuinely separate clicks are always in different tasks.\n */\n protected isDuplicateActivationClick(): boolean {\n if (this._handlingActivationClick) return true\n this._handlingActivationClick = true\n queueMicrotask(() => { this._handlingActivationClick = false })\n return false\n }\n\n private _resetDefaults: Map<string, any> | null = null\n\n /**\n * Form reset callback - called when form.reset() is invoked.\n * Restores every formValue-bearing property to its attribute-declared\n * default captured at first connect (native defaultValue/defaultChecked\n * semantics). Non-form state (e.g. a checkbox's submission `value`, a\n * ty-radio's option `value`) is deliberately left alone — the old\n * blanket 'value' reset corrupted radio groups by wiping child values.\n * Like a native control the field also looks untouched again: the\n * validation message it showed is gone (an `error` the author set stays)\n * and a blur shows nothing until the user edits it.\n */\n formResetCallback(): void {\n this._userEdited = false\n if (this._validates) this._validity.reset()\n\n for (const [name, def] of this._resetDefaults ?? []) {\n this.setProperty(name, def)\n }\n\n this.onFormReset()\n }\n \n /**\n * Hook: Called when form is reset\n * Subclasses can override to perform additional reset actions\n */\n protected onFormReset(): void {\n }\n}","/**\n * CSS Utilities for Ty Components\n * Handles dynamic CSS loading into Shadow DOM\n */\n\nimport type { StyleContent } from '../types/common'\n\n/** Cache of loaded CSSStyleSheet objects */\nconst styleCache = new Map<string, CSSStyleSheet>()\n\n/**\n * Ensure CSS is loaded into a shadow root\n * Uses CSSStyleSheet API for efficient style sharing\n * \n * @param shadowRoot - The shadow root to attach styles to\n * @param styleContent - Style content with CSS text and optional ID\n */\nexport function ensureStyles(\n shadowRoot: ShadowRoot, \n styleContent: StyleContent\n): void {\n const { css, id } = styleContent\n \n let sheet: CSSStyleSheet\n\n if (id && styleCache.has(id)) {\n sheet = styleCache.get(id)!\n } else {\n sheet = new CSSStyleSheet()\n sheet.replaceSync(css)\n\n if (id) {\n styleCache.set(id, sheet)\n }\n }\n \n // Append only if not already adopted\n const existing = shadowRoot.adoptedStyleSheets || []\n if (!existing.includes(sheet)) {\n shadowRoot.adoptedStyleSheets = [...existing, sheet]\n }\n}\n\n/**\n * Build CSS class list from properties\n * Filters out falsy values\n * \n * @param classes - Array of class names or falsy values\n * @returns Space-separated class string\n */\nexport function buildClassList(...classes: (string | false | null | undefined)[]): string {\n return classes.filter(Boolean).join(' ')\n}\n\n","/**\n * Button Component Styles\n *\n * Three appearance variants × five semantic flavors × three tones (+/base/-).\n * Each variant uses ONE token system:\n *\n * - solid → flat per-segment tokens --ty-solid-{flavor}{,-hover,-active,\n * -strong,-soft,-fg}. Derived in tyrell-theme.css via OKLCH on\n * 3 axes (color / hover-active / theme chroma-hue); literal in\n * tyrell.css. The component does no color math for the fill.\n * Depth chrome (border + drop shadow) IS computed here, from\n * the fill, via relative color — see the button.solid rule.\n * - outlined → --ty-color-{flavor}-{strong|base|soft} (text === border at\n * rest); hover/active/focus always resolve to -strong,\n * whatever the resting tone was — see outlinedFlavor().\n * - ghost → same as outlined, text only (no border), --ty-bg-{flavor}-soft\n * background on hover.\n *\n * Neutral is the exception in both outlined and ghost: its `+` tone reads\n * --ty-solid-neutral-strong (the ink dial solid buttons use — the only\n * value that actually inverts light↔dark for full contrast) instead of the\n * generic --ty-color-neutral-strong text-emphasis token. Base/soft neutral\n * stay on the generic token like every other flavor.\n *\n * Per-instance overrides via host CSS variables:\n * --ty-button-bg, --ty-button-bg-hover, --ty-button-color, --ty-button-border,\n * --ty-solid-border-color, --ty-solid-border-width\n */\n\nimport { FLAVORS } from '../types/common.js'\n\n/* Each generator takes an optional fallback flavor `fb`: token references\n then become var(--ty-*-f, var(--ty-*-fb)). Built-ins pass no fallback\n (their tokens always exist); buttonCustomFlavorCss() passes 'neutral' so a\n custom flavor with missing tokens degrades to neutral instead of an\n invisible button. */\n\nconst tokenRef = (prefix: string, f: string, suffix: string, fb?: string) =>\n fb\n ? `var(${prefix}-${f}${suffix}, var(${prefix}-${fb}${suffix}))`\n : `var(${prefix}-${f}${suffix})`\n\n/* Nudge a fill by an interaction offset (hover/active), tone-aware: each\n tone's states derive from the TONE's own fill, not the base fill —\n otherwise tone- hover jumps from the soft fill to near-base darkness.\n States deliberately do NOT re-derive the text color: fg is decided by\n the tone's REST fill and stays stable through interaction — the ±0.04/\n 0.08 L nudges keep AA for any rest-passing fill, and re-deriving would\n flicker black↔white whenever a nudge crosses the fg threshold. */\nconst nudged = (fillExpr: string, offsetDial: string) =>\n `oklch(from ${fillExpr} calc(l + var(--ty-${offsetDial})) c h)`\n\n/* Fill-relative nudge: moves TOWARD mid-lightness by the dial's magnitude,\n whatever the fill. Needed for neutral+ — full-contrast ink sits at an L\n extreme in both modes (near-black light / near-white dark), where the\n MODE-directional dials clip into the L ceiling/floor and vanish. */\nconst nudgedMid = (fillExpr: string, offsetDial: string) =>\n `oklch(from ${fillExpr} calc(l + sign(0.5 - l) * abs(var(--ty-${offsetDial}))) c h)`\n\n/* Solid rules assign --_solid-bg (the CURRENT fill — swapped by hover/\n active) and --_solid-rest (the tone's RESTING fill — set only by rest/\n tone rules, never by state rules). The base button.solid rule holds the\n single set of formulas that consume them: background follows --_solid-bg;\n the depth border derives from --_solid-rest so it stays STATIONARY while\n the fill steps up on hover — the fill rises toward the lit edge instead\n of dragging the edge along with it. */\nconst solidFlavor = (f: string, fb?: string) => {\n const solid = (suffix: string) => tokenRef('--ty-solid', f, suffix, fb)\n // Neutral reads its own, stronger border offset (no hue separates ink\n // from the canvas — see --ty-button-border-l-neutral in tyrell.css).\n // Colored flavors must RESET to the plain dial: the bare button.solid\n // rule (which matches every solid button) sets the neutral chain.\n // Muted rest fills EVERY flavor with the neutral swatch (see button.muted\n // below) — the border must follow, or a muted colored button reads as\n // neutral-filled but keeps its (invisible, in dark mode) colored-flavor\n // border dial while neutral alone gets a visible edge. --_muted-border-l\n // is unset on hover/active so the border reverts to the flavor's own dial\n // the moment the real color is revealed.\n const borderL =\n f === 'neutral'\n ? ' --_border-l: var(--ty-button-border-l-neutral, var(--ty-button-border-l, -0.15));'\n : ' --_border-l: var(--_muted-border-l, var(--ty-button-border-l, -0.15));'\n // Neutral+ is full-contrast ink at an L extreme — its hover/active must\n // move toward mid (fill-relative), not in the mode's direction.\n const plusNudge = f === 'neutral' ? nudgedMid : nudged\n return `\nbutton.solid.${f} { --_ring: ${tokenRef('--ty-color', f, '', fb)}; --_solid-bg: var(--ty-button-bg, var(--_muted-solid-bg, ${solid('')})); --_solid-rest: var(--ty-button-bg, var(--_muted-solid-bg, ${solid('')}));${borderL} color: var(--ty-button-color, var(--_muted-solid-fg, ${solid('-fg')})); }\nbutton.solid.${f}.tone-plus { --_solid-bg: var(--ty-button-bg, var(--_muted-solid-bg, ${solid('-strong')})); --_solid-rest: var(--ty-button-bg, var(--_muted-solid-bg, ${solid('-strong')})); color: var(--ty-button-color, var(--_muted-solid-fg, ${solid('-strong-fg')})); }\nbutton.solid.${f}.tone-minus { --_solid-bg: var(--ty-button-bg, var(--_muted-solid-bg, ${solid('-soft')})); --_solid-rest: var(--ty-button-bg, var(--_muted-solid-bg, ${solid('-soft')})); color: var(--ty-button-color, var(--_muted-solid-fg, ${solid('-soft-fg')})); }\nbutton.solid.${f}:hover:not(:disabled) { --_solid-bg: var(--ty-button-bg-hover, ${solid('-hover')}); }\nbutton.solid.${f}:active:not(:disabled) { --_solid-bg: ${solid('-active')}; }\nbutton.solid.${f}.tone-plus:hover:not(:disabled) { --_solid-bg: var(--ty-button-bg-hover, ${plusNudge(solid('-strong'), 'solid-hover-l')}); }\nbutton.solid.${f}.tone-plus:active:not(:disabled) { --_solid-bg: ${plusNudge(solid('-strong'), 'solid-active-l')}; }\nbutton.solid.${f}.tone-minus:hover:not(:disabled) { --_solid-bg: var(--ty-button-bg-hover, ${nudged(solid('-soft'), 'solid-hover-l')}); }\nbutton.solid.${f}.tone-minus:active:not(:disabled) { --_solid-bg: ${nudged(solid('-soft'), 'solid-active-l')}; }\n`\n}\n\nconst outlinedFlavor = (f: string, fb?: string) => {\n const color = (suffix: string) => tokenRef('--ty-color', f, suffix, fb)\n // Neutral+ only: bare text/border need page contrast, which the\n // per-flavor ladder is FOR (it deliberately inverts per mode) — pointing\n // base/soft at the solid ink ramp was a real bug (dark-mode contrast\n // against the canvas measured 1.01/1.20 — invisible; WCAG minimum is\n // 4.5). Strong stays on ink: at 0.93 dark / 0.15 light it's still 16.5:1,\n // and matches solid's \"+\" for the loud-CTA identity that was the ask.\n const textInk = (suffix: string) => (f === 'neutral' && suffix === '-strong' ? `var(--ty-solid-neutral${suffix})` : color(suffix))\n return `\nbutton.outlined.${f} {\n color: var(--ty-button-color, var(--_muted-outlined-line, ${textInk('')}));\n border-color: var(--ty-button-border, var(--_muted-outlined-line, ${textInk('')}));\n}\nbutton.outlined.${f}.tone-plus {\n color: var(--ty-button-color, var(--_muted-outlined-line, ${textInk('-strong')}));\n border-color: var(--ty-button-border, var(--_muted-outlined-line, ${textInk('-strong')}));\n}\nbutton.outlined.${f}.tone-minus {\n color: var(--ty-button-color, var(--_muted-outlined-line, ${textInk('-soft')}));\n border-color: var(--ty-button-border, var(--_muted-outlined-line, ${textInk('-soft')}));\n}\nbutton.outlined.${f}:hover:not(:disabled) {\n background: var(--ty-button-bg-hover, ${tokenRef('--ty-bg', f, '-soft', fb)});\n}\n/* Rest is whatever tone you picked; hover/active/focus always escalates to\n the SAME peak — most-emphasized (\"+\") color, regardless of starting\n tone. tone-plus is already there at rest, so this is a no-op for it.\n :hover only, :not(.muted) — muted's hover-reveal is a DIFFERENT contract\n (reveal the plain button's RESTING color, tested directly against it);\n this rule would outrank that fallback and show strong instead.\n :active/:focus-visible apply to muted too (no exclusion) — muted's own\n reveal-on-press mechanism has much lower specificity than this rule, so\n it simply wins outright, landing muted and plain on the same escalated\n color when both are pressed — which is what muted's OWN test expects. */\nbutton.outlined.${f}:not(.muted):hover:not(:disabled),\nbutton.outlined.${f}:active:not(:disabled),\nbutton.outlined.${f}:focus-visible {\n color: var(--ty-button-color, ${textInk('-strong')});\n border-color: var(--ty-button-border, ${textInk('-strong')});\n}\n`\n}\n\nconst ghostFlavor = (f: string, fb?: string) => {\n const color = (suffix: string) => tokenRef('--ty-color', f, suffix, fb)\n // Neutral+ only: bare text needs page contrast — same reasoning and same\n // measured bug as outlinedFlavor above (base/soft on the solid ink ramp\n // read 1.01/1.20 against the dark canvas; WCAG minimum is 4.5). Strong\n // stays on ink: still 16.5:1, and matches solid's \"+\" loud-CTA identity.\n const ink = (suffix: string) => (f === 'neutral' && suffix === '-strong' ? `var(--ty-solid-neutral${suffix})` : color(suffix))\n return `\nbutton.ghost.${f} { color: var(--ty-button-color, var(--_muted-ghost-fg, ${ink('')})); }\nbutton.ghost.${f}.tone-plus { color: var(--ty-button-color, var(--_muted-ghost-fg, ${ink('-strong')})); }\nbutton.ghost.${f}.tone-minus { color: var(--ty-button-color, var(--_muted-ghost-fg, ${ink('-soft')})); }\nbutton.ghost.${f}:hover:not(:disabled) {\n background: var(--ty-button-bg-hover, ${tokenRef('--ty-bg', f, '-soft', fb)});\n}\n/* See outlinedFlavor above — same escalation-to-peak, same :hover-only\n :not(.muted) split, text only. */\nbutton.ghost.${f}:not(.muted):hover:not(:disabled),\nbutton.ghost.${f}:active:not(:disabled),\nbutton.ghost.${f}:focus-visible {\n color: var(--ty-button-color, ${ink('-strong')});\n}\n`\n}\n\n/** Rules for one custom (non-built-in) flavor across all three appearances. */\nexport const buttonCustomFlavorCss = (base: string) =>\n solidFlavor(base, 'neutral') + outlinedFlavor(base, 'neutral') + ghostFlavor(base, 'neutral')\n\nexport const buttonStyles = `\n/* One-cell grid. Unconstrained, the host hugs the button exactly; a box\n imposed on it (flex-column or grid-cell stretch, width/height/min-height\n from outside) grows the cell and the button fills it — the whole host is\n the click target, no dead strip that looks clickable and isn't.\n height: fit-content opts out of a flex/grid ROW's default stretch, which\n would turn the button into a slab as tall as its tallest sibling; an\n explicit height still wins (outer-tree declarations beat :host). Column\n floor is min-content, not auto: auto floors at the button's min-width\n (4rem), and a squeezed flex row would crush a long label. Row floor is\n the rung, so a ::part(button) { height: 100% } can't shrink the button to\n its text. Both maxes are 1fr, not auto: a consumer justify-content /\n align-content (Tailwind justify-center) stops an auto track from\n stretching, fr ignores it. */\n:host {\n --_rung: var(--ty-button-height);\n display: inline-grid;\n grid-template: minmax(var(--_rung), 1fr) / minmax(min-content, 1fr);\n height: fit-content;\n font-family: inherit;\n}\n\n:host([action]) {\n --_rung: var(--ty-button-action-size);\n}\n\n/* Action is a square — stretching it would distort it. A flex column or\n grid cell doesn't widen it; a height (or width) alone makes a bigger\n square. Unless asked: wide still means full width. */\n:host([action]:not([wide])) {\n width: fit-content;\n aspect-ratio: 1;\n}\n\n/* flex-grow fills a flex ROW. In a flex column it grows the height, so the\n row track stops at the button's own height: full width, not a slab. The\n cost: a height set on a wide host isn't filled either; size it with\n size / --ty-button-height. The button's own flex-grow covers a consumer\n display: flex on the host. */\n:host([wide]) {\n display: grid;\n flex-grow: 1;\n grid-template-rows: minmax(var(--_rung), max-content);\n}\n\n:host([wide]) button {\n flex-grow: 1;\n}\n\n/* Button size ladder — one source of truth, same shape as the field ladder\n (see field-size.ts). Per-rung values live on the HOST, not on the inner\n button's size class: a normal declaration in the outer tree beats :host\n (encapsulation context is sorted before specificity), so a consumer can\n write \"ty-button { --ty-button-height: 44px }\" and have it win. Declared on\n the inner button they would be unreachable — a declaration on the element\n always beats an inherited one.\n\n Base block = the DEFAULT_SIZE rung (sm), because a component left at its\n default never gets a \"size\" attribute to match on (setProperty reflects,\n defaults don't). :host([size]) rules override it.\n\n Buttons run a 4px ladder (24-40px). Shared scale with fields\n (--ty-size-sm/md/lg — see tyrell.css): field sm = button md (32px),\n field md = button lg (36px), field lg = button xl (40px) — a button\n and a field of the paired size sit flush, same height, in a row. */\n:host {\n --ty-button-height: 1.75rem; /* 28px */\n --ty-button-min-width: 4rem;\n --ty-button-pad-x: var(--ty-spacing-2);\n --ty-button-pad-y: 0px;\n --ty-button-font: var(--ty-font-xs);\n --ty-button-leading: var(--ty-leading-xs);\n --ty-button-tracking: var(--ty-tracking-xs);\n --ty-button-gap: var(--ty-spacing-1);\n /* Action = icon-only square: one dial for the box, one for the icon. */\n --ty-button-action-size: 1.5rem;\n --ty-button-action-icon: 0.875rem;\n}\n\n:host([size=\"xs\"]) {\n --ty-button-height: 1.5rem; /* 24px */\n --ty-button-pad-x: var(--ty-spacing-2);\n --ty-button-pad-y: 0px;\n --ty-button-font: var(--ty-font-xs);\n --ty-button-leading: var(--ty-leading-xs);\n --ty-button-tracking: var(--ty-tracking-xs);\n --ty-button-gap: var(--ty-spacing-1);\n --ty-button-action-size: 1.375rem;\n --ty-button-action-icon: 0.75rem;\n}\n\n:host([size=\"md\"]) {\n --ty-button-height: 2rem; /* 32px — matches field sm */\n --ty-button-pad-x: var(--ty-spacing-3);\n --ty-button-pad-y: 0.375rem;\n --ty-button-font: var(--ty-font-sm);\n --ty-button-leading: var(--ty-leading-sm);\n --ty-button-tracking: var(--ty-tracking-sm);\n --ty-button-gap: var(--ty-spacing-2);\n --ty-button-action-size: 2rem;\n --ty-button-action-icon: 1rem;\n}\n\n:host([size=\"lg\"]) {\n --ty-button-height: 2.25rem; /* 36px — matches field md */\n --ty-button-pad-x: var(--ty-spacing-4);\n --ty-button-pad-y: 0.375rem;\n --ty-button-font: var(--ty-font-sm);\n --ty-button-leading: var(--ty-leading-sm);\n --ty-button-tracking: var(--ty-tracking-sm);\n --ty-button-gap: var(--ty-spacing-2);\n --ty-button-action-size: 2.25rem;\n --ty-button-action-icon: 1.125rem;\n}\n\n:host([size=\"xl\"]) {\n --ty-button-height: 2.5rem; /* 40px — matches field lg */\n --ty-button-pad-x: var(--ty-spacing-6);\n --ty-button-pad-y: var(--ty-spacing-2);\n --ty-button-font: var(--ty-font-base);\n --ty-button-leading: var(--ty-leading-base);\n --ty-button-tracking: var(--ty-tracking-base);\n --ty-button-gap: var(--ty-spacing-2);\n --ty-button-action-size: 2.5rem;\n --ty-button-action-icon: 1.25rem;\n}\n\nbutton {\n /* Native form controls do NOT inherit font from the shadow host — the UA\n stylesheet sets one on them, which beats inheritance. Must be explicit\n here or the button silently falls back to the system font. */\n font-family: inherit;\n position: relative;\n display: flex;\n align-items: center;\n justify-content: center;\n gap: var(--ty-button-gap);\n height: var(--ty-button-height);\n /* Fill a host made taller than the rung (see :host above). Cyclic while\n the grid sizes its track, so it never inflates an unconstrained host. */\n min-height: 100%;\n padding: var(--ty-button-pad-y) var(--ty-button-pad-x);\n font-size: var(--ty-button-font);\n line-height: var(--ty-button-leading);\n letter-spacing: var(--ty-button-tracking);\n /* Mode-flipped weight dial (tyrell.css): medium in light, normal in dark —\n light-on-dark text blooms, a fixed semibold read heavy there. Override\n with --ty-weight-action at any scope. */\n font-weight: var(--ty-weight-action, var(--ty-font-medium));\n white-space: nowrap;\n cursor: pointer;\n user-select: none;\n transition: var(--ty-local-transition, background-color 0.2s ease, color 0.2s ease, border-color 0.2s ease, box-shadow 0.2s ease);\n background: transparent;\n color: var(--ty-color-neutral);\n border: 1px solid transparent;\n}\n\nbutton:not(.action) {\n min-width: var(--ty-button-min-width);\n}\n\nbutton:not(.pill) {\n border-radius: var(--ty-radius-md);\n}\n\nbutton.xs:not(.pill) { border-radius: var(--ty-button-radius-xs, var(--ty-radius-md)); }\nbutton.sm:not(.pill) { border-radius: var(--ty-button-radius-sm, var(--ty-radius-md)); }\nbutton.md:not(.pill) { border-radius: var(--ty-button-radius-md, var(--ty-radius-md)); }\nbutton.lg:not(.pill) { border-radius: var(--ty-button-radius-lg, var(--ty-radius-md)); }\nbutton.xl:not(.pill) { border-radius: var(--ty-button-radius-xl, var(--ty-radius-md)); }\n\nbutton:focus-visible {\n outline: none;\n}\n\nbutton:disabled {\n cursor: not-allowed;\n opacity: 0.6;\n}\n\n/* Spinner overlays the button center; original content kept in flow but\n hidden via visibility so width/height are preserved (no layout shift). */\n.loader-icon {\n display: none;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n width: 1em;\n height: 1em;\n color: currentColor;\n}\n.loader-icon svg {\n width: 100%;\n height: 100%;\n}\nbutton.loading {\n cursor: wait;\n}\nbutton.loading > *:not(.loader-icon) {\n visibility: hidden;\n}\nbutton.loading > .loader-icon {\n display: inline-flex;\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n animation: ty-button-spin 0.7s linear infinite;\n}\n@keyframes ty-button-spin {\n to { transform: translate(-50%, -50%) rotate(360deg); }\n}\n@media (prefers-reduced-motion: reduce) {\n button.loading > .loader-icon {\n animation-duration: 1.6s;\n }\n}\n\n::slotted(*) {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n}\n\n::slotted(ty-icon) {\n flex-shrink: 0;\n}\n\n/* Action = icon-only square. Its size is a floor, not a fixed box: the\n grid stretches it over a host given a size (the host never stretches it —\n see :host), and a ::part(button) min-width / min-height raises the floor\n without losing that. An icon never outgrows the square, so auto height\n is safe here; a text button keeps its fixed height, because its padding\n plus line-height can exceed the rung. */\nbutton.action {\n gap: 0px !important;\n height: auto;\n min-width: var(--ty-button-action-size);\n min-height: var(--ty-button-action-size);\n padding: 0px !important;\n}\n\nbutton.action ::slotted(ty-icon) {\n height: var(--ty-button-action-icon);\n width: var(--ty-button-action-icon);\n}\n\n/* MUTED: show the neutral tokens at rest instead of the flavor color; reveal the\n real flavor on interaction. Implemented as a fallback tier the flavor\n rules above already read (--_muted-*), which sits behind the public\n --ty-button-{bg,color,border} override slots and ahead of the flavor's\n own token — so a custom brand color still wins, muted or not. Unsetting\n --_muted-* on interaction falls the var() chain through to whatever's\n next (the user's override, or the real flavor color).\n Hover reveal is gated to real pointers (touch has no hover); :active /\n :focus-visible cover the tap case so touch still gets the color on press. */\n\n/* --_muted-solid-* reads the SOLID neutral ink tokens — a fill's L doesn't\n need page contrast. --_muted-outlined-line / --_muted-ghost-fg are bare\n text/border and DO — they stay on the regular text ladder (it already\n inverts correctly per mode), except tone-plus, which is legible AND\n loud on the ink dial (16.5:1 dark, matches solid's \"+\" identity). Base/\n soft on ink measured 1.01/1.20 dark contrast against the canvas —\n invisible; WCAG minimum is 4.5. */\nbutton.muted {\n --_muted-solid-bg: var(--ty-solid-neutral);\n --_muted-solid-fg: var(--ty-solid-neutral-fg);\n --_muted-outlined-line: var(--ty-color-neutral);\n --_muted-ghost-fg: var(--ty-color-neutral);\n --_muted-border-l: var(--ty-button-border-l-neutral, var(--ty-button-border-l, -0.15));\n}\nbutton.muted.tone-plus {\n --_muted-solid-bg: var(--ty-solid-neutral-strong);\n /* fg must track the tone's fill: neutral+ is inverted ink in dark mode\n (white fill), so inheriting base neutral's white fg would be\n white-on-white. */\n --_muted-solid-fg: var(--ty-solid-neutral-strong-fg);\n --_muted-outlined-line: var(--ty-solid-neutral-strong);\n --_muted-ghost-fg: var(--ty-solid-neutral-strong);\n}\nbutton.muted.tone-minus {\n --_muted-solid-bg: var(--ty-solid-neutral-soft);\n --_muted-solid-fg: var(--ty-solid-neutral-soft-fg);\n --_muted-outlined-line: var(--ty-color-neutral-soft);\n --_muted-ghost-fg: var(--ty-color-neutral-soft);\n}\n@media (hover: hover) and (pointer: fine) {\n button.muted:hover:not(:disabled) {\n --_muted-solid-bg: unset;\n --_muted-solid-fg: unset;\n --_muted-outlined-line: unset;\n --_muted-ghost-fg: unset;\n --_muted-border-l: unset;\n }\n}\nbutton.muted:active:not(:disabled),\nbutton.muted:focus-visible:not(:disabled) {\n --_muted-solid-bg: unset;\n --_muted-solid-fg: unset;\n --_muted-outlined-line: unset;\n --_muted-ghost-fg: unset;\n --_muted-border-l: unset;\n}\n\nbutton.pill {\n border-radius: 9999px;\n padding-left: 1.25em;\n padding-right: 1.25em;\n}\n\nbutton.pill.xs { padding-left: 1em; padding-right: 1em; }\nbutton.pill.sm { padding-left: 1.125em; padding-right: 1.125em; }\nbutton.pill.lg { padding-left: 1.5em; padding-right: 1.5em; }\nbutton.pill.xl { padding-left: 1.75em; padding-right: 1.75em; }\n\n/* An icon-only round button is \"action pill\": action's square (padding 0,\n !important) with pill's radius. The shadow <button> can't see what is\n slotted into it, so no :has() here could detect an icon-only pill. */\n\n/* SOLID — flat: one variable per segment. No color math here; all the\n --ty-solid-{flavor}-{hover,active,strong,soft} tokens are DERIVED in\n tyrell-theme.css (OKLCH) or set literally in tyrell.css. Override any\n single token to recolor that one segment. Bare .solid = custom-flavor\n fallback, themable via --ty-button-{bg,bg-hover,color}. */\n\nbutton.solid {\n --_ring: var(--ty-color-neutral);\n --_solid-bg: var(--ty-button-bg, var(--ty-solid-neutral));\n --_solid-rest: var(--ty-button-bg, var(--ty-solid-neutral));\n /* Bare .solid is the flavorless default = neutral ink, so it takes the\n neutral border offset; colored flavor rules reset this to the plain\n dial. */\n --_border-l: var(--ty-button-border-l-neutral, var(--ty-button-border-l, -0.15));\n background: var(--_solid-bg);\n color: var(--ty-button-color, var(--ty-solid-neutral-fg));\n /* Depth chrome — border + drop shadow, both scaled by --ty-button-depth.\n (A top-edge sheen — inset 0 1px 0 <lightened fill> — used to live here\n too; dropped, it read as a dizzying bright line rather than a subtle\n highlight.) depth 0 = border matches fill exactly and the shadow goes\n transparent — pixel-flat, but the 1px border stays in the layout so\n toggling depth never shifts geometry (and solid now shares the same\n box as outlined/ghost, which always had a 1px border).\n --ty-button-border-l flips sign with the mode (tyrell.css): dark mode\n runs a LIGHTER-than-fill hairline (fills read washed-out against dark\n surfaces without a lit edge), light mode a slightly darker one.\n Direct escape hatches outrank the derivation: --ty-solid-border-color\n pins the border to ANY color (the L-offset dials stop mattering), and\n --ty-solid-border-width changes thickness (widths ≠ 1px do shift\n geometry — that's inherent).\n Browsers without relative color drop these declarations: border falls\n back to the base button's 1px transparent, shadows to none. */\n border: var(--ty-solid-border-width, 1px) solid\n var(--ty-solid-border-color,\n oklch(from var(--_solid-rest, var(--_solid-bg)) calc(l + var(--_border-l, -0.15) * var(--ty-button-depth, 0.35)) c h));\n box-shadow: 0 1px 2px oklch(0 0 0 / calc(0.4 * var(--ty-button-depth, 0.35)));\n}\nbutton.solid.tone-plus { --_solid-bg: var(--ty-button-bg, var(--ty-solid-neutral-strong)); --_solid-rest: var(--ty-button-bg, var(--ty-solid-neutral-strong)); color: var(--ty-button-color, var(--ty-solid-neutral-strong-fg)); }\nbutton.solid.tone-minus { --_solid-bg: var(--ty-button-bg, var(--ty-solid-neutral-soft)); --_solid-rest: var(--ty-button-bg, var(--ty-solid-neutral-soft)); color: var(--ty-button-color, var(--ty-solid-neutral-soft-fg)); }\nbutton.solid:hover:not(:disabled) { --_solid-bg: var(--ty-button-bg-hover, var(--ty-solid-neutral-hover)); }\nbutton.solid:active:not(:disabled) { --_solid-bg: var(--ty-solid-neutral-active); }\nbutton.solid.tone-plus:hover:not(:disabled) {\n --_solid-bg: var(--ty-button-bg-hover, oklch(from var(--ty-solid-neutral-strong) calc(l + sign(0.5 - l) * abs(var(--ty-solid-hover-l))) c h));\n}\nbutton.solid.tone-plus:active:not(:disabled) {\n --_solid-bg: oklch(from var(--ty-solid-neutral-strong) calc(l + sign(0.5 - l) * abs(var(--ty-solid-active-l))) c h);\n}\nbutton.solid.tone-minus:hover:not(:disabled) {\n --_solid-bg: var(--ty-button-bg-hover, oklch(from var(--ty-solid-neutral-soft) calc(l + var(--ty-solid-hover-l)) c h));\n}\nbutton.solid.tone-minus:active:not(:disabled) {\n --_solid-bg: oklch(from var(--ty-solid-neutral-soft) calc(l + var(--ty-solid-active-l)) c h);\n}\n\n${FLAVORS.map((f) => solidFlavor(f)).join('')}\nbutton.solid:focus-visible {\n box-shadow: 0 0 0 2px var(--ty-focus-ring-gap), 0 0 0 4px var(--_ring);\n}\n\n/* OUTLINED — transparent bg, text === border (uses --ty-color-*).\n Bare .outlined rule = fallback for custom flavors. Text is bound to\n border color, so the fallback chain prefers --ty-button-border, then\n --ty-button-color. */\n\nbutton.outlined {\n background: transparent;\n color: var(--ty-button-border, var(--ty-button-color, var(--ty-color-neutral)));\n border-color: var(--ty-button-border, var(--ty-button-color, var(--ty-color-neutral)));\n}\nbutton.outlined:hover:not(:disabled) {\n background: var(--ty-button-bg-hover, var(--ty-bg-neutral-soft));\n}\n\n${FLAVORS.map((f) => outlinedFlavor(f)).join('')}\n\n/* GHOST — text only, hover bg (uses --ty-color-* + --ty-bg-*-soft).\n Bare .ghost rule = fallback for custom flavors. */\n\nbutton.ghost {\n background: transparent;\n border: none;\n color: var(--ty-button-color, var(--ty-color-neutral));\n}\nbutton.ghost:hover:not(:disabled) {\n background: var(--ty-button-bg-hover, var(--ty-bg-neutral-soft));\n}\n\n${FLAVORS.map((f) => ghostFlavor(f)).join('')}`;\n","/**\n * Custom (non-built-in) flavor support.\n *\n * Built-in flavors get static per-flavor CSS in each component's stylesheet.\n * Any other flavor string is a custom flavor: the component generates the\n * same wiring at runtime, pointed at the user's design tokens\n * (--ty-color-X / --ty-bg-X / --ty-solid-X / ...), and adopts it as a\n * constructed stylesheet.\n *\n * Why an adopted sheet: render() implementations replace shadowRoot.innerHTML\n * (which would destroy an injected <style> element), and inline style on the\n * host would defeat page-level overrides. Adopted sheets survive renders, and\n * outer-document rules on the host still take precedence over :host rules —\n * so `ty-tag[flavor=\"X\"] { --tag-bg: ... }` escape hatches keep working.\n */\n\nimport { FLAVORS } from '../types/common.js'\n\nexport interface CustomFlavorParts {\n /** Full flavor string as given, e.g. \"brand+\" */\n flavor: string\n /** Flavor with any +/- shade suffix stripped, e.g. \"brand\" */\n base: string\n /** \"\" | \"+\" | \"-\" */\n shade: string\n}\n\n/**\n * Keep a shadow root's custom-flavor sheet in sync with the current flavor.\n *\n * Built-in flavors (and anything that isn't a plain identifier, so attribute\n * values can't inject CSS) remove the sheet. Custom flavors get `css(parts)`\n * adopted into the shadow root. Returns the sheet to store for the next call.\n */\nexport function syncCustomFlavorSheet(\n shadow: ShadowRoot,\n sheet: CSSStyleSheet | null,\n flavor: unknown,\n css: (parts: CustomFlavorParts) => string,\n): CSSStyleSheet | null {\n const full = String(flavor || '')\n const base = full.replace(/[+-]$/, '')\n if ((FLAVORS as readonly string[]).includes(base) || !/^[A-Za-z][A-Za-z0-9_-]*$/.test(base)) {\n if (sheet) {\n shadow.adoptedStyleSheets = shadow.adoptedStyleSheets.filter((s) => s !== sheet)\n }\n return null\n }\n if (!sheet) {\n sheet = new CSSStyleSheet()\n shadow.adoptedStyleSheets = [...shadow.adoptedStyleSheets, sheet]\n }\n sheet.replaceSync(css({ flavor: full, base, shade: full.slice(base.length) }))\n return sheet\n}\n","/**\n * Global loader-icon registry.\n *\n * Set once at app bootstrap to override the default spinner SVG used by\n * every loading-aware component (`ty-button`, `ty-select`, etc.). Components\n * call `getLoaderSvg()` on every render, so changing the\n * registered SVG affects future renders.\n *\n * The wrapper element rotates the SVG with `transform: rotate()`, so prefer\n * a *static* SVG. If you must use a self-animating SVG, disable the wrapper\n * spin with the `--ty-loader-animation: none` CSS custom property.\n *\n * @example\n * import { setLoaderSvg } from 'tyrell-components'\n * setLoaderSvg('<svg viewBox=\"0 0 24 24\">...</svg>')\n *\n * // CDN / vanilla\n * window.tyLoader.set('<svg ...>...</svg>')\n *\n * // Reset to default\n * setLoaderSvg(null)\n */\n\nconst DEFAULT_LOADER_SVG = `<svg viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\"><circle cx=\"12\" cy=\"12\" r=\"10\" stroke=\"currentColor\" stroke-width=\"3\" stroke-opacity=\"0.25\"/><path d=\"M22 12a10 10 0 0 1-10 10\" stroke=\"currentColor\" stroke-width=\"3\" stroke-linecap=\"round\"/></svg>`\n\nlet customLoaderSvg: string | null = null\n\n/**\n * Register a custom spinner SVG (markup string). Pass `null` to reset to\n * the built-in default.\n */\nexport function setLoaderSvg(svg: string | null): void {\n customLoaderSvg = svg && svg.trim() ? svg : null\n}\n\n/**\n * Get the currently registered spinner SVG, or the built-in default if\n * none has been set. Components call this on every render.\n */\nexport function getLoaderSvg(): string {\n return customLoaderSvg ?? DEFAULT_LOADER_SVG\n}\n\n/** Reset the registered loader back to the built-in default. */\nexport function resetLoaderSvg(): void {\n customLoaderSvg = null\n}\n","/**\n * TyButton Web Component — three appearances (solid/outlined/ghost) × six\n * flavors × three tones. Append `+`/`-` to a flavor for stronger/softer tone.\n */\n\nimport type { Flavor, Size, TyButtonElement } from \"../types/common.js\";\nimport { DEFAULT_SIZE } from \"../types/common.js\";\nimport { TyComponent } from \"../base/ty-component.js\";\nimport type { PropertyChange } from \"../utils/property-manager.js\";\nimport { ensureStyles, buildClassList } from \"../utils/styles.js\";\nimport { buttonStyles, buttonCustomFlavorCss } from \"../styles/button.js\";\nimport { syncCustomFlavorSheet } from \"../utils/flavor-sheet.js\";\nimport { getLoaderSvg } from \"../utils/loader-registry.js\";\n\ntype Appearance = \"solid\" | \"outlined\" | \"ghost\";\n\ninterface ButtonState {\n flavor: Flavor;\n size: Size;\n appearance: Appearance;\n disabled: boolean;\n loading: boolean;\n type: \"button\" | \"submit\" | \"reset\";\n pill: boolean;\n action: boolean;\n wide: boolean;\n name: string;\n value: string;\n}\n\n/**\n * Ty Button Component\n */\nexport class TyButton\n extends TyComponent<ButtonState>\n implements TyButtonElement\n{\n static formAssociated = true;\n\n protected static properties = {\n flavor: {\n type: \"string\" as const,\n visual: true,\n default: \"neutral\",\n },\n size: {\n type: \"string\" as const,\n visual: true,\n default: DEFAULT_SIZE,\n validate: (v: any) => [\"xs\", \"sm\", \"md\", \"lg\", \"xl\"].includes(v),\n coerce: (v: any) => {\n if (![\"xs\", \"sm\", \"md\", \"lg\", \"xl\"].includes(v)) {\n console.warn(`[ty-button] Invalid size '${v}'. Using '${DEFAULT_SIZE}'.`);\n return DEFAULT_SIZE;\n }\n return v;\n },\n },\n appearance: {\n type: \"string\" as const,\n visual: true,\n default: \"solid\",\n validate: (v: any) => [\"solid\", \"outlined\", \"ghost\"].includes(v),\n coerce: (v: any) => {\n if (![\"solid\", \"outlined\", \"ghost\"].includes(v)) {\n console.warn(`[ty-button] Invalid appearance '${v}'. Using 'solid'.`);\n return \"solid\";\n }\n return v;\n },\n },\n disabled: {\n type: \"boolean\" as const,\n visual: true,\n default: false,\n },\n loading: {\n type: \"boolean\" as const,\n visual: true,\n default: false,\n },\n type: {\n type: \"string\" as const,\n visual: false,\n default: \"submit\",\n },\n pill: {\n type: \"boolean\" as const,\n visual: true,\n default: false,\n },\n action: {\n type: \"boolean\" as const,\n visual: true,\n default: false,\n },\n muted: {\n type: \"boolean\" as const,\n visual: true,\n default: false,\n },\n wide: {\n type: \"boolean\" as const,\n visual: false,\n default: false,\n },\n name: {\n type: \"string\" as const,\n default: \"\",\n },\n value: {\n type: \"string\" as const,\n default: \"\",\n },\n };\n\n private _structureInitialized = false;\n\n // Disabled by an ancestor <fieldset disabled> (or its own attribute), as\n // reported by formDisabledCallback. Kept apart from the `disabled`\n // property, like native: re-enabling the fieldset restores the button.\n private _formDisabled = false;\n\n // Adopted sheet with generated rules for a custom (non-built-in) flavor\n private _customFlavorSheet: CSSStyleSheet | null = null;\n\n // The click event this button dispatched last (see initializeButtonStructure)\n private _ownClick: Event | null = null;\n\n constructor() {\n super();\n ensureStyles(this.shadowRoot!, { css: buttonStyles, id: \"ty-button\" });\n\n // Some clicks land on the host and never pass the inner <button>:\n // host.click(), a wrapping <label>, a press on host padding or border,\n // fireEvent/userEvent on the host. Swallow them and press the inner\n // button instead, so they get the same guard, the same single click\n // event and the same submit/reset as a press on the button itself.\n // Capture, so this runs before any bubbling listener on the host.\n this.addEventListener(\n \"click\",\n (e: Event) => {\n const button = this.shadowRoot!.querySelector(\"button\");\n if (!button || e === this._ownClick) return;\n // On its way to the inner button, which handles it\n if (e.composedPath().includes(button)) return;\n e.stopImmediatePropagation();\n button.click();\n },\n true,\n );\n }\n\n protected onConnect(): void {\n this._syncCustomFlavor();\n }\n protected onDisconnect(): void {}\n protected onPropertiesChanged(changes: PropertyChange[]): void {\n if (changes.some((c) => c.name === \"flavor\")) {\n this._syncCustomFlavor();\n }\n }\n\n formDisabledCallback(disabled: boolean): void {\n this._formDisabled = disabled;\n if (this._structureInitialized) this.render();\n }\n\n private get _isDisabled(): boolean {\n return this.disabled || this._formDisabled;\n }\n\n /**\n * Custom flavors: adopt generated per-flavor rules pointed at the user's\n * design tokens (--ty-solid-X / --ty-color-X / --ty-bg-X), falling back to\n * neutral for any token the user didn't define. Tone (+/-) is handled by\n * the tone-plus/tone-minus classes, so only the base flavor matters here.\n */\n private _syncCustomFlavor(): void {\n const { base } = this.parseFlavor();\n this._customFlavorSheet = syncCustomFlavorSheet(\n this.shadowRoot!,\n this._customFlavorSheet,\n base,\n () => buttonCustomFlavorCss(base),\n );\n }\n\n get flavor(): Flavor {\n return this.getProperty(\"flavor\") as Flavor;\n }\n set flavor(value: Flavor) {\n this.setProperty(\"flavor\", value);\n }\n\n get size(): Size {\n return this.getProperty(\"size\") as Size;\n }\n set size(value: Size) {\n this.setProperty(\"size\", value);\n }\n\n get appearance(): Appearance {\n return this.getProperty(\"appearance\") as Appearance;\n }\n set appearance(value: Appearance) {\n this.setProperty(\"appearance\", value);\n }\n\n get disabled(): boolean {\n return this.getProperty(\"disabled\");\n }\n set disabled(value: boolean) {\n this.setProperty(\"disabled\", value);\n }\n\n get loading(): boolean {\n return this.getProperty(\"loading\");\n }\n set loading(value: boolean) {\n this.setProperty(\"loading\", value);\n }\n\n get type(): \"button\" | \"submit\" | \"reset\" {\n return this.getProperty(\"type\");\n }\n set type(value: \"button\" | \"submit\" | \"reset\") {\n this.setProperty(\"type\", value);\n }\n\n get pill(): boolean {\n return this.getProperty(\"pill\");\n }\n set pill(value: boolean) {\n this.setProperty(\"pill\", value);\n }\n\n get action(): boolean {\n return this.getProperty(\"action\");\n }\n set action(value: boolean) {\n this.setProperty(\"action\", value);\n }\n\n get muted(): boolean {\n return this.getProperty(\"muted\");\n }\n set muted(value: boolean) {\n this.setProperty(\"muted\", value);\n }\n\n get wide(): boolean {\n return this.getProperty(\"wide\");\n }\n set wide(value: boolean) {\n this.setProperty(\"wide\", value);\n }\n\n get name(): string {\n return this.getProperty(\"name\");\n }\n set name(value: string) {\n this.setProperty(\"name\", value);\n }\n\n get value(): string {\n return this.getProperty(\"value\");\n }\n set value(value: string) {\n this.setProperty(\"value\", value);\n }\n\n /** Parse the optional `+`/`-` shade suffix from a flavor string. */\n private parseFlavor(): { base: string; tone: \"\" | \"+\" | \"-\" } {\n const f = this.flavor || \"\";\n if (f.length > 1 && f.endsWith(\"+\"))\n return { base: f.slice(0, -1), tone: \"+\" };\n if (f.length > 1 && f.endsWith(\"-\"))\n return { base: f.slice(0, -1), tone: \"-\" };\n return { base: f, tone: \"\" };\n }\n\n private buildClasses(): string {\n const { base, tone } = this.parseFlavor();\n return buildClassList(\n base,\n this.size,\n this.appearance,\n this.pill && \"pill\",\n this.action && \"action\",\n this.muted && \"muted\",\n tone === \"+\" && \"tone-plus\",\n tone === \"-\" && \"tone-minus\",\n );\n }\n\n private handleFormAction(): void {\n const form = this._internals.form;\n if (!form) return;\n\n switch (this.type) {\n case \"submit\":\n // Contribute name=value only to THIS submission, like a native\n // submitter. requestSubmit() builds the form data set synchronously,\n // so clearing right after is safe — and required: a value left\n // behind would ride along when a sibling button submits next.\n if (this.name && this.value) {\n this._internals.setFormValue(this.value);\n }\n try {\n form.requestSubmit();\n } finally {\n if (this.name && this.value) this._internals.setFormValue(null);\n }\n break;\n case \"reset\":\n form.reset();\n break;\n case \"button\":\n break;\n }\n }\n\n private initializeButtonStructure(): void {\n const shadow = this.shadowRoot!;\n const classes = this.buildClasses();\n\n const button = document.createElement(\"button\");\n button.disabled = this._isDisabled;\n button.className = classes;\n // The only thing the outside can reach. The control fills whatever box\n // the host gets (see :host in styles/button.ts), but host styling like\n // padding or border-radius never lands on the control — this does.\n // Same convention as ty-tag::part(container) / ty-tabs::part(strip).\n button.setAttribute(\"part\", \"button\");\n\n const loader = document.createElement(\"span\");\n loader.className = \"loader-icon\";\n loader.setAttribute(\"aria-hidden\", \"true\");\n loader.innerHTML = getLoaderSvg();\n\n const startSlot = document.createElement(\"slot\");\n startSlot.name = \"start\";\n startSlot.className = \"start\";\n\n const defaultSlot = document.createElement(\"slot\");\n\n const endSlot = document.createElement(\"slot\");\n endSlot.name = \"end\";\n endSlot.className = \"end\";\n\n button.appendChild(loader);\n button.appendChild(startSlot);\n button.appendChild(defaultSlot);\n button.appendChild(endSlot);\n\n // The native click never leaves the shadow root, so bubbling listeners\n // see exactly one click per press: the CustomEvent below, or none at all\n // while disabled or loading (a disabled native button fires no click).\n // Capture listeners above the button can't be shielded: the native\n // click passes them on its way in, before this runs.\n // Like native, listeners run BEFORE the default action, and\n // preventDefault() in any of them cancels the submit/reset.\n button.addEventListener(\"click\", (e: Event) => {\n // A click in a ty-popup slotted in here (<ty-button>Share<ty-popup>…)\n // is not a press of this button: let it through as it is, so it\n // doesn't submit the form and listeners see its real target.\n const path = e.composedPath();\n if (path.slice(0, path.indexOf(button)).some((n) => n instanceof Element && n.localName === \"ty-popup\")) return;\n e.stopPropagation();\n if (this._isDisabled || this.loading) return;\n const click = new CustomEvent(\"click\", {\n bubbles: true,\n composed: true,\n cancelable: true,\n detail: { originalEvent: e },\n });\n this._ownClick = click;\n if (this.dispatchEvent(click)) this.handleFormAction();\n });\n\n this.applyLoadingState(button);\n shadow.appendChild(button);\n this._structureInitialized = true;\n }\n\n private applyLoadingState(button: HTMLButtonElement): void {\n const isLoading = this.loading;\n button.classList.toggle(\"loading\", isLoading);\n if (isLoading) {\n button.setAttribute(\"aria-busy\", \"true\");\n // Clicks are swallowed while loading; say so, but stay focusable.\n button.setAttribute(\"aria-disabled\", \"true\");\n // Pull the latest registered loader SVG so registry changes take effect\n const loader = button.querySelector(\".loader-icon\");\n if (loader) loader.innerHTML = getLoaderSvg();\n } else {\n button.removeAttribute(\"aria-busy\");\n button.removeAttribute(\"aria-disabled\");\n }\n }\n\n protected render(): void {\n const shadow = this.shadowRoot!;\n\n if (!this._structureInitialized) {\n this.initializeButtonStructure();\n return;\n }\n\n const classes = this.buildClasses();\n const button = shadow.querySelector(\"button\");\n if (button) {\n button.disabled = this._isDisabled;\n button.className = classes;\n this.applyLoadingState(button);\n }\n }\n}\n\nif (!customElements.get(\"ty-button\")) {\n customElements.define(\"ty-button\", TyButton);\n}\n","/** Icon Component Styles */\n\nexport const iconStyles = `\n:host {\n /* Display & Layout - CRITICAL: No containment to prevent paint deferral */\n /* Block-level flex, NOT inline-flex: as an inline box the icon generates a\n line box in its parent, so a shrink-wrapping wrapper (badge, .rounded-full\n chip) inherits the parent's line-height strut and renders taller than wide\n — a 12px icon in a 24px-line-height badge becomes a 22x34 oval. To place an\n icon inline with text, make the *text wrapper* inline-flex instead. */\n display: flex;\n align-items: center;\n justify-content: center;\n line-height: 0;\n \n width: var(--ty-icon-size, 1em);\n height: var(--ty-icon-size, 1em);\n \n aspect-ratio: 1 / 1;\n \n \n color: inherit;\n transition: color 150ms cubic-bezier(0.4, 0, 0.2, 1);\n \n flex-shrink: 0;\n \n /* Visibility - Force immediate rendering */\n visibility: visible !important;\n opacity: 1;\n \n /* ANTI-FLICKER: Force browser to paint immediately */\n will-change: contents;\n \n /* Prevent any sub-pixel rendering issues */\n transform: translateZ(0);\n -webkit-font-smoothing: antialiased;\n}\n\n/* The SVG element inside shadow DOM (registry / fallback path) */\n:host svg {\n width: 100%;\n height: 100%;\n display: block;\n\n /* Force immediate SVG rendering */\n will-change: auto;\n transform: translateZ(0);\n}\n\n/* Slotted SVG (server-side path: <ty-icon><svg>...</svg></ty-icon>).\n ::slotted() targets light-DOM children so they fill the host the same way\n shadow-DOM SVG does. Color is inherited from :host via currentColor. */\n::slotted(svg),\n::slotted(img) {\n width: 100%;\n height: 100%;\n display: block;\n}\n\n/* In a named slot the icon sits alongside text (button start/end), so inline\n layout is what the host expects there. */\n:host([slot]) {\n display: inline-flex;\n}\n\n:host(.icon-xs) {\n width: 0.75em;\n height: 0.75em;\n}\n\n:host(.icon-sm) {\n width: 0.875em;\n height: 0.875em;\n}\n\n:host(.icon-md) {\n width: 1em;\n height: 1em;\n}\n\n:host(.icon-lg) {\n width: 1.25em;\n height: 1.25em;\n}\n\n:host(.icon-xl) {\n width: 1.5em;\n height: 1.5em;\n}\n\n:host(.icon-2xl) {\n width: 2em;\n height: 2em;\n}\n\n/* Fixed pixel sizes */\n:host(.icon-12) {\n width: 12px;\n height: 12px;\n}\n\n:host(.icon-14) {\n width: 14px;\n height: 14px;\n}\n\n:host(.icon-16) {\n width: 16px;\n height: 16px;\n}\n\n:host(.icon-18) {\n width: 18px;\n height: 18px;\n}\n\n:host(.icon-20) {\n width: 20px;\n height: 20px;\n}\n\n:host(.icon-24) {\n width: 24px;\n height: 24px;\n}\n\n:host(.icon-32) {\n width: 32px;\n height: 32px;\n}\n\n:host(.icon-48) {\n width: 48px;\n height: 48px;\n}\n\n:host(.icon-64) {\n width: 64px;\n height: 64px;\n}\n\n:host(.icon-80) {\n width: 80px;\n height: 80px;\n}\n\n:host(.icon-96) {\n width: 96px;\n height: 96px;\n}\n\n:host(.icon-spin) {\n animation: icon-spin 1s linear infinite;\n}\n\n:host(.icon-spin.icon-tempo-slow) {\n animation: icon-spin 2s linear infinite;\n}\n\n:host(.icon-spin.icon-tempo-fast) {\n animation: icon-spin 0.5s linear infinite;\n}\n\n@keyframes icon-spin {\n from {\n transform: rotate(0deg);\n }\n\n to {\n transform: rotate(360deg);\n }\n}\n\n:host(.icon-pulse) {\n animation: icon-pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;\n}\n\n:host(.icon-pulse.icon-tempo-slow) {\n animation: icon-pulse 3s cubic-bezier(0.4, 0, 0.6, 1) infinite;\n}\n\n:host(.icon-pulse.icon-tempo-fast) {\n animation: icon-pulse 1s cubic-bezier(0.4, 0, 0.6, 1) infinite;\n}\n\n@keyframes icon-pulse {\n 0%,\n 100% {\n opacity: 1;\n }\n\n 50% {\n opacity: 0.5;\n }\n}\n\n/* Accessibility: ensure icons are not announced by screen readers by default */\n:host {\n -webkit-user-select: none;\n user-select: none;\n}\n\n:host(:not(.icon-clickable)) {\n pointer-events: none;\n}\n\n:host(.icon-clickable) {\n cursor: pointer;\n pointer-events: auto;\n transition: color 150ms cubic-bezier(0.4, 0, 0.2, 1), transform 150ms cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n:host(.icon-clickable:hover) {\n transform: scale(1.1);\n}\n\n:host(.icon-clickable:active) {\n transform: scale(0.95);\n}\n\n:host(.icon-disabled) {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n:host(.icon-block) {\n display: block;\n}\n`;\n\n","// AUTO-GENERATED FILE - DO NOT EDIT\n// This file is generated from package.json by scripts/generate-version.js\n// Run 'npm run generate:version' to regenerate\n\n/**\n * Current version of tyrell-components\n * \n * This is automatically synced with package.json during build.\n * Use `npm version` to bump versions.\n */\nexport const VERSION = '1.0.0-TC58'\n","/**\n * Icon Registry System\n * Simple icon storage and retrieval with Cache API persistence\n */\n\nimport { VERSION } from '../version.js'\n\n/** Icon registry - maps icon names to SVG strings */\nconst iconRegistry = new Map<string, string>()\n\n/** Watchers for registry changes - now receives Set of changed icon names */\nconst watchers = new Map<string, (changedIcons: Set<string>) => void>()\n\n/** Track which icons each watcher cares about (for selective notification) */\nconst watcherIconNames = new Map<string, string>()\n\n/** Pending notifications - batched for performance */\nlet pendingNotifications: Set<string> | null = null\nlet notificationTimer: number | null = null\n\n/** Cache API configuration */\nconst CACHE_NAME = `ty-icons-v${VERSION}`\n// Use a fake URL base for Cache API (requires valid URL format)\nconst CACHE_URL_BASE = 'https://ty-icons.local/'\n\n/** Track in-flight cache reads to avoid duplicate work */\nconst cacheReadPromises = new Map<string, Promise<string | null>>()\n\n/** Flag to track if old caches have been cleared */\nlet oldCachesCleared = false\n\n/**\n * Clear old cache versions on first use\n * This runs lazily the first time any icon is requested\n */\nasync function clearOldCaches(): Promise<void> {\n if (oldCachesCleared || !('caches' in window)) return\n\n oldCachesCleared = true\n\n try {\n const cacheNames = await caches.keys()\n const oldCaches = cacheNames.filter(name =>\n name.startsWith('ty-icons-v') && name !== CACHE_NAME\n )\n\n await Promise.all(oldCaches.map(name => caches.delete(name)))\n\n if (oldCaches.length > 0) {\n console.log(`🗑️ Cleared ${oldCaches.length} old icon cache(s)`)\n }\n } catch (err) {\n console.warn('[ty-icons] Failed to clear old caches:', err)\n }\n}\n\n/**\n * Cache an icon in Cache API (non-blocking background operation)\n * @param name Icon name\n * @param svg SVG string\n */\nasync function cacheIcon(name: string, svg: string): Promise<void> {\n if (!('caches' in window)) return\n\n try {\n const cache = await caches.open(CACHE_NAME)\n const response = new Response(svg, {\n headers: { 'Content-Type': 'image/svg+xml' }\n })\n // Cache API requires valid URLs\n await cache.put(`${CACHE_URL_BASE}${name}`, response)\n } catch (err) {\n // Silent fail - caching is an optimization, not critical\n console.warn(`[ty-icons] Failed to cache icon \"${name}\":`, err)\n }\n}\n\n/**\n * Read icon directly from cache (for immediate rendering)\n * This is the key function that prevents icon twitching!\n * @param name Icon name\n * @returns Promise<string | null> - SVG string from cache or null\n */\nexport async function getCachedIcon(name: string): Promise<string | null> {\n const existingPromise = cacheReadPromises.get(name)\n if (existingPromise) {\n return existingPromise\n }\n\n const readPromise = (async () => {\n try {\n // Clear old caches on first cache access\n await clearOldCaches()\n\n const cache = await caches.open(CACHE_NAME)\n const response = await cache.match(`${CACHE_URL_BASE}${name}`)\n\n if (response) {\n return await response.text()\n }\n } catch (err) {\n console.warn(`[ty-icons] Failed to read icon \"${name}\" from cache:`, err)\n }\n\n return null\n })()\n\n // Store promise to avoid duplicate work\n cacheReadPromises.set(name, readPromise)\n\n readPromise.finally(() => {\n cacheReadPromises.delete(name)\n })\n\n return readPromise\n}\n\n/**\n * Register multiple icons at once\n * Always updates memory and notifies watchers immediately\n * Cache update happens in background (only if different from cached version)\n * @param icons Object mapping icon names to SVG strings\n */\nexport function registerIcons(icons: Record<string, string>): void {\n const changedIcons = new Set<string>()\n\n Object.entries(icons).forEach(([name, svg]) => {\n // Memory registry is the fast, synchronous source of truth\n iconRegistry.set(name, svg)\n changedIcons.add(name)\n })\n\n if (changedIcons.size > 0) {\n scheduleNotification(changedIcons)\n }\n}\n\n/**\n * Lookup an icon by name from memory\n * NOTE: This does NOT check cache - use getCachedIcon() for that\n * @param name Icon name\n * @returns SVG string or undefined\n */\nexport function getIcon(name: string): string | undefined {\n return iconRegistry.get(name)\n}\n\n/**\n * Check if an icon exists in memory\n * NOTE: This does NOT check cache\n * @param name Icon name\n * @returns true if icon is registered in memory\n */\nexport function hasIcon(name: string): boolean {\n return iconRegistry.has(name)\n}\n\n/**\n * Clear all registered icons from memory and cache\n */\nexport async function clearIcons(): Promise<void> {\n const allIcons = new Set(iconRegistry.keys())\n iconRegistry.clear()\n\n if ('caches' in window) {\n try {\n await caches.delete(CACHE_NAME)\n oldCachesCleared = false // Allow re-clearing next time\n } catch (err) {\n console.warn('[ty-icons] Failed to clear icon cache:', err)\n }\n }\n\n scheduleNotification(allIcons)\n}\n\n/**\n * Add a watcher for registry changes\n * @param id Unique watcher ID\n * @param iconName Optional icon name to watch (for selective notification)\n * @param callback Function to call when watched icons change\n */\nexport function addWatcher(\n id: string,\n iconName: string | undefined,\n callback: (changedIcons: Set<string>) => void\n): void {\n watchers.set(id, callback)\n if (iconName) {\n watcherIconNames.set(id, iconName)\n }\n}\n\n/**\n * Remove a watcher\n * @param id Watcher ID to remove\n */\nexport function removeWatcher(id: string): void {\n watchers.delete(id)\n watcherIconNames.delete(id)\n}\n\n/**\n * Schedule notification for changed icons (batched and deferred)\n */\nfunction scheduleNotification(changedIcons: Set<string>): void {\n if (!pendingNotifications) {\n pendingNotifications = new Set()\n }\n\n changedIcons.forEach(name => pendingNotifications!.add(name))\n\n if (notificationTimer !== null) {\n clearTimeout(notificationTimer)\n }\n\n const scheduleCallback = typeof requestIdleCallback !== 'undefined'\n ? requestIdleCallback\n : (cb: IdleRequestCallback) => setTimeout(cb, 0)\n\n notificationTimer = scheduleCallback(() => {\n const toNotify = pendingNotifications\n pendingNotifications = null\n notificationTimer = null\n\n if (toNotify && toNotify.size > 0) {\n notifyWatchers(toNotify)\n }\n }) as number\n}\n\n/**\n * Notify watchers of changed icons (selective notification)\n */\nfunction notifyWatchers(changedIcons: Set<string>): void {\n watchers.forEach((callback, watcherId) => {\n const watchedIcon = watcherIconNames.get(watcherId)\n\n // Watching a specific icon: only notify when that icon changed\n if (watchedIcon) {\n if (changedIcons.has(watchedIcon)) {\n callback(new Set([watchedIcon]))\n }\n } else {\n // Watcher wants all changes\n callback(changedIcons)\n }\n })\n}\n\n/**\n * Get all registered icon names (memory only, not cache)\n * @returns Array of icon names\n */\nexport function getIconNames(): string[] {\n return Array.from(iconRegistry.keys())\n}\n\n/**\n * Get cache statistics\n * @returns Promise with cache info\n */\nexport async function getCacheInfo(): Promise<{\n version: string\n cacheName: string\n available: boolean\n iconCount?: number\n}> {\n const info = {\n version: VERSION,\n cacheName: CACHE_NAME,\n available: 'caches' in window\n }\n\n if (!info.available) return info\n\n try {\n const cache = await caches.open(CACHE_NAME)\n const keys = await cache.keys()\n const iconKeys = keys.filter(req => req.url.startsWith(CACHE_URL_BASE))\n\n return {\n ...info,\n iconCount: iconKeys.length\n }\n } catch (err) {\n console.warn('[ty-icons] Failed to get cache info:', err)\n return info\n }\n}\n","/**\n * TyIcon Web Component — SVG icon with size variants and animations.\n */\n\nimport type { IconSize, IconTempo, TyIconElement } from '../types/common.js'\nimport { TyComponent } from '../base/ty-component.js'\nimport type { PropertyChange } from '../utils/property-manager.js'\nimport { ensureStyles } from '../utils/styles.js'\nimport { iconStyles } from '../styles/icon.js'\nimport * as IconRegistry from '../utils/icon-registry.js'\n\nlet _iconIdCounter = 0\n\n/** Fallback SVG for missing icons - More visible to prevent layout shift */\nconst NOT_FOUND_ICON = `<svg xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 512 512\"\n fill=\"currentColor\"\n opacity=\"0.2\">\n <path d=\"M256 512A256 256 0 1 0 256 0a256 256 0 1 0 0 512z\"/>\n</svg>`\n\n/**\n * Component internal state (for typing TyComponent)\n */\ninterface IconState {\n name: string\n size: string\n spin: boolean\n pulse: boolean\n tempo: string\n}\n\n/**\n * Ty Icon Component\n */\nexport class TyIcon extends TyComponent<IconState> implements TyIconElement {\n static formAssociated = false\n\n protected static properties = {\n name: { type: 'string' as const, visual: true, default: '' },\n size: { type: 'string' as const, visual: true, default: '' },\n spin: { type: 'boolean' as const, visual: true, default: false },\n pulse: { type: 'boolean' as const, visual: true, default: false },\n tempo: { type: 'string' as const, visual: true, default: '' },\n }\n\n private _watchId: string | null = null\n\n /** Track currently rendered SVG to avoid unnecessary re-renders */\n private _currentSvg: string = ''\n\n /**\n * Single shadow-DOM <slot> that holds either:\n * - light-DOM children supplied by the user (server-side path: pasted SVG), or\n * - fallback content driven by the registry (`name=`) or NOT_FOUND_ICON.\n *\n * Browser slot semantics handle precedence: when the host has assigned nodes,\n * the slot's fallback content is hidden automatically — no detection logic needed.\n */\n private _slot: HTMLSlotElement | null = null\n\n constructor() {\n super() // TyComponent handles attachInternals() and attachShadow()\n\n ensureStyles(this.shadowRoot!, { css: iconStyles, id: 'ty-icon' })\n\n // Build the slot once. Fallback content shows when no light-DOM children are slotted.\n this._slot = document.createElement('slot')\n this._slot.innerHTML = NOT_FOUND_ICON\n this._currentSvg = NOT_FOUND_ICON\n this.shadowRoot!.appendChild(this._slot)\n }\n\n // observedAttributes auto-generated by TyComponent from properties config\n\n protected onConnect(): void {\n this._watchId = `ty-icon-${++_iconIdCounter}`\n\n // Watch for registry changes that affect this icon\n if (this.name) {\n IconRegistry.addWatcher(this._watchId, this.name, (changedIcons) => {\n if (this.name && changedIcons.has(this.name)) {\n this.render()\n }\n })\n }\n\n this.updateClasses()\n\n // TyComponent will call render() automatically after this hook\n }\n\n protected onDisconnect(): void {\n if (this._watchId) {\n IconRegistry.removeWatcher(this._watchId)\n this._watchId = null\n }\n }\n\n /**\n * Handle property changes - called BEFORE render\n * Detects name changes to update icon registry watcher\n */\n protected onPropertiesChanged(changes: PropertyChange[]): void {\n for (const change of changes) {\n if (change.name === 'name') {\n if (this._watchId) {\n IconRegistry.removeWatcher(this._watchId)\n }\n\n const newName = change.newValue || ''\n if (newName && this.isConnected) {\n this._watchId = `ty-icon-${++_iconIdCounter}`\n IconRegistry.addWatcher(this._watchId, newName, (changedIcons) => {\n if (this.name && changedIcons.has(this.name)) {\n this.render()\n }\n })\n }\n }\n }\n\n // Update host element classes for any visual change\n this.updateClasses()\n }\n\n get name(): string {\n return this.getProperty('name')\n }\n\n set name(value: string) {\n this.setProperty('name', value)\n }\n\n get size(): IconSize | undefined {\n const val = this.getProperty('size')\n return val || undefined\n }\n\n set size(value: IconSize | undefined) {\n this.setProperty('size', value || '')\n }\n\n get spin(): boolean {\n return this.getProperty('spin')\n }\n\n set spin(value: boolean) {\n this.setProperty('spin', value)\n }\n\n get pulse(): boolean {\n return this.getProperty('pulse')\n }\n\n set pulse(value: boolean) {\n this.setProperty('pulse', value)\n }\n\n get tempo(): IconTempo | undefined {\n const val = this.getProperty('tempo')\n return val || undefined\n }\n\n set tempo(value: IconTempo | undefined) {\n this.setProperty('tempo', value || '')\n }\n\n /** Build CSS classes for the host element */\n private buildClasses(): string[] {\n const classes: string[] = []\n\n const size = this.getProperty('size')\n if (size) {\n classes.push(`icon-${size}`)\n }\n\n if (this.getProperty('spin')) {\n classes.push('icon-spin')\n }\n\n if (this.getProperty('pulse')) {\n classes.push('icon-pulse')\n }\n\n const tempo = this.getProperty('tempo')\n if (tempo && (this.getProperty('spin') || this.getProperty('pulse'))) {\n classes.push(`icon-tempo-${tempo}`)\n }\n\n // Preserve user-added classes that don't conflict\n const currentClasses = this.className.split(/\\s+/).filter(cls => {\n return cls &&\n !cls.startsWith('icon-') &&\n cls !== 'icon-spin' &&\n cls !== 'icon-pulse'\n })\n\n return [...classes, ...currentClasses]\n }\n\n /** Update host element classes */\n private updateClasses(): void {\n const newClasses = this.buildClasses().join(' ')\n if (this.className !== newClasses) {\n this.className = newClasses\n }\n }\n\n /**\n * Render the icon SVG. Unknown/unset names fall back to NOT_FOUND_ICON\n * immediately rather than rendering nothing (prevents layout shift).\n */\n protected render(): void {\n const name = this.getProperty('name')\n\n if (!name) {\n this.renderSvg(NOT_FOUND_ICON)\n return\n }\n\n const memorySvg = IconRegistry.getIcon(name)\n if (memorySvg) {\n this.renderSvg(memorySvg)\n return\n }\n\n this.renderSvg(NOT_FOUND_ICON)\n }\n\n /**\n * Update the slot's fallback content.\n * If the user has slotted light-DOM children (e.g., raw <svg>), the browser\n * shows those instead and the fallback stays hidden — but we still keep it\n * up to date so removing the children reveals the right registry/fallback SVG.\n */\n private renderSvg(svg: string): void {\n if (this._currentSvg === svg) {\n return\n }\n\n if (this._slot) {\n this._slot.innerHTML = svg\n this._currentSvg = svg\n }\n }\n}\n\nif (!customElements.get('ty-icon')) {\n customElements.define('ty-icon', TyIcon)\n}\n\nexport { IconRegistry }\n","/** Tag Component Styles */\n\nimport { FLAVORS } from '../types/common.js'\n\n/* Neutral maps to text/border tokens instead of flavor tokens, so it is\n written out by hand in the template below. */\nconst COLOR_FLAVORS = FLAVORS.filter((f) => f !== 'neutral')\n\nconst tagFlavor = (f: string) => `\n:host([flavor=\"${f}\"]) {\n --tag-bg: var(--ty-bg-${f});\n --tag-color: var(--ty-color-${f});\n --tag-border-color: var(--ty-border-${f});\n}\n:host([flavor=\"${f}+\"]) {\n --tag-bg: var(--ty-bg-${f}-bold);\n --tag-color: var(--ty-color-${f}-strong);\n --tag-border-color: var(--ty-color-${f});\n}\n:host([flavor=\"${f}-\"]) {\n --tag-bg: var(--ty-bg-${f}-soft);\n --tag-color: var(--ty-color-${f});\n --tag-border-color: var(--ty-border-${f});\n}\n:host([flavor=\"${f}\"]) .tag-container[tabindex]:hover,\n:host([flavor=\"${f}+\"]) .tag-container[tabindex]:hover,\n:host([flavor=\"${f}-\"]) .tag-container[tabindex]:hover {\n background: var(--ty-bg-${f}-bold);\n}\n:host([flavor=\"${f}\"]) .tag-container[tabindex]:focus,\n:host([flavor=\"${f}+\"]) .tag-container[tabindex]:focus,\n:host([flavor=\"${f}-\"]) .tag-container[tabindex]:focus {\n box-shadow: 0 0 0 3px var(--ty-color-${f}-faint);\n}\n`\n\nexport const tagStyles = `\n:host([hidden]) {\n display: none !important;\n}\n\n.tag-container {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: var(--ty-spacing-1);\n border-radius: var(--ty-radius-full);\n /* Mode-flipped weight dial (tyrell.css): 440 light / 400 dark. Chips are\n labels, not actions — they run lighter than buttons. Override with\n --ty-weight-label at any scope. */\n font-weight: var(--ty-weight-label, 440);\n text-align: center;\n white-space: nowrap;\n user-select: none;\n box-sizing: border-box;\n\n /* Default MD size — anchor at 28px, even +4 steps for other sizes */\n padding: 0 0.625rem; /* 0 10px */\n font-size: var(--ty-font-xs); /* 14px */\n line-height: var(--ty-leading-xs); /* 21px */\n letter-spacing: var(--ty-tracking-xs); /* -0.013em */\n min-height: 28px;\n\n transition: var(--ty-transition-all);\n\n /* Colors via custom properties — override on :host for full control */\n background: var(--tag-bg, transparent);\n color: var(--tag-color, var(--ty-text));\n border: 1px solid;\n border-color: var(--tag-border-color, var(--ty-border));\n}\n\n:host([no-pill]) .tag-container {\n border-radius: var(--ty-radius-md);\n /* 6px instead of full pill */\n}\n\n/* Tags with value attribute but NOT selected should be clickable */\n:host([value]:not([selected])) .tag-container:not([aria-disabled=\"true\"]) {\n cursor: pointer;\n}\n\n:host([selected]) .tag-container:not([aria-disabled=\"true\"]) {\n cursor: initial;\n}\n\n.tag-container[tabindex]:not([aria-disabled=\"true\"]):hover {\n background: var(--ty-bg-neutral-soft);\n transform: translateY(-1px);\n box-shadow: var(--ty-shadow-sm);\n}\n\n.tag-container[tabindex]:not([aria-disabled=\"true\"]):active {\n transform: translateY(0);\n box-shadow: var(--ty-shadow-sm);\n}\n\n.tag-container[tabindex]:focus {\n outline: none;\n}\n\n.tag-container[aria-disabled=\"true\"] {\n opacity: 0.6;\n cursor: not-allowed;\n pointer-events: none;\n}\n\n.tag-start,\n.tag-content,\n.tag-end {\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n}\n\n.tag-content {\n flex: 1;\n min-width: 0;\n}\n\n.tag-dismiss {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n padding: 0;\n background: none;\n border: none;\n color: currentColor;\n cursor: pointer;\n border-radius: var(--ty-radius-full);\n transition: var(--ty-transition-all);\n opacity: 0.7;\n flex-shrink: 0;\n width: var(--ty-spacing-4);\n /* 16px */\n height: var(--ty-spacing-4);\n}\n\n.tag-dismiss:hover {\n opacity: 1;\n background: rgba(0, 0, 0, 0.1);\n}\n\n.tag-dismiss svg {\n width: 100%;\n height: 100%;\n}\n\n:host([size=\"xs\"]) .tag-container {\n padding: 0 0.375rem; /* 0 6px */\n font-size: var(--ty-font-xs); /* 12px */\n line-height: var(--ty-leading-xs);\n letter-spacing: var(--ty-tracking-xs);\n min-height: 20px;\n}\n\n:host([size=\"xs\"]) .tag-dismiss {\n width: var(--ty-spacing-3);\n height: var(--ty-spacing-3);\n margin-left: var(--ty-spacing-2);\n}\n\n:host([size=\"sm\"]) .tag-container {\n padding: 0 var(--ty-spacing-2); /* 0 8px */\n font-size: var(--ty-font-xs); /* 12px */\n line-height: var(--ty-leading-xs);\n letter-spacing: var(--ty-tracking-xs);\n min-height: 24px;\n}\n\n:host([size=\"sm\"]) .tag-dismiss {\n width: var(--ty-spacing-3);\n height: var(--ty-spacing-3);\n margin-left: var(--ty-spacing-2);\n}\n\n/* MD is the default — no explicit [size=\"md\"] selector needed */\n\n:host([size=\"lg\"]) .tag-container {\n padding: 0 var(--ty-spacing-3); /* 0 12px */\n font-size: var(--ty-font-sm); /* 14px */\n line-height: var(--ty-leading-sm); /* 21px */\n letter-spacing: var(--ty-tracking-sm); /* -0.013em */\n min-height: 32px;\n}\n\n:host([size=\"lg\"]) .tag-dismiss {\n width: var(--ty-spacing-5);\n height: var(--ty-spacing-5);\n margin-left: var(--ty-spacing-4);\n}\n\n:host([size=\"xl\"]) .tag-container {\n padding: 0 0.875rem; /* 0 14px */\n font-size: var(--ty-font-sm); /* 14px */\n line-height: var(--ty-leading-sm); /* 21px */\n letter-spacing: var(--ty-tracking-sm); /* -0.013em */\n min-height: 36px;\n}\n\n:host([size=\"xl\"]) .tag-dismiss {\n width: var(--ty-spacing-5);\n height: var(--ty-spacing-5);\n margin-left: var(--ty-spacing-4);\n}\n\n/* Each flavor sets --tag-bg / --tag-color / --tag-border-color on :host.\n Append '+' to flavor for a stronger shade (mild background, strong color),\n or '-' for a softer shade (soft background, base color).\n Generated per flavor above; neutral diverges (text/border tokens) and\n stays hand-written below. */\n\n${COLOR_FLAVORS.map(tagFlavor).join('')}\n:host([flavor=\"neutral\"]) {\n --tag-color: var(--ty-text-bold);\n --tag-bg: var(--ty-bg-neutral-soft);\n --tag-border-color: var(--ty-border-bold);\n}\n\n:host([flavor=\"neutral+\"]) {\n --tag-bg: var(--ty-bg-neutral-bold);\n --tag-color: var(--ty-text-bold);\n --tag-border-color: var(--ty-border-strong);\n}\n:host([flavor=\"neutral-\"]) {\n --tag-bg: var(--ty-bg-neutral-soft);\n --tag-color: var(--ty-text-soft);\n --tag-border-color: var(--ty-border);\n}\n:host([flavor=\"neutral\"]) .tag-container[tabindex]:hover,\n:host([flavor=\"neutral+\"]) .tag-container[tabindex]:hover,\n:host([flavor=\"neutral-\"]) .tag-container[tabindex]:hover {\n background: var(--ty-bg-neutral-soft);\n}\n:host([flavor=\"neutral\"]) .tag-container[tabindex]:focus,\n:host([flavor=\"neutral+\"]) .tag-container[tabindex]:focus,\n:host([flavor=\"neutral-\"]) .tag-container[tabindex]:focus {\n box-shadow: 0 0 0 3px var(--ty-border-soft);\n}\n\n.tag-start ::slotted(*),\n.tag-content ::slotted(*),\n.tag-end ::slotted(*) {\n display: flex;\n align-items: center;\n}\n\n.tag-start ::slotted(ty-icon),\n.tag-end ::slotted(ty-icon) {\n width: 1em;\n height: 1em;\n flex-shrink: 0;\n}\n\n.tag-end ::slotted(.count) {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: var(--ty-spacing-6);\n /* 24px */\n height: var(--ty-spacing-5);\n /* 20px */\n padding: 0 var(--ty-spacing-2);\n /* 0 8px */\n background: rgba(0, 0, 0, 0.1);\n border-radius: var(--ty-radius-full);\n font-size: var(--ty-font-xs);\n font-weight: var(--ty-font-semibold);\n line-height: var(--ty-line-height-none);\n flex-shrink: 0;\n}\n\n.tag-content {\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n:host([data-type=\"user\"]) .tag-container {\n min-width: var(--ty-spacing-20);\n /* 80px for user tags */\n}\n\n/* Dark mode is handled automatically by the centralized variables */\n`;\n","/**\n * TyTag Web Component — tag/chip with slots and semantic flavors.\n */\n\nimport type {\n Flavor,\n Size,\n TyTagElement,\n TyTagEventDetail,\n} from \"../types/common.js\";\nimport { DEFAULT_SIZE } from \"../types/common.js\";\nimport { syncCustomFlavorSheet } from \"../utils/flavor-sheet.js\";\nimport { TyComponent } from \"../base/ty-component.js\";\nimport type { PropertyChange } from \"../utils/property-manager.js\";\nimport { ensureStyles } from \"../utils/styles.js\";\nimport { tagStyles } from \"../styles/tag.js\";\n\ninterface TagState {\n flavor: Flavor;\n size: Size;\n value: string;\n selected: boolean;\n noPill: boolean;\n clickable: boolean;\n dismissible: boolean;\n disabled: boolean;\n}\n\n/**\n * Ty Tag Component\n *\n * @example\n * ```html\n * <ty-tag flavor=\"primary\">Primary Tag</ty-tag>\n * <ty-tag flavor=\"success\" dismissible>Success Tag</ty-tag>\n * <ty-tag flavor=\"danger\" clickable>Clickable Tag</ty-tag>\n * <ty-tag value=\"tag-1\" selected>Selected Tag</ty-tag>\n * ```\n */\nexport class TyTag extends TyComponent<TagState> implements TyTagElement {\n static formAssociated = true;\n\n protected static properties = {\n flavor: {\n type: \"string\" as const,\n visual: true,\n default: \"neutral\",\n // Built-in: primary | success | danger | warning | neutral.\n // Append `+` for stronger or `-` for softer shade (e.g. \"primary+\",\n // \"danger-\"). Any other string is a custom flavor: if you define the\n // design tokens (--ty-bg-X, --ty-color-X, --ty-border-X) it just works\n // (see _syncCustomFlavor), and ty-tag[flavor=\"X\"] { --tag-bg: ...; }\n // rules in the page still override.\n },\n size: {\n type: \"string\" as const,\n visual: true,\n default: DEFAULT_SIZE,\n validate: (v: any) => [\"xs\", \"sm\", \"md\", \"lg\", \"xl\"].includes(v),\n coerce: (v: any) => {\n if (![\"xs\", \"sm\", \"md\", \"lg\", \"xl\"].includes(v)) {\n console.warn(`[ty-tag] Invalid size '${v}'. Using '${DEFAULT_SIZE}'.`);\n return DEFAULT_SIZE;\n }\n return v;\n },\n },\n value: {\n type: \"string\" as const,\n visual: true,\n default: \"\",\n },\n selected: {\n type: \"boolean\" as const,\n visual: true,\n default: false,\n },\n // Fully rounded is the default; no-pill squares the corners.\n noPill: {\n type: \"boolean\" as const,\n visual: true,\n default: false,\n },\n clickable: {\n type: \"boolean\" as const,\n visual: true,\n default: false,\n },\n dismissible: {\n type: \"boolean\" as const,\n visual: true,\n default: false,\n },\n disabled: {\n type: \"boolean\" as const,\n visual: true,\n default: false,\n },\n };\n\n private _cleanup: (() => void) | null = null;\n\n // Adopted sheet holding generated rules for a custom (non-built-in) flavor.\n // Must be an adopted sheet, not a <style> element — render() replaces\n // shadowRoot.innerHTML, which would destroy an injected element.\n private _customFlavorSheet: CSSStyleSheet | null = null;\n\n constructor() {\n super(); // TyComponent handles attachInternals() and attachShadow()\n\n ensureStyles(this.shadowRoot!, { css: tagStyles, id: \"ty-tag\" });\n }\n\n // observedAttributes auto-generated by TyComponent from properties config\n\n /** TyComponent calls render() automatically after this hook. */\n protected onConnect(): void {\n this._syncCustomFlavor();\n // Setup event listeners after initial render happens\n // Use queueMicrotask to ensure render() has been called by TyComponent\n queueMicrotask(() => {\n this.setupEventListeners();\n });\n }\n\n /**\n * Custom (non-built-in) flavors: generate the same --tag-* wiring the\n * built-in flavors get, pointed at the user's design tokens\n * (--ty-bg-X / --ty-color-X / --ty-border-X). See utils/flavor-sheet.ts\n * for why this is an adopted sheet and how page-level overrides survive.\n */\n private _syncCustomFlavor(): void {\n this._customFlavorSheet = syncCustomFlavorSheet(\n this.shadowRoot!,\n this._customFlavorSheet,\n this.flavor,\n ({ flavor, base, shade }) => {\n const bg =\n shade === \"+\" ? `--ty-bg-${base}-bold`\n : shade === \"-\" ? `--ty-bg-${base}-soft`\n : `--ty-bg-${base}`;\n const color = shade === \"+\" ? `--ty-color-${base}-strong` : `--ty-color-${base}`;\n return `\n:host([flavor=\"${flavor}\"]) {\n --tag-bg: var(${bg});\n --tag-color: var(${color});\n --tag-border-color: var(--ty-border-${base}, var(--ty-color-${base}));\n}\n:host([flavor=\"${flavor}\"]) .tag-container[tabindex]:hover {\n background: var(--ty-bg-${base}-bold, var(--tag-bg));\n}\n:host([flavor=\"${flavor}\"]) .tag-container[tabindex]:focus {\n box-shadow: 0 0 0 3px var(--ty-color-${base}-faint, var(--tag-color));\n}`;\n },\n );\n }\n\n protected onDisconnect(): void {\n this.cleanupEventListeners();\n }\n\n /**\n * Handle property changes - called BEFORE render\n */\n protected onPropertiesChanged(changes: PropertyChange[]): void {\n if (changes.some((c) => c.name === \"flavor\")) {\n this._syncCustomFlavor();\n }\n }\n\n // Arrow functions for stable listener references.\n private handleClick = (event: Event): void => {\n if (this.clickable && !this.disabled) {\n event.preventDefault();\n event.stopPropagation();\n this.dispatchTagEvent(\"click\", { target: this });\n this.dispatchTagEvent(\"pointerdown\", { target: this });\n }\n };\n\n private handleDismiss = (event: Event): void => {\n if (this.dismissible && !this.disabled) {\n event.preventDefault();\n event.stopPropagation();\n this.dispatchTagEvent(\"dismiss\", { target: this });\n }\n };\n\n private handleKeydown = (event: Event): void => {\n const keyboardEvent = event as KeyboardEvent;\n if (this.disabled) return;\n\n const keyCode = keyboardEvent.keyCode;\n\n switch (keyCode) {\n case 13: // Enter\n case 32: // Space\n if (this.clickable) {\n keyboardEvent.preventDefault();\n this.dispatchTagEvent(\"click\", { target: this });\n }\n break;\n\n case 8: // Backspace\n case 46: // Delete\n if (this.dismissible) {\n keyboardEvent.preventDefault();\n this.dispatchTagEvent(\"dismiss\", { target: this });\n }\n break;\n }\n };\n\n private dispatchTagEvent(eventType: string, detail: TyTagEventDetail): void {\n this.dispatchEvent(\n new CustomEvent(eventType, {\n detail,\n bubbles: true,\n composed: true,\n cancelable: true,\n }),\n );\n }\n\n private cleanupEventListeners(): void {\n if (this._cleanup) {\n this._cleanup();\n this._cleanup = null;\n }\n }\n\n private setupEventListeners(): void {\n this.cleanupEventListeners();\n\n const shadow = this.shadowRoot!;\n const container = shadow.querySelector(\".tag-container\");\n const dismissBtn = shadow.querySelector(\".tag-dismiss\");\n\n if (!container) return;\n\n container.addEventListener(\"click\", this.handleClick);\n container.addEventListener(\"keydown\", this.handleKeydown);\n\n if (dismissBtn) {\n dismissBtn.addEventListener(\"click\", this.handleDismiss);\n }\n\n this._cleanup = () => {\n container.removeEventListener(\"click\", this.handleClick);\n container.removeEventListener(\"keydown\", this.handleKeydown);\n if (dismissBtn) {\n dismissBtn.removeEventListener(\"click\", this.handleDismiss);\n }\n };\n }\n\n protected render(): void {\n const shadow = this.shadowRoot!;\n\n const tabindex = this.clickable ? ' tabindex=\"0\"' : \"\";\n const ariaDisabled = this.disabled ? ' aria-disabled=\"true\"' : \"\";\n const dataValue = this.value ? ` data-value=\"${this.value}\"` : \"\";\n\n const dismissButton = this.dismissible\n ? `\n <button class=\"tag-dismiss\" type=\"button\" aria-label=\"Remove tag\">\n <svg viewBox=\"0 0 20 20\" fill=\"currentColor\">\n <path fill-rule=\"evenodd\" d=\"M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z\" clip-rule=\"evenodd\" />\n </svg>\n </button>\n `\n : \"\";\n\n shadow.innerHTML = `\n <div class=\"tag-container\" part=\"container\"${tabindex}${ariaDisabled}${dataValue}>\n <div class=\"tag-start\">\n <slot name=\"start\" class=\"tag-start\"></slot>\n </div>\n <div class=\"tag-content\">\n <slot></slot>\n </div>\n <div class=\"tag-end\">\n <slot name=\"end\"></slot>\n ${dismissButton}\n </div>\n </div>\n `;\n\n // Re-setup event listeners after innerHTML replace (destroys old elements)\n if (this._connected) {\n this.setupEventListeners();\n }\n }\n\n get flavor(): Flavor {\n return this.getProperty(\"flavor\");\n }\n\n set flavor(value: Flavor) {\n this.setProperty(\"flavor\", value);\n }\n\n get size(): Size {\n return this.getProperty(\"size\") as Size;\n }\n\n set size(value: Size) {\n this.setProperty(\"size\", value);\n }\n\n get value(): string {\n return this.getProperty(\"value\");\n }\n\n set value(val: string) {\n this.setProperty(\"value\", val);\n }\n\n get selected(): boolean {\n return this.getProperty(\"selected\");\n }\n\n set selected(value: boolean) {\n this.setProperty(\"selected\", value);\n }\n\n get noPill(): boolean {\n return this.getProperty(\"noPill\");\n }\n\n set noPill(value: boolean) {\n this.setProperty(\"noPill\", value);\n }\n\n get clickable(): boolean {\n return this.getProperty(\"clickable\");\n }\n\n set clickable(value: boolean) {\n this.setProperty(\"clickable\", value);\n }\n\n get dismissible(): boolean {\n return this.getProperty(\"dismissible\");\n }\n\n set dismissible(value: boolean) {\n this.setProperty(\"dismissible\", value);\n }\n\n get disabled(): boolean {\n return this.getProperty(\"disabled\");\n }\n\n set disabled(value: boolean) {\n this.setProperty(\"disabled\", value);\n }\n}\n\nif (!customElements.get(\"ty-tag\")) {\n customElements.define(\"ty-tag\", TyTag);\n}\n","/** Option Component Styles */\n\nexport const optionStyles = `\n.option-content {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--ty-spacing-2);\n box-sizing: border-box;\n width: 100%;\n\n cursor: pointer;\n user-select: none;\n\n transition: var(--ty-transition-all);\n\n /* Linear-paired typography */\n color: var(--ty-text);\n font-family: inherit;\n font-size: var(--ty-font-sm);\n line-height: var(--ty-leading-sm);\n letter-spacing: var(--ty-tracking-sm);\n padding: var(--ty-spacing-2) var(--ty-spacing-3);\n border-radius: var(--ty-radius-md);\n}\n\n/* Cloned copy (projected into the select's trigger field): host defaults to\n inline like any unstyled custom element, which ignores width/overflow —\n force a block box so the parent's flex-basis:0 truncation (select.ts\n .select-stub.has-clone slot[name=\"selected\"]) actually clips it, and\n collapse the content to a single ellipsized line instead of wrapping. */\n:host([cloned]) {\n display: block;\n min-width: 0;\n overflow: hidden;\n}\n\n/* The clone sits in the select's TRIGGER, so its type follows the field size\n ladder (styles/field-size.ts) rather than the dropdown list's own scale —\n the --ty-field-* vars inherit from ty-select through the light DOM. The\n fallbacks cover a ty-option rendered outside a select. */\n:host([cloned]) .option-content {\n display: block;\n padding: 0px;\n background: transparent;\n min-width: 0;\n overflow: hidden;\n white-space: nowrap;\n text-overflow: ellipsis;\n font-size: var(--ty-field-font, var(--ty-font-sm));\n line-height: var(--ty-field-leading, var(--ty-leading-sm));\n letter-spacing: var(--ty-field-tracking, var(--ty-tracking-sm));\n}\n\n.option-content:hover {\n background: var(--ty-bg-neutral-soft);\n}\n\n.option-content[highlighted] {\n background: var(--ty-bg-neutral-soft);\n color: var(--ty-text-strong);\n}\n\n/* Selected: quiet — bolder text color only, no background slab, no weight change */\n.option-content[selected] {\n background: transparent;\n color: var(--ty-text-bold);\n}\n\n/* Lucide check — right-aligned. Its box is always reserved so selecting\n (or highlighting) never changes the row's width and rewraps the text. */\n.option-check {\n display: block;\n visibility: hidden;\n flex-shrink: 0;\n width: 14px;\n height: 14px;\n margin-left: auto;\n color: var(--ty-color-primary);\n}\n\n.option-content[selected] .option-check {\n visibility: visible;\n}\n\n/* Never show the check on the copy cloned into the select's trigger field */\n:host([cloned]) .option-check {\n display: none;\n}\n\n.option-content[selected]:hover {\n background: var(--ty-bg-neutral-soft);\n}\n\n.option-content[disabled] {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.option-content[hidden] {}\n\n.option-content * {\n pointer-events: none;\n}\n`\n","/**\n * TyOption Web Component - rich HTML alternative to native <option>.\n * Property-attribute synchronization keeps it compatible with frameworks.\n */\n\nimport type { TyOptionElement } from '../types/common.js'\nimport { ensureStyles } from '../utils/styles.js'\nimport { coerceBoolean } from '../utils/property-manager.js'\nimport { upgradeProperties } from '../utils/upgrade-properties.js'\nimport { optionStyles } from '../styles/option.js'\n\n/** Lucide `check` — shown on selected options (kept inline: shadow DOM can't rely on the icon registry) */\nconst CHECK_SVG = `\n <svg class=\"option-check\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\n stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\n <path d=\"M20 6 9 17l-5-5\" />\n </svg>\n`\n\nexport class TyOption extends HTMLElement implements TyOptionElement {\n private _value: string | undefined = undefined\n private _selected = false\n private _disabled = false\n private _highlighted = false\n private _hidden = false\n\n constructor() {\n super()\n\n const shadow = this.attachShadow({ mode: 'open' })\n ensureStyles(shadow, { css: optionStyles, id: 'ty-option' })\n\n this.render()\n }\n\n static get observedAttributes(): string[] {\n return ['value', 'disabled', 'selected', 'highlighted', 'hidden']\n }\n\n connectedCallback(): void {\n upgradeProperties(this)\n this.render()\n }\n\n\n attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void {\n if (oldValue === newValue) return\n\n switch (name) {\n case 'value':\n this._value = newValue || undefined\n break\n case 'selected':\n this._selected = newValue !== null\n break\n case 'disabled':\n this._disabled = newValue !== null\n break\n case 'highlighted':\n this._highlighted = newValue !== null\n break\n case 'hidden':\n this._hidden = newValue !== null\n break\n }\n\n this.render()\n }\n\n /**\n * Get value from either property or attribute, with textContent fallback.\n * Property takes precedence (for framework compatibility).\n */\n private getOptionValue(): string {\n // Explicit priority: property > attribute > textContent\n // This correctly handles empty strings\n \n if (this._value !== undefined) {\n return this._value\n }\n \n const attrValue = this.getAttribute('value')\n if (attrValue !== null) {\n return attrValue\n }\n \n return this.textContent?.trim() || ''\n }\n\n // NOTE: All setters trigger re-render to support property changes from frameworks like React\n\n get value(): string | undefined {\n return this.getOptionValue()\n }\n\n set value(val: string | undefined) {\n if (this._value !== val) {\n this._value = val\n if (val !== undefined) {\n this.setAttribute('value', val)\n } else {\n this.removeAttribute('value')\n }\n this.render()\n }\n }\n\n get selected(): boolean {\n return this._selected\n }\n\n set selected(value: boolean) {\n value = coerceBoolean(value)\n if (this._selected !== value) {\n this._selected = value\n if (value) {\n this.setAttribute('selected', '')\n } else {\n this.removeAttribute('selected')\n }\n this.render()\n }\n }\n\n get disabled(): boolean {\n return this._disabled\n }\n\n set disabled(value: boolean) {\n value = coerceBoolean(value)\n if (this._disabled !== value) {\n this._disabled = value\n if (value) {\n this.setAttribute('disabled', '')\n } else {\n this.removeAttribute('disabled')\n }\n this.render()\n }\n }\n\n get highlighted(): boolean {\n return this._highlighted\n }\n\n set highlighted(value: boolean) {\n value = coerceBoolean(value)\n if (this._highlighted !== value) {\n this._highlighted = value\n if (value) {\n this.setAttribute('highlighted', '')\n } else {\n this.removeAttribute('highlighted')\n }\n this.render()\n }\n }\n\n get hidden(): boolean {\n return this._hidden\n }\n\n set hidden(value: boolean) {\n value = coerceBoolean(value)\n if (this._hidden !== value) {\n this._hidden = value\n if (value) {\n this.setAttribute('hidden', '')\n } else {\n this.removeAttribute('hidden')\n }\n this.render()\n }\n }\n\n\n private render(): void {\n const shadow = this.shadowRoot!\n\n // Create wrapper once — the check icon alone communicates selection;\n // clicking a selected option again deselects it (see select.ts), so no\n // separate clear affordance is needed on mobile.\n if (!shadow.querySelector('.option-content')) {\n shadow.innerHTML = `<div class=\"option-content\"><slot></slot>${CHECK_SVG}</div>`\n }\n\n const content = shadow.querySelector('.option-content')\n if (content) {\n if (this._disabled) {\n content.setAttribute('disabled', '')\n } else {\n content.removeAttribute('disabled')\n }\n\n if (this._selected) {\n content.setAttribute('selected', '')\n } else {\n content.removeAttribute('selected')\n }\n\n if (this._highlighted) {\n content.setAttribute('highlighted', '')\n } else {\n content.removeAttribute('highlighted')\n }\n\n if (this._hidden) {\n content.setAttribute('hidden', '')\n } else {\n content.removeAttribute('hidden')\n }\n }\n }\n}\n\nif (!customElements.get('ty-option')) {\n customElements.define('ty-option', TyOption)\n}\n","/**\n * `error` shows a neutral ty-input, ty-select or ty-date-picker as danger by\n * writing flavor=\"danger\". The flavor attribute it replaced ('' for none) waits\n * in this attribute until the error clears and it goes back. On the element,\n * not in a field: a copy of it (cloneNode, innerHTML, a page snapshot) carries\n * that danger as a plain attribute and must still tell it from the author's.\n */\nexport const ERROR_FLAVOR = 'data-error-flavor'\n","/**\n * Field Size Ladder\n * One source of truth for how `size` scales every field component.\n * Components consume the --ty-field-* vars; nothing hardcodes a size.\n */\n\n/* --ty-field-leading is an even pixel value at every rung, not the matching\n --ty-leading-* token: a single-line field centers its line box inside the\n field height, so an odd line box (--ty-leading-sm is 21px) leaves a half\n pixel that Chrome rounds down and the text sits 1px low. Multi-line text\n (textarea, copy multiline) keeps the real leading tokens.\n\n Base block = the DEFAULT_SIZE ladder rung, because a component left at its\n default never gets a `size` attribute to match on (setProperty reflects,\n defaults don't). :host([size]) rules override it. */\nexport const fieldSizeVars = `\n:host {\n --ty-field-height: var(--ty-size-sm, 2rem);\n --ty-field-pad-x: 10px;\n --ty-field-font: var(--ty-font-sm);\n --ty-field-leading: 20px;\n --ty-field-tracking: var(--ty-tracking-sm);\n --ty-field-label-font: var(--ty-font-xs);\n --ty-field-label-leading: var(--ty-leading-xs);\n --ty-field-label-gap: 5px;\n /* Text that sits OUTSIDE the field box (label, error message) has to line up\n with the value INSIDE it. The value is inset by the wrapper's 1px border\n plus --ty-field-pad-x; outside text only ever cleared the padding, so it\n started exactly 1px to the left of the value it labelled — at every rung,\n on every field. Resolved per rung: the calc reads whichever --ty-field-pad-x\n is winning on the host. */\n --ty-field-outer-pad-x: calc(var(--ty-field-pad-x) + 1px);\n --ty-field-control: 24px;\n --ty-field-icon: 16px;\n}\n\n:host([size=\"xs\"]) {\n --ty-field-height: var(--ty-size-xs, 1.75rem);\n --ty-field-pad-x: 8px;\n --ty-field-font: var(--ty-font-xs);\n --ty-field-leading: 16px;\n --ty-field-tracking: var(--ty-tracking-xs);\n --ty-field-label-font: var(--ty-font-xs);\n --ty-field-label-leading: var(--ty-leading-xs);\n --ty-field-label-gap: 4px;\n --ty-field-control: 20px;\n --ty-field-icon: 14px;\n}\n\n:host([size=\"md\"]) {\n --ty-field-height: var(--ty-size-md, 2.25rem);\n --ty-field-pad-x: 12px;\n --ty-field-font: var(--ty-font-sm);\n --ty-field-leading: 20px;\n --ty-field-tracking: var(--ty-tracking-sm);\n --ty-field-label-font: var(--ty-font-sm);\n --ty-field-label-leading: var(--ty-leading-sm);\n --ty-field-label-gap: 6px;\n --ty-field-control: 28px;\n --ty-field-icon: 18px;\n}\n\n:host([size=\"lg\"]) {\n --ty-field-height: var(--ty-size-lg, 2.5rem);\n --ty-field-pad-x: 14px;\n --ty-field-font: var(--ty-font-base);\n --ty-field-leading: 24px;\n --ty-field-tracking: var(--ty-tracking-base);\n --ty-field-label-font: var(--ty-font-sm);\n --ty-field-label-leading: var(--ty-leading-sm);\n --ty-field-label-gap: 6px;\n --ty-field-control: 32px;\n --ty-field-icon: 20px;\n}\n\n:host([size=\"xl\"]) {\n --ty-field-height: var(--ty-size-xl, 2.75rem);\n --ty-field-pad-x: 16px;\n --ty-field-font: var(--ty-font-lg);\n --ty-field-leading: 28px;\n --ty-field-tracking: var(--ty-tracking-base);\n --ty-field-label-font: var(--ty-font-base);\n --ty-field-label-leading: var(--ty-leading-base);\n --ty-field-label-gap: 8px;\n --ty-field-control: 36px;\n --ty-field-icon: 22px;\n}\n\n/* Narrow viewports drop the two biggest rungs one step — same ladder, no\n component-specific overrides.\n\n A stepped-down rung must carry the WHOLE rung: --ty-field-control is the\n in-field button box (ty-copy's copy button, the date-picker's icon), and it\n sets the wrapper's content height. Leave it at the original rung and the\n field ends up taller than --ty-field-height — the ladder silently breaks on\n exactly one component. */\n@media (max-width: 640px) {\n :host([size=\"lg\"]) {\n --ty-field-height: var(--ty-size-md, 2.25rem);\n --ty-field-pad-x: 12px;\n --ty-field-font: var(--ty-font-sm);\n --ty-field-leading: 20px;\n --ty-field-control: 28px;\n --ty-field-icon: 18px;\n }\n\n :host([size=\"xl\"]) {\n --ty-field-height: var(--ty-size-lg, 2.5rem);\n --ty-field-pad-x: 14px;\n --ty-field-font: var(--ty-font-base);\n --ty-field-leading: 24px;\n --ty-field-control: 32px;\n --ty-field-icon: 20px;\n }\n}\n\n@media (max-width: 480px) {\n :host([size=\"xl\"]) {\n --ty-field-height: var(--ty-size-md, 2.25rem);\n --ty-field-pad-x: 12px;\n --ty-field-font: var(--ty-font-sm);\n --ty-field-leading: 20px;\n --ty-field-control: 28px;\n --ty-field-icon: 18px;\n }\n}\n`\n","/** Input Component Styles */\n\nimport { FLAVORS } from \"../types/common.js\";\nimport { fieldSizeVars } from \"./field-size.js\";\n\n/* Flavor rules only set --input-accent (border), --input-accent-bold\n (hover/focus border), and --input-ring (focus shadow); the wrapper base\n rules consume them. They double as the per-instance override API:\n `ty-input { --input-accent: … }`. Neutral is skipped — it IS the default\n chrome (--ty-input-* tokens), and input's auto-danger-on-error logic\n relies on neutral being the unstyled state.\n\n Fallback flavor `fb` is used for custom flavors: suffixed tokens fall\n back to the custom base color first (a flavor defining only\n --ty-color-X still gets sensible hover/focus), then to neutral.\n\n Emphasis ladder mirrors the neutral chrome (faint rest → soft hover →\n focus + ring): a flavored field rests on its -soft shade and only\n escalates to the full color on hover/focus — a resting field shouldn't\n shout its full-saturation border (tones shift the whole ladder). */\nconst inputFlavor = (f: string, fb?: string) => {\n const c = (s: string) =>\n fb\n ? s\n ? `var(--ty-color-${f}${s}, var(--ty-color-${f}, var(--ty-color-${fb}${s})))`\n : `var(--ty-color-${f}, var(--ty-color-${fb}))`\n : s\n ? `var(--ty-color-${f}${s}, var(--ty-color-${f}))`\n : `var(--ty-color-${f})`;\n return `\n:host([flavor=\"${f}\"]) {\n --input-accent: var(--ty-input-${f}-border, ${c(\"-soft\")});\n --input-accent-bold: ${c(\"\")};\n --input-ring: color-mix(in oklab, ${c(\"\")} 15%, transparent);\n}\n:host([flavor=\"${f}+\"]) {\n --input-accent: ${c(\"\")};\n --input-accent-bold: ${c(\"-strong\")};\n --input-ring: color-mix(in oklab, ${c(\"-strong\")} 15%, transparent);\n}\n:host([flavor=\"${f}-\"]) {\n --input-accent: ${c(\"-faint\")};\n --input-accent-bold: ${c(\"-soft\")};\n --input-ring: color-mix(in oklab, ${c(\"-soft\")} 15%, transparent);\n}\n`;\n};\n\n/** Rules for one custom (non-built-in) flavor — see utils/flavor-sheet.ts. */\nexport const inputCustomFlavorCss = (base: string) => inputFlavor(base, \"neutral\");\n\nexport const inputStyles = `\n${fieldSizeVars}\n:host {\n display: block;\n font-family: inherit;\n width: 100%;\n}\n\n.input-container {\n display: flex;\n flex-direction: column;\n width: 100%;\n box-sizing: border-box;\n}\n\n.ty-field-label {\n font-size: var(--ty-field-label-font);\n line-height: var(--ty-field-label-leading);\n letter-spacing: var(--ty-tracking-sm);\n font-weight: var(--ty-font-medium);\n color: var(--ty-label-color);\n margin-bottom: var(--ty-field-label-gap);\n padding-left: var(--ty-field-outer-pad-x);\n display: flex;\n align-items: center;\n}\n\n.required-icon {\n display: inline-flex;\n align-items: center;\n color: var(--ty-color-danger);\n width: 12px;\n height: 12px;\n margin-left: 4px;\n vertical-align: middle;\n}\n\n.required-icon svg {\n width: 100%;\n height: 100%;\n}\n\n.input-wrapper {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n width: 100%;\n box-sizing: border-box;\n border: 1px solid var(--input-accent, var(--input-border, var(--ty-input-border)));\n border-radius: var(--ty-radius-base);\n background: var(--input-bg, var(--input-bg, var(--ty-input-bg)));\n transition: var(--ty-local-transition, all 0.15s ease-in-out);\n\n min-height: var(--ty-field-height);\n padding: 0 var(--ty-field-pad-x);\n}\n\n/* Wrapper states — --input-accent* are set by the flavor rules below;\n without a flavor attribute they're unset and the default chrome chain\n (per-instance --input-* var, then --ty-input-* token) applies. */\n/* :not(.focused) — hover must never override focus. Without the guard this\n rule out-ranks .focused by specificity, so hovering a FOCUSED unflavored\n input swapped its primary focus border for the dimmer neutral hover\n border (focus ring stayed, border dimmed — read as a glitch). Same\n pattern as date-picker's :hover:not(.open). */\n.input-wrapper:hover:not(.disabled):not(.focused) {\n border-color: var(--input-accent-bold, var(--input-border-hover, var(--ty-input-border-hover)));\n}\n\n.input-wrapper.focused {\n border-color: var(--input-accent-bold, var(--input-border-focus, var(--ty-input-border-focus)));\n box-shadow: 0 0 0 3px var(--input-ring, var(--input-shadow-focus, var(--ty-input-shadow-focus)));\n}\n\n.input-wrapper.disabled {\n cursor: not-allowed;\n opacity: 0.5;\n background: var(--input-disabled-bg, var(--ty-input-disabled-bg));\n border-color: var(--input-disabled-border, var(--ty-input-disabled-border));\n}\n\n::slotted([slot=\"start\"]),\n::slotted([slot=\"end\"]) {\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n color: var(--ty-text-soft);\n}\n\n/* Password reveal toggle (rendered for type=\"password\") */\n.password-toggle {\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n width: 1.25rem;\n height: 1.25rem;\n padding: 0;\n border: none;\n background: none;\n cursor: pointer;\n color: var(--input-placeholder, var(--ty-input-placeholder));\n transition: var(--ty-local-transition, color 0.15s ease-in-out);\n}\n.password-toggle:hover {\n color: var(--input-color, var(--ty-input-color));\n}\n.password-toggle:focus-visible {\n outline: 2px solid var(--input-accent, var(--ty-color-primary));\n outline-offset: 2px;\n border-radius: 2px;\n}\n.password-toggle svg {\n width: 1rem;\n height: 1rem;\n}\n\n::slotted(ty-icon) {\n width: 1em;\n height: 1em;\n flex-shrink: 0;\n}\n\n.error-message {\n font-size: var(--ty-font-xs);\n line-height: var(--ty-leading-xs);\n letter-spacing: var(--ty-tracking-xs);\n color: var(--ty-color-danger);\n margin-top: 4px;\n padding-left: var(--ty-field-outer-pad-x);\n}\n\n.input-wrapper.error {\n border-color: var(--ty-color-danger);\n background: var(--ty-bg-danger-soft);\n}\n\n.input-wrapper.error.focused {\n border-color: var(--ty-color-danger-bold);\n box-shadow: 0 0 0 3px var(--input-shadow-focus, var(--ty-input-shadow-focus));\n}\n\ninput {\n flex: 1;\n min-width: 0;\n box-sizing: border-box;\n border: none;\n outline: none;\n background: transparent;\n color: var(--input-color, var(--ty-input-color));\n font-family: inherit;\n font-size: var(--ty-field-font);\n line-height: var(--ty-field-leading);\n letter-spacing: var(--ty-field-tracking);\n font-weight: var(--ty-font-normal);\n padding: 0;\n margin: 0;\n}\n\n/* Remove number input spinner arrows */\ninput[type=\"number\"]::-webkit-outer-spin-button,\ninput[type=\"number\"]::-webkit-inner-spin-button {\n -webkit-appearance: none;\n margin: 0;\n}\n\ninput[type=\"number\"] {\n -moz-appearance: textfield;\n}\n\ninput:disabled {\n cursor: not-allowed;\n color: var(--input-disabled-color, var(--ty-input-disabled-color));\n}\n\ninput::placeholder {\n color: var(--input-placeholder, var(--ty-input-placeholder));\n font-weight: 400;\n}\n\n/* Semantic flavor modifiers set --input-accent*, consumed above */\n${FLAVORS.filter((f) => f !== \"neutral\").map((f) => inputFlavor(f)).join(\"\")}\n\ninput:focus-visible {\n outline: none;\n}\n\n@media (prefers-contrast: high) {\n .input-wrapper {\n border-width: 2px;\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .input-wrapper {\n transition: none;\n }\n}\n`\n","/**\n * Number Formatting Utilities\n *\n * Uses native Intl.NumberFormat for locale-aware number formatting\n * Supports currency, percent, compact notation, and custom precision\n */\n\nexport type NumberFormatType = 'number' | 'currency' | 'percent' | 'compact'\n\nexport interface FormatConfig {\n type: NumberFormatType\n locale?: string\n currency?: string\n precision?: number\n}\n\n/**\n * Format a number based on configuration\n * \n * @example\n * ```typescript\n * formatNumber(1234.56, { type: 'currency', currency: 'USD', locale: 'en-US' })\n * // Returns: \"$1,234.56\"\n * \n * formatNumber(0.15, { type: 'percent', precision: 2 })\n * // Returns: \"15.00%\"\n * \n * formatNumber(1234567, { type: 'compact' })\n * // Returns: \"1.2M\"\n * ```\n */\nexport function formatNumber(\n value: number,\n config: FormatConfig\n): string {\n const { type, locale = 'en-US', currency = 'USD', precision } = config\n \n const options: Intl.NumberFormatOptions = {}\n \n if (precision !== undefined) {\n options.minimumFractionDigits = precision\n options.maximumFractionDigits = precision\n }\n\n switch (type) {\n case 'currency':\n options.style = 'currency'\n options.currency = currency\n break\n \n case 'percent':\n options.style = 'percent'\n // Note: Intl.NumberFormat expects decimal (0.15 for 15%)\n // We'll handle the division in the input component\n break\n \n case 'compact':\n options.notation = 'compact'\n options.compactDisplay = 'short'\n break\n \n case 'number':\n default:\n options.style = 'decimal'\n break\n }\n \n const formatter = new Intl.NumberFormat(locale, options)\n const formatted = formatter.format(value)\n \n // Normalize Unicode spaces (U+202F narrow no-break, U+2009 thin) to U+00A0 —\n // HTML input elements don't render the exotic ones reliably\n return formatted\n .replace(/\\u202F/g, '\\u00A0') // Narrow no-break space → non-breaking space\n .replace(/\\u2009/g, '\\u00A0') // Thin space → non-breaking space\n}\n\n/**\n * Parse a numeric string to a number\n *\n * Simple rule: the last occurring . or , is the decimal separator.\n * Everything else is stripped. This works for both US (1,234.56) and\n * European (1.234,56) input, and for mobile keyboards that use , as decimal.\n * One grouping exception: a repeated separator (\"1.234.567\") can't be a\n * decimal point, so it's stripped as thousands grouping. A LONE separator is\n * always decimal — \"$1,234\" pasted from formatted text parses as 1.234; this\n * known ambiguity is resolved in favor of typed input (\"12,50\" → 12.5).\n *\n * @example\n * ```typescript\n * parseNumericValue(\"1,234.56\") // 1234.56 (last separator is .)\n * parseNumericValue(\"1.234,56\") // 1234.56 (last separator is ,)\n * parseNumericValue(\"12,50\") // 12.5 (last separator is ,)\n * parseNumericValue(\"12.50\") // 12.5 (last separator is .)\n * parseNumericValue(\"1234\") // 1234\n * parseNumericValue(\"1.234.567\") // 1234567 (repeated separator = grouping)\n * parseNumericValue(\"$1,234\") // 1.234 (lone separator = decimal; known paste ambiguity)\n * parseNumericValue(\"15%\") // 15\n * parseNumericValue(\"\") // null\n * ```\n */\nexport function parseNumericValue(value: string): number | null {\n if (!value || value.trim() === '') return null\n\n // Strip everything except digits, dots, commas, and minus\n let stripped = value\n .replace(/[^\\d.,-]/g, '')\n .trim()\n\n if (stripped === '' || stripped === '-') return null\n\n // Find the last occurring . or , — that's the decimal separator candidate\n const lastComma = stripped.lastIndexOf(',')\n const lastDot = stripped.lastIndexOf('.')\n const lastSep = Math.max(lastComma, lastDot)\n\n if (lastSep === -1) {\n // No separators — pure integer\n const parsed = parseFloat(stripped)\n return isNaN(parsed) ? null : parsed\n }\n\n const sepChar = stripped[lastSep]\n const before = stripped.slice(0, lastSep)\n const after = stripped.slice(lastSep + 1)\n\n // A repeated separator can't be a decimal point — it's thousands grouping\n // (\"1.234.567\" → 1234567). A LONE separator is always treated as decimal:\n // this path parses what the user TYPES (mobile keyboards use , as decimal),\n // so typing wins over the pasted-\"$1,234\" ambiguity.\n if (before.includes(sepChar)) {\n const parsed = parseFloat(stripped.replace(/[.,]/g, ''))\n return isNaN(parsed) ? null : parsed\n }\n\n const intPart = before.replace(/[.,]/g, '')\n const decPart = after\n\n const parsed = parseFloat(intPart + '.' + decPart)\n return isNaN(parsed) ? null : parsed\n}\n\n/**\n * Check if input type requires numeric formatting\n * \n * @example\n * ```typescript\n * shouldFormat('currency') // true\n * shouldFormat('percent') // true\n * shouldFormat('text') // false\n * ```\n */\nexport function shouldFormat(type: string): boolean {\n return ['number', 'currency', 'percent', 'compact'].includes(type)\n}\n\n","/**\n * Locale Resolution Utilities\n *\n * Cascade for resolving locale/language preferences, so developers can set it\n * per-component, per-section, per-page, or fall back to the browser default.\n */\n\n/**\n * Get the effective locale for an element using the resolution cascade.\n * \n * Resolution order:\n * 1. Explicit locale attribute on the element\n * 2. Closest ancestor element with a `lang` attribute\n * 3. Document root element's `lang` attribute\n * 4. Browser's navigator.language\n * 5. Fallback to 'en-US'\n * \n * @param element - The element to get locale for\n * @param explicitLocale - Optional explicit locale value (from component's locale attribute)\n * @returns The resolved locale string (e.g., 'en-US', 'fr-FR')\n * \n * @example\n * ```html\n * <html lang=\"en-US\">\n * <div lang=\"fr-FR\">\n * <ty-input></ty-input> <!-- Uses 'fr-FR' -->\n * <ty-input locale=\"de-DE\"></ty-input> <!-- Uses 'de-DE' -->\n * </div>\n * <ty-input></ty-input> <!-- Uses 'en-US' -->\n * </html>\n * ```\n */\nexport function getEffectiveLocale(\n element: HTMLElement,\n explicitLocale?: string | null\n): string {\n // 1. Explicit locale attribute takes highest priority\n if (explicitLocale) {\n return explicitLocale;\n }\n\n // 2. Check closest ancestor with lang attribute\n // This allows per-section locale overrides\n const langElement = element.closest('[lang]');\n if (langElement) {\n const lang = langElement.getAttribute('lang');\n if (lang) return lang;\n }\n\n // 3. Check document root (html element)\n if (document.documentElement.lang) {\n return document.documentElement.lang;\n }\n\n // 4. Use browser's language preference\n if (navigator.language) {\n return navigator.language;\n }\n\n // 5. Ultimate fallback\n return 'en-US';\n}\n\n/**\n * Create a MutationObserver to watch for lang attribute changes.\n * Useful for components that need to react to dynamic locale changes.\n * \n * @param element - The element to observe\n * @param callback - Function to call when lang changes\n * @returns Cleanup function to disconnect the observer\n * \n * @example\n * ```typescript\n * class TyInput extends HTMLElement {\n * private _localeObserver?: () => void;\n * \n * connectedCallback() {\n * this._localeObserver = observeLocaleChanges(this, () => {\n * this.render(); // Re-render when locale changes\n * });\n * }\n * \n * disconnectedCallback() {\n * this._localeObserver?.();\n * }\n * }\n * ```\n */\nexport function observeLocaleChanges(\n element: HTMLElement,\n callback: (newLocale: string) => void\n): () => void {\n let currentLocale = getEffectiveLocale(element);\n\n const observer = new MutationObserver((mutations) => {\n for (const mutation of mutations) {\n if (mutation.type === 'attributes' && mutation.attributeName === 'lang') {\n const newLocale = getEffectiveLocale(element);\n if (newLocale !== currentLocale) {\n currentLocale = newLocale;\n callback(newLocale);\n }\n }\n }\n });\n\n // subtree: true so any ancestor's lang change is seen\n observer.observe(document.documentElement, {\n attributes: true,\n attributeFilter: ['lang'],\n subtree: true\n });\n\n return () => observer.disconnect();\n}\n","/**\n * Shared inline SVG icons for shadow-DOM components.\n *\n * Kept inline (not the icon registry) because shadow roots must render\n * without registry setup. Styling hooks target the wrapper element\n * (e.g. `.required-icon svg`), never the svg's own classes.\n */\n\n/** Lucide `asterisk` — required-field indicator. */\nexport const REQUIRED_ICON_SVG = `<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M12 6v12\"/><path d=\"M17.196 9 6.804 15\"/><path d=\"m6.804 9 10.392 6\"/></svg>`;\n","/**\n * TyInput Web Component - text input with label, error, icon slots and\n * locale-aware numeric formatting (format-on-blur / raw-on-focus via a parsed\n * \"shadow value\"). Debounce 0-5000ms; blur flushes any pending debounced event.\n */\n\nimport type { Flavor, Size, InputType, TyInputElement } from '../types/common.js'\nimport { DEFAULT_SIZE } from '../types/common.js'\nimport { TyComponent } from '../base/ty-component.js'\nimport type { PropertyChange } from '../utils/property-manager.js'\nimport { ensureStyles } from '../utils/styles.js'\nimport { syncCustomFlavorSheet } from '../utils/flavor-sheet.js'\nimport { ERROR_FLAVOR } from '../utils/error-flavor.js'\nimport { inputStyles, inputCustomFlavorCss } from '../styles/input.js'\nimport {\n formatNumber,\n parseNumericValue,\n shouldFormat as shouldFormatType,\n type FormatConfig\n} from '../utils/number-format.js'\nimport { getEffectiveLocale, observeLocaleChanges } from '../utils/locale.js'\n\nimport { REQUIRED_ICON_SVG } from '../utils/icons.js'\nimport { nativeMessage, nativeValidity, lengthValidity, toLimit } from '../utils/validity.js'\n\n/** Password reveal toggle icons (Lucide eye / eye-off) */\nconst EYE_ICON_SVG = `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M2.062 12.348a1 1 0 0 1 0-.696 10.75 10.75 0 0 1 19.876 0 1 1 0 0 1 0 .696 10.75 10.75 0 0 1-19.876 0\"/><circle cx=\"12\" cy=\"12\" r=\"3\"/></svg>`\nconst EYE_OFF_ICON_SVG = `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M10.733 5.076a10.744 10.744 0 0 1 11.205 6.575 1 1 0 0 1 0 .696 10.747 10.747 0 0 1-1.444 2.49\"/><path d=\"M14.084 14.158a3 3 0 0 1-4.242-4.242\"/><path d=\"M17.479 17.499a10.75 10.75 0 0 1-15.417-5.151 1 1 0 0 1 0-.696 10.75 10.75 0 0 1 4.446-5.143\"/><path d=\"m2 2 20 20\"/></svg>`\n\ninterface InputState {\n // Shadow value - parsed numeric value for formatting\n shadowValue: number | string | null\n\n // Focus state - toggles format/raw display\n isFocused: boolean\n\n // Listener setup tracking\n listenersSetup: boolean\n\n // Event handler references (for cleanup)\n inputHandler: ((e: Event) => void) | null\n changeHandler: ((e: Event) => void) | null\n focusHandler: ((e: Event) => void) | null\n blurHandler: ((e: Event) => void) | null\n\n // Debounce timers\n inputDebounceTimer: number | null\n changeDebounceTimer: number | null\n\n // Locale observer cleanup\n localeObserver?: () => void\n}\n\nexport class TyInput extends TyComponent<InputState> implements TyInputElement {\n static formAssociated = true\n\n // PROPERTY CONFIGURATION - Declarative property lifecycle\n protected static properties = {\n type: {\n type: 'string' as const,\n visual: true,\n default: 'text',\n validate: (v: any) => {\n const validTypes: InputType[] = [\n 'text', 'email', 'password', 'number', 'tel', 'url',\n 'currency', 'percent', 'compact'\n ]\n return validTypes.includes(v)\n },\n coerce: (v: any) => {\n const validTypes: InputType[] = [\n 'text', 'email', 'password', 'number', 'tel', 'url',\n 'currency', 'percent', 'compact'\n ]\n if (!validTypes.includes(v)) {\n console.warn(`[ty-input] Invalid type '${v}'. Using 'text'.`)\n return 'text'\n }\n return v\n }\n },\n value: {\n type: 'string' as const,\n visual: true,\n formValue: true,\n emitChange: true,\n default: ''\n },\n name: {\n type: 'string' as const,\n default: ''\n },\n placeholder: {\n type: 'string' as const,\n visual: true,\n default: ''\n },\n label: {\n type: 'string' as const,\n visual: true,\n default: ''\n },\n disabled: {\n type: 'boolean' as const,\n visual: true,\n default: false\n },\n required: {\n type: 'boolean' as const,\n visual: true,\n default: false\n },\n // Native constraint rules. pattern/minlength/maxlength check text types;\n // min/max check the numeric value of number/currency/percent/compact.\n // Unset ('') means no rule.\n pattern: {\n type: 'string' as const,\n visual: true,\n default: ''\n },\n minlength: {\n type: 'string' as const,\n visual: true,\n default: ''\n },\n maxlength: {\n type: 'string' as const,\n visual: true,\n default: ''\n },\n min: {\n type: 'string' as const,\n visual: true,\n default: ''\n },\n max: {\n type: 'string' as const,\n visual: true,\n default: ''\n },\n // Wording for the length messages; the browser only supplies too-short\n // for typed text (see lengthValidity). Placeholders: {minlength}\n // {maxlength} {length}.\n tooShortMessage: {\n type: 'string' as const,\n visual: true,\n default: ''\n },\n tooLongMessage: {\n type: 'string' as const,\n visual: true,\n default: ''\n },\n error: {\n type: 'string' as const,\n visual: true,\n default: ''\n },\n size: {\n type: 'string' as const,\n visual: true,\n default: DEFAULT_SIZE,\n validate: (v: any) => [\"xs\", \"sm\", \"md\", \"lg\", \"xl\"].includes(v),\n coerce: (v: any) => {\n if (![\"xs\", \"sm\", \"md\", \"lg\", \"xl\"].includes(v)) {\n console.warn(`[ty-input] Invalid size '${v}'. Using '${DEFAULT_SIZE}'.`)\n return DEFAULT_SIZE\n }\n return v\n }\n },\n // Any string is accepted: built-ins get static CSS, other identifiers\n // become custom flavors (see _syncCustomFlavor), garbage degrades to\n // the default look.\n flavor: {\n type: 'string' as const,\n visual: true,\n default: 'neutral'\n },\n currency: {\n type: 'string' as const,\n visual: true,\n default: 'USD'\n },\n locale: {\n type: 'string' as const,\n visual: true,\n default: 'en-US'\n },\n precision: {\n type: 'number' as const,\n visual: true,\n default: undefined,\n validate: (v: any) => {\n if (v === undefined || v === null) return true\n return typeof v === 'number' && v >= 0 && v <= 10\n },\n coerce: (v: any) => {\n if (v === undefined || v === null) return undefined\n const num = Number(v)\n if (isNaN(num)) return undefined\n return Math.max(0, Math.min(10, Math.floor(num)))\n }\n },\n debounce: {\n type: 'number' as const,\n default: 0,\n validate: (v: any) => {\n const num = Number(v)\n return !isNaN(num) && num >= 0 && num <= 5000\n },\n coerce: (v: any) => {\n const num = Number(v)\n if (isNaN(num)) return 0\n return Math.max(0, Math.min(5000, Math.floor(num)))\n }\n }\n }\n\n // INTERNAL STATE - Not managed by PropertyManager\n // NOTE: _internals provided by TyComponent base class\n\n // Shadow value - parsed numeric value for formatting\n private _shadowValue: number | string | null = null\n\n // Focus state - toggles format/raw display\n private _isFocused = false\n\n // Listener setup tracking\n private _listenersSetup = false\n\n private _customFlavorSheet: CSSStyleSheet | null = null\n\n // Store references to handlers for cleanup\n private _inputHandler: ((e: Event) => void) | null = null\n private _changeHandler: ((e: Event) => void) | null = null\n private _focusHandler: ((e: Event) => void) | null = null\n private _blurHandler: ((e: Event) => void) | null = null\n\n // Debounce timers\n private _inputDebounceTimer: number | null = null\n private _changeDebounceTimer: number | null = null\n\n // Locale observer cleanup function\n private _localeObserver?: () => void\n\n constructor() {\n super() // TyComponent handles attachInternals() and attachShadow()\n\n const shadow = this.shadowRoot!\n ensureStyles(shadow, { css: inputStyles, id: 'ty-input' })\n }\n\n /** TyComponent already handled pre-connection property capture. */\n protected onConnect(): void {\n this.initializeShadowValue()\n\n // NOTE: Event listeners are set up in render() after input element is created\n // setupEventListeners() will be called after initial render\n\n // Setup locale observer to watch for ancestor lang changes\n this._localeObserver = observeLocaleChanges(this, () => {\n this.render()\n })\n\n this._syncCustomFlavor()\n this.syncErrorFlavor()\n }\n\n /** Custom (non-built-in) flavors — see utils/flavor-sheet.ts. */\n private _syncCustomFlavor(): void {\n this._customFlavorSheet = syncCustomFlavorSheet(\n this.shadowRoot!,\n this._customFlavorSheet,\n this.flavor,\n ({ base }) => inputCustomFlavorCss(base)\n )\n }\n\n /**\n * `error` turns a neutral field danger; clearing it (the author, or\n * validation dropping the message it showed) puts back exactly the flavor\n * attribute the author had, or none, kept meanwhile in ERROR_FLAVOR (same\n * as ty-select and ty-date-picker). Runs once connected: while the element\n * upgrades, `error` may come before the `flavor` written next to it.\n */\n private syncErrorFlavor(): void {\n if (!this._connected) return\n const flavor = this.getProperty('flavor')\n const replaced = this.getAttribute(ERROR_FLAVOR)\n if (this.getProperty('error')) {\n if (replaced === null && flavor === 'neutral') {\n this.setAttribute(ERROR_FLAVOR, this.getAttribute('flavor') ?? '')\n this.setProperty('flavor', 'danger')\n }\n } else if (replaced !== null) {\n this.removeAttribute(ERROR_FLAVOR)\n if (flavor !== 'danger') return\n if (!replaced) this.removeAttribute('flavor')\n else this.setProperty('flavor', replaced)\n }\n }\n\n protected onDisconnect(): void {\n this.removeEventListeners()\n\n if (this._localeObserver) {\n this._localeObserver()\n this._localeObserver = undefined\n }\n\n if (this._inputDebounceTimer !== null) {\n clearTimeout(this._inputDebounceTimer)\n this._inputDebounceTimer = null\n }\n if (this._changeDebounceTimer !== null) {\n clearTimeout(this._changeDebounceTimer)\n this._changeDebounceTimer = null\n }\n }\n\n // TYCOMPONENT LIFECYCLE HOOKS\n\n /** Handle property changes — called BEFORE render. */\n protected onPropertiesChanged(changes: PropertyChange[]): void {\n for (const { name, newValue } of changes) {\n switch (name) {\n case 'flavor':\n // The author picked a flavor while the error showed: theirs now.\n // Neutral, or none, is no pick: the error shows danger again, the\n // same as when the field starts out that way.\n if (newValue !== 'danger') {\n this.removeAttribute(ERROR_FLAVOR)\n this.syncErrorFlavor()\n }\n this._syncCustomFlavor()\n break\n\n case 'value':\n // Parse to shadow value for numeric types\n this._shadowValue = this.parseShadowValue(newValue || '')\n break\n\n case 'type':\n const currentValue = this.getProperty('value') || ''\n this._shadowValue = this.parseShadowValue(currentValue)\n break\n\n case 'error':\n this.syncErrorFlavor()\n break\n }\n }\n }\n\n protected onFormReset(): void {\n // Base class restored `value` to its attribute-declared default —\n // re-derive the parsed shadow value (and form value) from it.\n this._shadowValue = null\n this.initializeShadowValue()\n\n this._isFocused = false\n\n if (this._inputDebounceTimer !== null) {\n clearTimeout(this._inputDebounceTimer)\n this._inputDebounceTimer = null\n }\n if (this._changeDebounceTimer !== null) {\n clearTimeout(this._changeDebounceTimer)\n this._changeDebounceTimer = null\n }\n this.render()\n }\n\n /**\n * Override form value to return shadow value\n * This ensures numeric types submit their parsed values\n */\n protected getFormValue(): FormDataEntryValue | null {\n const formValue = this._shadowValue !== null ? String(this._shadowValue) : ''\n return formValue\n }\n\n private initializeShadowValue(): void {\n const currentValue = this.getProperty('value')\n if (currentValue) {\n this._shadowValue = this.parseShadowValue(currentValue)\n this._internals.setFormValue(\n this._shadowValue !== null ? String(this._shadowValue) : ''\n )\n } else {\n // Empty still submits name= (like a native input), not nothing\n this._internals.setFormValue('')\n }\n }\n\n private parseShadowValue(value: string): number | string | null {\n // Defensive check: ensure value is actually a string before calling .trim()\n if (!value || typeof value !== 'string' || value.trim() === '') return null\n\n if (shouldFormatType(this.type)) {\n const parsed = parseNumericValue(value)\n if (parsed !== null && this.precision === 0) {\n return Math.round(parsed)\n }\n return parsed\n }\n\n return value\n }\n\n private shouldFormat(): boolean {\n return shouldFormatType(this.type) &&\n !this._isFocused &&\n this._shadowValue !== null &&\n typeof this._shadowValue === 'number'\n }\n\n private getFormatConfig(): FormatConfig {\n return {\n type: this.type as 'number' | 'currency' | 'percent' | 'compact',\n locale: this.locale, // Use getter which calls getEffectiveLocale correctly\n currency: this.currency,\n precision: this.precision\n }\n }\n\n private getDisplayValue(): string {\n if (this.shouldFormat()) {\n let valueToFormat = this._shadowValue as number\n\n // For percent: divide by 100 (user enters 15, displays as 15%)\n if (this.type === 'percent') {\n valueToFormat = valueToFormat / 100\n }\n\n return formatNumber(valueToFormat, this.getFormatConfig())\n }\n\n return this._shadowValue !== null ? String(this._shadowValue) : ''\n }\n\n // PROPERTY ACCESSORS\n\n get type(): InputType { return this.getProperty('type') }\n set type(v: InputType) { this.setProperty('type', v) }\n\n // Value - special getter returns shadow value\n get value(): string {\n return this._shadowValue !== null ? String(this._shadowValue) : ''\n }\n set value(v: string) { this.setProperty('value', v) }\n\n get name(): string { return this.getProperty('name') }\n set name(v: string) { this.setProperty('name', v) }\n\n get placeholder(): string { return this.getProperty('placeholder') }\n set placeholder(v: string) { this.setProperty('placeholder', v) }\n\n get label(): string { return this.getProperty('label') }\n set label(v: string) { this.setProperty('label', v) }\n\n get disabled(): boolean { return this.getProperty('disabled') }\n set disabled(v: boolean) { this.setProperty('disabled', v) }\n\n /** Focus the inner <input>: the host itself isn't focusable. */\n focus(options?: FocusOptions): void {\n (this.shadowRoot?.querySelector('input') as HTMLInputElement | null)?.focus(options)\n }\n\n get required(): boolean { return this.getProperty('required') }\n set required(v: boolean) { this.setProperty('required', v) }\n\n get pattern(): string { return this.getProperty('pattern') }\n set pattern(v: string) { this.setProperty('pattern', v ?? '') }\n\n get minLength(): number { return toLimit(this.getProperty('minlength')) ?? -1 }\n set minLength(v: number) { this.setProperty('minlength', v == null || v < 0 ? '' : String(v)) }\n\n get maxLength(): number { return toLimit(this.getProperty('maxlength')) ?? -1 }\n set maxLength(v: number) { this.setProperty('maxlength', v == null || v < 0 ? '' : String(v)) }\n\n get min(): string { return this.getProperty('min') }\n set min(v: string) { this.setProperty('min', v == null ? '' : String(v)) }\n\n get max(): string { return this.getProperty('max') }\n set max(v: string) { this.setProperty('max', v == null ? '' : String(v)) }\n\n get tooShortMessage(): string { return this.getProperty('tooShortMessage') }\n set tooShortMessage(v: string) { this.setProperty('tooShortMessage', v ?? '') }\n\n get tooLongMessage(): string { return this.getProperty('tooLongMessage') }\n set tooLongMessage(v: string) { this.setProperty('tooLongMessage', v ?? '') }\n\n get error(): string { return this.getProperty('error') }\n set error(v: string) { this.setProperty('error', v) }\n\n get size(): Size { return this.getProperty('size') as Size }\n set size(v: Size) { this.setProperty('size', v) }\n\n get flavor(): Flavor { return this.getProperty('flavor') as Flavor }\n set flavor(v: Flavor) {\n // Even the danger an error already shows: the author's now, so it stays\n // when the error clears\n this.removeAttribute(ERROR_FLAVOR)\n this.setProperty('flavor', v)\n }\n\n attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void {\n // Same for flavor=\"danger\" written over that danger (React 18 sets props\n // as attributes): the base skips a write that changes nothing.\n if (name === 'flavor' && newValue === 'danger' && oldValue === newValue) this.removeAttribute(ERROR_FLAVOR)\n super.attributeChangedCallback(name, oldValue, newValue)\n }\n\n get currency(): string { return this.getProperty('currency') }\n set currency(v: string) { this.setProperty('currency', v) }\n\n // Locale - special getter uses getEffectiveLocale()\n get locale(): string {\n return getEffectiveLocale(this, this.getProperty('locale'))\n }\n set locale(v: string) { this.setProperty('locale', v) }\n\n get precision(): number | undefined { return this.getProperty('precision') }\n set precision(v: number | string | undefined) { this.setProperty('precision', v) }\n\n get debounce(): number { return this.getProperty('debounce') }\n set debounce(v: number | string) { this.setProperty('debounce', v) }\n\n get form(): HTMLFormElement | null {\n return this._internals.form\n }\n\n private buildClassList(): string {\n const classes: string[] = []\n\n if (this.disabled) classes.push('disabled')\n if (this.required) classes.push('required')\n if (this.error) classes.push('error')\n\n return classes.join(' ')\n }\n\n private dispatchInputEvent(rawValue: string, originalEvent: Event): void {\n this.dispatchEvent(new CustomEvent('input', {\n detail: {\n value: this._shadowValue,\n formattedValue: this.shouldFormat() ? this.getDisplayValue() : null,\n rawValue: rawValue,\n originalEvent: originalEvent\n },\n bubbles: true,\n composed: true\n }))\n }\n\n private dispatchChangeEvent(rawValue: string, originalEvent: Event): void {\n this.dispatchEvent(new CustomEvent('change', {\n detail: {\n value: this._shadowValue,\n formattedValue: this.shouldFormat() ? this.getDisplayValue() : null,\n rawValue: rawValue,\n originalEvent: originalEvent\n },\n bubbles: true,\n composed: true\n }))\n }\n\n private removeEventListeners(): void {\n if (!this._listenersSetup) return\n\n const shadow = this.shadowRoot\n if (!shadow) return\n\n const inputEl = shadow.querySelector('input')\n if (!inputEl) return\n\n if (this._inputHandler) {\n inputEl.removeEventListener('input', this._inputHandler)\n this._inputHandler = null\n }\n\n if (this._changeHandler) {\n inputEl.removeEventListener('change', this._changeHandler)\n this._changeHandler = null\n }\n\n if (this._focusHandler) {\n inputEl.removeEventListener('focus', this._focusHandler)\n this._focusHandler = null\n }\n\n if (this._blurHandler) {\n inputEl.removeEventListener('blur', this._blurHandler)\n this._blurHandler = null\n }\n inputEl.removeEventListener('keydown', this._implicitSubmit)\n\n this._listenersSetup = false\n }\n\n /** IMPORTANT: Only called ONCE, not on every render. */\n /**\n * Enter submits the owning form, like a native input (HTML implicit\n * submission): through the form's default button when it has one (nothing\n * if that button is disabled), otherwise only when this is the form's only\n * text field.\n */\n private _implicitSubmit = (e: KeyboardEvent): void => {\n if (e.key !== 'Enter' || e.isComposing || e.defaultPrevented) return\n const form = this._internals.form\n if (!form) return\n const controls = Array.from(form.elements) as HTMLElement[]\n const isSubmitter = (el: HTMLElement) =>\n (el instanceof HTMLButtonElement && el.type === 'submit') ||\n (el instanceof HTMLInputElement && (el.type === 'submit' || el.type === 'image')) ||\n (el.tagName === 'TY-BUTTON' && !['button', 'reset'].includes(el.getAttribute('type') ?? ''))\n const submitter = controls.find(isSubmitter)\n if (submitter) {\n if ((submitter as HTMLButtonElement).disabled || submitter.hasAttribute('disabled')) return\n e.preventDefault()\n // ty-button handles clicks on its inner <button>\n const target = submitter.tagName === 'TY-BUTTON'\n ? submitter.shadowRoot?.querySelector('button') ?? submitter\n : submitter\n target.click()\n return\n }\n const textFields = controls.filter((el) =>\n el.tagName === 'TY-INPUT' ||\n (el instanceof HTMLInputElement && !['button', 'checkbox', 'radio', 'file', 'hidden', 'image', 'reset', 'submit', 'range', 'color'].includes(el.type)))\n if (textFields.length === 1) {\n e.preventDefault()\n form.requestSubmit()\n }\n }\n\n private setupEventListeners(): void {\n if (this._listenersSetup) {\n return // Already setup\n }\n\n const shadow = this.shadowRoot!\n const inputEl = shadow.querySelector('input')\n const wrapperEl = shadow.querySelector('.input-wrapper')\n\n if (!inputEl || !wrapperEl) {\n console.warn('[TyInput.setupEventListeners] ⚠️ Input element not found!')\n return\n }\n\n\n // Input event - update shadow value and form (with debounce support)\n this._inputHandler = (e: Event) => {\n this._userEdited = true\n\n // Stop native event from propagating - only our custom event should bubble\n e.stopPropagation()\n e.stopImmediatePropagation()\n\n const target = e.target as HTMLInputElement\n const rawValue = target.value\n\n this._shadowValue = this.parseShadowValue(rawValue)\n\n this._internals.setFormValue(\n this._shadowValue !== null ? String(this._shadowValue) : ''\n )\n this.updateValidity()\n\n if (this._inputDebounceTimer !== null) {\n clearTimeout(this._inputDebounceTimer)\n }\n\n if (this.debounce > 0) {\n this._inputDebounceTimer = window.setTimeout(() => {\n // Use current value, not the captured rawValue\n this.dispatchInputEvent(inputEl.value, e)\n this._inputDebounceTimer = null\n }, this.debounce)\n } else {\n this.dispatchInputEvent(rawValue, e)\n }\n }\n\n // Change event (with debounce support)\n this._changeHandler = (e: Event) => {\n // Stop native event from propagating - only our custom event should bubble\n e.stopPropagation()\n e.stopImmediatePropagation()\n\n const target = e.target as HTMLInputElement\n const rawValue = target.value\n\n this._shadowValue = this.parseShadowValue(rawValue)\n\n this._internals.setFormValue(\n this._shadowValue !== null ? String(this._shadowValue) : ''\n )\n this.updateValidity()\n\n if (this._changeDebounceTimer !== null) {\n clearTimeout(this._changeDebounceTimer)\n }\n\n if (this.debounce > 0) {\n this._changeDebounceTimer = window.setTimeout(() => {\n // Use current value, not the captured rawValue\n this.dispatchChangeEvent(inputEl.value, e)\n this._changeDebounceTimer = null\n }, this.debounce)\n } else {\n this.dispatchChangeEvent(rawValue, e)\n }\n }\n\n // Focus event - show raw value for numeric types\n this._focusHandler = (e: Event) => {\n this._isFocused = true\n wrapperEl.classList.add('focused')\n\n // For numeric types, show raw shadow value\n if (shouldFormatType(this.type) && this._shadowValue !== null) {\n inputEl.value = String(this._shadowValue)\n }\n\n this.dispatchEvent(new CustomEvent('focus', {\n detail: { originalEvent: e },\n bubbles: true,\n composed: true\n }))\n }\n\n // Blur event - fire pending debounced events immediately, then show formatted value\n this._blurHandler = (e: Event) => {\n const target = e.target as HTMLInputElement\n const rawValue = target.value\n\n // Fire any pending debounced input event immediately on blur\n if (this._inputDebounceTimer !== null) {\n clearTimeout(this._inputDebounceTimer)\n this._inputDebounceTimer = null\n this.dispatchInputEvent(rawValue, e)\n }\n\n // Fire any pending debounced change event immediately on blur\n if (this._changeDebounceTimer !== null) {\n clearTimeout(this._changeDebounceTimer)\n this._changeDebounceTimer = null\n this.dispatchChangeEvent(rawValue, e)\n }\n\n this._isFocused = false\n wrapperEl.classList.remove('focused')\n\n // Like native :user-invalid: once edited, leaving the field shows its message\n if (this._userEdited) this.revealValidity()\n\n // For numeric types, show formatted value\n if (this.shouldFormat()) {\n inputEl.value = this.getDisplayValue()\n }\n\n this.dispatchEvent(new CustomEvent('blur', {\n detail: { originalEvent: e },\n bubbles: true,\n composed: true\n }))\n }\n\n inputEl.addEventListener('input', this._inputHandler)\n inputEl.addEventListener('change', this._changeHandler)\n inputEl.addEventListener('focus', this._focusHandler)\n inputEl.addEventListener('blur', this._blurHandler)\n inputEl.addEventListener('keydown', this._implicitSubmit)\n\n this._listenersSetup = true\n }\n\n /** Render the input component with wrapper and slots. */\n render(): void {\n\n const shadow = this.shadowRoot!\n const existingInput = shadow.querySelector('input')\n const existingWrapper = shadow.querySelector('.input-wrapper')\n const existingLabel = shadow.querySelector('.ty-field-label')\n const existingError = shadow.querySelector('.error-message')\n const classes = this.buildClassList()\n\n // Map input type (all numeric types use 'text' in DOM, others pass through)\n const inputType = ['password', 'email', 'tel', 'url'].includes(this.type)\n ? this.type\n : 'text'\n\n // Set inputmode for mobile keyboard hint\n const inputMode = shouldFormatType(this.type) ? 'decimal'\n : this.type === 'email' ? 'email'\n : this.type === 'tel' ? 'tel'\n : this.type === 'url' ? 'url'\n : undefined\n\n const displayValue = this.getDisplayValue()\n\n // If input exists, just update properties\n if (existingInput && existingWrapper) {\n\n existingInput.type = inputType\n // Only on a real change: any write marks the value as set by script,\n // and the inner input then stops reporting tooShort (updateValidity).\n if (existingInput.value !== displayValue) existingInput.value = displayValue\n existingInput.placeholder = this.placeholder\n existingInput.name = this.name\n if (inputMode) existingInput.inputMode = inputMode\n else existingInput.removeAttribute('inputmode')\n\n existingWrapper.className = `input-wrapper ${classes}`\n\n // Set disabled property AND manage attribute\n existingInput.disabled = this.disabled\n if (this.disabled) {\n existingInput.setAttribute('disabled', '')\n } else {\n existingInput.removeAttribute('disabled')\n }\n\n // Set required property AND manage attribute\n existingInput.required = this.required\n if (this.required) {\n existingInput.setAttribute('required', '')\n } else {\n existingInput.removeAttribute('required')\n }\n\n this.syncConstraintAttributes(existingInput)\n\n // a11y: the shadow <label> isn't programmatically linked to this input,\n // so give the control an accessible name directly.\n if (this.label) existingInput.setAttribute('aria-label', this.label)\n else existingInput.removeAttribute('aria-label')\n\n // ===== BUG FIX: Dynamic label creation =====\n if (this.label) {\n if (existingLabel) {\n existingLabel.innerHTML = `${this.label}${this.required ? `<span class=\"required-icon\">${REQUIRED_ICON_SVG}</span>` : ''}`\n ; (existingLabel as HTMLElement).style.display = 'flex'\n } else {\n // Label doesn't exist but we need one - CREATE IT!\n const labelEl = document.createElement('label')\n labelEl.className = 'ty-field-label'\n labelEl.innerHTML = `${this.label}${this.required ? `<span class=\"required-icon\">${REQUIRED_ICON_SVG}</span>` : ''}`\n\n // Insert label BEFORE the input-wrapper\n const container = shadow.querySelector('.input-container')\n if (container) {\n container.insertBefore(labelEl, existingWrapper)\n }\n }\n } else if (existingLabel) {\n ; (existingLabel as HTMLElement).style.display = 'none'\n }\n\n if (this.error) {\n if (existingError) {\n existingError.textContent = this.error\n } else {\n const errorEl = document.createElement('div')\n errorEl.className = 'error-message'\n errorEl.textContent = this.error\n shadow.querySelector('.input-container')?.appendChild(errorEl)\n }\n } else if (existingError) {\n existingError.remove()\n }\n } else {\n\n const labelHtml = this.label ? `\n <label class=\"ty-field-label\">\n ${this.label}\n ${this.required ? `<span class=\"required-icon\">${REQUIRED_ICON_SVG}</span>` : ''}\n </label>\n ` : ''\n\n const errorHtml = this.error ? `\n <div class=\"error-message\">${this.error}</div>\n ` : ''\n\n shadow.innerHTML = `\n <div class=\"input-container\">\n ${labelHtml}\n <div class=\"input-wrapper ${classes}\">\n <slot name=\"start\"></slot>\n <input\n type=\"${inputType}\"\n value=\"${displayValue}\"\n placeholder=\"${this.placeholder}\"\n name=\"${this.name}\"\n ${inputMode ? `inputmode=\"${inputMode}\"` : ''}\n />\n <slot name=\"end\"></slot>\n ${inputType === 'password' ? `\n <button class=\"password-toggle\" type=\"button\"\n aria-label=\"Show password\" aria-pressed=\"false\">\n ${EYE_ICON_SVG}\n </button>` : ''}\n </div>\n ${errorHtml}\n </div>\n `\n\n const inputEl = shadow.querySelector('input')!\n inputEl.disabled = this.disabled\n inputEl.required = this.required\n this.syncConstraintAttributes(inputEl)\n if (this.label) inputEl.setAttribute('aria-label', this.label) // a11y: name the control\n\n this.setupPasswordToggle()\n\n // Setup event listeners ONCE\n this.setupEventListeners()\n }\n\n // Reflect constraint validation (required, etc.) to the owning <form>.\n this.updateValidity()\n }\n\n /**\n * Wire the password reveal toggle (rendered only for type=\"password\").\n * Toggles the NATIVE input's type between password/text — the component's\n * `type` property stays \"password\" (form value and API unaffected).\n */\n private setupPasswordToggle(): void {\n const shadow = this.shadowRoot!\n const toggle = shadow.querySelector('.password-toggle') as HTMLButtonElement | null\n const inputEl = shadow.querySelector('input')\n if (!toggle || !inputEl) return\n\n // Keep focus in the input while clicking the toggle\n toggle.addEventListener('mousedown', (e) => e.preventDefault())\n toggle.addEventListener('click', () => {\n const reveal = inputEl.type === 'password'\n inputEl.type = reveal ? 'text' : 'password'\n toggle.innerHTML = reveal ? EYE_OFF_ICON_SVG : EYE_ICON_SVG\n toggle.setAttribute('aria-label', reveal ? 'Hide password' : 'Show password')\n toggle.setAttribute('aria-pressed', String(reveal))\n })\n }\n\n /**\n * pattern, minlength and maxlength go on the inner <input>: pattern for the\n * browser's own patternMismatch check, minlength for its tooShort message\n * after the user types, maxlength so typing stops at the limit like a\n * native field. Formatted (numeric) types show a display string, so they\n * get none.\n */\n private syncConstraintAttributes(inputEl: HTMLInputElement): void {\n const text = !shouldFormatType(this.type)\n const set = (name: string, v: string) =>\n text && v !== '' ? inputEl.setAttribute(name, v) : inputEl.removeAttribute(name)\n set('pattern', this.pattern)\n set('minlength', toLimit(this.getProperty('minlength')) != null ? String(this.minLength) : '')\n set('maxlength', toLimit(this.getProperty('maxlength')) != null ? String(this.maxLength) : '')\n }\n\n /**\n * Reflect constraint validation to the owning <form> via ElementInternals.\n * Without this the inner shadow <input> can't block the outer form.\n * Rules, first failing one supplies the message:\n * - required: empty => valueMissing\n * - email/url: the inner input's own typeMismatch\n * - text types: pattern, minlength, maxlength\n * - number/currency/percent/compact: min, max against the numeric value\n * Empty values only fail `required`, like native inputs.\n * Disabled fields are barred from constraint validation.\n */\n private updateValidity(): void {\n const inputEl = this.shadowRoot?.querySelector('input') as HTMLInputElement | null\n if (this.disabled) {\n this.applyValidity({})\n return\n }\n const current = inputEl ? inputEl.value : String(this.getProperty('value') ?? '')\n if (current.trim() === '') {\n if (this.required) {\n this.applyValidity({ valueMissing: true }, nativeMessage('input', { type: 'text', required: true }), inputEl ?? undefined)\n } else {\n this.applyValidity({})\n }\n return\n }\n\n const flags: ValidityStateFlags = {}\n const messages: string[] = []\n const fail = (flag: keyof ValidityStateFlags, message: string) => {\n flags[flag] = true\n messages.push(message)\n }\n\n if (shouldFormatType(this.type)) {\n // A native number input judges min/max: it parses them (' 5 ' or\n // '0x10' is no rule at all) and words the message, so the flag and\n // the message can't disagree.\n const n = typeof this._shadowValue === 'number' ? this._shadowValue : null\n if (n !== null && (this.min || this.max)) {\n const { validity, message } = nativeValidity('input', { type: 'number', step: 'any', min: this.min, max: this.max }, String(n))\n if (validity.rangeUnderflow) fail('rangeUnderflow', message)\n if (validity.rangeOverflow) fail('rangeOverflow', message)\n }\n } else {\n if (inputEl?.validity.typeMismatch) fail('typeMismatch', inputEl.validationMessage)\n if (inputEl?.validity.patternMismatch) fail('patternMismatch', inputEl.validationMessage)\n const { tooShort, tooLong } = lengthValidity(current, {\n minlength: this.getProperty('minlength'),\n maxlength: this.getProperty('maxlength'),\n tooShortMessage: this.tooShortMessage,\n tooLongMessage: this.tooLongMessage,\n }, inputEl)\n if (tooShort) fail('tooShort', tooShort)\n if (tooLong) fail('tooLong', tooLong)\n }\n\n this.applyValidity(flags, messages[0], inputEl ?? undefined)\n }\n}\n\nif (!customElements.get('ty-input')) {\n customElements.define('ty-input', TyInput)\n}\n","/**\n * Checkbox Component Styles — self-contained (no inputStyles import).\n *\n * The checkbox is \"just the tick\": a single checkmark whose color/opacity\n * carries the state. Full flavor color when checked, faint when unchecked,\n * dash at mid-opacity when indeterminate, grayscale when disabled.\n */\n\nimport { FLAVORS } from \"../types/common.js\";\n\n/* Flavor rules only set --checkbox-color (checked) / --checkbox-ring (focus\n ring). Unchecked stays neutral for every flavor — a tinted unchecked tick\n was the dimmest thing on the page. The base rules below consume\n them. Doubles as the per-instance override API: `ty-checkbox {\n --checkbox-color: … }`. --checkbox-ring pre-resolves the color-mix() here\n (rather than inlining a nested var(...,fallback) as a color-mix argument\n directly in the box-shadow rule) — that nested form fails at\n computed-value time in some engines. Fallback flavor `fb` is used for\n custom flavors so missing tokens degrade to neutral. */\nconst checkboxFlavor = (f: string, fb?: string) => {\n const tok = (s: string) =>\n fb\n ? `var(--ty-color-${f}${s}, var(--ty-color-${fb}${s}))`\n : `var(--ty-color-${f}${s})`;\n return `\n:host([flavor=\"${f}\"]) { --checkbox-color: ${tok(\"-strong\")}; --checkbox-ring: color-mix(in oklab, ${tok(\"\")} 25%, transparent); }\n:host([flavor=\"${f}+\"]) { --checkbox-color: ${tok(\"-strong\")}; --checkbox-ring: color-mix(in oklab, ${tok(\"-strong\")} 25%, transparent); }\n:host([flavor=\"${f}-\"]) { --checkbox-color: ${tok(\"\")}; --checkbox-ring: color-mix(in oklab, ${tok(\"\")} 25%, transparent); }\n`;\n};\n\n/** Rules for one custom (non-built-in) flavor — see utils/flavor-sheet.ts. */\nexport const checkboxCustomFlavorCss = (base: string) => checkboxFlavor(base, \"neutral\");\n\nexport const checkboxStyles = `\n:host {\n display: inline-flex;\n width: auto;\n vertical-align: middle;\n}\n\n.checkbox-container {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n /* One line box of the surrounding text (inherited line-height), tick\n centered in it: next to a <label> the tick sits on the first line's\n middle instead of 2px high (a 16px box top-aligned with a 20px line). */\n min-height: 1.25em;\n min-height: 1lh;\n outline: none;\n transition: var(--ty-local-transition, all 0.15s ease-in-out);\n user-select: none;\n cursor: pointer;\n border-radius: 6px;\n gap: var(--ty-spacing-1);\n /* Default (no flavor attribute) is neutral — defaults don't reflect to the\n host attribute, so the fallbacks here carry the default look. */\n /* Unchecked: faint neutral tick (30% of body text) so it recedes\n next to the label; checked jumps to full body text. */\n color: var(--checkbox-color-off, color-mix(in oklab, var(--ty-text) 30%, transparent));\n /* Room for the hover pill, inside the one-line height (border-box). */\n box-sizing: border-box;\n padding: 2px;\n border-radius: 5px;\n}\n\n.checkbox-container:hover {\n background: var(--checkbox-hover-bg, color-mix(in oklab, var(--ty-text) 8%, transparent));\n}\n\n/* Hover previews the tick, but stays well short of checked (100%): at 80%\n a hovered unchecked box read as already checked. The pill carries the\n hover feedback; the tick only hints. */\n.checkbox-container:not([aria-checked=\"true\"]):not([aria-checked=\"mixed\"]):hover {\n color: var(--checkbox-color-off-hover, color-mix(in oklab, var(--ty-text) 50%, transparent));\n}\n\n/* Checked is the flavor's STRONG tone (neutral: body text) so it sits far\n from the mid-tone unchecked tick in lightness, not only in hue. */\n.checkbox-container[aria-checked=\"true\"] {\n color: var(--checkbox-color, var(--ty-text));\n}\n\n/* Visible focus ring (keyboard) — .focused is toggled by the component.\n Matches the checked-state color so a danger checkbox gets a red ring,\n not a fixed primary one. */\n.checkbox-container.focused,\n.checkbox-container:focus-visible {\n box-shadow: 0 0 0 3px var(--checkbox-ring, color-mix(in oklab, var(--ty-color-primary) 25%, transparent));\n}\n\n.checkbox-icon {\n display: flex;\n align-items: center;\n justify-content: center;\n color: inherit;\n transition: var(--ty-local-transition, color 0.15s ease-in-out);\n pointer-events: none;\n /* Let the container handle the click */\n}\n\n.checkbox-container svg {\n width: 16px;\n height: 16px;\n}\n\n.checkbox-container.xs svg {\n width: 12px;\n height: 12px;\n}\n\n.checkbox-container.sm svg {\n width: 14px;\n height: 14px;\n}\n\n.checkbox-container.lg svg {\n width: 20px;\n height: 20px;\n}\n\n.checkbox-container.xl svg {\n width: 24px;\n height: 24px;\n}\n\n/* Semantic flavors set --checkbox-color[-off], consumed above */\n${FLAVORS.map((f) => checkboxFlavor(f)).join(\"\")}\n\n/* Clean tick: no box, just the mark. Checked and mixed carry the flavor\n color; unchecked is the neutral tick set on the container above. */\n.checkbox-container[aria-checked=\"mixed\"] {\n color: var(--checkbox-color, var(--ty-text));\n}\n\n/* Disabled must stay distinguishable from merely-unchecked: grayscale kills\n the flavor color, and disabled-unchecked drops below the unchecked 0.35. */\n.checkbox-container.disabled {\n pointer-events: none;\n cursor: not-allowed;\n opacity: 0.5;\n filter: grayscale(1);\n}\n\n.checkbox-container.disabled:not([aria-checked=\"true\"]) {\n opacity: 0.45;\n}\n\n.checkbox-container.disabled:hover {\n background: none;\n}\n\n.checkbox-container.error .checkbox-icon {\n color: var(--ty-color-danger);\n}\n\n.checkbox-container.error:focus {\n box-shadow: 0 0 0 3px color-mix(in oklab, var(--ty-color-danger) 15%, transparent);\n}\n`;\n","/**\n * TyCheckbox Web Component — \"just the box\" primitive: renders only the\n * checkbox visual + state. Label, required asterisk and error display are the\n * consumer's responsibility — wrap in a `<label>` for click delegation.\n */\n\nimport type { Flavor, Size } from \"../types/common.js\";\nimport { DEFAULT_SIZE } from \"../types/common.js\";\nimport { TyComponent } from \"../base/ty-component.js\";\nimport type { PropertyChange } from \"../utils/property-manager.js\";\nimport { ensureStyles } from \"../utils/styles.js\";\nimport { syncCustomFlavorSheet } from \"../utils/flavor-sheet.js\";\nimport { checkboxStyles, checkboxCustomFlavorCss } from \"../styles/checkbox.js\";\nimport { nativeMessage } from \"../utils/validity.js\";\n\n/**\n * Component internal state (for typing TyComponent)\n */\ninterface CheckboxState {\n checked: boolean;\n listenersSetup: boolean;\n}\n\n/**\n * Checkmark icon (Lucide `check`, same glyph as ty-option's selected check;\n * stroke-width 3 for presence at 16px — it replaces a heavy fill glyph).\n * Same glyph for checked and unchecked — checked shows it at full color,\n * unchecked at faint color (see styles).\n */\nconst CHECK_ICON = `<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"3\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M20 6 9 17l-5-5\"/></svg>`;\n\n/**\n * Dash icon (Lucide `minus`) — shown while indeterminate.\n */\nconst DASH_ICON = `<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"3\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M5 12h14\"/></svg>`;\n\n/**\n * TyCheckbox Element Interface\n */\nexport interface TyCheckboxElement extends HTMLElement {\n checked: boolean;\n indeterminate: boolean;\n value: string;\n name: string;\n disabled: boolean;\n required: boolean;\n size: Size;\n flavor: Flavor;\n form: HTMLFormElement | null;\n}\n\n/**\n * Ty Checkbox Component\n */\nexport class TyCheckbox\n extends TyComponent<CheckboxState>\n implements TyCheckboxElement\n{\n static formAssociated = true;\n\n protected static properties = {\n checked: {\n type: \"boolean\" as const,\n visual: true,\n formValue: true,\n emitChange: true,\n default: false,\n },\n // Visual/ARIA \"mixed\" state (native semantics: no form-value effect,\n // clicking resolves to checked)\n indeterminate: {\n type: \"boolean\" as const,\n visual: true,\n default: false,\n },\n // Form submission value (when checked)\n value: {\n type: \"string\" as const,\n default: \"on\",\n },\n name: {\n type: \"string\" as const,\n default: \"\",\n },\n disabled: {\n type: \"boolean\" as const,\n visual: true,\n default: false,\n },\n required: {\n type: \"boolean\" as const,\n visual: true,\n default: false,\n },\n size: {\n type: \"string\" as const,\n visual: true,\n default: DEFAULT_SIZE,\n validate: (v: any) => [\"xs\", \"sm\", \"md\", \"lg\", \"xl\"].includes(v),\n coerce: (v: any) => {\n if (![\"xs\", \"sm\", \"md\", \"lg\", \"xl\"].includes(v)) {\n console.warn(`[ty-checkbox] Invalid size '${v}'. Using '${DEFAULT_SIZE}'.`);\n return DEFAULT_SIZE;\n }\n return v;\n },\n },\n // Any string is accepted: built-ins get static CSS, other identifiers\n // become custom flavors (see _syncCustomFlavor), garbage degrades to\n // the default look.\n flavor: {\n type: \"string\" as const,\n visual: true,\n default: \"neutral\",\n },\n };\n\n // Internal state, not managed by PropertyManager\n // (_internals is provided by the TyComponent base class)\n private _customFlavorSheet: CSSStyleSheet | null = null;\n private _listenersSetup: boolean = false;\n\n // Store references to handlers for cleanup\n private _clickHandler: ((e: Event) => void) | null = null;\n private _keydownHandler: ((e: Event) => void) | null = null;\n private _focusHandler: (() => void) | null = null;\n private _blurHandler: (() => void) | null = null;\n\n constructor() {\n super(); // TyComponent handles attachInternals() and attachShadow()\n\n const shadow = this.shadowRoot!;\n ensureStyles(shadow, { css: checkboxStyles, id: \"ty-checkbox\" });\n }\n\n // observedAttributes auto-generated by TyComponent from properties config\n\n /** TyComponent already handled pre-connection property capture. */\n protected onConnect(): void {\n // Re-arm listeners on RE-connect: the base class skips render() when\n // already rendered, and onDisconnect removed the listeners. No-ops on\n // first connect (no container yet — render() attaches them).\n this.setupEventListeners();\n this._syncCustomFlavor();\n }\n\n /** Custom (non-built-in) flavors — see utils/flavor-sheet.ts. */\n private _syncCustomFlavor(): void {\n this._customFlavorSheet = syncCustomFlavorSheet(\n this.shadowRoot!,\n this._customFlavorSheet,\n this.flavor,\n ({ base }) => checkboxCustomFlavorCss(base),\n );\n }\n\n protected onDisconnect(): void {\n this.removeEventListeners();\n }\n\n /**\n * Handle property changes - called BEFORE render\n */\n protected onPropertiesChanged(changes: PropertyChange[]): void {\n if (changes.some((c) => c.name === \"flavor\")) {\n this._syncCustomFlavor();\n }\n }\n\n /**\n * Override form value to return value when checked, null when unchecked\n */\n protected getFormValue(): FormDataEntryValue | null {\n return this.checked ? this.value : null;\n }\n\n private buildClassList(): string {\n const classes: string[] = [this.size];\n\n if (this.disabled) classes.push(\"disabled\");\n if (this.required) classes.push(\"required\");\n\n return classes.join(\" \");\n }\n\n private handleCheckboxClick(e: Event): void {\n if (this.disabled) return;\n if (this.isDuplicateActivationClick()) return;\n\n // Native semantics: clicking an indeterminate checkbox resolves to checked\n const newValue = this.indeterminate ? true : !this.checked;\n if (this.indeterminate) this.indeterminate = false;\n this.checked = newValue;\n\n // Emit custom events after property update\n setTimeout(() => {\n const eventDetail = {\n value: newValue,\n checked: newValue,\n formValue: newValue ? this.value : null,\n originalEvent: e,\n };\n\n this.dispatchEvent(\n new CustomEvent(\"input\", {\n detail: eventDetail,\n bubbles: true,\n composed: true,\n }),\n );\n\n this.dispatchEvent(\n new CustomEvent(\"change\", {\n detail: eventDetail,\n bubbles: true,\n composed: true,\n }),\n );\n }, 0);\n }\n\n private handleCheckboxKeydown(e: KeyboardEvent): void {\n if (this.disabled) return;\n\n if ([\"Space\", \" \", \"Enter\"].includes(e.key)) {\n e.preventDefault(); // Prevent default for keyboard to avoid page scroll\n e.stopPropagation();\n this.handleCheckboxClick(e);\n }\n }\n\n private removeEventListeners(): void {\n if (!this._listenersSetup) return;\n\n // Click lives on the HOST (label delegation + full-element trigger) —\n // remove it before the shadow-container guard below.\n if (this._clickHandler) {\n this.removeEventListener(\"click\", this._clickHandler);\n this._clickHandler = null;\n }\n\n const shadow = this.shadowRoot;\n if (!shadow) return;\n\n const checkboxEl = shadow.querySelector(\".checkbox-container\");\n if (!checkboxEl) {\n this._listenersSetup = false;\n return;\n }\n\n if (this._keydownHandler) {\n checkboxEl.removeEventListener(\"keydown\", this._keydownHandler);\n this._keydownHandler = null;\n }\n\n if (this._focusHandler) {\n checkboxEl.removeEventListener(\"focus\", this._focusHandler);\n this._focusHandler = null;\n }\n\n if (this._blurHandler) {\n checkboxEl.removeEventListener(\"blur\", this._blurHandler);\n this._blurHandler = null;\n }\n\n this._listenersSetup = false;\n }\n\n /**\n * Setup event listeners for checkbox functionality\n * IMPORTANT: Only called ONCE, not on every render\n */\n private setupEventListeners(): void {\n if (this._listenersSetup) return;\n\n const shadow = this.shadowRoot!;\n const checkboxEl = shadow.querySelector(\".checkbox-container\");\n\n if (!checkboxEl) return;\n\n // Create and store handler references for cleanup\n this._clickHandler = (e: Event) => {\n this.handleCheckboxClick(e);\n };\n\n this._keydownHandler = (e: Event) => {\n this.handleCheckboxKeydown(e as KeyboardEvent);\n };\n\n this._focusHandler = () => {\n checkboxEl.classList.add(\"focused\");\n };\n\n this._blurHandler = () => {\n checkboxEl.classList.remove(\"focused\");\n };\n\n // Click on the HOST: makes the whole element a trigger and lets a wrapping\n // <label> delegate (the synthetic click lands on the host, not the shadow).\n // Keyboard/focus stay on the focusable container.\n this.addEventListener(\"click\", this._clickHandler);\n checkboxEl.addEventListener(\"keydown\", this._keydownHandler);\n checkboxEl.addEventListener(\"focus\", this._focusHandler);\n checkboxEl.addEventListener(\"blur\", this._blurHandler);\n\n this._listenersSetup = true;\n }\n\n /**\n * Render the checkbox — just the box visual.\n * Label, required asterisk, and error UI are the consumer's responsibility.\n */\n protected render(): void {\n const shadow = this.shadowRoot!;\n let checkboxEl = shadow.querySelector(\".checkbox-container\") as HTMLElement;\n const classes = this.buildClassList();\n const ariaChecked = this.indeterminate ? \"mixed\" : String(this.checked);\n\n if (!checkboxEl) {\n checkboxEl = document.createElement(\"div\");\n checkboxEl.className = \"checkbox-container \" + classes;\n checkboxEl.tabIndex = this.disabled ? -1 : 0;\n checkboxEl.setAttribute(\"role\", \"checkbox\");\n checkboxEl.setAttribute(\"aria-checked\", ariaChecked);\n checkboxEl.setAttribute(\"aria-disabled\", String(this.disabled));\n checkboxEl.setAttribute(\"aria-required\", String(this.required));\n\n const checkboxIcon = document.createElement(\"div\");\n checkboxIcon.className = \"checkbox-icon\";\n checkboxEl.appendChild(checkboxIcon);\n\n shadow.appendChild(checkboxEl);\n } else {\n checkboxEl.className = \"checkbox-container \" + classes;\n checkboxEl.tabIndex = this.disabled ? -1 : 0;\n checkboxEl.setAttribute(\"aria-checked\", ariaChecked);\n checkboxEl.setAttribute(\"aria-disabled\", String(this.disabled));\n checkboxEl.setAttribute(\"aria-required\", String(this.required));\n }\n\n // Dash while indeterminate, tick otherwise (tick's color/opacity carries\n // the checked/unchecked distinction via CSS).\n const icon = checkboxEl.querySelector(\".checkbox-icon\")!;\n icon.innerHTML = this.indeterminate ? DASH_ICON : CHECK_ICON;\n\n // (Re)attach listeners — onDisconnect removes them, so a reconnected\n // element needs them again even though the container already exists.\n this.setupEventListeners();\n\n // a11y: role=\"checkbox\" lives on this inner element, but the associated\n // <label> names the (form-associated) host. Mirror that name onto the role\n // element so it has an accessible name.\n this.applyLabelName(checkboxEl);\n\n // Reflect constraint validation to the owning <form> (required was cosmetic).\n this.updateValidity();\n }\n\n /** Focus the checkbox itself (the host is not focusable; its role element is). */\n focus(options?: FocusOptions): void {\n const el = this.shadowRoot?.querySelector(\".checkbox-container\") as HTMLElement | null;\n if (el) el.focus(options);\n else super.focus(options);\n }\n\n /** required + unchecked => valueMissing (the browser's own message); otherwise valid. */\n private updateValidity(): void {\n const anchor = this.shadowRoot?.querySelector(\".checkbox-container\") as HTMLElement | null;\n if (this.disabled) { this.applyValidity({}); return; }\n if (this.required && !this.checked) {\n this.applyValidity(\n { valueMissing: true },\n nativeMessage(\"input\", { type: \"checkbox\", required: true }),\n anchor ?? undefined,\n );\n } else {\n this.applyValidity({});\n }\n }\n\n get checked(): boolean {\n return this.getProperty(\"checked\");\n }\n\n set checked(value: boolean) {\n this.setProperty(\"checked\", value);\n }\n\n get indeterminate(): boolean {\n return this.getProperty(\"indeterminate\");\n }\n\n set indeterminate(value: boolean) {\n this.setProperty(\"indeterminate\", value);\n }\n\n get value(): string {\n return this.getProperty(\"value\");\n }\n\n set value(val: string) {\n this.setProperty(\"value\", val);\n }\n\n get name(): string {\n return this.getProperty(\"name\");\n }\n\n set name(val: string) {\n this.setProperty(\"name\", val);\n }\n\n get disabled(): boolean {\n return this.getProperty(\"disabled\");\n }\n\n set disabled(value: boolean) {\n this.setProperty(\"disabled\", value);\n }\n\n get required(): boolean {\n return this.getProperty(\"required\");\n }\n\n set required(value: boolean) {\n this.setProperty(\"required\", value);\n }\n\n get size(): Size {\n return this.getProperty(\"size\") as Size;\n }\n\n set size(value: Size) {\n this.setProperty(\"size\", value);\n }\n\n get flavor(): Flavor {\n return this.getProperty(\"flavor\") as Flavor;\n }\n\n set flavor(value: Flavor) {\n this.setProperty(\"flavor\", value);\n }\n\n get form(): HTMLFormElement | null {\n return this._internals.form;\n }\n}\n\nif (!customElements.get(\"ty-checkbox\")) {\n customElements.define(\"ty-checkbox\", TyCheckbox);\n}\n\n","/**\n * Switch Component Styles\n * Track + thumb visual, ARIA role=\"switch\".\n *\n * Reuses input-container/error-message rules from input styles for label\n * and error layout consistency.\n */\n\nimport { FLAVORS } from \"../types/common.js\";\nimport { inputStyles } from \"./input.js\";\n\n/* Flavor rules only set --switch-track; the single checked-state rule below\n consumes it. The var doubles as the per-instance override API:\n `ty-switch { --switch-track: … }` (outer-document host rules beat :host).\n Optional fallback flavor `fb` is used for custom flavors so missing\n tokens degrade to neutral instead of an unstyled track. */\nconst switchFlavor = (f: string, fb?: string) => {\n const tok = (s: string) =>\n fb\n ? `var(--ty-color-${f}${s}, var(--ty-color-${fb}${s}))`\n : `var(--ty-color-${f}${s})`;\n return `\n:host([flavor=\"${f}\"]) { --switch-track: ${tok(\"\")}; }\n:host([flavor=\"${f}+\"]) { --switch-track: ${tok(\"-strong\")}; }\n:host([flavor=\"${f}-\"]) { --switch-track: ${tok(\"-soft\")}; }\n`;\n};\n\n/** Rules for one custom (non-built-in) flavor — see utils/flavor-sheet.ts. */\nexport const switchCustomFlavorCss = (base: string) => switchFlavor(base, \"neutral\");\n\nexport const switchStyles = `\n${inputStyles}\n\n/* Override input's :host so the switch sizes to its visual */\n:host {\n display: inline-flex;\n width: auto;\n vertical-align: middle;\n}\n\n/* The switch container is just the visual */\n.switch-container {\n /* One line box of the surrounding text, track centered in it — lines up\n with the first line of a wrapping <label> (same fix as ty-checkbox). */\n display: inline-flex;\n align-items: center;\n min-height: 1.25em;\n min-height: 1lh;\n cursor: pointer;\n user-select: none;\n outline: none;\n vertical-align: middle;\n}\n\n.switch-container.disabled {\n cursor: not-allowed;\n opacity: 0.55;\n}\n\n.switch-container:focus-visible .switch-track,\n.switch-container.focused .switch-track {\n box-shadow: 0 0 0 3px var(--ty-input-shadow-focus);\n}\n\n.switch-track {\n position: relative;\n flex-shrink: 0;\n width: 36px;\n height: 20px;\n border-radius: var(--ty-radius-full, 999px);\n background: var(--ty-color-neutral-soft, var(--ty-input-border));\n transition: var(--ty-local-transition, background-color 0.18s ease-in-out);\n box-sizing: border-box;\n}\n\n.switch-thumb {\n position: absolute;\n top: 2px;\n left: 2px;\n width: 16px;\n height: 16px;\n border-radius: min(50%, var(--ty-radius-full, 50%));\n background: white;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);\n transition: var(--ty-local-transition, transform 0.18s ease-in-out, background-color 0.18s ease-in-out);\n}\n\n/* Default (no flavor attribute) is primary — defaults don't reflect to the\n host attribute, so the base rule's fallback carries the default look. */\n.switch-container[aria-checked=\"true\"] .switch-track {\n background: var(--switch-track, var(--ty-color-primary));\n}\n\n.switch-container[aria-checked=\"true\"] .switch-thumb {\n transform: translateX(16px);\n}\n\n.switch-container.xs .switch-track { width: 26px; height: 14px; }\n.switch-container.xs .switch-thumb { width: 10px; height: 10px; }\n.switch-container.xs[aria-checked=\"true\"] .switch-thumb { transform: translateX(12px); }\n\n.switch-container.sm .switch-track { width: 30px; height: 16px; }\n.switch-container.sm .switch-thumb { width: 12px; height: 12px; }\n.switch-container.sm[aria-checked=\"true\"] .switch-thumb { transform: translateX(14px); }\n\n/* md is default — already set above */\n\n.switch-container.lg .switch-track { width: 44px; height: 24px; }\n.switch-container.lg .switch-thumb { width: 20px; height: 20px; }\n.switch-container.lg[aria-checked=\"true\"] .switch-thumb { transform: translateX(20px); }\n\n.switch-container.xl .switch-track { width: 52px; height: 28px; }\n.switch-container.xl .switch-thumb { width: 24px; height: 24px; }\n.switch-container.xl[aria-checked=\"true\"] .switch-thumb { transform: translateX(24px); }\n\n/* Flavor variants set --switch-track, consumed above */\n${FLAVORS.map((f) => switchFlavor(f)).join(\"\")}\n\n`;\n","/**\n * TySwitch Web Component\n *\n * \"Just the toggle\" primitive — renders only the track + thumb visual.\n * Label, required asterisk, and error display are the consumer's\n * responsibility — wrap in a `<label>` for click delegation.\n */\n\nimport type { Flavor, Size } from \"../types/common.js\";\nimport { DEFAULT_SIZE } from \"../types/common.js\";\nimport { TyComponent } from \"../base/ty-component.js\";\nimport type { PropertyChange } from \"../utils/property-manager.js\";\nimport { ensureStyles } from \"../utils/styles.js\";\nimport { syncCustomFlavorSheet } from \"../utils/flavor-sheet.js\";\nimport { switchStyles, switchCustomFlavorCss } from \"../styles/switch.js\";\nimport { nativeMessage } from \"../utils/validity.js\";\n\ninterface SwitchState {\n checked: boolean;\n listenersSetup: boolean;\n}\n\nexport interface TySwitchElement extends HTMLElement {\n checked: boolean;\n value: string;\n name: string;\n disabled: boolean;\n required: boolean;\n size: Size;\n flavor: Flavor;\n form: HTMLFormElement | null;\n}\n\nexport class TySwitch\n extends TyComponent<SwitchState>\n implements TySwitchElement {\n static formAssociated = true;\n\n protected static properties = {\n checked: {\n type: \"boolean\" as const,\n visual: true,\n formValue: true,\n emitChange: true,\n default: false,\n },\n value: {\n type: \"string\" as const,\n default: \"on\",\n },\n name: {\n type: \"string\" as const,\n default: \"\",\n },\n disabled: {\n type: \"boolean\" as const,\n visual: true,\n default: false,\n },\n required: {\n type: \"boolean\" as const,\n visual: true,\n default: false,\n },\n size: {\n type: \"string\" as const,\n visual: true,\n default: DEFAULT_SIZE,\n validate: (v: any) => [\"xs\", \"sm\", \"md\", \"lg\", \"xl\"].includes(v),\n coerce: (v: any) => {\n if (![\"xs\", \"sm\", \"md\", \"lg\", \"xl\"].includes(v)) {\n console.warn(`[ty-switch] Invalid size '${v}'. Using '${DEFAULT_SIZE}'.`);\n return DEFAULT_SIZE;\n }\n return v;\n },\n },\n // Any string is accepted: built-ins get static CSS, other identifiers\n // become custom flavors (see _syncCustomFlavor), garbage degrades to\n // the default look.\n flavor: {\n type: \"string\" as const,\n visual: true,\n default: \"primary\",\n },\n };\n\n private _customFlavorSheet: CSSStyleSheet | null = null;\n private _listenersSetup: boolean = false;\n private _clickHandler: ((e: Event) => void) | null = null;\n private _keydownHandler: ((e: Event) => void) | null = null;\n private _focusHandler: (() => void) | null = null;\n private _blurHandler: (() => void) | null = null;\n\n constructor() {\n super();\n const shadow = this.shadowRoot!;\n ensureStyles(shadow, { css: switchStyles, id: \"ty-switch\" });\n }\n\n protected onConnect(): void {\n // Re-arm listeners on RE-connect (base skips render() when already\n // rendered; onDisconnect removed them). No-op on first connect.\n this.setupEventListeners();\n this._syncCustomFlavor();\n }\n protected onDisconnect(): void {\n this.removeEventListeners();\n }\n protected onPropertiesChanged(changes: PropertyChange[]): void {\n if (changes.some((c) => c.name === \"flavor\")) {\n this._syncCustomFlavor();\n }\n }\n\n /** Custom (non-built-in) flavors — see utils/flavor-sheet.ts. */\n private _syncCustomFlavor(): void {\n this._customFlavorSheet = syncCustomFlavorSheet(\n this.shadowRoot!,\n this._customFlavorSheet,\n this.flavor,\n ({ base }) => switchCustomFlavorCss(base),\n );\n }\n\n protected getFormValue(): FormDataEntryValue | null {\n return this.checked ? this.value : null;\n }\n\n private buildClassList(): string {\n const classes: string[] = [this.size];\n if (this.disabled) classes.push(\"disabled\");\n if (this.required) classes.push(\"required\");\n return classes.join(\" \");\n }\n\n private handleSwitchClick(e: Event): void {\n if (this.disabled) return;\n if (this.isDuplicateActivationClick()) return;\n const newValue = !this.checked;\n this.checked = newValue;\n\n setTimeout(() => {\n const eventDetail = {\n value: newValue,\n checked: newValue,\n formValue: newValue ? this.value : null,\n originalEvent: e,\n };\n this.dispatchEvent(\n new CustomEvent(\"input\", { detail: eventDetail, bubbles: true, composed: true }),\n );\n this.dispatchEvent(\n new CustomEvent(\"change\", { detail: eventDetail, bubbles: true, composed: true }),\n );\n }, 0);\n }\n\n private handleSwitchKeydown(e: KeyboardEvent): void {\n if (this.disabled) return;\n if ([\"Space\", \" \", \"Enter\"].includes(e.key)) {\n e.preventDefault();\n e.stopPropagation();\n this.handleSwitchClick(e);\n }\n }\n\n private removeEventListeners(): void {\n if (!this._listenersSetup) return;\n\n // Click lives on the HOST (label delegation + full-element trigger) —\n // remove it before the shadow-container guard below.\n if (this._clickHandler) {\n this.removeEventListener(\"click\", this._clickHandler);\n this._clickHandler = null;\n }\n\n const shadow = this.shadowRoot;\n if (!shadow) return;\n const el = shadow.querySelector(\".switch-container\");\n if (!el) {\n this._listenersSetup = false;\n return;\n }\n\n if (this._keydownHandler) {\n el.removeEventListener(\"keydown\", this._keydownHandler);\n this._keydownHandler = null;\n }\n if (this._focusHandler) {\n el.removeEventListener(\"focus\", this._focusHandler);\n this._focusHandler = null;\n }\n if (this._blurHandler) {\n el.removeEventListener(\"blur\", this._blurHandler);\n this._blurHandler = null;\n }\n this._listenersSetup = false;\n }\n\n private setupEventListeners(): void {\n if (this._listenersSetup) return;\n const shadow = this.shadowRoot!;\n const el = shadow.querySelector(\".switch-container\");\n if (!el) return;\n\n this._clickHandler = (e: Event) => this.handleSwitchClick(e);\n this._keydownHandler = (e: Event) => this.handleSwitchKeydown(e as KeyboardEvent);\n this._focusHandler = () => el.classList.add(\"focused\");\n this._blurHandler = () => el.classList.remove(\"focused\");\n\n // Click on the HOST: whole element is a trigger and a wrapping <label>\n // delegates (the synthetic click lands on the host, not the shadow).\n this.addEventListener(\"click\", this._clickHandler);\n el.addEventListener(\"keydown\", this._keydownHandler);\n el.addEventListener(\"focus\", this._focusHandler);\n el.addEventListener(\"blur\", this._blurHandler);\n\n this._listenersSetup = true;\n }\n\n protected render(): void {\n const shadow = this.shadowRoot!;\n let switchEl = shadow.querySelector(\".switch-container\") as HTMLElement;\n const classes = this.buildClassList();\n\n if (!switchEl) {\n switchEl = document.createElement(\"div\");\n switchEl.className = \"switch-container \" + classes;\n switchEl.tabIndex = this.disabled ? -1 : 0;\n switchEl.setAttribute(\"role\", \"switch\");\n switchEl.setAttribute(\"aria-checked\", this.checked ? \"true\" : \"false\");\n switchEl.setAttribute(\"aria-disabled\", this.disabled ? \"true\" : \"false\");\n switchEl.setAttribute(\"aria-required\", this.required ? \"true\" : \"false\");\n\n const track = document.createElement(\"div\");\n track.className = \"switch-track\";\n const thumb = document.createElement(\"div\");\n thumb.className = \"switch-thumb\";\n track.appendChild(thumb);\n switchEl.appendChild(track);\n\n shadow.appendChild(switchEl);\n } else {\n switchEl.className = \"switch-container \" + classes;\n switchEl.tabIndex = this.disabled ? -1 : 0;\n switchEl.setAttribute(\"aria-checked\", this.checked ? \"true\" : \"false\");\n switchEl.setAttribute(\"aria-disabled\", this.disabled ? \"true\" : \"false\");\n switchEl.setAttribute(\"aria-required\", this.required ? \"true\" : \"false\");\n }\n\n // (Re)attach listeners — onDisconnect removes them, so a reconnected\n // element needs them again even though the container already exists.\n this.setupEventListeners();\n\n // a11y: mirror the wrapping <label> name onto the role=\"switch\" element.\n this.applyLabelName(switchEl);\n\n // Reflect constraint validation to the owning <form> (required was cosmetic).\n this.updateValidity();\n }\n\n /** Focus the switch itself (the host is not focusable; its role element is). */\n focus(options?: FocusOptions): void {\n const el = this.shadowRoot?.querySelector(\".switch-container\") as HTMLElement | null;\n if (el) el.focus(options);\n else super.focus(options);\n }\n\n /** required + unchecked => valueMissing; otherwise valid. The message is a\n * native checkbox's, as a switch where the browser has one (Safari's\n * `switch` attribute). */\n private updateValidity(): void {\n const anchor = this.shadowRoot?.querySelector(\".switch-container\") as HTMLElement | null;\n if (this.disabled) { this.applyValidity({}); return; }\n if (this.required && !this.checked) {\n this.applyValidity(\n { valueMissing: true },\n nativeMessage(\"input\", { type: \"checkbox\", switch: true, required: true }),\n anchor ?? undefined,\n );\n } else {\n this.applyValidity({});\n }\n }\n\n get checked(): boolean { return this.getProperty(\"checked\"); }\n set checked(value: boolean) { this.setProperty(\"checked\", value); }\n\n get value(): string { return this.getProperty(\"value\"); }\n set value(val: string) { this.setProperty(\"value\", val); }\n\n get name(): string { return this.getProperty(\"name\"); }\n set name(val: string) { this.setProperty(\"name\", val); }\n\n get disabled(): boolean { return this.getProperty(\"disabled\"); }\n set disabled(value: boolean) { this.setProperty(\"disabled\", value); }\n\n get required(): boolean { return this.getProperty(\"required\"); }\n set required(value: boolean) { this.setProperty(\"required\", value); }\n\n get size(): Size { return this.getProperty(\"size\") as Size; }\n set size(value: Size) { this.setProperty(\"size\", value); }\n\n get flavor(): Flavor { return this.getProperty(\"flavor\") as Flavor; }\n set flavor(value: Flavor) { this.setProperty(\"flavor\", value); }\n\n get form(): HTMLFormElement | null { return this._internals.form; }\n}\n\nif (!customElements.get(\"ty-switch\")) {\n customElements.define(\"ty-switch\", TySwitch);\n}\n","/**\n * Radio Group + Radio Styles\n *\n * ty-radio-group: optional label + vertical/horizontal stack of radios + error message\n * ty-radio: circle with inner dot when checked\n */\n\nimport { FLAVORS } from \"../types/common.js\";\nimport { inputStyles } from \"./input.js\";\n\n/* Flavor rules only set --radio-color (checked border + inner dot); base\n rules below consume it. Doubles as the per-instance override API:\n `ty-radio { --radio-color: … }`. Fallback flavor `fb` is used for custom\n flavors so missing tokens degrade to neutral. */\nconst radioFlavor = (f: string, fb?: string) => {\n const tok = (s: string) =>\n fb\n ? `var(--ty-color-${f}${s}, var(--ty-color-${fb}${s}))`\n : `var(--ty-color-${f}${s})`;\n return `\n:host([flavor=\"${f}\"]) { --radio-color: ${tok(\"\")}; }\n:host([flavor=\"${f}+\"]) { --radio-color: ${tok(\"-strong\")}; }\n:host([flavor=\"${f}-\"]) { --radio-color: ${tok(\"-soft\")}; }\n`;\n};\n\n/** Rules for one custom (non-built-in) flavor — see utils/flavor-sheet.ts. */\nexport const radioCustomFlavorCss = (base: string) => radioFlavor(base, \"neutral\");\n\nexport const radioStyles = `\n${inputStyles}\n\n/* Override input's :host. ty-radio is just the circle (inline);\n ty-radio-group is a form-field block. */\n:host(ty-radio) {\n display: inline-flex;\n width: auto;\n vertical-align: middle;\n}\n\n:host(ty-radio-group) {\n display: block;\n width: 100%;\n}\n\n.radio-group-container {\n display: flex;\n flex-direction: column;\n gap: 0.4rem;\n font-family: inherit;\n color: var(--ty-text);\n}\n\n.radio-group-label {\n font-size: var(--ty-font-sm);\n line-height: var(--ty-leading-sm);\n font-weight: var(--ty-font-medium);\n color: var(--ty-text);\n display: flex;\n align-items: center;\n gap: 0.25rem;\n}\n\n.radio-group-list {\n display: flex;\n gap: 0.6rem;\n align-items: flex-start;\n}\n\n.radio-group-list.vertical {\n flex-direction: column;\n align-items: flex-start;\n}\n\n.radio-group-list.horizontal {\n flex-direction: row;\n flex-wrap: wrap;\n align-items: center;\n}\n\n.radio-group-error {\n font-size: var(--ty-font-xs);\n line-height: var(--ty-leading-xs);\n color: var(--ty-color-danger);\n}\n\n.radio-group-container .required-icon {\n width: 0.65em;\n height: 0.65em;\n color: var(--ty-color-danger);\n}\n.radio-group-container .required-icon svg {\n width: 100%;\n height: 100%;\n}\n\n/* A radio item is just the circle */\n.radio-container {\n /* One line box of the surrounding text, circle centered in it — lines up\n with the first line of a wrapping <label> (same as ty-checkbox). */\n display: inline-flex;\n align-items: center;\n min-height: 1.25em;\n min-height: 1lh;\n cursor: pointer;\n user-select: none;\n outline: none;\n vertical-align: middle;\n}\n\n.radio-container:not(.disabled):not([aria-checked=\"true\"]):hover .radio-circle {\n border-color: var(--radio-ring-off-hover, color-mix(in oklab, var(--ty-text) 80%, transparent));\n}\n\n.radio-container.disabled {\n cursor: not-allowed;\n opacity: 0.55;\n}\n\n.radio-container:focus-visible .radio-circle,\n.radio-container.focused .radio-circle {\n box-shadow: 0 0 0 3px var(--ty-input-shadow-focus);\n}\n\n.radio-circle {\n position: relative;\n flex-shrink: 0;\n width: 18px;\n height: 18px;\n border-radius: 50%;\n /* Unchecked ring at ~3:1 in both modes, like ty-checkbox's unchecked\n tick — --ty-input-border (the soft border) nearly vanished in dark. */\n border: 2px solid var(--radio-ring-off, color-mix(in oklab, var(--ty-text) 45%, transparent));\n background: var(--ty-input-bg);\n box-sizing: border-box;\n transition: var(--ty-local-transition, border-color 0.15s ease-in-out);\n}\n\n/* Default (no flavor attribute) is primary — defaults don't reflect to the\n host attribute, so the base rules' fallback carries the default look. */\n.radio-circle::after {\n content: \"\";\n position: absolute;\n top: 50%;\n left: 50%;\n width: 8px;\n height: 8px;\n border-radius: 50%;\n background: var(--radio-color, var(--ty-color-primary));\n transform: translate(-50%, -50%) scale(0);\n transition: transform 0.15s ease-in-out;\n}\n\n.radio-container[aria-checked=\"true\"] .radio-circle {\n border-color: var(--radio-color, var(--ty-color-primary));\n}\n\n.radio-container[aria-checked=\"true\"] .radio-circle::after {\n transform: translate(-50%, -50%) scale(1);\n}\n\n.radio-container.xs .radio-circle { width: 14px; height: 14px; }\n.radio-container.xs .radio-circle::after { width: 6px; height: 6px; }\n\n.radio-container.sm .radio-circle { width: 16px; height: 16px; }\n.radio-container.sm .radio-circle::after { width: 7px; height: 7px; }\n\n.radio-container.lg .radio-circle { width: 22px; height: 22px; }\n.radio-container.lg .radio-circle::after { width: 10px; height: 10px; }\n\n.radio-container.xl .radio-circle { width: 26px; height: 26px; }\n.radio-container.xl .radio-circle::after { width: 12px; height: 12px; }\n\n/* Flavor variants — set --radio-color, consumed by the base rules above */\n${FLAVORS.map((f) => radioFlavor(f)).join(\"\")}\n`;\n","/**\n * TyRadio + TyRadioGroup Web Components - exclusive selection within a group.\n * ty-radio-group owns the value and form integration; ty-radio is one choice.\n * Keyboard follows W3C ARIA: arrow keys move focus AND selection together.\n */\n\nimport type { Flavor, Size } from \"../types/common.js\";\nimport { DEFAULT_SIZE } from \"../types/common.js\";\nimport { TyComponent } from \"../base/ty-component.js\";\nimport type { PropertyChange } from \"../utils/property-manager.js\";\nimport { ensureStyles } from \"../utils/styles.js\";\nimport { syncCustomFlavorSheet } from \"../utils/flavor-sheet.js\";\nimport { radioStyles, radioCustomFlavorCss } from \"../styles/radio.js\";\n\nimport { REQUIRED_ICON_SVG } from \"../utils/icons.js\";\nimport { nativeMessage } from \"../utils/validity.js\";\n\n// TyRadio — individual radio button\n\ninterface RadioState {\n listenersSetup: boolean;\n}\n\nexport interface TyRadioElement extends HTMLElement {\n value: string;\n checked: boolean;\n disabled: boolean;\n size: Size;\n flavor: Flavor;\n}\n\nexport class TyRadio\n extends TyComponent<RadioState>\n implements TyRadioElement {\n\n protected static properties = {\n value: { type: \"string\" as const, default: \"\" },\n checked: {\n type: \"boolean\" as const,\n visual: true,\n default: false,\n },\n disabled: {\n type: \"boolean\" as const,\n visual: true,\n default: false,\n },\n size: {\n type: \"string\" as const,\n visual: true,\n default: DEFAULT_SIZE,\n },\n flavor: {\n type: \"string\" as const,\n visual: true,\n default: \"primary\",\n },\n };\n\n private _customFlavorSheet: CSSStyleSheet | null = null;\n private _listenersSetup: boolean = false;\n private _clickHandler: ((e: Event) => void) | null = null;\n private _focusHandler: (() => void) | null = null;\n private _blurHandler: (() => void) | null = null;\n // Roving tab stop, set by the owning ty-radio-group: one radio per group\n // is in the Tab order (the checked one, else the first). Standalone\n // radios keep their own stop.\n private _tabStop = true;\n\n constructor() {\n super();\n const shadow = this.shadowRoot!;\n ensureStyles(shadow, { css: radioStyles, id: \"ty-radio\" });\n }\n\n /** @internal Group-managed roving tabindex. */\n setTabStop(on: boolean): void {\n this._tabStop = on;\n const el = this.shadowRoot?.querySelector(\".radio-container\") as HTMLElement | null;\n if (el) el.tabIndex = this.disabled || !on ? -1 : 0;\n }\n\n /** Focus the radio itself (the host is not focusable; its role element is). */\n focus(options?: FocusOptions): void {\n const el = this.shadowRoot?.querySelector(\".radio-container\") as HTMLElement | null;\n if (el) el.focus(options);\n else super.focus(options);\n }\n\n protected onConnect(): void {\n // Re-arm listeners on RE-connect (base skips render() when already\n // rendered; onDisconnect removed them). No-op on first connect.\n this.setupEventListeners();\n\n // Tell the group we exist. During HTML parsing the group connects BEFORE\n // its children, so its own onConnect sync sees an empty group — each\n // radio announcing itself lets the group re-sync as children arrive.\n this.dispatchEvent(\n new CustomEvent(\"ty-radio-connected\", { bubbles: true }),\n );\n this._syncCustomFlavor();\n }\n protected onDisconnect(): void {\n this.removeEventListeners();\n }\n protected onPropertiesChanged(changes: PropertyChange[]): void {\n if (changes.some((c) => c.name === \"flavor\")) {\n this._syncCustomFlavor();\n }\n }\n\n /** Custom (non-built-in) flavors — see utils/flavor-sheet.ts. */\n private _syncCustomFlavor(): void {\n this._customFlavorSheet = syncCustomFlavorSheet(\n this.shadowRoot!,\n this._customFlavorSheet,\n this.flavor,\n ({ base }) => radioCustomFlavorCss(base),\n );\n }\n\n private buildClassList(): string {\n const classes: string[] = [this.size];\n if (this.disabled) classes.push(\"disabled\");\n return classes.join(\" \");\n }\n\n private handleClick(e: Event): void {\n if (this.disabled) return;\n e.stopPropagation();\n // Notify the group — group will set checked attribute on this and clear others\n this.dispatchEvent(\n new CustomEvent(\"ty-radio-select\", {\n detail: { value: this.value },\n bubbles: true,\n composed: true,\n }),\n );\n }\n\n private removeEventListeners(): void {\n if (!this._listenersSetup) return;\n\n // Click lives on the HOST (label delegation + full-element trigger) —\n // remove it before the shadow-container guard below.\n if (this._clickHandler) {\n this.removeEventListener(\"click\", this._clickHandler);\n this._clickHandler = null;\n }\n\n const el = this.shadowRoot?.querySelector(\".radio-container\");\n if (!el) {\n this._listenersSetup = false;\n return;\n }\n if (this._focusHandler) {\n el.removeEventListener(\"focus\", this._focusHandler);\n this._focusHandler = null;\n }\n if (this._blurHandler) {\n el.removeEventListener(\"blur\", this._blurHandler);\n this._blurHandler = null;\n }\n this._listenersSetup = false;\n }\n\n private setupEventListeners(): void {\n if (this._listenersSetup) return;\n const el = this.shadowRoot!.querySelector(\".radio-container\");\n if (!el) return;\n\n this._clickHandler = (e: Event) => this.handleClick(e);\n this._focusHandler = () => el.classList.add(\"focused\");\n this._blurHandler = () => el.classList.remove(\"focused\");\n\n // Click on the HOST: whole element is a trigger and a wrapping <label>\n // delegates (the synthetic click lands on the host, not the shadow).\n this.addEventListener(\"click\", this._clickHandler);\n el.addEventListener(\"focus\", this._focusHandler);\n el.addEventListener(\"blur\", this._blurHandler);\n this._listenersSetup = true;\n }\n\n protected render(): void {\n const shadow = this.shadowRoot!;\n let radioEl = shadow.querySelector(\".radio-container\") as HTMLElement;\n const classes = this.buildClassList();\n\n if (!radioEl) {\n radioEl = document.createElement(\"div\");\n radioEl.className = \"radio-container \" + classes;\n radioEl.tabIndex = this.disabled || !this._tabStop ? -1 : 0;\n radioEl.setAttribute(\"role\", \"radio\");\n radioEl.setAttribute(\"aria-checked\", String(this.checked));\n radioEl.setAttribute(\"aria-disabled\", String(this.disabled));\n\n const circle = document.createElement(\"div\");\n circle.className = \"radio-circle\";\n radioEl.appendChild(circle);\n\n shadow.appendChild(radioEl);\n } else {\n radioEl.className = \"radio-container \" + classes;\n radioEl.tabIndex = this.disabled || !this._tabStop ? -1 : 0;\n radioEl.setAttribute(\"aria-checked\", String(this.checked));\n radioEl.setAttribute(\"aria-disabled\", String(this.disabled));\n }\n\n // (Re)attach listeners — onDisconnect removes them, so a reconnected\n // element needs them again even though the container already exists.\n this.setupEventListeners();\n\n // a11y: name the role=\"radio\" element from its wrapping <label>.\n this.applyLabelName(radioEl);\n }\n\n get value(): string { return this.getProperty(\"value\"); }\n set value(v: string) { this.setProperty(\"value\", v); }\n\n get checked(): boolean { return this.getProperty(\"checked\"); }\n set checked(v: boolean) { this.setProperty(\"checked\", v); }\n\n get disabled(): boolean { return this.getProperty(\"disabled\"); }\n set disabled(v: boolean) { this.setProperty(\"disabled\", v); }\n\n get size(): Size { return this.getProperty(\"size\") as Size; }\n set size(v: Size) { this.setProperty(\"size\", v); }\n\n get flavor(): Flavor { return this.getProperty(\"flavor\") as Flavor; }\n set flavor(v: Flavor) { this.setProperty(\"flavor\", v); }\n}\n\nif (!customElements.get(\"ty-radio\")) {\n customElements.define(\"ty-radio\", TyRadio);\n}\n\n// TyRadioGroup — manages exclusive selection\n\ninterface RadioGroupState {\n listenersSetup: boolean;\n}\n\nexport interface TyRadioGroupElement extends HTMLElement {\n value: string;\n name: string;\n label: string;\n disabled: boolean;\n required: boolean;\n error: string;\n orientation: \"vertical\" | \"horizontal\";\n size: Size;\n flavor: Flavor;\n form: HTMLFormElement | null;\n}\n\nexport class TyRadioGroup\n extends TyComponent<RadioGroupState>\n implements TyRadioGroupElement {\n\n static formAssociated = true;\n\n protected static properties = {\n value: {\n type: \"string\" as const,\n visual: true,\n formValue: true,\n emitChange: true,\n default: \"\",\n },\n name: { type: \"string\" as const, default: \"\" },\n label: { type: \"string\" as const, visual: true, default: \"\" },\n disabled: { type: \"boolean\" as const, visual: true, default: false },\n required: { type: \"boolean\" as const, visual: true, default: false },\n error: { type: \"string\" as const, visual: true, default: \"\" },\n orientation: {\n type: \"string\" as const,\n visual: true,\n default: \"vertical\",\n },\n size: {\n type: \"string\" as const,\n visual: true,\n default: DEFAULT_SIZE,\n },\n flavor: {\n type: \"string\" as const,\n visual: true,\n default: \"primary\",\n },\n };\n\n private _listenersSetup: boolean = false;\n private _selectHandler: ((e: Event) => void) | null = null;\n private _keydownHandler: ((e: Event) => void) | null = null;\n private _connectedHandler: ((e: Event) => void) | null = null;\n\n constructor() {\n super();\n const shadow = this.shadowRoot!;\n ensureStyles(shadow, { css: radioStyles, id: \"ty-radio-group\" });\n }\n\n protected onConnect(): void {\n // Re-arm listeners on RE-connect; no-op on first (setup runs in render too)\n this.setupEventListeners();\n // Sync radio children with current value once light DOM is ready.\n // NOTE: during HTML parsing this runs before children are parsed — the\n // ty-radio-connected listener covers late-arriving radios.\n queueMicrotask(() => this.syncChildren());\n }\n\n protected onDisconnect(): void {\n this.removeEventListeners();\n }\n\n protected onPropertiesChanged(changes: PropertyChange[]): void {\n if (changes.some((c) => c.name === \"value\" || c.name === \"size\" || c.name === \"flavor\" || c.name === \"disabled\" || c.name === \"required\")) {\n this.syncChildren();\n }\n }\n\n protected getFormValue(): FormDataEntryValue | null {\n return this.value || null;\n }\n\n /**\n * Find ty-radio descendants in this group's light DOM. Searches deeply\n * because consumers may wrap each radio in a `<label>` for click delegation.\n *\n * Only upgraded radios: when a group is cloned from a template or set via\n * innerHTML, elements upgrade in tree order, so the group's initial `value`\n * sync runs while its radios are still plain HTMLElements. Writing\n * checked/size/flavor onto those would create own properties that shadow\n * the accessors after upgrade. Each radio fires ty-radio-connected once\n * upgraded, which re-syncs the group.\n */\n /** Focus the group's tab stop: the checked radio, else the first enabled one. */\n focus(options?: FocusOptions): void {\n const enabled = this.getRadios().filter((r) => !r.disabled);\n const stop = enabled.find((r) => r.checked) ?? enabled[0];\n if (stop) stop.focus(options);\n else super.focus(options);\n }\n\n private getRadios(): TyRadio[] {\n return (Array.from(this.querySelectorAll(\"ty-radio\")) as TyRadio[])\n .filter((r) => typeof r.setTabStop === \"function\");\n }\n\n private syncChildren(): void {\n const radios = this.getRadios();\n for (const radio of radios) {\n radio.checked = radio.value === this.value;\n // Inherit size/flavor/disabled from group unless radio set its own.\n // Group-imposed disable is marked so re-enabling the group releases\n // exactly the radios it disabled — individually-disabled ones stay off.\n if (this.disabled) {\n if (!radio.disabled) {\n radio.disabled = true;\n radio.dataset.tyGroupDisabled = \"\";\n }\n } else if (\"tyGroupDisabled\" in radio.dataset) {\n radio.disabled = false;\n delete radio.dataset.tyGroupDisabled;\n }\n radio.size = this.size;\n radio.flavor = this.flavor;\n }\n // One Tab stop per group: the checked radio, else the first enabled one.\n const enabled = radios.filter((r) => !r.disabled);\n const stop = enabled.find((r) => r.checked) ?? enabled[0];\n for (const radio of radios) radio.setTabStop(radio === stop);\n this.updateValidity();\n }\n\n /** Report `required` to the owning form — without this the asterisk\n showed but an empty group submitted anyway. The message is a native\n radio's; it needs a name, a nameless radio never reports valueMissing. */\n private updateValidity(): void {\n if (this.required && !this.disabled && !this.value) {\n const anchor = this.getRadios().find((r) => !r.disabled);\n const target = anchor?.shadowRoot?.querySelector(\".radio-container\") as HTMLElement | null;\n this.applyValidity(\n { valueMissing: true },\n nativeMessage(\"input\", { type: \"radio\", name: \"ty\", required: true }),\n target ?? undefined,\n );\n } else {\n this.applyValidity({});\n }\n }\n\n private handleRadioSelect(e: Event): void {\n if (this.disabled) return;\n const detail = (e as CustomEvent).detail;\n const newValue = detail?.value;\n if (typeof newValue !== \"string\" || newValue === this.value) return;\n\n this.value = newValue;\n this.syncChildren();\n\n setTimeout(() => {\n const eventDetail = {\n value: newValue,\n formValue: newValue,\n originalEvent: e,\n };\n this.dispatchEvent(\n new CustomEvent(\"input\", { detail: eventDetail, bubbles: true, composed: true }),\n );\n this.dispatchEvent(\n new CustomEvent(\"change\", { detail: eventDetail, bubbles: true, composed: true }),\n );\n }, 0);\n }\n\n /**\n * Arrow-key navigation within group (W3C radio practice: arrow keys move\n * focus and selection together).\n */\n private handleKeydown(e: KeyboardEvent): void {\n if (this.disabled) return;\n const radios = this.getRadios().filter((r) => !r.disabled);\n if (radios.length === 0) return;\n\n const active = document.activeElement;\n const current = radios.find((r) => r === active || r.contains(active));\n let nextIndex = -1;\n\n if ([\"ArrowDown\", \"ArrowRight\"].includes(e.key)) {\n e.preventDefault();\n nextIndex = current ? (radios.indexOf(current) + 1) % radios.length : 0;\n } else if ([\"ArrowUp\", \"ArrowLeft\"].includes(e.key)) {\n e.preventDefault();\n nextIndex = current\n ? (radios.indexOf(current) - 1 + radios.length) % radios.length\n : radios.length - 1;\n } else if ([\"Space\", \" \", \"Enter\"].includes(e.key)) {\n if (current) {\n e.preventDefault();\n this.value = current.value;\n this.syncChildren();\n const eventDetail = {\n value: current.value,\n formValue: current.value,\n originalEvent: e,\n };\n setTimeout(() => {\n this.dispatchEvent(new CustomEvent(\"change\", { detail: eventDetail, bubbles: true, composed: true }));\n }, 0);\n }\n return;\n } else {\n return;\n }\n\n const next = radios[nextIndex];\n if (next) {\n next.focus();\n // Per W3C: arrow keys also change selection\n this.value = next.value;\n this.syncChildren();\n const eventDetail = {\n value: next.value,\n formValue: next.value,\n originalEvent: e,\n };\n setTimeout(() => {\n this.dispatchEvent(new CustomEvent(\"change\", { detail: eventDetail, bubbles: true, composed: true }));\n }, 0);\n }\n }\n\n private removeEventListeners(): void {\n if (!this._listenersSetup) return;\n if (this._selectHandler) {\n this.removeEventListener(\"ty-radio-select\", this._selectHandler);\n this._selectHandler = null;\n }\n if (this._keydownHandler) {\n this.removeEventListener(\"keydown\", this._keydownHandler);\n this._keydownHandler = null;\n }\n if (this._connectedHandler) {\n this.removeEventListener(\"ty-radio-connected\", this._connectedHandler);\n this._connectedHandler = null;\n }\n this._listenersSetup = false;\n }\n\n private setupEventListeners(): void {\n if (this._listenersSetup) return;\n this._selectHandler = (e: Event) => this.handleRadioSelect(e);\n this._keydownHandler = (e: Event) => this.handleKeydown(e as KeyboardEvent);\n // Radios announce themselves on connect — re-sync so radios parsed AFTER\n // the group's own onConnect still receive the group's value/size/flavor.\n this._connectedHandler = () => this.syncChildren();\n this.addEventListener(\"ty-radio-select\", this._selectHandler);\n this.addEventListener(\"keydown\", this._keydownHandler);\n this.addEventListener(\"ty-radio-connected\", this._connectedHandler);\n this._listenersSetup = true;\n }\n\n protected render(): void {\n const shadow = this.shadowRoot!;\n let container = shadow.querySelector(\".radio-group-container\") as HTMLElement;\n\n if (!container) {\n container = document.createElement(\"div\");\n container.className = \"radio-group-container\";\n container.setAttribute(\"role\", \"radiogroup\");\n container.setAttribute(\"aria-disabled\", String(this.disabled));\n\n if (this.label) {\n const labelEl = document.createElement(\"div\");\n labelEl.className = \"radio-group-label\";\n labelEl.textContent = this.label;\n if (this.required) {\n const req = document.createElement(\"span\");\n req.className = \"required-icon\";\n req.innerHTML = REQUIRED_ICON_SVG;\n labelEl.appendChild(req);\n }\n container.appendChild(labelEl);\n }\n\n // List wrapper that hosts the slot\n const list = document.createElement(\"div\");\n list.className = \"radio-group-list \" + this.orientation;\n const slot = document.createElement(\"slot\");\n list.appendChild(slot);\n container.appendChild(list);\n\n if (this.error) {\n const errorEl = document.createElement(\"div\");\n errorEl.className = \"radio-group-error\";\n errorEl.textContent = this.error;\n container.appendChild(errorEl);\n }\n\n shadow.appendChild(container);\n this.setupEventListeners();\n } else {\n let labelEl = container.querySelector(\".radio-group-label\") as HTMLElement;\n if (this.label) {\n if (!labelEl) {\n labelEl = document.createElement(\"div\");\n labelEl.className = \"radio-group-label\";\n container.insertBefore(labelEl, container.firstChild);\n }\n labelEl.textContent = this.label;\n if (this.required && !labelEl.querySelector(\".required-icon\")) {\n const req = document.createElement(\"span\");\n req.className = \"required-icon\";\n req.innerHTML = REQUIRED_ICON_SVG;\n labelEl.appendChild(req);\n } else if (!this.required) {\n labelEl.querySelector(\".required-icon\")?.remove();\n }\n } else if (labelEl) {\n labelEl.remove();\n }\n\n const list = container.querySelector(\".radio-group-list\") as HTMLElement;\n if (list) list.className = \"radio-group-list \" + this.orientation;\n\n let errorEl = container.querySelector(\".radio-group-error\") as HTMLElement;\n if (this.error) {\n if (!errorEl) {\n errorEl = document.createElement(\"div\");\n errorEl.className = \"radio-group-error\";\n container.appendChild(errorEl);\n }\n errorEl.textContent = this.error;\n } else if (errorEl) {\n errorEl.remove();\n }\n\n container.setAttribute(\"aria-disabled\", String(this.disabled));\n }\n\n // Always sync child radios after render\n this.syncChildren();\n }\n\n get value(): string { return this.getProperty(\"value\"); }\n set value(v: string) { this.setProperty(\"value\", v); }\n\n get name(): string { return this.getProperty(\"name\"); }\n set name(v: string) { this.setProperty(\"name\", v); }\n\n get label(): string { return this.getProperty(\"label\"); }\n set label(v: string) { this.setProperty(\"label\", v); }\n\n get disabled(): boolean { return this.getProperty(\"disabled\"); }\n set disabled(v: boolean) { this.setProperty(\"disabled\", v); }\n\n get required(): boolean { return this.getProperty(\"required\"); }\n set required(v: boolean) { this.setProperty(\"required\", v); }\n\n get error(): string { return this.getProperty(\"error\"); }\n set error(v: string) { this.setProperty(\"error\", v); }\n\n get orientation(): \"vertical\" | \"horizontal\" {\n return this.getProperty(\"orientation\") as \"vertical\" | \"horizontal\";\n }\n set orientation(v: \"vertical\" | \"horizontal\") {\n this.setProperty(\"orientation\", v);\n }\n\n get size(): Size { return this.getProperty(\"size\") as Size; }\n set size(v: Size) { this.setProperty(\"size\", v); }\n\n get flavor(): Flavor { return this.getProperty(\"flavor\") as Flavor; }\n set flavor(v: Flavor) { this.setProperty(\"flavor\", v); }\n\n get form(): HTMLFormElement | null { return this._internals.form; }\n}\n\nif (!customElements.get(\"ty-radio-group\")) {\n customElements.define(\"ty-radio-group\", TyRadioGroup);\n}\n","/**\n * Copy Component Styles\n * Read-only field with copy-to-clipboard functionality\n * Extends input styles with copy-specific styling\n */\n\nimport { FLAVORS } from \"../types/common.js\";\n\n/* Flavor rules only set --copy-color (button), --copy-color-hover, and\n --copy-bg-hover (wrapper hover); the base rules below consume them.\n Doubles as the per-instance override API. Fallback flavor `fb` is used\n for custom flavors so missing tokens degrade to neutral. */\nconst copyFlavor = (f: string, fb?: string) => {\n const c = (s: string) =>\n fb\n ? `var(--ty-color-${f}${s}, var(--ty-color-${fb}${s}))`\n : `var(--ty-color-${f}${s})`;\n const bg = (s: string) =>\n fb\n ? `var(--ty-bg-${f}${s}, var(--ty-bg-${fb}${s}))`\n : `var(--ty-bg-${f}${s})`;\n return `\n:host([flavor=\"${f}\"]) { --copy-color: ${c(\"\")}; --copy-color-hover: ${c(\"-strong\")}; --copy-bg-hover: ${bg(\"-soft\")}; }\n:host([flavor=\"${f}+\"]) { --copy-color: ${c(\"-strong\")}; --copy-color-hover: ${c(\"-strong\")}; --copy-bg-hover: ${bg(\"-soft\")}; }\n:host([flavor=\"${f}-\"]) { --copy-color: ${c(\"-soft\")}; --copy-color-hover: ${c(\"\")}; --copy-bg-hover: ${bg(\"-soft\")}; }\n`;\n};\n\n/** Rules for one custom (non-built-in) flavor — see utils/flavor-sheet.ts. */\nexport const copyCustomFlavorCss = (base: string) => copyFlavor(base, \"neutral\");\n\nexport const copyStyles = `\n.copy-field-value {\n flex: 1;\n font-size: var(--ty-field-font);\n line-height: var(--ty-field-leading);\n letter-spacing: var(--ty-field-tracking);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n user-select: none;\n padding: 0;\n margin: 0;\n background: transparent;\n border: none;\n /* Field text token, like ty-input's <input>. inherit took the ambient page\n color, so inside a scoped dark block on a light page the value went dark. */\n color: var(--input-color, var(--ty-input-color));\n font-family: inherit;\n}\n\n/* format=\"code\": the reset above set font-family: inherit on the <code>\n too, so \"code\" rendered exactly like \"text\". */\ncode.copy-field-value {\n font-family: var(--ty-font-mono, ui-monospace, SFMono-Regular, Menlo, Consolas, monospace);\n font-size: calc(var(--ty-field-font) * 0.93);\n}\n\n.copy-field-value.multiline {\n white-space: pre-wrap;\n word-break: break-word;\n max-height: 200px;\n overflow-y: auto;\n}\n\n/* Keep the copy button pinned to the top-right when content wraps to multiple lines */\n.input-wrapper:has(.copy-field-value.multiline) {\n align-items: flex-start;\n padding-top: 8px;\n padding-bottom: 8px;\n}\n\n/* Scroll long content instead of clipping with an ellipsis */\n.copy-field-value.horizontal-scroll {\n overflow-x: auto;\n overflow-y: hidden;\n text-overflow: clip;\n white-space: nowrap;\n}\n\n/* Multiline + horizontal scroll (e.g. code blocks): preserve lines, scroll both axes */\n.copy-field-value.multiline.horizontal-scroll {\n white-space: pre;\n word-break: normal;\n overflow-y: auto;\n}\n\n/* Hide scrollbars on scrollable value - content still scrolls, chrome stays clean */\n.copy-field-value.multiline,\n.copy-field-value.horizontal-scroll {\n scrollbar-width: none; /* Firefox */\n}\n.copy-field-value.multiline::-webkit-scrollbar,\n.copy-field-value.horizontal-scroll::-webkit-scrollbar {\n display: none; /* Chrome/Safari */\n}\n\n/* Hover state — flavor-soft background (primary by default) */\n.input-wrapper:not(.disabled):hover {\n background: var(--copy-bg-hover, var(--ty-bg-primary-soft));\n transition: var(--ty-local-transition, background 0.2s ease);\n}\n\n.copy-button {\n flex-shrink: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n width: var(--ty-field-control);\n height: var(--ty-field-control);\n cursor: pointer;\n border: none;\n background: transparent;\n color: var(--copy-color, var(--ty-text-soft));\n transition: var(--ty-local-transition, color 0.2s ease, transform 0.2s ease);\n padding: 0;\n margin: 0;\n}\n\n.copy-button:hover:not(.disabled) {\n color: var(--copy-color-hover, var(--ty-text));\n transform: scale(1.1);\n}\n\n.copy-button.success {\n color: var(--ty-color-success);\n animation: copy-feedback 0.3s ease;\n}\n\n.copy-button.error {\n color: var(--ty-color-danger);\n animation: copy-feedback 0.3s ease;\n}\n\n@keyframes copy-feedback {\n 0%, 100% { transform: scale(1); }\n 50% { transform: scale(1.2); }\n}\n\n.copy-button svg {\n width: var(--ty-field-icon);\n height: var(--ty-field-icon);\n}\n\n.input-wrapper.disabled .copy-button {\n cursor: not-allowed;\n opacity: 0.5;\n}\n\n.input-wrapper.disabled {\n cursor: not-allowed;\n}\n\n/* Semantic flavors set --copy-*, consumed above */\n${FLAVORS.map((f) => copyFlavor(f)).join(\"\")}\n`\n","/**\n * TyCopy Web Component — read-only field with copy-to-clipboard, styled like\n * ty-input. For API keys, tokens, URLs, code snippets, etc.\n */\n\nimport type { Flavor, Size } from '../types/common.js'\nimport { DEFAULT_SIZE } from '../types/common.js'\nimport { TyComponent } from '../base/ty-component.js'\nimport type { PropertyChange } from '../utils/property-manager.js'\nimport { ensureStyles } from '../utils/styles.js'\nimport { syncCustomFlavorSheet } from '../utils/flavor-sheet.js'\nimport { inputStyles } from '../styles/input.js'\nimport { copyStyles, copyCustomFlavorCss } from '../styles/copy.js'\n\n/** Copy icon SVG (from Lucide) */\nconst COPY_ICON_SVG = `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg>`\n\n/** Check icon SVG (from Lucide) - shown after successful copy */\nconst CHECK_ICON_SVG = `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"/></svg>`\n\n/** X icon SVG (from Lucide) - shown on copy failure */\nconst ERROR_ICON_SVG = `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M18 6 6 18\"/><path d=\"m6 6 12 12\"/></svg>`\n\nimport { REQUIRED_ICON_SVG } from '../utils/icons.js'\n\n/**\n * Component internal state\n */\ninterface CopyState {\n value: string\n label: string\n size: Size\n flavor: Flavor\n format: 'text' | 'code'\n multiline: boolean\n horizontalScroll: boolean\n disabled: boolean\n required: boolean\n}\n\n/**\n * TyCopy Element Interface\n */\nexport interface TyCopyElement extends HTMLElement {\n value: string\n label: string\n size: Size\n flavor: Flavor\n format: 'text' | 'code'\n multiline: boolean\n horizontalScroll: boolean\n disabled: boolean\n required: boolean\n}\n\n/** Escape text for insertion into an innerHTML template. */\nfunction escapeText(text: string): string {\n return text\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n}\n\n/**\n * Ty Copy Field Component\n */\nexport class TyCopy extends TyComponent<CopyState> implements TyCopyElement {\n static formAssociated = true\n\n protected static properties = {\n value: {\n type: 'string' as const,\n visual: true,\n formValue: true,\n default: '',\n },\n label: {\n type: 'string' as const,\n visual: true,\n default: '',\n },\n size: {\n type: 'string' as const,\n visual: true,\n default: DEFAULT_SIZE,\n validate: (v: any) => ['xs', 'sm', 'md', 'lg', 'xl'].includes(v),\n coerce: (v: any) => {\n if (!['xs', 'sm', 'md', 'lg', 'xl'].includes(v)) {\n console.warn(`[ty-copy] Invalid size '${v}'. Using '${DEFAULT_SIZE}'.`)\n return DEFAULT_SIZE\n }\n return v\n },\n },\n // Any string is accepted: built-ins get static CSS, other identifiers\n // become custom flavors (see _syncCustomFlavor), garbage degrades to\n // the default look.\n flavor: {\n type: 'string' as const,\n visual: true,\n default: 'neutral',\n },\n format: {\n type: 'string' as const,\n visual: true,\n default: 'text',\n coerce: (v: any) => (v === 'code' ? 'code' : 'text'),\n },\n multiline: {\n type: 'boolean' as const,\n visual: true,\n default: false,\n },\n horizontalScroll: {\n type: 'boolean' as const,\n visual: true,\n default: false,\n },\n disabled: {\n type: 'boolean' as const,\n visual: true,\n default: false,\n },\n required: {\n type: 'boolean' as const,\n visual: true,\n default: false,\n },\n }\n\n // Internal state, not managed by PropertyManager\n private _copyTimeout: number | null = null\n private _showingSuccess = false\n private _customFlavorSheet: CSSStyleSheet | null = null\n\n constructor() {\n super() // TyComponent handles attachInternals() and attachShadow()\n\n ensureStyles(this.shadowRoot!, { css: inputStyles, id: 'ty-input' })\n ensureStyles(this.shadowRoot!, { css: copyStyles, id: 'ty-copy' })\n }\n\n // observedAttributes auto-generated by TyComponent from properties config\n\n /** TyComponent already handled pre-connection property capture. */\n protected onConnect(): void {\n // TyComponent will call render() automatically after this hook\n this._syncCustomFlavor()\n }\n\n /** Custom (non-built-in) flavors — see utils/flavor-sheet.ts. */\n private _syncCustomFlavor(): void {\n this._customFlavorSheet = syncCustomFlavorSheet(\n this.shadowRoot!,\n this._customFlavorSheet,\n this.flavor,\n ({ base }) => copyCustomFlavorCss(base),\n )\n }\n\n protected onDisconnect(): void {\n if (this._copyTimeout !== null) {\n clearTimeout(this._copyTimeout)\n this._copyTimeout = null\n }\n }\n\n /**\n * Handle property changes - called BEFORE render\n */\n protected onPropertiesChanged(changes: PropertyChange[]): void {\n if (changes.some((c) => c.name === 'flavor')) {\n this._syncCustomFlavor()\n }\n }\n\n private buildClassList(): string {\n const classes: string[] = []\n\n if (this.disabled) classes.push('disabled')\n if (this.required) classes.push('required')\n\n return classes.join(' ')\n }\n\n private async copyToClipboard(): Promise<void> {\n if (this.disabled || !this.value) return\n\n const value = this.value\n\n try {\n await navigator.clipboard.writeText(value)\n\n this.dispatchEvent(new CustomEvent('copy-success', {\n detail: { value },\n bubbles: true,\n composed: true\n }))\n } catch (err) {\n // Fallback for non-secure contexts (non-HTTPS)\n try {\n const textarea = document.createElement('textarea')\n textarea.value = value\n textarea.style.position = 'fixed'\n textarea.style.opacity = '0'\n document.body.appendChild(textarea)\n textarea.select()\n document.execCommand('copy')\n document.body.removeChild(textarea)\n\n this.dispatchEvent(new CustomEvent('copy-success', {\n detail: { value },\n bubbles: true,\n composed: true\n }))\n } catch (fallbackErr) {\n console.error('[ty-copy] Failed to copy:', fallbackErr)\n this.dispatchEvent(new CustomEvent('copy-error', {\n detail: { error: fallbackErr },\n bubbles: true,\n composed: true\n }))\n this.showCopyError()\n return\n }\n }\n\n // Show success animation (after either method succeeds)\n this.showCopySuccess()\n }\n\n /**\n * Show copy success animation\n * Uses state flag so render() can show the correct icon\n */\n private showCopySuccess(): void {\n if (this._copyTimeout !== null) {\n clearTimeout(this._copyTimeout)\n }\n\n this._showingSuccess = true\n // Update just the button without full re-render\n const copyButton = this.shadowRoot!.querySelector('.copy-button')\n if (copyButton) {\n copyButton.classList.add('success')\n copyButton.innerHTML = CHECK_ICON_SVG\n copyButton.setAttribute('aria-label', 'Copied!')\n }\n\n this._copyTimeout = window.setTimeout(() => {\n this._showingSuccess = false\n const btn = this.shadowRoot!.querySelector('.copy-button')\n if (btn) {\n btn.classList.remove('success')\n btn.innerHTML = COPY_ICON_SVG\n btn.setAttribute('aria-label', 'Copy to clipboard')\n }\n this._copyTimeout = null\n }, 2000)\n }\n\n /**\n * Show copy error animation\n * Swaps copy icon → red X icon → copy icon\n */\n private showCopyError(): void {\n if (this._copyTimeout !== null) {\n clearTimeout(this._copyTimeout)\n }\n\n this._showingSuccess = false\n const copyButton = this.shadowRoot!.querySelector('.copy-button')\n if (copyButton) {\n copyButton.classList.add('error')\n copyButton.innerHTML = ERROR_ICON_SVG\n copyButton.setAttribute('aria-label', 'Copy failed')\n }\n\n this._copyTimeout = window.setTimeout(() => {\n const btn = this.shadowRoot!.querySelector('.copy-button')\n if (btn) {\n btn.classList.remove('error')\n btn.innerHTML = COPY_ICON_SVG\n btn.setAttribute('aria-label', 'Copy to clipboard')\n }\n this._copyTimeout = null\n }, 2000)\n }\n\n private setupEventListeners(): void {\n const shadow = this.shadowRoot!\n const inputWrapper = shadow.querySelector('.input-wrapper')\n const copyButton = shadow.querySelector('.copy-button')\n\n // Make entire field clickable for copying\n if (inputWrapper && !this.disabled) {\n const wrapperEl = inputWrapper as HTMLElement\n wrapperEl.addEventListener('click', (e) => {\n // Prevent double-triggering if button was clicked\n if (e.target === copyButton || (e.target as HTMLElement).closest('.copy-button')) {\n return\n }\n this.copyToClipboard()\n })\n\n // Add visual feedback - make it look clickable\n wrapperEl.style.cursor = 'pointer'\n }\n\n if (copyButton) {\n copyButton.addEventListener('click', () => {\n this.copyToClipboard()\n })\n }\n }\n\n protected render(): void {\n const shadow = this.shadowRoot!\n const classes = this.buildClassList()\n\n const valueClass = [\n 'copy-field-value',\n this.multiline ? 'multiline' : '',\n this.horizontalScroll ? 'horizontal-scroll' : '',\n ].filter(Boolean).join(' ')\n // The value is shown as TEXT: it's often markup or code (`<ty-button>`),\n // which unescaped would render as elements — or run, for untrusted values.\n const shown = escapeText(this.value || '')\n const displayElement = this.format === 'code'\n ? `<code class=\"${valueClass}\">${shown}</code>`\n : `<div class=\"${valueClass}\">${shown}</div>`\n\n const labelHtml = this.label ? `\n <label class=\"ty-field-label\">\n ${this.label}\n ${this.required ? `<span class=\"required-icon\">${REQUIRED_ICON_SVG}</span>` : ''}\n </label>\n ` : ''\n\n shadow.innerHTML = `\n <div class=\"input-container\">\n ${labelHtml}\n <div class=\"input-wrapper ${classes}\">\n ${displayElement}\n <button class=\"copy-button${this._showingSuccess ? ' success' : ''}\" type=\"button\" aria-label=\"${this._showingSuccess ? 'Copied!' : 'Copy to clipboard'}\" ${this.disabled ? 'disabled' : ''}>\n ${this._showingSuccess ? CHECK_ICON_SVG : COPY_ICON_SVG}\n </button>\n </div>\n </div>\n `\n\n // Re-setup event listeners after render\n this.setupEventListeners()\n }\n\n get value(): string {\n return this.getProperty('value')\n }\n\n set value(val: string) {\n this.setProperty('value', val)\n }\n\n get label(): string {\n return this.getProperty('label')\n }\n\n set label(val: string) {\n this.setProperty('label', val)\n }\n\n get size(): Size {\n return this.getProperty('size') as Size\n }\n\n set size(value: Size) {\n this.setProperty('size', value)\n }\n\n get flavor(): Flavor {\n return this.getProperty('flavor') as Flavor\n }\n\n set flavor(value: Flavor) {\n this.setProperty('flavor', value)\n }\n\n get format(): 'text' | 'code' {\n return this.getProperty('format')\n }\n\n set format(value: 'text' | 'code') {\n this.setProperty('format', value)\n }\n\n get multiline(): boolean {\n return this.getProperty('multiline')\n }\n\n set multiline(value: boolean) {\n this.setProperty('multiline', value)\n }\n\n get horizontalScroll(): boolean {\n return this.getProperty('horizontalScroll')\n }\n\n set horizontalScroll(value: boolean) {\n this.setProperty('horizontalScroll', value)\n }\n\n get disabled(): boolean {\n return this.getProperty('disabled')\n }\n\n set disabled(value: boolean) {\n this.setProperty('disabled', value)\n }\n\n get required(): boolean {\n return this.getProperty('required')\n }\n\n set required(value: boolean) {\n this.setProperty('required', value)\n }\n}\n\nif (!customElements.get('ty-copy')) {\n customElements.define('ty-copy', TyCopy)\n}\n\n// Also exposed as ty-copy-field — says what it is (a read-only field with a\n// copy button). A constructor can only register once, hence the subclass.\nif (!customElements.get('ty-copy-field')) {\n customElements.define('ty-copy-field', class TyCopyField extends TyCopy { })\n}\n","export const fileUploadStyles = `\n:host {\n display: block;\n font-family: inherit;\n width: 100%;\n}\n\n.file-upload-container {\n display: flex;\n flex-direction: column;\n width: 100%;\n box-sizing: border-box;\n}\n\n.upload-label {\n font-size: var(--ty-font-sm);\n line-height: var(--ty-leading-sm);\n letter-spacing: var(--ty-tracking-sm);\n font-weight: var(--ty-font-medium);\n color: var(--ty-label-color);\n margin-bottom: 6px;\n padding-left: 4px;\n display: flex;\n align-items: center;\n}\n\n.required-icon {\n color: var(--ty-color-danger);\n margin-left: 4px;\n font-size: 0.75rem;\n line-height: 1;\n}\n\n.drop-zone {\n border: 2px dashed var(--ty-border);\n border-radius: var(--ty-radius-base);\n padding: 2rem 1.5rem;\n text-align: center;\n cursor: pointer;\n transition: var(--ty-local-transition, border-color 0.15s ease, background-color 0.15s ease, box-shadow 0.15s ease);\n outline: none;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 0.5rem;\n min-height: 140px;\n user-select: none;\n}\n\n.drop-zone:hover:not(.disabled) {\n border-color: var(--ty-input-border-hover);\n background: var(--ty-surface-content);\n}\n\n.drop-zone.focused {\n border-color: var(--ty-input-border-focus);\n box-shadow: 0 0 0 3px var(--ty-input-shadow-focus);\n}\n\n.drop-zone.drag-active {\n border-color: var(--ty-color-primary);\n border-style: solid;\n background: var(--ty-bg-primary-soft);\n}\n\n.drop-zone.drag-active .upload-icon {\n color: var(--ty-color-primary);\n transform: translateY(-2px);\n}\n\n.drop-zone.has-files {\n min-height: 80px;\n padding: 1.25rem 1.5rem;\n}\n\n.drop-zone.disabled {\n opacity: 0.5;\n cursor: not-allowed;\n pointer-events: none;\n}\n\n.drop-zone.error {\n border-color: var(--ty-color-danger);\n}\n\n.drop-zone.error:not(.disabled) {\n background: var(--ty-bg-danger-soft);\n}\n\n.upload-icon {\n color: var(--ty-text-faint);\n width: 2.5rem;\n height: 2.5rem;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: var(--ty-local-transition, color 0.15s ease, transform 0.15s ease);\n pointer-events: none;\n}\n\n.upload-icon svg {\n width: 100%;\n height: 100%;\n}\n\n.upload-hint {\n color: var(--ty-text-soft);\n font-size: var(--ty-font-sm);\n line-height: var(--ty-leading-sm);\n pointer-events: none;\n}\n\n.browse-link {\n color: var(--ty-color-primary);\n font-weight: var(--ty-font-medium);\n}\n\n.upload-sub-hint {\n color: var(--ty-text-faint);\n font-size: var(--ty-font-xs);\n line-height: var(--ty-leading-xs);\n pointer-events: none;\n}\n\n.file-list {\n display: flex;\n flex-direction: column;\n gap: 0.375rem;\n margin-top: 0.5rem;\n}\n\n.file-item {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n padding: 0.5rem 0.75rem;\n border-radius: var(--ty-radius-base);\n background: var(--ty-surface-content);\n border: 1px solid var(--ty-border-soft);\n}\n\n.file-icon {\n color: var(--ty-text-faint);\n flex-shrink: 0;\n width: 1rem;\n height: 1rem;\n display: flex;\n align-items: center;\n}\n\n.file-icon svg {\n width: 100%;\n height: 100%;\n}\n\n.file-name {\n flex: 1;\n font-size: var(--ty-font-sm);\n color: var(--ty-text);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n min-width: 0;\n}\n\n.file-size {\n font-size: var(--ty-font-xs);\n color: var(--ty-text-faint);\n flex-shrink: 0;\n font-variant-numeric: tabular-nums;\n}\n\n.file-remove {\n flex-shrink: 0;\n cursor: pointer;\n color: var(--ty-text-faint);\n width: 1.25rem;\n height: 1.25rem;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 50%;\n transition: var(--ty-local-transition, color 0.15s ease, background-color 0.15s ease);\n border: none;\n background: none;\n padding: 0;\n outline: none;\n}\n\n.file-remove:hover {\n color: var(--ty-color-danger);\n background: var(--ty-bg-danger-soft);\n}\n\n.file-remove:focus-visible {\n box-shadow: 0 0 0 2px var(--ty-color-danger);\n}\n\n.file-remove svg {\n width: 12px;\n height: 12px;\n}\n\n.error-message {\n font-size: var(--ty-font-xs);\n line-height: var(--ty-leading-xs);\n color: var(--ty-color-danger);\n margin-top: 4px;\n padding-left: 4px;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .drop-zone,\n .upload-icon,\n .file-remove {\n transition: none;\n }\n}\n\n@media (prefers-contrast: high) {\n .drop-zone {\n border-width: 3px;\n }\n}\n`\n","/**\n * TyFileUpload Web Component — drop zone + file picker primitive. Replaces\n * `<input type=\"file\">` with a styleable, drag-and-drop-capable equivalent.\n * Form-associated: participates in FormData and form.reset().\n */\n\nimport { TyComponent } from \"../base/ty-component.js\";\nimport type { PropertyChange } from \"../utils/property-manager.js\";\nimport { ensureStyles } from \"../utils/styles.js\";\nimport { fileUploadStyles } from \"../styles/file-upload.js\";\nimport { nativeMessage } from \"../utils/validity.js\";\n\ninterface FileUploadState {\n listenersSetup: boolean;\n}\n\nexport interface TyFileUploadElement extends HTMLElement {\n multiple: boolean;\n accept: string;\n name: string;\n disabled: boolean;\n required: boolean;\n label: string;\n placeholder: string;\n error: string;\n files: File[];\n form: HTMLFormElement | null;\n}\n\nconst UPLOAD_ICON = `<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4\"/><polyline points=\"17 8 12 3 7 8\"/><line x1=\"12\" y1=\"3\" x2=\"12\" y2=\"15\"/></svg>`;\n\nconst FILE_ICON = `<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z\"/><polyline points=\"14 2 14 8 20 8\"/></svg>`;\n\nconst X_ICON = `<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"/><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"/></svg>`;\n\nfunction formatBytes(bytes: number): string {\n if (bytes < 1024) return `${bytes} B`;\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;\n if (bytes < 1024 * 1024 * 1024) return `${(bytes / 1024 / 1024).toFixed(1)} MB`;\n return `${(bytes / 1024 / 1024 / 1024).toFixed(1)} GB`;\n}\n\nexport class TyFileUpload\n extends TyComponent<FileUploadState>\n implements TyFileUploadElement\n{\n static formAssociated = true;\n\n protected static properties = {\n multiple: {\n type: \"boolean\" as const,\n visual: true,\n default: false,\n },\n accept: {\n type: \"string\" as const,\n visual: true,\n default: \"\",\n },\n name: {\n type: \"string\" as const,\n default: \"\",\n },\n disabled: {\n type: \"boolean\" as const,\n visual: true,\n default: false,\n },\n required: {\n type: \"boolean\" as const,\n visual: true,\n default: false,\n },\n label: {\n type: \"string\" as const,\n visual: true,\n default: \"\",\n },\n placeholder: {\n type: \"string\" as const,\n visual: true,\n default: \"Drop files here or click to browse\",\n },\n error: {\n type: \"string\" as const,\n visual: true,\n default: \"\",\n },\n };\n\n private _files: File[] = [];\n private _isDragging: boolean = false;\n private _listenersSetup: boolean = false;\n\n private _dropZoneClickHandler: ((e: Event) => void) | null = null;\n private _dropZoneKeydownHandler: ((e: KeyboardEvent) => void) | null = null;\n private _dropZoneFocusHandler: (() => void) | null = null;\n private _dropZoneBlurHandler: (() => void) | null = null;\n private _dragoverHandler: ((e: DragEvent) => void) | null = null;\n private _dragleaveHandler: ((e: DragEvent) => void) | null = null;\n private _dropHandler: ((e: DragEvent) => void) | null = null;\n private _inputChangeHandler: ((e: Event) => void) | null = null;\n\n constructor() {\n super();\n ensureStyles(this.shadowRoot!, { css: fileUploadStyles, id: \"ty-file-upload\" });\n }\n\n protected onConnect(): void {\n // Empty still submits (see getFormValue), so set the value up front\n this.updateFormValue();\n }\n\n protected onDisconnect(): void {\n this.removeEventListeners();\n }\n\n protected onPropertiesChanged(_changes: PropertyChange[]): void {}\n\n protected onFormReset(): void {\n this._files = [];\n this.updateFormValue();\n if (this._connected) this.render();\n\n const fileInput = this.shadowRoot?.querySelector(\n \".file-input\",\n ) as HTMLInputElement | null;\n if (fileInput) fileInput.value = \"\";\n }\n\n protected updateFormValue(): void {\n super.updateFormValue();\n this.updateValidity();\n }\n\n /** Report `required` to the owning form, like ty-input and ty-textarea\n do — without this the asterisk showed but submission went through.\n The message is a native file input's. */\n private updateValidity(): void {\n if (this.required && !this.disabled && this._files.length === 0) {\n const anchor = this.shadowRoot?.querySelector(\".drop-zone\") as HTMLElement | null;\n this.applyValidity(\n { valueMissing: true },\n nativeMessage(\"input\", { type: \"file\", required: true, multiple: this.multiple }),\n anchor ?? undefined,\n );\n } else {\n this.applyValidity({});\n }\n }\n\n protected getFormValue(): FormData | string | null {\n // Native fidelity: an unnamed control is excluded from submission, and a\n // named one with no file submits one empty file (like <input type=file>).\n if (!this.name) return null;\n const fd = new FormData();\n if (this._files.length === 0) {\n fd.append(this.name, new File([], '', { type: 'application/octet-stream' }));\n }\n for (const file of this._files) {\n fd.append(this.name, file);\n }\n return fd;\n }\n\n /** Focus the drop zone: the host itself isn't focusable. */\n focus(options?: FocusOptions): void {\n const zone = this.shadowRoot?.querySelector('.drop-zone') as HTMLElement | null;\n if (zone) zone.focus(options);\n else super.focus(options);\n }\n\n /**\n * Match a file against the `accept` attribute the way native inputs do:\n * comma-separated list of `.ext`, `type/subtype` or `type/*` entries.\n * No/blank accept matches everything.\n */\n private matchesAccept(file: File): boolean {\n const accept = this.accept?.trim();\n if (!accept) return true;\n return accept.split(\",\").some((raw) => {\n const entry = raw.trim().toLowerCase();\n if (!entry) return false;\n if (entry.startsWith(\".\")) return file.name.toLowerCase().endsWith(entry);\n const type = file.type.toLowerCase();\n if (entry.endsWith(\"/*\")) return type.startsWith(entry.slice(0, -1));\n return type === entry;\n });\n }\n\n get files(): File[] {\n return [...this._files];\n }\n\n get multiple(): boolean {\n return this.getProperty(\"multiple\");\n }\n set multiple(v: boolean) {\n this.setProperty(\"multiple\", v);\n }\n\n get accept(): string {\n return this.getProperty(\"accept\");\n }\n set accept(v: string) {\n this.setProperty(\"accept\", v);\n }\n\n get name(): string {\n return this.getProperty(\"name\");\n }\n set name(v: string) {\n this.setProperty(\"name\", v);\n }\n\n get disabled(): boolean {\n return this.getProperty(\"disabled\");\n }\n set disabled(v: boolean) {\n this.setProperty(\"disabled\", v);\n }\n\n get required(): boolean {\n return this.getProperty(\"required\");\n }\n set required(v: boolean) {\n this.setProperty(\"required\", v);\n }\n\n get label(): string {\n return this.getProperty(\"label\");\n }\n set label(v: string) {\n this.setProperty(\"label\", v);\n }\n\n get placeholder(): string {\n return this.getProperty(\"placeholder\");\n }\n set placeholder(v: string) {\n this.setProperty(\"placeholder\", v);\n }\n\n get error(): string {\n return this.getProperty(\"error\");\n }\n set error(v: string) {\n this.setProperty(\"error\", v);\n }\n\n get form(): HTMLFormElement | null {\n return this._internals.form;\n }\n\n private setFiles(newFiles: File[]): void {\n this._files = this.multiple ? newFiles : newFiles.slice(0, 1);\n this.updateFormValue();\n this.render();\n\n const detail = {\n value: this._files,\n files: this._files,\n names: this._files.map((f) => f.name),\n };\n\n setTimeout(() => {\n this.dispatchEvent(\n new CustomEvent(\"change\", { detail, bubbles: true, composed: true }),\n );\n // The user changed the files (setFiles is only reached from picking,\n // dropping or removing): show the message now if the field is invalid,\n // including a setCustomValidity() the change handler just made.\n this.revealValidity();\n }, 0);\n }\n\n private removeFile(index: number): void {\n const updated = [...this._files];\n updated.splice(index, 1);\n this.setFiles(updated);\n\n const fileInput = this.shadowRoot?.querySelector(\n \".file-input\",\n ) as HTMLInputElement | null;\n if (fileInput) fileInput.value = \"\";\n }\n\n private setupEventListeners(): void {\n if (this._listenersSetup) return;\n const shadow = this.shadowRoot!;\n const dropZone = shadow.querySelector(\".drop-zone\") as HTMLElement;\n const fileInput = shadow.querySelector(\".file-input\") as HTMLInputElement;\n\n this._dropZoneClickHandler = (e: Event) => {\n if (this.disabled) return;\n if ((e.target as HTMLElement).closest(\".file-remove\")) return;\n fileInput.click();\n };\n\n this._dropZoneKeydownHandler = (e: KeyboardEvent) => {\n if (this.disabled) return;\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n fileInput.click();\n }\n };\n\n this._dropZoneFocusHandler = () => {\n dropZone.classList.add(\"focused\");\n };\n\n this._dropZoneBlurHandler = () => {\n dropZone.classList.remove(\"focused\");\n };\n\n this._dragoverHandler = (e: DragEvent) => {\n if (this.disabled) return;\n e.preventDefault();\n e.stopPropagation();\n if (!this._isDragging) {\n this._isDragging = true;\n dropZone.classList.add(\"drag-active\");\n }\n };\n\n this._dragleaveHandler = (e: DragEvent) => {\n if (!dropZone.contains(e.relatedTarget as Node)) {\n this._isDragging = false;\n dropZone.classList.remove(\"drag-active\");\n }\n };\n\n this._dropHandler = (e: DragEvent) => {\n if (this.disabled) return;\n e.preventDefault();\n e.stopPropagation();\n this._isDragging = false;\n dropZone.classList.remove(\"drag-active\");\n // The native picker filters by `accept`, but drag-and-drop bypasses the\n // dialog entirely — apply the same filter here (native inputs do too).\n const files = Array.from(e.dataTransfer?.files ?? []).filter((f) =>\n this.matchesAccept(f),\n );\n if (files.length > 0) this.setFiles(files);\n };\n\n this._inputChangeHandler = (e: Event) => {\n const input = e.target as HTMLInputElement;\n if (input.files && input.files.length > 0) {\n this.setFiles(Array.from(input.files));\n }\n };\n\n dropZone.addEventListener(\"click\", this._dropZoneClickHandler);\n dropZone.addEventListener(\n \"keydown\",\n this._dropZoneKeydownHandler as EventListener,\n );\n dropZone.addEventListener(\"focus\", this._dropZoneFocusHandler);\n dropZone.addEventListener(\"blur\", this._dropZoneBlurHandler);\n dropZone.addEventListener(\n \"dragover\",\n this._dragoverHandler as EventListener,\n );\n dropZone.addEventListener(\n \"dragleave\",\n this._dragleaveHandler as EventListener,\n );\n dropZone.addEventListener(\"drop\", this._dropHandler as EventListener);\n fileInput.addEventListener(\"change\", this._inputChangeHandler);\n\n this._listenersSetup = true;\n }\n\n private removeEventListeners(): void {\n if (!this._listenersSetup) return;\n const shadow = this.shadowRoot;\n if (!shadow) return;\n\n const dropZone = shadow.querySelector(\".drop-zone\");\n const fileInput = shadow.querySelector(\".file-input\");\n if (!dropZone || !fileInput) return;\n\n if (this._dropZoneClickHandler)\n dropZone.removeEventListener(\"click\", this._dropZoneClickHandler);\n if (this._dropZoneKeydownHandler)\n dropZone.removeEventListener(\n \"keydown\",\n this._dropZoneKeydownHandler as EventListener,\n );\n if (this._dropZoneFocusHandler)\n dropZone.removeEventListener(\"focus\", this._dropZoneFocusHandler);\n if (this._dropZoneBlurHandler)\n dropZone.removeEventListener(\"blur\", this._dropZoneBlurHandler);\n if (this._dragoverHandler)\n dropZone.removeEventListener(\n \"dragover\",\n this._dragoverHandler as EventListener,\n );\n if (this._dragleaveHandler)\n dropZone.removeEventListener(\n \"dragleave\",\n this._dragleaveHandler as EventListener,\n );\n if (this._dropHandler)\n dropZone.removeEventListener(\"drop\", this._dropHandler as EventListener);\n if (this._inputChangeHandler)\n fileInput.removeEventListener(\"change\", this._inputChangeHandler);\n\n this._listenersSetup = false;\n }\n\n private buildDropZoneClasses(): string {\n const classes = [\"drop-zone\"];\n if (this._isDragging) classes.push(\"drag-active\");\n if (this._files.length > 0) classes.push(\"has-files\");\n if (this.disabled) classes.push(\"disabled\");\n if (this.error) classes.push(\"error\");\n return classes.join(\" \");\n }\n\n private renderFileList(fileList: HTMLElement): void {\n fileList.innerHTML = \"\";\n for (let i = 0; i < this._files.length; i++) {\n const file = this._files[i];\n\n const item = document.createElement(\"div\");\n item.className = \"file-item\";\n\n const icon = document.createElement(\"span\");\n icon.className = \"file-icon\";\n icon.innerHTML = FILE_ICON;\n\n const name = document.createElement(\"span\");\n name.className = \"file-name\";\n name.textContent = file.name;\n name.title = file.name;\n\n const size = document.createElement(\"span\");\n size.className = \"file-size\";\n size.textContent = formatBytes(file.size);\n\n const removeBtn = document.createElement(\"button\");\n removeBtn.className = \"file-remove\";\n removeBtn.type = \"button\";\n removeBtn.innerHTML = X_ICON;\n removeBtn.setAttribute(\"aria-label\", `Remove ${file.name}`);\n\n const capturedIndex = i;\n removeBtn.addEventListener(\"click\", (e) => {\n e.stopPropagation();\n this.removeFile(capturedIndex);\n });\n\n item.appendChild(icon);\n item.appendChild(name);\n item.appendChild(size);\n item.appendChild(removeBtn);\n fileList.appendChild(item);\n }\n }\n\n protected render(): void {\n const shadow = this.shadowRoot!;\n let container = shadow.querySelector(\n \".file-upload-container\",\n ) as HTMLElement | null;\n\n if (!container) {\n container = document.createElement(\"div\");\n container.className = \"file-upload-container\";\n\n const labelEl = document.createElement(\"div\");\n labelEl.className = \"upload-label\";\n container.appendChild(labelEl);\n\n const dropZone = document.createElement(\"div\");\n dropZone.className = \"drop-zone\";\n dropZone.setAttribute(\"role\", \"button\");\n\n const fileInput = document.createElement(\"input\");\n fileInput.type = \"file\";\n fileInput.className = \"file-input\";\n fileInput.style.display = \"none\";\n dropZone.appendChild(fileInput);\n\n const uploadIcon = document.createElement(\"div\");\n uploadIcon.className = \"upload-icon\";\n uploadIcon.innerHTML = UPLOAD_ICON;\n dropZone.appendChild(uploadIcon);\n\n const hintEl = document.createElement(\"div\");\n hintEl.className = \"upload-hint\";\n dropZone.appendChild(hintEl);\n\n const subHintEl = document.createElement(\"div\");\n subHintEl.className = \"upload-sub-hint\";\n dropZone.appendChild(subHintEl);\n\n container.appendChild(dropZone);\n\n const fileList = document.createElement(\"div\");\n fileList.className = \"file-list\";\n container.appendChild(fileList);\n\n const errorEl = document.createElement(\"div\");\n errorEl.className = \"error-message\";\n container.appendChild(errorEl);\n\n shadow.appendChild(container);\n this.setupEventListeners();\n }\n\n const labelEl = container.querySelector(\".upload-label\") as HTMLElement;\n if (this.label) {\n labelEl.style.display = \"\";\n labelEl.innerHTML = \"\";\n labelEl.appendChild(document.createTextNode(this.label));\n if (this.required) {\n const req = document.createElement(\"span\");\n req.className = \"required-icon\";\n req.textContent = \"*\";\n req.setAttribute(\"aria-hidden\", \"true\");\n labelEl.appendChild(req);\n }\n } else {\n labelEl.style.display = \"none\";\n }\n\n const dropZone = container.querySelector(\".drop-zone\") as HTMLElement;\n dropZone.className = this.buildDropZoneClasses();\n dropZone.tabIndex = this.disabled ? -1 : 0;\n dropZone.setAttribute(\"aria-disabled\", String(this.disabled));\n dropZone.setAttribute(\"aria-label\", this.placeholder || \"Upload files\");\n\n const fileInput = container.querySelector(\n \".file-input\",\n ) as HTMLInputElement;\n fileInput.multiple = this.multiple;\n fileInput.accept = this.accept;\n fileInput.disabled = this.disabled;\n\n // Upload icon — hide once files are selected to give room to the compact zone\n const uploadIcon = container.querySelector(\".upload-icon\") as HTMLElement;\n uploadIcon.style.display = this._files.length > 0 ? \"none\" : \"\";\n\n const hintEl = container.querySelector(\".upload-hint\") as HTMLElement;\n if (this._files.length > 0) {\n hintEl.innerHTML = `<strong>${this._files.length} file${this._files.length !== 1 ? \"s\" : \"\"} selected</strong>`;\n } else {\n hintEl.innerHTML = `Drop files here or <span class=\"browse-link\">click to browse</span>`;\n }\n\n const subHintEl = container.querySelector(\n \".upload-sub-hint\",\n ) as HTMLElement;\n if (this.accept && this._files.length === 0) {\n subHintEl.textContent = `Accepted: ${this.accept}`;\n subHintEl.style.display = \"\";\n } else {\n subHintEl.style.display = \"none\";\n }\n\n const fileList = container.querySelector(\".file-list\") as HTMLElement;\n this.renderFileList(fileList);\n\n const errorEl = container.querySelector(\".error-message\") as HTMLElement;\n errorEl.textContent = this.error;\n errorEl.style.display = this.error ? \"\" : \"none\";\n\n // required / disabled may have changed without a file change.\n this.updateValidity();\n }\n}\n\nif (!customElements.get(\"ty-file-upload\")) {\n customElements.define(\"ty-file-upload\", TyFileUpload);\n}\n","/**\n * Styles for ty-textarea component\n * Enhanced textarea with auto-resize functionality\n */\n\nimport { fieldSizeVars } from './field-size.js'\n\nexport const textareaStyles = `\n${fieldSizeVars}\n:host {\n display: block;\n font-family: inherit;\n width: 100%;\n}\n\n.textarea-container {\n display: flex;\n flex-direction: column;\n width: 100%;\n box-sizing: border-box;\n position: relative;\n /* For absolute positioned dummy element */\n}\n\n/* Bordered container — owns the border + active state (composer layout):\n header (top slot) · textarea (borderless) · footer (bottom slot). */\n.textarea-wrapper {\n position: relative;\n width: 100%;\n display: flex;\n flex-direction: column;\n box-sizing: border-box;\n border: 1px solid var(--input-border, var(--ty-input-border));\n border-radius: var(--ty-radius-base);\n background: var(--input-bg, var(--ty-input-bg));\n transition: var(--ty-local-transition, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out);\n}\n\n/* Active ring tied to the TEXTAREA specifically (not :focus-within) so tabbing\n to a footer button doesn't make the whole field look focused. */\n.textarea-wrapper:has(textarea:focus) {\n border-color: var(--input-border-focus, var(--ty-input-border-focus));\n box-shadow: 0 0 0 3px var(--input-shadow-focus, var(--ty-input-shadow-focus));\n}\n\n/* Error + disabled reflected from the inner textarea (both in shadow DOM, so\n :has is reliable here — unlike slotted content). */\n.textarea-wrapper:has(textarea.error) {\n border-color: var(--ty-color-danger);\n background: var(--ty-bg-danger-soft);\n}\n.textarea-wrapper:has(textarea.error):has(textarea:focus) {\n border-color: var(--ty-color-danger-bold);\n}\n.textarea-wrapper:has(textarea:disabled) {\n opacity: 0.5;\n background: var(--input-disabled-bg, var(--ty-input-disabled-bg));\n border-color: var(--input-disabled-border, var(--ty-input-disabled-border));\n}\n\n/* Scroll region wraps just the textarea so the custom scrollbar never overlaps\n the header/footer. */\n.textarea-scroll {\n position: relative;\n flex: 1 1 auto;\n min-height: 0;\n display: flex;\n}\n\n/* Custom scrollbar track positioned to the scroll region (textarea edges) */\n.textarea-scroll .ty-scrollbar-track-y {\n top: 2px;\n right: 2px;\n bottom: 2px;\n border-radius: 0 4px 4px 0;\n}\n\n/* Header / footer slot regions — zero footprint until they have content\n (the component toggles .has-content via slotchange). footer defaults to\n space-between so \"tools … submit\" works; a single wide button fills it. */\n.textarea-header,\n.textarea-footer {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n}\n.textarea-footer { justify-content: space-between; }\n.textarea-header.has-content {\n padding: 6px 10px;\n border-bottom: 1px solid var(--ty-textarea-divider, var(--input-border, var(--ty-input-border)));\n}\n.textarea-footer.has-content {\n padding: 6px 10px;\n border-top: 1px solid var(--ty-textarea-divider, var(--input-border, var(--ty-input-border)));\n}\n\n.ty-field-label {\n font-size: var(--ty-field-label-font);\n line-height: var(--ty-field-label-leading);\n letter-spacing: var(--ty-tracking-sm);\n font-weight: var(--ty-font-medium);\n color: var(--ty-label-color);\n margin-bottom: var(--ty-field-label-gap);\n padding-left: var(--ty-field-outer-pad-x);\n display: flex;\n align-items: center;\n}\n\n/* Required marker — same as ty-input's (styles/input.ts). */\n.required-icon {\n display: inline-flex;\n align-items: center;\n color: var(--ty-color-danger);\n width: 12px;\n height: 12px;\n margin-left: 4px;\n vertical-align: middle;\n}\n\n.required-icon svg {\n width: 100%;\n height: 100%;\n}\n\n.error-message {\n font-size: var(--ty-font-xs);\n line-height: var(--ty-leading-xs);\n letter-spacing: var(--ty-tracking-xs);\n color: var(--ty-color-danger);\n margin-top: 4px;\n padding-left: var(--ty-field-outer-pad-x);\n}\n\n/* Error state is reflected on .textarea-wrapper (see above). */\n\ntextarea {\n font-family: inherit;\n /* Borderless — the .textarea-wrapper owns the border/background now. */\n box-sizing: border-box;\n width: 100%;\n flex: 1 1 auto;\n border: none;\n background: transparent;\n color: var(--input-color, var(--ty-input-color));\n font-family: inherit;\n /* Linear-paired typography */\n font-size: var(--ty-font-sm);\n line-height: var(--ty-leading-sm);\n letter-spacing: var(--ty-tracking-sm);\n font-weight: var(--ty-font-normal);\n outline: none;\n\n min-height: 80px;\n padding: 12px 12px;\n\n overflow: hidden;\n /* Hide scrollbars since we're auto-resizing */\n resize: none;\n\n white-space: pre-wrap;\n word-wrap: break-word;\n}\n\n/* Hide native scrollbar for webkit when custom scrollbar is active\n (scrollbar-width: none handles Firefox; this handles Chrome/Safari) */\n:host([data-custom-scroll]) textarea::-webkit-scrollbar {\n display: none;\n}\n\n/* Disabled — visual state lives on the wrapper; just the cursor/text here. */\ntextarea:disabled {\n cursor: not-allowed;\n color: var(--input-disabled-color, var(--ty-input-disabled-color));\n}\n\ntextarea::placeholder {\n color: var(--input-placeholder, var(--ty-input-placeholder));\n font-weight: 400;\n}\n\ntextarea.resize-both {\n resize: both;\n}\n\ntextarea.resize-horizontal {\n resize: horizontal;\n}\n\ntextarea.resize-vertical {\n resize: vertical;\n}\n\ntextarea.resize-none {\n resize: none;\n}\n\n/* Auto-resize mode (default) disables manual resize */\ntextarea:not(.resize-both):not(.resize-horizontal):not(.resize-vertical) {\n resize: none;\n}\n\n.textarea-dummy {\n /* Hidden element that measures text height */\n position: absolute !important;\n top: 0 !important;\n left: 0 !important;\n visibility: hidden !important;\n white-space: pre-wrap !important;\n word-break: break-word !important;\n box-sizing: border-box !important;\n overflow: hidden !important;\n pointer-events: none !important;\n z-index: -1 !important;\n\n word-wrap: break-word !important;\n overflow-wrap: break-word !important;\n}\n\ntextarea.xs {\n min-height: 64px;\n padding: 8px var(--ty-field-pad-x);\n font-size: var(--ty-font-xs);\n line-height: var(--ty-leading-xs);\n letter-spacing: var(--ty-tracking-xs);\n}\n\ntextarea.sm {\n min-height: 72px;\n padding: 10px var(--ty-field-pad-x);\n font-size: var(--ty-font-sm);\n line-height: var(--ty-leading-sm);\n letter-spacing: var(--ty-tracking-sm);\n}\n\ntextarea.md {\n min-height: 80px;\n padding: 12px var(--ty-field-pad-x);\n font-size: var(--ty-font-sm);\n line-height: var(--ty-leading-sm);\n letter-spacing: var(--ty-tracking-sm);\n}\n\ntextarea.lg {\n min-height: 96px;\n padding: 14px var(--ty-field-pad-x);\n font-size: var(--ty-font-base);\n line-height: var(--ty-leading-base);\n letter-spacing: var(--ty-tracking-base);\n}\n\ntextarea.xl {\n min-height: 112px;\n padding: 16px var(--ty-field-pad-x);\n font-size: var(--ty-font-lg);\n line-height: var(--ty-leading-lg);\n letter-spacing: var(--ty-tracking-lg);\n}\n\ntextarea:focus-visible {\n outline: none;\n /* We use box-shadow instead */\n}\n\n@media (prefers-contrast: high) {\n textarea {\n border-width: 2px;\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n textarea {\n transition: none;\n }\n\n .textarea-dummy {\n transition: none;\n }\n}\n\n@container (max-width: 480px) {\n textarea.lg {\n font-size: var(--ty-font-sm);\n line-height: var(--ty-leading-sm);\n letter-spacing: var(--ty-tracking-sm);\n padding: 12px var(--ty-field-pad-x);\n min-height: 80px;\n }\n\n textarea.xl {\n font-size: var(--ty-font-base);\n line-height: var(--ty-leading-base);\n letter-spacing: var(--ty-tracking-base);\n padding: 14px var(--ty-field-pad-x);\n min-height: 96px;\n }\n}\n\n@container (max-width: 320px) {\n textarea.xl {\n font-size: var(--ty-font-sm);\n line-height: var(--ty-leading-sm);\n letter-spacing: var(--ty-tracking-sm);\n padding: 12px var(--ty-field-pad-x);\n min-height: 80px;\n }\n}\n\n/* Fallback for browsers without container query support */\n@media (max-width: 640px) {\n textarea.lg {\n font-size: var(--ty-font-sm);\n line-height: var(--ty-leading-sm);\n letter-spacing: var(--ty-tracking-sm);\n padding: 12px var(--ty-field-pad-x);\n min-height: 80px;\n }\n\n textarea.xl {\n font-size: var(--ty-font-base);\n line-height: var(--ty-leading-base);\n letter-spacing: var(--ty-tracking-base);\n padding: 14px var(--ty-field-pad-x);\n min-height: 96px;\n }\n}\n\n@media (max-width: 480px) {\n textarea.xl {\n font-size: var(--ty-font-sm);\n line-height: var(--ty-leading-sm);\n letter-spacing: var(--ty-tracking-sm);\n padding: 12px var(--ty-field-pad-x);\n min-height: 80px;\n }\n}\n\ntextarea {\n transition: var(--ty-local-transition,\n border-color 0.15s ease-in-out,\n box-shadow 0.15s ease-in-out,\n background-color 0.15s ease-in-out,\n height 0.1s ease-out);\n}\n\n/* Disable height transition on focus to avoid jarring effect */\ntextarea:focus {\n transition: var(--ty-local-transition,\n border-color 0.15s ease-in-out,\n box-shadow 0.15s ease-in-out,\n background-color 0.15s ease-in-out);\n}\n\n@media (prefers-reduced-motion: reduce) {\n textarea {\n transition: none;\n }\n}\n`\n","/**\n * CustomScrollbar - attaches a rendered scrollbar (vertical and/or horizontal)\n * to any scrollable element. Overlay approach: native overflow:auto is kept for\n * scroll physics, the native scrollbar is hidden via CSS, and custom track/thumb\n * elements are synced on top. Append `trackY`/`trackX` to your DOM; `destroy()`\n * cleans up. Classes: `.ty-scrollbar-{track,thumb}-{y,x}` plus state classes\n * `.has-overflow`, `.dragging`, `.scrolling` (brief auto-hide after scroll).\n */\n\nexport interface CustomScrollbarOptions {\n vertical?: boolean\n horizontal?: boolean\n autoHideDelay?: number\n}\n\n/**\n * Check if custom scrollbar is enabled globally.\n * Default: true (custom scrollbar on).\n * Set data-ty-scrollbar=\"native\" on <html> to opt out.\n */\nexport function isCustomScrollbarEnabled(): boolean {\n return document.documentElement.getAttribute('data-ty-scrollbar') !== 'native'\n}\n\nexport class CustomScrollbar {\n private _scrollEl: HTMLElement\n private _vertical: boolean\n private _horizontal: boolean\n private _autoHideDelay: number\n\n readonly trackY: HTMLElement | null = null\n readonly thumbY: HTMLElement | null = null\n readonly trackX: HTMLElement | null = null\n readonly thumbX: HTMLElement | null = null\n\n private _isDragging = false\n private _dragAxis: 'x' | 'y' = 'y'\n private _dragStartPos = 0\n private _dragStartScroll = 0\n private _rafId: number | null = null\n private _hideTimeout: ReturnType<typeof setTimeout> | null = null\n private _resizeObserver: ResizeObserver | null = null\n\n private _onScroll: () => void\n private _onThumbYDown: (e: PointerEvent) => void\n private _onThumbXDown: (e: PointerEvent) => void\n private _onTrackYDown: (e: PointerEvent) => void\n private _onTrackXDown: (e: PointerEvent) => void\n private _onDragMove: (e: PointerEvent) => void\n private _onDragEnd: (e: PointerEvent) => void\n\n constructor(scrollEl: HTMLElement, options: CustomScrollbarOptions = {}) {\n this._scrollEl = scrollEl\n this._vertical = options.vertical !== false // default true\n this._horizontal = options.horizontal ?? false\n this._autoHideDelay = options.autoHideDelay ?? 1000\n\n this._onScroll = this._handleScroll.bind(this)\n this._onThumbYDown = this._handleThumbYDown.bind(this)\n this._onThumbXDown = this._handleThumbXDown.bind(this)\n this._onTrackYDown = this._handleTrackYDown.bind(this)\n this._onTrackXDown = this._handleTrackXDown.bind(this)\n this._onDragMove = this._handleDragMove.bind(this)\n this._onDragEnd = this._handleDragEnd.bind(this)\n\n if (this._vertical) {\n this.trackY = this._createTrack('y')\n this.thumbY = this._createThumb('y')\n this.trackY.appendChild(this.thumbY)\n }\n\n if (this._horizontal) {\n this.trackX = this._createTrack('x')\n this.thumbX = this._createThumb('x')\n this.trackX.appendChild(this.thumbX)\n }\n\n this._scrollEl.addEventListener('scroll', this._onScroll, { passive: true })\n\n if (this.thumbY) {\n this.thumbY.addEventListener('pointerdown', this._onThumbYDown)\n }\n if (this.trackY) {\n this.trackY.addEventListener('pointerdown', this._onTrackYDown)\n }\n if (this.thumbX) {\n this.thumbX.addEventListener('pointerdown', this._onThumbXDown)\n }\n if (this.trackX) {\n this.trackX.addEventListener('pointerdown', this._onTrackXDown)\n }\n\n this._resizeObserver = new ResizeObserver(() => this.update())\n this._resizeObserver.observe(this._scrollEl)\n\n this.update()\n }\n\n private _createTrack(axis: 'x' | 'y'): HTMLElement {\n const el = document.createElement('div')\n el.className = `ty-scrollbar-track-${axis}`\n return el\n }\n\n private _createThumb(axis: 'x' | 'y'): HTMLElement {\n const el = document.createElement('div')\n el.className = `ty-scrollbar-thumb-${axis}`\n return el\n }\n\n /** Force update thumb size and position */\n update(): void {\n this._updateVertical()\n this._updateHorizontal()\n }\n\n /** Reset scroll position */\n scrollToTop(smooth = false): void {\n this._scrollEl.scrollTo({ top: 0, behavior: smooth ? 'smooth' : 'auto' })\n }\n\n scrollToBottom(smooth = false): void {\n this._scrollEl.scrollTo({ top: this._scrollEl.scrollHeight, behavior: smooth ? 'smooth' : 'auto' })\n }\n\n scrollToLeft(smooth = false): void {\n this._scrollEl.scrollTo({ left: 0, behavior: smooth ? 'smooth' : 'auto' })\n }\n\n scrollToRight(smooth = false): void {\n this._scrollEl.scrollTo({ left: this._scrollEl.scrollWidth, behavior: smooth ? 'smooth' : 'auto' })\n }\n\n /** Cleanup all listeners and observers */\n destroy(): void {\n this._scrollEl.removeEventListener('scroll', this._onScroll)\n\n if (this.thumbY) {\n this.thumbY.removeEventListener('pointerdown', this._onThumbYDown)\n }\n if (this.trackY) {\n this.trackY.removeEventListener('pointerdown', this._onTrackYDown)\n }\n if (this.thumbX) {\n this.thumbX.removeEventListener('pointerdown', this._onThumbXDown)\n }\n if (this.trackX) {\n this.trackX.removeEventListener('pointerdown', this._onTrackXDown)\n }\n\n if (this._resizeObserver) {\n this._resizeObserver.disconnect()\n this._resizeObserver = null\n }\n\n if (this._rafId !== null) {\n cancelAnimationFrame(this._rafId)\n this._rafId = null\n }\n\n if (this._hideTimeout !== null) {\n clearTimeout(this._hideTimeout)\n this._hideTimeout = null\n }\n }\n\n private _handleScroll(): void {\n if (this._rafId !== null) return\n\n this._rafId = requestAnimationFrame(() => {\n this._rafId = null\n this._updateThumbPositions()\n this._showScrollbars()\n })\n }\n\n private _updateVertical(): void {\n if (!this.trackY || !this.thumbY) return\n\n const { scrollHeight, clientHeight } = this._scrollEl\n const hasOverflow = scrollHeight > clientHeight + 2\n\n this.trackY.classList.toggle('has-overflow', hasOverflow)\n\n if (hasOverflow) {\n const ratio = clientHeight / scrollHeight\n this.thumbY.style.height = `${Math.max(ratio * 100, 0)}%`\n }\n\n this._updateThumbY()\n }\n\n private _updateHorizontal(): void {\n if (!this.trackX || !this.thumbX) return\n\n const { scrollWidth, clientWidth } = this._scrollEl\n const hasOverflow = scrollWidth > clientWidth + 2\n\n this.trackX.classList.toggle('has-overflow', hasOverflow)\n\n if (hasOverflow) {\n const ratio = clientWidth / scrollWidth\n this.thumbX.style.width = `${Math.max(ratio * 100, 0)}%`\n }\n\n this._updateThumbX()\n }\n\n private _updateThumbPositions(): void {\n this._updateThumbY()\n this._updateThumbX()\n }\n\n private _updateThumbY(): void {\n if (!this.trackY || !this.thumbY) return\n\n const { scrollTop, scrollHeight, clientHeight } = this._scrollEl\n const maxScroll = scrollHeight - clientHeight\n if (maxScroll <= 0) return\n\n const scrollRatio = scrollTop / maxScroll\n const trackHeight = this.trackY.clientHeight\n const thumbHeight = this.thumbY.offsetHeight\n const maxThumbTop = trackHeight - thumbHeight\n\n this.thumbY.style.top = `${scrollRatio * maxThumbTop}px`\n }\n\n private _updateThumbX(): void {\n if (!this.trackX || !this.thumbX) return\n\n const { scrollLeft, scrollWidth, clientWidth } = this._scrollEl\n const maxScroll = scrollWidth - clientWidth\n if (maxScroll <= 0) return\n\n const scrollRatio = scrollLeft / maxScroll\n const trackWidth = this.trackX.clientWidth\n const thumbWidth = this.thumbX.offsetWidth\n const maxThumbLeft = trackWidth - thumbWidth\n\n this.thumbX.style.left = `${scrollRatio * maxThumbLeft}px`\n }\n\n private _showScrollbars(): void {\n if (this._isDragging) return\n\n this.trackY?.classList.add('scrolling')\n this.trackX?.classList.add('scrolling')\n\n if (this._hideTimeout !== null) {\n clearTimeout(this._hideTimeout)\n }\n\n this._hideTimeout = setTimeout(() => {\n this.trackY?.classList.remove('scrolling')\n this.trackX?.classList.remove('scrolling')\n this._hideTimeout = null\n }, this._autoHideDelay)\n }\n\n private _handleThumbYDown(e: PointerEvent): void {\n if (e.button !== 0) return\n e.preventDefault()\n e.stopPropagation()\n\n this._isDragging = true\n this._dragAxis = 'y'\n this._dragStartPos = e.clientY\n this._dragStartScroll = this._scrollEl.scrollTop\n\n this.thumbY!.setPointerCapture(e.pointerId)\n this.trackY?.classList.add('dragging')\n\n this.thumbY!.addEventListener('pointermove', this._onDragMove)\n this.thumbY!.addEventListener('pointerup', this._onDragEnd)\n this.thumbY!.addEventListener('pointercancel', this._onDragEnd)\n }\n\n private _handleThumbXDown(e: PointerEvent): void {\n if (e.button !== 0) return\n e.preventDefault()\n e.stopPropagation()\n\n this._isDragging = true\n this._dragAxis = 'x'\n this._dragStartPos = e.clientX\n this._dragStartScroll = this._scrollEl.scrollLeft\n\n this.thumbX!.setPointerCapture(e.pointerId)\n this.trackX?.classList.add('dragging')\n\n this.thumbX!.addEventListener('pointermove', this._onDragMove)\n this.thumbX!.addEventListener('pointerup', this._onDragEnd)\n this.thumbX!.addEventListener('pointercancel', this._onDragEnd)\n }\n\n private _handleDragMove(e: PointerEvent): void {\n if (!this._isDragging) return\n\n if (this._dragAxis === 'y') {\n const delta = e.clientY - this._dragStartPos\n const { scrollHeight, clientHeight } = this._scrollEl\n const trackHeight = this.trackY!.clientHeight\n const thumbHeight = this.thumbY!.offsetHeight\n const maxThumbTop = trackHeight - thumbHeight\n if (maxThumbTop <= 0) return\n const scrollRatio = (scrollHeight - clientHeight) / maxThumbTop\n this._scrollEl.scrollTop = this._dragStartScroll + delta * scrollRatio\n } else {\n const delta = e.clientX - this._dragStartPos\n const { scrollWidth, clientWidth } = this._scrollEl\n const trackWidth = this.trackX!.clientWidth\n const thumbWidth = this.thumbX!.offsetWidth\n const maxThumbLeft = trackWidth - thumbWidth\n if (maxThumbLeft <= 0) return\n const scrollRatio = (scrollWidth - clientWidth) / maxThumbLeft\n this._scrollEl.scrollLeft = this._dragStartScroll + delta * scrollRatio\n }\n }\n\n private _handleDragEnd(e: PointerEvent): void {\n const thumb = this._dragAxis === 'y' ? this.thumbY! : this.thumbX!\n const track = this._dragAxis === 'y' ? this.trackY : this.trackX\n\n this._isDragging = false\n\n thumb.releasePointerCapture(e.pointerId)\n track?.classList.remove('dragging')\n\n thumb.removeEventListener('pointermove', this._onDragMove)\n thumb.removeEventListener('pointerup', this._onDragEnd)\n thumb.removeEventListener('pointercancel', this._onDragEnd)\n\n this._showScrollbars()\n }\n\n private _handleTrackYDown(e: PointerEvent): void {\n if (e.target === this.thumbY || e.button !== 0) return\n e.preventDefault()\n\n const trackRect = this.trackY!.getBoundingClientRect()\n const clickRatio = (e.clientY - trackRect.top) / trackRect.height\n const { scrollHeight, clientHeight } = this._scrollEl\n\n this._scrollEl.scrollTo({\n top: clickRatio * (scrollHeight - clientHeight),\n behavior: 'smooth'\n })\n }\n\n private _handleTrackXDown(e: PointerEvent): void {\n if (e.target === this.thumbX || e.button !== 0) return\n e.preventDefault()\n\n const trackRect = this.trackX!.getBoundingClientRect()\n const clickRatio = (e.clientX - trackRect.left) / trackRect.width\n const { scrollWidth, clientWidth } = this._scrollEl\n\n this._scrollEl.scrollTo({\n left: clickRatio * (scrollWidth - clientWidth),\n behavior: 'smooth'\n })\n }\n}\n","/**\n * Shared CSS for CustomScrollbar utility\n * Include this in any component that uses CustomScrollbar\n */\n\nexport const customScrollbarStyles = `\n/* Vertical track */\n.ty-scrollbar-track-y {\n position: absolute;\n top: 0;\n right: 0;\n bottom: 0;\n width: var(--ty-scrollbar-width, 8px);\n z-index: 3;\n opacity: 0;\n pointer-events: none;\n transition: opacity 0.25s ease-out;\n cursor: pointer;\n}\n\n.ty-scrollbar-track-y.has-overflow {\n pointer-events: auto;\n}\n\n.ty-scrollbar-track-y.has-overflow:hover,\n.ty-scrollbar-track-y.has-overflow.scrolling,\n.ty-scrollbar-track-y.dragging {\n opacity: 1;\n}\n\n.ty-scrollbar-track-y::before {\n content: '';\n position: absolute;\n inset: 0;\n background: var(--ty-scrollbar-track, transparent);\n border-radius: var(--ty-scrollbar-radius, 4px);\n opacity: 0;\n transition: opacity 0.15s ease-out;\n}\n\n.ty-scrollbar-track-y:hover::before,\n.ty-scrollbar-track-y.dragging::before {\n opacity: 1;\n background: var(--ty-scrollbar-track-hover, color-mix(in oklab, var(--ty-color-neutral-bold) 8%, transparent));\n}\n\n.ty-scrollbar-thumb-y {\n position: absolute;\n right: 0;\n width: 100%;\n min-height: var(--ty-scrollbar-thumb-min-height, 30px);\n background: var(--ty-scrollbar-thumb, color-mix(in oklab, var(--ty-color-neutral-bold) 40%, transparent));\n border-radius: var(--ty-scrollbar-radius, 4px);\n transition: var(--ty-local-transition, background 0.15s ease-out);\n box-sizing: border-box;\n border: 1px solid transparent;\n}\n\n.ty-scrollbar-thumb-y:hover,\n.ty-scrollbar-track-y.dragging .ty-scrollbar-thumb-y {\n background: var(--ty-scrollbar-thumb-hover, color-mix(in oklab, var(--ty-color-neutral-bold) 55%, transparent));\n}\n\n.ty-scrollbar-thumb-y:active,\n.ty-scrollbar-track-y.dragging .ty-scrollbar-thumb-y {\n background: var(--ty-scrollbar-thumb-active, color-mix(in oklab, var(--ty-color-neutral-bold) 70%, transparent));\n}\n\n/* Horizontal track */\n.ty-scrollbar-track-x {\n position: absolute;\n bottom: 0;\n left: 0;\n right: 0;\n height: var(--ty-scrollbar-width, 8px);\n z-index: 3;\n opacity: 0;\n pointer-events: none;\n transition: opacity 0.25s ease-out;\n cursor: pointer;\n}\n\n.ty-scrollbar-track-x.has-overflow {\n pointer-events: auto;\n}\n\n.ty-scrollbar-track-x.has-overflow:hover,\n.ty-scrollbar-track-x.has-overflow.scrolling,\n.ty-scrollbar-track-x.dragging {\n opacity: 1;\n}\n\n.ty-scrollbar-track-x::before {\n content: '';\n position: absolute;\n inset: 0;\n background: var(--ty-scrollbar-track, transparent);\n border-radius: var(--ty-scrollbar-radius, 4px);\n opacity: 0;\n transition: opacity 0.15s ease-out;\n}\n\n.ty-scrollbar-track-x:hover::before,\n.ty-scrollbar-track-x.dragging::before {\n opacity: 1;\n background: var(--ty-scrollbar-track-hover, color-mix(in oklab, var(--ty-color-neutral-bold) 8%, transparent));\n}\n\n.ty-scrollbar-thumb-x {\n position: absolute;\n bottom: 0;\n height: 100%;\n min-width: var(--ty-scrollbar-thumb-min-height, 30px);\n background: var(--ty-scrollbar-thumb, color-mix(in oklab, var(--ty-color-neutral-bold) 40%, transparent));\n border-radius: var(--ty-scrollbar-radius, 4px);\n transition: var(--ty-local-transition, background 0.15s ease-out);\n box-sizing: border-box;\n border: 1px solid transparent;\n}\n\n.ty-scrollbar-thumb-x:hover,\n.ty-scrollbar-track-x.dragging .ty-scrollbar-thumb-x {\n background: var(--ty-scrollbar-thumb-hover, color-mix(in oklab, var(--ty-color-neutral-bold) 55%, transparent));\n}\n\n.ty-scrollbar-thumb-x:active,\n.ty-scrollbar-track-x.dragging .ty-scrollbar-thumb-x {\n background: var(--ty-scrollbar-thumb-active, color-mix(in oklab, var(--ty-color-neutral-bold) 70%, transparent));\n}\n\n/* Touch devices: hide the custom scrollbar */\n@media (pointer: coarse) and (hover: none) {\n .ty-scrollbar-track-y,\n .ty-scrollbar-track-x {\n display: none !important;\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .ty-scrollbar-track-y,\n .ty-scrollbar-track-x,\n .ty-scrollbar-thumb-y,\n .ty-scrollbar-thumb-x {\n transition-duration: 0ms !important;\n }\n}\n`;\n","/**\n * ty-textarea — form-associated textarea that auto-resizes to its content,\n * within optional min-height/max-height constraints.\n *\n * @fires {CustomEvent<{value: string, originalEvent: Event}>} input - Emitted on every edit\n * @fires {CustomEvent<{value: string, originalEvent: Event}>} change - Emitted on blur, if the value changed (like a native textarea)\n */\n\nimport { DEFAULT_SIZE } from '../types/common.js'\nimport { TyComponent } from '../base/ty-component.js'\nimport type { PropertyChange } from '../utils/property-manager.js'\nimport { ensureStyles } from '../utils/styles.js'\nimport { textareaStyles } from '../styles/textarea.js'\nimport { CustomScrollbar, isCustomScrollbarEnabled } from '../utils/custom-scrollbar.js'\nimport { customScrollbarStyles } from '../styles/custom-scrollbar.js'\nimport { nativeMessage, lengthValidity, toLimit } from '../utils/validity.js'\nimport { REQUIRED_ICON_SVG } from '../utils/icons.js'\n\n/** For typing TyComponent only — actual state lives in private fields. */\ninterface TextareaState {\n value: string\n isFocused: boolean\n textareaEl: HTMLTextAreaElement | null\n dummyEl: HTMLPreElement | null\n}\n\n/** Font style properties copied onto the measurement dummy element. */\ninterface FontStyle {\n fontFamily: string\n fontSize: string\n fontWeight: string\n lineHeight: string\n letterSpacing: string\n fontStyle: string\n}\n\n/** Spacing style properties copied onto the measurement dummy element. */\ninterface SpacingStyle {\n padding: string\n paddingTop: string\n paddingRight: string\n paddingBottom: string\n paddingLeft: string\n margin: string\n borderWidth: string\n}\n\nexport interface TyTextareaElement extends HTMLElement {\n value?: string\n name?: string\n placeholder?: string\n label?: string\n disabled?: boolean\n required?: boolean\n minLength?: number\n maxLength?: number\n tooShortMessage?: string\n tooLongMessage?: string\n error?: string\n size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl'\n rows?: string | number\n cols?: string | number\n resize?: 'none' | 'both' | 'horizontal' | 'vertical'\n minHeight?: string\n maxHeight?: string\n}\n\nexport class TyTextarea extends TyComponent<TextareaState> implements TyTextareaElement {\n static formAssociated = true\n\n protected static properties = {\n value: {\n type: 'string' as const,\n visual: true,\n formValue: true,\n emitChange: true,\n default: ''\n },\n name: {\n type: 'string' as const,\n default: ''\n },\n placeholder: {\n type: 'string' as const,\n visual: true,\n default: ''\n },\n label: {\n type: 'string' as const,\n visual: true,\n default: ''\n },\n disabled: {\n type: 'boolean' as const,\n visual: true,\n default: false\n },\n required: {\n type: 'boolean' as const,\n visual: true,\n default: false\n },\n // Length rules, like ty-input's. Unset ('') means no rule.\n minlength: {\n type: 'string' as const,\n visual: true,\n default: ''\n },\n maxlength: {\n type: 'string' as const,\n visual: true,\n default: ''\n },\n // Wording for the length messages; the browser only supplies too-short\n // for typed text (see lengthValidity). Placeholders: {minlength}\n // {maxlength} {length}.\n tooShortMessage: {\n type: 'string' as const,\n visual: true,\n default: ''\n },\n tooLongMessage: {\n type: 'string' as const,\n visual: true,\n default: ''\n },\n error: {\n type: 'string' as const,\n visual: true,\n default: ''\n },\n size: {\n type: 'string' as const,\n visual: true,\n default: DEFAULT_SIZE,\n validate: (v: any) => ['xs', 'sm', 'md', 'lg', 'xl'].includes(v),\n coerce: (v: any) => {\n if (!['xs', 'sm', 'md', 'lg', 'xl'].includes(v)) {\n console.warn(`[ty-textarea] Invalid size '${v}'. Using '${DEFAULT_SIZE}'.`)\n return DEFAULT_SIZE\n }\n return v\n }\n },\n rows: {\n type: 'string' as const,\n visual: true,\n default: '3',\n coerce: (v: any) => String(v)\n },\n cols: {\n type: 'string' as const,\n visual: true,\n default: '',\n coerce: (v: any) => v ? String(v) : ''\n },\n resize: {\n type: 'string' as const,\n visual: true,\n default: 'none',\n validate: (v: any) => ['none', 'both', 'horizontal', 'vertical'].includes(v),\n coerce: (v: any) => {\n if (!['none', 'both', 'horizontal', 'vertical'].includes(v)) {\n console.warn(`[ty-textarea] Invalid resize '${v}'. Using 'none'.`)\n return 'none'\n }\n return v\n }\n },\n minHeight: {\n type: 'string' as const,\n visual: true,\n default: ''\n },\n maxHeight: {\n type: 'string' as const,\n visual: true,\n default: ''\n }\n }\n\n // Internal state, not managed by PropertyManager (_internals comes from TyComponent).\n private _textareaEl: HTMLTextAreaElement | null = null\n private _dummyEl: HTMLPreElement | null = null\n private _scrollbar: CustomScrollbar | null = null\n\n private _isFocused = false\n\n constructor() {\n super() // TyComponent handles attachInternals() and attachShadow()\n\n const shadow = this.shadowRoot!\n ensureStyles(shadow, { css: textareaStyles, id: 'ty-textarea' })\n\n if (isCustomScrollbarEnabled()) {\n ensureStyles(shadow, { css: customScrollbarStyles, id: 'ty-custom-scrollbar' })\n }\n }\n\n // observedAttributes auto-generated by TyComponent from properties config\n\n protected onConnect(): void {\n // No special initialization needed — TyComponent handles everything.\n }\n\n protected onDisconnect(): void {\n this._destroyScrollbar()\n\n // Cloning + replacing drops every listener attached to the textarea.\n if (this._textareaEl) {\n const newTextarea = this._textareaEl.cloneNode(true)\n this._textareaEl.parentNode?.replaceChild(newTextarea, this._textareaEl)\n this._textareaEl = null\n }\n this._dummyEl = null\n }\n\n /** Called BEFORE render. Visual property changes re-render automatically. */\n protected onPropertiesChanged(changes: PropertyChange[]): void {\n }\n\n protected getFormValue(): FormDataEntryValue | null {\n return this.getProperty('value') || null\n }\n\n get value(): string { return this.getProperty('value') }\n set value(v: string) { this.setProperty('value', v) }\n\n get name(): string { return this.getProperty('name') }\n set name(v: string) { this.setProperty('name', v) }\n\n get placeholder(): string { return this.getProperty('placeholder') }\n set placeholder(v: string) { this.setProperty('placeholder', v) }\n\n get label(): string { return this.getProperty('label') }\n set label(v: string) { this.setProperty('label', v) }\n\n get disabled(): boolean { return this.getProperty('disabled') }\n set disabled(v: boolean) { this.setProperty('disabled', v) }\n\n /** Focus the inner <textarea>: the host itself isn't focusable. */\n focus(options?: FocusOptions): void {\n (this.shadowRoot?.querySelector('textarea') as HTMLTextAreaElement | null)?.focus(options)\n }\n\n get required(): boolean { return this.getProperty('required') }\n set required(v: boolean) { this.setProperty('required', v) }\n\n get minLength(): number { return toLimit(this.getProperty('minlength')) ?? -1 }\n set minLength(v: number) { this.setProperty('minlength', v == null || v < 0 ? '' : String(v)) }\n\n get maxLength(): number { return toLimit(this.getProperty('maxlength')) ?? -1 }\n set maxLength(v: number) { this.setProperty('maxlength', v == null || v < 0 ? '' : String(v)) }\n\n get tooShortMessage(): string { return this.getProperty('tooShortMessage') }\n set tooShortMessage(v: string) { this.setProperty('tooShortMessage', v ?? '') }\n\n get tooLongMessage(): string { return this.getProperty('tooLongMessage') }\n set tooLongMessage(v: string) { this.setProperty('tooLongMessage', v ?? '') }\n\n get error(): string { return this.getProperty('error') }\n set error(v: string) { this.setProperty('error', v) }\n\n get size(): 'xs' | 'sm' | 'md' | 'lg' | 'xl' {\n return this.getProperty('size') as 'xs' | 'sm' | 'md' | 'lg' | 'xl'\n }\n set size(v: 'xs' | 'sm' | 'md' | 'lg' | 'xl') {\n this.setProperty('size', v)\n }\n\n get rows(): string { return this.getProperty('rows') }\n set rows(v: string | number) { this.setProperty('rows', v) }\n\n get cols(): string { return this.getProperty('cols') }\n set cols(v: string | number) { this.setProperty('cols', v) }\n\n get resize(): 'none' | 'both' | 'horizontal' | 'vertical' {\n return this.getProperty('resize') as 'none' | 'both' | 'horizontal' | 'vertical'\n }\n set resize(v: 'none' | 'both' | 'horizontal' | 'vertical') {\n this.setProperty('resize', v)\n }\n\n get minHeight(): string { return this.getProperty('minHeight') }\n set minHeight(v: string) { this.setProperty('minHeight', v) }\n\n get maxHeight(): string { return this.getProperty('maxHeight') }\n set maxHeight(v: string) { this.setProperty('maxHeight', v) }\n\n private getFontStyle(el: HTMLElement): FontStyle {\n const computedStyle = window.getComputedStyle(el)\n return {\n fontFamily: computedStyle.fontFamily,\n fontSize: computedStyle.fontSize,\n fontWeight: computedStyle.fontWeight,\n lineHeight: computedStyle.lineHeight,\n letterSpacing: computedStyle.letterSpacing,\n fontStyle: computedStyle.fontStyle\n }\n }\n\n private getSpacingStyle(el: HTMLElement): SpacingStyle {\n const computedStyle = window.getComputedStyle(el)\n return {\n padding: computedStyle.padding,\n paddingTop: computedStyle.paddingTop,\n paddingRight: computedStyle.paddingRight,\n paddingBottom: computedStyle.paddingBottom,\n paddingLeft: computedStyle.paddingLeft,\n margin: computedStyle.margin,\n borderWidth: computedStyle.borderWidth\n }\n }\n\n /** Hidden dummy element used to measure the content height. */\n private setupDummyElement(textareaEl: HTMLTextAreaElement): HTMLPreElement {\n const root = this.shadowRoot!\n const existingDummy = root.querySelector<HTMLPreElement>('.textarea-dummy')\n\n if (existingDummy) {\n existingDummy.remove()\n }\n\n const dummyEl = document.createElement('pre')\n const fontStyle = this.getFontStyle(textareaEl)\n const spacingStyle = this.getSpacingStyle(textareaEl)\n\n dummyEl.className = 'textarea-dummy'\n\n // The dummy must match the textarea's box exactly or the measurement lies.\n const style = dummyEl.style\n style.position = 'absolute'\n style.top = '0'\n style.left = '0'\n style.visibility = 'hidden'\n style.whiteSpace = 'pre-wrap'\n style.wordBreak = 'break-word'\n style.boxSizing = 'border-box'\n style.overflow = 'hidden'\n style.pointerEvents = 'none'\n\n Object.entries(fontStyle).forEach(([prop, value]) => {\n ; (style as any)[prop] = value\n })\n\n Object.entries(spacingStyle).forEach(([prop, value]) => {\n ; (style as any)[prop] = value\n })\n\n root.appendChild(dummyEl)\n\n this._dummyEl = dummyEl\n return dummyEl\n }\n\n /** Resize the textarea to the dummy's measured height, within min/max. */\n private resizeTextarea(textareaEl: HTMLTextAreaElement, dummyEl: HTMLPreElement): void {\n if (!textareaEl || !dummyEl) return\n\n const value = this.value\n const placeholder = this.placeholder\n const content = (value === '' && placeholder) ? placeholder : value + ' '\n const currentHeight = textareaEl.clientHeight\n\n dummyEl.textContent = content\n dummyEl.style.width = `${textareaEl.clientWidth}px`\n\n const measuredHeight = dummyEl.scrollHeight\n\n const minHeight = this.minHeight ? parseInt(this.minHeight.replace('px', ''), 10) : null\n const maxHeight = this.maxHeight ? parseInt(this.maxHeight.replace('px', ''), 10) : null\n\n let constrainedHeight = measuredHeight\n if (minHeight !== null) constrainedHeight = Math.max(constrainedHeight, minHeight)\n if (maxHeight !== null) constrainedHeight = Math.min(constrainedHeight, maxHeight)\n\n // Only update if height changed significantly (avoid micro-adjustments)\n if (Math.abs(constrainedHeight - currentHeight) > 2) {\n textareaEl.style.height = `${constrainedHeight}px`\n\n const needsScroll = maxHeight !== null && measuredHeight >= maxHeight\n if (needsScroll) {\n textareaEl.style.overflowY = 'auto'\n this._setupScrollbar(textareaEl)\n } else {\n textareaEl.style.overflowY = 'hidden'\n this._destroyScrollbar()\n }\n }\n\n // Keep scrollbar thumb in sync after resize\n this._scrollbar?.update()\n }\n\n private _setupScrollbar(textareaEl: HTMLTextAreaElement): void {\n if (this._scrollbar || !isCustomScrollbarEnabled()) return\n\n // Hide native scrollbar (Firefox + Chrome/Safari via data attribute)\n textareaEl.style.scrollbarWidth = 'none'\n this.setAttribute('data-custom-scroll', '')\n\n this._scrollbar = new CustomScrollbar(textareaEl, {\n vertical: true,\n horizontal: false\n })\n\n // Append track to the scroll region (position: relative) so it tracks the\n // textarea edges and never overlaps the header/footer.\n const scroll = this.shadowRoot!.querySelector('.textarea-scroll')\n if (scroll && this._scrollbar.trackY) {\n scroll.appendChild(this._scrollbar.trackY)\n }\n }\n\n private _destroyScrollbar(): void {\n if (!this._scrollbar) return\n\n this._scrollbar.trackY?.remove()\n this._scrollbar.destroy()\n this._scrollbar = null\n\n // Restore native scrollbar\n this.removeAttribute('data-custom-scroll')\n if (this._textareaEl) {\n this._textareaEl.style.scrollbarWidth = ''\n }\n }\n\n private emitValueEvent(type: 'input' | 'change', originalEvent: Event): void {\n const data = {\n bubbles: true,\n composed: true,\n detail: {\n value: this.value,\n originalEvent\n }\n }\n\n // setTimeout: fire after the native (composed) input event has bubbled out\n setTimeout(() => this.dispatchEvent(new CustomEvent(type, data)), 0)\n }\n\n private handleInputEvent = (e: Event): void => {\n this._userEdited = true\n const target = e.target as HTMLTextAreaElement\n const newValue = target.value\n\n // Assign through the property so the full lifecycle runs.\n this.value = newValue\n\n if (this._textareaEl && this._dummyEl) {\n this.resizeTextarea(this._textareaEl, this._dummyEl)\n }\n\n this._internals.setFormValue(this.value || '')\n this.updateValidity()\n this.emitValueEvent('input', e)\n }\n\n // Value when focus arrived; change fires on blur only if it differs.\n // Tracked here rather than via the native change event, which skips\n // programmatic edits (dictation, extensions, tests).\n private _valueAtFocus: string | null = null\n\n private handleFocusEvent = (): void => {\n this._isFocused = true\n this._valueAtFocus = this.value\n }\n\n private handleBlurEvent = (e: Event): void => {\n this._isFocused = false\n // Like native :user-invalid: once edited, leaving the field shows its message\n if (this._userEdited) this.revealValidity()\n if (this._valueAtFocus !== null && this.value !== this._valueAtFocus) {\n this.emitValueEvent('change', e)\n }\n this._valueAtFocus = null\n }\n\n private buildClassList(): string {\n const classes: string[] = [this.size]\n\n if (this.disabled) classes.push('disabled')\n if (this.required) classes.push('required')\n if (this.error) classes.push('error')\n if (this.resize !== 'none') classes.push(`resize-${this.resize}`)\n\n const customClass = this.getAttribute('class')\n if (customClass) classes.push(customClass)\n\n return classes.join(' ')\n }\n\n private applyHeightConstraints(textareaEl: HTMLTextAreaElement): void {\n if (this.minHeight) {\n textareaEl.style.minHeight = this.minHeight\n }\n if (this.maxHeight) {\n textareaEl.style.maxHeight = this.maxHeight\n }\n }\n\n private setupTextareaEvents(textareaEl: HTMLTextAreaElement): void {\n textareaEl.addEventListener('input', this.handleInputEvent)\n textareaEl.addEventListener('focus', this.handleFocusEvent)\n textareaEl.addEventListener('blur', this.handleBlurEvent)\n }\n\n protected render(): void {\n const root = this.shadowRoot!\n const existingContainer = root.querySelector<HTMLDivElement>('.textarea-container')\n const existingLabel = root.querySelector<HTMLLabelElement>('label')\n const existingTextarea = root.querySelector<HTMLTextAreaElement>('textarea')\n const existingError = root.querySelector<HTMLDivElement>('.error-message')\n\n if (existingContainer && existingTextarea) {\n // Update existing elements in place\n if (this.label) {\n if (existingLabel) {\n existingLabel.innerHTML = `${this.label}${this.required ? `<span class=\"required-icon\">${REQUIRED_ICON_SVG}</span>` : ''}`\n existingLabel.style.display = 'flex'\n }\n } else if (existingLabel) {\n existingLabel.style.display = 'none'\n }\n\n // Only on a real change: any write marks the value as set by script,\n // and the inner textarea then stops reporting tooShort (updateValidity).\n if (existingTextarea.value !== (this.value || '')) existingTextarea.value = this.value || ''\n existingTextarea.placeholder = this.placeholder || ''\n existingTextarea.disabled = this.disabled\n existingTextarea.required = this.required\n this.syncConstraintAttributes(existingTextarea)\n existingTextarea.className = this.buildClassList()\n // a11y: shadow <label> isn't linked to the control; name it directly.\n if (this.label) existingTextarea.setAttribute('aria-label', this.label)\n else existingTextarea.removeAttribute('aria-label')\n\n if (this.name) {\n existingTextarea.setAttribute('name', this.name)\n } else {\n existingTextarea.removeAttribute('name')\n }\n\n if (this.rows) existingTextarea.setAttribute('rows', this.rows)\n if (this.cols) existingTextarea.setAttribute('cols', this.cols)\n\n this.applyHeightConstraints(existingTextarea)\n\n if (this.error) {\n if (!existingError) {\n const errorEl = document.createElement('div')\n errorEl.className = 'error-message'\n existingContainer.appendChild(errorEl)\n }\n const errorEl = root.querySelector<HTMLDivElement>('.error-message')\n if (errorEl) errorEl.textContent = this.error\n } else if (existingError) {\n existingError.remove()\n }\n\n const dummyEl = this.setupDummyElement(existingTextarea)\n setTimeout(() => this.resizeTextarea(existingTextarea, dummyEl), 0)\n\n this._textareaEl = existingTextarea\n\n } else {\n const container = document.createElement('div')\n container.className = 'textarea-container'\n\n const labelEl = document.createElement('label')\n labelEl.className = 'ty-field-label'\n if (this.label) {\n labelEl.innerHTML = `${this.label}${this.required ? `<span class=\"required-icon\">${REQUIRED_ICON_SVG}</span>` : ''}`\n labelEl.style.display = 'flex'\n } else {\n labelEl.style.display = 'none'\n }\n\n const textareaEl = document.createElement('textarea')\n textareaEl.value = this.value || ''\n textareaEl.placeholder = this.placeholder || ''\n textareaEl.disabled = this.disabled\n textareaEl.required = this.required\n this.syncConstraintAttributes(textareaEl)\n textareaEl.className = this.buildClassList()\n if (this.label) textareaEl.setAttribute('aria-label', this.label) // a11y: name the control\n\n if (this.name) {\n textareaEl.setAttribute('name', this.name)\n }\n\n textareaEl.setAttribute('rows', this.rows || '3')\n if (this.cols) textareaEl.setAttribute('cols', this.cols)\n\n this.applyHeightConstraints(textareaEl)\n this.setupTextareaEvents(textareaEl)\n\n // Build composer structure:\n // .textarea-wrapper (border) > [.textarea-header > slot] · .textarea-scroll(textarea) · [.textarea-footer > slot]\n const wrapperEl = document.createElement('div')\n wrapperEl.className = 'textarea-wrapper'\n\n const headerEl = document.createElement('div')\n headerEl.className = 'textarea-header'\n const headerSlot = document.createElement('slot')\n headerSlot.setAttribute('name', 'header')\n headerEl.appendChild(headerSlot)\n\n // Scroll region wraps only the textarea so the custom scrollbar can't\n // overlap header/footer.\n const scrollEl = document.createElement('div')\n scrollEl.className = 'textarea-scroll'\n scrollEl.appendChild(textareaEl)\n\n const footerEl = document.createElement('div')\n footerEl.className = 'textarea-footer'\n const footerSlot = document.createElement('slot')\n footerSlot.setAttribute('name', 'footer')\n footerEl.appendChild(footerSlot)\n\n wrapperEl.appendChild(headerEl)\n wrapperEl.appendChild(scrollEl)\n wrapperEl.appendChild(footerEl)\n\n // Collapse empty slots (no padding/divider) by toggling .has-content.\n // slotchange fires on initial assignment too.\n const syncSlot = (slot: HTMLSlotElement, region: HTMLElement) => {\n const update = () =>\n region.classList.toggle('has-content', slot.assignedNodes({ flatten: true }).length > 0)\n slot.addEventListener('slotchange', update)\n update()\n }\n syncSlot(headerSlot, headerEl)\n syncSlot(footerSlot, footerEl)\n\n container.appendChild(labelEl)\n container.appendChild(wrapperEl)\n\n if (this.error) {\n const errorEl = document.createElement('div')\n errorEl.className = 'error-message'\n errorEl.textContent = this.error\n container.appendChild(errorEl)\n }\n\n root.appendChild(container)\n\n const dummyEl = this.setupDummyElement(textareaEl)\n setTimeout(() => this.resizeTextarea(textareaEl, dummyEl), 0)\n\n this._textareaEl = textareaEl\n }\n\n // Reflect constraint validation to the owning <form>. Without this `required`\n // is cosmetic — the inner shadow <textarea> can't block the outer form.\n this.updateValidity()\n }\n\n /**\n * minlength goes on the inner <textarea> for the browser's own too-short\n * message after the user types, maxlength so typing stops at the limit\n * (like ty-input).\n */\n private syncConstraintAttributes(ta: HTMLTextAreaElement): void {\n const set = (name: string, limit: number | null) =>\n limit !== null ? ta.setAttribute(name, String(limit)) : ta.removeAttribute(name)\n set('minlength', toLimit(this.getProperty('minlength')))\n set('maxlength', toLimit(this.getProperty('maxlength')))\n }\n\n /**\n * required + empty => valueMissing (the browser's own message); otherwise\n * minlength / maxlength, worded like ty-input's (lengthValidity). Empty\n * values only fail `required`, like native. Disabled fields are barred\n * from constraint validation.\n */\n private updateValidity(): void {\n const ta = this.shadowRoot?.querySelector('textarea') as HTMLTextAreaElement | null\n if (this.disabled) { this.applyValidity({}); return }\n const current = ta ? ta.value : String(this.value ?? '')\n if (current.trim() === '') {\n if (this.required) {\n this.applyValidity({ valueMissing: true }, nativeMessage('textarea', { required: true }), ta ?? undefined)\n } else {\n this.applyValidity({})\n }\n return\n }\n const { tooShort, tooLong } = lengthValidity(current, {\n minlength: this.getProperty('minlength'),\n maxlength: this.getProperty('maxlength'),\n tooShortMessage: this.tooShortMessage,\n tooLongMessage: this.tooLongMessage,\n }, ta)\n this.applyValidity({ tooShort: !!tooShort, tooLong: !!tooLong }, tooShort ?? tooLong, ta ?? undefined)\n }\n}\n\nif (!customElements.get('ty-textarea')) {\n customElements.define('ty-textarea', TyTextarea)\n}\n","/**\n * Core positioning engine for floating elements\n *\n * Handles smart positioning of tooltips, dropdowns, popups, and other\n * floating elements relative to anchor elements with automatic overflow\n * detection and placement fallback.\n */\n\n/**\n * Placement orientation - how the floating element is positioned\n */\nexport type PlacementOrientation = 'horizontal' | 'vertical';\n\n/**\n * Vertical alignment options\n */\nexport type VerticalAlign = 'top' | 'start' | 'center' | 'bottom' | 'end';\n\n/**\n * Horizontal alignment options\n */\nexport type HorizontalAlign = 'start' | 'center' | 'end';\n\n/**\n * All available placement options\n */\nexport type Placement = \n | 'top-start' | 'top' | 'top-end'\n | 'right-start' | 'right' | 'right-end'\n | 'bottom-start' | 'bottom' | 'bottom-end'\n | 'left-start' | 'left' | 'left-end';\n\n/**\n * Placement configuration\n */\nexport interface PlacementConfig {\n vertical: VerticalAlign;\n horizontal: HorizontalAlign;\n orientation?: PlacementOrientation;\n}\n\n/**\n * Element rectangle with calculated center points\n */\nexport interface ElementRect {\n top: number;\n left: number;\n right: number;\n bottom: number;\n width: number;\n height: number;\n centerX: number;\n centerY: number;\n}\n\n/**\n * Viewport dimensions and scroll position\n */\nexport interface ViewportRect {\n width: number;\n height: number;\n scrollX: number;\n scrollY: number;\n}\n\n/**\n * Overflow data for all edges\n */\nexport interface OverflowData {\n top: number;\n left: number;\n bottom: number;\n right: number;\n}\n\n/**\n * Calculated position result\n */\nexport interface PositionResult {\n x: number;\n y: number;\n placement: Placement;\n overflow: OverflowData;\n overflowAmount: number;\n fits: boolean;\n}\n\n/**\n * Options for findBestPosition\n */\nexport interface PositionOptions {\n targetEl: HTMLElement;\n floatingEl: HTMLElement;\n preferences?: Placement[];\n offset?: number;\n padding?: number;\n containerPadding?: number;\n}\n\n/**\n * Options for calculatePlacement\n */\nexport interface CalculatePlacementOptions {\n targetRect: ElementRect;\n floatingRect: ElementRect;\n placement: Placement;\n offset: number;\n padding: number;\n scrollbarWidth: number;\n containerPadding: number;\n}\n\n/**\n * Cleanup function type\n */\nexport type CleanupFn = () => void;\n\n/**\n * Map of all placement configurations\n */\nexport const placements: Record<Placement, PlacementConfig> = {\n 'top-start': {\n vertical: 'top',\n horizontal: 'start',\n },\n 'top': {\n vertical: 'top',\n horizontal: 'center',\n },\n 'top-end': {\n vertical: 'top',\n horizontal: 'end',\n },\n 'right-start': {\n vertical: 'start',\n horizontal: 'end',\n orientation: 'vertical',\n },\n 'right': {\n vertical: 'center',\n horizontal: 'end',\n orientation: 'vertical',\n },\n 'right-end': {\n vertical: 'end',\n horizontal: 'end',\n orientation: 'vertical',\n },\n 'bottom-start': {\n vertical: 'bottom',\n horizontal: 'start',\n },\n 'bottom': {\n vertical: 'bottom',\n horizontal: 'center',\n },\n 'bottom-end': {\n vertical: 'bottom',\n horizontal: 'end',\n },\n 'left-start': {\n vertical: 'start',\n horizontal: 'start',\n orientation: 'vertical',\n },\n 'left': {\n vertical: 'center',\n horizontal: 'start',\n orientation: 'vertical',\n },\n 'left-end': {\n vertical: 'end',\n horizontal: 'start',\n orientation: 'vertical',\n },\n};\n\n/**\n * Default placement preference lists for different use cases\n */\nexport const placementPreferences = {\n default: [\n 'bottom-start', 'bottom-end', 'top-start', 'top-end',\n 'bottom', 'top', 'left', 'right'\n ] as Placement[],\n tooltip: [\n 'top', 'bottom', 'left', 'right',\n 'top-start', 'top-end', 'bottom-start', 'bottom-end'\n ] as Placement[],\n dropdown: [\n 'bottom-start', 'bottom-end', 'top-start', 'top-end',\n 'bottom', 'top', 'right', 'left'\n ] as Placement[],\n};\n\n/** The four sides a floating element can sit on. */\nexport type PlacementSide = 'top' | 'right' | 'bottom' | 'left';\n\n/** Cross-axis alignment against the anchor. Omitted means centred. */\nexport type PlacementAlign = 'start' | 'end';\n\nconst OPPOSITE_SIDE: Record<PlacementSide, PlacementSide> = {\n top: 'bottom',\n bottom: 'top',\n left: 'right',\n right: 'left',\n};\n\n/** Split `'left-end'` into `{ side: 'left', align: 'end' }`. */\nexport function parsePlacement(\n placement: Placement\n): { side: PlacementSide; align?: PlacementAlign } {\n const [side, align] = placement.split('-') as [PlacementSide, PlacementAlign | undefined];\n return { side, align };\n}\n\n/**\n * Fallback order to try for a requested placement, best-fit first.\n *\n * FLIP BEFORE RE-ALIGN. When a placement overflows it is almost always the\n * SIDE axis that ran out of room, and re-aligning on the same side does not\n * change the fit at all: `bottom-start` and `bottom-end` need identical\n * vertical space. Flipping to the opposite side is the move that actually\n * helps, so the requested alignment is carried across the flip first, and only\n * then do we try other alignments.\n *\n * This also keeps the old hand-written chains intact for the four bare sides —\n * `top` still degrades to `bottom` as its very next candidate, exactly as\n * before aligned placements existed.\n *\n * Callers previously hand-wrote a 4-entry chain per side, which silently\n * dropped every aligned placement onto the default chain.\n */\nexport function preferenceChain(placement: Placement): Placement[] {\n const { side, align } = parsePlacement(placement);\n const opposite = OPPOSITE_SIDE[side];\n const perpendicular: PlacementSide[] =\n side === 'top' || side === 'bottom' ? ['right', 'left'] : ['bottom', 'top'];\n\n // The requested alignment on a given side, then that side's other alignments.\n const exact = (s: PlacementSide): Placement =>\n (align ? `${s}-${align}` : s) as Placement;\n const rest = (s: PlacementSide): Placement[] =>\n (align\n ? [s, `${s}-${align === 'start' ? 'end' : 'start'}`]\n : [`${s}-start`, `${s}-end`]) as Placement[];\n\n return [\n exact(side),\n exact(opposite), // flip first — the only move that fixes side-axis overflow\n ...rest(side),\n ...rest(opposite),\n ...perpendicular.flatMap((s) => [exact(s), ...rest(s)]),\n ];\n}\n\n/**\n * Map a `Placement` onto `computeAnchoredPosition`'s inputs, so dropdown-style\n * components (ty-select, ty-date-picker) accept the same `placement` vocabulary\n * as ty-popup / ty-tooltip.\n *\n * Dropdowns only ever live above or below their trigger, so a left/right\n * placement degrades to \"auto\" side while keeping its alignment. Bare sides\n * default to start-aligned, matching a native <select> and the behaviour these\n * components had before `placement` existed.\n */\nexport function placementToAnchored(\n placement?: Placement | '' | null\n): { side: 'top' | 'bottom' | 'auto'; align: 'start' | 'center' | 'end' } {\n if (!placement) return { side: 'auto', align: 'start' };\n const { side, align } = parsePlacement(placement);\n return {\n side: side === 'top' || side === 'bottom' ? side : 'auto',\n align: align ?? 'start',\n };\n}\n\n/**\n * Get element dimensions relative to viewport with calculated center points\n */\nfunction getElementRect(el: HTMLElement): ElementRect {\n const rect = el.getBoundingClientRect();\n return {\n top: rect.top,\n left: rect.left,\n right: rect.right,\n bottom: rect.bottom,\n width: rect.width,\n height: rect.height,\n centerX: rect.left + rect.width / 2,\n centerY: rect.top + rect.height / 2,\n };\n}\n\n/**\n * Get viewport dimensions and scroll position\n */\nfunction getViewportRect(): ViewportRect {\n return {\n width: window.innerWidth,\n height: window.innerHeight,\n scrollX: window.scrollX,\n scrollY: window.scrollY,\n };\n}\n\n/**\n * Calculate position for a specific placement\n * Returns x, y coordinates and overflow information\n */\nfunction calculatePlacement(options: CalculatePlacementOptions): PositionResult {\n const {\n targetRect,\n floatingRect,\n placement,\n offset,\n padding,\n scrollbarWidth,\n containerPadding,\n } = options;\n\n const config = placements[placement];\n const { vertical, horizontal, orientation } = config;\n const viewport = getViewportRect();\n\n let x: number;\n if (orientation === 'vertical') {\n // Left/right placements\n if (horizontal === 'start') {\n x = targetRect.left - floatingRect.width - offset + containerPadding;\n } else {\n x = targetRect.right + offset - containerPadding;\n }\n } else {\n // Top/bottom placements. containerPadding is the floating element's\n // transparent wrap (shadow room) — the VISIBLE panel is inset by it, so\n // aligned edges must shift the box outward to bring the panel flush.\n if (horizontal === 'start') {\n x = targetRect.left - containerPadding;\n } else if (horizontal === 'center') {\n x = targetRect.centerX - floatingRect.width / 2;\n } else {\n x = targetRect.right - floatingRect.width + containerPadding;\n }\n }\n\n let y: number;\n if (orientation === 'vertical') {\n // Left/right placements\n if (vertical === 'center') {\n y = targetRect.centerY - floatingRect.height / 2;\n } else if (vertical === 'end') {\n // Bottom edges flush (left-end / right-end): shift the box DOWN by the\n // wrap so the visible panel's bottom lands on the trigger's bottom.\n // The old `- containerPadding` had the sign flipped — the panel sat\n // 2×wrap above flush.\n y = targetRect.bottom - floatingRect.height + containerPadding;\n } else {\n // Top edges flush (left-start / right-start): shift the box UP by the\n // wrap so the visible panel's top lands on the trigger's top.\n y = targetRect.top - containerPadding;\n }\n } else {\n // Top/bottom placements\n if (vertical === 'top') {\n y = targetRect.top - floatingRect.height - offset + containerPadding;\n } else {\n y = targetRect.bottom + offset - containerPadding;\n }\n }\n\n const overflow: OverflowData = {\n top: Math.min(0, y - padding),\n left: Math.min(0, x - padding),\n bottom: Math.min(0, viewport.height - (y + floatingRect.height + padding)),\n right: Math.min(0, viewport.width - (x + floatingRect.width + padding + scrollbarWidth)),\n };\n\n // Sum of absolute overflow values\n const overflowAmount = Object.values(overflow).reduce(\n (sum, val) => sum + Math.abs(val),\n 0\n );\n\n return {\n x: Math.round(x),\n y: Math.round(y),\n placement,\n overflow,\n overflowAmount,\n fits: overflowAmount === 0,\n };\n}\n\n/**\n * Find the best position for the floating element\n * Tries all preference placements and returns the one that fits best\n */\nexport function findBestPosition(options: PositionOptions): PositionResult {\n const {\n targetEl,\n floatingEl,\n preferences = placementPreferences.default,\n offset = 8,\n padding = 8,\n containerPadding = 0,\n } = options;\n\n const targetRect = getElementRect(targetEl);\n const floatingRect = getElementRect(floatingEl);\n const scrollbarWidth = 15;\n\n const candidates = preferences.map(placement =>\n calculatePlacement({\n targetRect,\n floatingRect,\n placement,\n offset,\n padding,\n containerPadding,\n scrollbarWidth,\n })\n );\n\n // Find first that fits, or one with least overflow\n const bestPosition = candidates.find(c => c.fits) ||\n candidates.reduce((best, current) =>\n current.overflowAmount < best.overflowAmount ? current : best\n );\n\n // Adjust for scrollbar if needed\n if (bestPosition.overflow.right < 0) {\n bestPosition.x += bestPosition.overflow.right;\n }\n\n return bestPosition;\n}\n\n// Anchored modal popups (select, date-picker)\n\n/**\n * Below/above placement for trigger-anchored `<dialog>` popups.\n *\n * Unlike findBestPosition (12-placement engine for non-modal floats), these\n * popups only ever open below or above their trigger, and their CSS anchors\n * with `top:` when below but `bottom:` when above — so both conventions are\n * returned and the caller picks by `below`.\n */\nexport interface AnchoredPopupOptions {\n anchorRect: DOMRect | ElementRect;\n popupWidth: number;\n popupHeight: number;\n /** Gap between trigger and popup edge (px, default 4) */\n gap?: number;\n /** Minimum distance from viewport edges (px, default 8) */\n padding?: number;\n /** Horizontal anchor edge: trigger's left edge (\"start\", default), its\n * right edge (\"end\"), or centred on it. Either way the result is clamped\n * into the viewport, same as before. */\n align?: \"start\" | \"center\" | \"end\";\n /** Preferred vertical side. \"auto\" (default) keeps the historic behaviour:\n * below when it fits, otherwise whichever side has more room. Naming a\n * side honours it when it fits and still flips rather than clipping. */\n side?: \"top\" | \"bottom\" | \"auto\";\n}\n\nexport interface AnchoredPopupPosition {\n /** Popup left edge, viewport coords, clamped into view */\n x: number;\n /** CSS `top` value when below */\n topY: number;\n /** CSS `bottom` value when above */\n bottomY: number;\n below: boolean;\n}\n\nexport function computeAnchoredPosition(o: AnchoredPopupOptions): AnchoredPopupPosition {\n const gap = o.gap ?? 4;\n const padding = o.padding ?? 8;\n const vw = window.innerWidth;\n const vh = window.innerHeight;\n\n const spaceBelow = vh - o.anchorRect.bottom;\n const spaceAbove = o.anchorRect.top;\n\n const needed = o.popupHeight + gap + padding;\n const fitsBelow = spaceBelow >= needed;\n const fitsAbove = spaceAbove >= needed;\n\n // \"auto\": below when it fits — and when neither side fits, the side with MORE\n // room instead of blindly flipping up (a trigger near the viewport top used\n // to clip the popup off-screen).\n // A named side is honoured when it fits, and still flips rather than clipping\n // when it doesn't; if neither fits we fall back to the roomier side.\n const side = o.side ?? \"auto\";\n const below =\n side === \"bottom\" ? (fitsBelow || !fitsAbove ? true : false)\n : side === \"top\" ? (fitsAbove || !fitsBelow ? false : true)\n : fitsBelow || spaceBelow >= spaceAbove;\n\n // Anchor to the trigger's left edge (\"start\"), right edge (\"end\"), or centre,\n // clamped into the viewport either way.\n const rawX =\n o.align === \"end\" ? o.anchorRect.right - o.popupWidth\n : o.align === \"center\"\n ? o.anchorRect.left + (o.anchorRect.width - o.popupWidth) / 2\n : o.anchorRect.left;\n const x = Math.max(padding, Math.min(rawX, vw - o.popupWidth - padding));\n\n return {\n x,\n topY: o.anchorRect.bottom + gap,\n bottomY: vh - o.anchorRect.top + gap,\n below,\n };\n}\n\n","/**\n * Tooltip Styles\n *\n * The tooltip popover is created in document.body (top-layer Popover API)\n * and styled inline by the component — see applyFlavorStyles() in\n * components/tooltip.ts. The shadow root only needs the host to not affect\n * layout.\n */\n\nimport type { StyleContent } from '../types/common.js';\n\nexport const tooltipStyles: StyleContent = {\n id: 'ty-tooltip',\n css: `\n:host {\n display: contents;\n}\n`,\n};\n","/**\n * Tooltip Component — shows content on hover/focus with smart positioning.\n * The anchor is the tooltip's PARENT element; the popover itself lives in\n * document.body (top layer), not in this element's shadow root.\n */\n\nimport { findBestPosition, preferenceChain, type Placement, type CleanupFn } from '../utils/positioning.js';\nimport { ensureStyles } from '../utils/styles.js';\nimport { tooltipStyles } from '../styles/tooltip.js';\nimport type { Flavor } from '../types/common.js';\n\n/**\n * Tooltip flavors are the standard ones: neutral (default) / primary /\n * success / danger / warning with + and - tones, or a custom flavor.\n * 'dark' is kept as a silent alias for neutral.\n */\nexport type TooltipFlavor = 'dark' | Flavor;\n\n/**\n * Tooltip attributes configuration\n */\nexport interface TooltipAttributes {\n placement: Placement;\n offset: number;\n delay: number;\n disabled: boolean;\n flavor: TooltipFlavor;\n}\n\n/** Timeout state for show/hide delays. */\ninterface TimeoutState {\n showTimeout: number | null;\n hideTimeout: number | null;\n}\n\nconst autoUpdateCleanup = new WeakMap<TyTooltip, CleanupFn>();\nconst eventCleanup = new WeakMap<TyTooltip, CleanupFn>();\nconst timeoutState = new WeakMap<TyTooltip, TimeoutState>();\nconst popoverElements = new WeakMap<TyTooltip, HTMLElement>();\n// Cached separately from getAnchorElement()/el.parentElement — by the time\n// disconnectedCallback fires the element has already been removed from the\n// DOM, so parentElement is null and cleanup() couldn't otherwise find the\n// anchor to strip its aria-describedby.\nconst anchorElements = new WeakMap<TyTooltip, HTMLElement>();\n\n/**\n * Normalize the flavor attribute. Any plain identifier (with optional +/-\n * shade suffix) is accepted — built-ins and custom flavors alike get their\n * colors from tokens in applyFlavorStyles(). Anything else (including\n * would-be CSS injection through the attribute) falls back to 'neutral'.\n */\nfunction validateFlavor(flavor: string | null): TooltipFlavor {\n const full = flavor || 'neutral';\n const base = full.replace(/[+-]$/, '');\n return /^[A-Za-z][A-Za-z0-9_-]*$/.test(base) ? (full as TooltipFlavor) : 'neutral';\n}\n\nfunction getTimeoutState(el: TyTooltip): TimeoutState {\n let state = timeoutState.get(el);\n if (!state) {\n state = { showTimeout: null, hideTimeout: null };\n timeoutState.set(el, state);\n }\n return state;\n}\n\nfunction parseBoolAttr(el: Element, name: string): boolean {\n return el.hasAttribute(name);\n}\n\nfunction parseIntAttr(el: Element, name: string, defaultValue: number): number {\n const value = el.getAttribute(name);\n if (value === null) return defaultValue;\n const parsed = parseInt(value, 10);\n return isNaN(parsed) ? defaultValue : parsed;\n}\n\nfunction getTooltipAttributes(el: TyTooltip): TooltipAttributes {\n return {\n placement: (el.getAttribute('placement') || 'top') as Placement,\n offset: parseIntAttr(el, 'offset', 8),\n delay: parseIntAttr(el, 'delay', 600),\n disabled: parseBoolAttr(el, 'disabled'),\n flavor: validateFlavor(el.getAttribute('flavor')),\n };\n}\n\n/** The anchor is the tooltip's parent element. */\nfunction getAnchorElement(el: TyTooltip): HTMLElement | null {\n return el.parentElement;\n}\n\n/**\n * Add `id` to the anchor's aria-describedby without clobbering a value the\n * consumer may already have set for something else (WAI-ARIA APG tooltip\n * pattern: append, don't overwrite).\n */\nfunction addDescribedBy(anchor: HTMLElement, id: string): void {\n const ids = (anchor.getAttribute('aria-describedby') || '').split(/\\s+/).filter(Boolean);\n if (!ids.includes(id)) {\n ids.push(id);\n anchor.setAttribute('aria-describedby', ids.join(' '));\n }\n}\n\n/** Inverse of addDescribedBy — used on teardown. */\nfunction removeDescribedBy(anchor: HTMLElement, id: string): void {\n const ids = (anchor.getAttribute('aria-describedby') || '').split(/\\s+/).filter((x) => x && x !== id);\n if (ids.length > 0) {\n anchor.setAttribute('aria-describedby', ids.join(' '));\n } else {\n anchor.removeAttribute('aria-describedby');\n }\n}\n\n/**\n * Get or create popover element using Popover API\n * The popover is created in document.body for top-layer placement\n */\n/**\n * Enter motion for all tooltip popovers — one document-level sheet (the\n * popover lives in document.body, outside any shadow root, and\n * @starting-style can't be expressed inline). Faster and calmer than the\n * popup recipe: 120ms fade + 4px slide from the anchor side, no overshoot —\n * tooltips fire on every hover, bounce would grate. Enter-only, matching\n * modal/select/date-picker.\n */\nfunction ensureTooltipMotionStyles(): void {\n if (document.getElementById('ty-tooltip-motion')) return;\n const style = document.createElement('style');\n style.id = 'ty-tooltip-motion';\n style.textContent = `\n.ty-tooltip-popover:popover-open {\n transition:\n opacity var(--ty-tooltip-duration, 120ms) ease-out,\n translate var(--ty-tooltip-duration, 120ms) ease-out;\n}\n@starting-style {\n .ty-tooltip-popover:popover-open { opacity: 0; translate: 0 4px; }\n .ty-tooltip-popover:popover-open[data-side=\"bottom\"] { translate: 0 -4px; }\n .ty-tooltip-popover:popover-open[data-side=\"left\"] { translate: 4px 0; }\n .ty-tooltip-popover:popover-open[data-side=\"right\"] { translate: -4px 0; }\n}\n`;\n document.head.appendChild(style);\n}\n\nfunction getOrCreatePopover(el: TyTooltip): HTMLElement {\n ensureTooltipMotionStyles();\n let popover = popoverElements.get(el);\n\n if (!popover) {\n popover = document.createElement('div');\n popover.id = `ty-tooltip-${Math.random().toString(36).slice(2, 11)}`;\n popover.setAttribute('popover', 'manual');\n // WAI-ARIA APG tooltip pattern: the popover needs role=\"tooltip\" and\n // the trigger needs aria-describedby pointing at it, or a keyboard/\n // screen-reader user gets no indication the tooltip exists at all —\n // hover-only visibility isn't enough on its own.\n popover.setAttribute('role', 'tooltip');\n popover.className = 'ty-tooltip-popover';\n\n // Apply inline styles (since popover is outside shadow DOM, we need inline styles)\n const styles = `\n position: fixed;\n margin: 0;\n padding: 8px 12px;\n background: var(--ty-tooltip-bg, #262626);\n color: var(--ty-tooltip-color, #f5f5f5);\n border: none;\n border-radius: 6px;\n font-size: var(--ty-font-xs, 12px);\n font-weight: var(--ty-font-semibold, 600);\n line-height: 1.5;\n max-width: 250px;\n text-align: center;\n box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.2), 0 4px 6px -4px rgba(0, 0, 0, 0.1);\n user-select: none;\n pointer-events: none;\n `;\n\n popover.style.cssText = styles;\n\n document.body.appendChild(popover);\n popoverElements.set(el, popover);\n\n const anchor = anchorElements.get(el);\n if (anchor) addDescribedBy(anchor, popover.id);\n }\n\n // Resync on every call (not just creation) — content and flavor can\n // change between shows, and this is eagerly called from connectedCallback\n // (see below) so a keyboard user tabbing straight to the trigger gets a\n // real aria-describedby target immediately, not one that only exists\n // after the (default 600ms) hover delay has already elapsed.\n const { flavor } = getTooltipAttributes(el);\n popover.setAttribute('data-flavor', flavor);\n // innerHTML, not textContent — the tooltip's own docs promise \"Content is\n // any HTML nested inside the ty-tooltip element\"; textContent silently\n // stripped it. Relocating the developer's own authored markup between two\n // elements they control isn't a new trust boundary (same model ty-select\n // already uses to clone rich option HTML into its trigger).\n popover.innerHTML = el.innerHTML;\n applyFlavorStyles(popover, flavor);\n\n return popover;\n}\n\n/**\n * Apply flavor-specific styles to popover.\n *\n * Same flavors as every other component. neutral (the default, and the\n * legacy 'dark') is a fixed dark chip on the --ty-tooltip-* tokens — a\n * tooltip should pop whether the page is light or dark. Every other flavor\n * — primary / success / danger / warning or custom, with + / - tones — is a\n * SOLID fill on the solid-button tokens (--ty-solid-X, -fg, -strong, -soft):\n * the popover floats over arbitrary content, so the translucent --ty-bg-X\n * tints it used before went unreadable. Custom flavors with missing tokens\n * fall back to the neutral chip. The flavor has passed validateFlavor's\n * identifier guard, so interpolating it into var() names is safe.\n */\nfunction applyFlavorStyles(popover: HTMLElement, flavor: TooltipFlavor): void {\n popover.style.removeProperty('background');\n popover.style.removeProperty('color');\n popover.style.removeProperty('border-color');\n\n const base = flavor.replace(/[+-]$/, '');\n const shade = flavor.slice(base.length);\n\n if ((base === 'neutral' || base === 'dark') && shade === '') {\n popover.style.background = 'var(--ty-tooltip-bg, #262626)';\n popover.style.color = 'var(--ty-tooltip-color, #f5f5f5)';\n popover.style.borderColor = 'var(--ty-tooltip-border, #404040)';\n return;\n }\n\n const f = base === 'dark' ? 'neutral' : base;\n const sfx = shade === '+' ? '-strong' : shade === '-' ? '-soft' : '';\n popover.style.background = `var(--ty-solid-${f}${sfx}, var(--ty-tooltip-bg, #262626))`;\n popover.style.color = `var(--ty-solid-${f}${sfx}-fg, var(--ty-solid-${f}-fg, var(--ty-tooltip-color, #f5f5f5)))`;\n popover.style.borderColor = 'transparent';\n}\n\nfunction updatePosition(el: TyTooltip): void {\n const { placement, offset } = getTooltipAttributes(el);\n const anchor = getAnchorElement(el);\n const popover = popoverElements.get(el);\n\n if (!anchor || !popover) {\n console.warn('[ty-tooltip] updatePosition: missing anchor or popover');\n return;\n }\n\n // Handles all 12 placements. The old hand-written chain only matched the four\n // bare sides, so 'top-start' & co. fell through to the default and the\n // requested alignment was silently dropped.\n const preferences: Placement[] = preferenceChain(placement);\n\n const position = findBestPosition({\n targetEl: anchor,\n floatingEl: popover,\n preferences,\n offset,\n });\n\n popover.style.left = `${position.x}px`;\n popover.style.top = `${position.y}px`;\n // Resolved side (post-flip) drives the directional entrance slide\n popover.dataset.side = position.placement.split('-')[0];\n}\n\nfunction cleanupAutoUpdate(el: TyTooltip): void {\n const cleanup = autoUpdateCleanup.get(el);\n if (cleanup) {\n cleanup();\n autoUpdateCleanup.delete(el);\n }\n}\n\n/**\n * Setup auto-update for position tracking.\n * Note: This does NOT calculate initial position — call updatePosition() separately.\n */\nfunction setupAutoUpdate(el: TyTooltip): void {\n const anchor = getAnchorElement(el);\n const popover = popoverElements.get(el);\n\n if (!anchor || !popover) {\n console.warn('[ty-tooltip] setupAutoUpdate: missing anchor or popover');\n return;\n }\n\n let timeoutId: number | null = null;\n const debouncedUpdate = () => {\n if (timeoutId !== null) {\n clearTimeout(timeoutId);\n }\n timeoutId = window.setTimeout(() => {\n timeoutId = null;\n updatePosition(el);\n }, 10);\n };\n\n const resizeObserver = new ResizeObserver(debouncedUpdate);\n resizeObserver.observe(anchor);\n resizeObserver.observe(popover);\n\n let scrollRafId: number | null = null;\n const handleScroll = () => {\n if (scrollRafId === null) {\n scrollRafId = requestAnimationFrame(() => {\n scrollRafId = null;\n updatePosition(el);\n });\n }\n };\n\n window.addEventListener('scroll', handleScroll, true);\n window.addEventListener('resize', debouncedUpdate);\n\n const cleanup = () => {\n resizeObserver.disconnect();\n window.removeEventListener('scroll', handleScroll, true);\n window.removeEventListener('resize', debouncedUpdate);\n if (timeoutId !== null) {\n clearTimeout(timeoutId);\n }\n if (scrollRafId !== null) {\n cancelAnimationFrame(scrollRafId);\n }\n };\n\n autoUpdateCleanup.set(el, cleanup);\n}\n\nfunction clearTimeouts(el: TyTooltip): void {\n const state = getTimeoutState(el);\n if (state.showTimeout !== null) {\n clearTimeout(state.showTimeout);\n state.showTimeout = null;\n }\n if (state.hideTimeout !== null) {\n clearTimeout(state.hideTimeout);\n state.hideTimeout = null;\n }\n}\n\n/** Escape dismisses an open tooltip without moving focus or the pointer\n (WCAG 1.4.13 \"dismissible\"). One document listener per open tooltip. */\nconst escapeHandlers = new WeakMap<TyTooltip, (e: KeyboardEvent) => void>();\n\nfunction listenForEscape(el: TyTooltip): void {\n if (escapeHandlers.has(el)) return;\n const handler = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n clearTimeouts(el);\n hideTooltip(el);\n }\n };\n escapeHandlers.set(el, handler);\n document.addEventListener('keydown', handler, true);\n}\n\nfunction stopListeningForEscape(el: TyTooltip): void {\n const handler = escapeHandlers.get(el);\n if (!handler) return;\n document.removeEventListener('keydown', handler, true);\n escapeHandlers.delete(el);\n}\n\n/** Show immediately (no delay). */\nfunction showTooltip(el: TyTooltip): void {\n const { disabled } = getTooltipAttributes(el);\n if (disabled) return;\n\n const popover = getOrCreatePopover(el);\n\n try {\n popover.showPopover();\n el._open = true;\n\n updatePosition(el);\n setupAutoUpdate(el);\n listenForEscape(el);\n } catch (e) {\n console.warn('[ty-tooltip] Failed to show popover', e);\n }\n}\n\n/** Hide immediately (no delay). */\nfunction hideTooltip(el: TyTooltip): void {\n stopListeningForEscape(el);\n const popover = popoverElements.get(el);\n if (!popover) return;\n\n try {\n popover.hidePopover();\n el._open = false;\n cleanupAutoUpdate(el);\n } catch (e) {\n // Already hidden, ignore\n }\n}\n\nfunction scheduleShow(el: TyTooltip): void {\n const state = getTimeoutState(el);\n const { delay } = getTooltipAttributes(el);\n\n clearTimeouts(el);\n state.showTimeout = window.setTimeout(() => showTooltip(el), delay);\n}\n\nfunction scheduleHide(el: TyTooltip): void {\n const state = getTimeoutState(el);\n\n clearTimeouts(el);\n state.hideTimeout = window.setTimeout(() => hideTooltip(el), 200);\n}\n\nfunction setupEvents(el: TyTooltip): void {\n const anchor = getAnchorElement(el);\n if (!anchor) return;\n anchorElements.set(el, anchor);\n\n const handleEnter = () => scheduleShow(el);\n const handleLeave = () => scheduleHide(el);\n const handleFocus = () => scheduleShow(el);\n const handleBlur = () => scheduleHide(el);\n\n anchor.addEventListener('mouseenter', handleEnter);\n anchor.addEventListener('mouseleave', handleLeave);\n anchor.addEventListener('focusin', handleFocus);\n anchor.addEventListener('focusout', handleBlur);\n\n eventCleanup.set(el, () => {\n anchor.removeEventListener('mouseenter', handleEnter);\n anchor.removeEventListener('mouseleave', handleLeave);\n anchor.removeEventListener('focusin', handleFocus);\n anchor.removeEventListener('focusout', handleBlur);\n });\n}\n\n/** Cleanup all resources, including the popover element. */\nfunction cleanup(el: TyTooltip): void {\n clearTimeouts(el);\n cleanupAutoUpdate(el);\n stopListeningForEscape(el);\n\n const eventsCleanup = eventCleanup.get(el);\n if (eventsCleanup) {\n eventsCleanup();\n eventCleanup.delete(el);\n }\n\n // Strip aria-describedby before removing the popover it points at — by\n // this point (disconnectedCallback) el.parentElement is already null, so\n // this must use the cached anchor, not getAnchorElement(el).\n const popover = popoverElements.get(el);\n const anchor = anchorElements.get(el);\n if (popover && anchor) {\n removeDescribedBy(anchor, popover.id);\n }\n if (popover) {\n popover.remove();\n popoverElements.delete(el);\n }\n\n anchorElements.delete(el);\n timeoutState.delete(el);\n}\n\n/**\n * TyTooltip Web Component\n */\nexport class TyTooltip extends HTMLElement {\n /** Internal open state */\n _open = false;\n\n static get observedAttributes() {\n return ['placement', 'offset', 'delay', 'disabled', 'flavor'];\n }\n\n constructor() {\n super();\n this.attachShadow({ mode: 'open' });\n }\n\n connectedCallback() {\n this._open = false;\n\n // Styles are needed for :host { display: contents }\n ensureStyles(this.shadowRoot!, tooltipStyles);\n\n setupEvents(this);\n\n // Eagerly create the (hidden) popover so role=\"tooltip\" + the anchor's\n // aria-describedby exist from connect, not only after the first show —\n // a keyboard user tabbing to the trigger must not wait out the hover\n // delay just to get an accessible description.\n getOrCreatePopover(this);\n }\n\n disconnectedCallback() {\n cleanup(this);\n }\n\n attributeChangedCallback(name: string, _oldValue: string | null, newValue: string | null) {\n // Restyle the popover on flavor change even while hidden — it's cached\n // in popoverElements once created, so a change made while closed would\n // otherwise be silently lost until the element is torn down.\n if (name === 'flavor') {\n const popover = popoverElements.get(this);\n if (popover) {\n const flavor = validateFlavor(newValue);\n applyFlavorStyles(popover, flavor);\n }\n }\n\n // Close tooltip if disabled\n if (name === 'disabled' && newValue !== null) {\n hideTooltip(this);\n }\n }\n}\n\nif (!customElements.get('ty-tooltip')) {\n customElements.define('ty-tooltip', TyTooltip);\n}\n","/**\n * CSS-based scroll prevention.\n *\n * Prevents page scrolling via CSS rather than event cancellation — no event\n * manipulation, no interference with component keyboard navigation, scroll\n * position preserved. Reference-counted so multiple components can lock at once.\n */\n\ninterface LockState {\n locked: boolean;\n scrollY: number;\n activeLocks: Set<string>;\n}\n\nconst lockState: LockState = {\n locked: false,\n scrollY: 0,\n activeLocks: new Set<string>(),\n};\n\n// Debug flag (exposed globally for testing)\ndeclare global {\n interface Window {\n tyScrollDebug?: boolean;\n }\n}\n\nfunction getBodyEl(): HTMLElement {\n return document.body;\n}\n\nfunction getDocEl(): HTMLElement {\n return document.documentElement;\n}\n\nfunction getScrollY(): number {\n return window.scrollY || getDocEl().scrollTop || 0;\n}\n\nfunction getScrollbarWidth(): number {\n return window.innerWidth - getDocEl().clientWidth;\n}\n\n/**\n * Lock body scrolling using overflow: hidden on <html>.\n *\n * Avoids position: fixed on <body> which breaks centered/max-width body layouts\n * by snapping the body to the left edge. Using <html> instead leaves body layout\n * untouched while still preventing scroll.\n */\nfunction lockBodyFixed(): void {\n if (lockState.locked) return;\n\n const scrollbarWidth = getScrollbarWidth();\n const docEl = getDocEl();\n\n if (window.tyScrollDebug) {\n console.log('🔒 Locking body scroll:', { scrollbarWidth });\n }\n\n lockState.scrollY = getScrollY();\n lockState.locked = true;\n\n docEl.style.overflow = 'hidden';\n\n // Compensate for scrollbar disappearing to prevent layout shift\n if (scrollbarWidth > 0) {\n docEl.style.paddingRight = `${scrollbarWidth}px`;\n }\n\n docEl.classList.add('ty-scroll-locked');\n}\n\n/**\n * Unlock body scrolling\n */\nfunction unlockBodyFixed(): void {\n if (!lockState.locked) return;\n\n const docEl = getDocEl();\n\n if (window.tyScrollDebug) {\n console.log('🔓 Unlocking body scroll');\n }\n\n docEl.classList.remove('ty-scroll-locked');\n docEl.style.overflow = '';\n docEl.style.paddingRight = '';\n\n lockState.locked = false;\n}\n\n/**\n * Lock scrolling for a specific component.\n * \n * Multiple components can lock scrolling simultaneously.\n * Scroll remains locked until ALL components unlock.\n * \n * @param componentId - Unique identifier for the component\n */\nexport function lockScroll(componentId: string): void {\n if (lockState.activeLocks.has(componentId)) return;\n\n lockState.activeLocks.add(componentId);\n\n if (lockState.activeLocks.size === 1) {\n lockBodyFixed();\n }\n}\n\n/**\n * Unlock scrolling for a specific component.\n * \n * Scroll remains locked if other components still have locks active.\n * \n * @param componentId - Unique identifier for the component\n */\nexport function unlockScroll(componentId: string): void {\n if (!lockState.activeLocks.has(componentId)) return;\n\n lockState.activeLocks.delete(componentId);\n\n if (lockState.activeLocks.size === 0) {\n unlockBodyFixed();\n }\n}\n\n/**\n * Emergency unlock - removes all scroll locks immediately.\n * \n * Use this for cleanup or error recovery scenarios.\n */\nexport function forceUnlockAll(): void {\n lockState.activeLocks.clear();\n unlockBodyFixed();\n}\n\n/**\n * Enable scroll lock debugging - useful for testing and development\n */\nexport function enableDebug(): void {\n console.log('🔍 CSS Scroll lock debugging enabled');\n window.tyScrollDebug = true;\n}\n\n/**\n * Disable scroll lock debugging\n */\nexport function disableDebug(): void {\n console.log('🔍 CSS Scroll lock debugging disabled');\n window.tyScrollDebug = false;\n}\n\n/**\n * Get the set of currently active component locks.\n * \n * @returns Set of component IDs that currently have scroll locked\n */\nexport function getActiveLocks(): Set<string> {\n return new Set(lockState.activeLocks);\n}\n\n/**\n * Check if scrolling is currently locked.\n * \n * @returns true if any component has scroll locked\n */\nexport function isLocked(): boolean {\n return lockState.locked;\n}\n\n/**\n * Check if scrolling is locked by a specific component.\n * \n * @param componentId - Component identifier to check\n * @returns true if this specific component has scroll locked\n */\nexport function isLockedBy(componentId: string): boolean {\n return lockState.activeLocks.has(componentId);\n}\n\n/**\n * Get the complete lock state for debugging.\n * \n * @returns Current state including scroll position and active locks\n */\nexport function getLockState(): Readonly<{\n locked: boolean;\n scrollY: number;\n activeLocks: string[];\n}> {\n return {\n locked: lockState.locked,\n scrollY: lockState.scrollY,\n activeLocks: Array.from(lockState.activeLocks),\n };\n}\n","/**\n * Popup Component Styles\n * \n * Popup component with dropdown-like behavior and tooltip positioning.\n * Uses dialog element for top layer rendering like dropdown and date-picker.\n */\n\nexport const popupStyles = `\n.popup-dialog {\n position: fixed;\n top: 0;\n left: 0;\n\n /* Reset dialog defaults */\n margin: 0;\n border: none;\n background: transparent;\n max-width: none;\n max-height: none;\n\n /* Shadow infrastructure - provide space for user shadows */\n padding: var(--popup-padding, 16px);\n\n /* Hidden by default - even when [open] (for positioning phase) */\n visibility: hidden;\n opacity: 0;\n /* NO TRANSFORM here - apply only when animating to avoid measurement errors! */\n\n transition:\n opacity var(--ty-popup-duration, 180ms) var(--ty-popup-ease, cubic-bezier(0.34, 1.56, 0.64, 1)),\n visibility var(--ty-popup-duration, 180ms) var(--ty-popup-ease, cubic-bezier(0.34, 1.56, 0.64, 1)),\n transform var(--ty-popup-duration, 180ms) var(--ty-popup-ease, cubic-bezier(0.34, 1.56, 0.64, 1));\n\n /* Prevent interactions when hidden */\n pointer-events: none;\n}\n\n/* Apply position variables only when position is calculated (like dropdown) */\n.popup-dialog.position-calculated {\n top: var(--popup-y, 0px);\n left: var(--popup-x, 0px);\n}\n\n/* Entrance prep (right before .open): scale + a short slide from the anchor\n side. data-side is the RESOLVED side (post-flip), set by updatePosition. */\n.popup-dialog.preparing-animation {\n transform: scale(var(--ty-popup-scale, 0.96));\n}\n\n/* The prep pose must land instantly. Transitioned, it had barely left\n scale(1) when .open arrived a frame later, so the entrance (and any\n springy --ty-popup-ease) ran over almost no distance. */\n.popup-dialog.preparing-animation:not(.open) {\n transition: none;\n}\n\n.popup-dialog[data-side=\"bottom\"].preparing-animation:not(.open) {\n transform: translateY(-6px) scale(var(--ty-popup-scale, 0.96));\n}\n\n.popup-dialog[data-side=\"top\"].preparing-animation:not(.open) {\n transform: translateY(6px) scale(var(--ty-popup-scale, 0.96));\n}\n\n.popup-dialog[data-side=\"left\"].preparing-animation:not(.open) {\n transform: translateX(6px) scale(var(--ty-popup-scale, 0.96));\n}\n\n.popup-dialog[data-side=\"right\"].preparing-animation:not(.open) {\n transform: translateX(-6px) scale(var(--ty-popup-scale, 0.96));\n}\n\n.popup-dialog.open {\n visibility: visible;\n opacity: 1;\n transform: scale(1);\n pointer-events: auto;\n}\n\n/* Make dialog backdrop transparent like dropdown/date-picker */\n.popup-dialog::backdrop {\n background: transparent;\n}\n\n/* Neutral structural container — users control all visuals via slotted content */\n.popup-container {\n display: contents;\n}\n\n/* Slotted content defines its own styling */\n#popup-content {\n display: contents;\n}\n\n/* Users have complete control over the popup's appearance; only essential\n positioning is imposed here. */\n#popup-content ::slotted(*) {\n position: relative;\n\n /* Prevent content from being too wide - still helpful */\n max-width: min(400px, 90vw);\n max-height: min(500px, 80vh);\n overflow: auto;\n}\n`;\n","/**\n * Popup Component - click-triggered popup positioned against its PARENT element\n * (the anchor). Stays open for interaction; closes on outside click or ESC.\n */\n\nimport { findBestPosition, preferenceChain, type Placement } from '../utils/positioning.js';\nimport { lockScroll, unlockScroll } from '../utils/scroll-lock.js';\nimport { ensureStyles } from '../utils/styles.js';\nimport { popupStyles } from '../styles/popup.js';\n\n/**\n * Popup attributes configuration\n */\nexport interface PopupAttributes {\n manual: boolean; // Override click trigger\n disableClose: boolean; // Disable auto-close\n placement: Placement; // Position preference\n offset: number; // Spacing from anchor\n}\n\n// WeakMaps for state management\nconst anchorClickHandlers = new WeakMap<TyPopup, (e: Event) => void>();\nconst anchorKeyClickHandlers = new WeakMap<TyPopup, (e: Event) => void>();\nconst outsideClickHandlers = new WeakMap<TyPopup, (e: Event) => void>();\n/** Pending close-out (exit transition) per popup, so a reopen can cancel it. */\nconst closeTimers = new WeakMap<TyPopup, ReturnType<typeof setTimeout>>();\nconst escapeHandlers = new WeakMap<TyPopup, (e: KeyboardEvent) => void>();\nconst closeRequestHandlers = new WeakMap<TyPopup, (e: CustomEvent) => void>();\nconst popupIds = new WeakMap<TyPopup, string>(); // Store popup ID for scroll locking\n/** Opened by a pointer press whose click hasn't come yet. */\nconst pointerPresses = new WeakSet<TyPopup>();\n\nfunction parseBoolAttr(el: Element, name: string): boolean {\n return el.hasAttribute(name);\n}\n\nfunction parseIntAttr(el: Element, name: string, defaultValue: number): number {\n const value = el.getAttribute(name);\n if (value === null) return defaultValue;\n const parsed = parseInt(value, 10);\n return isNaN(parsed) ? defaultValue : parsed;\n}\n\nfunction getPopupAttributes(el: TyPopup): PopupAttributes {\n return {\n manual: parseBoolAttr(el, 'manual'),\n disableClose: parseBoolAttr(el, 'disable-close'),\n placement: (el.getAttribute('placement') || 'bottom') as Placement,\n offset: parseIntAttr(el, 'offset', 8),\n };\n}\n\n/**\n * Get the parent element as anchor (like tooltip)\n */\nfunction getAnchorElement(el: TyPopup): HTMLElement | null {\n return el.parentElement;\n}\n\nfunction getPopupDialog(shadowRoot: ShadowRoot): HTMLDialogElement | null {\n return shadowRoot.querySelector<HTMLDialogElement>('.popup-dialog');\n}\n\n/**\n * Get or create a unique popup ID for scroll locking\n */\nfunction getPopupId(el: TyPopup): string {\n let id = popupIds.get(el);\n if (!id) {\n id = `popup-${el.id || Math.random().toString(36).substr(2, 9)}`;\n popupIds.set(el, id);\n }\n return id;\n}\n\nfunction updatePosition(el: TyPopup): void {\n const { placement, offset } = getPopupAttributes(el);\n const shadowRoot = el.shadowRoot;\n const anchor = getAnchorElement(el);\n const dialog = shadowRoot ? getPopupDialog(shadowRoot) : null;\n\n if (!anchor || !dialog) return;\n\n // Handles all 12 placements. The old hand-written chain only matched the four\n // bare sides, so 'bottom-start' & co. fell through to the default and the\n // requested alignment was silently dropped.\n const preferences: Placement[] = preferenceChain(placement);\n\n const positionData = findBestPosition({\n targetEl: anchor,\n floatingEl: dialog,\n preferences,\n offset,\n padding: 8,\n containerPadding: 16,\n });\n\n el.style.setProperty('--popup-x', `${positionData.x}px`);\n el.style.setProperty('--popup-y', `${positionData.y}px`);\n\n // Resolved side (post-flip) drives the directional entrance slide in CSS\n dialog.dataset.side = positionData.placement.split('-')[0];\n\n // Add position class like dropdown does (this applies the variables)\n dialog.classList.add('position-calculated');\n}\n\n/**\n * Close popup with clean animation -> position reset -> hide sequence\n */\nfunction closePopup(el: TyPopup, force = false): void {\n const { disableClose } = getPopupAttributes(el);\n if (!force && disableClose) return;\n\n const shadowRoot = el.shadowRoot;\n const dialog = shadowRoot ? getPopupDialog(shadowRoot) : null;\n if (!dialog) return;\n\n // Don't unlock scroll here: the dialog's `open` watcher (render) does,\n // once it is closed\n\n dialog.classList.remove('open');\n dialog.classList.remove('preparing-animation');\n\n const anchor = getAnchorElement(el);\n if (anchor?.hasAttribute('aria-haspopup')) anchor.setAttribute('aria-expanded', 'false');\n\n // Wait out the exit transition: the longest of the dialog's transition\n // durations, so a custom --ty-popup-duration isn't cut short.\n const exitMs = Math.max(0, ...getComputedStyle(dialog).transitionDuration\n .split(',').map((d) => parseFloat(d) * (d.trim().endsWith('ms') ? 1 : 1000)));\n clearTimeout(closeTimers.get(el));\n closeTimers.set(el, setTimeout(() => {\n closeTimers.delete(el);\n dialog.classList.remove('position-calculated');\n dialog.close(); // the `open` watcher unlocks; the 'close' listener emits 'close'\n }, exitMs + 20));\n}\n\n/**\n * Open popup with dialog open but hidden → position → animate sequence\n */\nfunction openPopup(el: TyPopup): void {\n const shadowRoot = el.shadowRoot;\n const dialog = shadowRoot ? getPopupDialog(shadowRoot) : null;\n if (!dialog) return;\n\n // Already open (or opening): one popup, one 'open' event. Called while it\n // is closing out, cancel the close and show it again.\n const anchor = getAnchorElement(el);\n if (dialog.open) {\n const pending = closeTimers.get(el);\n if (pending !== undefined) {\n clearTimeout(pending);\n closeTimers.delete(el);\n dialog.classList.add('open');\n if (anchor?.hasAttribute('aria-haspopup')) anchor.setAttribute('aria-expanded', 'true');\n }\n return;\n }\n\n // Lock scroll using the stored popup ID\n const popupId = getPopupId(el);\n lockScroll(popupId);\n\n // Step 1: showModal() immediately - dialog gets [open] attribute and proper layout\n dialog.showModal();\n\n if (anchor?.hasAttribute('aria-haspopup')) anchor.setAttribute('aria-expanded', 'true');\n\n // Step 2: Wait for layout to settle, then measure and position\n requestAnimationFrame(() => {\n // Now dialog has [open] and accurate dimensions\n // Calculate and apply position while dialog is hidden by CSS\n updatePosition(el);\n\n // Step 3: Add scale transform for animation prep\n dialog.classList.add('preparing-animation');\n // Commit the prep pose before .open so the entrance starts from it.\n void dialog.offsetWidth;\n\n // Step 4: Third RAF - THEN add open class for smooth scale animation\n requestAnimationFrame(() => {\n // Now animate: scale(0.95) → scale(1) + opacity + visibility\n dialog.classList.add('open');\n\n el.dispatchEvent(new CustomEvent('open'));\n });\n });\n}\n\nfunction togglePopup(el: TyPopup): void {\n const shadowRoot = el.shadowRoot;\n const dialog = shadowRoot ? getPopupDialog(shadowRoot) : null;\n if (!dialog) return;\n\n if (dialog.classList.contains('open')) {\n closePopup(el);\n } else {\n openPopup(el);\n }\n}\n\nfunction handleAnchorClick(el: TyPopup, event: Event): void {\n event.preventDefault();\n event.stopPropagation();\n togglePopup(el);\n}\n\nfunction handleOutsideClick(el: TyPopup, event: Event): void {\n event.stopPropagation();\n const shadowRoot = el.shadowRoot;\n const dialog = shadowRoot ? getPopupDialog(shadowRoot) : null;\n\n // Close if clicking on dialog backdrop (not popup content)\n if (dialog && event.target === dialog) {\n event.preventDefault();\n closePopup(el);\n }\n}\n\n/**\n * The key comes from inside a modal dialog nested in the popup that is still\n * open (a date-picker calendar, a ty-select list, a ty-modal). That one is on\n * top, so the key is its own: leave it alone, propagation included, since\n * those components listen on document. Same rule as ty-modal's.\n */\nfunction fromNestedDialog(el: TyPopup, event: Event): boolean {\n const dialog = el.shadowRoot ? getPopupDialog(el.shadowRoot) : null;\n for (const node of event.composedPath()) {\n if (node === dialog) return false;\n if (node instanceof HTMLDialogElement && node.matches(':modal')) return true;\n }\n return false;\n}\n\nfunction handleEscape(el: TyPopup, event: KeyboardEvent): void {\n if (fromNestedDialog(el, event)) return;\n event.stopPropagation();\n if (event.key === 'Escape') {\n const { disableClose } = getPopupAttributes(el);\n if (disableClose) {\n event.preventDefault();\n } else {\n closePopup(el);\n }\n }\n}\n\n/**\n * Handle close requests from inside popup content\n */\nfunction handleCloseRequest(el: TyPopup, event: CustomEvent): void {\n event.stopPropagation();\n closePopup(el, true);\n}\n\n/**\n * Setup click listener on anchor element (unless manual=true)\n */\nfunction setupAnchorEvents(el: TyPopup): void {\n const { manual } = getPopupAttributes(el);\n const anchor = getAnchorElement(el);\n\n if (!anchor || manual) return;\n\n // Screen reader gets no other signal that clicking this opens something —\n // the popup itself is a real <dialog> (showModal()), which already gives\n // it role=\"dialog\" + focus-trap for free, so only the trigger needs this.\n anchor.setAttribute('aria-haspopup', 'dialog');\n if (!anchor.hasAttribute('aria-expanded')) anchor.setAttribute('aria-expanded', 'false');\n\n // Remove any existing listeners first\n const existingHandler = anchorClickHandlers.get(el);\n if (existingHandler) {\n anchor.removeEventListener('pointerdown', existingHandler);\n }\n const existingKeyHandler = anchorKeyClickHandlers.get(el);\n if (existingKeyHandler) {\n anchor.removeEventListener('click', existingKeyHandler);\n }\n\n const handler = (e: Event) => {\n pointerPresses.add(el);\n handleAnchorClick(el, e);\n };\n anchorClickHandlers.set(el, handler);\n anchor.addEventListener('pointerdown', handler);\n\n // pointerdown covers mouse/touch; keyboard activation (Enter/Space on a\n // focused anchor) and anchor.click() fire only 'click', with detail === 0\n // — without this, a keyboard-only user could focus the anchor but had no\n // way to open the popup (same gap fixed in ty-tabs). A ty-button anchor\n // emits a CustomEvent click instead, the native one in detail.originalEvent\n // (a <label> around it gets there too).\n const keyHandler = (e: Event) => {\n // The click that ends a pointer press: it already toggled on pointerdown.\n // Detail alone can't tell: a ty-button re-presses its inner button, with\n // detail 0, for a press on its padding or border.\n if (pointerPresses.delete(el)) return;\n const d = (e as CustomEvent).detail;\n const click: Event = typeof d === 'number' ? e : d?.originalEvent ?? e;\n if ((click as MouseEvent).detail !== 0) return;\n // A key press on a control in the popup content bubbles up to the anchor\n // too. Not a press on the anchor: a mouse press there doesn't toggle either.\n if (click.composedPath().includes(el)) return;\n handleAnchorClick(el, e);\n };\n anchorKeyClickHandlers.set(el, keyHandler);\n anchor.addEventListener('click', keyHandler);\n}\n\nfunction cleanupAnchorEvents(el: TyPopup): void {\n const anchor = getAnchorElement(el);\n const handler = anchorClickHandlers.get(el);\n\n if (anchor && handler) {\n anchor.removeEventListener('pointerdown', handler);\n anchorClickHandlers.delete(el);\n }\n const keyHandler = anchorKeyClickHandlers.get(el);\n if (anchor && keyHandler) {\n anchor.removeEventListener('click', keyHandler);\n anchorKeyClickHandlers.delete(el);\n }\n anchor?.removeAttribute('aria-haspopup');\n anchor?.removeAttribute('aria-expanded');\n}\n\nfunction render(el: TyPopup): void {\n const shadowRoot = el.shadowRoot;\n if (!shadowRoot) return;\n\n const existingDialog = getPopupDialog(shadowRoot);\n\n ensureStyles(shadowRoot, { css: popupStyles, id: 'ty-popup' });\n\n if (!existingDialog) {\n const dialog = document.createElement('dialog');\n const container = document.createElement('div');\n const content = document.createElement('slot');\n\n dialog.className = 'popup-dialog';\n container.className = 'popup-container';\n content.id = 'popup-content';\n\n shadowRoot.appendChild(dialog);\n dialog.appendChild(container);\n container.appendChild(content);\n\n el.style.setProperty('--popup-x', '0px');\n el.style.setProperty('--popup-y', '0px');\n\n const outsideHandler = (e: Event) => handleOutsideClick(el, e);\n outsideClickHandlers.set(el, outsideHandler);\n dialog.addEventListener('pointerdown', outsideHandler);\n\n const escapeHandler = (e: KeyboardEvent) => handleEscape(el, e);\n escapeHandlers.set(el, escapeHandler);\n el.addEventListener('keydown', escapeHandler);\n\n // Closed, by us or not (Escape: the browser's cancel; a ty-modal around\n // it closing): tidy up as the `open` attribute goes. The `close` event\n // comes a task later: the page would stay locked that long, and a popup\n // reopened meanwhile would lose its new lock to it.\n new MutationObserver(() => {\n if (dialog.open) return;\n // Closed before the close-out timer ran (Escape). Left pending, the\n // timer would shut it again right after a reopen.\n clearTimeout(closeTimers.get(el));\n closeTimers.delete(el);\n // A press whose click never came (a touch that turned into a pan)\n pointerPresses.delete(el);\n unlockScroll(getPopupId(el));\n dialog.classList.remove('open');\n dialog.classList.remove('preparing-animation');\n const anchor = getAnchorElement(el);\n if (anchor?.hasAttribute('aria-haspopup')) anchor.setAttribute('aria-expanded', 'false');\n }).observe(dialog, { attributes: true, attributeFilter: ['open'] });\n\n dialog.addEventListener('close', () => {\n // ponytail: non-bubbling, like native <dialog> — bubbling close from\n // a popup inside a ty-modal would trip the modal's own close listener.\n el.dispatchEvent(new CustomEvent('close'));\n });\n }\n\n el.closePopup = () => closePopup(el, true);\n el.openPopup = () => openPopup(el);\n el.togglePopup = () => togglePopup(el);\n\n // render() runs again on every attribute change: one listener, not one each\n const existingCloseRequest = closeRequestHandlers.get(el);\n if (existingCloseRequest) el.removeEventListener('ty:close-popup', existingCloseRequest as EventListener);\n const closeRequestHandler = (e: CustomEvent) => handleCloseRequest(el, e);\n closeRequestHandlers.set(el, closeRequestHandler);\n el.addEventListener('ty:close-popup', closeRequestHandler as EventListener);\n\n setupAnchorEvents(el);\n}\n\nfunction cleanup(el: TyPopup): void {\n // Force unlock scroll if popup is being removed\n const popupId = popupIds.get(el);\n if (popupId) {\n unlockScroll(popupId);\n popupIds.delete(el);\n }\n\n cleanupAnchorEvents(el);\n\n const shadowRoot = el.shadowRoot;\n const dialog = shadowRoot ? getPopupDialog(shadowRoot) : null;\n\n if (dialog) {\n const outsideHandler = outsideClickHandlers.get(el);\n if (outsideHandler) {\n dialog.removeEventListener('pointerdown', outsideHandler);\n outsideClickHandlers.delete(el);\n }\n }\n\n const escapeHandler = escapeHandlers.get(el);\n if (escapeHandler) {\n el.removeEventListener('keydown', escapeHandler);\n escapeHandlers.delete(el);\n }\n\n const closeRequestHandler = closeRequestHandlers.get(el);\n if (closeRequestHandler) {\n el.removeEventListener('ty:close-popup', closeRequestHandler as EventListener);\n closeRequestHandlers.delete(el);\n }\n}\n\n/**\n * TyPopup Web Component\n */\nexport class TyPopup extends HTMLElement {\n /** Programmatic API methods */\n closePopup?: () => void;\n openPopup?: () => void;\n togglePopup?: () => void;\n\n static get observedAttributes() {\n return ['manual', 'disable-close', 'placement', 'offset'];\n }\n\n constructor() {\n super();\n this.attachShadow({ mode: 'open' });\n }\n\n connectedCallback() {\n render(this);\n }\n\n disconnectedCallback() {\n cleanup(this);\n }\n\n attributeChangedCallback(name: string, _oldValue: string | null, _newValue: string | null) {\n render(this);\n\n switch (name) {\n case 'placement':\n case 'offset':\n // Update position immediately if open and placement-related attributes change\n render(this);\n break;\n\n case 'manual':\n case 'disable-close':\n // Recreate anchor events if manual changes\n cleanupAnchorEvents(this);\n setupAnchorEvents(this);\n break;\n }\n }\n}\n\nif (!customElements.get('ty-popup')) {\n customElements.define('ty-popup', TyPopup);\n}\n","/**\n * Modal Styles\n * \n * CSS for the modal component wrapper.\n * The modal is a pure wrapper - all content styling is user-defined.\n */\n\nexport const modalStyles = `\n:host {\n display: contents;\n /* Don't interfere with layout */\n}\n\n/* Part of the modal wrapper functionality, not user content styling */\n.close-button {\n position: absolute;\n top: -8px;\n right: -8px;\n background: transparent;\n border: none;\n cursor: pointer;\n padding: 4px;\n border-radius: 4px;\n transition: var(--ty-transition-colors);\n z-index: 1;\n color: #d8d8d8;\n\n /* Remove all default browser styling that could cause outlines/borders */\n outline: none;\n box-shadow: none;\n -webkit-appearance: none;\n -moz-appearance: none;\n appearance: none;\n\n /* Remove mobile tap highlights and focus rings */\n -webkit-tap-highlight-color: transparent;\n -webkit-touch-callout: none;\n -webkit-user-select: none;\n -moz-user-select: none;\n -ms-user-select: none;\n user-select: none;\n}\n\n.close-button:hover {\n color: white;\n}\n\n/* Explicitly remove focus and active states for all interaction modes */\n.close-button:focus,\n.close-button:focus-visible,\n.close-button:focus-within,\n.close-button:active {\n outline: none !important;\n box-shadow: none !important;\n border: none !important;\n background: transparent !important;\n}\n\n/* Override hover color even in focus/active states */\n.close-button:hover,\n.close-button:focus:hover,\n.close-button:active:hover {\n color: white;\n}\n\n.close-button.hide {\n visibility: hidden;\n}\n\n/* Pure wrapper: only essential modal functionality, no styling of user content */\n.ty-modal-dialog {\n /* Reset default dialog styles */\n padding: 18px;\n border: none;\n margin: 0;\n background: transparent;\n\n /* Centered */\n position: fixed;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n\n z-index: 1000;\n overflow: hidden;\n\n /* No sizing - let user content determine size */\n max-width: 85vw;\n max-height: 90vh;\n\n outline: none;\n}\n\n/* Panel zoom-in synced with the backdrop fade (shadcn-style zoom-in-95).\n Enter-only: animating exit on a native <dialog> means delaying close(). */\n.ty-modal-dialog[open] {\n animation: ty-modal-enter var(--ty-modal-duration, 200ms) ease-out;\n}\n\n@keyframes ty-modal-enter {\n from {\n opacity: 0;\n transform: translate(-50%, -50%) scale(0.93);\n }\n\n to {\n opacity: 1;\n transform: translate(-50%, -50%) scale(1);\n }\n}\n\n/* Backdrop is part of modal functionality, not user content */\n.ty-modal-dialog::backdrop {\n background: var(--ty-modal-backdrop, rgba(0, 0, 0, 0.5));\n backdrop-filter: var(--ty-modal-backdrop-blur, blur(2px));\n animation: ty-modal-backdrop-enter var(--ty-modal-duration, 200ms) ease-out;\n}\n\n/* When backdrop is disabled */\n.ty-modal-dialog:not([data-backdrop])::backdrop {\n background: transparent;\n backdrop-filter: none;\n}\n\n/* Minimal container - no styling imposed on user content */\n.modal-content {\n color: var(--ty-text);\n}\n\n@keyframes ty-modal-backdrop-enter {\n from {\n opacity: 0;\n }\n\n to {\n opacity: 1;\n }\n}\n`;\n","/**\n * Modal Component - wrapper around the native <dialog> element providing\n * backdrop, scroll locking and keyboard interaction, without styling content.\n * Closing runs through a cancellable `beforeclose` event (unsaved-state flows).\n */\n\nimport { lockScroll, unlockScroll } from '../utils/scroll-lock.js';\nimport { coerceBoolean } from '../utils/property-manager.js';\nimport { ensureStyles } from '../utils/styles.js';\nimport { upgradeProperties } from '../utils/upgrade-properties.js';\nimport { modalStyles } from '../styles/modal.js';\n\n// Types\n\n/**\n * Modal attributes configuration\n */\nexport interface ModalAttributes {\n open: boolean; // Controls modal visibility\n backdrop: boolean; // Show backdrop behind modal\n closeOnOutsideClick: boolean; // Close on backdrop click\n closeOnEscape: boolean; // Close on ESC key\n}\n\n/**\n * How a modal close was triggered.\n */\nexport type ModalCloseReason =\n | 'programmatic' // .hide() called\n | 'backdrop' // user clicked the backdrop\n | 'escape' // user pressed ESC\n | 'close-button' // user clicked the built-in X\n | 'native'; // <dialog>.close() fired without us routing it\n\n/**\n * Modal close event detail\n */\nexport interface ModalCloseDetail {\n reason: ModalCloseReason;\n returnValue?: string; // Optional return value from dialog\n}\n\n/**\n * Modal beforeclose event detail — fired *before* the modal closes. The event\n * is cancellable; consumers can call `event.preventDefault()` to abort the\n * close, render their own UI (e.g. a styled \"Discard changes?\" prompt), and\n * later call `.hide()` themselves when ready.\n */\nexport interface ModalBeforeCloseDetail {\n reason: ModalCloseReason;\n}\n\n// WeakMaps for State Management\n\nconst backdropClickHandlers = new WeakMap<TyModal, (e: Event) => void>();\nconst escapeKeyHandlers = new WeakMap<TyModal, (e: KeyboardEvent) => void>();\nconst closeButtonHandlers = new WeakMap<TyModal, (e: Event) => void>();\nconst hoverEnterHandlers = new WeakMap<TyModal, (e: Event) => void>();\nconst hoverLeaveHandlers = new WeakMap<TyModal, (e: Event) => void>();\nconst modalIds = new WeakMap<TyModal, string>(); // Store unique modal ID for scroll locking\n// Why the modal is closing, handed from closeModal() to the render() pass that\n// the `open` attribute removal triggers — otherwise `close` can only ever\n// report 'programmatic' and the reason the consumer saw in `beforeclose`\n// (backdrop / escape / close-button) is lost.\nconst pendingCloseReasons = new WeakMap<TyModal, ModalCloseReason>();\n\n// Constants\n\n/** Lucide X icon for the close button. */\nconst CLOSE_ICON = `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"lucide lucide-x-icon lucide-x\"><path d=\"M18 6 6 18\"/><path d=\"m6 6 12 12\"/></svg>`;\n\n// Helper Functions\n\n/**\n * Boolean attribute semantics: presence -> true, explicit 'false' -> false.\n */\nfunction parseBoolAttr(el: Element, name: string): boolean {\n if (!el.hasAttribute(name)) {\n return false;\n }\n \n const value = el.getAttribute(name);\n \n if (value !== null && value.toLowerCase() === 'false') {\n return false;\n }\n \n return true;\n}\n\nfunction getModalAttributes(el: TyModal): ModalAttributes {\n return {\n open: parseBoolAttr(el, 'open'),\n // The backdrop is the default; no-backdrop names the deviation (see prevent-* below).\n backdrop: !parseBoolAttr(el, 'no-backdrop'),\n // Closing is the default, so the HTML-idiomatic switch is a presence\n // boolean naming the DEVIATION: <ty-modal prevent-outside-click>.\n //\n // parseBoolAttr (not hasAttribute) on purpose, but NOT a documented API:\n // a safety net for generated markup — a server template rendering\n // prevent-escape=\"{{ falsy }}\", or a framework that stringifies `false`\n // instead of omitting the attribute.\n closeOnOutsideClick: !parseBoolAttr(el, 'prevent-outside-click'),\n closeOnEscape: !parseBoolAttr(el, 'prevent-escape'),\n };\n}\n\nfunction getModalDialog(shadowRoot: ShadowRoot): HTMLDialogElement | null {\n return shadowRoot.querySelector<HTMLDialogElement>('.ty-modal-dialog');\n}\n\n/**\n * Get or create a unique modal ID for scroll locking\n */\nfunction getModalId(el: TyModal): string {\n let id = modalIds.get(el);\n if (!id) {\n id = `modal-${el.id || Math.random().toString(36).slice(2, 11)}`;\n modalIds.set(el, id);\n }\n return id;\n}\n\n/**\n * Check if device is mobile (for hover behavior)\n */\nfunction isMobile(): boolean {\n return window.innerWidth < 768 || navigator.maxTouchPoints > 0;\n}\n\nfunction dispatchModalEvent(el: TyModal, eventType: string, detail: unknown): void {\n // Non-bubbling, like the native <dialog> events these mirror. A modal opened\n // from inside another modal is a light-DOM descendant of the outer one, so a\n // bubbling `close` would land on the outer modal's own close listener and\n // take both down. Listen on the element itself.\n const event = new CustomEvent(eventType, {\n detail,\n cancelable: true,\n });\n el.dispatchEvent(event);\n}\n\n// Dialog Structure Creation\n\nfunction ensureInternalDialog(shadowRoot: ShadowRoot): HTMLDialogElement {\n let dialog = getModalDialog(shadowRoot);\n \n if (!dialog) {\n dialog = document.createElement('dialog');\n const closeButton = document.createElement('button');\n const contentDiv = document.createElement('div');\n const slot = document.createElement('slot');\n \n dialog.className = 'ty-modal-dialog';\n \n closeButton.className = 'close-button';\n closeButton.type = 'button';\n closeButton.setAttribute('aria-label', 'Close modal');\n closeButton.innerHTML = CLOSE_ICON;\n \n contentDiv.className = 'modal-content';\n contentDiv.appendChild(slot);\n \n dialog.appendChild(closeButton);\n dialog.appendChild(contentDiv);\n shadowRoot.appendChild(dialog);\n }\n \n return dialog;\n}\n\n// Event Handlers\n\n/**\n * Close modal with cancellable beforeclose lifecycle.\n *\n * 1. Emit `beforeclose` (cancellable, bubbles, composed). Consumers can\n * `event.preventDefault()` to abort the close — render your own UI for\n * unsaved-state flows.\n * 2. Remove the `open` attribute, which triggers the actual close.\n *\n * Callers pass `reason` so consumers can decide differently based on intent\n * (e.g. \"OK to discard via ESC, but not via .hide() during a save\").\n */\nfunction closeModal(\n el: TyModal,\n reason: ModalCloseReason = 'programmatic',\n opts?: { force?: boolean }\n): void {\n const shadowRoot = el.shadowRoot;\n const dialog = shadowRoot ? getModalDialog(shadowRoot) : null;\n\n if (!dialog || !dialog.open) return;\n\n // `force: true` bypasses the cancellable event. Used by consumers AFTER\n // they've shown their own confirm UI and the user said \"yes, close\" —\n // calling `.hide()` again without force would re-trigger their intercept.\n if (!opts?.force) {\n const beforeClose = new CustomEvent<ModalBeforeCloseDetail>('beforeclose', {\n detail: { reason },\n cancelable: true,\n });\n el.dispatchEvent(beforeClose);\n if (beforeClose.defaultPrevented) return;\n }\n\n // Remove open attribute (triggers actual close, which emits `close`).\n pendingCloseReasons.set(el, reason);\n el.removeAttribute('open');\n}\n\nfunction openModal(el: TyModal): void {\n el.setAttribute('open', 'true');\n}\n\nfunction handleBackdropClick(el: TyModal, event: Event): void {\n event.stopPropagation();\n const shadowRoot = el.shadowRoot;\n const dialog = shadowRoot ? getModalDialog(shadowRoot) : null;\n \n // Only close if clicking on dialog backdrop (not content)\n if (dialog && event.target === dialog) {\n event.preventDefault();\n closeModal(el, 'backdrop');\n }\n}\n\n/**\n * The key comes from inside a modal dialog nested in this one that is still\n * open — a ty-select list, a date-picker calendar, a ty-popup. That one is on\n * top, so the key is its own (native nested dialogs close top-down): leave it\n * alone entirely, propagation included, since those components listen on\n * document.\n */\nfunction fromNestedDialog(dialog: HTMLDialogElement, event: Event): boolean {\n for (const node of event.composedPath()) {\n if (node === dialog) return false;\n if (node instanceof HTMLDialogElement && node.matches(':modal')) return true;\n }\n return false;\n}\n\n/**\n * Close the modal dialogs still open inside the modal's content (a select\n * list, a calendar, a popup, a nested modal). Each sits in the top layer on\n * its own, so closing the modal would leave it open: hidden along with the\n * modal, yet still modal (the page stays inert) and still holding its scroll\n * lock. The components watch their dialog and tidy up after it. A nested\n * ty-modal closes its own way: a no-backdrop one isn't `:modal` but holds a\n * lock too. Content a wrapper component slots into the modal from its own\n * light DOM counts as well.\n */\nfunction closeNestedDialogs(root: ParentNode, seen = new WeakSet<Element>()): void {\n const close = (node: Element) => {\n if (seen.has(node)) return;\n seen.add(node);\n if (node instanceof TyModal && node.open) node.removeAttribute('open');\n if (node instanceof HTMLDialogElement && node.matches(':modal')) node.close();\n if (node.shadowRoot) closeNestedDialogs(node.shadowRoot, seen);\n if (node instanceof HTMLSlotElement) {\n for (const assigned of node.assignedElements({ flatten: true })) {\n close(assigned);\n closeNestedDialogs(assigned, seen);\n }\n }\n };\n root.querySelectorAll('*').forEach(close);\n}\n\nfunction handleEscapeKey(el: TyModal, event: KeyboardEvent): void {\n const dialog = event.currentTarget as HTMLDialogElement;\n if (fromNestedDialog(dialog, event)) return;\n event.stopPropagation();\n if (event.key === 'Escape') {\n event.preventDefault();\n closeModal(el, 'escape');\n }\n}\n\nfunction handleCloseButtonClick(el: TyModal, event: Event): void {\n event.preventDefault();\n event.stopPropagation();\n closeModal(el, 'close-button');\n}\n\nfunction handleHoverEnter(_el: TyModal, event: Event): void {\n const content = event.currentTarget as HTMLElement;\n const dialog = content.closest('.ty-modal-dialog');\n if (dialog) {\n const closeButton = dialog.querySelector<HTMLElement>('.close-button');\n if (closeButton) {\n closeButton.classList.add('hide');\n }\n }\n}\n\nfunction handleHoverLeave(_el: TyModal, event: Event): void {\n const content = event.currentTarget as HTMLElement;\n const dialog = content.closest('.ty-modal-dialog');\n if (dialog) {\n const closeButton = dialog.querySelector<HTMLElement>('.close-button');\n if (closeButton) {\n closeButton.classList.remove('hide');\n }\n }\n}\n\nfunction setupBackdropClick(el: TyModal, dialog: HTMLDialogElement, enabled: boolean): void {\n const existingHandler = backdropClickHandlers.get(el);\n if (existingHandler) {\n dialog.removeEventListener('click', existingHandler);\n backdropClickHandlers.delete(el);\n }\n \n if (enabled) {\n const handler = (e: Event) => handleBackdropClick(el, e);\n backdropClickHandlers.set(el, handler);\n dialog.addEventListener('click', handler);\n }\n}\n\nfunction setupEscapeKey(el: TyModal, dialog: HTMLDialogElement, enabled: boolean): void {\n const existingHandler = escapeKeyHandlers.get(el);\n if (existingHandler) {\n dialog.removeEventListener('keydown', existingHandler);\n escapeKeyHandlers.delete(el);\n }\n \n if (enabled) {\n const handler = (e: KeyboardEvent) => handleEscapeKey(el, e);\n escapeKeyHandlers.set(el, handler);\n dialog.addEventListener('keydown', handler);\n } else {\n // ESC-close disabled: consume the keydown so the browser never sees a\n // close request. Without this, only the FIRST close request is\n // cancelable — the CloseWatcher anti-trap rule force-closes on a second\n // consecutive ESC (fires our close with reason 'native'). Consuming the\n // key is the standard guard-dialog approach; the Android back gesture is\n // a separate close-request path we deliberately leave force-closable, so\n // an ultimate escape hatch always remains.\n const handler = (e: KeyboardEvent) => {\n if (e.key === 'Escape' && !fromNestedDialog(dialog, e)) e.preventDefault();\n };\n escapeKeyHandlers.set(el, handler);\n dialog.addEventListener('keydown', handler);\n }\n}\n\nfunction setupCloseButton(el: TyModal, dialog: HTMLDialogElement, showButton: boolean): void {\n const closeButton = dialog.querySelector<HTMLButtonElement>('.close-button');\n if (!closeButton) return;\n \n // Show or hide close button: hidden under prevent-outside-click\n if (showButton) {\n closeButton.style.display = '';\n } else {\n closeButton.style.display = 'none';\n }\n \n const existingHandler = closeButtonHandlers.get(el);\n if (existingHandler) {\n closeButton.removeEventListener('click', existingHandler);\n closeButtonHandlers.delete(el);\n }\n \n if (showButton) {\n const handler = (e: Event) => handleCloseButtonClick(el, e);\n closeButtonHandlers.set(el, handler);\n closeButton.addEventListener('click', handler);\n }\n}\n\n/**\n * Setup close button hover handlers (desktop only)\n */\nfunction setupCloseButtonHover(el: TyModal, dialog: HTMLDialogElement): void {\n const modalContent = dialog.querySelector<HTMLElement>('.modal-content');\n if (!modalContent) return;\n \n const existingEnterHandler = hoverEnterHandlers.get(el);\n const existingLeaveHandler = hoverLeaveHandlers.get(el);\n \n if (existingEnterHandler) {\n modalContent.removeEventListener('mouseenter', existingEnterHandler);\n hoverEnterHandlers.delete(el);\n }\n \n if (existingLeaveHandler) {\n modalContent.removeEventListener('mouseleave', existingLeaveHandler);\n hoverLeaveHandlers.delete(el);\n }\n \n if (!isMobile()) {\n const enterHandler = (e: Event) => handleHoverEnter(el, e);\n const leaveHandler = (e: Event) => handleHoverLeave(el, e);\n \n hoverEnterHandlers.set(el, enterHandler);\n hoverLeaveHandlers.set(el, leaveHandler);\n \n modalContent.addEventListener('mouseenter', enterHandler);\n modalContent.addEventListener('mouseleave', leaveHandler);\n }\n}\n\n// Core Render Function\n\nfunction render(el: TyModal): void {\n const shadowRoot = el.shadowRoot;\n if (!shadowRoot) return;\n \n const attributes = getModalAttributes(el);\n const dialog = ensureInternalDialog(shadowRoot);\n const modalId = getModalId(el);\n \n ensureStyles(shadowRoot, { css: modalStyles, id: 'ty-modal' });\n \n dialog.className = 'ty-modal-dialog';\n \n if (attributes.backdrop) {\n dialog.setAttribute('data-backdrop', 'true');\n } else {\n dialog.removeAttribute('data-backdrop');\n }\n\n // Accessible name: <dialog> has an implicit role=\"dialog\" for free, but\n // nothing gives it a NAME unless the consumer's own slotted heading\n // happens to get wired up manually. Opt-in `label` attribute (same\n // pattern as ty-select/ty-date-picker's `label` prop) — unset stays\n // exactly as before (no regression, just no fix without opting in).\n const label = el.getAttribute('label');\n if (label) {\n dialog.setAttribute('aria-label', label);\n } else {\n dialog.removeAttribute('aria-label');\n }\n \n setupBackdropClick(el, dialog, attributes.closeOnOutsideClick);\n setupEscapeKey(el, dialog, attributes.closeOnEscape);\n\n // showModal() gives ESC-to-close for free — the browser fires `cancel` and\n // closes the dialog itself, bypassing our keydown handler entirely. That\n // made prevent-escape a no-op. Always intercept `cancel` and route\n // it through closeModal() so the attribute (and `beforeclose`) is honoured.\n dialog.oncancel = (event: Event) => {\n event.preventDefault();\n if (getModalAttributes(el).closeOnEscape) closeModal(el, 'escape');\n };\n setupCloseButton(el, dialog, attributes.closeOnOutsideClick);\n setupCloseButtonHover(el, dialog);\n \n if (attributes.open) {\n if (!dialog.open) {\n lockScroll(modalId);\n\n if (attributes.backdrop) {\n dialog.showModal();\n } else {\n dialog.show();\n }\n\n syncBackdropZoom();\n dispatchModalEvent(el, 'open', {});\n }\n } else {\n if (dialog.open) {\n unlockScroll(modalId);\n\n closeNestedDialogs(el);\n dialog.close();\n syncBackdropZoom();\n\n const reason = pendingCloseReasons.get(el) ?? 'programmatic';\n pendingCloseReasons.delete(el);\n\n dispatchModalEvent(el, 'close', { reason } as ModalCloseDetail);\n }\n }\n // no-zoom can flip while the modal is open\n syncBackdropZoom();\n \n // Handle dialog's native close event.\n //\n // Only the dialog's own: a bubbling `close` from a component inside it\n // (ty-select's and ty-date-picker's don't bubble, a third-party one's may)\n // would reach `onclose` too and close the whole modal with its dropdown.\n // The native dialog `close` event is not composed and targets the dialog\n // itself, so we only react when `event.target` is the dialog.\n dialog.onclose = (event: Event) => {\n if (event.target !== dialog) return;\n\n unlockScroll(modalId);\n closeNestedDialogs(el);\n\n if (el.hasAttribute('open')) {\n el.removeAttribute('open');\n dispatchModalEvent(el, 'close', {\n reason: 'native',\n returnValue: dialog.returnValue || undefined\n } as ModalCloseDetail);\n }\n syncBackdropZoom();\n };\n}\n\n/**\n * Vaul-style page zoom, on by default: while any open modal lacks `no-zoom`,\n * <html> carries .ty-modal-zoom and tyrell.css scales <body> down slightly.\n * The dialog itself lives in the top layer, which escapes ancestor\n * transforms, so only the page behind it moves. State is derived, not\n * counted — the last zooming modal out clears the class, nested modals keep it.\n */\nfunction syncBackdropZoom(): void {\n const anyOpen = Array.from(\n document.querySelectorAll('ty-modal[open], ty-dialog[open]'),\n ).some((m) => parseBoolAttr(m as HTMLElement, 'open') && !parseBoolAttr(m as HTMLElement, 'no-zoom'));\n document.documentElement.classList.toggle('ty-modal-zoom', anyOpen);\n}\n\nfunction cleanup(el: TyModal): void {\n const modalId = modalIds.get(el);\n const shadowRoot = el.shadowRoot;\n const dialog = shadowRoot ? getModalDialog(shadowRoot) : null;\n \n // Force unlock scroll if modal removed while open\n if (modalId) {\n unlockScroll(modalId);\n modalIds.delete(el);\n }\n syncBackdropZoom();\n \n if (!dialog) return;\n \n const backdropHandler = backdropClickHandlers.get(el);\n if (backdropHandler) {\n dialog.removeEventListener('click', backdropHandler);\n backdropClickHandlers.delete(el);\n }\n \n const escapeHandler = escapeKeyHandlers.get(el);\n if (escapeHandler) {\n dialog.removeEventListener('keydown', escapeHandler);\n escapeKeyHandlers.delete(el);\n }\n \n const closeButton = dialog.querySelector<HTMLButtonElement>('.close-button');\n if (closeButton) {\n const closeHandler = closeButtonHandlers.get(el);\n if (closeHandler) {\n closeButton.removeEventListener('click', closeHandler);\n closeButtonHandlers.delete(el);\n }\n }\n \n const modalContent = dialog.querySelector<HTMLElement>('.modal-content');\n if (modalContent) {\n const enterHandler = hoverEnterHandlers.get(el);\n const leaveHandler = hoverLeaveHandlers.get(el);\n \n if (enterHandler) {\n modalContent.removeEventListener('mouseenter', enterHandler);\n hoverEnterHandlers.delete(el);\n }\n \n if (leaveHandler) {\n modalContent.removeEventListener('mouseleave', leaveHandler);\n hoverLeaveHandlers.delete(el);\n }\n }\n}\n\n// Component Definition\n\n/**\n * TyModal Web Component\n */\nexport class TyModal extends HTMLElement {\n /** Programmatic API methods */\n show?: () => void;\n /**\n * Close the modal. Without `force`, fires `beforeclose` first — consumers\n * can `preventDefault()` to abort. With `force: true`, bypasses the\n * cancellable event; used when the consumer has already obtained user\n * consent through their own UI.\n */\n hide?: (opts?: { force?: boolean }) => void;\n \n static get observedAttributes() {\n return ['open', 'no-backdrop', 'no-zoom', 'prevent-outside-click', 'prevent-escape', 'label'];\n }\n\n // Property mirrors for the boolean attributes. Frameworks that\n // property-bind (React, Vue, CLJS wrappers) hand us real booleans —\n // `preventEscape = true` — which never reach attributeChangedCallback.\n // Reflect them to the attribute so one code path (getModalAttributes) rules.\n get open(): boolean { return parseBoolAttr(this, 'open'); }\n set open(v: boolean) { coerceBoolean(v) ? this.setAttribute('open', 'true') : this.removeAttribute('open'); }\n\n get noBackdrop(): boolean { return parseBoolAttr(this, 'no-backdrop'); }\n set noBackdrop(v: boolean) {\n coerceBoolean(v) ? this.setAttribute('no-backdrop', '') : this.removeAttribute('no-backdrop');\n }\n\n get noZoom(): boolean { return parseBoolAttr(this, 'no-zoom'); }\n set noZoom(v: boolean) {\n coerceBoolean(v) ? this.setAttribute('no-zoom', '') : this.removeAttribute('no-zoom');\n }\n\n // Presence-boolean mirrors: true sets the attribute, false removes it —\n // like native `disabled`.\n get preventOutsideClick(): boolean { return parseBoolAttr(this, 'prevent-outside-click'); }\n set preventOutsideClick(v: boolean) {\n coerceBoolean(v) ? this.setAttribute('prevent-outside-click', '') : this.removeAttribute('prevent-outside-click');\n }\n\n get preventEscape(): boolean { return parseBoolAttr(this, 'prevent-escape'); }\n set preventEscape(v: boolean) {\n coerceBoolean(v) ? this.setAttribute('prevent-escape', '') : this.removeAttribute('prevent-escape');\n }\n\n constructor() {\n super();\n this.attachShadow({ mode: 'open' });\n }\n \n connectedCallback() {\n upgradeProperties(this);\n render(this);\n \n this.show = () => openModal(this);\n this.hide = (opts?: { force?: boolean }) => closeModal(this, 'programmatic', opts);\n }\n \n disconnectedCallback() {\n cleanup(this);\n }\n \n attributeChangedCallback(_name: string, _oldValue: string | null, _newValue: string | null) {\n // React (and any framework that conditionally mounts an already-open\n // modal) sets initial attributes BEFORE inserting the element into the\n // document, and showModal() on a disconnected <dialog> throws\n // InvalidStateError. Defer — connectedCallback render()s on insertion\n // and applies `open` then.\n if (!this.isConnected) return;\n render(this);\n }\n}\n\nif (!customElements.get('ty-modal')) {\n customElements.define('ty-modal', TyModal);\n}\n\n// Also exposed as ty-dialog — the platform/ARIA name (wraps native <dialog>).\n// A constructor can only register once, hence the subclass.\nif (!customElements.get('ty-dialog')) {\n customElements.define('ty-dialog', class TyDialog extends TyModal { });\n}","/**\n * Select Field Styles — shared chrome for ty-select (both single and\n * multiple modes). Formerly split across ty-dropdown / ty-multiselect;\n * those were consolidated into ty-select and this file kept the name.\n */\n\nimport { FLAVORS } from \"../types/common.js\";\nimport { fieldSizeVars } from \"./field-size.js\";\nimport { customScrollbarStyles } from \"./custom-scrollbar.js\";\n\n/* Flavor rules only set --select-accent (border), --select-accent-bold\n (hover/open border), and --select-ring (open focus ring); the .select-stub\n rules below consume them. Doubles as the per-instance override API:\n `ty-select { --select-accent: … }`. Neutral is skipped — it IS the default\n unstyled chrome (--ty-input-* tokens), same convention as\n ty-input/ty-date-picker. Fallback flavor `fb` is used for custom flavors\n so missing tokens degrade to neutral. */\nconst selectFlavor = (f: string, fb?: string) => {\n const c = (s: string) =>\n fb\n ? s\n ? `var(--ty-color-${f}${s}, var(--ty-color-${f}, var(--ty-color-${fb}${s})))`\n : `var(--ty-color-${f}, var(--ty-color-${fb}))`\n : s\n ? `var(--ty-color-${f}${s}, var(--ty-color-${f}))`\n : `var(--ty-color-${f})`;\n return `\n:host([flavor=\"${f}\"]) {\n --select-accent: var(--ty-input-${f}-border, ${c(\"-soft\")});\n --select-accent-bold: ${c(\"\")};\n --select-ring: color-mix(in oklab, ${c(\"\")} 15%, transparent);\n}\n:host([flavor=\"${f}+\"]) {\n --select-accent: ${c(\"\")};\n --select-accent-bold: ${c(\"-strong\")};\n --select-ring: color-mix(in oklab, ${c(\"-strong\")} 15%, transparent);\n}\n:host([flavor=\"${f}-\"]) {\n --select-accent: ${c(\"-faint\")};\n --select-accent-bold: ${c(\"-soft\")};\n --select-ring: color-mix(in oklab, ${c(\"-soft\")} 15%, transparent);\n}\n`;\n};\n\n/** Rules for one custom (non-built-in) flavor — see utils/flavor-sheet.ts. */\nexport const selectCustomFlavorCss = (base: string) => selectFlavor(base, \"neutral\");\n\nexport const selectBaseStyles = `\n${fieldSizeVars}\n:host {\n display: block;\n width: 100%;\n font-family: inherit;\n --mobile-border-color: var(--ty-border, #5858587d);\n}\n\n/* compact is a toolbar/filter-bar trigger — it must hug its own content so\n it can sit inline next to other toolbar items, not claim a full row.\n inline-block (not plain inline): a block box still ignores width and\n collapses vertical margin, which is what we're fixing above. */\n:host([compact]) {\n display: inline-block;\n width: auto;\n}\n\n/* A custom slot=\"trigger\" is the same situation as compact: the trigger is\n the consumer's own button, not a form field — hug it so chips/toolbar\n items can sit right next to it. [has-trigger] is reflected by\n setupTriggerSlot() because Blink does not parse :has() inside :host(). */\n:host([has-trigger]) {\n display: inline-block;\n width: auto;\n}\n\n.dropdown-dialog {\n position: fixed;\n width: var(--dropdown-width, 200px);\n max-width: 100vw;\n margin: 0;\n padding: 0;\n border: none;\n background: transparent;\n box-sizing: border-box;\n padding: var(--dropdown-padding, 20px);\n /* Modal handles z-index automatically */\n\n opacity: 0;\n /* Panel-level entrance: individual scale/translate compose with the\n collision-shift transform below. The single-select skin flattens the\n inner .dropdown-options animation (select.ts: \"panel appears as one\"),\n so the dialog carries the motion for both skins. */\n scale: 0.96;\n translate: 0 -6px;\n transform-origin: top center;\n transition:\n opacity var(--ty-popup-duration, 180ms) var(--ty-popup-ease, cubic-bezier(0.34, 1.56, 0.64, 1)),\n scale var(--ty-popup-duration, 180ms) var(--ty-popup-ease, cubic-bezier(0.34, 1.56, 0.64, 1)),\n translate var(--ty-popup-duration, 180ms) var(--ty-popup-ease, cubic-bezier(0.34, 1.56, 0.64, 1));\n\n transform: translate(var(--dropdown-offset-x, 0px), var(--dropdown-offset-y, 0px));\n top: -1000px;\n left: -1000px;\n}\n\n/* When opened via showModal(), apply flex layout and direction */\n.dropdown-dialog[open] {\n display: flex;\n flex-direction: column;\n}\n\n.dropdown-dialog.position-below {\n left: var(--dropdown-x);\n top: var(--dropdown-y);\n}\n\n.dropdown-dialog.position-above {\n left: var(--dropdown-x);\n bottom: var(--dropdown-y);\n top: auto;\n flex-direction: column-reverse;\n translate: 0 6px;\n transform-origin: bottom center;\n}\n\n.dropdown-dialog.position-above .dropdown-header {\n margin-top: 4px;\n}\n\n.dropdown-dialog.position-below .dropdown-header {\n margin-bottom: 4px;\n}\n\n.dropdown-dialog.position-below .dropdown-options {\n box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -2px rgba(0, 0, 0, 0.1), var(--ty-shadow-md);\n}\n\n.dropdown-dialog.position-above .dropdown-options {\n transform: translateY(6px) scale(0.96);\n transform-origin: bottom center;\n}\n\n.dropdown-dialog.open {\n opacity: 1;\n scale: 1;\n translate: 0 0;\n}\n\n.dropdown-dialog.open .dropdown-options {\n opacity: 1;\n transform: translateY(0) scale(1);\n}\n\n/* Transitions never start on an element that was display:none last frame —\n showModal() + .open land in the same frame, so the enter transition was\n silently skipped. @starting-style supplies the first-frame \"from\" values\n (this is the platform mechanism for animating dialog/top-layer entry). */\n@starting-style {\n .dropdown-dialog.open {\n opacity: 0;\n scale: 0.96;\n translate: 0 -6px;\n }\n\n .dropdown-dialog.open.position-above {\n translate: 0 6px;\n }\n\n .dropdown-dialog.open .dropdown-options {\n opacity: 0;\n transform: translateY(-6px) scale(0.96);\n }\n\n .dropdown-dialog.open.position-above .dropdown-options {\n transform: translateY(6px) scale(0.96);\n }\n}\n\n.dropdown-dialog::backdrop {\n background: transparent;\n}\n\n.dropdown-header {\n display: flex;\n align-items: center;\n gap: var(--ty-spacing-2);\n position: relative;\n}\n\n.dropdown-search-input {\n font-family: inherit;\n width: 100%;\n min-width: 0;\n box-sizing: border-box;\n background: var(--input-bg, var(--ty-input-bg));\n color: var(--input-color, var(--ty-input-color));\n border: 1px solid var(--input-border, var(--ty-input-border));\n border-radius: var(--ty-radius-md);\n font-family: inherit;\n font-size: var(--ty-font-sm);\n line-height: var(--ty-leading-sm);\n letter-spacing: var(--ty-tracking-sm);\n font-weight: var(--ty-font-normal);\n min-height: var(--ty-size-md);\n padding: var(--ty-spacing-2) var(--ty-spacing-3);\n padding-right: calc(var(--ty-spacing-3) + 1rem + var(--ty-spacing-2));\n transition: var(--ty-transition-all);\n outline: none;\n}\n\n.dropdown-search-input:focus {\n border-color: var(--input-border-focus, var(--ty-input-border-focus));\n box-shadow: 0 0 0 3px var(--input-shadow-focus, var(--ty-input-shadow-focus));\n}\n\n.dropdown-search-input:disabled {\n background-color: var(--input-disabled-bg, var(--ty-input-disabled-bg));\n color: var(--input-disabled-color, var(--ty-input-disabled-color));\n cursor: not-allowed;\n opacity: 0.6;\n}\n\n.dropdown-search-input::placeholder {\n color: var(--input-placeholder, var(--ty-input-placeholder));\n}\n\n.dropdown-search-chevron {\n position: absolute;\n top: 50%;\n right: var(--ty-spacing-3);\n transform: translateY(-50%);\n width: 1rem;\n height: 1rem;\n color: var(--input-placeholder, var(--ty-input-placeholder));\n transition: var(--ty-transition-transform);\n pointer-events: none;\n}\n\n.dropdown-search-chevron.open {\n transform: translateY(-50%) rotate(180deg);\n}\n\n.dropdown-search-chevron svg {\n width: 100%;\n height: 100%;\n}\n\n.select-stub {\n min-height: var(--ty-size-md);\n display: flex;\n flex-wrap: wrap;\n gap: 0.25rem;\n align-items: center;\n padding: 0 2.5rem 0 0.75rem;\n transition: var(--ty-transition-all), opacity 0.2s ease;\n outline: none;\n background: var(--input-bg, var(--ty-input-bg));\n color: var(--input-color, var(--ty-input-color));\n border: 1px solid var(--select-accent, var(--input-border, var(--ty-input-border)));\n border-radius: var(--ty-radius-md);\n font-family: inherit;\n font-size: var(--ty-field-font);\n line-height: var(--ty-field-leading);\n letter-spacing: var(--ty-field-tracking);\n cursor: pointer;\n position: relative;\n width: 100%;\n box-sizing: border-box;\n}\n\n/* Geometry comes from the shared ladder (styles/field-size.ts) so a size is\n the same height on every field. Right padding stays 2.5rem for chevron room.\n Zero vertical padding — with align-items:center ANY vertical padding adds on\n top of min-height instead of being absorbed by it, overflowing the shared\n field height. */\n.select-stub {\n min-height: var(--ty-field-height);\n padding: 0 2.5rem 0 var(--ty-field-pad-x);\n}\n\n.select-stub:hover {\n border-color: var(--select-accent-bold, var(--input-border-hover, var(--ty-input-border-hover)));\n}\n\n.select-stub[disabled] {\n background-color: var(--input-disabled-bg, var(--ty-input-disabled-bg));\n color: var(--input-disabled-color, var(--ty-input-disabled-color));\n cursor: not-allowed;\n opacity: 0.6;\n}\n\n.dropdown-wrapper:has(.dropdown-chevron.open) .select-stub {\n opacity: 0;\n pointer-events: none;\n}\n\n/* Open state — same escalation as ty-input's .focused: bolder border + ring.\n Applies whenever the stub stays visible while open (field skin without\n the opacity-hide above kicking in — e.g. single-select with no tags).\n :not(.custom-trigger) — that skin has its own unconditional box-shadow:\n none reset below; excluding it here keeps the two rules from competing\n on specificity (:has()/:not() here would otherwise outrank it).\n :not(:has(search:focus)) — the search row auto-focuses on open, which\n already carries its own real :focus ring (below); without this guard the\n stub's \"fake\" open-ring stacks on top of it, and the field reads as two\n simultaneously-focused controls. Real focus wins; the stub ring is only\n for select skins that have nothing else to show it. */\n.dropdown-wrapper:has(.dropdown-chevron.open):not(:has(.dropdown-search-input:focus)) .select-stub:not(.custom-trigger),\n.select-stub:focus,\n.select-stub:focus-visible {\n border-color: var(--select-accent-bold, var(--input-border-focus, var(--ty-input-border-focus)));\n box-shadow: 0 0 0 3px var(--select-ring, var(--input-shadow-focus, var(--ty-input-shadow-focus)));\n}\n\n/* Custom trigger (slot=\"trigger\"): setupTriggerSlot() toggles this class when\n the consumer assigns their own content — the slot's fallback (start/selected/\n placeholder/end/chevron, i.e. the whole default field skin) is entirely\n replaced at that point, so the wrapping .select-stub itself must go bare.\n Without this, the stub's own border/background/padding and the open/focus\n ring above still wrapped the custom content in a second, unwanted outline. */\n.select-stub.custom-trigger {\n min-height: 0;\n padding: 0;\n border: none;\n background: transparent;\n}\n.select-stub.custom-trigger:hover,\n.dropdown-wrapper:has(.dropdown-chevron.open) .select-stub.custom-trigger,\n.select-stub.custom-trigger:focus,\n.select-stub.custom-trigger:focus-visible {\n border-color: transparent;\n box-shadow: none;\n}\n\n/* Error line + state — same as ty-input's. A custom trigger keeps its own\n look; only the line shows under it. contain: inline-size — compact and\n slot=\"trigger\" selects hug their trigger, and the message must not widen\n the host. */\n.error-message {\n font-size: var(--ty-font-xs);\n line-height: var(--ty-leading-xs);\n letter-spacing: var(--ty-tracking-xs);\n color: var(--ty-color-danger);\n margin-top: 4px;\n padding-left: var(--ty-field-outer-pad-x);\n contain: inline-size;\n}\n\n/* Under a trigger narrower than the message it wraps at a readable width,\n spilling past the trigger instead of stacking a word per line. The\n percentage keeps it out of the host's width. A custom trigger is the\n consumer's own box: the line starts at its edge. */\n:host([compact]) .error-message,\n:host([has-trigger]) .error-message {\n box-sizing: border-box;\n width: max(100%, 20em);\n}\n:host([has-trigger]) .error-message {\n padding-left: 0;\n}\n\n.select-stub.error:not(.custom-trigger) {\n border-color: var(--ty-color-danger);\n background: var(--ty-bg-danger-soft);\n}\n\n.select-stub.error:not(.custom-trigger):focus,\n.select-stub.error:not(.custom-trigger):focus-visible {\n border-color: var(--ty-color-danger-bold);\n box-shadow: 0 0 0 3px var(--input-shadow-focus, var(--ty-input-shadow-focus));\n}\n\n/* Hide stub chips when mobile dialog is open (let modal show them) */\n.dropdown-mode-mobile .dropdown-wrapper:has(.mobile-dialog[open]) .select-chips {\n display: none;\n}\n\n/* When tags are present, reduce padding to make room */\n.select-stub.has-tags {\n padding: 0.25rem 2.5rem 0.25rem 0.5rem;\n width: 100%;\n}\n\n.select-stub.has-tags slot[name=\"selected\"] {\n display: flex;\n flex-wrap: wrap;\n gap: 0.25rem;\n}\n\n.dropdown-chevron {\n position: absolute;\n top: 50%;\n right: var(--ty-spacing-3);\n transform: translateY(-50%);\n width: 1rem;\n height: 1rem;\n color: var(--input-placeholder, var(--ty-input-placeholder));\n transition: var(--ty-transition-transform);\n pointer-events: none;\n}\n\n.dropdown-chevron.open {\n transform: translateY(-50%) rotate(180deg);\n}\n\n.dropdown-chevron svg {\n width: 100%;\n height: 100%;\n}\n\n\n.select-chips {\n display: flex;\n flex-wrap: wrap;\n gap: 0.5rem;\n align-items: center;\n min-width: 0;\n}\n\n/* No flex-grow here — the placeholder only ever renders inside .select-stub,\n and select.ts sets flex: 1 1 0% on it. A bare flex-grow: 1 (implicit\n flex-basis:auto) is the wrap bug that fix exists to prevent; leaving it\n here would silently reintroduce it if the specific rule ever moved. */\n.dropdown-placeholder {\n color: var(--input-placeholder, var(--ty-input-placeholder, #9ca3af));\n font-size: var(--ty-field-font);\n line-height: var(--ty-field-leading);\n letter-spacing: var(--ty-field-tracking);\n font-weight: var(--ty-font-light);\n font-style: italic;\n}\n\n.dropdown-placeholder.hidden {\n display: none;\n}\n\n.dropdown-options {\n opacity: 0;\n /* Floating surface/border, not --input-* — this is a popup panel over\n arbitrary page content, not a form field. --ty-input-border resolves to\n the deliberately-faint resting-state input border (barely visible by\n design, escalates on hover/focus); reused here it made the popup's own\n edge nearly invisible against the page behind it. --ty-floating-border\n is the token tuned for exactly this: floating panels over content. */\n background: var(--ty-surface-floating);\n border: 1px solid var(--ty-floating-border);\n border-radius: var(--ty-radius-lg);\n max-height: 16rem;\n width: 100%;\n max-width: 100%;\n overflow-x: hidden;\n overflow-y: auto;\n scroll-behavior: smooth;\n box-sizing: border-box;\n position: relative;\n box-shadow:\n 0 20px 25px -5px rgba(0, 0, 0, 0.1),\n 0 10px 10px -5px rgba(0, 0, 0, 0.04);\n\n transform: translateY(-6px) scale(0.96);\n transform-origin: top center;\n transition:\n opacity var(--ty-popup-duration, 180ms) var(--ty-popup-ease, cubic-bezier(0.34, 1.56, 0.64, 1)),\n transform var(--ty-popup-duration, 180ms) var(--ty-popup-ease, cubic-bezier(0.34, 1.56, 0.64, 1));\n\n display: flex;\n flex-wrap: wrap;\n padding: 0.5rem;\n gap: 0.5rem;\n\n}\n\n/* Hide native scrollbar only when custom scrollbar is active */\n.dropdown-options.ty-custom-scroll {\n scrollbar-width: none;\n -ms-overflow-style: none;\n}\n\n.dropdown-options.ty-custom-scroll::-webkit-scrollbar {\n display: none;\n}\n\n/* Options wrapper - positioned container for scrollbar track */\n.dropdown-options-wrapper {\n position: relative;\n}\n\n.dropdown-options-wrapper:hover .ty-scrollbar-track-y.has-overflow {\n opacity: 1;\n}\n\n.dropdown-options ty-tag {\n user-select: none;\n transition: transform 0.1s ease;\n}\n\n.dropdown-options ty-tag:hover {\n transform: scale(1.02);\n}\n\n.dropdown-options ty-tag:active {\n transform: scale(0.98);\n}\n\n.dropdown-options ty-tag[selected] {\n opacity: 0.5;\n}\n\n.select-chips ty-tag {\n max-width: 150px;\n}\n\n@media (max-width: 640px) {\n .select-chips ty-tag {\n max-width: 100px;\n }\n}\n\n\n.select-container {\n display: flex;\n flex-direction: column;\n /* No gap here — label→field spacing comes from .ty-field-label's\n margin-bottom (6px), same as ty-input/ty-date-picker/ty-textarea.\n A flex gap would STACK on that margin (flex margins don't collapse),\n which is exactly the 4px misalignment this used to cause. */\n}\n\n.dropdown-wrapper {\n position: relative;\n display: block;\n width: 100%;\n}\n\n.ty-field-label {\n font-size: var(--ty-field-label-font);\n line-height: var(--ty-field-label-leading);\n letter-spacing: var(--ty-tracking-sm);\n font-weight: var(--ty-font-medium);\n color: var(--ty-label-color);\n margin-bottom: var(--ty-field-label-gap);\n padding-left: var(--ty-field-outer-pad-x);\n display: flex;\n align-items: center;\n}\n\n.required-icon {\n display: inline-flex;\n align-items: center;\n color: #ef4444;\n width: 12px;\n height: 12px;\n vertical-align: middle;\n margin-left: 4px;\n}\n\n.required-icon svg {\n width: 100%;\n height: 100%;\n}\n\n:host([disabled]) .select-container {\n pointer-events: none;\n}\n\n.dropdown-mode-mobile .mobile-dialog {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n width: 100vw;\n height: 100dvh; /* dvh, not vh — shrinks with the on-screen keyboard so the\n dialog never sits partly behind it */\n max-width: 100vw;\n max-height: 100dvh;\n margin: 0;\n padding: 0;\n padding-top: 6dvh; /* Sit higher than the old 10vh, but 4dvh left the\n floating label with no headroom — it sits above\n .mobile-search-header via position:absolute, so it\n needs room inside this padding, not just inside the\n content box, or it crowds the very top of the screen */\n border: none;\n background: transparent; /* Backdrop handles background */\n /* Note: Don't set display - browser controls <dialog> visibility */\n align-items: flex-start;\n justify-content: center;\n opacity: 0;\n transition: opacity 300ms ease;\n}\n\n/* When opened via showModal(), add flex layout */\n.dropdown-mode-mobile .mobile-dialog[open] {\n display: flex;\n}\n\n.dropdown-mode-mobile .mobile-dialog.open {\n opacity: 1;\n}\n\n/* Native dialog backdrop with blur */\n.dropdown-mode-mobile .mobile-dialog::backdrop {\n background: rgba(0, 0, 0, 0.65); /* was 0.5 — needed more depth to reliably\n carry white header text/icons over a\n light page blurred behind it */\n backdrop-filter: blur(8px);\n -webkit-backdrop-filter: blur(8px);\n}\n\n.dropdown-mode-mobile .mobile-dialog-content {\n position: relative;\n display: flex;\n flex-direction: column;\n width: calc(100% - 32px); /* Side margins */\n max-width: 400px;\n min-height: 200px;\n max-height: 90dvh; /* leaves room below the 6dvh padding-top, shrinks with keyboard */\n opacity: 0;\n transform: scale(0.95);\n transition: \n opacity 300ms cubic-bezier(0.16, 1, 0.3, 1),\n transform 300ms cubic-bezier(0.16, 1, 0.3, 1);\n}\n\n.dropdown-mode-mobile .mobile-dialog.open .mobile-dialog-content {\n opacity: 1;\n transform: scale(1);\n}\n\n.dropdown-mode-mobile .mobile-search-input:focus {\n border-color: var(--ty-border);\n}\n\n/* Mobile search header - label floats above, search + close below */\n.dropdown-mode-mobile .mobile-search-header {\n flex-shrink: 0;\n display: flex;\n flex-direction: column;\n margin-bottom: 16px;\n padding: 0;\n background: transparent;\n position: relative;\n}\n\n.dropdown-mode-mobile .mobile-header-content {\n display: flex;\n align-items: center;\n gap: 12px;\n width: 100%;\n /* When search is disabled, updateSearchVisibility() hides the icon+input\n (see select.ts) but leaves the close button as the row's only child —\n without this it falls back to flex-start and strands the button on the\n left. Harmless when search IS shown: the input's flex:1 already\n consumes all remaining space, so justify-content never gets a say. */\n justify-content: flex-end;\n}\n\n.dropdown-mode-mobile .mobile-header-label {\n position: absolute;\n bottom: 100%;\n left: 2px;\n margin-bottom: 8px; /* was 4px — too tight against the search row */\n font-size: var(--ty-font-base); /* was --ty-font-lg — read as oversized/heavy paired with 700 */\n line-height: var(--ty-leading-base);\n letter-spacing: var(--ty-tracking-base);\n font-weight: 600; /* was 700 — 700 at font-lg read as clunky */\n /* This sits on the dialog's ::backdrop (rgba(0,0,0,.65) + blur) — a fixed\n DARK overlay regardless of theme, not the theme's own surface color.\n A theme-toggling token (light mode → black) fights that: black text on\n a dark blurred backdrop is the wrong combination. Fixed white, same\n reasoning as ty-tooltip's deliberately theme-independent default in\n tyrell.css — this element's job is to pop against a dark backdrop in\n both themes, not to track the page's light/dark state. */\n color: #ffffff;\n pointer-events: none;\n}\n\n/* Close button — borderless ghost icon button (was a bordered circle badge,\n which read as a heavy, disconnected \"chip\" next to the plain search icon).\n Matches ty-button's ghost treatment: transparent at rest, soft neutral\n fill on hover/active, no border ever. */\n.dropdown-mode-mobile .mobile-close-button {\n flex-shrink: 0;\n width: 32px;\n height: 32px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: transparent;\n border: none;\n border-radius: 50%;\n /* Same reasoning as .mobile-header-label: fixed white, not a theme token —\n this sits on the dark ::backdrop blur in both themes, never on a theme\n surface. */\n color: #ffffff;\n cursor: pointer;\n transition: var(--ty-transition-all);\n padding: 0;\n}\n\n/* Hover/active fills also go fixed-white-tinted rather than theme neutral —\n --ty-bg-neutral-soft is a LIGHT fill in light mode, which would swallow\n the white icon it's meant to sit behind. */\n.dropdown-mode-mobile .mobile-close-button:hover {\n background: rgba(255, 255, 255, 0.15);\n color: #ffffff;\n}\n\n.dropdown-mode-mobile .mobile-close-button:active {\n transform: scale(0.9);\n background: rgba(255, 255, 255, 0.25);\n}\n\n.dropdown-mode-mobile .mobile-close-button svg {\n width: 18px;\n height: 18px;\n}\n\n.dropdown-mode-mobile .mobile-search-input {\n font-family: inherit;\n flex: 1;\n min-width: 0;\n box-sizing: border-box;\n background: var(--ty-surface-floating);\n color: var(--ty-text);\n border: 2px solid;\n border-color: var(--mobile-border-color);\n border-radius: var(--ty-radius-md);\n font-family: inherit;\n font-size: var(--ty-font-sm);\n line-height: var(--ty-leading-sm);\n letter-spacing: var(--ty-tracking-sm);\n font-weight: var(--ty-font-normal);\n padding: var(--ty-spacing-2) var(--ty-spacing-3);\n height: 40px;\n transition: var(--ty-transition-all);\n outline: none;\n}\n\n.dropdown-mode-mobile .mobile-search-input::placeholder {\n color: var(--ty-text-faint);\n}\n\n.dropdown-mode-mobile .mobile-search-input:focus {\n border-color: var(--ty-border);\n}\n\n/* Mobile body - contains both sections */\n.dropdown-mode-mobile .mobile-body {\n position: relative;\n display: flex;\n flex-direction: column;\n height: var(--body-height, 350px);\n max-height: 350px;\n overflow: hidden;\n background: var(--ty-surface-floating);\n border-radius: var(--ty-radius-lg);\n box-shadow: \n 0 20px 25px -5px rgba(0, 0, 0, 0.1),\n 0 10px 10px -5px rgba(0, 0, 0, 0.04);\n border: 2px solid;\n border-color: var(--mobile-border-color);\n}\n\n/* Section headers are labels, not buttons */\n\n.dropdown-mode-mobile .section-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n height: 36px;\n flex-shrink: 0;\n padding: 0 16px;\n font-size: 11px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.06em;\n color: var(--ty-text-bold);\n background: transparent;\n cursor: default;\n user-select: none;\n}\n\n.dropdown-mode-mobile .section-header .section-title {\n flex: 1;\n}\n\n.dropdown-mode-mobile .section-header .section-count {\n font-weight: 500;\n color: var(--ty-text-faint);\n margin-left: 0.25rem;\n}\n\n/* The two sections are an accordion: exactly one is open, the other is its\n header and nothing else. Both share a 36px basis (the header) and the open\n one claims the free space with flex-grow — a number, so it interpolates.\n max-height can't do this job: the open state has no finite height to\n animate to, and a transition to the keyword none simply snaps. */\n\n.dropdown-mode-mobile .mobile-body .section-header {\n height: 36px;\n flex: 0 0 36px;\n}\n\n.dropdown-mode-mobile .mobile-selected-section,\n.dropdown-mode-mobile .mobile-available-section {\n display: flex;\n flex-direction: column;\n background: var(--ty-input-bg);\n overflow: hidden;\n min-height: 36px;\n flex: 0 1 36px;\n transition: flex-grow 220ms cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n.dropdown-mode-mobile .mobile-body[data-expanded=\"selected\"] .mobile-selected-section,\n.dropdown-mode-mobile .mobile-body[data-expanded=\"available\"] .mobile-available-section {\n flex-grow: 1;\n}\n\n/* Nothing selected: the strip can never take the space, whatever the body\n says — expanding into an empty panel is just a gap. */\n.dropdown-mode-mobile .mobile-selected-section[data-empty=\"true\"] {\n flex-grow: 0;\n}\n\n.dropdown-mode-mobile .mobile-selected-section .section-content {\n flex: 1;\n min-height: 0;\n overflow-y: auto;\n overscroll-behavior: contain;\n padding: 0.75rem 1rem;\n display: flex;\n flex-wrap: wrap;\n gap: 0.5rem;\n align-content: flex-start;\n /* Soft fade at bottom edge — hints at scrollable overflow */\n -webkit-mask-image: linear-gradient(to bottom, black calc(100% - 12px), transparent);\n mask-image: linear-gradient(to bottom, black calc(100% - 12px), transparent);\n}\n\n.dropdown-mode-mobile .mobile-available-section .section-content {\n flex: 1;\n min-height: 0;\n overflow-y: auto;\n overscroll-behavior: contain;\n padding: 0.75rem 1rem;\n display: flex;\n flex-wrap: wrap;\n gap: 0.5rem;\n align-content: flex-start;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .dropdown-mode-mobile .mobile-selected-section,\n .dropdown-mode-mobile .mobile-available-section {\n transition: none;\n }\n}\n\n/* Headers are the accordion control: full-width, tappable, chevron flips to\n point at whichever section currently owns the space. */\n.dropdown-mode-mobile .mobile-body .section-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n width: 100%;\n border: none;\n background: transparent;\n font: inherit;\n text-align: left;\n cursor: pointer;\n -webkit-tap-highlight-color: transparent;\n}\n\n.dropdown-mode-mobile .mobile-body .section-header svg {\n width: 1rem;\n height: 1rem;\n flex-shrink: 0;\n opacity: 0.5;\n transition: transform 180ms ease;\n}\n\n.dropdown-mode-mobile .mobile-body .section-header[aria-expanded=\"true\"] svg {\n transform: rotate(180deg);\n}\n\n/* Nothing selected: the strip is just its header, so it isn't a control */\n.dropdown-mode-mobile .mobile-selected-section[data-empty=\"true\"] .section-header {\n cursor: default;\n}\n\n.dropdown-mode-mobile .mobile-selected-section[data-empty=\"true\"] .section-header svg {\n display: none;\n}\n\n/* Chips in the selected strip are shadow-local buttons, not slotted tags —\n the strip mirrors the selection rather than re-homing the consumer's\n ty-option elements, so tapping one can deselect without moving nodes\n between two slots. */\n.dropdown-mode-mobile .mobile-selected-chip {\n display: inline-flex;\n align-items: center;\n gap: 0.375rem;\n padding: 0.25rem 0.5rem 0.25rem 0.625rem;\n border: 1px solid var(--ty-border);\n border-radius: 9999px;\n background: var(--ty-surface-content);\n color: var(--ty-text);\n font: inherit;\n font-size: var(--ty-font-sm);\n line-height: var(--ty-leading-sm);\n cursor: pointer;\n transition: transform 0.1s ease, border-color 0.15s ease;\n animation: ty-select-tag-enter 180ms cubic-bezier(0.16, 1, 0.3, 1);\n}\n\n.dropdown-mode-mobile .mobile-selected-chip svg {\n width: 0.875rem;\n height: 0.875rem;\n flex-shrink: 0;\n opacity: 0.6;\n}\n\n@media (hover: hover) {\n .dropdown-mode-mobile .mobile-selected-chip:hover {\n border-color: var(--ty-text-soft);\n }\n .dropdown-mode-mobile .mobile-selected-chip:hover svg {\n opacity: 1;\n }\n}\n\n.dropdown-mode-mobile .mobile-selected-chip:active {\n transform: scale(0.96);\n}\n\n/* Selected strip collapses (no text needed).\n Available shows the empty message only when there are zero tags total. */\n\n.dropdown-mode-mobile .empty-state {\n display: none;\n width: 100%;\n padding: 2rem 1rem;\n text-align: center;\n color: var(--ty-text-faint);\n font-size: var(--ty-font-sm);\n line-height: var(--ty-leading-sm);\n letter-spacing: var(--ty-tracking-sm);\n font-style: italic;\n}\n\n.dropdown-mode-mobile .mobile-available-section[data-empty=\"true\"] .empty-state {\n display: block;\n}\n\n.dropdown-mode-mobile .mobile-selected-section[data-empty=\"true\"] .section-content,\n.dropdown-mode-mobile .mobile-available-section[data-empty=\"true\"] slot {\n display: none;\n}\n\n.dropdown-mode-mobile .section-content ::slotted(ty-tag) {\n cursor: pointer;\n user-select: none;\n transition: transform 0.1s ease;\n margin: 2px 0;\n /* Fade + scale entry — replays on each (re)insertion when a tag moves\n between selected and available slots */\n animation: ty-select-tag-enter 180ms cubic-bezier(0.16, 1, 0.3, 1);\n}\n\n@media (hover: hover) {\n .dropdown-mode-mobile .section-content ::slotted(ty-tag:hover) {\n transform: scale(1.02);\n }\n}\n\n.dropdown-mode-mobile .section-content ::slotted(ty-tag:active) {\n transform: scale(0.96);\n}\n\n.dropdown-mode-mobile .section-content ::slotted(ty-tag[hidden]) {\n display: none !important;\n}\n\n@keyframes ty-select-tag-enter {\n from { opacity: 0; transform: scale(0.85); }\n to { opacity: 1; transform: scale(1); }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .dropdown-mode-mobile .section-content ::slotted(ty-tag) {\n animation: none;\n }\n}\n\n/* Spinner overlay shown inside the options area while the parent\n (external-search mode) is fetching. Search input stays usable.\n\n Carries its own surface so it stays visible even when the host\n has restyled the popup with a transparent or unusual background.\n Override with --ty-loader-bg / --ty-loader-radius / --ty-loader-border.\n*/\n.dropdown-loading {\n display: none;\n align-items: center;\n justify-content: center;\n gap: var(--ty-spacing-2);\n padding: var(--ty-spacing-4) var(--ty-spacing-3);\n color: var(--ty-text-soft);\n font-size: var(--ty-font-sm);\n min-height: 4rem;\n /* Match the .dropdown-options popup look — same background, border, radius, shadow */\n background: var(--ty-loader-bg, var(--ty-surface-floating));\n border: 1px solid var(--ty-loader-border, var(--ty-floating-border));\n border-radius: var(--ty-loader-radius, var(--ty-radius-lg));\n box-shadow: var(--ty-loader-shadow, 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04));\n box-sizing: border-box;\n}\n\n.dropdown-options-wrapper.loading .dropdown-loading {\n display: flex;\n}\n\n/* Slot is transparent for layout — fallback (spinner + text) and user-provided\n slotted content both act as direct flex children of .dropdown-loading. */\n.dropdown-loading > slot[name=\"loading\"] {\n display: contents;\n}\n\n/* Mobile: full-screen dialog is the surface — drop the card chrome,\n stack vertically, scale up so it feels native to a fullscreen view.\n Slotted content adapts automatically since the slot is display:contents. */\n.dropdown-mode-mobile .dropdown-loading {\n background: transparent;\n border: none;\n box-shadow: none;\n flex: 1;\n flex-direction: column;\n gap: var(--ty-spacing-3);\n padding: var(--ty-spacing-8) var(--ty-spacing-4);\n min-height: 12rem;\n}\n\n.dropdown-mode-mobile .dropdown-loading-spinner {\n width: 2rem;\n height: 2rem;\n}\n\n.dropdown-mode-mobile .dropdown-loading-text {\n font-size: var(--ty-font-base);\n}\n\n.dropdown-options-wrapper.loading .dropdown-options,\n.dropdown-options-wrapper.loading > slot#options-slot,\n.dropdown-options-wrapper.loading .empty-state {\n display: none;\n}\n\n.dropdown-loading-spinner {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 1.125rem;\n height: 1.125rem;\n flex-shrink: 0;\n animation: ty-select-spin 0.7s linear infinite;\n /* Active-state indicator — full accent, not the soft resting shade */\n color: var(--select-accent-bold, var(--ty-color-primary));\n}\n\n.dropdown-loading-spinner svg {\n width: 100%;\n height: 100%;\n}\n\n.dropdown-loading-text {\n color: var(--ty-text-soft);\n}\n\n@keyframes ty-select-spin {\n to { transform: rotate(360deg); }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .dropdown-loading-spinner {\n animation-duration: 1.6s;\n }\n}\n\n${customScrollbarStyles}\n\n/* Flavor variants set --select-accent*, consumed above */\n${FLAVORS.filter((f) => f !== \"neutral\").map((f) => selectFlavor(f)).join(\"\")}\n`;\n\n","/**\n * Select Component Styles\n * Layered over the shared select-field styles (popup, mobile modal, search).\n *\n * Skins:\n * - default FIELD: the base .select-stub already carries the form-field\n * look (width 100%, --ty-input-* tokens) — only text treatment added here\n * - .compact: content-hugging trigger for toolbars, count badge\n * - .custom-trigger (slot=\"trigger\"): all chrome stripped\n */\n\nexport const selectStyles = `\n/* Compact skin hugs its content (field skin = base styles) */\n.select-stub.compact {\n display: inline-flex;\n flex-wrap: nowrap;\n width: auto;\n gap: 0.5rem;\n /* extra right padding = room for the absolutely-positioned chevron */\n padding: 0.5rem 2.25rem 0.5rem 0.875rem;\n}\n\n/* Consumer-provided trigger (slot=\"trigger\"): no chrome at all */\n.select-stub.custom-trigger {\n display: inline-block;\n width: auto;\n border: none;\n background: none;\n padding: 0;\n min-height: 0;\n border-radius: 0;\n}\n.select-stub.custom-trigger:hover {\n border: none;\n}\n\n.select-count {\n flex-shrink: 0;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 1.25rem;\n height: 1.25rem;\n padding: 0 0.375rem;\n border-radius: 9999px;\n /* --ty-text-primary never existed as a token — this silently fell back\n to inherited/unset color. Now follows the select's own flavor. */\n background: color-mix(in oklab, var(--select-accent, var(--ty-color-primary)) 15%, transparent);\n color: var(--select-accent-bold, var(--ty-color-primary-strong));\n font-size: var(--ty-font-xs);\n font-weight: var(--ty-font-semibold);\n font-style: normal;\n}\n.select-count[hidden] {\n display: none;\n}\n\n/* Clear (x) button — normal flex child of .select-stub, not absolutely\n positioned like .dropdown-chevron: it just takes its own space in the\n row, no padding-right gutter math needed. Lives in the trigger slot's\n fallback content, so it's automatically absent under slot=\"trigger\". */\n.select-clear {\n flex-shrink: 0;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 1rem;\n height: 1rem;\n padding: 0;\n border: none;\n background: none;\n color: var(--input-placeholder, var(--ty-input-placeholder));\n cursor: pointer;\n border-radius: var(--ty-radius-sm);\n transition: var(--ty-local-transition, all 0.15s ease);\n}\n/* Pull toward the chevron: the stub's right padding (chevron room) left 12px\n between them on the field skin, 8px on compact. Both land at 6px. */\n.select-stub .select-clear {\n margin-right: -0.375rem;\n}\n.select-stub.compact .select-clear {\n margin-right: -0.125rem;\n}\n.select-clear[hidden] {\n display: none;\n}\n.select-clear:hover {\n /* Destructive utility action — neutral at rest, warns danger-red on\n hover regardless of the field's own flavor. */\n color: var(--ty-color-danger);\n background-color: var(--ty-bg-danger-soft);\n}\n.select-clear svg {\n width: 100%;\n height: 100%;\n}\n\n/* Selection text (field skin): single line, ellipsis, input colors.\n flex-basis 0, not auto — .select-stub is flex-wrap:wrap, and auto's\n hypothetical size is the FULL untruncated text width (wrap-line\n assignment happens before shrinking), which pushed fixed-size siblings\n (.select-clear) onto a second line even though the text visibly had\n room after truncating. 0 makes this item contribute ~nothing to the\n line-fit check up front; grow/shrink + overflow:hidden still truncate\n it identically. */\n.select-stub .dropdown-placeholder {\n font-style: normal;\n flex: 1 1 0%;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n color: var(--input-color, var(--ty-input-color));\n}\n\n.select-stub .dropdown-placeholder.placeholder-shown {\n color: var(--input-placeholder, var(--ty-input-placeholder));\n}\n.select-stub .dropdown-placeholder[hidden] {\n display: none;\n}\n\n/* Single-select display clone (slot=\"selected\"): the selected ty-option\n projected into the stub — its own :host([cloned]) styling strips the\n list-row chrome; here it just takes the text's flex slot. */\n.select-stub slot[name=\"selected\"] {\n display: none;\n}\n.select-stub.has-clone slot[name=\"selected\"] {\n display: block;\n /* flex-basis 0, not auto — same reasoning as .dropdown-placeholder above:\n .select-stub is flex-wrap:wrap, and auto's hypothetical size is the\n clone's full untruncated text width, which pushes .select-clear onto\n a second line. */\n flex: 1 1 0%;\n min-width: 0;\n overflow: hidden;\n}\n.select-stub.compact.has-clone slot[name=\"selected\"] {\n flex: 0 1 auto;\n}\n\n/* start/end slot content (icons etc.) — spacing comes from the stub's flex\n gap; muted like ty-input adornments. end sits before the chevron. */\n.select-stub ::slotted([slot=\"start\"]),\n.select-stub ::slotted([slot=\"end\"]) {\n flex-shrink: 0;\n color: var(--ty-text-soft);\n}\n\n/* Compact skin: the text IS the trigger label — no grow, regular text color.\n flex-basis: auto (not the field skin's 0%) — content-hugging needs its\n natural content width as the starting point; 0% would collapse it since\n grow is also 0 here (nothing left to expand it back out). */\n.select-stub.compact .dropdown-placeholder {\n flex: 0 1 auto;\n color: var(--ty-text);\n}\n\n/* Trigger stays visible while the popup is open (the popup hides it) */\n.dropdown-wrapper:has(.dropdown-chevron.open) .select-stub {\n opacity: 1;\n pointer-events: auto;\n}\n\n/* One-panel popup: search header fused with the options list */\n\n/* Single unified shadow around the whole panel (header + list as one silhouette) */\n.dropdown-dialog.open {\n filter: drop-shadow(0 12px 24px rgba(0, 0, 0, 0.14)) drop-shadow(0 2px 6px rgba(0, 0, 0, 0.08));\n}\n\n/* Card-style header: the search input keeps its own bordered-field look\n (base styles) and sits inset in the panel, TagPicker-style — no divider,\n whitespace separates it from the list. The header's OWN surface/border is\n part of the floating panel's chrome, not a form field — --ty-surface-\n floating/--ty-floating-border, matching .dropdown-options below it (same\n reasoning as the base-panel fix: --ty-input-* is deliberately faint for\n resting form fields and read as a missing/mismatched edge here). */\n.dropdown-header {\n background: var(--ty-surface-floating);\n border: 1px solid var(--ty-floating-border);\n border-bottom: none;\n border-radius: var(--ty-radius-lg) var(--ty-radius-lg) 0 0;\n padding: var(--ty-spacing-2) var(--ty-spacing-2) var(--ty-spacing-1);\n}\n.dropdown-dialog.position-below .dropdown-header {\n margin-bottom: 0;\n}\n.dropdown-dialog.position-above .dropdown-header {\n margin-top: 0;\n border-top: none;\n border-bottom: 1px solid var(--ty-floating-border);\n border-radius: 0 0 var(--ty-radius-lg) var(--ty-radius-lg);\n padding: var(--ty-spacing-1) var(--ty-spacing-2) var(--ty-spacing-2);\n}\n\n/* Magnifier adornment inside the search field (header padding + field inset) */\n.dropdown-search-icon {\n position: absolute;\n top: 50%;\n left: calc(var(--ty-spacing-2) + var(--ty-spacing-3));\n transform: translateY(-50%);\n width: 1rem;\n height: 1rem;\n color: var(--input-placeholder, var(--ty-input-placeholder));\n pointer-events: none;\n}\n.dropdown-search-icon svg {\n width: 100%;\n height: 100%;\n}\n\n/* Mobile header: flex row, icon flows inline before the input. Same 32x32\n footprint as .mobile-close-button (18px glyph centered in the box, not a\n bare 18px glyph flush at the edge) so the row has two matching bookends —\n a bare icon on one side and a 32px circle on the other read as lopsided\n even with equal flex gap on both sides. Matching them also centers the\n search input's flex:1 fill symmetrically between the two. Fixed white +\n 18px glyph, same reasoning as .mobile-header-label — this sits on the\n dark ::backdrop blur in both themes, not a theme surface. */\n.dropdown-mode-mobile .mobile-header-content .dropdown-search-icon {\n position: static;\n transform: none;\n flex-shrink: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 32px;\n height: 32px;\n color: #ffffff;\n}\n.dropdown-mode-mobile .mobile-header-content .dropdown-search-icon svg {\n width: 18px;\n height: 18px;\n}\n\n/* Search input: bordered field from base styles; just size + icon room */\n.dropdown-search-input {\n min-height: 2.25rem;\n padding-right: var(--ty-spacing-2);\n /* room for the magnifier adornment */\n padding-left: calc(var(--ty-spacing-3) + 1rem + var(--ty-spacing-2));\n}\n/* Trigger already has a chevron - no second one inside the search row */\n.dropdown-search-chevron {\n display: none;\n}\n\n/* With the search row hidden nothing inside is focusable, so the <dialog>\n itself receives focus on open — suppress its UA focus ring */\n.dropdown-dialog:focus,\n.dropdown-dialog:focus-visible {\n outline: none;\n}\n\n/* Search row hidden ('auto' below threshold / searchable=\"false\"):\n the options panel owns the whole silhouette */\n.dropdown-header[hidden] {\n display: none;\n}\n.dropdown-header[hidden] ~ .dropdown-options-wrapper .dropdown-options {\n border-top: 1px solid var(--ty-floating-border);\n border-radius: var(--ty-radius-lg);\n}\n.mobile-search-input[hidden],\n.mobile-header-content .dropdown-search-icon[hidden] {\n display: none;\n}\n\n/* Options: vertical list rows fused under the search header.\n No own shadow/animation - the panel appears as one via dialog opacity. */\n.dropdown-options {\n flex-direction: column;\n flex-wrap: nowrap;\n align-items: stretch;\n gap: 0;\n /* Card-style list: rounded rows sit inset from the panel edges */\n padding: var(--ty-spacing-1);\n border-top: none;\n border-radius: 0 0 var(--ty-radius-lg) var(--ty-radius-lg);\n box-shadow: none;\n transform: none;\n transition: none;\n /* ~9-10 visible rows before scrolling (custom scrollbar, native hidden) */\n max-height: 24rem;\n}\n.dropdown-dialog.position-below .dropdown-options {\n box-shadow: none;\n}\n.dropdown-dialog.position-above .dropdown-options {\n border-top: 1px solid var(--ty-floating-border);\n border-bottom: none;\n border-radius: var(--ty-radius-lg) var(--ty-radius-lg) 0 0;\n}\n\n/* Loading panel continues the fused silhouette exactly like .dropdown-options —\n the base layer styles it as a floating card (radius + shadow), which left a\n see-through gap under the search header while loading. */\n.dropdown-loading {\n border-top: none;\n border-radius: 0 0 var(--ty-radius-lg) var(--ty-radius-lg);\n box-shadow: none;\n}\n.dropdown-dialog.position-above .dropdown-loading {\n border-top: 1px solid var(--ty-floating-border);\n border-bottom: none;\n border-radius: var(--ty-radius-lg) var(--ty-radius-lg) 0 0;\n}\n\n/* Selection tick lives inside ty-option (lucide check on [selected]) */\n\n/* Mobile modal: same vertical list */\n.dropdown-mode-mobile .section-content ::slotted(ty-option) {\n display: block;\n width: 100%;\n}\n`;\n","/**\n * Mobile detection utility\n *\n * Uses CSS media query via matchMedia for reliable detection:\n * - `pointer: coarse` identifies touch-primary devices (not laptops with touchscreens)\n * - Breakpoint is evaluated by the browser, always in sync with CSS\n * - Called on each use (not cached), so it responds to viewport changes and rotation\n */\n\n/**\n * Default mobile breakpoint (px).\n * Matches phones in portrait and most phones in landscape.\n */\nconst MOBILE_BREAKPOINT = 768;\n\n/**\n * Detect mobile touch devices.\n * Returns true when the primary pointer is coarse (touch) AND viewport is narrow.\n */\nexport function isMobileTouch(breakpoint: number = MOBILE_BREAKPOINT): boolean {\n return window.matchMedia(`(pointer: coarse) and (max-width: ${breakpoint}px)`).matches;\n}\n","/**\n * TySelect Web Component — THE select control (replaces ty-dropdown/ty-multiselect).\n * Cardinality follows native <select>: default single (scalar value, picking closes\n * the popup), `multiple` toggles options and submits repeated `name=` FormData entries.\n * Skins: default form field, `compact` content-hugging trigger, slot=\"trigger\" custom.\n */\nimport type { Flavor, Size } from \"../types/common.js\";\nimport { DEFAULT_SIZE } from \"../types/common.js\";\nimport { ensureStyles } from \"../utils/styles.js\";\nimport { syncCustomFlavorSheet } from \"../utils/flavor-sheet.js\";\nimport { ERROR_FLAVOR } from \"../utils/error-flavor.js\";\nimport { selectBaseStyles, selectCustomFlavorCss } from \"../styles/select-base.js\";\nimport { selectStyles } from \"../styles/select.js\";\nimport { getLoaderSvg } from \"../utils/loader-registry.js\";\nimport { lockScroll, unlockScroll } from \"../utils/scroll-lock.js\";\nimport { computeAnchoredPosition, placementToAnchored, type Placement } from \"../utils/positioning.js\";\nimport { isMobileTouch } from \"../utils/mobile.js\";\nimport { TyComponent } from \"../base/ty-component.js\";\nimport type { PropertyChange } from \"../utils/property-manager.js\";\nimport {\n CustomScrollbar,\n isCustomScrollbarEnabled,\n} from \"../utils/custom-scrollbar.js\";\n\n// Element Hash Utility (for consistent scroll lock IDs)\n\nlet elementIdCounter = 0;\n\n/** Element hashes; automatically garbage collects when the element is destroyed. */\nconst elementIds = new WeakMap<object, number>();\n\n/** Consistent numeric hash for an element — same value across calls. */\nfunction getElementHash(element: object): number {\n let id = elementIds.get(element);\n if (id === undefined) {\n id = ++elementIdCounter;\n elementIds.set(element, id);\n }\n return id;\n}\n\n// SVG Icons\n\nimport { REQUIRED_ICON_SVG } from \"../utils/icons.js\";\nimport { nativeMessage } from \"../utils/validity.js\";\n\n/**\n * Option count above which the popup grows a search row. Tied to the list's\n * own geometry rather than a taste call: .dropdown-options-wrapper caps at\n * 16rem, which is about seven rows — so this is exactly the point where the\n * list stops being scannable at a glance and starts scrolling. Below it you\n * can see every option already; above it you can't.\n */\nconst SEARCH_AUTO_THRESHOLD = 7;\n\nconst CHEVRON_DOWN_SVG = `<svg viewBox=\"0 0 20 20\" fill=\"currentColor\">\n <path fill-rule=\"evenodd\" d=\"M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z\" clip-rule=\"evenodd\" />\n</svg>`;\n\n/**\n * create-transform=\"slug\": lowercase, spaces → '_', strip anything else\n * non-alphanumeric, collapse/trim stray underscores.\n */\nfunction slugify(text: string): string {\n return text\n .trim()\n .toLowerCase()\n .replace(/\\s+/g, \"_\")\n .replace(/[^a-z0-9_]/g, \"\")\n .replace(/_+/g, \"_\")\n .replace(/^_|_$/g, \"\");\n}\n\n/**\n * Search (magnifier) icon SVG — popup search input adornment (from Lucide)\n */\nconst SEARCH_ICON_SVG = `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <circle cx=\"11\" cy=\"11\" r=\"8\"/><path d=\"m21 21-4.3-4.3\"/>\n</svg>`;\n\n/**\n * Clear (X) icon SVG — .select-clear button, shown in the trigger's fallback\n * chrome (default/compact skins) when clearable and something is selected.\n */\nconst CLEAR_ICON_SVG = `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"></line>\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"></line>\n</svg>`;\n\ninterface TagData {\n value: string;\n text: string;\n element: HTMLElement;\n}\n\ninterface SelectState {\n open: boolean;\n search: string;\n highlightedIndex: number;\n filteredTags: TagData[];\n selectedValues: string[];\n mode: \"desktop\" | \"mobile\";\n}\n\ntype ChangeAction = \"add\" | \"remove\" | \"clear\" | \"set\" | \"create\";\n\n/**\n * Detail for the cancelable `create` event — fired before a new option is\n * minted from typed search text (see tryCreateFromSearch). Listeners may\n * mutate `value` (e.g. slugify it) or call preventDefault() to take over\n * entirely (create their own <ty-option>, e.g. after a server round-trip).\n */\ninterface CreateEventDetail {\n value: string;\n label: string;\n}\n\n/**\n * Selected item info — enough for out-of-band chip rendering\n */\ninterface SelectedItem {\n value: string;\n label: string;\n flavor: string | null;\n}\n\n/**\n * Change event detail. `value` follows cardinality: scalar (or null) for\n * single select, array for multiple — `values` is always the array form.\n */\ninterface ChangeEventDetail {\n value: string | string[] | null;\n values: string[];\n items: SelectedItem[];\n action: ChangeAction;\n item: string | null;\n}\n\n/**\n * Ty Select Component\n */\nexport class TySelect extends TyComponent<SelectState> {\n // PROPERTY CONFIGURATION - Declarative property lifecycle\n protected static properties = {\n value: {\n type: \"string\" as const,\n visual: true,\n formValue: true,\n emitChange: false,\n default: \"\",\n coerce: (v: any) => {\n // Handle array input (from React, Reagent, etc.)\n if (Array.isArray(v)) {\n return v.join(\",\");\n }\n if (v === null || v === undefined) {\n return \"\";\n }\n return String(v);\n },\n },\n name: {\n type: \"string\" as const,\n default: \"\",\n },\n // Cardinality — native <select> semantics: absent = single select\n multiple: {\n type: \"boolean\" as const,\n visual: true,\n default: false,\n },\n // Skin — absent = form field (matches ty-input); present = compact\n // content-hugging trigger (toolbars, filter bars)\n compact: {\n type: \"boolean\" as const,\n visual: true,\n default: false,\n },\n placeholder: {\n type: \"string\" as const,\n visual: true,\n default: \"Select...\",\n },\n label: {\n type: \"string\" as const,\n visual: true,\n default: \"\",\n },\n disabled: {\n type: \"boolean\" as const,\n visual: true,\n default: false,\n },\n readonly: {\n type: \"boolean\" as const,\n visual: true,\n default: false,\n },\n required: {\n type: \"boolean\" as const,\n visual: true,\n default: false,\n },\n // Error line under the field, same as ty-input's; '' clears it.\n // Validation writes it too (submit, reportValidity — utils/validity.ts).\n error: {\n type: \"string\" as const,\n visual: true,\n default: \"\",\n },\n // Built-in × clear button in the default/compact trigger, shown once\n // something is selected. Automatically absent under slot=\"trigger\" —\n // it lives in the slot's fallback content, same mechanism that already\n // hides the chevron there. no-clear turns it off, like ty-date-picker.\n noClear: {\n type: \"boolean\" as const,\n visual: true,\n default: false,\n },\n externalSearch: {\n type: \"boolean\" as const,\n visual: true,\n default: false,\n aliases: { \"external-search\": true },\n },\n // Enter on unmatched search text mints a new <ty-option> — forces the\n // search row on (same as external-search: the input IS the mechanism).\n allowCreate: {\n type: \"boolean\" as const,\n visual: true,\n default: false,\n aliases: { \"allow-create\": true },\n },\n // Opt-in normalizer for the value minted by allow-create (label/display\n // text is always kept verbatim). 'none' (default): value === typed text.\n // 'slug': lowercase, spaces → '_', strips anything else non-alphanumeric.\n createTransform: {\n type: \"string\" as const,\n visual: false,\n default: \"none\",\n aliases: { \"create-transform\": true },\n coerce: (v: any) => (v === \"slug\" ? \"slug\" : \"none\"),\n },\n // The search row is automatic — it appears once the list is long enough\n // to scroll (SEARCH_AUTO_THRESHOLD). `not-searchable` is the single\n // opt-out, named as the deviation from the default like native\n // `disabled`; bare presence means true per the standard boolean-attribute\n // coercion. There is deliberately no positive `searchable` attribute:\n // forcing the row on where the auto rule says it isn't needed was an\n // option nobody could reason about from the markup.\n // external-search/allow-create still pin it on — the input IS their\n // mechanism, so not-searchable cannot turn it off.\n notSearchable: {\n type: \"boolean\" as const,\n visual: true,\n default: false,\n },\n // Horizontal anchor for the popup: \"start\" (default) matches the\n // trigger's left edge, \"end\" matches its right edge — either way\n // clamped into the viewport. Useful with slot=\"trigger\" custom\n // triggers whose own position makes left-anchoring look wrong (e.g.\n // an icon button at the right edge of a toolbar).\n align: {\n type: \"string\" as const,\n visual: true,\n default: \"start\",\n validate: (v: any) => [\"start\", \"center\", \"end\"].includes(v),\n coerce: (v: any) =>\n v === \"end\" ? \"end\" : v === \"center\" ? \"center\" : \"start\",\n },\n // Full placement, same vocabulary as ty-popup/ty-tooltip: a side plus an\n // optional cross-axis alignment (\"bottom-end\", \"top-start\", …). A dropdown\n // only lives above or below its trigger, so left/right degrade to auto-side\n // with the alignment kept. Takes precedence over `align` when set; `align`\n // stays supported on its own for back-compat.\n placement: {\n type: \"string\" as const,\n visual: true,\n default: \"\",\n },\n size: {\n type: \"string\" as const,\n visual: true,\n default: DEFAULT_SIZE,\n validate: (v: any) => [\"xs\", \"sm\", \"md\", \"lg\", \"xl\"].includes(v),\n coerce: (v: any) => {\n if (![\"xs\", \"sm\", \"md\", \"lg\", \"xl\"].includes(v)) {\n console.warn(`[ty-select] Invalid size. Using ${DEFAULT_SIZE}.`);\n return DEFAULT_SIZE;\n }\n return v;\n },\n },\n debounce: {\n type: \"number\" as const,\n default: 0,\n validate: (v: any) => v >= 0 && v <= 5000,\n coerce: (v: any) => {\n const num = Number(v);\n if (isNaN(num)) return 0;\n return Math.max(0, Math.min(5000, num));\n },\n },\n \"available-label\": {\n type: \"string\" as const,\n visual: true,\n default: \"Available\",\n },\n \"selected-label\": {\n type: \"string\" as const,\n visual: true,\n default: \"Selected\",\n },\n \"no-options-message\": {\n type: \"string\" as const,\n visual: true,\n default: \"No options available\",\n },\n loading: {\n type: \"boolean\" as const,\n visual: true,\n default: false,\n },\n // Any string is accepted: built-ins get static CSS, other identifiers\n // become custom flavors (see _syncCustomFlavor), garbage degrades to\n // the default look.\n flavor: {\n type: \"string\" as const,\n visual: true,\n default: \"neutral\",\n },\n };\n\n // INTERNAL STATE\n private _name: string = \"\";\n private _multiple = false;\n private _compact = false;\n private _placeholder: string = \"Select...\";\n private _label: string = \"\";\n private _disabled = false;\n private _readonly = false;\n private _required = false;\n private _clearable = true;\n private _externalSearch = false;\n private _allowCreate = false;\n private _createTransform: \"none\" | \"slug\" = \"none\";\n private _notSearchable = false;\n private _loading = false;\n private _scrollLockId: string | null = null;\n private _size: Size = DEFAULT_SIZE;\n private _availableLabel: string = \"Available\";\n private _selectedLabel: string = \"Selected\";\n private _noOptionsMessage: string = \"No options available\";\n\n private _state: SelectState = {\n open: false,\n search: \"\",\n highlightedIndex: -1,\n filteredTags: [],\n selectedValues: [],\n mode: \"desktop\", // Updated dynamically on render via syncMode()\n };\n\n private _stubClickHandler: ((e: Event) => void) | null = null;\n private _tagClickHandler: ((e: Event) => void) | null = null;\n private _searchInputHandler: ((e: Event) => void) | null = null;\n private _blockSearchClick: ((e: Event) => void) | null = null;\n private _keyboardHandler: ((e: KeyboardEvent) => void) | null = null;\n\n private _debounce: number = 0;\n private _searchDebounceTimer: number | null = null;\n\n private _optionsScrollbar: CustomScrollbar | null = null;\n\n // MutationObserver for light-DOM children — re-syncs selected tags' visual\n // state when consumers swap tag children (external-search refresh pattern).\n private _childObserver: MutationObserver | null = null;\n\n // Last single-select display clone — survives external-search option swaps\n // that remove the matching option (and often the clone itself) from the DOM.\n private _selectedClone: HTMLElement | null = null;\n\n private _customFlavorSheet: CSSStyleSheet | null = null;\n\n // The slotted trigger carrying the error's aria (see syncFieldChrome).\n private _ariaTrigger: HTMLElement | null = null;\n\n constructor() {\n super(); // TyComponent handles attachInternals() and attachShadow()\n\n const shadow = this.shadowRoot!;\n ensureStyles(shadow, { css: selectBaseStyles, id: \"ty-select-base\" });\n ensureStyles(shadow, { css: selectStyles, id: \"ty-select\" });\n\n // DON'T render here - wait for onConnect() to initialize values first\n // This matches dropdown.ts pattern and prevents showing empty state\n }\n\n /** TyComponent handles property capture automatically. */\n protected onConnect(): void {\n // SAFETY: Close any open dialogs to prevent scroll locking\n const shadow = this.shadowRoot!;\n const dialogs = shadow.querySelectorAll(\"dialog\");\n dialogs.forEach((dialog) => {\n if (dialog.open) {\n console.warn(\"⚠️ Found open dialog on connect, closing it\");\n dialog.close();\n }\n });\n\n // Render FIRST to create DOM structure...\n this.render();\n\n // ...THEN resolve initial selection state. Synchronous, not deferred to\n // a frame: `value` is the selection (see getSelectedValues()), and any\n // consumer reading it — most directly ty-selected-tags, which renders\n // its OWN connectedCallback synchronously right after this element's —\n // must see the real answer immediately. A deferred frame here used to be\n // invisible because the OLD `.value` getter re-scanned option[selected]\n // attributes directly, which are present in the DOM from parse time\n // regardless of when this element's own JS runs; state has no such\n // freebie and must be populated in the same tick. Re-verified against\n // the full unit + e2e suite with no deferral: nothing here actually\n // depended on waiting a frame.\n this.initializeState();\n // Empty single selects still submit name= (see getFormValue)\n this.updateFormValue();\n\n // Observe light-DOM children — re-sync selected state when consumers swap\n // tag children (external-search refresh). syncSelectedTags is idempotent\n // (only acts on tags whose desired-vs-actual selected state differs), so\n // spurious firings caused by our own re-slot work are no-ops.\n this._childObserver = new MutationObserver(() => {\n this.ensureOptionRoles();\n if (this._state.selectedValues.length > 0) {\n this.syncSelectedTags(this._state.selectedValues);\n }\n // Option count may have crossed the auto threshold\n this.updateSearchVisibility();\n // External-search consumers replace ALL ty-option children — often\n // including our display clone. Rebuild the selection display (idempotent:\n // a clone that already matches is left alone, so no observer loop).\n this.updateSelectionDisplay();\n // Mobile's \"Available (N)\" count and empty-state come from\n // updateMobileSelectedState(), which internal search filtering already\n // triggers — but external-search bypasses internal filtering entirely\n // (handleSearchInput returns early for it), so this was the only place\n // left that could catch a child-list change and it didn't. Without\n // this, .mobile-available-section[data-empty=\"true\"] slot { display:\n // none } stays stuck hidden after a consumer replaces the options —\n // the new options are correctly in the DOM, just invisible.\n this.updateMobileSelectedState();\n });\n this._childObserver.observe(this, { childList: true });\n // MutationObserver only fires on FUTURE mutations — cover the initial\n // set of options too (the common case: none selected yet at connect).\n this.ensureOptionRoles();\n\n this._syncCustomFlavor();\n this.syncErrorFlavor();\n\n // Keys while the list is open (handleKeyboard). Here, not in the\n // build-once render paths, so a moved select gets it back. Capture: the\n // open list is the topmost dialog, so its keys are ours before a ty-popup\n // or ty-modal around it stops them.\n if (!this._keyboardHandler) {\n this._keyboardHandler = this.handleKeyboard.bind(this);\n document.addEventListener(\"keydown\", this._keyboardHandler, true);\n }\n }\n\n /** Custom (non-built-in) flavors — see utils/flavor-sheet.ts. */\n private _syncCustomFlavor(): void {\n this._customFlavorSheet = syncCustomFlavorSheet(\n this.shadowRoot!,\n this._customFlavorSheet,\n this.getProperty(\"flavor\"),\n ({ base }) => selectCustomFlavorCss(base),\n );\n }\n\n /**\n * `error` turns a neutral select danger, like ty-input; clearing it puts\n * back exactly the flavor attribute the author had, or none, kept meanwhile\n * in ERROR_FLAVOR. Runs once connected: while the element upgrades, `error`\n * may come before the `flavor` written next to it.\n */\n private syncErrorFlavor(): void {\n if (!this._connected) return;\n const flavor = this.getProperty(\"flavor\");\n const replaced = this.getAttribute(ERROR_FLAVOR);\n if (this.getProperty(\"error\")) {\n if (replaced === null && flavor === \"neutral\") {\n this.setAttribute(ERROR_FLAVOR, this.getAttribute(\"flavor\") ?? \"\");\n this.setProperty(\"flavor\", \"danger\");\n }\n } else if (replaced !== null) {\n this.removeAttribute(ERROR_FLAVOR);\n if (flavor !== \"danger\") return;\n if (!replaced) this.removeAttribute(\"flavor\");\n else this.setProperty(\"flavor\", replaced);\n }\n }\n\n protected onDisconnect(): void {\n // Removed while open (e.g. along with the ty-modal around it): close\n // properly, or the scroll lock outlives the element.\n if (this._state.open) {\n if (this._state.mode === \"mobile\") this.closeMobileModal();\n else this.closeDropdown();\n }\n\n // CRITICAL: Close all dialogs to prevent scroll locking\n const shadow = this.shadowRoot!;\n const dialogs = shadow.querySelectorAll(\"dialog\");\n dialogs.forEach((dialog) => {\n if (dialog.open) {\n dialog.close();\n }\n });\n\n if (this._keyboardHandler) {\n document.removeEventListener(\"keydown\", this._keyboardHandler, true);\n this._keyboardHandler = null;\n }\n\n if (this._searchDebounceTimer !== null) {\n clearTimeout(this._searchDebounceTimer);\n this._searchDebounceTimer = null;\n }\n\n this._destroyOptionsScrollbar();\n\n if (this._childObserver) {\n this._childObserver.disconnect();\n this._childObserver = null;\n }\n }\n\n /** Handle state synchronization BEFORE render. */\n protected onPropertiesChanged(changes: PropertyChange[]): void {\n for (const { name, newValue } of changes) {\n switch (name) {\n case \"value\":\n const selectedValues = this.parseValue(newValue);\n this._state.selectedValues = selectedValues;\n\n // CRITICAL: Only sync tags if we're connected and tags exist\n // During initial property setup (before onConnect), tags don't exist yet\n if (this.isConnected && this.shadowRoot) {\n this.syncSelectedTags(selectedValues);\n this.updateSelectionDisplay();\n this.updateMobileSelectedState();\n }\n // (not-yet-connected: sync deferred to initializeState)\n break;\n case \"name\":\n this._name = newValue || \"\";\n break;\n case \"flavor\":\n // The author picked a flavor while the error showed: theirs now.\n // Neutral, or none, is no pick: the error shows danger again, the\n // same as when the select starts out that way.\n if (newValue !== \"danger\") {\n this.removeAttribute(ERROR_FLAVOR);\n this.syncErrorFlavor();\n }\n this._syncCustomFlavor();\n break;\n case \"error\":\n this.syncErrorFlavor();\n break;\n case \"multiple\":\n this._multiple = newValue;\n // Dropping to single with a multi selection: keep only the first\n if (!newValue && this._state.selectedValues.length > 1) {\n this.updateComponentValue(\n [this._state.selectedValues[0]],\n false,\n \"set\",\n null,\n );\n }\n break;\n case \"compact\":\n this._compact = newValue;\n break;\n case \"placeholder\":\n this._placeholder = newValue || \"Select...\";\n if (this.isConnected && this.shadowRoot)\n this.updateSelectionDisplay();\n break;\n case \"label\":\n this._label = newValue || \"\";\n break;\n case \"disabled\":\n this._disabled = newValue;\n break;\n case \"readonly\":\n this._readonly = newValue;\n break;\n case \"required\":\n this._required = newValue;\n break;\n case \"noClear\":\n this._clearable = !newValue;\n if (this.isConnected && this.shadowRoot) this.updateSelectionDisplay();\n break;\n case \"externalSearch\":\n this._externalSearch = newValue;\n break;\n case \"notSearchable\":\n this._notSearchable = newValue;\n if (this.isConnected && this.shadowRoot)\n this.updateSearchVisibility();\n break;\n case \"allowCreate\":\n this._allowCreate = newValue;\n if (this.isConnected && this.shadowRoot)\n this.updateSearchVisibility();\n break;\n case \"createTransform\":\n this._createTransform = newValue;\n break;\n case \"size\":\n this._size = newValue;\n break;\n case \"debounce\":\n this._debounce = newValue;\n break;\n case \"available-label\":\n this._availableLabel = newValue || \"Available\";\n break;\n case \"selected-label\":\n this._selectedLabel = newValue || \"Selected\";\n break;\n case \"no-options-message\":\n this._noOptionsMessage = newValue || \"No options available\";\n break;\n case \"loading\":\n this._loading = newValue;\n this.applyLoadingState();\n break;\n }\n }\n }\n\n /**\n * Toggle the loading visual state on the open popup.\n * Replaces the available-options area with a centered spinner; search input stays usable.\n * Pulls the latest registered loader SVG on each call so registry changes\n * take effect on the next loading toggle.\n */\n private applyLoadingState(): void {\n const shadow = this.shadowRoot;\n if (!shadow) return;\n const svg = this._loading ? getLoaderSvg() : null;\n shadow.querySelectorAll(\".dropdown-options-wrapper\").forEach((wrapper) => {\n wrapper.classList.toggle(\"loading\", this._loading);\n if (this._loading) {\n wrapper.setAttribute(\"aria-busy\", \"true\");\n const spinner = wrapper.querySelector(\".dropdown-loading-spinner\");\n if (spinner && svg) spinner.innerHTML = svg;\n } else {\n wrapper.removeAttribute(\"aria-busy\");\n }\n });\n }\n\n /** Form value: a plain entry for single, FormData with repeated entries for multiple (HTMX standard). */\n protected getFormValue(): FormDataEntryValue | FormData | null {\n const selectedValues = this._state.selectedValues;\n\n if (this._name && selectedValues.length > 0) {\n // Single select submits one plain entry\n if (!this._multiple) return selectedValues[0];\n\n // Multiple submits repeated `name=` entries (HTMX standard)\n const formData = new FormData();\n selectedValues.forEach((value) => {\n formData.append(this._name, value);\n });\n return formData;\n }\n\n // Native fidelity: a single select with nothing chosen submits name=\n // (like a <select> on its empty placeholder option); multiple submits nothing.\n if (this._name && !this._multiple) return \"\";\n return null;\n }\n\n /** Focus the trigger: a slotted one, else the field. The host itself isn't focusable. */\n focus(options?: FocusOptions): void {\n if (this._disabled) return; // like a disabled <select>\n const trigger = this.querySelector(':scope > [slot=\"trigger\"]') as HTMLElement | null;\n const stub = this.shadowRoot?.querySelector(\".select-stub\") as HTMLElement | null;\n const target = trigger ?? stub;\n if (target) target.focus(options);\n else super.focus(options);\n }\n\n private parseValue(value: string | null): string[] {\n // Defensive check: ensure value is actually a string before calling .trim()\n if (!value || typeof value !== \"string\" || value.trim() === \"\") return [];\n return value\n .split(\",\")\n .map((v) => v.trim())\n .filter((v) => v !== \"\");\n }\n\n /** Initialize component state from the value property / pre-selected children. */\n private initializeState(): void {\n const initialValue = this.getProperty(\"value\") || \"\";\n\n if (initialValue) {\n // Explicit value provided - sync tags directly\n // DON'T use updateComponentValue() because the property is already set!\n const selectedValues = this.parseValue(initialValue);\n\n this._state.selectedValues = selectedValues;\n\n this.syncSelectedTags(selectedValues);\n\n this.updateSelectionDisplay();\n this.updateMobileSelectedState();\n } else {\n this.resolveDeclarativeSelection();\n }\n }\n\n /**\n * Declarative init: no `value` attribute, but markup pre-marked one or more\n * options `selected` — native <select> semantics. This is the ONE place\n * selection is read FROM the DOM rather than treated as a rendering of\n * state (see getSelectedValues()): it seeds initial state, once. After\n * this, `value` rules — flipping an option's `selected` property later\n * does nothing, same as native.\n *\n * Called from initializeState() at connect AND from the child observer:\n * a real HTML parser upgrades a custom element the moment its start tag is\n * seen, BEFORE its children exist — `<ty-select>` connects with zero\n * `<ty-option>` children when it's part of the page's own markup (as\n * opposed to an already-built fragment attached via innerHTML/appendChild,\n * where children exist at connect). Calling this only at connect would\n * silently miss every option parsed after that instant, which is the\n * common case for markup that is literally in the page's initial HTML.\n *\n * Safe to call repeatedly: no-ops once `value` has ever been explicitly\n * set (attribute or property) or state is already non-empty — including\n * after a real `.clear()`, which removes `selected` from every option via\n * syncSelectedTags, so there is nothing left here to (re-)seed from.\n */\n private resolveDeclarativeSelection(): void {\n if (this.getAttribute(\"value\") || this._state.selectedValues.length > 0) {\n return;\n }\n const preSelectedTags = this.getTagElements()\n .filter((tag) => tag.hasAttribute(\"selected\"))\n .map((tag) => this.getTagData(tag).value);\n\n if (preSelectedTags.length > 0) {\n // updateComponentValue's change-guard compares against STATE (empty\n // here), not the DOM, so it correctly sees this as a real change.\n this.updateComponentValue(preSelectedTags, false);\n return;\n }\n\n // Found nothing YET, and the document is still parsing: a real HTML\n // parser upgrades a custom element the moment its start tag is seen —\n // BEFORE its children exist — so `<ty-select>` that's part of the\n // page's own markup can connect with zero `<ty-option>` children even\n // though its full option list, `selected` attributes included, is\n // right there a few tokens later in the same document. (Not a factor\n // for an already-built fragment attached via innerHTML/appendChild,\n // where children exist at connect — only for markup the browser's own\n // parser is still working through.) Recheck once, when parsing is\n // guaranteed complete, same technique as the streaming-parse guard in\n // syncSelectedClone. Deliberately NOT re-run from the child observer:\n // that would also fire for a LATER external-search swap, and could\n // resurrect a selection the user had just deliberately cleared from a\n // freshly-swapped-in option that happens to carry a stale `selected`\n // attribute from server-rendered markup.\n if (document.readyState === \"loading\") {\n document.addEventListener(\n \"DOMContentLoaded\",\n () => { if (this.isConnected) this.resolveDeclarativeSelection(); },\n { once: true },\n );\n }\n }\n\n // TAG MANAGEMENT METHODS\n\n /**\n * Get all option elements from the component (ty-option preferred, ty-tag accepted)\n */\n private getTagElements(): HTMLElement[] {\n // :not([cloned]) — the single-select display clone (slot=\"selected\")\n // lives in our light DOM too and must never count as an option\n return Array.from(\n this.querySelectorAll(\"ty-option:not([cloned]), ty-tag:not([cloned])\"),\n ) as HTMLElement[];\n }\n\n private getTagData(element: HTMLElement): TagData {\n const value =\n (element as any).value ||\n element.getAttribute(\"value\") ||\n element.textContent ||\n \"\";\n // Display label: explicit label attribute wins over textContent —\n // native <option label> semantics; lets rich options declare clean text\n const text =\n element.getAttribute(\"label\") || element.textContent || \"\";\n\n return { value, text, element };\n }\n\n /**\n * Select an option - attribute only. The option stays in the list with\n * selected styling; chips are rendered out-of-band (ty-selected-options).\n */\n private selectTag(tag: HTMLElement): void {\n tag.setAttribute(\"selected\", \"\");\n }\n\n /**\n * Deselect an option - attribute only.\n */\n private deselectTag(tag: HTMLElement): void {\n tag.removeAttribute(\"selected\");\n }\n\n /**\n * Get the array of currently selected values.\n *\n * Reads STATE (`_state.selectedValues`), not the DOM: `value` is the\n * selection, and an option's `selected` attribute is a rendering of it\n * (written by syncSelectedTags below), never the other way round. This\n * matters whenever options don't fully reflect the selection — external\n * search legitimately has a selected value with no matching option\n * present; a DOM scan would report empty and desync .value, `required`\n * validation and the click-toggle logic from what's actually selected.\n */\n private getSelectedValues(): string[] {\n return [...this._state.selectedValues];\n }\n\n private syncSelectedTags(selectedValues: string[]): void {\n const selectedSet = new Set(selectedValues);\n const tags = this.getTagElements();\n\n tags.forEach((tag) => {\n const tagValue = this.getTagData(tag).value;\n const shouldBeSelected = selectedSet.has(tagValue);\n const isSelected = tag.hasAttribute(\"selected\");\n\n if (shouldBeSelected && !isSelected) {\n this.selectTag(tag);\n } else if (!shouldBeSelected && isSelected) {\n this.deselectTag(tag);\n }\n // ARIA listbox pattern: every option reports its live selected state,\n // not just ones that changed this pass — cheap (idempotent setAttribute).\n tag.setAttribute(\"aria-selected\", String(shouldBeSelected));\n });\n }\n\n /**\n * role=\"option\" for every current option/tag — separate from\n * syncSelectedTags (which only runs when the `value` property changes)\n * so it also covers the \"nothing selected yet, value never touched\"\n * startup case. Idempotent; cheap to call from the child MutationObserver\n * on every light-DOM change.\n */\n private ensureOptionRoles(): void {\n this.getTagElements().forEach((tag) => {\n if (!tag.hasAttribute(\"role\")) tag.setAttribute(\"role\", \"option\");\n if (!tag.hasAttribute(\"aria-selected\")) tag.setAttribute(\"aria-selected\", \"false\");\n });\n }\n\n /** Central update function — synchronizes everything via TyComponent's property system. */\n private updateComponentValue(\n newValues: string[],\n dispatchChange: boolean = false,\n action: ChangeAction = \"set\",\n item: string | null = null,\n reveal: boolean = dispatchChange,\n ): void {\n const oldValues = this.getSelectedValues();\n\n const valueStr = newValues.join(\",\");\n\n if (JSON.stringify(newValues.sort()) !== JSON.stringify(oldValues.sort())) {\n // Use TyComponent's property system - this will trigger:\n // 1. onPropertiesChanged() → syncs tags via syncSelectedTags()\n // 2. onPropertiesChanged() → updates placeholder via updateSelectionDisplay()\n // 3. updateFormValue() → automatic (formValue: true in config)\n // 4. render() → automatic if visual properties changed\n this.setProperty(\"value\", valueStr);\n\n // Explicit call, not just relying on render()'s cascade — `value` may\n // not always be flagged as a \"visual\" property requiring a full\n // re-render, and validity must update the moment selection changes.\n this.updateValidity();\n\n // Dispatch change event (with rich items for out-of-band chip rendering)\n if (dispatchChange) {\n this.dispatchChangeEvent({\n // Scalar for single select, array for multiple\n value: this._multiple ? [...newValues] : (newValues[0] ?? null),\n values: newValues,\n items: this.getSelectedItems(newValues),\n action,\n item,\n });\n // A user change, like a native select's :user-invalid: show the\n // message now if it left the field invalid (including a\n // setCustomValidity() the change handler just made).\n if (reveal) this.revealValidity();\n }\n }\n }\n\n /**\n * Build rich item info for values, read off the matching option elements\n */\n private getSelectedItems(values: string[]): SelectedItem[] {\n const byValue = new Map(\n this.getTagElements().map((el) => [this.getTagData(el).value, el]),\n );\n return values.map((value) => {\n const el = byValue.get(value);\n return {\n value,\n // label attribute wins (native <option label> semantics)\n label: el?.getAttribute(\"label\") || el?.textContent?.trim() || value,\n flavor: el?.getAttribute(\"flavor\") ?? null,\n };\n });\n }\n\n // DROPDOWN METHODS\n\n private calculatePosition(): void {\n const shadow = this.shadowRoot!;\n const stub = shadow.querySelector(\".select-stub\") as HTMLElement;\n const dialog = shadow.querySelector(\n \".dropdown-dialog\",\n ) as HTMLDialogElement;\n\n if (!stub || !dialog) return;\n\n const stubRect = stub.getBoundingClientRect();\n\n // Get dialog dimensions (it's already shown with showModal).\n // Cap the estimate: with hundreds of options the raw measurement can be\n // the uncapped content height, which made \"fits below?\" always false.\n // 440px ≈ options max-height (24rem) + search header.\n const MAX_POPUP_ESTIMATE = 440;\n const dialogRect = dialog.getBoundingClientRect();\n const estimatedHeight = Math.min(\n dialogRect.height || 200,\n MAX_POPUP_ESTIMATE,\n );\n\n const wrapPadding = 20;\n\n // Popup width is independent of the trigger — a small button trigger still\n // gets a usable list. Overridable via --ty-select-popup-width.\n const cssWidth = parseFloat(\n getComputedStyle(this).getPropertyValue(\"--ty-select-popup-width\"),\n );\n const popupWidth = !isNaN(cssWidth)\n ? cssWidth\n : Math.max(stubRect.width, 320);\n\n // `placement` wins when set; otherwise fall back to the older `align`-only\n // API so existing markup keeps its behaviour.\n const requested = this.getProperty(\"placement\") as Placement | \"\";\n const anchored = requested\n ? placementToAnchored(requested)\n : {\n side: \"auto\" as const,\n align: this.getProperty(\"align\") as \"start\" | \"center\" | \"end\",\n };\n\n const pos = computeAnchoredPosition({\n anchorRect: stubRect,\n popupWidth,\n popupHeight: estimatedHeight,\n align: anchored.align,\n side: anchored.side,\n gap: 8, // unified trigger→popup offset (select/date-picker/popup)\n });\n const positionBelow = pos.below;\n\n // Shift by the dialog's transparent wrap (room for shadows)\n const x = pos.x - wrapPadding;\n const y = (positionBelow ? pos.topY : pos.bottomY) - wrapPadding;\n const width = popupWidth + wrapPadding + wrapPadding;\n\n this.style.setProperty(\"--dropdown-x\", `${x}px`);\n this.style.setProperty(\"--dropdown-y\", `${y}px`);\n this.style.setProperty(\"--dropdown-width\", `${width}px`);\n this.style.setProperty(\"--dropdown-offset-x\", \"0px\");\n this.style.setProperty(\"--dropdown-offset-y\", \"0px\");\n this.style.setProperty(\"--dropdown-padding\", `${wrapPadding}px`);\n\n if (positionBelow) {\n dialog.classList.add(\"position-below\");\n dialog.classList.remove(\"position-above\");\n } else {\n dialog.classList.add(\"position-above\");\n dialog.classList.remove(\"position-below\");\n }\n\n // Optional: Store direction for debugging\n this.style.setProperty(\n \"--dropdown-direction\",\n positionBelow ? \"below\" : \"above\",\n );\n }\n\n // CUSTOM SCROLLBAR FOR OPTIONS\n\n private _setupOptionsScrollbar(): void {\n if (!isCustomScrollbarEnabled()) return;\n\n const shadow = this.shadowRoot!;\n const optionsDiv = shadow.querySelector(\".dropdown-options\") as HTMLElement;\n const optionsWrapper = shadow.querySelector(\n \".dropdown-options-wrapper\",\n ) as HTMLElement;\n if (!optionsDiv || !optionsWrapper) return;\n\n this._destroyOptionsScrollbar();\n\n optionsDiv.classList.add(\"ty-custom-scroll\");\n this._optionsScrollbar = new CustomScrollbar(optionsDiv, {\n vertical: true,\n });\n\n if (this._optionsScrollbar.trackY) {\n optionsWrapper.appendChild(this._optionsScrollbar.trackY);\n }\n }\n\n private _destroyOptionsScrollbar(): void {\n if (this._optionsScrollbar) {\n this._optionsScrollbar.trackY?.remove();\n this._optionsScrollbar.destroy();\n this._optionsScrollbar = null;\n }\n }\n\n /**\n * Open dropdown dialog (desktop mode)\n *\n * `<dialog>.showModal()` puts the dialog in the top layer with a backdrop, but\n * does NOT prevent the page behind it from scrolling. We use the shared scroll\n * lock utility (overflow:hidden on <html>) to keep wheel/touch scrolling from\n * leaking through to the body — same behavior <ty-dropdown> and <ty-modal>\n * implement.\n */\n private openDropdown(): void {\n const shadow = this.shadowRoot!;\n const dialog = shadow.querySelector(\n \".dropdown-dialog\",\n ) as HTMLDialogElement;\n if (!dialog) return;\n\n const stubEl = shadow.querySelector(\".select-stub\");\n if (stubEl) stubEl.setAttribute(\"aria-expanded\", \"true\");\n\n // Lock body scroll while dropdown is open\n const lockId = `select-${this.id || \"anon\"}-${getElementHash(this)}`;\n this._scrollLockId = lockId;\n lockScroll(lockId);\n\n dialog.showModal();\n\n // Position BEFORE adding .open: calculatePosition reads layout\n // (getBoundingClientRect), which commits the dialog's pre-open styles —\n // without that flush the enter transition never runs, the dropdown just\n // pops in. (This ordering is why the date-picker animated and select\n // didn't.)\n this.calculatePosition();\n dialog.classList.add(\"open\");\n\n this._state.open = true;\n\n const chevron = shadow.querySelector(\".dropdown-chevron\");\n if (chevron) chevron.classList.add(\"open\");\n\n const searchChevron = shadow.querySelector(\".dropdown-search-chevron\");\n if (searchChevron) searchChevron.classList.add(\"open\");\n\n const tags = this.getTagElements().map((el) => this.getTagData(el));\n this._state.filteredTags = tags;\n this._state.highlightedIndex = -1;\n\n // Ensure options area is visible (may have been hidden from previous search)\n this.updateOptionsVisibility(true);\n\n this._setupOptionsScrollbar();\n\n // Focus search input (when the search row is shown)\n const searchInput = shadow.querySelector(\n \".dropdown-search-input\",\n ) as HTMLInputElement;\n if (searchInput && this.shouldShowSearch()) {\n setTimeout(() => searchInput.focus(), 100);\n }\n\n // Lifecycle event (also fires empty search if external-search)\n this.fireOpenEvent();\n }\n\n private closeDropdown(): void {\n const shadow = this.shadowRoot!;\n const dialog = shadow.querySelector(\n \".dropdown-dialog\",\n ) as HTMLDialogElement;\n\n if (!dialog) return;\n\n const stubEl = shadow.querySelector(\".select-stub\");\n if (stubEl) stubEl.setAttribute(\"aria-expanded\", \"false\");\n\n this._destroyOptionsScrollbar();\n\n dialog.classList.remove(\"open\");\n dialog.classList.remove(\"position-above\");\n dialog.classList.remove(\"position-below\");\n dialog.close();\n\n // Unlock body scroll (paired with the lock in openDropdown)\n if (this._scrollLockId) {\n unlockScroll(this._scrollLockId);\n this._scrollLockId = null;\n }\n\n this._state.open = false;\n this._state.highlightedIndex = -1;\n\n const chevron = shadow.querySelector(\".dropdown-chevron\");\n if (chevron) chevron.classList.remove(\"open\");\n\n const searchChevron = shadow.querySelector(\".dropdown-search-chevron\");\n if (searchChevron) searchChevron.classList.remove(\"open\");\n\n // Reset search and restore all tags\n const hadQuery = this._state.search !== \"\";\n this._state.search = \"\";\n const searchInput = shadow.querySelector(\n \".dropdown-search-input\",\n ) as HTMLInputElement;\n if (searchInput) {\n searchInput.value = \"\";\n }\n\n if (this._externalSearch) {\n // External mode — notify consumer so it can reset its own filtered state.\n // Bypass the debounce timer (which would delay the clear by `debounce` ms);\n // close-time should be immediate so the consumer's filtered state syncs\n // before the dropdown reopens. Only fire if there was actually a query.\n if (hadQuery) {\n if (this._searchDebounceTimer !== null) {\n clearTimeout(this._searchDebounceTimer);\n this._searchDebounceTimer = null;\n }\n this.fireSearchEvent(\"\");\n }\n } else {\n // Internal mode — restore visibility of all tags ourselves\n const allTags = this.getTagElements().map((el) => this.getTagData(el));\n this._state.filteredTags = allTags;\n this.updateTagVisibility(allTags, allTags);\n this.clearHighlights(allTags);\n }\n\n // Lifecycle event\n this.fireCloseEvent();\n }\n\n /** Open mobile modal — <dialog> handles z-index natively. */\n private openMobileModal(): void {\n const shadow = this.shadowRoot!;\n const dialog = shadow.querySelector(\".mobile-dialog\") as HTMLDialogElement;\n if (!dialog) return;\n\n const stubEl = shadow.querySelector(\".select-stub\");\n if (stubEl) stubEl.setAttribute(\"aria-expanded\", \"true\");\n\n // Lock body scroll while mobile modal is open\n const lockId = `select-${this.id || \"anon\"}-${getElementHash(this)}`;\n this._scrollLockId = lockId;\n lockScroll(lockId);\n\n // Show dialog using native API (handles z-index automatically).\n // getBoundingClientRect flush between showModal and .open lets the enter\n // transition run (see openDropdown).\n dialog.showModal();\n dialog.getBoundingClientRect();\n dialog.classList.add(\"open\");\n\n this._state.open = true;\n\n // Initialize options state. Also ensure nothing stays hidden from a\n // previous search — mirrors openDropdown()'s updateOptionsVisibility(true)\n // (\"may have been hidden from previous search\"), which openMobileModal()\n // never had a mobile-appropriate equivalent for: desktop hides the whole\n // options container (a single display:none toggle, harmless to reset\n // unconditionally), mobile hides individual options via their `hidden`\n // attribute (updateTagVisibility), so the reset has to happen here.\n const tags = this.getTagElements().map((el) => this.getTagData(el));\n this._state.filteredTags = tags;\n this.updateTagVisibility(tags, tags);\n\n // Focus the search input: the `autofocus` attribute on\n // .mobile-search-input (see render template) handles this — showModal()\n // itself runs the spec'd \"dialog focusing steps\" on every call, which\n // look for an autofocus descendant and focus it natively, skipping it\n // automatically if it's hidden (search disabled) in favor of the next\n // focusable element. A manual searchInput.focus() call here, AFTER\n // showModal() already ran its own focusing steps in the same task, was\n // racing that native behavior — document.activeElement ended up back on\n // the host element, not the input, which is why typing did nothing:\n // keystrokes weren't reaching the search box at all despite it visually\n // looking focused (cursor showing from the browser's own caret paint,\n // not actual DOM focus).\n\n // Update state after slots are ready\n requestAnimationFrame(() => {\n this.updateMobileSelectedState();\n });\n\n // Lifecycle event (also fires empty search if external-search)\n this.fireOpenEvent();\n }\n\n private closeMobileModal(): void {\n const shadow = this.shadowRoot!;\n const dialog = shadow.querySelector(\".mobile-dialog\") as HTMLDialogElement;\n if (!dialog) return;\n\n const stubEl = shadow.querySelector(\".select-stub\");\n if (stubEl) stubEl.setAttribute(\"aria-expanded\", \"false\");\n\n // Close immediately — ::backdrop doesn't support transitions\n dialog.classList.remove(\"open\");\n dialog.close();\n\n // Unlock body scroll (paired with the lock in openMobileModal)\n if (this._scrollLockId) {\n unlockScroll(this._scrollLockId);\n this._scrollLockId = null;\n }\n\n this._state.open = false;\n this._state.highlightedIndex = -1;\n\n const hadQuery = this._state.search !== \"\";\n this._state.search = \"\";\n const searchInput = shadow.querySelector(\n \".mobile-search-input\",\n ) as HTMLInputElement;\n if (searchInput) {\n searchInput.value = \"\";\n }\n\n if (this._externalSearch) {\n // External mode — notify consumer that the search was cleared on close\n // (bypass debounce, see desktop close path for rationale).\n if (hadQuery) {\n if (this._searchDebounceTimer !== null) {\n clearTimeout(this._searchDebounceTimer);\n this._searchDebounceTimer = null;\n }\n this.fireSearchEvent(\"\");\n }\n } else {\n // Internal mode — unhide all tags ourselves\n const allTags = this.getTagElements();\n allTags.forEach((el) => el.removeAttribute(\"hidden\"));\n }\n\n // Lifecycle event\n this.fireCloseEvent();\n }\n\n // EVENT HANDLERS\n\n private handleStubClick(e: Event): void {\n e.preventDefault();\n e.stopPropagation();\n\n if (this._disabled || this._readonly) {\n return;\n }\n\n this.openDropdown();\n }\n\n /**\n * .select-clear click — must stop propagation before it bubbles to the\n * stub's own click handler (which would otherwise also open the dropdown).\n */\n private handleClearClick(e: Event): void {\n e.preventDefault();\n e.stopPropagation();\n\n if (this._disabled || this._readonly) {\n return;\n }\n\n this.clear();\n // The user emptied it: show the message now if that left it invalid\n this.revealValidity();\n }\n\n /**\n * Keyboard-open the (closed) stub. The stub is a plain div with\n * tabindex=\"0\", not a native <button> — Enter/Space don't turn into\n * click events on their own the way they do for real form controls, and\n * without this a keyboard-only user could Tab to the field but never\n * open it. document-level handleKeyboard() only runs once already open\n * (it early-returns on !this._state.open), so this is the other half.\n */\n private handleStubKeydown(e: KeyboardEvent): void {\n if (this._disabled || this._readonly || this._state.open) return;\n if (e.key === \"Enter\" || e.key === \" \" || e.key === \"ArrowDown\") {\n e.preventDefault();\n this.openDropdown();\n }\n }\n\n private handleTagClick(e: Event): void {\n const target = e.target as HTMLElement;\n\n const tag = target.closest(\"ty-option, ty-tag\") as HTMLElement | null;\n\n if (!tag || tag.hasAttribute(\"disabled\")) return;\n\n e.preventDefault();\n e.stopPropagation();\n\n this.selectByTag(tag);\n }\n\n /**\n * Select/toggle a tag by element — the part of handleTagClick that has no\n * dependency on a real DOM event, so keyboard/programmatic callers (Enter\n * on a highlighted option, allow-create's exact-match dedup) can call it\n * directly instead of faking an Event object just to satisfy\n * preventDefault()/stopPropagation().\n */\n private selectByTag(tag: HTMLElement): void {\n const tagValue = this.getTagData(tag).value;\n const currentValues = this.getSelectedValues();\n\n // Single select: picking replaces the selection and closes the popup\n // (native <select> semantics — re-picking the same option just closes)\n if (!this._multiple) {\n this.updateComponentValue([tagValue], true, \"set\", tagValue);\n if (this._state.mode === \"mobile\") {\n this.closeMobileModal();\n } else {\n this.closeDropdown();\n }\n return;\n }\n\n // Multiple: toggle — clicking a selected option deselects it. Reads\n // `currentValues` (state), not the tag's own attribute: see\n // getSelectedValues() for why the attribute isn't the source of truth.\n if (currentValues.includes(tagValue)) {\n const newValues = currentValues.filter((v) => v !== tagValue);\n this.updateComponentValue(newValues, true, \"remove\", tagValue);\n } else {\n this.updateComponentValue(\n [...currentValues, tagValue],\n true,\n \"add\",\n tagValue,\n );\n }\n }\n\n /**\n * allow-create: Enter with unmatched search text mints a new option.\n * Returns true if it handled the key (created, or selected an existing\n * exact match instead of duplicating) — false if there's nothing to do\n * (blank query, or allow-create is off), so the caller's normal Enter\n * handling (select highlighted, or no-op) proceeds.\n */\n private tryCreateFromSearch(): boolean {\n if (!this._allowCreate) return false;\n\n const query = (this._state.search || \"\").trim();\n if (!query) return false;\n\n const queryLower = query.toLowerCase();\n const allTags = this.getTagElements().map((el) => this.getTagData(el));\n\n // Dedup: typed text exactly matches an existing option (by value or\n // display text) — select it instead of minting a duplicate.\n const existing = allTags.find(\n (t) =>\n t.value.toLowerCase() === queryLower ||\n t.text.toLowerCase() === queryLower,\n );\n if (existing) {\n this.selectByTag(existing.element);\n return true;\n }\n\n const rawLabel = query;\n const defaultValue =\n this._createTransform === \"slug\" ? slugify(rawLabel) : rawLabel;\n if (!defaultValue) return true; // slugified to nothing — handled no-op\n\n const detail: CreateEventDetail = { value: defaultValue, label: rawLabel };\n const event = new CustomEvent(\"create\", {\n detail,\n bubbles: true,\n composed: true,\n cancelable: true,\n });\n this.dispatchEvent(event);\n if (event.defaultPrevented) return true; // consumer takes over entirely\n\n const finalValue = detail.value;\n const option = document.createElement(\"ty-option\");\n option.setAttribute(\"value\", finalValue);\n option.textContent = rawLabel;\n this.appendChild(option);\n\n if (!this._multiple) {\n this.updateComponentValue([finalValue], true, \"create\", finalValue);\n if (this._state.mode === \"mobile\") {\n this.closeMobileModal();\n } else {\n this.closeDropdown();\n }\n return true;\n }\n\n const currentValues = this.getSelectedValues();\n this.updateComponentValue(\n [...currentValues, finalValue],\n true,\n \"create\",\n finalValue,\n );\n this.clearSearchAfterCreate();\n return true;\n }\n\n /**\n * Multiple + allow-create: clear the search box and re-show the full\n * (now-longer) option list so the next tag can be typed immediately —\n * the tags-input pattern.\n */\n private clearSearchAfterCreate(): void {\n this._state.search = \"\";\n this._state.highlightedIndex = -1;\n const shadow = this.shadowRoot;\n if (!shadow) return;\n const desktopInput = shadow.querySelector(\n \".dropdown-search-input\",\n ) as HTMLInputElement | null;\n const mobileInput = shadow.querySelector(\n \".mobile-search-input\",\n ) as HTMLInputElement | null;\n if (desktopInput) desktopInput.value = \"\";\n if (mobileInput) mobileInput.value = \"\";\n\n const allTags = this.getTagElements().map((el) => this.getTagData(el));\n this._state.filteredTags = allTags;\n this.updateTagVisibility(allTags, allTags);\n this.updateOptionsVisibility(true);\n this.clearHighlights(allTags);\n this.updateMobileSelectedState();\n (desktopInput ?? mobileInput)?.focus();\n }\n\n private blockSearchClick(e: Event): void {\n e.stopPropagation();\n e.preventDefault();\n }\n\n private handleSearchInput(e: Event): void {\n // Typing is a request to see results, so the list takes the space back\n // even if the selected strip was the one open.\n if (this._state.mode === \"mobile\") this.expandMobileSection(\"available\");\n const target = e.target as HTMLInputElement;\n const query = target.value;\n\n this._state.search = query;\n\n if (this._externalSearch) {\n // External (remote) search: parent owns filtering — delegate via event.\n // Tag visibility is left untouched; consumer is expected to update children.\n this.dispatchSearchEvent(query);\n return;\n }\n\n // Internal search: filter ALL options locally — selected ones stay visible\n // (with selected styling) so they can be toggled off while searching\n const allTags = this.getTagElements().map((el) => this.getTagData(el));\n const filtered = this.filterTags(allTags, query);\n\n this._state.filteredTags = filtered;\n this._state.highlightedIndex = -1;\n\n this.updateTagVisibility(filtered, allTags);\n\n // Hide options area if no results (desktop)\n this.updateOptionsVisibility(filtered.length > 0);\n\n // Refresh mobile count + empty-state to reflect filtered visibility\n this.updateMobileSelectedState();\n\n this.clearHighlights(allTags);\n }\n\n private handleKeyboard(e: KeyboardEvent): void {\n if (!this._state.open) return;\n\n const shadow = this.shadowRoot!;\n const searchInput = shadow.querySelector(\n \".dropdown-search-input\",\n ) as HTMLInputElement;\n const target = e.target as HTMLElement;\n\n // Only handle navigation keys when dropdown is open and either:\n // 1. Event comes from search input, OR\n // 2. Event comes from document but search input is not focused\n const shouldHandle =\n target === searchInput || document.activeElement !== searchInput;\n\n if (!shouldHandle) return;\n\n const filteredTags = this._state.filteredTags;\n const tagsCount = filteredTags.length;\n const currentHighlightedIndex = this._state.highlightedIndex;\n\n switch (e.key) {\n case \"Escape\":\n e.preventDefault();\n e.stopPropagation();\n if (this._state.mode === \"mobile\") {\n this.closeMobileModal();\n } else {\n this.closeDropdown();\n }\n // Back on the trigger, like a native select\n this.focus();\n break;\n\n case \"Enter\":\n e.preventDefault();\n e.stopPropagation();\n // A highlighted (arrowed-to) option always wins — the user picked\n // it explicitly, so allow-create must not shadow it with a new one.\n if (\n currentHighlightedIndex >= 0 &&\n currentHighlightedIndex < tagsCount\n ) {\n this.selectByTag(filteredTags[currentHighlightedIndex].element);\n } else {\n this.tryCreateFromSearch();\n }\n break;\n\n case \"ArrowUp\":\n e.preventDefault();\n e.stopPropagation();\n\n const newIndexUp = this.nextEnabledTagIndex(\n filteredTags,\n currentHighlightedIndex,\n -1,\n );\n this._state.highlightedIndex = newIndexUp;\n this.highlightTag(filteredTags, newIndexUp);\n break;\n\n case \"ArrowDown\":\n e.preventDefault();\n e.stopPropagation();\n\n const newIndexDown = this.nextEnabledTagIndex(\n filteredTags,\n currentHighlightedIndex,\n 1,\n );\n this._state.highlightedIndex = newIndexDown;\n this.highlightTag(filteredTags, newIndexDown);\n break;\n }\n }\n\n /**\n * Next tag index in `direction` (-1/1) that isn't disabled, wrapping\n * around — mirrors handleTagClick's disabled check so keyboard nav can\n * never land on/select what a click already refuses to. Returns -1 if\n * every tag is disabled (or there are none).\n */\n private nextEnabledTagIndex(\n tags: TagData[],\n fromIndex: number,\n direction: 1 | -1,\n ): number {\n const count = tags.length;\n if (count === 0) return -1;\n\n let index = fromIndex === -1\n ? (direction === 1 ? 0 : count - 1)\n : (fromIndex + direction + count) % count;\n\n for (let i = 0; i < count; i++) {\n if (!tags[index].element.hasAttribute(\"disabled\")) return index;\n index = (index + direction + count) % count;\n }\n\n return -1;\n }\n\n // SEARCH & FILTERING HELPERS\n\n private filterTags(tags: TagData[], query: string): TagData[] {\n if (!query || query.trim() === \"\") {\n return tags;\n }\n\n const searchLower = query.toLowerCase();\n return tags.filter(({ text }) => text.toLowerCase().includes(searchLower));\n }\n\n private updateTagVisibility(\n filteredTags: TagData[],\n allTags: TagData[],\n ): void {\n const visibleValues = new Set(filteredTags.map((tag) => tag.value));\n\n allTags.forEach(({ value, element }) => {\n if (visibleValues.has(value)) {\n element.removeAttribute(\"hidden\");\n } else {\n element.setAttribute(\"hidden\", \"\");\n }\n });\n }\n\n private updateOptionsVisibility(hasOptions: boolean): void {\n const shadow = this.shadowRoot!;\n const options = shadow.querySelector(\".dropdown-options\") as HTMLElement;\n if (options) {\n options.style.display = hasOptions ? \"\" : \"none\";\n }\n }\n\n private clearHighlights(tags: TagData[]): void {\n tags.forEach(({ element }) => {\n element.removeAttribute(\"highlighted\");\n });\n }\n\n private highlightTag(tags: TagData[], index: number): void {\n this.clearHighlights(tags);\n\n if (index >= 0 && index < tags.length) {\n const { element } = tags[index];\n element.setAttribute(\"highlighted\", \"\");\n\n element.scrollIntoView({\n behavior: \"smooth\",\n block: \"nearest\",\n inline: \"nearest\",\n });\n }\n }\n\n /** Dispatch the search event for external search handling, with optional debounce. */\n private dispatchSearchEvent(query: string): void {\n if (this._searchDebounceTimer !== null) {\n clearTimeout(this._searchDebounceTimer);\n this._searchDebounceTimer = null;\n }\n\n if (this._debounce > 0) {\n this._searchDebounceTimer = window.setTimeout(() => {\n this.fireSearchEvent(query);\n this._searchDebounceTimer = null;\n }, this._debounce);\n } else {\n this.fireSearchEvent(query);\n }\n }\n\n private fireSearchEvent(query: string): void {\n this.dispatchEvent(\n new CustomEvent(\"search\", {\n detail: {\n query,\n element: this,\n },\n bubbles: true,\n composed: true,\n }),\n );\n }\n\n /**\n * Dispatch lifecycle events for popup open/close.\n * On open with external-search, also fire a `search` event with an empty\n * query so consumers have a clean hook to reset/refetch the option list.\n */\n private fireOpenEvent(): void {\n this.dispatchEvent(\n // ponytail: popup lifecycle events do NOT bubble — same as native\n // <dialog> open/close. A bubbling `close` from a select nested in a\n // ty-modal lands on the modal's own `close` listener and closes it.\n new CustomEvent(\"open\", {\n detail: { mode: this._state.mode, element: this },\n }),\n );\n if (this._externalSearch) {\n this.fireSearchEvent(\"\");\n }\n }\n\n private fireCloseEvent(): void {\n this.dispatchEvent(\n // ponytail: non-bubbling, see fireOpenEvent()\n new CustomEvent(\"close\", {\n detail: { mode: this._state.mode, element: this },\n }),\n );\n }\n\n // CHANGE EVENT DISPATCHING\n\n private dispatchChangeEvent(detail: ChangeEventDetail): void {\n this.dispatchEvent(\n new CustomEvent(\"change\", {\n detail,\n bubbles: true,\n cancelable: true,\n }),\n );\n }\n\n // RENDERING\n\n protected render(): void {\n // Sync mode on every render so rotation/resize is picked up\n this._state.mode = isMobileTouch() ? \"mobile\" : \"desktop\";\n\n if (this._state.mode === \"mobile\") {\n this.renderMobile();\n } else {\n this.renderDesktop();\n }\n\n this.updateSearchVisibility();\n\n // Loading wrapper is rendered dynamically — re-apply each render\n this.applyLoadingState();\n\n // The shadow DOM is built once; attributes toggled later are patched in.\n this.syncFieldChrome();\n\n // Reflect constraint validation (required) to the owning <form>.\n this.updateValidity();\n }\n\n /**\n * Patch label, required marker and disabled/compact state onto the\n * already-built shadow DOM. renderDesktop/renderMobile only write markup on\n * first render, so without this toggling `required`, `label`, `disabled` or\n * `compact` after connect never showed up.\n */\n private syncFieldChrome(): void {\n const shadow = this.shadowRoot;\n const container = shadow?.querySelector(\".select-container\");\n if (!shadow || !container) return;\n\n const labelId = `select-label-${getElementHash(this)}`;\n let label = container.querySelector(\":scope > .ty-field-label\") as HTMLLabelElement | null;\n if (this._label) {\n if (!label) {\n label = document.createElement(\"label\");\n label.className = \"ty-field-label\";\n label.id = labelId;\n container.prepend(label);\n }\n label.innerHTML = `${this._label}${this._required ? `<span class=\"required-icon\">${REQUIRED_ICON_SVG}</span>` : \"\"}`;\n } else {\n label?.remove();\n }\n\n // Error line under the trigger (every skin, custom trigger included) —\n // same markup as ty-input's\n const error: string = this.getProperty(\"error\") || \"\";\n const errorId = `select-error-${getElementHash(this)}`;\n let errorLine = container.querySelector(\":scope > .error-message\");\n if (error) {\n if (!errorLine) {\n errorLine = document.createElement(\"div\");\n errorLine.className = \"error-message\";\n errorLine.id = errorId;\n container.append(errorLine);\n }\n errorLine.textContent = error;\n } else {\n errorLine?.remove();\n }\n\n const stub = shadow.querySelector(\".select-stub\") as HTMLElement | null;\n if (stub) {\n stub.classList.toggle(\"disabled\", this._disabled);\n stub.classList.toggle(\"compact\", this._compact);\n stub.classList.toggle(\"error\", !!error);\n stub.tabIndex = this._disabled ? -1 : 0;\n stub.toggleAttribute(\"disabled\", this._disabled);\n if (this._disabled) stub.setAttribute(\"aria-disabled\", \"true\");\n else stub.removeAttribute(\"aria-disabled\");\n if (this._label) stub.setAttribute(\"aria-labelledby\", labelId);\n else stub.removeAttribute(\"aria-labelledby\");\n // The combobox carries the invalid state and reads the line out\n if (error) {\n stub.setAttribute(\"aria-invalid\", \"true\");\n stub.setAttribute(\"aria-describedby\", errorId);\n } else {\n stub.removeAttribute(\"aria-invalid\");\n stub.removeAttribute(\"aria-describedby\");\n }\n }\n // A slotted trigger is what takes focus (focus()), so it carries the\n // state too. aria-describedby can't reach into our shadow root from the\n // light DOM: the message goes in aria-description instead.\n const trigger = error\n ? (this.querySelector(':scope > [slot=\"trigger\"]') as HTMLElement | null)\n : null;\n if (this._ariaTrigger && this._ariaTrigger !== trigger) {\n this._ariaTrigger.removeAttribute(\"aria-invalid\");\n this._ariaTrigger.removeAttribute(\"aria-description\");\n }\n if (trigger) {\n trigger.setAttribute(\"aria-invalid\", \"true\");\n trigger.setAttribute(\"aria-description\", error);\n }\n this._ariaTrigger = trigger;\n shadow\n .querySelectorAll<HTMLInputElement>(\".dropdown-search-input, .mobile-search-input\")\n .forEach((input) => (input.disabled = this._disabled));\n }\n\n /**\n * Reflect constraint validation to the owning <form> via ElementInternals.\n * Without this `required` is only cosmetic — form.checkValidity() (and a\n * real submit) never actually blocks on an empty required select. Mirrors\n * ty-input's updateValidity(): empty + required => valueMissing, with a\n * native <select>'s message; disabled fields are barred from constraint\n * validation.\n */\n private updateValidity(): void {\n if (this.disabled) {\n this.applyValidity({});\n return;\n }\n if (this.required && this.getSelectedValues().length === 0) {\n const stub = this.shadowRoot?.querySelector(\".select-stub\") as HTMLElement | null;\n this.applyValidity(\n { valueMissing: true },\n nativeMessage(\"select\", { required: true, multiple: this._multiple }),\n stub ?? undefined,\n );\n } else {\n this.applyValidity({});\n }\n }\n\n /**\n * When a consumer slots their own trigger (slot=\"trigger\"), strip the\n * default field chrome so the trigger is styled entirely by the consumer.\n */\n private setupTriggerSlot(): void {\n const shadow = this.shadowRoot!;\n const stub = shadow.querySelector(\".select-stub\");\n const slot = shadow.querySelector(\n 'slot[name=\"trigger\"]',\n ) as HTMLSlotElement | null;\n if (!stub || !slot) return;\n const sync = () => {\n const hasTrigger = slot.assignedElements().length > 0;\n stub.classList.toggle(\"custom-trigger\", hasTrigger);\n // Reflected for :host([has-trigger]) styling (content-hugging width).\n // Blink does not parse :has() inside :host(), so detection lives here.\n this.toggleAttribute(\"has-trigger\", hasTrigger);\n };\n slot.addEventListener(\"slotchange\", () => {\n sync();\n this.syncFieldChrome(); // error aria onto a newly slotted trigger\n });\n sync();\n }\n\n private setupEventListeners(): void {\n const shadow = this.shadowRoot!;\n const stub = shadow.querySelector(\".select-stub\");\n const optionsSlot = shadow.querySelector(\"#options-slot\");\n const searchInput = shadow.querySelector(\".dropdown-search-input\");\n\n if (stub) {\n this._stubClickHandler = this.handleStubClick.bind(this);\n stub.addEventListener(\"click\", this._stubClickHandler);\n stub.addEventListener(\"keydown\", this.handleStubKeydown.bind(this) as EventListener);\n }\n\n const clearBtn = shadow.querySelector(\".select-clear\");\n clearBtn?.addEventListener(\"click\", this.handleClearClick.bind(this));\n\n this.setupTriggerSlot();\n\n if (optionsSlot) {\n this._tagClickHandler = this.handleTagClick.bind(this);\n optionsSlot.addEventListener(\"click\", this._tagClickHandler);\n }\n\n if (searchInput) {\n this._searchInputHandler = this.handleSearchInput.bind(this);\n this._blockSearchClick = this.blockSearchClick.bind(this);\n\n searchInput.addEventListener(\"input\", this._searchInputHandler);\n searchInput.addEventListener(\"click\", this._blockSearchClick);\n }\n\n const dialog = shadow.querySelector(\n \".dropdown-dialog\",\n ) as HTMLDialogElement;\n if (dialog) {\n dialog.addEventListener(\"click\", (e) => {\n // Only close if clicking directly on the dialog (backdrop), not its children\n if (e.target === dialog) {\n this.closeDropdown();\n }\n });\n // A close request handleKeyboard didn't get (Escape whose keydown\n // someone else stopped, a back gesture): close our way, not natively.\n dialog.addEventListener(\"cancel\", (e) => {\n e.preventDefault();\n this.closeDropdown();\n this.focus();\n });\n this.syncOnOutsideClose(dialog, () => this.closeDropdown());\n }\n }\n\n private buildStubClasses(): string {\n const classes: string[] = [];\n if (this._disabled) classes.push(\"disabled\");\n if (this._compact) classes.push(\"compact\");\n return classes.join(\" \");\n }\n\n private renderDesktop(): void {\n const shadow = this.shadowRoot!;\n\n // Only set innerHTML and setup listeners if container doesn't exist\n if (!shadow.querySelector(\".select-container\")) {\n const stubClasses = this.buildStubClasses();\n const listboxId = `select-listbox-${getElementHash(this)}`;\n const labelId = `select-label-${getElementHash(this)}`;\n\n const labelHtml = this._label\n ? `\n <label class=\"ty-field-label\" id=\"${labelId}\">\n ${this._label}\n ${this._required ? `<span class=\"required-icon\">${REQUIRED_ICON_SVG}</span>` : \"\"}\n </label>\n `\n : \"\";\n\n const searchPlaceholder = \"Search...\";\n\n shadow.innerHTML = `\n <div class=\"select-container dropdown-mode-desktop\">\n ${labelHtml}\n <div class=\"dropdown-wrapper\">\n <div class=\"dropdown-stub select-stub ${stubClasses}\"\n role=\"combobox\"\n aria-haspopup=\"listbox\"\n aria-expanded=\"false\"\n aria-controls=\"${listboxId}\"\n ${this._label ? `aria-labelledby=\"${labelId}\"` : \"\"}\n tabindex=\"${this._disabled ? \"-1\" : \"0\"}\"\n ${this._disabled ? 'disabled aria-disabled=\"true\"' : \"\"}>\n <slot name=\"trigger\">\n <slot name=\"start\"></slot>\n <slot name=\"selected\"></slot>\n <span class=\"dropdown-placeholder\">${this._placeholder}</span>\n <span class=\"select-count\" hidden></span>\n <slot name=\"end\"></slot>\n <button class=\"select-clear\" type=\"button\" aria-label=\"Clear selection\" hidden>\n ${CLEAR_ICON_SVG}\n </button>\n <div class=\"dropdown-chevron\">\n ${CHEVRON_DOWN_SVG}\n </div>\n </slot>\n </div>\n <dialog class=\"dropdown-dialog\">\n <div class=\"dropdown-header\">\n <div class=\"dropdown-search-icon\" aria-hidden=\"true\">\n ${SEARCH_ICON_SVG}\n </div>\n <input\n class=\"dropdown-search-input\"\n type=\"text\"\n placeholder=\"${searchPlaceholder}\"\n ${this._disabled ? \"disabled\" : \"\"}\n />\n <div class=\"dropdown-search-chevron\">\n ${CHEVRON_DOWN_SVG}\n </div>\n </div>\n <div class=\"dropdown-options-wrapper\">\n <div class=\"dropdown-options\" id=\"${listboxId}\" role=\"listbox\" ${this._multiple ? 'aria-multiselectable=\"true\"' : \"\"}>\n <slot id=\"options-slot\"></slot>\n </div>\n <div class=\"dropdown-loading\" aria-hidden=\"true\">\n <slot name=\"loading\">\n <span class=\"dropdown-loading-spinner\"></span>\n <span class=\"dropdown-loading-text\">Searching…</span>\n </slot>\n </div>\n </div>\n </dialog>\n </div>\n </div>\n `;\n\n // Setup event listeners ONCE\n this.setupEventListeners();\n\n // Don't initialize here - will be done in connectedCallback\n // after properties are set and children are available\n }\n\n // Always update placeholder visibility on re-render\n this.updateSelectionDisplay();\n }\n\n private renderMobile(): void {\n const shadow = this.shadowRoot!;\n\n // Only set innerHTML and setup listeners if container doesn't exist\n if (!shadow.querySelector(\".select-container\")) {\n const stubClasses = this.buildStubClasses();\n const listboxId = `select-listbox-${getElementHash(this)}`;\n const labelId = `select-label-${getElementHash(this)}`;\n\n const labelHtml = this._label\n ? `\n <label class=\"ty-field-label\" id=\"${labelId}\">\n ${this._label}\n ${this._required ? `<span class=\"required-icon\">${REQUIRED_ICON_SVG}</span>` : \"\"}\n </label>\n `\n : \"\";\n\n const closeButtonSvg = `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"></line>\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"></line>\n </svg>`;\n\n // Search placeholder: \"Search <label>...\" or just \"Search...\"\n const searchPlaceholder = this._label\n ? `Search ${this._label}...`\n : \"Search...\";\n\n // Search is always available — only the mode (internal vs external) varies.\n const searchHeaderHtml = `\n <div class=\"mobile-search-header\">\n ${this._label ? `<span class=\"mobile-header-label\">${this._label}</span>` : \"\"}\n <div class=\"mobile-header-content\">\n <div class=\"dropdown-search-icon\" aria-hidden=\"true\">\n ${SEARCH_ICON_SVG}\n </div>\n <input\n class=\"mobile-search-input\"\n type=\"text\"\n placeholder=\"${searchPlaceholder}\"\n autofocus\n ${this._disabled ? \"disabled\" : \"\"}\n />\n <button class=\"mobile-close-button\" type=\"button\" aria-label=\"Close\">\n ${closeButtonSvg}\n </button>\n </div>\n </div>\n `;\n\n shadow.innerHTML = `\n <div class=\"select-container dropdown-mode-mobile\">\n ${labelHtml}\n <div class=\"dropdown-wrapper\">\n <div class=\"dropdown-stub select-stub ${stubClasses}\"\n role=\"combobox\"\n aria-haspopup=\"listbox\"\n aria-expanded=\"false\"\n aria-controls=\"${listboxId}\"\n ${this._label ? `aria-labelledby=\"${labelId}\"` : \"\"}\n tabindex=\"${this._disabled ? \"-1\" : \"0\"}\"\n ${this._disabled ? 'disabled aria-disabled=\"true\"' : \"\"}>\n <slot name=\"trigger\">\n <slot name=\"start\"></slot>\n <slot name=\"selected\"></slot>\n <span class=\"dropdown-placeholder\">${this._placeholder}</span>\n <span class=\"select-count\" hidden></span>\n <slot name=\"end\"></slot>\n <button class=\"select-clear\" type=\"button\" aria-label=\"Clear selection\" hidden>\n ${CLEAR_ICON_SVG}\n </button>\n <div class=\"dropdown-chevron\">\n ${CHEVRON_DOWN_SVG}\n </div>\n </slot>\n </div>\n\n <dialog class=\"mobile-dialog\">\n <div class=\"mobile-dialog-content\">\n\n <!-- HEADER (matches dropdown.ts) -->\n ${searchHeaderHtml}\n\n <!-- BODY: options list with toggleable selected state -->\n <div class=\"mobile-body\" data-expanded=\"available\">\n\n <!-- SELECTED STRIP (pinned above the list, collapses when empty) -->\n <div class=\"mobile-selected-section\" data-empty=\"true\">\n <button class=\"section-header\" type=\"button\" data-section=\"selected\" aria-expanded=\"false\">\n <span class=\"section-title\">${this._selectedLabel} <span class=\"section-count\">(0)</span></span>\n ${CHEVRON_DOWN_SVG}\n </button>\n <div class=\"section-content mobile-selected-chips\"></div>\n </div>\n\n <!-- AVAILABLE LIST (always visible, takes remaining space) -->\n <div class=\"mobile-available-section\" data-empty=\"false\">\n <button class=\"section-header\" type=\"button\" data-section=\"available\" aria-expanded=\"true\">\n <span class=\"section-title\">${this._availableLabel} <span class=\"section-count\"></span></span>\n ${CHEVRON_DOWN_SVG}\n </button>\n <div class=\"section-content dropdown-options-wrapper\" id=\"${listboxId}\" role=\"listbox\" ${this._multiple ? 'aria-multiselectable=\"true\"' : \"\"}>\n <slot id=\"options-slot\"></slot>\n <div class=\"empty-state\">${this._noOptionsMessage}</div>\n <div class=\"dropdown-loading\" aria-hidden=\"true\">\n <slot name=\"loading\">\n <span class=\"dropdown-loading-spinner\"></span>\n <span class=\"dropdown-loading-text\">Searching…</span>\n </slot>\n </div>\n </div>\n </div>\n\n </div>\n </div>\n </dialog>\n </div>\n </div>\n `;\n\n // Setup event listeners ONCE\n this.setupMobileEventListeners();\n }\n\n // Always update placeholder visibility\n this.updateSelectionDisplay();\n }\n\n private setupMobileEventListeners(): void {\n // handleKeyboard (wired in onConnect) serves mobile too: it branches on\n // `_state.mode` wherever mobile needs different behavior (selectByTag,\n // tryCreateFromSearch).\n const shadow = this.shadowRoot!;\n const stub = shadow.querySelector(\".select-stub\");\n const optionsSlot = shadow.querySelector(\"#options-slot\");\n const searchInput = shadow.querySelector(\".mobile-search-input\");\n const closeButton = shadow.querySelector(\".mobile-close-button\");\n const dialog = shadow.querySelector(\".mobile-dialog\") as HTMLDialogElement;\n\n if (stub) {\n stub.addEventListener(\"click\", (e) => this.handleMobileStubClick(e));\n stub.addEventListener(\"keydown\", (e) => this.handleMobileStubKeydown(e as KeyboardEvent));\n }\n\n const clearBtn = shadow.querySelector(\".select-clear\");\n clearBtn?.addEventListener(\"click\", this.handleClearClick.bind(this));\n\n this.setupTriggerSlot();\n\n if (optionsSlot) {\n optionsSlot.addEventListener(\"click\", (e) =>\n this.handleMobileTagClick(e),\n );\n }\n\n if (searchInput) {\n searchInput.addEventListener(\"input\", (e) => this.handleSearchInput(e));\n }\n\n shadow.querySelectorAll(\".mobile-body .section-header\").forEach((header) => {\n header.addEventListener(\"click\", () =>\n this.expandMobileSection(\n (header as HTMLElement).dataset.section === \"selected\" ? \"selected\" : \"available\",\n ),\n );\n });\n\n if (closeButton) {\n closeButton.addEventListener(\"click\", () => this.closeMobileModal());\n }\n\n // Backdrop click to close (native dialog behavior)\n if (dialog) {\n dialog.addEventListener(\"click\", (e) => {\n // Only close if clicking directly on the dialog element (backdrop)\n // Not if clicking on its children (dialog-content)\n if (e.target === dialog) {\n this.closeMobileModal();\n }\n });\n\n // Also handle Escape key via cancel event\n dialog.addEventListener(\"cancel\", (e) => {\n e.preventDefault(); // Prevent default to handle it our way\n this.closeMobileModal();\n this.focus();\n });\n this.syncOnOutsideClose(dialog, () => this.closeMobileModal());\n }\n }\n\n /**\n * The dialog was closed by someone else — a ty-modal around this select\n * closes the dialogs still open inside it. Run our own close too, so the\n * open state, aria-expanded and the scroll lock follow. Watches the `open`\n * attribute rather than the `close` event: that one comes a task later,\n * so right after modal.hide() the stub would still say expanded. Our own\n * close() calls land here with the state already closed, and a dialog\n * reopened since then is open again: both are no-ops.\n */\n private syncOnOutsideClose(dialog: HTMLDialogElement, close: () => void): void {\n new MutationObserver(() => {\n if (this._state.open && !dialog.open) close();\n }).observe(dialog, { attributes: true, attributeFilter: [\"open\"] });\n }\n\n private handleMobileStubClick(e: Event): void {\n e.preventDefault();\n e.stopPropagation();\n\n if (this._disabled || this._readonly) {\n return;\n }\n\n this.openMobileModal();\n }\n\n /** Keyboard-open the (closed) mobile stub — see handleStubKeydown for why this is needed. */\n private handleMobileStubKeydown(e: KeyboardEvent): void {\n if (this._disabled || this._readonly || this._state.open) return;\n if (e.key === \"Enter\" || e.key === \" \" || e.key === \"ArrowDown\") {\n e.preventDefault();\n this.openMobileModal();\n }\n }\n\n private handleMobileTagClick(e: Event): void {\n // Use the same tag click handler as desktop\n // It already handles mobile mode for auto-close\n this.handleTagClick(e);\n }\n\n private updateMobileSelectedState(): void {\n if (this._state.mode !== \"mobile\") return;\n\n const shadow = this.shadowRoot!;\n this.renderMobileSelectedChips();\n const availableSection = shadow.querySelector(\".mobile-available-section\");\n\n if (availableSection) {\n // Count what's actually still on offer: options hidden by search\n // filtering don't count, and neither do ones already in the strip\n // above — \"Selected (11)\" next to \"Available (40)\" out of 40 total\n // reads like 51 options exist.\n const visibleAvailable = this.getTagElements().filter(\n (tag) => !tag.hasAttribute(\"hidden\") && !tag.hasAttribute(\"selected\"),\n ).length;\n\n availableSection.setAttribute(\n \"data-empty\",\n String(visibleAvailable === 0),\n );\n\n this.setMobileSectionTitle(availableSection, this._availableLabel, visibleAvailable);\n }\n }\n\n /** \"Label (n)\" with the count in its own muted span — same shape for both\n sections, and re-reads the label so selected-label/available-label\n changes after first render show up. */\n private setMobileSectionTitle(section: Element, label: string, n: number): void {\n const title = section.querySelector(\".section-title\");\n if (!title) return;\n const count = document.createElement(\"span\");\n count.className = \"section-count\";\n count.textContent = `(${n})`;\n title.replaceChildren(`${label} `, count);\n }\n\n /**\n * Hand the dialog's spare vertical space to one section or the other. Only\n * one can own it: on a phone there isn't enough height for two scrollable\n * lists to both be usefully tall, so tapping a header trades the space\n * rather than splitting it. Selecting from the list hands it back to\n * \"available\" — you're still picking, so that's the list you want open.\n */\n private expandMobileSection(section: \"selected\" | \"available\"): void {\n const shadow = this.shadowRoot;\n const body = shadow?.querySelector(\".mobile-body\") as HTMLElement | null;\n if (!body) return;\n\n // Nothing selected means nothing to expand into — the strip is a 36px\n // header at that point, so the request is a no-op rather than a jump to\n // an empty panel.\n if (section === \"selected\" && this._state.selectedValues.length === 0) return;\n\n body.dataset.expanded = section;\n shadow!.querySelectorAll(\".mobile-body .section-header\").forEach((header) => {\n const owns = (header as HTMLElement).dataset.section === section;\n header.setAttribute(\"aria-expanded\", String(owns));\n });\n }\n\n /**\n * The selected values as dismissible chips, pinned above the available\n * list so a long list can never scroll the current selection out of sight.\n * Rebuilt wholesale: the strip is small, and diffing it would have to\n * track chip identity for the sake of a handful of nodes.\n */\n private renderMobileSelectedChips(): void {\n const shadow = this.shadowRoot!;\n const section = shadow.querySelector(\".mobile-selected-section\");\n const host = shadow.querySelector(\".mobile-selected-chips\");\n if (!section || !host) return;\n\n const selected = this._state.selectedValues;\n section.setAttribute(\"data-empty\", String(selected.length === 0));\n\n this.setMobileSectionTitle(section, this._selectedLabel, selected.length);\n\n // Last chip dismissed while the strip had the space — give it back.\n if (selected.length === 0) this.expandMobileSection(\"available\");\n\n const labelFor = (value: string): string => {\n const option = this.getTagElements().find(\n (tag) => this.getTagData(tag).value === value,\n );\n return option ? this.getTagData(option).text : value;\n };\n\n host.textContent = \"\";\n for (const value of selected) {\n const chip = document.createElement(\"button\");\n chip.type = \"button\";\n chip.className = \"mobile-selected-chip\";\n chip.dataset.value = value;\n chip.setAttribute(\"aria-label\", `Remove ${labelFor(value)}`);\n chip.innerHTML = `<span class=\"chip-label\"></span>${CLEAR_ICON_SVG}`;\n (chip.querySelector(\".chip-label\") as HTMLElement).textContent = labelFor(value);\n chip.addEventListener(\"click\", (e) => {\n e.preventDefault();\n e.stopPropagation();\n this.deselectValue(value);\n });\n host.appendChild(chip);\n }\n }\n\n /**\n * Should the popup show a search row? external-search/allow-create pin it\n * on (the input is the only way to get a query out at all), not-searchable\n * forces it off, and otherwise it follows the list: shown once there are\n * more options than fit without scrolling.\n */\n private shouldShowSearch(): boolean {\n if (this._externalSearch) return true;\n if (this._allowCreate) return true;\n if (this._notSearchable) return false;\n return this.getTagElements().length > SEARCH_AUTO_THRESHOLD;\n }\n\n /**\n * Toggle the search row (desktop header / mobile input) per shouldShowSearch.\n */\n private updateSearchVisibility(): void {\n const shadow = this.shadowRoot;\n if (!shadow) return;\n const show = this.shouldShowSearch();\n const header = shadow.querySelector(\n \".dropdown-header\",\n ) as HTMLElement | null;\n if (header) header.hidden = !show;\n // Mobile keeps its header (label + close button); only the input+icon hide\n const mobileInput = shadow.querySelector(\n \".mobile-search-input\",\n ) as HTMLElement | null;\n if (mobileInput) mobileInput.hidden = !show;\n const mobileIcon = shadow.querySelector(\n \".mobile-header-content .dropdown-search-icon\",\n ) as HTMLElement | null;\n if (mobileIcon) mobileIcon.hidden = !show;\n }\n\n /**\n * Selection summary appropriate to cardinality × skin:\n * - single (field or compact): the selected OPTION itself — cloned into\n * slot=\"selected\" so rich HTML options display intact (dropdown parity);\n * placeholder when empty\n * - multiple + field: joined labels (ellipsis via CSS), or placeholder\n * - multiple + compact: placeholder + count badge\n */\n private updateSelectionDisplay(): void {\n const shadow = this.shadowRoot!;\n const stub = shadow.querySelector(\".select-stub\");\n if (!stub) return;\n\n // Selection comes from STATE, not from scanning option elements —\n // external search replaces the option children, and the selection must\n // survive even when the current results don't include the selected value.\n const values = this._state.selectedValues;\n const count = values.length;\n stub.classList.toggle(\"has-selection\", count > 0);\n stub.classList.toggle(\"compact\", this._compact);\n\n const badge = stub.querySelector(\".select-count\") as HTMLElement | null;\n if (badge) {\n badge.textContent = String(count);\n badge.hidden = count === 0 || !this._multiple || !this._compact;\n }\n\n const clearBtn = stub.querySelector(\".select-clear\") as HTMLElement | null;\n if (clearBtn) {\n clearBtn.hidden = !(count > 0 && this._clearable && !this._disabled && !this._readonly);\n }\n\n // Single select: project the selected option into the stub as a clone\n // (rich HTML content survives — same mechanism as ty-dropdown).\n const wantClone = !this._multiple && count > 0 ? values[0] : null;\n this.syncSelectedClone(wantClone);\n // Reflects the OUTCOME (did a clone actually get built or restored?),\n // not the intent — a value can be selected with no option ever having\n // existed to clone from (external search: a preset value before any\n // result has loaded). Basing this on intent alone hid the placeholder\n // AND had nothing to show in its place: a blank field with a clear\n // button that implied a selection nothing on screen confirmed.\n const hasClone = this._selectedClone !== null;\n stub.classList.toggle(\"has-clone\", hasClone);\n\n const textEl = stub.querySelector(\n \".dropdown-placeholder\",\n ) as HTMLElement | null;\n if (textEl) {\n // The clone replaces the text display entirely in single mode\n textEl.hidden = hasClone;\n const showLabels = count > 0 && this._multiple && !this._compact;\n if (showLabels) {\n textEl.textContent = this.getSelectedItems(values)\n .map((i) => i.label)\n .join(\", \");\n textEl.classList.remove(\"placeholder-shown\");\n } else if (wantClone !== null) {\n // Single-select wanted a clone but couldn't produce one. Fall back\n // to the raw value — still true, unlike the placeholder text, and\n // still visibly \"something is selected\" without inventing a label.\n textEl.textContent = values.join(\", \");\n textEl.classList.remove(\"placeholder-shown\");\n } else {\n textEl.textContent = this._placeholder;\n textEl.classList.add(\"placeholder-shown\");\n }\n }\n }\n\n /**\n * Keep exactly one display clone (slot=\"selected\", marked `cloned`) in our\n * light DOM matching the given value — or none. The clone never counts as\n * an option (getTagElements filters [cloned]) and ty-option's own\n * :host([cloned]) styling strips its list-row chrome.\n */\n private syncSelectedClone(value: string | null): void {\n const existing = this.querySelector(\n ':scope > [cloned][slot=\"selected\"]',\n ) as HTMLElement | null;\n if (existing?.getAttribute(\"value\") === value) {\n // Streaming-parse guard: when the `value` attribute syncs DURING HTML\n // parsing, the selected option's children may not exist yet, so the\n // clone captures an empty shell and the trigger renders blank forever\n // (the early-return below would keep it — \"value matches, all good\").\n // An empty clone whose source option HAS children is that artifact:\n // fall through and re-clone from the now-complete option.\n const stale =\n value !== null &&\n existing.childNodes.length === 0 &&\n (this.getTagElements().find(\n (el) => this.getTagData(el).value === value,\n )?.childNodes.length ?? 0) > 0;\n if (!stale) {\n this._selectedClone = existing;\n return; // already right\n }\n }\n\n existing?.remove();\n if (value === null) {\n this._selectedClone = null;\n return;\n }\n\n const option = this.getTagElements().find(\n (el) => this.getTagData(el).value === value,\n );\n if (option) {\n const clone = option.cloneNode(true) as HTMLElement;\n clone.removeAttribute(\"selected\"); // no tick/selected styling in the stub\n clone.setAttribute(\"slot\", \"selected\");\n clone.setAttribute(\"cloned\", \"true\");\n this.appendChild(clone);\n this._selectedClone = clone;\n // Captured mid-parse (the option has no children yet — see the\n // staleness guard above)? The guard only runs when something calls back\n // in here, and the child observer is childList-only on the select: a\n // text node landing INSIDE the option never fires it. So if this option\n // is the LAST child, nothing would ever re-sync and the trigger stays\n // blank. Re-run once when the parser is done. No-op after load.\n if (option.childNodes.length === 0 && document.readyState === \"loading\") {\n document.addEventListener(\n \"DOMContentLoaded\",\n () => { if (this.isConnected) this.updateSelectionDisplay(); },\n { once: true },\n );\n }\n } else if (this._selectedClone?.getAttribute(\"value\") === value) {\n // The option list no longer contains the selection (external search\n // swapped the children — possibly wiping our clone with them). Restore\n // the saved display clone so the selection stays visible.\n const restored = this._selectedClone.cloneNode(true) as HTMLElement;\n this.appendChild(restored);\n this._selectedClone = restored;\n }\n }\n\n // PUBLIC API - Getters/Setters\n\n /**\n * Deselect a value programmatically WITH a change event.\n * Used by out-of-band chip displays (ty-selected-options) so dismissing a chip\n * fires change like any in-popup interaction (HTMX hx-trigger=\"change\" etc.).\n */\n deselectValue(value: string): void {\n const current = this.getSelectedValues();\n if (!current.includes(value)) return;\n this.updateComponentValue(\n current.filter((v) => v !== value),\n true,\n \"remove\",\n value,\n );\n }\n\n /**\n * Clear the entire selection programmatically WITH a change event\n * (action: 'clear'). No-op if nothing is selected. Exists so slot=\"trigger\"\n * consumers (custom chrome, built-in clear UI hidden by design) can wire\n * their own clear icon's click handler to it. Shows no validation\n * message (a code reset after a save shouldn't flag the field); the\n * built-in × does.\n */\n clear(): void {\n this.updateComponentValue([], true, \"clear\", null, false);\n }\n\n get value(): string {\n // State is the source of truth — see getSelectedValues().\n return this.getSelectedValues().join(\",\");\n }\n\n set value(val: string) {\n this.setProperty(\"value\", val);\n }\n\n get name(): string {\n return this.getProperty(\"name\");\n }\n\n set name(val: string) {\n this.setProperty(\"name\", val);\n }\n\n get multiple(): boolean {\n return this.getProperty(\"multiple\");\n }\n\n set multiple(value: boolean) {\n this.setProperty(\"multiple\", value);\n }\n\n get compact(): boolean {\n return this.getProperty(\"compact\");\n }\n\n set compact(value: boolean) {\n this.setProperty(\"compact\", value);\n }\n\n get placeholder(): string {\n return this.getProperty(\"placeholder\");\n }\n\n set placeholder(val: string) {\n this.setProperty(\"placeholder\", val);\n }\n\n get label(): string {\n return this.getProperty(\"label\");\n }\n\n set label(val: string) {\n this.setProperty(\"label\", val);\n }\n\n get disabled(): boolean {\n return this.getProperty(\"disabled\");\n }\n\n set disabled(value: boolean) {\n this.setProperty(\"disabled\", value);\n }\n\n get loading(): boolean {\n return this.getProperty(\"loading\");\n }\n\n set loading(value: boolean) {\n this.setProperty(\"loading\", value);\n }\n\n get readonly(): boolean {\n return this.getProperty(\"readonly\");\n }\n\n set readonly(value: boolean) {\n this.setProperty(\"readonly\", value);\n }\n\n get noClear(): boolean {\n return this.getProperty(\"noClear\");\n }\n\n set noClear(value: boolean) {\n this.setProperty(\"noClear\", value);\n }\n\n get required(): boolean {\n return this.getProperty(\"required\");\n }\n\n set required(value: boolean) {\n this.setProperty(\"required\", value);\n }\n\n get error(): string {\n return this.getProperty(\"error\");\n }\n\n set error(value: string) {\n this.setProperty(\"error\", value);\n }\n\n get notSearchable(): boolean {\n return this.getProperty(\"notSearchable\");\n }\n\n set notSearchable(value: boolean) {\n this.setProperty(\"notSearchable\", value);\n }\n\n get externalSearch(): boolean {\n return this.getProperty(\"externalSearch\");\n }\n\n set externalSearch(value: boolean) {\n this.setProperty(\"externalSearch\", value);\n }\n\n get debounce(): number {\n return this.getProperty(\"debounce\");\n }\n\n set debounce(value: number | string) {\n const numValue = typeof value === \"string\" ? parseInt(value, 10) : value;\n this.setProperty(\"debounce\", numValue);\n }\n\n get size(): Size {\n return this.getProperty(\"size\") as Size;\n }\n\n set size(value: Size) {\n this.setProperty(\"size\", value);\n }\n\n get align(): \"start\" | \"center\" | \"end\" {\n return this.getProperty(\"align\") as \"start\" | \"center\" | \"end\";\n }\n\n set align(value: \"start\" | \"center\" | \"end\") {\n this.setProperty(\"align\", value);\n }\n\n get placement(): Placement | \"\" {\n return this.getProperty(\"placement\") as Placement | \"\";\n }\n\n set placement(value: Placement | \"\") {\n this.setProperty(\"placement\", value);\n }\n\n get flavor(): Flavor {\n return this.getProperty(\"flavor\") as Flavor;\n }\n\n set flavor(value: Flavor) {\n // Even the danger an error already shows: the author's now, so it stays\n // when the error clears\n this.removeAttribute(ERROR_FLAVOR);\n this.setProperty(\"flavor\", value);\n }\n\n attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void {\n // Same for flavor=\"danger\" written over that danger (React 18 sets props\n // as attributes): the base skips a write that changes nothing.\n if (name === \"flavor\" && newValue === \"danger\" && oldValue === newValue) this.removeAttribute(ERROR_FLAVOR);\n super.attributeChangedCallback(name, oldValue, newValue);\n }\n\n get form(): HTMLFormElement | null {\n return this._internals.form;\n }\n}\n\nif (!customElements.get(\"ty-select\")) {\n customElements.define(\"ty-select\", TySelect);\n}\n","/**\n * TySelectedOptions - out-of-band dismissible <ty-tag> chips for a picker's selection.\n * Pairs with any element exposing a comma-joined `value` + bubbling `change`; labels\n * and flavors are read from the picker's matching option (`[value=\"...\"]`). Custom chips\n * come from an optional <template> child, stamped onto cloned nodes (never innerHTML).\n */\n\n/** Minimal shape of a picker this element can drive. */\ninterface Picker extends HTMLElement {\n value: string\n}\n\n/** Split a comma-joined picker value into clean values. */\nfunction parseValues(raw: string): string[] {\n return raw.split(',').map(s => s.trim()).filter(Boolean)\n}\n\n/** Replace {key} placeholders from ctx; unknown keys are left as-is. */\nfunction interpolate(text: string, ctx: Record<string, string>): string {\n return text.replace(/\\{([\\w-]+)\\}/g, (match, key) => ctx[key] ?? match)\n}\n\nexport class TySelectedOptions extends HTMLElement {\n static get observedAttributes(): string[] {\n return ['for']\n }\n\n private _picker: Picker | null = null\n private _onChange = (): void => this.renderChips()\n private _childObserver: MutationObserver | null = null\n private _pickerObserver: MutationObserver | null = null\n private _lastTemplate: HTMLTemplateElement | null = null\n\n // While the linked picker's popup is open, chips FREEZE: no re-render, no\n // hide, no style writes — whatever was on screen stays exactly as it is\n // (INVARIANTS.md §1: position-indifferent, and §2 trivially — we never\n // touch our own inline style). The popup is a top-layer <dialog>, so it\n // paints over the chips like any dropdown covers content beneath it. One\n // refresh on close renders the final selection.\n private _pickerOpen = false\n\n private _onPickerOpen = (): void => {\n this._pickerOpen = true\n }\n\n private _onPickerClose = (): void => {\n this._pickerOpen = false\n this.renderChips()\n }\n\n connectedCallback(): void {\n // Chips participate directly in the parent layout (flex gap, wrap, etc.)\n if (!this.style.display) this.style.display = 'contents'\n this.bind()\n this.renderChips()\n\n // The picker's OWN declarative init (an option pre-marked `selected` in\n // markup, no `value` attribute on the picker) has the identical parse\n // -timing problem this component works around for its <template> child\n // below: a real HTML parser upgrades the picker the moment its start tag\n // is seen, before its <ty-option> children exist, so the picker may not\n // have resolved anything yet when we read `.value` above. And unlike a\n // real selection change, that resolution — once it finally happens on\n // DOMContentLoaded (see the picker's own resolveDeclarativeSelection) —\n // deliberately fires no `change` event and touches no attribute our\n // `_pickerObserver` below would catch (the options' `selected` attribute\n // was already correct from markup, so nothing toggles). Recheck once,\n // same technique, same trigger.\n if (document.readyState === 'loading') {\n document.addEventListener(\n 'DOMContentLoaded',\n () => { if (this.isConnected) this.renderChips() },\n { once: true },\n )\n }\n\n // During HTML parsing we connect BEFORE our <template> child is parsed —\n // re-render when it arrives so server-rendered pages get templated chips.\n // renderChips re-appends the SAME template node, so its own mutations\n // don't change template() identity → no re-render loop.\n this._childObserver = new MutationObserver(() => {\n const template = this.template()\n if (template !== this._lastTemplate) {\n this.renderChips()\n }\n })\n this._childObserver.observe(this, { childList: true })\n }\n\n disconnectedCallback(): void {\n this.unbind()\n this._childObserver?.disconnect()\n this._childObserver = null\n }\n\n attributeChangedCallback(): void {\n if (!this.isConnected) return\n this.bind()\n this.renderChips()\n }\n\n /** Resolve the picker: `for` id, else the previous element sibling. */\n private resolvePicker(): Picker | null {\n const id = this.getAttribute('for')\n const el = id\n ? document.getElementById(id)\n : this.previousElementSibling\n return (el as Picker) ?? null\n }\n\n private bind(): void {\n const next = this.resolvePicker()\n if (next === this._picker) return\n this.unbind()\n this._picker = next\n this._picker?.addEventListener('change', this._onChange)\n this._picker?.addEventListener('open', this._onPickerOpen)\n this._picker?.addEventListener('close', this._onPickerClose)\n\n // The picker stamps `selected` onto its options ASYNC after connect\n // (rAF init) and on external option swaps — neither fires `change`.\n // Watch the picker's subtree so initial values render as chips too.\n if (this._picker) {\n this._pickerObserver = new MutationObserver(() => this.renderChips())\n this._pickerObserver.observe(this._picker, {\n childList: true,\n subtree: true,\n attributes: true,\n attributeFilter: ['selected'],\n })\n }\n }\n\n private unbind(): void {\n this._picker?.removeEventListener('change', this._onChange)\n this._picker?.removeEventListener('open', this._onPickerOpen)\n this._picker?.removeEventListener('close', this._onPickerClose)\n this._pickerObserver?.disconnect()\n this._pickerObserver = null\n this._picker = null\n // Don't leave chips frozen if the picker is swapped/removed mid-open.\n this._pickerOpen = false\n }\n\n private values(): string[] {\n return parseValues(this._picker?.value ?? '')\n }\n\n /** The optional chip template (direct child only). */\n private template(): HTMLTemplateElement | null {\n return this.querySelector(':scope > template')\n }\n\n /**\n * Interpolation context for a value: value, label, flavor plus every\n * data-* attribute of the picker's matching option.\n */\n /** The picker's option for a value (never its display clone). */\n private option(value: string): HTMLElement | null {\n return this._picker?.querySelector(`[value=\"${CSS.escape(value)}\"]:not([cloned])`) as HTMLElement | null\n }\n\n private context(value: string): Record<string, string> {\n const opt = this.option(value)\n const ctx: Record<string, string> = {\n value,\n // label attribute wins (native <option label> semantics)\n label: opt?.getAttribute('label') || opt?.textContent?.trim() || value,\n flavor: opt?.getAttribute('flavor') ?? '',\n }\n if (opt) {\n for (const attr of Array.from(opt.attributes)) {\n if (attr.name.startsWith('data-')) ctx[attr.name] = attr.value\n }\n }\n return ctx\n }\n\n /**\n * The template's blueprint fragment. HTML-parsed templates carry children in\n * .content; framework-rendered ones (DOM-created by React/Replicant/etc.)\n * carry them as regular childNodes — support both.\n */\n private templateSource(template: HTMLTemplateElement): DocumentFragment {\n // Any content node counts — a text-only template (\"{label}\") is valid.\n if (template.content.hasChildNodes()) return template.content\n const frag = document.createDocumentFragment()\n template.childNodes.forEach(n => frag.appendChild(n.cloneNode(true)))\n return frag\n }\n\n /**\n * Stamp the template for one value: clone, interpolate placeholders in\n * attributes and text nodes, wire dismiss. Attribute values that were a\n * single unresolved placeholder are removed (e.g. flavor=\"{flavor}\" with\n * no flavor on the option).\n */\n private stampTemplate(template: HTMLTemplateElement, value: string): DocumentFragment {\n const ctx = this.context(value)\n const clone = this.templateSource(template).cloneNode(true) as DocumentFragment\n\n const walker = document.createTreeWalker(clone, NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_TEXT)\n for (let node = walker.nextNode(); node; node = walker.nextNode()) {\n if (node.nodeType === Node.TEXT_NODE) {\n if (node.textContent?.includes('{')) {\n node.textContent = interpolate(node.textContent, ctx)\n }\n } else {\n const el = node as Element\n for (const attr of Array.from(el.attributes)) {\n if (!attr.value.includes('{')) continue\n const resolved = interpolate(attr.value, ctx)\n // Single-placeholder attribute that is empty OR unresolved → drop it\n // (e.g. flavor=\"{flavor}\" with no flavor, name=\"{data-icon}\" with no data-icon)\n if (/^\\{[\\w-]+\\}$/.test(attr.value) && (resolved === '' || resolved === attr.value)) {\n el.removeAttribute(attr.name)\n } else {\n el.setAttribute(attr.name, resolved)\n }\n }\n }\n }\n\n // Dismiss anywhere inside the stamped chip deselects this value\n for (const el of Array.from(clone.children)) {\n el.addEventListener('dismiss', (e) => {\n e.stopPropagation()\n this.deselect(value)\n })\n }\n return clone\n }\n\n /**\n * Default chip when no template is provided: the option's own content,\n * cloned, so a rich option makes a rich chip. An explicit `label` on the\n * option replaces it with that text; a <template> child replaces it entirely.\n */\n private defaultChip(value: string): HTMLElement {\n const ctx = this.context(value)\n const opt = this.option(value)\n const tag = document.createElement('ty-tag')\n tag.setAttribute('value', value)\n tag.setAttribute('dismissible', 'true')\n if (ctx.flavor) tag.setAttribute('flavor', ctx.flavor)\n if (opt && !opt.hasAttribute('label') && opt.hasChildNodes()) {\n opt.childNodes.forEach(n => tag.appendChild(n.cloneNode(true)))\n } else {\n tag.textContent = ctx.label\n }\n tag.addEventListener('dismiss', () => this.deselect(value))\n return tag\n }\n\n private renderChips(): void {\n // Frozen while the picker's popup is open — the selection may churn as\n // the user picks, but the chip row must not move/grow under the popup.\n // _onPickerClose renders the final state.\n if (this._pickerOpen) return\n\n const template = this.template()\n this._lastTemplate = template\n\n if (!this._picker) {\n this.replaceChildren(...(template ? [template] : []))\n return\n }\n\n const frag = document.createDocumentFragment()\n // Template survives re-renders - it is part of our light DOM\n if (template) frag.appendChild(template)\n for (const value of this.values()) {\n frag.appendChild(template ? this.stampTemplate(template, value) : this.defaultChip(value))\n }\n this.replaceChildren(frag)\n }\n\n /** Remove a value from the picker; picker re-emits change → chips re-render. */\n private deselect(value: string): void {\n if (!this._picker) return\n const picker = this._picker as Picker & { deselectValue?: (v: string) => void }\n if (typeof picker.deselectValue === 'function') {\n // ty-select path — fires a proper change event (chips re-render via listener)\n picker.deselectValue(value)\n } else {\n // Generic picker fallback — value setters usually don't emit change\n picker.value = this.values().filter(v => v !== value).join(',')\n this.renderChips()\n }\n }\n}\n\nif (!customElements.get('ty-selected-options')) {\n customElements.define('ty-selected-options', TySelectedOptions)\n}\n\n// Original tag name — kept working indefinitely. A constructor can only\n// register once, hence the subclass (see ty-modal/ty-dialog for precedent).\nif (!customElements.get('ty-selected-tags')) {\n customElements.define('ty-selected-tags', class TySelectedTags extends TySelectedOptions { })\n}\n","/**\n * Tabs Component Styles — ty-tabs container: top/bottom placement, animated\n * active marker, carousel viewport. Customizable via CSS Parts (::part).\n */\n\nexport const tabsStyles = `\n:host {\n display: block;\n /* Defaults. The width/height attributes override these (and page CSS)\n through the per-instance sheet. */\n width: 100%;\n height: 400px;\n box-sizing: border-box;\n}\n\n.tabs-container {\n width: 100%;\n height: 100%;\n display: flex;\n flex-direction: column;\n position: relative;\n box-sizing: border-box;\n}\n\n.tabs-container[data-placement=\"bottom\"] {\n flex-direction: column-reverse;\n}\n\n/* Tab buttons container — exposed as a CSS Part for full styling control */\n.tab-buttons {\n display: flex;\n gap: 0;\n flex-shrink: 0;\n position: relative;\n\n /* Default minimal styling - customize via ::part(buttons-container) */\n background: transparent;\n}\n\n/* Separator drawn as a pseudo-element, not a border: a border sits OUTSIDE the\n strip's box, so the marker (absolutely positioned inside the strip) could only\n ever stop just above it, reading as two stacked lines. As an overlaid line it\n lands inside the marker's range, and .tab-strip's z-index lets the marker\n cover it. */\n.tab-buttons::after {\n content: \"\";\n position: absolute;\n left: 0;\n right: 0;\n bottom: 0;\n height: 1px;\n /* --ty-tabs-separator: transparent removes the line (e.g. with a pill marker) */\n background: var(--ty-tabs-separator, var(--ty-border));\n pointer-events: none;\n}\n\n.tabs-container[data-placement=\"bottom\"] .tab-buttons::after {\n bottom: auto;\n top: 0;\n}\n\n/* Scrollable strip holding the buttons + marker. Tabs never collapse — the\n strip scrolls (scrollbar hidden; touch/wheel still work) and activation\n glides the active tab into view. The \"…\" trigger sits OUTSIDE this strip,\n pinned at the edge. position:relative makes it the offsetParent for the\n marker, so the marker scrolls with the buttons and can't desync. */\n.tab-strip {\n display: flex;\n flex: 1 1 auto;\n min-width: 0;\n position: relative;\n /* Paints the marker + buttons over .tab-buttons::after (the separator line) */\n z-index: 1;\n overflow-x: auto;\n scrollbar-width: none;\n /* Edge fades — a mask, not overlays, so it works over any background.\n --fade-left/right are set from the scroll listener: 0px at a hard edge,\n 28px when more tabs continue past that side. */\n --fade-left: 0px;\n --fade-right: 0px;\n -webkit-mask-image: linear-gradient(to right,\n transparent, black var(--fade-left),\n black calc(100% - var(--fade-right)), transparent);\n mask-image: linear-gradient(to right,\n transparent, black var(--fade-left),\n black calc(100% - var(--fade-right)), transparent);\n}\n\n.tab-strip::-webkit-scrollbar {\n display: none;\n}\n\n/* When every tab fits there is nothing to scroll, so drop the clipping —\n both overflow and the mask cut a custom marker's box-shadow off at the\n strip edge. Set by updateOverflow(); clipping stays the pre-measurement\n default so overflowing tabs can't spill for a frame on first render. */\n.tab-strip.unclipped {\n overflow: visible;\n -webkit-mask-image: none;\n mask-image: none;\n}\n\n/* Marker wrapper — exposed as a CSS Part for custom marker styling */\n.marker-wrapper {\n position: absolute;\n z-index: 0;\n /* Behind buttons */\n pointer-events: none;\n /* Don't block clicks */\n transition: left var(--ty-tabs-transition-duration, 300ms) var(--ty-tabs-transition-easing, ease-in-out),\n width var(--ty-tabs-transition-duration, 300ms) var(--ty-tabs-transition-easing, ease-in-out),\n height var(--ty-tabs-transition-duration, 300ms) var(--ty-tabs-transition-easing, ease-in-out),\n top var(--ty-tabs-transition-duration, 300ms) var(--ty-tabs-transition-easing, ease-in-out);\n}\n\n.default-marker {\n position: absolute;\n bottom: 0;\n left: 0;\n height: 3px;\n width: 100%;\n background: var(--ty-color-primary);\n pointer-events: none;\n}\n\n/* Bottom placement: marker rides the top edge, next to the content it marks */\n.tabs-container[data-placement=\"bottom\"] .default-marker {\n bottom: auto;\n top: 0;\n}\n\n::slotted([slot=\"marker\"]) {\n display: block;\n width: 100%;\n height: 100%;\n box-sizing: border-box;\n}\n\n.tab-button {\n /* Material's floor for SCROLLABLE tabs. 120px is the fixed-tab number and it\n manufactured overflow: five short labels claimed 600px whether they needed\n it or not. Equal-width rhythm is what the \"fixed\" attribute is for. */\n min-width: var(--ty-tab-min-width, 72px);\n /* Scrollable tabs keep their natural width and let the strip scroll — that is\n the whole contract. Without this they are flex items with the default\n shrink of 1, so they squeeze toward the floor and their labels ellipsize\n before the strip ever overflows. Squeezing is what \"fixed\" is for. */\n flex-shrink: 0;\n padding: 6px 12px;\n border: none;\n background: transparent;\n cursor: pointer;\n font: inherit;\n color: var(--ty-text-soft);\n transition: var(--ty-local-transition, color 200ms, background-color 200ms);\n white-space: nowrap;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 8px;\n font-weight: var(--ty-font-bold);\n font-size: var(--ty-font-sm);\n position: relative;\n /* Establish stacking context */\n z-index: 10;\n /* Above marker */\n}\n\n/* Fixed tabs: the bar is divided between them instead of scrolling. Material\n calls this \"fixed tabs\" — for a small, known set of short labels. No\n min-width floor, no overflow, no \"…\". */\n.tabs-container[data-fixed] .tab-button {\n flex: 1 1 0;\n min-width: 0;\n}\n\n/* Fixed tabs only. A scrollable tab is never narrower than its label, so\n ellipsizing there would hide text the user could simply scroll to. */\n.tabs-container[data-fixed] .tab-label {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.tab-button[aria-selected=true] {\n color: var(--ty-text-strong);\n}\n\n.tab-button[disabled] {\n opacity: 0.5;\n cursor: not-allowed;\n pointer-events: none;\n}\n\n.tab-button:focus-visible {\n outline: 2px solid var(--ty-color-primary);\n outline-offset: -2px;\n}\n\n/* Overflow \"more\" trigger (pill) + menu */\n.tab-overflow-trigger {\n flex-shrink: 0;\n align-self: center;\n min-width: 36px;\n height: 24px;\n margin: 0 8px;\n padding: 0 10px;\n border: 1px solid var(--ty-border);\n border-radius: 9999px;\n background: transparent;\n cursor: pointer;\n color: var(--ty-text-soft);\n font-size: 16px;\n line-height: 1;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n position: relative;\n z-index: 10;\n transition: color 200ms, border-color 200ms;\n}\n\n.tab-overflow-trigger:hover {\n color: var(--ty-text-strong);\n border-color: var(--ty-text-soft);\n}\n\n.tab-overflow-trigger:focus-visible {\n outline: 2px solid var(--ty-color-primary);\n outline-offset: -2px;\n}\n\n.tab-overflow-menu {\n display: flex;\n flex-direction: column;\n min-width: 160px;\n max-height: 300px;\n overflow-y: auto;\n padding: var(--ty-spacing-2, 4px);\n background: var(--ty-surface-floating);\n border-radius: var(--ty-radius-md);\n box-shadow: var(--ty-shadow-md, 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px -1px rgba(0, 0, 0, 0.1));\n}\n\n.tab-overflow-item {\n padding: var(--ty-spacing-2, 6px) var(--ty-spacing-3, 12px);\n border: none;\n background: transparent;\n text-align: left;\n cursor: pointer;\n border-radius: var(--ty-radius-md);\n color: var(--ty-text);\n font: inherit;\n font-size: var(--ty-font-sm);\n white-space: nowrap;\n}\n\n.tab-overflow-item:hover {\n background: var(--ty-bg-neutral-soft);\n color: var(--ty-text-strong);\n}\n\n.tab-overflow-item[data-active=\"true\"] {\n color: var(--ty-color-primary);\n font-weight: var(--ty-font-bold);\n}\n\n.tab-overflow-item[disabled] {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n/* Panels viewport — exposed as a CSS Part */\n.panels-viewport {\n position: relative;\n flex: 1;\n overflow: hidden;\n /* Critical: hides off-screen panels */\n min-height: 0;\n /* Allows flex child to shrink */\n}\n\n/* Panels wrapper slides horizontally */\n.panels-wrapper {\n display: flex;\n height: 100%;\n transition: transform var(--ty-tabs-transition-duration, 300ms) var(--ty-tabs-transition-easing, ease-in-out);\n}\n\n@media (prefers-reduced-motion: reduce) {\n .panels-wrapper {\n transition-duration: 0ms !important;\n }\n\n .marker-wrapper {\n transition-duration: 0ms !important;\n }\n}\n\n::slotted(ty-tab) {\n /* One carousel page: the viewport's width. */\n width: 100%;\n height: 100%;\n flex-shrink: 0;\n}\n\n/* Snap: an early \\`active\\` correction lands without sliding or fading. */\n.tabs-container[data-snap] .panels-wrapper,\n.tabs-container[data-snap] ::slotted(ty-tab) {\n transition: none;\n}\n`;","/**\n * Tabs Component — carousel-based tabs with sliding transitions, an animated\n * active marker, and fixed container dimensions. Expects `ty-tab` children;\n * rich labels come from `slot=\"label-{tab-id}\"` children of `ty-tabs` itself.\n */\n\nimport { ensureStyles } from '../utils/styles.js';\nimport { tabsStyles } from '../styles/tabs.js';\n\n/**\n * Tabs container attributes configuration\n */\nexport interface TabsAttributes {\n width: string; // Content area width (accepts px or %)\n height: string; // Total container height including buttons\n active: string | null; // ID of currently active tab\n placement: 'top' | 'bottom'; // Position of tab buttons\n fixed: boolean; // Split the bar into equal shares instead of scrolling\n}\n\n/**\n * Tab change event detail. Fired whenever the shown tab changes after the\n * first one is shown — never for the initial tab.\n */\nexport interface TabChangeDetail {\n activeId: string; // ID of newly shown tab\n activeIndex: number; // Index of newly shown tab\n previousId: string | null; // ID of the tab shown before (null if it no longer exists)\n previousIndex: number | null; // Its index, or null if it no longer exists\n}\n\n/** Marker position for the animated indicator. */\ninterface MarkerPosition {\n left: number; // Left offset in pixels\n top: number; // Top offset in pixels\n width: number; // Width in pixels\n height: number; // Height in pixels\n}\n\nconst eventHandlers = new WeakMap<TyTabs, {\n tabClickHandlers: Map<string, (e: Event) => void>;\n tabKeydownHandlers: Map<string, (e: Event) => void>;\n}>();\n\nconst resizeObservers = new WeakMap<TyTabs, ResizeObserver>();\n\n// The tab actually on screen. Kept here, not in the `active` attribute: a\n// server morph (Datastar, idiomorph) rewrites or drops attributes, and the\n// component must keep showing what it showed. `active` is a request; this is\n// the state.\nconst shownTabs = new WeakMap<TyTabs, string | null>();\n\n// Per-instance sheet: `:host` sizing from the width/height attributes, and the\n// rule that hides every panel but the shown one. Lives in the shadow root, so\n// a morph that rewrites the host's `style` or the children's attributes can't\n// touch it (see flavor-sheet.ts for the same pattern).\nconst instanceSheets = new WeakMap<TyTabs, CSSStyleSheet>();\n\n// The app's first `active` correction (mount, then apply state — React\n// effects, Datastar data-attr) snaps instead of sliding over from tab 0.\n// Holds the page's input count from when the first tab was shown: once the\n// user has pressed anything, a correction is the app reacting to them (a Next\n// button) and animates like a click.\nconst pendingInitialSnap = new WeakMap<TyTabs, number>();\nlet userInputs = 0;\nconst countInput = () => { userInputs++; };\naddEventListener('pointerdown', countInput, { capture: true, passive: true });\naddEventListener('keydown', countInput, { capture: true, passive: true });\n\n// `active` named a tab that wasn't a child yet when the first tab was shown\n// (a classic <script> in <head> upgrades ty-tabs before the parser has\n// created its children). Moving to it when it arrives is still the initial\n// tab: snap, no event.\nconst awaitedTabs = new WeakMap<TyTabs, string>();\n\nlet snapCount = 0;\n\nfunction getTabsAttributes(el: TyTabs): Pick<TabsAttributes, 'placement' | 'fixed'> {\n return {\n placement: (el.getAttribute('placement') || 'top') as 'top' | 'bottom',\n fixed: el.hasAttribute('fixed'),\n };\n}\n\n/** Direct children only — a nested ty-tabs owns its own ty-tab children. */\nfunction getChildTabs(el: TyTabs): HTMLElement[] {\n return Array.from(el.querySelectorAll(':scope > ty-tab'));\n}\n\nfunction getTabId(tab: HTMLElement): string | null {\n return tab.getAttribute('id');\n}\n\n/**\n * Find the rich label element for a tab-id.\n * DIRECT children only — a slot in ty-tabs' shadow root can only be filled by a\n * direct child of ty-tabs, so a `slot=\"label-x\"` buried inside a ty-tab would be\n * detected but never rendered, blanking the button.\n */\nfunction getSlotLabel(tabsEl: TyTabs, tabId: string): Element | null {\n return tabsEl.querySelector(`:scope > [slot='label-${tabId}']`);\n}\n\nfunction hasSlotLabel(tabsEl: TyTabs, tabId: string): boolean {\n return getSlotLabel(tabsEl, tabId) !== null;\n}\n\n/**\n * Determine label type: 'slot' (rich content) or 'text' (simple attribute).\n * Checks ty-tabs element for slot='label-{tab-id}' direct children.\n */\nfunction getTabLabelType(tabsEl: TyTabs, tab: HTMLElement): 'slot' | 'text' {\n const tabId = getTabId(tab);\n if (tabId && hasSlotLabel(tabsEl, tabId)) {\n return 'slot';\n }\n return 'text';\n}\n\nfunction isTabDisabled(tab: HTMLElement): boolean {\n return tab.hasAttribute('disabled');\n}\n\nfunction hasCustomMarker(el: TyTabs): boolean {\n return el.querySelector(':scope > [slot=\"marker\"]') !== null;\n}\n\nfunction findTabIndex(tabs: HTMLElement[], tabId: string): number | undefined {\n const index = tabs.findIndex(tab => getTabId(tab) === tabId);\n return index >= 0 ? index : undefined;\n}\n\n/**\n * Shown tab id read fresh. Deferred work (rAF, resize) must use this rather\n * than values captured when it was scheduled — the shown tab can change in\n * between.\n */\nfunction currentActive(el: TyTabs): string | null {\n return shownTabs.get(el) ?? null;\n}\n\n/**\n * The tab that should be shown: a valid `active`, else the tab already shown\n * (a missing or unknown `active` — e.g. a morph dropped it — keeps the\n * current tab), else the first tab.\n */\nfunction getActiveTabId(el: TyTabs, tabs: HTMLElement[]): string | null {\n const ids = tabs.map(getTabId).filter((id): id is string => !!id);\n const activeAttr = el.getAttribute('active');\n if (activeAttr && ids.includes(activeAttr)) return activeAttr;\n\n const shown = shownTabs.get(el);\n if (shown && ids.includes(shown)) return shown;\n\n return ids[0] ?? null;\n}\n\n/**\n * User activation (click, keys, \"…\" menu). Applied and dispatched\n * synchronously: with Datastar's `data-attr:active=\"$tab\"` +\n * `data-on:ty-tab-change`, a deferred event lets data-attr write the old\n * signal value back over the click before the handler updates it.\n */\nfunction activateTab(el: TyTabs, tabId: string): void {\n el.setAttribute('active', tabId);\n syncShownTab(el, true);\n}\n\nfunction dispatchTabChangeEvent(\n el: TyTabs,\n activeId: string,\n activeIndex: number,\n previousId: string | null,\n previousIndex: number | null\n): void {\n const event = new CustomEvent<TabChangeDetail>('ty-tab-change', {\n detail: {\n activeId,\n activeIndex,\n previousId,\n previousIndex,\n },\n bubbles: true,\n cancelable: false,\n });\n el.dispatchEvent(event);\n}\n\nfunction handleTabClick(el: TyTabs, tabId: string, event: Event): void {\n event.preventDefault();\n event.stopPropagation();\n activateTab(el, tabId);\n}\n\nfunction cleanupEventListeners(el: TyTabs): void {\n const handlers = eventHandlers.get(el);\n if (!handlers) return;\n \n const shadowRoot = el.shadowRoot;\n if (!shadowRoot) return;\n \n handlers.tabClickHandlers.forEach((handler, tabId) => {\n const button = shadowRoot.querySelector<HTMLButtonElement>(`[data-tab-id='${tabId}']`);\n if (button) {\n button.removeEventListener('click', handler);\n }\n });\n handlers.tabKeydownHandlers.forEach((handler, tabId) => {\n const button = shadowRoot.querySelector<HTMLButtonElement>(`[data-tab-id='${tabId}']`);\n if (button) {\n button.removeEventListener('keydown', handler);\n }\n });\n\n handlers.tabClickHandlers.clear();\n handlers.tabKeydownHandlers.clear();\n}\n\nfunction handleTabKeydown(el: TyTabs, shadowRoot: ShadowRoot, tabId: string, e: KeyboardEvent): void {\n if (!['ArrowRight', 'ArrowLeft', 'Home', 'End'].includes(e.key)) return;\n const ids = Array.from(\n shadowRoot.querySelectorAll<HTMLButtonElement>('.tab-buttons [data-tab-id]:not([disabled])'),\n ).map((b) => b.getAttribute('data-tab-id')!);\n const i = ids.indexOf(tabId);\n if (i < 0 || ids.length === 0) return;\n e.preventDefault();\n const next =\n e.key === 'Home' ? ids[0]\n : e.key === 'End' ? ids[ids.length - 1]\n : e.key === 'ArrowRight' ? ids[(i + 1) % ids.length]\n : ids[(i - 1 + ids.length) % ids.length];\n if (next === tabId) return;\n handleTabClick(el, next, e);\n requestAnimationFrame(() => {\n shadowRoot.querySelector<HTMLButtonElement>(`.tab-buttons [data-tab-id='${next}']`)?.focus();\n });\n}\n\nfunction setupEventListeners(el: TyTabs, shadowRoot: ShadowRoot, tabs: HTMLElement[]): void {\n cleanupEventListeners(el);\n\n const handlers = {\n tabClickHandlers: new Map<string, (e: Event) => void>(),\n tabKeydownHandlers: new Map<string, (e: Event) => void>(),\n };\n\n tabs.forEach((tab) => {\n const tabId = getTabId(tab);\n if (!tabId) return;\n\n const button = shadowRoot.querySelector<HTMLButtonElement>(`[data-tab-id='${tabId}']`);\n if (button) {\n // 'click', not pointerdown: the browser fires click only for a tap or\n // mouse click, never for a finger drag, so swiping the strip to scroll\n // it doesn't activate whichever tab the drag started on. A mouse click\n // also leaves focus on the button (pointerdown + preventDefault\n // cancelled that), so arrow keys work right after clicking. Enter/Space\n // on a focused button fire click too, covering keyboard activation.\n const handler = (e: Event) => handleTabClick(el, tabId, e);\n // Arrow keys / Home / End (WAI-ARIA tabs, automatic activation). The\n // buttons use a roving tabindex — only the active one is tabbable — so\n // without this, keyboard users could never reach the other tabs.\n const keydownHandler = (e: Event) => handleTabKeydown(el, shadowRoot, tabId, e as KeyboardEvent);\n button.addEventListener('click', handler);\n button.addEventListener('keydown', keydownHandler);\n handlers.tabClickHandlers.set(tabId, handler);\n handlers.tabKeydownHandlers.set(tabId, keydownHandler);\n }\n });\n\n eventHandlers.set(el, handlers);\n}\n\n/**\n * Carousel position. A percentage of the wrapper's own width — one panel —\n * so it needs no measuring and stays aligned through resizes.\n */\nfunction carouselTransform(activeIndex: number): string {\n // `* -100`, not `-${…}`: index 0 must read back as the browser stores it\n // (\"translateX(0%)\"), or the realign check in syncShownTab never matches.\n return `translateX(${activeIndex * -100}%)`;\n}\n\n/**\n * Land the next carousel/panel change without the slide and fade. Held for\n * two frames rather than a forced style flush: Chromium 138 still faded a\n * panel corrected before the first frame, because the flush didn't see the\n * instance sheet's rule change yet. Tokened, so an earlier snap ending can't\n * cut a later one short.\n */\nfunction snapNextChange(container: HTMLElement | null): void {\n if (!container) return;\n const token = String(++snapCount);\n container.setAttribute('data-snap', token);\n requestAnimationFrame(() => requestAnimationFrame(() => {\n if (container.getAttribute('data-snap') === token) container.removeAttribute('data-snap');\n }));\n}\n\nfunction updateTransform(el: TyTabs, activeIndex: number): void {\n const panelsWrapper = el.shadowRoot?.querySelector<HTMLElement>('.panels-wrapper');\n if (panelsWrapper) panelsWrapper.style.transform = carouselTransform(activeIndex);\n}\n\n/** Write an attribute on a light-DOM child only when it differs — no mutation churn for observers (or morphers) watching it. */\nfunction setAttr(node: Element, name: string, value: string): void {\n if (node.getAttribute(name) !== value) node.setAttribute(name, value);\n}\n\n/**\n * Keep the instance sheet in sync: `:host` size from the width/height\n * attributes, and the rule hiding every panel but `shownId`.\n *\n * The size is `!important` so an attribute beats page CSS; without the\n * attribute there's no declaration and page CSS (or the 100% / 400px\n * defaults) decides. Values go through CSSOM, never into CSS text, so an\n * attribute can't inject rules.\n *\n * The hide rule is `!important` too — the inline styles it replaces couldn't\n * be overridden by page CSS either.\n */\nfunction syncInstanceSheet(el: TyTabs, shownId: string | null): void {\n const shadowRoot = el.shadowRoot;\n if (!shadowRoot) return;\n\n let sheet = instanceSheets.get(el);\n if (!sheet) {\n sheet = new CSSStyleSheet();\n sheet.replaceSync(':host {} ::slotted(ty-tab) {}');\n const hide = (sheet.cssRules[1] as CSSStyleRule).style;\n hide.setProperty('opacity', '0', 'important');\n hide.setProperty('visibility', 'hidden', 'important');\n hide.setProperty('pointer-events', 'none', 'important');\n shadowRoot.adoptedStyleSheets = [...shadowRoot.adoptedStyleSheets, sheet];\n instanceSheets.set(el, sheet);\n }\n\n const host = (sheet.cssRules[0] as CSSStyleRule).style;\n for (const prop of ['width', 'height']) {\n const value = el.getAttribute(prop);\n if (value) host.setProperty(prop, value, 'important');\n else host.removeProperty(prop);\n }\n\n (sheet.cssRules[1] as CSSStyleRule).selectorText = shownId\n ? `::slotted(ty-tab:not(#${CSS.escape(shownId)}))`\n : '::slotted(ty-tab)';\n}\n\n/** Update ARIA attributes on tab buttons without re-rendering. */\nfunction updateAriaAttributes(el: TyTabs, shadowRoot: ShadowRoot, activeId: string): void {\n const tabs = getChildTabs(el);\n \n tabs.forEach((tab, idx) => {\n const tabId = getTabId(tab);\n if (!tabId) return;\n \n const button = shadowRoot.querySelector<HTMLButtonElement>(`[data-tab-id='${tabId}']`);\n const isActive = tabId === activeId;\n \n if (button) {\n button.setAttribute('aria-selected', String(isActive));\n button.setAttribute('tabindex', isActive ? '0' : '-1');\n // data-active lets consumers style slotted label content\n button.setAttribute('data-active', String(isActive));\n\n const slottedLabel = getSlotLabel(el, tabId);\n if (slottedLabel) {\n setAttr(slottedLabel, 'data-active', String(isActive));\n }\n }\n });\n}\n\n/**\n * Panel visibility (via the instance sheet) and the panels' best-effort\n * `data-active` hint. Panels get no inline style and no ARIA attributes —\n * a morph would strip them; ty-tab carries its tabpanel role internally.\n */\nfunction updatePanelInteraction(el: TyTabs, activeId: string | null): void {\n syncInstanceSheet(el, activeId);\n\n getChildTabs(el).forEach((tab) => {\n const tabId = getTabId(tab);\n // A leaving panel stays visible while it fades out; inert takes it out\n // of the tab order and the a11y tree right away.\n (tab as any).setShown?.(!!tabId && tabId === activeId);\n if (!tabId) return;\n setAttr(tab, 'data-active', String(tabId === activeId));\n });\n}\n\n/** Marker position in pixels for the active tab button, or null if not found. */\nfunction calculateMarkerPosition(\n el: TyTabs,\n shadowRoot: ShadowRoot,\n activeId: string\n): MarkerPosition | null {\n const button = shadowRoot.querySelector<HTMLElement>(`[data-tab-id='${activeId}']`);\n const buttonsContainer = shadowRoot.querySelector<HTMLElement>('.tab-buttons');\n \n if (!button || !buttonsContainer) return null;\n\n // offsetLeft/Top/Width/Height are all layout-space, relative to the\n // offsetParent's border box — unlike getBoundingClientRect(), they don't\n // reflect an ancestor's CSS transform. ty-modal's entrance animation scales\n // the whole dialog in from 0.93, and a rect taken mid-animation used to get\n // baked into the marker's size permanently: nothing re-measures it\n // afterwards, since a transform never fires ResizeObserver.\n const left = button.offsetLeft;\n const top = button.offsetTop;\n const width = button.offsetWidth;\n const height = button.offsetHeight;\n\n return { left, top, width, height };\n}\n\nfunction updateMarker(el: TyTabs, activeId: string, forceSnap = false): void {\n const shadowRoot = el.shadowRoot;\n if (!shadowRoot) return;\n\n const marker = shadowRoot.querySelector<HTMLElement>('.marker-wrapper');\n if (!marker) return;\n\n const position = calculateMarkerPosition(el, shadowRoot, activeId);\n if (!position) return;\n\n // Snap without animating when the marker was never positioned, or was\n // positioned while the tabs were hidden (zero-size rects) — otherwise it\n // visibly glides in from 0,0 on first display. `forceSnap` covers the\n // related case where the first paint already had a real position (tab 0,\n // by getActiveTabId's default) and `active` is corrected right after.\n const snap = forceSnap || !marker.style.left || marker.offsetWidth === 0;\n if (snap) marker.style.transition = 'none';\n\n marker.style.left = `${position.left}px`;\n marker.style.top = `${position.top}px`;\n marker.style.width = `${position.width}px`;\n marker.style.height = `${position.height}px`;\n\n if (snap) {\n marker.offsetWidth; // flush styles so the snap isn't animated\n marker.style.transition = '';\n }\n}\n\n/**\n * Bring the shown tab in line with getActiveTabId() — the one place the\n * shown tab changes. Fires `ty-tab-change` when it moves from one tab to\n * another, then lets a lazy tab fire `ty-tab-load`; showing the first tab\n * (on connect, or when tabs first arrive) fires nothing.\n *\n * `user` is a click/key/menu activation: it animates and never snaps.\n * External changes (`active` set by app or server, children morphed) snap\n * for the first tab shown and for the first correction after it, as long as\n * the user hasn't pressed anything since.\n */\nfunction syncShownTab(el: TyTabs, user = false): void {\n const shadowRoot = el.shadowRoot;\n if (!shadowRoot) return;\n\n const tabs = getChildTabs(el);\n const previousId = shownTabs.get(el) ?? null;\n const tabId = getActiveTabId(el, tabs);\n const newIndex = (tabId ? findTabIndex(tabs, tabId) : undefined) ?? 0;\n const container = shadowRoot.querySelector<HTMLElement>('.tabs-container');\n\n if (tabId === previousId) {\n // Same tab, but tabs added, removed or reordered before it moved its\n // slot: realign the carousel. Not a navigation — snap, no event.\n const wrapper = shadowRoot.querySelector<HTMLElement>('.panels-wrapper');\n if (wrapper && wrapper.style.transform !== carouselTransform(newIndex)) {\n snapNextChange(container);\n wrapper.style.transform = carouselTransform(newIndex);\n }\n return;\n }\n\n shownTabs.set(el, tabId);\n const initial = previousId === null;\n const arrived = !user && tabId !== null && awaitedTabs.get(el) === tabId;\n awaitedTabs.delete(el);\n const requested = el.getAttribute('active');\n if (initial && requested && requested !== tabId) awaitedTabs.set(el, requested);\n\n const snap = !user && (initial || arrived || pendingInitialSnap.get(el) === userInputs);\n if (initial) pendingInitialSnap.set(el, userInputs);\n else if (!arrived) pendingInitialSnap.delete(el);\n\n if (snap) snapNextChange(container);\n updateTransform(el, newIndex);\n updateAriaAttributes(el, shadowRoot, tabId || '');\n updatePanelInteraction(el, tabId);\n\n // First tab: render()'s frame measures the marker once layout exists.\n if (!tabId || initial) return;\n\n updateMarker(el, tabId, snap);\n scrollActiveIntoView(el, tabId, !snap);\n\n // The \"…\" menu is not rebuilt on activation, so re-mark it here.\n shadowRoot.querySelectorAll<HTMLElement>('.tab-overflow-item').forEach((item) => {\n item.setAttribute('data-active', String(item.dataset.tabId === tabId));\n });\n\n (tabs[newIndex] as any)?.resetScroll?.();\n\n if (arrived) return; // still the initial tab\n\n const previousIndex = findTabIndex(tabs, previousId!);\n dispatchTabChangeEvent(el, tabId, newIndex, previousIndex === undefined ? null : previousId, previousIndex ?? null);\n\n // A lazy tab with no content fires ty-tab-load. Not for the first tab.\n (tabs[newIndex] as any)?._requestLoad?.(newIndex);\n}\n\nfunction setupResizeObserver(el: TyTabs): void {\n const oldObserver = resizeObservers.get(el);\n if (oldObserver) {\n oldObserver.disconnect();\n }\n\n // Observe unconditionally (not just for '%' widths) — overflow can happen\n // at any fixed width too, and needs to react to container resizes. The\n // carousel is percentage-based, so it needs nothing here.\n const observer = new ResizeObserver(() => {\n const activeId = currentActive(el);\n\n // Overflow before marker: the \"…\" trigger appearing/vanishing reflows the\n // strip, and the marker must be measured against the final layout.\n updateOverflow(el);\n\n if (activeId) {\n updateMarker(el, activeId);\n scrollActiveIntoView(el, activeId, false);\n }\n });\n\n observer.observe(el);\n resizeObservers.set(el, observer);\n}\n\nfunction cleanupResizeObserver(el: TyTabs): void {\n const observer = resizeObservers.get(el);\n if (observer) {\n observer.disconnect();\n resizeObservers.delete(el);\n }\n}\n\n/**\n * Generate HTML for tab buttons using slots for rich labels.\n * Slots are looked up as direct children of tabs-el with slot='label-{tab-id}'.\n * Also renders marker wrapper with optional default underline (only if no custom marker).\n */\nfunction renderTabButtons(tabsEl: TyTabs, tabs: HTMLElement[], activeId: string | null): string {\n const buttons = tabs.map((tab) => {\n const tabId = getTabId(tab);\n if (!tabId) return '';\n \n const labelType = getTabLabelType(tabsEl, tab);\n const textLabel = labelType === 'text' ? (tab.getAttribute('label') || 'Tab') : '';\n const disabled = isTabDisabled(tab);\n const active = tabId === activeId;\n \n return `<button\n class=\"tab-button\"\n role=\"tab\"\n data-tab-id=\"${tabId}\"\n id=\"tab-${tabId}\"\n aria-selected=\"${active}\"\n tabindex=\"${active ? '0' : '-1'}\"\n data-active=\"${active}\"\n ${disabled ? 'disabled aria-disabled=\"true\"' : ''}\n >\n ${labelType === 'slot' ? `<slot name=\"label-${tabId}\"></slot>` : `<span class=\"tab-label\">${textLabel}</span>`}\n </button>`;\n }).join('');\n \n return `\n <div class=\"tab-buttons\" part=\"buttons-container\">\n <div class=\"tab-strip\" role=\"tablist\" part=\"strip\">\n <div class=\"marker-wrapper\" part=\"marker-wrapper\">\n ${!hasCustomMarker(tabsEl) ? '<div class=\"default-marker\"></div>' : ''}\n <slot name=\"marker\"></slot>\n </div>\n ${buttons}\n </div>\n </div>\n `;\n}\n\n/**\n * Generate HTML for ONLY the button elements (no marker wrapper).\n * Used during smart updates to preserve the marker wrapper.\n */\nfunction renderButtonsOnly(tabsEl: TyTabs, tabs: HTMLElement[], activeId: string | null): string {\n return tabs.map((tab) => {\n const tabId = getTabId(tab);\n if (!tabId) return '';\n \n const labelType = getTabLabelType(tabsEl, tab);\n const textLabel = labelType === 'text' ? (tab.getAttribute('label') || 'Tab') : '';\n const disabled = isTabDisabled(tab);\n const active = tabId === activeId;\n \n return `<button\n class=\"tab-button\"\n role=\"tab\"\n data-tab-id=\"${tabId}\"\n id=\"tab-${tabId}\"\n aria-selected=\"${active}\"\n tabindex=\"${active ? '0' : '-1'}\"\n data-active=\"${active}\"\n ${disabled ? 'disabled aria-disabled=\"true\"' : ''}\n >\n ${labelType === 'slot' ? `<slot name=\"label-${tabId}\"></slot>` : `<span class=\"tab-label\">${textLabel}</span>`}\n </button>`;\n }).join('');\n}\n\n/** Build a display label for a tab's overflow-menu entry. */\nfunction getTabMenuLabel(tabsEl: TyTabs, tab: HTMLElement): string {\n const tabId = getTabId(tab);\n if (tabId && getTabLabelType(tabsEl, tab) === 'slot') {\n const slotted = getSlotLabel(tabsEl, tabId);\n return slotted?.textContent?.trim() || tabId;\n }\n return tab.getAttribute('label') || 'Tab';\n}\n\n/** Remove the \"more\" trigger + its popup, if present. */\nfunction removeOverflowMenu(shadowRoot: ShadowRoot): void {\n shadowRoot.querySelector('.tab-overflow-trigger')?.remove();\n}\n\n/**\n * Build the \"more\" trigger button + its ty-popup jump menu listing ALL tabs\n * (active one marked), and append it to the buttons container — outside the\n * scrollable strip, so it stays pinned at the edge.\n * Reuses ty-popup instead of a second floating-menu implementation.\n */\nfunction renderOverflowMenu(el: TyTabs, container: HTMLElement, allTabs: HTMLElement[]): void {\n const activeId = getActiveTabId(el, allTabs);\n\n const trigger = document.createElement('button');\n trigger.className = 'tab-overflow-trigger';\n trigger.type = 'button';\n trigger.setAttribute('aria-label', `${allTabs.length} tabs`);\n trigger.textContent = '⋯';\n\n const popup = document.createElement('ty-popup');\n popup.setAttribute('placement', 'bottom');\n\n const menu = document.createElement('div');\n menu.className = 'tab-overflow-menu';\n menu.setAttribute('role', 'menu');\n\n allTabs.forEach((tab) => {\n const tabId = getTabId(tab);\n if (!tabId) return;\n\n const item = document.createElement('button');\n item.type = 'button';\n item.className = 'tab-overflow-item';\n item.setAttribute('role', 'menuitem');\n item.setAttribute('data-tab-id', tabId);\n item.setAttribute('data-active', String(tabId === activeId));\n item.textContent = getTabMenuLabel(el, tab);\n if (isTabDisabled(tab)) {\n item.disabled = true;\n } else {\n item.addEventListener('click', () => {\n activateTab(el, tabId);\n (popup as any).closePopup?.();\n });\n }\n menu.appendChild(item);\n });\n\n popup.appendChild(menu);\n trigger.appendChild(popup);\n container.appendChild(trigger);\n}\n\n/**\n * Tabs never collapse: the strip scrolls horizontally (scrollbar hidden) and\n * activating a tab glides it into view. This only decides whether the \"…\"\n * jump menu is needed — shown when the strip actually overflows. scrollWidth/\n * clientWidth are both integer-rounded the same way, so summing fractional\n * button widths (the old false-positive \"…\" with room to spare) can't happen.\n */\nfunction updateOverflow(el: TyTabs): void {\n const shadowRoot = el.shadowRoot;\n if (!shadowRoot) return;\n\n const container = shadowRoot.querySelector<HTMLElement>('.tab-buttons');\n const strip = shadowRoot.querySelector<HTMLElement>('.tab-strip');\n if (!container || !strip) return;\n\n // Fixed tabs divide the bar between them, so there is nothing to overflow,\n // nothing to scroll and nothing to fade. Leave the strip unclipped so a\n // custom marker's shadow can breathe.\n if (getTabsAttributes(el).fixed) {\n removeOverflowMenu(shadowRoot);\n strip.classList.add('unclipped');\n strip.style.removeProperty('--fade-left');\n strip.style.removeProperty('--fade-right');\n return;\n }\n\n // Taking the trigger away widens the strip, so the browser clamps scrollLeft\n // down by the trigger's width — and putting the trigger back does NOT undo\n // that. Since this runs on every activation, the loss showed up as the strip\n // jerking ~52px toward the start and gliding back. Restore it once the layout\n // has settled, below.\n const savedScrollLeft = strip.scrollLeft;\n removeOverflowMenu(shadowRoot);\n\n // A zero measurement means the element is display:none or mid-layout —\n // we can't know whether it overflows, so leave the trigger off.\n if (strip.clientWidth <= 0) return;\n\n // Content extent comes from the buttons, not scrollWidth: an unclipped strip\n // has no scrolling box, so scrollWidth would just echo clientWidth and we'd\n // never notice it started overflowing again.\n const buttons = strip.querySelectorAll<HTMLElement>('.tab-button');\n const last = buttons[buttons.length - 1];\n const contentWidth = last ? last.offsetLeft + last.offsetWidth : 0;\n const stripWidth = strip.clientWidth;\n const hidden = contentWidth - stripWidth;\n\n // Clipping the strip is what cuts a custom marker's box-shadow off, so only\n // clip when the tabs actually need to scroll.\n strip.classList.toggle('unclipped', hidden <= 1);\n\n if (hidden <= 1) { // everything fits\n strip.scrollLeft = savedScrollLeft;\n updateEdgeFades(strip);\n return;\n }\n\n renderOverflowMenu(el, container, getChildTabs(el));\n\n // The trigger pays for itself out of the strip's width. When the tabs\n // overflowed by less than it costs, adding it hides MORE than it reveals —\n // the sliver that was one small scroll away is now a whole tab plus the\n // trigger's own footprint. Measure what it actually took and back out.\n const triggerCost = container.clientWidth - strip.clientWidth;\n if (hidden <= triggerCost) {\n removeOverflowMenu(shadowRoot);\n }\n\n strip.scrollLeft = savedScrollLeft;\n updateEdgeFades(strip);\n}\n\n/**\n * Fade the strip's edges where more tabs continue past them — left fade when\n * scrolled away from the start, right fade while there's content beyond the\n * viewport. Driven by --fade-left/right consumed by the strip's mask-image.\n */\nfunction updateEdgeFades(strip: HTMLElement): void {\n const maxScroll = strip.scrollWidth - strip.clientWidth;\n // Never fade more than is actually hidden: a full 28px veil over a 4px\n // sliver of overflow obscures far more than it hints at.\n const fade = (distance: number) => `${distance > 1 ? Math.min(28, distance) : 0}px`;\n strip.style.setProperty('--fade-left', fade(strip.scrollLeft));\n strip.style.setProperty('--fade-right', fade(maxScroll - strip.scrollLeft));\n}\n\n/**\n * Center the active tab button in the strip, clamped at both ends. With tabs\n * [1..6] and 4 visible: activating 3 shows [2,3,4,5]; activating 5 wants\n * [4,5,…] but clamps at the right edge, showing [3,4,5,6]. The recenter\n * motion itself is the \"more tabs over here\" affordance. Smooth on\n * user-driven activation, instant on first render / resize.\n */\nfunction scrollActiveIntoView(el: TyTabs, activeId: string, smooth: boolean): void {\n const shadowRoot = el.shadowRoot;\n if (!shadowRoot) return;\n\n const strip = shadowRoot.querySelector<HTMLElement>('.tab-strip');\n const button = shadowRoot.querySelector<HTMLElement>(`[data-tab-id='${activeId}']`);\n if (!strip || !button || strip.clientWidth <= 0) return;\n\n const centered = button.offsetLeft + button.offsetWidth / 2 - strip.clientWidth / 2;\n const target = Math.max(0, Math.min(centered, strip.scrollWidth - strip.clientWidth));\n\n if (Math.round(target) !== Math.round(strip.scrollLeft)) {\n const reduce = window.matchMedia('(prefers-reduced-motion: reduce)').matches;\n strip.scrollTo({ left: target, behavior: smooth && !reduce ? 'smooth' : 'auto' });\n }\n}\n\n/**\n * Render the tabs container with buttons and panel viewport.\n * Smart rendering: checks if structure exists and only updates when needed.\n */\nfunction render(el: TyTabs): void {\n const shadowRoot = el.shadowRoot;\n if (!shadowRoot) return;\n \n const { placement, fixed } = getTabsAttributes(el);\n const tabs = getChildTabs(el);\n const activeId = getActiveTabId(el, tabs);\n const activeIndex = activeId ? (findTabIndex(tabs, activeId) ?? 0) : 0;\n\n // Each <ty-tab> IS its tabpanel — role + accessible name sit on its shadow\n // .tab-panel (the focus target), where a morph can't strip them. The name\n // comes from here because rich `label-{id}` slots live on ty-tabs. No\n // aria-controls on the tab BUTTON: ARIA id-references don't resolve across\n // a shadow-tree boundary.\n tabs.forEach((tab) => (tab as any).setPanelLabel?.(getTabMenuLabel(el, tab)));\n\n const existingContainer = shadowRoot.querySelector('.tabs-container');\n const existingButtons = shadowRoot.querySelector('.tab-buttons');\n const existingStrip = shadowRoot.querySelector<HTMLElement>('.tab-strip');\n const existingViewport = shadowRoot.querySelector('.panels-viewport');\n\n // Base sheet first: the instance sheet (created by updatePanelInteraction)\n // must come after it.\n ensureStyles(shadowRoot, { css: tabsStyles, id: 'ty-tabs' });\n\n if (existingContainer && existingButtons && existingStrip && existingViewport) {\n // === SMART UPDATE: Structure exists, only update what changed ===\n\n existingContainer.setAttribute('data-placement', placement);\n existingContainer.toggleAttribute('data-fixed', fixed);\n\n // Preserve the marker wrapper; only the buttons are recreated. Removing\n // every button momentarily empties the strip, which clamps its scrollLeft\n // to 0 — capture it first and restore after re-append, so the ensure-\n // visible glide below starts from where the user actually was.\n // Save BEFORE the trigger goes: removing it widens the strip, which clamps\n // scrollLeft down by the trigger's width. Reading it afterwards would save\n // the already-clamped value and \"restore\" the strip 52px short.\n const savedScrollLeft = existingStrip.scrollLeft;\n existingButtons.querySelector('.tab-overflow-trigger')?.remove();\n const allButtons = existingStrip.querySelectorAll('.tab-button');\n allButtons.forEach(button => button.remove());\n\n const buttonsHtml = renderButtonsOnly(el, tabs, activeId);\n const tempDiv = document.createElement('div');\n tempDiv.innerHTML = buttonsHtml;\n\n Array.from(tempDiv.children).forEach(button => {\n existingStrip.appendChild(button);\n });\n existingStrip.scrollLeft = savedScrollLeft;\n\n // Re-setup event listeners (buttons were recreated)\n setupEventListeners(el, shadowRoot, tabs);\n updateAriaAttributes(el, shadowRoot, activeId || '');\n\n // Tabs arriving into an empty ty-tabs: the first one just appears.\n const firstShow = !shownTabs.get(el);\n requestAnimationFrame(() => {\n // Re-read rather than close over render-time values — see the full\n // render branch below for why a stale replay corrupts the state.\n const currentId = currentActive(el);\n\n // Overflow before marker: inserting/removing the \"…\" trigger reflows the\n // strip, and the marker must be measured against the final layout.\n updateOverflow(el);\n\n if (currentId) {\n updateMarker(el, currentId, firstShow);\n scrollActiveIntoView(el, currentId, !firstShow);\n }\n });\n\n updatePanelInteraction(el, activeId);\n\n } else {\n // === FULL RENDER: First time or structure missing ===\n\n shadowRoot.innerHTML = `\n <div class=\"tabs-container\" data-placement=\"${placement}\"${fixed ? ' data-fixed' : ''}>\n ${renderTabButtons(el, tabs, activeId)}\n <div class=\"panels-viewport\" part=\"panels-container\">\n <div class=\"panels-wrapper\" style=\"transform: ${carouselTransform(activeIndex)}\">\n <slot></slot>\n </div>\n </div>\n </div>\n `;\n\n // Position the marker once layout exists\n requestAnimationFrame(() => {\n // Re-read the shown tab instead of closing over render-time values:\n // `active` can change between render() and this frame (the common\n // \"mount, then apply the real active tab\" pattern), and syncShownTab\n // has already moved the marker, carousel, aria and panel visibility to\n // the new tab. Replaying the stale tab here drags the marker back to\n // the old tab while everything else stays on the new one.\n const currentId = currentActive(el);\n\n // Overflow before marker — see the smart-update branch.\n updateOverflow(el);\n\n if (currentId) {\n updateMarker(el, currentId);\n scrollActiveIntoView(el, currentId, false); // first paint: snap, no glide\n }\n });\n\n setupEventListeners(el, shadowRoot, tabs);\n updateAriaAttributes(el, shadowRoot, activeId || '');\n\n // The strip survives smart updates (only buttons are recreated), so one\n // listener per full render is enough. Keeps the edge fades in sync while\n // the user drags/wheels and during the smooth recenter glide.\n const strip = shadowRoot.querySelector<HTMLElement>('.tab-strip');\n strip?.addEventListener('scroll', () => updateEdgeFades(strip), { passive: true });\n\n updatePanelInteraction(el, activeId);\n\n // Hide the default marker whenever a custom one is slotted in.\n const markerSlot = shadowRoot.querySelector('slot[name=\"marker\"]') as HTMLSlotElement;\n if (markerSlot) {\n const updateDefaultMarkerVisibility = () => {\n const defaultMarker = shadowRoot.querySelector('.default-marker') as HTMLElement;\n if (defaultMarker) {\n const hasCustom = markerSlot.assignedElements().length > 0;\n defaultMarker.style.display = hasCustom ? 'none' : '';\n }\n };\n markerSlot.addEventListener('slotchange', updateDefaultMarkerVisibility);\n // Check immediately in case content is already slotted\n updateDefaultMarkerVisibility();\n }\n }\n}\n\nfunction cleanup(el: TyTabs): void {\n cleanupEventListeners(el);\n cleanupResizeObserver(el);\n}\n\n/**\n * TyTabs Web Component\n */\nexport class TyTabs extends HTMLElement {\n static get observedAttributes() {\n return ['width', 'height', 'active', 'placement', 'fixed'];\n }\n \n constructor() {\n super();\n this.attachShadow({ mode: 'open' });\n }\n \n private _childObserver: MutationObserver | null = null;\n private _updateQueued = false;\n private _structureDirty = false;\n\n /** ID of the tab currently shown (`active` may be stale or missing after a morph). */\n get activeTab(): string | null {\n return shownTabs.get(this) ?? null;\n }\n\n connectedCallback() {\n render(this);\n syncShownTab(this);\n // Here, not in render(): a re-inserted element takes render()'s smart\n // path, and disconnectedCallback has dropped the observer.\n setupResizeObserver(this);\n\n // Frameworks and server morphs add/remove ty-tab children — the button\n // strip renders from light DOM, so watch it. render() only touches\n // shadow DOM, so no observer feedback loop.\n this._childObserver = new MutationObserver(() => this._queueUpdate(true));\n this._childObserver.observe(this, { childList: true });\n }\n\n disconnectedCallback() {\n this._childObserver?.disconnect();\n this._childObserver = null;\n cleanup(this);\n }\n\n /**\n * External changes (`active` set by app or server, children added or\n * removed, a ty-tab's id/label/disabled changed — ty-tab reports those)\n * settle in one microtask: a morph sets attributes and swaps children in\n * one go, and the shown tab must be decided once the whole batch has\n * landed — `active` may name a tab that is appended after it.\n */\n _queueUpdate(structure: boolean): void {\n this._structureDirty ||= structure;\n if (this._updateQueued) return;\n this._updateQueued = true;\n queueMicrotask(() => {\n this._updateQueued = false;\n if (!this.isConnected) return;\n // Child changes made after this was queued are still waiting for their\n // own observer microtask, which would run after this one. Take them now.\n if (this._childObserver?.takeRecords().length) this._structureDirty = true;\n if (this._structureDirty) {\n this._structureDirty = false;\n render(this);\n }\n syncShownTab(this);\n });\n }\n\n attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null) {\n // Before connect, connectedCallback renders everything at once.\n if (!this.isConnected) return;\n // `active` only moves the shown tab — no re-render: rebuilding the\n // buttons and the \"…\" trigger momentarily widens the strip and the\n // ensure-visible glide twitches back ~52px.\n if (name === 'active') {\n // A new request replaces the one still waiting for its tab.\n if (oldValue !== newValue) awaitedTabs.delete(this);\n this._queueUpdate(false);\n } else render(this);\n }\n}\n\nif (!customElements.get('ty-tabs')) {\n customElements.define('ty-tabs', TyTabs);\n}\n","/**\n * Tab Component Styles\n */\n\nimport { customScrollbarStyles } from './custom-scrollbar.js'\n\nexport const tabStyles = `\n:host {\n width: 100%;\n height: 100%;\n display: block;\n box-sizing: border-box;\n flex-shrink: 0;\n /* ty-tabs hides inactive panels with opacity + visibility. visibility\n transitions as \"visible until the fade ends\", so a panel leaving fades out\n and only then drops out of the tab order. */\n transition:\n opacity var(--ty-tabs-transition-duration, 400ms) var(--ty-tabs-transition-easing, ease-in-out),\n visibility var(--ty-tabs-transition-duration, 400ms);\n}\n\n@media (prefers-reduced-motion: reduce) {\n :host {\n transition-duration: 0ms !important;\n }\n}\n\n.tab-wrapper {\n width: 100%;\n height: 100%;\n position: relative;\n overflow: hidden;\n}\n\n.tab-panel {\n width: 100%;\n height: 100%;\n overflow: auto;\n box-sizing: border-box;\n}\n\n/* Lazy tabs: placeholder while loading, message + Retry when it failed. */\n.tab-loading,\n.tab-error {\n display: none;\n box-sizing: border-box;\n min-height: 100%;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 12px;\n padding: 24px;\n text-align: center;\n}\n\n.tab-panel[data-load=\"loading\"] .tab-loading,\n.tab-panel[data-load=\"failed\"] .tab-error {\n display: flex;\n}\n\n/* Fades in late, so a fast load never flashes it. */\n.tab-panel[data-load=\"loading\"] .tab-loading {\n animation: ty-tab-status-in 200ms ease-out 150ms both;\n}\n\n@keyframes ty-tab-status-in {\n from { opacity: 0; }\n}\n\n.tab-spinner {\n display: inline-flex;\n width: 20px;\n height: 20px;\n color: var(--ty-text-soft);\n animation: var(--ty-loader-animation, ty-tab-spin 0.7s linear infinite);\n}\n\n.tab-spinner svg {\n width: 100%;\n height: 100%;\n}\n\n@keyframes ty-tab-spin {\n to { transform: rotate(360deg); }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .tab-spinner {\n animation-duration: 1.6s;\n }\n}\n\n.tab-error {\n color: var(--ty-text-soft);\n font-size: 14px;\n}\n\n.tab-retry {\n font: inherit;\n font-size: 13px;\n padding: 4px 14px;\n border: 1px solid var(--ty-border);\n border-radius: 9999px;\n background: transparent;\n color: var(--ty-text-strong);\n cursor: pointer;\n}\n\n.tab-retry:hover {\n border-color: var(--ty-text-soft);\n}\n\n.tab-retry:focus-visible {\n outline: 2px solid var(--ty-color-primary);\n outline-offset: 2px;\n}\n\n.tab-panel.ty-custom-scroll {\n scrollbar-width: none;\n -ms-overflow-style: none;\n}\n\n.tab-panel.ty-custom-scroll::-webkit-scrollbar {\n display: none;\n}\n\n.tab-wrapper:hover .ty-scrollbar-track-y.has-overflow {\n opacity: 1;\n}\n\n${customScrollbarStyles}\n`;\n","/** Individual tab panel with custom scrollbar via CustomScrollbar utility. */\n\nimport { ensureStyles } from '../utils/styles.js';\nimport { tabStyles } from '../styles/tab.js';\nimport { CustomScrollbar, isCustomScrollbarEnabled } from '../utils/custom-scrollbar.js';\nimport { getLoaderSvg } from '../utils/loader-registry.js';\n\nexport interface TabAttributes {\n id: string | null;\n label: string | null;\n disabled: boolean;\n lazy: boolean;\n}\n\n/**\n * `ty-tab-load`: a lazy tab with no content was shown. Fired on the ty-tab\n * and doesn't bubble, so a lazy tab nested in another doesn't trigger the\n * outer one's listener. Listen on the tab, or on ty-tabs with capture.\n */\nexport interface TabLoadDetail {\n id: string;\n index: number;\n}\n\n/**\n * Lazy tab lifecycle. `idle`: not lazy, or has content. `empty`: lazy with\n * nothing to show, not asked for yet. `loading`: ty-tab-load fired, waiting\n * for content. `failed`: the app called loadFailed().\n */\ntype LoadState = 'idle' | 'empty' | 'loading' | 'failed';\n\n/** Children that are status placeholders, not content. */\nconst STATUS_SLOTS = new Set(['loading', 'error']);\n\n/** Elements that render nothing, so they aren't content either. */\nconst INERT_ELEMENTS = new Set(['template', 'script', 'style']);\n\nexport class TyTab extends HTMLElement {\n private _scrollbar: CustomScrollbar | null = null\n private _panelLabel: string | null = null\n private _shown = true\n private _load: LoadState = 'idle'\n private _contentObserver: MutationObserver | null = null\n private _contentChanged = false\n\n static get observedAttributes() {\n return ['id', 'label', 'disabled', 'lazy'];\n }\n\n constructor() {\n super();\n this.attachShadow({ mode: 'open' });\n }\n\n connectedCallback() {\n this._render();\n // Re-inserted (moved): the shadow tree survived, the scrollbar didn't.\n if (!this._scrollbar) this._setupScrollbar();\n this._watchContent();\n }\n\n /** Accessible name. Set by ty-tabs, which also knows rich `label-{id}` slots. */\n setPanelLabel(label: string): void {\n this._panelLabel = label;\n this._syncPanel();\n }\n\n /** Set by ty-tabs: a panel that isn't shown is inert. */\n setShown(shown: boolean): void {\n this._shown = shown;\n this._syncPanel();\n }\n\n disconnectedCallback() {\n this._destroyScrollbar();\n // Disconnecting drops the observer's pending records. A move (emptied\n // and reinserted in one go) must still react to them on reconnect.\n this._contentChanged = !!this._contentObserver?.takeRecords().length;\n this._contentObserver?.disconnect();\n this._contentObserver = null;\n }\n\n /**\n * Called by ty-tabs when this tab becomes the shown one — never for the\n * tab shown first, whose content the page is expected to carry. A lazy\n * tab with no content (or whose load failed) asks for it.\n */\n _requestLoad(index: number): void {\n // Content that came with the switch (same morph) counts.\n if (this._contentObserver?.takeRecords().length) this._checkContent(false);\n if (this._load === 'empty' || this._load === 'failed') this._fireLoad(index);\n }\n\n /**\n * Report that loading this tab's content failed: shows `slot=\"error\"`\n * (default \"Couldn't load.\") with a Retry button. Retry, or showing the\n * tab again, fires `ty-tab-load` once more. Content arriving clears it.\n */\n loadFailed(): void {\n if (this._load === 'loading' || this._load === 'empty') this._setLoad('failed');\n }\n\n attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null) {\n this._render();\n if (name === 'lazy') {\n if (this.isConnected) this._watchContent();\n return;\n }\n // ty-tabs renders this tab's button from id/label/disabled. A morph\n // changes them in place, which ty-tabs' childList observer can't see.\n const tabs = this.parentElement;\n if (oldValue !== newValue && this.isConnected && tabs?.localName === 'ty-tabs') {\n (tabs as any)._queueUpdate?.(true);\n }\n }\n\n private _render(): void {\n const shadowRoot = this.shadowRoot;\n if (!shadowRoot) return;\n\n if (!shadowRoot.querySelector('.tab-wrapper')) {\n ensureStyles(shadowRoot, { css: tabStyles, id: 'ty-tab' });\n\n // The panel semantics live in the shadow root, where a server morph of\n // the ty-tab can't strip them. tabindex: keyboard users can reach (and\n // scroll) a panel with no focusable content; it's also what gets focus,\n // so it carries the role and name.\n shadowRoot.innerHTML = `\n <div class=\"tab-wrapper\">\n <div class=\"tab-panel\" role=\"tabpanel\" tabindex=\"0\">\n <slot></slot>\n </div>\n </div>\n `;\n }\n this._syncPanel();\n }\n\n /** Lazy tabs track whether they have content; others don't watch. */\n private _watchContent(): void {\n const lazy = this.hasAttribute('lazy');\n if (lazy && !this._contentObserver) {\n // characterData: a reply can be bare text, which no childList sees\n // once the text node exists (morphs update text nodes in place).\n this._contentObserver = new MutationObserver(() => this._checkContent(true));\n this._contentObserver.observe(this, { childList: true, characterData: true, subtree: true });\n } else if (!lazy && this._contentObserver) {\n this._contentObserver.disconnect();\n this._contentObserver = null;\n }\n const changed = this._contentChanged;\n this._contentChanged = false;\n this._checkContent(changed);\n }\n\n private _hasContent(): boolean {\n for (const node of Array.from(this.childNodes)) {\n if (node.nodeType === Node.TEXT_NODE && node.textContent!.trim()) return true;\n if (node.nodeType !== Node.ELEMENT_NODE) continue;\n const el = node as Element;\n if (!STATUS_SLOTS.has(el.getAttribute('slot') ?? '') && !INERT_ELEMENTS.has(el.localName)) return true;\n }\n return false;\n }\n\n /**\n * `mutated`: content changed under a connected tab. Content that goes away\n * (a morph with the server's empty markup) loads again — right away when\n * this tab is the one shown, otherwise the next time it's shown.\n */\n private _checkContent(mutated: boolean): void {\n if (!this.hasAttribute('lazy') || this._hasContent()) {\n this._setLoad('idle');\n return;\n }\n if (this._load !== 'idle') return;\n this._setLoad('empty');\n if (!mutated) return;\n // Decide once ty-tabs has applied a switch from the same morph: the tab\n // being left doesn't load, the one switched to loads through _requestLoad.\n queueMicrotask(() => {\n if (this._load === 'empty' && this._shown && this.parentElement?.localName === 'ty-tabs') this._fireLoad();\n });\n }\n\n private _fireLoad(index?: number): void {\n const tabs = this.parentElement;\n if (index === undefined) {\n index = tabs?.localName === 'ty-tabs'\n ? Array.from(tabs.querySelectorAll(':scope > ty-tab')).indexOf(this)\n : 0;\n }\n this._setLoad('loading');\n this.dispatchEvent(new CustomEvent<TabLoadDetail>('ty-tab-load', { detail: { id: this.id, index } }));\n }\n\n /**\n * Placeholder and error, built the first time a tab loads: tabs that never\n * do carry no hidden \"Couldn't load / Retry\" text.\n */\n private _ensureStatus(panel: HTMLElement): void {\n if (panel.querySelector('.tab-loading')) return;\n panel.insertAdjacentHTML('beforeend', `\n <div class=\"tab-loading\" part=\"loading\">\n <slot name=\"loading\"><span class=\"tab-spinner\" part=\"spinner\" aria-hidden=\"true\"></span></slot>\n </div>\n <div class=\"tab-error\" part=\"error\" role=\"alert\">\n <slot name=\"error\">Couldn't load.</slot>\n <button type=\"button\" class=\"tab-retry\" part=\"retry\">Retry</button>\n </div>\n `);\n panel.querySelector('.tab-retry')!.addEventListener('click', () => {\n // Retry hides itself; keep focus in the tab instead of dropping to <body>.\n panel.focus({ preventScroll: true });\n this._fireLoad();\n });\n }\n\n private _setLoad(state: LoadState): void {\n if (state === this._load) return;\n this._load = state;\n const panel = this.shadowRoot?.querySelector<HTMLElement>('.tab-panel');\n if (!panel) return;\n // Blank while empty: an initial tab nobody asked to load shows no spinner.\n if (state === 'loading' || state === 'failed') {\n this._ensureStatus(panel);\n panel.dataset.load = state;\n } else {\n delete panel.dataset.load;\n }\n if (state === 'loading') {\n panel.setAttribute('aria-busy', 'true');\n // Picked up per load, so an app's setLoaderSvg() applies.\n panel.querySelector('.tab-spinner')!.innerHTML = getLoaderSvg();\n } else {\n panel.removeAttribute('aria-busy');\n }\n }\n\n private _syncPanel(): void {\n const panel = this.shadowRoot?.querySelector<HTMLElement>('.tab-panel');\n if (!panel) return;\n\n // ty-tabs can upgrade before its children, so the name it pushes may\n // never have landed: read a rich `label-{id}` sibling ourselves meanwhile.\n const tabs = this.parentElement;\n const rich = !this._panelLabel && this.id && tabs?.localName === 'ty-tabs'\n ? tabs.querySelector(`:scope > [slot=\"label-${CSS.escape(this.id)}\"]`)\n : null;\n const label = this._panelLabel || rich?.textContent?.trim() || this.getAttribute('label');\n if (label) panel.setAttribute('aria-label', label);\n else panel.removeAttribute('aria-label');\n\n // A leaving panel stays visible while it fades out; inert drops it (and\n // its slotted content) from the tab order and the a11y tree right away.\n panel.parentElement!.inert = !this._shown;\n }\n\n private _setupScrollbar(): void {\n const panel = this.shadowRoot?.querySelector('.tab-panel') as HTMLElement;\n const wrapper = this.shadowRoot?.querySelector('.tab-wrapper') as HTMLElement;\n if (!panel || !wrapper) return;\n\n if (!isCustomScrollbarEnabled()) return;\n\n panel.classList.add('ty-custom-scroll');\n this._scrollbar = new CustomScrollbar(panel, { vertical: true });\n\n // Append track to wrapper (outside the scroll area, so it stays fixed)\n if (this._scrollbar.trackY) {\n wrapper.appendChild(this._scrollbar.trackY);\n }\n }\n\n private _destroyScrollbar(): void {\n if (this._scrollbar) {\n this._scrollbar.trackY?.remove();\n this._scrollbar.destroy();\n this._scrollbar = null;\n }\n }\n\n resetScroll(): void {\n this._scrollbar?.scrollToTop(false);\n }\n}\n\nif (!customElements.get('ty-tab')) {\n customElements.define('ty-tab', TyTab);\n}\n","/**\n * Wizard Component Styles\n *\n * Inline rail: indicator + label side by side, connectors between steps that\n * fill as steps complete. One accent (active = where you are); completed is\n * solid ink with a check, pending a faint ring, error a danger ring with \"!\".\n * When the labels don't fit, the rail collapses to \"Step N of M\" over a\n * segment bar (measured in JS, see updateCompact).\n *\n * CSS Parts (::part): indicators-wrapper, step-circle, progress (segment bar),\n * panels-container.\n */\n\nexport const wizardStyles = `\n:host {\n display: block;\n width: var(--ty-wizard-width, 100%); /* set by width attribute — not a public token */\n box-sizing: border-box;\n\n /* State accents. Completed is ink, not green: one accent marks where you\n * are, color is kept for \"here\" and for problems. */\n --ty-wizard-active-accent: var(--ty-color-primary);\n --ty-wizard-completed-accent: var(--ty-text-strong, var(--ty-color-neutral-strong));\n --ty-wizard-error-accent: var(--ty-color-danger);\n --ty-wizard-pending-accent: color-mix(in oklab, var(--ty-text, currentColor) 35%, transparent);\n\n /* Container chrome. One surface, hairline divider, no shadow by default:\n * the wizard is a layout primitive, the page decides elevation. */\n --ty-wizard-bg: var(--ty-surface-elevated);\n --ty-wizard-border: var(--ty-border);\n --ty-wizard-radius: var(--ty-radius-lg, 12px);\n --ty-wizard-shadow: none;\n\n --ty-wizard-header-bg: transparent;\n --ty-wizard-header-border: var(--ty-wizard-border);\n --ty-wizard-header-padding: 14px 20px;\n\n --ty-wizard-progress-track: var(--ty-border);\n --ty-wizard-progress-fill: var(--ty-wizard-completed-accent);\n --ty-wizard-progress-height: 1.5px;\n\n /* Panel slide — same motion as ty-tabs. */\n --ty-wizard-transition-duration: var(--ty-transition-duration, 300ms);\n --ty-wizard-transition-easing: var(--ty-transition-easing, ease-in-out);\n\n --ty-wizard-circle-size: 24px;\n --ty-wizard-circle-border-width: 1.5px;\n\n --ty-wizard-panels-bg: transparent;\n\n --ty-wizard-focus-outline: var(--ty-wizard-active-accent);\n}\n\n.wizard-container {\n display: flex;\n flex-direction: column;\n position: relative;\n box-sizing: border-box;\n border-radius: var(--ty-wizard-radius);\n border: 1px solid var(--ty-wizard-border);\n background: var(--ty-wizard-bg);\n box-shadow: var(--ty-wizard-shadow);\n overflow: hidden;\n}\n\n.step-indicators-wrapper {\n flex-shrink: 0;\n padding: var(--ty-wizard-header-padding);\n border-bottom: 1px solid var(--ty-wizard-header-border);\n background: var(--ty-wizard-header-bg);\n}\n\n/* ---------- Rail ---------- */\n\n.step-indicators {\n display: flex;\n align-items: center;\n gap: 12px;\n}\n\n.step-indicator {\n display: flex;\n align-items: center;\n gap: 8px;\n /* Content basis: labels keep their width, extra space goes to connectors\n (equally). If they don't fit at all, JS switches to the compact header. */\n flex: 1 1 auto;\n min-width: 0;\n cursor: pointer;\n background: transparent;\n border: none;\n padding: 0;\n font: inherit;\n color: inherit;\n text-align: left;\n outline: none;\n}\n\n.step-indicator:last-child {\n flex: 0 0 auto;\n}\n\n/* Connector to the next step — a pseudo-element, so the tablist owns only tabs. */\n.step-indicator:not(:last-child)::after {\n content: \"\";\n flex: 1 1 auto;\n min-width: 16px;\n height: var(--ty-wizard-progress-height);\n border-radius: 1px;\n margin-left: 4px;\n background: var(--ty-wizard-progress-track);\n transition: background var(--ty-wizard-transition-duration) var(--ty-wizard-transition-easing);\n}\n\n.step-indicator[data-done=\"true\"]:not(:last-child)::after {\n background: var(--ty-wizard-progress-fill);\n}\n\n.step-indicator[aria-disabled=\"true\"] {\n opacity: 0.45;\n cursor: not-allowed;\n pointer-events: none;\n}\n\n.step-indicator:focus-visible .step-circle {\n outline: 2px solid var(--ty-wizard-focus-outline);\n outline-offset: 2px;\n}\n\n.step-circle {\n width: var(--ty-wizard-circle-size);\n height: var(--ty-wizard-circle-size);\n border-radius: 50%;\n border: var(--ty-wizard-circle-border-width) solid;\n display: flex;\n align-items: center;\n justify-content: center;\n box-sizing: border-box;\n flex-shrink: 0;\n font-size: calc(var(--ty-wizard-circle-size) * 0.46);\n font-weight: 600;\n font-variant-numeric: tabular-nums;\n line-height: 1;\n transition: var(--ty-local-transition, background-color var(--ty-wizard-transition-duration) var(--ty-wizard-transition-easing), border-color var(--ty-wizard-transition-duration) var(--ty-wizard-transition-easing), color var(--ty-wizard-transition-duration) var(--ty-wizard-transition-easing));\n}\n\n.step-circle svg {\n width: 58%;\n height: 58%;\n}\n\n.step-circle[data-state=\"completed\"] {\n background: var(--ty-wizard-completed-accent);\n border-color: var(--ty-wizard-completed-accent);\n /* Derived from the accent this circle paints, so any override stays legible. */\n color: oklch(\n from var(--ty-wizard-completed-accent)\n clamp(0, (var(--ty-solid-fg-threshold, 0.57) - l) * 1000, 1) 0 0\n );\n}\n\n.step-circle[data-state=\"active\"] {\n background: color-mix(in oklab, var(--ty-wizard-active-accent) 12%, var(--ty-wizard-bg));\n border-color: var(--ty-wizard-active-accent);\n /* Nudged toward the text color so the number clears 4.5:1 on its tint. */\n color: color-mix(in oklab, var(--ty-wizard-active-accent) 75%, var(--ty-text-strong, currentColor));\n}\n\n.step-circle[data-state=\"pending\"] {\n background: transparent;\n border-color: var(--ty-wizard-pending-accent);\n color: var(--ty-text-soft, var(--ty-color-neutral));\n}\n\n.step-circle[data-state=\"error\"] {\n background: color-mix(in oklab, var(--ty-wizard-error-accent) 12%, var(--ty-wizard-bg));\n border-color: var(--ty-wizard-error-accent);\n color: color-mix(in oklab, var(--ty-wizard-error-accent) 75%, var(--ty-text-strong, currentColor));\n}\n\n.step-text {\n display: flex;\n flex-direction: column;\n gap: 0;\n min-width: 0;\n}\n\n.step-label {\n font-size: var(--ty-font-sm, 14px);\n font-weight: 500;\n line-height: 1.3;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n color: var(--ty-text-soft, var(--ty-color-neutral));\n transition: var(--ty-local-transition, color 200ms);\n}\n\n.step-indicator[data-state=\"completed\"] .step-label,\n.step-indicator[data-state=\"active\"] .step-label {\n color: var(--ty-text-strong, var(--ty-color-neutral-strong));\n}\n\n.step-indicator[aria-selected=\"true\"] .step-label {\n font-weight: 600;\n}\n\n.step-indicator[data-state=\"error\"] .step-label {\n color: var(--ty-wizard-error-accent);\n}\n\n/* Only where you are (or what's wrong) gets a second line. Hidden ones keep\n * their width (height 0), so connectors don't shift as you move. */\n.step-description {\n height: 0;\n visibility: hidden;\n font-size: var(--ty-font-xs, 12px);\n line-height: 1.3;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n color: var(--ty-text-soft, var(--ty-color-neutral));\n}\n\n.step-indicator[aria-selected=\"true\"] .step-description,\n.step-indicator[data-state=\"error\"] .step-description {\n height: auto;\n /* inherit, not visible: the rail is visibility:hidden in compact mode. */\n visibility: inherit;\n}\n\n.step-indicator:hover:not([aria-selected=\"true\"]) .step-label {\n color: var(--ty-text-strong, var(--ty-color-neutral-strong));\n}\n\n/* Custom indicator content via slots */\n::slotted([slot^=\"indicator-\"]) {\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n/* ---------- Compact header (narrow containers) ---------- */\n\n.step-compact {\n display: none;\n flex-direction: column;\n gap: 10px;\n}\n\n.compact-top {\n display: flex;\n align-items: baseline;\n justify-content: space-between;\n gap: 12px;\n min-width: 0;\n}\n\n.compact-where {\n display: flex;\n align-items: baseline;\n gap: 6px;\n min-width: 0;\n white-space: nowrap;\n}\n\n.compact-count {\n font-size: var(--ty-font-xs, 12px);\n color: var(--ty-text-soft, var(--ty-color-neutral));\n}\n\n.compact-count::after {\n content: \"·\";\n margin-left: 6px;\n color: var(--ty-text-faint, var(--ty-color-neutral));\n}\n\n.compact-label {\n font-size: var(--ty-font-sm, 14px);\n font-weight: 600;\n color: var(--ty-text-strong, var(--ty-color-neutral-strong));\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.compact-description {\n font-size: var(--ty-font-xs, 12px);\n color: var(--ty-text-faint, var(--ty-color-neutral));\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.compact-segments {\n display: flex;\n gap: 4px;\n}\n\n.compact-segment {\n flex: 1;\n height: 3px;\n border-radius: 2px;\n background: var(--ty-wizard-progress-track);\n transition: background var(--ty-wizard-transition-duration) var(--ty-wizard-transition-easing);\n}\n\n.compact-segment[data-state=\"completed\"] { background: var(--ty-wizard-progress-fill); }\n.compact-segment[data-state=\"active\"] { background: var(--ty-wizard-active-accent); }\n.compact-segment[data-state=\"error\"] { background: var(--ty-wizard-error-accent); }\n\n/* .compact is set from JS when the rail's natural width doesn't fit (or a\n vertical wizard is under 360px). The rail stays laid out, hidden, so it\n can still be measured. */\n.wizard-container.compact { flex-direction: column; }\n.wizard-container.compact .step-indicators {\n position: absolute;\n visibility: hidden;\n pointer-events: none;\n width: max-content;\n}\n.wizard-container.compact .step-compact { display: flex; }\n.wizard-container.compact .step-indicators-wrapper {\n padding: var(--ty-wizard-header-padding);\n border-right: none;\n border-bottom: 1px solid var(--ty-wizard-header-border);\n min-width: 0;\n}\n\n/* ---------- Vertical ---------- */\n\n:host([orientation=\"vertical\"]) .wizard-container:not(.compact) {\n flex-direction: row;\n}\n\n:host([orientation=\"vertical\"]) .wizard-container:not(.compact) .step-indicators-wrapper {\n border-bottom: none;\n border-right: 1px solid var(--ty-wizard-header-border);\n padding: 20px 18px;\n min-width: 170px;\n box-sizing: border-box;\n}\n\n:host([orientation=\"vertical\"]) .step-indicators {\n flex-direction: column;\n align-items: stretch;\n gap: 0;\n}\n\n:host([orientation=\"vertical\"]) .step-indicator {\n flex: 0 0 auto;\n align-items: flex-start;\n gap: 10px;\n position: relative;\n padding-bottom: 26px;\n}\n\n:host([orientation=\"vertical\"]) .step-indicator:last-child {\n padding-bottom: 0;\n}\n\n:host([orientation=\"vertical\"]) .step-text {\n /* Center the label's line box on the circle (label line-height is 1.3). */\n padding-top: calc((var(--ty-wizard-circle-size) - var(--ty-font-sm, 14px) * 1.3) / 2);\n}\n\n:host([orientation=\"vertical\"]) .step-indicator:not(:last-child)::after {\n position: absolute;\n left: calc(var(--ty-wizard-circle-size) / 2 - var(--ty-wizard-progress-height) / 2);\n top: calc(var(--ty-wizard-circle-size) + 4px);\n bottom: 4px;\n width: var(--ty-wizard-progress-height);\n height: auto;\n min-width: 0;\n margin: 0;\n}\n\n/* ---------- Panels ---------- */\n\n.panels-viewport {\n position: relative;\n flex: 1;\n min-width: 0;\n height: var(--ty-wizard-panel-height, auto);\n overflow: hidden;\n background: var(--ty-wizard-panels-bg);\n}\n\n/* Carousel, like ty-tabs: steps sit side by side and the row slides. A flex\n * row is as tall as its tallest step, so the wizard doesn't jump between\n * steps (the height attribute overrides). */\n.panels-wrapper {\n display: flex;\n height: 100%;\n transform: translateX(calc(var(--ty-wizard-active-index, 0) * -100%));\n transition: transform var(--ty-wizard-transition-duration) var(--ty-wizard-transition-easing);\n will-change: transform;\n}\n\n::slotted(ty-step) {\n flex: 0 0 100%;\n min-width: 0;\n transition: visibility 0s linear 0s;\n}\n\n/* Off-screen steps leave the tab order once the slide has finished. */\n::slotted(ty-step:not([data-active=\"true\"])) {\n visibility: hidden;\n pointer-events: none;\n transition: visibility 0s linear var(--ty-wizard-transition-duration);\n}\n\n@media (prefers-reduced-motion: reduce) {\n .panels-wrapper,\n ::slotted(ty-step),\n ::slotted(ty-step:not([data-active=\"true\"])),\n .step-circle,\n .compact-segment,\n .step-indicator::after {\n transition-duration: 0ms !important;\n transition-delay: 0ms !important;\n }\n}\n\n.sr-only {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border-width: 0;\n}\n`;\n","/**\n * Wizard Component — stepper with an inline indicator rail (compact\n * \"Step N of M\" header in narrow containers), sliding panels (carousel, like\n * ty-tabs), and step completion tracking. Expects `ty-step` children.\n * \"Dumb\" like ty-tabs: it renders and fires events; all navigation and\n * validation is the consumer's.\n */\n\nimport { ensureStyles } from '../utils/styles.js';\nimport { wizardStyles } from '../styles/wizard.js';\n\n/**\n * Wizard container attributes configuration\n */\nexport interface WizardAttributes {\n width: string; // Wizard width (px or %)\n height: string; // Panel height; empty = tallest step\n active: string | null; // ID of currently active step\n completed: string; // Comma-separated IDs of completed steps\n orientation: 'horizontal' | 'vertical'; // Rail on top, or on the left\n}\n\n/**\n * Wizard step change event detail\n */\nexport interface WizardStepChangeDetail {\n activeId: string; // ID of newly active step\n activeIndex: number; // Index of newly active step\n previousId: string | null; // ID of previously active step (null if first render)\n previousIndex: number | null; // Index of previously active step\n direction: 'forward' | 'backward' | 'none'; // Direction of navigation\n}\n\nconst eventHandlers = new WeakMap<TyWizard, {\n stepClickHandlers: Map<string, (e: Event) => void>;\n}>();\n\nfunction getWizardAttributes(el: TyWizard): WizardAttributes {\n return {\n width: el.getAttribute('width') || '100%',\n height: el.getAttribute('height') || '',\n active: el.getAttribute('active'),\n completed: el.getAttribute('completed') || '',\n orientation: (el.getAttribute('orientation') || 'horizontal') as 'horizontal' | 'vertical',\n };\n}\n\nfunction getChildSteps(el: TyWizard): HTMLElement[] {\n return Array.from(el.querySelectorAll('ty-step'));\n}\n\nfunction getStepId(step: HTMLElement): string | null {\n return step.getAttribute('id');\n}\n\nfunction getCompletedStepIds(el: TyWizard): Set<string> {\n const completedAttr = el.getAttribute('completed') || '';\n if (!completedAttr.trim()) return new Set();\n return new Set(completedAttr.split(',').map(id => id.trim()).filter(Boolean));\n}\n\n/**\n * Check if wizard has a direct child indicator slot for this step-id.\n * Looks in ty-wizard's light DOM for slot='indicator-{step-id}' elements.\n */\nfunction hasCustomIndicator(wizardEl: TyWizard, stepId: string): boolean {\n return wizardEl.querySelector(`[slot='indicator-${stepId}']`) !== null;\n}\n\nfunction isStepDisabled(step: HTMLElement): boolean {\n return step.hasAttribute('disabled');\n}\n\nfunction findStepIndex(steps: HTMLElement[], stepId: string): number | undefined {\n const index = steps.findIndex(step => getStepId(step) === stepId);\n return index >= 0 ? index : undefined;\n}\n\n/** Active step ID, defaulting to the first step if not specified. */\nfunction getActiveStepId(el: TyWizard, steps: HTMLElement[]): string | null {\n const activeAttr = el.getAttribute('active');\n\n if (activeAttr && findStepIndex(steps, activeAttr) !== undefined) {\n return activeAttr;\n }\n\n // Default to first step\n if (steps.length > 0) {\n return getStepId(steps[0]);\n }\n\n return null;\n}\n\nfunction setActiveStep(el: TyWizard, stepId: string): void {\n el.setAttribute('active', stepId);\n}\n\nfunction dispatchStepChangeEvent(\n el: TyWizard,\n activeId: string,\n activeIndex: number,\n previousId: string | null,\n previousIndex: number | null\n): void {\n const direction = previousIndex === null ? 'none'\n : activeIndex > previousIndex ? 'forward'\n : activeIndex < previousIndex ? 'backward'\n : 'none';\n\n const event = new CustomEvent<WizardStepChangeDetail>('ty-wizard-step-change', {\n detail: {\n activeId,\n activeIndex,\n previousId,\n previousIndex,\n direction,\n },\n bubbles: true,\n cancelable: false,\n });\n el.dispatchEvent(event);\n}\n\n/** Step indicator click — only dispatches an event; it never navigates. */\nfunction handleStepClick(el: TyWizard, stepId: string, event: Event): void {\n event.preventDefault();\n event.stopPropagation();\n\n const steps = getChildSteps(el);\n const targetIndex = steps.findIndex(s => getStepId(s) === stepId);\n if (targetIndex < 0) return;\n\n const currentActive = getActiveStepId(el, steps);\n const currentIndex = currentActive ? findStepIndex(steps, currentActive) ?? null : null;\n\n // Just dispatch event - user handles the actual navigation\n const direction = currentIndex === null ? 'none'\n : targetIndex > currentIndex ? 'forward'\n : targetIndex < currentIndex ? 'backward'\n : 'none';\n\n const event2 = new CustomEvent<WizardStepChangeDetail>('ty-wizard-step-change', {\n detail: {\n activeId: stepId,\n activeIndex: targetIndex,\n previousId: currentActive,\n previousIndex: currentIndex,\n direction,\n },\n bubbles: true,\n cancelable: false,\n });\n el.dispatchEvent(event2);\n}\n\nfunction cleanupEventListeners(el: TyWizard): void {\n const handlers = eventHandlers.get(el);\n if (!handlers) return;\n\n const shadowRoot = el.shadowRoot;\n if (!shadowRoot) return;\n\n handlers.stepClickHandlers.forEach((handler, stepId) => {\n const button = shadowRoot.querySelector<HTMLButtonElement>(`[data-step-id='${stepId}']`);\n if (button) {\n button.removeEventListener('pointerdown', handler);\n button.removeEventListener('click', handler);\n }\n });\n\n handlers.stepClickHandlers.clear();\n}\n\nfunction setupEventListeners(el: TyWizard, shadowRoot: ShadowRoot, steps: HTMLElement[]): void {\n cleanupEventListeners(el);\n\n const handlers = {\n stepClickHandlers: new Map<string, (e: Event) => void>(),\n };\n\n steps.forEach((step) => {\n const stepId = getStepId(step);\n if (!stepId) return;\n\n const button = shadowRoot.querySelector<HTMLButtonElement>(`[data-step-id='${stepId}']`);\n if (button) {\n // pointerdown for pointers; click only when it came from the keyboard\n // (Enter/Space report detail 0), so a mouse click doesn't fire twice.\n const handler = (e: Event) => {\n if (e.type === 'click' && (e as MouseEvent).detail !== 0) return;\n handleStepClick(el, stepId, e);\n };\n button.addEventListener('pointerdown', handler);\n button.addEventListener('click', handler);\n handlers.stepClickHandlers.set(stepId, handler);\n }\n });\n\n eventHandlers.set(el, handlers);\n}\n\n/** Update ARIA/state attributes on step indicators without re-rendering. */\nfunction updateStepIndicators(el: TyWizard, shadowRoot: ShadowRoot, activeId: string): void {\n const steps = getChildSteps(el);\n const completedIds = getCompletedStepIds(el);\n steps.forEach((step) => {\n const stepId = getStepId(step);\n if (!stepId) return;\n\n const button = shadowRoot.querySelector<HTMLButtonElement>(`[data-step-id='${stepId}']`);\n const circle = shadowRoot.querySelector<HTMLElement>(`[data-step-id='${stepId}'] .step-circle`);\n const isActive = stepId === activeId;\n\n if (button) {\n button.setAttribute('aria-selected', String(isActive));\n button.setAttribute('tabindex', isActive ? '0' : '-1');\n button.setAttribute('data-active', String(isActive));\n }\n\n // Same status logic as rendering (respects the step's status attribute)\n const state = getStepStatus(step, stepId, activeId, completedIds);\n button?.setAttribute('data-state', state);\n circle?.setAttribute('data-state', state);\n\n const slottedIndicator = el.querySelector(`[slot='indicator-${stepId}']`);\n if (slottedIndicator) {\n slottedIndicator.setAttribute('data-active', String(isActive));\n }\n });\n}\n\n/** Mark the active panel. data-active hides off-screen steps (wizard CSS) and\n * framework conditional rendering. */\nfunction updatePanelInteraction(el: TyWizard, activeId: string): void {\n getChildSteps(el).forEach((step) => {\n const stepId = getStepId(step);\n if (!stepId) return;\n step.setAttribute('data-active', String(stepId === activeId));\n });\n}\n\n/**\n * Update only the active step state without re-rendering DOM.\n * This is called when only the active or completed attribute changes.\n */\nfunction updateActiveStepState(el: TyWizard, stepId: string): void {\n const steps = getChildSteps(el);\n const shadowRoot = el.shadowRoot;\n if (!shadowRoot) return;\n\n const currentActive = getActiveStepId(el, steps);\n const currentIndex = currentActive ? findStepIndex(steps, currentActive) : undefined;\n const newIndex = findStepIndex(steps, stepId);\n\n // Only update if different step and valid\n if (currentActive === stepId || newIndex === undefined) return;\n\n el.style.setProperty('--ty-wizard-active-index', String(newIndex));\n updateStepIndicators(el, shadowRoot, stepId);\n updatePanelInteraction(el, stepId);\n\n // Reset scroll position of new active panel\n const newPanel = steps[newIndex] as any;\n if (newPanel?.resetScroll) {\n newPanel.resetScroll();\n }\n\n dispatchStepChangeEvent(\n el,\n stepId,\n newIndex,\n currentActive,\n currentIndex ?? null\n );\n}\n\n/** Step status: the explicit `status` attribute wins, otherwise it's derived. */\nfunction getStepStatus(step: HTMLElement, stepId: string, activeId: string | null, completedIds: Set<string>): string {\n const explicitStatus = step.getAttribute('status');\n if (explicitStatus && ['completed', 'active', 'pending', 'error'].includes(explicitStatus)) {\n return explicitStatus;\n }\n\n const isActive = stepId === activeId;\n const isCompleted = completedIds.has(stepId);\n // Active wins: revisiting a finished step shows where you are.\n return isActive ? 'active' : isCompleted ? 'completed' : 'pending';\n}\n\nconst CHECK_SVG = `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"3\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"><polyline points=\"20 6 9 17 4 12\"></polyline></svg>`;\nconst ALERT_SVG = `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"3\" stroke-linecap=\"round\" aria-hidden=\"true\"><line x1=\"12\" y1=\"5\" x2=\"12\" y2=\"13\"></line><line x1=\"12\" y1=\"18.5\" x2=\"12\" y2=\"18.6\"></line></svg>`;\n\nconst STATE_TEXT: Record<string, string> = {\n completed: 'completed',\n active: 'current',\n pending: 'not started',\n error: 'has an error',\n};\n\nfunction renderStepIndicators(wizardEl: TyWizard, steps: HTMLElement[], activeId: string | null, completedIds: Set<string>): string {\n const total = steps.length;\n const activeIndex = Math.max(0, activeId ? steps.findIndex(s => getStepId(s) === activeId) : 0);\n\n const indicators = steps.map((step, index) => {\n const stepId = getStepId(step);\n if (!stepId) return '';\n\n const label = step.getAttribute('label') || `Step ${index + 1}`;\n const description = step.getAttribute('description') || '';\n const disabled = isStepDisabled(step);\n const isActive = stepId === activeId;\n const state = getStepStatus(step, stepId, activeId, completedIds);\n\n const circleContent = hasCustomIndicator(wizardEl, stepId)\n ? `<slot name=\"indicator-${stepId}\"></slot>`\n : state === 'completed' ? CHECK_SVG\n : state === 'error' ? ALERT_SVG\n : `<span aria-hidden=\"true\">${index + 1}</span>`;\n\n // No aria-controls: the button lives in shadow DOM, the panel (<ty-step>)\n // is light DOM — ARIA id-references don't resolve across a shadow-tree\n // boundary. role=tab + aria-selected here, aria-labelledby on the step.\n // The connector to the next step is this button's ::after, so the\n // tablist owns nothing but tabs.\n return `<button\n class=\"step-indicator\"\n role=\"tab\"\n type=\"button\"\n data-step-id=\"${stepId}\"\n id=\"step-${stepId}\"\n data-state=\"${state}\"\n data-done=\"${state === 'completed' || (state === 'active' && completedIds.has(stepId))}\"\n aria-selected=\"${isActive}\"\n tabindex=\"${isActive ? '0' : '-1'}\"\n data-active=\"${isActive}\"\n ${disabled ? 'disabled aria-disabled=\"true\"' : ''}\n >\n <span class=\"step-circle\" data-state=\"${state}\" part=\"step-circle\">${circleContent}</span>\n <span class=\"step-text\">\n <span class=\"step-label\">${label}</span>\n ${description ? `<span class=\"step-description\">${description}</span>` : ''}\n <span class=\"sr-only\">, step ${index + 1} of ${total}, ${STATE_TEXT[state] ?? state}</span>\n </span>\n </button>`;\n }).join('');\n\n // Compact header for narrow containers: \"Step N of M · Label\" + segments.\n const active = steps[activeIndex];\n const activeLabel = active ? (active.getAttribute('label') || `Step ${activeIndex + 1}`) : '';\n const activeDescription = active?.getAttribute('description') || '';\n const segments = steps.map((step) => {\n const stepId = getStepId(step) || '';\n return `<span class=\"compact-segment\" data-state=\"${getStepStatus(step, stepId, activeId, completedIds)}\"></span>`;\n }).join('');\n\n return `\n <div class=\"step-indicators-wrapper\" part=\"indicators-wrapper\">\n <div class=\"step-indicators\" role=\"tablist\" aria-label=\"Steps\">\n ${indicators}\n </div>\n <div class=\"step-compact\">\n <div class=\"compact-top\">\n <span class=\"compact-where\">\n <span class=\"compact-count\">Step ${total ? activeIndex + 1 : 0} of ${total}</span>\n <span class=\"compact-label\">${activeLabel}</span>\n </span>\n ${activeDescription ? `<span class=\"compact-description\">${activeDescription}</span>` : ''}\n </div>\n <div class=\"compact-segments\" part=\"progress\">${segments}</div>\n </div>\n </div>\n `;\n}\n\n/**\n * Render the wizard container with step indicators and panel viewport.\n * The indicator strip is rebuilt on every render; the panel viewport (and its\n * slot) is created once.\n */\nfunction render(el: TyWizard): void {\n const shadowRoot = el.shadowRoot;\n if (!shadowRoot) return;\n\n const { width, height } = getWizardAttributes(el);\n const steps = getChildSteps(el);\n const activeId = getActiveStepId(el, steps);\n const completedIds = getCompletedStepIds(el);\n\n // Each <ty-step> IS its tabpanel (single catch-all <slot> in the viewport)\n // — same pattern and rationale as ty-tabs.\n steps.forEach((step) => {\n const stepId = getStepId(step);\n if (!stepId) return;\n step.setAttribute('role', 'tabpanel');\n step.setAttribute('aria-labelledby', `step-${stepId}`);\n step.setAttribute('tabindex', '0');\n });\n\n ensureStyles(shadowRoot, { css: wizardStyles, id: 'ty-wizard' });\n\n el.style.setProperty('--ty-wizard-width', width);\n el.style.setProperty('--ty-wizard-active-index', String(Math.max(0, activeId ? steps.findIndex(s => getStepId(s) === activeId) : 0)));\n // height sizes the panels only; unset = the tallest step.\n if (height) el.style.setProperty('--ty-wizard-panel-height', height);\n else el.style.removeProperty('--ty-wizard-panel-height');\n\n let container = shadowRoot.querySelector('.wizard-container');\n let viewport = shadowRoot.querySelector('.panels-viewport');\n\n if (!container || !viewport) {\n shadowRoot.innerHTML = `\n <div class=\"wizard-container\">\n <div class=\"panels-viewport\" part=\"panels-container\">\n <div class=\"panels-wrapper\">\n <slot></slot>\n </div>\n </div>\n </div>\n `;\n container = shadowRoot.querySelector('.wizard-container')!;\n viewport = shadowRoot.querySelector('.panels-viewport')!;\n }\n\n shadowRoot.querySelector('.step-indicators-wrapper')?.remove();\n const tmp = document.createElement('div');\n tmp.innerHTML = renderStepIndicators(el, steps, activeId, completedIds);\n container.insertBefore(tmp.firstElementChild!, viewport);\n\n setupEventListeners(el, shadowRoot, steps);\n updateStepIndicators(el, shadowRoot, activeId || '');\n if (activeId) updatePanelInteraction(el, activeId);\n\n if (!resizeObservers.has(el)) {\n const ro = new ResizeObserver(() => updateCompact(el));\n ro.observe(el);\n resizeObservers.set(el, ro);\n // Label widths change once web fonts arrive; the host size doesn't.\n document.fonts?.ready.then(() => el.isConnected && updateCompact(el));\n }\n updateCompact(el);\n}\n\n/**\n * Collapse to the compact header when the rail doesn't fit: its natural\n * width (circles + full label text + minimum connectors) exceeds the header's\n * content box. Vertical wizards collapse under 360px, where rail + panel\n * side by side get cramped.\n */\nfunction updateCompact(el: TyWizard): void {\n const shadowRoot = el.shadowRoot;\n const container = shadowRoot?.querySelector<HTMLElement>('.wizard-container');\n const wrapper = shadowRoot?.querySelector<HTMLElement>('.step-indicators-wrapper');\n const rail = shadowRoot?.querySelector<HTMLElement>('.step-indicators');\n if (!container || !wrapper || !rail) return;\n\n let compact: boolean;\n if (el.getAttribute('orientation') === 'vertical') {\n compact = el.clientWidth < 360;\n } else {\n // Sum the parts: flex intrinsic sizing with flex-basis 0 undercounts.\n // Labels are overflow:hidden, so scrollWidth is their full text width.\n const buttons = Array.from(rail.querySelectorAll<HTMLElement>('.step-indicator'));\n const px = (v: string) => parseFloat(v) || 0;\n let natural = px(getComputedStyle(rail).columnGap) * Math.max(0, buttons.length - 1);\n buttons.forEach((b, i) => {\n const circle = b.querySelector<HTMLElement>('.step-circle');\n const texts = Array.from(b.querySelectorAll<HTMLElement>('.step-label, .step-description'));\n natural += (circle?.offsetWidth ?? 0) + px(getComputedStyle(b).columnGap)\n + Math.max(0, ...texts.map((t) => t.scrollWidth));\n if (i < buttons.length - 1) {\n const after = getComputedStyle(b, '::after');\n natural += px(getComputedStyle(b).columnGap) + px(after.minWidth) + px(after.marginLeft);\n }\n });\n const cs = getComputedStyle(wrapper);\n const available = wrapper.clientWidth - parseFloat(cs.paddingLeft) - parseFloat(cs.paddingRight);\n compact = natural > available + 0.5;\n }\n container.classList.toggle('compact', compact);\n}\n\nconst resizeObservers = new WeakMap<TyWizard, ResizeObserver>();\n\nfunction cleanup(el: TyWizard): void {\n cleanupEventListeners(el);\n resizeObservers.get(el)?.disconnect();\n resizeObservers.delete(el);\n}\n\n/**\n * TyWizard Web Component\n */\nexport class TyWizard extends HTMLElement {\n static get observedAttributes() {\n return ['width', 'height', 'active', 'completed', 'orientation'];\n }\n\n constructor() {\n super();\n this.attachShadow({ mode: 'open' });\n }\n\n private _childObserver: MutationObserver | null = null;\n private _childRenderQueued = false;\n\n connectedCallback() {\n render(this);\n\n // Frameworks add/remove ty-step children dynamically — the indicator\n // strip renders from light DOM, so watch it. Batched on a microtask;\n // render() only touches shadow DOM, so no observer feedback loop.\n this._childObserver = new MutationObserver((records) => {\n // Re-render for added/removed steps, and for attribute changes on a\n // direct ty-step child (status/label/description/disabled) — frameworks\n // may update a step's status after the wizard's own active/completed,\n // which left a stale indicator (e.g. an error X on a completed step).\n const relevant = records.some((r) =>\n (r.type === 'childList' && r.target === this) ||\n ((r.target as Element).tagName === 'TY-STEP' && (r.target as Element).parentElement === this));\n if (!relevant || this._childRenderQueued) return;\n this._childRenderQueued = true;\n queueMicrotask(() => {\n this._childRenderQueued = false;\n if (this.isConnected) render(this);\n });\n });\n this._childObserver.observe(this, {\n childList: true,\n subtree: true,\n attributes: true,\n attributeFilter: ['status', 'label', 'description', 'disabled'],\n });\n }\n\n disconnectedCallback() {\n this._childObserver?.disconnect();\n this._childObserver = null;\n cleanup(this);\n }\n\n attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null) {\n // Smart rendering: only full render when structural attributes change\n if (name === 'active') {\n if (newValue) {\n updateActiveStepState(this, newValue);\n }\n // Always call render after active change to update indicator states\n render(this);\n } else if (name === 'completed') {\n render(this);\n } else {\n render(this);\n }\n }\n}\n\n// Register the custom element\nif (!customElements.get('ty-wizard')) {\n customElements.define('ty-wizard', TyWizard);\n}\n","/**\n * Step Component Styles\n */\n\nimport { customScrollbarStyles } from './custom-scrollbar.js'\n\nexport const stepStyles = `\n:host {\n /* Panel height: the wizard's height attribute, or the content (auto). */\n height: var(--ty-wizard-panel-height, auto);\n display: block;\n box-sizing: border-box;\n}\n\n.step-wrapper {\n width: 100%;\n height: 100%;\n position: relative;\n overflow: hidden;\n}\n\n.step-panel {\n width: 100%;\n height: 100%;\n overflow: auto;\n box-sizing: border-box;\n}\n\n.step-panel.ty-custom-scroll {\n scrollbar-width: none;\n -ms-overflow-style: none;\n}\n\n.step-panel.ty-custom-scroll::-webkit-scrollbar {\n display: none;\n}\n\n.step-wrapper:hover .ty-scrollbar-track-y.has-overflow {\n opacity: 1;\n}\n\n${customScrollbarStyles}\n`;\n","/** Individual wizard step panel with custom scrollbar via CustomScrollbar utility. */\n\nimport { ensureStyles } from '../utils/styles.js';\nimport { stepStyles } from '../styles/step.js';\nimport { CustomScrollbar, isCustomScrollbarEnabled } from '../utils/custom-scrollbar.js';\n\nexport type StepStatus = 'completed' | 'active' | 'pending' | 'error';\n\nexport interface StepAttributes {\n id: string | null;\n label: string | null;\n description: string | null;\n disabled: boolean;\n status: StepStatus | null;\n}\n\nexport class TyStep extends HTMLElement {\n private _scrollbar: CustomScrollbar | null = null\n\n static get observedAttributes() {\n return ['id', 'label', 'description', 'disabled', 'status'];\n }\n\n constructor() {\n super();\n this.attachShadow({ mode: 'open' });\n }\n\n connectedCallback() {\n this._render();\n }\n\n disconnectedCallback() {\n this._destroyScrollbar();\n }\n\n attributeChangedCallback(_name: string, _oldValue: string | null, _newValue: string | null) {\n this._render();\n }\n\n private _render(): void {\n const shadowRoot = this.shadowRoot;\n if (!shadowRoot) return;\n\n const id = this.getAttribute('id');\n\n if (!shadowRoot.querySelector('.step-wrapper')) {\n ensureStyles(shadowRoot, { css: stepStyles, id: 'ty-step' });\n\n shadowRoot.innerHTML = `\n <div class=\"step-wrapper\"\n role=\"tabpanel\"\n ${id ? `id=\"panel-${id}\"` : ''}\n ${id ? `aria-labelledby=\"step-${id}\"` : ''}\n >\n <div class=\"step-panel\">\n <slot></slot>\n </div>\n </div>\n `;\n\n this._setupScrollbar();\n }\n }\n\n private _setupScrollbar(): void {\n const panel = this.shadowRoot?.querySelector('.step-panel') as HTMLElement;\n const wrapper = this.shadowRoot?.querySelector('.step-wrapper') as HTMLElement;\n if (!panel || !wrapper) return;\n\n if (!isCustomScrollbarEnabled()) return;\n\n panel.classList.add('ty-custom-scroll');\n this._scrollbar = new CustomScrollbar(panel, { vertical: true });\n\n if (this._scrollbar.trackY) {\n wrapper.appendChild(this._scrollbar.trackY);\n }\n }\n\n private _destroyScrollbar(): void {\n if (this._scrollbar) {\n this._scrollbar.trackY?.remove();\n this._scrollbar.destroy();\n this._scrollbar = null;\n }\n }\n\n resetScroll(): void {\n this._scrollbar?.scrollToTop(false);\n }\n}\n\nif (!customElements.get('ty-step')) {\n customElements.define('ty-step', TyStep);\n}\n","/** Calendar Month Styles */\n\nimport { FLAVORS } from \"../types/common.js\";\n\n/* Flavor rules set --calendar-month-* local vars, wired in as the fallback\n BEHIND every existing --ty-calendar-* public override (so those keep\n working exactly as before) and AHEAD of the hardcoded primary default.\n Doubles as the per-instance override API for a specific flavor: e.g.\n `ty-calendar-month { --calendar-month-accent: ... }`. Fallback flavor\n `fb` is used for custom flavors so missing tokens degrade to neutral. */\nconst calendarMonthFlavor = (f: string, fb?: string) => {\n const color = (s: string) =>\n fb\n ? `var(--ty-color-${f}${s}, var(--ty-color-${fb}${s}))`\n : `var(--ty-color-${f}${s})`;\n const solid = (s: string) =>\n fb\n ? `var(--ty-solid-${f}${s}, var(--ty-solid-${fb}${s}))`\n : `var(--ty-solid-${f}${s})`;\n /* Selected is a solid fill on the same tokens as a solid button, so a\n selected day and a primary button always match. Hover for the +/-\n tones (no dedicated -hover token) mixes the fill toward its own\n foreground: darker in light mode, lighter in dark mode. */\n return `\n:host([flavor=\"${f}\"]) {\n --calendar-month-accent: ${color(\"\")};\n --calendar-month-selected-bg: ${solid(\"\")};\n --calendar-month-selected-color: ${solid(\"-fg\")};\n --calendar-month-selected-hover-bg: ${solid(\"-hover\")};\n}\n:host([flavor=\"${f}+\"]) {\n --calendar-month-accent: ${color(\"-strong\")};\n --calendar-month-selected-bg: ${solid(\"-strong\")};\n --calendar-month-selected-color: ${solid(\"-strong-fg\")};\n --calendar-month-selected-hover-bg: color-mix(in oklab, ${solid(\"-strong\")} 85%, ${solid(\"-strong-fg\")});\n}\n:host([flavor=\"${f}-\"]) {\n --calendar-month-accent: ${color(\"-soft\")};\n --calendar-month-selected-bg: ${solid(\"-soft\")};\n --calendar-month-selected-color: ${solid(\"-soft-fg\")};\n --calendar-month-selected-hover-bg: color-mix(in oklab, ${solid(\"-soft\")} 85%, ${solid(\"-soft-fg\")});\n}\n`;\n};\n\n/** Built-in flavor rules — also used by ty-calendar's month/year grid, so\n the selected month and the selected day share one fill. */\nexport const calendarMonthFlavorCss = FLAVORS.map((f) => calendarMonthFlavor(f)).join(\"\");\n\n/** Rules for one custom (non-built-in) flavor — see utils/flavor-sheet.ts. */\nexport const calendarMonthCustomFlavorCss = (base: string) => calendarMonthFlavor(base, \"neutral\");\n\nexport const calendarMonthStyles = `\n/* Theming tokens are applied as var(--ty-calendar-*, <default>) at point\n of use (not declared on :host) so consumers can override any of them\n from outside the shadow root. The 3 accent aliases — --ty-calendar-accent,\n --ty-calendar-today-accent, --ty-calendar-muted — still cascade into the\n derived defaults, so overriding one retints the related cells. */\n\n.calendar-flex-container {\n display: flex;\n flex-direction: column;\n box-sizing: border-box;\n gap: 0;\n padding: 0.75rem;\n border-radius: var(--ty-radius-md);\n font-family: inherit;\n user-select: none;\n width: var(--calendar-width, fit-content);\n /* Same public knob the nav reads — one value sizes the whole calendar. */\n min-width: var(--ty-calendar-width, 280px);\n max-width: var(--calendar-max-width, none);\n}\n\n/* Rows: header + 6 day rows */\n.calendar-row {\n display: flex;\n flex: 1;\n min-height: 0;\n}\n\n.calendar-header-row {\n flex: 0 0 auto;\n color: var(--ty-calendar-header-color, var(--ty-color-neutral-soft));\n}\n\n.calendar-day-row {\n flex: 1;\n min-height: 2rem;\n margin-bottom: 0.125rem;\n}\n\n.calendar-cell {\n flex: 1;\n display: flex;\n align-items: center;\n justify-content: center;\n min-width: 0;\n position: relative;\n box-sizing: border-box;\n}\n\n.calendar-header-cell {\n text-align: center;\n font-weight: 500;\n padding: 0.25rem;\n}\n\n.calendar-day-cell {\n aspect-ratio: 1;\n\n display: flex;\n align-items: center;\n justify-content: center;\n flex-direction: column;\n\n margin: 0.125rem;\n\n /* Visual: ghost cells — no boxes; the border is a theming hook only */\n border-radius: var(--ty-calendar-day-radius, 0.5rem);\n border: 1px solid var(--ty-calendar-day-border, transparent);\n background-color: var(--ty-calendar-day-bg, transparent);\n color: var(--ty-calendar-day-color, var(--ty-calendar-muted, var(--ty-text)));\n cursor: pointer;\n transition: var(--ty-local-transition, background-color 0.15s ease, color 0.15s ease);\n\n font-weight: 400;\n font-variant-numeric: tabular-nums;\n}\n\n/* Hover: a visible neutral pill, no border flash */\n.calendar-day-cell:hover {\n color: var(--ty-calendar-day-hover-color, var(--ty-text-strong));\n background-color: var(--ty-calendar-day-hover-bg, var(--ty-bg-neutral));\n border-color: var(--ty-calendar-day-hover-border, transparent);\n font-weight: 500;\n}\n\n/* Keyboard focus ring (roving tabindex — see calendar-month.ts's render()).\n :focus-visible, not :focus, so mouse/pointerdown activation doesn't flash\n a ring; only Tab-in / arrow-key navigation does. */\n.calendar-day-cell:focus-visible {\n outline: none;\n box-shadow: 0 0 0 2px var(--calendar-month-accent, var(--ty-color-primary));\n}\n\n/* Today: accent number plus a dot under it (built-in content only). The dot\n is currentColor, so it turns light on the selected fill. */\n.calendar-day-cell.today {\n background-color: var(--ty-calendar-today-bg, transparent);\n color: var(--ty-calendar-today-color, var(--ty-calendar-today-accent, var(--calendar-month-accent, var(--ty-color-primary))));\n border-color: var(--ty-calendar-today-border, transparent);\n font-weight: 600;\n}\n\n.calendar-day-cell.today:hover {\n background-color: var(--ty-calendar-day-hover-bg, var(--ty-bg-neutral));\n}\n\n.calendar-day-cell.today.default-content::after {\n content: \"\";\n position: absolute;\n /* Anchored to the number (em), not the cell, so the gap holds at every size */\n top: calc(50% + 0.72em);\n left: 50%;\n width: 4px;\n height: 4px;\n margin-left: -2px;\n border-radius: 50%;\n background: currentColor;\n}\n\n/* Weekend: no distinction by default (hook kept for theming) */\n.calendar-day-cell.weekend {\n color: var(--ty-calendar-weekend-color, var(--ty-calendar-day-color, var(--ty-text)));\n}\n\n/* Other month: recedes at rest, comes back on hover. Deliberately below the\n 4.5:1 text minimum — these days are secondary context (the current month\n is the content), and they stay clickable. Override with\n --ty-calendar-other-month-color for a stronger value. */\n.calendar-day-cell.other-month {\n color: var(--ty-calendar-other-month-color, color-mix(in oklab, var(--ty-text-faint) 65%, transparent));\n}\n\n.calendar-day-cell.other-month:hover {\n color: var(--ty-calendar-day-hover-color, var(--ty-text-soft, var(--ty-text-)));\n background-color: var(--ty-calendar-day-hover-bg, var(--ty-bg-neutral-soft));\n}\n\n/* Disabled - outside min/max bounds */\n/* Out of min/max range: still legible (so the range reads at a glance),\n struck through so it can't be mistaken for an adjacent-month day. */\n.calendar-day-cell.disabled {\n color: var(--ty-calendar-disabled-color, var(--ty-text-faint));\n opacity: var(--ty-calendar-disabled-opacity, 0.7);\n text-decoration: line-through;\n text-decoration-color: color-mix(in oklab, currentColor 60%, transparent);\n cursor: default;\n pointer-events: none;\n}\n\n/* Selected: the one strong element in the grid — a solid fill on the solid\n button tokens. Override order: --ty-calendar-selected-bg, then\n --ty-calendar-accent, then flavor, then primary. Hover darkens the fill\n and keeps the shape (no border swap). */\n.calendar-day-cell.selected {\n background-color: var(--ty-calendar-selected-bg, var(--ty-calendar-accent, var(--calendar-month-selected-bg, var(--ty-solid-primary, var(--ty-color-primary)))));\n color: var(--ty-calendar-selected-color, var(--calendar-month-selected-color, var(--ty-solid-primary-fg, white)));\n border-color: var(--ty-calendar-selected-border, transparent);\n font-weight: 600;\n}\n\n.calendar-day-cell.selected:hover {\n background-color: var(--ty-calendar-selected-hover-bg, var(--calendar-month-selected-hover-bg, color-mix(in oklab, var(--ty-calendar-selected-bg, var(--ty-calendar-accent, var(--calendar-month-selected-bg, var(--ty-solid-primary, var(--ty-color-primary))))) 85%, var(--ty-calendar-selected-color, var(--calendar-month-selected-color, var(--ty-solid-primary-fg, white))))));\n color: var(--ty-calendar-selected-color, var(--calendar-month-selected-color, var(--ty-solid-primary-fg, white)));\n border-color: var(--ty-calendar-selected-hover-border, var(--ty-calendar-selected-border, transparent));\n}\n\n.calendar-day-cell.selected.other-month {\n opacity: 0.7;\n}\n\n.calendar-size-sm {\n padding: 0.5rem;\n min-width: var(--ty-calendar-width, 240px);\n}\n\n.calendar-size-sm .calendar-header-cell {\n font-size: 0.625rem;\n padding: 0.125rem;\n}\n\n.calendar-size-sm .calendar-day-cell {\n font-size: 0.75rem;\n margin: 0.0625rem;\n}\n\n.calendar-size-sm .calendar-day-row {\n min-height: 1.5rem;\n}\n\n.calendar-size-md {\n padding: 0.75rem;\n min-width: var(--ty-calendar-width, 280px);\n}\n\n.calendar-size-md .calendar-header-cell {\n font-size: 0.6875rem;\n padding: 0.25rem;\n}\n\n.calendar-size-md .calendar-day-cell {\n font-size: 0.8125rem;\n margin: 0.125rem;\n}\n\n.calendar-size-md .calendar-day-row {\n min-height: 2rem;\n}\n\n.calendar-size-lg {\n padding: 1rem;\n min-width: var(--ty-calendar-width, 360px);\n}\n\n.calendar-size-lg .calendar-header-cell {\n font-size: 0.75rem;\n padding: 0.375rem;\n}\n\n.calendar-size-lg .calendar-day-cell {\n font-size: 0.875rem;\n margin: 0.1875rem;\n}\n\n.calendar-size-lg .calendar-day-row {\n min-height: 2.5rem;\n}\n\n/* Kept for backwards compatibility */\n.calendar-day {\n width: 100%;\n height: 100%;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n box-sizing: border-box;\n}\n\n/* Flavor variants set --calendar-month-*, consumed above */\n${calendarMonthFlavorCss}\n`;\n","/**\n * Calendar month generation and localization (native Date API only).\n *\n * Timestamps: `value` is UTC midnight (timezone-independent, for storage/server),\n * `localValue` is local midnight (for display/local math). Both denote the same\n * calendar date but are different moments in time.\n */\n\n/**\n * Rich context for a single calendar day\n * Contains all metadata needed for rendering and event handling\n */\nexport interface DayContext {\n /** Timestamp in milliseconds (UTC midnight) - use for server communication and storage */\n value: number;\n \n /** Timestamp in milliseconds (local midnight) - use for local calculations and display */\n localValue: number;\n \n /** Year (e.g., 2025) */\n year: number;\n \n /** Month (1-12, 1 = January) */\n month: number;\n \n /** Day of month (1-31) */\n dayInMonth: number;\n \n /** Is this a weekend day? (Saturday or Sunday) */\n weekend: boolean;\n \n /** Is this day from a different month? */\n otherMonth: boolean;\n \n /** Is this from the previous month? */\n prevMonth?: boolean;\n \n /** Is this from the next month? */\n nextMonth?: boolean;\n \n /** Is this today? */\n today?: boolean;\n \n /** Is this a holiday? (extensible for future use) */\n holiday?: boolean;\n \n /** Is this day selected? (from calendar's internal state) */\n isSelected?: boolean;\n \n /** Calendar's selected year (if any) */\n selectedYear?: number;\n \n /** Calendar's selected month (if any) */\n selectedMonth?: number;\n \n /** Calendar's selected day (if any) */\n selectedDay?: number;\n}\n\nfunction validateMonth(month: number): void {\n if (!Number.isInteger(month) || month < 1 || month > 12) {\n throw new RangeError(`Invalid month: ${month}. Must be an integer between 1 and 12.`);\n }\n}\n\nfunction validateYear(year: number): void {\n if (!Number.isInteger(year) || year < 1 || year > 9999) {\n throw new RangeError(`Invalid year: ${year}. Must be an integer between 1 and 9999.`);\n }\n}\n\n/** Same calendar day (ignoring time), in local timezone. */\nfunction isSameDay(date1: Date, date2: Date): boolean {\n return date1.getFullYear() === date2.getFullYear()\n && date1.getMonth() === date2.getMonth()\n && date1.getDate() === date2.getDate();\n}\n\n/** Create a date at midnight local time. */\nfunction createMidnightDate(year: number, month: number, day: number): Date {\n return new Date(year, month - 1, day, 0, 0, 0, 0);\n}\n\n/** Today at midnight local time. */\nfunction getTodayMidnight(): Date {\n const now = new Date();\n return new Date(now.getFullYear(), now.getMonth(), now.getDate(), 0, 0, 0, 0);\n}\n\n/**\n * Create a DayContext from a Date object\n * \n * @param date - The date to create context for (should be at midnight)\n * @param targetYear - The year of the calendar month being displayed\n * @param targetMonth - The month (1-12) of the calendar month being displayed\n * @param selection - Optional selection state from calendar\n * @returns Rich day context with metadata\n */\nfunction createDayContext(\n date: Date,\n targetYear: number,\n targetMonth: number,\n selection?: { year?: number; month?: number; day?: number }\n): DayContext {\n const year = date.getFullYear();\n const month = date.getMonth() + 1; // Convert to 1-based\n const dayInMonth = date.getDate();\n const dayOfWeek = date.getDay(); // 0 = Sunday, 6 = Saturday\n\n const isOtherMonth = year !== targetYear || month !== targetMonth;\n\n let isPrevMonth = false;\n let isNextMonth = false;\n \n if (isOtherMonth) {\n if (year < targetYear || (year === targetYear && month < targetMonth)) {\n isPrevMonth = true;\n } else {\n isNextMonth = true;\n }\n }\n \n // Compare at midnight for consistency\n const todayMidnight = getTodayMidnight();\n const isToday = isSameDay(date, todayMidnight);\n\n const isSelected = selection?.year === year\n && selection?.month === month\n && selection?.day === dayInMonth;\n\n // value: UTC midnight (consistent worldwide for the same date)\n // localValue: Local midnight (respects user's timezone)\n const utcValue = Date.UTC(year, month - 1, dayInMonth, 0, 0, 0, 0);\n const localValue = date.getTime();\n \n return {\n value: utcValue,\n localValue,\n year,\n month,\n dayInMonth,\n weekend: dayOfWeek === 0 || dayOfWeek === 6,\n otherMonth: isOtherMonth,\n prevMonth: isPrevMonth,\n nextMonth: isNextMonth,\n today: isToday,\n isSelected,\n selectedYear: selection?.year,\n selectedMonth: selection?.month,\n selectedDay: selection?.day,\n };\n}\n\n/**\n * Get the Monday at or before a given date\n * (Monday = start of week in ISO 8601)\n * \n * @param date - Any date\n * @returns The Monday of that week at midnight\n */\nfunction getMondayOfWeek(date: Date): Date {\n const dayOfWeek = date.getDay(); // 0 = Sunday, 1 = Monday, etc.\n\n // Days to subtract to reach Monday; Sunday (0) wraps back 6 days\n const daysToMonday = dayOfWeek === 0 ? 6 : dayOfWeek - 1;\n\n const monday = new Date(date);\n monday.setDate(date.getDate() - daysToMonday);\n monday.setHours(0, 0, 0, 0); // Ensure midnight\n \n return monday;\n}\n\n/**\n * Get the start date for the calendar grid\n * (The Monday at or before the first day of the month)\n * \n * @param year - Year\n * @param month - Month (1-12)\n * @returns The Monday that starts the calendar grid\n */\nfunction getMonthGridStart(year: number, month: number): Date {\n // month is 1-based, Date constructor is 0-based\n const firstDay = createMidnightDate(year, month, 1);\n return getMondayOfWeek(firstDay);\n}\n\n/**\n * Add days to a date safely\n * Creates a new date without mutating the original\n * \n * @param date - Starting date\n * @param days - Number of days to add\n * @returns New date with days added\n */\nfunction addDays(date: Date, days: number): Date {\n const result = new Date(date);\n result.setDate(result.getDate() + days);\n return result;\n}\n\n/**\n * Generate N consecutive days starting from a date\n * \n * @param startDate - Starting date\n * @param count - Number of days to generate\n * @param targetYear - Year of the calendar month\n * @param targetMonth - Month (1-12) of the calendar month\n * @param selection - Optional selection state to include in day contexts\n * @returns Array of day contexts\n */\nfunction generateDays(\n startDate: Date,\n count: number,\n targetYear: number,\n targetMonth: number,\n selection?: { year?: number; month?: number; day?: number }\n): DayContext[] {\n const days: DayContext[] = [];\n \n for (let i = 0; i < count; i++) {\n const date = addDays(startDate, i);\n days.push(createDayContext(date, targetYear, targetMonth, selection));\n }\n \n return days;\n}\n\n/**\n * Generate a 42-day calendar grid for a given month\n * \n * Returns 6 weeks (42 days) starting from the Monday at or before\n * the first day of the month. This ensures a complete calendar view\n * with days from the previous and next months as needed.\n * \n * @param year - Year (e.g., 2025)\n * @param month - Month (1-12, 1 = January)\n * @param selection - Optional selection state to include in day contexts\n * @returns Array of 42 day contexts with rich metadata\n * \n * @throws {RangeError} If year or month are invalid\n * \n * @example\n * const days = getCalendarMonthDays(2025, 10); // October 2025\n * console.log(days.length); // 42\n * console.log(days[0].dayInMonth); // First day shown (might be from September)\n */\nexport function getCalendarMonthDays(\n year: number, \n month: number,\n selection?: { year?: number; month?: number; day?: number }\n): DayContext[] {\n validateYear(year);\n validateMonth(month);\n \n const startDate = getMonthGridStart(year, month);\n return generateDays(startDate, 42, year, month, selection);\n}\n\n/**\n * Get localized weekday names in Monday-first order\n * \n * Note: Intl.DateTimeFormat returns Sunday-first by default,\n * so we reorder to Monday-first: [Mon, Tue, Wed, Thu, Fri, Sat, Sun]\n * \n * @param locale - Locale string (e.g., \"en-US\", \"de-DE\", \"ja-JP\")\n * @param style - Display style: \"long\" (Monday), \"short\" (Mon), \"narrow\" (M)\n * @returns Array of 7 weekday names starting with Monday\n * \n * @example\n * getLocalizedWeekdays(\"en-US\", \"short\")\n * // Returns: [\"Mon\", \"Tue\", \"Wed\", \"Thu\", \"Fri\", \"Sat\", \"Sun\"]\n * \n * getLocalizedWeekdays(\"de-DE\", \"long\")\n * // Returns: [\"Montag\", \"Dienstag\", \"Mittwoch\", ...]\n */\nexport function getLocalizedWeekdays(\n locale: string,\n style: 'long' | 'short' | 'narrow' = 'short'\n): string[] {\n const formatter = new Intl.DateTimeFormat(locale, { weekday: style });\n \n // January 7, 2024 is a Sunday\n const sunday = new Date(2024, 0, 7);\n\n // Sunday-first array: [Sun, Mon, Tue, Wed, Thu, Fri, Sat]\n const sundayFirst = Array.from({ length: 7 }, (_, i) => {\n const date = addDays(sunday, i);\n return formatter.format(date);\n });\n \n // Reorder to Monday-first: [Mon, Tue, Wed, Thu, Fri, Sat, Sun]\n const [firstDay, ...rest] = sundayFirst;\n return [...rest, firstDay];\n}\n\n/**\n * Get month name in specified locale\n * \n * @param month - Month (1-12)\n * @param locale - Locale string\n * @param style - Display style\n * @returns Localized month name\n * \n * @throws {RangeError} If month is invalid\n */\nexport function getMonthName(\n month: number,\n locale: string = 'en-US',\n style: 'long' | 'short' | 'narrow' = 'long'\n): string {\n validateMonth(month);\n \n const date = new Date(2024, month - 1, 1);\n const formatter = new Intl.DateTimeFormat(locale, { month: style });\n return formatter.format(date);\n}\n\n/**\n * Parse an ISO date string (YYYY-MM-DD) into year, month, day components\n * \n * @param isoString - ISO date string (YYYY-MM-DD)\n * @returns Object with year, month (1-12), and day, or null if invalid\n * \n * @example\n * parseISODate(\"2025-10-13\")\n * // Returns: { year: 2025, month: 10, day: 13 }\n */\nexport function parseISODate(isoString: string): { year: number; month: number; day: number } | null {\n const match = isoString.match(/^(\\d{4})-(\\d{2})-(\\d{2})$/);\n if (!match) return null;\n \n const year = parseInt(match[1], 10);\n const month = parseInt(match[2], 10);\n const day = parseInt(match[3], 10);\n \n if (year < 1 || year > 9999) return null;\n if (month < 1 || month > 12) return null;\n if (day < 1 || day > 31) return null;\n \n // Check if date is valid (handles Feb 30, etc.)\n const date = new Date(year, month - 1, day);\n if (date.getFullYear() !== year || date.getMonth() !== month - 1 || date.getDate() !== day) {\n return null;\n }\n \n return { year, month, day };\n}\n\n","/**\n * TyCalendarMonth Web Component — a stateless, property-driven calendar month\n * renderer (42-day grid, Monday-first) with customizable day content/styling.\n */\n\nimport { ensureStyles } from '../utils/styles.js';\nimport { liftProperties, upgradeProperties } from '../utils/upgrade-properties.js';\nimport { syncCustomFlavorSheet } from '../utils/flavor-sheet.js';\nimport { calendarMonthStyles, calendarMonthCustomFlavorCss } from '../styles/calendar-month.js';\nimport {\n getCalendarMonthDays,\n getLocalizedWeekdays,\n parseISODate,\n type DayContext\n} from '../utils/calendar-utils.js';\nimport { getEffectiveLocale, observeLocaleChanges } from '../utils/locale.js';\n\n/**\n * Calendar size variants\n */\nexport type CalendarSize = 'sm' | 'md' | 'lg';\n\n/**\n * Custom day content render function\n * Must return a DOM element or string\n */\nexport type DayContentFn = (dayContext: DayContext) => HTMLElement | string;\n\n/**\n * Day click event detail\n */\nexport interface DayClickDetail {\n dayContext: DayContext;\n value: number;\n year: number;\n month: number;\n day: number;\n isHoliday?: boolean;\n isToday?: boolean;\n isWeekend: boolean;\n isOtherMonth: boolean;\n}\n\nfunction defaultDayContent(dayContext: DayContext): string {\n return dayContext.dayInMonth.toString();\n}\n\nfunction getDefaultDayClasses(dayContext: DayContext): string[] {\n const classes = ['calendar-day'];\n\n if (dayContext.today) classes.push('today');\n if (dayContext.weekend) classes.push('weekend');\n if (dayContext.otherMonth) classes.push('other-month');\n if (dayContext.isSelected) classes.push('selected');\n\n return classes;\n}\n\nfunction isDOMElement(value: unknown): value is HTMLElement {\n return value instanceof HTMLElement;\n}\n\n/**\n * ISO date string (\"YYYY-MM-DD\") → UTC-midnight timestamp, matching\n * DayContext.value semantics. null when unset/invalid.\n */\nfunction isoToUTCTimestamp(iso: string | null | undefined): number | null {\n if (!iso) return null;\n const parsed = parseISODate(iso);\n if (!parsed) return null;\n return Date.UTC(parsed.year, parsed.month - 1, parsed.day);\n}\n\nfunction normalizeSizeValue(value: string | number | null | undefined): string | null {\n if (!value || value === '') return null;\n\n const strValue = String(value);\n\n if (/^\\d+(\\.\\d+)?$/.test(strValue)) {\n return `${strValue}px`;\n }\n\n // Otherwise use as-is (supports %, rem, vw, etc.)\n return strValue;\n}\n\n/**\n * TyCalendarMonth Web Component\n */\nexport class TyCalendarMonth extends HTMLElement {\n private _displayYear: number;\n private _displayMonth: number;\n private _locale: string = 'en-US';\n private _size: CalendarSize = 'md';\n private _width?: string;\n private _minWidth?: string;\n private _maxWidth?: string;\n private _dayContentFn?: DayContentFn;\n private _customCSS?: CSSStyleSheet;\n private _value?: number; // Selected date as timestamp (from parent calendar)\n private _min?: string; // ISO date - days before this are disabled\n private _max?: string; // ISO date - days after this are disabled\n private _localeObserver?: () => void; // Cleanup function for locale observer\n private _customFlavorSheet: CSSStyleSheet | null = null;\n\n // ARIA grid roving-tabindex state — index into the flat 42-day array.\n // null means \"not yet resolved\"; render() picks a sensible default\n // (selected day, else today, else the 1st rendered day) and persists it\n // across re-renders so keyboard focus survives unrelated prop changes.\n // Reset to null on month/year navigation (see the property setters below)\n // so the new month gets a fresh default instead of a stale index.\n private _focusedIndex: number | null = null;\n private _cellElements: HTMLElement[] = [];\n\n /**\n * Observed attributes. `display-year`/`display-month` mirror the\n * displayYear/displayMonth properties (which are what ty-calendar drives).\n */\n static get observedAttributes(): string[] {\n return ['display-year', 'display-month', 'locale', 'size', 'min', 'max', 'flavor'];\n }\n\n constructor() {\n super();\n\n const today = new Date();\n this._displayYear = today.getFullYear();\n this._displayMonth = today.getMonth() + 1; // 1-based month\n\n this.attachShadow({ mode: 'open' });\n // display-year/display-month go through the setters (attributeChangedCallback)\n liftProperties(this);\n }\n\n connectedCallback() {\n if (!this._displayMonth) {\n this._displayMonth = new Date().getMonth() + 1;\n }\n if (!this._displayYear) {\n this._displayYear = new Date().getFullYear();\n }\n if (!this._locale) {\n this._locale = this.getAttribute('locale') || 'en-US';\n }\n const sizeAttr = this.getAttribute('size');\n if (sizeAttr && (sizeAttr === 'sm' || sizeAttr === 'md' || sizeAttr === 'lg')) {\n this._size = sizeAttr;\n }\n\n // After the attribute reads: a property set before upgrade wins\n upgradeProperties(this);\n\n // Setup locale observer to watch for ancestor lang changes\n this._localeObserver = observeLocaleChanges(this, () => {\n this.render();\n });\n\n this._syncCustomFlavor();\n this.render();\n }\n\n disconnectedCallback() {\n if (this._localeObserver) {\n this._localeObserver();\n this._localeObserver = undefined;\n }\n }\n\n attributeChangedCallback(name: string, _oldValue: string | null, newValue: string | null) {\n if (name === 'display-year' || name === 'display-month') {\n const n = Number(newValue);\n const valid = Number.isInteger(n) && (name === 'display-year' ? n > 0 : n >= 1 && n <= 12);\n if (valid) {\n if (name === 'display-year') this.displayYear = n;\n else this.displayMonth = n;\n }\n } else if (name === 'locale') {\n this._locale = newValue || 'en-US';\n this.render();\n } else if (name === 'size') {\n if (newValue === 'sm' || newValue === 'md' || newValue === 'lg') {\n this._size = newValue;\n this.render();\n }\n } else if (name === 'min' || name === 'max') {\n this[name === 'min' ? '_min' : '_max'] = newValue ?? undefined;\n this.render();\n } else if (name === 'flavor') {\n this._syncCustomFlavor();\n }\n }\n\n /**\n * Custom (non-built-in) flavors — the `flavor` attribute itself drives\n * built-in flavors directly via `:host([flavor=\"X\"])` CSS, no JS needed.\n * See utils/flavor-sheet.ts.\n */\n private _syncCustomFlavor(): void {\n this._customFlavorSheet = syncCustomFlavorSheet(\n this.shadowRoot!,\n this._customFlavorSheet,\n this.getAttribute('flavor'),\n ({ base }) => calendarMonthCustomFlavorCss(base),\n );\n }\n\n get displayYear(): number {\n return this._displayYear;\n }\n\n set displayYear(value: number) {\n if (this._displayYear !== value) {\n this._displayYear = value;\n this._focusedIndex = null;\n this.render();\n }\n }\n\n get displayMonth(): number {\n return this._displayMonth;\n }\n\n set displayMonth(value: number) {\n if (this._displayMonth !== value) {\n this._displayMonth = value;\n this._focusedIndex = null;\n this.render();\n }\n }\n\n get locale(): string {\n return getEffectiveLocale(this, this.getAttribute('locale'));\n }\n\n set locale(value: string) {\n if (this._locale !== value) {\n this._locale = value;\n this.render();\n }\n }\n\n get size(): CalendarSize {\n return this._size;\n }\n\n set size(value: CalendarSize) {\n if (this._size !== value) {\n this._size = value;\n this.render();\n }\n }\n\n get flavor(): string {\n return this.getAttribute('flavor') || 'primary';\n }\n\n set flavor(value: string) {\n if (value) this.setAttribute('flavor', value);\n else this.removeAttribute('flavor');\n }\n\n get width(): string | undefined {\n return this._width;\n }\n\n set width(value: string | undefined) {\n if (this._width !== value) {\n this._width = value;\n this.applyWidthProperties();\n }\n }\n\n get minWidth(): string | undefined {\n return this._minWidth;\n }\n\n set minWidth(value: string | undefined) {\n if (this._minWidth !== value) {\n this._minWidth = value;\n this.applyWidthProperties();\n }\n }\n\n get maxWidth(): string | undefined {\n return this._maxWidth;\n }\n\n set maxWidth(value: string | undefined) {\n if (this._maxWidth !== value) {\n this._maxWidth = value;\n this.applyWidthProperties();\n }\n }\n\n get dayContentFn(): DayContentFn | undefined {\n return this._dayContentFn;\n }\n\n set dayContentFn(fn: DayContentFn | undefined) {\n if (this._dayContentFn !== fn) {\n this._dayContentFn = fn;\n this.render();\n }\n }\n\n get customCSS(): CSSStyleSheet | undefined {\n return this._customCSS;\n }\n\n set customCSS(sheet: CSSStyleSheet | undefined) {\n if (this._customCSS !== sheet) {\n this._customCSS = sheet;\n this.applyCustomCSS();\n }\n }\n\n get min(): string | undefined {\n return this._min;\n }\n\n set min(value: string | undefined) {\n if (this._min !== value) {\n this._min = value;\n this.render();\n }\n }\n\n get max(): string | undefined {\n return this._max;\n }\n\n set max(value: string | undefined) {\n if (this._max !== value) {\n this._max = value;\n this.render();\n }\n }\n\n get value(): number | undefined {\n return this._value;\n }\n\n set value(timestamp: number | null | undefined) {\n const newValue = timestamp ?? undefined;\n if (this._value !== newValue) {\n this._value = newValue;\n this.render();\n }\n }\n\n /**\n * Apply width-related properties as CSS custom properties\n */\n private applyWidthProperties(): void {\n const normalizedWidth = normalizeSizeValue(this._width);\n const normalizedMinWidth = normalizeSizeValue(this._minWidth);\n const normalizedMaxWidth = normalizeSizeValue(this._maxWidth);\n\n if (normalizedWidth) {\n this.style.setProperty('--calendar-width', normalizedWidth);\n } else {\n this.style.removeProperty('--calendar-width');\n }\n\n if (normalizedMinWidth) {\n this.style.setProperty('--calendar-min-width', normalizedMinWidth);\n } else {\n this.style.removeProperty('--calendar-min-width');\n }\n\n if (normalizedMaxWidth) {\n this.style.setProperty('--calendar-max-width', normalizedMaxWidth);\n } else {\n this.style.removeProperty('--calendar-max-width');\n }\n }\n\n private applyCustomCSS(): void {\n if (!this._customCSS || !this.shadowRoot) return;\n\n const existing = this.shadowRoot.adoptedStyleSheets;\n if (!existing.includes(this._customCSS)) {\n this.shadowRoot.adoptedStyleSheets = [...existing, this._customCSS];\n }\n }\n\n /**\n * Force re-render of the calendar month\n * Useful when external data changes (e.g., async event loading)\n */\n refresh(): void {\n this.render();\n }\n\n private dispatchDayClick(dayContext: DayContext, _domEvent: Event): void {\n const detail: DayClickDetail = {\n dayContext,\n value: dayContext.value,\n year: dayContext.year,\n month: dayContext.month,\n day: dayContext.dayInMonth,\n isHoliday: dayContext.holiday,\n isToday: dayContext.today,\n isWeekend: dayContext.weekend,\n isOtherMonth: dayContext.otherMonth,\n };\n\n // Dispatch both 'day-click' and 'day-select' (alias)\n for (const eventType of ['day-click', 'day-select']) {\n const event = new CustomEvent(eventType, {\n detail,\n bubbles: true,\n cancelable: true,\n });\n this.dispatchEvent(event);\n }\n }\n\n /**\n * WAI-ARIA grid pattern: gridcell + roving tabindex (exactly one cell in\n * the whole grid is tabindex=\"0\" at a time — the rest are -1, so Tab\n * enters/exits the grid in one hop and arrow keys move focus inside it).\n * Disabled days are excluded from the roving set entirely.\n */\n private renderDayCell(dayContext: DayContext, disabled: boolean, isRoving: boolean): HTMLElement {\n const dayElement = document.createElement('div');\n\n const content = this._dayContentFn\n ? this._dayContentFn(dayContext)\n : defaultDayContent(dayContext);\n\n if (this._dayContentFn && content && !isDOMElement(content) && typeof content !== 'string') {\n throw new Error(\n `Custom dayContentFn must return a DOM element or string, got: ${typeof content}. ` +\n `Use document.createElement() to create DOM elements.`\n );\n }\n\n const classes = getDefaultDayClasses(dayContext);\n if (disabled) classes.push('disabled');\n // Built-in content only: styles like the today dot assume a bare number.\n if (!this._dayContentFn) classes.push('default-content');\n dayElement.className = classes.join(' ');\n\n if (typeof content === 'string') {\n dayElement.textContent = content;\n } else if (isDOMElement(content)) {\n dayElement.appendChild(content);\n }\n\n dayElement.setAttribute('role', 'gridcell');\n dayElement.setAttribute(\n 'aria-label',\n new Intl.DateTimeFormat(this._locale, { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' })\n .format(new Date(dayContext.localValue)),\n );\n dayElement.setAttribute('aria-selected', String(!!dayContext.isSelected));\n if (dayContext.today) dayElement.setAttribute('aria-current', 'date');\n\n if (disabled) {\n dayElement.setAttribute('aria-disabled', 'true');\n dayElement.setAttribute('tabindex', '-1');\n } else {\n dayElement.setAttribute('tabindex', isRoving ? '0' : '-1');\n // 'click', not pointerdown: click fires for a tap but not for a finger\n // drag, so scrolling the page over an inline calendar neither picks the\n // day under the finger nor gets cancelled by the re-render a pick\n // triggers. Disabled days don't emit.\n dayElement.addEventListener('click', (event: Event) => {\n this.dispatchDayClick(dayContext, event);\n });\n dayElement.addEventListener('keydown', (event: Event) => {\n const ke = event as KeyboardEvent;\n if (ke.key === 'Enter' || ke.key === ' ') {\n ke.preventDefault();\n this.dispatchDayClick(dayContext, event);\n }\n });\n }\n\n return dayElement;\n }\n\n private render(): void {\n const root = this.shadowRoot;\n if (!root) return;\n\n ensureStyles(root, { css: calendarMonthStyles, id: 'ty-calendar-month' });\n\n this.applyCustomCSS();\n\n this.applyWidthProperties();\n\n let selection: { year?: number; month?: number; day?: number } | undefined;\n if (this._value) {\n const date = new Date(this._value);\n selection = {\n year: date.getFullYear(),\n month: date.getMonth() + 1, // Convert to 1-based\n day: date.getDate()\n };\n }\n\n const days = getCalendarMonthDays(this._displayYear, this._displayMonth, selection);\n\n const weekdays = getLocalizedWeekdays(this._locale, 'short');\n\n root.innerHTML = '';\n\n const calendarContainer = document.createElement('div');\n calendarContainer.className = `calendar-flex-container calendar-size-${this._size}`;\n calendarContainer.setAttribute('role', 'grid');\n calendarContainer.setAttribute(\n 'aria-label',\n new Intl.DateTimeFormat(this._locale, { month: 'long', year: 'numeric' })\n .format(new Date(this._displayYear, this._displayMonth - 1, 1)),\n );\n\n const headerRow = document.createElement('div');\n headerRow.className = 'calendar-row calendar-header-row';\n headerRow.setAttribute('role', 'row');\n\n weekdays.forEach(weekday => {\n const headerCell = document.createElement('div');\n headerCell.className = 'calendar-cell calendar-header-cell';\n headerCell.setAttribute('role', 'columnheader');\n headerCell.textContent = weekday;\n headerRow.appendChild(headerCell);\n });\n\n calendarContainer.appendChild(headerRow);\n\n const dayWeeks: DayContext[][] = [];\n for (let i = 0; i < 42; i += 7) {\n dayWeeks.push(days.slice(i, i + 7));\n }\n\n // Bounds for disabling days (UTC-midnight, same space as DayContext.value)\n const minTs = isoToUTCTimestamp(this._min);\n const maxTs = isoToUTCTimestamp(this._max);\n\n // Roving-tabindex target: keep the persisted index if still valid and\n // not disabled, else fall back to selected day, else today, else the\n // first rendered day — always something focusable exists in the grid.\n const disabledAt = (i: number) => {\n const v = days[i].value;\n return (minTs !== null && v < minTs) || (maxTs !== null && v > maxTs);\n };\n const firstEnabled = (pred: (i: number) => boolean): number => {\n for (let i = 0; i < 42; i++) {\n if (pred(i) && !disabledAt(i)) return i;\n }\n return -1;\n };\n let defaultIndex = firstEnabled(i => !!days[i].isSelected);\n // Only \"selected\" and \"today\" are meaningful enough to persist into\n // _focusedIndex — the arbitrary catch-all below exists purely so this\n // render always has SOMETHING to draw as tabindex=\"0\". Parent/child prop\n // sync (see calendar.ts syncChildComponents) pushes min/max and value in\n // separate steps, so a transient render can land here with no selection\n // yet; committing that arbitrary pick to _focusedIndex would make it\n // \"valid and enabled\" and permanently block the real selection, once it\n // arrives, from ever reclaiming the roving-focus slot.\n let provisional = false;\n if (defaultIndex === -1) defaultIndex = firstEnabled(i => !!days[i].today);\n if (defaultIndex === -1) {\n defaultIndex = firstEnabled(() => true);\n provisional = true;\n }\n if (defaultIndex === -1) defaultIndex = 0; // every day disabled — nothing focusable either way\n if (\n this._focusedIndex === null ||\n this._focusedIndex < 0 ||\n this._focusedIndex > 41 ||\n disabledAt(this._focusedIndex)\n ) {\n this._focusedIndex = provisional ? null : defaultIndex;\n }\n const effectiveFocusedIndex = this._focusedIndex ?? defaultIndex;\n\n this._cellElements = [];\n let flatIndex = 0;\n dayWeeks.forEach(week => {\n const dayRow = document.createElement('div');\n dayRow.className = 'calendar-row calendar-day-row';\n dayRow.setAttribute('role', 'row');\n\n week.forEach(dayContext => {\n const disabled =\n (minTs !== null && dayContext.value < minTs) ||\n (maxTs !== null && dayContext.value > maxTs);\n const dayCell = this.renderDayCell(dayContext, disabled, flatIndex === effectiveFocusedIndex);\n dayCell.className = `${dayCell.className} calendar-cell calendar-day-cell`;\n dayRow.appendChild(dayCell);\n this._cellElements[flatIndex] = dayCell;\n flatIndex++;\n });\n\n calendarContainer.appendChild(dayRow);\n });\n\n // Arrow-key roving-tabindex navigation: Left/Right move a day,\n // Up/Down move a week — pure index arithmetic works because `days` is a\n // flat, chronologically-ordered 42-cell array (Monday-first weeks), so\n // index+1 is always the next calendar day and index+7 the next week.\n // Delegated on the grid (one listener, not 42) — this component is\n // stateless about which month is shown, so moving past the rendered\n // 42-day range just clamps at the edge rather than crossing months.\n calendarContainer.addEventListener('keydown', (event: Event) => {\n const ke = event as KeyboardEvent;\n const delta =\n ke.key === 'ArrowLeft' ? -1 :\n ke.key === 'ArrowRight' ? 1 :\n ke.key === 'ArrowUp' ? -7 :\n ke.key === 'ArrowDown' ? 7 :\n 0;\n if (delta === 0) return;\n\n const currentIndex = this._focusedIndex ?? defaultIndex;\n const nextIndex = currentIndex + delta;\n if (nextIndex < 0 || nextIndex > 41 || disabledAt(nextIndex)) return;\n\n ke.preventDefault();\n this._cellElements[currentIndex]?.setAttribute('tabindex', '-1');\n this._focusedIndex = nextIndex;\n const nextCell = this._cellElements[nextIndex];\n if (nextCell) {\n nextCell.setAttribute('tabindex', '0');\n nextCell.focus();\n }\n });\n\n root.appendChild(calendarContainer);\n }\n}\n\nif (!customElements.get('ty-calendar-month')) {\n customElements.define('ty-calendar-month', TyCalendarMonth);\n}","/** Calendar Navigation Styles */\n\nexport const calendarNavigationStyles = `\n/* Theming tokens applied as var(--ty-calendar-nav-*, <default>) at point of\n use (NOT on :host) so consumers can override them from outside — this\n component is nested inside ty-calendar's shadow, so a :host default would\n block inherited overrides. --ty-calendar-accent still cascades in. */\n\n:host([data-size=\"md\"]) {\n --nav-btn-size: 1.875rem;\n --nav-btn-icon-size: 1.125rem;\n --nav-font-size: 1rem;\n --nav-padding: 0.5rem 0.75rem;\n --nav-default-width: 280px;\n}\n\n:host([data-size=\"sm\"]) {\n --nav-btn-size: 1.5rem;\n --nav-btn-icon-size: 0.9375rem;\n --nav-font-size: 0.875rem;\n --nav-padding: 0.375rem 0.5rem;\n --nav-default-width: 240px;\n}\n\n:host([data-size=\"lg\"]) {\n --nav-btn-size: 2.25rem;\n --nav-btn-icon-size: 1.25rem;\n --nav-font-size: 1.125rem;\n --nav-padding: 0.625rem 1rem;\n --nav-default-width: 360px;\n}\n\n.calendar-navigation-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: var(--nav-padding);\n font-family: inherit;\n user-select: none;\n /* --ty-calendar-width is the public knob: set it on ty-calendar (or any\n ancestor) and BOTH the nav and the day grid follow it, because custom\n properties inherit through shadow boundaries. --nav-default-width can't\n serve that role — it's declared on :host([data-size]) inside this shadow\n root, and a declaration on the element always beats a value inherited\n into it, so an outside override of it is silently dead. --nav-width\n (set inline by the width attribute) still wins over both. */\n width: var(--nav-width, var(--ty-calendar-width, var(--nav-default-width)));\n box-sizing: border-box;\n}\n\n/* Title (left) opens the month/year view; arrows (right) step months, or\n years while that view is open. */\n.nav-group {\n display: flex;\n align-items: center;\n gap: 0.25rem;\n flex: 0 0 auto;\n}\n\n.nav-title {\n display: inline-flex;\n align-items: center;\n gap: 0.375rem;\n min-width: 0;\n margin-left: -0.375rem;\n padding: 0.25rem 0.375rem;\n border: none;\n border-radius: var(--ty-radius-base);\n background: transparent;\n font-family: inherit;\n font-size: var(--nav-font-size);\n line-height: 1.2;\n white-space: nowrap;\n cursor: pointer;\n transition: var(--ty-local-transition, background-color 0.15s ease);\n outline: none;\n}\n\n.nav-title:hover,\n.nav-title[aria-expanded=\"true\"] {\n background-color: var(--ty-calendar-nav-hover-bg, var(--ty-bg-neutral-soft));\n}\n\n.nav-title:focus-visible {\n outline: 2px solid var(--ty-calendar-nav-focus-outline, var(--ty-calendar-accent, var(--ty-color-primary)));\n outline-offset: 2px;\n}\n\n.nav-title-month {\n font-weight: 600;\n letter-spacing: -0.01em;\n color: var(--ty-calendar-nav-title-color, var(--ty-text-strong, var(--ty-color-neutral-strong)));\n}\n\n.nav-title-year {\n font-weight: 400;\n color: var(--ty-calendar-nav-year-color, var(--ty-text-soft, var(--ty-color-neutral)));\n}\n\n.nav-caret {\n display: inline-flex;\n color: var(--ty-calendar-nav-color, var(--ty-color-neutral));\n transition: transform 0.15s ease;\n}\n\n.nav-caret svg {\n width: 1em;\n height: 1em;\n display: block;\n}\n\n.nav-title[aria-expanded=\"true\"] .nav-caret {\n transform: rotate(180deg);\n}\n\n.nav-btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: var(--nav-btn-size);\n height: var(--nav-btn-size);\n padding: 0;\n border: 1px solid var(--ty-calendar-nav-border, var(--ty-border));\n border-radius: var(--ty-radius-base);\n background-color: transparent;\n color: var(--ty-calendar-nav-color, var(--ty-color-neutral-strong));\n cursor: pointer;\n transition: var(--ty-local-transition, all 0.15s ease);\n outline: none;\n}\n\n.nav-btn:hover {\n background-color: var(--ty-calendar-nav-hover-bg, var(--ty-bg-neutral-soft));\n color: var(--ty-calendar-nav-hover-color, var(--ty-color-neutral-strong));\n}\n\n.nav-btn:active {\n background-color: var(--ty-calendar-nav-active-bg, var(--ty-bg-neutral));\n transform: scale(0.95);\n}\n\n.nav-btn:disabled {\n opacity: 0.35;\n cursor: default;\n pointer-events: none;\n}\n\n.nav-btn:focus-visible {\n outline: 2px solid var(--ty-calendar-nav-focus-outline, var(--ty-calendar-accent, var(--ty-color-primary)));\n outline-offset: 2px;\n}\n\n.nav-btn svg {\n width: var(--nav-btn-icon-size);\n height: var(--nav-btn-icon-size);\n display: block;\n}\n`;\n","/**\n * TyCalendarNavigation Web Component — pure presentation for calendar\n * month/year navigation. Stateless: all state comes from properties,\n * changes are emitted via events.\n */\n\nimport { ensureStyles } from '../utils/styles.js';\nimport { calendarNavigationStyles } from '../styles/calendar-navigation.js';\nimport { getMonthName, parseISODate } from '../utils/calendar-utils.js';\nimport { getEffectiveLocale, observeLocaleChanges } from '../utils/locale.js';\nimport { TyComponent } from '../base/ty-component.js';\nimport type { PropertyChange } from '../utils/property-manager.js';\n\n/**\n * Navigation change event detail\n */\nexport interface NavigationChangeDetail {\n month: number; // 1-12\n year: number; // e.g., 2025\n}\n\n/**\n * Internal navigation state (minimal - just for current display)\n */\ninterface NavigationState {\n displayMonth: number;\n displayYear: number;\n}\n\nconst CHEVRON_LEFT_SVG = `<?xml version='1.0' encoding='UTF-8'?>\n<svg width='24' viewBox='0 0 24 24' height='24' xmlns='http://www.w3.org/2000/svg' stroke-width='0' stroke='currentColor' fill='currentColor'>\n<path fill='none' d='M0 0h24v24H0V0z'/>\n<path d='M15.41 16.59L10.83 12l4.58-4.59L14 6l-6 6 6 6 1.41-1.41z'/>\n</svg>`;\n\nconst CHEVRON_RIGHT_SVG = `<?xml version='1.0' encoding='UTF-8'?>\n<svg width='24' viewBox='0 0 24 24' height='24' xmlns='http://www.w3.org/2000/svg' stroke-width='0' stroke='currentColor' fill='currentColor'>\n<path fill='none' d='M0 0h24v24H0V0z'/>\n<path d='M8.59 16.59L13.17 12 8.59 7.41 10 6l6 6-6 6-1.41-1.41z'/>\n</svg>`;\n\nconst CARET_DOWN_SVG = `<svg width='24' viewBox='0 0 24 24' height='24' xmlns='http://www.w3.org/2000/svg' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'>\n<path d='m6 9 6 6 6-6'/>\n</svg>`;\n\n/** Which grid the calendar shows: days of a month, or the months of a year. */\nexport type CalendarView = 'days' | 'months';\n\n/**\n * TyCalendarNavigation Web Component\n */\nexport class TyCalendarNavigation extends TyComponent<NavigationState> {\n protected static properties = {\n 'display-month': {\n type: 'number' as const,\n visual: true,\n default: () => new Date().getMonth() + 1, // 1-based\n validate: (v: any) => {\n const num = Number(v);\n return Number.isInteger(num) && num >= 1 && num <= 12;\n },\n coerce: (v: any) => {\n const num = Number(v);\n if (isNaN(num) || num < 1 || num > 12) {\n console.warn(`[ty-calendar-navigation] Invalid month '${v}'. Using current month.`);\n return new Date().getMonth() + 1;\n }\n return num;\n }\n },\n 'display-year': {\n type: 'number' as const,\n visual: true,\n default: () => new Date().getFullYear(),\n validate: (v: any) => {\n const num = Number(v);\n return Number.isInteger(num) && num >= 1 && num <= 9999;\n },\n coerce: (v: any) => {\n const num = Number(v);\n if (isNaN(num) || num < 1 || num > 9999) {\n console.warn(`[ty-calendar-navigation] Invalid year '${v}'. Using current year.`);\n return new Date().getFullYear();\n }\n return num;\n }\n },\n \n locale: {\n type: 'string' as const,\n visual: true,\n default: 'en-US'\n },\n \n size: {\n type: 'string' as const,\n visual: true,\n default: 'md',\n validate: (v: any) => ['sm', 'md', 'lg'].includes(v),\n coerce: (v: any) => {\n if (!['sm', 'md', 'lg'].includes(v)) {\n console.warn(`[ty-calendar-navigation] Invalid size '${v}'. Using 'md'.`);\n return 'md';\n }\n return v;\n }\n },\n \n width: {\n type: 'string' as const,\n visual: true,\n default: ''\n },\n\n // Which grid the parent shows. 'days': title opens the month/year view,\n // arrows step months. 'months': title shows the year and closes the\n // view, arrows step years.\n view: {\n type: 'string' as const,\n visual: true,\n default: 'days',\n validate: (v: any) => v === 'days' || v === 'months',\n coerce: (v: any) => (v === 'months' ? 'months' : 'days')\n },\n\n // Navigation bounds — ISO dates. Buttons that would move the display\n // entirely outside [min, max] months are disabled; year jumps clamp.\n min: {\n type: 'string' as const,\n visual: true,\n default: ''\n },\n max: {\n type: 'string' as const,\n visual: true,\n default: ''\n }\n };\n \n private _state: NavigationState;\n private _localeObserver?: () => void; // Cleanup function for locale observer\n \n constructor() {\n super(); // TyComponent handles attachShadow\n \n const today = new Date();\n this._state = {\n displayMonth: today.getMonth() + 1,\n displayYear: today.getFullYear()\n };\n \n const shadow = this.shadowRoot!;\n ensureStyles(shadow, { css: calendarNavigationStyles, id: 'ty-calendar-navigation' });\n }\n \n protected onConnect(): void {\n this._state.displayMonth = this.displayMonth;\n this._state.displayYear = this.displayYear;\n \n // Setup locale observer to watch for ancestor lang changes\n this._localeObserver = observeLocaleChanges(this, () => {\n this.render();\n });\n \n this.render();\n }\n \n protected onDisconnect(): void {\n if (this._localeObserver) {\n this._localeObserver();\n this._localeObserver = undefined;\n }\n }\n \n /**\n * Called when properties change\n * Update internal state BEFORE render\n */\n protected onPropertiesChanged(changes: PropertyChange[]): void {\n for (const { name, newValue } of changes) {\n switch (name) {\n case 'display-month':\n this._state.displayMonth = newValue as number;\n break;\n case 'display-year':\n this._state.displayYear = newValue as number;\n break;\n case 'locale':\n case 'size':\n case 'width':\n case 'view':\n // These properties just affect rendering\n // TyComponent will call render() automatically for visual properties\n break;\n }\n }\n }\n \n get displayMonth(): number {\n return this.getProperty('display-month');\n }\n \n set displayMonth(value: number) {\n this.setProperty('display-month', value);\n }\n \n get displayYear(): number {\n return this.getProperty('display-year');\n }\n \n set displayYear(value: number) {\n this.setProperty('display-year', value);\n }\n \n get locale(): string {\n // Use getEffectiveLocale to check ancestor lang attributes\n return getEffectiveLocale(this, this.getProperty('locale'));\n }\n \n set locale(value: string) {\n this.setProperty('locale', value);\n }\n \n get size(): 'sm' | 'md' | 'lg' {\n return this.getProperty('size') as 'sm' | 'md' | 'lg';\n }\n \n set size(value: 'sm' | 'md' | 'lg') {\n this.setProperty('size', value);\n }\n \n get width(): string {\n return this.getProperty('width');\n }\n\n set width(value: string) {\n this.setProperty('width', value);\n }\n\n get view(): CalendarView {\n return this.getProperty('view') as CalendarView;\n }\n\n set view(value: CalendarView) {\n this.setProperty('view', value);\n }\n\n get min(): string {\n return this.getProperty('min');\n }\n\n set min(value: string) {\n this.setProperty('min', value ?? '');\n }\n\n get max(): string {\n return this.getProperty('max');\n }\n\n set max(value: string) {\n this.setProperty('max', value ?? '');\n }\n \n private emitChangeEvent(month: number, year: number): void {\n const detail: NavigationChangeDetail = {\n month,\n year,\n };\n \n const event = new CustomEvent('change', {\n detail,\n bubbles: true,\n cancelable: true,\n });\n \n this.dispatchEvent(event);\n }\n \n /**\n * Month index (year * 12 + month - 1) — flat, comparable month math.\n */\n private static monthIndex(year: number, month: number): number {\n return year * 12 + (month - 1);\n }\n\n /**\n * min/max as month indices (null when unset/invalid)\n */\n private boundIndices(): { minIdx: number | null; maxIdx: number | null } {\n const min = parseISODate(this.min);\n const max = parseISODate(this.max);\n return {\n minIdx: min ? TyCalendarNavigation.monthIndex(min.year, min.month) : null,\n maxIdx: max ? TyCalendarNavigation.monthIndex(max.year, max.month) : null,\n };\n }\n\n /**\n * Clamp a target month index to [min, max]\n */\n private clampIndex(idx: number): number {\n const { minIdx, maxIdx } = this.boundIndices();\n if (minIdx !== null && idx < minIdx) return minIdx;\n if (maxIdx !== null && idx > maxIdx) return maxIdx;\n return idx;\n }\n\n /**\n * Navigate by month/year delta, clamped to bounds.\n * Year jumps near a bound land ON the bound month instead of overshooting.\n */\n private navigateBy(deltaMonths: number): void {\n const current = TyCalendarNavigation.monthIndex(\n this._state.displayYear,\n this._state.displayMonth\n );\n const target = this.clampIndex(current + deltaMonths);\n if (target === current) return; // Already at the bound\n\n this.emitChangeEvent((target % 12) + 1, Math.floor(target / 12));\n }\n\n /**\n * True when navigating by deltaMonths can't move the display (bound reached)\n */\n private isNavDisabled(deltaMonths: number): boolean {\n const current = TyCalendarNavigation.monthIndex(\n this._state.displayYear,\n this._state.displayMonth\n );\n return this.clampIndex(current + deltaMonths) === current;\n }\n \n private createButton(\n className: string,\n title: string,\n svg: string,\n onClick: () => void,\n disabled = false\n ): HTMLButtonElement {\n const button = document.createElement('button');\n button.type = 'button';\n button.className = className;\n button.title = title;\n button.setAttribute('aria-label', title);\n button.innerHTML = svg;\n button.disabled = disabled;\n button.addEventListener('click', onClick);\n return button;\n }\n \n protected render(): void {\n const root = this.shadowRoot;\n if (!root) return;\n \n ensureStyles(root, { css: calendarNavigationStyles, id: 'ty-calendar-navigation' });\n \n const size = this.size;\n this.setAttribute('data-size', size);\n \n const width = this.width;\n if (width) {\n this.style.setProperty('--nav-width', width);\n } else {\n this.style.removeProperty('--nav-width');\n }\n \n const months = this.view === 'months';\n const monthName = getMonthName(this._state.displayMonth, this.locale, 'long');\n\n root.innerHTML = '';\n\n const header = document.createElement('div');\n header.className = 'calendar-navigation-header';\n\n // Title: a button that flips the parent between the day grid and the\n // month/year grid (the parent listens for 'view-toggle').\n const title = document.createElement('button');\n title.type = 'button';\n title.className = 'nav-title';\n title.setAttribute('aria-expanded', String(months));\n title.setAttribute('aria-label', months ? 'Back to days' : 'Choose month and year');\n\n if (!months) {\n const month = document.createElement('span');\n month.className = 'nav-title-month';\n month.textContent = monthName;\n title.appendChild(month);\n }\n const year = document.createElement('span');\n year.className = months ? 'nav-title-month' : 'nav-title-year';\n year.textContent = String(this._state.displayYear);\n title.appendChild(year);\n\n const caret = document.createElement('span');\n caret.className = 'nav-caret';\n caret.innerHTML = CARET_DOWN_SVG;\n title.appendChild(caret);\n\n title.addEventListener('click', () => {\n this.dispatchEvent(new CustomEvent('view-toggle', {\n detail: { view: months ? 'days' : 'months' },\n }));\n });\n\n // Arrows: months in the day view, years in the month view.\n const step = months ? 12 : 1;\n const unit = months ? 'year' : 'month';\n const arrows = document.createElement('div');\n arrows.className = 'nav-group nav-arrows';\n arrows.appendChild(\n this.createButton(\n `nav-btn nav-${unit}-prev`,\n `Previous ${unit}`,\n CHEVRON_LEFT_SVG,\n () => this.navigateBy(-step),\n this.isNavDisabled(-step)\n )\n );\n arrows.appendChild(\n this.createButton(\n `nav-btn nav-${unit}-next`,\n `Next ${unit}`,\n CHEVRON_RIGHT_SVG,\n () => this.navigateBy(step),\n this.isNavDisabled(step)\n )\n );\n\n header.appendChild(title);\n header.appendChild(arrows);\n\n root.appendChild(header);\n }\n}\n\nif (!customElements.get('ty-calendar-navigation')) {\n customElements.define('ty-calendar-navigation', TyCalendarNavigation);\n}","/**\n * Calendar Orchestration Styles\n * Container for navigation + month display, plus the month/year grid\n * ty-calendar shows in place of the day grid.\n */\n\nimport { calendarMonthFlavorCss } from './calendar-month.js';\n\nconst selectedBg = 'var(--ty-calendar-selected-bg, var(--ty-calendar-accent, var(--calendar-month-selected-bg, var(--ty-solid-primary, var(--ty-color-primary)))))';\nconst selectedFg = 'var(--ty-calendar-selected-color, var(--calendar-month-selected-color, var(--ty-solid-primary-fg, white)))';\n\nexport const calendarStyles = `\n.calendar-container {\n display: flex;\n flex-direction: column;\n gap: 0.125rem;\n box-sizing: border-box;\n font-family: inherit;\n /* Nav is a fixed width and the grid is fit-content, so in any host wider\n than them (a popup, a stretched cell) the default stretch alignment\n left-pinned both. Centring keeps the block centred in whatever space it\n gets — without widening the calendar itself to fill it. */\n align-items: center;\n}\n\n@media (max-width: 320px) {\n .calendar-container {\n gap: 0.375rem;\n }\n}\n\n/* Month/year view: 3 x 4 months. min-height is set inline to the day\n grid's height, so the popup doesn't jump when the view flips. */\n.month-grid {\n display: grid;\n grid-template-columns: repeat(3, 1fr);\n grid-auto-rows: 1fr;\n gap: 0.375rem;\n box-sizing: border-box;\n padding: 0.75rem;\n min-width: 280px;\n width: var(--calendar-width, auto);\n}\n\n.month-grid.size-sm { padding: 0.5rem; min-width: 240px; gap: 0.25rem; }\n.month-grid.size-lg { padding: 1rem; min-width: 360px; gap: 0.5rem; }\n\n.month-cell {\n position: relative;\n display: flex;\n align-items: center;\n justify-content: center;\n min-height: 2.5rem;\n padding: 0;\n border: none;\n border-radius: var(--ty-calendar-day-radius, 0.5rem);\n background: transparent;\n color: var(--ty-calendar-day-color, var(--ty-text));\n font-family: inherit;\n font-size: 0.875rem;\n cursor: pointer;\n outline: none;\n transition: var(--ty-local-transition, background-color 0.15s ease, color 0.15s ease);\n}\n\n.month-grid.size-sm .month-cell { font-size: 0.75rem; min-height: 2rem; }\n.month-grid.size-lg .month-cell { font-size: 1rem; min-height: 3rem; }\n\n.month-cell:hover {\n color: var(--ty-calendar-day-hover-color, var(--ty-text-strong));\n background-color: var(--ty-calendar-day-hover-bg, var(--ty-bg-neutral));\n font-weight: 500;\n}\n\n.month-cell:focus-visible {\n box-shadow: 0 0 0 2px var(--calendar-month-accent, var(--ty-color-primary));\n}\n\n/* Current month: accent + dot, like today in the day grid */\n.month-cell.current {\n color: var(--ty-calendar-today-color, var(--ty-calendar-today-accent, var(--calendar-month-accent, var(--ty-color-primary))));\n font-weight: 600;\n}\n\n.month-cell.current::after {\n content: \"\";\n position: absolute;\n top: calc(50% + 0.72em);\n left: 50%;\n width: 4px;\n height: 4px;\n margin-left: -2px;\n border-radius: 50%;\n background: currentColor;\n}\n\n.month-cell.selected {\n background-color: ${selectedBg};\n color: ${selectedFg};\n font-weight: 600;\n}\n\n.month-cell.selected:hover {\n background-color: var(--ty-calendar-selected-hover-bg, var(--calendar-month-selected-hover-bg, color-mix(in oklab, ${selectedBg} 85%, ${selectedFg})));\n}\n\n.month-cell:disabled {\n color: var(--ty-calendar-disabled-color, var(--ty-text-faint));\n opacity: var(--ty-calendar-disabled-opacity, 0.7);\n text-decoration: line-through;\n text-decoration-color: color-mix(in oklab, currentColor 60%, transparent);\n cursor: default;\n pointer-events: none;\n}\n\n${calendarMonthFlavorCss}\n`;\n","/**\n * TyCalendar Web Component — orchestrates ty-calendar-navigation +\n * ty-calendar-month: owns selection state, distributes properties to the\n * children, and participates in forms via ElementInternals.\n */\n\nimport { ensureStyles } from '../utils/styles.js';\nimport { liftProperties, upgradeProperties } from '../utils/upgrade-properties.js';\nimport { calendarStyles } from '../styles/calendar.js';\n// Side-effect imports: register the child elements this component createElements\nimport './calendar-month.js';\nimport './calendar-navigation.js';\nimport type { DayContentFn, DayClickDetail, CalendarSize } from './calendar-month.js';\nimport type { NavigationChangeDetail, CalendarView } from './calendar-navigation.js';\nimport { parseISODate, getMonthName, type DayContext } from '../utils/calendar-utils.js';\nimport { getEffectiveLocale, observeLocaleChanges } from '../utils/locale.js';\nimport { ValidityController, nativeMessage } from '../utils/validity.js';\n\n/**\n * Internal calendar state\n */\ninterface CalendarState {\n displayYear: number;\n displayMonth: number;\n selectedYear?: number;\n selectedMonth?: number;\n selectedDay?: number;\n}\n\n/**\n * Calendar change event detail (day selection)\n */\nexport interface CalendarChangeDetail {\n year: number;\n month: number;\n day: number;\n action: 'select';\n source: 'day-click';\n dayContext: DayContext;\n}\n\n/**\n * Calendar navigate event detail (month/year change)\n */\nexport interface CalendarNavigateDetail {\n month: number;\n year: number;\n action: 'navigate';\n source: 'navigation';\n}\n\nfunction getCurrentDate(): { year: number; month: number; day: number } {\n const now = new Date();\n return {\n year: now.getFullYear(),\n month: now.getMonth() + 1, // 1-based\n day: now.getDate(),\n };\n}\n\nfunction parseYear(yearStr: string | null): number | null {\n if (!yearStr || !/^\\d{4}$/.test(yearStr)) return null;\n return parseInt(yearStr, 10);\n}\n\nfunction parseMonth(monthStr: string | null): number | null {\n if (!monthStr || !/^\\d{1,2}$/.test(monthStr)) return null;\n const month = parseInt(monthStr, 10);\n return month >= 1 && month <= 12 ? month : null;\n}\n\n/**\n * Parse a day string, validated against the given month's length.\n */\nfunction parseDay(dayStr: string | null, year: number, month: number): number | null {\n if (!dayStr || !/^\\d{1,2}$/.test(dayStr)) return null;\n const day = parseInt(dayStr, 10);\n\n const daysInMonth = new Date(year, month, 0).getDate();\n\n return day >= 1 && day <= daysInMonth ? day : null;\n}\n\n/** Format date as ISO string (YYYY-MM-DD) for form submission */\nfunction formatDateISO(year: number, month: number, day: number): string {\n const monthStr = month.toString().padStart(2, '0');\n const dayStr = day.toString().padStart(2, '0');\n return `${year}-${monthStr}-${dayStr}`;\n}\n\n/**\n * TyCalendar Web Component\n */\nexport class TyCalendar extends HTMLElement {\n private _state: CalendarState;\n private _hideNavigation: boolean = false;\n private _stateless: boolean = false;\n private _size: CalendarSize = 'md';\n private _width?: string;\n private _dayContentFn?: DayContentFn;\n private _customCSS?: CSSStyleSheet;\n private _min?: string; // ISO date bound - passed to navigation + month\n private _max?: string; // ISO date bound - passed to navigation + month\n private _flavor: string = 'primary'; // passed to month display only (nav stays neutral chrome)\n\n private _navigation?: HTMLElement;\n private _monthDisplay?: HTMLElement;\n private _container?: HTMLElement;\n\n // Day grid, or the month/year grid opened from the title\n private _view: CalendarView = 'days';\n private _monthGrid?: HTMLElement;\n private _dayGridHeight = 0;\n\n private _internals?: ElementInternals;\n private _validity?: ValidityController;\n // Markup-declared value, captured once on connect — form.reset() reverts to\n // this rather than whatever the year/month/day attributes currently say,\n // since the value setter overwrites those attributes on every user pick.\n private _initialValue: string = '';\n\n // Counts value sets: see `set value`\n private _valueSets = 0;\n\n // Locale observer cleanup\n private _localeObserver?: () => void;\n\n static formAssociated = true;\n\n static get observedAttributes(): string[] {\n return ['value', 'year', 'month', 'day', 'hide-navigation', 'stateless', 'locale', 'name', 'size', 'width', 'min', 'max', 'flavor'];\n }\n\n constructor() {\n super();\n\n const current = getCurrentDate();\n this._state = {\n displayYear: current.year,\n displayMonth: current.month,\n };\n\n this.attachShadow({ mode: 'open' });\n // The `value` attribute goes through the setter (attributeChangedCallback)\n liftProperties(this);\n\n if ('attachInternals' in this) {\n this._internals = this.attachInternals();\n this._validity = new ValidityController(this, this._internals);\n }\n }\n\n connectedCallback() {\n this.initializeFromAttributes();\n\n // After the markup value is captured for form.reset(): a property set\n // before upgrade is a property set, not the default\n upgradeProperties(this);\n\n this.render();\n\n this.updateFormValue();\n \n // Setup locale observer to watch for ancestor lang changes\n this._localeObserver = observeLocaleChanges(this, () => {\n this.render();\n });\n }\n\n disconnectedCallback() {\n if (this._localeObserver) {\n this._localeObserver();\n this._localeObserver = undefined;\n }\n \n this._navigation = undefined;\n this._monthDisplay = undefined;\n this._monthGrid = undefined;\n this._container = undefined;\n this._view = 'days';\n }\n\n attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null) {\n if (oldValue === newValue) return;\n\n switch (name) {\n // `value` is the ISO-date form of year/month/day — the setter fans it\n // out to those attributes (and syncs children), so no extra work here.\n case 'value':\n this.value = newValue || '';\n break;\n\n case 'year':\n case 'month':\n case 'day':\n this.syncStateFromAttributes();\n this.syncChildComponents();\n this.updateFormValue();\n break;\n\n case 'hide-navigation':\n this._hideNavigation = newValue !== null;\n this.render();\n break;\n\n case 'stateless':\n this._stateless = newValue !== null && newValue !== 'false';\n // No re-render needed, just changes behavior\n break;\n\n case 'locale':\n // Attribute is the source of truth — `get locale` resolves it via\n // getEffectiveLocale; children just need a re-sync.\n this.syncChildComponents();\n break;\n\n case 'size':\n if (newValue === 'sm' || newValue === 'md' || newValue === 'lg') {\n this._size = newValue;\n // Clear width when size is set (mutually exclusive)\n this._width = undefined;\n this.removeAttribute('width');\n this.syncChildComponents();\n }\n break;\n\n case 'width':\n this._width = newValue || undefined;\n // Clear size when width is set (mutually exclusive)\n if (newValue) {\n this._size = 'md'; // Reset to default\n this.removeAttribute('size');\n }\n this.syncChildComponents();\n break;\n\n case 'name':\n this.updateFormValue();\n break;\n\n case 'min':\n case 'max':\n this[name === 'min' ? '_min' : '_max'] = newValue || undefined;\n this.syncChildComponents();\n this.updateValidity(); // bounds change can (in)validate current selection\n break;\n\n case 'flavor':\n this._flavor = newValue || 'primary';\n this.syncChildComponents();\n break;\n }\n }\n\n get min(): string | undefined {\n return this._min;\n }\n\n set min(value: string | undefined) {\n // Reflect to attribute; attributeChangedCallback syncs children\n if (value) this.setAttribute('min', value);\n else this.removeAttribute('min');\n }\n\n get max(): string | undefined {\n return this._max;\n }\n\n set max(value: string | undefined) {\n if (value) this.setAttribute('max', value);\n else this.removeAttribute('max');\n }\n\n get flavor(): string {\n return this._flavor;\n }\n\n set flavor(value: string) {\n if (value) this.setAttribute('flavor', value);\n else this.removeAttribute('flavor');\n }\n\n get year(): number | undefined {\n return this._state.selectedYear;\n }\n\n set year(value: number | undefined) {\n if (value !== undefined) {\n // In stateless mode, only update display\n if (this._stateless) {\n this._state.displayYear = value;\n this.setAttribute('year', value.toString());\n } else {\n // In stateful mode, update both selection and display\n this._state.selectedYear = value;\n this._state.displayYear = value;\n this.setAttribute('year', value.toString());\n }\n } else {\n if (!this._stateless) {\n delete this._state.selectedYear;\n }\n this.removeAttribute('year');\n }\n this.syncChildComponents();\n if (!this._stateless) {\n this.updateFormValue();\n }\n }\n\n get month(): number | undefined {\n return this._state.selectedMonth;\n }\n\n set month(value: number | undefined) {\n if (value !== undefined) {\n // In stateless mode, only update display\n if (this._stateless) {\n this._state.displayMonth = value;\n this.setAttribute('month', value.toString());\n } else {\n // In stateful mode, update both selection and display\n this._state.selectedMonth = value;\n this._state.displayMonth = value;\n this.setAttribute('month', value.toString());\n }\n } else {\n if (!this._stateless) {\n delete this._state.selectedMonth;\n }\n this.removeAttribute('month');\n }\n this.syncChildComponents();\n if (!this._stateless) {\n this.updateFormValue();\n }\n }\n\n get day(): number | undefined {\n return this._state.selectedDay;\n }\n\n set day(value: number | undefined) {\n if (value !== undefined) {\n this._state.selectedDay = value;\n this.setAttribute('day', value.toString());\n } else {\n delete this._state.selectedDay;\n this.removeAttribute('day');\n }\n this.syncChildComponents();\n this.updateFormValue();\n }\n\n get locale(): string {\n return getEffectiveLocale(this, this.getAttribute('locale'));\n }\n\n set locale(value: string) {\n this.setAttribute('locale', value);\n }\n\n get hideNavigation(): boolean {\n return this._hideNavigation;\n }\n\n set hideNavigation(value: boolean) {\n this._hideNavigation = value;\n if (value) this.setAttribute('hide-navigation', '');\n else this.removeAttribute('hide-navigation');\n }\n\n get stateless(): boolean {\n return this._stateless;\n }\n\n set stateless(value: boolean) {\n this._stateless = value;\n if (value) {\n this.setAttribute('stateless', '');\n } else {\n this.removeAttribute('stateless');\n }\n }\n\n get size(): CalendarSize {\n return this._size;\n }\n\n set size(value: CalendarSize) {\n if (this._size !== value) {\n this._size = value;\n // Clear width when size is set (mutually exclusive)\n this._width = undefined;\n this.removeAttribute('width');\n this.setAttribute('size', value);\n this.syncChildComponents();\n }\n }\n\n get width(): string | undefined {\n return this._width;\n }\n\n set width(value: string | undefined) {\n if (this._width !== value) {\n this._width = value;\n if (value) {\n // Clear size when width is set (mutually exclusive)\n this._size = 'md'; // Reset to default\n this.removeAttribute('size');\n this.setAttribute('width', value);\n } else {\n this.removeAttribute('width');\n }\n this.syncChildComponents();\n }\n }\n\n get dayContentFn(): DayContentFn | undefined {\n return this._dayContentFn;\n }\n\n set dayContentFn(fn: DayContentFn | undefined) {\n this._dayContentFn = fn;\n this.syncChildComponents();\n }\n\n get customCSS(): CSSStyleSheet | undefined {\n return this._customCSS;\n }\n\n set customCSS(sheet: CSSStyleSheet | undefined) {\n this._customCSS = sheet;\n this.syncChildComponents();\n }\n\n get value(): string {\n const { selectedYear, selectedMonth, selectedDay } = this._state;\n if (selectedYear && selectedMonth && selectedDay) {\n return formatDateISO(selectedYear, selectedMonth, selectedDay);\n }\n return '';\n }\n\n set value(isoDate: string) {\n // While the element upgrades, an attribute write below runs\n // connectedCallback, where a `value` set before the upgrade comes in:\n // that one stands, this one stops.\n const set = ++this._valueSets;\n const superseded = () => set !== this._valueSets;\n\n if (!isoDate) {\n delete this._state.selectedYear;\n delete this._state.selectedMonth;\n delete this._state.selectedDay;\n \n // In normal mode, also clear attributes\n if (!this._stateless) {\n this.removeAttribute('year');\n if (superseded()) return;\n this.removeAttribute('month');\n if (superseded()) return;\n this.removeAttribute('day');\n }\n } else {\n // Not a string (a Date): ignored, as an unparsable string is\n const match = typeof isoDate === 'string' && isoDate.match(/^(\\d{4})-(\\d{2})-(\\d{2})$/);\n if (match) {\n const year = parseInt(match[1], 10);\n const month = parseInt(match[2], 10);\n const day = parseInt(match[3], 10);\n\n this._state.selectedYear = year;\n this._state.selectedMonth = month;\n this._state.selectedDay = day;\n \n // Update display to show this month\n this._state.displayYear = year;\n this._state.displayMonth = month;\n\n // In normal mode, update attributes\n // In stateless mode, skip attribute updates (parent controls attributes)\n if (!this._stateless) {\n this.setAttribute('year', year.toString());\n if (superseded()) return;\n this.setAttribute('month', month.toString());\n if (superseded()) return;\n this.setAttribute('day', day.toString());\n }\n }\n }\n this.syncChildComponents();\n\n if (!this._stateless) {\n this.updateFormValue();\n }\n }\n\n /**\n * Initialize state from HTML attributes on first load\n */\n private initializeFromAttributes(): void {\n const yearStr = this.getAttribute('year');\n const monthStr = this.getAttribute('month');\n const dayStr = this.getAttribute('day');\n const hideNav = this.hasAttribute('hide-navigation');\n const statelessStr = this.getAttribute('stateless');\n const sizeStr = this.getAttribute('size');\n const widthStr = this.getAttribute('width');\n\n this._min = this.getAttribute('min') || undefined;\n this._max = this.getAttribute('max') || undefined;\n\n const year = parseYear(yearStr);\n if (year) {\n this._state.displayYear = year;\n }\n\n const month = parseMonth(monthStr);\n if (month) {\n this._state.displayMonth = month;\n }\n\n // Parse day (only if year and month are valid)\n if (year && month) {\n const day = parseDay(dayStr, year, month);\n if (day) {\n this._state.selectedYear = year;\n this._state.selectedMonth = month;\n this._state.selectedDay = day;\n }\n }\n\n this._hideNavigation = hideNav;\n\n if (statelessStr !== null) {\n this._stateless = statelessStr !== 'false';\n }\n\n if (sizeStr && (sizeStr === 'sm' || sizeStr === 'md' || sizeStr === 'lg')) {\n this._size = sizeStr;\n }\n\n if (widthStr) {\n this._width = widthStr;\n }\n\n this._initialValue = this.value;\n }\n\n formResetCallback(): void {\n this.value = this._initialValue;\n }\n\n private syncStateFromAttributes(): void {\n const yearStr = this.getAttribute('year');\n const monthStr = this.getAttribute('month');\n const dayStr = this.getAttribute('day');\n\n const year = parseYear(yearStr);\n const month = parseMonth(monthStr);\n\n if (year) this._state.displayYear = year;\n if (month) this._state.displayMonth = month;\n\n // Update selection (only if all three are valid)\n if (year && month) {\n const day = parseDay(dayStr, year, month);\n if (day) {\n this._state.selectedYear = year;\n this._state.selectedMonth = month;\n this._state.selectedDay = day;\n } else {\n // Clear selection if day is invalid\n delete this._state.selectedYear;\n delete this._state.selectedMonth;\n delete this._state.selectedDay;\n }\n } else {\n // Clear selection if year or month is invalid\n delete this._state.selectedYear;\n delete this._state.selectedMonth;\n delete this._state.selectedDay;\n }\n }\n\n private syncChildComponents(): void {\n if (this._navigation) {\n (this._navigation as any).displayMonth = this._state.displayMonth;\n (this._navigation as any).displayYear = this._state.displayYear;\n (this._navigation as any).locale = this.locale;\n (this._navigation as any).size = this._size;\n (this._navigation as any).min = this._min ?? '';\n (this._navigation as any).max = this._max ?? '';\n // Always sync width (set or clear)\n (this._navigation as any).width = this._width;\n (this._navigation as any).view = this._view;\n }\n\n if (this._monthGrid) {\n this.showBody();\n }\n\n if (this._monthDisplay) {\n (this._monthDisplay as any).displayMonth = this._state.displayMonth;\n (this._monthDisplay as any).displayYear = this._state.displayYear;\n (this._monthDisplay as any).locale = this.locale;\n (this._monthDisplay as any).size = this._size;\n (this._monthDisplay as any).min = this._min;\n (this._monthDisplay as any).max = this._max;\n (this._monthDisplay as any).flavor = this._flavor;\n // Always sync width (set or clear)\n (this._monthDisplay as any).width = this._width;\n\n if (this._dayContentFn) {\n (this._monthDisplay as any).dayContentFn = this._dayContentFn;\n }\n\n if (this._customCSS) {\n (this._monthDisplay as any).customCSS = this._customCSS;\n }\n\n // Update selection value (convert to Date timestamp)\n const { selectedYear, selectedMonth, selectedDay } = this._state;\n if (selectedYear && selectedMonth && selectedDay) {\n const date = new Date(selectedYear, selectedMonth - 1, selectedDay);\n (this._monthDisplay as any).value = date.getTime();\n } else {\n (this._monthDisplay as any).value = null;\n }\n }\n }\n\n private updateFormValue(): void {\n // Skip form participation in stateless mode\n if (this._stateless) return;\n \n if (!this._internals) return;\n\n const elementName = this.getAttribute('name');\n const { selectedYear, selectedMonth, selectedDay } = this._state;\n\n if (elementName && selectedYear && selectedMonth && selectedDay) {\n const isoDate = formatDateISO(selectedYear, selectedMonth, selectedDay);\n this._internals.setFormValue(isoDate);\n } else {\n this._internals.setFormValue('');\n }\n\n this.updateValidity();\n }\n\n /**\n * Selection outside [min, max] => rangeUnderflow/rangeOverflow, with a\n * native date input's message.\n * UI can't produce this (days are disabled), but programmatic values can.\n */\n private updateValidity(): void {\n if (!this._internals) return;\n\n const { selectedYear, selectedMonth, selectedDay } = this._state;\n if (selectedYear && selectedMonth && selectedDay) {\n const sel = Date.UTC(selectedYear, selectedMonth - 1, selectedDay);\n const min = this._min ? parseISODate(this._min) : null;\n const max = this._max ? parseISODate(this._max) : null;\n const message = () => nativeMessage(\n 'input',\n { type: 'date', min: this._min, max: this._max },\n formatDateISO(selectedYear, selectedMonth, selectedDay),\n );\n\n if (min && sel < Date.UTC(min.year, min.month - 1, min.day)) {\n this._validity!.set({ rangeUnderflow: true }, message());\n return;\n }\n if (max && sel > Date.UTC(max.year, max.month - 1, max.day)) {\n this._validity!.set({ rangeOverflow: true }, message());\n return;\n }\n }\n\n this._validity!.set({});\n }\n\n // --- Constraint validation (same API as native form controls) -------------\n\n get form(): HTMLFormElement | null { return this._internals?.form ?? null; }\n get validity(): ValidityState | undefined { return this._internals?.validity; }\n get validationMessage(): string { return this._internals?.validationMessage ?? ''; }\n get willValidate(): boolean { return this._internals?.willValidate ?? false; }\n checkValidity(): boolean { return this._internals?.checkValidity() ?? true; }\n reportValidity(): boolean { return this._validity?.report() ?? true; }\n setCustomValidity(message: string): void { this._validity?.setCustom(message); }\n\n private handleNavigationChange(event: CustomEvent<NavigationChangeDetail>): void {\n event.preventDefault();\n event.stopPropagation();\n\n const { month, year } = event.detail;\n this.goTo(month, year);\n }\n\n /** Show a month (and emit navigate). Shared by the arrows, the month grid\n and Page Up / Page Down. */\n private goTo(month: number, year: number): void {\n this._state.displayMonth = month;\n this._state.displayYear = year;\n\n this.syncChildComponents();\n\n const navigateDetail: CalendarNavigateDetail = {\n month,\n year,\n action: 'navigate',\n source: 'navigation',\n };\n\n this.dispatchEvent(new CustomEvent('navigate', {\n detail: navigateDetail,\n bubbles: true,\n composed: true,\n cancelable: false,\n }));\n }\n\n private handleDayClick(event: CustomEvent<DayClickDetail>): void {\n event.preventDefault();\n event.stopPropagation();\n\n const { dayContext, year, month, day } = event.detail;\n\n // In stateless mode, just re-dispatch the event without updating internal state\n if (this._stateless) {\n this.dispatchEvent(new CustomEvent('day-click', {\n detail: event.detail,\n bubbles: true,\n composed: true,\n cancelable: true,\n }));\n return;\n }\n\n // Normal mode: update selection state\n this._state.selectedYear = year;\n this._state.selectedMonth = month;\n this._state.selectedDay = day;\n this._state.displayYear = year;\n this._state.displayMonth = month;\n\n this.setAttribute('year', year.toString());\n this.setAttribute('month', month.toString());\n this.setAttribute('day', day.toString());\n\n this.updateFormValue();\n\n this.syncChildComponents();\n\n const changeDetail: CalendarChangeDetail = {\n year,\n month,\n day,\n action: 'select',\n source: 'day-click',\n dayContext,\n };\n\n this.dispatchEvent(new CustomEvent('change', {\n detail: changeDetail,\n bubbles: true,\n composed: true,\n cancelable: false,\n }));\n }\n\n /**\n * Force re-render of the calendar\n * Useful after updating dayContentFn or other dynamic properties\n */\n refresh(): void {\n this.syncChildComponents();\n \n // Force month display to re-render (for async data updates)\n if (this._monthDisplay && typeof (this._monthDisplay as any).refresh === 'function') {\n (this._monthDisplay as any).refresh();\n }\n }\n\n private createNavigation(): HTMLElement {\n const nav = document.createElement('ty-calendar-navigation');\n\n (nav as any).displayMonth = this._state.displayMonth;\n (nav as any).displayYear = this._state.displayYear;\n (nav as any).locale = this.locale;\n (nav as any).size = this._size;\n (nav as any).min = this._min ?? '';\n (nav as any).max = this._max ?? '';\n\n // Only set width if explicitly provided\n if (this._width) {\n (nav as any).width = this._width;\n }\n\n (nav as any).view = this._view;\n\n nav.addEventListener('change', (e) => this.handleNavigationChange(e as CustomEvent<NavigationChangeDetail>));\n nav.addEventListener('view-toggle', (e) => {\n this.setView((e as CustomEvent<{ view: CalendarView }>).detail.view);\n this.focusNavTitle();\n });\n\n this._navigation = nav;\n\n return nav;\n }\n\n private createMonthDisplay(): HTMLElement {\n const month = document.createElement('ty-calendar-month');\n\n (month as any).displayMonth = this._state.displayMonth;\n (month as any).displayYear = this._state.displayYear;\n (month as any).locale = this.locale;\n (month as any).size = this._size;\n (month as any).min = this._min;\n (month as any).max = this._max;\n (month as any).flavor = this._flavor;\n\n // Only set width if explicitly provided\n if (this._width) {\n (month as any).width = this._width;\n }\n\n const { selectedYear, selectedMonth, selectedDay } = this._state;\n if (selectedYear && selectedMonth && selectedDay) {\n const date = new Date(selectedYear, selectedMonth - 1, selectedDay);\n (month as any).value = date.getTime();\n }\n\n if (this._dayContentFn) {\n (month as any).dayContentFn = this._dayContentFn;\n }\n\n if (this._customCSS) {\n (month as any).customCSS = this._customCSS;\n }\n\n month.addEventListener('day-click', (e) => this.handleDayClick(e as CustomEvent<DayClickDetail>));\n\n this._monthDisplay = month;\n\n return month;\n }\n\n private render(): void {\n const root = this.shadowRoot;\n if (!root) return;\n\n ensureStyles(root, { css: calendarStyles, id: 'ty-calendar' });\n\n root.innerHTML = '';\n this._monthGrid = undefined;\n\n const container = document.createElement('div');\n container.className = 'calendar-container';\n container.addEventListener('keydown', (e) => this.handleKeydown(e as KeyboardEvent));\n this._container = container;\n\n if (!this._hideNavigation) {\n const nav = this.createNavigation();\n container.appendChild(nav);\n }\n\n const month = this.createMonthDisplay();\n container.appendChild(month);\n\n root.appendChild(container);\n\n if (this._view === 'months') this.showBody();\n }\n\n // ---------------------------------------------------------------------------\n // Month/year view\n // ---------------------------------------------------------------------------\n\n private setView(view: CalendarView): void {\n if (view === this._view) return;\n if (view === 'months' && this._monthDisplay) {\n // Keep the popup the same height while the grid is swapped\n this._dayGridHeight = this._monthDisplay.getBoundingClientRect().height;\n }\n this._view = view;\n if (this._navigation) (this._navigation as any).view = view;\n this.showBody();\n }\n\n /** Put the day grid or a freshly built month grid under the navigation. */\n private showBody(): void {\n const container = this._container;\n if (!container || !this._monthDisplay) return;\n\n if (this._view === 'days') {\n this._monthGrid?.remove();\n this._monthGrid = undefined;\n if (!this._monthDisplay.isConnected) container.appendChild(this._monthDisplay);\n return;\n }\n\n const grid = this.buildMonthGrid();\n if (this._monthGrid) this._monthGrid.replaceWith(grid);\n else {\n this._monthDisplay.remove();\n container.appendChild(grid);\n }\n this._monthGrid = grid;\n }\n\n private static monthIndex(year: number, month: number): number {\n return year * 12 + (month - 1);\n }\n\n /** min/max as month indices (null when unset) */\n private boundIndices(): { minIdx: number | null; maxIdx: number | null } {\n const min = this._min ? parseISODate(this._min) : null;\n const max = this._max ? parseISODate(this._max) : null;\n return {\n minIdx: min ? TyCalendar.monthIndex(min.year, min.month) : null,\n maxIdx: max ? TyCalendar.monthIndex(max.year, max.month) : null,\n };\n }\n\n private buildMonthGrid(): HTMLElement {\n const { displayYear, displayMonth, selectedYear, selectedMonth } = this._state;\n const today = getCurrentDate();\n const { minIdx, maxIdx } = this.boundIndices();\n\n const grid = document.createElement('div');\n grid.className = `month-grid size-${this._size}`;\n grid.setAttribute('role', 'grid');\n grid.setAttribute('aria-label', String(displayYear));\n if (this._dayGridHeight) grid.style.minHeight = `${this._dayGridHeight}px`;\n if (this._width) grid.style.setProperty('--calendar-width', this._width);\n\n for (let month = 1; month <= 12; month++) {\n const idx = TyCalendar.monthIndex(displayYear, month);\n const disabled = (minIdx !== null && idx < minIdx) || (maxIdx !== null && idx > maxIdx);\n const selected = selectedYear === displayYear && selectedMonth === month;\n\n const cell = document.createElement('button');\n cell.type = 'button';\n cell.className = 'month-cell';\n cell.setAttribute('role', 'gridcell');\n cell.setAttribute('aria-selected', String(selected));\n cell.setAttribute('aria-label', `${getMonthName(month, this.locale, 'long')} ${displayYear}`);\n cell.dataset.month = String(month);\n cell.tabIndex = month === displayMonth ? 0 : -1;\n cell.disabled = disabled;\n if (selected) cell.classList.add('selected');\n if (today.year === displayYear && today.month === month) cell.classList.add('current');\n cell.textContent = getMonthName(month, this.locale, 'short');\n cell.addEventListener('click', () => this.pickMonth(month));\n grid.appendChild(cell);\n }\n\n // Arrows move within the 3-column grid\n grid.addEventListener('keydown', (e: KeyboardEvent) => {\n const delta =\n e.key === 'ArrowLeft' ? -1 :\n e.key === 'ArrowRight' ? 1 :\n e.key === 'ArrowUp' ? -3 :\n e.key === 'ArrowDown' ? 3 :\n 0;\n if (!delta) return;\n const cells = Array.from(grid.querySelectorAll<HTMLButtonElement>('.month-cell'));\n const current = cells.findIndex(c => c === (this.shadowRoot as ShadowRoot).activeElement);\n const next = cells[(current === -1 ? displayMonth - 1 : current) + delta];\n if (!next || next.disabled) return;\n e.preventDefault();\n cells.forEach(c => (c.tabIndex = -1));\n next.tabIndex = 0;\n next.focus();\n });\n\n return grid;\n }\n\n private pickMonth(month: number): void {\n this.setView('days');\n this.goTo(month, this._state.displayYear);\n this.focusDayGrid();\n }\n\n // ---------------------------------------------------------------------------\n // Keyboard: Page Up/Down = month (year in the month view), Shift = year,\n // Escape closes the month view (and stops there, so a surrounding\n // date-picker popup stays open).\n // ---------------------------------------------------------------------------\n\n private handleKeydown(e: KeyboardEvent): void {\n if (e.key === 'Escape' && this._view === 'months') {\n e.preventDefault();\n e.stopPropagation();\n this.setView('days');\n this.focusNavTitle();\n return;\n }\n\n if (e.key !== 'PageUp' && e.key !== 'PageDown') return;\n e.preventDefault();\n\n const sign = e.key === 'PageUp' ? -1 : 1;\n const step = e.shiftKey || this._view === 'months' ? 12 : 1;\n const current = TyCalendar.monthIndex(this._state.displayYear, this._state.displayMonth);\n const { minIdx, maxIdx } = this.boundIndices();\n let target = current + sign * step;\n if (minIdx !== null && target < minIdx) target = minIdx;\n if (maxIdx !== null && target > maxIdx) target = maxIdx;\n if (target === current) return;\n\n this.goTo((target % 12) + 1, Math.floor(target / 12));\n if (this._view === 'months') {\n const cell = this._monthGrid?.querySelector<HTMLElement>('.month-cell[tabindex=\"0\"]');\n cell?.focus();\n } else {\n this.focusDayGrid();\n }\n }\n\n private focusNavTitle(): void {\n requestAnimationFrame(() => {\n (this._navigation?.shadowRoot?.querySelector('.nav-title') as HTMLElement | null)?.focus();\n });\n }\n\n /** Focus the grid's tab stop (the focused day, or month in the month view). */\n focus(options?: FocusOptions): void {\n const cell = this._view === 'months'\n ? this._monthGrid?.querySelector<HTMLElement>('.month-cell[tabindex=\"0\"]')\n : this._monthDisplay?.shadowRoot?.querySelector('.calendar-day-cell[tabindex=\"0\"]') as HTMLElement | null;\n if (cell) cell.focus(options);\n else super.focus(options);\n }\n\n private focusDayGrid(): void {\n requestAnimationFrame(() => {\n const cell = this._monthDisplay?.shadowRoot?.querySelector('.calendar-day-cell[tabindex=\"0\"]') as HTMLElement | null;\n cell?.focus();\n });\n }\n}\n\nif (!customElements.get('ty-calendar')) {\n customElements.define('ty-calendar', TyCalendar);\n}","/** Date Picker Component Styles */\n\nimport { FLAVORS } from \"../types/common.js\";\nimport { fieldSizeVars } from \"./field-size.js\";\n\n/* Flavor rules only set --date-picker-accent (border), -accent-bold\n (hover/focus border), and -ring (focus shadow); the stub base rules\n consume them. Doubles as the per-instance override API. Neutral is\n skipped — the 'default' flavor is the unstyled --ty-date-picker-* chrome.\n Fallback flavor `fb` is used for custom flavors (suffixed tokens fall\n back to the custom base color, then neutral). */\nconst datePickerFlavor = (f: string, fb?: string) => {\n const c = (s: string) =>\n fb\n ? s\n ? `var(--ty-color-${f}${s}, var(--ty-color-${f}, var(--ty-color-${fb}${s})))`\n : `var(--ty-color-${f}, var(--ty-color-${fb}))`\n : s\n ? `var(--ty-color-${f}${s}, var(--ty-color-${f}))`\n : `var(--ty-color-${f})`;\n return `\n:host([flavor=\"${f}\"]) {\n --date-picker-accent: var(--ty-input-${f}-border, ${c(\"-soft\")});\n --date-picker-accent-bold: ${c(\"\")};\n --date-picker-ring: color-mix(in oklab, ${c(\"\")} 15%, transparent);\n}\n:host([flavor=\"${f}+\"]) {\n --date-picker-accent: ${c(\"\")};\n --date-picker-accent-bold: ${c(\"-strong\")};\n --date-picker-ring: color-mix(in oklab, ${c(\"-strong\")} 15%, transparent);\n}\n:host([flavor=\"${f}-\"]) {\n --date-picker-accent: ${c(\"-faint\")};\n --date-picker-accent-bold: ${c(\"-soft\")};\n --date-picker-ring: color-mix(in oklab, ${c(\"-soft\")} 15%, transparent);\n}\n`;\n};\n\n/** Rules for one custom (non-built-in) flavor — see utils/flavor-sheet.ts. */\nexport const datePickerCustomFlavorCss = (base: string) => datePickerFlavor(base, \"neutral\");\n\nexport const datePickerStyles = `\n${fieldSizeVars}\n:host {\n display: block;\n width: auto;\n min-width: 200px;\n font-family: inherit;\n\n /* Theming tokens — date-picker stub. Thin shim over --ty-input-*: override\n these to retheme just the date-picker trigger, not other inputs. */\n --ty-date-picker-bg: var(--ty-input-bg);\n --ty-date-picker-color: var(--ty-input-color);\n --ty-date-picker-placeholder: var(--ty-input-placeholder);\n --ty-date-picker-border: var(--ty-input-border);\n --ty-date-picker-border-hover: var(--ty-input-border-hover);\n --ty-date-picker-border-focus: var(--ty-input-border-focus);\n --ty-date-picker-shadow-focus: var(--ty-input-shadow-focus);\n --ty-date-picker-disabled-bg: var(--ty-input-disabled-bg);\n --ty-date-picker-disabled-color: var(--ty-input-disabled-color);\n --ty-date-picker-radius: var(--ty-radius-md);\n\n /* Theming tokens — calendar popup surface. Shared with ty-calendar /\n ty-calendar-month theming. */\n --ty-calendar-surface-bg: var(--ty-surface-floating);\n --ty-calendar-surface-border: var(--ty-input-border);\n --ty-calendar-surface-shadow: var(--ty-shadow-lg, 0 4px 20px rgba(0, 0, 0, 0.08), 0 1px 3px rgba(0, 0, 0, 0.1));\n --ty-calendar-surface-radius: var(--ty-radius-lg);\n\n /* Theming tokens — time section */\n --ty-calendar-time-bg: transparent;\n --ty-calendar-time-border: var(--ty-border-faint);\n --ty-calendar-time-label-color: var(--ty-color-neutral);\n --ty-calendar-time-input-color: var(--ty-input-color);\n --ty-calendar-time-placeholder-color: var(--ty-input-placeholder);\n --ty-calendar-time-icon-color: var(--ty-color-neutral-soft);\n}\n\n/* Container structure (reuses dropdown patterns) */\n.dropdown-container {\n display: flex;\n flex-direction: column;\n width: 100%;\n box-sizing: border-box;\n}\n\n.ty-field-label {\n font-size: var(--ty-field-label-font);\n line-height: var(--ty-field-label-leading);\n letter-spacing: var(--ty-tracking-sm);\n font-weight: var(--ty-font-medium);\n color: var(--ty-label-color);\n margin-bottom: var(--ty-field-label-gap);\n padding-left: var(--ty-field-outer-pad-x);\n display: flex;\n align-items: center;\n}\n\n.required-icon {\n display: inline-flex;\n align-items: center;\n color: #ef4444;\n width: 12px;\n height: 12px;\n vertical-align: middle;\n margin-left: 4px;\n}\n\n.dropdown-wrapper {\n position: relative;\n display: block;\n width: 100%;\n}\n\n.date-picker-stub ::slotted([slot=\"start\"]) {\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n margin-right: 0.5rem;\n color: var(--ty-text-soft);\n}\n\n.date-picker-stub ::slotted(ty-icon[slot=\"start\"]) {\n width: 1em;\n height: 1em;\n}\n\n.date-picker-stub {\n width: 100%;\n cursor: pointer;\n box-sizing: border-box;\n position: relative;\n display: flex;\n align-items: center;\n background: var(--ty-date-picker-bg);\n color: var(--ty-date-picker-color);\n border: 1px solid var(--date-picker-accent, var(--ty-date-picker-border));\n border-radius: var(--ty-date-picker-radius);\n font-family: inherit;\n font-size: var(--ty-field-font);\n font-weight: var(--ty-font-normal);\n line-height: var(--ty-field-leading);\n min-height: var(--ty-field-height);\n padding: 0 var(--ty-field-pad-x);\n padding-right: calc(var(--ty-field-pad-x) + 1rem + var(--ty-field-pad-x));\n transition: var(--ty-transition-all), opacity 0.2s ease;\n outline: none;\n}\n\n.date-picker-stub:hover:not([disabled]):not(.open) {\n border-color: var(--date-picker-accent-bold, var(--ty-date-picker-border-hover));\n}\n\n.date-picker-stub[disabled] {\n background-color: var(--ty-date-picker-disabled-bg);\n color: var(--ty-date-picker-disabled-color);\n cursor: not-allowed;\n opacity: 0.6;\n}\n\n.date-picker-stub:focus,\n.date-picker-stub.open {\n border-color: var(--date-picker-accent-bold, var(--ty-date-picker-border-focus));\n box-shadow: 0 0 0 3px var(--date-picker-ring, var(--ty-date-picker-shadow-focus));\n}\n\n/* Flavor variants — set --date-picker-accent*, consumed by the stub rules above */\n${FLAVORS.filter((f) => f !== \"neutral\").map((f) => datePickerFlavor(f)).join(\"\")}\n\n/* Error line + state — same as ty-input's */\n.error-message {\n font-size: var(--ty-font-xs);\n line-height: var(--ty-leading-xs);\n letter-spacing: var(--ty-tracking-xs);\n color: var(--ty-color-danger);\n margin-top: 4px;\n padding-left: var(--ty-field-outer-pad-x);\n}\n\n.date-picker-stub.error {\n border-color: var(--ty-color-danger);\n background: var(--ty-bg-danger-soft);\n}\n\n.date-picker-stub.error:focus,\n.date-picker-stub.error.open {\n border-color: var(--ty-color-danger-bold);\n box-shadow: 0 0 0 3px var(--ty-date-picker-shadow-focus);\n}\n\n.stub-text {\n flex: 1;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n user-select: none;\n color: inherit;\n pointer-events: none;\n}\n\n.stub-text.placeholder {\n color: var(--ty-date-picker-placeholder);\n}\n\n.stub-icons {\n display: flex;\n align-items: center;\n gap: var(--ty-spacing-1);\n position: absolute;\n right: var(--ty-spacing-3);\n top: 50%;\n transform: translateY(-50%);\n height: 1rem;\n pointer-events: none;\n z-index: 2;\n}\n\n.stub-clear {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 1rem;\n height: 1rem;\n padding: 0;\n border: none;\n background: none;\n color: var(--ty-color-neutral-soft);\n cursor: pointer;\n border-radius: var(--ty-radius-sm);\n transition: var(--ty-local-transition, all 0.15s ease);\n pointer-events: auto;\n}\n\n.stub-clear:hover {\n /* Clear is a destructive utility action, not the field's semantic flavor\n — it stays neutral at rest and always warns danger-red on hover,\n regardless of the field's own flavor. (--ty-color-negative/\n --ty-bg-negative-faint used here previously don't exist as tokens —\n this silently fell back to unstyled inherited color.) */\n color: var(--ty-color-danger);\n background-color: var(--ty-bg-danger-soft);\n}\n\n.stub-arrow {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 1rem;\n height: 1rem;\n color: var(--date-picker-accent, var(--ty-color-neutral-soft));\n}\n\n.date-picker-stub:hover .stub-arrow {\n color: var(--date-picker-accent-bold, var(--ty-color-neutral));\n}\n\n.date-picker-stub:focus .stub-arrow,\n.date-picker-stub.open .stub-arrow {\n color: var(--date-picker-accent-bold, var(--ty-date-picker-border-focus));\n}\n\n/* Calendar dialog (showModal positioning system) */\n.calendar-dialog {\n position: fixed;\n flex-direction: column;\n max-width: 90vw;\n margin: 0;\n padding: 0;\n border: none;\n background: transparent;\n box-sizing: border-box;\n padding: var(--calendar-padding, 8px);\n\n opacity: 0;\n /* Entrance motion uses the individual scale/translate properties so it\n composes with the collision-shift transform below (they apply first). */\n scale: 0.96;\n translate: 0 -6px;\n transform-origin: top center;\n transition:\n opacity var(--ty-popup-duration, 180ms) var(--ty-popup-ease, cubic-bezier(0.34, 1.56, 0.64, 1)),\n scale var(--ty-popup-duration, 180ms) var(--ty-popup-ease, cubic-bezier(0.34, 1.56, 0.64, 1)),\n translate var(--ty-popup-duration, 180ms) var(--ty-popup-ease, cubic-bezier(0.34, 1.56, 0.64, 1));\n\n transform: translate(var(--calendar-offset-x, 0px), var(--calendar-offset-y, 0px));\n top: -1000px;\n left: -1000px;\n}\n\n.calendar-dialog.position-below {\n left: var(--calendar-x);\n top: var(--calendar-y);\n}\n\n.calendar-dialog.position-above {\n left: var(--calendar-x);\n bottom: var(--calendar-y);\n top: auto;\n flex-direction: column-reverse;\n translate: 0 6px;\n transform-origin: bottom center;\n}\n\n.calendar-dialog.open {\n opacity: 1;\n scale: 1;\n translate: 0 0;\n}\n\n/* First-frame \"from\" values — see select-base.ts: transitions can't start on\n an element that was display:none last frame; @starting-style fixes that. */\n@starting-style {\n .calendar-dialog.open {\n opacity: 0;\n scale: 0.96;\n translate: 0 -6px;\n }\n\n .calendar-dialog.open.position-above {\n translate: 0 6px;\n }\n}\n\n.calendar-dialog::backdrop {\n background: transparent\n}\n\n.calendar-content {\n background-color: var(--ty-calendar-surface-bg);\n border: 1px solid var(--ty-calendar-surface-border);\n border-radius: var(--ty-calendar-surface-radius);\n box-shadow: var(--ty-calendar-surface-shadow);\n overflow: hidden;\n display: flex;\n flex-direction: column;\n align-items: center;\n}\n\n/* Native input is invisible — used only to trigger the OS picker */\n.native-date-input {\n position: absolute;\n inset: 0;\n opacity: 0;\n width: 100%;\n height: 100%;\n margin: 0;\n padding: 0;\n border: none;\n cursor: pointer;\n z-index: 1;\n}\n\n.native-date-input::-webkit-calendar-picker-indicator {\n position: absolute;\n inset: 0;\n width: 100%;\n height: 100%;\n margin: 0;\n padding: 0;\n cursor: pointer;\n}\n\n.time-section {\n display: flex;\n flex-direction: column;\n gap: 0.375rem;\n width: 100%;\n box-sizing: border-box;\n padding: 0.75rem 1rem 0.875rem;\n border-top: 1px solid var(--ty-calendar-time-border);\n background-color: var(--ty-calendar-time-bg);\n}\n\n.time-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 0.75rem;\n}\n\n.time-label {\n display: inline-flex;\n align-items: center;\n gap: 0.5rem;\n font-size: var(--ty-font-sm);\n font-weight: 500;\n color: var(--ty-calendar-time-label-color);\n}\n\n.time-icon {\n display: flex;\n color: var(--ty-calendar-time-icon-color);\n width: 1rem;\n height: 1rem;\n}\n\n.time-fields {\n display: inline-flex;\n align-items: center;\n gap: 0.25rem;\n}\n\n.time-colon {\n font-weight: 600;\n color: var(--ty-calendar-time-label-color);\n}\n\n.time-input {\n width: 2.75rem;\n height: 2.125rem;\n box-sizing: border-box;\n border: 1px solid var(--ty-input-border);\n border-radius: var(--ty-radius-md, 0.5rem);\n background: var(--ty-input-bg);\n color: var(--ty-calendar-time-input-color);\n font-family: inherit;\n font-size: var(--ty-font-base, 0.9375rem);\n font-weight: 500;\n font-variant-numeric: tabular-nums;\n text-align: center;\n padding: 0;\n outline: none;\n caret-color: transparent;\n transition: var(--ty-transition-all);\n}\n\n.time-input::selection {\n background: var(--ty-bg-primary-soft, var(--ty-bg-primary));\n}\n\n.time-input:hover {\n border-color: var(--ty-input-border-hover, var(--ty-input-border));\n}\n\n.time-input:focus {\n border-color: var(--ty-input-border-focus);\n box-shadow: 0 0 0 3px var(--ty-input-shadow-focus);\n}\n\n.time-summary {\n display: flex;\n justify-content: space-between;\n gap: 0.75rem;\n font-size: var(--ty-font-xs, 0.75rem);\n color: var(--ty-calendar-time-label-color);\n}\n\n.time-summary-iso {\n font-family: var(--ty-font-mono, ui-monospace, SFMono-Regular, monospace);\n color: var(--ty-calendar-time-placeholder-color);\n}\n`;\n","/**\n * TyDatePicker Web Component — read-only input stub + calendar dropdown\n * (modal <dialog>), optional time input, form participation via\n * ElementInternals. Value is a UTC instant (wall-clock with `native`);\n * display is local.\n */\n\nimport { ensureStyles } from '../utils/styles.js';\nimport { syncCustomFlavorSheet } from '../utils/flavor-sheet.js';\nimport { ERROR_FLAVOR } from '../utils/error-flavor.js';\nimport { datePickerStyles, datePickerCustomFlavorCss } from '../styles/date-picker.js';\nimport { lockScroll, unlockScroll } from '../utils/scroll-lock.js';\nimport { computeAnchoredPosition, placementToAnchored, type Placement } from '../utils/positioning.js';\nimport { getEffectiveLocale, observeLocaleChanges } from '../utils/locale.js';\nimport { isMobileTouch } from '../utils/mobile.js';\nimport { TyComponent } from '../base/ty-component.js';\nimport type { Flavor } from '../types/common.js';\nimport { DEFAULT_SIZE } from '../types/common.js';\nimport type { PropertyChange } from '../utils/property-manager.js';\nimport { nativeMessage } from '../utils/validity.js';\n\n/**\n * Date components (internal representation in local timezone)\n */\ninterface DateComponents {\n year?: number;\n month?: number; // 1-12\n day?: number;\n hour?: number; // 0-23\n minute?: number; // 0-59\n second?: number; // 0-59\n // The instant a zoned value (ISO with Z/offset, epoch ms) was read from,\n // kept until the user edits: in the hour repeated when summer time ends\n // the wall-clock alone can't say which of the two instants it was.\n epoch?: number;\n}\n\n/**\n * Internal date picker state\n */\ninterface DatePickerState extends DateComponents {\n withTime: boolean;\n open: boolean;\n}\n\ntype DatePickerSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl';\n\n/**\n * Date picker flavors (visual styles)\n */\ntype DatePickerFlavor = 'default' | Flavor;\n\ntype DateFormatType = 'short' | 'medium' | 'long' | 'full';\n\n/**\n * Change event detail\n */\nexport interface DatePickerChangeDetail {\n value: string | null; // What the form submits (see componentsToOutputValue)\n localValue: string | null; // Local \"2024-09-21\", or \"2024-09-21T10:30\" with with-time\n milliseconds: number | null; // Epoch timestamp (date-only: when the day starts locally)\n formatted: string | null; // Local formatted display\n source: 'selection' | 'time-change' | 'clear' | 'external';\n}\n\nconst CALENDAR_ICON_SVG = `<svg stroke='currentColor' fill='none' stroke-width='2' viewBox='0 0 24 24' width='16' height='16' xmlns='http://www.w3.org/2000/svg'><rect x='3' y='4' width='18' height='18' rx='2' ry='2'></rect><line x1='16' y1='2' x2='16' y2='6'></line><line x1='8' y1='2' x2='8' y2='6'></line><line x1='3' y1='10' x2='21' y2='10'></line></svg>`;\n\nconst CLEAR_ICON_SVG = `<svg stroke='currentColor' fill='none' stroke-width='2' viewBox='0 0 24 24' width='14' height='14' xmlns='http://www.w3.org/2000/svg'><line x1='18' y1='6' x2='6' y2='18'></line><line x1='6' y1='6' x2='18' y2='18'></line></svg>`;\n\nconst SCHEDULE_ICON_SVG = `<svg stroke='currentColor' fill='none' stroke-width='2' viewBox='0 0 24 24' width='16' height='16' xmlns='http://www.w3.org/2000/svg'><circle cx='12' cy='12' r='10'></circle><polyline points='12,6 12,12 16,14'></polyline></svg>`;\n\n// Stable per-instance id (survives across full-rebuild re-renders, unlike a\n// fresh Math.random() per render) — used to wire the stub's aria-labelledby\n// to the label element it's paired with. Same pattern as select.ts's\n// getElementHash.\nconst elementIds = new WeakMap<object, number>();\nlet elementIdCounter = 0;\nfunction getElementHash(element: object): number {\n let id = elementIds.get(element);\n if (id === undefined) {\n id = ++elementIdCounter;\n elementIds.set(element, id);\n }\n return id;\n}\n\n/** Zone-less date or date-time ('2024-09-21', '2024-09-21T10:30[:00[.000]]'): local wall-clock. */\nconst LOCAL_VALUE = /^(\\d{4})-(\\d{2})-(\\d{2})(?:[T ](\\d{2}):(\\d{2})(?::(\\d{2})(?:\\.\\d+)?)?)?$/;\n\n/** A Date whose UTC fields are these components: formats a wall-clock as written (timeZone 'UTC'). */\nfunction wallClockDate(c: DateComponents): Date {\n const date = new Date(0);\n date.setUTCFullYear(c.year!, c.month! - 1, c.day!);\n date.setUTCHours(c.hour || 0, c.minute || 0, c.second || 0);\n return date;\n}\n\n/**\n * Parse ANY input format into date/time components.\n * Accepts:\n * - Date only: '2024-09-21' (that calendar day)\n * - Datetime-local: '2024-09-21T10:30[:45]' (local wall-clock)\n * - UTC strings: '2024-09-21T08:30:00Z' or '2024-09-21T08:30:00.000Z'\n * - With timezone: '2024-09-21T10:30:00+02:00'\n * - Timestamps: milliseconds since epoch (a number, not a digit string)\n *\n * A zone-less value is taken as written, even a time the clocks skip when\n * summer time starts (like <input type=datetime-local>); 2024-02-30 or 24:00\n * is no value. An instant reads as its LOCAL day and time, and keeps its\n * epoch. The time is kept in date-only mode too: with-time turned on later\n * shows it.\n */\nfunction parseValue(value: string | number | null | undefined): DateComponents | null {\n if (value === null || value === undefined || value === '') return null;\n\n if (typeof value === 'string') {\n const local = LOCAL_VALUE.exec(value);\n if (local) {\n const [year, month, day, hour, minute, second] = local.slice(1, 7).map((g) => Number(g ?? 0));\n const components = { year, month, day, hour, minute, second };\n const check = wallClockDate(components);\n const real = check.getUTCMonth() === month - 1 && check.getUTCDate() === day &&\n hour < 24 && minute < 60 && second < 60;\n return real ? components : null;\n }\n }\n\n const dateObj = typeof value === 'number' || typeof value === 'string' ? new Date(value) : null;\n if (!dateObj || isNaN(dateObj.getTime())) {\n return null;\n }\n\n // Extract components in LOCAL timezone for display\n return {\n year: dateObj.getFullYear(),\n month: dateObj.getMonth() + 1, // Convert to 1-based\n day: dateObj.getDate(),\n hour: dateObj.getHours(),\n minute: dateObj.getMinutes(),\n second: dateObj.getSeconds(),\n epoch: dateObj.getTime(),\n };\n}\n\n/**\n * Convert internal components to Date object.\n */\nfunction componentsToDateObject(components: DateComponents): Date | null {\n const { year, month, day, hour, minute, second } = components;\n\n if (!year || !month || !day) return null;\n\n // Not the constructor: it reads years 0-99 as 1900-1999. Noon is never\n // skipped by a clock change, so the day can't shift before setHours.\n const date = new Date(2000, 0, 1, 12);\n date.setFullYear(year, month - 1, day);\n date.setHours(hour || 0, minute || 0, second || 0, 0);\n return date;\n}\n\n/** Date-only mode ignores the time it keeps (see parseValue): the day starts at midnight. */\nfunction effectiveComponents(components: DateComponents, withTime: boolean): DateComponents {\n return withTime ? components : { ...components, hour: 0, minute: 0, second: 0, epoch: undefined };\n}\n\n/**\n * Convert internal components to the submitted value.\n *\n * Default — a UTC ISO 8601 instant, unambiguous for a server:\n * - date+time: the picked moment, e.g. '2024-09-21T08:30:00.000Z'\n * - date-only: the moment the day starts in the browser's timezone,\n * e.g. '2024-09-20T22:00:00.000Z' (midnight Sept 21 CEST = 10pm Sept 20 UTC)\n *\n * `native` — wall-clock with no zone, like the browser's own inputs:\n * '2024-09-21' (type=date) or '2024-09-21T10:30' (type=datetime-local).\n */\nfunction componentsToOutputValue(components: DateComponents, withTime: boolean, native: boolean): string | null {\n if (!components.year || !components.month || !components.day) {\n return null;\n }\n\n const c = effectiveComponents(components, withTime);\n if (native) return componentsToLocalValue(c, withTime);\n if (c.epoch !== undefined) return new Date(c.epoch).toISOString();\n const dateObj = componentsToDateObject(c);\n return dateObj ? dateObj.toISOString() : null;\n}\n\n/**\n * Convert internal components to local datetime-local format.\n * \n * For date+time mode: Outputs local datetime without timezone\n * Example: '2024-09-21T10:30' ('2024-09-21T10:30:45' with seconds)\n * \n * For date-only mode: Outputs date only\n * Example: '2024-09-21'\n * \n * This format matches HTML5 <input type=\"datetime-local\"> and is useful\n * for setting other inputs or displaying local time without timezone conversion.\n */\nfunction componentsToLocalValue(components: DateComponents, withTime: boolean): string | null {\n if (!components.year || !components.month || !components.day) {\n return null;\n }\n\n const year = components.year.toString().padStart(4, '0');\n const month = components.month.toString().padStart(2, '0');\n const day = components.day.toString().padStart(2, '0');\n\n if (withTime) {\n const hour = (components.hour || 0).toString().padStart(2, '0');\n const minute = (components.minute || 0).toString().padStart(2, '0');\n const second = components.second ? `:${components.second.toString().padStart(2, '0')}` : '';\n return `${year}-${month}-${day}T${hour}:${minute}${second}`;\n } else {\n return `${year}-${month}-${day}`;\n }\n}\n\n/**\n * The Date to format for display: the local moment, or with `native` the\n * wall-clock as written (formatted in UTC) — a time the clocks skip shows\n * as the value says, not shifted an hour.\n */\nfunction displayDate(components: DateComponents, native: boolean): { date: Date | null; timeZone?: string } {\n return native\n ? { date: wallClockDate(components), timeZone: 'UTC' }\n : { date: componentsToDateObject(components) };\n}\n\n/**\n * Format components for display in input using Intl API.\n */\nfunction formatDisplayValue(\n components: DateComponents,\n formatType: DateFormatType,\n locale: string,\n withTime: boolean,\n native: boolean\n): string | null {\n if (!components.year || !components.month || !components.day) {\n return null;\n }\n\n const { date, timeZone } = displayDate(components, native);\n if (!date) return null;\n\n const options: Intl.DateTimeFormatOptions = {\n dateStyle: formatType || 'long',\n timeZone,\n };\n\n if (withTime) {\n options.timeStyle = 'short';\n }\n\n const formatter = new Intl.DateTimeFormat(locale, options);\n return formatter.format(date);\n}\n\n/**\n * TimeFields drives the two time inputs (hours, minutes) in the popup footer.\n * Each field takes two digits: a first digit that can't start a valid\n * two-digit value (3-9 for hours, 6-9 for minutes) completes the field at\n * once, and a completed hour moves focus to minutes. Arrow Up/Down step the\n * value (wrapping), Backspace in an untouched minutes field goes back to\n * hours, Left/Right cross between the fields.\n */\nclass TimeFields {\n private hour: number;\n private minute: number;\n private typed = '';\n\n constructor(\n private hourEl: HTMLInputElement,\n private minuteEl: HTMLInputElement,\n private onChange: (hour: number, minute: number) => void,\n hour = 0,\n minute = 0,\n ) {\n this.hour = hour;\n this.minute = minute;\n this.paint();\n this.wire(hourEl, 'hour');\n this.wire(minuteEl, 'minute');\n }\n\n private static pad(n: number): string {\n return n.toString().padStart(2, '0');\n }\n\n private paint(): void {\n this.hourEl.value = TimeFields.pad(this.hour);\n this.minuteEl.value = TimeFields.pad(this.minute);\n }\n\n private wire(el: HTMLInputElement, part: 'hour' | 'minute'): void {\n const max = part === 'hour' ? 23 : 59;\n // Largest first digit that can still take a second one (2x hours, 5x minutes)\n const maxLead = part === 'hour' ? 2 : 5;\n\n el.addEventListener('focus', () => {\n this.typed = '';\n el.select();\n });\n el.addEventListener('click', () => el.select());\n el.addEventListener('blur', () => { this.typed = ''; });\n // Everything goes through keydown; swallow stray input (IME, paste)\n el.addEventListener('input', () => this.paint());\n\n el.addEventListener('keydown', (e: KeyboardEvent) => {\n const set = (v: number) => {\n if (part === 'hour') this.hour = v; else this.minute = v;\n this.paint();\n this.onChange(this.hour, this.minute);\n };\n const current = part === 'hour' ? this.hour : this.minute;\n\n if (/^\\d$/.test(e.key)) {\n e.preventDefault();\n const digit = Number(e.key);\n const next = this.typed + e.key;\n const complete = next.length === 2 || (next.length === 1 && digit > maxLead);\n set(Math.min(Number(next), max));\n if (complete) {\n this.typed = '';\n if (part === 'hour') this.minuteEl.focus();\n else el.select();\n } else {\n this.typed = next;\n }\n return;\n }\n\n switch (e.key) {\n case 'ArrowUp':\n case 'ArrowDown': {\n e.preventDefault();\n const delta = e.key === 'ArrowUp' ? 1 : -1;\n this.typed = '';\n set((current + delta + max + 1) % (max + 1));\n el.select();\n return;\n }\n case 'Backspace':\n case 'Delete':\n e.preventDefault();\n if (part === 'minute' && this.typed === '' && e.key === 'Backspace' && current === 0) {\n this.hourEl.focus();\n return;\n }\n this.typed = '';\n set(0);\n el.select();\n return;\n case 'ArrowLeft':\n if (part === 'minute') { e.preventDefault(); this.hourEl.focus(); }\n return;\n case 'ArrowRight':\n if (part === 'hour') { e.preventDefault(); this.minuteEl.focus(); }\n return;\n case 'Tab':\n case 'Escape':\n case 'Enter':\n return;\n default:\n // Letters, ':' etc. — the fields only take digits\n if (e.key.length === 1 && !e.metaKey && !e.ctrlKey) e.preventDefault();\n }\n });\n }\n\n getTime(): { hour: number; minute: number } {\n return { hour: this.hour, minute: this.minute };\n }\n\n setTime(hour: number, minute: number): void {\n this.hour = hour;\n this.minute = minute;\n this.paint();\n }\n}\n\nexport class TyDatePicker extends TyComponent<DatePickerState> {\n protected static properties = {\n // Same placement vocabulary as ty-popup/ty-tooltip/ty-select: a side plus\n // an optional cross-axis alignment (\"bottom-end\", \"top-start\", …). The\n // calendar only lives above or below the field, so left/right degrade to\n // auto-side with the alignment kept. Empty = auto (below when it fits).\n placement: {\n type: 'string' as const,\n visual: true,\n default: '',\n },\n size: {\n type: 'string' as const,\n visual: true,\n default: DEFAULT_SIZE,\n validate: (v: any) => [\"xs\", \"sm\", \"md\", \"lg\", \"xl\"].includes(v),\n coerce: (v: any) => {\n if (![\"xs\", \"sm\", \"md\", \"lg\", \"xl\"].includes(v)) {\n console.warn(`[ty-date-picker] Invalid size '${v}'. Using '${DEFAULT_SIZE}'.`);\n return DEFAULT_SIZE;\n }\n return v;\n }\n },\n flavor: {\n type: 'string' as const,\n visual: true,\n default: 'default'\n },\n label: {\n type: 'string' as const,\n visual: true,\n default: ''\n },\n placeholder: {\n type: 'string' as const,\n visual: true,\n default: 'Select date...'\n },\n name: {\n type: 'string' as const,\n visual: false, // Non-visual, just for form field name\n default: ''\n },\n // Date bounds (ISO) — passed through to the embedded ty-calendar\n min: {\n type: 'string' as const,\n visual: true,\n default: ''\n },\n max: {\n type: 'string' as const,\n visual: true,\n default: ''\n },\n\n required: {\n type: 'boolean' as const,\n visual: true,\n default: false\n },\n disabled: {\n type: 'boolean' as const,\n visual: true,\n default: false\n },\n // Built-in × clear button; no-clear turns it off.\n noClear: {\n type: 'boolean' as const,\n visual: true,\n default: false\n },\n error: {\n type: 'string' as const,\n visual: true,\n default: ''\n },\n\n format: {\n type: 'string' as const,\n visual: true,\n default: 'long',\n validate: (v: any) => ['short', 'medium', 'long', 'full'].includes(v),\n coerce: (v: any) => {\n const validFormats = ['short', 'medium', 'long', 'full'];\n if (!validFormats.includes(v)) {\n console.warn(`[ty-date-picker] Invalid format '${v}'. Using 'long'.`);\n return 'long';\n }\n return v;\n }\n },\n\n locale: {\n type: 'string' as const,\n visual: true,\n default: ''\n },\n\n // Note: Custom getter/setter will handle the complex logic\n value: {\n type: 'string' as const,\n visual: true,\n formValue: true, // Syncs to form\n emitChange: false, // We emit custom 'change' events manually with full detail\n default: null // null when no date selected\n },\n\n 'with-time': {\n type: 'boolean' as const,\n visual: true,\n default: false\n },\n\n // Submit wall-clock values like the browser's own date inputs\n // (see componentsToOutputValue) instead of a UTC instant.\n native: {\n type: 'boolean' as const,\n visual: true,\n default: false\n }\n };\n\n private _state: DatePickerState = {\n withTime: false,\n open: false,\n };\n\n // Event listeners (stored for cleanup)\n private _clickListener?: (e: Event) => void;\n private _keydownListener?: (e: Event) => void;\n private _dialogClickListener?: (e: Event) => void;\n\n // Reopen guard — prevents click event from reopening after pointerdown close\n private _closeTimestamp = 0;\n\n // initializeState() ran (first connect): value/with-time/native changes\n // before that wait for it, and the `value` getter normalizes on the fly.\n private _initialized = false;\n\n // syncFormValue() is writing the value it emits: the 'value' case doesn't\n // read it back (a date-only value would drop the time the picker keeps).\n private _syncing = false;\n\n private _timeInput?: TimeFields;\n\n // Locale observer cleanup\n private _localeObserver?: () => void;\n private _customFlavorSheet: CSSStyleSheet | null = null;\n\n static formAssociated = true;\n\n // observedAttributes is auto-generated by TyComponent from properties config\n\n constructor() {\n super(); // TyComponent handles attachShadow and attachInternals\n\n const shadow = this.shadowRoot!;\n ensureStyles(shadow, { css: datePickerStyles, id: 'ty-date-picker' });\n }\n\n /** TyComponent handles property capture automatically. */\n protected onConnect(): void {\n // Moved in the DOM: keep the state (a date-only value would lose the\n // time it keeps if read back); only the popup is gone.\n if (this._initialized) this._state.open = false;\n else this.initializeState();\n this.syncErrorFlavor();\n\n this.render();\n this.updateFormValue();\n\n // Setup locale observer to watch for ancestor lang changes\n this._localeObserver = observeLocaleChanges(this, () => {\n this.render();\n });\n\n this._syncCustomFlavor();\n }\n\n /** Custom (non-built-in) flavors — see utils/flavor-sheet.ts. */\n private _syncCustomFlavor(): void {\n // 'default' is this component's neutral: map it to a built-in so no\n // custom sheet is generated for it.\n const flavor = this.flavor === 'default' ? 'neutral' : this.flavor;\n this._customFlavorSheet = syncCustomFlavorSheet(\n this.shadowRoot!,\n this._customFlavorSheet,\n flavor,\n ({ base }) => datePickerCustomFlavorCss(base),\n );\n }\n\n protected onDisconnect(): void {\n if (this._localeObserver) {\n this._localeObserver();\n this._localeObserver = undefined;\n }\n\n this.cleanup();\n }\n\n /** Handle state updates BEFORE render. */\n protected onPropertiesChanged(changes: PropertyChange[]): void {\n for (const { name, newValue } of changes) {\n switch (name) {\n case 'flavor':\n // The author picked a flavor while the error showed: theirs now.\n // Unflavored ('default'/'neutral', or none) is no pick: the error\n // shows danger again, the same as when the field starts out that way.\n if (newValue !== 'danger') {\n this.removeAttribute(ERROR_FLAVOR);\n this.syncErrorFlavor();\n }\n this._syncCustomFlavor();\n break;\n\n case 'size':\n case 'label':\n case 'placeholder':\n case 'required':\n case 'disabled':\n this.updateValidity();\n break;\n\n case 'noClear':\n case 'format':\n case 'locale':\n // These properties just affect rendering, no internal state to update\n // TyComponent will call render() automatically for visual properties\n break;\n\n case 'error':\n this.syncErrorFlavor();\n break;\n\n case 'value': {\n // The picker's own output: the state already holds it (and more —\n // the time a date-only value leaves out)\n if (!this._initialized || this._syncing) break;\n // A value from outside replaces the date (null/garbage: clears it)\n this._state = {\n withTime: this._state.withTime,\n open: this._state.open,\n ...parseValue(newValue as string),\n };\n // Heals the property back to the normalized form syncFormValue\n // pushes into ElementInternals — otherwise a raw value (another\n // format, garbage, or one from formResetCallback's\n // setProperty(name, def)) sticks as `.value`, diverging from what\n // FormData submits.\n this.syncFormValue();\n break;\n }\n\n case 'with-time': {\n if (!this._initialized) break;\n const newWithTime = newValue as boolean;\n\n if (newWithTime !== this._state.withTime) {\n this._state.withTime = newWithTime;\n // Same day (and time), new shape\n this.syncFormValue();\n this.updateValidity(); // a date or a datetime-local message\n }\n break;\n }\n\n case 'native':\n // Same day, new shape\n if (this._initialized) this.syncFormValue();\n break;\n }\n }\n }\n\n\n /**\n * Get form value - the submitted string from current state (see\n * componentsToOutputValue). TyComponent calls this automatically when the\n * value property changes.\n */\n protected getFormValue(): FormDataEntryValue | null {\n return this.outputValue(this.getComponents());\n }\n\n private outputValue(components: DateComponents): string | null {\n return componentsToOutputValue(components, this._state.withTime, !!this.getProperty('native'));\n }\n\n protected updateFormValue(): void {\n // Empty submits name= like a native <input type=\"date\">, not nothing\n this._internals.setFormValue(this.getFormValue() ?? '');\n this.updateValidity();\n }\n\n /** The field's focusable element: the stub, or the native input on touch devices. */\n private focusTarget(): HTMLElement | null {\n return this.shadowRoot?.querySelector<HTMLElement>('.native-date-input')\n ?? this.shadowRoot?.querySelector<HTMLElement>('.date-picker-stub')\n ?? null;\n }\n\n /** Focus the field: the host itself isn't focusable. Disabled: nothing, like a native input. */\n focus(options?: FocusOptions): void {\n if (this.getProperty('disabled')) return;\n const target = this.focusTarget();\n if (target) target.focus(options);\n else super.focus(options);\n }\n\n /**\n * `required` used to be cosmetic: nothing reported valueMissing, so an empty\n * required picker never blocked its form. Disabled pickers don't validate.\n * The message is a native date (datetime-local with time) input's.\n */\n private updateValidity(): void {\n if (this.getProperty('disabled') || !this.getProperty('required') || this.getFormValue()) {\n this.applyValidity({});\n return;\n }\n const type = this._state.withTime ? 'datetime-local' : 'date';\n this.applyValidity({ valueMissing: true }, nativeMessage('input', { type, required: true }), this.focusTarget() ?? undefined);\n }\n\n private getComponents(): DateComponents {\n return {\n year: this._state.year,\n month: this._state.month,\n day: this._state.day,\n hour: this._state.hour,\n minute: this._state.minute,\n second: this._state.second,\n epoch: this._state.epoch,\n };\n }\n\n /**\n * Whether internal state has a complete date\n */\n private hasDate(): boolean {\n return !!(this._state.year && this._state.month && this._state.day);\n }\n\n /**\n * Format current components for display using Intl API\n */\n private getFormattedValue(components?: DateComponents): string | null {\n const c = components || this.getComponents();\n if (!c.year || !c.month || !c.day) return null;\n return formatDisplayValue(\n c,\n (this.getProperty('format') as DateFormatType) || 'long',\n getEffectiveLocale(this, this.getProperty('locale')),\n this._state.withTime,\n !!this.getProperty('native')\n );\n }\n\n /**\n * Initialize component state from attributes\n */\n private initializeState(): void {\n this._state = {\n ...parseValue(this.getProperty('value')),\n withTime: this.getProperty('with-time'),\n open: false,\n };\n\n this._initialized = true;\n this.syncFormValue();\n }\n\n private updateState(updates: Partial<DatePickerState>, forceSync: boolean = false): void {\n this._state = { ...this._state, ...updates };\n\n // STAGING: Only sync attributes if dialog is closed OR force-sync is true\n // This prevents re-renders during time input editing\n const shouldSync = forceSync || !this._state.open || !this._state.withTime;\n\n if (shouldSync) {\n this.syncFormValue();\n }\n }\n\n /**\n * Sync form value with current state\n * Compares before setting to prevent circular triggers\n */\n private syncFormValue(): void {\n const formValue = this.getFormValue() as string | null;\n const currentValue = this.getProperty('value');\n\n // Only update property if value actually changed (prevents circular triggers)\n if (formValue !== currentValue) {\n // Use property setter to maintain TyComponent lifecycle\n // This will automatically handle attribute sync and form value update\n this._syncing = true;\n try {\n this.setProperty('value', formValue || null);\n } finally {\n this._syncing = false;\n }\n }\n\n // Form value sync handled automatically by TyComponent (formValue: true)\n }\n\n /**\n * `error` turns an unflavored field ('default'/'neutral') danger, like\n * ty-input; clearing it puts back exactly the flavor attribute the author\n * had, or none, kept meanwhile in ERROR_FLAVOR. Runs once connected: while\n * the element upgrades, `error` may come before the `flavor` written next\n * to it.\n */\n private syncErrorFlavor(): void {\n if (!this._connected) return;\n const flavor = this.getProperty('flavor');\n const replaced = this.getAttribute(ERROR_FLAVOR);\n if (this.getProperty('error')) {\n if (replaced === null && (flavor === 'default' || flavor === 'neutral')) {\n this.setAttribute(ERROR_FLAVOR, this.getAttribute('flavor') ?? '');\n this.setProperty('flavor', 'danger');\n }\n } else if (replaced !== null) {\n this.removeAttribute(ERROR_FLAVOR);\n if (flavor !== 'danger') return;\n if (!replaced) this.removeAttribute('flavor');\n else this.setProperty('flavor', replaced);\n }\n }\n\n /**\n * Handle time changes from the footer's hour/minute fields\n */\n handleTimeInputChange(hour: number, minute: number): void {\n if (!this.hasDate()) return;\n\n // The fields show no seconds: an edited time has none\n const components = { ...this.getComponents(), hour, minute, second: 0, epoch: undefined };\n this.updateState(components, true);\n this.emitChangeEvent(components, 'time-change');\n this.updateTimeSummary();\n this.revealValidity();\n }\n\n /** Footer summary under the time fields: \"Wed, Sep 23 · 14:30\" + local ISO. */\n private updateTimeSummary(summary: Element | null | undefined = this.shadowRoot?.querySelector('.time-summary')): void {\n if (!summary) return;\n const c = this.getComponents();\n const text = summary.querySelector('.time-summary-date') as HTMLElement;\n const iso = summary.querySelector('.time-summary-iso') as HTMLElement;\n if (!c.year || !c.month || !c.day) {\n text.textContent = 'Pick a day';\n iso.textContent = '';\n return;\n }\n const locale = getEffectiveLocale(this, this.getProperty('locale')) || undefined;\n const { date, timeZone } = displayDate(c, !!this.getProperty('native'));\n const day = new Intl.DateTimeFormat(locale, { weekday: 'short', month: 'short', day: 'numeric', timeZone }).format(date!);\n const time = new Intl.DateTimeFormat(locale, { hour: '2-digit', minute: '2-digit', hourCycle: 'h23', timeZone }).format(date!);\n text.textContent = `${day} · ${time}`;\n iso.textContent = componentsToLocalValue(c, true) ?? '';\n }\n\n private emitChangeEvent(components: DateComponents | null, source: 'selection' | 'time-change' | 'clear' | 'external'): void {\n const value = components ? this.outputValue(components) : null;\n const localValue = components ? componentsToLocalValue(components, this._state.withTime) : null;\n const effective = components && effectiveComponents(components, this._state.withTime);\n const milliseconds = effective\n ? effective.epoch ?? componentsToDateObject(effective)?.getTime() ?? null\n : null;\n const formatted = components ? this.getFormattedValue(components) : null;\n\n const detail: DatePickerChangeDetail = {\n value,\n localValue,\n milliseconds,\n formatted,\n source,\n };\n\n const event = new CustomEvent<DatePickerChangeDetail>('change', {\n detail,\n bubbles: true,\n cancelable: true,\n });\n\n this.dispatchEvent(event);\n }\n\n get size(): DatePickerSize { return this.getProperty('size') as DatePickerSize; }\n set size(v: DatePickerSize) { this.setProperty('size', v); }\n\n get placement(): Placement | '' { return this.getProperty('placement') as Placement | ''; }\n set placement(v: Placement | '') { this.setProperty('placement', v); }\n\n get flavor(): DatePickerFlavor { return this.getProperty('flavor') as DatePickerFlavor; }\n set flavor(v: DatePickerFlavor) {\n // Even the danger an error already shows: the author's now, so it stays\n // when the error clears\n this.removeAttribute(ERROR_FLAVOR);\n this.setProperty('flavor', v);\n }\n\n attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void {\n // Same for flavor=\"danger\" written over that danger (React 18 sets props\n // as attributes): the base skips a write that changes nothing.\n if (name === 'flavor' && newValue === 'danger' && oldValue === newValue) this.removeAttribute(ERROR_FLAVOR);\n super.attributeChangedCallback(name, oldValue, newValue);\n }\n\n get label(): string { return this.getProperty('label'); }\n set label(v: string) { this.setProperty('label', v); }\n\n get placeholder(): string { return this.getProperty('placeholder'); }\n set placeholder(v: string) { this.setProperty('placeholder', v); }\n\n get name(): string { return this.getProperty('name'); }\n set name(v: string) { this.setProperty('name', v); }\n\n get format(): DateFormatType { return this.getProperty('format') as DateFormatType; }\n set format(v: DateFormatType) { this.setProperty('format', v); }\n\n get locale(): string { return this.getProperty('locale'); }\n set locale(v: string) { this.setProperty('locale', v); }\n\n get required(): boolean { return this.getProperty('required'); }\n set required(v: boolean) { this.setProperty('required', v); }\n\n get disabled(): boolean { return this.getProperty('disabled'); }\n set disabled(v: boolean) { this.setProperty('disabled', v); }\n\n get noClear(): boolean { return this.getProperty('noClear'); }\n set noClear(v: boolean) { this.setProperty('noClear', v); }\n\n get min(): string { return this.getProperty('min'); }\n set min(v: string) { this.setProperty('min', v ?? ''); }\n\n get max(): string { return this.getProperty('max'); }\n set max(v: string) { this.setProperty('max', v ?? ''); }\n\n get withTime(): boolean { return this.getProperty('with-time'); }\n set withTime(v: boolean) { this.setProperty('with-time', v); }\n\n get native(): boolean { return this.getProperty('native'); }\n set native(v: boolean) { this.setProperty('native', v); }\n\n get error(): string { return this.getProperty('error'); }\n set error(v: string) { this.setProperty('error', v); }\n\n // Value keeps custom accessors (format normalization)\n /**\n * Get current value — the string the form submits: a UTC ISO instant, or\n * wall-clock ('YYYY-MM-DD' / 'YYYY-MM-DDTHH:mm') with `native`. null when\n * empty (the form then submits name=, like a native date input).\n */\n get value(): string | null {\n if (this._initialized) return this.getProperty('value') || null;\n // Not connected yet: the raw value, as it will submit once it is\n const parsed = parseValue(this.getProperty('value'));\n return parsed && componentsToOutputValue(parsed, !!this.getProperty('with-time'), !!this.getProperty('native'));\n }\n\n /**\n * Set value: any format parseValue() reads, a Date, epoch milliseconds,\n * or null. It's normalized to the submitted form.\n *\n * When set to null/undefined/empty string, the attribute is removed.\n */\n set value(val: string | number | Date | null) {\n if (val === null || val === undefined || val === '') {\n this.setProperty('value', null); // TyComponent will remove attribute\n } else if (typeof val === 'string') {\n this.setProperty('value', val);\n } else {\n const date = new Date(val);\n this.setProperty('value', isNaN(date.getTime()) ? null : date.toISOString());\n }\n }\n\n /**\n * Clear the date value programmatically WITH a change event (source:\n * 'clear'). Works regardless of `no-clear` — lets any\n * external trigger (e.g. a button elsewhere in the page) clear the value\n * without needing the built-in clear button. Mirrors ty-select's clear().\n */\n clear(): void {\n this.clearValue();\n }\n\n private buildStubClasses(): string {\n const classes = ['date-picker-stub'];\n\n if (this.getProperty('disabled')) classes.push('disabled');\n if (this.getProperty('required')) classes.push('required');\n if (this.getProperty('error')) classes.push('error');\n if (this._state.open) classes.push('open');\n\n return classes.join(' ');\n }\n\n private renderStub(): HTMLElement {\n const stub = document.createElement('div');\n stub.className = this.buildStubClasses();\n\n const isDisabled = this.getProperty('disabled');\n if (isDisabled) {\n stub.setAttribute('disabled', 'true');\n }\n\n // Not text-editable (click/Enter/Space just opens the calendar dialog),\n // so role=\"button\" — not role=\"combobox\", which implies typing. The\n // popup is a real <dialog> opened via showModal() (see openDropdown),\n // so it already gets role=\"dialog\" + focus-trap from the browser for\n // free; only the trigger itself needs wiring.\n stub.setAttribute('role', 'button');\n stub.setAttribute('aria-haspopup', 'dialog');\n stub.setAttribute('aria-expanded', String(this._state.open));\n stub.setAttribute('tabindex', isDisabled ? '-1' : '0');\n if (isDisabled) stub.setAttribute('aria-disabled', 'true');\n if (this.getProperty('label')) {\n stub.setAttribute('aria-labelledby', `date-picker-label-${getElementHash(this)}`);\n }\n // Same gap as ty-select had: a plain div's Enter/Space don't turn into\n // click events on their own, so without this a keyboard-only user could\n // Tab to the field but never open it.\n stub.addEventListener('keydown', (e: Event) => {\n const ke = e as KeyboardEvent;\n // Only the stub's own keys: Enter/Space on the clear button clear\n if (this._state.open || e.target !== stub) return;\n if (ke.key === 'Enter' || ke.key === ' ') {\n ke.preventDefault();\n this.handleStubClick(e);\n }\n });\n\n // Start slot — leading icon (search, calendar variant, etc.)\n const startSlot = document.createElement('slot');\n startSlot.name = 'start';\n\n const displayText = document.createElement('span');\n displayText.className = 'stub-text';\n\n const formattedValue = this.getFormattedValue();\n const placeholder = this.getProperty('placeholder') || 'Select date...';\n displayText.textContent = formattedValue || placeholder;\n\n if (!formattedValue) {\n displayText.classList.add('placeholder');\n }\n\n const iconContainer = document.createElement('div');\n iconContainer.className = 'stub-icons';\n\n const clearable = !this.getProperty('noClear');\n if (clearable && formattedValue && !isDisabled) {\n const clearButton = document.createElement('button');\n clearButton.className = 'stub-clear';\n clearButton.type = 'button';\n clearButton.innerHTML = CLEAR_ICON_SVG;\n clearButton.addEventListener('click', (e) => this.handleClearClick(e));\n iconContainer.appendChild(clearButton);\n }\n\n const calendarIcon = document.createElement('span');\n calendarIcon.className = 'stub-arrow';\n calendarIcon.innerHTML = CALENDAR_ICON_SVG;\n iconContainer.appendChild(calendarIcon);\n\n stub.addEventListener('click', (e) => this.handleStubClick(e));\n\n stub.appendChild(startSlot);\n stub.appendChild(displayText);\n stub.appendChild(iconContainer);\n\n return stub;\n }\n\n private createTimeField(part: 'hour' | 'minute'): HTMLInputElement {\n const input = document.createElement('input');\n input.type = 'text';\n input.className = `time-input time-${part}`;\n input.inputMode = 'numeric';\n input.autocomplete = 'off';\n input.maxLength = 2;\n input.setAttribute('aria-label', part === 'hour' ? 'Hours' : 'Minutes');\n return input;\n }\n\n /** Footer: clock + \"Time\" on the left, HH : MM on the right, summary below. */\n private renderTimeSection(): HTMLElement {\n const timeSection = document.createElement('div');\n timeSection.className = 'time-section';\n timeSection.setAttribute('role', 'group');\n timeSection.setAttribute('aria-label', 'Time');\n\n const row = document.createElement('div');\n row.className = 'time-row';\n\n const label = document.createElement('span');\n label.className = 'time-label';\n const icon = document.createElement('span');\n icon.className = 'time-icon';\n icon.innerHTML = SCHEDULE_ICON_SVG;\n label.appendChild(icon);\n label.appendChild(document.createTextNode('Time'));\n\n const fields = document.createElement('div');\n fields.className = 'time-fields';\n const hourEl = this.createTimeField('hour');\n const minuteEl = this.createTimeField('minute');\n const colon = document.createElement('span');\n colon.className = 'time-colon';\n colon.textContent = ':';\n fields.appendChild(hourEl);\n fields.appendChild(colon);\n fields.appendChild(minuteEl);\n\n this._timeInput = new TimeFields(\n hourEl,\n minuteEl,\n (hour, minute) => this.handleTimeInputChange(hour, minute),\n this._state.hour || 0,\n this._state.minute || 0,\n );\n\n row.appendChild(label);\n row.appendChild(fields);\n\n const summary = document.createElement('div');\n summary.className = 'time-summary';\n summary.setAttribute('aria-live', 'polite');\n const summaryDate = document.createElement('span');\n summaryDate.className = 'time-summary-date';\n const summaryIso = document.createElement('span');\n summaryIso.className = 'time-summary-iso';\n summary.appendChild(summaryDate);\n summary.appendChild(summaryIso);\n\n this.updateTimeSummary(summary);\n\n timeSection.appendChild(row);\n timeSection.appendChild(summary);\n return timeSection;\n }\n\n private renderCalendarDropdown(): HTMLDialogElement {\n const dialog = document.createElement('dialog');\n dialog.className = 'calendar-dialog';\n\n const contentWrapper = document.createElement('div');\n contentWrapper.className = 'calendar-content';\n\n const calendar = document.createElement('ty-calendar') as any;\n\n if (this._state.year && this._state.month && this._state.day) {\n calendar.setAttribute('year', this._state.year.toString());\n calendar.setAttribute('month', this._state.month.toString());\n calendar.setAttribute('day', this._state.day.toString());\n }\n\n const locale = getEffectiveLocale(this, this.getProperty('locale'));\n if (locale) {\n calendar.setAttribute('locale', locale);\n }\n\n const min = this.getProperty('min');\n const max = this.getProperty('max');\n if (min) calendar.setAttribute('min', min);\n if (max) calendar.setAttribute('max', max);\n\n const flavor = this.calendarFlavor();\n if (flavor) calendar.setAttribute('flavor', flavor);\n\n calendar.addEventListener('change', (e: Event) => this.handleCalendarChange(e));\n\n contentWrapper.appendChild(calendar);\n\n if (this._state.withTime) {\n contentWrapper.appendChild(this.renderTimeSection());\n }\n\n dialog.appendChild(contentWrapper);\n\n // Closed by someone else — a ty-modal around the picker closes the\n // dialogs still open inside it: run our own close, so the open state,\n // aria-expanded and the scroll lock follow. The `open` attribute, not the\n // `close` event: that one comes a task later, so right after modal.hide()\n // the stub would still say expanded. Our own close lands here with the\n // state already closed, a picker removed meanwhile has cleaned up\n // (onDisconnect): both no-ops.\n new MutationObserver(() => {\n if (this._state.open && !dialog.open && this.isConnected) this.closeDropdown();\n }).observe(dialog, { attributes: true, attributeFilter: ['open'] });\n\n return dialog;\n }\n\n /**\n * Match the popup calendar to the stub's flavor — the one the user set, not\n * the danger an error swapped in. 'default' is the stub's own unstyled\n * state, not a real flavor: the calendar stays on its own default.\n */\n private calendarFlavor(): string | null {\n const replaced = this.getAttribute(ERROR_FLAVOR);\n const flavor = replaced ?? this.getProperty('flavor');\n return flavor && flavor !== 'default' ? flavor : null;\n }\n\n /**\n * Render native date input for mobile touch devices.\n * Uses <input type=\"date\"> or <input type=\"datetime-local\"> when with-time.\n * Reuses .date-picker-stub styling and existing event/state infrastructure.\n */\n private renderNativeInput(): HTMLElement {\n const wrapper = document.createElement('div');\n wrapper.className = 'dropdown-wrapper';\n\n const stub = document.createElement('div');\n stub.className = this.buildStubClasses();\n\n const isDisabled = this.getProperty('disabled');\n if (isDisabled) {\n stub.setAttribute('disabled', 'true');\n }\n\n // Native input (hidden, activated via picker indicator)\n const input = document.createElement('input');\n input.className = 'native-date-input';\n this.syncNativeInput(input);\n const localValue = input.value;\n\n // Placeholder span (native date inputs ignore placeholder attr)\n const placeholder = this.getProperty('placeholder') || 'Select date...';\n const formattedValue = this.getFormattedValue();\n const placeholderEl = document.createElement('span');\n placeholderEl.className = 'stub-text' + (formattedValue ? '' : ' placeholder');\n placeholderEl.textContent = formattedValue || placeholder;\n\n input.addEventListener('change', () => {\n if (!input.value) {\n this.clearValue();\n } else {\n const parsed = parseValue(input.value);\n if (parsed) {\n // A new day (type=date) keeps the time, like the calendar; a\n // user edit drops the loaded instant\n const { hour, minute, second } = this._state.withTime ? parsed : this._state;\n const components = { ...parsed, hour, minute, second, epoch: undefined };\n this.updateState(components, true);\n this.emitChangeEvent(components, 'selection');\n }\n }\n this.revealValidity();\n });\n\n // Start slot — leading icon\n const startSlot = document.createElement('slot');\n startSlot.name = 'start';\n\n stub.appendChild(startSlot);\n stub.appendChild(input);\n stub.appendChild(placeholderEl);\n\n const iconContainer = document.createElement('div');\n iconContainer.className = 'stub-icons';\n\n const clearable = !this.getProperty('noClear');\n if (clearable && localValue && !isDisabled) {\n const clearButton = document.createElement('button');\n clearButton.className = 'stub-clear';\n clearButton.type = 'button';\n clearButton.innerHTML = CLEAR_ICON_SVG;\n clearButton.addEventListener('click', (e) => this.handleClearClick(e));\n iconContainer.appendChild(clearButton);\n }\n\n const calendarIcon = document.createElement('span');\n calendarIcon.className = 'stub-arrow';\n calendarIcon.innerHTML = CALENDAR_ICON_SVG;\n iconContainer.appendChild(calendarIcon);\n\n stub.appendChild(iconContainer);\n\n wrapper.appendChild(stub);\n\n return wrapper;\n }\n\n\n /**\n * The touch devices' native input follows the picker: type (date, or\n * datetime-local with time), disabled, required, min/max (datetime-local\n * wants a time suffix) and value — also when they change at runtime.\n */\n private syncNativeInput(input: HTMLInputElement): void {\n const withTime = this._state.withTime;\n // Type first: the value is sanitized for the type it's set under\n input.type = withTime ? 'datetime-local' : 'date';\n input.disabled = !!this.getProperty('disabled');\n input.required = !!this.getProperty('required');\n const min = this.getProperty('min');\n const max = this.getProperty('max');\n if (min) input.min = withTime ? `${min}T00:00` : min;\n else input.removeAttribute('min');\n if (max) input.max = withTime ? `${max}T23:59` : max;\n else input.removeAttribute('max');\n input.value = componentsToLocalValue(this.getComponents(), withTime) ?? '';\n }\n\n private calculateCalendarPosition(): void {\n if (!this.shadowRoot) return;\n\n // Mobile uses native input, no positioning needed\n if (isMobileTouch()) return;\n\n const stub = this.shadowRoot.querySelector('.date-picker-stub') as HTMLElement;\n const dialog = this.shadowRoot.querySelector('.calendar-dialog') as HTMLElement;\n\n if (!stub || !dialog) return;\n\n const stubRect = stub.getBoundingClientRect();\n\n // Measure when shown; the estimate only covers the pre-layout call\n const dialogRect = dialog.getBoundingClientRect();\n const estimatedHeight = dialogRect.height || 400;\n const popupWidth = dialogRect.width || 320;\n\n const wrapPadding = 8;\n\n const anchored = placementToAnchored(\n this.getProperty('placement') as Placement | ''\n );\n\n const pos = computeAnchoredPosition({\n anchorRect: stubRect,\n popupWidth,\n popupHeight: estimatedHeight,\n // gap 0 IS the unified 8px visual offset: the dialog's --calendar-padding\n // (8px) is not compensated on y (unlike select's wrapPadding), so the\n // calendar face already sits 8px from the trigger.\n gap: 0,\n align: anchored.align,\n side: anchored.side,\n });\n const positionBelow = pos.below;\n\n const x = pos.x - wrapPadding;\n const y = positionBelow ? pos.topY : pos.bottomY;\n\n this.style.setProperty('--calendar-x', `${x}px`);\n this.style.setProperty('--calendar-y', `${y}px`);\n this.style.setProperty('--calendar-offset-x', '0px');\n this.style.setProperty('--calendar-offset-y', '0px');\n\n if (positionBelow) {\n dialog.classList.add('position-below');\n dialog.classList.remove('position-above');\n } else {\n dialog.classList.add('position-above');\n dialog.classList.remove('position-below');\n }\n }\n\n private renderContainer(): HTMLElement {\n const container = document.createElement('div');\n container.className = 'dropdown-container';\n\n const label = this.getProperty('label');\n\n if (label) {\n const labelEl = document.createElement('label');\n labelEl.className = 'ty-field-label';\n labelEl.id = `date-picker-label-${getElementHash(this)}`;\n labelEl.innerHTML = label + (this.getProperty('required') ? '<span class=\"required-icon\">*</span>' : '');\n container.appendChild(labelEl);\n }\n\n return container;\n }\n\n protected render(): void {\n if (!this.shadowRoot) return;\n\n ensureStyles(this.shadowRoot, { css: datePickerStyles, id: 'ty-date-picker' });\n\n // Mobile: native input, no dialog/event listeners/scroll lock\n if (isMobileTouch()) {\n const existingNativeInput = this.shadowRoot.querySelector('.native-date-input');\n if (existingNativeInput) {\n // PARTIAL UPDATE: don't destroy DOM while native picker may be open\n this.updateDisplay();\n return;\n }\n // FIRST RENDER: build from scratch\n this.shadowRoot.innerHTML = '';\n const container = this.renderContainer();\n container.appendChild(this.renderNativeInput());\n this.shadowRoot.appendChild(container);\n this.syncErrorLine();\n this.updateValidity(); // re-anchor to the new field\n return;\n }\n\n const existingDialog = this.shadowRoot.querySelector('.calendar-dialog') as HTMLDialogElement;\n const isDialogOpen = existingDialog && existingDialog.open;\n\n if (isDialogOpen && this._state.open) {\n // PARTIAL UPDATE: Dialog is open - just update display\n this.updateDisplay();\n this.calculateCalendarPosition();\n return;\n }\n\n // FULL REBUILD: Dialog is closed or doesn't exist. It replaces the\n // focused stub (an `error` a form library sets after focusing the\n // field, a clear): the focus stays on the field, like ty-input's.\n const hadFocus = !!this.shadowRoot.activeElement;\n this.shadowRoot.innerHTML = '';\n\n const container = this.renderContainer();\n const wrapper = document.createElement('div');\n wrapper.className = 'dropdown-wrapper';\n\n wrapper.appendChild(this.renderStub());\n wrapper.appendChild(this.renderCalendarDropdown());\n\n container.appendChild(wrapper);\n this.shadowRoot.appendChild(container);\n this.syncErrorLine();\n\n this.setupEventListeners();\n this.updateValidity(); // re-anchor to the new stub\n if (hadFocus) this.focus({ preventScroll: true });\n }\n\n /**\n * The `error` line under the field — same markup as ty-input's; the field\n * (stub, or the native input on touch devices) is described by it.\n */\n private syncErrorLine(): void {\n const container = this.shadowRoot?.querySelector('.dropdown-container');\n if (!container) return;\n const error = this.getProperty('error');\n const errorId = `date-picker-error-${getElementHash(this)}`;\n let line = container.querySelector(':scope > .error-message');\n if (error) {\n if (!line) {\n line = document.createElement('div');\n line.className = 'error-message';\n line.id = errorId;\n container.appendChild(line);\n }\n line.textContent = error;\n this.focusTarget()?.setAttribute('aria-describedby', errorId);\n } else {\n line?.remove();\n this.focusTarget()?.removeAttribute('aria-describedby');\n }\n }\n\n /**\n * Update display without destroying DOM (for open dialog)\n */\n private updateDisplay(): void {\n if (!this.shadowRoot) return;\n\n const formattedValue = this.getFormattedValue();\n const placeholder = this.getProperty('placeholder') || 'Select date...';\n const hasValue = this.hasDate();\n const clearable = !this.getProperty('noClear');\n const isDisabled = this.getProperty('disabled');\n\n // Update stub text (shared between mobile and desktop)\n const stubText = this.shadowRoot.querySelector('.stub-text');\n if (stubText) {\n stubText.textContent = formattedValue || placeholder;\n stubText.classList.toggle('placeholder', !formattedValue);\n }\n\n const clearButton = this.shadowRoot.querySelector('.stub-clear') as HTMLElement;\n if (clearButton) {\n clearButton.style.display = (clearable && hasValue && !isDisabled) ? '' : 'none';\n }\n\n const stub = this.shadowRoot.querySelector('.date-picker-stub');\n if (stub) stub.className = this.buildStubClasses();\n this.syncErrorLine();\n\n // Mobile: also sync the native input (with-time may have changed its type)\n if (isMobileTouch()) {\n const nativeInput = this.shadowRoot.querySelector('.native-date-input') as HTMLInputElement;\n if (nativeInput) this.syncNativeInput(nativeInput);\n stub?.toggleAttribute('disabled', !!isDisabled);\n return;\n }\n\n // Desktop: update calendar and time input\n const calendar = this.shadowRoot.querySelector('ty-calendar') as any;\n if (calendar && hasValue) {\n calendar.setAttribute('year', this._state.year!.toString());\n calendar.setAttribute('month', this._state.month!.toString());\n calendar.setAttribute('day', this._state.day!.toString());\n }\n\n // Keep an already-open popup's flavor/bounds in sync. render() only\n // rebuilds (and re-forwards these) while the dialog is CLOSED — while\n // open it takes this partial-update path instead, so without this the\n // calendar would stay stuck on whatever flavor/min/max was active when\n // it was opened.\n if (calendar) {\n const flavor = this.calendarFlavor();\n if (flavor) calendar.setAttribute('flavor', flavor);\n else calendar.removeAttribute('flavor');\n\n const min = this.getProperty('min');\n const max = this.getProperty('max');\n if (min) calendar.setAttribute('min', min);\n else calendar.removeAttribute('min');\n if (max) calendar.setAttribute('max', max);\n else calendar.removeAttribute('max');\n }\n\n if (this._timeInput && this._state.hour !== undefined && this._state.minute !== undefined) {\n this._timeInput.setTime(this._state.hour, this._state.minute);\n }\n this.updateTimeSummary();\n }\n\n private setupEventListeners(): void {\n if (this._clickListener) {\n document.removeEventListener('click', this._clickListener);\n }\n if (this._keydownListener) {\n document.removeEventListener('keydown', this._keydownListener);\n }\n\n this._clickListener = (e: Event) => this.handleOutsideClick(e);\n this._keydownListener = (e: Event) => this.handleEscapeKey(e);\n\n document.addEventListener('click', this._clickListener);\n document.addEventListener('keydown', this._keydownListener);\n\n const dialog = this.shadowRoot?.querySelector('.calendar-dialog');\n if (dialog) {\n this._dialogClickListener = (e: Event) => this.handleDialogClick(e);\n dialog.addEventListener('click', this._dialogClickListener);\n }\n }\n\n private handleStubClick(event: Event): void {\n event.preventDefault();\n\n // Heal state/DOM desync: a host re-render can replace the dialog element\n // while `open` is still true, stranding the picker (openDropdown\n // early-returns on _state.open). Reality wins: closed dialog → closed state.\n const dialog = this.shadowRoot?.querySelector('.calendar-dialog') as HTMLDialogElement | null;\n if (this._state.open && (!dialog || !dialog.open)) {\n this.updateState({ open: false }, true);\n unlockScroll(`date-picker-${getElementHash(this)}`);\n }\n\n const disabled = this.getProperty('disabled');\n // FIXME: Timestamp guard is a workaround. Calendar day cells use pointerdown,\n // which closes the dialog before the click event fires — the click then hits the\n // stub and reopens. Proper fix: switch calendar-month day cells from pointerdown\n // to click so the event is consumed before the dialog closes.\n if (!disabled && Date.now() - this._closeTimestamp > 300) {\n this.openDropdown();\n }\n }\n\n /**\n * Clear the date value, sync state, emit event, and re-render.\n */\n private clearValue(): void {\n this.updateState({\n year: undefined,\n month: undefined,\n day: undefined,\n hour: undefined,\n minute: undefined,\n second: undefined,\n epoch: undefined,\n }, true);\n\n this.value = null;\n this.emitChangeEvent(null, 'clear');\n this.render();\n }\n\n private handleClearClick(event: Event): void {\n event.preventDefault();\n event.stopPropagation();\n this.clearValue();\n // Touch devices: the × just went display:none (updateDisplay) and takes\n // the focus with it; the desktop rebuild keeps it on the stub already.\n // Focus the app's change handler moved elsewhere stays there.\n const active = document.activeElement;\n if (this.matches(':focus-within') || !active || active === document.body) {\n this.shadowRoot?.querySelector<HTMLElement>('.native-date-input')?.focus({ preventScroll: true });\n }\n // A user change: show the message now if that left the field invalid\n this.revealValidity();\n }\n\n private handleCalendarChange(event: Event): void {\n event.preventDefault();\n event.stopPropagation();\n\n const customEvent = event as CustomEvent;\n const detail = customEvent.detail;\n const dayContext = detail.dayContext;\n\n if (!dayContext) return;\n\n const newComponents: DateComponents = {\n year: dayContext.year,\n month: dayContext.month,\n day: dayContext.dayInMonth,\n hour: this._state.hour,\n minute: this._state.minute,\n second: this._state.second,\n epoch: undefined,\n };\n\n // Force sync when calendar date changes\n this.updateState(newComponents, true);\n this.emitChangeEvent(newComponents, 'selection');\n this.revealValidity();\n\n if (!this._state.withTime) {\n this.closeDropdown();\n } else {\n // Auto-focus time input after date selection\n requestAnimationFrame(() => {\n if (!this.shadowRoot) return;\n this.updateTimeSummary();\n const timeInput = this.shadowRoot.querySelector('.time-hour') as HTMLInputElement;\n if (timeInput) {\n timeInput.focus();\n }\n });\n }\n }\n\n private handleDialogClick(event: Event): void {\n if (!this.shadowRoot) return;\n\n const dialog = this.shadowRoot.querySelector('.calendar-dialog');\n const content = this.shadowRoot.querySelector('.calendar-content');\n\n // Close if clicking on dialog backdrop (not calendar content)\n if (event.target === dialog && this._state.open && content && !content.contains(event.target as Node)) {\n event.preventDefault();\n event.stopPropagation();\n this.closeDropdown();\n }\n }\n\n private handleOutsideClick(event: Event): void {\n if (!this.shadowRoot) return;\n\n const target = event.target as Node;\n const dialog = this.shadowRoot.querySelector('.calendar-dialog');\n\n if (this._state.open && dialog && !this.contains(target) && !dialog.contains(target)) {\n this.closeDropdown();\n }\n }\n\n private handleEscapeKey(event: Event): void {\n const keyboardEvent = event as KeyboardEvent;\n\n if (keyboardEvent.key === 'Escape' && this._state.open) {\n keyboardEvent.preventDefault();\n this.closeDropdown();\n }\n }\n\n private openDropdown(): void {\n if (this._state.open) return;\n if (isMobileTouch()) return;\n\n this.updateState({ open: true });\n\n // ponytail: non-bubbling, like native <dialog> — a bubbling open/close\n // from a picker nested in ty-modal hits the modal's own listeners.\n this.dispatchEvent(new CustomEvent('open'));\n\n this.render();\n\n requestAnimationFrame(() => {\n if (!this.shadowRoot) return;\n // Closed or removed since (removal cleaned up already), or no longer\n // shown: a ty-modal around it closed in the same task. showModal()\n // would throw on a detached dialog, or float the calendar over the\n // page with the scroll locked and nothing left to close it.\n if (!this._state.open || !this.isConnected) return;\n if (this.shadowRoot.querySelector('.date-picker-stub')?.checkVisibility() === false) {\n this.closeDropdown();\n return;\n }\n\n const dialog = this.shadowRoot.querySelector('.calendar-dialog') as HTMLDialogElement;\n if (dialog) {\n const pickerId = `date-picker-${getElementHash(this)}`;\n lockScroll(pickerId);\n\n dialog.showModal();\n this.calculateCalendarPosition();\n dialog.classList.add('open');\n\n const stubEl = this.shadowRoot.querySelector('.date-picker-stub');\n if (stubEl) stubEl.setAttribute('aria-expanded', 'true');\n\n // Remove focus from any focused elements to prevent the blue outline\n const focusedElement = this.shadowRoot.activeElement as HTMLElement;\n if (focusedElement) {\n focusedElement.blur();\n }\n }\n });\n }\n\n private closeDropdown(): void {\n if (!this._state.open) return;\n\n this._closeTimestamp = Date.now();\n const pickerId = `date-picker-${getElementHash(this)}`;\n\n // Force sync any staged updates when closing\n this.updateState({ open: false }, true);\n\n unlockScroll(pickerId);\n\n if (this.shadowRoot) {\n const dialog = this.shadowRoot.querySelector('.calendar-dialog') as HTMLDialogElement;\n if (dialog) {\n dialog.classList.remove('position-above', 'position-below', 'open');\n dialog.close();\n }\n // closeDropdown() doesn't call render(), so the stub's aria-expanded\n // (still \"true\" from open) needs an explicit flip here too.\n const stubEl = this.shadowRoot.querySelector('.date-picker-stub');\n if (stubEl) stubEl.setAttribute('aria-expanded', 'false');\n }\n\n // ponytail: non-bubbling, see openDropdown()\n this.dispatchEvent(new CustomEvent('close'));\n\n this.render();\n // Back on the field (the rebuilt stub), like a native picker closing\n this.focus();\n }\n\n private cleanup(): void {\n if (this._clickListener) {\n document.removeEventListener('click', this._clickListener);\n }\n if (this._keydownListener) {\n document.removeEventListener('keydown', this._keydownListener);\n }\n\n if (this._dialogClickListener && this.shadowRoot) {\n const dialog = this.shadowRoot.querySelector('.calendar-dialog');\n if (dialog) {\n dialog.removeEventListener('click', this._dialogClickListener);\n }\n }\n\n if (this._state.open) {\n const pickerId = `date-picker-${getElementHash(this)}`;\n unlockScroll(pickerId);\n }\n\n this._clickListener = undefined;\n this._keydownListener = undefined;\n this._dialogClickListener = undefined;\n this._timeInput = undefined;\n }\n}\n\nif (!customElements.get('ty-date-picker')) {\n customElements.define('ty-date-picker', TyDatePicker);\n}","/**\n * TyResizeObserver styles\n * Minimal styling - just ensures component participates in layout\n */\n\nexport const resizeObserverStyles = `\n:host {\n /* Default to block display, user can override */\n display: block;\n position: relative;\n}\n\n::slotted(*) {\n /* No default styling - preserve natural layout */\n}\n`\n","/**\n * Resize Observer Registry & Callbacks\n * \n * Provides global registry for element sizes and optional callback subscriptions.\n */\n\nexport interface ElementSize {\n width: number\n height: number\n}\n\nexport type ResizeCallback = (size: ElementSize) => void\n\nconst sizes = new Map<string, ElementSize>()\nconst callbacks = new Map<string, Set<ResizeCallback>>()\n\n/**\n * Get current size for element by ID (sync query)\n * \n * @example\n * const size = getSize('parent-container')\n * if (size) console.log(`Width: ${size.width}px`)\n */\nexport function getSize(id: string): ElementSize | undefined {\n return sizes.get(id)\n}\n\n/**\n * Subscribe to size changes for element by ID\n * Returns unsubscribe function\n * \n * @example\n * const unsubscribe = onResize('parent', ({ width, height }) => {\n * console.log(`Resized to ${width}x${height}`)\n * })\n * // Later: unsubscribe()\n */\nexport function onResize(id: string, callback: ResizeCallback): () => void {\n if (!callbacks.has(id)) {\n callbacks.set(id, new Set())\n }\n callbacks.get(id)!.add(callback)\n\n // Call immediately with current size if available\n const current = sizes.get(id)\n if (current) callback(current)\n\n return () => {\n callbacks.get(id)?.delete(callback)\n if (callbacks.get(id)?.size === 0) {\n callbacks.delete(id)\n }\n }\n}\n\n/**\n * Get all registered sizes (for debugging/window API)\n */\nexport function getAllSizes(): Record<string, ElementSize> {\n return Object.fromEntries(sizes)\n}\n\n/**\n * Internal: Update size in registry and notify callbacks\n */\nexport function updateSize(id: string, width: number, height: number): void {\n sizes.set(id, { width, height })\n\n const cbs = callbacks.get(id)\n if (cbs) {\n const size = { width, height }\n cbs.forEach(cb => cb(size))\n }\n}\n\n/**\n * Internal: Remove size from registry and cleanup callbacks\n */\nexport function removeSize(id: string): void {\n sizes.delete(id)\n callbacks.delete(id)\n}","/**\n * TyResizeObserver Web Component - self-observing element that tracks its own\n * dimensions in a global registry keyed by element ID. Optional debounce.\n */\n\nimport { ensureStyles } from '../utils/styles.js'\nimport { resizeObserverStyles } from '../styles/resize-observer.js'\nimport { updateSize, removeSize } from '../utils/resize-observer.js'\nimport { upgradeProperties } from '../utils/upgrade-properties.js'\n\nexport class TyResizeObserver extends HTMLElement {\n private _resizeObserver: ResizeObserver | null = null\n private _debounceTimer: number | null = null\n\n static get observedAttributes(): string[] {\n return ['id', 'debounce']\n }\n\n /**\n * Debounce in milliseconds (default: 0 = no debounce)\n */\n get debounce(): number {\n return parseInt(this.getAttribute('debounce') || '0')\n }\n\n set debounce(value: number) {\n this.setAttribute('debounce', String(value))\n }\n\n constructor() {\n super()\n\n const shadow = this.attachShadow({ mode: 'open' })\n ensureStyles(shadow, { css: resizeObserverStyles, id: 'ty-resize-observer' })\n\n shadow.innerHTML = '<slot></slot>'\n }\n\n connectedCallback(): void {\n upgradeProperties(this)\n this.setupObserver()\n }\n\n attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void {\n // Renaming the id must migrate the registry entry — otherwise the old\n // key stays registered forever while updates land under the new key.\n if (name === 'id' && oldValue && oldValue !== newValue) {\n removeSize(oldValue)\n if (newValue && this.isConnected) {\n const { width, height } = this.getBoundingClientRect()\n updateSize(newValue, width, height)\n }\n }\n }\n\n disconnectedCallback(): void {\n this.cleanup()\n }\n\n private setupObserver(): void {\n this._resizeObserver = new ResizeObserver((entries) => {\n if (this.debounce > 0) {\n if (this._debounceTimer) clearTimeout(this._debounceTimer)\n this._debounceTimer = window.setTimeout(() => {\n this.handleResize(entries)\n }, this.debounce)\n } else {\n this.handleResize(entries)\n }\n })\n\n // Observe the custom element itself (not shadow root)\n this._resizeObserver.observe(this)\n }\n\n private handleResize(entries: ResizeObserverEntry[]): void {\n const { width, height } = entries[0].contentRect\n\n if (this.id) {\n updateSize(this.id, width, height)\n }\n }\n\n private cleanup(): void {\n if (this._resizeObserver) {\n this._resizeObserver.disconnect()\n this._resizeObserver = null\n }\n\n if (this._debounceTimer) {\n clearTimeout(this._debounceTimer)\n this._debounceTimer = null\n }\n\n if (this.id) {\n removeSize(this.id)\n }\n }\n}\n\nif (!customElements.get('ty-resize-observer')) {\n customElements.define('ty-resize-observer', TyResizeObserver)\n}\n","/**\n * TyScrollContainer styles\n * Component-specific styles + shared custom scrollbar styles\n */\n\nimport { customScrollbarStyles } from './custom-scrollbar.js'\n\nexport const scrollContainerStyles = `\n:host {\n display: block;\n position: relative;\n overflow: hidden;\n}\n\n.scroll-wrapper {\n width: 100%;\n height: 100%;\n overflow-y: auto;\n overflow-x: hidden;\n}\n\n:host([overflow-x]) .scroll-wrapper {\n overflow-x: auto;\n}\n\n:host([max-height]) .scroll-wrapper {\n max-height: var(--scroll-max-height);\n}\n\n/* hide-scrollbar: hides native, no custom */\n:host([hide-scrollbar]) .scroll-wrapper {\n scrollbar-width: none;\n -ms-overflow-style: none;\n}\n\n:host([hide-scrollbar]) .scroll-wrapper::-webkit-scrollbar {\n display: none;\n}\n\n/* scroll-anchoring: we manage scroll position in JS, so turn off the browser's\n native scroll anchoring to avoid double-compensation. */\n:host([scroll-anchoring]) .scroll-wrapper {\n overflow-anchor: none;\n}\n\n/* custom-scrollbar: hides native */\n:host([custom-scrollbar]) .scroll-wrapper {\n scrollbar-width: none;\n -ms-overflow-style: none;\n}\n\n:host([custom-scrollbar]) .scroll-wrapper::-webkit-scrollbar {\n display: none;\n}\n\n:host([custom-scrollbar]:hover) .ty-scrollbar-track-y.has-overflow,\n:host([custom-scrollbar]:hover) .ty-scrollbar-track-x.has-overflow {\n opacity: 1;\n}\n\n/* Corner gap when both axes are present */\n:host([custom-scrollbar][overflow-x]) .ty-scrollbar-track-y {\n bottom: var(--ty-scrollbar-width, 8px);\n}\n\n:host([custom-scrollbar]) .ty-scrollbar-track-x {\n right: var(--ty-scrollbar-width, 8px);\n}\n\n.shadow-overlay {\n position: absolute;\n inset: 0;\n pointer-events: none;\n z-index: 2;\n}\n\n.shadow-top,\n.shadow-bottom,\n.shadow-left,\n.shadow-right {\n position: absolute;\n opacity: 0;\n transition: var(--ty-scroll-shadow-transition, opacity 0.2s ease-out);\n pointer-events: none;\n}\n\n.shadow-top {\n top: -40px;\n left: 0;\n right: 0;\n height: 80px;\n background: var(--ty-scroll-shadow-top, radial-gradient(\n ellipse 100% 30% at center,\n color-mix(in oklab, var(--ty-color-neutral-bold) 12%, transparent),\n transparent,\n transparent\n ));\n clip-path: inset(50% 0 0 0);\n}\n\n.shadow-bottom {\n bottom: -30px;\n left: 0;\n right: 0;\n height: 60px;\n background: var(--ty-scroll-shadow-bottom, radial-gradient(\n ellipse 100% 20% at center,\n color-mix(in oklab, var(--ty-color-neutral-bold) 18%, transparent),\n transparent,\n transparent\n ));\n clip-path: inset(0 0 50% 0);\n}\n\n.shadow-left {\n left: -30px;\n top: 0;\n bottom: 0;\n width: 60px;\n background: var(--ty-scroll-shadow-left, radial-gradient(\n ellipse 30% 100% at center,\n color-mix(in oklab, var(--ty-color-neutral-bold) 12%, transparent),\n transparent,\n transparent\n ));\n clip-path: inset(0 0 0 50%);\n}\n\n.shadow-right {\n right: -30px;\n top: 0;\n bottom: 0;\n width: 60px;\n background: var(--ty-scroll-shadow-right, radial-gradient(\n ellipse 30% 100% at center,\n color-mix(in oklab, var(--ty-color-neutral-bold) 12%, transparent),\n transparent,\n transparent\n ));\n clip-path: inset(0 50% 0 0);\n}\n\n.shadow-left,\n.shadow-right {\n display: none;\n}\n\n:host([overflow-x]) .shadow-left,\n:host([overflow-x]) .shadow-right {\n display: block;\n}\n\n.shadow-top.visible,\n.shadow-bottom.visible,\n.shadow-left.visible,\n.shadow-right.visible {\n opacity: 1;\n}\n\n:host([no-shadow]) .shadow-overlay {\n display: none;\n}\n\n/* Touch devices - restore native scrollbar */\n@media (pointer: coarse) and (hover: none) {\n :host([custom-scrollbar]) .scroll-wrapper {\n scrollbar-width: thin;\n scrollbar-color: var(--ty-border, color-mix(in oklab, var(--ty-color-neutral-bold) 25%, transparent)) transparent;\n }\n :host([custom-scrollbar]) .scroll-wrapper::-webkit-scrollbar {\n display: block;\n width: 4px;\n height: 4px;\n }\n :host([custom-scrollbar]) .scroll-wrapper::-webkit-scrollbar-thumb {\n background: var(--ty-border, color-mix(in oklab, var(--ty-color-neutral-bold) 25%, transparent));\n border-radius: 2px;\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .shadow-top,\n .shadow-bottom,\n .shadow-left,\n .shadow-right {\n transition-duration: 0ms !important;\n }\n}\n\n${customScrollbarStyles}\n`;\n","/**\n * TyScrollContainer Web Component - scroll wrapper with edge shadow indicators\n * and an optional custom-rendered scrollbar (CustomScrollbar utility).\n */\n\nimport { ensureStyles } from '../utils/styles.js'\nimport { scrollContainerStyles } from '../styles/scroll-container.js'\nimport { CustomScrollbar } from '../utils/custom-scrollbar.js'\nimport { upgradeProperties } from '../utils/upgrade-properties.js'\n\nexport class TyScrollContainer extends HTMLElement {\n private _scrollWrapper: HTMLElement | null = null\n private _shadowTop: HTMLElement | null = null\n private _shadowBottom: HTMLElement | null = null\n private _shadowLeft: HTMLElement | null = null\n private _shadowRight: HTMLElement | null = null\n private _scrollbar: CustomScrollbar | null = null\n private _resizeObserver: ResizeObserver | null = null\n private _contentObserver: MutationObserver | null = null\n private _rafId: number | null = null\n // Edge-trigger state for nearstart/nearend (fire once on entering the zone).\n private _nearStartFired = false\n private _nearEndFired = false\n\n static get observedAttributes(): string[] {\n return ['no-shadow', 'max-height', 'hide-scrollbar', 'custom-scrollbar', 'overflow-x', 'scroll-anchoring']\n }\n\n // ============ Property Accessors ============\n\n /** Edge shadows are on by default; no-shadow turns them off. */\n get noShadow(): boolean {\n return this.hasAttribute('no-shadow')\n }\n\n set noShadow(value: boolean) {\n value ? this.setAttribute('no-shadow', '') : this.removeAttribute('no-shadow')\n }\n\n get maxHeight(): string | null {\n return this.getAttribute('max-height')\n }\n\n set maxHeight(value: string | null) {\n if (value) this.setAttribute('max-height', value)\n else this.removeAttribute('max-height')\n this._updateMaxHeight()\n }\n\n get hideScrollbar(): boolean {\n return this.hasAttribute('hide-scrollbar')\n }\n\n set hideScrollbar(value: boolean) {\n if (value) this.setAttribute('hide-scrollbar', '')\n else this.removeAttribute('hide-scrollbar')\n }\n\n get customScrollbar(): boolean {\n return this.hasAttribute('custom-scrollbar')\n }\n\n set customScrollbar(value: boolean) {\n if (value) this.setAttribute('custom-scrollbar', '')\n else this.removeAttribute('custom-scrollbar')\n }\n\n get overflowX(): boolean {\n return this.hasAttribute('overflow-x')\n }\n\n set overflowX(value: boolean) {\n if (value) this.setAttribute('overflow-x', '')\n else this.removeAttribute('overflow-x')\n }\n\n /** Distance (px) from an edge at which nearstart/nearend fire. Default 100. */\n get nearEdgeThreshold(): number {\n const v = parseInt(this.getAttribute('near-edge-threshold') || '', 10)\n return Number.isFinite(v) ? v : 100\n }\n\n set nearEdgeThreshold(value: number | null) {\n if (value == null) this.removeAttribute('near-edge-threshold')\n else this.setAttribute('near-edge-threshold', String(value))\n }\n\n /** Preserve visual position when content is added above the viewport\n * (e.g. prepending older messages in a chat). Opt-in. */\n get scrollAnchoring(): boolean {\n return this.hasAttribute('scroll-anchoring')\n }\n\n set scrollAnchoring(value: boolean) {\n if (value) this.setAttribute('scroll-anchoring', '')\n else this.removeAttribute('scroll-anchoring')\n }\n\n constructor() {\n super()\n\n const shadow = this.attachShadow({ mode: 'open' })\n ensureStyles(shadow, { css: scrollContainerStyles, id: 'ty-scroll-container' })\n\n shadow.innerHTML = `\n <div class=\"scroll-wrapper\">\n <slot></slot>\n </div>\n <div class=\"shadow-overlay\">\n <div class=\"shadow-top\"></div>\n <div class=\"shadow-bottom\"></div>\n <div class=\"shadow-left\"></div>\n <div class=\"shadow-right\"></div>\n </div>\n `\n\n this._scrollWrapper = shadow.querySelector('.scroll-wrapper')\n this._shadowTop = shadow.querySelector('.shadow-top')\n this._shadowBottom = shadow.querySelector('.shadow-bottom')\n this._shadowLeft = shadow.querySelector('.shadow-left')\n this._shadowRight = shadow.querySelector('.shadow-right')\n }\n\n connectedCallback(): void {\n upgradeProperties(this)\n this._scrollWrapper?.addEventListener('scroll', this._onScroll, { passive: true })\n\n this._resizeObserver = new ResizeObserver(() => {\n this._scrollbar?.update()\n this._updateShadowState()\n })\n\n if (this._scrollWrapper) {\n this._resizeObserver.observe(this._scrollWrapper)\n\n const slot = this._scrollWrapper.querySelector('slot') as HTMLSlotElement | null\n if (slot) {\n slot.addEventListener('slotchange', this._onSlotChange)\n }\n }\n\n this._updateMaxHeight()\n this._updateShadowState()\n this._setupScrollbar()\n this._setupAnchoring()\n }\n\n disconnectedCallback(): void {\n this._scrollWrapper?.removeEventListener('scroll', this._onScroll)\n this._destroyScrollbar()\n this._teardownAnchoring()\n\n if (this._resizeObserver) {\n this._resizeObserver.disconnect()\n this._resizeObserver = null\n }\n\n if (this._rafId !== null) {\n cancelAnimationFrame(this._rafId)\n this._rafId = null\n }\n }\n\n attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void {\n if (oldValue === newValue) return\n\n if (name === 'max-height') {\n this._updateMaxHeight()\n this._updateShadowState()\n this._scrollbar?.update()\n }\n\n if (name === 'custom-scrollbar' || name === 'overflow-x') {\n this._destroyScrollbar()\n this._setupScrollbar()\n this._updateShadowState()\n }\n\n if (name === 'scroll-anchoring') {\n this._teardownAnchoring()\n this._setupAnchoring()\n }\n }\n\n // ============ Private: Scroll Anchoring ============\n\n // Preserve visual position when content is added ABOVE the viewport (chat\n // \"load older\" prepends). A MutationObserver watches the host's children;\n // any added node sitting above the visible area shifts everything down, so we\n // add its (above-the-fold) height back to scrollTop. Append-at-bottom is\n // untouched. CSS sets overflow-anchor:none so native anchoring doesn't fight us.\n private _setupAnchoring(): void {\n if (this._contentObserver || !this.scrollAnchoring) return\n\n this._contentObserver = new MutationObserver((records) => {\n const wrap = this._scrollWrapper\n if (!wrap) return\n\n const added = new Set<Node>()\n for (const r of records) r.addedNodes.forEach((n) => added.add(n))\n if (added.size === 0) return\n\n // Total height of the unbroken run of newly-added nodes at the TOP of\n // the content — those were prepended above whatever the user was\n // reading, so the viewport must move down by exactly that to stay put.\n //\n // Deciding this per-node by on-screen geometry (what this did before)\n // undercounts the moment the prepended block is taller than the current\n // scrollTop: scrollTop hasn't been compensated yet, so every node past\n // the fold measures as \"below the viewport\" and gets skipped — even\n // though it too was inserted above the anchor. A batch prepend (\"load\n // 12 older rows\") is the normal case, so the fix has to be positional,\n // not visual.\n let addedAbove = 0\n for (const child of Array.from(this.children)) {\n if (!added.has(child)) break\n addedAbove += (child as HTMLElement).offsetHeight\n }\n\n if (addedAbove > 0) {\n wrap.scrollTop += addedAbove\n this._scrollbar?.update()\n }\n })\n this._contentObserver.observe(this, { childList: true })\n }\n\n private _teardownAnchoring(): void {\n this._contentObserver?.disconnect()\n this._contentObserver = null\n }\n\n // ============ Private: Scrollbar Setup ============\n\n private _setupScrollbar(): void {\n // Idempotent: attributeChangedCallback (attrs set before insertion) and\n // connectedCallback can both call this. Without the guard a second\n // CustomScrollbar + track is created → two thumbs.\n if (this._scrollbar) return\n if (!this._scrollWrapper || !this.customScrollbar) return\n\n this._scrollbar = new CustomScrollbar(this._scrollWrapper, {\n vertical: true,\n horizontal: this.overflowX\n })\n\n const shadowRoot = this.shadowRoot!\n if (this._scrollbar.trackY) shadowRoot.appendChild(this._scrollbar.trackY)\n if (this._scrollbar.trackX) shadowRoot.appendChild(this._scrollbar.trackX)\n }\n\n private _destroyScrollbar(): void {\n if (this._scrollbar) {\n this._scrollbar.trackY?.remove()\n this._scrollbar.trackX?.remove()\n this._scrollbar.destroy()\n this._scrollbar = null\n }\n }\n\n // ============ Private: Max Height ============\n\n private _updateMaxHeight(): void {\n if (this._scrollWrapper) {\n const maxHeight = this.maxHeight\n if (maxHeight) {\n this._scrollWrapper.style.setProperty('--scroll-max-height', maxHeight)\n this._scrollWrapper.style.maxHeight = maxHeight\n } else {\n this._scrollWrapper.style.removeProperty('--scroll-max-height')\n this._scrollWrapper.style.maxHeight = ''\n }\n }\n }\n\n // ============ Private: Scroll Handling ============\n\n private _onScroll = (): void => {\n if (this._rafId !== null) return\n\n this._rafId = requestAnimationFrame(() => {\n this._rafId = null\n this._updateShadowState()\n })\n }\n\n private _onSlotChange = (): void => {\n this._scrollbar?.update()\n this._updateShadowState()\n }\n\n // ============ Private: Shadow State ============\n\n private _updateShadowState(): void {\n if (!this._scrollWrapper) return\n const { scrollTop, scrollLeft, scrollHeight, scrollWidth, clientHeight, clientWidth } = this._scrollWrapper\n const threshold = 2\n\n if (this._shadowTop) {\n this._shadowTop.classList.toggle('visible', scrollTop > threshold)\n }\n if (this._shadowBottom) {\n this._shadowBottom.classList.toggle('visible', scrollTop + clientHeight < scrollHeight - threshold)\n }\n\n if (this.overflowX) {\n if (this._shadowLeft) {\n this._shadowLeft.classList.toggle('visible', scrollLeft > threshold)\n }\n if (this._shadowRight) {\n this._shadowRight.classList.toggle('visible', scrollLeft + clientWidth < scrollWidth - threshold)\n }\n }\n\n // Near-edge events for infinite scroll (vertical). Edge-triggered: fire once\n // when entering the zone, re-arm only after leaving it. Runs on scroll,\n // slotchange and resize (all route through here), so loading more content\n // re-arms naturally once it grows the scroll distance.\n const scrollable = scrollHeight - clientHeight\n if (scrollable > 0) {\n const t = this.nearEdgeThreshold\n const distEnd = scrollable - scrollTop\n this._nearEndFired = this._maybeEmitEdge(\n 'nearend', distEnd, t, this._nearEndFired,\n { distance: distEnd, scrollTop, scrollHeight, clientHeight })\n this._nearStartFired = this._maybeEmitEdge(\n 'nearstart', scrollTop, t, this._nearStartFired,\n { distance: scrollTop, scrollTop, scrollHeight, clientHeight })\n } else {\n // Not scrollable → re-arm both so they fire fresh once content overflows.\n this._nearStartFired = false\n this._nearEndFired = false\n }\n }\n\n /** Edge-trigger one near-edge event; returns the new \"fired\" state. */\n private _maybeEmitEdge(\n name: string, distance: number, threshold: number, fired: boolean, detail: object\n ): boolean {\n if (distance > threshold) return false // out of zone → re-arm\n if (!fired) {\n this.dispatchEvent(new CustomEvent(name, { detail, bubbles: true, composed: true }))\n }\n return true\n }\n\n // ============ Public API ============\n\n updateShadows(): void {\n this._updateShadowState()\n this._scrollbar?.update()\n }\n\n scrollToTop(smooth = true): void {\n this._scrollWrapper?.scrollTo({ top: 0, behavior: smooth ? 'smooth' : 'auto' })\n }\n\n scrollToBottom(smooth = true): void {\n if (this._scrollWrapper) {\n this._scrollWrapper.scrollTo({ top: this._scrollWrapper.scrollHeight, behavior: smooth ? 'smooth' : 'auto' })\n }\n }\n\n scrollToLeft(smooth = true): void {\n this._scrollWrapper?.scrollTo({ left: 0, behavior: smooth ? 'smooth' : 'auto' })\n }\n\n scrollToRight(smooth = true): void {\n if (this._scrollWrapper) {\n this._scrollWrapper.scrollTo({ left: this._scrollWrapper.scrollWidth, behavior: smooth ? 'smooth' : 'auto' })\n }\n }\n\n /** Scroll a slotted descendant (element or CSS selector) into view. */\n scrollToElement(target: Element | string, smooth = true): void {\n const el = typeof target === 'string' ? this.querySelector(target) : target\n el?.scrollIntoView({ behavior: smooth ? 'smooth' : 'auto', block: 'nearest' })\n }\n\n get scrollElement(): HTMLElement | null {\n return this._scrollWrapper\n }\n}\n\ncustomElements.define('ty-scroll-container', TyScrollContainer)\n","// Ty TypeScript Components - CDN Entry Point\n// Components ONLY - NO icon data included\n// Users can register icons via IconRegistry\n\nexport { TyButton } from './components/button.js'\nexport { TyIcon, IconRegistry } from './components/icon.js'\nexport { TyTag } from './components/tag.js'\nexport { TyOption } from './components/option.js'\nexport { TyInput } from './components/input.js'\nexport { TyCheckbox } from './components/checkbox.js'\nexport { TySwitch } from './components/switch.js'\nexport { TyRadio, TyRadioGroup } from './components/radio.js'\nexport { TyCopy } from './components/copy.js'\nexport { TyFileUpload } from './components/file-upload.js'\nexport { TyTextarea } from './components/textarea.js'\nexport { TyTooltip } from './components/tooltip.js'\nexport { TyPopup } from './components/popup.js'\nexport { TyModal } from './components/modal.js'\nexport { TySelect } from './components/select.js'\nexport { TySelectedOptions } from './components/selected-tags.js'\nexport { TySelectedOptions as TySelectedTags } from './components/selected-tags.js'\nexport { TyTabs } from './components/tabs.js'\nexport { TyTab } from './components/tab.js'\nexport { TyWizard } from './components/wizard.js'\nexport { TyStep } from './components/step.js'\nexport { TyCalendarMonth } from './components/calendar-month.js'\nexport { TyCalendarNavigation } from './components/calendar-navigation.js'\nexport { TyCalendar } from './components/calendar.js'\nexport { TyDatePicker } from './components/date-picker.js'\nexport { TyResizeObserver } from './components/resize-observer.js'\nexport { TyScrollContainer } from './components/scroll-container.js'\n\n// Types\nexport type {\n Flavor,\n Size,\n InputType,\n IconSize,\n IconTempo,\n TyButtonElement,\n TyIconElement,\n TyTagElement,\n TyTagEventDetail,\n TyOptionElement,\n TyInputElement\n} from './types/common.js'\n\nexport type { TyCheckboxElement } from './components/checkbox.js'\nexport type { TySwitchElement } from './components/switch.js'\nexport type { TyRadioElement, TyRadioGroupElement } from './components/radio.js'\nexport type { TyCopyElement } from './components/copy.js'\nexport type { TyFileUploadElement } from './components/file-upload.js'\nexport type { TyTextareaElement } from './components/textarea.js'\nexport type { TooltipFlavor, TooltipAttributes } from './components/tooltip.js'\nexport type { PopupAttributes } from './components/popup.js'\nexport type { ModalAttributes, ModalCloseDetail } from './components/modal.js'\nexport type { TabsAttributes, TabChangeDetail } from './components/tabs.js'\nexport type { TabAttributes } from './components/tab.js'\nexport type { WizardAttributes, WizardStepChangeDetail } from './components/wizard.js'\nexport type { StepAttributes, StepStatus } from './components/step.js'\nexport type { DayContentFn, DayClickDetail, CalendarSize } from './components/calendar-month.js'\nexport type { NavigationChangeDetail } from './components/calendar-navigation.js'\nexport type { CalendarChangeDetail, CalendarNavigateDetail } from './components/calendar.js'\nexport type { DatePickerChangeDetail } from './components/date-picker.js'\nexport type { DayContext } from './utils/calendar-utils.js'\n\n// Utilities - Including Icon Registry\nexport {\n lockScroll,\n unlockScroll,\n forceUnlockAll,\n isLocked,\n isLockedBy,\n getActiveLocks,\n getLockState,\n enableDebug as enableScrollLockDebug,\n disableDebug as disableScrollLockDebug\n} from './utils/scroll-lock.js'\n\n// Resize Observer utilities\nexport {\n getSize,\n onResize,\n getAllSizes\n} from './utils/resize-observer.js'\n\n// Loader registry — global override for the spinner SVG used by loading-aware components\nexport { setLoaderSvg, getLoaderSvg, resetLoaderSvg } from './utils/loader-registry.js'\n\nexport type {\n ElementSize as ResizeSize,\n ResizeCallback\n} from './utils/resize-observer.js'\n\nexport type {\n Placement,\n PositionResult,\n CleanupFn\n} from './utils/positioning.js'\n\n// Version (auto-generated from package.json)\nimport { VERSION } from './version.js'\n\n// Global API\n// Expose window.tyIcons for script tag usage\nimport { registerIcons, getIcon, hasIcon, getIconNames, getCacheInfo, clearIcons } from './utils/icon-registry.js'\nimport { getSize as getResizeSize, onResize as subscribeResize, getAllSizes } from './utils/resize-observer.js'\nimport type { ResizeCallback } from './utils/resize-observer.js'\nimport { setLoaderSvg as registrySetLoaderSvg, getLoaderSvg as registryGetLoaderSvg, resetLoaderSvg as registryResetLoaderSvg } from './utils/loader-registry.js'\n\nif (typeof window !== 'undefined') {\n window.tyVersion = VERSION\n // One-time load banner — helps consumers confirm which version of the\n // library their page is actually running.\n console.log(\n `%c[tyrell-components]%c v${VERSION}`,\n 'color:#06b6d4;font-weight:600',\n 'color:inherit;font-weight:400'\n )\n window.tyIcons = {\n register: (icons: Record<string, string>) => {\n registerIcons(icons)\n console.log(`✅ Registered ${Object.keys(icons).length} icons`)\n },\n get: (name: string) => getIcon(name),\n has: (name: string) => hasIcon(name),\n list: () => getIconNames(),\n cacheInfo: () => getCacheInfo(),\n clearCache: () => clearIcons()\n }\n\n // Resize Observer API\n window.tyResizeObserver = {\n getSize: (id: string) => getResizeSize(id),\n onResize: (id: string, callback: ResizeCallback) => subscribeResize(id, callback),\n get sizes() { return getAllSizes() }\n }\n\n // Loader registry — set once at boot to override the default spinner everywhere\n window.tyLoader = {\n set: (svg: string | null) => registrySetLoaderSvg(svg),\n get: () => registryGetLoaderSvg(),\n reset: () => registryResetLoaderSvg()\n }\n}"],"names":["IconRegistry.addWatcher","IconRegistry.removeWatcher","IconRegistry.getIcon","CHECK_SVG","parsed","shouldFormatType","labelEl","dropZone","fileInput","uploadIcon","hintEl","subHintEl","fileList","errorEl","parseBoolAttr","parseIntAttr","getAnchorElement","updatePosition","cleanup","escapeHandlers","fromNestedDialog","render","elementIdCounter","elementIds","getElementHash","CLEAR_ICON_SVG","eventHandlers","resizeObservers","cleanupEventListeners","setupEventListeners","updatePanelInteraction","currentActive","container","getResizeSize","subscribeResize","getAllSizes","registrySetLoaderSvg","registryGetLoaderSvg","registryResetLoaderSvg"],"mappings":"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;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA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;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA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AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;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"}