@jungherz-de/glasskit-elements 1.19.1 → 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 +36 -0
- package/README.md +40 -27
- package/SKILL.md +107 -25
- 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 +7 -4
- package/dist/components/glk-checkbox.js +12 -2
- package/dist/components/glk-date-strip.js +5 -4
- 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/components/shared/{dates-CNWaJf09.js → dates-D4JTqoiG.js} +25 -4
- package/dist/glasskit-elements.esm.js +519 -75
- package/dist/glasskit-elements.js +519 -75
- 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 +6 -3
- 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-date-strip.js +4 -3
- package/src/components/navigation/glk-pill.js +14 -1
- package/src/dates.js +25 -4
|
@@ -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);
|
|
@@ -692,8 +840,8 @@ customElements.define('glk-steps', GlkSteps);
|
|
|
692
840
|
// Date helpers shared by <glk-date-strip> and <glk-calendar>. Everything
|
|
693
841
|
// works on local calendar days — a date is "YYYY-MM-DD" in the element API
|
|
694
842
|
// and a local Date inside — so a day never shifts across midnight the way a
|
|
695
|
-
// UTC timestamp would. Names come from Intl,
|
|
696
|
-
//
|
|
843
|
+
// UTC timestamp would. Names come from Intl, in the language resolveLocale()
|
|
844
|
+
// finds for the element.
|
|
697
845
|
|
|
698
846
|
const pad = n => String(n).padStart(2, '0');
|
|
699
847
|
|
|
@@ -721,8 +869,29 @@ function parseJsonObject(text) {
|
|
|
721
869
|
}
|
|
722
870
|
}
|
|
723
871
|
|
|
724
|
-
|
|
725
|
-
|
|
872
|
+
/**
|
|
873
|
+
* The language to name days and months in: the element's locale attribute;
|
|
874
|
+
* else the language of the page around it — the lang of the nearest
|
|
875
|
+
* ancestor, looked up across shadow roots through their hosts, so
|
|
876
|
+
* <html lang="de"> reaches an element inside another component's shadow
|
|
877
|
+
* tree and a <section lang="en"> in a German page stays English; else the
|
|
878
|
+
* browser's; else English. An empty lang means "unknown" in HTML and falls
|
|
879
|
+
* through to the browser's language. (Since 1.19.2 — before, the browser's
|
|
880
|
+
* language came right after the attribute.)
|
|
881
|
+
*/
|
|
882
|
+
function resolveLocale(attr, el) {
|
|
883
|
+
if (attr) return attr;
|
|
884
|
+
for (let node = el; node; ) {
|
|
885
|
+
const tagged = node.closest?.('[lang]');
|
|
886
|
+
if (tagged) {
|
|
887
|
+
const lang = tagged.getAttribute('lang').trim();
|
|
888
|
+
if (lang) return lang;
|
|
889
|
+
break;
|
|
890
|
+
}
|
|
891
|
+
const root = node.getRootNode?.();
|
|
892
|
+
node = typeof ShadowRoot !== 'undefined' && root instanceof ShadowRoot ? root.host : null;
|
|
893
|
+
}
|
|
894
|
+
return (typeof navigator !== 'undefined' && navigator.language) || 'en';
|
|
726
895
|
}
|
|
727
896
|
|
|
728
897
|
// Intl formatters are cheap to keep and not to make; one set per locale.
|
|
@@ -790,7 +959,8 @@ function revealCentered(scroller, item, smooth) {
|
|
|
790
959
|
// Attributes: start (YYYY-MM-DD, default today), days (count, default 7),
|
|
791
960
|
// value (YYYY-MM-DD), today (YYYY-MM-DD, default the browser's
|
|
792
961
|
// day), marks (JSON {date: tone | {tone, disabled}}), locale
|
|
793
|
-
// (default the
|
|
962
|
+
// (default the page language, else the browser's), label
|
|
963
|
+
// (aria-label of the group)
|
|
794
964
|
// Properties: value, marks (object or JSON text), locale, label
|
|
795
965
|
// Event: glk-change { value } — only on a change made by the user
|
|
796
966
|
// Part: strip
|
|
@@ -823,7 +993,7 @@ class GlkDateStrip extends GlkElement {
|
|
|
823
993
|
}
|
|
824
994
|
|
|
825
995
|
_build() {
|
|
826
|
-
const f = formatters(resolveLocale(this.getAttribute('locale')));
|
|
996
|
+
const f = formatters(resolveLocale(this.getAttribute('locale'), this));
|
|
827
997
|
const marks = parseJsonObject(this.getAttribute('marks'));
|
|
828
998
|
const start = parseIso(this.getAttribute('start')) ?? new Date();
|
|
829
999
|
const today = this.getAttribute('today') || isoDate(new Date());
|
|
@@ -935,7 +1105,7 @@ class GlkDateStrip extends GlkElement {
|
|
|
935
1105
|
get marks() { return parseJsonObject(this.getAttribute('marks')); }
|
|
936
1106
|
set marks(v) { this.setAttribute('marks', typeof v === 'string' ? v : JSON.stringify(v ?? {})); }
|
|
937
1107
|
|
|
938
|
-
get locale() { return resolveLocale(this.getAttribute('locale')); }
|
|
1108
|
+
get locale() { return resolveLocale(this.getAttribute('locale'), this); }
|
|
939
1109
|
set locale(v) {
|
|
940
1110
|
if (v) this.setAttribute('locale', v);
|
|
941
1111
|
else this.removeAttribute('locale');
|
|
@@ -1278,9 +1448,24 @@ customElements.define('glk-empty', GlkEmpty);
|
|
|
1278
1448
|
const VARIANTS$3 = ['primary', 'secondary', 'tertiary'];
|
|
1279
1449
|
const SIZES$1 = ['sm', 'md', 'lg', 'auto'];
|
|
1280
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
|
+
|
|
1281
1456
|
class GlkButton extends GlkElement {
|
|
1282
1457
|
static get observedAttributes() {
|
|
1283
|
-
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();
|
|
1284
1469
|
}
|
|
1285
1470
|
|
|
1286
1471
|
render() {
|
|
@@ -1291,6 +1476,7 @@ class GlkButton extends GlkElement {
|
|
|
1291
1476
|
if (this.getBoolAttr('disabled')) {
|
|
1292
1477
|
this._btn.disabled = true;
|
|
1293
1478
|
}
|
|
1479
|
+
for (const attr of FORWARDED_ARIA) this._forward(attr);
|
|
1294
1480
|
|
|
1295
1481
|
this._btn.appendChild(document.createElement('slot'));
|
|
1296
1482
|
this._wrapper.appendChild(this._btn);
|
|
@@ -1304,12 +1490,50 @@ class GlkButton extends GlkElement {
|
|
|
1304
1490
|
return;
|
|
1305
1491
|
}
|
|
1306
1492
|
this.emit('glk-click');
|
|
1493
|
+
this._activateForm(e);
|
|
1307
1494
|
};
|
|
1308
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);
|
|
1309
1498
|
}
|
|
1310
1499
|
|
|
1311
1500
|
teardownEvents() {
|
|
1312
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
|
+
});
|
|
1313
1537
|
}
|
|
1314
1538
|
|
|
1315
1539
|
onAttributeChanged(name) {
|
|
@@ -1325,9 +1549,17 @@ class GlkButton extends GlkElement {
|
|
|
1325
1549
|
case 'type':
|
|
1326
1550
|
this._btn.setAttribute('type', this.getAttribute('type') || 'button');
|
|
1327
1551
|
break;
|
|
1552
|
+
default:
|
|
1553
|
+
if (FORWARDED_ARIA.includes(name)) this._forward(name);
|
|
1328
1554
|
}
|
|
1329
1555
|
}
|
|
1330
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
|
+
|
|
1331
1563
|
_computeClasses() {
|
|
1332
1564
|
const classes = ['glass-btn'];
|
|
1333
1565
|
const variant = this.getAttribute('variant');
|
|
@@ -1349,6 +1581,11 @@ class GlkButton extends GlkElement {
|
|
|
1349
1581
|
|
|
1350
1582
|
get disabled() { return this.getBoolAttr('disabled'); }
|
|
1351
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; }
|
|
1352
1589
|
}
|
|
1353
1590
|
|
|
1354
1591
|
customElements.define('glk-button', GlkButton);
|
|
@@ -1367,12 +1604,15 @@ class GlkInput extends GlkFormElement {
|
|
|
1367
1604
|
render() {
|
|
1368
1605
|
const group = this.createElement('div', ['glass-input-group']);
|
|
1369
1606
|
|
|
1370
|
-
// Label
|
|
1371
|
-
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' });
|
|
1372
1611
|
this._labelEl.textContent = this.getAttribute('label') || '';
|
|
1373
1612
|
|
|
1374
1613
|
// Input
|
|
1375
1614
|
this._input = this.createElement('input', this._computeInputClasses(), {
|
|
1615
|
+
id: 'field',
|
|
1376
1616
|
type: this.getAttribute('type') || 'text'
|
|
1377
1617
|
});
|
|
1378
1618
|
|
|
@@ -1389,8 +1629,8 @@ class GlkInput extends GlkFormElement {
|
|
|
1389
1629
|
if (this.getBoolAttr('required')) this._input.required = true;
|
|
1390
1630
|
for (const attr of FORWARDED) this._forward(attr);
|
|
1391
1631
|
|
|
1392
|
-
// Hint
|
|
1393
|
-
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' });
|
|
1394
1634
|
this._hintEl.textContent = this.getAttribute('hint') || '';
|
|
1395
1635
|
|
|
1396
1636
|
group.appendChild(this._labelEl);
|
|
@@ -1400,6 +1640,7 @@ class GlkInput extends GlkFormElement {
|
|
|
1400
1640
|
this._group = group;
|
|
1401
1641
|
this._wrapper.appendChild(group);
|
|
1402
1642
|
|
|
1643
|
+
this._applyDescription();
|
|
1403
1644
|
this._syncFormValue();
|
|
1404
1645
|
}
|
|
1405
1646
|
|
|
@@ -1437,12 +1678,14 @@ class GlkInput extends GlkFormElement {
|
|
|
1437
1678
|
case 'error':
|
|
1438
1679
|
this._input.className = this._computeInputClasses().join(' ');
|
|
1439
1680
|
this._hintEl.className = this._computeHintClasses().join(' ');
|
|
1681
|
+
this._applyDescription();
|
|
1440
1682
|
break;
|
|
1441
1683
|
case 'hint':
|
|
1442
1684
|
this._hintEl.textContent = this.getAttribute('hint') || '';
|
|
1443
1685
|
if (this.getAttribute('hint') && !this._hintEl.parentNode) {
|
|
1444
1686
|
this._group.appendChild(this._hintEl);
|
|
1445
1687
|
}
|
|
1688
|
+
this._applyDescription();
|
|
1446
1689
|
break;
|
|
1447
1690
|
case 'disabled':
|
|
1448
1691
|
this._input.disabled = this.getBoolAttr('disabled');
|
|
@@ -1462,6 +1705,19 @@ class GlkInput extends GlkFormElement {
|
|
|
1462
1705
|
}
|
|
1463
1706
|
}
|
|
1464
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
|
+
|
|
1465
1721
|
_forward(attr) {
|
|
1466
1722
|
const value = this.getAttribute(attr);
|
|
1467
1723
|
if (value === null) this._input.removeAttribute(attr);
|
|
@@ -1480,6 +1736,8 @@ class GlkInput extends GlkFormElement {
|
|
|
1480
1736
|
return classes;
|
|
1481
1737
|
}
|
|
1482
1738
|
|
|
1739
|
+
get _validityField() { return this._input; }
|
|
1740
|
+
|
|
1483
1741
|
_syncFormValue() {
|
|
1484
1742
|
this.setFormValue(this._input.value);
|
|
1485
1743
|
}
|
|
@@ -1512,10 +1770,11 @@ class GlkTextarea extends GlkFormElement {
|
|
|
1512
1770
|
render() {
|
|
1513
1771
|
const group = this.createElement('div', ['glass-input-group']);
|
|
1514
1772
|
|
|
1515
|
-
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' });
|
|
1516
1775
|
this._labelEl.textContent = this.getAttribute('label') || '';
|
|
1517
1776
|
|
|
1518
|
-
this._textarea = this.createElement('textarea', ['glass-textarea']);
|
|
1777
|
+
this._textarea = this.createElement('textarea', ['glass-textarea'], { id: 'field' });
|
|
1519
1778
|
const placeholder = this.getAttribute('placeholder');
|
|
1520
1779
|
if (placeholder) this._textarea.setAttribute('placeholder', placeholder);
|
|
1521
1780
|
|
|
@@ -1573,9 +1832,14 @@ class GlkTextarea extends GlkFormElement {
|
|
|
1573
1832
|
this._textarea.value = this.getAttribute('value') || '';
|
|
1574
1833
|
this._syncFormValue();
|
|
1575
1834
|
break;
|
|
1835
|
+
case 'required':
|
|
1836
|
+
this._textarea.required = this.getBoolAttr('required');
|
|
1837
|
+
break;
|
|
1576
1838
|
}
|
|
1577
1839
|
}
|
|
1578
1840
|
|
|
1841
|
+
get _validityField() { return this._textarea; }
|
|
1842
|
+
|
|
1579
1843
|
_syncFormValue() {
|
|
1580
1844
|
this.setFormValue(this._textarea.value);
|
|
1581
1845
|
}
|
|
@@ -1607,10 +1871,11 @@ class GlkSelect extends GlkFormElement {
|
|
|
1607
1871
|
render() {
|
|
1608
1872
|
const group = this.createElement('div', ['glass-input-group']);
|
|
1609
1873
|
|
|
1610
|
-
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' });
|
|
1611
1876
|
this._labelEl.textContent = this.getAttribute('label') || '';
|
|
1612
1877
|
|
|
1613
|
-
this._select = this.createElement('select', ['glass-select']);
|
|
1878
|
+
this._select = this.createElement('select', ['glass-select'], { id: 'field' });
|
|
1614
1879
|
|
|
1615
1880
|
const name = this.getAttribute('name');
|
|
1616
1881
|
if (name) this._select.setAttribute('name', name);
|
|
@@ -1698,9 +1963,14 @@ class GlkSelect extends GlkFormElement {
|
|
|
1698
1963
|
this._applyValue(this.getAttribute('value'));
|
|
1699
1964
|
this._syncFormValue();
|
|
1700
1965
|
break;
|
|
1966
|
+
case 'required':
|
|
1967
|
+
this._select.required = this.getBoolAttr('required');
|
|
1968
|
+
break;
|
|
1701
1969
|
}
|
|
1702
1970
|
}
|
|
1703
1971
|
|
|
1972
|
+
get _validityField() { return this._select; }
|
|
1973
|
+
|
|
1704
1974
|
_syncFormValue() {
|
|
1705
1975
|
this.setFormValue(this._select.value);
|
|
1706
1976
|
}
|
|
@@ -1726,7 +1996,7 @@ const SEARCH_SVG = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" s
|
|
|
1726
1996
|
|
|
1727
1997
|
class GlkSearch extends GlkFormElement {
|
|
1728
1998
|
static get observedAttributes() {
|
|
1729
|
-
return ['placeholder', 'name', 'value', 'disabled'];
|
|
1999
|
+
return ['placeholder', 'name', 'value', 'disabled', 'label'];
|
|
1730
2000
|
}
|
|
1731
2001
|
|
|
1732
2002
|
render() {
|
|
@@ -1742,6 +2012,10 @@ class GlkSearch extends GlkFormElement {
|
|
|
1742
2012
|
const placeholder = this.getAttribute('placeholder');
|
|
1743
2013
|
if (placeholder) this._input.setAttribute('placeholder', placeholder);
|
|
1744
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
|
+
|
|
1745
2019
|
const name = this.getAttribute('name');
|
|
1746
2020
|
if (name) this._input.setAttribute('name', name);
|
|
1747
2021
|
|
|
@@ -1786,9 +2060,18 @@ class GlkSearch extends GlkFormElement {
|
|
|
1786
2060
|
case 'disabled':
|
|
1787
2061
|
this._input.disabled = this.getBoolAttr('disabled');
|
|
1788
2062
|
break;
|
|
2063
|
+
case 'label':
|
|
2064
|
+
this._applyLabel();
|
|
2065
|
+
break;
|
|
1789
2066
|
}
|
|
1790
2067
|
}
|
|
1791
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
|
+
|
|
1792
2075
|
_syncFormValue() {
|
|
1793
2076
|
this.setFormValue(this._input.value);
|
|
1794
2077
|
}
|
|
@@ -1809,14 +2092,21 @@ customElements.define('glk-search', GlkSearch);
|
|
|
1809
2092
|
|
|
1810
2093
|
class GlkToggle extends GlkFormElement {
|
|
1811
2094
|
static get observedAttributes() {
|
|
1812
|
-
return ['checked', 'disabled', 'label', 'name', 'value'];
|
|
2095
|
+
return ['checked', 'disabled', 'label', 'name', 'value', 'required'];
|
|
1813
2096
|
}
|
|
1814
2097
|
|
|
2098
|
+
static get hostStyles() { return checkControlSheet; }
|
|
2099
|
+
|
|
1815
2100
|
render() {
|
|
1816
2101
|
const label = this.createElement('label', ['glass-toggle']);
|
|
1817
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.
|
|
1818
2107
|
this._input = this.createElement('input', ['glass-toggle__input'], {
|
|
1819
|
-
type: 'checkbox'
|
|
2108
|
+
type: 'checkbox',
|
|
2109
|
+
role: 'switch'
|
|
1820
2110
|
});
|
|
1821
2111
|
|
|
1822
2112
|
const name = this.getAttribute('name');
|
|
@@ -1835,14 +2125,12 @@ class GlkToggle extends GlkFormElement {
|
|
|
1835
2125
|
|
|
1836
2126
|
if (this.getBoolAttr('checked')) this._input.checked = true;
|
|
1837
2127
|
if (this.getBoolAttr('disabled')) this._input.disabled = true;
|
|
2128
|
+
if (this.getBoolAttr('required')) this._input.required = true;
|
|
1838
2129
|
|
|
1839
2130
|
this._defaultChecked = this.getBoolAttr('checked');
|
|
1840
2131
|
this._wrapper.appendChild(label);
|
|
1841
2132
|
|
|
1842
2133
|
this._syncFormValue();
|
|
1843
|
-
this.setAttribute('role', 'switch');
|
|
1844
|
-
this.setAttribute('aria-checked', String(this._input.checked));
|
|
1845
|
-
if (this.getBoolAttr('disabled')) this.setAttribute('aria-disabled', 'true');
|
|
1846
2134
|
}
|
|
1847
2135
|
|
|
1848
2136
|
setupEvents() {
|
|
@@ -1850,16 +2138,17 @@ class GlkToggle extends GlkFormElement {
|
|
|
1850
2138
|
this._syncing = true;
|
|
1851
2139
|
this.setBoolAttr('checked', this._input.checked);
|
|
1852
2140
|
this._syncing = false;
|
|
1853
|
-
this.setAttribute('aria-checked', String(this._input.checked));
|
|
1854
2141
|
this._syncFormValue();
|
|
1855
2142
|
this.emit('glk-change', { checked: this._input.checked });
|
|
1856
2143
|
this.dispatchEvent(new Event('change', { bubbles: true }));
|
|
1857
2144
|
};
|
|
1858
2145
|
this._input.addEventListener('change', this._onChange);
|
|
2146
|
+
this._unforwardClicks = forwardHostClicks(this, () => this._input);
|
|
1859
2147
|
}
|
|
1860
2148
|
|
|
1861
2149
|
teardownEvents() {
|
|
1862
2150
|
this._input?.removeEventListener('change', this._onChange);
|
|
2151
|
+
this._unforwardClicks?.();
|
|
1863
2152
|
}
|
|
1864
2153
|
|
|
1865
2154
|
onAttributeChanged(name) {
|
|
@@ -1868,12 +2157,10 @@ class GlkToggle extends GlkFormElement {
|
|
|
1868
2157
|
switch (name) {
|
|
1869
2158
|
case 'checked':
|
|
1870
2159
|
this._input.checked = this.getBoolAttr('checked');
|
|
1871
|
-
this.setAttribute('aria-checked', String(this._input.checked));
|
|
1872
2160
|
this._syncFormValue();
|
|
1873
2161
|
break;
|
|
1874
2162
|
case 'disabled':
|
|
1875
2163
|
this._input.disabled = this.getBoolAttr('disabled');
|
|
1876
|
-
this.setAttribute('aria-disabled', String(this.getBoolAttr('disabled')));
|
|
1877
2164
|
break;
|
|
1878
2165
|
case 'label':
|
|
1879
2166
|
this._labelEl.textContent = this.getAttribute('label') || '';
|
|
@@ -1881,9 +2168,14 @@ class GlkToggle extends GlkFormElement {
|
|
|
1881
2168
|
case 'name':
|
|
1882
2169
|
this._input.setAttribute('name', this.getAttribute('name') || '');
|
|
1883
2170
|
break;
|
|
2171
|
+
case 'required':
|
|
2172
|
+
this._input.required = this.getBoolAttr('required');
|
|
2173
|
+
break;
|
|
1884
2174
|
}
|
|
1885
2175
|
}
|
|
1886
2176
|
|
|
2177
|
+
get _validityField() { return this._input; }
|
|
2178
|
+
|
|
1887
2179
|
_syncFormValue() {
|
|
1888
2180
|
const val = this.getAttribute('value') || 'on';
|
|
1889
2181
|
this.setFormValue(this._input.checked ? val : null);
|
|
@@ -1892,7 +2184,6 @@ class GlkToggle extends GlkFormElement {
|
|
|
1892
2184
|
resetValue() {
|
|
1893
2185
|
this._input.checked = this._defaultChecked;
|
|
1894
2186
|
this.setBoolAttr('checked', this._defaultChecked);
|
|
1895
|
-
this.setAttribute('aria-checked', String(this._defaultChecked));
|
|
1896
2187
|
this._syncFormValue();
|
|
1897
2188
|
}
|
|
1898
2189
|
|
|
@@ -1907,7 +2198,6 @@ class GlkToggle extends GlkFormElement {
|
|
|
1907
2198
|
set checked(v) {
|
|
1908
2199
|
if (this._input) this._input.checked = v;
|
|
1909
2200
|
this.setBoolAttr('checked', v);
|
|
1910
|
-
this.setAttribute('aria-checked', String(v));
|
|
1911
2201
|
this._syncFormValue();
|
|
1912
2202
|
}
|
|
1913
2203
|
|
|
@@ -1930,9 +2220,11 @@ const CHECKMARK_SVG = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor
|
|
|
1930
2220
|
|
|
1931
2221
|
class GlkCheckbox extends GlkFormElement {
|
|
1932
2222
|
static get observedAttributes() {
|
|
1933
|
-
return ['checked', 'disabled', 'label', 'name', 'value'];
|
|
2223
|
+
return ['checked', 'disabled', 'label', 'name', 'value', 'required'];
|
|
1934
2224
|
}
|
|
1935
2225
|
|
|
2226
|
+
static get hostStyles() { return checkControlSheet; }
|
|
2227
|
+
|
|
1936
2228
|
render() {
|
|
1937
2229
|
const label = this.createElement('label', ['glass-checkbox']);
|
|
1938
2230
|
|
|
@@ -1955,6 +2247,7 @@ class GlkCheckbox extends GlkFormElement {
|
|
|
1955
2247
|
|
|
1956
2248
|
if (this.getBoolAttr('checked')) this._input.checked = true;
|
|
1957
2249
|
if (this.getBoolAttr('disabled')) this._input.disabled = true;
|
|
2250
|
+
if (this.getBoolAttr('required')) this._input.required = true;
|
|
1958
2251
|
|
|
1959
2252
|
this._defaultChecked = this.getBoolAttr('checked');
|
|
1960
2253
|
this._wrapper.appendChild(label);
|
|
@@ -1971,10 +2264,12 @@ class GlkCheckbox extends GlkFormElement {
|
|
|
1971
2264
|
this.dispatchEvent(new Event('change', { bubbles: true }));
|
|
1972
2265
|
};
|
|
1973
2266
|
this._input.addEventListener('change', this._onChange);
|
|
2267
|
+
this._unforwardClicks = forwardHostClicks(this, () => this._input);
|
|
1974
2268
|
}
|
|
1975
2269
|
|
|
1976
2270
|
teardownEvents() {
|
|
1977
2271
|
this._input?.removeEventListener('change', this._onChange);
|
|
2272
|
+
this._unforwardClicks?.();
|
|
1978
2273
|
}
|
|
1979
2274
|
|
|
1980
2275
|
onAttributeChanged(name) {
|
|
@@ -1994,9 +2289,14 @@ class GlkCheckbox extends GlkFormElement {
|
|
|
1994
2289
|
case 'name':
|
|
1995
2290
|
this._input.setAttribute('name', this.getAttribute('name') || '');
|
|
1996
2291
|
break;
|
|
2292
|
+
case 'required':
|
|
2293
|
+
this._input.required = this.getBoolAttr('required');
|
|
2294
|
+
break;
|
|
1997
2295
|
}
|
|
1998
2296
|
}
|
|
1999
2297
|
|
|
2298
|
+
get _validityField() { return this._input; }
|
|
2299
|
+
|
|
2000
2300
|
_syncFormValue() {
|
|
2001
2301
|
const val = this.getAttribute('value') || 'on';
|
|
2002
2302
|
this.setFormValue(this._input.checked ? val : null);
|
|
@@ -2056,9 +2356,11 @@ function syncGroupTabIndex(group) {
|
|
|
2056
2356
|
|
|
2057
2357
|
class GlkRadio extends GlkFormElement {
|
|
2058
2358
|
static get observedAttributes() {
|
|
2059
|
-
return ['checked', 'disabled', 'label', 'name', 'value'];
|
|
2359
|
+
return ['checked', 'disabled', 'label', 'name', 'value', 'required'];
|
|
2060
2360
|
}
|
|
2061
2361
|
|
|
2362
|
+
static get hostStyles() { return checkControlSheet; }
|
|
2363
|
+
|
|
2062
2364
|
render() {
|
|
2063
2365
|
const label = this.createElement('label', ['glass-radio']);
|
|
2064
2366
|
|
|
@@ -2113,11 +2415,13 @@ class GlkRadio extends GlkFormElement {
|
|
|
2113
2415
|
|
|
2114
2416
|
this._input.addEventListener('change', this._onChange);
|
|
2115
2417
|
this._input.addEventListener('keydown', this._onKeyDown);
|
|
2418
|
+
this._unforwardClicks = forwardHostClicks(this, () => this._input);
|
|
2116
2419
|
}
|
|
2117
2420
|
|
|
2118
2421
|
teardownEvents() {
|
|
2119
2422
|
this._input?.removeEventListener('change', this._onChange);
|
|
2120
2423
|
this._input?.removeEventListener('keydown', this._onKeyDown);
|
|
2424
|
+
this._unforwardClicks?.();
|
|
2121
2425
|
}
|
|
2122
2426
|
|
|
2123
2427
|
/** Shared by user change and arrow-key selection, so both look identical. */
|
|
@@ -2152,6 +2456,26 @@ class GlkRadio extends GlkFormElement {
|
|
|
2152
2456
|
}
|
|
2153
2457
|
}
|
|
2154
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
|
+
|
|
2155
2479
|
onAttributeChanged(name) {
|
|
2156
2480
|
if (this._syncing) return;
|
|
2157
2481
|
if (!this._input) return;
|
|
@@ -2225,7 +2549,8 @@ class GlkRange extends GlkFormElement {
|
|
|
2225
2549
|
|
|
2226
2550
|
const header = this.createElement('div', ['glass-range-header']);
|
|
2227
2551
|
|
|
2228
|
-
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' });
|
|
2229
2554
|
this._labelEl.textContent = this.getAttribute('label') || '';
|
|
2230
2555
|
|
|
2231
2556
|
this._valueEl = this.createElement('span', ['glass-range-value']);
|
|
@@ -2234,6 +2559,7 @@ class GlkRange extends GlkFormElement {
|
|
|
2234
2559
|
header.appendChild(this._valueEl);
|
|
2235
2560
|
|
|
2236
2561
|
this._input = this.createElement('input', ['glass-range'], {
|
|
2562
|
+
id: 'field',
|
|
2237
2563
|
type: 'range',
|
|
2238
2564
|
min: this.getAttribute('min') || '0',
|
|
2239
2565
|
max: this.getAttribute('max') || '100',
|
|
@@ -2363,6 +2689,10 @@ function parseList(json) {
|
|
|
2363
2689
|
class GlkSegmented extends GlkFormElement {
|
|
2364
2690
|
static get observedAttributes() { return ['options', 'value', 'full', 'overflow', 'label']; }
|
|
2365
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
|
+
|
|
2366
2696
|
render() {
|
|
2367
2697
|
this._group = this.createElement('div', ['glass-segmented'], { role: 'group', part: 'group' });
|
|
2368
2698
|
this._wrapper.appendChild(this._group);
|
|
@@ -2487,7 +2817,7 @@ customElements.define('glk-segmented', GlkSegmented);
|
|
|
2487
2817
|
// today), value (YYYY-MM-DD), today (YYYY-MM-DD), min, max
|
|
2488
2818
|
// (YYYY-MM-DD; days outside cannot be picked), marks (JSON
|
|
2489
2819
|
// {date: tone | [tone, …]}, up to three dots), locale (default
|
|
2490
|
-
// the
|
|
2820
|
+
// the page language, else the browser's), week-start (0 = Sunday … 6 = Saturday;
|
|
2491
2821
|
// default from the locale, Monday where the browser cannot say),
|
|
2492
2822
|
// label (aria-label of the day group), prev-label / next-label
|
|
2493
2823
|
// (names of the nav buttons, English by default)
|
|
@@ -2525,6 +2855,9 @@ class GlkCalendar extends GlkFormElement {
|
|
|
2525
2855
|
return ['month', 'value', 'today', 'min', 'max', 'marks', 'locale', 'week-start', 'label', 'prev-label', 'next-label'];
|
|
2526
2856
|
}
|
|
2527
2857
|
|
|
2858
|
+
// Delegated focus would land on the month arrow, not on the chosen day.
|
|
2859
|
+
static get delegatesFocus() { return false; }
|
|
2860
|
+
|
|
2528
2861
|
render() {
|
|
2529
2862
|
this._root = this.createElement('div', ['glass-calendar'], { part: 'calendar' });
|
|
2530
2863
|
const head = this.createElement('div', ['glass-calendar__head'], { part: 'head' });
|
|
@@ -2545,7 +2878,7 @@ class GlkCalendar extends GlkFormElement {
|
|
|
2545
2878
|
get _todayIso() { return this.getAttribute('today') || isoDate(new Date()); }
|
|
2546
2879
|
|
|
2547
2880
|
_build() {
|
|
2548
|
-
const locale = resolveLocale(this.getAttribute('locale'));
|
|
2881
|
+
const locale = resolveLocale(this.getAttribute('locale'), this);
|
|
2549
2882
|
const f = formatters(locale);
|
|
2550
2883
|
const month = this.month;
|
|
2551
2884
|
const first = parseIso(month);
|
|
@@ -2722,7 +3055,7 @@ class GlkCalendar extends GlkFormElement {
|
|
|
2722
3055
|
get marks() { return parseJsonObject(this.getAttribute('marks')); }
|
|
2723
3056
|
set marks(v) { this.setAttribute('marks', typeof v === 'string' ? v : JSON.stringify(v ?? {})); }
|
|
2724
3057
|
|
|
2725
|
-
get locale() { return resolveLocale(this.getAttribute('locale')); }
|
|
3058
|
+
get locale() { return resolveLocale(this.getAttribute('locale'), this); }
|
|
2726
3059
|
set locale(v) {
|
|
2727
3060
|
if (v) this.setAttribute('locale', v);
|
|
2728
3061
|
else this.removeAttribute('locale');
|
|
@@ -2983,6 +3316,29 @@ class GlkProgress extends GlkElement {
|
|
|
2983
3316
|
|
|
2984
3317
|
customElements.define('glk-progress', GlkProgress);
|
|
2985
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
|
+
|
|
2986
3342
|
class GlkModal extends GlkElement {
|
|
2987
3343
|
static get observedAttributes() {
|
|
2988
3344
|
return ['open', 'title'];
|
|
@@ -2991,13 +3347,13 @@ class GlkModal extends GlkElement {
|
|
|
2991
3347
|
static get observesLightDom() { return true; }
|
|
2992
3348
|
|
|
2993
3349
|
render() {
|
|
2994
|
-
this._overlay = this.createElement('
|
|
3350
|
+
this._overlay = this.createElement('dialog', ['glass-modal-overlay'], { part: 'overlay' });
|
|
2995
3351
|
|
|
2996
3352
|
const modal = this.createElement('div', ['glass-modal'], { part: 'modal' });
|
|
2997
3353
|
|
|
2998
|
-
// Header
|
|
3354
|
+
// Header — the title names the dialog
|
|
2999
3355
|
const header = this.createElement('div', ['glass-modal__header'], { part: 'header' });
|
|
3000
|
-
this._titleEl = this.createElement('h2', ['glass-modal__title']);
|
|
3356
|
+
this._titleEl = this.createElement('h2', ['glass-modal__title'], { id: 'title' });
|
|
3001
3357
|
this.takeTitle();
|
|
3002
3358
|
this._applyTitle();
|
|
3003
3359
|
header.appendChild(this._titleEl);
|
|
@@ -3018,10 +3374,8 @@ class GlkModal extends GlkElement {
|
|
|
3018
3374
|
|
|
3019
3375
|
this._overlay.appendChild(modal);
|
|
3020
3376
|
this._wrapper.appendChild(this._overlay);
|
|
3021
|
-
|
|
3022
|
-
|
|
3023
|
-
this._overlay.classList.add('is-active');
|
|
3024
|
-
}
|
|
3377
|
+
// `open` is applied in setupEvents, which also runs when a moved element
|
|
3378
|
+
// comes back.
|
|
3025
3379
|
}
|
|
3026
3380
|
|
|
3027
3381
|
projectLightDom() {
|
|
@@ -3046,33 +3400,49 @@ class GlkModal extends GlkElement {
|
|
|
3046
3400
|
setupEvents() {
|
|
3047
3401
|
// Close on overlay click (outside modal)
|
|
3048
3402
|
this._onOverlayClick = (e) => {
|
|
3049
|
-
if (e.target === this._overlay)
|
|
3050
|
-
this.removeAttribute('open');
|
|
3051
|
-
this.emit('glk-close');
|
|
3052
|
-
}
|
|
3403
|
+
if (e.target === this._overlay) this._dismiss();
|
|
3053
3404
|
};
|
|
3054
3405
|
this._overlay.addEventListener('click', this._onOverlayClick);
|
|
3055
3406
|
|
|
3056
|
-
//
|
|
3057
|
-
this.
|
|
3058
|
-
|
|
3059
|
-
|
|
3060
|
-
this.emit('glk-close');
|
|
3061
|
-
}
|
|
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();
|
|
3062
3411
|
};
|
|
3063
|
-
|
|
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();
|
|
3064
3424
|
}
|
|
3065
3425
|
|
|
3066
3426
|
teardownEvents() {
|
|
3067
3427
|
this._overlay?.removeEventListener('click', this._onOverlayClick);
|
|
3068
|
-
|
|
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();
|
|
3069
3437
|
}
|
|
3070
3438
|
|
|
3071
3439
|
onAttributeChanged(name, _old, value) {
|
|
3072
3440
|
if (!this._overlay) return;
|
|
3073
3441
|
switch (name) {
|
|
3074
3442
|
case 'open':
|
|
3075
|
-
|
|
3443
|
+
if (!this.isConnected) return; // setupEvents applies it on connect
|
|
3444
|
+
if (this.open) this._show();
|
|
3445
|
+
else this._hide();
|
|
3076
3446
|
break;
|
|
3077
3447
|
case 'title':
|
|
3078
3448
|
if (this.takeTitle(value)) this._applyTitle();
|
|
@@ -3080,11 +3450,52 @@ class GlkModal extends GlkElement {
|
|
|
3080
3450
|
}
|
|
3081
3451
|
}
|
|
3082
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
|
+
|
|
3083
3491
|
show() { this.setAttribute('open', ''); }
|
|
3084
3492
|
close() { this.removeAttribute('open'); }
|
|
3085
3493
|
|
|
3086
3494
|
_applyTitle() {
|
|
3087
|
-
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');
|
|
3088
3499
|
}
|
|
3089
3500
|
|
|
3090
3501
|
// `title` is the heading, never a tooltip — see GlkElement.takeTitle().
|
|
@@ -3376,9 +3787,9 @@ class GlkPopover extends GlkElement {
|
|
|
3376
3787
|
render() {
|
|
3377
3788
|
this._anchor = this.createElement('div', ['glass-popover-anchor']);
|
|
3378
3789
|
|
|
3379
|
-
|
|
3380
|
-
|
|
3381
|
-
this._anchor.appendChild(
|
|
3790
|
+
this._triggerSlot = document.createElement('slot');
|
|
3791
|
+
this._triggerSlot.setAttribute('name', 'trigger');
|
|
3792
|
+
this._anchor.appendChild(this._triggerSlot);
|
|
3382
3793
|
|
|
3383
3794
|
this._popover = this.createElement('div', ['glass-popover']);
|
|
3384
3795
|
this._applyPlacement();
|
|
@@ -3402,7 +3813,23 @@ class GlkPopover extends GlkElement {
|
|
|
3402
3813
|
}
|
|
3403
3814
|
}
|
|
3404
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
|
+
|
|
3405
3828
|
setupEvents() {
|
|
3829
|
+
this._onSlotChange = () => this._applyExpanded();
|
|
3830
|
+
this._triggerSlot.addEventListener('slotchange', this._onSlotChange);
|
|
3831
|
+
this._applyExpanded();
|
|
3832
|
+
|
|
3406
3833
|
// Toggle when the slotted trigger is clicked.
|
|
3407
3834
|
this._onTriggerClick = (e) => {
|
|
3408
3835
|
const path = e.composedPath();
|
|
@@ -3434,6 +3861,7 @@ class GlkPopover extends GlkElement {
|
|
|
3434
3861
|
}
|
|
3435
3862
|
|
|
3436
3863
|
teardownEvents() {
|
|
3864
|
+
this._triggerSlot?.removeEventListener('slotchange', this._onSlotChange);
|
|
3437
3865
|
this.removeEventListener('click', this._onTriggerClick);
|
|
3438
3866
|
document.removeEventListener('click', this._onDocClick);
|
|
3439
3867
|
document.removeEventListener('keydown', this._onKeydown);
|
|
@@ -3445,6 +3873,7 @@ class GlkPopover extends GlkElement {
|
|
|
3445
3873
|
case 'open': {
|
|
3446
3874
|
const isOpen = this.getBoolAttr('open');
|
|
3447
3875
|
this._popover.classList.toggle('is-open', isOpen);
|
|
3876
|
+
this._applyExpanded();
|
|
3448
3877
|
this.emit(isOpen ? 'glk-open' : 'glk-close');
|
|
3449
3878
|
break;
|
|
3450
3879
|
}
|
|
@@ -3637,17 +4066,19 @@ class GlkAccordionItem extends GlkElement {
|
|
|
3637
4066
|
|
|
3638
4067
|
render() {
|
|
3639
4068
|
this._item = this.createElement('div', ['glass-accordion__item']);
|
|
3640
|
-
if (this.getBoolAttr('open')) this._item.classList.add('is-open');
|
|
3641
4069
|
|
|
3642
|
-
// Trigger button
|
|
3643
|
-
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
|
+
});
|
|
3644
4075
|
this.takeTitle();
|
|
3645
4076
|
this._triggerText = document.createTextNode(this._title || '');
|
|
3646
4077
|
this._trigger.appendChild(this._triggerText);
|
|
3647
4078
|
this._trigger.insertAdjacentHTML('beforeend', CHEVRON_SVG);
|
|
3648
4079
|
|
|
3649
4080
|
// Content
|
|
3650
|
-
this._content = this.createElement('div', ['glass-accordion__content']);
|
|
4081
|
+
this._content = this.createElement('div', ['glass-accordion__content'], { id: 'content' });
|
|
3651
4082
|
const body = this.createElement('div', ['glass-accordion__body']);
|
|
3652
4083
|
body.appendChild(document.createElement('slot'));
|
|
3653
4084
|
this._content.appendChild(body);
|
|
@@ -3656,6 +4087,19 @@ class GlkAccordionItem extends GlkElement {
|
|
|
3656
4087
|
this._item.appendChild(this._content);
|
|
3657
4088
|
|
|
3658
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;
|
|
3659
4103
|
}
|
|
3660
4104
|
|
|
3661
4105
|
setupEvents() {
|
|
@@ -3674,7 +4118,7 @@ class GlkAccordionItem extends GlkElement {
|
|
|
3674
4118
|
if (!this._item) return;
|
|
3675
4119
|
switch (name) {
|
|
3676
4120
|
case 'open':
|
|
3677
|
-
this.
|
|
4121
|
+
this._applyOpen();
|
|
3678
4122
|
break;
|
|
3679
4123
|
case 'title':
|
|
3680
4124
|
if (this.takeTitle(value)) this._applyTitle();
|