@jungherz-de/glasskit-elements 1.19.2 → 1.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +45 -0
- package/README.md +56 -31
- package/SKILL.md +124 -27
- package/dist/components/base.js +185 -12
- package/dist/components/glk-accordion-item.js +20 -5
- package/dist/components/glk-button.js +69 -2
- package/dist/components/glk-calendar.js +3 -0
- package/dist/components/glk-checkbox.js +12 -2
- package/dist/components/glk-input.js +25 -4
- package/dist/components/glk-modal.js +99 -21
- package/dist/components/glk-pill.js +14 -1
- package/dist/components/glk-popover.js +21 -3
- package/dist/components/glk-radio.js +26 -2
- package/dist/components/glk-range.js +3 -1
- package/dist/components/glk-search.js +14 -1
- package/dist/components/glk-segmented.js +4 -0
- package/dist/components/glk-select.js +8 -2
- package/dist/components/glk-textarea.js +8 -2
- package/dist/components/glk-toggle.js +18 -11
- package/dist/glasskit-elements.esm.js +528 -68
- package/dist/glasskit-elements.js +528 -68
- package/dist/glasskit-elements.min.js +1 -1
- package/package.json +3 -3
- package/src/base.js +184 -11
- package/src/components/buttons/glk-button.js +69 -2
- package/src/components/containers/glk-accordion-item.js +20 -5
- package/src/components/feedback/glk-modal.js +99 -21
- package/src/components/feedback/glk-popover.js +21 -3
- package/src/components/forms/glk-calendar.js +3 -0
- package/src/components/forms/glk-checkbox.js +12 -2
- package/src/components/forms/glk-input.js +25 -4
- package/src/components/forms/glk-radio.js +26 -2
- package/src/components/forms/glk-range.js +3 -1
- package/src/components/forms/glk-search.js +14 -1
- package/src/components/forms/glk-segmented.js +4 -0
- package/src/components/forms/glk-select.js +8 -2
- package/src/components/forms/glk-textarea.js +8 -2
- package/src/components/forms/glk-toggle.js +18 -11
- package/src/components/navigation/glk-pill.js +14 -1
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
// GlassKit v1.
|
|
1
|
+
// GlassKit v1.21.0 – Constructable Stylesheet
|
|
2
2
|
// Auto-generated by build-styles-js.mjs – do not edit manually.
|
|
3
3
|
|
|
4
|
-
// The [data-theme] blocks that declare --gl-* …
|
|
5
|
-
const tokensCss = ":root,[data-theme=dark]{color-scheme:dark;--gl-color-primary:#f5a623;--gl-color-primary-dark:#d4692a;--gl-color-primary-mid:color-mix(in srgb, var(--gl-color-primary) 32%, var(--gl-color-primary-dark));--gl-color-bg-dark:#0e2530;--gl-color-bg-mid:#1a3d4e;--gl-color-bg-light:#1b3e50;--gl-color-text:#ffffff;--gl-color-text-muted:rgba(255, 255, 255, 0.60);--gl-color-text-on-light:#1a3a4a;--gl-color-text-heading:#ffffff;--gl-color-success:#34c759;--gl-color-error:#ff3b30;--gl-color-warning:#ffcc00;--gl-color-success-dark:#2da44e;--gl-color-error-dark:#d63027;--gl-color-on-primary:#ffffff;--gl-color-on-success:#ffffff;--gl-color-on-error:#ffffff;--gl-color-primary-on-surface:color-mix(in srgb, var(--gl-color-primary) 50%, #ffffff);--gl-color-success-on-surface:color-mix(in srgb, var(--gl-color-success) 62%, #ffffff);--gl-color-error-on-surface:color-mix(in srgb, var(--gl-color-error) 50%, #ffffff);--gl-color-warning-on-surface:color-mix(in srgb, var(--gl-color-warning) 80%, #ffffff);--gl-state-scrim:rgba(0, 0, 0, 0.30);--gl-color-primary-surface:color-mix(in srgb, var(--gl-color-primary) 25%, transparent);--gl-color-primary-border:var(--gl-border-warm);--gl-color-success-surface:color-mix(in srgb, var(--gl-color-success) 15%, transparent);--gl-color-success-border:color-mix(in srgb, var(--gl-color-success) 30%, transparent);--gl-color-error-surface:color-mix(in srgb, var(--gl-color-error) 15%, transparent);--gl-color-error-border:color-mix(in srgb, var(--gl-color-error) 30%, transparent);--gl-color-warning-surface:color-mix(in srgb, var(--gl-color-warning) 15%, transparent);--gl-color-warning-border:color-mix(in srgb, var(--gl-color-warning) 30%, transparent);--gl-surface-1:rgba(255, 255, 255, 0.08);--gl-surface-2:rgba(255, 255, 255, 0.10);--gl-surface-3:rgba(255, 255, 255, 0.14);--gl-surface-4:rgba(255, 255, 255, 0.16);--gl-surface-5:rgba(255, 255, 255, 0.22);--gl-surface-milk:rgba(255, 255, 255, 0.55);--gl-surface-milk-strong:rgba(255, 255, 255, 0.75);--gl-surface-overlay:rgba(0, 0, 0, 0.50);--gl-card-glow-top:rgba(255, 255, 255, 0.32);--gl-card-glow-mid:rgba(255, 255, 255, 0.22);--gl-card-glow-low:rgba(255, 255, 255, 0.14);--gl-card-glow-bottom:rgba(255, 255, 255, 0.08);--gl-card-icon-color:rgba(255, 255, 255, 0.8);--gl-card-text-color:rgba(255, 255, 255, 0.7);--gl-border-subtle:rgba(255, 255, 255, 0.18);--gl-border-medium:rgba(255, 255, 255, 0.30);--gl-border-strong:rgba(255, 255, 255, 0.40);--gl-border-milk:rgba(255, 255, 255, 0.60);--gl-border-warm:color-mix(in srgb, color-mix(in srgb, var(--gl-color-primary) 68%, #ffffff) 35%, transparent);--gl-border-focus:color-mix(in srgb, var(--gl-color-primary) 60%, transparent);--gl-icon-default:rgba(255, 255, 255, 0.6);--gl-icon-muted:rgba(255, 255, 255, 0.45);--gl-icon-strong:rgba(255, 255, 255, 0.8);--gl-icon-on-primary:var(--gl-color-on-primary, #ffffff);--gl-icon-on-secondary:#1a3a4a;--gl-icon-on-tertiary:rgba(255, 255, 255, 0.6);--gl-blur:24px;--gl-blur-light:16px;--gl-blur-soft:12px;--gl-blur-heavy:40px;--gl-radius-pill:50%;--gl-radius-full:9999px;--gl-radius-card:24px;--gl-radius-btn:16px;--gl-radius-input:14px;--gl-radius-sm:12px;--gl-radius-xs:8px;--gl-shadow-card:0 8px 32px rgba(0, 0, 0, 0.18);--gl-shadow-btn:0 4px 16px rgba(0, 0, 0, 0.12);--gl-shadow-btn-primary:0 6px 24px color-mix(in srgb, var(--gl-color-primary-mid) 35%, transparent),0 2px 8px rgba(0, 0, 0, 0.15);--gl-shadow-glow:0 2px 12px rgba(255, 255, 255, 0.08),0 4px 16px rgba(0, 0, 0, 0.15);--gl-shadow-modal:0 24px 80px rgba(0, 0, 0, 0.4),0 8px 32px rgba(0, 0, 0, 0.2);--gl-shadow-toast:0 8px 32px rgba(0, 0, 0, 0.25);--gl-shadow-focus:0 0 0 3px color-mix(in srgb, var(--gl-color-primary) 30%, transparent);--gl-inset-subtle:inset 0 1px 1px rgba(255, 255, 255, 0.10);--gl-inset-medium:inset 0 1px 1px rgba(255, 255, 255, 0.15);--gl-inset-strong:inset 0 1px 2px rgba(255, 255, 255, 0.25);--gl-inset-milk:inset 0 1px 2px rgba(255, 255, 255, 0.40);--gl-bg-aurora-1:rgba(60, 160, 160, 0.25);--gl-bg-aurora-2:rgba(200, 140, 60, 0.12);--gl-bg-aurora-3:rgba(80, 180, 200, 0.18);--gl-bg-light-streak-1:rgba(90, 210, 200, 0.14);--gl-bg-light-streak-2:rgba(110, 200, 190, 0.10);--gl-bg-warm-glow:rgba(220, 160, 70, 0.10);--gl-space-2xs:4px;--gl-space-xs:8px;--gl-space-sm:12px;--gl-space-md:16px;--gl-space-lg:20px;--gl-space-xl:24px;--gl-space-2xl:32px;--gl-space-3xl:40px;--gl-space-4xl:56px;--gl-font-family:-apple-system,BlinkMacSystemFont,'SF Pro Display','Segoe UI',Roboto,Helvetica,Arial,sans-serif;--gl-font-size-xs:13px;--gl-font-size-sm:14px;--gl-font-size-base:15px;--gl-font-size-btn:16px;--gl-font-size-lg:18px;--gl-font-size-title:24px;--gl-font-size-modal:20px;--gl-font-weight-normal:400;--gl-font-weight-medium:500;--gl-font-weight-semibold:600;--gl-transition:all 0.25s ease;--gl-transition-fast:all 0.15s ease;--gl-transition-modal:all 0.3s cubic-bezier(0.4, 0, 0.2, 1);--gl-tab-bar-height:82px;--gl-tab-bar-floating-bottom:16px;--gl-tab-bar-floating-gap:var(--gl-space-sm);--gl-tab-bar-floating-padding:6px 10px;--gl-tab-bar-floating-radius:var(--gl-radius-full);--gl-tab-bar-accessory-size:56px;--gl-tab-bar-spotlight-color:var(--gl-color-primary);--gl-placeholder:rgba(255, 255, 255, 0.35);--gl-accordion-body-color:var(--gl-color-text-muted);--gl-toggle-thumb-bg:linear-gradient(to bottom,\n rgba(255,255,255,0.9) 0%,\n rgba(255,255,255,0.7) 100%);--gl-range-track-bg:var(--gl-surface-2);--gl-range-track-border:var(--gl-border-subtle)}[data-theme=light]{color-scheme:light;--gl-color-primary:#e8852d;--gl-color-primary-dark:#c96a1e;--gl-color-primary-mid:color-mix(in srgb, var(--gl-color-primary) 52%, var(--gl-color-primary-dark));--gl-color-bg-dark:#e8ecf1;--gl-color-bg-mid:#f0f4f8;--gl-color-bg-light:#f5f7fa;--gl-color-text:#1a2a36;--gl-color-text-muted:rgba(26, 42, 54, 0.55);--gl-color-text-on-light:#1a3a4a;--gl-color-text-heading:#0f1f2a;--gl-color-success:#28a745;--gl-color-error:#dc3545;--gl-color-warning:#e6a800;--gl-color-success-dark:#1e7e34;--gl-color-error-dark:#b02a37;--gl-color-on-primary:#ffffff;--gl-color-on-success:#ffffff;--gl-color-on-error:#ffffff;--gl-color-primary-on-surface:color-mix(in srgb, var(--gl-color-primary) 60%, #000000);--gl-color-success-on-surface:color-mix(in srgb, var(--gl-color-success) 68%, #000000);--gl-color-error-on-surface:color-mix(in srgb, var(--gl-color-error) 82%, #000000);--gl-color-warning-on-surface:color-mix(in srgb, var(--gl-color-warning) 56%, #000000);--gl-state-scrim:rgba(255, 255, 255, 0.30);--gl-color-primary-surface:color-mix(in srgb, var(--gl-color-primary) 25%, transparent);--gl-color-primary-border:var(--gl-border-warm);--gl-color-success-surface:color-mix(in srgb, var(--gl-color-success) 15%, transparent);--gl-color-success-border:color-mix(in srgb, var(--gl-color-success) 30%, transparent);--gl-color-error-surface:color-mix(in srgb, var(--gl-color-error) 15%, transparent);--gl-color-error-border:color-mix(in srgb, var(--gl-color-error) 30%, transparent);--gl-color-warning-surface:color-mix(in srgb, var(--gl-color-warning) 15%, transparent);--gl-color-warning-border:color-mix(in srgb, var(--gl-color-warning) 30%, transparent);--gl-surface-1:rgba(255, 255, 255, 0.50);--gl-surface-2:rgba(255, 255, 255, 0.60);--gl-surface-3:rgba(255, 255, 255, 0.70);--gl-surface-4:rgba(255, 255, 255, 0.75);--gl-surface-5:rgba(255, 255, 255, 0.85);--gl-surface-milk:rgba(255, 255, 255, 0.85);--gl-surface-milk-strong:rgba(255, 255, 255, 0.92);--gl-surface-overlay:rgba(0, 0, 0, 0.25);--gl-card-glow-top:rgba(255, 255, 255, 0.90);--gl-card-glow-mid:rgba(255, 255, 255, 0.78);--gl-card-glow-low:rgba(255, 255, 255, 0.65);--gl-card-glow-bottom:rgba(255, 255, 255, 0.50);--gl-card-icon-color:rgba(26, 42, 54, 0.5);--gl-card-text-color:rgba(26, 42, 54, 0.6);--gl-border-subtle:rgba(0, 0, 0, 0.08);--gl-border-medium:rgba(0, 0, 0, 0.12);--gl-border-strong:rgba(0, 0, 0, 0.15);--gl-border-milk:rgba(0, 0, 0, 0.10);--gl-border-warm:color-mix(in srgb, var(--gl-color-primary) 30%, transparent);--gl-border-focus:color-mix(in srgb, var(--gl-color-primary) 50%, transparent);--gl-icon-default:rgba(26, 42, 54, 0.50);--gl-icon-muted:rgba(26, 42, 54, 0.35);--gl-icon-strong:rgba(26, 42, 54, 0.70);--gl-icon-on-primary:var(--gl-color-on-primary, #ffffff);--gl-icon-on-secondary:#1a3a4a;--gl-icon-on-tertiary:rgba(26, 42, 54, 0.50);--gl-shadow-card:0 4px 20px rgba(0, 0, 0, 0.06);--gl-shadow-btn:0 2px 10px rgba(0, 0, 0, 0.06);--gl-shadow-btn-primary:0 4px 16px color-mix(in srgb, var(--gl-color-primary) 25%, transparent),0 2px 6px rgba(0, 0, 0, 0.08);--gl-shadow-glow:0 2px 8px rgba(0, 0, 0, 0.05),0 4px 12px rgba(0, 0, 0, 0.04);--gl-shadow-modal:0 16px 48px rgba(0, 0, 0, 0.12),0 4px 16px rgba(0, 0, 0, 0.08);--gl-shadow-toast:0 4px 20px rgba(0, 0, 0, 0.10);--gl-shadow-focus:0 0 0 3px color-mix(in srgb, var(--gl-color-primary) 25%, transparent);--gl-inset-subtle:inset 0 1px 1px rgba(255, 255, 255, 0.60);--gl-inset-medium:inset 0 1px 1px rgba(255, 255, 255, 0.70);--gl-inset-strong:inset 0 1px 2px rgba(255, 255, 255, 0.80);--gl-inset-milk:inset 0 1px 2px rgba(255, 255, 255, 0.90);--gl-bg-aurora-1:rgba(100, 200, 220, 0.15);--gl-bg-aurora-2:rgba(240, 180, 100, 0.10);--gl-bg-aurora-3:rgba(120, 200, 230, 0.12);--gl-bg-light-streak-1:rgba(140, 230, 220, 0.10);--gl-bg-light-streak-2:rgba(160, 220, 210, 0.08);--gl-bg-warm-glow:rgba(240, 180, 100, 0.08);--gl-placeholder:rgba(26, 42, 54, 0.30);--gl-accordion-body-color:var(--gl-color-text-muted);--gl-toggle-thumb-bg:linear-gradient(to bottom, #ffffff 0%, #f0f0f0 100%);--gl-range-track-bg:var(--gl-surface-2);--gl-range-track-border:var(--gl-border-subtle)}";
|
|
4
|
+
// The [data-theme] and [data-density] blocks that declare --gl-* …
|
|
5
|
+
const tokensCss = ":root,[data-theme=dark]{color-scheme:dark;--gl-color-primary:#f5a623;--gl-color-primary-dark:#d4692a;--gl-color-primary-mid:color-mix(in srgb, var(--gl-color-primary) 32%, var(--gl-color-primary-dark));--gl-color-bg-dark:#0e2530;--gl-color-bg-mid:#1a3d4e;--gl-color-bg-light:#1b3e50;--gl-color-text:#ffffff;--gl-color-text-muted:rgba(255, 255, 255, 0.60);--gl-color-text-on-light:#1a3a4a;--gl-color-text-heading:#ffffff;--gl-select-chevron:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='rgba(255,255,255,0.6)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E\");--gl-color-success:#34c759;--gl-color-error:#ff3b30;--gl-color-warning:#ffcc00;--gl-color-success-dark:#2da44e;--gl-color-error-dark:#d63027;--gl-color-on-primary:#ffffff;--gl-color-on-success:#ffffff;--gl-color-on-error:#ffffff;--gl-color-primary-on-surface:color-mix(in srgb, var(--gl-color-primary) 50%, #ffffff);--gl-color-success-on-surface:color-mix(in srgb, var(--gl-color-success) 62%, #ffffff);--gl-color-error-on-surface:color-mix(in srgb, var(--gl-color-error) 50%, #ffffff);--gl-color-warning-on-surface:color-mix(in srgb, var(--gl-color-warning) 80%, #ffffff);--gl-state-scrim:rgba(0, 0, 0, 0.30);--gl-color-primary-surface:color-mix(in srgb, var(--gl-color-primary) 25%, transparent);--gl-color-primary-border:var(--gl-border-warm);--gl-color-success-surface:color-mix(in srgb, var(--gl-color-success) 15%, transparent);--gl-color-success-border:color-mix(in srgb, var(--gl-color-success) 30%, transparent);--gl-color-error-surface:color-mix(in srgb, var(--gl-color-error) 15%, transparent);--gl-color-error-border:color-mix(in srgb, var(--gl-color-error) 30%, transparent);--gl-color-warning-surface:color-mix(in srgb, var(--gl-color-warning) 15%, transparent);--gl-color-warning-border:color-mix(in srgb, var(--gl-color-warning) 30%, transparent);--gl-surface-1:rgba(255, 255, 255, 0.08);--gl-surface-2:rgba(255, 255, 255, 0.10);--gl-surface-3:rgba(255, 255, 255, 0.14);--gl-surface-4:rgba(255, 255, 255, 0.16);--gl-surface-5:rgba(255, 255, 255, 0.22);--gl-surface-milk:rgba(255, 255, 255, 0.55);--gl-surface-milk-strong:rgba(255, 255, 255, 0.75);--gl-surface-overlay:rgba(0, 0, 0, 0.50);--gl-card-glow-top:rgba(255, 255, 255, 0.32);--gl-card-glow-mid:rgba(255, 255, 255, 0.22);--gl-card-glow-low:rgba(255, 255, 255, 0.14);--gl-card-glow-bottom:rgba(255, 255, 255, 0.08);--gl-card-icon-color:rgba(255, 255, 255, 0.8);--gl-card-text-color:rgba(255, 255, 255, 0.7);--gl-border-subtle:rgba(255, 255, 255, 0.18);--gl-border-medium:rgba(255, 255, 255, 0.30);--gl-border-strong:rgba(255, 255, 255, 0.40);--gl-border-milk:rgba(255, 255, 255, 0.60);--gl-border-warm:color-mix(in srgb, color-mix(in srgb, var(--gl-color-primary) 68%, #ffffff) 35%, transparent);--gl-border-focus:color-mix(in srgb, var(--gl-color-primary) 60%, transparent);--gl-icon-default:rgba(255, 255, 255, 0.6);--gl-icon-muted:rgba(255, 255, 255, 0.45);--gl-icon-strong:rgba(255, 255, 255, 0.8);--gl-icon-on-primary:var(--gl-color-on-primary, #ffffff);--gl-icon-on-secondary:#1a3a4a;--gl-icon-on-tertiary:rgba(255, 255, 255, 0.6);--gl-blur:24px;--gl-blur-light:16px;--gl-blur-soft:12px;--gl-blur-heavy:40px;--gl-radius-pill:50%;--gl-radius-full:9999px;--gl-radius-card:24px;--gl-radius-btn:16px;--gl-radius-input:14px;--gl-radius-sm:12px;--gl-radius-xs:8px;--gl-shadow-card:0 8px 32px rgba(0, 0, 0, 0.18);--gl-shadow-btn:0 4px 16px rgba(0, 0, 0, 0.12);--gl-shadow-btn-primary:0 6px 24px color-mix(in srgb, var(--gl-color-primary-mid) 35%, transparent),0 2px 8px rgba(0, 0, 0, 0.15);--gl-shadow-glow:0 2px 12px rgba(255, 255, 255, 0.08),0 4px 16px rgba(0, 0, 0, 0.15);--gl-shadow-modal:0 24px 80px rgba(0, 0, 0, 0.4),0 8px 32px rgba(0, 0, 0, 0.2);--gl-shadow-toast:0 8px 32px rgba(0, 0, 0, 0.25);--gl-shadow-focus:0 0 0 3px color-mix(in srgb, var(--gl-color-primary) 30%, transparent);--gl-inset-subtle:inset 0 1px 1px rgba(255, 255, 255, 0.10);--gl-inset-medium:inset 0 1px 1px rgba(255, 255, 255, 0.15);--gl-inset-strong:inset 0 1px 2px rgba(255, 255, 255, 0.25);--gl-inset-milk:inset 0 1px 2px rgba(255, 255, 255, 0.40);--gl-bg-aurora-1:rgba(60, 160, 160, 0.25);--gl-bg-aurora-2:rgba(200, 140, 60, 0.12);--gl-bg-aurora-3:rgba(80, 180, 200, 0.18);--gl-bg-light-streak-1:rgba(90, 210, 200, 0.14);--gl-bg-light-streak-2:rgba(110, 200, 190, 0.10);--gl-bg-warm-glow:rgba(220, 160, 70, 0.10);--gl-space-2xs:4px;--gl-space-xs:8px;--gl-space-sm:12px;--gl-space-md:16px;--gl-space-lg:20px;--gl-space-xl:24px;--gl-space-2xl:32px;--gl-space-3xl:40px;--gl-space-4xl:56px;--gl-control-height:52px;--gl-btn-height:56px;--gl-btn-height-sm:44px;--gl-btn-height-lg:64px;--gl-textarea-min-height:120px;--gl-list-item-min-height:56px;--gl-toggle-width:52px;--gl-toggle-height:30px;--gl-toggle-thumb-size:22px;--gl-check-size:24px;--gl-modal-action-height:52px;--gl-font-family:-apple-system,BlinkMacSystemFont,'SF Pro Display','Segoe UI',Roboto,Helvetica,Arial,sans-serif;--gl-font-size-xs:13px;--gl-font-size-sm:14px;--gl-font-size-base:15px;--gl-font-size-btn:16px;--gl-font-size-lg:18px;--gl-font-size-title:24px;--gl-font-size-modal:20px;--gl-font-weight-normal:400;--gl-font-weight-medium:500;--gl-font-weight-semibold:600;--gl-transition:all 0.25s ease;--gl-transition-fast:all 0.15s ease;--gl-transition-modal:all 0.3s cubic-bezier(0.4, 0, 0.2, 1);--gl-tab-bar-height:82px;--gl-modal-max-width:340px;--gl-tab-bar-floating-bottom:16px;--gl-tab-bar-floating-gap:var(--gl-space-sm);--gl-tab-bar-floating-padding:6px 10px;--gl-tab-bar-floating-radius:var(--gl-radius-full);--gl-tab-bar-accessory-size:56px;--gl-tab-bar-spotlight-color:var(--gl-color-primary);--gl-placeholder:rgba(255, 255, 255, 0.35);--gl-accordion-body-color:var(--gl-color-text-muted);--gl-toggle-thumb-bg:linear-gradient(to bottom,\n rgba(255,255,255,0.9) 0%,\n rgba(255,255,255,0.7) 100%);--gl-range-track-bg:var(--gl-surface-2);--gl-range-track-border:var(--gl-border-subtle)}[data-theme=light]{color-scheme:light;--gl-color-primary:#e8852d;--gl-color-primary-dark:#c96a1e;--gl-color-primary-mid:color-mix(in srgb, var(--gl-color-primary) 52%, var(--gl-color-primary-dark));--gl-color-bg-dark:#e8ecf1;--gl-color-bg-mid:#f0f4f8;--gl-color-bg-light:#f5f7fa;--gl-color-text:#1a2a36;--gl-color-text-muted:rgba(26, 42, 54, 0.55);--gl-color-text-on-light:#1a3a4a;--gl-color-text-heading:#0f1f2a;--gl-select-chevron:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='rgba(26,42,54,0.55)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E\");--gl-color-success:#28a745;--gl-color-error:#dc3545;--gl-color-warning:#e6a800;--gl-color-success-dark:#1e7e34;--gl-color-error-dark:#b02a37;--gl-color-on-primary:#ffffff;--gl-color-on-success:#ffffff;--gl-color-on-error:#ffffff;--gl-color-primary-on-surface:color-mix(in srgb, var(--gl-color-primary) 60%, #000000);--gl-color-success-on-surface:color-mix(in srgb, var(--gl-color-success) 68%, #000000);--gl-color-error-on-surface:color-mix(in srgb, var(--gl-color-error) 82%, #000000);--gl-color-warning-on-surface:color-mix(in srgb, var(--gl-color-warning) 56%, #000000);--gl-state-scrim:rgba(255, 255, 255, 0.30);--gl-color-primary-surface:color-mix(in srgb, var(--gl-color-primary) 25%, transparent);--gl-color-primary-border:var(--gl-border-warm);--gl-color-success-surface:color-mix(in srgb, var(--gl-color-success) 15%, transparent);--gl-color-success-border:color-mix(in srgb, var(--gl-color-success) 30%, transparent);--gl-color-error-surface:color-mix(in srgb, var(--gl-color-error) 15%, transparent);--gl-color-error-border:color-mix(in srgb, var(--gl-color-error) 30%, transparent);--gl-color-warning-surface:color-mix(in srgb, var(--gl-color-warning) 15%, transparent);--gl-color-warning-border:color-mix(in srgb, var(--gl-color-warning) 30%, transparent);--gl-surface-1:rgba(255, 255, 255, 0.50);--gl-surface-2:rgba(255, 255, 255, 0.60);--gl-surface-3:rgba(255, 255, 255, 0.70);--gl-surface-4:rgba(255, 255, 255, 0.75);--gl-surface-5:rgba(255, 255, 255, 0.85);--gl-surface-milk:rgba(255, 255, 255, 0.85);--gl-surface-milk-strong:rgba(255, 255, 255, 0.92);--gl-surface-overlay:rgba(0, 0, 0, 0.25);--gl-card-glow-top:rgba(255, 255, 255, 0.90);--gl-card-glow-mid:rgba(255, 255, 255, 0.78);--gl-card-glow-low:rgba(255, 255, 255, 0.65);--gl-card-glow-bottom:rgba(255, 255, 255, 0.50);--gl-card-icon-color:rgba(26, 42, 54, 0.5);--gl-card-text-color:rgba(26, 42, 54, 0.6);--gl-border-subtle:rgba(0, 0, 0, 0.08);--gl-border-medium:rgba(0, 0, 0, 0.12);--gl-border-strong:rgba(0, 0, 0, 0.15);--gl-border-milk:rgba(0, 0, 0, 0.10);--gl-border-warm:color-mix(in srgb, var(--gl-color-primary) 30%, transparent);--gl-border-focus:color-mix(in srgb, var(--gl-color-primary) 50%, transparent);--gl-icon-default:rgba(26, 42, 54, 0.50);--gl-icon-muted:rgba(26, 42, 54, 0.35);--gl-icon-strong:rgba(26, 42, 54, 0.70);--gl-icon-on-primary:var(--gl-color-on-primary, #ffffff);--gl-icon-on-secondary:#1a3a4a;--gl-icon-on-tertiary:rgba(26, 42, 54, 0.50);--gl-shadow-card:0 4px 20px rgba(0, 0, 0, 0.06);--gl-shadow-btn:0 2px 10px rgba(0, 0, 0, 0.06);--gl-shadow-btn-primary:0 4px 16px color-mix(in srgb, var(--gl-color-primary) 25%, transparent),0 2px 6px rgba(0, 0, 0, 0.08);--gl-shadow-glow:0 2px 8px rgba(0, 0, 0, 0.05),0 4px 12px rgba(0, 0, 0, 0.04);--gl-shadow-modal:0 16px 48px rgba(0, 0, 0, 0.12),0 4px 16px rgba(0, 0, 0, 0.08);--gl-shadow-toast:0 4px 20px rgba(0, 0, 0, 0.10);--gl-shadow-focus:0 0 0 3px color-mix(in srgb, var(--gl-color-primary) 25%, transparent);--gl-inset-subtle:inset 0 1px 1px rgba(255, 255, 255, 0.60);--gl-inset-medium:inset 0 1px 1px rgba(255, 255, 255, 0.70);--gl-inset-strong:inset 0 1px 2px rgba(255, 255, 255, 0.80);--gl-inset-milk:inset 0 1px 2px rgba(255, 255, 255, 0.90);--gl-bg-aurora-1:rgba(100, 200, 220, 0.15);--gl-bg-aurora-2:rgba(240, 180, 100, 0.10);--gl-bg-aurora-3:rgba(120, 200, 230, 0.12);--gl-bg-light-streak-1:rgba(140, 230, 220, 0.10);--gl-bg-light-streak-2:rgba(160, 220, 210, 0.08);--gl-bg-warm-glow:rgba(240, 180, 100, 0.08);--gl-placeholder:rgba(26, 42, 54, 0.30);--gl-accordion-body-color:var(--gl-color-text-muted);--gl-toggle-thumb-bg:linear-gradient(to bottom, #ffffff 0%, #f0f0f0 100%);--gl-range-track-bg:var(--gl-surface-2);--gl-range-track-border:var(--gl-border-subtle)}[data-density=compact]{--gl-control-height:40px;--gl-control-padding-x:var(--gl-space-sm);--gl-btn-height:40px;--gl-btn-height-sm:32px;--gl-btn-height-lg:48px;--gl-textarea-min-height:88px;--gl-list-item-min-height:48px;--gl-list-item-padding-y:10px;--gl-toggle-width:44px;--gl-toggle-height:26px;--gl-toggle-thumb-size:18px;--gl-check-size:20px;--gl-modal-action-height:44px}";
|
|
6
6
|
|
|
7
7
|
// … and everything else, in two pieces around where they were.
|
|
8
8
|
const componentsHead = "[class*=gl-],[class*=glass-],[class*=glass-]::after,[class*=glass-]::before{box-sizing:border-box}";
|
|
9
|
-
const componentsTail = ".glass-bg{background:radial-gradient(ellipse at 20% 40%,var(--gl-bg-aurora-1) 0,transparent 55%),radial-gradient(ellipse at 80% 65%,var(--gl-bg-aurora-2) 0,transparent 50%),radial-gradient(ellipse at 50% 20%,var(--gl-bg-aurora-3) 0,transparent 50%),linear-gradient(170deg,var(--gl-color-bg-light) 0,var(--gl-color-bg-mid) 50%,var(--gl-color-bg-dark) 100%);position:relative;min-height:100vh;overflow-x:hidden;font-family:var(--gl-font-family);color:var(--gl-color-text);-webkit-font-smoothing:antialiased;transition:background .4s,color .3s;isolation:isolate}.glass-bg::before{content:'';position:absolute;top:20%;left:-30%;width:160%;height:55%;background:radial-gradient(ellipse at 35% 45%,var(--gl-bg-light-streak-1) 0,transparent 50%),radial-gradient(ellipse at 65% 55%,var(--gl-bg-light-streak-2) 0,transparent 45%);transform:rotate(-8deg);pointer-events:none;z-index:-1}.glass-bg::after{content:'';position:absolute;top:40%;right:-20%;width:70%;height:50%;background:radial-gradient(ellipse at center,var(--gl-bg-warm-glow) 0,transparent 65%);pointer-events:none;z-index:-1}.glass-bg>*{position:relative}.glass-bg--has-tab-bar{padding-bottom:var(--gl-tab-bar-height)}.glass-bg--has-tab-bar-floating{padding-bottom:calc(var(--gl-tab-bar-accessory-size) + var(--gl-tab-bar-floating-bottom) + var(--gl-space-md))}.glass-nav{display:flex;justify-content:space-between;align-items:center;padding:0 var(--gl-space-xs)}.glass-pill{width:46px;height:46px;border-radius:var(--gl-radius-pill);background:var(--gl-surface-3);backdrop-filter:blur(var(--gl-blur));-webkit-backdrop-filter:blur(var(--gl-blur));border:1.5px solid var(--gl-border-strong);display:flex;align-items:center;justify-content:center;cursor:pointer;transition:var(--gl-transition);color:var(--gl-color-text);box-shadow:var(--gl-shadow-glow),var(--gl-inset-medium);outline:0;-webkit-tap-highlight-color:transparent}.glass-pill:hover{background:var(--gl-surface-5);transform:scale(1.05)}.glass-pill:active{transform:scale(.95)}.glass-pill ::slotted(svg),.glass-pill svg{width:20px;height:20px;fill:none;stroke:var(--gl-color-text);stroke-width:2.2;stroke-linecap:round;stroke-linejoin:round}.glass-title{text-align:center;color:var(--gl-color-text-heading);font-size:var(--gl-font-size-title);font-weight:var(--gl-font-weight-semibold);line-height:1.3;text-shadow:0 2px 12px rgba(0,0,0,.15);letter-spacing:-.3px}.glass-card{background:var(--gl-surface-2);backdrop-filter:blur(var(--gl-blur));-webkit-backdrop-filter:blur(var(--gl-blur));border:1.5px solid var(--gl-border-medium);border-radius:var(--gl-radius-card);padding:var(--gl-space-3xl) var(--gl-space-xl) var(--gl-space-2xl);box-shadow:var(--gl-shadow-card),var(--gl-inset-strong)}.glass-card--glow{position:relative;overflow:hidden;background:linear-gradient(to bottom,var(--gl-card-glow-top) 0,var(--gl-card-glow-mid) 25%,var(--gl-card-glow-low) 55%,var(--gl-card-glow-bottom) 100%)}.glass-card--glow::before{content:'';position:absolute;top:0;left:10%;right:10%;height:1px;background:linear-gradient(90deg,transparent 0,rgba(255,255,255,.5) 30%,rgba(255,255,255,.6) 50%,rgba(255,255,255,.5) 70%,transparent 100%);z-index:1}.glass-card__icon{display:flex;align-items:center;justify-content:center;margin:0 auto var(--gl-space-lg)}.glass-card__icon svg{width:64px;height:64px;stroke:var(--gl-card-icon-color);stroke-width:1.2;fill:none}.glass-card__text{color:var(--gl-card-text-color);font-size:var(--gl-font-size-base);font-weight:var(--gl-font-weight-normal);line-height:1.55;text-align:center}.glass-btn{display:flex;align-items:center;justify-content:center;gap:10px;width:100%;height:56px;border:none;border-radius:var(--gl-radius-btn);font-family:var(--gl-font-family);font-size:var(--gl-font-size-btn);font-weight:var(--gl-font-weight-semibold);cursor:pointer;transition:var(--gl-transition);outline:0;-webkit-tap-highlight-color:transparent}a.glass-btn{display:inline-flex;text-decoration:none}.glass-btn[hidden]{display:none}.glass-btn ::slotted(svg),.glass-btn svg{width:20px;height:20px;flex-shrink:0;fill:none;stroke:currentColor;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}.glass-btn--primary{background:linear-gradient(135deg,var(--gl-color-primary) 0,var(--gl-color-primary-mid) 50%,var(--gl-color-primary-dark) 100%);color:var(--gl-color-on-primary,#fff);border:1px solid var(--gl-border-warm);box-shadow:var(--gl-shadow-btn-primary),var(--gl-inset-strong)}.glass-btn--primary ::slotted(svg),.glass-btn--primary svg{fill:var(--gl-icon-on-primary);stroke:var(--gl-icon-on-primary);stroke-width:0}.glass-btn--primary:hover{transform:translateY(-1px)}.glass-btn--primary:active{transform:translateY(1px)}.glass-btn--secondary{background:linear-gradient(to bottom,var(--gl-surface-milk-strong) 0,var(--gl-surface-milk) 100%);backdrop-filter:blur(var(--gl-blur));-webkit-backdrop-filter:blur(var(--gl-blur));border:1.5px solid var(--gl-border-milk);color:var(--gl-color-text-on-light);box-shadow:var(--gl-shadow-btn),var(--gl-inset-milk)}.glass-btn--secondary ::slotted(svg),.glass-btn--secondary svg{fill:none;stroke:var(--gl-icon-on-secondary);stroke-width:2;stroke-linecap:round;stroke-linejoin:round}.glass-btn--secondary:hover{transform:translateY(-1px)}.glass-btn--secondary:active{transform:translateY(1px)}.glass-btn--tertiary{background:var(--gl-surface-2);backdrop-filter:blur(var(--gl-blur-light));-webkit-backdrop-filter:blur(var(--gl-blur-light));border:1px solid var(--gl-border-subtle);color:var(--gl-color-text-muted);box-shadow:0 4px 12px rgba(0,0,0,.1),var(--gl-inset-subtle)}.glass-btn--tertiary ::slotted(svg),.glass-btn--tertiary svg{fill:none;stroke:var(--gl-icon-on-tertiary);stroke-width:2;stroke-linecap:round;stroke-linejoin:round}.glass-btn--tertiary:hover{background:var(--gl-surface-4);color:var(--gl-color-text);transform:translateY(-1px)}.glass-btn--tertiary:active{transform:translateY(1px)}.glass-btn--sm{height:44px;font-size:var(--gl-font-size-sm);border-radius:var(--gl-radius-sm)}.glass-btn--lg{height:64px;font-size:var(--gl-font-size-lg)}.glass-btn--auto{width:auto;padding:0 var(--gl-space-xl)}.glass-status{background:var(--gl-surface-1);backdrop-filter:blur(var(--gl-blur-light));-webkit-backdrop-filter:blur(var(--gl-blur-light));border:1px solid var(--gl-border-subtle);border-radius:var(--gl-radius-btn);padding:var(--gl-space-md) var(--gl-space-lg);display:flex;align-items:center;gap:var(--gl-space-sm);box-shadow:0 4px 12px rgba(0,0,0,.08),var(--gl-inset-subtle)}.glass-status ::slotted(svg),.glass-status svg{width:20px;height:20px;flex-shrink:0;stroke:var(--gl-icon-muted);stroke-width:2;fill:none;stroke-linecap:round;stroke-linejoin:round}.glass-status p{color:var(--gl-color-text-muted);font-size:var(--gl-font-size-sm);font-weight:var(--gl-font-weight-normal);line-height:1.45}.glass-input-group{display:flex;flex-direction:column;gap:var(--gl-space-xs)}.glass-label{font-size:var(--gl-font-size-sm);font-weight:var(--gl-font-weight-medium);color:var(--gl-icon-strong);padding-left:var(--gl-space-2xs)}.glass-input{width:100%;height:52px;padding:0 var(--gl-space-md);background:var(--gl-surface-2);backdrop-filter:blur(var(--gl-blur-light));-webkit-backdrop-filter:blur(var(--gl-blur-light));border:1.5px solid var(--gl-border-medium);border-radius:var(--gl-radius-input);color:var(--gl-color-text);font-family:var(--gl-font-family);font-size:var(--gl-font-size-base);transition:var(--gl-transition);outline:0;box-shadow:var(--gl-inset-subtle);-webkit-tap-highlight-color:transparent}.glass-input::placeholder{color:var(--gl-placeholder)}.glass-input[type=date],.glass-input[type=datetime-local],.glass-input[type=month],.glass-input[type=time]{-webkit-appearance:none;appearance:none}.glass-input::-webkit-date-and-time-value{text-align:start}.glass-input:focus{border-color:var(--gl-border-focus);background:var(--gl-surface-3);box-shadow:var(--gl-shadow-focus),var(--gl-inset-medium)}.glass-input:disabled{opacity:.4;cursor:not-allowed}.glass-input--error{border-color:var(--gl-color-error)}.glass-input--error:focus{box-shadow:0 0 0 3px color-mix(in srgb,var(--gl-color-error) 25%,transparent),var(--gl-inset-medium)}.glass-hint{font-size:var(--gl-font-size-xs);color:var(--gl-color-text-muted);padding-left:var(--gl-space-2xs)}.glass-hint--error{color:var(--gl-color-error)}.glass-textarea{width:100%;min-height:120px;padding:var(--gl-space-md);background:var(--gl-surface-2);backdrop-filter:blur(var(--gl-blur-light));-webkit-backdrop-filter:blur(var(--gl-blur-light));border:1.5px solid var(--gl-border-medium);border-radius:var(--gl-radius-input);color:var(--gl-color-text);font-family:var(--gl-font-family);font-size:var(--gl-font-size-base);line-height:1.5;resize:vertical;transition:var(--gl-transition);outline:0;box-shadow:var(--gl-inset-subtle)}.glass-textarea::placeholder{color:var(--gl-placeholder)}.glass-textarea:focus{border-color:var(--gl-border-focus);background:var(--gl-surface-3);box-shadow:var(--gl-shadow-focus),var(--gl-inset-medium)}.glass-select{width:100%;height:52px;padding:0 var(--gl-space-3xl) 0 var(--gl-space-md);background:var(--gl-surface-2);backdrop-filter:blur(var(--gl-blur-light));-webkit-backdrop-filter:blur(var(--gl-blur-light));border:1.5px solid var(--gl-border-medium);border-radius:var(--gl-radius-input);color:var(--gl-color-text);font-family:var(--gl-font-family);font-size:var(--gl-font-size-base);transition:var(--gl-transition);outline:0;box-shadow:var(--gl-inset-subtle);cursor:pointer;appearance:none;-webkit-appearance:none;background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='rgba(255,255,255,0.6)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E\");background-repeat:no-repeat;background-position:right 16px center}.glass-select:focus{border-color:var(--gl-border-focus);box-shadow:var(--gl-shadow-focus),var(--gl-inset-medium)}.glass-select option{background:var(--gl-color-bg-mid);color:var(--gl-color-text)}.glass-search{position:relative;display:flex;align-items:center}.glass-search__icon{position:absolute;left:var(--gl-space-md);width:18px;height:18px;stroke:var(--gl-icon-muted)!important;stroke-width:2!important;stroke-linecap:round!important;stroke-linejoin:round!important;fill:none!important;pointer-events:none;z-index:2}.glass-search .glass-input{padding-left:44px;border-radius:var(--gl-radius-full)}.glass-toggle{display:inline-flex;align-items:flex-start;gap:var(--gl-space-sm);cursor:pointer;-webkit-tap-highlight-color:transparent}.glass-toggle__input{position:absolute;opacity:0;margin:0;width:52px;height:30px;pointer-events:none}.glass-toggle__track{position:relative;width:52px;height:30px;background:var(--gl-surface-2);backdrop-filter:blur(var(--gl-blur-soft));-webkit-backdrop-filter:blur(var(--gl-blur-soft));border:1.5px solid var(--gl-border-medium);border-radius:var(--gl-radius-full);transition:var(--gl-transition);box-shadow:var(--gl-inset-subtle);flex-shrink:0;margin-top:max(0px,calc((1lh - 30px)/ 2))}.glass-toggle__thumb{position:absolute;top:3px;left:3px;width:22px;height:22px;border-radius:var(--gl-radius-pill);background:var(--gl-toggle-thumb-bg);box-shadow:0 2px 6px rgba(0,0,0,.2),var(--gl-inset-milk);transition:var(--gl-transition)}.glass-toggle__input:checked+.glass-toggle__track{background:linear-gradient(135deg,var(--gl-color-primary) 0,var(--gl-color-primary-dark) 100%);border-color:var(--gl-border-warm)}.glass-toggle__input:checked+.glass-toggle__track .glass-toggle__thumb{transform:translateX(22px)}.glass-toggle__input:focus-visible+.glass-toggle__track{box-shadow:var(--gl-shadow-focus)}.glass-toggle__label{font-size:var(--gl-font-size-base);color:var(--gl-color-text);user-select:none;margin-top:max(0px,calc((30px - 1lh)/ 2))}.glass-checkbox{display:inline-flex;align-items:flex-start;gap:var(--gl-space-sm);cursor:pointer;-webkit-tap-highlight-color:transparent}.glass-checkbox__input{position:absolute;opacity:0;margin:0;width:24px;height:24px;pointer-events:none}.glass-checkbox__box{width:24px;height:24px;border-radius:var(--gl-radius-xs);background:var(--gl-surface-2);backdrop-filter:blur(var(--gl-blur-soft));-webkit-backdrop-filter:blur(var(--gl-blur-soft));border:1.5px solid var(--gl-border-medium);display:flex;align-items:center;justify-content:center;transition:var(--gl-transition);box-shadow:var(--gl-inset-subtle);flex-shrink:0;margin-top:max(0px,calc((1lh - 24px)/ 2))}.glass-checkbox__box svg{width:14px;height:14px;stroke:var(--gl-color-on-primary,#ffffff);stroke-width:3;fill:none;stroke-linecap:round;stroke-linejoin:round;opacity:0;transform:scale(.5);transition:var(--gl-transition-fast)}.glass-checkbox__input:checked+.glass-checkbox__box{background:linear-gradient(135deg,var(--gl-color-primary) 0,var(--gl-color-primary-dark) 100%);border-color:var(--gl-border-warm)}.glass-checkbox__input:checked+.glass-checkbox__box svg{opacity:1;transform:scale(1)}.glass-checkbox__input:focus-visible+.glass-checkbox__box{box-shadow:var(--gl-shadow-focus)}.glass-checkbox__label{font-size:var(--gl-font-size-base);color:var(--gl-color-text);user-select:none;margin-top:max(0px,calc((24px - 1lh)/ 2))}.glass-radio{display:inline-flex;align-items:flex-start;gap:var(--gl-space-sm);cursor:pointer;-webkit-tap-highlight-color:transparent}.glass-radio__input{position:absolute;opacity:0;margin:0;width:24px;height:24px;pointer-events:none}.glass-radio__circle{width:24px;height:24px;border-radius:var(--gl-radius-pill);background:var(--gl-surface-2);backdrop-filter:blur(var(--gl-blur-soft));border:1.5px solid var(--gl-border-medium);display:flex;align-items:center;justify-content:center;transition:var(--gl-transition);box-shadow:var(--gl-inset-subtle);flex-shrink:0;margin-top:max(0px,calc((1lh - 24px)/ 2))}.glass-radio__dot{width:10px;height:10px;border-radius:var(--gl-radius-pill);background:#fff;opacity:0;transform:scale(0);transition:var(--gl-transition-fast)}.glass-radio__input:checked+.glass-radio__circle{background:linear-gradient(135deg,var(--gl-color-primary) 0,var(--gl-color-primary-dark) 100%);border-color:var(--gl-border-warm)}.glass-radio__input:checked+.glass-radio__circle .glass-radio__dot{opacity:1;transform:scale(1)}.glass-radio__input:focus-visible+.glass-radio__circle{box-shadow:var(--gl-shadow-focus)}.glass-radio__label{font-size:var(--gl-font-size-base);color:var(--gl-color-text);user-select:none;margin-top:max(0px,calc((24px - 1lh)/ 2))}.glass-range-group{display:flex;flex-direction:column;gap:var(--gl-space-xs)}.glass-range-header{display:flex;justify-content:space-between;align-items:baseline}.glass-range-value{font-size:var(--gl-font-size-sm);font-weight:var(--gl-font-weight-semibold);color:var(--gl-color-primary);font-variant-numeric:tabular-nums}.glass-range{-webkit-appearance:none;appearance:none;width:100%;height:6px;border-radius:var(--gl-radius-full);background:var(--gl-range-track-bg);border:1px solid var(--gl-range-track-border);outline:0;cursor:pointer}.glass-range::-webkit-slider-thumb{-webkit-appearance:none;appearance:none;box-sizing:border-box;width:26px;height:26px;border-radius:var(--gl-radius-pill);background:linear-gradient(135deg,var(--gl-color-primary) 0,var(--gl-color-primary-dark) 100%);border:2px solid rgba(255,255,255,.5);box-shadow:0 2px 8px color-mix(in srgb,var(--gl-color-primary-mid) 35%,transparent),var(--gl-inset-strong);margin-top:-2px;cursor:pointer;transition:var(--gl-transition)}.glass-range::-webkit-slider-thumb:hover{transform:scale(1.1)}.glass-range::-moz-range-thumb{width:26px;height:26px;border-radius:var(--gl-radius-pill);background:linear-gradient(135deg,var(--gl-color-primary) 0,var(--gl-color-primary-dark) 100%);border:2px solid rgba(255,255,255,.5);box-shadow:0 2px 8px color-mix(in srgb,var(--gl-color-primary-mid) 35%,transparent);cursor:pointer}.glass-range::-moz-range-track{height:6px;border-radius:var(--gl-radius-full);background:var(--gl-range-track-bg);border:1px solid var(--gl-range-track-border)}.glass-range:focus-visible{box-shadow:var(--gl-shadow-focus)}.glass-progress{width:100%;display:flex;flex-direction:column;gap:var(--gl-space-xs)}.glass-progress__header{display:flex;justify-content:space-between;align-items:baseline}.glass-progress__label{font-size:var(--gl-font-size-sm);font-weight:var(--gl-font-weight-medium);color:var(--gl-icon-strong)}.glass-progress__value{font-size:var(--gl-font-size-xs);font-weight:var(--gl-font-weight-semibold);color:var(--gl-color-text-muted);font-variant-numeric:tabular-nums}.glass-progress__track{width:100%;height:8px;border-radius:var(--gl-radius-full);background:var(--gl-surface-2);border:1px solid var(--gl-border-subtle);overflow:hidden;box-shadow:var(--gl-inset-subtle)}.glass-progress__fill{height:100%;border-radius:var(--gl-radius-full);background:linear-gradient(90deg,var(--gl-color-primary) 0,var(--gl-color-primary-dark) 100%);box-shadow:0 0 8px color-mix(in srgb,var(--gl-color-primary) 30%,transparent),var(--gl-inset-strong);transition:width .5s cubic-bezier(.4, 0, .2, 1);position:relative}.glass-progress__fill::after{content:'';position:absolute;top:0;left:0;right:0;height:50%;border-radius:var(--gl-radius-full);background:linear-gradient(to bottom,rgba(255,255,255,.3) 0,transparent 100%)}.glass-progress--sm .glass-progress__track{height:4px}.glass-progress--lg .glass-progress__track{height:12px}.glass-progress--success .glass-progress__fill{background:linear-gradient(90deg,var(--gl-color-success) 0,var(--gl-color-success-dark,#2da44e) 100%);box-shadow:0 0 8px color-mix(in srgb,var(--gl-color-success) 30%,transparent),var(--gl-inset-strong)}.glass-progress--error .glass-progress__fill{background:linear-gradient(90deg,var(--gl-color-error) 0,var(--gl-color-error-dark,#d63027) 100%);box-shadow:0 0 8px color-mix(in srgb,var(--gl-color-error) 30%,transparent),var(--gl-inset-strong)}.glass-modal-overlay{position:fixed;inset:0;background:var(--gl-surface-overlay);backdrop-filter:blur(var(--gl-blur-soft));-webkit-backdrop-filter:blur(var(--gl-blur-soft));display:flex;align-items:center;justify-content:center;padding:var(--gl-space-lg);z-index:1000;opacity:0;pointer-events:none;transition:var(--gl-transition-modal);font-family:var(--gl-font-family);-webkit-font-smoothing:antialiased}.glass-modal-overlay.is-active{opacity:1;pointer-events:auto}.glass-modal{width:100%;max-width:340px;background:linear-gradient(to bottom,var(--gl-card-glow-top) 0,var(--gl-card-glow-bottom) 100%);backdrop-filter:blur(var(--gl-blur-heavy));-webkit-backdrop-filter:blur(var(--gl-blur-heavy));border:1.5px solid var(--gl-border-medium);border-radius:var(--gl-radius-card);overflow:hidden;box-shadow:var(--gl-shadow-modal);transform:scale(.9) translateY(20px);transition:var(--gl-transition-modal);position:relative}.glass-modal-overlay.is-active .glass-modal{transform:scale(1) translateY(0)}.glass-modal::before{content:'';position:absolute;top:0;left:10%;right:10%;height:1px;background:linear-gradient(90deg,transparent 0,rgba(255,255,255,.4) 30%,rgba(255,255,255,.5) 50%,rgba(255,255,255,.4) 70%,transparent 100%)}.glass-modal__header{padding:var(--gl-space-xl) var(--gl-space-xl) var(--gl-space-sm);text-align:center}.glass-modal__title{font-size:var(--gl-font-size-modal);font-weight:var(--gl-font-weight-semibold);color:var(--gl-color-text)}.glass-modal__body{padding:var(--gl-space-sm) var(--gl-space-xl) var(--gl-space-xl);text-align:center}.glass-modal__body p{color:var(--gl-color-text-muted);font-size:var(--gl-font-size-base);line-height:1.55}.glass-modal__footer{display:flex;border-top:1px solid var(--gl-border-subtle)}.glass-modal__action{flex:1;height:52px;background:0 0;border:none;font-family:var(--gl-font-family);font-size:var(--gl-font-size-btn);font-weight:var(--gl-font-weight-medium);color:var(--gl-color-text-muted);cursor:pointer;transition:var(--gl-transition-fast);outline:0}.glass-modal__action:hover{background:var(--gl-surface-1)}.glass-modal__action+.glass-modal__action{border-left:1px solid var(--gl-border-subtle)}.glass-modal__action--primary{color:var(--gl-color-primary);font-weight:var(--gl-font-weight-semibold)}.glass-modal__action--danger{color:var(--gl-color-error);font-weight:var(--gl-font-weight-semibold)}.glass-toast{position:fixed;top:var(--gl-toast-top,var(--gl-space-4xl));left:50%;transform:translateX(-50%) translateY(-20px);min-width:280px;max-width:340px;padding:var(--gl-space-md) var(--gl-space-lg);background:linear-gradient(to bottom,var(--gl-surface-4) 0,var(--gl-surface-2) 100%);backdrop-filter:blur(var(--gl-blur));-webkit-backdrop-filter:blur(var(--gl-blur));border:1px solid var(--gl-border-medium);border-radius:var(--gl-radius-btn);display:flex;align-items:center;gap:var(--gl-space-sm);box-shadow:var(--gl-shadow-toast),var(--gl-inset-medium);z-index:1100;opacity:0;pointer-events:none;transition:var(--gl-transition-modal);font-family:var(--gl-font-family);-webkit-font-smoothing:antialiased}.glass-toast.is-visible{opacity:1;transform:translateX(-50%) translateY(0);pointer-events:auto}.glass-toast__icon{width:22px;height:22px;flex-shrink:0;stroke:currentColor;stroke-width:2;fill:none;stroke-linecap:round;stroke-linejoin:round}.glass-toast__icon ::slotted(svg){display:block;width:100%;height:100%}.glass-toast--success .glass-toast__icon{stroke:var(--gl-color-success)}.glass-toast--error .glass-toast__icon{stroke:var(--gl-color-error)}.glass-toast--warning .glass-toast__icon{stroke:var(--gl-color-warning)}.glass-toast__text{flex:1 1 auto;min-width:0;font-size:var(--gl-font-size-sm);font-weight:var(--gl-font-weight-medium);color:var(--gl-color-text);line-height:1.4}.glass-toast:has(.glass-toast__action){width:max-content;max-width:min(480px,calc(100% - 2 * var(--gl-space-md)))}.glass-toast--success{--gl-toast-action-surface:var(--gl-color-success-surface);--gl-toast-action-border:var(--gl-color-success-border);--gl-toast-action-ink:var(--gl-color-success-on-surface)}.glass-toast--error{--gl-toast-action-surface:var(--gl-color-error-surface);--gl-toast-action-border:var(--gl-color-error-border);--gl-toast-action-ink:var(--gl-color-error-on-surface)}.glass-toast--warning{--gl-toast-action-surface:var(--gl-color-warning-surface);--gl-toast-action-border:var(--gl-color-warning-border);--gl-toast-action-ink:var(--gl-color-warning-on-surface)}.glass-toast__action,.glass-toast__close{-webkit-appearance:none;appearance:none;flex:none;position:relative;font:inherit;cursor:pointer;transition:var(--gl-transition-fast);outline:0;-webkit-tap-highlight-color:transparent}.glass-toast__action{height:32px;padding:0 14px;border:1px solid var(--gl-toast-action-border,var(--gl-color-primary-border));border-radius:var(--gl-radius-full);background:linear-gradient(var(--gl-toast-action-surface,var(--gl-color-primary-surface)),var(--gl-toast-action-surface,var(--gl-color-primary-surface))),linear-gradient(var(--gl-state-scrim),var(--gl-state-scrim)),var(--gl-state-scrim);color:var(--gl-toast-action-ink,var(--gl-color-primary-on-surface));font-size:var(--gl-font-size-sm);font-weight:var(--gl-font-weight-semibold);white-space:nowrap}.glass-toast__action::after{content:\"\";position:absolute;inset:-6px 0}.glass-toast__action:hover{box-shadow:inset 0 0 0 100px color-mix(in srgb,var(--gl-toast-action-ink,var(--gl-color-primary-on-surface)) 10%,transparent)}.glass-toast__action:active{transform:scale(.96)}.glass-toast__close{width:28px;height:28px;margin:0 -8px 0 -4px;padding:0;display:inline-flex;align-items:center;justify-content:center;border:0;border-radius:50%;background:0 0;color:var(--gl-color-text-muted)}.glass-toast__close::after{content:\"\";position:absolute;inset:-8px}.glass-toast__close:hover{background:var(--gl-surface-3);color:var(--gl-color-text)}.glass-toast__close svg{width:16px;height:16px;fill:none;stroke:currentColor;stroke-width:2;stroke-linecap:round}.glass-toast__action:focus-visible,.glass-toast__close:focus-visible{box-shadow:var(--gl-shadow-focus)}.glass-tab-bar{position:fixed;bottom:0;left:0;right:0;height:var(--gl-tab-bar-height);background:linear-gradient(to bottom,var(--gl-surface-3) 0,var(--gl-surface-1) 100%);backdrop-filter:blur(var(--gl-blur));-webkit-backdrop-filter:blur(var(--gl-blur));border-top:1px solid var(--gl-border-subtle);display:flex;justify-content:space-around;align-items:flex-start;padding-top:var(--gl-space-xs);padding-bottom:env(safe-area-inset-bottom,8px);z-index:900;box-shadow:0 -4px 20px rgba(0,0,0,.08),var(--gl-inset-subtle)}.glass-tab-bar__item{display:flex;flex-direction:column;align-items:center;gap:var(--gl-space-2xs);padding:var(--gl-space-2xs) var(--gl-space-sm);background:0 0;border:none;cursor:pointer;transition:var(--gl-transition);outline:0;-webkit-tap-highlight-color:transparent;min-width:60px}.glass-tab-bar__icon{width:24px;height:24px;display:flex;align-items:center;justify-content:center;position:relative}.glass-tab-bar__icon svg{width:24px;height:24px;fill:none;stroke:var(--gl-icon-muted);stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round;transition:var(--gl-transition)}.glass-tab-bar__label{font-size:10px;font-weight:var(--gl-font-weight-medium);color:var(--gl-icon-muted);transition:var(--gl-transition);letter-spacing:.2px}.glass-tab-bar__item.is-active .glass-tab-bar__icon svg{stroke:var(--gl-color-primary);filter:drop-shadow(0 0 6px color-mix(in srgb, var(--gl-color-primary) 35%, transparent))}.glass-tab-bar__item.is-active .glass-tab-bar__label{color:var(--gl-color-primary)}.glass-tab-bar__item.is-active .glass-tab-bar__icon::after{content:'';position:absolute;bottom:-6px;left:50%;transform:translateX(-50%);width:4px;height:4px;border-radius:var(--gl-radius-pill);background:var(--gl-color-primary);box-shadow:0 0 6px color-mix(in srgb,var(--gl-color-primary) 50%,transparent)}.glass-tab-bar__item:not(.is-active):hover .glass-tab-bar__icon svg{stroke:var(--gl-icon-default)}.glass-tab-bar__item:not(.is-active):hover .glass-tab-bar__label{color:var(--gl-icon-default)}.glass-tab-bar__badge{position:absolute;top:-4px;right:-8px;min-width:16px;height:16px;padding:0 4px;border-radius:var(--gl-radius-full);background:var(--gl-color-error-dark,#d63027);color:#fff;font-size:10px;font-weight:var(--gl-font-weight-semibold);display:flex;align-items:center;justify-content:center;box-shadow:0 2px 6px color-mix(in srgb,var(--gl-color-error) 40%,transparent)}.glass-tab-bar-dock{position:fixed;left:50%;bottom:calc(var(--gl-tab-bar-floating-bottom) + env(safe-area-inset-bottom,0px));transform:translateX(-50%);display:flex;align-items:center;gap:var(--gl-tab-bar-floating-gap);z-index:900;max-width:calc(100vw - 2 * var(--gl-space-md))}.glass-tab-bar-dock--accessory-left{flex-direction:row-reverse}.glass-tab-bar.glass-tab-bar--floating{position:static;left:auto;right:auto;bottom:auto;height:auto;width:max-content;padding:var(--gl-tab-bar-floating-padding);border-radius:var(--gl-tab-bar-floating-radius);border:1px solid var(--gl-border-subtle);background:linear-gradient(to bottom,var(--gl-surface-3) 0,var(--gl-surface-1) 100%);box-shadow:0 8px 32px rgba(0,0,0,.18),0 2px 8px rgba(0,0,0,.08),var(--gl-inset-subtle);display:flex;justify-content:flex-start;align-items:center;gap:var(--gl-space-2xs)}.glass-tab-bar--floating .glass-tab-bar__item{position:relative;border-radius:var(--gl-radius-full);padding:var(--gl-space-2xs) var(--gl-space-sm);min-width:auto;align-items:center}.glass-tab-bar--floating .glass-tab-bar__item>*{position:relative;z-index:1}.glass-tab-bar--floating .glass-tab-bar__item.is-active::before{content:'';position:absolute;inset:0;border-radius:inherit;background:radial-gradient(circle at center,color-mix(in srgb,var(--gl-tab-bar-spotlight-color) 28%,transparent) 0,color-mix(in srgb,var(--gl-tab-bar-spotlight-color) 10%,transparent) 55%,transparent 100%);pointer-events:none;z-index:0}.glass-tab-bar--floating .glass-tab-bar__item.is-active .glass-tab-bar__icon::after{display:none}.glass-tab-bar__accessory{width:var(--gl-tab-bar-accessory-size);height:var(--gl-tab-bar-accessory-size);border-radius:var(--gl-radius-pill);background:linear-gradient(to bottom,var(--gl-surface-3) 0,var(--gl-surface-1) 100%);backdrop-filter:blur(var(--gl-blur));-webkit-backdrop-filter:blur(var(--gl-blur));border:1px solid var(--gl-border-subtle);box-shadow:0 8px 32px rgba(0,0,0,.18),0 2px 8px rgba(0,0,0,.08),var(--gl-inset-subtle);display:flex;align-items:center;justify-content:center;cursor:pointer;transition:var(--gl-transition);outline:0;padding:0;-webkit-tap-highlight-color:transparent;flex-shrink:0}.glass-tab-bar__accessory ::slotted(svg),.glass-tab-bar__accessory svg{width:22px;height:22px;fill:none;stroke:var(--gl-icon-default);stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round;transition:var(--gl-transition)}.glass-tab-bar__accessory:hover{transform:translateY(-1px)}.glass-tab-bar__accessory:hover ::slotted(svg),.glass-tab-bar__accessory:hover svg{stroke:var(--gl-icon-strong)}.glass-tab-bar__accessory:focus-visible{box-shadow:0 8px 32px rgba(0,0,0,.18),var(--gl-shadow-focus),var(--gl-inset-subtle)}.glass-tab-bar__accessory--accent{background:linear-gradient(135deg,var(--gl-color-primary) 0,color-mix(in srgb,var(--gl-color-primary) 70%,transparent) 100%);border-color:color-mix(in srgb,var(--gl-color-primary) 50%,transparent);box-shadow:0 8px 32px color-mix(in srgb,var(--gl-color-primary) 35%,transparent),var(--gl-inset-medium)}.glass-tab-bar__accessory--accent ::slotted(svg),.glass-tab-bar__accessory--accent svg{stroke:var(--gl-color-on-primary,#ffffff)}.glass-tab-bar__accessory--accent:hover ::slotted(svg),.glass-tab-bar__accessory--accent:hover svg{stroke:var(--gl-color-on-primary,#ffffff)}.glass-tab-bar__accessory--success{background:linear-gradient(135deg,var(--gl-color-success) 0,color-mix(in srgb,var(--gl-color-success) 70%,transparent) 100%);border-color:color-mix(in srgb,var(--gl-color-success) 50%,transparent);box-shadow:0 8px 32px color-mix(in srgb,var(--gl-color-success) 35%,transparent),var(--gl-inset-medium)}.glass-tab-bar__accessory--success ::slotted(svg),.glass-tab-bar__accessory--success svg{stroke:var(--gl-color-on-success,#ffffff)}.glass-tab-bar__accessory--error{background:linear-gradient(135deg,var(--gl-color-error) 0,color-mix(in srgb,var(--gl-color-error) 70%,transparent) 100%);border-color:color-mix(in srgb,var(--gl-color-error) 50%,transparent);box-shadow:0 8px 32px color-mix(in srgb,var(--gl-color-error) 35%,transparent),var(--gl-inset-medium)}.glass-tab-bar__accessory--error ::slotted(svg),.glass-tab-bar__accessory--error svg{stroke:var(--gl-color-on-error,#ffffff)}.glass-accordion{display:flex;flex-direction:column;gap:var(--gl-space-xs)}.glass-accordion__item{background:var(--gl-surface-2);backdrop-filter:blur(var(--gl-blur-light));-webkit-backdrop-filter:blur(var(--gl-blur-light));border:1px solid var(--gl-border-subtle);border-radius:var(--gl-radius-btn);overflow:hidden;transition:var(--gl-transition);box-shadow:var(--gl-inset-subtle)}.glass-accordion__item.is-open{background:var(--gl-surface-3);border-color:var(--gl-border-medium);box-shadow:0 4px 16px rgba(0,0,0,.1),var(--gl-inset-medium)}.glass-accordion__trigger{width:100%;display:flex;align-items:center;justify-content:space-between;gap:var(--gl-space-sm);padding:var(--gl-space-md) var(--gl-space-lg);background:0 0;border:none;cursor:pointer;font-family:var(--gl-font-family);font-size:var(--gl-font-size-base);font-weight:var(--gl-font-weight-semibold);color:var(--gl-color-text);text-align:left;outline:0;transition:var(--gl-transition);-webkit-tap-highlight-color:transparent}.glass-accordion__trigger:hover{color:var(--gl-color-primary)}.glass-accordion__trigger-icon{display:flex;align-items:center;justify-content:center;flex-shrink:0}.glass-accordion__trigger-icon svg{width:18px;height:18px;fill:none;stroke:var(--gl-icon-default);stroke-width:2;stroke-linecap:round;stroke-linejoin:round;transition:transform .3s cubic-bezier(.4, 0, .2, 1)}.glass-accordion__item.is-open .glass-accordion__trigger-icon svg{transform:rotate(180deg);stroke:var(--gl-color-primary)}.glass-accordion__content{max-height:0;overflow:hidden;transition:max-height .35s cubic-bezier(.4, 0, .2, 1)}.glass-accordion__item.is-open .glass-accordion__content{max-height:500px}.glass-accordion__body{padding:0 var(--gl-space-lg) var(--gl-space-lg);color:var(--gl-accordion-body-color);font-size:var(--gl-font-size-sm);line-height:1.6}.glass-badge{--gl-badge-accent:var(--gl-color-primary);--gl-badge-accent-text:var(--gl-color-primary-on-surface, var(--gl-color-primary));display:inline-flex;align-items:center;gap:var(--gl-space-2xs);padding:var(--gl-space-2xs) var(--gl-space-sm);background:var(--gl-surface-3);backdrop-filter:blur(var(--gl-blur-soft));-webkit-backdrop-filter:blur(var(--gl-blur-soft));border:1px solid var(--gl-border-subtle);border-radius:var(--gl-radius-full);font-size:var(--gl-font-size-xs);font-weight:var(--gl-font-weight-medium);color:var(--gl-color-text);box-shadow:var(--gl-inset-subtle)}.glass-badge--primary{--gl-badge-accent:var(--gl-color-primary);--gl-badge-accent-text:var(--gl-color-primary-on-surface, var(--gl-color-primary));background:linear-gradient(135deg,var(--gl-color-primary-surface,rgba(245,166,35,.25)) 0,color-mix(in srgb,var(--gl-color-primary-dark) 20%,transparent) 100%),var(--gl-state-scrim,transparent);border-color:var(--gl-color-primary-border,var(--gl-border-warm));color:var(--gl-color-primary-on-surface,var(--gl-color-primary))}.glass-badge--success{--gl-badge-accent:var(--gl-color-success);--gl-badge-accent-text:var(--gl-color-success-on-surface, var(--gl-color-success));background:linear-gradient(var(--gl-color-success-surface,rgba(52,199,89,.15)) 0,var(--gl-color-success-surface,rgba(52,199,89,.15)) 100%),var(--gl-state-scrim,transparent);border-color:var(--gl-color-success-border,rgba(52,199,89,.3));color:var(--gl-color-success-on-surface,var(--gl-color-success))}.glass-badge--error{--gl-badge-accent:var(--gl-color-error);--gl-badge-accent-text:var(--gl-color-error-on-surface, var(--gl-color-error));background:linear-gradient(var(--gl-color-error-surface,rgba(255,59,48,.15)) 0,var(--gl-color-error-surface,rgba(255,59,48,.15)) 100%),var(--gl-state-scrim,transparent);border-color:var(--gl-color-error-border,rgba(255,59,48,.3));color:var(--gl-color-error-on-surface,var(--gl-color-error))}.glass-badge--warning{--gl-badge-accent:var(--gl-color-warning);--gl-badge-accent-text:var(--gl-color-warning-on-surface, var(--gl-color-warning));background:linear-gradient(var(--gl-color-warning-surface,rgba(255,204,0,.15)) 0,var(--gl-color-warning-surface,rgba(255,204,0,.15)) 100%),var(--gl-state-scrim,transparent);border-color:var(--gl-color-warning-border,rgba(255,204,0,.3));color:var(--gl-color-warning-on-surface,var(--gl-color-warning))}.glass-badge--interactive{font-family:inherit;-webkit-appearance:none;appearance:none;cursor:pointer;transition:var(--gl-transition-fast);outline:0;-webkit-tap-highlight-color:transparent}.glass-badge--interactive:hover{border-color:color-mix(in srgb,var(--gl-badge-accent) 45%,var(--gl-border-subtle));box-shadow:var(--gl-inset-subtle),inset 0 0 0 100px color-mix(in srgb,var(--gl-badge-accent) 12%,transparent)}.glass-badge--interactive:active{transform:scale(.96)}.glass-badge--interactive:focus-visible{box-shadow:var(--gl-shadow-focus),var(--gl-inset-subtle)}.glass-badge--selected{border-color:color-mix(in srgb,var(--gl-badge-accent) 55%,transparent);color:var(--gl-badge-accent-text);box-shadow:var(--gl-inset-subtle),inset 0 0 0 100px color-mix(in srgb,var(--gl-badge-accent) 22%,transparent)}.glass-badge--interactive.glass-badge--selected:hover{box-shadow:var(--gl-inset-subtle),inset 0 0 0 100px color-mix(in srgb,var(--gl-badge-accent) 30%,transparent)}.glass-badge--interactive.glass-badge--selected:focus-visible{box-shadow:var(--gl-shadow-focus),var(--gl-inset-subtle),inset 0 0 0 100px color-mix(in srgb,var(--gl-badge-accent) 22%,transparent)}.glass-divider{height:1px;border:none;background:linear-gradient(90deg,transparent 0,var(--gl-border-subtle) 20%,var(--gl-border-medium) 50%,var(--gl-border-subtle) 80%,transparent 100%)}.glass-avatar{width:44px;height:44px;border-radius:var(--gl-radius-pill);background:var(--gl-surface-3);backdrop-filter:blur(var(--gl-blur-soft));-webkit-backdrop-filter:blur(var(--gl-blur-soft));border:1.5px solid var(--gl-border-strong);display:flex;align-items:center;justify-content:center;overflow:hidden;box-shadow:var(--gl-shadow-glow),var(--gl-inset-medium);flex-shrink:0;font-size:var(--gl-font-size-btn);font-weight:var(--gl-font-weight-semibold);color:var(--gl-color-text)}.glass-avatar ::slotted(img),.glass-avatar img{width:100%;height:100%;object-fit:cover}.glass-avatar--sm{width:32px;height:32px;font-size:var(--gl-font-size-xs)}.glass-avatar--lg{width:56px;height:56px;font-size:var(--gl-font-size-lg)}.glass-theme-toggle{width:46px;height:46px;border-radius:var(--gl-radius-pill);background:var(--gl-surface-3);backdrop-filter:blur(var(--gl-blur));-webkit-backdrop-filter:blur(var(--gl-blur));border:1.5px solid var(--gl-border-strong);display:flex;align-items:center;justify-content:center;cursor:pointer;transition:var(--gl-transition);box-shadow:var(--gl-shadow-glow),var(--gl-inset-medium);outline:0;-webkit-tap-highlight-color:transparent}.glass-theme-toggle:hover{background:var(--gl-surface-5);transform:scale(1.05)}.glass-theme-toggle:active{transform:scale(.95)}.glass-theme-toggle svg{width:20px;height:20px;fill:none;stroke:var(--gl-color-text);stroke-width:2;stroke-linecap:round;stroke-linejoin:round}.glass-theme-toggle .icon-sun{display:none}.glass-theme-toggle .icon-moon,[data-theme=light] .glass-theme-toggle .icon-sun{display:block}[data-theme=light] .glass-theme-toggle .icon-moon{display:none}.glass-popover-anchor{position:relative;display:inline-block}.glass-popover{position:absolute;top:calc(100% + var(--gl-space-xs));left:50%;transform:translateX(-50%) translateY(-4px) scale(.96);transform-origin:top center;min-width:220px;padding:var(--gl-space-sm);background:var(--gl-surface-3);backdrop-filter:blur(var(--gl-blur));-webkit-backdrop-filter:blur(var(--gl-blur));border:1px solid var(--gl-border-medium);border-radius:var(--gl-radius-card);box-shadow:var(--gl-shadow-card),var(--gl-inset-strong);opacity:0;visibility:hidden;pointer-events:none;transition:opacity .18s,transform .18s cubic-bezier(.2,.8,.2,1),visibility 0s linear .18s;z-index:50}.glass-popover.is-open{opacity:1;visibility:visible;pointer-events:auto;transform:translateX(-50%) translateY(0) scale(1);transition:opacity .18s,transform .22s cubic-bezier(.2,.8,.2,1),visibility linear}.glass-popover--top{top:auto;bottom:calc(100% + var(--gl-space-xs));transform-origin:bottom center}.glass-popover--start{left:0;transform:translateY(-4px) scale(.96);transform-origin:top left}.glass-popover--start.is-open{transform:translateY(0) scale(1)}.glass-popover--end{left:auto;right:0;transform:translateY(-4px) scale(.96);transform-origin:top right}.glass-popover--end.is-open{transform:translateY(0) scale(1)}.glass-list{background:var(--gl-surface-1);backdrop-filter:blur(var(--gl-blur-light));-webkit-backdrop-filter:blur(var(--gl-blur-light));border:1px solid var(--gl-border-subtle);border-radius:var(--gl-radius-btn);box-shadow:0 4px 12px rgba(0,0,0,.08),var(--gl-inset-subtle);overflow:hidden;display:flex;flex-direction:column;width:100%;margin:0;padding:0;list-style:none}.glass-list--flush{border-radius:0;border-left:none;border-right:none;margin-left:calc(var(--gl-space-lg) * -1);margin-right:calc(var(--gl-space-lg) * -1)}.glass-list--bare{background:0 0;backdrop-filter:none;-webkit-backdrop-filter:none;border:none;border-radius:0;box-shadow:none}.glass-list__section-header{padding:var(--gl-space-xs) var(--gl-space-lg) var(--gl-space-2xs);font-size:var(--gl-font-size-xs);font-weight:var(--gl-font-weight-semibold);color:var(--gl-color-text-muted);text-transform:uppercase;letter-spacing:.3px}.glass-list__item{position:relative;display:flex;align-items:center;gap:var(--gl-space-sm);padding:var(--gl-space-md) var(--gl-space-lg);min-height:56px;color:var(--gl-color-text);font-size:var(--gl-font-size-base);text-decoration:none;background:0 0;border:none;width:100%;text-align:left;font-family:inherit;list-style:none}.glass-list__item:not(:last-child)::after{content:'';position:absolute;left:calc(var(--gl-space-lg) + 28px + var(--gl-space-sm));right:var(--gl-space-lg);bottom:0;height:1px;background:var(--gl-border-subtle);pointer-events:none}.glass-list__item:not(:has(.glass-list__leading)):not(:last-child)::after{left:var(--gl-space-lg)}.glass-list__item:has(.glass-list__leading--lg):not(:last-child)::after{left:calc(var(--gl-space-lg) + 40px + var(--gl-space-sm))}.glass-list__item--center{justify-content:center;text-align:center;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.glass-list__item--center>.glass-list__title{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.glass-list__item--interactive{cursor:pointer;transition:background .15s}.glass-list__item--interactive:focus-visible,.glass-list__item--interactive:hover{background:var(--gl-surface-2);outline:0}.glass-list__item--interactive:active{background:var(--gl-surface-3)}.glass-list__item--danger{color:var(--gl-color-error)}.glass-list__item--danger .glass-list__leading,.glass-list__item--danger .glass-list__title{color:inherit}.glass-list__item--accent{color:var(--gl-color-primary)}.glass-list__item--accent .glass-list__leading,.glass-list__item--accent .glass-list__title{color:inherit}.glass-list__leading{flex-shrink:0;width:28px;height:28px;display:flex;align-items:center;justify-content:center;color:var(--gl-icon-strong)}.glass-list__leading ::slotted(svg),.glass-list__leading svg{width:24px;height:24px;stroke:currentColor;stroke-width:2;fill:none;stroke-linecap:round;stroke-linejoin:round}.glass-list__leading--lg{width:40px;height:40px;border-radius:var(--gl-radius-xs);overflow:hidden}.glass-list__leading--lg ::slotted(svg),.glass-list__leading--lg svg{width:32px;height:32px}.glass-list__leading--lg ::slotted(img),.glass-list__leading--lg img{width:100%;height:100%;object-fit:cover;display:block}.glass-list__content{flex:1 1 0;min-width:0;display:flex;flex-direction:column;gap:2px;overflow:hidden}.glass-list__title{font-size:var(--gl-font-size-base);font-weight:var(--gl-font-weight-medium);color:var(--gl-color-text);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.glass-list__subtitle{font-size:var(--gl-font-size-sm);color:var(--gl-color-text-muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.glass-list__subtitle--wrap{white-space:normal;display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;overflow:hidden}.glass-list__trailing{flex-shrink:0;display:flex;align-items:center;gap:var(--gl-space-xs);color:var(--gl-color-text-muted);font-size:var(--gl-font-size-sm)}.glass-list__trailing ::slotted(svg),.glass-list__trailing svg{width:18px;height:18px;stroke:var(--gl-icon-muted);stroke-width:2;fill:none;stroke-linecap:round;stroke-linejoin:round}.glass-list__value{color:var(--gl-color-text-muted);font-size:var(--gl-font-size-sm);white-space:nowrap}.glass-skeleton{display:flex;flex-direction:column;gap:10px}.glass-skeleton__line{height:12px;border-radius:6px;background:linear-gradient(90deg,var(--gl-surface-1) 0,var(--gl-surface-4) 50%,var(--gl-surface-1) 100%);background-size:200% 100%;animation:1.4s ease-in-out infinite glass-skeleton}.glass-skeleton__line--title{height:18px}@keyframes glass-skeleton{from{background-position:200% 0}to{background-position:-200% 0}}.glass-table-wrap{overflow-x:auto;border-radius:var(--gl-radius-sm)}.glass-table{width:100%;border-collapse:collapse;font-size:var(--gl-font-size-sm);color:var(--gl-color-text)}.glass-table th{text-align:left;padding:8px 10px;white-space:nowrap;font-weight:var(--gl-font-weight-medium);color:var(--gl-color-text-muted);border-bottom:1px solid var(--gl-border-medium)}.glass-table td{padding:9px 10px;vertical-align:top;border-bottom:1px solid var(--gl-border-subtle)}.glass-table tbody tr:last-child td{border-bottom:0}.glass-table tbody tr:hover td{background:var(--gl-surface-1)}.glass-table__num{text-align:right;font-variant-numeric:tabular-nums}.glass-table__muted{color:var(--gl-color-text-muted)}.glass-prose{font-size:var(--gl-font-size-base);line-height:1.6;color:var(--gl-color-text)}.glass-prose>:first-child{margin-top:0}.glass-prose>:last-child{margin-bottom:0}.glass-prose h1,.glass-prose h2,.glass-prose h3{color:var(--gl-color-text-heading);line-height:1.25;margin:1.2em 0 .4em}.glass-prose h1{font-size:var(--gl-font-size-title)}.glass-prose h2{font-size:var(--gl-font-size-modal)}.glass-prose h3{font-size:var(--gl-font-size-lg)}.glass-prose blockquote,.glass-prose ol,.glass-prose p,.glass-prose pre,.glass-prose table,.glass-prose ul{margin:0 0 .9em}.glass-prose ol,.glass-prose ul{padding-left:1.3em}.glass-prose strong{color:var(--gl-color-text-heading)}.glass-prose a{color:var(--gl-color-primary);text-decoration:underline;text-underline-offset:2px}.glass-prose code{font-family:ui-monospace,'SF Mono',Menlo,monospace;font-size:.9em;background:var(--gl-surface-2);padding:1px 5px;border-radius:4px}.glass-prose pre{padding:12px 14px;overflow-x:auto;background:var(--gl-surface-1);border-radius:var(--gl-radius-sm)}.glass-prose pre code{background:0 0;padding:0}.glass-prose blockquote{padding:8px 14px;border-left:3px solid var(--gl-color-primary);background:var(--gl-surface-1);border-radius:0 var(--gl-radius-xs) var(--gl-radius-xs) 0}.glass-prose img{max-width:100%;height:auto;border-radius:var(--gl-radius-sm)}.glass-prose hr{height:1px;border:0;margin:1.2em 0;background:var(--gl-border-subtle)}.glass-prose table{width:100%;border-collapse:collapse}.glass-prose td,.glass-prose th{padding:6px 8px;text-align:left;border-bottom:1px solid var(--gl-border-subtle)}.glass-segmented{display:inline-flex;gap:4px;padding:4px;max-width:100%;background:var(--gl-surface-1);border:1px solid var(--gl-border-subtle);border-radius:var(--gl-radius-btn);box-shadow:var(--gl-inset-subtle)}.glass-segmented--full{display:flex}.glass-segmented--full .glass-segmented__item{flex:1 1 0}.glass-segmented--scroll{overflow-x:auto;overflow-y:hidden;scrollbar-width:none;overscroll-behavior-x:contain}.glass-segmented--scroll::-webkit-scrollbar{display:none}.glass-segmented--wrap{flex-wrap:wrap}.glass-segmented__item{-webkit-appearance:none;appearance:none;display:inline-flex;align-items:center;justify-content:center;gap:6px;padding:8px 14px;border:0;border-radius:var(--gl-radius-sm);background:0 0;color:var(--gl-color-text-muted);font-family:inherit;font-size:var(--gl-font-size-sm);font-weight:var(--gl-font-weight-medium);white-space:nowrap;cursor:pointer;transition:var(--gl-transition-fast);outline:0;-webkit-tap-highlight-color:transparent}.glass-segmented__item:hover{color:var(--gl-color-text)}.glass-segmented__item[aria-pressed=true]{background:var(--gl-surface-5);color:var(--gl-color-text-heading);box-shadow:var(--gl-shadow-btn)}.glass-segmented__item:focus-visible{box-shadow:var(--gl-shadow-focus)}.glass-segmented__item[aria-pressed=true]:focus-visible{box-shadow:var(--gl-shadow-focus),var(--gl-shadow-btn)}.glass-segmented__item:disabled{opacity:.45;cursor:not-allowed}.glass-segmented__dot{width:10px;height:10px;border-radius:50%;background:var(--gl-segmented-tone,currentColor)}.glass-segmented__item--success{--gl-segmented-tone:var(--gl-color-success)}.glass-segmented__item--warning{--gl-segmented-tone:var(--gl-color-warning)}.glass-segmented__item--error{--gl-segmented-tone:var(--gl-color-error)}.glass-steps{display:flex;align-items:center;gap:6px;margin:0;padding:0;list-style:none;min-width:0;container-type:inline-size}.glass-steps__item{display:flex;align-items:center;gap:6px;flex:0 1 auto;min-width:0;font-size:var(--gl-font-size-xs);color:var(--gl-color-text-muted);white-space:nowrap}.glass-steps__num{flex:none;width:22px;height:22px;border-radius:50%;display:inline-flex;align-items:center;justify-content:center;border:1px solid var(--gl-border-medium);font-size:11px;font-weight:var(--gl-font-weight-semibold)}.glass-steps__num svg{width:12px;height:12px;fill:none;stroke:currentColor;stroke-width:2.5;stroke-linecap:round;stroke-linejoin:round}.glass-steps__label{min-width:0;overflow:hidden;text-overflow:ellipsis}.glass-steps__item--done .glass-steps__num{background:var(--gl-color-success-surface);border-color:var(--gl-color-success-border);color:var(--gl-color-success-on-surface)}.glass-steps__item--current{color:var(--gl-color-text-heading)}.glass-steps__item--current .glass-steps__num{background:var(--gl-color-primary);border-color:transparent;color:var(--gl-color-on-primary)}.glass-steps__line{flex:1 1 8px;min-width:8px;height:1px;background:var(--gl-border-subtle)}@container (max-width:360px){.glass-steps__label{display:none}.glass-steps__item--current .glass-steps__label{display:inline}}.glass-sheet-overlay{position:fixed;inset:0;z-index:1000;display:flex;align-items:flex-end;justify-content:center;background:var(--gl-surface-overlay);backdrop-filter:blur(var(--gl-blur-soft));-webkit-backdrop-filter:blur(var(--gl-blur-soft));font-family:var(--gl-font-family);-webkit-font-smoothing:antialiased;opacity:0;transition:var(--gl-transition-modal);transition-property:opacity}.glass-sheet-overlay[hidden]{display:none}.glass-sheet-overlay.is-active{opacity:1}.glass-sheet{width:min(100%,560px);max-height:88dvh;overflow:auto;padding:8px var(--gl-space-lg) calc(var(--gl-space-lg) + env(safe-area-inset-bottom,0px));background:linear-gradient(to bottom,var(--gl-card-glow-top) 0,var(--gl-card-glow-bottom) 100%);backdrop-filter:blur(var(--gl-blur-heavy));-webkit-backdrop-filter:blur(var(--gl-blur-heavy));color:var(--gl-color-text);border:1.5px solid var(--gl-border-medium);border-radius:var(--gl-radius-card) var(--gl-radius-card) 0 0;box-shadow:var(--gl-shadow-modal)}.glass-sheet-overlay .glass-sheet{transform:translateY(100%);transition:var(--gl-transition-modal);transition-property:transform}.glass-sheet-overlay.is-active .glass-sheet{transform:translateY(0)}.glass-sheet--inline{border-radius:var(--gl-radius-card);box-shadow:var(--gl-shadow-card)}.glass-sheet__grip{width:40px;height:4px;margin:4px auto 12px;border-radius:2px;background:var(--gl-border-strong)}.glass-sheet__title{margin:0 0 8px;font-size:var(--gl-font-size-modal);font-weight:var(--gl-font-weight-semibold);color:var(--gl-color-text-heading)}.glass-sheet__body{font-size:var(--gl-font-size-base);line-height:1.55}.glass-sheet__actions{display:flex;flex-direction:column;gap:8px;margin-top:16px}@media (prefers-reduced-motion:reduce){.glass-skeleton__line{animation:none}.glass-sheet-overlay,.glass-sheet-overlay .glass-sheet{transition:none}}.glass-empty{display:flex;flex-direction:column;align-items:center;gap:8px;padding:28px 16px;text-align:center}.glass-empty__icon{display:inline-flex;align-items:center;justify-content:center;width:48px;height:48px;border-radius:50%;background:var(--gl-surface-2);color:var(--gl-icon-default)}.glass-empty__icon ::slotted(svg),.glass-empty__icon svg{width:24px;height:24px;fill:none;stroke:currentColor;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}.glass-empty__title{margin:4px 0 0;font-weight:var(--gl-font-weight-semibold);color:var(--gl-color-text-heading)}.glass-empty__text{margin:0;max-width:38ch;font-size:var(--gl-font-size-sm);line-height:1.55;color:var(--gl-color-text-muted)}.glass-empty__action{display:flex;flex-wrap:wrap;justify-content:center;gap:8px;margin-top:8px}.glass-date-strip{display:flex;gap:6px;padding:4px;overflow-x:auto;overflow-y:hidden;scrollbar-width:none;overscroll-behavior-x:contain}.glass-date-strip::-webkit-scrollbar{display:none}.glass-date-strip__day{-webkit-appearance:none;appearance:none;flex:1 0 44px;min-width:44px;display:flex;flex-direction:column;align-items:center;gap:2px;padding:8px 4px 6px;border:1px solid var(--gl-border-subtle);border-radius:var(--gl-radius-input);background:var(--gl-surface-1);color:var(--gl-color-text);font-family:inherit;cursor:pointer;transition:var(--gl-transition-fast);outline:0;-webkit-tap-highlight-color:transparent}.glass-date-strip__day:hover{background:var(--gl-surface-3)}.glass-date-strip__day[aria-pressed=true]{--gl-date-strip-ink:var(--gl-color-on-primary);background:var(--gl-color-primary);color:var(--gl-color-on-primary);border-color:transparent;box-shadow:var(--gl-shadow-btn-primary)}.glass-date-strip__day:focus-visible{box-shadow:var(--gl-shadow-focus)}.glass-date-strip__day[aria-pressed=true]:focus-visible{box-shadow:var(--gl-shadow-focus),var(--gl-shadow-btn-primary)}.glass-date-strip__day:disabled,.glass-date-strip__day[aria-disabled=true]{opacity:.45;cursor:not-allowed}.glass-date-strip__day:disabled:hover,.glass-date-strip__day[aria-disabled=true]:hover{background:var(--gl-surface-1)}.glass-date-strip__day--today .glass-date-strip__num{text-decoration:underline;text-underline-offset:3px}.glass-date-strip__wd{font-size:var(--gl-font-size-xs);opacity:.75;text-transform:uppercase;letter-spacing:.04em}.glass-date-strip__num{font-size:var(--gl-font-size-lg);font-weight:var(--gl-font-weight-semibold);line-height:1.1}.glass-date-strip__mark{width:6px;height:6px;margin-top:2px;border-radius:50%;background:var(--gl-date-strip-tone,transparent)}.glass-date-strip__mark--primary{--gl-date-strip-tone:var(--gl-date-strip-ink, var(--gl-color-primary))}.glass-date-strip__mark--success{--gl-date-strip-tone:var(--gl-date-strip-ink, var(--gl-color-success))}.glass-date-strip__mark--warning{--gl-date-strip-tone:var(--gl-date-strip-ink, var(--gl-color-warning))}.glass-date-strip__mark--error{--gl-date-strip-tone:var(--gl-date-strip-ink, var(--gl-color-error))}.glass-calendar{display:block}.glass-calendar__head{display:flex;align-items:center;justify-content:space-between;gap:8px;margin-bottom:8px}.glass-calendar__title{flex:1 1 auto;min-width:0;text-align:center;font-weight:var(--gl-font-weight-semibold);color:var(--gl-color-text-heading);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.glass-calendar__nav{-webkit-appearance:none;appearance:none;flex:none;width:32px;height:32px;padding:0;display:inline-flex;align-items:center;justify-content:center;border:1px solid var(--gl-border-subtle);border-radius:var(--gl-radius-full);background:var(--gl-surface-1);color:var(--gl-color-text);font-family:inherit;cursor:pointer;transition:var(--gl-transition-fast);outline:0;-webkit-tap-highlight-color:transparent}.glass-calendar__nav:hover{background:var(--gl-surface-3)}.glass-calendar__nav:focus-visible{box-shadow:var(--gl-shadow-focus)}.glass-calendar__nav svg{width:16px;height:16px;fill:none;stroke:currentColor;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}.glass-calendar__grid{display:grid;grid-template-columns:repeat(7,minmax(0,1fr));gap:4px}.glass-calendar__wd{padding:4px 0;text-align:center;font-size:var(--gl-font-size-xs);color:var(--gl-color-text-muted);text-transform:uppercase;letter-spacing:.04em;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.glass-calendar__day{-webkit-appearance:none;appearance:none;aspect-ratio:1;min-width:0;padding:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:2px;border:1px solid transparent;border-radius:var(--gl-radius-sm);background:0 0;color:var(--gl-color-text);font-family:inherit;font-size:var(--gl-font-size-sm);cursor:pointer;transition:var(--gl-transition-fast);outline:0;-webkit-tap-highlight-color:transparent}.glass-calendar__day:hover{background:var(--gl-surface-2)}.glass-calendar__day--other{opacity:.35}.glass-calendar__day--today{border-color:var(--gl-border-warm)}.glass-calendar__day[aria-pressed=true]{--gl-calendar-ink:var(--gl-color-on-primary);background:var(--gl-color-primary);color:var(--gl-color-on-primary)}.glass-calendar__day:focus-visible{box-shadow:var(--gl-shadow-focus)}.glass-calendar__day:disabled,.glass-calendar__day[aria-disabled=true]{opacity:.45;cursor:not-allowed}.glass-calendar__day:disabled:hover,.glass-calendar__day[aria-disabled=true]:hover{background:0 0}.glass-calendar__marks{display:flex;gap:2px;height:5px}.glass-calendar__mark{width:5px;height:5px;border-radius:50%;background:var(--gl-calendar-tone,transparent)}.glass-calendar__mark--primary{--gl-calendar-tone:var(--gl-calendar-ink, var(--gl-color-primary))}.glass-calendar__mark--success{--gl-calendar-tone:var(--gl-calendar-ink, var(--gl-color-success))}.glass-calendar__mark--warning{--gl-calendar-tone:var(--gl-calendar-ink, var(--gl-color-warning))}.glass-calendar__mark--error{--gl-calendar-tone:var(--gl-calendar-ink, var(--gl-color-error))}.glass-image-picker{display:flex;align-items:center;gap:14px}.glass-image-picker__preview{flex:none;width:72px;height:72px;display:flex;align-items:center;justify-content:center;border:1px solid var(--gl-border-subtle);border-radius:var(--gl-radius-input);background:var(--gl-surface-2);color:var(--gl-icon-muted);overflow:hidden}.glass-image-picker__preview--round{border-radius:50%}.glass-image-picker__preview img{display:block;width:100%;height:100%;object-fit:cover}.glass-image-picker__preview svg{width:28px;height:28px;fill:none;stroke:currentColor;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}.glass-image-picker__meta{flex:1 1 auto;min-width:0;display:flex;flex-direction:column;align-items:flex-start;gap:6px}.glass-image-picker__label{font-size:var(--gl-font-size-sm);font-weight:var(--gl-font-weight-medium);color:var(--gl-icon-strong);overflow-wrap:anywhere}.glass-image-picker__hint{font-size:var(--gl-font-size-xs);color:var(--gl-color-text-muted)}.glass-image-picker__actions{display:flex;flex-wrap:wrap;gap:8px}.gl-stack{display:flex;flex-direction:column}.gl-row{display:flex;flex-direction:row;align-items:center}.gl-stack--2xs{gap:var(--gl-space-2xs)}.gl-stack--xs{gap:var(--gl-space-xs)}.gl-stack--sm{gap:var(--gl-space-sm)}.gl-stack--md{gap:var(--gl-space-md)}.gl-stack--lg{gap:var(--gl-space-lg)}.gl-stack--xl{gap:var(--gl-space-xl)}.gl-row--xs{gap:var(--gl-space-xs)}.gl-row--sm{gap:var(--gl-space-sm)}.gl-row--md{gap:var(--gl-space-md)}.gl-text-center{text-align:center}.gl-text-muted{color:var(--gl-color-text-muted)}.gl-text-sm{font-size:var(--gl-font-size-sm)}.gl-mt-sm{margin-top:var(--gl-space-sm)}.gl-mt-md{margin-top:var(--gl-space-md)}.gl-mt-lg{margin-top:var(--gl-space-lg)}.gl-mt-xl{margin-top:var(--gl-space-xl)}.gl-mb-sm{margin-bottom:var(--gl-space-sm)}.gl-mb-md{margin-bottom:var(--gl-space-md)}.gl-mb-lg{margin-bottom:var(--gl-space-lg)}.gl-mb-xl{margin-bottom:var(--gl-space-xl)}.gl-px{padding-left:var(--gl-space-lg);padding-right:var(--gl-space-lg)}.gl-w-full{width:100%}.gl-flex-1{flex:1}svg.glass-icon--fill{fill:currentColor;stroke:none}\n";
|
|
9
|
+
const componentsTail = ".glass-bg{background:radial-gradient(ellipse at 20% 40%,var(--gl-bg-aurora-1) 0,transparent 55%),radial-gradient(ellipse at 80% 65%,var(--gl-bg-aurora-2) 0,transparent 50%),radial-gradient(ellipse at 50% 20%,var(--gl-bg-aurora-3) 0,transparent 50%),linear-gradient(170deg,var(--gl-color-bg-light) 0,var(--gl-color-bg-mid) 50%,var(--gl-color-bg-dark) 100%);position:relative;min-height:100vh;overflow-x:hidden;font-family:var(--gl-font-family);color:var(--gl-color-text);-webkit-font-smoothing:antialiased;transition:background .4s,color .3s;isolation:isolate}.glass-bg::before{content:'';position:absolute;top:20%;left:-30%;width:160%;height:55%;background:radial-gradient(ellipse at 35% 45%,var(--gl-bg-light-streak-1) 0,transparent 50%),radial-gradient(ellipse at 65% 55%,var(--gl-bg-light-streak-2) 0,transparent 45%);transform:rotate(-8deg);pointer-events:none;z-index:-1}.glass-bg::after{content:'';position:absolute;top:40%;right:-20%;width:70%;height:50%;background:radial-gradient(ellipse at center,var(--gl-bg-warm-glow) 0,transparent 65%);pointer-events:none;z-index:-1}.glass-bg>*{position:relative}.glass-bg--has-tab-bar{padding-bottom:var(--gl-tab-bar-height)}.glass-bg--has-tab-bar-floating{padding-bottom:calc(var(--gl-tab-bar-accessory-size) + var(--gl-tab-bar-floating-bottom) + var(--gl-space-md))}.glass-nav{display:flex;justify-content:space-between;align-items:center;padding:0 var(--gl-space-xs)}.glass-pill{width:46px;height:46px;border-radius:var(--gl-radius-pill);background:var(--gl-surface-3);backdrop-filter:blur(var(--gl-blur));-webkit-backdrop-filter:blur(var(--gl-blur));border:1.5px solid var(--gl-border-strong);display:flex;align-items:center;justify-content:center;cursor:pointer;transition:var(--gl-transition);color:var(--gl-color-text);box-shadow:var(--gl-shadow-glow),var(--gl-inset-medium);outline:0;-webkit-tap-highlight-color:transparent}.glass-pill:hover{background:var(--gl-surface-5);transform:scale(1.05)}.glass-pill:active{transform:scale(.95)}.glass-pill ::slotted(svg),.glass-pill svg{width:20px;height:20px;fill:none;stroke:var(--gl-color-text);stroke-width:2.2;stroke-linecap:round;stroke-linejoin:round}.glass-title{text-align:center;color:var(--gl-color-text-heading);font-size:var(--gl-font-size-title);font-weight:var(--gl-font-weight-semibold);line-height:1.3;text-shadow:0 2px 12px rgba(0,0,0,.15);letter-spacing:-.3px}.glass-card{background:var(--gl-surface-2);backdrop-filter:blur(var(--gl-blur));-webkit-backdrop-filter:blur(var(--gl-blur));border:1.5px solid var(--gl-border-medium);border-radius:var(--gl-radius-card);padding:var(--gl-space-3xl) var(--gl-space-xl) var(--gl-space-2xl);box-shadow:var(--gl-shadow-card),var(--gl-inset-strong)}.glass-card--glow{position:relative;overflow:hidden;background:linear-gradient(to bottom,var(--gl-card-glow-top) 0,var(--gl-card-glow-mid) 25%,var(--gl-card-glow-low) 55%,var(--gl-card-glow-bottom) 100%)}.glass-card--glow::before{content:'';position:absolute;top:0;left:10%;right:10%;height:1px;background:linear-gradient(90deg,transparent 0,rgba(255,255,255,.5) 30%,rgba(255,255,255,.6) 50%,rgba(255,255,255,.5) 70%,transparent 100%);z-index:1}.glass-card__icon{display:flex;align-items:center;justify-content:center;margin:0 auto var(--gl-space-lg)}.glass-card__icon svg{width:64px;height:64px;stroke:var(--gl-card-icon-color);stroke-width:1.2;fill:none}.glass-card__text{color:var(--gl-card-text-color);font-size:var(--gl-font-size-base);font-weight:var(--gl-font-weight-normal);line-height:1.55;text-align:center}.glass-btn{display:flex;align-items:center;justify-content:center;gap:10px;width:100%;height:var(--gl-btn-height,56px);border:none;border-radius:var(--gl-radius-btn);font-family:var(--gl-font-family);font-size:var(--gl-font-size-btn);font-weight:var(--gl-font-weight-semibold);cursor:pointer;transition:var(--gl-transition);outline:0;-webkit-tap-highlight-color:transparent}a.glass-btn{display:inline-flex;text-decoration:none}.glass-btn[hidden]{display:none}.glass-btn ::slotted(svg),.glass-btn svg{width:20px;height:20px;flex-shrink:0;fill:none;stroke:currentColor;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}.glass-btn--primary{background:linear-gradient(135deg,var(--gl-color-primary) 0,var(--gl-color-primary-mid) 50%,var(--gl-color-primary-dark) 100%);color:var(--gl-color-on-primary,#fff);border:1px solid var(--gl-border-warm);box-shadow:var(--gl-shadow-btn-primary),var(--gl-inset-strong)}.glass-btn--primary ::slotted(svg),.glass-btn--primary svg{fill:var(--gl-icon-on-primary);stroke:var(--gl-icon-on-primary);stroke-width:0}.glass-btn--primary:hover{transform:translateY(-1px)}.glass-btn--primary:active{transform:translateY(1px)}.glass-btn--secondary{background:linear-gradient(to bottom,var(--gl-surface-milk-strong) 0,var(--gl-surface-milk) 100%);backdrop-filter:blur(var(--gl-blur));-webkit-backdrop-filter:blur(var(--gl-blur));border:1.5px solid var(--gl-border-milk);color:var(--gl-color-text-on-light);box-shadow:var(--gl-shadow-btn),var(--gl-inset-milk)}.glass-btn--secondary ::slotted(svg),.glass-btn--secondary svg{fill:none;stroke:var(--gl-icon-on-secondary);stroke-width:2;stroke-linecap:round;stroke-linejoin:round}.glass-btn--secondary:hover{transform:translateY(-1px)}.glass-btn--secondary:active{transform:translateY(1px)}.glass-btn--tertiary{background:var(--gl-surface-2);backdrop-filter:blur(var(--gl-blur-light));-webkit-backdrop-filter:blur(var(--gl-blur-light));border:1px solid var(--gl-border-subtle);color:var(--gl-color-text-muted);box-shadow:0 4px 12px rgba(0,0,0,.1),var(--gl-inset-subtle)}.glass-btn--tertiary ::slotted(svg),.glass-btn--tertiary svg{fill:none;stroke:var(--gl-icon-on-tertiary);stroke-width:2;stroke-linecap:round;stroke-linejoin:round}.glass-btn--tertiary:hover{background:var(--gl-surface-4);color:var(--gl-color-text);transform:translateY(-1px)}.glass-btn--tertiary:active{transform:translateY(1px)}.glass-btn--sm{height:var(--gl-btn-height-sm,44px);font-size:var(--gl-font-size-sm);border-radius:var(--gl-radius-sm)}.glass-btn--lg{height:var(--gl-btn-height-lg,64px);font-size:var(--gl-font-size-lg)}.glass-btn--auto{width:auto;padding:0 var(--gl-space-xl)}.glass-status{background:var(--gl-surface-1);backdrop-filter:blur(var(--gl-blur-light));-webkit-backdrop-filter:blur(var(--gl-blur-light));border:1px solid var(--gl-border-subtle);border-radius:var(--gl-radius-btn);padding:var(--gl-space-md) var(--gl-space-lg);display:flex;align-items:center;gap:var(--gl-space-sm);box-shadow:0 4px 12px rgba(0,0,0,.08),var(--gl-inset-subtle)}.glass-status ::slotted(svg),.glass-status svg{width:20px;height:20px;flex-shrink:0;stroke:var(--gl-icon-muted);stroke-width:2;fill:none;stroke-linecap:round;stroke-linejoin:round}.glass-status p{color:var(--gl-color-text-muted);font-size:var(--gl-font-size-sm);font-weight:var(--gl-font-weight-normal);line-height:1.45}.glass-input-group{display:flex;flex-direction:column;gap:var(--gl-space-xs)}.glass-label{font-size:var(--gl-font-size-sm);font-weight:var(--gl-font-weight-medium);color:var(--gl-icon-strong);padding-inline-start:var(--gl-space-2xs)}.glass-input{width:100%;height:var(--gl-control-height,52px);padding:0 var(--gl-control-padding-x,var(--gl-space-md));background:var(--gl-surface-2);backdrop-filter:blur(var(--gl-blur-light));-webkit-backdrop-filter:blur(var(--gl-blur-light));border:1.5px solid var(--gl-border-medium);border-radius:var(--gl-radius-input);color:var(--gl-color-text);font-family:var(--gl-font-family);font-size:var(--gl-font-size-base);transition:var(--gl-transition);outline:0;box-shadow:var(--gl-inset-subtle);-webkit-tap-highlight-color:transparent}.glass-input::placeholder{color:var(--gl-placeholder)}.glass-input[type=date],.glass-input[type=datetime-local],.glass-input[type=month],.glass-input[type=time]{-webkit-appearance:none;appearance:none}.glass-input::-webkit-date-and-time-value{text-align:start}.glass-input:focus{border-color:var(--gl-border-focus);background:var(--gl-surface-3);box-shadow:var(--gl-shadow-focus),var(--gl-inset-medium)}.glass-input:disabled{opacity:.4;cursor:not-allowed}.glass-input--error{border-color:var(--gl-color-error)}.glass-input--error:focus{box-shadow:0 0 0 3px color-mix(in srgb,var(--gl-color-error) 25%,transparent),var(--gl-inset-medium)}.glass-hint{font-size:var(--gl-font-size-xs);color:var(--gl-color-text-muted);padding-inline-start:var(--gl-space-2xs)}.glass-hint--error{color:var(--gl-color-error)}.glass-textarea{width:100%;min-height:var(--gl-textarea-min-height,120px);padding:var(--gl-space-md) var(--gl-control-padding-x,var(--gl-space-md));background:var(--gl-surface-2);backdrop-filter:blur(var(--gl-blur-light));-webkit-backdrop-filter:blur(var(--gl-blur-light));border:1.5px solid var(--gl-border-medium);border-radius:var(--gl-radius-input);color:var(--gl-color-text);font-family:var(--gl-font-family);font-size:var(--gl-font-size-base);line-height:1.5;resize:vertical;transition:var(--gl-transition);outline:0;box-shadow:var(--gl-inset-subtle)}.glass-textarea::placeholder{color:var(--gl-placeholder)}.glass-textarea:focus{border-color:var(--gl-border-focus);background:var(--gl-surface-3);box-shadow:var(--gl-shadow-focus),var(--gl-inset-medium)}.glass-select{width:100%;height:var(--gl-control-height,52px);padding:0 var(--gl-space-3xl) 0 var(--gl-control-padding-x,var(--gl-space-md));background:var(--gl-surface-2);backdrop-filter:blur(var(--gl-blur-light));-webkit-backdrop-filter:blur(var(--gl-blur-light));border:1.5px solid var(--gl-border-medium);border-radius:var(--gl-radius-input);color:var(--gl-color-text);font-family:var(--gl-font-family);font-size:var(--gl-font-size-base);transition:var(--gl-transition);outline:0;box-shadow:var(--gl-inset-subtle);cursor:pointer;appearance:none;-webkit-appearance:none;background-image:var(--gl-select-chevron, url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='rgba(255,255,255,0.6)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E\"));background-repeat:no-repeat;background-position:right 16px center}.glass-select:dir(rtl){padding:0 var(--gl-control-padding-x,var(--gl-space-md)) 0 var(--gl-space-3xl);background-position:left 16px center}.glass-select:focus{border-color:var(--gl-border-focus);box-shadow:var(--gl-shadow-focus),var(--gl-inset-medium)}.glass-select option{background:var(--gl-color-bg-mid);color:var(--gl-color-text)}.glass-search{position:relative;display:flex;align-items:center}.glass-search__icon{position:absolute;inset-inline-start:var(--gl-space-md);width:18px;height:18px;stroke:var(--gl-icon-muted)!important;stroke-width:2!important;stroke-linecap:round!important;stroke-linejoin:round!important;fill:none!important;pointer-events:none;z-index:2}.glass-search .glass-input{padding-inline-start:44px;border-radius:var(--gl-radius-full)}.glass-toggle{display:inline-flex;align-items:flex-start;gap:var(--gl-space-sm);cursor:pointer;-webkit-tap-highlight-color:transparent}.glass-toggle__input{position:absolute;z-index:1;opacity:0;cursor:inherit;width:var(--gl-toggle-width,52px);height:var(--gl-toggle-height,30px);margin:0;font:inherit;margin-top:max(0px,calc((1lh - var(--gl-toggle-height,30px))/ 2))}.glass-toggle__track{position:relative;width:var(--gl-toggle-width,52px);height:var(--gl-toggle-height,30px);background:var(--gl-surface-2);backdrop-filter:blur(var(--gl-blur-soft));-webkit-backdrop-filter:blur(var(--gl-blur-soft));border:1.5px solid var(--gl-border-medium);border-radius:var(--gl-radius-full);transition:var(--gl-transition);box-shadow:var(--gl-inset-subtle);flex-shrink:0;margin-top:max(0px,calc((1lh - var(--gl-toggle-height,30px))/ 2))}.glass-toggle__thumb{position:absolute;top:calc((var(--gl-toggle-height,30px) - var(--gl-toggle-thumb-size,22px))/ 2 - 1px);left:calc((var(--gl-toggle-height,30px) - var(--gl-toggle-thumb-size,22px))/ 2 - 1px);width:var(--gl-toggle-thumb-size,22px);height:var(--gl-toggle-thumb-size,22px);border-radius:var(--gl-radius-pill);background:var(--gl-toggle-thumb-bg);box-shadow:0 2px 6px rgba(0,0,0,.2),var(--gl-inset-milk);transition:var(--gl-transition)}.glass-toggle__input:checked+.glass-toggle__track{background:linear-gradient(135deg,var(--gl-color-primary) 0,var(--gl-color-primary-dark) 100%);border-color:var(--gl-border-warm)}.glass-toggle__input:checked+.glass-toggle__track .glass-toggle__thumb{transform:translateX(calc(var(--gl-toggle-width,52px) - var(--gl-toggle-height,30px)))}.glass-toggle__thumb:dir(rtl){left:auto;right:calc((var(--gl-toggle-height,30px) - var(--gl-toggle-thumb-size,22px))/ 2 - 1px)}.glass-toggle__input:checked+.glass-toggle__track .glass-toggle__thumb:dir(rtl){transform:translateX(calc(var(--gl-toggle-height,30px) - var(--gl-toggle-width,52px)))}.glass-toggle__input:focus-visible+.glass-toggle__track{box-shadow:var(--gl-shadow-focus)}.glass-toggle__label{font-size:var(--gl-font-size-base);color:var(--gl-color-text);user-select:none;margin-top:max(0px,calc((var(--gl-toggle-height,30px) - 1lh)/ 2))}.glass-checkbox__label:empty,.glass-radio__label:empty,.glass-toggle__label:empty{display:none}.glass-checkbox{display:inline-flex;align-items:flex-start;gap:var(--gl-space-sm);cursor:pointer;-webkit-tap-highlight-color:transparent}.glass-checkbox__input{position:absolute;z-index:1;opacity:0;cursor:inherit;width:var(--gl-check-size,24px);height:var(--gl-check-size,24px);margin:0;font:inherit;margin-top:max(0px,calc((1lh - var(--gl-check-size,24px))/ 2))}.glass-checkbox__box{width:var(--gl-check-size,24px);height:var(--gl-check-size,24px);border-radius:var(--gl-radius-xs);background:var(--gl-surface-2);backdrop-filter:blur(var(--gl-blur-soft));-webkit-backdrop-filter:blur(var(--gl-blur-soft));border:1.5px solid var(--gl-border-medium);display:flex;align-items:center;justify-content:center;transition:var(--gl-transition);box-shadow:var(--gl-inset-subtle);flex-shrink:0;margin-top:max(0px,calc((1lh - var(--gl-check-size,24px))/ 2))}.glass-checkbox__box svg{width:14px;height:14px;stroke:var(--gl-color-on-primary,#ffffff);stroke-width:3;fill:none;stroke-linecap:round;stroke-linejoin:round;opacity:0;transform:scale(.5);transition:var(--gl-transition-fast)}.glass-checkbox__input:checked+.glass-checkbox__box{background:linear-gradient(135deg,var(--gl-color-primary) 0,var(--gl-color-primary-dark) 100%);border-color:var(--gl-border-warm)}.glass-checkbox__input:checked+.glass-checkbox__box svg{opacity:1;transform:scale(1)}.glass-checkbox__input:focus-visible+.glass-checkbox__box{box-shadow:var(--gl-shadow-focus)}.glass-checkbox__label{font-size:var(--gl-font-size-base);color:var(--gl-color-text);user-select:none;margin-top:max(0px,calc((var(--gl-check-size,24px) - 1lh)/ 2))}.glass-radio{display:inline-flex;align-items:flex-start;gap:var(--gl-space-sm);cursor:pointer;-webkit-tap-highlight-color:transparent}.glass-radio__input{position:absolute;z-index:1;opacity:0;cursor:inherit;width:var(--gl-check-size,24px);height:var(--gl-check-size,24px);margin:0;font:inherit;margin-top:max(0px,calc((1lh - var(--gl-check-size,24px))/ 2))}.glass-radio__circle{width:var(--gl-check-size,24px);height:var(--gl-check-size,24px);border-radius:var(--gl-radius-pill);background:var(--gl-surface-2);backdrop-filter:blur(var(--gl-blur-soft));border:1.5px solid var(--gl-border-medium);display:flex;align-items:center;justify-content:center;transition:var(--gl-transition);box-shadow:var(--gl-inset-subtle);flex-shrink:0;margin-top:max(0px,calc((1lh - var(--gl-check-size,24px))/ 2))}.glass-radio__dot{width:10px;height:10px;border-radius:var(--gl-radius-pill);background:#fff;opacity:0;transform:scale(0);transition:var(--gl-transition-fast)}.glass-radio__input:checked+.glass-radio__circle{background:linear-gradient(135deg,var(--gl-color-primary) 0,var(--gl-color-primary-dark) 100%);border-color:var(--gl-border-warm)}.glass-radio__input:checked+.glass-radio__circle .glass-radio__dot{opacity:1;transform:scale(1)}.glass-radio__input:focus-visible+.glass-radio__circle{box-shadow:var(--gl-shadow-focus)}.glass-radio__label{font-size:var(--gl-font-size-base);color:var(--gl-color-text);user-select:none;margin-top:max(0px,calc((var(--gl-check-size,24px) - 1lh)/ 2))}.glass-range-group{display:flex;flex-direction:column;gap:var(--gl-space-xs)}.glass-range-header{display:flex;justify-content:space-between;align-items:baseline}.glass-range-value{font-size:var(--gl-font-size-sm);font-weight:var(--gl-font-weight-semibold);color:var(--gl-color-primary);font-variant-numeric:tabular-nums}.glass-range{-webkit-appearance:none;appearance:none;width:100%;height:6px;border-radius:var(--gl-radius-full);background:var(--gl-range-track-bg);border:1px solid var(--gl-range-track-border);outline:0;cursor:pointer}.glass-range::-webkit-slider-thumb{-webkit-appearance:none;appearance:none;box-sizing:border-box;width:26px;height:26px;border-radius:var(--gl-radius-pill);background:linear-gradient(135deg,var(--gl-color-primary) 0,var(--gl-color-primary-dark) 100%);border:2px solid rgba(255,255,255,.5);box-shadow:0 2px 8px color-mix(in srgb,var(--gl-color-primary-mid) 35%,transparent),var(--gl-inset-strong);margin-top:-2px;cursor:pointer;transition:var(--gl-transition)}.glass-range::-webkit-slider-thumb:hover{transform:scale(1.1)}.glass-range::-moz-range-thumb{width:26px;height:26px;border-radius:var(--gl-radius-pill);background:linear-gradient(135deg,var(--gl-color-primary) 0,var(--gl-color-primary-dark) 100%);border:2px solid rgba(255,255,255,.5);box-shadow:0 2px 8px color-mix(in srgb,var(--gl-color-primary-mid) 35%,transparent);cursor:pointer}.glass-range::-moz-range-track{height:6px;border-radius:var(--gl-radius-full);background:var(--gl-range-track-bg);border:1px solid var(--gl-range-track-border)}.glass-range:focus-visible{box-shadow:var(--gl-shadow-focus)}.glass-progress{width:100%;display:flex;flex-direction:column;gap:var(--gl-space-xs)}.glass-progress__header{display:flex;justify-content:space-between;align-items:baseline}.glass-progress__label{font-size:var(--gl-font-size-sm);font-weight:var(--gl-font-weight-medium);color:var(--gl-icon-strong)}.glass-progress__value{font-size:var(--gl-font-size-xs);font-weight:var(--gl-font-weight-semibold);color:var(--gl-color-text-muted);font-variant-numeric:tabular-nums}.glass-progress__track{width:100%;height:8px;border-radius:var(--gl-radius-full);background:var(--gl-surface-2);border:1px solid var(--gl-border-subtle);overflow:hidden;box-shadow:var(--gl-inset-subtle)}.glass-progress__fill{height:100%;border-radius:var(--gl-radius-full);background:linear-gradient(90deg,var(--gl-color-primary) 0,var(--gl-color-primary-dark) 100%);box-shadow:0 0 8px color-mix(in srgb,var(--gl-color-primary) 30%,transparent),var(--gl-inset-strong);transition:width .5s cubic-bezier(.4, 0, .2, 1);position:relative}.glass-progress__fill::after{content:'';position:absolute;top:0;left:0;right:0;height:50%;border-radius:var(--gl-radius-full);background:linear-gradient(to bottom,rgba(255,255,255,.3) 0,transparent 100%)}.glass-progress--sm .glass-progress__track{height:4px}.glass-progress--lg .glass-progress__track{height:12px}.glass-progress--success .glass-progress__fill{background:linear-gradient(90deg,var(--gl-color-success) 0,var(--gl-color-success-dark,#2da44e) 100%);box-shadow:0 0 8px color-mix(in srgb,var(--gl-color-success) 30%,transparent),var(--gl-inset-strong)}.glass-progress--error .glass-progress__fill{background:linear-gradient(90deg,var(--gl-color-error) 0,var(--gl-color-error-dark,#d63027) 100%);box-shadow:0 0 8px color-mix(in srgb,var(--gl-color-error) 30%,transparent),var(--gl-inset-strong)}.glass-progress__fill:dir(rtl){scale:-1 1}.glass-modal-overlay{position:fixed;inset:0;background:var(--gl-surface-overlay);backdrop-filter:blur(var(--gl-blur-soft));-webkit-backdrop-filter:blur(var(--gl-blur-soft));display:flex;align-items:center;justify-content:center;padding:var(--gl-space-lg);z-index:1000;opacity:0;pointer-events:none;transition:var(--gl-transition-modal);font-family:var(--gl-font-family);-webkit-font-smoothing:antialiased}.glass-modal-overlay.is-active{opacity:1;pointer-events:auto}dialog.glass-modal-overlay{width:auto;height:auto;max-width:none;max-height:none;margin:0;border:0;color:inherit}dialog.glass-modal-overlay:not([open]){display:none}dialog.glass-modal-overlay::backdrop{background:0 0}.glass-modal{width:100%;max-width:var(--gl-modal-max-width,340px);background:linear-gradient(to bottom,var(--gl-card-glow-top) 0,var(--gl-card-glow-bottom) 100%);backdrop-filter:blur(var(--gl-blur-heavy));-webkit-backdrop-filter:blur(var(--gl-blur-heavy));border:1.5px solid var(--gl-border-medium);border-radius:var(--gl-radius-card);overflow:hidden;box-shadow:var(--gl-shadow-modal);transform:scale(.9) translateY(20px);transition:var(--gl-transition-modal);position:relative}.glass-modal-overlay.is-active .glass-modal{transform:scale(1) translateY(0)}.glass-modal::before{content:'';position:absolute;top:0;left:10%;right:10%;height:1px;background:linear-gradient(90deg,transparent 0,rgba(255,255,255,.4) 30%,rgba(255,255,255,.5) 50%,rgba(255,255,255,.4) 70%,transparent 100%)}.glass-modal__header{padding:var(--gl-space-xl) var(--gl-space-xl) var(--gl-space-sm);text-align:center}.glass-modal__title{font-size:var(--gl-font-size-modal);font-weight:var(--gl-font-weight-semibold);color:var(--gl-color-text)}.glass-modal__body{padding:var(--gl-space-sm) var(--gl-space-xl) var(--gl-space-xl);text-align:center}.glass-modal__body p{color:var(--gl-color-text-muted);font-size:var(--gl-font-size-base);line-height:1.55}.glass-modal__footer{display:flex;border-top:1px solid var(--gl-border-subtle)}.glass-modal__action{flex:1;height:var(--gl-modal-action-height,52px);background:0 0;border:none;font-family:var(--gl-font-family);font-size:var(--gl-font-size-btn);font-weight:var(--gl-font-weight-medium);color:var(--gl-color-text-muted);cursor:pointer;transition:var(--gl-transition-fast);outline:0}.glass-modal__action:hover{background:var(--gl-surface-1)}.glass-modal__action+.glass-modal__action{border-inline-start:1px solid var(--gl-border-subtle)}.glass-modal__action--primary{color:var(--gl-color-primary);font-weight:var(--gl-font-weight-semibold)}.glass-modal__action--danger{color:var(--gl-color-error);font-weight:var(--gl-font-weight-semibold)}.glass-toast{position:fixed;top:var(--gl-toast-top,var(--gl-space-4xl));left:50%;transform:translateX(-50%) translateY(-20px);min-width:280px;max-width:340px;padding:var(--gl-space-md) var(--gl-space-lg);background:linear-gradient(to bottom,var(--gl-surface-4) 0,var(--gl-surface-2) 100%);backdrop-filter:blur(var(--gl-blur));-webkit-backdrop-filter:blur(var(--gl-blur));border:1px solid var(--gl-border-medium);border-radius:var(--gl-radius-btn);display:flex;align-items:center;gap:var(--gl-space-sm);box-shadow:var(--gl-shadow-toast),var(--gl-inset-medium);z-index:1100;opacity:0;pointer-events:none;transition:var(--gl-transition-modal);font-family:var(--gl-font-family);-webkit-font-smoothing:antialiased}.glass-toast.is-visible{opacity:1;transform:translateX(-50%) translateY(0);pointer-events:auto}.glass-toast__icon{width:22px;height:22px;flex-shrink:0;stroke:currentColor;stroke-width:2;fill:none;stroke-linecap:round;stroke-linejoin:round}.glass-toast__icon ::slotted(svg){display:block;width:100%;height:100%}.glass-toast--success .glass-toast__icon{stroke:var(--gl-color-success)}.glass-toast--error .glass-toast__icon{stroke:var(--gl-color-error)}.glass-toast--warning .glass-toast__icon{stroke:var(--gl-color-warning)}.glass-toast__text{flex:1 1 auto;min-width:0;font-size:var(--gl-font-size-sm);font-weight:var(--gl-font-weight-medium);color:var(--gl-color-text);line-height:1.4}.glass-toast:has(.glass-toast__action){width:max-content;max-width:min(480px,calc(100% - 2 * var(--gl-space-md)))}.glass-toast--success{--gl-toast-action-surface:var(--gl-color-success-surface);--gl-toast-action-border:var(--gl-color-success-border);--gl-toast-action-ink:var(--gl-color-success-on-surface)}.glass-toast--error{--gl-toast-action-surface:var(--gl-color-error-surface);--gl-toast-action-border:var(--gl-color-error-border);--gl-toast-action-ink:var(--gl-color-error-on-surface)}.glass-toast--warning{--gl-toast-action-surface:var(--gl-color-warning-surface);--gl-toast-action-border:var(--gl-color-warning-border);--gl-toast-action-ink:var(--gl-color-warning-on-surface)}.glass-toast__action,.glass-toast__close{-webkit-appearance:none;appearance:none;flex:none;position:relative;font:inherit;cursor:pointer;transition:var(--gl-transition-fast);outline:0;-webkit-tap-highlight-color:transparent}.glass-toast__action{height:32px;padding:0 14px;border:1px solid var(--gl-toast-action-border,var(--gl-color-primary-border));border-radius:var(--gl-radius-full);background:linear-gradient(var(--gl-toast-action-surface,var(--gl-color-primary-surface)),var(--gl-toast-action-surface,var(--gl-color-primary-surface))),linear-gradient(var(--gl-state-scrim),var(--gl-state-scrim)),var(--gl-state-scrim);color:var(--gl-toast-action-ink,var(--gl-color-primary-on-surface));font-size:var(--gl-font-size-sm);font-weight:var(--gl-font-weight-semibold);white-space:nowrap}.glass-toast__action::after{content:\"\";position:absolute;inset:-6px 0}.glass-toast__action:hover{box-shadow:inset 0 0 0 100px color-mix(in srgb,var(--gl-toast-action-ink,var(--gl-color-primary-on-surface)) 10%,transparent)}.glass-toast__action:active{transform:scale(.96)}.glass-toast__close{width:28px;height:28px;margin-block:0;margin-inline:-4px -8px;padding:0;display:inline-flex;align-items:center;justify-content:center;border:0;border-radius:50%;background:0 0;color:var(--gl-color-text-muted)}.glass-toast__close::after{content:\"\";position:absolute;inset:-8px}.glass-toast__close:hover{background:var(--gl-surface-3);color:var(--gl-color-text)}.glass-toast__close svg{width:16px;height:16px;fill:none;stroke:currentColor;stroke-width:2;stroke-linecap:round}.glass-toast__action:focus-visible,.glass-toast__close:focus-visible{box-shadow:var(--gl-shadow-focus)}.glass-tab-bar{position:fixed;bottom:0;left:0;right:0;height:var(--gl-tab-bar-height);background:linear-gradient(to bottom,var(--gl-surface-3) 0,var(--gl-surface-1) 100%);backdrop-filter:blur(var(--gl-blur));-webkit-backdrop-filter:blur(var(--gl-blur));border-top:1px solid var(--gl-border-subtle);display:flex;justify-content:space-around;align-items:flex-start;padding-top:var(--gl-space-xs);padding-bottom:env(safe-area-inset-bottom,8px);z-index:900;box-shadow:0 -4px 20px rgba(0,0,0,.08),var(--gl-inset-subtle)}.glass-tab-bar__item{display:flex;flex-direction:column;align-items:center;gap:var(--gl-space-2xs);padding:var(--gl-space-2xs) var(--gl-space-sm);background:0 0;border:none;cursor:pointer;transition:var(--gl-transition);outline:0;-webkit-tap-highlight-color:transparent;min-width:60px}.glass-tab-bar__icon{width:24px;height:24px;display:flex;align-items:center;justify-content:center;position:relative}.glass-tab-bar__icon svg{width:24px;height:24px;fill:none;stroke:var(--gl-icon-muted);stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round;transition:var(--gl-transition)}.glass-tab-bar__label{font-size:10px;font-weight:var(--gl-font-weight-medium);color:var(--gl-icon-muted);transition:var(--gl-transition);letter-spacing:.2px}.glass-tab-bar__item.is-active .glass-tab-bar__icon svg{stroke:var(--gl-color-primary);filter:drop-shadow(0 0 6px color-mix(in srgb, var(--gl-color-primary) 35%, transparent))}.glass-tab-bar__item.is-active .glass-tab-bar__label{color:var(--gl-color-primary)}.glass-tab-bar__item.is-active .glass-tab-bar__icon::after{content:'';position:absolute;bottom:-6px;left:50%;transform:translateX(-50%);width:4px;height:4px;border-radius:var(--gl-radius-pill);background:var(--gl-color-primary);box-shadow:0 0 6px color-mix(in srgb,var(--gl-color-primary) 50%,transparent)}.glass-tab-bar__item:not(.is-active):hover .glass-tab-bar__icon svg{stroke:var(--gl-icon-default)}.glass-tab-bar__item:not(.is-active):hover .glass-tab-bar__label{color:var(--gl-icon-default)}.glass-tab-bar__badge{position:absolute;top:-4px;inset-inline-end:-8px;min-width:16px;height:16px;padding:0 4px;border-radius:var(--gl-radius-full);background:var(--gl-color-error-dark,#d63027);color:#fff;font-size:10px;font-weight:var(--gl-font-weight-semibold);display:flex;align-items:center;justify-content:center;box-shadow:0 2px 6px color-mix(in srgb,var(--gl-color-error) 40%,transparent)}.glass-tab-bar-dock{position:fixed;left:50%;bottom:calc(var(--gl-tab-bar-floating-bottom) + env(safe-area-inset-bottom,0px));transform:translateX(-50%);display:flex;align-items:center;gap:var(--gl-tab-bar-floating-gap);z-index:900;max-width:calc(100vw - 2 * var(--gl-space-md))}.glass-tab-bar-dock--accessory-left{flex-direction:row-reverse}.glass-tab-bar.glass-tab-bar--floating{position:static;left:auto;right:auto;bottom:auto;height:auto;width:max-content;padding:var(--gl-tab-bar-floating-padding);border-radius:var(--gl-tab-bar-floating-radius);border:1px solid var(--gl-border-subtle);background:linear-gradient(to bottom,var(--gl-surface-3) 0,var(--gl-surface-1) 100%);box-shadow:0 8px 32px rgba(0,0,0,.18),0 2px 8px rgba(0,0,0,.08),var(--gl-inset-subtle);display:flex;justify-content:flex-start;align-items:center;gap:var(--gl-space-2xs)}.glass-tab-bar--floating .glass-tab-bar__item{position:relative;border-radius:var(--gl-radius-full);padding:var(--gl-space-2xs) var(--gl-space-sm);min-width:auto;align-items:center}.glass-tab-bar--floating .glass-tab-bar__item>*{position:relative;z-index:1}.glass-tab-bar--floating .glass-tab-bar__item.is-active::before{content:'';position:absolute;inset:0;border-radius:inherit;background:radial-gradient(circle at center,color-mix(in srgb,var(--gl-tab-bar-spotlight-color) 28%,transparent) 0,color-mix(in srgb,var(--gl-tab-bar-spotlight-color) 10%,transparent) 55%,transparent 100%);pointer-events:none;z-index:0}.glass-tab-bar--floating .glass-tab-bar__item.is-active .glass-tab-bar__icon::after{display:none}.glass-tab-bar__accessory{width:var(--gl-tab-bar-accessory-size);height:var(--gl-tab-bar-accessory-size);border-radius:var(--gl-radius-pill);background:linear-gradient(to bottom,var(--gl-surface-3) 0,var(--gl-surface-1) 100%);backdrop-filter:blur(var(--gl-blur));-webkit-backdrop-filter:blur(var(--gl-blur));border:1px solid var(--gl-border-subtle);box-shadow:0 8px 32px rgba(0,0,0,.18),0 2px 8px rgba(0,0,0,.08),var(--gl-inset-subtle);display:flex;align-items:center;justify-content:center;cursor:pointer;transition:var(--gl-transition);outline:0;padding:0;-webkit-tap-highlight-color:transparent;flex-shrink:0}.glass-tab-bar__accessory ::slotted(svg),.glass-tab-bar__accessory svg{width:22px;height:22px;fill:none;stroke:var(--gl-icon-default);stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round;transition:var(--gl-transition)}.glass-tab-bar__accessory:hover{transform:translateY(-1px)}.glass-tab-bar__accessory:hover ::slotted(svg),.glass-tab-bar__accessory:hover svg{stroke:var(--gl-icon-strong)}.glass-tab-bar__accessory:focus-visible{box-shadow:0 8px 32px rgba(0,0,0,.18),var(--gl-shadow-focus),var(--gl-inset-subtle)}.glass-tab-bar__accessory--accent{background:linear-gradient(135deg,var(--gl-color-primary) 0,color-mix(in srgb,var(--gl-color-primary) 70%,transparent) 100%);border-color:color-mix(in srgb,var(--gl-color-primary) 50%,transparent);box-shadow:0 8px 32px color-mix(in srgb,var(--gl-color-primary) 35%,transparent),var(--gl-inset-medium)}.glass-tab-bar__accessory--accent ::slotted(svg),.glass-tab-bar__accessory--accent svg{stroke:var(--gl-color-on-primary,#ffffff)}.glass-tab-bar__accessory--accent:hover ::slotted(svg),.glass-tab-bar__accessory--accent:hover svg{stroke:var(--gl-color-on-primary,#ffffff)}.glass-tab-bar__accessory--success{background:linear-gradient(135deg,var(--gl-color-success) 0,color-mix(in srgb,var(--gl-color-success) 70%,transparent) 100%);border-color:color-mix(in srgb,var(--gl-color-success) 50%,transparent);box-shadow:0 8px 32px color-mix(in srgb,var(--gl-color-success) 35%,transparent),var(--gl-inset-medium)}.glass-tab-bar__accessory--success ::slotted(svg),.glass-tab-bar__accessory--success svg{stroke:var(--gl-color-on-success,#ffffff)}.glass-tab-bar__accessory--error{background:linear-gradient(135deg,var(--gl-color-error) 0,color-mix(in srgb,var(--gl-color-error) 70%,transparent) 100%);border-color:color-mix(in srgb,var(--gl-color-error) 50%,transparent);box-shadow:0 8px 32px color-mix(in srgb,var(--gl-color-error) 35%,transparent),var(--gl-inset-medium)}.glass-tab-bar__accessory--error ::slotted(svg),.glass-tab-bar__accessory--error svg{stroke:var(--gl-color-on-error,#ffffff)}.glass-accordion{display:flex;flex-direction:column;gap:var(--gl-space-xs)}.glass-accordion__item{background:var(--gl-surface-2);backdrop-filter:blur(var(--gl-blur-light));-webkit-backdrop-filter:blur(var(--gl-blur-light));border:1px solid var(--gl-border-subtle);border-radius:var(--gl-radius-btn);overflow:hidden;transition:var(--gl-transition);box-shadow:var(--gl-inset-subtle)}.glass-accordion__item.is-open{background:var(--gl-surface-3);border-color:var(--gl-border-medium);box-shadow:0 4px 16px rgba(0,0,0,.1),var(--gl-inset-medium)}.glass-accordion__trigger{width:100%;display:flex;align-items:center;justify-content:space-between;gap:var(--gl-space-sm);padding:var(--gl-space-md) var(--gl-space-lg);background:0 0;border:none;cursor:pointer;font-family:var(--gl-font-family);font-size:var(--gl-font-size-base);font-weight:var(--gl-font-weight-semibold);color:var(--gl-color-text);text-align:start;outline:0;transition:var(--gl-transition);-webkit-tap-highlight-color:transparent}.glass-accordion__trigger:hover{color:var(--gl-color-primary)}.glass-accordion__trigger-icon{display:flex;align-items:center;justify-content:center;flex-shrink:0}.glass-accordion__trigger-icon svg{width:18px;height:18px;fill:none;stroke:var(--gl-icon-default);stroke-width:2;stroke-linecap:round;stroke-linejoin:round;transition:transform .3s cubic-bezier(.4, 0, .2, 1)}.glass-accordion__item.is-open .glass-accordion__trigger-icon svg{transform:rotate(180deg);stroke:var(--gl-color-primary)}.glass-accordion__content{max-height:0;overflow:hidden;transition:max-height .35s cubic-bezier(.4, 0, .2, 1)}.glass-accordion__item.is-open .glass-accordion__content{max-height:500px}.glass-accordion__body{padding:0 var(--gl-space-lg) var(--gl-space-lg);color:var(--gl-accordion-body-color);font-size:var(--gl-font-size-sm);line-height:1.6}.glass-badge{--gl-badge-accent:var(--gl-color-primary);--gl-badge-accent-text:var(--gl-color-primary-on-surface, var(--gl-color-primary));display:inline-flex;align-items:center;gap:var(--gl-space-2xs);padding:var(--gl-space-2xs) var(--gl-space-sm);background:var(--gl-surface-3);backdrop-filter:blur(var(--gl-blur-soft));-webkit-backdrop-filter:blur(var(--gl-blur-soft));border:1px solid var(--gl-border-subtle);border-radius:var(--gl-radius-full);font-size:var(--gl-font-size-xs);font-weight:var(--gl-font-weight-medium);color:var(--gl-color-text);box-shadow:var(--gl-inset-subtle)}.glass-badge--primary{--gl-badge-accent:var(--gl-color-primary);--gl-badge-accent-text:var(--gl-color-primary-on-surface, var(--gl-color-primary));background:linear-gradient(135deg,var(--gl-color-primary-surface,rgba(245,166,35,.25)) 0,color-mix(in srgb,var(--gl-color-primary-dark) 20%,transparent) 100%),var(--gl-state-scrim,transparent);border-color:var(--gl-color-primary-border,var(--gl-border-warm));color:var(--gl-color-primary-on-surface,var(--gl-color-primary))}.glass-badge--success{--gl-badge-accent:var(--gl-color-success);--gl-badge-accent-text:var(--gl-color-success-on-surface, var(--gl-color-success));background:linear-gradient(var(--gl-color-success-surface,rgba(52,199,89,.15)) 0,var(--gl-color-success-surface,rgba(52,199,89,.15)) 100%),var(--gl-state-scrim,transparent);border-color:var(--gl-color-success-border,rgba(52,199,89,.3));color:var(--gl-color-success-on-surface,var(--gl-color-success))}.glass-badge--error{--gl-badge-accent:var(--gl-color-error);--gl-badge-accent-text:var(--gl-color-error-on-surface, var(--gl-color-error));background:linear-gradient(var(--gl-color-error-surface,rgba(255,59,48,.15)) 0,var(--gl-color-error-surface,rgba(255,59,48,.15)) 100%),var(--gl-state-scrim,transparent);border-color:var(--gl-color-error-border,rgba(255,59,48,.3));color:var(--gl-color-error-on-surface,var(--gl-color-error))}.glass-badge--warning{--gl-badge-accent:var(--gl-color-warning);--gl-badge-accent-text:var(--gl-color-warning-on-surface, var(--gl-color-warning));background:linear-gradient(var(--gl-color-warning-surface,rgba(255,204,0,.15)) 0,var(--gl-color-warning-surface,rgba(255,204,0,.15)) 100%),var(--gl-state-scrim,transparent);border-color:var(--gl-color-warning-border,rgba(255,204,0,.3));color:var(--gl-color-warning-on-surface,var(--gl-color-warning))}.glass-badge--interactive{font-family:inherit;-webkit-appearance:none;appearance:none;cursor:pointer;transition:var(--gl-transition-fast);outline:0;-webkit-tap-highlight-color:transparent}.glass-badge--interactive:hover{border-color:color-mix(in srgb,var(--gl-badge-accent) 45%,var(--gl-border-subtle));box-shadow:var(--gl-inset-subtle),inset 0 0 0 100px color-mix(in srgb,var(--gl-badge-accent) 12%,transparent)}.glass-badge--interactive:active{transform:scale(.96)}.glass-badge--interactive:focus-visible{box-shadow:var(--gl-shadow-focus),var(--gl-inset-subtle)}.glass-badge--selected{border-color:color-mix(in srgb,var(--gl-badge-accent) 55%,transparent);color:var(--gl-badge-accent-text);box-shadow:var(--gl-inset-subtle),inset 0 0 0 100px color-mix(in srgb,var(--gl-badge-accent) 22%,transparent)}.glass-badge--interactive.glass-badge--selected:hover{box-shadow:var(--gl-inset-subtle),inset 0 0 0 100px color-mix(in srgb,var(--gl-badge-accent) 30%,transparent)}.glass-badge--interactive.glass-badge--selected:focus-visible{box-shadow:var(--gl-shadow-focus),var(--gl-inset-subtle),inset 0 0 0 100px color-mix(in srgb,var(--gl-badge-accent) 22%,transparent)}.glass-divider{height:1px;border:none;background:linear-gradient(90deg,transparent 0,var(--gl-border-subtle) 20%,var(--gl-border-medium) 50%,var(--gl-border-subtle) 80%,transparent 100%)}.glass-avatar{width:44px;height:44px;border-radius:var(--gl-radius-pill);background:var(--gl-surface-3);backdrop-filter:blur(var(--gl-blur-soft));-webkit-backdrop-filter:blur(var(--gl-blur-soft));border:1.5px solid var(--gl-border-strong);display:flex;align-items:center;justify-content:center;overflow:hidden;box-shadow:var(--gl-shadow-glow),var(--gl-inset-medium);flex-shrink:0;font-size:var(--gl-font-size-btn);font-weight:var(--gl-font-weight-semibold);color:var(--gl-color-text)}.glass-avatar ::slotted(img),.glass-avatar img{width:100%;height:100%;object-fit:cover}.glass-avatar--sm{width:32px;height:32px;font-size:var(--gl-font-size-xs)}.glass-avatar--lg{width:56px;height:56px;font-size:var(--gl-font-size-lg)}.glass-theme-toggle{width:46px;height:46px;border-radius:var(--gl-radius-pill);background:var(--gl-surface-3);backdrop-filter:blur(var(--gl-blur));-webkit-backdrop-filter:blur(var(--gl-blur));border:1.5px solid var(--gl-border-strong);display:flex;align-items:center;justify-content:center;cursor:pointer;transition:var(--gl-transition);box-shadow:var(--gl-shadow-glow),var(--gl-inset-medium);outline:0;-webkit-tap-highlight-color:transparent}.glass-theme-toggle:hover{background:var(--gl-surface-5);transform:scale(1.05)}.glass-theme-toggle:active{transform:scale(.95)}.glass-theme-toggle svg{width:20px;height:20px;fill:none;stroke:var(--gl-color-text);stroke-width:2;stroke-linecap:round;stroke-linejoin:round}.glass-theme-toggle .icon-sun{display:none}.glass-theme-toggle .icon-moon,[data-theme=light] .glass-theme-toggle .icon-sun{display:block}[data-theme=light] .glass-theme-toggle .icon-moon{display:none}.glass-popover-anchor{position:relative;display:inline-block}.glass-popover{position:absolute;top:calc(100% + var(--gl-space-xs));left:50%;transform:translateX(-50%) translateY(-4px) scale(.96);transform-origin:top center;min-width:220px;padding:var(--gl-space-sm);background:var(--gl-surface-3);backdrop-filter:blur(var(--gl-blur));-webkit-backdrop-filter:blur(var(--gl-blur));border:1px solid var(--gl-border-medium);border-radius:var(--gl-radius-card);box-shadow:var(--gl-shadow-card),var(--gl-inset-strong);opacity:0;visibility:hidden;pointer-events:none;transition:opacity .18s,transform .18s cubic-bezier(.2,.8,.2,1),visibility 0s linear .18s;z-index:50}.glass-popover.is-open{opacity:1;visibility:visible;pointer-events:auto;transform:translateX(-50%) translateY(0) scale(1);transition:opacity .18s,transform .22s cubic-bezier(.2,.8,.2,1),visibility linear}.glass-popover--top{top:auto;bottom:calc(100% + var(--gl-space-xs));transform-origin:bottom center}.glass-popover--start{inset-inline-start:0;inset-inline-end:auto;transform:translateY(-4px) scale(.96);transform-origin:top left}.glass-popover--start:dir(rtl){transform-origin:top right}.glass-popover--start.is-open{transform:translateY(0) scale(1)}.glass-popover--end{inset-inline-start:auto;inset-inline-end:0;transform:translateY(-4px) scale(.96);transform-origin:top right}.glass-popover--end:dir(rtl){transform-origin:top left}.glass-popover--end.is-open{transform:translateY(0) scale(1)}.glass-list{background:var(--gl-surface-1);backdrop-filter:blur(var(--gl-blur-light));-webkit-backdrop-filter:blur(var(--gl-blur-light));border:1px solid var(--gl-border-subtle);border-radius:var(--gl-radius-btn);box-shadow:0 4px 12px rgba(0,0,0,.08),var(--gl-inset-subtle);overflow:hidden;display:flex;flex-direction:column;width:100%;margin:0;padding:0;list-style:none}.glass-list--flush{border-radius:0;border-left:none;border-right:none;margin-left:calc(var(--gl-space-lg) * -1);margin-right:calc(var(--gl-space-lg) * -1)}.glass-list--bare{background:0 0;backdrop-filter:none;-webkit-backdrop-filter:none;border:none;border-radius:0;box-shadow:none}.glass-list__section-header{padding:var(--gl-space-xs) var(--gl-space-lg) var(--gl-space-2xs);font-size:var(--gl-font-size-xs);font-weight:var(--gl-font-weight-semibold);color:var(--gl-color-text-muted);text-transform:uppercase;letter-spacing:.3px}.glass-list__item{position:relative;display:flex;align-items:center;gap:var(--gl-space-sm);padding:var(--gl-list-item-padding-y,var(--gl-space-md)) var(--gl-space-lg);min-height:var(--gl-list-item-min-height,56px);color:var(--gl-color-text);font-size:var(--gl-font-size-base);text-decoration:none;background:0 0;border:none;width:100%;text-align:start;font-family:inherit;list-style:none}.glass-list__item:not(:last-child)::after{content:'';position:absolute;inset-inline-start:calc(var(--gl-space-lg) + 28px + var(--gl-space-sm));inset-inline-end:var(--gl-space-lg);bottom:0;height:1px;background:var(--gl-border-subtle);pointer-events:none}.glass-list__item:not(:has(.glass-list__leading:not([hidden]))):not(:last-child)::after{inset-inline-start:var(--gl-space-lg)}.glass-list__item:has(.glass-list__leading--lg:not([hidden])):not(:last-child)::after{inset-inline-start:calc(var(--gl-space-lg) + 40px + var(--gl-space-sm))}.glass-list__item--center{justify-content:center;text-align:center;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.glass-list__item--center>.glass-list__title{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.glass-list__item--interactive{cursor:pointer;transition:background .15s}.glass-list__item--interactive:focus-visible,.glass-list__item--interactive:hover{background:var(--gl-surface-2);outline:0}.glass-list__item--interactive:active{background:var(--gl-surface-3)}.glass-list__item--danger{color:var(--gl-color-error)}.glass-list__item--danger .glass-list__leading,.glass-list__item--danger .glass-list__title{color:inherit}.glass-list__item--accent{color:var(--gl-color-primary)}.glass-list__item--accent .glass-list__leading,.glass-list__item--accent .glass-list__title{color:inherit}.glass-list__leading{flex-shrink:0;width:28px;height:28px;display:flex;align-items:center;justify-content:center;color:var(--gl-icon-strong)}.glass-list__leading[hidden],.glass-list__trailing[hidden]{display:none}.glass-list__leading ::slotted(svg),.glass-list__leading svg{width:24px;height:24px;stroke:currentColor;stroke-width:2;fill:none;stroke-linecap:round;stroke-linejoin:round}.glass-list__leading--lg{width:40px;height:40px;border-radius:var(--gl-radius-xs);overflow:hidden}.glass-list__leading--lg ::slotted(svg),.glass-list__leading--lg svg{width:32px;height:32px}.glass-list__leading--lg ::slotted(img),.glass-list__leading--lg img{width:100%;height:100%;object-fit:cover;display:block}.glass-list__content{flex:1 1 0;min-width:0;display:flex;flex-direction:column;gap:2px;overflow:hidden}.glass-list__title{font-size:var(--gl-font-size-base);font-weight:var(--gl-font-weight-medium);color:var(--gl-color-text);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.glass-list__subtitle{font-size:var(--gl-font-size-sm);color:var(--gl-color-text-muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.glass-list__subtitle--wrap{white-space:normal;display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;overflow:hidden}.glass-list__trailing{flex-shrink:0;display:flex;align-items:center;gap:var(--gl-space-xs);color:var(--gl-color-text-muted);font-size:var(--gl-font-size-sm)}.glass-list__trailing ::slotted(svg),.glass-list__trailing svg{width:18px;height:18px;stroke:var(--gl-icon-muted);stroke-width:2;fill:none;stroke-linecap:round;stroke-linejoin:round}.glass-list__value{color:var(--gl-color-text-muted);font-size:var(--gl-font-size-sm);white-space:nowrap}.glass-skeleton{display:flex;flex-direction:column;gap:10px}.glass-skeleton__line{height:12px;border-radius:6px;background:linear-gradient(90deg,var(--gl-surface-1) 0,var(--gl-surface-4) 50%,var(--gl-surface-1) 100%);background-size:200% 100%;animation:1.4s ease-in-out infinite glass-skeleton}.glass-skeleton__line--title{height:18px}@keyframes glass-skeleton{from{background-position:200% 0}to{background-position:-200% 0}}.glass-table-wrap{overflow-x:auto;border-radius:var(--gl-radius-sm)}.glass-table{width:100%;border-collapse:collapse;font-size:var(--gl-font-size-sm);color:var(--gl-color-text)}.glass-table th{text-align:start;padding:8px 10px;white-space:nowrap;font-weight:var(--gl-font-weight-medium);color:var(--gl-color-text-muted);border-bottom:1px solid var(--gl-border-medium)}.glass-table td{padding:9px 10px;vertical-align:top;border-bottom:1px solid var(--gl-border-subtle)}.glass-table tbody tr:last-child td{border-bottom:0}.glass-table tbody tr:hover td{background:var(--gl-surface-1)}.glass-table__num{text-align:end;font-variant-numeric:tabular-nums}.glass-table__muted{color:var(--gl-color-text-muted)}.glass-prose{font-size:var(--gl-font-size-base);line-height:1.6;color:var(--gl-color-text)}.glass-prose>:first-child{margin-top:0}.glass-prose>:last-child{margin-bottom:0}.glass-prose h1,.glass-prose h2,.glass-prose h3{color:var(--gl-color-text-heading);line-height:1.25;margin:1.2em 0 .4em}.glass-prose h1{font-size:var(--gl-font-size-title)}.glass-prose h2{font-size:var(--gl-font-size-modal)}.glass-prose h3{font-size:var(--gl-font-size-lg)}.glass-prose blockquote,.glass-prose ol,.glass-prose p,.glass-prose pre,.glass-prose table,.glass-prose ul{margin:0 0 .9em}.glass-prose ol,.glass-prose ul{padding-inline-start:1.3em}.glass-prose strong{color:var(--gl-color-text-heading)}.glass-prose a{color:var(--gl-color-primary);text-decoration:underline;text-underline-offset:2px}.glass-prose code{font-family:ui-monospace,'SF Mono',Menlo,monospace;font-size:.9em;background:var(--gl-surface-2);padding:1px 5px;border-radius:4px}.glass-prose pre{padding:12px 14px;overflow-x:auto;background:var(--gl-surface-1);border-radius:var(--gl-radius-sm)}.glass-prose pre code{background:0 0;padding:0}.glass-prose blockquote{padding:8px 14px;border-inline-start:3px solid var(--gl-color-primary);background:var(--gl-surface-1);border-start-start-radius:0;border-end-start-radius:0;border-start-end-radius:var(--gl-radius-xs);border-end-end-radius:var(--gl-radius-xs)}.glass-prose img{max-width:100%;height:auto;border-radius:var(--gl-radius-sm)}.glass-prose hr{height:1px;border:0;margin:1.2em 0;background:var(--gl-border-subtle)}.glass-prose table{width:100%;border-collapse:collapse}.glass-prose td,.glass-prose th{padding:6px 8px;text-align:start;border-bottom:1px solid var(--gl-border-subtle)}.glass-segmented{display:inline-flex;gap:4px;padding:4px;max-width:100%;background:var(--gl-surface-1);border:1px solid var(--gl-border-subtle);border-radius:var(--gl-radius-btn);box-shadow:var(--gl-inset-subtle)}.glass-segmented--full{display:flex}.glass-segmented--full .glass-segmented__item{flex:1 1 0}.glass-segmented--scroll{overflow-x:auto;overflow-y:hidden;scrollbar-width:none;overscroll-behavior-x:contain}.glass-segmented--scroll::-webkit-scrollbar{display:none}.glass-segmented--wrap{flex-wrap:wrap}.glass-segmented__item{-webkit-appearance:none;appearance:none;display:inline-flex;align-items:center;justify-content:center;gap:6px;padding:8px 14px;border:0;border-radius:var(--gl-radius-sm);background:0 0;color:var(--gl-color-text-muted);font-family:inherit;font-size:var(--gl-font-size-sm);font-weight:var(--gl-font-weight-medium);white-space:nowrap;cursor:pointer;transition:var(--gl-transition-fast);outline:0;-webkit-tap-highlight-color:transparent}.glass-segmented__item:hover{color:var(--gl-color-text)}.glass-segmented__item[aria-pressed=true]{background:var(--gl-surface-5);color:var(--gl-color-text-heading);box-shadow:var(--gl-shadow-btn)}.glass-segmented__item:focus-visible{box-shadow:var(--gl-shadow-focus)}.glass-segmented__item[aria-pressed=true]:focus-visible{box-shadow:var(--gl-shadow-focus),var(--gl-shadow-btn)}.glass-segmented__item:disabled{opacity:.45;cursor:not-allowed}.glass-segmented__dot{width:10px;height:10px;border-radius:50%;background:var(--gl-segmented-tone,currentColor)}.glass-segmented__item--success{--gl-segmented-tone:var(--gl-color-success)}.glass-segmented__item--warning{--gl-segmented-tone:var(--gl-color-warning)}.glass-segmented__item--error{--gl-segmented-tone:var(--gl-color-error)}.glass-steps{display:flex;align-items:center;gap:6px;margin:0;padding:0;list-style:none;min-width:0;container-type:inline-size}.glass-steps__item{display:flex;align-items:center;gap:6px;flex:0 1 auto;min-width:0;font-size:var(--gl-font-size-xs);color:var(--gl-color-text-muted);white-space:nowrap}.glass-steps__num{flex:none;width:22px;height:22px;border-radius:50%;display:inline-flex;align-items:center;justify-content:center;border:1px solid var(--gl-border-medium);font-size:11px;font-weight:var(--gl-font-weight-semibold)}.glass-steps__num svg{width:12px;height:12px;fill:none;stroke:currentColor;stroke-width:2.5;stroke-linecap:round;stroke-linejoin:round}.glass-steps__label{min-width:0;overflow:hidden;text-overflow:ellipsis}.glass-steps__item--done .glass-steps__num{background:var(--gl-color-success-surface);border-color:var(--gl-color-success-border);color:var(--gl-color-success-on-surface)}.glass-steps__item--current{color:var(--gl-color-text-heading)}.glass-steps__item--current .glass-steps__num{background:var(--gl-color-primary);border-color:transparent;color:var(--gl-color-on-primary)}.glass-steps__line{flex:1 1 8px;min-width:8px;height:1px;background:var(--gl-border-subtle)}@container (max-width:360px){.glass-steps__label{display:none}.glass-steps__item--current .glass-steps__label{display:inline}}.glass-sheet-overlay{position:fixed;inset:0;z-index:1000;display:flex;align-items:flex-end;justify-content:center;background:var(--gl-surface-overlay);backdrop-filter:blur(var(--gl-blur-soft));-webkit-backdrop-filter:blur(var(--gl-blur-soft));font-family:var(--gl-font-family);-webkit-font-smoothing:antialiased;opacity:0;transition:var(--gl-transition-modal);transition-property:opacity}.glass-sheet-overlay[hidden]{display:none}.glass-sheet-overlay.is-active{opacity:1}.glass-sheet{width:min(100%,560px);max-height:88dvh;overflow:auto;padding:8px var(--gl-space-lg) calc(var(--gl-space-lg) + env(safe-area-inset-bottom,0px));background:linear-gradient(to bottom,var(--gl-card-glow-top) 0,var(--gl-card-glow-bottom) 100%);backdrop-filter:blur(var(--gl-blur-heavy));-webkit-backdrop-filter:blur(var(--gl-blur-heavy));color:var(--gl-color-text);border:1.5px solid var(--gl-border-medium);border-radius:var(--gl-radius-card) var(--gl-radius-card) 0 0;box-shadow:var(--gl-shadow-modal)}.glass-sheet-overlay .glass-sheet{transform:translateY(100%);transition:var(--gl-transition-modal);transition-property:transform}.glass-sheet-overlay.is-active .glass-sheet{transform:translateY(0)}.glass-sheet--inline{border-radius:var(--gl-radius-card);box-shadow:var(--gl-shadow-card)}.glass-sheet__grip{width:40px;height:4px;margin:4px auto 12px;border-radius:2px;background:var(--gl-border-strong)}.glass-sheet__title{margin:0 0 8px;font-size:var(--gl-font-size-modal);font-weight:var(--gl-font-weight-semibold);color:var(--gl-color-text-heading)}.glass-sheet__body{font-size:var(--gl-font-size-base);line-height:1.55}.glass-sheet__actions{display:flex;flex-direction:column;gap:8px;margin-top:16px}@media (prefers-reduced-motion:reduce){.glass-skeleton__line{animation:none}.glass-sheet-overlay,.glass-sheet-overlay .glass-sheet{transition:none}}.glass-empty{display:flex;flex-direction:column;align-items:center;gap:8px;padding:28px 16px;text-align:center}.glass-empty__icon{display:inline-flex;align-items:center;justify-content:center;width:48px;height:48px;border-radius:50%;background:var(--gl-surface-2);color:var(--gl-icon-default)}.glass-empty__icon ::slotted(svg),.glass-empty__icon svg{width:24px;height:24px;fill:none;stroke:currentColor;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}.glass-empty__title{margin:4px 0 0;font-weight:var(--gl-font-weight-semibold);color:var(--gl-color-text-heading)}.glass-empty__text{margin:0;max-width:38ch;font-size:var(--gl-font-size-sm);line-height:1.55;color:var(--gl-color-text-muted)}.glass-empty__action{display:flex;flex-wrap:wrap;justify-content:center;gap:8px;margin-top:8px}.glass-date-strip{display:flex;gap:6px;padding:4px;overflow-x:auto;overflow-y:hidden;scrollbar-width:none;overscroll-behavior-x:contain}.glass-date-strip::-webkit-scrollbar{display:none}.glass-date-strip__day{-webkit-appearance:none;appearance:none;flex:1 0 44px;min-width:44px;display:flex;flex-direction:column;align-items:center;gap:2px;padding:8px 4px 6px;border:1px solid var(--gl-border-subtle);border-radius:var(--gl-radius-input);background:var(--gl-surface-1);color:var(--gl-color-text);font-family:inherit;cursor:pointer;transition:var(--gl-transition-fast);outline:0;-webkit-tap-highlight-color:transparent}.glass-date-strip__day:hover{background:var(--gl-surface-3)}.glass-date-strip__day[aria-pressed=true]{--gl-date-strip-ink:var(--gl-color-on-primary);background:var(--gl-color-primary);color:var(--gl-color-on-primary);border-color:transparent;box-shadow:var(--gl-shadow-btn-primary)}.glass-date-strip__day:focus-visible{box-shadow:var(--gl-shadow-focus)}.glass-date-strip__day[aria-pressed=true]:focus-visible{box-shadow:var(--gl-shadow-focus),var(--gl-shadow-btn-primary)}.glass-date-strip__day:disabled,.glass-date-strip__day[aria-disabled=true]{opacity:.45;cursor:not-allowed}.glass-date-strip__day:disabled:hover,.glass-date-strip__day[aria-disabled=true]:hover{background:var(--gl-surface-1)}.glass-date-strip__day--today .glass-date-strip__num{text-decoration:underline;text-underline-offset:3px}.glass-date-strip__wd{font-size:var(--gl-font-size-xs);opacity:.75;text-transform:uppercase;letter-spacing:.04em}.glass-date-strip__num{font-size:var(--gl-font-size-lg);font-weight:var(--gl-font-weight-semibold);line-height:1.1}.glass-date-strip__mark{width:6px;height:6px;margin-top:2px;border-radius:50%;background:var(--gl-date-strip-tone,transparent)}.glass-date-strip__mark--primary{--gl-date-strip-tone:var(--gl-date-strip-ink, var(--gl-color-primary))}.glass-date-strip__mark--success{--gl-date-strip-tone:var(--gl-date-strip-ink, var(--gl-color-success))}.glass-date-strip__mark--warning{--gl-date-strip-tone:var(--gl-date-strip-ink, var(--gl-color-warning))}.glass-date-strip__mark--error{--gl-date-strip-tone:var(--gl-date-strip-ink, var(--gl-color-error))}.glass-calendar{display:block}.glass-calendar__head{display:flex;align-items:center;justify-content:space-between;gap:8px;margin-bottom:8px}.glass-calendar__title{flex:1 1 auto;min-width:0;text-align:center;font-weight:var(--gl-font-weight-semibold);color:var(--gl-color-text-heading);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.glass-calendar__nav{-webkit-appearance:none;appearance:none;flex:none;width:32px;height:32px;padding:0;display:inline-flex;align-items:center;justify-content:center;border:1px solid var(--gl-border-subtle);border-radius:var(--gl-radius-full);background:var(--gl-surface-1);color:var(--gl-color-text);font-family:inherit;cursor:pointer;transition:var(--gl-transition-fast);outline:0;-webkit-tap-highlight-color:transparent}.glass-calendar__nav:hover{background:var(--gl-surface-3)}.glass-calendar__nav:focus-visible{box-shadow:var(--gl-shadow-focus)}.glass-calendar__nav svg{width:16px;height:16px;fill:none;stroke:currentColor;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}.glass-calendar__grid{display:grid;grid-template-columns:repeat(7,minmax(0,1fr));gap:4px}.glass-calendar__wd{padding:4px 0;text-align:center;font-size:var(--gl-font-size-xs);color:var(--gl-color-text-muted);text-transform:uppercase;letter-spacing:.04em;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.glass-calendar__day{-webkit-appearance:none;appearance:none;aspect-ratio:1;min-width:0;padding:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:2px;border:1px solid transparent;border-radius:var(--gl-radius-sm);background:0 0;color:var(--gl-color-text);font-family:inherit;font-size:var(--gl-font-size-sm);cursor:pointer;transition:var(--gl-transition-fast);outline:0;-webkit-tap-highlight-color:transparent}.glass-calendar__day:hover{background:var(--gl-surface-2)}.glass-calendar__day--other{opacity:.35}.glass-calendar__day--today{border-color:var(--gl-border-warm)}.glass-calendar__day[aria-pressed=true]{--gl-calendar-ink:var(--gl-color-on-primary);background:var(--gl-color-primary);color:var(--gl-color-on-primary)}.glass-calendar__day:focus-visible{box-shadow:var(--gl-shadow-focus)}.glass-calendar__day:disabled,.glass-calendar__day[aria-disabled=true]{opacity:.45;cursor:not-allowed}.glass-calendar__day:disabled:hover,.glass-calendar__day[aria-disabled=true]:hover{background:0 0}.glass-calendar__marks{display:flex;gap:2px;height:5px}.glass-calendar__mark{width:5px;height:5px;border-radius:50%;background:var(--gl-calendar-tone,transparent)}.glass-calendar__mark--primary{--gl-calendar-tone:var(--gl-calendar-ink, var(--gl-color-primary))}.glass-calendar__mark--success{--gl-calendar-tone:var(--gl-calendar-ink, var(--gl-color-success))}.glass-calendar__mark--warning{--gl-calendar-tone:var(--gl-calendar-ink, var(--gl-color-warning))}.glass-calendar__mark--error{--gl-calendar-tone:var(--gl-calendar-ink, var(--gl-color-error))}.glass-image-picker{display:flex;align-items:center;gap:14px}.glass-image-picker__preview{flex:none;width:72px;height:72px;display:flex;align-items:center;justify-content:center;border:1px solid var(--gl-border-subtle);border-radius:var(--gl-radius-input);background:var(--gl-surface-2);color:var(--gl-icon-muted);overflow:hidden}.glass-image-picker__preview--round{border-radius:50%}.glass-image-picker__preview img{display:block;width:100%;height:100%;object-fit:cover}.glass-image-picker__preview svg{width:28px;height:28px;fill:none;stroke:currentColor;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}.glass-image-picker__meta{flex:1 1 auto;min-width:0;display:flex;flex-direction:column;align-items:flex-start;gap:6px}.glass-image-picker__label{font-size:var(--gl-font-size-sm);font-weight:var(--gl-font-weight-medium);color:var(--gl-icon-strong);overflow-wrap:anywhere}.glass-image-picker__hint{font-size:var(--gl-font-size-xs);color:var(--gl-color-text-muted)}.glass-image-picker__actions{display:flex;flex-wrap:wrap;gap:8px}.gl-stack{display:flex;flex-direction:column}.gl-row{display:flex;flex-direction:row;align-items:center}.gl-stack--2xs{gap:var(--gl-space-2xs)}.gl-stack--xs{gap:var(--gl-space-xs)}.gl-stack--sm{gap:var(--gl-space-sm)}.gl-stack--md{gap:var(--gl-space-md)}.gl-stack--lg{gap:var(--gl-space-lg)}.gl-stack--xl{gap:var(--gl-space-xl)}.gl-row--xs{gap:var(--gl-space-xs)}.gl-row--sm{gap:var(--gl-space-sm)}.gl-row--md{gap:var(--gl-space-md)}.gl-text-center{text-align:center}.gl-text-muted{color:var(--gl-color-text-muted)}.gl-text-sm{font-size:var(--gl-font-size-sm)}.gl-mt-sm{margin-top:var(--gl-space-sm)}.gl-mt-md{margin-top:var(--gl-space-md)}.gl-mt-lg{margin-top:var(--gl-space-lg)}.gl-mt-xl{margin-top:var(--gl-space-xl)}.gl-mb-sm{margin-bottom:var(--gl-space-sm)}.gl-mb-md{margin-bottom:var(--gl-space-md)}.gl-mb-lg{margin-bottom:var(--gl-space-lg)}.gl-mb-xl{margin-bottom:var(--gl-space-xl)}.gl-px{padding-left:var(--gl-space-lg);padding-right:var(--gl-space-lg)}.gl-w-full{width:100%}.gl-flex-1{flex:1}svg.glass-icon--fill{fill:currentColor;stroke:none}\n";
|
|
10
10
|
|
|
11
11
|
const componentsCss = componentsHead + componentsTail;
|
|
12
12
|
const css = componentsHead + tokensCss + componentsTail;
|
|
@@ -31,25 +31,58 @@ componentsSheet.replaceSync(componentsCss);
|
|
|
31
31
|
// inherits them like any other custom property. They are wrapped in a cascade
|
|
32
32
|
// layer so an ordinary (unlayered) brand stylesheet wins over them, no matter
|
|
33
33
|
// whether it loads before or after this module.
|
|
34
|
+
//
|
|
35
|
+
// Only the custom properties go there. GlassKit's token blocks also set
|
|
36
|
+
// color-scheme, and on the document that is no default: it switches the whole
|
|
37
|
+
// page to dark — native controls, scrollbars, the root text colour, link
|
|
38
|
+
// colours — on pages that never asked for GlassKit's theme. The elements set
|
|
39
|
+
// color-scheme on their own theme wrapper instead (host sheet below).
|
|
40
|
+
//
|
|
41
|
+
// The --gl-* names themselves are still global. A page that declares them
|
|
42
|
+
// itself, or wants them on part of the page only, switches the defaults off
|
|
43
|
+
// with <html data-glk-defaults="off">. The attribute is watched, so it may
|
|
44
|
+
// also be set or removed later.
|
|
34
45
|
|
|
35
46
|
const TOKENS_INJECTED = '__glkDefaultTokensInjected';
|
|
47
|
+
const DEFAULTS_ATTR = 'data-glk-defaults';
|
|
48
|
+
let defaultTokensSheet = null;
|
|
36
49
|
|
|
37
50
|
function injectDefaultTokens() {
|
|
38
51
|
if (typeof document === 'undefined') return; // SSR / non-DOM
|
|
39
52
|
if (globalThis[TOKENS_INJECTED]) return; // another bundle copy did it
|
|
40
53
|
globalThis[TOKENS_INJECTED] = true;
|
|
41
54
|
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
55
|
+
const tokens = tokensCss.replace(/color-scheme\s*:[^;}]*;?/g, '');
|
|
56
|
+
defaultTokensSheet = new CSSStyleSheet();
|
|
57
|
+
defaultTokensSheet.replaceSync(`@layer glasskit-defaults { ${tokens} }`);
|
|
58
|
+
syncDefaultTokens();
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** Adopts or drops the default tokens to match <html data-glk-defaults>. */
|
|
62
|
+
function syncDefaultTokens() {
|
|
63
|
+
if (!defaultTokensSheet) return;
|
|
64
|
+
const wanted = document.documentElement.getAttribute(DEFAULTS_ATTR) !== 'off';
|
|
65
|
+
const sheets = document.adoptedStyleSheets;
|
|
66
|
+
if (wanted === sheets.includes(defaultTokensSheet)) return;
|
|
67
|
+
// Add or remove only this sheet — never assign a fresh list — so an app's
|
|
68
|
+
// own adopted sheets survive.
|
|
69
|
+
document.adoptedStyleSheets = wanted
|
|
70
|
+
? [...sheets, defaultTokensSheet]
|
|
71
|
+
: sheets.filter(sheet => sheet !== defaultTokensSheet);
|
|
46
72
|
}
|
|
47
73
|
|
|
48
74
|
injectDefaultTokens();
|
|
49
75
|
|
|
50
|
-
// ── Global Theme Sync ──
|
|
51
|
-
// Single MutationObserver that watches data-theme on <html>
|
|
76
|
+
// ── Global Theme & Density Sync ──
|
|
77
|
+
// Single MutationObserver that watches data-theme and data-density on <html>
|
|
52
78
|
// and notifies all GlkElement instances.
|
|
79
|
+
//
|
|
80
|
+
// The density tokens themselves arrive from <html> by inheritance, like every
|
|
81
|
+
// other token: GlassKit's [data-density="compact"] preset is part of
|
|
82
|
+
// tokensCss, not of the components sheet. The wrapper mirrors the attribute
|
|
83
|
+
// anyway, as it mirrors data-theme — a rule keyed on it (a component rule, a
|
|
84
|
+
// subclass's hostStyles) can match inside a shadow root only on an element
|
|
85
|
+
// there.
|
|
53
86
|
|
|
54
87
|
const instances = new Set();
|
|
55
88
|
|
|
@@ -57,6 +90,11 @@ function getCurrentTheme() {
|
|
|
57
90
|
return document.documentElement.getAttribute('data-theme') || 'dark';
|
|
58
91
|
}
|
|
59
92
|
|
|
93
|
+
/** The density on <html>, or null — there is no default to fall back to. */
|
|
94
|
+
function getCurrentDensity() {
|
|
95
|
+
return document.documentElement.getAttribute('data-density');
|
|
96
|
+
}
|
|
97
|
+
|
|
60
98
|
function syncAllThemes() {
|
|
61
99
|
const theme = getCurrentTheme();
|
|
62
100
|
for (const instance of instances) {
|
|
@@ -64,32 +102,103 @@ function syncAllThemes() {
|
|
|
64
102
|
}
|
|
65
103
|
}
|
|
66
104
|
|
|
105
|
+
function syncAllDensities() {
|
|
106
|
+
const density = getCurrentDensity();
|
|
107
|
+
for (const instance of instances) {
|
|
108
|
+
instance._syncDensity(density);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
67
112
|
if (typeof window !== 'undefined' && typeof MutationObserver !== 'undefined') {
|
|
68
|
-
const observer = new MutationObserver(
|
|
113
|
+
const observer = new MutationObserver(records => {
|
|
114
|
+
if (records.some(r => r.attributeName === 'data-theme')) syncAllThemes();
|
|
115
|
+
if (records.some(r => r.attributeName === 'data-density')) syncAllDensities();
|
|
116
|
+
if (records.some(r => r.attributeName === DEFAULTS_ATTR)) syncDefaultTokens();
|
|
117
|
+
});
|
|
69
118
|
observer.observe(document.documentElement, {
|
|
70
119
|
attributes: true,
|
|
71
|
-
attributeFilter: ['data-theme']
|
|
120
|
+
attributeFilter: ['data-theme', 'data-density', DEFAULTS_ATTR]
|
|
72
121
|
});
|
|
73
122
|
}
|
|
74
123
|
|
|
75
124
|
// ── Host Stylesheet ──
|
|
76
125
|
// Sets display:block on all custom elements by default.
|
|
77
126
|
// Inline components (badge, avatar) override this.
|
|
127
|
+
//
|
|
128
|
+
// The wrapper carries the theme's color-scheme, so native parts inside the
|
|
129
|
+
// elements — a select's list, a date picker, scrollbars — match the element,
|
|
130
|
+
// whatever the page around it uses.
|
|
131
|
+
|
|
132
|
+
const wrapperRules = `
|
|
133
|
+
.glk-wrapper { display: contents; }
|
|
134
|
+
.glk-wrapper[data-theme="dark"] { color-scheme: dark; }
|
|
135
|
+
.glk-wrapper[data-theme="light"] { color-scheme: light; }
|
|
136
|
+
`;
|
|
78
137
|
|
|
79
138
|
const hostSheet = new CSSStyleSheet();
|
|
80
139
|
hostSheet.replaceSync(`
|
|
81
140
|
:host { display: block; }
|
|
82
141
|
:host([hidden]) { display: none; }
|
|
83
|
-
|
|
142
|
+
${wrapperRules}
|
|
84
143
|
`);
|
|
85
144
|
|
|
86
145
|
const inlineHostSheet = new CSSStyleSheet();
|
|
87
146
|
inlineHostSheet.replaceSync(`
|
|
88
147
|
:host { display: inline-block; }
|
|
89
148
|
:host([hidden]) { display: none; }
|
|
90
|
-
|
|
149
|
+
${wrapperRules}
|
|
91
150
|
`);
|
|
92
151
|
|
|
152
|
+
/**
|
|
153
|
+
* Host rules for glk-checkbox, glk-radio and glk-toggle. Their control is an
|
|
154
|
+
* inline-flex label inside a block host; sitting on the text baseline it left
|
|
155
|
+
* room for descenders below, so the host was about 4px taller than the
|
|
156
|
+
* control and the control sat high in a centred row. Aligned to the top of
|
|
157
|
+
* its line, the label is as tall as the host.
|
|
158
|
+
*/
|
|
159
|
+
const checkControlSheet = new CSSStyleSheet();
|
|
160
|
+
checkControlSheet.replaceSync(`
|
|
161
|
+
.glass-checkbox, .glass-radio, .glass-toggle { vertical-align: top; }
|
|
162
|
+
`);
|
|
163
|
+
|
|
164
|
+
// ── Clicks Aimed at the Host ──
|
|
165
|
+
// The innermost target of the latest pointerdown anywhere in the document;
|
|
166
|
+
// tracked once, on first use.
|
|
167
|
+
let lastPressed = null;
|
|
168
|
+
let trackingPresses = false;
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* For elements whose control is a native input or button inside the shadow
|
|
172
|
+
* root: glk-checkbox, glk-radio, glk-toggle, glk-button. A click aimed at the
|
|
173
|
+
* host itself — host.click(), or the click a <label> around the element or
|
|
174
|
+
* naming it dispatches — reaches only the host. The control never saw it, so
|
|
175
|
+
* nothing changed where a native checkbox toggles and a native button
|
|
176
|
+
* submits. Such a click is handed to the control; the original is stopped, so
|
|
177
|
+
* listeners see one click, the control's.
|
|
178
|
+
*
|
|
179
|
+
* A pointer press on the host's own empty box (the host is a block, the
|
|
180
|
+
* control is narrower) also lands on the host. Chrome cannot tell it apart
|
|
181
|
+
* from a label's click by the event, only by where the pointer went down; it
|
|
182
|
+
* stays a no-op, as before. Returns the teardown.
|
|
183
|
+
*/
|
|
184
|
+
function forwardHostClicks(host, getField) {
|
|
185
|
+
if (!trackingPresses && typeof window !== 'undefined') {
|
|
186
|
+
trackingPresses = true;
|
|
187
|
+
window.addEventListener('pointerdown', e => { lastPressed = e.composedPath()[0]; },
|
|
188
|
+
{ capture: true, passive: true });
|
|
189
|
+
}
|
|
190
|
+
const onClick = (e) => {
|
|
191
|
+
if (e.composedPath()[0] !== host) return; // from inside: the input had it
|
|
192
|
+
if (e.isTrusted && lastPressed === host) return; // a press on the empty box
|
|
193
|
+
const field = getField();
|
|
194
|
+
if (!field || field.disabled) return;
|
|
195
|
+
e.stopImmediatePropagation();
|
|
196
|
+
field.click();
|
|
197
|
+
};
|
|
198
|
+
host.addEventListener('click', onClick);
|
|
199
|
+
return () => host.removeEventListener('click', onClick);
|
|
200
|
+
}
|
|
201
|
+
|
|
93
202
|
// ── Base Class ──
|
|
94
203
|
|
|
95
204
|
class GlkElement extends HTMLElement {
|
|
@@ -112,6 +221,13 @@ class GlkElement extends HTMLElement {
|
|
|
112
221
|
*/
|
|
113
222
|
static get observesLightDom() { return false; }
|
|
114
223
|
|
|
224
|
+
/**
|
|
225
|
+
* Turned on by elements built around one native field: focus() on the
|
|
226
|
+
* host, a click on the label text and a <label for> outside all land in
|
|
227
|
+
* that field.
|
|
228
|
+
*/
|
|
229
|
+
static get delegatesFocus() { return false; }
|
|
230
|
+
|
|
115
231
|
static get observedAttributes() {
|
|
116
232
|
return [];
|
|
117
233
|
}
|
|
@@ -119,7 +235,7 @@ class GlkElement extends HTMLElement {
|
|
|
119
235
|
constructor() {
|
|
120
236
|
super();
|
|
121
237
|
this._initialized = false;
|
|
122
|
-
this._shadow = this.attachShadow({ mode: 'open' });
|
|
238
|
+
this._shadow = this.attachShadow({ mode: 'open', delegatesFocus: this.constructor.delegatesFocus });
|
|
123
239
|
const displaySheet = this.constructor.displayInline ? inlineHostSheet : hostSheet;
|
|
124
240
|
const sheets = [componentsSheet, displaySheet];
|
|
125
241
|
const extra = this.constructor.hostStyles;
|
|
@@ -135,9 +251,17 @@ class GlkElement extends HTMLElement {
|
|
|
135
251
|
this._wrapper = document.createElement('div');
|
|
136
252
|
this._wrapper.className = 'glk-wrapper';
|
|
137
253
|
this._wrapper.setAttribute('data-theme', getCurrentTheme());
|
|
254
|
+
this._syncDensity(getCurrentDensity());
|
|
138
255
|
this._shadow.appendChild(this._wrapper);
|
|
139
256
|
|
|
140
257
|
this.render();
|
|
258
|
+
} else {
|
|
259
|
+
// Back in the document. While it was out, the observer did not reach
|
|
260
|
+
// it, so a theme or density switched in the meantime is caught up here
|
|
261
|
+
// — the wrapper's data-theme also sets the color-scheme of the native
|
|
262
|
+
// parts inside.
|
|
263
|
+
this._syncTheme(getCurrentTheme());
|
|
264
|
+
this._syncDensity(getCurrentDensity());
|
|
141
265
|
}
|
|
142
266
|
|
|
143
267
|
// Everything below runs on every connect, not just the first. Moving an
|
|
@@ -173,6 +297,16 @@ class GlkElement extends HTMLElement {
|
|
|
173
297
|
}
|
|
174
298
|
}
|
|
175
299
|
|
|
300
|
+
/** Mirrors data-density from <html>; without one there, the wrapper has none. */
|
|
301
|
+
_syncDensity(density) {
|
|
302
|
+
if (!this._wrapper) return;
|
|
303
|
+
if (density) {
|
|
304
|
+
this._wrapper.setAttribute('data-density', density);
|
|
305
|
+
} else {
|
|
306
|
+
this._wrapper.removeAttribute('data-density');
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
176
310
|
/** Subclasses override to build inner DOM inside this._wrapper. */
|
|
177
311
|
render() {}
|
|
178
312
|
|
|
@@ -260,14 +394,26 @@ class GlkFormElement extends GlkElement {
|
|
|
260
394
|
|
|
261
395
|
static formAssociated = true;
|
|
262
396
|
|
|
397
|
+
// One native field inside, so focus goes there. The button groups
|
|
398
|
+
// (glk-segmented, glk-calendar) turn this off again: their first button is
|
|
399
|
+
// not the chosen one.
|
|
400
|
+
static get delegatesFocus() { return true; }
|
|
401
|
+
|
|
263
402
|
constructor() {
|
|
264
403
|
super();
|
|
265
404
|
this._internals = this.attachInternals();
|
|
266
405
|
}
|
|
267
406
|
|
|
407
|
+
attributeChangedCallback(name, oldValue, newValue) {
|
|
408
|
+
super.attributeChangedCallback(name, oldValue, newValue);
|
|
409
|
+
// required, min, pattern, type … all change what counts as valid.
|
|
410
|
+
if (this._initialized) this.syncValidity();
|
|
411
|
+
}
|
|
412
|
+
|
|
268
413
|
get form() { return this._internals.form; }
|
|
269
414
|
get validationMessage() { return this._internals.validationMessage; }
|
|
270
415
|
get validity() { return this._internals.validity; }
|
|
416
|
+
get willValidate() { return this._internals.willValidate; }
|
|
271
417
|
|
|
272
418
|
checkValidity() { return this._internals.checkValidity(); }
|
|
273
419
|
reportValidity() { return this._internals.reportValidity(); }
|
|
@@ -286,11 +432,38 @@ class GlkFormElement extends GlkElement {
|
|
|
286
432
|
|
|
287
433
|
setFormValue(value) {
|
|
288
434
|
this._internals.setFormValue(value);
|
|
435
|
+
this.syncValidity();
|
|
289
436
|
}
|
|
290
437
|
|
|
291
438
|
setValidity(flags, message, anchor) {
|
|
292
439
|
this._internals.setValidity(flags, message, anchor);
|
|
293
440
|
}
|
|
441
|
+
|
|
442
|
+
/**
|
|
443
|
+
* The native field whose constraint validation the host reports, or null.
|
|
444
|
+
* Subclasses built around one field return it.
|
|
445
|
+
*/
|
|
446
|
+
get _validityField() { return null; }
|
|
447
|
+
|
|
448
|
+
/**
|
|
449
|
+
* A form asks the host — checkValidity(), reportValidity(), submitting — and
|
|
450
|
+
* the host knows nothing by itself, so the inner field's verdict is copied
|
|
451
|
+
* over after everything that can change it: a value (every setFormValue
|
|
452
|
+
* lands here), an attribute, a reset. The field is the anchor: the browser's
|
|
453
|
+
* bubble points at it, and reportValidity() focuses it.
|
|
454
|
+
*/
|
|
455
|
+
syncValidity() {
|
|
456
|
+
const field = this._validityField;
|
|
457
|
+
if (!field) return;
|
|
458
|
+
const message = field.validationMessage;
|
|
459
|
+
// A field barred from validation (disabled) can still carry flags, but
|
|
460
|
+
// it has no message, and setValidity() refuses flags without one.
|
|
461
|
+
if (!field.willValidate || field.validity.valid || !message) {
|
|
462
|
+
this._internals.setValidity({});
|
|
463
|
+
} else {
|
|
464
|
+
this._internals.setValidity(field.validity, message, field);
|
|
465
|
+
}
|
|
466
|
+
}
|
|
294
467
|
}
|
|
295
468
|
|
|
296
469
|
class GlkNav extends GlkElement {
|
|
@@ -303,9 +476,13 @@ class GlkNav extends GlkElement {
|
|
|
303
476
|
|
|
304
477
|
customElements.define('glk-nav', GlkNav);
|
|
305
478
|
|
|
479
|
+
// Handed down to the native button, which is what assistive technology reads —
|
|
480
|
+
// <glk-popover> sets aria-expanded on its trigger.
|
|
481
|
+
const FORWARDED_ARIA$1 = ['aria-expanded', 'aria-haspopup', 'aria-pressed'];
|
|
482
|
+
|
|
306
483
|
class GlkPill extends GlkElement {
|
|
307
484
|
static get observedAttributes() {
|
|
308
|
-
return ['label', 'disabled'];
|
|
485
|
+
return ['label', 'disabled', ...FORWARDED_ARIA$1];
|
|
309
486
|
}
|
|
310
487
|
|
|
311
488
|
render() {
|
|
@@ -315,6 +492,7 @@ class GlkPill extends GlkElement {
|
|
|
315
492
|
|
|
316
493
|
const ariaLabel = this.getAttribute('label');
|
|
317
494
|
if (ariaLabel) this._btn.setAttribute('aria-label', ariaLabel);
|
|
495
|
+
for (const attr of FORWARDED_ARIA$1) this._forward(attr);
|
|
318
496
|
|
|
319
497
|
// Slotted content (SVG icons, text)
|
|
320
498
|
this._btn.appendChild(document.createElement('slot'));
|
|
@@ -343,8 +521,16 @@ class GlkPill extends GlkElement {
|
|
|
343
521
|
case 'disabled':
|
|
344
522
|
this._btn.disabled = this.getBoolAttr('disabled');
|
|
345
523
|
break;
|
|
524
|
+
default:
|
|
525
|
+
if (FORWARDED_ARIA$1.includes(name)) this._forward(name);
|
|
346
526
|
}
|
|
347
527
|
}
|
|
528
|
+
|
|
529
|
+
_forward(attr) {
|
|
530
|
+
const value = this.getAttribute(attr);
|
|
531
|
+
if (value === null) this._btn.removeAttribute(attr);
|
|
532
|
+
else this._btn.setAttribute(attr, value);
|
|
533
|
+
}
|
|
348
534
|
}
|
|
349
535
|
|
|
350
536
|
customElements.define('glk-pill', GlkPill);
|
|
@@ -1300,9 +1486,24 @@ customElements.define('glk-empty', GlkEmpty);
|
|
|
1300
1486
|
const VARIANTS$3 = ['primary', 'secondary', 'tertiary'];
|
|
1301
1487
|
const SIZES$1 = ['sm', 'md', 'lg', 'auto'];
|
|
1302
1488
|
|
|
1489
|
+
// States that whoever owns the element sets on it — <glk-popover> sets
|
|
1490
|
+
// aria-expanded on its trigger. Assistive technology reads the native button
|
|
1491
|
+
// inside, so they are handed down to it.
|
|
1492
|
+
const FORWARDED_ARIA = ['aria-expanded', 'aria-haspopup', 'aria-pressed'];
|
|
1493
|
+
|
|
1303
1494
|
class GlkButton extends GlkElement {
|
|
1304
1495
|
static get observedAttributes() {
|
|
1305
|
-
return ['variant', 'size', 'disabled', 'type'];
|
|
1496
|
+
return ['variant', 'size', 'disabled', 'type', ...FORWARDED_ARIA];
|
|
1497
|
+
}
|
|
1498
|
+
|
|
1499
|
+
// The native button sits in the shadow root, outside every form. Form
|
|
1500
|
+
// association gives the element its form, so type="submit" and "reset"
|
|
1501
|
+
// can act on it (see _activateForm).
|
|
1502
|
+
static formAssociated = true;
|
|
1503
|
+
|
|
1504
|
+
constructor() {
|
|
1505
|
+
super();
|
|
1506
|
+
this._internals = this.attachInternals();
|
|
1306
1507
|
}
|
|
1307
1508
|
|
|
1308
1509
|
render() {
|
|
@@ -1313,6 +1514,7 @@ class GlkButton extends GlkElement {
|
|
|
1313
1514
|
if (this.getBoolAttr('disabled')) {
|
|
1314
1515
|
this._btn.disabled = true;
|
|
1315
1516
|
}
|
|
1517
|
+
for (const attr of FORWARDED_ARIA) this._forward(attr);
|
|
1316
1518
|
|
|
1317
1519
|
this._btn.appendChild(document.createElement('slot'));
|
|
1318
1520
|
this._wrapper.appendChild(this._btn);
|
|
@@ -1326,12 +1528,50 @@ class GlkButton extends GlkElement {
|
|
|
1326
1528
|
return;
|
|
1327
1529
|
}
|
|
1328
1530
|
this.emit('glk-click');
|
|
1531
|
+
this._activateForm(e);
|
|
1329
1532
|
};
|
|
1330
1533
|
this._btn.addEventListener('click', this._onClick);
|
|
1534
|
+
// host.click() and a <label> for the element reach the host only.
|
|
1535
|
+
this._unforwardClicks = forwardHostClicks(this, () => this._btn);
|
|
1331
1536
|
}
|
|
1332
1537
|
|
|
1333
1538
|
teardownEvents() {
|
|
1334
1539
|
this._btn?.removeEventListener('click', this._onClick);
|
|
1540
|
+
this._unforwardClicks?.();
|
|
1541
|
+
}
|
|
1542
|
+
|
|
1543
|
+
/**
|
|
1544
|
+
* type="submit" submits the element's form, type="reset" resets it. Both
|
|
1545
|
+
* wait until the click has finished bubbling, so a listener that calls
|
|
1546
|
+
* preventDefault() on the click stops them — as on a native button.
|
|
1547
|
+
*/
|
|
1548
|
+
_activateForm(click) {
|
|
1549
|
+
const type = this.getAttribute('type');
|
|
1550
|
+
const form = this._internals.form;
|
|
1551
|
+
if (!form || (type !== 'submit' && type !== 'reset')) return;
|
|
1552
|
+
// Through the prototype: a control with id or name "reset" or
|
|
1553
|
+
// "requestSubmit" in the form shadows the methods on the form itself.
|
|
1554
|
+
const { reset, requestSubmit } = HTMLFormElement.prototype;
|
|
1555
|
+
setTimeout(() => {
|
|
1556
|
+
if (click.defaultPrevented || this._internals.form !== form) return;
|
|
1557
|
+
if (type === 'reset') {
|
|
1558
|
+
reset.call(form);
|
|
1559
|
+
return;
|
|
1560
|
+
}
|
|
1561
|
+
// requestSubmit() accepts native buttons only as the submitter, so the
|
|
1562
|
+
// submit event is told about this element instead. The listener goes
|
|
1563
|
+
// again right away: a form that fails validation fires no submit event,
|
|
1564
|
+
// and the next submit must not inherit this submitter.
|
|
1565
|
+
const nameSubmitter = (e) => {
|
|
1566
|
+
Object.defineProperty(e, 'submitter', { configurable: true, get: () => this });
|
|
1567
|
+
};
|
|
1568
|
+
form.addEventListener('submit', nameSubmitter, { capture: true });
|
|
1569
|
+
try {
|
|
1570
|
+
requestSubmit.call(form);
|
|
1571
|
+
} finally {
|
|
1572
|
+
form.removeEventListener('submit', nameSubmitter, { capture: true });
|
|
1573
|
+
}
|
|
1574
|
+
});
|
|
1335
1575
|
}
|
|
1336
1576
|
|
|
1337
1577
|
onAttributeChanged(name) {
|
|
@@ -1347,9 +1587,17 @@ class GlkButton extends GlkElement {
|
|
|
1347
1587
|
case 'type':
|
|
1348
1588
|
this._btn.setAttribute('type', this.getAttribute('type') || 'button');
|
|
1349
1589
|
break;
|
|
1590
|
+
default:
|
|
1591
|
+
if (FORWARDED_ARIA.includes(name)) this._forward(name);
|
|
1350
1592
|
}
|
|
1351
1593
|
}
|
|
1352
1594
|
|
|
1595
|
+
_forward(attr) {
|
|
1596
|
+
const value = this.getAttribute(attr);
|
|
1597
|
+
if (value === null) this._btn.removeAttribute(attr);
|
|
1598
|
+
else this._btn.setAttribute(attr, value);
|
|
1599
|
+
}
|
|
1600
|
+
|
|
1353
1601
|
_computeClasses() {
|
|
1354
1602
|
const classes = ['glass-btn'];
|
|
1355
1603
|
const variant = this.getAttribute('variant');
|
|
@@ -1371,6 +1619,11 @@ class GlkButton extends GlkElement {
|
|
|
1371
1619
|
|
|
1372
1620
|
get disabled() { return this.getBoolAttr('disabled'); }
|
|
1373
1621
|
set disabled(v) { this.setBoolAttr('disabled', v); }
|
|
1622
|
+
|
|
1623
|
+
get type() { return this.getAttribute('type') || 'button'; }
|
|
1624
|
+
set type(v) { this.setAttribute('type', v); }
|
|
1625
|
+
|
|
1626
|
+
get form() { return this._internals.form; }
|
|
1374
1627
|
}
|
|
1375
1628
|
|
|
1376
1629
|
customElements.define('glk-button', GlkButton);
|
|
@@ -1389,12 +1642,15 @@ class GlkInput extends GlkFormElement {
|
|
|
1389
1642
|
render() {
|
|
1390
1643
|
const group = this.createElement('div', ['glass-input-group']);
|
|
1391
1644
|
|
|
1392
|
-
// Label
|
|
1393
|
-
this.
|
|
1645
|
+
// Label — tied to the field by id, which only has to be unique inside
|
|
1646
|
+
// this shadow root. That gives the field its accessible name, and a click
|
|
1647
|
+
// on the label text focuses it.
|
|
1648
|
+
this._labelEl = this.createElement('label', ['glass-label'], { for: 'field' });
|
|
1394
1649
|
this._labelEl.textContent = this.getAttribute('label') || '';
|
|
1395
1650
|
|
|
1396
1651
|
// Input
|
|
1397
1652
|
this._input = this.createElement('input', this._computeInputClasses(), {
|
|
1653
|
+
id: 'field',
|
|
1398
1654
|
type: this.getAttribute('type') || 'text'
|
|
1399
1655
|
});
|
|
1400
1656
|
|
|
@@ -1411,8 +1667,8 @@ class GlkInput extends GlkFormElement {
|
|
|
1411
1667
|
if (this.getBoolAttr('required')) this._input.required = true;
|
|
1412
1668
|
for (const attr of FORWARDED) this._forward(attr);
|
|
1413
1669
|
|
|
1414
|
-
// Hint
|
|
1415
|
-
this._hintEl = this.createElement('span', this._computeHintClasses());
|
|
1670
|
+
// Hint — read out with the field as its description
|
|
1671
|
+
this._hintEl = this.createElement('span', this._computeHintClasses(), { id: 'hint' });
|
|
1416
1672
|
this._hintEl.textContent = this.getAttribute('hint') || '';
|
|
1417
1673
|
|
|
1418
1674
|
group.appendChild(this._labelEl);
|
|
@@ -1422,6 +1678,7 @@ class GlkInput extends GlkFormElement {
|
|
|
1422
1678
|
this._group = group;
|
|
1423
1679
|
this._wrapper.appendChild(group);
|
|
1424
1680
|
|
|
1681
|
+
this._applyDescription();
|
|
1425
1682
|
this._syncFormValue();
|
|
1426
1683
|
}
|
|
1427
1684
|
|
|
@@ -1459,12 +1716,14 @@ class GlkInput extends GlkFormElement {
|
|
|
1459
1716
|
case 'error':
|
|
1460
1717
|
this._input.className = this._computeInputClasses().join(' ');
|
|
1461
1718
|
this._hintEl.className = this._computeHintClasses().join(' ');
|
|
1719
|
+
this._applyDescription();
|
|
1462
1720
|
break;
|
|
1463
1721
|
case 'hint':
|
|
1464
1722
|
this._hintEl.textContent = this.getAttribute('hint') || '';
|
|
1465
1723
|
if (this.getAttribute('hint') && !this._hintEl.parentNode) {
|
|
1466
1724
|
this._group.appendChild(this._hintEl);
|
|
1467
1725
|
}
|
|
1726
|
+
this._applyDescription();
|
|
1468
1727
|
break;
|
|
1469
1728
|
case 'disabled':
|
|
1470
1729
|
this._input.disabled = this.getBoolAttr('disabled');
|
|
@@ -1484,6 +1743,19 @@ class GlkInput extends GlkFormElement {
|
|
|
1484
1743
|
}
|
|
1485
1744
|
}
|
|
1486
1745
|
|
|
1746
|
+
/**
|
|
1747
|
+
* The hint describes the field; with `error` set it is the error message
|
|
1748
|
+
* and the field is marked invalid. Server-side errors arrive this way, so
|
|
1749
|
+
* `error` stays a marker for assistive technology and does not block the
|
|
1750
|
+
* form — only the field's own constraints (required, pattern …) do.
|
|
1751
|
+
*/
|
|
1752
|
+
_applyDescription() {
|
|
1753
|
+
if (this.getAttribute('hint')) this._input.setAttribute('aria-describedby', 'hint');
|
|
1754
|
+
else this._input.removeAttribute('aria-describedby');
|
|
1755
|
+
if (this.getBoolAttr('error')) this._input.setAttribute('aria-invalid', 'true');
|
|
1756
|
+
else this._input.removeAttribute('aria-invalid');
|
|
1757
|
+
}
|
|
1758
|
+
|
|
1487
1759
|
_forward(attr) {
|
|
1488
1760
|
const value = this.getAttribute(attr);
|
|
1489
1761
|
if (value === null) this._input.removeAttribute(attr);
|
|
@@ -1502,6 +1774,8 @@ class GlkInput extends GlkFormElement {
|
|
|
1502
1774
|
return classes;
|
|
1503
1775
|
}
|
|
1504
1776
|
|
|
1777
|
+
get _validityField() { return this._input; }
|
|
1778
|
+
|
|
1505
1779
|
_syncFormValue() {
|
|
1506
1780
|
this.setFormValue(this._input.value);
|
|
1507
1781
|
}
|
|
@@ -1534,10 +1808,11 @@ class GlkTextarea extends GlkFormElement {
|
|
|
1534
1808
|
render() {
|
|
1535
1809
|
const group = this.createElement('div', ['glass-input-group']);
|
|
1536
1810
|
|
|
1537
|
-
this
|
|
1811
|
+
// Tied to the field by an id that only has to be unique in this shadow root.
|
|
1812
|
+
this._labelEl = this.createElement('label', ['glass-label'], { for: 'field' });
|
|
1538
1813
|
this._labelEl.textContent = this.getAttribute('label') || '';
|
|
1539
1814
|
|
|
1540
|
-
this._textarea = this.createElement('textarea', ['glass-textarea']);
|
|
1815
|
+
this._textarea = this.createElement('textarea', ['glass-textarea'], { id: 'field' });
|
|
1541
1816
|
const placeholder = this.getAttribute('placeholder');
|
|
1542
1817
|
if (placeholder) this._textarea.setAttribute('placeholder', placeholder);
|
|
1543
1818
|
|
|
@@ -1595,9 +1870,14 @@ class GlkTextarea extends GlkFormElement {
|
|
|
1595
1870
|
this._textarea.value = this.getAttribute('value') || '';
|
|
1596
1871
|
this._syncFormValue();
|
|
1597
1872
|
break;
|
|
1873
|
+
case 'required':
|
|
1874
|
+
this._textarea.required = this.getBoolAttr('required');
|
|
1875
|
+
break;
|
|
1598
1876
|
}
|
|
1599
1877
|
}
|
|
1600
1878
|
|
|
1879
|
+
get _validityField() { return this._textarea; }
|
|
1880
|
+
|
|
1601
1881
|
_syncFormValue() {
|
|
1602
1882
|
this.setFormValue(this._textarea.value);
|
|
1603
1883
|
}
|
|
@@ -1629,10 +1909,11 @@ class GlkSelect extends GlkFormElement {
|
|
|
1629
1909
|
render() {
|
|
1630
1910
|
const group = this.createElement('div', ['glass-input-group']);
|
|
1631
1911
|
|
|
1632
|
-
this
|
|
1912
|
+
// Tied to the field by an id that only has to be unique in this shadow root.
|
|
1913
|
+
this._labelEl = this.createElement('label', ['glass-label'], { for: 'field' });
|
|
1633
1914
|
this._labelEl.textContent = this.getAttribute('label') || '';
|
|
1634
1915
|
|
|
1635
|
-
this._select = this.createElement('select', ['glass-select']);
|
|
1916
|
+
this._select = this.createElement('select', ['glass-select'], { id: 'field' });
|
|
1636
1917
|
|
|
1637
1918
|
const name = this.getAttribute('name');
|
|
1638
1919
|
if (name) this._select.setAttribute('name', name);
|
|
@@ -1720,9 +2001,14 @@ class GlkSelect extends GlkFormElement {
|
|
|
1720
2001
|
this._applyValue(this.getAttribute('value'));
|
|
1721
2002
|
this._syncFormValue();
|
|
1722
2003
|
break;
|
|
2004
|
+
case 'required':
|
|
2005
|
+
this._select.required = this.getBoolAttr('required');
|
|
2006
|
+
break;
|
|
1723
2007
|
}
|
|
1724
2008
|
}
|
|
1725
2009
|
|
|
2010
|
+
get _validityField() { return this._select; }
|
|
2011
|
+
|
|
1726
2012
|
_syncFormValue() {
|
|
1727
2013
|
this.setFormValue(this._select.value);
|
|
1728
2014
|
}
|
|
@@ -1748,7 +2034,7 @@ const SEARCH_SVG = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" s
|
|
|
1748
2034
|
|
|
1749
2035
|
class GlkSearch extends GlkFormElement {
|
|
1750
2036
|
static get observedAttributes() {
|
|
1751
|
-
return ['placeholder', 'name', 'value', 'disabled'];
|
|
2037
|
+
return ['placeholder', 'name', 'value', 'disabled', 'label'];
|
|
1752
2038
|
}
|
|
1753
2039
|
|
|
1754
2040
|
render() {
|
|
@@ -1764,6 +2050,10 @@ class GlkSearch extends GlkFormElement {
|
|
|
1764
2050
|
const placeholder = this.getAttribute('placeholder');
|
|
1765
2051
|
if (placeholder) this._input.setAttribute('placeholder', placeholder);
|
|
1766
2052
|
|
|
2053
|
+
// The search field has no visible label; `label` names it for assistive
|
|
2054
|
+
// technology. Without it the placeholder is all a screen reader can say.
|
|
2055
|
+
this._applyLabel();
|
|
2056
|
+
|
|
1767
2057
|
const name = this.getAttribute('name');
|
|
1768
2058
|
if (name) this._input.setAttribute('name', name);
|
|
1769
2059
|
|
|
@@ -1808,9 +2098,18 @@ class GlkSearch extends GlkFormElement {
|
|
|
1808
2098
|
case 'disabled':
|
|
1809
2099
|
this._input.disabled = this.getBoolAttr('disabled');
|
|
1810
2100
|
break;
|
|
2101
|
+
case 'label':
|
|
2102
|
+
this._applyLabel();
|
|
2103
|
+
break;
|
|
1811
2104
|
}
|
|
1812
2105
|
}
|
|
1813
2106
|
|
|
2107
|
+
_applyLabel() {
|
|
2108
|
+
const label = this.getAttribute('label');
|
|
2109
|
+
if (label) this._input.setAttribute('aria-label', label);
|
|
2110
|
+
else this._input.removeAttribute('aria-label');
|
|
2111
|
+
}
|
|
2112
|
+
|
|
1814
2113
|
_syncFormValue() {
|
|
1815
2114
|
this.setFormValue(this._input.value);
|
|
1816
2115
|
}
|
|
@@ -1831,14 +2130,21 @@ customElements.define('glk-search', GlkSearch);
|
|
|
1831
2130
|
|
|
1832
2131
|
class GlkToggle extends GlkFormElement {
|
|
1833
2132
|
static get observedAttributes() {
|
|
1834
|
-
return ['checked', 'disabled', 'label', 'name', 'value'];
|
|
2133
|
+
return ['checked', 'disabled', 'label', 'name', 'value', 'required'];
|
|
1835
2134
|
}
|
|
1836
2135
|
|
|
2136
|
+
static get hostStyles() { return checkControlSheet; }
|
|
2137
|
+
|
|
1837
2138
|
render() {
|
|
1838
2139
|
const label = this.createElement('label', ['glass-toggle']);
|
|
1839
2140
|
|
|
2141
|
+
// The native checkbox is the switch: role, checked state and name (from
|
|
2142
|
+
// the label around it) all sit on one control. The host has no role of
|
|
2143
|
+
// its own — it used to carry role="switch" as well, and screen readers met
|
|
2144
|
+
// a switch with a checkbox inside.
|
|
1840
2145
|
this._input = this.createElement('input', ['glass-toggle__input'], {
|
|
1841
|
-
type: 'checkbox'
|
|
2146
|
+
type: 'checkbox',
|
|
2147
|
+
role: 'switch'
|
|
1842
2148
|
});
|
|
1843
2149
|
|
|
1844
2150
|
const name = this.getAttribute('name');
|
|
@@ -1857,14 +2163,12 @@ class GlkToggle extends GlkFormElement {
|
|
|
1857
2163
|
|
|
1858
2164
|
if (this.getBoolAttr('checked')) this._input.checked = true;
|
|
1859
2165
|
if (this.getBoolAttr('disabled')) this._input.disabled = true;
|
|
2166
|
+
if (this.getBoolAttr('required')) this._input.required = true;
|
|
1860
2167
|
|
|
1861
2168
|
this._defaultChecked = this.getBoolAttr('checked');
|
|
1862
2169
|
this._wrapper.appendChild(label);
|
|
1863
2170
|
|
|
1864
2171
|
this._syncFormValue();
|
|
1865
|
-
this.setAttribute('role', 'switch');
|
|
1866
|
-
this.setAttribute('aria-checked', String(this._input.checked));
|
|
1867
|
-
if (this.getBoolAttr('disabled')) this.setAttribute('aria-disabled', 'true');
|
|
1868
2172
|
}
|
|
1869
2173
|
|
|
1870
2174
|
setupEvents() {
|
|
@@ -1872,16 +2176,17 @@ class GlkToggle extends GlkFormElement {
|
|
|
1872
2176
|
this._syncing = true;
|
|
1873
2177
|
this.setBoolAttr('checked', this._input.checked);
|
|
1874
2178
|
this._syncing = false;
|
|
1875
|
-
this.setAttribute('aria-checked', String(this._input.checked));
|
|
1876
2179
|
this._syncFormValue();
|
|
1877
2180
|
this.emit('glk-change', { checked: this._input.checked });
|
|
1878
2181
|
this.dispatchEvent(new Event('change', { bubbles: true }));
|
|
1879
2182
|
};
|
|
1880
2183
|
this._input.addEventListener('change', this._onChange);
|
|
2184
|
+
this._unforwardClicks = forwardHostClicks(this, () => this._input);
|
|
1881
2185
|
}
|
|
1882
2186
|
|
|
1883
2187
|
teardownEvents() {
|
|
1884
2188
|
this._input?.removeEventListener('change', this._onChange);
|
|
2189
|
+
this._unforwardClicks?.();
|
|
1885
2190
|
}
|
|
1886
2191
|
|
|
1887
2192
|
onAttributeChanged(name) {
|
|
@@ -1890,12 +2195,10 @@ class GlkToggle extends GlkFormElement {
|
|
|
1890
2195
|
switch (name) {
|
|
1891
2196
|
case 'checked':
|
|
1892
2197
|
this._input.checked = this.getBoolAttr('checked');
|
|
1893
|
-
this.setAttribute('aria-checked', String(this._input.checked));
|
|
1894
2198
|
this._syncFormValue();
|
|
1895
2199
|
break;
|
|
1896
2200
|
case 'disabled':
|
|
1897
2201
|
this._input.disabled = this.getBoolAttr('disabled');
|
|
1898
|
-
this.setAttribute('aria-disabled', String(this.getBoolAttr('disabled')));
|
|
1899
2202
|
break;
|
|
1900
2203
|
case 'label':
|
|
1901
2204
|
this._labelEl.textContent = this.getAttribute('label') || '';
|
|
@@ -1903,9 +2206,14 @@ class GlkToggle extends GlkFormElement {
|
|
|
1903
2206
|
case 'name':
|
|
1904
2207
|
this._input.setAttribute('name', this.getAttribute('name') || '');
|
|
1905
2208
|
break;
|
|
2209
|
+
case 'required':
|
|
2210
|
+
this._input.required = this.getBoolAttr('required');
|
|
2211
|
+
break;
|
|
1906
2212
|
}
|
|
1907
2213
|
}
|
|
1908
2214
|
|
|
2215
|
+
get _validityField() { return this._input; }
|
|
2216
|
+
|
|
1909
2217
|
_syncFormValue() {
|
|
1910
2218
|
const val = this.getAttribute('value') || 'on';
|
|
1911
2219
|
this.setFormValue(this._input.checked ? val : null);
|
|
@@ -1914,7 +2222,6 @@ class GlkToggle extends GlkFormElement {
|
|
|
1914
2222
|
resetValue() {
|
|
1915
2223
|
this._input.checked = this._defaultChecked;
|
|
1916
2224
|
this.setBoolAttr('checked', this._defaultChecked);
|
|
1917
|
-
this.setAttribute('aria-checked', String(this._defaultChecked));
|
|
1918
2225
|
this._syncFormValue();
|
|
1919
2226
|
}
|
|
1920
2227
|
|
|
@@ -1929,7 +2236,6 @@ class GlkToggle extends GlkFormElement {
|
|
|
1929
2236
|
set checked(v) {
|
|
1930
2237
|
if (this._input) this._input.checked = v;
|
|
1931
2238
|
this.setBoolAttr('checked', v);
|
|
1932
|
-
this.setAttribute('aria-checked', String(v));
|
|
1933
2239
|
this._syncFormValue();
|
|
1934
2240
|
}
|
|
1935
2241
|
|
|
@@ -1952,9 +2258,11 @@ const CHECKMARK_SVG = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor
|
|
|
1952
2258
|
|
|
1953
2259
|
class GlkCheckbox extends GlkFormElement {
|
|
1954
2260
|
static get observedAttributes() {
|
|
1955
|
-
return ['checked', 'disabled', 'label', 'name', 'value'];
|
|
2261
|
+
return ['checked', 'disabled', 'label', 'name', 'value', 'required'];
|
|
1956
2262
|
}
|
|
1957
2263
|
|
|
2264
|
+
static get hostStyles() { return checkControlSheet; }
|
|
2265
|
+
|
|
1958
2266
|
render() {
|
|
1959
2267
|
const label = this.createElement('label', ['glass-checkbox']);
|
|
1960
2268
|
|
|
@@ -1977,6 +2285,7 @@ class GlkCheckbox extends GlkFormElement {
|
|
|
1977
2285
|
|
|
1978
2286
|
if (this.getBoolAttr('checked')) this._input.checked = true;
|
|
1979
2287
|
if (this.getBoolAttr('disabled')) this._input.disabled = true;
|
|
2288
|
+
if (this.getBoolAttr('required')) this._input.required = true;
|
|
1980
2289
|
|
|
1981
2290
|
this._defaultChecked = this.getBoolAttr('checked');
|
|
1982
2291
|
this._wrapper.appendChild(label);
|
|
@@ -1993,10 +2302,12 @@ class GlkCheckbox extends GlkFormElement {
|
|
|
1993
2302
|
this.dispatchEvent(new Event('change', { bubbles: true }));
|
|
1994
2303
|
};
|
|
1995
2304
|
this._input.addEventListener('change', this._onChange);
|
|
2305
|
+
this._unforwardClicks = forwardHostClicks(this, () => this._input);
|
|
1996
2306
|
}
|
|
1997
2307
|
|
|
1998
2308
|
teardownEvents() {
|
|
1999
2309
|
this._input?.removeEventListener('change', this._onChange);
|
|
2310
|
+
this._unforwardClicks?.();
|
|
2000
2311
|
}
|
|
2001
2312
|
|
|
2002
2313
|
onAttributeChanged(name) {
|
|
@@ -2016,9 +2327,14 @@ class GlkCheckbox extends GlkFormElement {
|
|
|
2016
2327
|
case 'name':
|
|
2017
2328
|
this._input.setAttribute('name', this.getAttribute('name') || '');
|
|
2018
2329
|
break;
|
|
2330
|
+
case 'required':
|
|
2331
|
+
this._input.required = this.getBoolAttr('required');
|
|
2332
|
+
break;
|
|
2019
2333
|
}
|
|
2020
2334
|
}
|
|
2021
2335
|
|
|
2336
|
+
get _validityField() { return this._input; }
|
|
2337
|
+
|
|
2022
2338
|
_syncFormValue() {
|
|
2023
2339
|
const val = this.getAttribute('value') || 'on';
|
|
2024
2340
|
this.setFormValue(this._input.checked ? val : null);
|
|
@@ -2078,9 +2394,11 @@ function syncGroupTabIndex(group) {
|
|
|
2078
2394
|
|
|
2079
2395
|
class GlkRadio extends GlkFormElement {
|
|
2080
2396
|
static get observedAttributes() {
|
|
2081
|
-
return ['checked', 'disabled', 'label', 'name', 'value'];
|
|
2397
|
+
return ['checked', 'disabled', 'label', 'name', 'value', 'required'];
|
|
2082
2398
|
}
|
|
2083
2399
|
|
|
2400
|
+
static get hostStyles() { return checkControlSheet; }
|
|
2401
|
+
|
|
2084
2402
|
render() {
|
|
2085
2403
|
const label = this.createElement('label', ['glass-radio']);
|
|
2086
2404
|
|
|
@@ -2135,11 +2453,13 @@ class GlkRadio extends GlkFormElement {
|
|
|
2135
2453
|
|
|
2136
2454
|
this._input.addEventListener('change', this._onChange);
|
|
2137
2455
|
this._input.addEventListener('keydown', this._onKeyDown);
|
|
2456
|
+
this._unforwardClicks = forwardHostClicks(this, () => this._input);
|
|
2138
2457
|
}
|
|
2139
2458
|
|
|
2140
2459
|
teardownEvents() {
|
|
2141
2460
|
this._input?.removeEventListener('change', this._onChange);
|
|
2142
2461
|
this._input?.removeEventListener('keydown', this._onKeyDown);
|
|
2462
|
+
this._unforwardClicks?.();
|
|
2143
2463
|
}
|
|
2144
2464
|
|
|
2145
2465
|
/** Shared by user change and arrow-key selection, so both look identical. */
|
|
@@ -2174,6 +2494,26 @@ class GlkRadio extends GlkFormElement {
|
|
|
2174
2494
|
}
|
|
2175
2495
|
}
|
|
2176
2496
|
|
|
2497
|
+
get _validityField() { return this._input; }
|
|
2498
|
+
|
|
2499
|
+
/**
|
|
2500
|
+
* Radios are missing a value as a group: one required radio makes the
|
|
2501
|
+
* whole group required, and any checked one satisfies it. Each input here
|
|
2502
|
+
* sits alone in its shadow root, so the group's verdict is worked out across
|
|
2503
|
+
* the elements and handed to every member. The inner input carries
|
|
2504
|
+
* `required` only while the group lacks a value — that way it produces the
|
|
2505
|
+
* browser's own message for it.
|
|
2506
|
+
*/
|
|
2507
|
+
syncValidity() {
|
|
2508
|
+
const group = this._group();
|
|
2509
|
+
const missing = group.some(el => el.hasAttribute('required')) && !group.some(el => el.checked);
|
|
2510
|
+
for (const el of group) {
|
|
2511
|
+
if (!el._input) continue; // not rendered yet; syncs when it is
|
|
2512
|
+
el._input.required = missing;
|
|
2513
|
+
super.syncValidity.call(el);
|
|
2514
|
+
}
|
|
2515
|
+
}
|
|
2516
|
+
|
|
2177
2517
|
onAttributeChanged(name) {
|
|
2178
2518
|
if (this._syncing) return;
|
|
2179
2519
|
if (!this._input) return;
|
|
@@ -2247,7 +2587,8 @@ class GlkRange extends GlkFormElement {
|
|
|
2247
2587
|
|
|
2248
2588
|
const header = this.createElement('div', ['glass-range-header']);
|
|
2249
2589
|
|
|
2250
|
-
this
|
|
2590
|
+
// Tied to the slider by an id that only has to be unique in this shadow root.
|
|
2591
|
+
this._labelEl = this.createElement('label', [], { for: 'field' });
|
|
2251
2592
|
this._labelEl.textContent = this.getAttribute('label') || '';
|
|
2252
2593
|
|
|
2253
2594
|
this._valueEl = this.createElement('span', ['glass-range-value']);
|
|
@@ -2256,6 +2597,7 @@ class GlkRange extends GlkFormElement {
|
|
|
2256
2597
|
header.appendChild(this._valueEl);
|
|
2257
2598
|
|
|
2258
2599
|
this._input = this.createElement('input', ['glass-range'], {
|
|
2600
|
+
id: 'field',
|
|
2259
2601
|
type: 'range',
|
|
2260
2602
|
min: this.getAttribute('min') || '0',
|
|
2261
2603
|
max: this.getAttribute('max') || '100',
|
|
@@ -2385,6 +2727,10 @@ function parseList(json) {
|
|
|
2385
2727
|
class GlkSegmented extends GlkFormElement {
|
|
2386
2728
|
static get observedAttributes() { return ['options', 'value', 'full', 'overflow', 'label']; }
|
|
2387
2729
|
|
|
2730
|
+
// A row of buttons with one tab stop: delegated focus would land on the
|
|
2731
|
+
// first button, not the chosen one.
|
|
2732
|
+
static get delegatesFocus() { return false; }
|
|
2733
|
+
|
|
2388
2734
|
render() {
|
|
2389
2735
|
this._group = this.createElement('div', ['glass-segmented'], { role: 'group', part: 'group' });
|
|
2390
2736
|
this._wrapper.appendChild(this._group);
|
|
@@ -2547,6 +2893,9 @@ class GlkCalendar extends GlkFormElement {
|
|
|
2547
2893
|
return ['month', 'value', 'today', 'min', 'max', 'marks', 'locale', 'week-start', 'label', 'prev-label', 'next-label'];
|
|
2548
2894
|
}
|
|
2549
2895
|
|
|
2896
|
+
// Delegated focus would land on the month arrow, not on the chosen day.
|
|
2897
|
+
static get delegatesFocus() { return false; }
|
|
2898
|
+
|
|
2550
2899
|
render() {
|
|
2551
2900
|
this._root = this.createElement('div', ['glass-calendar'], { part: 'calendar' });
|
|
2552
2901
|
const head = this.createElement('div', ['glass-calendar__head'], { part: 'head' });
|
|
@@ -3005,6 +3354,29 @@ class GlkProgress extends GlkElement {
|
|
|
3005
3354
|
|
|
3006
3355
|
customElements.define('glk-progress', GlkProgress);
|
|
3007
3356
|
|
|
3357
|
+
// Since 1.20.0 the overlay is a native <dialog>, opened with showModal(). The
|
|
3358
|
+
// browser then does what a modal needs: the dialog lies in the top layer, the
|
|
3359
|
+
// page behind it is inert — for the pointer, the keyboard and screen readers
|
|
3360
|
+
// alike — focus moves in on opening and goes back to where it came from on
|
|
3361
|
+
// closing, and the content is out of reach while the modal is closed.
|
|
3362
|
+
// GlassKit (1.20.0) styles dialog.glass-modal-overlay for this.
|
|
3363
|
+
//
|
|
3364
|
+
// The element keeps the fade: the dialog opens before .is-active is set and
|
|
3365
|
+
// closes only after the overlay has faded (safety net 400 ms; at once under
|
|
3366
|
+
// prefers-reduced-motion). Escape arrives as the dialog's cancel event and
|
|
3367
|
+
// takes the same path as a click on the dimmed area.
|
|
3368
|
+
//
|
|
3369
|
+
// Which element gets the focus on opening, the browsers decide differently:
|
|
3370
|
+
// Chrome takes the first field of the content, Safari the first action. An
|
|
3371
|
+
// element marked autofocus — in the content or among the actions — settles
|
|
3372
|
+
// it in both.
|
|
3373
|
+
|
|
3374
|
+
const CLOSE_FALLBACK_MS = 400;
|
|
3375
|
+
|
|
3376
|
+
function reducedMotion$1() {
|
|
3377
|
+
return typeof matchMedia === 'function' && matchMedia('(prefers-reduced-motion: reduce)').matches;
|
|
3378
|
+
}
|
|
3379
|
+
|
|
3008
3380
|
class GlkModal extends GlkElement {
|
|
3009
3381
|
static get observedAttributes() {
|
|
3010
3382
|
return ['open', 'title'];
|
|
@@ -3013,13 +3385,13 @@ class GlkModal extends GlkElement {
|
|
|
3013
3385
|
static get observesLightDom() { return true; }
|
|
3014
3386
|
|
|
3015
3387
|
render() {
|
|
3016
|
-
this._overlay = this.createElement('
|
|
3388
|
+
this._overlay = this.createElement('dialog', ['glass-modal-overlay'], { part: 'overlay' });
|
|
3017
3389
|
|
|
3018
3390
|
const modal = this.createElement('div', ['glass-modal'], { part: 'modal' });
|
|
3019
3391
|
|
|
3020
|
-
// Header
|
|
3392
|
+
// Header — the title names the dialog
|
|
3021
3393
|
const header = this.createElement('div', ['glass-modal__header'], { part: 'header' });
|
|
3022
|
-
this._titleEl = this.createElement('h2', ['glass-modal__title']);
|
|
3394
|
+
this._titleEl = this.createElement('h2', ['glass-modal__title'], { id: 'title' });
|
|
3023
3395
|
this.takeTitle();
|
|
3024
3396
|
this._applyTitle();
|
|
3025
3397
|
header.appendChild(this._titleEl);
|
|
@@ -3040,10 +3412,8 @@ class GlkModal extends GlkElement {
|
|
|
3040
3412
|
|
|
3041
3413
|
this._overlay.appendChild(modal);
|
|
3042
3414
|
this._wrapper.appendChild(this._overlay);
|
|
3043
|
-
|
|
3044
|
-
|
|
3045
|
-
this._overlay.classList.add('is-active');
|
|
3046
|
-
}
|
|
3415
|
+
// `open` is applied in setupEvents, which also runs when a moved element
|
|
3416
|
+
// comes back.
|
|
3047
3417
|
}
|
|
3048
3418
|
|
|
3049
3419
|
projectLightDom() {
|
|
@@ -3068,33 +3438,49 @@ class GlkModal extends GlkElement {
|
|
|
3068
3438
|
setupEvents() {
|
|
3069
3439
|
// Close on overlay click (outside modal)
|
|
3070
3440
|
this._onOverlayClick = (e) => {
|
|
3071
|
-
if (e.target === this._overlay)
|
|
3072
|
-
this.removeAttribute('open');
|
|
3073
|
-
this.emit('glk-close');
|
|
3074
|
-
}
|
|
3441
|
+
if (e.target === this._overlay) this._dismiss();
|
|
3075
3442
|
};
|
|
3076
3443
|
this._overlay.addEventListener('click', this._onOverlayClick);
|
|
3077
3444
|
|
|
3078
|
-
//
|
|
3079
|
-
this.
|
|
3080
|
-
|
|
3081
|
-
|
|
3082
|
-
this.emit('glk-close');
|
|
3083
|
-
}
|
|
3445
|
+
// Escape: the dialog would close at once; it fades out like a click outside.
|
|
3446
|
+
this._onCancel = (e) => {
|
|
3447
|
+
e.preventDefault();
|
|
3448
|
+
this._dismiss();
|
|
3084
3449
|
};
|
|
3085
|
-
|
|
3450
|
+
this._overlay.addEventListener('cancel', this._onCancel);
|
|
3451
|
+
|
|
3452
|
+
// The browser may also close the dialog by itself — Chrome does on a
|
|
3453
|
+
// second Escape without user activation in between, skipping cancel.
|
|
3454
|
+
this._onClose = () => {
|
|
3455
|
+
if (this._overlay.open) return; // a late event from an earlier close
|
|
3456
|
+
this._overlay.classList.remove('is-active');
|
|
3457
|
+
if (this.open) this._dismiss();
|
|
3458
|
+
};
|
|
3459
|
+
this._overlay.addEventListener('close', this._onClose);
|
|
3460
|
+
|
|
3461
|
+
if (this.open) this._show();
|
|
3086
3462
|
}
|
|
3087
3463
|
|
|
3088
3464
|
teardownEvents() {
|
|
3089
3465
|
this._overlay?.removeEventListener('click', this._onOverlayClick);
|
|
3090
|
-
|
|
3466
|
+
this._overlay?.removeEventListener('cancel', this._onCancel);
|
|
3467
|
+
this._overlay?.removeEventListener('close', this._onClose);
|
|
3468
|
+
// Taken out of the document, the dialog leaves the top layer but stays
|
|
3469
|
+
// open — shown in place, not modal. Closed now, it opens as a modal again
|
|
3470
|
+
// when the element comes back.
|
|
3471
|
+
clearTimeout(this._closeTimer);
|
|
3472
|
+
this._overlay?.removeEventListener('transitionend', this._onFaded);
|
|
3473
|
+
this._overlay?.classList.remove('is-active');
|
|
3474
|
+
if (this._overlay?.open) this._overlay.close();
|
|
3091
3475
|
}
|
|
3092
3476
|
|
|
3093
3477
|
onAttributeChanged(name, _old, value) {
|
|
3094
3478
|
if (!this._overlay) return;
|
|
3095
3479
|
switch (name) {
|
|
3096
3480
|
case 'open':
|
|
3097
|
-
|
|
3481
|
+
if (!this.isConnected) return; // setupEvents applies it on connect
|
|
3482
|
+
if (this.open) this._show();
|
|
3483
|
+
else this._hide();
|
|
3098
3484
|
break;
|
|
3099
3485
|
case 'title':
|
|
3100
3486
|
if (this.takeTitle(value)) this._applyTitle();
|
|
@@ -3102,11 +3488,52 @@ class GlkModal extends GlkElement {
|
|
|
3102
3488
|
}
|
|
3103
3489
|
}
|
|
3104
3490
|
|
|
3491
|
+
_show() {
|
|
3492
|
+
const dialog = this._overlay;
|
|
3493
|
+
clearTimeout(this._closeTimer);
|
|
3494
|
+
dialog.removeEventListener('transitionend', this._onFaded);
|
|
3495
|
+
if (!dialog.open) {
|
|
3496
|
+
dialog.showModal();
|
|
3497
|
+
// The actions are copies in the shadow root; the originals are not shown.
|
|
3498
|
+
(this._footer.querySelector('[autofocus]') || this.querySelector('[autofocus]'))?.focus();
|
|
3499
|
+
}
|
|
3500
|
+
void dialog.offsetHeight; // reflow, so the fade starts from the closed state
|
|
3501
|
+
requestAnimationFrame(() => {
|
|
3502
|
+
if (this.open) dialog.classList.add('is-active');
|
|
3503
|
+
});
|
|
3504
|
+
}
|
|
3505
|
+
|
|
3506
|
+
_hide() {
|
|
3507
|
+
const dialog = this._overlay;
|
|
3508
|
+
dialog.classList.remove('is-active');
|
|
3509
|
+
this._onFaded = (event) => {
|
|
3510
|
+
if (event && event.target !== dialog) return; // the panel's own transition
|
|
3511
|
+
clearTimeout(this._closeTimer);
|
|
3512
|
+
dialog.removeEventListener('transitionend', this._onFaded);
|
|
3513
|
+
if (!this.open && dialog.open) dialog.close();
|
|
3514
|
+
};
|
|
3515
|
+
if (!dialog.open || reducedMotion$1()) {
|
|
3516
|
+
this._onFaded();
|
|
3517
|
+
return;
|
|
3518
|
+
}
|
|
3519
|
+
dialog.addEventListener('transitionend', this._onFaded);
|
|
3520
|
+
this._closeTimer = setTimeout(this._onFaded, CLOSE_FALLBACK_MS);
|
|
3521
|
+
}
|
|
3522
|
+
|
|
3523
|
+
/** Closed by the user — a click outside, Escape. */
|
|
3524
|
+
_dismiss() {
|
|
3525
|
+
this.removeAttribute('open');
|
|
3526
|
+
this.emit('glk-close');
|
|
3527
|
+
}
|
|
3528
|
+
|
|
3105
3529
|
show() { this.setAttribute('open', ''); }
|
|
3106
3530
|
close() { this.removeAttribute('open'); }
|
|
3107
3531
|
|
|
3108
3532
|
_applyTitle() {
|
|
3109
|
-
if (this._titleEl)
|
|
3533
|
+
if (!this._titleEl) return;
|
|
3534
|
+
this._titleEl.textContent = this._title || '';
|
|
3535
|
+
if (this._title) this._overlay.setAttribute('aria-labelledby', 'title');
|
|
3536
|
+
else this._overlay.removeAttribute('aria-labelledby');
|
|
3110
3537
|
}
|
|
3111
3538
|
|
|
3112
3539
|
// `title` is the heading, never a tooltip — see GlkElement.takeTitle().
|
|
@@ -3398,9 +3825,9 @@ class GlkPopover extends GlkElement {
|
|
|
3398
3825
|
render() {
|
|
3399
3826
|
this._anchor = this.createElement('div', ['glass-popover-anchor']);
|
|
3400
3827
|
|
|
3401
|
-
|
|
3402
|
-
|
|
3403
|
-
this._anchor.appendChild(
|
|
3828
|
+
this._triggerSlot = document.createElement('slot');
|
|
3829
|
+
this._triggerSlot.setAttribute('name', 'trigger');
|
|
3830
|
+
this._anchor.appendChild(this._triggerSlot);
|
|
3404
3831
|
|
|
3405
3832
|
this._popover = this.createElement('div', ['glass-popover']);
|
|
3406
3833
|
this._applyPlacement();
|
|
@@ -3424,7 +3851,23 @@ class GlkPopover extends GlkElement {
|
|
|
3424
3851
|
}
|
|
3425
3852
|
}
|
|
3426
3853
|
|
|
3854
|
+
/**
|
|
3855
|
+
* The trigger says whether the popover is open. It lives in the light DOM,
|
|
3856
|
+
* so aria-expanded goes on it directly; <glk-button> and <glk-pill> hand
|
|
3857
|
+
* it on to their native button. Runs again when the trigger is swapped.
|
|
3858
|
+
*/
|
|
3859
|
+
_applyExpanded() {
|
|
3860
|
+
const open = String(this.getBoolAttr('open'));
|
|
3861
|
+
for (const trigger of this._triggerSlot.assignedElements()) {
|
|
3862
|
+
trigger.setAttribute('aria-expanded', open);
|
|
3863
|
+
}
|
|
3864
|
+
}
|
|
3865
|
+
|
|
3427
3866
|
setupEvents() {
|
|
3867
|
+
this._onSlotChange = () => this._applyExpanded();
|
|
3868
|
+
this._triggerSlot.addEventListener('slotchange', this._onSlotChange);
|
|
3869
|
+
this._applyExpanded();
|
|
3870
|
+
|
|
3428
3871
|
// Toggle when the slotted trigger is clicked.
|
|
3429
3872
|
this._onTriggerClick = (e) => {
|
|
3430
3873
|
const path = e.composedPath();
|
|
@@ -3456,6 +3899,7 @@ class GlkPopover extends GlkElement {
|
|
|
3456
3899
|
}
|
|
3457
3900
|
|
|
3458
3901
|
teardownEvents() {
|
|
3902
|
+
this._triggerSlot?.removeEventListener('slotchange', this._onSlotChange);
|
|
3459
3903
|
this.removeEventListener('click', this._onTriggerClick);
|
|
3460
3904
|
document.removeEventListener('click', this._onDocClick);
|
|
3461
3905
|
document.removeEventListener('keydown', this._onKeydown);
|
|
@@ -3467,6 +3911,7 @@ class GlkPopover extends GlkElement {
|
|
|
3467
3911
|
case 'open': {
|
|
3468
3912
|
const isOpen = this.getBoolAttr('open');
|
|
3469
3913
|
this._popover.classList.toggle('is-open', isOpen);
|
|
3914
|
+
this._applyExpanded();
|
|
3470
3915
|
this.emit(isOpen ? 'glk-open' : 'glk-close');
|
|
3471
3916
|
break;
|
|
3472
3917
|
}
|
|
@@ -3659,17 +4104,19 @@ class GlkAccordionItem extends GlkElement {
|
|
|
3659
4104
|
|
|
3660
4105
|
render() {
|
|
3661
4106
|
this._item = this.createElement('div', ['glass-accordion__item']);
|
|
3662
|
-
if (this.getBoolAttr('open')) this._item.classList.add('is-open');
|
|
3663
4107
|
|
|
3664
|
-
// Trigger button
|
|
3665
|
-
this._trigger = this.createElement('button', ['glass-accordion__trigger']
|
|
4108
|
+
// Trigger button — says whether its section is open, and which one it is
|
|
4109
|
+
this._trigger = this.createElement('button', ['glass-accordion__trigger'], {
|
|
4110
|
+
type: 'button',
|
|
4111
|
+
'aria-controls': 'content'
|
|
4112
|
+
});
|
|
3666
4113
|
this.takeTitle();
|
|
3667
4114
|
this._triggerText = document.createTextNode(this._title || '');
|
|
3668
4115
|
this._trigger.appendChild(this._triggerText);
|
|
3669
4116
|
this._trigger.insertAdjacentHTML('beforeend', CHEVRON_SVG);
|
|
3670
4117
|
|
|
3671
4118
|
// Content
|
|
3672
|
-
this._content = this.createElement('div', ['glass-accordion__content']);
|
|
4119
|
+
this._content = this.createElement('div', ['glass-accordion__content'], { id: 'content' });
|
|
3673
4120
|
const body = this.createElement('div', ['glass-accordion__body']);
|
|
3674
4121
|
body.appendChild(document.createElement('slot'));
|
|
3675
4122
|
this._content.appendChild(body);
|
|
@@ -3678,6 +4125,19 @@ class GlkAccordionItem extends GlkElement {
|
|
|
3678
4125
|
this._item.appendChild(this._content);
|
|
3679
4126
|
|
|
3680
4127
|
this._wrapper.appendChild(this._item);
|
|
4128
|
+
this._applyOpen();
|
|
4129
|
+
}
|
|
4130
|
+
|
|
4131
|
+
/**
|
|
4132
|
+
* A closed section is only squeezed to zero height; its links and fields
|
|
4133
|
+
* stayed in the tab order. inert takes them out, and out of the
|
|
4134
|
+
* accessibility tree, until the section opens.
|
|
4135
|
+
*/
|
|
4136
|
+
_applyOpen() {
|
|
4137
|
+
const open = this.getBoolAttr('open');
|
|
4138
|
+
this._item.classList.toggle('is-open', open);
|
|
4139
|
+
this._trigger.setAttribute('aria-expanded', String(open));
|
|
4140
|
+
this._content.inert = !open;
|
|
3681
4141
|
}
|
|
3682
4142
|
|
|
3683
4143
|
setupEvents() {
|
|
@@ -3696,7 +4156,7 @@ class GlkAccordionItem extends GlkElement {
|
|
|
3696
4156
|
if (!this._item) return;
|
|
3697
4157
|
switch (name) {
|
|
3698
4158
|
case 'open':
|
|
3699
|
-
this.
|
|
4159
|
+
this._applyOpen();
|
|
3700
4160
|
break;
|
|
3701
4161
|
case 'title':
|
|
3702
4162
|
if (this.takeTitle(value)) this._applyTitle();
|