@jungherz-de/glasskit-elements 1.19.2 → 1.20.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 +27 -0
- package/README.md +40 -27
- package/SKILL.md +105 -23
- package/dist/components/base.js +145 -10
- 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 +487 -65
- package/dist/glasskit-elements.js +487 -65
- package/dist/glasskit-elements.min.js +1 -1
- package/package.json +3 -3
- package/src/base.js +144 -9
- 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.20.0 – Constructable Stylesheet
|
|
2
2
|
// Auto-generated by build-styles-js.mjs – do not edit manually.
|
|
3
3
|
|
|
4
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)}";
|
|
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-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)}";
|
|
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: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-inline-start: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-inline-start: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: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-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:52px;height:30px;margin:0;font:inherit;margin-top:max(0px,calc((1lh - 30px)/ 2))}.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__thumb:dir(rtl){left:auto;right:3px}.glass-toggle__input:checked+.glass-toggle__track .glass-toggle__thumb:dir(rtl){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__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:24px;height:24px;margin:0;font:inherit;margin-top:max(0px,calc((1lh - 24px)/ 2))}.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;z-index:1;opacity:0;cursor:inherit;width:24px;height:24px;margin:0;font:inherit;margin-top:max(0px,calc((1lh - 24px)/ 2))}.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-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: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-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: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,18 +31,44 @@ 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();
|
|
@@ -65,31 +91,94 @@ function syncAllThemes() {
|
|
|
65
91
|
}
|
|
66
92
|
|
|
67
93
|
if (typeof window !== 'undefined' && typeof MutationObserver !== 'undefined') {
|
|
68
|
-
const observer = new MutationObserver(
|
|
94
|
+
const observer = new MutationObserver(records => {
|
|
95
|
+
if (records.some(r => r.attributeName === 'data-theme')) syncAllThemes();
|
|
96
|
+
if (records.some(r => r.attributeName === DEFAULTS_ATTR)) syncDefaultTokens();
|
|
97
|
+
});
|
|
69
98
|
observer.observe(document.documentElement, {
|
|
70
99
|
attributes: true,
|
|
71
|
-
attributeFilter: ['data-theme']
|
|
100
|
+
attributeFilter: ['data-theme', DEFAULTS_ATTR]
|
|
72
101
|
});
|
|
73
102
|
}
|
|
74
103
|
|
|
75
104
|
// ── Host Stylesheet ──
|
|
76
105
|
// Sets display:block on all custom elements by default.
|
|
77
106
|
// Inline components (badge, avatar) override this.
|
|
107
|
+
//
|
|
108
|
+
// The wrapper carries the theme's color-scheme, so native parts inside the
|
|
109
|
+
// elements — a select's list, a date picker, scrollbars — match the element,
|
|
110
|
+
// whatever the page around it uses.
|
|
111
|
+
|
|
112
|
+
const wrapperRules = `
|
|
113
|
+
.glk-wrapper { display: contents; }
|
|
114
|
+
.glk-wrapper[data-theme="dark"] { color-scheme: dark; }
|
|
115
|
+
.glk-wrapper[data-theme="light"] { color-scheme: light; }
|
|
116
|
+
`;
|
|
78
117
|
|
|
79
118
|
const hostSheet = new CSSStyleSheet();
|
|
80
119
|
hostSheet.replaceSync(`
|
|
81
120
|
:host { display: block; }
|
|
82
121
|
:host([hidden]) { display: none; }
|
|
83
|
-
|
|
122
|
+
${wrapperRules}
|
|
84
123
|
`);
|
|
85
124
|
|
|
86
125
|
const inlineHostSheet = new CSSStyleSheet();
|
|
87
126
|
inlineHostSheet.replaceSync(`
|
|
88
127
|
:host { display: inline-block; }
|
|
89
128
|
:host([hidden]) { display: none; }
|
|
90
|
-
|
|
129
|
+
${wrapperRules}
|
|
91
130
|
`);
|
|
92
131
|
|
|
132
|
+
/**
|
|
133
|
+
* Host rules for glk-checkbox, glk-radio and glk-toggle. Their control is an
|
|
134
|
+
* inline-flex label inside a block host; sitting on the text baseline it left
|
|
135
|
+
* room for descenders below, so the host was about 4px taller than the
|
|
136
|
+
* control and the control sat high in a centred row. Aligned to the top of
|
|
137
|
+
* its line, the label is as tall as the host.
|
|
138
|
+
*/
|
|
139
|
+
const checkControlSheet = new CSSStyleSheet();
|
|
140
|
+
checkControlSheet.replaceSync(`
|
|
141
|
+
.glass-checkbox, .glass-radio, .glass-toggle { vertical-align: top; }
|
|
142
|
+
`);
|
|
143
|
+
|
|
144
|
+
// ── Clicks Aimed at the Host ──
|
|
145
|
+
// The innermost target of the latest pointerdown anywhere in the document;
|
|
146
|
+
// tracked once, on first use.
|
|
147
|
+
let lastPressed = null;
|
|
148
|
+
let trackingPresses = false;
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* For elements whose control is a native input or button inside the shadow
|
|
152
|
+
* root: glk-checkbox, glk-radio, glk-toggle, glk-button. A click aimed at the
|
|
153
|
+
* host itself — host.click(), or the click a <label> around the element or
|
|
154
|
+
* naming it dispatches — reaches only the host. The control never saw it, so
|
|
155
|
+
* nothing changed where a native checkbox toggles and a native button
|
|
156
|
+
* submits. Such a click is handed to the control; the original is stopped, so
|
|
157
|
+
* listeners see one click, the control's.
|
|
158
|
+
*
|
|
159
|
+
* A pointer press on the host's own empty box (the host is a block, the
|
|
160
|
+
* control is narrower) also lands on the host. Chrome cannot tell it apart
|
|
161
|
+
* from a label's click by the event, only by where the pointer went down; it
|
|
162
|
+
* stays a no-op, as before. Returns the teardown.
|
|
163
|
+
*/
|
|
164
|
+
function forwardHostClicks(host, getField) {
|
|
165
|
+
if (!trackingPresses && typeof window !== 'undefined') {
|
|
166
|
+
trackingPresses = true;
|
|
167
|
+
window.addEventListener('pointerdown', e => { lastPressed = e.composedPath()[0]; },
|
|
168
|
+
{ capture: true, passive: true });
|
|
169
|
+
}
|
|
170
|
+
const onClick = (e) => {
|
|
171
|
+
if (e.composedPath()[0] !== host) return; // from inside: the input had it
|
|
172
|
+
if (e.isTrusted && lastPressed === host) return; // a press on the empty box
|
|
173
|
+
const field = getField();
|
|
174
|
+
if (!field || field.disabled) return;
|
|
175
|
+
e.stopImmediatePropagation();
|
|
176
|
+
field.click();
|
|
177
|
+
};
|
|
178
|
+
host.addEventListener('click', onClick);
|
|
179
|
+
return () => host.removeEventListener('click', onClick);
|
|
180
|
+
}
|
|
181
|
+
|
|
93
182
|
// ── Base Class ──
|
|
94
183
|
|
|
95
184
|
class GlkElement extends HTMLElement {
|
|
@@ -112,6 +201,13 @@ class GlkElement extends HTMLElement {
|
|
|
112
201
|
*/
|
|
113
202
|
static get observesLightDom() { return false; }
|
|
114
203
|
|
|
204
|
+
/**
|
|
205
|
+
* Turned on by elements built around one native field: focus() on the
|
|
206
|
+
* host, a click on the label text and a <label for> outside all land in
|
|
207
|
+
* that field.
|
|
208
|
+
*/
|
|
209
|
+
static get delegatesFocus() { return false; }
|
|
210
|
+
|
|
115
211
|
static get observedAttributes() {
|
|
116
212
|
return [];
|
|
117
213
|
}
|
|
@@ -119,7 +215,7 @@ class GlkElement extends HTMLElement {
|
|
|
119
215
|
constructor() {
|
|
120
216
|
super();
|
|
121
217
|
this._initialized = false;
|
|
122
|
-
this._shadow = this.attachShadow({ mode: 'open' });
|
|
218
|
+
this._shadow = this.attachShadow({ mode: 'open', delegatesFocus: this.constructor.delegatesFocus });
|
|
123
219
|
const displaySheet = this.constructor.displayInline ? inlineHostSheet : hostSheet;
|
|
124
220
|
const sheets = [componentsSheet, displaySheet];
|
|
125
221
|
const extra = this.constructor.hostStyles;
|
|
@@ -260,14 +356,26 @@ class GlkFormElement extends GlkElement {
|
|
|
260
356
|
|
|
261
357
|
static formAssociated = true;
|
|
262
358
|
|
|
359
|
+
// One native field inside, so focus goes there. The button groups
|
|
360
|
+
// (glk-segmented, glk-calendar) turn this off again: their first button is
|
|
361
|
+
// not the chosen one.
|
|
362
|
+
static get delegatesFocus() { return true; }
|
|
363
|
+
|
|
263
364
|
constructor() {
|
|
264
365
|
super();
|
|
265
366
|
this._internals = this.attachInternals();
|
|
266
367
|
}
|
|
267
368
|
|
|
369
|
+
attributeChangedCallback(name, oldValue, newValue) {
|
|
370
|
+
super.attributeChangedCallback(name, oldValue, newValue);
|
|
371
|
+
// required, min, pattern, type … all change what counts as valid.
|
|
372
|
+
if (this._initialized) this.syncValidity();
|
|
373
|
+
}
|
|
374
|
+
|
|
268
375
|
get form() { return this._internals.form; }
|
|
269
376
|
get validationMessage() { return this._internals.validationMessage; }
|
|
270
377
|
get validity() { return this._internals.validity; }
|
|
378
|
+
get willValidate() { return this._internals.willValidate; }
|
|
271
379
|
|
|
272
380
|
checkValidity() { return this._internals.checkValidity(); }
|
|
273
381
|
reportValidity() { return this._internals.reportValidity(); }
|
|
@@ -286,11 +394,38 @@ class GlkFormElement extends GlkElement {
|
|
|
286
394
|
|
|
287
395
|
setFormValue(value) {
|
|
288
396
|
this._internals.setFormValue(value);
|
|
397
|
+
this.syncValidity();
|
|
289
398
|
}
|
|
290
399
|
|
|
291
400
|
setValidity(flags, message, anchor) {
|
|
292
401
|
this._internals.setValidity(flags, message, anchor);
|
|
293
402
|
}
|
|
403
|
+
|
|
404
|
+
/**
|
|
405
|
+
* The native field whose constraint validation the host reports, or null.
|
|
406
|
+
* Subclasses built around one field return it.
|
|
407
|
+
*/
|
|
408
|
+
get _validityField() { return null; }
|
|
409
|
+
|
|
410
|
+
/**
|
|
411
|
+
* A form asks the host — checkValidity(), reportValidity(), submitting — and
|
|
412
|
+
* the host knows nothing by itself, so the inner field's verdict is copied
|
|
413
|
+
* over after everything that can change it: a value (every setFormValue
|
|
414
|
+
* lands here), an attribute, a reset. The field is the anchor: the browser's
|
|
415
|
+
* bubble points at it, and reportValidity() focuses it.
|
|
416
|
+
*/
|
|
417
|
+
syncValidity() {
|
|
418
|
+
const field = this._validityField;
|
|
419
|
+
if (!field) return;
|
|
420
|
+
const message = field.validationMessage;
|
|
421
|
+
// A field barred from validation (disabled) can still carry flags, but
|
|
422
|
+
// it has no message, and setValidity() refuses flags without one.
|
|
423
|
+
if (!field.willValidate || field.validity.valid || !message) {
|
|
424
|
+
this._internals.setValidity({});
|
|
425
|
+
} else {
|
|
426
|
+
this._internals.setValidity(field.validity, message, field);
|
|
427
|
+
}
|
|
428
|
+
}
|
|
294
429
|
}
|
|
295
430
|
|
|
296
431
|
class GlkNav extends GlkElement {
|
|
@@ -303,9 +438,13 @@ class GlkNav extends GlkElement {
|
|
|
303
438
|
|
|
304
439
|
customElements.define('glk-nav', GlkNav);
|
|
305
440
|
|
|
441
|
+
// Handed down to the native button, which is what assistive technology reads —
|
|
442
|
+
// <glk-popover> sets aria-expanded on its trigger.
|
|
443
|
+
const FORWARDED_ARIA$1 = ['aria-expanded', 'aria-haspopup', 'aria-pressed'];
|
|
444
|
+
|
|
306
445
|
class GlkPill extends GlkElement {
|
|
307
446
|
static get observedAttributes() {
|
|
308
|
-
return ['label', 'disabled'];
|
|
447
|
+
return ['label', 'disabled', ...FORWARDED_ARIA$1];
|
|
309
448
|
}
|
|
310
449
|
|
|
311
450
|
render() {
|
|
@@ -315,6 +454,7 @@ class GlkPill extends GlkElement {
|
|
|
315
454
|
|
|
316
455
|
const ariaLabel = this.getAttribute('label');
|
|
317
456
|
if (ariaLabel) this._btn.setAttribute('aria-label', ariaLabel);
|
|
457
|
+
for (const attr of FORWARDED_ARIA$1) this._forward(attr);
|
|
318
458
|
|
|
319
459
|
// Slotted content (SVG icons, text)
|
|
320
460
|
this._btn.appendChild(document.createElement('slot'));
|
|
@@ -343,8 +483,16 @@ class GlkPill extends GlkElement {
|
|
|
343
483
|
case 'disabled':
|
|
344
484
|
this._btn.disabled = this.getBoolAttr('disabled');
|
|
345
485
|
break;
|
|
486
|
+
default:
|
|
487
|
+
if (FORWARDED_ARIA$1.includes(name)) this._forward(name);
|
|
346
488
|
}
|
|
347
489
|
}
|
|
490
|
+
|
|
491
|
+
_forward(attr) {
|
|
492
|
+
const value = this.getAttribute(attr);
|
|
493
|
+
if (value === null) this._btn.removeAttribute(attr);
|
|
494
|
+
else this._btn.setAttribute(attr, value);
|
|
495
|
+
}
|
|
348
496
|
}
|
|
349
497
|
|
|
350
498
|
customElements.define('glk-pill', GlkPill);
|
|
@@ -1300,9 +1448,24 @@ customElements.define('glk-empty', GlkEmpty);
|
|
|
1300
1448
|
const VARIANTS$3 = ['primary', 'secondary', 'tertiary'];
|
|
1301
1449
|
const SIZES$1 = ['sm', 'md', 'lg', 'auto'];
|
|
1302
1450
|
|
|
1451
|
+
// States that whoever owns the element sets on it — <glk-popover> sets
|
|
1452
|
+
// aria-expanded on its trigger. Assistive technology reads the native button
|
|
1453
|
+
// inside, so they are handed down to it.
|
|
1454
|
+
const FORWARDED_ARIA = ['aria-expanded', 'aria-haspopup', 'aria-pressed'];
|
|
1455
|
+
|
|
1303
1456
|
class GlkButton extends GlkElement {
|
|
1304
1457
|
static get observedAttributes() {
|
|
1305
|
-
return ['variant', 'size', 'disabled', 'type'];
|
|
1458
|
+
return ['variant', 'size', 'disabled', 'type', ...FORWARDED_ARIA];
|
|
1459
|
+
}
|
|
1460
|
+
|
|
1461
|
+
// The native button sits in the shadow root, outside every form. Form
|
|
1462
|
+
// association gives the element its form, so type="submit" and "reset"
|
|
1463
|
+
// can act on it (see _activateForm).
|
|
1464
|
+
static formAssociated = true;
|
|
1465
|
+
|
|
1466
|
+
constructor() {
|
|
1467
|
+
super();
|
|
1468
|
+
this._internals = this.attachInternals();
|
|
1306
1469
|
}
|
|
1307
1470
|
|
|
1308
1471
|
render() {
|
|
@@ -1313,6 +1476,7 @@ class GlkButton extends GlkElement {
|
|
|
1313
1476
|
if (this.getBoolAttr('disabled')) {
|
|
1314
1477
|
this._btn.disabled = true;
|
|
1315
1478
|
}
|
|
1479
|
+
for (const attr of FORWARDED_ARIA) this._forward(attr);
|
|
1316
1480
|
|
|
1317
1481
|
this._btn.appendChild(document.createElement('slot'));
|
|
1318
1482
|
this._wrapper.appendChild(this._btn);
|
|
@@ -1326,12 +1490,50 @@ class GlkButton extends GlkElement {
|
|
|
1326
1490
|
return;
|
|
1327
1491
|
}
|
|
1328
1492
|
this.emit('glk-click');
|
|
1493
|
+
this._activateForm(e);
|
|
1329
1494
|
};
|
|
1330
1495
|
this._btn.addEventListener('click', this._onClick);
|
|
1496
|
+
// host.click() and a <label> for the element reach the host only.
|
|
1497
|
+
this._unforwardClicks = forwardHostClicks(this, () => this._btn);
|
|
1331
1498
|
}
|
|
1332
1499
|
|
|
1333
1500
|
teardownEvents() {
|
|
1334
1501
|
this._btn?.removeEventListener('click', this._onClick);
|
|
1502
|
+
this._unforwardClicks?.();
|
|
1503
|
+
}
|
|
1504
|
+
|
|
1505
|
+
/**
|
|
1506
|
+
* type="submit" submits the element's form, type="reset" resets it. Both
|
|
1507
|
+
* wait until the click has finished bubbling, so a listener that calls
|
|
1508
|
+
* preventDefault() on the click stops them — as on a native button.
|
|
1509
|
+
*/
|
|
1510
|
+
_activateForm(click) {
|
|
1511
|
+
const type = this.getAttribute('type');
|
|
1512
|
+
const form = this._internals.form;
|
|
1513
|
+
if (!form || (type !== 'submit' && type !== 'reset')) return;
|
|
1514
|
+
// Through the prototype: a control with id or name "reset" or
|
|
1515
|
+
// "requestSubmit" in the form shadows the methods on the form itself.
|
|
1516
|
+
const { reset, requestSubmit } = HTMLFormElement.prototype;
|
|
1517
|
+
setTimeout(() => {
|
|
1518
|
+
if (click.defaultPrevented || this._internals.form !== form) return;
|
|
1519
|
+
if (type === 'reset') {
|
|
1520
|
+
reset.call(form);
|
|
1521
|
+
return;
|
|
1522
|
+
}
|
|
1523
|
+
// requestSubmit() accepts native buttons only as the submitter, so the
|
|
1524
|
+
// submit event is told about this element instead. The listener goes
|
|
1525
|
+
// again right away: a form that fails validation fires no submit event,
|
|
1526
|
+
// and the next submit must not inherit this submitter.
|
|
1527
|
+
const nameSubmitter = (e) => {
|
|
1528
|
+
Object.defineProperty(e, 'submitter', { configurable: true, get: () => this });
|
|
1529
|
+
};
|
|
1530
|
+
form.addEventListener('submit', nameSubmitter, { capture: true });
|
|
1531
|
+
try {
|
|
1532
|
+
requestSubmit.call(form);
|
|
1533
|
+
} finally {
|
|
1534
|
+
form.removeEventListener('submit', nameSubmitter, { capture: true });
|
|
1535
|
+
}
|
|
1536
|
+
});
|
|
1335
1537
|
}
|
|
1336
1538
|
|
|
1337
1539
|
onAttributeChanged(name) {
|
|
@@ -1347,9 +1549,17 @@ class GlkButton extends GlkElement {
|
|
|
1347
1549
|
case 'type':
|
|
1348
1550
|
this._btn.setAttribute('type', this.getAttribute('type') || 'button');
|
|
1349
1551
|
break;
|
|
1552
|
+
default:
|
|
1553
|
+
if (FORWARDED_ARIA.includes(name)) this._forward(name);
|
|
1350
1554
|
}
|
|
1351
1555
|
}
|
|
1352
1556
|
|
|
1557
|
+
_forward(attr) {
|
|
1558
|
+
const value = this.getAttribute(attr);
|
|
1559
|
+
if (value === null) this._btn.removeAttribute(attr);
|
|
1560
|
+
else this._btn.setAttribute(attr, value);
|
|
1561
|
+
}
|
|
1562
|
+
|
|
1353
1563
|
_computeClasses() {
|
|
1354
1564
|
const classes = ['glass-btn'];
|
|
1355
1565
|
const variant = this.getAttribute('variant');
|
|
@@ -1371,6 +1581,11 @@ class GlkButton extends GlkElement {
|
|
|
1371
1581
|
|
|
1372
1582
|
get disabled() { return this.getBoolAttr('disabled'); }
|
|
1373
1583
|
set disabled(v) { this.setBoolAttr('disabled', v); }
|
|
1584
|
+
|
|
1585
|
+
get type() { return this.getAttribute('type') || 'button'; }
|
|
1586
|
+
set type(v) { this.setAttribute('type', v); }
|
|
1587
|
+
|
|
1588
|
+
get form() { return this._internals.form; }
|
|
1374
1589
|
}
|
|
1375
1590
|
|
|
1376
1591
|
customElements.define('glk-button', GlkButton);
|
|
@@ -1389,12 +1604,15 @@ class GlkInput extends GlkFormElement {
|
|
|
1389
1604
|
render() {
|
|
1390
1605
|
const group = this.createElement('div', ['glass-input-group']);
|
|
1391
1606
|
|
|
1392
|
-
// Label
|
|
1393
|
-
this.
|
|
1607
|
+
// Label — tied to the field by id, which only has to be unique inside
|
|
1608
|
+
// this shadow root. That gives the field its accessible name, and a click
|
|
1609
|
+
// on the label text focuses it.
|
|
1610
|
+
this._labelEl = this.createElement('label', ['glass-label'], { for: 'field' });
|
|
1394
1611
|
this._labelEl.textContent = this.getAttribute('label') || '';
|
|
1395
1612
|
|
|
1396
1613
|
// Input
|
|
1397
1614
|
this._input = this.createElement('input', this._computeInputClasses(), {
|
|
1615
|
+
id: 'field',
|
|
1398
1616
|
type: this.getAttribute('type') || 'text'
|
|
1399
1617
|
});
|
|
1400
1618
|
|
|
@@ -1411,8 +1629,8 @@ class GlkInput extends GlkFormElement {
|
|
|
1411
1629
|
if (this.getBoolAttr('required')) this._input.required = true;
|
|
1412
1630
|
for (const attr of FORWARDED) this._forward(attr);
|
|
1413
1631
|
|
|
1414
|
-
// Hint
|
|
1415
|
-
this._hintEl = this.createElement('span', this._computeHintClasses());
|
|
1632
|
+
// Hint — read out with the field as its description
|
|
1633
|
+
this._hintEl = this.createElement('span', this._computeHintClasses(), { id: 'hint' });
|
|
1416
1634
|
this._hintEl.textContent = this.getAttribute('hint') || '';
|
|
1417
1635
|
|
|
1418
1636
|
group.appendChild(this._labelEl);
|
|
@@ -1422,6 +1640,7 @@ class GlkInput extends GlkFormElement {
|
|
|
1422
1640
|
this._group = group;
|
|
1423
1641
|
this._wrapper.appendChild(group);
|
|
1424
1642
|
|
|
1643
|
+
this._applyDescription();
|
|
1425
1644
|
this._syncFormValue();
|
|
1426
1645
|
}
|
|
1427
1646
|
|
|
@@ -1459,12 +1678,14 @@ class GlkInput extends GlkFormElement {
|
|
|
1459
1678
|
case 'error':
|
|
1460
1679
|
this._input.className = this._computeInputClasses().join(' ');
|
|
1461
1680
|
this._hintEl.className = this._computeHintClasses().join(' ');
|
|
1681
|
+
this._applyDescription();
|
|
1462
1682
|
break;
|
|
1463
1683
|
case 'hint':
|
|
1464
1684
|
this._hintEl.textContent = this.getAttribute('hint') || '';
|
|
1465
1685
|
if (this.getAttribute('hint') && !this._hintEl.parentNode) {
|
|
1466
1686
|
this._group.appendChild(this._hintEl);
|
|
1467
1687
|
}
|
|
1688
|
+
this._applyDescription();
|
|
1468
1689
|
break;
|
|
1469
1690
|
case 'disabled':
|
|
1470
1691
|
this._input.disabled = this.getBoolAttr('disabled');
|
|
@@ -1484,6 +1705,19 @@ class GlkInput extends GlkFormElement {
|
|
|
1484
1705
|
}
|
|
1485
1706
|
}
|
|
1486
1707
|
|
|
1708
|
+
/**
|
|
1709
|
+
* The hint describes the field; with `error` set it is the error message
|
|
1710
|
+
* and the field is marked invalid. Server-side errors arrive this way, so
|
|
1711
|
+
* `error` stays a marker for assistive technology and does not block the
|
|
1712
|
+
* form — only the field's own constraints (required, pattern …) do.
|
|
1713
|
+
*/
|
|
1714
|
+
_applyDescription() {
|
|
1715
|
+
if (this.getAttribute('hint')) this._input.setAttribute('aria-describedby', 'hint');
|
|
1716
|
+
else this._input.removeAttribute('aria-describedby');
|
|
1717
|
+
if (this.getBoolAttr('error')) this._input.setAttribute('aria-invalid', 'true');
|
|
1718
|
+
else this._input.removeAttribute('aria-invalid');
|
|
1719
|
+
}
|
|
1720
|
+
|
|
1487
1721
|
_forward(attr) {
|
|
1488
1722
|
const value = this.getAttribute(attr);
|
|
1489
1723
|
if (value === null) this._input.removeAttribute(attr);
|
|
@@ -1502,6 +1736,8 @@ class GlkInput extends GlkFormElement {
|
|
|
1502
1736
|
return classes;
|
|
1503
1737
|
}
|
|
1504
1738
|
|
|
1739
|
+
get _validityField() { return this._input; }
|
|
1740
|
+
|
|
1505
1741
|
_syncFormValue() {
|
|
1506
1742
|
this.setFormValue(this._input.value);
|
|
1507
1743
|
}
|
|
@@ -1534,10 +1770,11 @@ class GlkTextarea extends GlkFormElement {
|
|
|
1534
1770
|
render() {
|
|
1535
1771
|
const group = this.createElement('div', ['glass-input-group']);
|
|
1536
1772
|
|
|
1537
|
-
this
|
|
1773
|
+
// Tied to the field by an id that only has to be unique in this shadow root.
|
|
1774
|
+
this._labelEl = this.createElement('label', ['glass-label'], { for: 'field' });
|
|
1538
1775
|
this._labelEl.textContent = this.getAttribute('label') || '';
|
|
1539
1776
|
|
|
1540
|
-
this._textarea = this.createElement('textarea', ['glass-textarea']);
|
|
1777
|
+
this._textarea = this.createElement('textarea', ['glass-textarea'], { id: 'field' });
|
|
1541
1778
|
const placeholder = this.getAttribute('placeholder');
|
|
1542
1779
|
if (placeholder) this._textarea.setAttribute('placeholder', placeholder);
|
|
1543
1780
|
|
|
@@ -1595,9 +1832,14 @@ class GlkTextarea extends GlkFormElement {
|
|
|
1595
1832
|
this._textarea.value = this.getAttribute('value') || '';
|
|
1596
1833
|
this._syncFormValue();
|
|
1597
1834
|
break;
|
|
1835
|
+
case 'required':
|
|
1836
|
+
this._textarea.required = this.getBoolAttr('required');
|
|
1837
|
+
break;
|
|
1598
1838
|
}
|
|
1599
1839
|
}
|
|
1600
1840
|
|
|
1841
|
+
get _validityField() { return this._textarea; }
|
|
1842
|
+
|
|
1601
1843
|
_syncFormValue() {
|
|
1602
1844
|
this.setFormValue(this._textarea.value);
|
|
1603
1845
|
}
|
|
@@ -1629,10 +1871,11 @@ class GlkSelect extends GlkFormElement {
|
|
|
1629
1871
|
render() {
|
|
1630
1872
|
const group = this.createElement('div', ['glass-input-group']);
|
|
1631
1873
|
|
|
1632
|
-
this
|
|
1874
|
+
// Tied to the field by an id that only has to be unique in this shadow root.
|
|
1875
|
+
this._labelEl = this.createElement('label', ['glass-label'], { for: 'field' });
|
|
1633
1876
|
this._labelEl.textContent = this.getAttribute('label') || '';
|
|
1634
1877
|
|
|
1635
|
-
this._select = this.createElement('select', ['glass-select']);
|
|
1878
|
+
this._select = this.createElement('select', ['glass-select'], { id: 'field' });
|
|
1636
1879
|
|
|
1637
1880
|
const name = this.getAttribute('name');
|
|
1638
1881
|
if (name) this._select.setAttribute('name', name);
|
|
@@ -1720,9 +1963,14 @@ class GlkSelect extends GlkFormElement {
|
|
|
1720
1963
|
this._applyValue(this.getAttribute('value'));
|
|
1721
1964
|
this._syncFormValue();
|
|
1722
1965
|
break;
|
|
1966
|
+
case 'required':
|
|
1967
|
+
this._select.required = this.getBoolAttr('required');
|
|
1968
|
+
break;
|
|
1723
1969
|
}
|
|
1724
1970
|
}
|
|
1725
1971
|
|
|
1972
|
+
get _validityField() { return this._select; }
|
|
1973
|
+
|
|
1726
1974
|
_syncFormValue() {
|
|
1727
1975
|
this.setFormValue(this._select.value);
|
|
1728
1976
|
}
|
|
@@ -1748,7 +1996,7 @@ const SEARCH_SVG = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" s
|
|
|
1748
1996
|
|
|
1749
1997
|
class GlkSearch extends GlkFormElement {
|
|
1750
1998
|
static get observedAttributes() {
|
|
1751
|
-
return ['placeholder', 'name', 'value', 'disabled'];
|
|
1999
|
+
return ['placeholder', 'name', 'value', 'disabled', 'label'];
|
|
1752
2000
|
}
|
|
1753
2001
|
|
|
1754
2002
|
render() {
|
|
@@ -1764,6 +2012,10 @@ class GlkSearch extends GlkFormElement {
|
|
|
1764
2012
|
const placeholder = this.getAttribute('placeholder');
|
|
1765
2013
|
if (placeholder) this._input.setAttribute('placeholder', placeholder);
|
|
1766
2014
|
|
|
2015
|
+
// The search field has no visible label; `label` names it for assistive
|
|
2016
|
+
// technology. Without it the placeholder is all a screen reader can say.
|
|
2017
|
+
this._applyLabel();
|
|
2018
|
+
|
|
1767
2019
|
const name = this.getAttribute('name');
|
|
1768
2020
|
if (name) this._input.setAttribute('name', name);
|
|
1769
2021
|
|
|
@@ -1808,9 +2060,18 @@ class GlkSearch extends GlkFormElement {
|
|
|
1808
2060
|
case 'disabled':
|
|
1809
2061
|
this._input.disabled = this.getBoolAttr('disabled');
|
|
1810
2062
|
break;
|
|
2063
|
+
case 'label':
|
|
2064
|
+
this._applyLabel();
|
|
2065
|
+
break;
|
|
1811
2066
|
}
|
|
1812
2067
|
}
|
|
1813
2068
|
|
|
2069
|
+
_applyLabel() {
|
|
2070
|
+
const label = this.getAttribute('label');
|
|
2071
|
+
if (label) this._input.setAttribute('aria-label', label);
|
|
2072
|
+
else this._input.removeAttribute('aria-label');
|
|
2073
|
+
}
|
|
2074
|
+
|
|
1814
2075
|
_syncFormValue() {
|
|
1815
2076
|
this.setFormValue(this._input.value);
|
|
1816
2077
|
}
|
|
@@ -1831,14 +2092,21 @@ customElements.define('glk-search', GlkSearch);
|
|
|
1831
2092
|
|
|
1832
2093
|
class GlkToggle extends GlkFormElement {
|
|
1833
2094
|
static get observedAttributes() {
|
|
1834
|
-
return ['checked', 'disabled', 'label', 'name', 'value'];
|
|
2095
|
+
return ['checked', 'disabled', 'label', 'name', 'value', 'required'];
|
|
1835
2096
|
}
|
|
1836
2097
|
|
|
2098
|
+
static get hostStyles() { return checkControlSheet; }
|
|
2099
|
+
|
|
1837
2100
|
render() {
|
|
1838
2101
|
const label = this.createElement('label', ['glass-toggle']);
|
|
1839
2102
|
|
|
2103
|
+
// The native checkbox is the switch: role, checked state and name (from
|
|
2104
|
+
// the label around it) all sit on one control. The host has no role of
|
|
2105
|
+
// its own — it used to carry role="switch" as well, and screen readers met
|
|
2106
|
+
// a switch with a checkbox inside.
|
|
1840
2107
|
this._input = this.createElement('input', ['glass-toggle__input'], {
|
|
1841
|
-
type: 'checkbox'
|
|
2108
|
+
type: 'checkbox',
|
|
2109
|
+
role: 'switch'
|
|
1842
2110
|
});
|
|
1843
2111
|
|
|
1844
2112
|
const name = this.getAttribute('name');
|
|
@@ -1857,14 +2125,12 @@ class GlkToggle extends GlkFormElement {
|
|
|
1857
2125
|
|
|
1858
2126
|
if (this.getBoolAttr('checked')) this._input.checked = true;
|
|
1859
2127
|
if (this.getBoolAttr('disabled')) this._input.disabled = true;
|
|
2128
|
+
if (this.getBoolAttr('required')) this._input.required = true;
|
|
1860
2129
|
|
|
1861
2130
|
this._defaultChecked = this.getBoolAttr('checked');
|
|
1862
2131
|
this._wrapper.appendChild(label);
|
|
1863
2132
|
|
|
1864
2133
|
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
2134
|
}
|
|
1869
2135
|
|
|
1870
2136
|
setupEvents() {
|
|
@@ -1872,16 +2138,17 @@ class GlkToggle extends GlkFormElement {
|
|
|
1872
2138
|
this._syncing = true;
|
|
1873
2139
|
this.setBoolAttr('checked', this._input.checked);
|
|
1874
2140
|
this._syncing = false;
|
|
1875
|
-
this.setAttribute('aria-checked', String(this._input.checked));
|
|
1876
2141
|
this._syncFormValue();
|
|
1877
2142
|
this.emit('glk-change', { checked: this._input.checked });
|
|
1878
2143
|
this.dispatchEvent(new Event('change', { bubbles: true }));
|
|
1879
2144
|
};
|
|
1880
2145
|
this._input.addEventListener('change', this._onChange);
|
|
2146
|
+
this._unforwardClicks = forwardHostClicks(this, () => this._input);
|
|
1881
2147
|
}
|
|
1882
2148
|
|
|
1883
2149
|
teardownEvents() {
|
|
1884
2150
|
this._input?.removeEventListener('change', this._onChange);
|
|
2151
|
+
this._unforwardClicks?.();
|
|
1885
2152
|
}
|
|
1886
2153
|
|
|
1887
2154
|
onAttributeChanged(name) {
|
|
@@ -1890,12 +2157,10 @@ class GlkToggle extends GlkFormElement {
|
|
|
1890
2157
|
switch (name) {
|
|
1891
2158
|
case 'checked':
|
|
1892
2159
|
this._input.checked = this.getBoolAttr('checked');
|
|
1893
|
-
this.setAttribute('aria-checked', String(this._input.checked));
|
|
1894
2160
|
this._syncFormValue();
|
|
1895
2161
|
break;
|
|
1896
2162
|
case 'disabled':
|
|
1897
2163
|
this._input.disabled = this.getBoolAttr('disabled');
|
|
1898
|
-
this.setAttribute('aria-disabled', String(this.getBoolAttr('disabled')));
|
|
1899
2164
|
break;
|
|
1900
2165
|
case 'label':
|
|
1901
2166
|
this._labelEl.textContent = this.getAttribute('label') || '';
|
|
@@ -1903,9 +2168,14 @@ class GlkToggle extends GlkFormElement {
|
|
|
1903
2168
|
case 'name':
|
|
1904
2169
|
this._input.setAttribute('name', this.getAttribute('name') || '');
|
|
1905
2170
|
break;
|
|
2171
|
+
case 'required':
|
|
2172
|
+
this._input.required = this.getBoolAttr('required');
|
|
2173
|
+
break;
|
|
1906
2174
|
}
|
|
1907
2175
|
}
|
|
1908
2176
|
|
|
2177
|
+
get _validityField() { return this._input; }
|
|
2178
|
+
|
|
1909
2179
|
_syncFormValue() {
|
|
1910
2180
|
const val = this.getAttribute('value') || 'on';
|
|
1911
2181
|
this.setFormValue(this._input.checked ? val : null);
|
|
@@ -1914,7 +2184,6 @@ class GlkToggle extends GlkFormElement {
|
|
|
1914
2184
|
resetValue() {
|
|
1915
2185
|
this._input.checked = this._defaultChecked;
|
|
1916
2186
|
this.setBoolAttr('checked', this._defaultChecked);
|
|
1917
|
-
this.setAttribute('aria-checked', String(this._defaultChecked));
|
|
1918
2187
|
this._syncFormValue();
|
|
1919
2188
|
}
|
|
1920
2189
|
|
|
@@ -1929,7 +2198,6 @@ class GlkToggle extends GlkFormElement {
|
|
|
1929
2198
|
set checked(v) {
|
|
1930
2199
|
if (this._input) this._input.checked = v;
|
|
1931
2200
|
this.setBoolAttr('checked', v);
|
|
1932
|
-
this.setAttribute('aria-checked', String(v));
|
|
1933
2201
|
this._syncFormValue();
|
|
1934
2202
|
}
|
|
1935
2203
|
|
|
@@ -1952,9 +2220,11 @@ const CHECKMARK_SVG = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor
|
|
|
1952
2220
|
|
|
1953
2221
|
class GlkCheckbox extends GlkFormElement {
|
|
1954
2222
|
static get observedAttributes() {
|
|
1955
|
-
return ['checked', 'disabled', 'label', 'name', 'value'];
|
|
2223
|
+
return ['checked', 'disabled', 'label', 'name', 'value', 'required'];
|
|
1956
2224
|
}
|
|
1957
2225
|
|
|
2226
|
+
static get hostStyles() { return checkControlSheet; }
|
|
2227
|
+
|
|
1958
2228
|
render() {
|
|
1959
2229
|
const label = this.createElement('label', ['glass-checkbox']);
|
|
1960
2230
|
|
|
@@ -1977,6 +2247,7 @@ class GlkCheckbox extends GlkFormElement {
|
|
|
1977
2247
|
|
|
1978
2248
|
if (this.getBoolAttr('checked')) this._input.checked = true;
|
|
1979
2249
|
if (this.getBoolAttr('disabled')) this._input.disabled = true;
|
|
2250
|
+
if (this.getBoolAttr('required')) this._input.required = true;
|
|
1980
2251
|
|
|
1981
2252
|
this._defaultChecked = this.getBoolAttr('checked');
|
|
1982
2253
|
this._wrapper.appendChild(label);
|
|
@@ -1993,10 +2264,12 @@ class GlkCheckbox extends GlkFormElement {
|
|
|
1993
2264
|
this.dispatchEvent(new Event('change', { bubbles: true }));
|
|
1994
2265
|
};
|
|
1995
2266
|
this._input.addEventListener('change', this._onChange);
|
|
2267
|
+
this._unforwardClicks = forwardHostClicks(this, () => this._input);
|
|
1996
2268
|
}
|
|
1997
2269
|
|
|
1998
2270
|
teardownEvents() {
|
|
1999
2271
|
this._input?.removeEventListener('change', this._onChange);
|
|
2272
|
+
this._unforwardClicks?.();
|
|
2000
2273
|
}
|
|
2001
2274
|
|
|
2002
2275
|
onAttributeChanged(name) {
|
|
@@ -2016,9 +2289,14 @@ class GlkCheckbox extends GlkFormElement {
|
|
|
2016
2289
|
case 'name':
|
|
2017
2290
|
this._input.setAttribute('name', this.getAttribute('name') || '');
|
|
2018
2291
|
break;
|
|
2292
|
+
case 'required':
|
|
2293
|
+
this._input.required = this.getBoolAttr('required');
|
|
2294
|
+
break;
|
|
2019
2295
|
}
|
|
2020
2296
|
}
|
|
2021
2297
|
|
|
2298
|
+
get _validityField() { return this._input; }
|
|
2299
|
+
|
|
2022
2300
|
_syncFormValue() {
|
|
2023
2301
|
const val = this.getAttribute('value') || 'on';
|
|
2024
2302
|
this.setFormValue(this._input.checked ? val : null);
|
|
@@ -2078,9 +2356,11 @@ function syncGroupTabIndex(group) {
|
|
|
2078
2356
|
|
|
2079
2357
|
class GlkRadio extends GlkFormElement {
|
|
2080
2358
|
static get observedAttributes() {
|
|
2081
|
-
return ['checked', 'disabled', 'label', 'name', 'value'];
|
|
2359
|
+
return ['checked', 'disabled', 'label', 'name', 'value', 'required'];
|
|
2082
2360
|
}
|
|
2083
2361
|
|
|
2362
|
+
static get hostStyles() { return checkControlSheet; }
|
|
2363
|
+
|
|
2084
2364
|
render() {
|
|
2085
2365
|
const label = this.createElement('label', ['glass-radio']);
|
|
2086
2366
|
|
|
@@ -2135,11 +2415,13 @@ class GlkRadio extends GlkFormElement {
|
|
|
2135
2415
|
|
|
2136
2416
|
this._input.addEventListener('change', this._onChange);
|
|
2137
2417
|
this._input.addEventListener('keydown', this._onKeyDown);
|
|
2418
|
+
this._unforwardClicks = forwardHostClicks(this, () => this._input);
|
|
2138
2419
|
}
|
|
2139
2420
|
|
|
2140
2421
|
teardownEvents() {
|
|
2141
2422
|
this._input?.removeEventListener('change', this._onChange);
|
|
2142
2423
|
this._input?.removeEventListener('keydown', this._onKeyDown);
|
|
2424
|
+
this._unforwardClicks?.();
|
|
2143
2425
|
}
|
|
2144
2426
|
|
|
2145
2427
|
/** Shared by user change and arrow-key selection, so both look identical. */
|
|
@@ -2174,6 +2456,26 @@ class GlkRadio extends GlkFormElement {
|
|
|
2174
2456
|
}
|
|
2175
2457
|
}
|
|
2176
2458
|
|
|
2459
|
+
get _validityField() { return this._input; }
|
|
2460
|
+
|
|
2461
|
+
/**
|
|
2462
|
+
* Radios are missing a value as a group: one required radio makes the
|
|
2463
|
+
* whole group required, and any checked one satisfies it. Each input here
|
|
2464
|
+
* sits alone in its shadow root, so the group's verdict is worked out across
|
|
2465
|
+
* the elements and handed to every member. The inner input carries
|
|
2466
|
+
* `required` only while the group lacks a value — that way it produces the
|
|
2467
|
+
* browser's own message for it.
|
|
2468
|
+
*/
|
|
2469
|
+
syncValidity() {
|
|
2470
|
+
const group = this._group();
|
|
2471
|
+
const missing = group.some(el => el.hasAttribute('required')) && !group.some(el => el.checked);
|
|
2472
|
+
for (const el of group) {
|
|
2473
|
+
if (!el._input) continue; // not rendered yet; syncs when it is
|
|
2474
|
+
el._input.required = missing;
|
|
2475
|
+
super.syncValidity.call(el);
|
|
2476
|
+
}
|
|
2477
|
+
}
|
|
2478
|
+
|
|
2177
2479
|
onAttributeChanged(name) {
|
|
2178
2480
|
if (this._syncing) return;
|
|
2179
2481
|
if (!this._input) return;
|
|
@@ -2247,7 +2549,8 @@ class GlkRange extends GlkFormElement {
|
|
|
2247
2549
|
|
|
2248
2550
|
const header = this.createElement('div', ['glass-range-header']);
|
|
2249
2551
|
|
|
2250
|
-
this
|
|
2552
|
+
// Tied to the slider by an id that only has to be unique in this shadow root.
|
|
2553
|
+
this._labelEl = this.createElement('label', [], { for: 'field' });
|
|
2251
2554
|
this._labelEl.textContent = this.getAttribute('label') || '';
|
|
2252
2555
|
|
|
2253
2556
|
this._valueEl = this.createElement('span', ['glass-range-value']);
|
|
@@ -2256,6 +2559,7 @@ class GlkRange extends GlkFormElement {
|
|
|
2256
2559
|
header.appendChild(this._valueEl);
|
|
2257
2560
|
|
|
2258
2561
|
this._input = this.createElement('input', ['glass-range'], {
|
|
2562
|
+
id: 'field',
|
|
2259
2563
|
type: 'range',
|
|
2260
2564
|
min: this.getAttribute('min') || '0',
|
|
2261
2565
|
max: this.getAttribute('max') || '100',
|
|
@@ -2385,6 +2689,10 @@ function parseList(json) {
|
|
|
2385
2689
|
class GlkSegmented extends GlkFormElement {
|
|
2386
2690
|
static get observedAttributes() { return ['options', 'value', 'full', 'overflow', 'label']; }
|
|
2387
2691
|
|
|
2692
|
+
// A row of buttons with one tab stop: delegated focus would land on the
|
|
2693
|
+
// first button, not the chosen one.
|
|
2694
|
+
static get delegatesFocus() { return false; }
|
|
2695
|
+
|
|
2388
2696
|
render() {
|
|
2389
2697
|
this._group = this.createElement('div', ['glass-segmented'], { role: 'group', part: 'group' });
|
|
2390
2698
|
this._wrapper.appendChild(this._group);
|
|
@@ -2547,6 +2855,9 @@ class GlkCalendar extends GlkFormElement {
|
|
|
2547
2855
|
return ['month', 'value', 'today', 'min', 'max', 'marks', 'locale', 'week-start', 'label', 'prev-label', 'next-label'];
|
|
2548
2856
|
}
|
|
2549
2857
|
|
|
2858
|
+
// Delegated focus would land on the month arrow, not on the chosen day.
|
|
2859
|
+
static get delegatesFocus() { return false; }
|
|
2860
|
+
|
|
2550
2861
|
render() {
|
|
2551
2862
|
this._root = this.createElement('div', ['glass-calendar'], { part: 'calendar' });
|
|
2552
2863
|
const head = this.createElement('div', ['glass-calendar__head'], { part: 'head' });
|
|
@@ -3005,6 +3316,29 @@ class GlkProgress extends GlkElement {
|
|
|
3005
3316
|
|
|
3006
3317
|
customElements.define('glk-progress', GlkProgress);
|
|
3007
3318
|
|
|
3319
|
+
// Since 1.20.0 the overlay is a native <dialog>, opened with showModal(). The
|
|
3320
|
+
// browser then does what a modal needs: the dialog lies in the top layer, the
|
|
3321
|
+
// page behind it is inert — for the pointer, the keyboard and screen readers
|
|
3322
|
+
// alike — focus moves in on opening and goes back to where it came from on
|
|
3323
|
+
// closing, and the content is out of reach while the modal is closed.
|
|
3324
|
+
// GlassKit (1.20.0) styles dialog.glass-modal-overlay for this.
|
|
3325
|
+
//
|
|
3326
|
+
// The element keeps the fade: the dialog opens before .is-active is set and
|
|
3327
|
+
// closes only after the overlay has faded (safety net 400 ms; at once under
|
|
3328
|
+
// prefers-reduced-motion). Escape arrives as the dialog's cancel event and
|
|
3329
|
+
// takes the same path as a click on the dimmed area.
|
|
3330
|
+
//
|
|
3331
|
+
// Which element gets the focus on opening, the browsers decide differently:
|
|
3332
|
+
// Chrome takes the first field of the content, Safari the first action. An
|
|
3333
|
+
// element marked autofocus — in the content or among the actions — settles
|
|
3334
|
+
// it in both.
|
|
3335
|
+
|
|
3336
|
+
const CLOSE_FALLBACK_MS = 400;
|
|
3337
|
+
|
|
3338
|
+
function reducedMotion$1() {
|
|
3339
|
+
return typeof matchMedia === 'function' && matchMedia('(prefers-reduced-motion: reduce)').matches;
|
|
3340
|
+
}
|
|
3341
|
+
|
|
3008
3342
|
class GlkModal extends GlkElement {
|
|
3009
3343
|
static get observedAttributes() {
|
|
3010
3344
|
return ['open', 'title'];
|
|
@@ -3013,13 +3347,13 @@ class GlkModal extends GlkElement {
|
|
|
3013
3347
|
static get observesLightDom() { return true; }
|
|
3014
3348
|
|
|
3015
3349
|
render() {
|
|
3016
|
-
this._overlay = this.createElement('
|
|
3350
|
+
this._overlay = this.createElement('dialog', ['glass-modal-overlay'], { part: 'overlay' });
|
|
3017
3351
|
|
|
3018
3352
|
const modal = this.createElement('div', ['glass-modal'], { part: 'modal' });
|
|
3019
3353
|
|
|
3020
|
-
// Header
|
|
3354
|
+
// Header — the title names the dialog
|
|
3021
3355
|
const header = this.createElement('div', ['glass-modal__header'], { part: 'header' });
|
|
3022
|
-
this._titleEl = this.createElement('h2', ['glass-modal__title']);
|
|
3356
|
+
this._titleEl = this.createElement('h2', ['glass-modal__title'], { id: 'title' });
|
|
3023
3357
|
this.takeTitle();
|
|
3024
3358
|
this._applyTitle();
|
|
3025
3359
|
header.appendChild(this._titleEl);
|
|
@@ -3040,10 +3374,8 @@ class GlkModal extends GlkElement {
|
|
|
3040
3374
|
|
|
3041
3375
|
this._overlay.appendChild(modal);
|
|
3042
3376
|
this._wrapper.appendChild(this._overlay);
|
|
3043
|
-
|
|
3044
|
-
|
|
3045
|
-
this._overlay.classList.add('is-active');
|
|
3046
|
-
}
|
|
3377
|
+
// `open` is applied in setupEvents, which also runs when a moved element
|
|
3378
|
+
// comes back.
|
|
3047
3379
|
}
|
|
3048
3380
|
|
|
3049
3381
|
projectLightDom() {
|
|
@@ -3068,33 +3400,49 @@ class GlkModal extends GlkElement {
|
|
|
3068
3400
|
setupEvents() {
|
|
3069
3401
|
// Close on overlay click (outside modal)
|
|
3070
3402
|
this._onOverlayClick = (e) => {
|
|
3071
|
-
if (e.target === this._overlay)
|
|
3072
|
-
this.removeAttribute('open');
|
|
3073
|
-
this.emit('glk-close');
|
|
3074
|
-
}
|
|
3403
|
+
if (e.target === this._overlay) this._dismiss();
|
|
3075
3404
|
};
|
|
3076
3405
|
this._overlay.addEventListener('click', this._onOverlayClick);
|
|
3077
3406
|
|
|
3078
|
-
//
|
|
3079
|
-
this.
|
|
3080
|
-
|
|
3081
|
-
|
|
3082
|
-
this.emit('glk-close');
|
|
3083
|
-
}
|
|
3407
|
+
// Escape: the dialog would close at once; it fades out like a click outside.
|
|
3408
|
+
this._onCancel = (e) => {
|
|
3409
|
+
e.preventDefault();
|
|
3410
|
+
this._dismiss();
|
|
3084
3411
|
};
|
|
3085
|
-
|
|
3412
|
+
this._overlay.addEventListener('cancel', this._onCancel);
|
|
3413
|
+
|
|
3414
|
+
// The browser may also close the dialog by itself — Chrome does on a
|
|
3415
|
+
// second Escape without user activation in between, skipping cancel.
|
|
3416
|
+
this._onClose = () => {
|
|
3417
|
+
if (this._overlay.open) return; // a late event from an earlier close
|
|
3418
|
+
this._overlay.classList.remove('is-active');
|
|
3419
|
+
if (this.open) this._dismiss();
|
|
3420
|
+
};
|
|
3421
|
+
this._overlay.addEventListener('close', this._onClose);
|
|
3422
|
+
|
|
3423
|
+
if (this.open) this._show();
|
|
3086
3424
|
}
|
|
3087
3425
|
|
|
3088
3426
|
teardownEvents() {
|
|
3089
3427
|
this._overlay?.removeEventListener('click', this._onOverlayClick);
|
|
3090
|
-
|
|
3428
|
+
this._overlay?.removeEventListener('cancel', this._onCancel);
|
|
3429
|
+
this._overlay?.removeEventListener('close', this._onClose);
|
|
3430
|
+
// Taken out of the document, the dialog leaves the top layer but stays
|
|
3431
|
+
// open — shown in place, not modal. Closed now, it opens as a modal again
|
|
3432
|
+
// when the element comes back.
|
|
3433
|
+
clearTimeout(this._closeTimer);
|
|
3434
|
+
this._overlay?.removeEventListener('transitionend', this._onFaded);
|
|
3435
|
+
this._overlay?.classList.remove('is-active');
|
|
3436
|
+
if (this._overlay?.open) this._overlay.close();
|
|
3091
3437
|
}
|
|
3092
3438
|
|
|
3093
3439
|
onAttributeChanged(name, _old, value) {
|
|
3094
3440
|
if (!this._overlay) return;
|
|
3095
3441
|
switch (name) {
|
|
3096
3442
|
case 'open':
|
|
3097
|
-
|
|
3443
|
+
if (!this.isConnected) return; // setupEvents applies it on connect
|
|
3444
|
+
if (this.open) this._show();
|
|
3445
|
+
else this._hide();
|
|
3098
3446
|
break;
|
|
3099
3447
|
case 'title':
|
|
3100
3448
|
if (this.takeTitle(value)) this._applyTitle();
|
|
@@ -3102,11 +3450,52 @@ class GlkModal extends GlkElement {
|
|
|
3102
3450
|
}
|
|
3103
3451
|
}
|
|
3104
3452
|
|
|
3453
|
+
_show() {
|
|
3454
|
+
const dialog = this._overlay;
|
|
3455
|
+
clearTimeout(this._closeTimer);
|
|
3456
|
+
dialog.removeEventListener('transitionend', this._onFaded);
|
|
3457
|
+
if (!dialog.open) {
|
|
3458
|
+
dialog.showModal();
|
|
3459
|
+
// The actions are copies in the shadow root; the originals are not shown.
|
|
3460
|
+
(this._footer.querySelector('[autofocus]') || this.querySelector('[autofocus]'))?.focus();
|
|
3461
|
+
}
|
|
3462
|
+
void dialog.offsetHeight; // reflow, so the fade starts from the closed state
|
|
3463
|
+
requestAnimationFrame(() => {
|
|
3464
|
+
if (this.open) dialog.classList.add('is-active');
|
|
3465
|
+
});
|
|
3466
|
+
}
|
|
3467
|
+
|
|
3468
|
+
_hide() {
|
|
3469
|
+
const dialog = this._overlay;
|
|
3470
|
+
dialog.classList.remove('is-active');
|
|
3471
|
+
this._onFaded = (event) => {
|
|
3472
|
+
if (event && event.target !== dialog) return; // the panel's own transition
|
|
3473
|
+
clearTimeout(this._closeTimer);
|
|
3474
|
+
dialog.removeEventListener('transitionend', this._onFaded);
|
|
3475
|
+
if (!this.open && dialog.open) dialog.close();
|
|
3476
|
+
};
|
|
3477
|
+
if (!dialog.open || reducedMotion$1()) {
|
|
3478
|
+
this._onFaded();
|
|
3479
|
+
return;
|
|
3480
|
+
}
|
|
3481
|
+
dialog.addEventListener('transitionend', this._onFaded);
|
|
3482
|
+
this._closeTimer = setTimeout(this._onFaded, CLOSE_FALLBACK_MS);
|
|
3483
|
+
}
|
|
3484
|
+
|
|
3485
|
+
/** Closed by the user — a click outside, Escape. */
|
|
3486
|
+
_dismiss() {
|
|
3487
|
+
this.removeAttribute('open');
|
|
3488
|
+
this.emit('glk-close');
|
|
3489
|
+
}
|
|
3490
|
+
|
|
3105
3491
|
show() { this.setAttribute('open', ''); }
|
|
3106
3492
|
close() { this.removeAttribute('open'); }
|
|
3107
3493
|
|
|
3108
3494
|
_applyTitle() {
|
|
3109
|
-
if (this._titleEl)
|
|
3495
|
+
if (!this._titleEl) return;
|
|
3496
|
+
this._titleEl.textContent = this._title || '';
|
|
3497
|
+
if (this._title) this._overlay.setAttribute('aria-labelledby', 'title');
|
|
3498
|
+
else this._overlay.removeAttribute('aria-labelledby');
|
|
3110
3499
|
}
|
|
3111
3500
|
|
|
3112
3501
|
// `title` is the heading, never a tooltip — see GlkElement.takeTitle().
|
|
@@ -3398,9 +3787,9 @@ class GlkPopover extends GlkElement {
|
|
|
3398
3787
|
render() {
|
|
3399
3788
|
this._anchor = this.createElement('div', ['glass-popover-anchor']);
|
|
3400
3789
|
|
|
3401
|
-
|
|
3402
|
-
|
|
3403
|
-
this._anchor.appendChild(
|
|
3790
|
+
this._triggerSlot = document.createElement('slot');
|
|
3791
|
+
this._triggerSlot.setAttribute('name', 'trigger');
|
|
3792
|
+
this._anchor.appendChild(this._triggerSlot);
|
|
3404
3793
|
|
|
3405
3794
|
this._popover = this.createElement('div', ['glass-popover']);
|
|
3406
3795
|
this._applyPlacement();
|
|
@@ -3424,7 +3813,23 @@ class GlkPopover extends GlkElement {
|
|
|
3424
3813
|
}
|
|
3425
3814
|
}
|
|
3426
3815
|
|
|
3816
|
+
/**
|
|
3817
|
+
* The trigger says whether the popover is open. It lives in the light DOM,
|
|
3818
|
+
* so aria-expanded goes on it directly; <glk-button> and <glk-pill> hand
|
|
3819
|
+
* it on to their native button. Runs again when the trigger is swapped.
|
|
3820
|
+
*/
|
|
3821
|
+
_applyExpanded() {
|
|
3822
|
+
const open = String(this.getBoolAttr('open'));
|
|
3823
|
+
for (const trigger of this._triggerSlot.assignedElements()) {
|
|
3824
|
+
trigger.setAttribute('aria-expanded', open);
|
|
3825
|
+
}
|
|
3826
|
+
}
|
|
3827
|
+
|
|
3427
3828
|
setupEvents() {
|
|
3829
|
+
this._onSlotChange = () => this._applyExpanded();
|
|
3830
|
+
this._triggerSlot.addEventListener('slotchange', this._onSlotChange);
|
|
3831
|
+
this._applyExpanded();
|
|
3832
|
+
|
|
3428
3833
|
// Toggle when the slotted trigger is clicked.
|
|
3429
3834
|
this._onTriggerClick = (e) => {
|
|
3430
3835
|
const path = e.composedPath();
|
|
@@ -3456,6 +3861,7 @@ class GlkPopover extends GlkElement {
|
|
|
3456
3861
|
}
|
|
3457
3862
|
|
|
3458
3863
|
teardownEvents() {
|
|
3864
|
+
this._triggerSlot?.removeEventListener('slotchange', this._onSlotChange);
|
|
3459
3865
|
this.removeEventListener('click', this._onTriggerClick);
|
|
3460
3866
|
document.removeEventListener('click', this._onDocClick);
|
|
3461
3867
|
document.removeEventListener('keydown', this._onKeydown);
|
|
@@ -3467,6 +3873,7 @@ class GlkPopover extends GlkElement {
|
|
|
3467
3873
|
case 'open': {
|
|
3468
3874
|
const isOpen = this.getBoolAttr('open');
|
|
3469
3875
|
this._popover.classList.toggle('is-open', isOpen);
|
|
3876
|
+
this._applyExpanded();
|
|
3470
3877
|
this.emit(isOpen ? 'glk-open' : 'glk-close');
|
|
3471
3878
|
break;
|
|
3472
3879
|
}
|
|
@@ -3659,17 +4066,19 @@ class GlkAccordionItem extends GlkElement {
|
|
|
3659
4066
|
|
|
3660
4067
|
render() {
|
|
3661
4068
|
this._item = this.createElement('div', ['glass-accordion__item']);
|
|
3662
|
-
if (this.getBoolAttr('open')) this._item.classList.add('is-open');
|
|
3663
4069
|
|
|
3664
|
-
// Trigger button
|
|
3665
|
-
this._trigger = this.createElement('button', ['glass-accordion__trigger']
|
|
4070
|
+
// Trigger button — says whether its section is open, and which one it is
|
|
4071
|
+
this._trigger = this.createElement('button', ['glass-accordion__trigger'], {
|
|
4072
|
+
type: 'button',
|
|
4073
|
+
'aria-controls': 'content'
|
|
4074
|
+
});
|
|
3666
4075
|
this.takeTitle();
|
|
3667
4076
|
this._triggerText = document.createTextNode(this._title || '');
|
|
3668
4077
|
this._trigger.appendChild(this._triggerText);
|
|
3669
4078
|
this._trigger.insertAdjacentHTML('beforeend', CHEVRON_SVG);
|
|
3670
4079
|
|
|
3671
4080
|
// Content
|
|
3672
|
-
this._content = this.createElement('div', ['glass-accordion__content']);
|
|
4081
|
+
this._content = this.createElement('div', ['glass-accordion__content'], { id: 'content' });
|
|
3673
4082
|
const body = this.createElement('div', ['glass-accordion__body']);
|
|
3674
4083
|
body.appendChild(document.createElement('slot'));
|
|
3675
4084
|
this._content.appendChild(body);
|
|
@@ -3678,6 +4087,19 @@ class GlkAccordionItem extends GlkElement {
|
|
|
3678
4087
|
this._item.appendChild(this._content);
|
|
3679
4088
|
|
|
3680
4089
|
this._wrapper.appendChild(this._item);
|
|
4090
|
+
this._applyOpen();
|
|
4091
|
+
}
|
|
4092
|
+
|
|
4093
|
+
/**
|
|
4094
|
+
* A closed section is only squeezed to zero height; its links and fields
|
|
4095
|
+
* stayed in the tab order. inert takes them out, and out of the
|
|
4096
|
+
* accessibility tree, until the section opens.
|
|
4097
|
+
*/
|
|
4098
|
+
_applyOpen() {
|
|
4099
|
+
const open = this.getBoolAttr('open');
|
|
4100
|
+
this._item.classList.toggle('is-open', open);
|
|
4101
|
+
this._trigger.setAttribute('aria-expanded', String(open));
|
|
4102
|
+
this._content.inert = !open;
|
|
3681
4103
|
}
|
|
3682
4104
|
|
|
3683
4105
|
setupEvents() {
|
|
@@ -3696,7 +4118,7 @@ class GlkAccordionItem extends GlkElement {
|
|
|
3696
4118
|
if (!this._item) return;
|
|
3697
4119
|
switch (name) {
|
|
3698
4120
|
case 'open':
|
|
3699
|
-
this.
|
|
4121
|
+
this._applyOpen();
|
|
3700
4122
|
break;
|
|
3701
4123
|
case 'title':
|
|
3702
4124
|
if (this.takeTitle(value)) this._applyTitle();
|