@jungherz-de/glasskit-elements 1.8.0 → 1.10.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/README.md +39 -4
- package/dist/components/glk-accordion-item.js +1 -1
- package/dist/components/glk-accordion.js +1 -1
- package/dist/components/glk-avatar.js +1 -1
- package/dist/components/glk-badge.js +1 -1
- package/dist/components/glk-button.js +1 -1
- package/dist/components/glk-card.js +1 -1
- package/dist/components/glk-checkbox.js +1 -1
- package/dist/components/glk-divider.js +1 -1
- package/dist/components/glk-input.js +1 -1
- package/dist/components/glk-list-item.js +1 -1
- package/dist/components/glk-list.js +1 -1
- package/dist/components/glk-modal.js +1 -1
- package/dist/components/glk-nav.js +1 -1
- package/dist/components/glk-pill.js +1 -1
- package/dist/components/glk-popover.js +1 -1
- package/dist/components/glk-progress.js +1 -1
- package/dist/components/glk-radio.js +1 -1
- package/dist/components/glk-range.js +1 -1
- package/dist/components/glk-search.js +1 -1
- package/dist/components/glk-select.js +1 -1
- package/dist/components/glk-status.js +1 -1
- package/dist/components/glk-tab-accessory.js +1 -1
- package/dist/components/glk-tab-bar.js +1 -1
- package/dist/components/glk-tab-dock.js +1 -1
- package/dist/components/glk-tab-item.js +1 -1
- package/dist/components/glk-textarea.js +1 -1
- package/dist/components/glk-title.js +1 -1
- package/dist/components/glk-toast.js +1 -1
- package/dist/components/glk-toggle.js +1 -1
- package/dist/components/shared/base-BzDV6jE3.js +240 -0
- package/dist/glasskit-elements.esm.js +44 -3
- package/dist/glasskit-elements.js +44 -3
- package/dist/glasskit-elements.min.js +1 -1
- package/package.json +3 -3
- package/src/base.js +29 -2
- package/dist/components/shared/base-Bm9Z714o.js +0 -199
package/README.md
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
<a href="#"><img src="https://img.shields.io/badge/vanilla_JS-no_dependencies-44cc11?style=flat-square" alt="Vanilla JS"></a>
|
|
6
6
|
<a href="#"><img src="https://img.shields.io/badge/components-29-7ec8e3?style=flat-square" alt="29 Components"></a>
|
|
7
7
|
<a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue?style=flat-square" alt="MIT License"></a>
|
|
8
|
-
<a href="CHANGELOG.md"><img src="https://img.shields.io/badge/changelog-v1.
|
|
8
|
+
<a href="CHANGELOG.md"><img src="https://img.shields.io/badge/changelog-v1.10.0-lightgrey?style=flat-square" alt="Changelog"></a>
|
|
9
9
|
<a href="https://www.npmjs.com/package/@jungherz-de/glasskit-elements"><img src="https://img.shields.io/badge/npm-%40jungherz--de%2Fglasskit--elements-cb3837?style=flat-square&logo=npm" alt="npm"></a>
|
|
10
10
|
</p>
|
|
11
11
|
|
|
@@ -66,7 +66,7 @@ It is the **app layer** of the GlassKit family — three layers, one design lang
|
|
|
66
66
|
|
|
67
67
|
```html
|
|
68
68
|
<!-- 1. GlassKit CSS -->
|
|
69
|
-
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@jungherz-de/glasskit@1.
|
|
69
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@jungherz-de/glasskit@1.10/glasskit.min.css">
|
|
70
70
|
|
|
71
71
|
<!-- 2. GlassKit Elements -->
|
|
72
72
|
<script src="https://cdn.jsdelivr.net/npm/@jungherz-de/glasskit-elements/dist/glasskit-elements.min.js"></script>
|
|
@@ -99,7 +99,7 @@ import '@jungherz-de/glasskit-elements/components/glk-toggle.js';
|
|
|
99
99
|
<!DOCTYPE html>
|
|
100
100
|
<html data-theme="dark">
|
|
101
101
|
<head>
|
|
102
|
-
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@jungherz-de/glasskit@1.
|
|
102
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@jungherz-de/glasskit@1.10/glasskit.min.css">
|
|
103
103
|
<script src="https://cdn.jsdelivr.net/npm/@jungherz-de/glasskit-elements/dist/glasskit-elements.min.js"></script>
|
|
104
104
|
</head>
|
|
105
105
|
<body>
|
|
@@ -192,11 +192,46 @@ const current = html.getAttribute('data-theme');
|
|
|
192
192
|
html.setAttribute('data-theme', current === 'dark' ? 'light' : 'dark');
|
|
193
193
|
```
|
|
194
194
|
|
|
195
|
+
### Icons
|
|
196
|
+
|
|
197
|
+
Pass an icon as a **direct child**, not wrapped:
|
|
198
|
+
|
|
199
|
+
```html
|
|
200
|
+
<glk-button><svg viewBox="0 0 24 24">…</svg>Save</glk-button>
|
|
201
|
+
<glk-list-item title="Download"><svg slot="leading" viewBox="0 0 24 24">…</svg></glk-list-item>
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
> **Requires GlassKit CSS >= 1.10.0.** The icon rules are descendant selectors, and a
|
|
205
|
+
> slotted icon stays in the light DOM — before 1.10.0 they never matched it, so button
|
|
206
|
+
> icons filled their container and list icons collapsed to 0×0. Wrapping the icon in a
|
|
207
|
+
> `<span slot="…">` still does not work: `::slotted()` cannot reach inside an assigned
|
|
208
|
+
> node. Size it yourself if you must wrap it.
|
|
209
|
+
|
|
210
|
+
### Branding
|
|
211
|
+
|
|
212
|
+
Override GlassKit's `--gl-*` tokens anywhere in the document. Every `<glk-*>` element
|
|
213
|
+
inherits them — no JavaScript, no per-element setup:
|
|
214
|
+
|
|
215
|
+
```css
|
|
216
|
+
/* brand.css, loaded after glasskit.css */
|
|
217
|
+
:root, [data-theme='dark'] { --gl-color-primary: #2e9e8f; }
|
|
218
|
+
[data-theme='light'] { --gl-color-primary: #21786d; }
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
> **Requires 1.9.0.** Before that, every element re-declared the tokens inside its own
|
|
222
|
+
> shadow root, so document-level overrides were silently ignored in components while
|
|
223
|
+
> still applying to plain `.glass-*` markup — projects came out half-branded. If you are
|
|
224
|
+
> upgrading from ≤1.8.0 and already ship a brand stylesheet, expect your components to
|
|
225
|
+
> change to the colors you intended all along.
|
|
226
|
+
|
|
227
|
+
Token defaults are placed on the document once, inside `@layer glasskit-defaults`, so
|
|
228
|
+
pages that never load `glasskit.css` still work and your brand file always wins.
|
|
229
|
+
|
|
195
230
|
---
|
|
196
231
|
|
|
197
232
|
## 🛠️ Architecture
|
|
198
233
|
|
|
199
|
-
- **Shadow DOM** with `adoptedStyleSheets` — GlassKit's `
|
|
234
|
+
- **Shadow DOM** with `adoptedStyleSheets` — GlassKit's `componentsSheet` is shared across all component instances; token declarations stay on the document so branding can be inherited
|
|
200
235
|
- **Theme wrapper** with `display: contents` — layout-transparent `<div>` for `data-theme` CSS selectors
|
|
201
236
|
- **Global `MutationObserver`** — single observer watches `data-theme` changes and syncs all instances
|
|
202
237
|
- **`GlkElement`** base class — handles Shadow DOM setup, theme sync, attribute reflection
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { G as GlkElement } from './shared/base-
|
|
1
|
+
import { G as GlkElement } from './shared/base-BzDV6jE3.js';
|
|
2
2
|
|
|
3
3
|
const CHEVRON_SVG = `<span class="glass-accordion__trigger-icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><polyline points="6 9 12 15 18 9"/></svg></span>`;
|
|
4
4
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { G as GlkElement } from './shared/base-
|
|
1
|
+
import { G as GlkElement } from './shared/base-BzDV6jE3.js';
|
|
2
2
|
|
|
3
3
|
// <glk-card fill> stretches the visible card to the height of its grid or flex
|
|
4
4
|
// cell. The host must become a grid for this: it is stretched by the outer
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as GlkFormElement } from './shared/base-
|
|
1
|
+
import { a as GlkFormElement } from './shared/base-BzDV6jE3.js';
|
|
2
2
|
|
|
3
3
|
const CHECKMARK_SVG = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"/></svg>`;
|
|
4
4
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as GlkFormElement } from './shared/base-
|
|
1
|
+
import { a as GlkFormElement } from './shared/base-BzDV6jE3.js';
|
|
2
2
|
|
|
3
3
|
const SEARCH_SVG = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>`;
|
|
4
4
|
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
// GlassKit v1.10.0 – Constructable Stylesheet
|
|
2
|
+
// Auto-generated by build-styles-js.mjs – do not edit manually.
|
|
3
|
+
|
|
4
|
+
// The [data-theme] blocks that declare --gl-* …
|
|
5
|
+
const tokensCss = ":root,[data-theme=dark]{color-scheme:dark;--gl-color-primary:#f5a623;--gl-color-primary-dark:#d4692a;--gl-color-primary-mid:#e07a24;--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-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-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:rgba(255, 200, 100, 0.35);--gl-border-focus:rgba(245, 166, 35, 0.60);--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 rgba(230, 130, 40, 0.35),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 rgba(245, 166, 35, 0.3);--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:#d97826;--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-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-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:rgba(232, 133, 45, 0.30);--gl-border-focus:rgba(232, 133, 45, 0.50);--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 rgba(232, 133, 45, 0.25),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 rgba(232, 133, 45, 0.25);--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
|
+
|
|
7
|
+
// … and everything else, in two pieces around where they were.
|
|
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}.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:0}.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:0}.glass-bg>*{position:relative;z-index:1}.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 ::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: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:center;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}.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}.glass-checkbox{display:inline-flex;align-items:center;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}.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}.glass-radio{display:inline-flex;align-items:center;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}.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}.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 rgba(230,130,40,.35),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 rgba(230,130,40,.35);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-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-width:2;fill:none;stroke-linecap:round;stroke-linejoin:round}.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{font-size:var(--gl-font-size-sm);font-weight:var(--gl-font-weight-medium);color:var(--gl-color-text);line-height:1.4}.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{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{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{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{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-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}.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/*# sourceMappingURL=glasskit.min.css.map */";
|
|
10
|
+
|
|
11
|
+
const componentsCss = componentsHead + componentsTail;
|
|
12
|
+
const css = componentsHead + tokensCss + componentsTail;
|
|
13
|
+
|
|
14
|
+
const glassSheet = new CSSStyleSheet();
|
|
15
|
+
glassSheet.replaceSync(css);
|
|
16
|
+
|
|
17
|
+
const tokensSheet = new CSSStyleSheet();
|
|
18
|
+
tokensSheet.replaceSync(tokensCss);
|
|
19
|
+
|
|
20
|
+
const componentsSheet = new CSSStyleSheet();
|
|
21
|
+
componentsSheet.replaceSync(componentsCss);
|
|
22
|
+
|
|
23
|
+
// ── Design Tokens ──
|
|
24
|
+
// The shadow roots deliberately adopt the *components* sheet only. Adopting
|
|
25
|
+
// the full GlassKit sheet would bring its [data-theme] blocks along, and those
|
|
26
|
+
// match the .glk-wrapper below — the tokens would then be re-declared inside
|
|
27
|
+
// every shadow root, where a matching rule always beats an inherited value.
|
|
28
|
+
// A project's own `:root { --gl-color-primary: … }` would never arrive.
|
|
29
|
+
//
|
|
30
|
+
// So the token defaults go on the document once, and every shadow root
|
|
31
|
+
// inherits them like any other custom property. They are wrapped in a cascade
|
|
32
|
+
// layer so an ordinary (unlayered) brand stylesheet wins over them, no matter
|
|
33
|
+
// whether it loads before or after this module.
|
|
34
|
+
|
|
35
|
+
const TOKENS_INJECTED = '__glkDefaultTokensInjected';
|
|
36
|
+
|
|
37
|
+
function injectDefaultTokens() {
|
|
38
|
+
if (typeof document === 'undefined') return; // SSR / non-DOM
|
|
39
|
+
if (globalThis[TOKENS_INJECTED]) return; // another bundle copy did it
|
|
40
|
+
globalThis[TOKENS_INJECTED] = true;
|
|
41
|
+
|
|
42
|
+
const sheet = new CSSStyleSheet();
|
|
43
|
+
sheet.replaceSync(`@layer glasskit-defaults { ${tokensCss} }`);
|
|
44
|
+
// Append — never assign — so an app's own adopted sheets survive.
|
|
45
|
+
document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet];
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
injectDefaultTokens();
|
|
49
|
+
|
|
50
|
+
// ── Global Theme Sync ──
|
|
51
|
+
// Single MutationObserver that watches data-theme on <html>
|
|
52
|
+
// and notifies all GlkElement instances.
|
|
53
|
+
|
|
54
|
+
const instances = new Set();
|
|
55
|
+
|
|
56
|
+
function getCurrentTheme() {
|
|
57
|
+
return document.documentElement.getAttribute('data-theme') || 'dark';
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function syncAllThemes() {
|
|
61
|
+
const theme = getCurrentTheme();
|
|
62
|
+
for (const instance of instances) {
|
|
63
|
+
instance._syncTheme(theme);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (typeof window !== 'undefined' && typeof MutationObserver !== 'undefined') {
|
|
68
|
+
const observer = new MutationObserver(syncAllThemes);
|
|
69
|
+
observer.observe(document.documentElement, {
|
|
70
|
+
attributes: true,
|
|
71
|
+
attributeFilter: ['data-theme']
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// ── Host Stylesheet ──
|
|
76
|
+
// Sets display:block on all custom elements by default.
|
|
77
|
+
// Inline components (badge, avatar) override this.
|
|
78
|
+
|
|
79
|
+
const hostSheet = new CSSStyleSheet();
|
|
80
|
+
hostSheet.replaceSync(`
|
|
81
|
+
:host { display: block; }
|
|
82
|
+
:host([hidden]) { display: none; }
|
|
83
|
+
.glk-wrapper { display: contents; }
|
|
84
|
+
`);
|
|
85
|
+
|
|
86
|
+
const inlineHostSheet = new CSSStyleSheet();
|
|
87
|
+
inlineHostSheet.replaceSync(`
|
|
88
|
+
:host { display: inline-block; }
|
|
89
|
+
:host([hidden]) { display: none; }
|
|
90
|
+
.glk-wrapper { display: contents; }
|
|
91
|
+
`);
|
|
92
|
+
|
|
93
|
+
// ── Base Class ──
|
|
94
|
+
|
|
95
|
+
class GlkElement extends HTMLElement {
|
|
96
|
+
|
|
97
|
+
/** Override in subclass to use inline-block display */
|
|
98
|
+
static get displayInline() { return false; }
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Optional CSSStyleSheet with component-specific host rules, adopted after
|
|
102
|
+
* the shared sheets. Keeps per-component selectors out of the shared sheet
|
|
103
|
+
* so an attribute like [fill] only means something where it is documented.
|
|
104
|
+
*/
|
|
105
|
+
static get hostStyles() { return null; }
|
|
106
|
+
|
|
107
|
+
static get observedAttributes() {
|
|
108
|
+
return [];
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
constructor() {
|
|
112
|
+
super();
|
|
113
|
+
this._initialized = false;
|
|
114
|
+
this._shadow = this.attachShadow({ mode: 'open' });
|
|
115
|
+
const displaySheet = this.constructor.displayInline ? inlineHostSheet : hostSheet;
|
|
116
|
+
const sheets = [componentsSheet, displaySheet];
|
|
117
|
+
const extra = this.constructor.hostStyles;
|
|
118
|
+
if (extra) sheets.push(extra);
|
|
119
|
+
this._shadow.adoptedStyleSheets = sheets;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
connectedCallback() {
|
|
123
|
+
if (!this._initialized) {
|
|
124
|
+
this._initialized = true;
|
|
125
|
+
|
|
126
|
+
// Create theme wrapper (display:contents makes it layout-transparent)
|
|
127
|
+
this._wrapper = document.createElement('div');
|
|
128
|
+
this._wrapper.className = 'glk-wrapper';
|
|
129
|
+
this._wrapper.setAttribute('data-theme', getCurrentTheme());
|
|
130
|
+
this._shadow.appendChild(this._wrapper);
|
|
131
|
+
|
|
132
|
+
this.render();
|
|
133
|
+
this.setupEvents();
|
|
134
|
+
|
|
135
|
+
// Register for theme sync
|
|
136
|
+
instances.add(this);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
disconnectedCallback() {
|
|
141
|
+
instances.delete(this);
|
|
142
|
+
this.teardownEvents();
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
attributeChangedCallback(name, oldValue, newValue) {
|
|
146
|
+
if (!this._initialized) return;
|
|
147
|
+
if (oldValue === newValue) return;
|
|
148
|
+
this.onAttributeChanged(name, oldValue, newValue);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
_syncTheme(theme) {
|
|
152
|
+
if (this._wrapper) {
|
|
153
|
+
this._wrapper.setAttribute('data-theme', theme);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/** Subclasses override to build inner DOM inside this._wrapper. */
|
|
158
|
+
render() {}
|
|
159
|
+
|
|
160
|
+
/** Subclasses override to attach event listeners. */
|
|
161
|
+
setupEvents() {}
|
|
162
|
+
|
|
163
|
+
/** Subclasses override to remove event listeners. */
|
|
164
|
+
teardownEvents() {}
|
|
165
|
+
|
|
166
|
+
/** Subclasses override to react to attribute changes. */
|
|
167
|
+
onAttributeChanged(name, oldValue, newValue) {}
|
|
168
|
+
|
|
169
|
+
// ── Utility Methods ──
|
|
170
|
+
|
|
171
|
+
getBoolAttr(name) {
|
|
172
|
+
return this.hasAttribute(name);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
setBoolAttr(name, value) {
|
|
176
|
+
if (value) {
|
|
177
|
+
this.setAttribute(name, '');
|
|
178
|
+
} else {
|
|
179
|
+
this.removeAttribute(name);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
createElement(tag, classes = [], attrs = {}) {
|
|
184
|
+
const el = document.createElement(tag);
|
|
185
|
+
if (classes.length) el.classList.add(...classes);
|
|
186
|
+
for (const [key, val] of Object.entries(attrs)) {
|
|
187
|
+
el.setAttribute(key, val);
|
|
188
|
+
}
|
|
189
|
+
return el;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
emit(eventName, detail = null) {
|
|
193
|
+
this.dispatchEvent(new CustomEvent(eventName, {
|
|
194
|
+
bubbles: true,
|
|
195
|
+
composed: true,
|
|
196
|
+
detail
|
|
197
|
+
}));
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// ── Form-Associated Base Class ──
|
|
202
|
+
|
|
203
|
+
class GlkFormElement extends GlkElement {
|
|
204
|
+
|
|
205
|
+
static formAssociated = true;
|
|
206
|
+
|
|
207
|
+
constructor() {
|
|
208
|
+
super();
|
|
209
|
+
this._internals = this.attachInternals();
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
get form() { return this._internals.form; }
|
|
213
|
+
get validationMessage() { return this._internals.validationMessage; }
|
|
214
|
+
get validity() { return this._internals.validity; }
|
|
215
|
+
|
|
216
|
+
checkValidity() { return this._internals.checkValidity(); }
|
|
217
|
+
reportValidity() { return this._internals.reportValidity(); }
|
|
218
|
+
|
|
219
|
+
formResetCallback() {
|
|
220
|
+
this.resetValue();
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
formStateRestoreCallback(state, mode) {
|
|
224
|
+
this.restoreValue(state);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/** Subclasses override. */
|
|
228
|
+
resetValue() {}
|
|
229
|
+
restoreValue(state) {}
|
|
230
|
+
|
|
231
|
+
setFormValue(value) {
|
|
232
|
+
this._internals.setFormValue(value);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
setValidity(flags, message, anchor) {
|
|
236
|
+
this._internals.setValidity(flags, message, anchor);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
export { GlkElement as G, GlkFormElement as a };
|