{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "template-still",
  "title": "Still",
  "description": "A dark landing page for a meditation app, with a breathing guide, sound scenes, a story carousel and store links, built from Glassy UI components.",
  "files": [
    {
      "path": "registry/glassyui/glass-provider.tsx",
      "content": "'use client';\n\nimport './styles/liquid.css';\n\nimport {\n  createContext,\n  useCallback,\n  useContext,\n  useEffect,\n  useMemo,\n  useState,\n  useSyncExternalStore,\n  type ReactNode,\n} from 'react';\nimport {\n  applyPreferences,\n  computeAutomaticSafeguards,\n  GLASS_THICKNESS,\n  loadPreferences,\n  persistPreferences,\n  type GlassyUiPreferences,\n  type GlassyUiTheme,\n} from './lib/preferences';\n\ntype PreferenceState = Required<GlassyUiPreferences>;\n\ntype SystemPreferenceState = Pick<\n  PreferenceState,\n  'theme' | 'quality' | 'reduceMotion' | 'reduceTransparency'\n>;\n\ntype PreferenceSources = {\n  explicit: GlassyUiPreferences;\n  system: SystemPreferenceState;\n};\n\ntype PreferenceContextValue = {\n  preferences: PreferenceState;\n  setPreferences: (prefs: Partial<GlassyUiPreferences>) => void;\n};\n\nconst DEFAULT_STATE: PreferenceState = {\n  theme: 'dark',\n  mode: 'clear',\n  reduceTransparency: false,\n  reduceMotion: false,\n  quality: 'high',\n  thickness: GLASS_THICKNESS.regular,\n};\n\nconst SERVER_SOURCES: PreferenceSources = {\n  explicit: {},\n  system: {\n    theme: DEFAULT_STATE.theme,\n    quality: DEFAULT_STATE.quality,\n    reduceMotion: DEFAULT_STATE.reduceMotion,\n    reduceTransparency: DEFAULT_STATE.reduceTransparency,\n  },\n};\n\nconst subscribeToHydration = () => () => {};\n\nconst transparencyQuery = '(prefers-reduced-transparency: reduce)';\n\nfunction subscribeToSystemTransparency(onChange: () => void) {\n  const query = window.matchMedia(transparencyQuery);\n  query.addEventListener('change', onChange);\n\n  return () => query.removeEventListener('change', onChange);\n}\n\nconst readSystemTransparency = () => window.matchMedia(transparencyQuery).matches;\n\nconst readServerTransparency = () => DEFAULT_STATE.reduceTransparency;\n\nconst PreferencesContext = createContext<PreferenceContextValue | null>(null);\n\nfunction warnPreferenceFailure(message: string, cause: unknown) {\n  console.warn(message, cause);\n}\n\nfunction mergePreferences(\n  base: PreferenceState,\n  next: Partial<GlassyUiPreferences>,\n): PreferenceState {\n  return {\n    ...base,\n    ...next,\n  };\n}\n\nfunction readSystemPreferences(): SystemPreferenceState {\n  if (typeof window === 'undefined') {\n    return {\n      theme: DEFAULT_STATE.theme,\n      quality: DEFAULT_STATE.quality,\n      reduceMotion: DEFAULT_STATE.reduceMotion,\n      reduceTransparency: DEFAULT_STATE.reduceTransparency,\n    };\n  }\n\n  const automatic = computeAutomaticSafeguards();\n\n  const systemPrefersLight =\n    window.matchMedia && window.matchMedia('(prefers-color-scheme: light)').matches;\n\n  return {\n    theme: systemPrefersLight ? 'light' : DEFAULT_STATE.theme,\n    quality: automatic.quality,\n    reduceMotion: automatic.reduceMotion,\n    reduceTransparency: automatic.reduceTransparency,\n  };\n}\n\nfunction readInitialPreferenceSources(): PreferenceSources {\n  if (typeof window === 'undefined') {\n    return { explicit: {}, system: readSystemPreferences() };\n  }\n\n  let explicit: GlassyUiPreferences = {};\n\n  try {\n    explicit = loadPreferences();\n  } catch (error) {\n    warnPreferenceFailure('Failed to load Glassy UI preferences', error);\n  }\n\n  return { explicit, system: readSystemPreferences() };\n}\n\n/**\n * Holds the glass preferences and applies them to the document. `defaultTheme` is the theme a\n * visitor sees until they choose one, whatever their system prefers; leave it out to follow the\n * system setting.\n */\nexport function GlassProvider({\n  children,\n  defaultTheme,\n}: {\n  children: ReactNode;\n  defaultTheme?: GlassyUiTheme;\n}) {\n  const [sources, setSources] = useState<PreferenceSources>(readInitialPreferenceSources);\n\n  const hydrated = useSyncExternalStore(\n    subscribeToHydration,\n    () => true,\n    () => false,\n  );\n\n  const activeSources = hydrated ? sources : SERVER_SOURCES;\n\n  const preferences = useMemo(\n    () =>\n      mergePreferences(\n        mergePreferences(\n          DEFAULT_STATE,\n          defaultTheme ? { ...activeSources.system, theme: defaultTheme } : activeSources.system,\n        ),\n        activeSources.explicit,\n      ),\n    [activeSources, defaultTheme],\n  );\n\n  useEffect(() => {\n    if (!hydrated || typeof document === 'undefined') {\n      return;\n    }\n\n    applyPreferences(document, preferences);\n  }, [hydrated, preferences]);\n\n  const update = useCallback((next: Partial<GlassyUiPreferences>) => {\n    // The document changes before React renders whatever asked for the change, so a\n    // control's own flip runs under the setting it lands in. Turning Reduce Motion off\n    // from its own switch then animates instead of snapping under the old setting.\n    if (typeof document !== 'undefined') {\n      applyPreferences(document, next);\n    }\n\n    setSources((previous) => {\n      const explicit = { ...previous.explicit, ...next };\n\n      if (typeof window !== 'undefined') {\n        try {\n          persistPreferences(explicit);\n        } catch (error) {\n          warnPreferenceFailure('Failed to persist Glassy UI preferences', error);\n        }\n      }\n\n      return { ...previous, explicit };\n    });\n  }, []);\n\n  useEffect(() => {\n    if (typeof window === 'undefined') {\n      return;\n    }\n\n    const queries = [\n      '(prefers-color-scheme: light)',\n      '(prefers-reduced-motion: reduce)',\n      '(prefers-reduced-transparency: reduce)',\n      '(pointer: coarse)',\n    ].map((query) => window.matchMedia(query));\n\n    const handler = () => {\n      setSources((previous) => ({ ...previous, system: readSystemPreferences() }));\n    };\n\n    queries.forEach((query) => query.addEventListener('change', handler));\n\n    return () => queries.forEach((query) => query.removeEventListener('change', handler));\n  }, []);\n\n  const value = useMemo<PreferenceContextValue>(\n    () => ({\n      preferences,\n      setPreferences: update,\n    }),\n    [preferences, update],\n  );\n\n  return <PreferencesContext.Provider value={value}>{children}</PreferencesContext.Provider>;\n}\n\nexport const PreferencesProvider = GlassProvider;\n\nexport function useOptionalPreferences() {\n  const context = useContext(PreferencesContext);\n\n  const reduceTransparency = useSyncExternalStore(\n    context ? subscribeToHydration : subscribeToSystemTransparency,\n    context ? () => context.preferences.reduceTransparency : readSystemTransparency,\n    readServerTransparency,\n  );\n\n  return (\n    context ?? {\n      preferences: { ...DEFAULT_STATE, reduceTransparency },\n      setPreferences: () => {},\n    }\n  );\n}\n\nexport function usePreferences() {\n  const context = useContext(PreferencesContext);\n\n  if (!context) {\n    throw new Error('usePreferences must be used within PreferencesProvider');\n  }\n\n  return context;\n}\n",
      "type": "registry:ui",
      "target": "components/glassyui/glass-provider.tsx"
    },
    {
      "path": "registry/glassyui/liquid-filters.tsx",
      "content": "export function LiquidFilters() {\n  return (\n    <svg\n      aria-hidden=\"true\"\n      focusable=\"false\"\n      className=\"lg-svg-filters\"\n      style={{ position: 'absolute', width: 0, height: 0, overflow: 'hidden' }}\n    >\n      <defs>\n        {/*\n          Simplified high-performance refraction filter.\n          Uses userSpaceOnUse for pixel-accurate displacement.\n          Chromatic aberration via RGB channel separation + offset.\n        */}\n        <filter\n          id=\"lg-liquid-refraction\"\n          x=\"-10%\"\n          y=\"-10%\"\n          width=\"120%\"\n          height=\"120%\"\n          filterUnits=\"objectBoundingBox\"\n          primitiveUnits=\"userSpaceOnUse\"\n          colorInterpolationFilters=\"sRGB\"\n        >\n          {/* Load bowl-shaped displacement map */}\n          <feImage href={DISPLACEMENT_MAP} preserveAspectRatio=\"none\" result=\"dispMap\" />\n\n          {/* Blur the background for glass diffusion - single pass for performance */}\n          <feGaussianBlur in=\"BackgroundImage\" stdDeviation=\"12\" result=\"blurred\" />\n\n          {/* Apply displacement based on bowl map */}\n          <feDisplacementMap\n            in=\"blurred\"\n            in2=\"dispMap\"\n            scale=\"20\"\n            xChannelSelector=\"R\"\n            yChannelSelector=\"G\"\n            result=\"displaced\"\n          />\n\n          {/* Chromatic aberration: separate RGB channels */}\n          <feColorMatrix\n            in=\"displaced\"\n            type=\"matrix\"\n            values=\"1 0 0 0 0  0 0 0 0 0  0 0 0 0 0  0 0 0 1 0\"\n            result=\"redChannel\"\n          />\n          <feColorMatrix\n            in=\"displaced\"\n            type=\"matrix\"\n            values=\"0 0 0 0 0  0 1 0 0 0  0 0 0 0 0  0 0 0 1 0\"\n            result=\"greenChannel\"\n          />\n          <feColorMatrix\n            in=\"displaced\"\n            type=\"matrix\"\n            values=\"0 0 0 0 0  0 0 0 0 0  0 0 1 0 0  0 0 0 1 0\"\n            result=\"blueChannel\"\n          />\n\n          {/* Offset channels for chromatic dispersion (Cauchy: blue bends more) */}\n          <feOffset in=\"redChannel\" dx=\"-1.5\" dy=\"-1\" result=\"redShift\" />\n          <feOffset in=\"greenChannel\" dx=\"0\" dy=\"0\" result=\"greenShift\" />\n          <feOffset in=\"blueChannel\" dx=\"1.5\" dy=\"1\" result=\"blueShift\" />\n\n          {/* Recombine RGB channels */}\n          <feBlend in=\"redShift\" in2=\"greenShift\" mode=\"screen\" result=\"rgMix\" />\n          <feBlend in=\"rgMix\" in2=\"blueShift\" mode=\"screen\" result=\"chromatic\" />\n\n          {/* Boost saturation slightly for vibrancy */}\n          <feColorMatrix in=\"chromatic\" type=\"saturate\" values=\"1.15\" result=\"refracted\" />\n\n          {/* Composite with source (glass tint overlay) */}\n          <feBlend in=\"SourceGraphic\" in2=\"refracted\" mode=\"normal\" />\n        </filter>\n\n        {/* Light mode specific filter with stronger chromatic aberration */}\n        <filter\n          id=\"lg-liquid-refraction-light\"\n          x=\"-10%\"\n          y=\"-10%\"\n          width=\"120%\"\n          height=\"120%\"\n          filterUnits=\"objectBoundingBox\"\n          primitiveUnits=\"userSpaceOnUse\"\n          colorInterpolationFilters=\"sRGB\"\n        >\n          <feImage href={DISPLACEMENT_MAP} preserveAspectRatio=\"none\" result=\"dispMap\" />\n\n          {/* Less blur in light mode for sharper refractions */}\n          <feGaussianBlur in=\"BackgroundImage\" stdDeviation=\"8\" result=\"blurred\" />\n\n          <feDisplacementMap\n            in=\"blurred\"\n            in2=\"dispMap\"\n            scale=\"25\"\n            xChannelSelector=\"R\"\n            yChannelSelector=\"G\"\n            result=\"displaced\"\n          />\n\n          {/* Stronger chromatic separation for light mode */}\n          <feColorMatrix\n            in=\"displaced\"\n            type=\"matrix\"\n            values=\"1 0 0 0 0  0 0 0 0 0  0 0 0 0 0  0 0 0 1 0\"\n            result=\"redChannel\"\n          />\n          <feColorMatrix\n            in=\"displaced\"\n            type=\"matrix\"\n            values=\"0 0 0 0 0  0 1 0 0 0  0 0 0 0 0  0 0 0 1 0\"\n            result=\"greenChannel\"\n          />\n          <feColorMatrix\n            in=\"displaced\"\n            type=\"matrix\"\n            values=\"0 0 0 0 0  0 0 0 0 0  0 0 1 0 0  0 0 0 1 0\"\n            result=\"blueChannel\"\n          />\n\n          {/* Stronger offsets for visible chromatic aberration */}\n          <feOffset in=\"redChannel\" dx=\"-2\" dy=\"-1.5\" result=\"redShift\" />\n          <feOffset in=\"greenChannel\" dx=\"0\" dy=\"0\" result=\"greenShift\" />\n          <feOffset in=\"blueChannel\" dx=\"2\" dy=\"1.5\" result=\"blueShift\" />\n\n          <feBlend in=\"redShift\" in2=\"greenShift\" mode=\"screen\" result=\"rgMix\" />\n          <feBlend in=\"rgMix\" in2=\"blueShift\" mode=\"screen\" result=\"chromatic\" />\n\n          <feColorMatrix in=\"chromatic\" type=\"saturate\" values=\"1.2\" result=\"refracted\" />\n\n          <feBlend in=\"SourceGraphic\" in2=\"refracted\" mode=\"normal\" />\n        </filter>\n\n        {/* Lightweight turbulence-based distortion for CSS filter usage */}\n        <filter\n          id=\"lg-glass-distort\"\n          x=\"-20%\"\n          y=\"-20%\"\n          width=\"140%\"\n          height=\"140%\"\n          colorInterpolationFilters=\"sRGB\"\n          filterUnits=\"objectBoundingBox\"\n        >\n          <feTurbulence\n            type=\"fractalNoise\"\n            baseFrequency=\"0.012 0.018\"\n            numOctaves=\"2\"\n            seed=\"9\"\n            result=\"noise\"\n          />\n          <feGaussianBlur in=\"noise\" stdDeviation=\"1.8\" result=\"softNoise\" />\n          <feDisplacementMap\n            in=\"SourceGraphic\"\n            in2=\"softNoise\"\n            scale=\"18\"\n            xChannelSelector=\"R\"\n            yChannelSelector=\"G\"\n          />\n        </filter>\n\n        {/* Switcher-style displacement map (used with backdrop-filter) */}\n        <filter\n          id=\"lg-switcher\"\n          x=\"0%\"\n          y=\"0%\"\n          width=\"100%\"\n          height=\"100%\"\n          filterUnits=\"objectBoundingBox\"\n          primitiveUnits=\"objectBoundingBox\"\n          colorInterpolationFilters=\"sRGB\"\n        >\n          {/* Static packed normal-ish map to bend the backdrop */}\n          <feImage href={SWITCHER_MAP} result=\"map\" preserveAspectRatio=\"none\" />\n\n          {/* Mild blur of the backdrop for diffusion */}\n          <feGaussianBlur in=\"SourceGraphic\" stdDeviation=\"0.08\" result=\"blur\" />\n\n          <feDisplacementMap\n            in=\"blur\"\n            in2=\"map\"\n            scale=\"20\"\n            xChannelSelector=\"R\"\n            yChannelSelector=\"G\"\n          />\n        </filter>\n      </defs>\n    </svg>\n  );\n}\n\nconst DISPLACEMENT_MAP =\n  'data:image/png;base64,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';\n\nconst SWITCHER_MAP =\n  'data:image/webp;base64,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';\n",
      "type": "registry:ui",
      "target": "components/glassyui/liquid-filters.tsx"
    },
    {
      "path": "registry/glassyui/lib/preferences.ts",
      "content": "export type GlassyUiMode = 'clear' | 'tinted';\n\nexport type GlassyUiQuality = 'low' | 'medium' | 'high';\n\nexport type GlassyUiTheme = 'light' | 'dark';\n\nexport interface GlassyUiPreferences {\n  theme?: GlassyUiTheme;\n  mode?: GlassyUiMode;\n  reduceTransparency?: boolean;\n  reduceMotion?: boolean;\n  quality?: GlassyUiQuality;\n  /**\n   * How thick the glass is, as a multiple of regular: its rim widens, bends the\n   * backdrop further and splits more colour. Kept between 0.25 and 2.\n   */\n  thickness?: number;\n}\n\n/** The range of the thickness preference. 1 is regular glass. */\nexport const GLASS_THICKNESS = { min: 0.25, max: 2, regular: 1 } as const;\n\nconst THICKNESS_PROPERTY = '--lg-glass-thickness';\n\nfunction clampThickness(value: number) {\n  return Math.min(Math.max(value, GLASS_THICKNESS.min), GLASS_THICKNESS.max);\n}\n\ntype NavigatorWithMemory = Navigator & { deviceMemory?: number };\n\nconst DATA_KEYS = {\n  theme: 'data-lg-theme',\n  mode: 'data-lg-mode',\n  reduceTransparency: 'data-lg-reduce-transparency',\n  reduceMotion: 'data-lg-reduce-motion',\n  quality: 'data-lg-quality',\n} as const;\n\nconst STORAGE_KEY = 'glassy-ui-preferences';\n\nconst THEMES = ['light', 'dark'] as const satisfies readonly GlassyUiTheme[];\n\nconst MODES = ['clear', 'tinted'] as const satisfies readonly GlassyUiMode[];\n\nconst QUALITIES = ['low', 'medium', 'high'] as const satisfies readonly GlassyUiQuality[];\n\nconst FLAGS = [true, false] as const;\n\nexport function applyPreferences(target: Document, prefs: GlassyUiPreferences) {\n  const root = target.documentElement;\n\n  if (prefs.theme) {\n    root.setAttribute(DATA_KEYS.theme, prefs.theme);\n  }\n\n  if (prefs.mode) {\n    root.setAttribute(DATA_KEYS.mode, prefs.mode);\n  }\n\n  if (prefs.reduceTransparency !== undefined) {\n    root.setAttribute(DATA_KEYS.reduceTransparency, prefs.reduceTransparency ? '1' : '0');\n  }\n\n  if (prefs.reduceMotion !== undefined) {\n    root.setAttribute(DATA_KEYS.reduceMotion, prefs.reduceMotion ? '1' : '0');\n  }\n\n  if (prefs.quality) {\n    root.setAttribute(DATA_KEYS.quality, prefs.quality);\n  }\n\n  if (prefs.thickness !== undefined) {\n    root.style.setProperty(THICKNESS_PROPERTY, String(clampThickness(prefs.thickness)));\n  }\n}\n\nexport function readPreferences(source: Document): Required<GlassyUiPreferences> {\n  const root = source.documentElement;\n\n  const readOption = <T extends string>(name: string, options: readonly T[], fallback: T) => {\n    const value = root.getAttribute(name);\n\n    return options.find((option) => option === value) ?? fallback;\n  };\n\n  return {\n    theme: readOption(DATA_KEYS.theme, THEMES, 'dark'),\n    mode: readOption(DATA_KEYS.mode, MODES, 'clear'),\n    reduceTransparency: root.getAttribute(DATA_KEYS.reduceTransparency) === '1',\n    reduceMotion: root.getAttribute(DATA_KEYS.reduceMotion) === '1',\n    quality: readOption(DATA_KEYS.quality, QUALITIES, 'high'),\n    thickness: clampThickness(\n      Number.parseFloat(root.style.getPropertyValue(THICKNESS_PROPERTY)) || GLASS_THICKNESS.regular,\n    ),\n  };\n}\n\nexport function persistPreferences(\n  prefs: GlassyUiPreferences,\n  storage: Storage = window.localStorage,\n) {\n  const current = loadPreferences(storage);\n  const merged = { ...current, ...prefs } satisfies GlassyUiPreferences;\n  storage.setItem(STORAGE_KEY, JSON.stringify(merged));\n}\n\nexport function loadPreferences(\n  storage: Pick<Storage, 'getItem'> = window.localStorage,\n): GlassyUiPreferences {\n  const raw = storage.getItem(STORAGE_KEY);\n\n  if (!raw) {\n    return {};\n  }\n\n  try {\n    return decodePreferences(raw);\n  } catch (error) {\n    console.warn('Failed to parse Glassy UI preferences', error);\n\n    return {};\n  }\n}\n\n/** Keep the stored fields that hold a known value; drop stale or malformed entries. */\nfunction decodePreferences(raw: string): GlassyUiPreferences {\n  const stored: ReadonlyMap<string, unknown> = new Map(Object.entries(JSON.parse(raw)));\n  const prefs: GlassyUiPreferences = {};\n\n  const keep = <K extends keyof GlassyUiPreferences>(\n    key: K,\n    options: readonly NonNullable<GlassyUiPreferences[K]>[],\n  ) => {\n    const value = options.find((option) => option === stored.get(key));\n\n    if (value !== undefined) {\n      prefs[key] = value;\n    }\n  };\n\n  keep('theme', THEMES);\n  keep('mode', MODES);\n  keep('reduceTransparency', FLAGS);\n  keep('reduceMotion', FLAGS);\n  keep('quality', QUALITIES);\n\n  const thickness = Number(stored.get('thickness'));\n\n  if (Number.isFinite(thickness) && stored.has('thickness')) {\n    prefs.thickness = clampThickness(thickness);\n  }\n\n  return prefs;\n}\n\nexport { STORAGE_KEY as PREFERENCE_STORAGE_KEY };\n\nexport function computeAutomaticSafeguards(): Required<\n  Pick<GlassyUiPreferences, 'quality' | 'reduceMotion' | 'reduceTransparency'>\n> {\n  if (typeof window === 'undefined') {\n    return { quality: 'high', reduceMotion: false, reduceTransparency: false };\n  }\n\n  const supportsMatchMedia = 'matchMedia' in window;\n  const coarsePointer = supportsMatchMedia && window.matchMedia('(pointer: coarse)').matches;\n\n  const prefersReducedMotion =\n    supportsMatchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches;\n\n  const prefersReducedTransparency =\n    supportsMatchMedia && window.matchMedia('(prefers-reduced-transparency: reduce)').matches;\n\n  // SAFETY: deviceMemory is a number where the Device Memory API exists and absent elsewhere.\n  const deviceMemory = (navigator as NavigatorWithMemory).deviceMemory;\n  const lowMemory = deviceMemory !== undefined && deviceMemory <= 4;\n\n  // Device heuristics only lower rendering quality. Opaque surfaces and stopped\n  // motion stay reserved for the user's own accessibility settings.\n  const quality: GlassyUiQuality =\n    prefersReducedTransparency || lowMemory\n      ? 'low'\n      : coarsePointer || prefersReducedMotion\n        ? 'medium'\n        : 'high';\n\n  return {\n    quality,\n    reduceMotion: Boolean(prefersReducedMotion),\n    reduceTransparency: Boolean(prefersReducedTransparency),\n  };\n}\n",
      "type": "registry:lib",
      "target": "components/glassyui/lib/preferences.ts"
    },
    {
      "path": "registry/glassyui/styles/liquid.css",
      "content": "/* Glassy UI styles live in the components layer, below Tailwind utilities, so\n   a className such as rounded-xl or p-8 overrides the library default. These\n   statements repeat Tailwind 4's own layer order, so it holds even when this\n   file loads before Tailwind. */\n@layer properties;\n@layer theme, base, components, utilities;\n\n@property --lg-fresnel {\n  syntax: '<number>';\n  initial-value: 0;\n  inherits: true;\n}\n\n@property --lg-specular {\n  syntax: '<number>';\n  initial-value: 0;\n  inherits: true;\n}\n\n@property --lg-refraction-scale {\n  syntax: '<number>';\n  initial-value: 0;\n  inherits: true;\n}\n\n@property --lg-refraction-blur {\n  syntax: '<number>';\n  initial-value: 0;\n  inherits: true;\n}\n\n@property --lg-refraction-scale-a {\n  syntax: '<number>';\n  initial-value: 0;\n  inherits: true;\n}\n\n@property --lg-refraction-scale-b {\n  syntax: '<number>';\n  initial-value: 0;\n  inherits: true;\n}\n\n@property --lg-refraction-blur-a {\n  syntax: '<number>';\n  initial-value: 0;\n  inherits: true;\n}\n\n@property --lg-refraction-blur-b {\n  syntax: '<number>';\n  initial-value: 0;\n  inherits: true;\n}\n\n@property --lg-refraction-dispersion {\n  syntax: '<number>';\n  initial-value: 0;\n  inherits: true;\n}\n\n@property --lg-rim-width-scale {\n  syntax: '<number>';\n  initial-value: 1;\n  inherits: true;\n}\n\n@property --lg-highlight-strength {\n  syntax: '<number>';\n  initial-value: 0;\n  inherits: true;\n}\n\n@property --lg-rim-micro-mask {\n  syntax: '<number>';\n  initial-value: 1;\n  inherits: true;\n}\n\n@property --lg-rim-corner-mask {\n  syntax: '<number>';\n  initial-value: 1;\n  inherits: true;\n}\n\n@property --lg-debug-micro-scale {\n  syntax: '<number>';\n  initial-value: 1;\n  inherits: true;\n}\n\n@property --lg-debug-corner-scale {\n  syntax: '<number>';\n  initial-value: 1;\n  inherits: true;\n}\n\n@property --lg-debug-ca-scale {\n  syntax: '<number>';\n  initial-value: 1;\n  inherits: true;\n}\n\n@property --lg-debug-ca-offset-scale {\n  syntax: '<number>';\n  initial-value: 1;\n  inherits: true;\n}\n\n@property --lg-debug-rim-thickness {\n  syntax: '<number>';\n  initial-value: 1;\n  inherits: true;\n}\n\n@property --lg-debug-rim-alpha-scale {\n  syntax: '<number>';\n  initial-value: 1;\n  inherits: true;\n}\n\n@property --lg-debug-tangent-scale {\n  syntax: '<number>';\n  initial-value: 1;\n  inherits: true;\n}\n\n@property --lg-debug-highlight-scale {\n  syntax: '<number>';\n  initial-value: 1;\n  inherits: true;\n}\n\n@property --lg-filter-scale {\n  syntax: '<number>';\n  initial-value: 0.98;\n  inherits: true;\n}\n\n@property --lg-bg {\n  syntax: '<color>';\n  initial-value: #1c1c1e;\n  inherits: true;\n}\n\n@property --lg-panel {\n  syntax: '<color>';\n  initial-value: rgba(255, 255, 255, 0.04);\n  inherits: true;\n}\n\n@property --lg-press {\n  syntax: '<number>';\n  initial-value: 0;\n  inherits: true;\n}\n\n/* How high a button's glass rests above the page: 1 at rest, lower under a\n   pointer, nearly down while pressed. Its shadow and the light it lets\n   through follow the height; the glass itself stays put. Registered so the\n   height eases instead of jumping. */\n@property --lg-button-rise {\n  syntax: '<number>';\n  initial-value: 1;\n  inherits: true;\n}\n\n/* Where the light on a prominent button comes from: 0deg straight overhead. A\n   pointer swings it over to the top left. Registered so the light eases\n   across instead of jumping. */\n@property --lg-button-light-angle {\n  syntax: '<angle>';\n  initial-value: 0deg;\n  inherits: true;\n}\n\n/* Glass scene material. Registered so the renderer reads resolved values and\n   tints can transition; engines without @property resolve them by probe. */\n@property --lg-scene-tint {\n  syntax: '<color>';\n  initial-value: transparent;\n  inherits: false;\n}\n\n@property --lg-scene-frost {\n  syntax: '<length>';\n  initial-value: 0px;\n  inherits: false;\n}\n\n@property --lg-scene-merge {\n  syntax: '<length>';\n  initial-value: 0px;\n  inherits: true;\n}\n\n@property --lg-scene-flow {\n  syntax: '<number>';\n  initial-value: 0;\n  inherits: false;\n}\n\n@property --lg-scene-ink {\n  syntax: '<color>';\n  initial-value: transparent;\n  inherits: false;\n}\n\n@layer base {\n  :where(.lg-glass-surface > *) {\n    position: relative;\n    z-index: 2;\n  }\n}\n\n@layer components {\n  :root {\n    /* Core Physics: the frost every glass layer reads. Controls, alerts, badges and\n       dock labels cap the blur at their own size and follow the rest. */\n    --lg-glass-blur: 20px;\n    --lg-glass-sat: 1.8;\n    --lg-glass-contrast: 0.9;\n    --lg-glass-brightness: 1;\n    --lg-glass-alpha: 0.02;\n    --lg-bg: #1c1c1e;\n    --lg-panel: rgba(255, 255, 255, 0.04);\n    --lg-foreground: #f5f5f7;\n    --lg-muted-foreground: #e5e5ea;\n    --lg-border: rgba(245, 245, 247, 0.22);\n    --lg-control-surface: rgba(245, 245, 247, 0.08);\n    --lg-control-surface-hover: rgba(245, 245, 247, 0.14);\n    --lg-opaque-surface: #2c2c2e;\n    /* Floating layers keep 4.5:1 text contrast over a pure white or black backdrop. */\n    --lg-overlay-surface: rgb(44 44 46 / 0.78);\n    --lg-scrim: rgb(0 0 0 / 0.45);\n    /* Slabs are clear glass. The page shows through, dimmed by brightness so\n       muted text keeps 4.5:1 over pure white. The lens rim is dimmed less, but\n       never above what holds that bar at the very edge. */\n    --lg-slab-tint: rgb(28 28 30 / 0.3);\n    --lg-slab-brightness: 0.38;\n    --lg-slab-rim-brightness: 0.46;\n    --lg-slab-blur: 3;\n    /* The header is a clearer slab. Its links sit clear of the rim, so the rim\n       lets the page through undimmed, bent and split into colour, while the top\n       keeps muted links at 4.5:1 over pure white. */\n    --lg-header-tint: rgb(28 28 30 / 0.35);\n    --lg-header-brightness: 0.55;\n    --lg-header-rim-brightness: 1;\n    /* Familiar blue for actions; Vermilion belongs to the brand and artwork. */\n    --lg-accent: #0067d9;\n    --lg-accent-foreground: #ffffff;\n    /* Prominent buttons are blue glass. The tint recolours whatever lies\n       behind them and caps how bright it can get, so white text keeps 4.5:1\n       over any backdrop. The fill stands in where there is no glass: reduced\n       transparency, forced colours and a GlassScene. */\n    --lg-prominent-fill: #0067d9;\n    --lg-prominent-tint: grayscale(1) contrast(0.4) brightness(0.55) sepia(1) hue-rotate(174deg)\n      saturate(6) brightness(1.12);\n    --lg-prominent-glow: 178 214 255;\n    --lg-prominent-shade: 4 33 65;\n    /* Focus stays neutral so it does not read as a blue selected state. */\n    --lg-focus-ring: #b8b8be;\n    --lg-invalid: #ff7a8e;\n    --lg-disabled-opacity: 0.45;\n    --lg-motion-duration: 200ms;\n    /* Springy settle for presses, toggles and moving indicators */\n    --lg-spring: cubic-bezier(0.34, 1.56, 0.64, 1);\n    --lg-ease-out: cubic-bezier(0.32, 0.72, 0, 1);\n    /* System controls: the resting track, the switch's on state and the white\n       knob that turns to clear glass under a finger */\n    --lg-track: rgb(118 118 128 / 0.36);\n    --lg-switch-on: #0067d9;\n    --lg-knob: #ffffff;\n    --lg-knob-shadow:\n      0 2px 6px rgb(28 28 30 / 0.16), 0 1px 2px rgb(28 28 30 / 0.1),\n      0 0 0 0.5px rgb(28 28 30 / 0.05);\n\n    /* The fixed light the CSS glass is lit by: where its highlight sits (0 to\n       1 across the glass), the direction it strikes the rims from, and its\n       strength. The glass never follows the pointer. */\n    --lg-light-x: 0.5;\n    --lg-light-y: 0.5;\n    --lg-light-dir-x: 0;\n    --lg-light-dir-y: 0;\n    --lg-light-level: 0;\n\n    /* Theme Colors */\n    --lg-ink-dark: #ffffff;\n    --lg-ink-light: #000000;\n    --lg-fresnel: 0;\n    --lg-specular: 0;\n    --lg-refraction-scale: 24;\n    --lg-refraction-blur: 16;\n\n    /* Edge reflex: strength of the lit bevel and of the shaded inner edge */\n    --lg-reflex-light: 0.42;\n    --lg-reflex-dark: 1.4;\n    --lg-button-reflex-light: 0.7;\n    --lg-sheen-alpha: 0.05;\n\n    /* Specular edge: a hairline ring brightest where the light enters (top\n       left), with a softer counter highlight on the far edge. The glow is the\n       light caught inside the glass thickness. */\n    --lg-rim-width: 1px;\n    --lg-specular-peak: 0.45;\n    --lg-specular-counter: 0.22;\n    --lg-specular-floor: 0.07;\n    --lg-glow-alpha: 0.06;\n\n    /* Lighting & Depth: outer shadows only, the glass edge lives in --lg-glass-rim */\n    --lg-shadow: 0 1px 2px rgb(0 0 0 / 0.18), 0 8px 24px -4px rgb(0 0 0 / 0.28);\n    --lg-shadow-raised: 0 2px 6px rgb(0 0 0 / 0.2), 0 30px 60px -18px rgb(0 0 0 / 0.55);\n    --lg-input-shadow: inset 0 1px 2px rgb(0 0 0 / 0.24), inset 0 -1px 0 rgb(255 255 255 / 0.06);\n\n    /* Chromium edge lens, read as plain numbers by useLensFilter:\n       depth scales the edge bend, blur is the frost radius in px. */\n    --lg-lens-depth: 1;\n    --lg-lens-blur: 6;\n    --lg-lens-saturation: 1.5;\n    --lg-lens-bevel: 0;\n    --lg-lens-thickness: 0;\n    --lg-lens-ior: 1.5;\n    --lg-lens-dispersion: 0.16;\n    --lg-lens-body-brightness: 1;\n    --lg-lens-rim-brightness: 1;\n    --lg-glass-thickness: 1;\n\n    --lg-noise-alpha: 0.03;\n\n    --lg-radius-md: 16px;\n    --lg-radius-lg: 24px;\n\n    /* Glass scene: shadow and highlight strength, and extra white in the tint. */\n    --lg-scene-shadow: 0.34;\n    --lg-scene-highlight: 1;\n    --lg-scene-tint-boost: 0;\n\n    --lg-noise-image: url('data:image/svg+xml,%3Csvg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 120 120\"%3E%3Cfilter id=\"grain\"%3E%3CfeTurbulence type=\"fractalNoise\" baseFrequency=\"0.8\" numOctaves=\"3\" stitchTiles=\"stitch\"/%3E%3CfeColorMatrix type=\"saturate\" values=\"0\"/%3E%3C/filter%3E%3Crect width=\"120\" height=\"120\" filter=\"url(%23grain)\" opacity=\"0.5\"/%3E%3C/svg%3E');\n  }\n\n  [data-lg-theme='dark'] {\n    color-scheme: dark;\n  }\n\n  /* Light theme */\n  [data-lg-theme='light'] {\n    color-scheme: light;\n    --lg-bg: #faf9f7;\n    --lg-panel: rgba(255, 255, 255, 0.5);\n    --lg-glass-alpha: 0.15;\n    --lg-glass-blur: 16px;\n    --lg-glass-contrast: 1;\n    --lg-glass-sat: 1.6;\n    --lg-glass-brightness: 1.06;\n    --lg-ink-dark: #222224;\n    --lg-ink-light: #222224;\n    --lg-ink: var(--lg-ink-dark);\n    --lg-foreground: #222224;\n    --lg-muted-foreground: #505055;\n    --lg-border: rgba(0, 0, 0, 0.14);\n    --lg-control-surface: rgba(255, 255, 255, 0.72);\n    --lg-control-surface-hover: rgba(255, 255, 255, 0.95);\n    --lg-opaque-surface: #ffffff;\n    --lg-overlay-surface: rgb(255 255 255 / 0.82);\n    --lg-scrim: rgb(0 0 0 / 0.16);\n    --lg-slab-tint: rgb(255 255 255 / 0.8);\n    --lg-slab-brightness: 1;\n    --lg-slab-rim-brightness: 1;\n    --lg-slab-blur: 3;\n    /* The tint alone keeps muted header links at 4.5:1 over pure black. */\n    --lg-header-tint: rgb(255 255 255 / 0.77);\n    --lg-header-brightness: 1;\n    --lg-header-rim-brightness: 1;\n    --lg-accent: #0067d9;\n    --lg-prominent-tint: grayscale(1) contrast(0.5) brightness(0.35) sepia(1) hue-rotate(172deg)\n      saturate(6) brightness(1.4);\n    --lg-focus-ring: #66666a;\n    --lg-invalid: #c4153f;\n    --lg-track: rgb(118 118 128 / 0.2);\n    --lg-switch-on: #0067d9;\n    --lg-noise-alpha: 0.02;\n    --lg-reflex-light: 1;\n    --lg-reflex-dark: 0.8;\n    --lg-button-reflex-light: 1;\n    --lg-sheen-alpha: 0.08;\n    --lg-specular-peak: 0.7;\n    --lg-specular-counter: 0.55;\n    --lg-specular-floor: 0.35;\n    --lg-glow-alpha: 0.14;\n    --lg-shadow: 0 1px 2px rgb(0 0 0 / 0.06), 0 8px 24px -6px rgb(0 0 0 / 0.14);\n    --lg-shadow-raised: 0 2px 6px rgb(0 0 0 / 0.06), 0 28px 56px -18px rgb(0 0 0 / 0.26);\n    --lg-input-shadow: inset 0 1px 2px rgb(0 0 0 / 0.08), inset 0 -1px 0 rgb(255 255 255 / 0.8);\n\n    --lg-refraction-scale: 24;\n    --lg-refraction-blur: 20;\n    --lg-fresnel: 0.1;\n    --lg-specular: 0.05;\n    --lg-highlight-strength: 0.1;\n\n    /* The light sits a little above centre and catches the top rims. */\n    --lg-light-y: 0.3;\n    --lg-light-dir-y: -0.35;\n    --lg-light-level: 0.15;\n\n    --lg-scene-shadow: 0.16;\n    --lg-scene-tint-boost: 0.06;\n  }\n\n  [data-lg-theme='dark'][data-lg-mode='clear'] {\n    --lg-glass-alpha: 0.02;\n    --lg-glass-sat: 1.8;\n    --lg-glass-contrast: 0.9;\n  }\n\n  [data-lg-theme='dark'][data-lg-mode='tinted'] {\n    --lg-glass-alpha: 0.12;\n    --lg-glass-sat: 1.5;\n    --lg-glass-contrast: 0.9;\n  }\n\n  [data-lg-theme='light'][data-lg-mode='clear'] {\n    --lg-glass-alpha: 0.08;\n    --lg-glass-sat: 1.8;\n    --lg-glass-contrast: 1.02;\n    --lg-glass-blur: 20px;\n  }\n\n  [data-lg-theme='light'][data-lg-mode='tinted'] {\n    --lg-glass-alpha: 0.25;\n    --lg-glass-sat: 1.4;\n    --lg-glass-contrast: 1;\n    --lg-glass-blur: 14px;\n  }\n\n  /* Tinted slabs frost harder and hold a denser tint; the rim still lets more\n     light through. The header matches the other slabs. */\n  [data-lg-theme='dark'][data-lg-mode='tinted'] {\n    --lg-slab-tint: rgb(28 28 30 / 0.55);\n    --lg-slab-brightness: 0.55;\n    --lg-slab-rim-brightness: 0.65;\n    --lg-slab-blur: 14;\n    --lg-header-tint: rgb(28 28 30 / 0.55);\n    --lg-header-brightness: 0.55;\n    --lg-header-rim-brightness: 0.65;\n  }\n\n  [data-lg-theme='light'][data-lg-mode='tinted'] {\n    --lg-slab-tint: rgb(255 255 255 / 0.9);\n    --lg-slab-blur: 14;\n    --lg-header-tint: rgb(255 255 255 / 0.9);\n  }\n\n  [data-lg-mode='tinted'] {\n    --lg-glass-alpha: 0.72;\n    --lg-glass-blur: 32px;\n    --lg-glass-sat: 1.4;\n    --lg-glass-contrast: 0.9;\n    --lg-lens-blur: 10;\n  }\n\n  /* Increased contrast keeps the glass and makes it predominantly black or\n     white, as the system's own glass does: dark glass dims what lies behind it\n     and light glass frosts denser, so text keeps 7:1 over any backdrop, and\n     muted text gets full contrast. Dark glass adds no white of its own, and\n     its Chromium lens dims as its frost does. Toasts and tooltips darken. A\n     ring in the text colour edges the glass (see Increased contrast below).\n     The dimming outranks the quality settings, which still lighten the frost. */\n  @media (prefers-contrast: more) {\n    [data-lg-theme='dark'],\n    [data-lg-theme='dark'][data-lg-mode],\n    [data-lg-theme='dark'][data-lg-mode][data-lg-quality] {\n      --lg-muted-foreground: var(--lg-foreground);\n      --lg-glass-alpha: 0.02;\n      --lg-glass-brightness: 0.22;\n      --lg-glass-contrast: 1;\n      --lg-sheen-alpha: 0;\n      --lg-lens-body-brightness: var(--lg-glass-brightness);\n      --lg-lens-rim-brightness: var(--lg-glass-brightness);\n      --lg-overlay-surface: rgb(28 28 30 / 0.88);\n      --lg-slab-tint: rgb(28 28 30 / 0.55);\n      --lg-slab-brightness: 0.5;\n      --lg-slab-rim-brightness: 0.65;\n      --lg-slab-blur: 14;\n      --lg-header-tint: rgb(28 28 30 / 0.55);\n      --lg-header-brightness: 0.5;\n      --lg-header-rim-brightness: 0.65;\n    }\n\n    [data-lg-theme='light'],\n    [data-lg-theme='light'][data-lg-mode] {\n      --lg-muted-foreground: var(--lg-foreground);\n      --lg-glass-alpha: 0.7;\n      --lg-slab-tint: rgb(255 255 255 / 0.9);\n      --lg-slab-blur: 14;\n      --lg-header-tint: rgb(255 255 255 / 0.9);\n    }\n  }\n\n  :root[data-lg-quality='low'] {\n    --lg-scene-highlight: 0.6;\n    --lg-glass-blur: 6px;\n    --lg-glass-sat: 1.05;\n    --lg-glass-contrast: 1;\n    --lg-glass-brightness: 1;\n    --lg-refraction-scale: 0;\n    --lg-refraction-blur: 0;\n    --lg-highlight-strength: 0;\n    --lg-lens-depth: 0;\n  }\n\n  /* Touch devices and reduced-motion settings land here. The colour split costs six\n     more filter passes a frame on every lens in view, so it is left out. */\n  :root[data-lg-quality='medium'] {\n    --lg-lens-dispersion: 0;\n    --lg-glass-blur: 12px;\n    --lg-glass-sat: 1.4;\n    --lg-glass-contrast: 0.96;\n    --lg-refraction-scale: 10;\n    --lg-refraction-blur: 8;\n  }\n\n  :root[data-lg-quality='high'] {\n    --lg-refraction-scale: 16;\n    --lg-refraction-blur: 10;\n  }\n\n  :root[data-lg-reduce-transparency='1'] {\n    --lg-glass-blur: 0px;\n    --lg-glass-alpha: 0.95;\n    --lg-noise-alpha: 0.01;\n    --lg-glass-contrast: 1;\n    --lg-glass-sat: 1;\n    --lg-glass-brightness: 1;\n    --lg-refraction-scale: 0;\n    --lg-lens-depth: 0;\n  }\n\n  [data-lg-theme='dark'][data-lg-reduce-transparency='1'] {\n    --lg-opaque-surface: #2c2c2e;\n    --lg-control-surface: #3a3a3c;\n    --lg-control-surface-hover: #48484a;\n    --lg-track: #48484a;\n  }\n\n  [data-lg-theme='light'][data-lg-reduce-transparency='1'] {\n    --lg-opaque-surface: #ffffff;\n    --lg-control-surface: #f0f0f2;\n    --lg-control-surface-hover: #e3e3e7;\n    --lg-track: #e6e6e9;\n  }\n\n  [data-lg-reduce-motion='1'] {\n    --lg-motion-duration: 0ms;\n  }\n\n  [data-lg-reduce-motion='1'] *,\n  [data-lg-reduce-motion='1'] *::before,\n  [data-lg-reduce-motion='1'] *::after {\n    animation-duration: 0ms !important;\n    transition-duration: 0ms !important;\n  }\n\n  /* A switch still shows its own change, in a short plain slide and a colour\n     fade: no spring, swell or glass. Everything else holds still. */\n  [data-lg-reduce-motion='1'] .lg-switch {\n    transition-duration: 160ms !important;\n  }\n\n  [data-lg-reduce-motion='1'] :is(.lg-switch-thumb, .lg-switch-lens-scene, .lg-switch-lens-track) {\n    transition-duration: 160ms !important;\n    transition-property: translate !important;\n    transition-timing-function: ease-out !important;\n  }\n\n  [data-lg-reduce-motion='1'] .lg-glass-surface::after {\n    transform: none !important;\n    transition: none !important;\n  }\n\n  [data-lg-reduce-motion='1'] .lg-button {\n    transform: none !important;\n    transition: none !important;\n  }\n\n  [data-lg-reduce-motion='1'] .lg-button__bloom {\n    display: none;\n  }\n\n  @media (prefers-reduced-motion: reduce) {\n    :root {\n      --lg-motion-duration: 0ms;\n    }\n\n    .lg-glass-surface,\n    .lg-glass-surface::after,\n    .lg-button,\n    .lg-button__distortion,\n    .lg-button__shine,\n    .lg-input,\n    .lg-dialog-overlay,\n    .lg-dialog-content,\n    .lg-popover-content,\n    .lg-tabs-trigger,\n    .lg-accordion-trigger,\n    .lg-accordion-chevron,\n    .lg-refraction-background,\n    .lg-noise,\n    .lg-switch,\n    .lg-switch-thumb,\n    .lg-slider-thumb,\n    .lg-checkbox,\n    .lg-radio,\n    .lg-check-tick,\n    .lg-check-dash,\n    .lg-radio-dot,\n    .lg-select-chevron,\n    .lg-progress-fill,\n    .lg-spinner-ring,\n    .lg-toast,\n    .lg-toast-root,\n    .lg-toast-close,\n    .lg-toast-action,\n    .lg-tooltip-content,\n    .lg-accordion-content,\n    .lg-avatar-image,\n    .lg-alert,\n    .lg-alert-fold,\n    .lg-skeleton::after,\n    .lg-command-list,\n    .lg-command-search,\n    .lg-page,\n    .lg-alert-close,\n    .lg-segmented-item,\n    .lg-segmented-indicator,\n    .lg-tabs-indicator,\n    .lg-dock-item,\n    .lg-dock-label,\n    .lg-sheet-content,\n    .lg-menu-content,\n    .lg-select-content,\n    .lg-lens,\n    .lg-scene-drop {\n      animation-duration: 0ms !important;\n      transition-duration: 0ms !important;\n    }\n\n    .lg-switch {\n      transition-duration: 160ms !important;\n    }\n\n    .lg-switch-thumb,\n    .lg-switch-lens-scene,\n    .lg-switch-lens-track {\n      transition-duration: 160ms !important;\n      transition-property: translate !important;\n      transition-timing-function: ease-out !important;\n    }\n\n    .lg-glass-surface::after,\n    .lg-button__distortion,\n    .lg-refraction-background,\n    .lg-button {\n      transform: none !important;\n    }\n\n    .lg-button__bloom {\n      display: none;\n    }\n  }\n\n  @keyframes lg-grain {\n    0% {\n      transform: translate3d(0, 0, 0);\n    }\n    20% {\n      transform: translate3d(-2%, 2%, 0);\n    }\n    40% {\n      transform: translate3d(-2%, -2%, 0);\n    }\n    60% {\n      transform: translate3d(2%, -2%, 0);\n    }\n    80% {\n      transform: translate3d(2%, 2%, 0);\n    }\n    100% {\n      transform: translate3d(0, 0, 0);\n    }\n  }\n\n  /* ============================================\n     Glass edge\n     Two layers make every glass edge. The bevel is an inset shadow stack: the\n     light caught in the glass thickness, a bright bevel on the lit top-left, a\n     softer counter-bevel, a shaded inner reflex, a faint chromatic fringe and\n     a highlight cast by the fixed light. The specular ring is a masked\n     hairline lit from the top left, with a glint where that light sits. Custom\n     properties resolve on the declaring element, so surfaces and buttons feed\n     both their own tokens.\n     ============================================ */\n\n  .lg-glass-surface,\n  .lg-button {\n    --lg-rim-gain: calc(\n      var(--lg-rim-tangent-alpha, 1) * var(--lg-debug-tangent-scale, 1) *\n        var(--lg-rim-micro-mask, 1) * var(--lg-debug-micro-scale, 1) *\n        var(--lg-rim-corner-mask, 1) * var(--lg-debug-corner-scale, 1) *\n        var(--lg-debug-rim-alpha-scale, 1)\n    );\n    --lg-glass-rim:\n      inset 0 0 calc(12px * var(--lg-rim-scale)) calc(-4px * var(--lg-rim-scale))\n        rgb(255 255 255 / calc(var(--lg-glow-alpha) * var(--lg-rim-gain))),\n      inset calc(1.5px * var(--lg-rim-scale)) calc(2.5px * var(--lg-rim-scale))\n        calc(1px * var(--lg-rim-scale)) -2px rgb(255 255 255 / calc(var(--lg-rim-light) * 0.7)),\n      inset calc(-1.5px * var(--lg-rim-scale)) calc(-2px * var(--lg-rim-scale))\n        calc(1px * var(--lg-rim-scale)) -2px rgb(255 255 255 / calc(var(--lg-rim-light) * 0.55)),\n      inset -0.3px -1px 4px 0 rgb(0 0 0 / calc(var(--lg-rim-dark) * 0.1)),\n      inset -1.5px 2.5px 0 -2px rgb(0 0 0 / calc(var(--lg-rim-dark) * 0.14)),\n      inset 0 3px 4px -2px rgb(0 0 0 / calc(var(--lg-rim-dark) * 0.14)),\n      inset var(--lg-rim-ca-offset) 0 3px -1px rgb(80 160 255 / var(--lg-rim-ca-alpha)),\n      inset calc(-1 * var(--lg-rim-ca-offset)) 0 3px -1px rgb(255 90 150 / var(--lg-rim-ca-alpha)),\n      inset var(--lg-rim-offset-x) var(--lg-rim-offset-y) 3px rgb(255 255 255 / var(--lg-rim-alpha));\n    /* to bottom right keeps both highlights on the corners at any aspect\n       ratio; a fixed angle would smear them along a wide pill. */\n    --lg-specular-ring:\n      radial-gradient(\n        circle at calc(var(--lg-light-x) * 100%) calc(var(--lg-light-y) * 100%),\n        rgb(255 255 255 / calc(var(--lg-light-level) * 0.85)),\n        transparent 42%\n      ),\n      linear-gradient(\n        to bottom right,\n        rgb(255 255 255 / calc(var(--lg-specular-peak) * var(--lg-rim-gain))) 0%,\n        rgb(255 255 255 / calc(var(--lg-specular-floor) * var(--lg-rim-gain))) 32%,\n        rgb(255 255 255 / calc(var(--lg-specular-floor) * var(--lg-rim-gain))) 68%,\n        rgb(255 255 255 / calc(var(--lg-specular-counter) * var(--lg-rim-gain))) 100%\n      );\n  }\n\n  /* Glass Surface - Global Refraction */\n  .lg-glass-surface {\n    --lg-thickness: calc(1 + var(--lg-light-strength) * 0.35);\n    --lg-surface-blur-base: calc(var(--lg-glass-blur) * var(--lg-thickness));\n    --lg-surface-blur: var(--lg-surface-blur-base);\n    --lg-surface-alpha: var(--lg-glass-alpha);\n    --lg-surface-lift: 0;\n    --lg-light-strength: calc(var(--lg-light-level) * 0.45);\n    /* Bevel thickness (scaled by distance-aware factor) */\n    --lg-rim-scale: calc(var(--lg-rim-width-scale, 1) * var(--lg-debug-rim-thickness, 1));\n    --lg-rim-offset-max: 4.5px;\n    --lg-rim-offset-max-scaled: calc(var(--lg-rim-offset-max) * var(--lg-rim-scale));\n    --lg-rim-tangent-alpha: 1;\n    --lg-rim-micro-mask: 1;\n    --lg-rim-corner-mask: 1;\n    --lg-rim-ca-offset: calc(2px * var(--lg-debug-ca-offset-scale, 1));\n    --lg-rim-ca-alpha: calc(0.06 * var(--lg-debug-ca-scale, 1));\n    --lg-rim-offset-x: clamp(\n      calc(-1 * var(--lg-rim-offset-max-scaled)),\n      calc(\n        var(--lg-light-dir-x) * -1 * var(--lg-rim-offset-max-scaled) *\n          (0.6 + var(--lg-light-strength))\n      ),\n      var(--lg-rim-offset-max-scaled)\n    );\n    --lg-rim-offset-y: clamp(\n      calc(-1 * var(--lg-rim-offset-max-scaled)),\n      calc(\n        var(--lg-light-dir-y) * -1 * var(--lg-rim-offset-max-scaled) *\n          (0.6 + var(--lg-light-strength))\n      ),\n      var(--lg-rim-offset-max-scaled)\n    );\n    --lg-rim-light: calc(var(--lg-reflex-light) * var(--lg-rim-gain));\n    --lg-rim-dark: var(--lg-reflex-dark);\n    --lg-rim-alpha: calc(\n      (0.05 + var(--lg-light-strength) * 0.12 + var(--lg-fresnel, 0) * 0.35 + var(--lg-specular) *\n          0.32) *\n        var(--lg-rim-gain)\n    );\n\n    position: relative;\n    border-radius: var(--lg-panel-radius, var(--lg-radius-lg));\n    isolation: isolate;\n    background: transparent;\n    color: var(--lg-foreground);\n    transition:\n      box-shadow var(--lg-motion-duration) ease,\n      transform var(--lg-motion-duration) ease;\n    box-shadow: var(--lg-panel-elevation-shadow, var(--lg-shadow));\n    overflow: hidden;\n    contain: layout paint style;\n  }\n\n  .lg-glass-surface[data-lg-preset='subtle'] {\n    --lg-surface-blur: min(var(--lg-surface-blur-base), 8px);\n    --lg-surface-alpha: max(var(--lg-glass-alpha), 0.06);\n    --lg-rim-offset-max: 1.5px;\n  }\n\n  .lg-glass-surface[data-lg-preset='standard'] {\n    --lg-surface-blur: min(var(--lg-surface-blur-base), 14px);\n    --lg-surface-alpha: max(var(--lg-glass-alpha), 0.08);\n  }\n\n  .lg-glass-surface[data-lg-preset='prominent'] {\n    --lg-surface-blur: min(var(--lg-surface-blur-base), 18px);\n    --lg-surface-alpha: max(var(--lg-glass-alpha), 0.12);\n  }\n\n  .lg-glass-surface[data-lg-preset='control'] {\n    --lg-surface-blur: min(var(--lg-surface-blur-base), 10px);\n    --lg-surface-alpha: max(var(--lg-glass-alpha), 0.08);\n    --lg-rim-offset-max: 1.25px;\n  }\n\n  .lg-glass-surface[data-lg-preset='showcase'] {\n    --lg-surface-blur: min(var(--lg-surface-blur-base), 24px);\n  }\n\n  /* An interactive surface brightens a touch on hover, wherever the pointer\n     rests on it. */\n  .lg-glass-surface[data-lg-interactive='true']:hover {\n    --lg-surface-lift: 0.04;\n  }\n\n  /* The lift eases in and out. Other frost has no transition, so it changes\n     with a theme or preference switch at once. */\n  .lg-glass-surface[data-lg-interactive='true']::before {\n    transition: background-color var(--lg-motion-duration) ease;\n  }\n\n  /* Panel shapes and spacing. Component defaults live here rather than in\n     className utilities, so a consumer's p-4 or rounded-none always wins. */\n  .lg-panel--panel {\n    --lg-panel-radius: var(--lg-radius-lg);\n    padding: 1.5rem;\n  }\n\n  .lg-panel--card {\n    --lg-panel-radius: var(--lg-radius-md);\n    padding: 1.25rem;\n  }\n\n  .lg-panel--pill {\n    --lg-panel-radius: 9999px;\n    padding: 0.75rem 1.25rem;\n  }\n\n  .lg-panel--raised {\n    --lg-panel-elevation-shadow: var(--lg-shadow-raised);\n  }\n\n  .lg-refraction-filter {\n    position: absolute;\n    width: 0;\n    height: 0;\n    overflow: hidden;\n    pointer-events: none;\n  }\n\n  /* The generated scene sits under the frost layer, which then drops its\n     backdrop blur and lays only its tint, bevel and sheen over the scene.\n     WebKit draws a filtered layer from its overflow origin, so a viewport\n     scene hanging off the top or left edge would land shifted. Clipping\n     keeps both origins at the surface corner. */\n  .lg-glass-surface > .lg-refraction-background {\n    position: absolute;\n    inset: 0;\n    z-index: -1;\n    overflow: hidden;\n    border-radius: inherit;\n    pointer-events: none;\n    transform: translateZ(0);\n  }\n\n  .lg-refraction-background > .lg-refraction-scene {\n    position: absolute;\n    inset: 0;\n  }\n\n  .lg-refraction-scene > * {\n    min-width: 100%;\n    min-height: 100%;\n  }\n\n  /* Position the scene without a transform: WebKit shifts transformed input\n     when the SVG filter combines refracted colour channels. Chromium filters\n     composited layers, so a scroll-driven animation on translate still carries\n     the scene through the scroll, and left/top hold what scrolling leaves unchanged. */\n  .lg-glass-surface[data-lg-refraction-background-space='viewport']\n    > .lg-refraction-background\n    > .lg-refraction-scene {\n    inset: 0 auto auto 0;\n    top: var(--lg-refraction-scene-y, 0px);\n    left: var(--lg-refraction-scene-x, 0px);\n    width: var(--lg-refraction-scene-width, 100vw);\n    height: var(--lg-refraction-scene-height, 100dvh);\n  }\n\n  .lg-glass-surface[data-lg-refraction='soft'] {\n    --lg-surface-blur: calc(var(--lg-surface-blur-base) * 0.9);\n  }\n\n  .lg-glass-surface[data-lg-refraction='strong'] {\n    --lg-surface-blur: calc(var(--lg-surface-blur-base) * 1.12);\n  }\n\n  /* Frost, bevel and sheen. Keep blend modes, masks, filters and opacity off\n     every ancestor of this layer: in Chromium each of them isolates the\n     backdrop and silently turns the blur into a no-op. The layer carries its\n     own rounded shape: Chromium drops the host's rounded clip from a backdrop\n     blur that sits inside another rounded overflow clip, such as a card. The\n     tint is background-color alone, so a consumer's before:bg-* utility\n     recolors the glass and keeps the sheen. */\n  .lg-glass-surface::before {\n    content: '';\n    position: absolute;\n    inset: 0;\n    z-index: 0;\n    border-radius: inherit;\n    pointer-events: none;\n\n    background-color: rgb(255 255 255 / calc(var(--lg-surface-alpha) + var(--lg-surface-lift)));\n    background-image:\n      radial-gradient(\n        circle at calc(var(--lg-light-x) * 100%) calc(var(--lg-light-y) * 100%),\n        rgb(\n          255 255 255 /\n            calc(\n              (var(--lg-light-strength) * 0.1 + var(--lg-highlight-strength) * 0.12) *\n                var(--lg-debug-highlight-scale, 1)\n            )\n        ),\n        transparent 65%\n      ),\n      linear-gradient(180deg, rgb(255 255 255 / var(--lg-sheen-alpha)), transparent 45%);\n    box-shadow: var(--lg-glass-rim);\n\n    -webkit-backdrop-filter: blur(var(--lg-surface-blur)) brightness(var(--lg-glass-brightness))\n      contrast(var(--lg-glass-contrast)) saturate(var(--lg-glass-sat));\n    backdrop-filter: blur(var(--lg-surface-blur)) brightness(var(--lg-glass-brightness))\n      contrast(var(--lg-glass-contrast)) saturate(var(--lg-glass-sat));\n  }\n\n  .lg-glass-surface[data-lg-generated-refraction='true']::before {\n    -webkit-backdrop-filter: none;\n    backdrop-filter: none;\n  }\n\n  /* Specular ring. The mask lives on this sibling of the frost layer, never\n     on an ancestor, so it cannot flatten the blur. */\n  .lg-glass-surface::after {\n    content: '';\n    position: absolute;\n    inset: 0;\n    z-index: 1;\n    padding: var(--lg-rim-width);\n    border-radius: inherit;\n    pointer-events: none;\n    background: var(--lg-specular-ring);\n    -webkit-mask:\n      linear-gradient(#000 0 0) content-box,\n      linear-gradient(#000 0 0);\n    -webkit-mask-composite: xor;\n    mask:\n      linear-gradient(#000 0 0) content-box,\n      linear-gradient(#000 0 0);\n    mask-composite: exclude;\n  }\n\n  /* Chromium edge lens: one SVG filter frosts, bends and saturates the\n     backdrop. Its displacement map is measured from the padding box the\n     frost layer fills. */\n  .lg-glass-surface[data-lg-lens='active']::before {\n    backdrop-filter: var(--lg-lens-filter);\n  }\n\n  /* Glass inside glass samples a backdrop the outer layer already saturated,\n     so it adds no saturation of its own. */\n  .lg-glass-surface .lg-glass-surface {\n    --lg-glass-sat: 1;\n    --lg-lens-saturation: 1;\n  }\n\n  .lg-noise {\n    position: absolute;\n    inset: 0;\n    z-index: 1;\n    border-radius: inherit;\n    pointer-events: none;\n    background-image: var(--lg-noise-image);\n    background-size: 128px 128px;\n    opacity: var(--lg-noise-alpha);\n    /* Static by default to avoid per-frame repaints; opt-in with data-lg-animate-noise=\"1\" on <html>. */\n    animation: none;\n    will-change: auto;\n  }\n\n  [data-lg-animate-noise='1'] .lg-noise {\n    animation: lg-grain 4s steps(10) infinite;\n  }\n\n  [data-lg-reduce-motion='1'] .lg-noise {\n    animation: none !important;\n  }\n\n  /* Light mode glass surface - emphasize refraction, minimize dynamic lighting */\n  [data-lg-theme='light'] .lg-glass-surface {\n    --lg-rim-offset-max: 2px;\n    --lg-rim-ca-alpha: calc(0.05 * var(--lg-debug-ca-scale, 1));\n  }\n\n  /* ============================================\n     Floating layers\n     Dialogs, popovers, toasts and tooltips frost on the element itself, so the\n     material survives their scrolling and their opacity animations. Their\n     denser tint keeps text readable over any backdrop.\n     ============================================ */\n\n  .lg-dialog-content,\n  .lg-popover-content,\n  .lg-toast-root,\n  .lg-tooltip-content,\n  .lg-sheet-content,\n  .lg-menu-content,\n  .lg-select-content {\n    background: var(--lg-overlay-surface);\n    -webkit-backdrop-filter: blur(var(--lg-surface-blur)) saturate(var(--lg-glass-sat));\n    backdrop-filter: blur(var(--lg-surface-blur)) saturate(var(--lg-glass-sat));\n  }\n\n  .lg-dialog-content::before,\n  .lg-popover-content::before,\n  .lg-toast-root::before,\n  .lg-tooltip-content::before,\n  .lg-sheet-content::before,\n  .lg-menu-content::before,\n  .lg-select-content::before {\n    background-color: transparent;\n    -webkit-backdrop-filter: none;\n    backdrop-filter: none;\n  }\n\n  /* Dialogs, popovers, sheets and menus are slabs of glass: the page shows\n     through, dimmed or lifted just enough to keep their text legible, and where\n     Chromium can run the lens their rim bends it. */\n  .lg-dialog-content,\n  .lg-popover-content,\n  .lg-sheet-content,\n  .lg-menu-content,\n  .lg-select-content {\n    --lg-lens-blur: var(--lg-slab-blur);\n    --lg-lens-body-brightness: var(--lg-slab-brightness);\n    --lg-lens-rim-brightness: var(--lg-slab-rim-brightness);\n\n    background: var(--lg-slab-tint);\n    -webkit-backdrop-filter: blur(calc(var(--lg-slab-blur) * 1px)) saturate(var(--lg-glass-sat))\n      brightness(var(--lg-slab-brightness));\n    backdrop-filter: blur(calc(var(--lg-slab-blur) * 1px)) saturate(var(--lg-glass-sat))\n      brightness(var(--lg-slab-brightness));\n  }\n\n  .lg-dialog-content[data-lg-lens='active'],\n  .lg-popover-content[data-lg-lens='active'],\n  .lg-sheet-content[data-lg-lens='active'],\n  .lg-menu-content[data-lg-lens='active'],\n  .lg-select-content[data-lg-lens='active'] {\n    -webkit-backdrop-filter: var(--lg-lens-filter);\n    backdrop-filter: var(--lg-lens-filter);\n  }\n\n  .lg-dialog-content[data-lg-lens='active']::before,\n  .lg-popover-content[data-lg-lens='active']::before,\n  .lg-sheet-content[data-lg-lens='active']::before,\n  .lg-menu-content[data-lg-lens='active']::before,\n  .lg-select-content[data-lg-lens='active']::before {\n    -webkit-backdrop-filter: none;\n    backdrop-filter: none;\n  }\n\n  .lg-dialog-content {\n    position: fixed;\n    top: 50%;\n    left: 50%;\n    z-index: 50;\n    width: calc(100vw - 2rem);\n    max-width: 520px;\n    max-height: calc(100dvh - 2rem);\n    translate: -50% -50%;\n    overflow-x: hidden;\n    overflow-y: auto;\n  }\n\n  @media (width >= 40rem) {\n    .lg-dialog-content {\n      padding: 2rem;\n    }\n  }\n\n  .lg-popover-content {\n    z-index: 50;\n    width: min(22rem, calc(100vw - 2rem));\n    max-height: calc(100dvh - 2rem);\n    overflow-x: hidden;\n    overflow-y: auto;\n    font-size: 0.875rem;\n    line-height: calc(1.25 / 0.875);\n  }\n\n  .lg-dialog-content:focus,\n  .lg-popover-content:focus {\n    outline: none;\n  }\n\n  .lg-tooltip-content {\n    z-index: 50;\n    max-width: calc(100vw - 2rem);\n    padding: 0.375rem 0.75rem;\n    font-size: 0.75rem;\n    line-height: calc(1 / 0.75);\n    font-weight: 500;\n  }\n\n  .lg-dialog-overlay {\n    position: fixed;\n    inset: 0;\n    z-index: 40;\n    background: var(--lg-scrim);\n    -webkit-backdrop-filter: blur(1.5px);\n    backdrop-filter: blur(1.5px);\n  }\n\n  /* Toasts stack in the top-right corner; each glass card keeps its own frost. */\n  .lg-toast-viewport {\n    position: fixed;\n    top: 1rem;\n    right: 1rem;\n    z-index: 100;\n    display: flex;\n    flex-direction: column;\n    gap: 0.75rem;\n    width: min(22rem, calc(100vw - 2rem));\n    max-width: calc(100vw - 2rem);\n    margin: 0;\n    padding: 0;\n    list-style: none;\n    pointer-events: none;\n  }\n\n  /* Radix turns selection off inline for the swipe, without the -webkit- prefix Safari needs. */\n  .lg-toast {\n    position: relative;\n    width: 100%;\n    list-style: none;\n    outline: none;\n    pointer-events: auto;\n    user-select: none;\n  }\n\n  .lg-toast-root {\n    display: grid;\n    grid-template-columns: minmax(0, 1fr) auto;\n    width: 100%;\n    font-size: 0.875rem;\n    line-height: calc(1.25 / 0.875);\n  }\n\n  .lg-toast-root > * {\n    grid-column: 1;\n  }\n\n  /* The dismiss button stands beside the words, not over them. */\n  .lg-toast-root > .lg-toast-close {\n    grid-column: 2;\n    grid-row: 1 / span 2;\n    align-self: start;\n  }\n\n  .lg-toast-close {\n    display: inline-flex;\n    flex: none;\n    align-items: center;\n    justify-content: center;\n    width: 1.75rem;\n    height: 1.75rem;\n    margin-block: -0.25rem 0;\n    margin-inline: 0.75rem -0.375rem;\n    padding: 0;\n    border: 0;\n    border-radius: 9999px;\n    background: transparent;\n    color: var(--lg-muted-foreground);\n    cursor: pointer;\n    transition:\n      background-color 180ms ease,\n      color 180ms ease;\n  }\n\n  .lg-toast-close:hover {\n    background: rgb(255 255 255 / 0.14);\n    color: var(--lg-foreground);\n  }\n\n  [data-lg-theme='light'] .lg-toast-close:hover {\n    background: rgb(0 0 0 / 0.07);\n  }\n\n  .lg-toast-close:focus-visible {\n    outline: 2px solid var(--lg-focus-ring);\n    outline-offset: 1px;\n    color: var(--lg-foreground);\n  }\n\n  .lg-toast-close > svg {\n    width: 1rem;\n    height: 1rem;\n  }\n\n  .lg-toast-action {\n    grid-column: 1;\n    justify-self: start;\n    height: 1.875rem;\n    margin-top: 0.625rem;\n    padding: 0 0.875rem;\n    border: 0;\n    border-radius: 9999px;\n    background: var(--lg-control-surface-hover);\n    box-shadow: inset 0 0 0 1px var(--lg-border);\n    color: var(--lg-foreground);\n    cursor: pointer;\n    font: inherit;\n    font-size: 0.8125rem;\n    font-weight: 600;\n    transition:\n      background-color 180ms ease,\n      scale 320ms var(--lg-spring);\n  }\n\n  .lg-toast-action:active {\n    scale: 0.94;\n  }\n\n  .lg-toast-action:focus-visible {\n    outline: 2px solid var(--lg-focus-ring);\n    outline-offset: 2px;\n  }\n\n  .lg-toast-title {\n    color: var(--lg-foreground);\n    font-size: 1rem;\n    line-height: 1.5;\n    font-weight: 600;\n  }\n\n  .lg-toast-description {\n    margin-top: 0.25rem;\n    color: var(--lg-muted-foreground);\n    font-size: 0.875rem;\n    line-height: calc(1.25 / 0.875);\n  }\n\n  /* ============================================\n     Reduced transparency\n     ============================================ */\n\n  /* Preference guards are !important because consumer utilities outrank every\n     other library default. Restyle them through --lg-opaque-surface and\n     --lg-control-surface, never by undoing the guard. */\n  [data-lg-reduce-transparency='1'] .lg-glass-surface::before {\n    -webkit-backdrop-filter: none !important;\n    backdrop-filter: none !important;\n    background: var(--lg-opaque-surface) !important;\n    box-shadow: none !important;\n    transform: none;\n  }\n\n  /* The ring keeps its mask and turns into a plain hairline border. */\n  [data-lg-reduce-transparency='1'] .lg-glass-surface::after,\n  [data-lg-reduce-transparency='1'] .lg-tabs-trigger[data-state='active']::after {\n    background: var(--lg-border);\n  }\n\n  /* The button draws the same hairline as an inset ring. A masked fill would\n     read to contrast checkers as a veil over the label. */\n  [data-lg-reduce-transparency='1'] .lg-button__rim {\n    background: none;\n    box-shadow: inset 0 0 0 var(--lg-rim-width) var(--lg-border);\n  }\n\n  [data-lg-reduce-transparency='1']\n    :is(\n      .lg-dialog-content,\n      .lg-popover-content,\n      .lg-toast-root,\n      .lg-tooltip-content,\n      .lg-sheet-content,\n      .lg-menu-content,\n      .lg-select-content,\n      .lg-dock-label\n    ) {\n    background: var(--lg-opaque-surface) !important;\n    -webkit-backdrop-filter: none !important;\n    backdrop-filter: none !important;\n  }\n\n  [data-lg-reduce-transparency='1']\n    :is(\n      .lg-button__distortion,\n      .lg-input,\n      .lg-accordion-trigger,\n      .lg-dialog-overlay,\n      .lg-badge,\n      .lg-alert\n    ) {\n    -webkit-backdrop-filter: none !important;\n    backdrop-filter: none !important;\n  }\n\n  /* Prominent glass has no fill of its own, so without the glass it is the\n     plain fill. */\n  [data-lg-reduce-transparency='1']\n    .lg-button--prominent\n    > .lg-button__layers\n    > .lg-button__distortion {\n    background: var(--lg-prominent-fill) !important;\n  }\n\n  [data-lg-reduce-transparency='1'] .lg-button__layers > .lg-button__light {\n    display: none !important;\n  }\n\n  /* Knobs stay solid white instead of turning to clear glass. */\n  [data-lg-reduce-transparency='1'] :is(.lg-switch-thumb, .lg-slider-thumb) {\n    background: var(--lg-knob) !important;\n  }\n\n  [data-lg-reduce-transparency='1'] .lg-switch-lens,\n  [data-lg-reduce-transparency='1'] .lg-switch-thumb::after {\n    display: none;\n  }\n\n  [data-lg-reduce-transparency='1'] .lg-button__shine,\n  [data-lg-reduce-transparency='1'] .lg-button__tint {\n    opacity: 0;\n  }\n\n  [data-lg-reduce-transparency='1'] .lg-button__bloom {\n    display: none;\n  }\n\n  [data-lg-reduce-transparency='1'] .lg-refraction-background {\n    display: none;\n  }\n\n  /* ============================================\n     Increased contrast: glass dimmed or frosted denser (see the tokens above),\n     edged by a ring in the text colour. The ring is the specular layer, which\n     paints above the frost, so every engine shows it.\n     Forced colors: solid surfaces, real outlines.\n     Both: buttons and fields drop their blur, and controls get outlines in the\n     text colour.\n     ============================================ */\n\n  @media (prefers-contrast: more) {\n    /* A guard like the transparency ones, so their hairline cannot replace it. */\n    .lg-glass-surface::after {\n      background: var(--lg-foreground) !important;\n    }\n\n    /* Dark glass adds no white of its own: presets and hover keep the base veil. */\n    [data-lg-theme='dark'] .lg-glass-surface {\n      --lg-surface-alpha: var(--lg-glass-alpha) !important;\n      --lg-surface-lift: 0 !important;\n    }\n\n    /* Light segmented tracks frost like the other glass, not as a slate well. */\n    [data-lg-theme='light']:not([data-lg-reduce-transparency='1']) .lg-segmented::before {\n      background-color: rgb(255 255 255 / var(--lg-glass-alpha));\n    }\n\n    /* A generated refraction shows its backdrop undimmed, so the pane frosts\n       and dims the page behind it instead. */\n    .lg-refraction-background {\n      display: none;\n    }\n\n    .lg-glass-surface[data-lg-generated-refraction='true']::before {\n      -webkit-backdrop-filter: blur(var(--lg-surface-blur)) brightness(var(--lg-glass-brightness))\n        contrast(var(--lg-glass-contrast)) saturate(var(--lg-glass-sat));\n      backdrop-filter: blur(var(--lg-surface-blur)) brightness(var(--lg-glass-brightness))\n        contrast(var(--lg-glass-contrast)) saturate(var(--lg-glass-sat));\n    }\n\n    /* Badges and alerts keep the solid fill their tone colours are set on. */\n    .lg-badge,\n    .lg-alert {\n      -webkit-backdrop-filter: none !important;\n      backdrop-filter: none !important;\n      background: var(--lg-opaque-surface) !important;\n    }\n\n    /* Overlays scroll their content, and their ring layer with it, so they\n       carry the ring as an outline that stays on their edge, focused or not. */\n    :is(\n      .lg-dialog-content,\n      .lg-popover-content,\n      .lg-sheet-content,\n      .lg-menu-content,\n      .lg-select-content\n    ) {\n      outline: 1px solid var(--lg-foreground) !important;\n      outline-offset: -1px !important;\n    }\n\n    :is(\n      .lg-dialog-content,\n      .lg-popover-content,\n      .lg-sheet-content,\n      .lg-menu-content,\n      .lg-select-content\n    )::after {\n      display: none;\n    }\n  }\n\n  @media (forced-colors: active) {\n    .lg-glass-surface {\n      outline: 1px solid CanvasText !important;\n      outline-offset: -1px !important;\n    }\n\n    .lg-glass-surface::before,\n    .lg-dialog-content,\n    .lg-popover-content,\n    .lg-toast-root,\n    .lg-tooltip-content,\n    .lg-sheet-content,\n    .lg-menu-content,\n    .lg-select-content,\n    .lg-dock-label,\n    .lg-badge,\n    .lg-alert {\n      -webkit-backdrop-filter: none !important;\n      backdrop-filter: none !important;\n      background: var(--lg-opaque-surface) !important;\n    }\n\n    .lg-glass-surface::before {\n      box-shadow: none !important;\n    }\n\n    /* The 1px outline replaces the specular ring. */\n    .lg-glass-surface::after {\n      display: none;\n    }\n\n    .lg-refraction-background {\n      display: none;\n    }\n  }\n\n  @media (prefers-contrast: more), (forced-colors: active) {\n    .lg-badge,\n    .lg-alert,\n    .lg-kbd,\n    .lg-progress-track,\n    .lg-dock-label,\n    .lg-switch,\n    .lg-slider-track,\n    .lg-segmented-indicator,\n    .lg-tabs-indicator {\n      outline: 1px solid CanvasText;\n      outline-offset: -1px;\n    }\n\n    .lg-segmented-indicator::after,\n    .lg-tabs-indicator::after,\n    .lg-lens::after,\n    .lg-button__bloom,\n    .lg-switch-lens,\n    .lg-switch-thumb::after {\n      display: none;\n    }\n\n    /* The switch's knob stays solid instead of turning to clear glass; forced\n       colours paint it with system colours below. */\n    .lg-switch-thumb {\n      background: var(--lg-knob) !important;\n    }\n\n    .lg-lens {\n      outline: 2px solid CanvasText;\n    }\n\n    .lg-tabs-trigger[data-state='active']::after {\n      display: none;\n    }\n\n    .lg-button:not(.lg-button--ghost, .lg-button--prominent) {\n      --lg-button-fill: var(--lg-opaque-surface) !important;\n      --lg-button-fill-hover: var(--lg-opaque-surface) !important;\n    }\n\n    .lg-button--prominent > .lg-button__layers > .lg-button__distortion {\n      background: var(--lg-prominent-fill) !important;\n    }\n\n    .lg-button__layers > .lg-button__light {\n      display: none !important;\n    }\n\n    .lg-button__distortion,\n    .lg-input,\n    .lg-accordion-trigger,\n    .lg-dialog-overlay {\n      -webkit-backdrop-filter: none !important;\n      backdrop-filter: none !important;\n    }\n\n    .lg-button .lg-button__rim {\n      padding: 0;\n      border: 1px solid CanvasText;\n      background: none;\n      -webkit-mask: none;\n      mask: none;\n    }\n\n    .lg-input,\n    .lg-checkbox,\n    .lg-radio,\n    .lg-accordion-trigger {\n      border-color: CanvasText !important;\n    }\n\n    /* Focusable surfaces such as tab panels need a ring distinct from the\n       1px surface outline. */\n    .lg-button:focus-visible,\n    .lg-input:focus,\n    .lg-checkbox:focus-visible,\n    .lg-radio:focus-visible,\n    .lg-glass-surface:focus-visible {\n      outline: 2px solid CanvasText !important;\n      outline-offset: 2px !important;\n    }\n  }\n\n  /* Forced colors repaint every author color, so the controls whose state is\n     their color opt out and use system colors directly. */\n  @media (forced-colors: active) {\n    .lg-switch,\n    .lg-switch-thumb,\n    .lg-slider-range,\n    .lg-slider-thumb,\n    .lg-segmented-indicator,\n    .lg-tabs-indicator,\n    .lg-checkbox,\n    .lg-radio,\n    .lg-progress-fill,\n    .lg-menu-item,\n    .lg-command-item {\n      forced-color-adjust: none;\n    }\n\n    .lg-progress-fill {\n      background: Highlight;\n      box-shadow: none;\n    }\n\n    .lg-page[data-current] {\n      background: Highlight;\n      color: HighlightText;\n      forced-color-adjust: none;\n    }\n\n    .lg-switch {\n      background: Canvas;\n    }\n\n    .lg-checkbox,\n    .lg-radio {\n      border-color: CanvasText;\n      background: Canvas;\n      box-shadow: none;\n      color: HighlightText;\n    }\n\n    .lg-checkbox[data-state='checked'],\n    .lg-checkbox[data-state='indeterminate'],\n    .lg-radio[data-state='checked'] {\n      border-color: Highlight;\n      background: Highlight;\n    }\n\n    .lg-radio-dot {\n      background: HighlightText;\n      box-shadow: none;\n    }\n\n    /* Forced colours strip the fill that gives an avatar its shape. */\n    .lg-avatar-face {\n      border: 1px solid CanvasText;\n      box-sizing: border-box;\n    }\n\n    .lg-switch[data-state='checked'],\n    .lg-slider-range,\n    .lg-menu-item[data-highlighted],\n    .lg-command-item[data-selected='true'] {\n      background: Highlight;\n      color: HighlightText;\n    }\n\n    /* A guard, like the transparency ones: the bubbles' glass rules are more\n       specific. */\n    .lg-segmented-indicator,\n    .lg-tabs-indicator {\n      background: Highlight !important;\n    }\n\n    /* The list prefix outranks the controls' own later state colors. */\n    .lg-tabs-list .lg-tabs-trigger[data-state='active'] {\n      color: HighlightText;\n      forced-color-adjust: none;\n    }\n\n    .lg-tabs-list:not([data-lg-indicator='ready']) .lg-tabs-trigger[data-state='active'] {\n      background: Highlight;\n    }\n\n    .lg-switch-thumb,\n    .lg-slider-thumb {\n      background: CanvasText !important;\n      box-shadow: none;\n    }\n\n    .lg-switch[data-state='checked'] .lg-switch-thumb {\n      background: HighlightText !important;\n    }\n\n    .lg-segmented .lg-segmented-item[data-state='checked'] {\n      color: HighlightText;\n      forced-color-adjust: none;\n    }\n\n    .lg-menu-item,\n    .lg-command-item,\n    .lg-toast-close {\n      color: CanvasText;\n    }\n  }\n\n  /* --- Buttons --- */\n\n  .lg-button {\n    --lg-radius: 999px;\n    --lg-surface-blur: min(var(--lg-glass-blur), 16px);\n    --lg-ink: var(--lg-foreground);\n    --lg-button-fill: rgb(255 255 255 / 0.07);\n    --lg-button-fill-hover: rgb(255 255 255 / 0.11);\n    --lg-button-sheen: 0.1;\n    --lg-button-glow: 0.14;\n    --lg-button-glow-pressed: 0.26;\n    --lg-button-shine: var(--lg-button-glow);\n    /* The fill highlight sits between the light and the centre. */\n    --lg-fill-x: calc(0.5 + (var(--lg-light-x) - 0.5) * 0.35);\n    --lg-fill-y: calc(0.5 + (var(--lg-light-y) - 0.5) * 0.35);\n    --lg-rim-scale: var(--lg-debug-rim-thickness, 1);\n    --lg-rim-offset-max: 1.1px;\n    --lg-rim-tangent-alpha: 1;\n    --lg-rim-micro-mask: 1;\n    --lg-rim-corner-mask: 1;\n    --lg-rim-offset-x: clamp(\n      calc(-1 * var(--lg-rim-offset-max)),\n      calc(var(--lg-light-dir-x) * -1 * var(--lg-rim-offset-max) * (0.7 + var(--lg-light-level))),\n      var(--lg-rim-offset-max)\n    );\n    --lg-rim-offset-y: clamp(\n      calc(-1 * var(--lg-rim-offset-max)),\n      calc(var(--lg-light-dir-y) * -1 * var(--lg-rim-offset-max) * (0.7 + var(--lg-light-level))),\n      var(--lg-rim-offset-max)\n    );\n    --lg-rim-light: calc(var(--lg-button-reflex-light) * var(--lg-rim-gain));\n    --lg-rim-dark: var(--lg-reflex-dark);\n    --lg-rim-alpha: calc((0.08 + var(--lg-light-level) * 0.12) * var(--lg-rim-gain));\n    --lg-rim-ca-offset: calc(1.5px * var(--lg-debug-ca-offset-scale, 1));\n    --lg-rim-ca-alpha: calc(0.06 * var(--lg-debug-ca-scale, 1));\n\n    position: relative;\n    display: inline-flex;\n    align-items: center;\n    justify-content: center;\n    gap: 0.5rem;\n    padding: 0.75rem 1.5rem;\n\n    border-radius: var(--lg-radius);\n    border: none;\n    background: transparent;\n    color: var(--lg-ink);\n    text-decoration: none;\n\n    font-weight: 500;\n    letter-spacing: -0.01em;\n    isolation: isolate;\n    cursor: pointer;\n    contain: layout paint style;\n\n    /* Each button is a slab of glass resting just above the page, lit from\n       above. A pointer lowers it halfway and a press sets it down, so its\n       shadow draws in under it; the glass itself stays put. */\n    --lg-button-rise: 1;\n    --lg-button-rise-time: calc(var(--lg-motion-duration) * 1.6);\n    --lg-button-shade: 0 0 0;\n    --lg-button-shade-near: 0.32;\n    --lg-button-shade-far: 0.36;\n    transition: --lg-button-rise var(--lg-button-rise-time) var(--lg-ease-out);\n  }\n\n  @media (hover: hover) {\n    .lg-button:not(:disabled, [aria-disabled='true']):hover {\n      --lg-button-rise: 0.5;\n    }\n  }\n\n  .lg-button[data-pressed='true']:not(:disabled, [aria-disabled='true']) {\n    --lg-button-rise: 0.2;\n    --lg-button-rise-time: calc(var(--lg-motion-duration) * 0.6);\n  }\n\n  .lg-button[data-lg-preset='control'] {\n    --lg-surface-blur: min(var(--lg-glass-blur), 10px);\n  }\n\n  .lg-button[data-lg-preset='showcase'] {\n    --lg-surface-blur: min(var(--lg-glass-blur), 16px);\n  }\n\n  .lg-button:focus-visible {\n    outline: 2px solid var(--lg-focus-ring);\n    outline-offset: 2px;\n  }\n\n  /* Disabled buttons dim their content, never the host: opacity on an ancestor\n     of the frost layer isolates its backdrop and flattens the glass. */\n  .lg-button:disabled,\n  .lg-button[aria-disabled='true'] {\n    cursor: not-allowed;\n    transform: none;\n  }\n\n  .lg-button:disabled :is(.lg-button__label, .lg-button__tint, .lg-button__rim),\n  .lg-button[aria-disabled='true'] :is(.lg-button__label, .lg-button__tint, .lg-button__rim) {\n    opacity: var(--lg-disabled-opacity);\n  }\n\n  .lg-button__layers {\n    position: absolute;\n    inset: 0;\n    border-radius: inherit;\n    pointer-events: none;\n    z-index: 0;\n    overflow: hidden;\n  }\n\n  /* Icons and text sit in one row, spaced by the button's own gap. */\n  .lg-button__label {\n    position: relative;\n    z-index: 1;\n    display: inline-flex;\n    align-items: center;\n    gap: inherit;\n  }\n\n  .lg-button__layers > span {\n    position: absolute;\n    inset: 0;\n    border-radius: inherit;\n  }\n\n  /* 0. The light the glass lets through, under it. Tinted glass shows it. */\n  .lg-button__layers > .lg-button__light {\n    display: none;\n  }\n\n  /* 1. Frost: the only backdrop layer */\n  .lg-button__distortion {\n    background: var(--lg-button-fill);\n    -webkit-backdrop-filter: blur(var(--lg-surface-blur)) saturate(var(--lg-glass-sat));\n    backdrop-filter: blur(var(--lg-surface-blur)) saturate(var(--lg-glass-sat));\n    transition: background-color var(--lg-motion-duration) ease;\n  }\n\n  .lg-button[data-lg-lens='active'] > .lg-button__layers > .lg-button__distortion {\n    backdrop-filter: var(--lg-lens-filter);\n  }\n\n  .lg-button:not(:disabled, [aria-disabled='true']):hover .lg-button__distortion {\n    background: var(--lg-button-fill-hover);\n  }\n\n  /* 2. Sheen and bevel: top-lit gradient, a gentle fixed highlight and the\n     shared glass bevel */\n  .lg-button__tint {\n    background:\n      radial-gradient(\n        circle at calc(var(--lg-fill-x) * 100%) calc(var(--lg-fill-y) * 100%),\n        rgb(255 255 255 / calc(var(--lg-light-level) * 0.08)),\n        transparent 70%\n      ),\n      linear-gradient(180deg, rgb(255 255 255 / var(--lg-button-sheen)), transparent 60%);\n    box-shadow: var(--lg-glass-rim);\n  }\n\n  /* 3. Shine: hover glow that lights up from within while pressed */\n  .lg-button__shine {\n    background: radial-gradient(\n      circle at calc(var(--lg-fill-x) * 100%) calc(var(--lg-fill-y) * 100%),\n      rgb(255 255 255 / var(--lg-button-shine)),\n      transparent 60%\n    );\n    opacity: 0;\n    transition: opacity var(--lg-motion-duration) ease;\n  }\n\n  .lg-button:not(:disabled, [aria-disabled='true']):hover .lg-button__shine,\n  .lg-button[data-pressed='true']:not(:disabled, [aria-disabled='true']) .lg-button__shine {\n    opacity: 1;\n  }\n\n  .lg-button[data-pressed='true'] {\n    --lg-button-shine: var(--lg-button-glow-pressed);\n  }\n\n  /* 4. Bloom: a press lights the glass from the fingertip outward. Script\n     places it at the press point and plays it once per press. It stays\n     faint: the slab setting down carries the press, and the light only\n     marks where it landed. */\n  .lg-button__layers > .lg-button__bloom {\n    inset: auto;\n    top: var(--lg-bloom-y, 50%);\n    left: var(--lg-bloom-x, 50%);\n    width: var(--lg-bloom-size, 0px);\n    height: var(--lg-bloom-size, 0px);\n    border-radius: 50%;\n    background: radial-gradient(\n      closest-side,\n      rgb(255 255 255 / 0.18),\n      rgb(255 255 255 / 0.05) 60%,\n      transparent\n    );\n    opacity: 0;\n    translate: -50% -50%;\n  }\n\n  /* 5. Rim: the shared specular ring */\n  .lg-button__rim {\n    padding: var(--lg-rim-width);\n    background: var(--lg-specular-ring);\n    -webkit-mask:\n      linear-gradient(#000 0 0) content-box,\n      linear-gradient(#000 0 0);\n    -webkit-mask-composite: xor;\n    mask:\n      linear-gradient(#000 0 0) content-box,\n      linear-gradient(#000 0 0);\n    mask-composite: exclude;\n  }\n\n  /* Button Variants. A slab's shadow falls straight down from it and draws in\n     as it lowers: a near, sharp contact shadow and a soft one further out. */\n  .lg-button--primary,\n  .lg-button--soft {\n    box-shadow:\n      0 calc(var(--lg-button-rise) * 1.8px) calc(var(--lg-button-rise) * 2px)\n        calc(var(--lg-button-rise) * -1px) rgb(var(--lg-button-shade) / var(--lg-button-shade-near)),\n      0 calc(var(--lg-button-rise) * 6.7px) calc(var(--lg-button-rise) * 10px)\n        calc(var(--lg-button-rise) * -5px) rgb(var(--lg-button-shade) / var(--lg-button-shade-far));\n  }\n\n  .lg-button--soft {\n    --lg-button-fill: rgb(255 255 255 / 0.04);\n    --lg-button-fill-hover: rgb(255 255 255 / 0.08);\n    --lg-button-shade-near: 0.2;\n    --lg-button-shade-far: 0.18;\n  }\n\n  .lg-button--ghost {\n    --lg-button-fill: transparent;\n    --lg-button-fill-hover: rgb(255 255 255 / 0.06);\n    box-shadow: none;\n  }\n\n  .lg-button--ghost .lg-button__distortion {\n    -webkit-backdrop-filter: none;\n    backdrop-filter: none;\n  }\n\n  .lg-button--ghost :is(.lg-button__rim, .lg-button__tint) {\n    display: none;\n  }\n\n  /* Sizes */\n  .lg-button--sm {\n    font-size: 0.8rem;\n    padding: 0.4rem 0.8rem;\n  }\n  .lg-button--md {\n    font-size: 0.95rem;\n    padding: 0.7rem 1.4rem;\n  }\n  .lg-button--lg {\n    font-size: 1.1rem;\n    padding: 1rem 2rem;\n  }\n\n  /* ============================================\n     LIGHT THEME - Button Overrides\n     ============================================ */\n\n  [data-lg-theme='light'] .lg-button {\n    --lg-button-fill: rgb(255 255 255 / 0.45);\n    --lg-button-fill-hover: rgb(255 255 255 / 0.6);\n    --lg-button-sheen: 0.35;\n    --lg-button-glow: 0.45;\n    --lg-button-glow-pressed: 0.75;\n    --lg-button-shade: 52 62 84;\n    --lg-button-shade-near: 0.18;\n    --lg-button-shade-far: 0.2;\n  }\n\n  [data-lg-theme='light'] .lg-button--soft {\n    --lg-button-shade-near: 0.12;\n    --lg-button-shade-far: 0.12;\n  }\n\n  [data-lg-theme='light'] .lg-button--soft {\n    --lg-button-fill: rgb(255 255 255 / 0.3);\n    --lg-button-fill-hover: rgb(255 255 255 / 0.45);\n  }\n\n  [data-lg-theme='light'] .lg-button--ghost {\n    --lg-button-fill: transparent;\n    --lg-button-fill-hover: rgb(0 0 0 / 0.04);\n  }\n\n  /* Prominent: a slab of blue glass. It passes on the light of whatever\n     lies behind it, tinted blue, so the page, the light it lets through and\n     the shadow under it all show in it. The tint caps how bright that light\n     can get, which keeps white text legible over any backdrop. Two classes\n     outrank the light-theme overrides above. */\n  .lg-button.lg-button--prominent {\n    --lg-ink: var(--lg-accent-foreground);\n    --lg-button-fill: var(--lg-prominent-fill);\n    --lg-button-fill-hover: var(--lg-prominent-fill);\n    --lg-button-sheen: 0;\n    --lg-button-glow: 0;\n    --lg-button-glow-pressed: 0;\n    /* The rays of the light cross the glass along x and y. */\n    --lg-button-ray-x: calc(sin(var(--lg-button-light-angle)) * -1);\n    --lg-button-ray-y: cos(var(--lg-button-light-angle));\n    /* The light eases over, gently at both ends, and returns briskly. */\n    --lg-button-rise-time: calc(var(--lg-motion-duration) * 1.5);\n    --lg-button-light-time: calc(var(--lg-motion-duration) * 1.75);\n    --lg-button-light-ease: cubic-bezier(0.25, 0.8, 0.3, 1);\n    /* The shadow stays under the slab and draws in as it lowers; only the\n       light along the rim follows the light. */\n    box-shadow:\n      0 calc(var(--lg-button-rise) * 1.8px) calc(var(--lg-button-rise) * 2px)\n        calc(var(--lg-button-rise) * -1px) rgb(var(--lg-prominent-shade) / 0.4),\n      0 calc(var(--lg-button-rise) * 6.7px) calc(var(--lg-button-rise) * 10px)\n        calc(var(--lg-button-rise) * -5px) rgb(var(--lg-prominent-shade) / 0.4);\n    transition:\n      --lg-button-rise var(--lg-button-rise-time) cubic-bezier(0.25, 0.8, 0.3, 1),\n      --lg-button-light-angle var(--lg-button-light-time) var(--lg-button-light-ease);\n  }\n\n  /* A pointer lowers the slab like any button and swings its light 50deg over\n     to the top left. */\n  @media (hover: hover) {\n    .lg-button.lg-button--prominent:not(:disabled, [aria-disabled='true']):hover {\n      --lg-button-light-angle: -50deg;\n      --lg-button-light-time: calc(var(--lg-motion-duration) * 2.75);\n      --lg-button-light-ease: cubic-bezier(0.45, 0, 0.55, 1);\n    }\n  }\n\n  /* Under the glass lies the light it lets through: a dim pool, a dark line\n     where the rounded edge turns the light aside and a bright one just inside\n     it where the edge gathers it. It sits a little below the glass, further\n     the higher the glass rests, so a press all but hides it. The pool is dense\n     enough that, should an ancestor cut the glass off from the page (opacity,\n     a filter or a mask), it alone keeps the white label at 4.5:1 over white. */\n  .lg-button--prominent > .lg-button__layers > .lg-button__light {\n    --lg-rise-cubed: calc(var(--lg-button-rise) * var(--lg-button-rise) * var(--lg-button-rise));\n\n    display: block;\n    /* Light coming in at a slant crosses the glass at a slant, so the pool\n       moves away from it. */\n    translate: calc(var(--lg-button-ray-x) * 1.2px) calc(var(--lg-rise-cubed) * 2px);\n    background: rgb(var(--lg-prominent-shade) / 0.6);\n    box-shadow:\n      inset 0 0 0 calc(1px + var(--lg-rise-cubed) * 1.6px) rgb(var(--lg-prominent-shade) / 0.5),\n      inset 0 0 0 calc(2px + var(--lg-rise-cubed) * 2.2px) rgb(var(--lg-prominent-glow) / 0.75);\n    filter: blur(calc(0.2px + var(--lg-button-rise) * 0.4px));\n  }\n\n  /* The face is that light, tinted. Its faint sheen turns with the light. */\n  .lg-button--prominent > .lg-button__layers > .lg-button__distortion {\n    -webkit-backdrop-filter: blur(0.6px) var(--lg-prominent-tint);\n    backdrop-filter: blur(0.6px) var(--lg-prominent-tint);\n    /* The solid fill replaces the tint and light together. Fading only the\n       fill exposes the untinted backdrop while those layers switch. */\n    transition: none;\n  }\n\n  .lg-button--prominent > .lg-button__layers > .lg-button__distortion,\n  .lg-button--prominent:not(:disabled, [aria-disabled='true']):hover\n    > .lg-button__layers\n    > .lg-button__distortion {\n    background: linear-gradient(\n      calc(180deg + var(--lg-button-light-angle)),\n      rgb(255 255 255 / 0.07),\n      transparent 45%\n    );\n  }\n\n  /* In Chromium the edge lens bends the light at the rim, then it is tinted. */\n  .lg-button--prominent[data-lg-lens='active'] > .lg-button__layers > .lg-button__distortion {\n    backdrop-filter: var(--lg-lens-filter) var(--lg-prominent-tint);\n  }\n\n  /* The rim: a dark line at the very edge, where it turns the light aside, a\n     soft sheen under the top, where it faces the light, and a glow along the\n     bottom, where the light the slab carried across leaves it. Set down, the\n     glass gathers more of that light and glows all round. All of it turns\n     with the light: the sheen moves round to the edge facing it and the glow\n     round to the far edge. */\n  .lg-button--prominent > .lg-button__layers > .lg-button__tint {\n    --lg-button-sunk: calc(1 - var(--lg-button-rise));\n\n    background: none;\n    box-shadow:\n      inset 0 0 0 1px rgb(var(--lg-prominent-shade) / 0.32),\n      inset calc(var(--lg-button-ray-x) * -5px) calc(var(--lg-button-ray-y) * -5px) 7px -4px\n        rgb(var(--lg-prominent-glow) / calc(0.5 + var(--lg-button-sunk) * 0.35)),\n      inset 0 0 calc(4px + var(--lg-button-sunk) * 10px) 0\n        rgb(var(--lg-prominent-glow) / calc(var(--lg-button-sunk) * 0.32)),\n      inset calc(var(--lg-button-ray-x) * 7px) calc(var(--lg-button-ray-y) * 7px) 8px -7px\n        rgb(255 255 255 / 0.22),\n      inset calc(var(--lg-button-ray-x) * 3px) calc(var(--lg-button-ray-y) * 3px) 4px -2px\n        rgb(0 0 0 / 0.08);\n  }\n\n  /* Just inside the dark line, a bright one where the edge gathers the\n     light: strongest along the top, faint at the sides, blue below. It turns\n     with the light, so the bright line moves round to the end facing it and\n     the blue one to the far end. */\n  .lg-button--prominent > .lg-button__layers > .lg-button__rim {\n    inset: 1px;\n    padding: 1px;\n    background: linear-gradient(\n      calc(180deg + var(--lg-button-light-angle)),\n      rgb(255 255 255 / 0.78),\n      rgb(255 255 255 / 0.12) 36% 64%,\n      rgb(var(--lg-prominent-glow) / 0.62)\n    );\n  }\n\n  /* Over a pale page the bright line brightens as the light swings over, so\n     it reads as clearly as it does against a dark one. */\n  [data-lg-theme='light'] .lg-button--prominent > .lg-button__layers > .lg-button__rim {\n    background: linear-gradient(\n      calc(180deg + var(--lg-button-light-angle)),\n      rgb(255 255 255 / calc(0.78 + max(0, var(--lg-button-ray-x)) * 0.2)),\n      rgb(255 255 255 / 0.12) 36% 64%,\n      rgb(var(--lg-prominent-glow) / 0.62)\n    );\n  }\n\n  /* Without a backdrop filter the face is the plain fill. */\n  @supports not ((-webkit-backdrop-filter: blur(1px)) or (backdrop-filter: blur(1px))) {\n    .lg-button--prominent > .lg-button__layers > .lg-button__distortion {\n      background: var(--lg-prominent-fill);\n    }\n  }\n\n  [data-lg-reduce-transparency='1'] .lg-button:not(.lg-button--ghost, .lg-button--prominent) {\n    --lg-button-fill: var(--lg-control-surface) !important;\n    --lg-button-fill-hover: var(--lg-control-surface-hover) !important;\n  }\n\n  /* Input Fields: a recessed glass well */\n  .lg-input {\n    width: 100%;\n    padding: 0.875rem 1.25rem;\n    border-radius: 16px;\n    border: 1px solid var(--lg-border);\n    background: var(--lg-control-surface);\n    color: var(--lg-foreground);\n    font-size: 1rem;\n    outline: none;\n    transition:\n      background var(--lg-motion-duration) ease,\n      border-color var(--lg-motion-duration) ease,\n      box-shadow var(--lg-motion-duration) ease;\n    -webkit-backdrop-filter: blur(min(var(--lg-glass-blur), 16px))\n      brightness(var(--lg-glass-brightness)) contrast(var(--lg-glass-contrast))\n      saturate(var(--lg-glass-sat));\n    backdrop-filter: blur(min(var(--lg-glass-blur), 16px)) brightness(var(--lg-glass-brightness))\n      contrast(var(--lg-glass-contrast)) saturate(var(--lg-glass-sat));\n    box-shadow: var(--lg-input-shadow);\n  }\n\n  /* A focused field fills in and its caret shows where typing goes. It draws no\n     ring: a text field counts as keyboard-focused even when clicked, so a ring\n     would follow every tap. The select trigger has no caret, so keyboard focus\n     still outlines it. */\n  .lg-input:focus {\n    background: var(--lg-control-surface-hover);\n  }\n\n  .lg-select-trigger:focus-visible {\n    outline: 2px solid var(--lg-focus-ring);\n    outline-offset: 2px;\n  }\n\n  .lg-input::placeholder {\n    color: var(--lg-muted-foreground);\n    opacity: 0.72;\n  }\n\n  .lg-input[aria-invalid='true'] {\n    border-color: var(--lg-invalid);\n    box-shadow: 0 0 0 1px var(--lg-invalid);\n  }\n\n  .lg-input:disabled {\n    cursor: not-allowed;\n    opacity: var(--lg-disabled-opacity);\n  }\n\n  /* ============================================\n     Checkbox and radio: a small glass well that fills with the accent, with a\n     mark that draws itself in and back out, so clearing a choice moves as\n     smoothly as making it. Every transition sits on the base rule, never on\n     the checked one, so both directions animate.\n     ============================================ */\n\n  .lg-check-field {\n    display: flex;\n    align-items: flex-start;\n    gap: 0.75rem;\n    color: var(--lg-foreground);\n    font-size: 0.9375rem;\n    line-height: 1.4;\n  }\n\n  .lg-check-text {\n    display: flex;\n    min-width: 0;\n    flex-direction: column;\n    padding-top: 0.0625rem;\n  }\n\n  /* Clicking the label toggles the box, so a quick second click must not select its text. The\n     description below it stays selectable. */\n  .lg-check-text > label {\n    cursor: pointer;\n    user-select: none;\n  }\n\n  .lg-check-text > span {\n    color: var(--lg-muted-foreground);\n    font-size: 0.8125rem;\n    line-height: 1.35;\n  }\n\n  .lg-check-field[data-size='sm'] {\n    gap: 0.625rem;\n    font-size: 0.875rem;\n  }\n\n  .lg-check-field[data-disabled] {\n    opacity: var(--lg-disabled-opacity);\n  }\n\n  .lg-check-field[data-disabled] .lg-check-text > label {\n    cursor: not-allowed;\n  }\n\n  .lg-radio-group {\n    display: grid;\n    gap: 0.75rem;\n  }\n\n  .lg-checkbox,\n  .lg-radio {\n    --lg-check-size: 1.25rem;\n    /* The edge of an empty box is what says it can be ticked, so it holds 3:1 over the\n       glass it sits on, which the hairline border of a text field does not. */\n    --lg-check-edge: rgb(244 245 249 / 0.78);\n\n    position: relative;\n    display: inline-grid;\n    flex: none;\n    place-items: center;\n    box-sizing: border-box;\n    width: var(--lg-check-size);\n    height: var(--lg-check-size);\n    margin: 0;\n    padding: 0;\n    border: 1.5px solid var(--lg-check-edge);\n    background: var(--lg-control-surface);\n    box-shadow: var(--lg-input-shadow);\n    color: #fff;\n    cursor: pointer;\n    -webkit-tap-highlight-color: transparent;\n    transition:\n      background-color 220ms ease,\n      border-color 220ms ease,\n      box-shadow 220ms ease,\n      scale 320ms var(--lg-spring);\n  }\n\n  [data-lg-theme='light'] .lg-checkbox,\n  [data-lg-theme='light'] .lg-radio {\n    --lg-check-edge: rgb(27 29 36 / 0.6);\n  }\n\n  .lg-checkbox {\n    border-radius: 0.4375rem;\n  }\n\n  .lg-radio {\n    border-radius: 9999px;\n  }\n\n  .lg-checkbox[data-size='sm'],\n  .lg-check-field[data-size='sm'] .lg-checkbox {\n    --lg-check-size: 1rem;\n\n    border-radius: 0.3125rem;\n  }\n\n  .lg-checkbox[data-state='unchecked']:hover:not([data-disabled]),\n  .lg-radio[data-state='unchecked']:hover:not([data-disabled]) {\n    background: var(--lg-control-surface-hover);\n  }\n\n  .lg-checkbox:active:not([data-disabled]),\n  .lg-radio:active:not([data-disabled]) {\n    scale: 0.9;\n  }\n\n  .lg-checkbox:focus-visible,\n  .lg-radio:focus-visible {\n    outline: 2px solid var(--lg-focus-ring);\n    outline-offset: 2px;\n  }\n\n  .lg-checkbox[aria-invalid='true'],\n  .lg-radio[aria-invalid='true'] {\n    border-color: var(--lg-invalid);\n  }\n\n  .lg-checkbox[data-disabled],\n  .lg-radio[data-disabled] {\n    cursor: not-allowed;\n    opacity: var(--lg-disabled-opacity);\n  }\n\n  .lg-checkbox[data-state='checked'],\n  .lg-checkbox[data-state='indeterminate'],\n  .lg-radio[data-state='checked'] {\n    border-color: transparent;\n    background:\n      linear-gradient(180deg, rgb(255 255 255 / 0.24), rgb(255 255 255 / 0) 62%), var(--lg-accent);\n    box-shadow:\n      inset 0 1px 0 rgb(255 255 255 / 0.4),\n      inset 0 -1px 0 rgb(0 0 0 / 0.14),\n      0 1px 3px rgb(0 0 0 / 0.28);\n  }\n\n  .lg-check-indicator {\n    display: grid;\n    width: 100%;\n    height: 100%;\n    place-items: center;\n    pointer-events: none;\n  }\n\n  .lg-check-mark {\n    width: 84%;\n    height: 84%;\n    fill: none;\n    stroke: currentColor;\n    stroke-width: 2.1;\n    stroke-linecap: round;\n    stroke-linejoin: round;\n  }\n\n  .lg-check-tick,\n  .lg-check-dash {\n    stroke-dasharray: 1;\n    stroke-dashoffset: 1;\n    transition: stroke-dashoffset 300ms var(--lg-ease-out);\n  }\n\n  .lg-checkbox[data-state='checked'] .lg-check-tick,\n  .lg-checkbox[data-state='indeterminate'] .lg-check-dash {\n    stroke-dashoffset: 0;\n  }\n\n  .lg-radio-dot {\n    width: 42%;\n    height: 42%;\n    border-radius: 9999px;\n    background: #fff;\n    box-shadow: 0 1px 2px rgb(0 0 0 / 0.3);\n    scale: 0;\n    transition: scale 160ms cubic-bezier(0.4, 0, 1, 1);\n  }\n\n  /* The dot springs in and shrinks straight out: the spring would swing it\n     through zero on the way back. */\n  .lg-radio[data-state='checked'] .lg-radio-dot {\n    scale: 1;\n    transition: scale 340ms var(--lg-spring);\n  }\n\n  /* ============================================\n     Textarea and select: the Input's recessed glass field\n     ============================================ */\n\n  .lg-textarea {\n    display: block;\n    min-height: 5.5rem;\n    line-height: 1.5;\n    resize: vertical;\n  }\n\n  .lg-textarea[data-resize='auto'] {\n    resize: none;\n    overflow-y: hidden;\n  }\n\n  .lg-select-trigger {\n    display: flex;\n    align-items: center;\n    justify-content: space-between;\n    gap: 0.75rem;\n    text-align: start;\n    cursor: pointer;\n    user-select: none;\n  }\n\n  .lg-select-trigger > span:first-child {\n    min-width: 0;\n    overflow: hidden;\n    text-overflow: ellipsis;\n    white-space: nowrap;\n  }\n\n  .lg-select-trigger[data-placeholder] {\n    color: var(--lg-muted-foreground);\n  }\n\n  .lg-select-chevron {\n    display: inline-flex;\n    flex: none;\n    color: var(--lg-muted-foreground);\n    transition: rotate 260ms var(--lg-spring);\n  }\n\n  .lg-select-chevron > svg {\n    width: 1rem;\n    height: 1rem;\n  }\n\n  .lg-select-trigger[data-state='open'] .lg-select-chevron {\n    rotate: 180deg;\n  }\n\n  .lg-select-content {\n    --lg-panel-radius: 1.25rem;\n\n    z-index: 60;\n    box-sizing: border-box;\n    min-width: var(--radix-select-trigger-width);\n    max-width: calc(100vw - 1rem);\n    max-height: var(--radix-select-content-available-height, 24rem);\n    padding: 0.375rem;\n    font-size: 0.9375rem;\n    line-height: 1.4;\n    transform-origin: var(--radix-select-content-transform-origin);\n  }\n\n  .lg-select-content:focus {\n    outline: none;\n  }\n\n  .lg-select-viewport {\n    max-height: inherit;\n    overflow-y: auto;\n    overscroll-behavior: contain;\n    scrollbar-width: none;\n  }\n\n  .lg-select-viewport::-webkit-scrollbar {\n    display: none;\n  }\n\n  .lg-select-scroll {\n    display: flex;\n    align-items: center;\n    justify-content: center;\n    height: 1.5rem;\n    color: var(--lg-muted-foreground);\n    cursor: default;\n  }\n\n  .lg-select-scroll > svg {\n    width: 1rem;\n    height: 1rem;\n  }\n\n  /* ============================================\n     Progress, spinner and skeleton: waiting, told quietly\n     ============================================ */\n\n  .lg-visually-hidden {\n    position: absolute;\n    width: 1px;\n    height: 1px;\n    margin: -1px;\n    padding: 0;\n    overflow: hidden;\n    border: 0;\n    clip-path: inset(50%);\n    white-space: nowrap;\n  }\n\n  .lg-progress {\n    --lg-progress-height: 0.5rem;\n\n    display: grid;\n    gap: 0.5rem;\n    width: 100%;\n    color: var(--lg-foreground);\n    font-size: 0.875rem;\n    line-height: 1.25rem;\n  }\n\n  .lg-progress[data-size='sm'] {\n    --lg-progress-height: 0.25rem;\n  }\n\n  .lg-progress[data-size='lg'] {\n    --lg-progress-height: 0.75rem;\n  }\n\n  .lg-progress-header {\n    display: flex;\n    align-items: baseline;\n    justify-content: space-between;\n    gap: 1rem;\n  }\n\n  .lg-progress-value {\n    color: var(--lg-muted-foreground);\n    font-variant-numeric: tabular-nums;\n  }\n\n  .lg-progress-track {\n    position: relative;\n    height: var(--lg-progress-height);\n    overflow: hidden;\n    border-radius: 9999px;\n    background: var(--lg-track);\n    box-shadow: inset 0 1px 2px rgb(0 0 0 / 0.18);\n  }\n\n  /* The whole pill slides in from the left, so its leading end stays round. */\n  .lg-progress-fill {\n    width: 100%;\n    height: 100%;\n    border-radius: inherit;\n    background-color: var(--lg-accent);\n    background-image: linear-gradient(180deg, rgb(255 255 255 / 0.34), rgb(255 255 255 / 0) 60%);\n    box-shadow: inset 0 1px 0 rgb(255 255 255 / 0.4);\n    translate: calc((var(--lg-progress, 0) - 100) * 1%) 0;\n    transition: translate 640ms var(--lg-ease-out);\n  }\n\n  .lg-progress[data-state='indeterminate'] .lg-progress-fill {\n    width: 40%;\n    translate: 75% 0;\n    transition: none;\n    /* Stepped at 30 frames a second: a loader that runs for a while does not need a frame\n       every 8 ms, and the GPU is spared most of them. */\n    animation: lg-progress-sweep 1.6s steps(48) infinite;\n  }\n\n  @keyframes lg-progress-sweep {\n    from {\n      translate: -100% 0;\n    }\n\n    to {\n      translate: 250% 0;\n    }\n  }\n\n  .lg-spinner {\n    --lg-spinner-size: 1.5rem;\n    --lg-spinner-width: 2px;\n\n    display: inline-flex;\n    flex: none;\n    width: var(--lg-spinner-size);\n    height: var(--lg-spinner-size);\n    border-radius: 9999px;\n    box-shadow: inset 0 0 0 var(--lg-spinner-width)\n      color-mix(in srgb, currentColor 20%, transparent);\n    color: var(--lg-foreground);\n    vertical-align: middle;\n  }\n\n  .lg-spinner[data-size='sm'] {\n    --lg-spinner-size: 1rem;\n    --lg-spinner-width: 1.5px;\n  }\n\n  .lg-spinner[data-size='lg'] {\n    --lg-spinner-size: 2.25rem;\n    --lg-spinner-width: 3px;\n  }\n\n  .lg-spinner-ring {\n    width: 100%;\n    height: 100%;\n    border-radius: inherit;\n    background: conic-gradient(from 0deg, transparent, currentColor);\n    -webkit-mask: radial-gradient(\n      farthest-side,\n      transparent calc(100% - var(--lg-spinner-width) - 0.5px),\n      #000 calc(100% - var(--lg-spinner-width))\n    );\n    mask: radial-gradient(\n      farthest-side,\n      transparent calc(100% - var(--lg-spinner-width) - 0.5px),\n      #000 calc(100% - var(--lg-spinner-width))\n    );\n    animation: lg-spinner-turn 0.9s linear infinite;\n  }\n\n  @keyframes lg-spinner-turn {\n    to {\n      rotate: 360deg;\n    }\n  }\n\n  .lg-skeleton {\n    position: relative;\n    display: block;\n    min-height: 1rem;\n    overflow: hidden;\n    border-radius: 0.625rem;\n    background: var(--lg-control-surface);\n  }\n\n  .lg-skeleton[data-variant='circle'] {\n    width: 2.5rem;\n    min-height: 0;\n    aspect-ratio: 1;\n    border-radius: 9999px;\n  }\n\n  .lg-skeleton[data-variant='line'] {\n    min-height: 0;\n    height: 0.875rem;\n    border-radius: 9999px;\n  }\n\n  .lg-skeleton::after {\n    content: '';\n    position: absolute;\n    inset: 0;\n    background: linear-gradient(\n      100deg,\n      transparent 20%,\n      rgb(255 255 255 / 0.14) 50%,\n      transparent 80%\n    );\n    translate: -100% 0;\n    /* Stepped at 30 frames a second, like the progress sweep. */\n    animation: lg-skeleton-sheen 1.8s steps(54) infinite;\n  }\n\n  [data-lg-theme='light'] .lg-skeleton::after {\n    background: linear-gradient(\n      100deg,\n      transparent 20%,\n      rgb(255 255 255 / 0.75) 50%,\n      transparent 80%\n    );\n  }\n\n  @keyframes lg-skeleton-sheen {\n    to {\n      translate: 100% 0;\n    }\n  }\n\n  .lg-skeleton-text {\n    display: grid;\n    gap: 0.625rem;\n    width: 100%;\n  }\n\n  .lg-skeleton-text > .lg-skeleton:last-child:not(:only-child) {\n    width: 62%;\n  }\n\n  /* ============================================\n     Alert: tinted glass with the badge's tones. Every tone keeps 4.5:1 text\n     contrast over a pure black or pure white backdrop in both themes.\n     ============================================ */\n\n  .lg-alert {\n    --lg-alert-fill: 13 44 82;\n    --lg-alert-ink: #b2d6ff;\n    --lg-alert-tint: 0 103 217;\n    --lg-alert-highlight: rgb(255 255 255 / 0.12);\n\n    display: flex;\n    align-items: flex-start;\n    gap: 0.75rem;\n    box-sizing: border-box;\n    width: 100%;\n    padding: 0.875rem 1rem;\n    border-radius: 1.125rem;\n    background: rgb(var(--lg-alert-fill) / 0.88);\n    box-shadow:\n      inset 0 1px 0 var(--lg-alert-highlight),\n      inset 0 0 0 0.5px rgb(var(--lg-alert-tint) / 0.45);\n    color: var(--lg-foreground);\n    font-size: 0.9375rem;\n    line-height: 1.4;\n    -webkit-backdrop-filter: blur(min(var(--lg-glass-blur), 16px))\n      brightness(var(--lg-glass-brightness)) contrast(var(--lg-glass-contrast))\n      saturate(var(--lg-glass-sat));\n    backdrop-filter: blur(min(var(--lg-glass-blur), 16px)) brightness(var(--lg-glass-brightness))\n      contrast(var(--lg-glass-contrast)) saturate(var(--lg-glass-sat));\n  }\n\n  .lg-alert[data-tone='success'] {\n    --lg-alert-fill: 22 60 48;\n    --lg-alert-ink: #7cebc0;\n    --lg-alert-tint: 51 214 159;\n  }\n\n  .lg-alert[data-tone='warning'] {\n    --lg-alert-fill: 70 54 22;\n    --lg-alert-ink: #ffd27a;\n    --lg-alert-tint: 255 189 56;\n  }\n\n  .lg-alert[data-tone='danger'] {\n    --lg-alert-fill: 76 30 44;\n    --lg-alert-ink: #ffa6b7;\n    --lg-alert-tint: 255 92 122;\n  }\n\n  [data-lg-theme='light'] .lg-alert {\n    --lg-alert-fill: 229 241 255;\n    --lg-alert-ink: #0054b3;\n    --lg-alert-tint: 0 103 217;\n    --lg-alert-highlight: rgb(255 255 255 / 0.9);\n  }\n\n  [data-lg-theme='light'] .lg-alert[data-tone='success'] {\n    --lg-alert-fill: 224 247 238;\n    --lg-alert-ink: #08603f;\n    --lg-alert-tint: 20 168 116;\n  }\n\n  [data-lg-theme='light'] .lg-alert[data-tone='warning'] {\n    --lg-alert-fill: 255 243 219;\n    --lg-alert-ink: #824c00;\n    --lg-alert-tint: 232 150 12;\n  }\n\n  [data-lg-theme='light'] .lg-alert[data-tone='danger'] {\n    --lg-alert-fill: 255 229 236;\n    --lg-alert-ink: #a8113a;\n    --lg-alert-tint: 232 52 90;\n  }\n\n  /* Dismissing folds the alert to nothing. The alert sits in a one-row grid, and the row shrinks\n     from its content to zero, so its padding and margin go with it and nothing is measured. */\n  .lg-alert-fold {\n    display: grid;\n    grid-template-rows: 1fr;\n  }\n\n  .lg-alert-fold-inner {\n    min-height: 0;\n  }\n\n  .lg-alert-fold[data-state='folding'] {\n    grid-template-rows: 0fr;\n    transition: grid-template-rows 240ms var(--lg-ease-out);\n  }\n\n  .lg-alert-fold[data-state='folding'] > .lg-alert-fold-inner {\n    overflow: hidden;\n  }\n\n  .lg-alert-fold[data-state='folding'] .lg-alert {\n    opacity: 0;\n    pointer-events: none;\n    transition: opacity 160ms ease-in;\n  }\n\n  .lg-alert-icon {\n    display: inline-flex;\n    flex: none;\n    width: 1.25rem;\n    height: 1.25rem;\n    margin-top: 0.0625rem;\n    color: var(--lg-alert-ink);\n  }\n\n  .lg-alert-icon > svg {\n    display: block;\n    width: 100%;\n    height: 100%;\n  }\n\n  .lg-alert-body {\n    display: grid;\n    flex: 1;\n    gap: 0.125rem;\n    min-width: 0;\n  }\n\n  .lg-alert-title {\n    margin: 0;\n    font-weight: 600;\n  }\n\n  .lg-alert-description {\n    opacity: 0.82;\n  }\n\n  .lg-alert-close {\n    display: inline-flex;\n    flex: none;\n    align-items: center;\n    justify-content: center;\n    width: 1.75rem;\n    height: 1.75rem;\n    margin: -0.25rem -0.375rem -0.25rem 0;\n    padding: 0;\n    border: 0;\n    border-radius: 9999px;\n    background: transparent;\n    color: var(--lg-foreground);\n    cursor: pointer;\n    opacity: 0.7;\n    transition:\n      background-color 180ms ease,\n      opacity 180ms ease;\n  }\n\n  .lg-alert-close:hover {\n    background: rgb(255 255 255 / 0.14);\n    opacity: 1;\n  }\n\n  [data-lg-theme='light'] .lg-alert-close:hover {\n    background: rgb(0 0 0 / 0.07);\n  }\n\n  .lg-alert-close:focus-visible {\n    outline: 2px solid var(--lg-focus-ring);\n    outline-offset: 1px;\n    opacity: 1;\n  }\n\n  .lg-alert-close > svg {\n    width: 1rem;\n    height: 1rem;\n  }\n\n  /* ============================================\n     Avatar: a round photo or coloured initials. A dot or a neighbour cuts\n     the circle away instead of ringing it, so it works on any backdrop.\n     ============================================ */\n\n  .lg-avatar {\n    --lg-avatar-size: 2.5rem;\n    --lg-avatar-dot: 0.625rem;\n\n    position: relative;\n    display: inline-flex;\n    flex: none;\n    width: var(--lg-avatar-size);\n    height: var(--lg-avatar-size);\n    font-size: calc(var(--lg-avatar-size) * 0.38);\n    vertical-align: middle;\n  }\n\n  .lg-avatar[data-size='xs'] {\n    --lg-avatar-size: 1.5rem;\n    --lg-avatar-dot: 0.4375rem;\n  }\n\n  .lg-avatar[data-size='sm'] {\n    --lg-avatar-size: 2rem;\n    --lg-avatar-dot: 0.5rem;\n  }\n\n  .lg-avatar[data-size='lg'] {\n    --lg-avatar-size: 3.5rem;\n    --lg-avatar-dot: 0.875rem;\n  }\n\n  .lg-avatar[data-size='xl'] {\n    --lg-avatar-size: 5rem;\n    --lg-avatar-dot: 1.125rem;\n  }\n\n  .lg-avatar-face {\n    position: relative;\n    display: flex;\n    align-items: center;\n    justify-content: center;\n    width: 100%;\n    height: 100%;\n    overflow: hidden;\n    border-radius: 9999px;\n    background: var(--lg-control-surface);\n    color: #fff;\n    font-weight: 600;\n    line-height: 1;\n    user-select: none;\n  }\n\n  .lg-avatar-face::after {\n    content: '';\n    position: absolute;\n    inset: 0;\n    border-radius: inherit;\n    box-shadow:\n      inset 0 0 0 1px rgb(255 255 255 / 0.18),\n      inset 0 1px 0 rgb(255 255 255 / 0.22);\n    pointer-events: none;\n  }\n\n  [data-lg-theme='light'] .lg-avatar-face::after {\n    box-shadow:\n      inset 0 0 0 1px rgb(0 0 0 / 0.1),\n      inset 0 1px 0 rgb(255 255 255 / 0.3);\n  }\n\n  .lg-avatar-image {\n    display: block;\n    width: 100%;\n    height: 100%;\n    object-fit: cover;\n  }\n\n  .lg-avatar-fallback {\n    --lg-avatar-from: #747479;\n    --lg-avatar-to: #535359;\n\n    display: flex;\n    align-items: center;\n    justify-content: center;\n    width: 100%;\n    height: 100%;\n    background: linear-gradient(145deg, var(--lg-avatar-from), var(--lg-avatar-to));\n    text-shadow: 0 1px 1px rgb(0 0 0 / 0.22);\n  }\n\n  .lg-avatar-fallback[data-tone='0'] {\n    --lg-avatar-from: #2d6de9;\n    --lg-avatar-to: #1a4fc7;\n  }\n\n  .lg-avatar-fallback[data-tone='1'] {\n    --lg-avatar-from: #b93f24;\n    --lg-avatar-to: #882c1a;\n  }\n\n  .lg-avatar-fallback[data-tone='2'] {\n    --lg-avatar-from: #707075;\n    --lg-avatar-to: #56565b;\n  }\n\n  .lg-avatar-fallback[data-tone='3'] {\n    --lg-avatar-from: #d0386f;\n    --lg-avatar-to: #a82458;\n  }\n\n  .lg-avatar-fallback[data-tone='4'] {\n    --lg-avatar-from: #b9540f;\n    --lg-avatar-to: #9c4308;\n  }\n\n  .lg-avatar-fallback[data-tone='5'] {\n    --lg-avatar-from: #1f8150;\n    --lg-avatar-to: #146c3c;\n  }\n\n  .lg-avatar-fallback[data-tone='6'] {\n    --lg-avatar-from: #0e7d8b;\n    --lg-avatar-to: #0a6674;\n  }\n\n  .lg-avatar-fallback[data-tone='7'] {\n    --lg-avatar-from: #747479;\n    --lg-avatar-to: #535359;\n  }\n\n  .lg-avatar-status {\n    --lg-status: #8e8e93;\n\n    position: absolute;\n    top: calc(var(--lg-avatar-size) * 0.8536 - var(--lg-avatar-dot) / 2);\n    left: calc(var(--lg-avatar-size) * 0.8536 - var(--lg-avatar-dot) / 2);\n    width: var(--lg-avatar-dot);\n    height: var(--lg-avatar-dot);\n    border-radius: 9999px;\n    background: var(--lg-status);\n  }\n\n  .lg-avatar[data-status='online'] > .lg-avatar-status {\n    --lg-status: #33d69f;\n  }\n\n  .lg-avatar[data-status='away'] > .lg-avatar-status {\n    --lg-status: #ffbd38;\n  }\n\n  .lg-avatar[data-status='busy'] > .lg-avatar-status {\n    --lg-status: #ff5c7a;\n  }\n\n  [data-lg-theme='light'] .lg-avatar[data-status='online'] > .lg-avatar-status {\n    --lg-status: #14a874;\n  }\n\n  [data-lg-theme='light'] .lg-avatar[data-status='away'] > .lg-avatar-status {\n    --lg-status: #e8960c;\n  }\n\n  [data-lg-theme='light'] .lg-avatar[data-status='busy'] > .lg-avatar-status {\n    --lg-status: #e8345a;\n  }\n\n  .lg-avatar[data-status] > .lg-avatar-face {\n    --lg-cut-status: radial-gradient(\n      circle at calc(var(--lg-avatar-size) * 0.8536) calc(var(--lg-avatar-size) * 0.8536),\n      transparent calc(var(--lg-avatar-dot) / 2 + 2px),\n      #000 calc(var(--lg-avatar-dot) / 2 + 2.5px)\n    );\n\n    -webkit-mask-image: var(--lg-cut-status), var(--lg-cut-next, linear-gradient(#000, #000));\n    mask-image: var(--lg-cut-status), var(--lg-cut-next, linear-gradient(#000, #000));\n    -webkit-mask-composite: source-in;\n    mask-composite: intersect;\n  }\n\n  .lg-avatar-group {\n    display: inline-flex;\n    align-items: center;\n    isolation: isolate;\n  }\n\n  .lg-avatar-group[data-size='xs'] .lg-avatar {\n    --lg-avatar-size: 1.5rem;\n    --lg-avatar-dot: 0.4375rem;\n  }\n\n  .lg-avatar-group[data-size='sm'] .lg-avatar {\n    --lg-avatar-size: 2rem;\n    --lg-avatar-dot: 0.5rem;\n  }\n\n  .lg-avatar-group[data-size='md'] .lg-avatar {\n    --lg-avatar-size: 2.5rem;\n    --lg-avatar-dot: 0.625rem;\n  }\n\n  .lg-avatar-group[data-size='lg'] .lg-avatar {\n    --lg-avatar-size: 3.5rem;\n    --lg-avatar-dot: 0.875rem;\n  }\n\n  .lg-avatar-group[data-size='xl'] .lg-avatar {\n    --lg-avatar-size: 5rem;\n    --lg-avatar-dot: 1.125rem;\n  }\n\n  .lg-avatar-group > .lg-avatar + .lg-avatar {\n    margin-inline-start: calc(var(--lg-avatar-size) * -0.2);\n  }\n\n  .lg-avatar-group > .lg-avatar:not(:last-child) > .lg-avatar-face {\n    --lg-cut-next: radial-gradient(\n      circle at calc(var(--lg-avatar-size) * 1.3) 50%,\n      transparent calc(var(--lg-avatar-size) / 2 + 2px),\n      #000 calc(var(--lg-avatar-size) / 2 + 2.5px)\n    );\n\n    -webkit-mask-image: var(--lg-cut-status, linear-gradient(#000, #000)), var(--lg-cut-next);\n    mask-image: var(--lg-cut-status, linear-gradient(#000, #000)), var(--lg-cut-next);\n    -webkit-mask-composite: source-in;\n    mask-composite: intersect;\n  }\n\n  [dir='rtl'] .lg-avatar-group > .lg-avatar:not(:last-child) > .lg-avatar-face {\n    --lg-cut-next: radial-gradient(\n      circle at calc(var(--lg-avatar-size) * -0.3) 50%,\n      transparent calc(var(--lg-avatar-size) / 2 + 2px),\n      #000 calc(var(--lg-avatar-size) / 2 + 2.5px)\n    );\n  }\n\n  .lg-avatar-more {\n    background: var(--lg-control-surface-hover);\n    color: var(--lg-foreground);\n    font-size: calc(var(--lg-avatar-size) * 0.32);\n  }\n\n  /* ============================================\n     Kbd: a keycap with a lit top edge and a dark lip\n     ============================================ */\n\n  .lg-kbd {\n    display: inline-flex;\n    align-items: center;\n    justify-content: center;\n    box-sizing: border-box;\n    min-width: 1.5rem;\n    height: 1.5rem;\n    padding: 0 0.4375rem;\n    border-radius: 0.4375rem;\n    background: var(--lg-control-surface);\n    box-shadow:\n      inset 0 1px 0 rgb(255 255 255 / 0.18),\n      inset 0 0 0 1px var(--lg-border),\n      0 1px 0 rgb(0 0 0 / 0.35);\n    color: var(--lg-foreground);\n    font: inherit;\n    font-size: 0.75rem;\n    font-weight: 600;\n    letter-spacing: 0.02em;\n    line-height: 1;\n  }\n\n  [data-lg-theme='light'] .lg-kbd {\n    box-shadow:\n      inset 0 1px 0 rgb(255 255 255 / 0.9),\n      inset 0 0 0 1px var(--lg-border),\n      0 1px 0 rgb(0 0 0 / 0.16);\n  }\n\n  .lg-kbd-group {\n    display: inline-flex;\n    align-items: center;\n    gap: 0.25rem;\n  }\n\n  /* ============================================\n     Scroll area: native scrolling with a thin glass scrollbar over its edge.\n     The bar shows while the pointer is over the area or it scrolls, rests\n     narrow, and widens under the pointer.\n     ============================================ */\n\n  .lg-scroll-area {\n    position: relative;\n    overflow: hidden;\n  }\n\n  /* A max-height on the area bounds the viewport as well as a height does. */\n  .lg-scroll-area-viewport {\n    width: 100%;\n    height: 100%;\n    max-height: inherit;\n    border-radius: inherit;\n  }\n\n  .lg-scroll-area-viewport:focus-visible {\n    outline: 2px solid var(--lg-focus-ring);\n    outline-offset: -2px;\n  }\n\n  .lg-scrollbar {\n    z-index: 1;\n    display: flex;\n    box-sizing: border-box;\n    padding: 3px;\n    touch-action: none;\n    user-select: none;\n    transition: padding 160ms var(--lg-ease-out);\n  }\n\n  .lg-scrollbar[data-orientation='vertical'] {\n    width: 10px;\n  }\n\n  .lg-scrollbar[data-orientation='horizontal'] {\n    flex-direction: column;\n    height: 10px;\n  }\n\n  .lg-scrollbar:hover {\n    padding: 2px;\n  }\n\n  .lg-scrollbar[data-state='visible'] {\n    animation: lg-scrollbar-in 160ms var(--lg-ease-out);\n  }\n\n  .lg-scrollbar[data-state='hidden'] {\n    animation: lg-scrollbar-out 240ms ease-in forwards;\n  }\n\n  /* A sliver of clear glass: a faint tint of the text colour, a lit rim and a\n     blur of what scrolls beneath it. */\n  .lg-scrollbar-thumb {\n    position: relative;\n    flex: 1;\n    border-radius: 999px;\n    background: color-mix(in srgb, var(--lg-foreground) 24%, transparent);\n    box-shadow: inset 0 0 0 0.5px rgb(255 255 255 / 0.24);\n    -webkit-backdrop-filter: blur(6px) saturate(1.6);\n    backdrop-filter: blur(6px) saturate(1.6);\n    transition: background-color 160ms var(--lg-ease-out);\n  }\n\n  [data-lg-theme='light'] .lg-scrollbar-thumb {\n    box-shadow:\n      inset 0 0 0 0.5px rgb(255 255 255 / 0.7),\n      0 0 0 0.5px rgb(0 0 0 / 0.06);\n  }\n\n  /* The pointer can catch more than the sliver it sees. */\n  .lg-scrollbar-thumb::before {\n    content: '';\n    position: absolute;\n    top: 50%;\n    left: 50%;\n    width: 100%;\n    height: 100%;\n    min-width: 24px;\n    min-height: 24px;\n    transform: translate(-50%, -50%);\n  }\n\n  .lg-scrollbar:hover .lg-scrollbar-thumb {\n    background: color-mix(in srgb, var(--lg-foreground) 40%, transparent);\n  }\n\n  @keyframes lg-scrollbar-in {\n    from {\n      opacity: 0;\n    }\n  }\n\n  @keyframes lg-scrollbar-out {\n    to {\n      opacity: 0;\n    }\n  }\n\n  [data-lg-reduce-transparency='1'] .lg-scrollbar-thumb {\n    -webkit-backdrop-filter: none;\n    backdrop-filter: none;\n    background: color-mix(in srgb, var(--lg-foreground) 55%, var(--lg-bg));\n  }\n\n  @media (prefers-contrast: more) {\n    .lg-scrollbar-thumb {\n      background: color-mix(in srgb, var(--lg-foreground) 70%, transparent);\n    }\n  }\n\n  @media (forced-colors: active) {\n    .lg-scrollbar-thumb {\n      forced-color-adjust: none;\n      background: CanvasText;\n      box-shadow: none;\n    }\n  }\n\n  /* ============================================\n     Command: a search field over a list that filters as you type. The\n     highlighted row is the menu's, and the list resizes with its results.\n     ============================================ */\n\n  .lg-command {\n    display: flex;\n    flex-direction: column;\n    width: 100%;\n    overflow: hidden;\n    border-radius: inherit;\n    color: var(--lg-foreground);\n    font-size: 0.9375rem;\n    line-height: 1.4;\n  }\n\n  .lg-command-dialog {\n    --lg-panel-radius: 1.5rem;\n\n    top: min(18vh, 9rem);\n    max-width: 40rem;\n    padding: 0;\n    translate: -50% 0;\n    overflow: hidden;\n  }\n\n  .lg-command-search {\n    display: flex;\n    flex: none;\n    align-items: center;\n    gap: 0.75rem;\n    height: 3.25rem;\n    padding: 0 1.125rem;\n    border-bottom: 1px solid var(--lg-border);\n    color: var(--lg-muted-foreground);\n    transition: box-shadow 200ms ease;\n  }\n\n  .lg-command-search:focus-within {\n    box-shadow: inset 0 -1px 0 color-mix(in srgb, var(--lg-focus-ring) 60%, transparent);\n  }\n\n  .lg-command-search > svg {\n    flex: none;\n    width: 1.125rem;\n    height: 1.125rem;\n  }\n\n  .lg-command-input {\n    flex: 1;\n    min-width: 0;\n    height: 100%;\n    padding: 0;\n    border: 0;\n    background: transparent;\n    color: var(--lg-foreground);\n    font: inherit;\n    font-size: 1rem;\n    outline: none;\n  }\n\n  .lg-command-input::placeholder {\n    color: var(--lg-muted-foreground);\n    opacity: 0.72;\n  }\n\n  .lg-command-list {\n    box-sizing: border-box;\n    height: min(calc(var(--cmdk-list-height, 22rem) + 0.75rem), 22rem);\n    max-height: min(22rem, 60dvh);\n    padding: 0.375rem;\n    overflow-x: hidden;\n    overflow-y: auto;\n    overscroll-behavior: contain;\n    scroll-padding-block: 0.375rem;\n    transition: height 160ms var(--lg-ease-out);\n  }\n\n  .lg-command-group [cmdk-group-heading] {\n    padding: 0.5rem 0.75rem 0.25rem;\n    color: var(--lg-muted-foreground);\n    font-size: 0.75rem;\n    font-weight: 600;\n    line-height: 1rem;\n    user-select: none;\n  }\n\n  .lg-command-item {\n    display: flex;\n    align-items: center;\n    gap: 0.625rem;\n    box-sizing: border-box;\n    min-height: 2.5rem;\n    padding: 0.5rem 0.75rem;\n    border-radius: 0.75rem;\n    color: var(--lg-foreground);\n    cursor: default;\n    outline: none;\n    user-select: none;\n  }\n\n  .lg-command-item > svg {\n    flex: none;\n    width: 1.125rem;\n    height: 1.125rem;\n    color: var(--lg-muted-foreground);\n  }\n\n  .lg-command-item[data-selected='true'] {\n    background: rgb(255 255 255 / 0.14);\n  }\n\n  [data-lg-theme='light'] .lg-command-item[data-selected='true'] {\n    background: rgb(0 0 0 / 0.06);\n  }\n\n  .lg-command-item[data-disabled='true'] {\n    opacity: var(--lg-disabled-opacity);\n    pointer-events: none;\n  }\n\n  .lg-command-empty {\n    padding: 2rem 1rem;\n    color: var(--lg-muted-foreground);\n    text-align: center;\n  }\n\n  .lg-command-separator {\n    height: 1px;\n    margin: 0.375rem 0.625rem;\n    background: var(--lg-border);\n  }\n\n  .lg-command-shortcut {\n    display: inline-flex;\n    align-items: center;\n    margin-inline-start: auto;\n    padding-inline-start: 1.5rem;\n    color: var(--lg-muted-foreground);\n    font-size: 0.75rem;\n    letter-spacing: 0.06em;\n  }\n\n  /* ============================================\n     Breadcrumb and pagination: where you are, and the way on\n     ============================================ */\n\n  .lg-breadcrumb {\n    color: var(--lg-muted-foreground);\n    font-size: 0.9375rem;\n    line-height: 1.4;\n  }\n\n  .lg-breadcrumb-list {\n    display: flex;\n    flex-wrap: wrap;\n    align-items: center;\n    gap: 0.125rem;\n    margin: 0;\n    padding: 0;\n    list-style: none;\n  }\n\n  .lg-breadcrumb-item {\n    display: inline-flex;\n    align-items: center;\n    gap: 0.125rem;\n    min-width: 0;\n  }\n\n  .lg-breadcrumb-link,\n  .lg-breadcrumb-ellipsis,\n  .lg-breadcrumb-page {\n    display: inline-flex;\n    align-items: center;\n    box-sizing: border-box;\n    min-height: 1.875rem;\n    padding: 0 0.625rem;\n    border-radius: 9999px;\n  }\n\n  .lg-breadcrumb-link,\n  .lg-breadcrumb-ellipsis {\n    border: 0;\n    background: transparent;\n    color: var(--lg-muted-foreground);\n    cursor: pointer;\n    font: inherit;\n    text-decoration: none;\n    transition:\n      background-color 180ms ease,\n      color 180ms ease;\n  }\n\n  .lg-breadcrumb-link:hover,\n  .lg-breadcrumb-ellipsis:hover,\n  .lg-breadcrumb-ellipsis[data-state='open'] {\n    background: rgb(255 255 255 / 0.1);\n    color: var(--lg-foreground);\n  }\n\n  [data-lg-theme='light'] .lg-breadcrumb-link:hover,\n  [data-lg-theme='light'] .lg-breadcrumb-ellipsis:hover,\n  [data-lg-theme='light'] .lg-breadcrumb-ellipsis[data-state='open'] {\n    background: rgb(0 0 0 / 0.06);\n  }\n\n  .lg-breadcrumb-link:focus-visible,\n  .lg-breadcrumb-ellipsis:focus-visible {\n    outline: 2px solid var(--lg-focus-ring);\n    outline-offset: 1px;\n  }\n\n  .lg-breadcrumb-ellipsis {\n    padding: 0 0.375rem;\n  }\n\n  .lg-breadcrumb-ellipsis > svg {\n    width: 1.25rem;\n    height: 1.25rem;\n  }\n\n  .lg-breadcrumb-page {\n    color: var(--lg-foreground);\n    font-weight: 600;\n  }\n\n  .lg-breadcrumb-separator {\n    display: inline-flex;\n    color: var(--lg-muted-foreground);\n    opacity: 0.65;\n  }\n\n  .lg-breadcrumb-separator > svg {\n    width: 1rem;\n    height: 1rem;\n  }\n\n  [dir='rtl'] .lg-breadcrumb-separator {\n    scale: -1 1;\n  }\n\n  .lg-breadcrumb-item:last-child > .lg-breadcrumb-separator {\n    display: none;\n  }\n\n  .lg-pagination-list {\n    display: flex;\n    flex-wrap: wrap;\n    align-items: center;\n    gap: 0.25rem;\n    margin: 0;\n    padding: 0;\n    list-style: none;\n  }\n\n  .lg-page {\n    display: inline-flex;\n    align-items: center;\n    justify-content: center;\n    box-sizing: border-box;\n    min-width: 2.25rem;\n    height: 2.25rem;\n    padding: 0 0.625rem;\n    border: 0;\n    border-radius: 9999px;\n    background: transparent;\n    box-shadow: inset 0 0 0 1px transparent;\n    color: var(--lg-foreground);\n    cursor: pointer;\n    font: inherit;\n    font-size: 0.9375rem;\n    font-variant-numeric: tabular-nums;\n    -webkit-tap-highlight-color: transparent;\n    transition:\n      background-color 200ms ease,\n      box-shadow 200ms ease,\n      scale 320ms var(--lg-spring);\n  }\n\n  .lg-page > svg {\n    width: 1.125rem;\n    height: 1.125rem;\n  }\n\n  .lg-page:hover:not(:disabled, [data-current]) {\n    background: var(--lg-control-surface-hover);\n  }\n\n  .lg-page:active:not(:disabled) {\n    scale: 0.92;\n  }\n\n  .lg-page:focus-visible {\n    outline: 2px solid var(--lg-focus-ring);\n    outline-offset: 2px;\n  }\n\n  .lg-page:disabled {\n    cursor: not-allowed;\n    opacity: var(--lg-disabled-opacity);\n  }\n\n  .lg-page[data-current] {\n    background: rgb(255 255 255 / 0.16);\n    box-shadow:\n      inset 0 1px 0 rgb(255 255 255 / 0.28),\n      inset 0 0 0 1px rgb(255 255 255 / 0.12);\n    font-weight: 600;\n  }\n\n  [data-lg-theme='light'] .lg-page[data-current] {\n    background: rgb(0 0 0 / 0.08);\n    box-shadow:\n      inset 0 1px 0 rgb(255 255 255 / 0.9),\n      inset 0 0 0 1px rgb(0 0 0 / 0.06);\n  }\n\n  .lg-page-gap {\n    display: inline-flex;\n    align-items: center;\n    justify-content: center;\n    min-width: 1.5rem;\n    color: var(--lg-muted-foreground);\n    user-select: none;\n  }\n\n  /* Tabs */\n  .lg-tabs-list {\n    display: flex;\n    width: 100%;\n    max-width: 100%;\n    gap: 0.25rem;\n    padding: 0.25rem;\n    font-size: 0.875rem;\n    line-height: calc(1.25 / 0.875);\n  }\n\n  .lg-tabs-trigger {\n    position: relative;\n    display: flex;\n    flex: 1 1 0%;\n    min-width: 0;\n    align-items: center;\n    justify-content: center;\n    border-radius: 9999px;\n    padding: 0.5rem 0.75rem;\n    color: var(--lg-muted-foreground);\n    transition:\n      color var(--lg-motion-duration) ease,\n      background-color var(--lg-motion-duration) ease,\n      box-shadow var(--lg-motion-duration) ease;\n  }\n\n  .lg-tabs-trigger:focus-visible {\n    outline: 2px solid var(--lg-focus-ring);\n    outline-offset: 2px;\n  }\n\n  .lg-tabs-trigger:disabled {\n    pointer-events: none;\n    opacity: var(--lg-disabled-opacity);\n  }\n\n  .lg-tabs-content {\n    margin-top: 0.75rem;\n    font-size: 0.875rem;\n    line-height: calc(1.25 / 0.875);\n  }\n\n  /* The active trigger is a small raised glass bubble */\n  .lg-tabs-trigger[data-state='active'] {\n    color: var(--lg-foreground);\n    background: rgb(255 255 255 / 0.12);\n    box-shadow:\n      inset 0 1px 0 rgb(255 255 255 / 0.22),\n      inset 0 -1px 0 rgb(0 0 0 / 0.12),\n      0 1px 3px rgb(0 0 0 / 0.24),\n      0 4px 12px -4px rgb(0 0 0 / 0.4);\n  }\n\n  [data-lg-theme='light'] .lg-tabs-trigger[data-state='active'] {\n    background: rgb(255 255 255 / 0.82);\n    box-shadow:\n      inset 0 1px 0 rgb(255 255 255 / 0.9),\n      0 1px 3px rgb(0 0 0 / 0.1),\n      0 4px 12px -4px rgb(0 0 0 / 0.16);\n  }\n\n  /* The bubble catches the same specular light as the glass around it. */\n  .lg-tabs-trigger[data-state='active']::after,\n  .lg-tabs-indicator::after {\n    content: '';\n    position: absolute;\n    inset: 0;\n    padding: var(--lg-rim-width);\n    border-radius: inherit;\n    pointer-events: none;\n    background: linear-gradient(\n      to bottom right,\n      rgb(255 255 255 / var(--lg-specular-peak)),\n      rgb(255 255 255 / var(--lg-specular-floor)) 38% 62%,\n      rgb(255 255 255 / var(--lg-specular-counter))\n    );\n    -webkit-mask:\n      linear-gradient(#000 0 0) content-box,\n      linear-gradient(#000 0 0);\n    -webkit-mask-composite: xor;\n    mask:\n      linear-gradient(#000 0 0) content-box,\n      linear-gradient(#000 0 0);\n    mask-composite: exclude;\n  }\n\n  /* Once scripts run, one bubble for the whole list moves between triggers\n     and the active trigger stops drawing its own. */\n  .lg-tabs-indicator {\n    display: none;\n  }\n\n  .lg-tabs-list[data-lg-indicator='ready'] > .lg-tabs-indicator {\n    --lg-bubble-alpha: 0.12;\n\n    position: absolute;\n    z-index: 1;\n    display: block;\n    border-radius: 9999px;\n    pointer-events: none;\n  }\n\n  [data-lg-theme='light'] .lg-tabs-list[data-lg-indicator='ready'] > .lg-tabs-indicator {\n    --lg-bubble-alpha: 0.82;\n  }\n\n  .lg-tabs-list[data-lg-indicator='ready'] .lg-tabs-trigger[data-state='active'] {\n    background: transparent;\n    box-shadow: none;\n    transition: color var(--lg-motion-duration) ease;\n  }\n\n  .lg-tabs-list[data-lg-indicator='ready'] .lg-tabs-trigger[data-state='active']::after {\n    display: none;\n  }\n\n  /* Accordion: the trigger shares the content card's corner radius */\n  .lg-accordion-trigger {\n    display: flex;\n    width: 100%;\n    justify-content: space-between;\n    border: 1px solid var(--lg-border);\n    border-radius: var(--lg-radius-md);\n    padding: 0.75rem 1rem;\n    background: var(--lg-control-surface);\n    box-shadow: none;\n    color: var(--lg-foreground);\n    font-size: 1rem;\n    line-height: 1.5;\n    font-weight: 500;\n    text-align: left;\n    -webkit-backdrop-filter: blur(min(var(--lg-glass-blur), 12px))\n      brightness(var(--lg-glass-brightness)) contrast(var(--lg-glass-contrast))\n      saturate(var(--lg-glass-sat));\n    backdrop-filter: blur(min(var(--lg-glass-blur), 12px)) brightness(var(--lg-glass-brightness))\n      contrast(var(--lg-glass-contrast)) saturate(var(--lg-glass-sat));\n    transition:\n      transform var(--lg-motion-duration) cubic-bezier(0.2, 0, 0, 1),\n      background-color var(--lg-motion-duration) ease;\n  }\n\n  .lg-accordion-trigger:hover {\n    background: var(--lg-control-surface-hover);\n  }\n\n  .lg-accordion-trigger:disabled {\n    pointer-events: none;\n    opacity: var(--lg-disabled-opacity);\n  }\n\n  .lg-accordion-content {\n    margin-top: 0.5rem;\n    overflow: hidden;\n    font-size: 0.875rem;\n    line-height: calc(1.25 / 0.875);\n  }\n\n  .lg-accordion-chevron {\n    flex: none;\n    transition: transform var(--lg-motion-duration) ease;\n  }\n\n  .lg-accordion-trigger[data-state='open'] .lg-accordion-chevron {\n    transform: rotate(180deg);\n  }\n\n  /* ============================================\n     Enter and exit motion. Radix keeps a closing layer mounted until its exit\n     animation ends; the reduced motion guards above cut both to zero. The\n     keyframes move scale and translate, never transform, so they compose\n     with positioning and with a sheet's drag offset.\n     ============================================ */\n\n  @keyframes lg-fade-in {\n    from {\n      opacity: 0;\n    }\n  }\n\n  @keyframes lg-fade-out {\n    to {\n      opacity: 0;\n    }\n  }\n\n  /* A layer grows out of whatever opened it. --lg-pop-x and --lg-pop-y hold the last few pixels\n     of its travel, away from its trigger; a dialog keeps its own centring in them and rises. */\n  @keyframes lg-pop-in {\n    from {\n      opacity: 0;\n      scale: 0.96;\n      translate: var(--lg-pop-x, 0) var(--lg-pop-y, 0);\n    }\n  }\n\n  @keyframes lg-pop-out {\n    to {\n      opacity: 0;\n      scale: 0.96;\n      translate: var(--lg-pop-x, 0) var(--lg-pop-y, 0);\n    }\n  }\n\n  .lg-dialog-content {\n    --lg-pop-x: -50%;\n    --lg-pop-y: calc(-50% + 0.5rem);\n  }\n\n  .lg-popover-content[data-side='bottom'],\n  .lg-menu-content[data-side='bottom'],\n  .lg-select-content[data-side='bottom'],\n  .lg-tooltip-content[data-side='bottom'] {\n    --lg-pop-y: -0.25rem;\n  }\n\n  .lg-popover-content[data-side='top'],\n  .lg-menu-content[data-side='top'],\n  .lg-select-content[data-side='top'],\n  .lg-tooltip-content[data-side='top'] {\n    --lg-pop-y: 0.25rem;\n  }\n\n  .lg-popover-content[data-side='right'],\n  .lg-menu-content[data-side='right'],\n  .lg-select-content[data-side='right'],\n  .lg-tooltip-content[data-side='right'] {\n    --lg-pop-x: -0.25rem;\n  }\n\n  .lg-popover-content[data-side='left'],\n  .lg-menu-content[data-side='left'],\n  .lg-select-content[data-side='left'],\n  .lg-tooltip-content[data-side='left'] {\n    --lg-pop-x: 0.25rem;\n  }\n\n  .lg-dialog-overlay[data-state='open'] {\n    animation: lg-fade-in 320ms var(--lg-ease-out);\n  }\n\n  .lg-dialog-overlay[data-state='closed'] {\n    animation: lg-fade-out 220ms ease-in forwards;\n  }\n\n  .lg-dialog-content[data-state='open'],\n  .lg-popover-content[data-state='open'],\n  .lg-menu-content[data-state='open'],\n  .lg-select-content[data-state='open'] {\n    animation: lg-pop-in 240ms var(--lg-ease-out);\n  }\n\n  .lg-dialog-content[data-state='closed'],\n  .lg-popover-content[data-state='closed'],\n  .lg-menu-content[data-state='closed'],\n  .lg-select-content[data-state='closed'] {\n    animation: lg-pop-out 160ms ease-in forwards;\n  }\n\n  .lg-popover-content {\n    transform-origin: var(--radix-popover-content-transform-origin);\n  }\n\n  .lg-menu-content {\n    transform-origin: var(--radix-dropdown-menu-content-transform-origin);\n  }\n\n  .lg-select-content {\n    transform-origin: var(--radix-select-content-transform-origin);\n  }\n\n  /* A tip settles in from the side it opens toward and fades on the way out. Moving from one\n     trigger to the next skips the entrance, so the tip follows the pointer instead of restarting. */\n  .lg-tooltip-content {\n    transform-origin: var(--radix-tooltip-content-transform-origin);\n  }\n\n  .lg-tooltip-content[data-state='delayed-open'] {\n    animation: lg-pop-in 140ms var(--lg-ease-out);\n  }\n\n  .lg-tooltip-content[data-state='instant-open'] {\n    animation: lg-fade-in 90ms ease-out;\n  }\n\n  .lg-tooltip-content[data-state='closed'] {\n    animation: lg-pop-out 100ms ease-in forwards;\n  }\n\n  /* A toast slides in from the side it will leave toward and back out when it goes: the side of\n     its swipe direction, the right unless the provider says otherwise. The slide is on the list\n     item and the fade on the glass itself: opacity on an ancestor of the frost would turn its blur\n     off until the animation ended. A swipe drags it and a fling sends it on its way. */\n  .lg-toast {\n    --lg-toast-shift-x: 2rem;\n    --lg-toast-shift-y: 0px;\n    --lg-toast-fly-x: calc(100% + 2rem);\n    --lg-toast-fly-y: 0px;\n  }\n\n  .lg-toast[data-swipe-direction='left'] {\n    --lg-toast-shift-x: -2rem;\n    --lg-toast-fly-x: calc(-100% - 2rem);\n  }\n\n  .lg-toast[data-swipe-direction='up'] {\n    --lg-toast-shift-x: 0px;\n    --lg-toast-shift-y: -2rem;\n    --lg-toast-fly-x: 0px;\n    --lg-toast-fly-y: calc(-100% - 2rem);\n  }\n\n  .lg-toast[data-swipe-direction='down'] {\n    --lg-toast-shift-x: 0px;\n    --lg-toast-shift-y: 2rem;\n    --lg-toast-fly-x: 0px;\n    --lg-toast-fly-y: calc(100% + 2rem);\n  }\n\n  @keyframes lg-toast-slide-in {\n    from {\n      translate: var(--lg-toast-shift-x) var(--lg-toast-shift-y);\n    }\n  }\n\n  @keyframes lg-toast-slide-out {\n    to {\n      translate: var(--lg-toast-shift-x) var(--lg-toast-shift-y);\n    }\n  }\n\n  @keyframes lg-toast-swipe-out {\n    from {\n      translate: var(--radix-toast-swipe-end-x, 0px) var(--radix-toast-swipe-end-y, 0px);\n    }\n\n    to {\n      translate: var(--lg-toast-fly-x) var(--lg-toast-fly-y);\n    }\n  }\n\n  .lg-toast[data-state='open'] {\n    animation: lg-toast-slide-in 420ms var(--lg-ease-out);\n  }\n\n  .lg-toast[data-state='open'] > .lg-toast-root {\n    animation: lg-fade-in 300ms ease-out;\n  }\n\n  .lg-toast[data-state='closed'] {\n    animation: lg-toast-slide-out 220ms ease-in forwards;\n  }\n\n  .lg-toast[data-state='closed'] > .lg-toast-root {\n    animation: lg-fade-out 200ms ease-in forwards;\n  }\n\n  .lg-toast[data-swipe='move'] {\n    translate: var(--radix-toast-swipe-move-x, 0px) var(--radix-toast-swipe-move-y, 0px);\n  }\n\n  .lg-toast[data-swipe='cancel'] {\n    translate: 0 0;\n    transition: translate 260ms var(--lg-spring);\n  }\n\n  .lg-toast[data-swipe='end'] {\n    animation: lg-toast-swipe-out 160ms ease-out forwards;\n  }\n\n  /* The card opens and closes like a curtain. Height and padding move, opacity does not, for\n     the same reason as the toast: the card's frost sits in a child layer. */\n  @keyframes lg-accordion-down {\n    from {\n      height: 0;\n      margin-top: 0;\n      padding-block: 0;\n    }\n\n    to {\n      height: var(--radix-accordion-content-height);\n    }\n  }\n\n  @keyframes lg-accordion-up {\n    from {\n      height: var(--radix-accordion-content-height);\n    }\n\n    to {\n      height: 0;\n      margin-top: 0;\n      padding-block: 0;\n    }\n  }\n\n  .lg-accordion-content[data-state='open'] {\n    animation: lg-accordion-down 300ms var(--lg-ease-out);\n  }\n\n  .lg-accordion-content[data-state='closed'] {\n    animation: lg-accordion-up 220ms ease-in forwards;\n  }\n\n  @keyframes lg-avatar-in {\n    from {\n      opacity: 0;\n      scale: 1.06;\n    }\n  }\n\n  .lg-avatar-image {\n    animation: lg-avatar-in 260ms var(--lg-ease-out);\n  }\n\n  /* ============================================\n     Switch: a pill track and a white knob that turns to clear glass while it\n     is held, the way the system toggle does\n     ============================================ */\n\n  .lg-switch {\n    --lg-switch-width: 3.75rem;\n    --lg-switch-height: 1.75rem;\n    --lg-switch-thumb-width: 2.25rem;\n    --lg-switch-thumb-height: 1.5rem;\n    --lg-switch-inset: 0.125rem;\n    --lg-switch-direction: 1;\n    /* Held, the knob swells past the track, and the lens shows what lies under it at\n       this share of its size. */\n    --lg-switch-swell: 1.57;\n    --lg-switch-minify: 0.85;\n    /* The colour of the track under the knob, which its rim and glow pick up. */\n    --lg-switch-lens-tint: var(--lg-track);\n\n    position: relative;\n    display: inline-flex;\n    flex: none;\n    align-items: center;\n    box-sizing: border-box;\n    width: var(--lg-switch-width);\n    height: var(--lg-switch-height);\n    margin: 0;\n    padding: 0 var(--lg-switch-inset);\n    border: none;\n    border-radius: 9999px;\n    background: var(--lg-track);\n    box-shadow: inset 0 1px 2px rgb(0 0 0 / 0.1);\n    cursor: pointer;\n    -webkit-tap-highlight-color: transparent;\n    transition: background-color 250ms ease;\n  }\n\n  .lg-switch[data-size='sm'] {\n    --lg-switch-width: 2.875rem;\n    --lg-switch-height: 1.5rem;\n    --lg-switch-thumb-width: 1.75rem;\n    --lg-switch-thumb-height: 1.25rem;\n  }\n\n  [dir='rtl'] .lg-switch,\n  .lg-switch[dir='rtl'] {\n    --lg-switch-direction: -1;\n  }\n\n  .lg-switch[data-state='checked'] {\n    --lg-switch-lens-tint: var(--lg-switch-on);\n\n    background: var(--lg-switch-on);\n  }\n\n  .lg-switch:focus-visible {\n    outline: 2px solid var(--lg-focus-ring);\n    outline-offset: 2px;\n  }\n\n  .lg-switch[data-disabled] {\n    cursor: not-allowed;\n    opacity: var(--lg-disabled-opacity);\n  }\n\n  .lg-switch-thumb {\n    position: relative;\n    display: block;\n    flex: none;\n    width: var(--lg-switch-thumb-width);\n    height: var(--lg-switch-thumb-height);\n    border-radius: 9999px;\n    background: var(--lg-knob);\n    box-shadow: var(--lg-knob-shadow);\n    pointer-events: none;\n    translate: 0 0;\n    transition:\n      translate 420ms var(--lg-spring),\n      scale 320ms var(--lg-spring),\n      background-color 180ms ease,\n      box-shadow 180ms ease;\n  }\n\n  .lg-switch[data-state='checked'] .lg-switch-thumb {\n    translate: calc(\n        (var(--lg-switch-width) - var(--lg-switch-thumb-width) - var(--lg-switch-inset) * 2) *\n          var(--lg-switch-direction)\n      )\n      0;\n  }\n\n  /* Held, the knob swells past the track into a lens of clear glass. Through it the\n     track and what lies around it show a little smaller, and they bend at the rim. Lit\n     from the top left, the rim takes the track's colour, heavier along the bottom and\n     right where the light leaves the glass, and glints on the left. A soft glow in the\n     same colour lies around it. After a flip it stays this size and glass while it\n     slides, and only then shrinks back. */\n  .lg-switch:is(:active, [data-lg-moving]):not([data-disabled]) .lg-switch-thumb {\n    background: rgb(255 255 255 / 0);\n    box-shadow:\n      0.4px 0.8px 0.8px rgb(0 0 0 / 0.14),\n      0 2px 5px rgb(0 0 0 / 0.06),\n      0 0 12px 3px color-mix(in srgb, var(--lg-switch-lens-tint) 18%, transparent);\n    scale: var(--lg-switch-swell);\n  }\n\n  .lg-switch-thumb::after {\n    content: '';\n    position: absolute;\n    inset: 0;\n    z-index: 1;\n    border-radius: inherit;\n    pointer-events: none;\n    opacity: 0;\n    /* Gradients and unblurred shadows only: WebKit draws a blurred inset shadow at low\n       resolution, which the swell would show as blocks. */\n    background:\n      radial-gradient(19% 7% at 15% 20%, rgb(255 255 255 / 0.95), rgb(255 255 255 / 0)),\n      radial-gradient(19% 7% at 15% 80%, rgb(255 255 255 / 0.85), rgb(255 255 255 / 0)),\n      linear-gradient(\n        to top,\n        color-mix(in srgb, var(--lg-switch-lens-tint) 18%, transparent),\n        transparent 32%\n      ),\n      linear-gradient(rgb(0 0 0 / 0.05), transparent 14%),\n      linear-gradient(rgb(255 255 255 / 0.07), rgb(255 255 255 / 0.02));\n    box-shadow:\n      inset 0.35px 0.6px color-mix(in srgb, var(--lg-switch-lens-tint) 80%, black),\n      inset 0 0 0 0.4px var(--lg-switch-lens-tint),\n      inset -0.6px -1.4px oklch(from var(--lg-switch-lens-tint) calc(l + 0.1) c h),\n      inset -0.9px -2.2px\n        color-mix(\n          in srgb,\n          oklch(from var(--lg-switch-lens-tint) calc(l + 0.18) c h) 45%,\n          transparent\n        );\n    transition:\n      opacity 180ms ease,\n      box-shadow 250ms ease;\n  }\n\n  .lg-switch:is(:active, [data-lg-moving]):not([data-disabled]) .lg-switch-thumb::after {\n    opacity: 1;\n  }\n\n  /* The lens reaches a margin past the knob so its rim has track to bend in, and cuts the\n     filtered view back to the knob, half a pixel inside so the rim's highlight covers the\n     copy's edge. A clip on the filtered element itself would let Chromium draw the\n     filter's margin outside it. It is hidden at rest, so the filter only runs while the\n     knob is glass. */\n  .lg-switch-lens {\n    position: absolute;\n    top: calc(var(--lg-switch-lens-margin, 0px) * -1);\n    left: calc(var(--lg-switch-lens-margin, 0px) * -1);\n    width: calc(var(--lg-switch-thumb-width) + var(--lg-switch-lens-margin, 0px) * 2);\n    height: calc(var(--lg-switch-thumb-height) + var(--lg-switch-lens-margin, 0px) * 2);\n    clip-path: inset(calc(var(--lg-switch-lens-margin, 0px) + 0.5px) round 9999px);\n    pointer-events: none;\n    opacity: 0;\n    visibility: hidden;\n    transition:\n      opacity 180ms ease,\n      visibility 0s linear 180ms;\n  }\n\n  /* The view is laid out at --lg-switch-lens-scale times the lens and scaled back down on\n     its own layer, so engines that filter at layout resolution bend it smoothly too.\n     WebKit draws a filtered layer from its overflow origin, so the view clips its own\n     overflow on a composited layer. It is filled with the colour behind the switch,\n     which the component reads when the knob is pressed, so the real track under the\n     knob stays hidden. */\n  .lg-switch-lens-view {\n    position: absolute;\n    top: 0;\n    left: 0;\n    width: calc(100% * var(--lg-switch-lens-scale, 1));\n    height: calc(100% * var(--lg-switch-lens-scale, 1));\n    overflow: hidden;\n    background: var(--lg-switch-lens-backdrop, var(--lg-bg));\n    transform-origin: 0 0;\n    transform: translateZ(0) scale(calc(1 / var(--lg-switch-lens-scale, 1)));\n  }\n\n  .lg-switch:is(:active, [data-lg-moving]):not([data-disabled]) .lg-switch-lens {\n    opacity: 1;\n    visibility: visible;\n    transition-delay: 0s;\n  }\n\n  /* The scene under the lens, around the knob's centre. It undoes the knob's swell with\n     the same timing, and shows what lies under the knob at --lg-switch-minify of its\n     size. */\n  .lg-switch-lens-scene {\n    position: absolute;\n    inset: 0;\n    scale: var(--lg-switch-minify);\n    transition: scale 320ms var(--lg-spring);\n  }\n\n  .lg-switch:is(:active, [data-lg-moving]):not([data-disabled]) .lg-switch-lens-scene {\n    scale: calc(var(--lg-switch-minify) / var(--lg-switch-swell));\n  }\n\n  /* The track as it lies under the knob, at the lens's scale: the knob's slide is undone\n     with the same timing, so the copy stays put while the knob passes over it. */\n  .lg-switch-lens-track {\n    position: absolute;\n    inset-inline-start: calc(\n      (var(--lg-switch-lens-margin, 0px) - var(--lg-switch-inset)) * var(--lg-switch-lens-scale, 1)\n    );\n    top: calc(\n      (var(--lg-switch-lens-margin, 0px) -\n          (var(--lg-switch-height) - var(--lg-switch-thumb-height)) / 2) *\n        var(--lg-switch-lens-scale, 1)\n    );\n    width: calc(var(--lg-switch-width) * var(--lg-switch-lens-scale, 1));\n    height: calc(var(--lg-switch-height) * var(--lg-switch-lens-scale, 1));\n    border-radius: 9999px;\n    background: var(--lg-track);\n    box-shadow: inset 0 calc(var(--lg-switch-lens-scale, 1) * 1px)\n      calc(var(--lg-switch-lens-scale, 1) * 2px) rgb(0 0 0 / 0.1);\n    translate: 0 0;\n    transition:\n      translate 420ms var(--lg-spring),\n      background-color 250ms ease;\n  }\n\n  .lg-switch[data-state='checked'] .lg-switch-lens-track {\n    background: var(--lg-switch-on);\n    translate: calc(\n        (var(--lg-switch-width) - var(--lg-switch-thumb-width) - var(--lg-switch-inset) * 2) *\n          var(--lg-switch-direction) * var(--lg-switch-lens-scale, 1) * -1\n      )\n      0;\n  }\n\n  /* ============================================\n     Slider: a thin track, an accent fill and the same capsule knob\n     ============================================ */\n\n  .lg-slider {\n    --lg-slider-thumb-width: 2.375rem;\n    --lg-slider-thumb-height: 1.5rem;\n    --lg-slider-track-size: 0.375rem;\n\n    position: relative;\n    display: flex;\n    align-items: center;\n    width: 100%;\n    height: var(--lg-slider-thumb-height);\n    touch-action: none;\n    user-select: none;\n    -webkit-tap-highlight-color: transparent;\n  }\n\n  .lg-slider[data-orientation='vertical'] {\n    flex-direction: column;\n    width: var(--lg-slider-thumb-height);\n    height: 100%;\n    min-height: 8rem;\n  }\n\n  .lg-slider[data-disabled] {\n    opacity: var(--lg-disabled-opacity);\n  }\n\n  .lg-slider-track {\n    position: relative;\n    flex-grow: 1;\n    overflow: hidden;\n    border-radius: 9999px;\n    background: var(--lg-track);\n  }\n\n  .lg-slider-track[data-orientation='horizontal'] {\n    height: var(--lg-slider-track-size);\n  }\n\n  .lg-slider-track[data-orientation='vertical'] {\n    width: var(--lg-slider-track-size);\n  }\n\n  .lg-slider-range {\n    position: absolute;\n    border-radius: inherit;\n    background: var(--lg-accent);\n  }\n\n  .lg-slider-range[data-orientation='horizontal'] {\n    height: 100%;\n  }\n\n  .lg-slider-range[data-orientation='vertical'] {\n    width: 100%;\n  }\n\n  .lg-slider-thumb {\n    display: block;\n    width: var(--lg-slider-thumb-width);\n    height: var(--lg-slider-thumb-height);\n    border-radius: 9999px;\n    background: var(--lg-knob);\n    box-shadow: var(--lg-knob-shadow);\n    cursor: grab;\n    /* Script stretches a dragged knob along the track with its speed. */\n    transform: scale(var(--lg-stretch-x, 1), var(--lg-stretch-y, 1));\n    transition:\n      scale 320ms var(--lg-spring),\n      background-color 180ms ease,\n      box-shadow 180ms ease;\n  }\n\n  .lg-slider[data-orientation='vertical'] .lg-slider-thumb {\n    width: var(--lg-slider-thumb-height);\n    height: var(--lg-slider-thumb-width);\n  }\n\n  .lg-slider-thumb:focus-visible {\n    outline: 2px solid var(--lg-focus-ring);\n    outline-offset: 2px;\n  }\n\n  .lg-slider[data-disabled] .lg-slider-thumb {\n    cursor: not-allowed;\n  }\n\n  /* Radix focuses the thumb it drags, so only that one turns to glass. */\n  .lg-slider:not([data-disabled]):active .lg-slider-thumb:focus {\n    background: rgb(255 255 255 / 0.16);\n    box-shadow:\n      inset 0 0 0 0.5px rgb(255 255 255 / 0.55),\n      inset 1.5px 2px 1px -1px rgb(255 255 255 / 0.9),\n      inset -1.5px -2px 1px -1px rgb(255 255 255 / 0.55),\n      inset 0 0 8px rgb(255 255 255 / 0.28),\n      0 4px 14px rgb(0 0 0 / 0.2);\n    cursor: grabbing;\n    scale: 1.3 1.4;\n  }\n\n  /* ============================================\n     Segmented control: one raised bubble slides between equal segments.\n     :has() counts the segments and finds the checked one, so the bubble is\n     placed before any script runs. Up to six segments.\n     ============================================ */\n\n  .lg-segmented {\n    --lg-segmented-pad: 0.1875rem;\n\n    display: grid;\n    grid-auto-columns: minmax(0, 1fr);\n    grid-auto-flow: column;\n    width: 100%;\n    padding: var(--lg-segmented-pad);\n    font-size: 0.875rem;\n    line-height: calc(1.25 / 0.875);\n  }\n\n  .lg-segmented:has(> button:nth-of-type(2):last-of-type) {\n    --lg-segmented-count: 2;\n  }\n\n  .lg-segmented:has(> button:nth-of-type(3):last-of-type) {\n    --lg-segmented-count: 3;\n  }\n\n  .lg-segmented:has(> button:nth-of-type(4):last-of-type) {\n    --lg-segmented-count: 4;\n  }\n\n  .lg-segmented:has(> button:nth-of-type(5):last-of-type) {\n    --lg-segmented-count: 5;\n  }\n\n  .lg-segmented:has(> button:nth-of-type(6):last-of-type) {\n    --lg-segmented-count: 6;\n  }\n\n  .lg-segmented:has(> button:nth-of-type(2)[data-state='checked']) {\n    --lg-segmented-index: 1;\n  }\n\n  .lg-segmented:has(> button:nth-of-type(3)[data-state='checked']) {\n    --lg-segmented-index: 2;\n  }\n\n  .lg-segmented:has(> button:nth-of-type(4)[data-state='checked']) {\n    --lg-segmented-index: 3;\n  }\n\n  .lg-segmented:has(> button:nth-of-type(5)[data-state='checked']) {\n    --lg-segmented-index: 4;\n  }\n\n  .lg-segmented:has(> button:nth-of-type(6)[data-state='checked']) {\n    --lg-segmented-index: 5;\n  }\n\n  .lg-segmented > .lg-segmented-indicator {\n    position: absolute;\n    top: var(--lg-segmented-pad);\n    bottom: var(--lg-segmented-pad);\n    left: var(--lg-segmented-pad);\n    z-index: 1;\n    width: calc((100% - var(--lg-segmented-pad) * 2) / var(--lg-segmented-count, 1));\n    border-radius: 9999px;\n    background: rgb(255 255 255 / 0.14);\n    box-shadow:\n      inset 0 1px 0 rgb(255 255 255 / 0.22),\n      inset 0 -1px 0 rgb(0 0 0 / 0.12),\n      0 1px 3px rgb(0 0 0 / 0.24),\n      0 4px 12px -4px rgb(0 0 0 / 0.4);\n    pointer-events: none;\n    translate: calc(var(--lg-segmented-index, 0) * 100%) 0;\n    transition:\n      translate 460ms var(--lg-spring),\n      opacity 200ms ease;\n  }\n\n  [dir='rtl'] .lg-segmented > .lg-segmented-indicator {\n    right: var(--lg-segmented-pad);\n    left: auto;\n    translate: calc(var(--lg-segmented-index, 0) * -100%) 0;\n  }\n\n  .lg-segmented:not(:has(> button[data-state='checked'])) > .lg-segmented-indicator {\n    opacity: 0;\n  }\n\n  /* Light glass on a white page would hide the white bubble, so the track\n     sinks into a faint slate well. */\n  [data-lg-theme='light']:not([data-lg-reduce-transparency='1']) .lg-segmented::before {\n    background-color: rgb(100 108 140 / 0.12);\n  }\n\n  [data-lg-theme='light'] .lg-segmented > .lg-segmented-indicator {\n    background: rgb(255 255 255 / 0.9);\n    box-shadow:\n      inset 0 1px 0 rgb(255 255 255 / 0.9),\n      0 1px 3px rgb(0 0 0 / 0.1),\n      0 4px 12px -4px rgb(0 0 0 / 0.16);\n  }\n\n  /* Once measured, script owns the bubble. It springs each edge toward the\n     selected item and writes --lg-lift while the bubble travels or is held,\n     which turns it into clearer glass that floats higher. */\n  .lg-segmented[data-lg-indicator='ready'] {\n    touch-action: pan-y;\n  }\n\n  .lg-segmented[data-lg-indicator='ready'] > .lg-segmented-indicator {\n    --lg-bubble-alpha: 0.14;\n  }\n\n  [data-lg-theme='light'] .lg-segmented[data-lg-indicator='ready'] > .lg-segmented-indicator {\n    --lg-bubble-alpha: 0.9;\n  }\n\n  .lg-segmented[data-lg-indicator='ready'] > .lg-segmented-indicator,\n  .lg-tabs-list[data-lg-indicator='ready'] > .lg-tabs-indicator {\n    --lg-bubble-shadow:\n      inset 0 1px 0 rgb(255 255 255 / 0.22), inset 0 -1px 0 rgb(0 0 0 / 0.12),\n      0 1px 3px rgb(0 0 0 / 0.24), 0 4px 12px -4px rgb(0 0 0 / 0.4);\n\n    top: 0;\n    right: auto;\n    bottom: auto;\n    left: 0;\n    /* A bead of glass: lit from above, clearer while it is lifted, and it\n       brightens and sharpens what lies under it. */\n    background: linear-gradient(\n      180deg,\n      rgb(255 255 255 / calc((var(--lg-bubble-alpha) + 0.08) * (1 - var(--lg-lift, 0) * 0.55))),\n      rgb(255 255 255 / calc(var(--lg-bubble-alpha) * (1 - var(--lg-lift, 0) * 0.55)))\n    );\n    -webkit-backdrop-filter: blur(2px) saturate(1.5)\n      brightness(calc(1.08 + var(--lg-lift, 0) * 0.14));\n    backdrop-filter: blur(2px) saturate(1.5) brightness(calc(1.08 + var(--lg-lift, 0) * 0.14));\n    box-shadow:\n      inset 0 0 0 calc(var(--lg-lift, 0) * 0.75px) rgb(255 255 255 / calc(var(--lg-lift, 0) * 0.5)),\n      inset 0 0 calc(var(--lg-lift, 0) * 12px) rgb(255 255 255 / calc(var(--lg-lift, 0) * 0.2)),\n      0 calc(var(--lg-lift, 0) * 8px) calc(var(--lg-lift, 0) * 22px)\n        rgb(0 0 0 / calc(var(--lg-lift, 0) * 0.25)),\n      var(--lg-bubble-shadow);\n    transition: opacity 200ms ease;\n  }\n\n  [data-lg-theme='light'] .lg-segmented[data-lg-indicator='ready'] > .lg-segmented-indicator,\n  [data-lg-theme='light'] .lg-tabs-list[data-lg-indicator='ready'] > .lg-tabs-indicator {\n    --lg-bubble-shadow:\n      inset 0 1px 0 rgb(255 255 255 / 0.9), 0 1px 3px rgb(0 0 0 / 0.1),\n      0 4px 12px -4px rgb(0 0 0 / 0.16);\n  }\n\n  :is(.lg-segmented-indicator, .lg-tabs-indicator)[data-lg-empty] {\n    opacity: 0;\n  }\n\n  .lg-segmented[data-lg-dragging] {\n    cursor: grabbing;\n    -webkit-user-select: none;\n    user-select: none;\n  }\n\n  .lg-segmented-indicator::after {\n    content: '';\n    position: absolute;\n    inset: 0;\n    padding: var(--lg-rim-width);\n    border-radius: inherit;\n    pointer-events: none;\n    background: linear-gradient(\n      to bottom right,\n      rgb(255 255 255 / var(--lg-specular-peak)),\n      rgb(255 255 255 / var(--lg-specular-floor)) 38% 62%,\n      rgb(255 255 255 / var(--lg-specular-counter))\n    );\n    -webkit-mask:\n      linear-gradient(#000 0 0) content-box,\n      linear-gradient(#000 0 0);\n    -webkit-mask-composite: xor;\n    mask:\n      linear-gradient(#000 0 0) content-box,\n      linear-gradient(#000 0 0);\n    mask-composite: exclude;\n  }\n\n  [data-lg-reduce-transparency='1'] :is(.lg-segmented-indicator, .lg-tabs-indicator)::after {\n    background: var(--lg-border);\n  }\n\n  [data-lg-reduce-transparency='1'] .lg-segmented > .lg-segmented-indicator,\n  [data-lg-reduce-transparency='1']\n    :is(.lg-segmented, .lg-tabs-list)[data-lg-indicator='ready']\n    > :is(.lg-segmented-indicator, .lg-tabs-indicator) {\n    background: var(--lg-control-surface-hover);\n  }\n\n  .lg-segmented-item {\n    position: relative;\n    z-index: 2;\n    display: flex;\n    min-width: 0;\n    align-items: center;\n    justify-content: center;\n    gap: 0.375rem;\n    margin: 0;\n    padding: 0.4375rem 0.875rem;\n    border: none;\n    border-radius: 9999px;\n    background: transparent;\n    color: var(--lg-muted-foreground);\n    font: inherit;\n    font-weight: 500;\n    white-space: nowrap;\n    cursor: pointer;\n    -webkit-tap-highlight-color: transparent;\n    transition: color var(--lg-motion-duration) ease;\n  }\n\n  .lg-segmented-item:hover:not([data-disabled]),\n  .lg-segmented-item[data-state='checked'] {\n    color: var(--lg-foreground);\n  }\n\n  .lg-segmented-item:focus-visible {\n    outline: 2px solid var(--lg-focus-ring);\n    outline-offset: -2px;\n  }\n\n  .lg-segmented-item[data-disabled] {\n    cursor: not-allowed;\n    opacity: var(--lg-disabled-opacity);\n  }\n\n  /* ============================================\n     Badge: a small frosted capsule. Every tone keeps 4.5:1 text contrast\n     over a pure black or pure white backdrop in both themes.\n     ============================================ */\n\n  .lg-badge {\n    --lg-badge-fill: 44 44 46;\n    --lg-badge-ink: #f5f5f7;\n    --lg-badge-tint: 142 142 147;\n    --lg-badge-highlight: rgb(255 255 255 / 0.12);\n\n    display: inline-flex;\n    align-items: center;\n    gap: 0.375rem;\n    box-sizing: border-box;\n    padding: 0.1875rem 0.625rem;\n    border-radius: 9999px;\n    background: rgb(var(--lg-badge-fill) / 0.88);\n    box-shadow:\n      inset 0 1px 0 var(--lg-badge-highlight),\n      inset 0 0 0 0.5px rgb(var(--lg-badge-tint) / 0.4);\n    color: var(--lg-badge-ink);\n    font-size: 0.75rem;\n    line-height: 1rem;\n    font-weight: 600;\n    white-space: nowrap;\n    -webkit-backdrop-filter: blur(min(var(--lg-glass-blur), 12px))\n      brightness(var(--lg-glass-brightness)) contrast(var(--lg-glass-contrast))\n      saturate(var(--lg-glass-sat));\n    backdrop-filter: blur(min(var(--lg-glass-blur), 12px)) brightness(var(--lg-glass-brightness))\n      contrast(var(--lg-glass-contrast)) saturate(var(--lg-glass-sat));\n  }\n\n  .lg-badge[data-tone='blue'] {\n    --lg-badge-fill: 13 44 82;\n    --lg-badge-ink: #b2d6ff;\n    --lg-badge-tint: 0 103 217;\n  }\n\n  .lg-badge[data-tone='green'] {\n    --lg-badge-fill: 22 60 48;\n    --lg-badge-ink: #7cebc0;\n    --lg-badge-tint: 51 214 159;\n  }\n\n  .lg-badge[data-tone='orange'] {\n    --lg-badge-fill: 70 54 22;\n    --lg-badge-ink: #ffd27a;\n    --lg-badge-tint: 255 189 56;\n  }\n\n  .lg-badge[data-tone='red'] {\n    --lg-badge-fill: 76 30 44;\n    --lg-badge-ink: #ffa6b7;\n    --lg-badge-tint: 255 92 122;\n  }\n\n  .lg-badge[data-tone='purple'] {\n    --lg-badge-fill: 44 36 92;\n    --lg-badge-ink: #c7b8ff;\n    --lg-badge-tint: 155 128 255;\n  }\n\n  [data-lg-theme='light'] .lg-badge {\n    --lg-badge-fill: 242 242 244;\n    --lg-badge-ink: #222224;\n    --lg-badge-highlight: rgb(255 255 255 / 0.9);\n  }\n\n  [data-lg-theme='light'] .lg-badge[data-tone='blue'] {\n    --lg-badge-fill: 229 241 255;\n    --lg-badge-ink: #0054b3;\n    --lg-badge-tint: 0 103 217;\n  }\n\n  [data-lg-theme='light'] .lg-badge[data-tone='green'] {\n    --lg-badge-fill: 224 247 238;\n    --lg-badge-ink: #08603f;\n    --lg-badge-tint: 20 168 116;\n  }\n\n  [data-lg-theme='light'] .lg-badge[data-tone='orange'] {\n    --lg-badge-fill: 255 243 219;\n    --lg-badge-ink: #824c00;\n    --lg-badge-tint: 232 150 12;\n  }\n\n  [data-lg-theme='light'] .lg-badge[data-tone='red'] {\n    --lg-badge-fill: 255 229 236;\n    --lg-badge-ink: #a8113a;\n    --lg-badge-tint: 232 52 90;\n  }\n\n  [data-lg-theme='light'] .lg-badge[data-tone='purple'] {\n    --lg-badge-fill: 237 232 255;\n    --lg-badge-ink: #5532d0;\n    --lg-badge-tint: 106 76 240;\n  }\n\n  .lg-badge-dot {\n    flex: none;\n    width: 0.375rem;\n    height: 0.375rem;\n    border-radius: 9999px;\n    background: rgb(var(--lg-badge-tint));\n  }\n\n  /* ============================================\n     Dock: a glass shelf under a row of icons that name themselves on hover\n     ============================================ */\n\n  .lg-dock {\n    --lg-dock-size: 3rem;\n    --lg-dock-gap: 0.5rem;\n    --lg-dock-pad: 0.625rem;\n\n    position: relative;\n    display: inline-flex;\n    align-items: center;\n    gap: var(--lg-dock-gap);\n    box-sizing: border-box;\n    height: calc(var(--lg-dock-size) + var(--lg-dock-pad) * 2);\n    padding: var(--lg-dock-pad) calc(var(--lg-dock-pad) + 0.125rem);\n    isolation: isolate;\n  }\n\n  .lg-dock > .lg-dock-shelf {\n    --lg-panel-radius: calc(var(--lg-dock-size) * 0.24 + var(--lg-dock-pad));\n\n    position: absolute;\n    inset: 0;\n    z-index: 0;\n    pointer-events: none;\n  }\n\n  .lg-dock-item {\n    position: relative;\n    z-index: 1;\n    display: flex;\n    flex: none;\n    align-items: center;\n    justify-content: center;\n    box-sizing: border-box;\n    width: calc(var(--lg-dock-size) * var(--lg-dock-scale, 1));\n    height: calc(var(--lg-dock-size) * var(--lg-dock-scale, 1));\n    margin: 0;\n    padding: 0;\n    border: none;\n    border-radius: 22.5%;\n    /* Nothing is painted behind the artwork, so an icon that bounces or has clear edges shows the\n       shelf. */\n    background: none;\n    color: inherit;\n    cursor: pointer;\n    /* The hover label sits outside the button, where a double click would otherwise select it\n       even while it is hidden. */\n    user-select: none;\n    -webkit-tap-highlight-color: transparent;\n  }\n\n  /* A consumer's icon dimensions take precedence over the full-size app artwork. */\n  .lg-dock-item > :where(:not(.lg-dock-label, .lg-dock-dot)) {\n    width: 100%;\n    height: 100%;\n  }\n\n  .lg-dock-item:focus-visible {\n    outline: 2px solid var(--lg-focus-ring);\n    outline-offset: 3px;\n  }\n\n  .lg-dock-label {\n    position: absolute;\n    bottom: calc(100% + 0.625rem);\n    left: 50%;\n    z-index: 2;\n    padding: 0.375rem 0.625rem;\n    border-radius: 0.625rem;\n    background: var(--lg-overlay-surface);\n    box-shadow:\n      inset 0 0 0 0.5px var(--lg-border),\n      var(--lg-shadow);\n    color: var(--lg-foreground);\n    font-size: 0.8125rem;\n    line-height: 1.125rem;\n    font-weight: 500;\n    white-space: nowrap;\n    pointer-events: none;\n    opacity: 0;\n    translate: -50% 0.25rem;\n    transition:\n      opacity 150ms ease,\n      translate 220ms var(--lg-ease-out);\n    -webkit-backdrop-filter: blur(min(var(--lg-glass-blur), 16px))\n      brightness(var(--lg-glass-brightness)) contrast(var(--lg-glass-contrast))\n      saturate(var(--lg-glass-sat));\n    backdrop-filter: blur(min(var(--lg-glass-blur), 16px)) brightness(var(--lg-glass-brightness))\n      contrast(var(--lg-glass-contrast)) saturate(var(--lg-glass-sat));\n  }\n\n  .lg-dock-item:hover > .lg-dock-label,\n  .lg-dock-item:focus-visible > .lg-dock-label {\n    opacity: 1;\n    translate: -50% 0;\n  }\n\n  .lg-dock-dot {\n    position: absolute;\n    bottom: calc(var(--lg-dock-pad) * -1 + 0.1875rem);\n    left: 50%;\n    width: 0.25rem;\n    height: 0.25rem;\n    border-radius: 9999px;\n    background: var(--lg-foreground);\n    opacity: 0;\n    translate: -50% 0;\n    transition: opacity 200ms ease;\n  }\n\n  .lg-dock-item[data-active='true'] > .lg-dock-dot {\n    opacity: 0.75;\n  }\n\n  .lg-dock-separator {\n    position: relative;\n    z-index: 1;\n    flex: none;\n    align-self: stretch;\n    width: 1px;\n    margin: 0.375rem 0.25rem;\n    background: var(--lg-border);\n  }\n\n  /* ============================================\n     Sheet: a glass card that slides in from an edge. A bottom sheet can be\n     dragged down by its grabber to dismiss it.\n     ============================================ */\n\n  @keyframes lg-sheet-in-bottom {\n    from {\n      translate: 0 calc(100% + 1rem);\n    }\n  }\n\n  @keyframes lg-sheet-out-bottom {\n    to {\n      translate: 0 calc(100% + 1rem);\n    }\n  }\n\n  @keyframes lg-sheet-in-top {\n    from {\n      translate: 0 calc(-100% - 1rem);\n    }\n  }\n\n  @keyframes lg-sheet-out-top {\n    to {\n      translate: 0 calc(-100% - 1rem);\n    }\n  }\n\n  @keyframes lg-sheet-in-left {\n    from {\n      translate: calc(-100% - 1rem) 0;\n    }\n  }\n\n  @keyframes lg-sheet-out-left {\n    to {\n      translate: calc(-100% - 1rem) 0;\n    }\n  }\n\n  @keyframes lg-sheet-in-right {\n    from {\n      translate: calc(100% + 1rem) 0;\n    }\n  }\n\n  @keyframes lg-sheet-out-right {\n    to {\n      translate: calc(100% + 1rem) 0;\n    }\n  }\n\n  .lg-sheet-content {\n    --lg-panel-radius: 2.5rem;\n\n    position: fixed;\n    z-index: 50;\n    display: flex;\n    flex-direction: column;\n    box-sizing: border-box;\n    overflow-x: hidden;\n    overflow-y: auto;\n    overscroll-behavior: contain;\n  }\n\n  .lg-sheet-content:focus {\n    outline: none;\n  }\n\n  .lg-sheet-content[data-side='bottom'],\n  .lg-sheet-content[data-side='top'] {\n    right: 0.5rem;\n    left: 0.5rem;\n    max-width: 40rem;\n    max-height: calc(100dvh - 3rem);\n    margin-inline: auto;\n  }\n\n  .lg-sheet-content[data-side='bottom'] {\n    bottom: 0.5rem;\n  }\n\n  .lg-sheet-content[data-side='top'] {\n    top: 0.5rem;\n  }\n\n  .lg-sheet-content[data-side='left'],\n  .lg-sheet-content[data-side='right'] {\n    top: 0.5rem;\n    bottom: 0.5rem;\n    width: min(24rem, calc(100vw - 1rem));\n  }\n\n  .lg-sheet-content[data-side='left'] {\n    left: 0.5rem;\n  }\n\n  .lg-sheet-content[data-side='right'] {\n    right: 0.5rem;\n  }\n\n  .lg-sheet-content[data-side='bottom'][data-state='open'] {\n    animation: lg-sheet-in-bottom 500ms var(--lg-ease-out);\n  }\n\n  .lg-sheet-content[data-side='bottom'][data-state='closed'] {\n    animation: lg-sheet-out-bottom 300ms var(--lg-ease-out) forwards;\n  }\n\n  .lg-sheet-content[data-side='top'][data-state='open'] {\n    animation: lg-sheet-in-top 500ms var(--lg-ease-out);\n  }\n\n  .lg-sheet-content[data-side='top'][data-state='closed'] {\n    animation: lg-sheet-out-top 300ms var(--lg-ease-out) forwards;\n  }\n\n  .lg-sheet-content[data-side='left'][data-state='open'] {\n    animation: lg-sheet-in-left 500ms var(--lg-ease-out);\n  }\n\n  .lg-sheet-content[data-side='left'][data-state='closed'] {\n    animation: lg-sheet-out-left 300ms var(--lg-ease-out) forwards;\n  }\n\n  .lg-sheet-content[data-side='right'][data-state='open'] {\n    animation: lg-sheet-in-right 500ms var(--lg-ease-out);\n  }\n\n  .lg-sheet-content[data-side='right'][data-state='closed'] {\n    animation: lg-sheet-out-right 300ms var(--lg-ease-out) forwards;\n  }\n\n  .lg-sheet-handle {\n    display: flex;\n    flex: none;\n    justify-content: center;\n    margin: -1rem -1.5rem 0.25rem;\n    padding: 0.625rem 0 0.75rem;\n    cursor: grab;\n    touch-action: none;\n  }\n\n  .lg-sheet-handle:active {\n    cursor: grabbing;\n  }\n\n  .lg-sheet-handle::before {\n    content: '';\n    width: 2.25rem;\n    height: 0.3125rem;\n    border-radius: 9999px;\n    background: var(--lg-muted-foreground);\n    opacity: 0.5;\n  }\n\n  /* ============================================\n     Menu: a frosted list with a soft lozenge under the highlighted row\n     ============================================ */\n\n  .lg-menu-content {\n    --lg-panel-radius: 1.125rem;\n\n    z-index: 50;\n    box-sizing: border-box;\n    min-width: 14rem;\n    max-width: calc(100vw - 1rem);\n    max-height: var(--radix-dropdown-menu-content-available-height, 100dvh);\n    overflow-x: hidden;\n    overflow-y: auto;\n    padding: 0.375rem;\n    font-size: 0.875rem;\n    line-height: calc(1.25 / 0.875);\n    transform-origin: var(--radix-dropdown-menu-content-transform-origin);\n  }\n\n  .lg-menu-content:focus {\n    outline: none;\n  }\n\n  .lg-menu-item {\n    position: relative;\n    display: flex;\n    align-items: center;\n    gap: 0.625rem;\n    min-height: 2.25rem;\n    box-sizing: border-box;\n    padding: 0.4375rem 0.75rem;\n    border-radius: 0.75rem;\n    color: var(--lg-foreground);\n    cursor: default;\n    outline: none;\n    user-select: none;\n  }\n\n  .lg-menu-item > svg {\n    flex: none;\n    width: 1rem;\n    height: 1rem;\n  }\n\n  .lg-menu-item[data-highlighted],\n  .lg-menu-item[data-state='open'] {\n    background: rgb(255 255 255 / 0.14);\n  }\n\n  [data-lg-theme='light'] .lg-menu-item[data-highlighted],\n  [data-lg-theme='light'] .lg-menu-item[data-state='open'] {\n    background: rgb(0 0 0 / 0.06);\n  }\n\n  .lg-menu-item[data-disabled] {\n    opacity: var(--lg-disabled-opacity);\n    pointer-events: none;\n  }\n\n  .lg-menu-item[data-tone='destructive'] {\n    color: var(--lg-invalid);\n  }\n\n  .lg-menu-item--inset {\n    padding-inline-start: 2rem;\n  }\n\n  .lg-menu-indicator {\n    position: absolute;\n    inset-inline-start: 0.5rem;\n    display: inline-flex;\n    width: 1rem;\n    align-items: center;\n    justify-content: center;\n  }\n\n  .lg-menu-indicator > svg {\n    width: 1rem;\n    height: 1rem;\n  }\n\n  .lg-menu-label {\n    padding: 0.375rem 0.75rem 0.25rem;\n    color: var(--lg-muted-foreground);\n    font-size: 0.75rem;\n    line-height: 1rem;\n    font-weight: 600;\n    user-select: none;\n  }\n\n  .lg-menu-separator {\n    height: 1px;\n    margin: 0.375rem 0.625rem;\n    background: var(--lg-border);\n  }\n\n  .lg-menu-shortcut {\n    margin-inline-start: auto;\n    padding-inline-start: 1.5rem;\n    color: var(--lg-muted-foreground);\n    font-size: 0.75rem;\n    letter-spacing: 0.06em;\n  }\n\n  .lg-menu-chevron {\n    margin-inline-start: auto;\n    color: var(--lg-muted-foreground);\n  }\n\n  [dir='rtl'] .lg-menu-chevron {\n    scale: -1 1;\n  }\n\n  /* ============================================\n     Lens: a draggable magnifier. Its view repeats the stage content, zoomed\n     around the lens center and bent at the rim by the generated refraction\n     filter where the engine supports it.\n     ============================================ */\n\n  .lg-lens-stage {\n    position: relative;\n    /* Focus must not scroll the padded lens view and shift the content beneath it. */\n    overflow: clip;\n    isolation: isolate;\n  }\n\n  .lg-lens {\n    --lg-lens-size: 10rem;\n    --lg-lens-zoom: 1.6;\n    --lg-lens-fill: var(--lg-bg);\n    --lg-lens-margin: 0px;\n\n    position: absolute;\n    top: 0;\n    left: 0;\n    z-index: 2;\n    width: var(--lg-lens-size);\n    height: var(--lg-lens-size);\n    border-radius: 50%;\n    box-shadow:\n      0 14px 34px -10px rgb(0 0 0 / 0.5),\n      0 2px 8px rgb(0 0 0 / 0.22);\n    cursor: grab;\n    touch-action: none;\n    -webkit-tap-highlight-color: transparent;\n    translate: calc(var(--lg-lens-x, 0px) - var(--lg-lens-size) / 2)\n      calc(var(--lg-lens-y, 0px) - var(--lg-lens-size) / 2);\n    transition:\n      scale 320ms var(--lg-spring),\n      box-shadow 200ms ease;\n  }\n\n  .lg-lens:active {\n    box-shadow:\n      0 22px 44px -12px rgb(0 0 0 / 0.55),\n      0 4px 12px rgb(0 0 0 / 0.24);\n    cursor: grabbing;\n    scale: 1.04;\n  }\n\n  .lg-lens:focus-visible {\n    outline: 2px solid var(--lg-focus-ring);\n    outline-offset: 3px;\n  }\n\n  /* The view reaches a margin past the lens so the rim filter has content to bend in.\n     WebKit draws a filtered layer from its overflow origin, so the view clips its own\n     overflow on a composited layer and is cut back to the lens by clip-path. */\n  .lg-lens-view {\n    position: absolute;\n    inset: calc(var(--lg-lens-margin) * -1);\n    overflow: hidden;\n    background: var(--lg-lens-fill);\n    clip-path: circle(calc(var(--lg-lens-size) / 2));\n    pointer-events: none;\n    transform: translateZ(0);\n  }\n\n  .lg-lens-scene {\n    position: absolute;\n    top: var(--lg-lens-margin);\n    left: var(--lg-lens-margin);\n    width: var(--lg-lens-stage-width, 100%);\n    height: var(--lg-lens-stage-height, 100%);\n    transform-origin: 0 0;\n    translate: calc(var(--lg-lens-size) / 2 - var(--lg-lens-x, 0px) * var(--lg-lens-zoom))\n      calc(var(--lg-lens-size) / 2 - var(--lg-lens-y, 0px) * var(--lg-lens-zoom));\n    scale: var(--lg-lens-zoom);\n  }\n\n  /* Bevel and sheen over the view, then the specular ring on top. */\n  .lg-lens::before {\n    content: '';\n    position: absolute;\n    inset: 0;\n    z-index: 1;\n    border-radius: inherit;\n    pointer-events: none;\n    background:\n      radial-gradient(circle at 32% 24%, rgb(255 255 255 / 0.22), transparent 42%),\n      linear-gradient(180deg, rgb(255 255 255 / 0.08), transparent 50%);\n    box-shadow:\n      inset 0 0 22px -6px rgb(255 255 255 / 0.5),\n      inset 2px 3px 1px -2px rgb(255 255 255 / 0.9),\n      inset -2px -3px 1px -2px rgb(255 255 255 / 0.55),\n      inset 0 -10px 18px -10px rgb(0 0 0 / 0.3);\n  }\n\n  .lg-lens::after {\n    content: '';\n    position: absolute;\n    inset: 0;\n    z-index: 2;\n    padding: 1px;\n    border-radius: inherit;\n    pointer-events: none;\n    background: linear-gradient(\n      to bottom right,\n      rgb(255 255 255 / 0.9),\n      rgb(255 255 255 / 0.16) 36% 64%,\n      rgb(255 255 255 / 0.5)\n    );\n    -webkit-mask:\n      linear-gradient(#000 0 0) content-box,\n      linear-gradient(#000 0 0);\n    -webkit-mask-composite: xor;\n    mask:\n      linear-gradient(#000 0 0) content-box,\n      linear-gradient(#000 0 0);\n    mask-composite: exclude;\n  }\n\n  /* ============================================\n     GLASS SCENE\n     One WebGL canvas draws every registered glass element in the scene as a\n     single refracting body. The canvas shows only once it has drawn; before\n     that, and whenever WebGL2 is missing, lost or switched off, every element\n     keeps its CSS glass. data-lg-scene=\"active\" marks an element whose\n     material the canvas has taken over.\n     ============================================ */\n\n  .lg-scene {\n    position: relative;\n    isolation: isolate;\n  }\n\n  /* The backdrop and the canvas sit below the scene's children. Their wrapper\n     adds no box, so they stack as before, except over a viewport backdrop\n     (below). */\n  .lg-scene-layers {\n    display: contents;\n    border-radius: inherit;\n  }\n\n  .lg-scene-backdrop,\n  .lg-scene-canvas {\n    position: absolute;\n    inset: 0;\n    z-index: -1;\n    border-radius: inherit;\n    pointer-events: none;\n  }\n\n  .lg-scene-backdrop {\n    display: block;\n    background: var(--lg-scene-backdrop, var(--lg-scene-image, none)) center / cover no-repeat;\n  }\n\n  /* A viewport backdrop holds still while the page scrolls the glass across\n     it, as background-attachment: fixed does. clip-path keeps it inside the\n     scene without becoming its containing block, and the canvas reads where\n     the layer sits, so the glass bends the backdrop that shows beside it. */\n  .lg-scene[data-lg-backdrop-space='viewport'] {\n    clip-path: inset(0);\n  }\n\n  /* The two layers share one box below the children, so the fixed backdrop\n     itself keeps a z-index of auto: over a fixed backdrop with a negative\n     z-index, iOS Safari paints the status bar solid and cuts the page off in a\n     hard line beneath it. */\n  .lg-scene[data-lg-backdrop-space='viewport'] > .lg-scene-layers {\n    display: block;\n    position: absolute;\n    inset: 0;\n    z-index: -1;\n    pointer-events: none;\n  }\n\n  .lg-scene[data-lg-backdrop-space='viewport']\n    > .lg-scene-layers\n    > :is(.lg-scene-backdrop, .lg-scene-canvas) {\n    z-index: auto;\n  }\n\n  .lg-scene[data-lg-backdrop-space='viewport'] > .lg-scene-layers > .lg-scene-backdrop {\n    position: fixed;\n    border-radius: 0;\n  }\n\n  .lg-scene-canvas {\n    display: none;\n    width: 100%;\n    height: 100%;\n  }\n\n  .lg-scene[data-lg-scene-renderer='webgl'] > .lg-scene-layers > .lg-scene-canvas {\n    display: block;\n  }\n\n  /* Each element hands the canvas the same material its CSS glass shows,\n     and the faintest colour of its text, which the face keeps legible. The\n     canvas frosts over a disk, which spreads light as far as a blur of half\n     its radius. A tenth of the surface blur keeps the shapes behind the glass\n     sharp, so its rim has something to bend. Milk-white frost hides them and\n     the glass reads as acrylic. */\n  .lg-scene .lg-glass-surface {\n    --lg-scene-tint: rgb(\n      255 255 255 /\n        calc(var(--lg-surface-alpha) + var(--lg-scene-tint-boost) + var(--lg-surface-lift))\n    );\n    --lg-scene-frost: calc(var(--lg-surface-blur) * 0.1);\n    --lg-scene-ink: var(--lg-muted-foreground);\n    transition:\n      box-shadow var(--lg-motion-duration) ease,\n      transform var(--lg-motion-duration) ease,\n      --lg-scene-tint var(--lg-motion-duration) ease;\n  }\n\n  /* The dock shelf carries no text, so it keeps its full colour. */\n  .lg-scene .lg-glass-surface.lg-dock-shelf {\n    --lg-scene-ink: transparent;\n  }\n\n  .lg-scene .lg-button {\n    --lg-scene-tint: var(--lg-button-fill);\n    --lg-scene-frost: calc(var(--lg-surface-blur) * 0.4);\n    --lg-scene-ink: var(--lg-ink);\n    transition:\n      transform calc(var(--lg-motion-duration) * 1.9) var(--lg-spring),\n      box-shadow var(--lg-motion-duration) ease,\n      --lg-scene-tint var(--lg-motion-duration) ease;\n  }\n\n  .lg-scene .lg-button:not(:disabled, [aria-disabled='true']):hover {\n    --lg-scene-tint: var(--lg-button-fill-hover);\n  }\n\n  .lg-scene .lg-glass-surface[data-lg-scene='active'],\n  .lg-scene .lg-button[data-lg-scene='active'] {\n    box-shadow: none !important;\n  }\n\n  .lg-scene .lg-glass-surface[data-lg-scene='active']::before,\n  .lg-scene .lg-glass-surface[data-lg-scene='active']::after,\n  .lg-scene .lg-glass-surface[data-lg-scene='active'] > .lg-noise,\n  .lg-scene\n    .lg-button[data-lg-scene='active']\n    > .lg-button__layers\n    > :is(\n      .lg-button__light,\n      .lg-button__distortion,\n      .lg-button__tint,\n      .lg-button__shine,\n      .lg-button__rim\n    ) {\n    display: none;\n  }\n\n  /* A button on a pane the canvas draws sits on glass already. It keeps its\n     frost but neither bends nor saturates that face again, which would undo\n     the face's legible range. */\n  .lg-scene\n    [data-lg-scene='active']\n    .lg-button:not(.lg-button--ghost)\n    > .lg-button__layers\n    > .lg-button__distortion {\n    -webkit-backdrop-filter: blur(var(--lg-surface-blur));\n    backdrop-filter: blur(var(--lg-surface-blur));\n  }\n\n  /* Glass nested in a scene's glass, like a segmented track, keeps its frost\n     and edges but casts no shadow, and its tint moves away from the pane's\n     text: darker under light text, lighter under dark text. On the canvas,\n     text on it keeps at least the contrast the face promised; the CSS glass\n     looks the same, so nothing changes when the canvas takes over. */\n  .lg-scene :is(.lg-glass-surface, [data-lg-scene='active']) .lg-glass-surface {\n    box-shadow: none;\n  }\n\n  .lg-scene :is(.lg-glass-surface, [data-lg-scene='active']) .lg-glass-surface::before {\n    background: rgb(0 0 0 / 0.14);\n    -webkit-backdrop-filter: blur(var(--lg-surface-blur));\n    backdrop-filter: blur(var(--lg-surface-blur));\n  }\n\n  [data-lg-theme='light']\n    .lg-scene\n    :is(.lg-glass-surface, [data-lg-scene='active'])\n    .lg-glass-surface::before {\n    background: rgb(255 255 255 / 0.22);\n  }\n\n  /* A plain piece of glass for scenes: a droplet, lens or pebble. Outside a\n     scene, or before the canvas draws, it shows as frosted CSS glass. */\n  .lg-scene-drop {\n    --lg-scene-tint: rgb(255 255 255 / calc(0.1 + var(--lg-scene-tint-boost)));\n    --lg-scene-frost: 3px;\n    --lg-scene-flow: 1;\n    border-radius: var(--lg-radius-lg);\n    background: rgb(255 255 255 / 0.08);\n    box-shadow:\n      inset 0 1px 0 rgb(255 255 255 / 0.35),\n      inset 0 0 0 1px rgb(255 255 255 / 0.14),\n      0 8px 24px rgb(0 0 0 / 0.18);\n    -webkit-backdrop-filter: blur(min(var(--lg-glass-blur), 8px))\n      brightness(var(--lg-glass-brightness)) contrast(var(--lg-glass-contrast))\n      saturate(var(--lg-glass-sat));\n    backdrop-filter: blur(min(var(--lg-glass-blur), 8px)) brightness(var(--lg-glass-brightness))\n      contrast(var(--lg-glass-contrast)) saturate(var(--lg-glass-sat));\n  }\n\n  .lg-scene-drop[data-lg-scene='active'] {\n    background: none !important;\n    box-shadow: none !important;\n    -webkit-backdrop-filter: none !important;\n    backdrop-filter: none !important;\n  }\n\n  :root[data-lg-reduce-transparency='1'] .lg-scene-drop {\n    background: var(--lg-opaque-surface);\n    -webkit-backdrop-filter: none;\n    backdrop-filter: none;\n  }\n\n  /* The system setting also protects components installed without a provider,\n     including their first paint. An explicit provider choice takes precedence. */\n  @media (prefers-reduced-transparency: reduce) {\n    :root:not([data-lg-reduce-transparency='0']) {\n      --lg-glass-blur: 0px;\n      --lg-glass-alpha: 0.95;\n      --lg-noise-alpha: 0.01;\n      --lg-glass-contrast: 1;\n      --lg-glass-sat: 1;\n      --lg-glass-brightness: 1;\n      --lg-refraction-scale: 0;\n      --lg-lens-depth: 0;\n      --lg-opaque-surface: #2c2c2e;\n      --lg-control-surface: #3a3a3c;\n      --lg-control-surface-hover: #48484a;\n      --lg-track: #48484a;\n    }\n\n    :root[data-lg-theme='light']:not([data-lg-reduce-transparency='0']) {\n      --lg-opaque-surface: #ffffff;\n      --lg-control-surface: #f0f0f2;\n      --lg-control-surface-hover: #e3e3e7;\n      --lg-track: #e6e6e9;\n    }\n\n    :root:not([data-lg-reduce-transparency='0']) .lg-glass-surface::before {\n      -webkit-backdrop-filter: none !important;\n      backdrop-filter: none !important;\n      background: var(--lg-opaque-surface) !important;\n      box-shadow: none !important;\n      transform: none;\n    }\n\n    :root:not([data-lg-reduce-transparency='0'])\n      :is(.lg-glass-surface, .lg-tabs-trigger[data-state='active'])::after,\n    :root:not([data-lg-reduce-transparency='0'])\n      :is(.lg-segmented-indicator, .lg-tabs-indicator)::after {\n      background: var(--lg-border);\n    }\n\n    :root:not([data-lg-reduce-transparency='0']) .lg-button__rim {\n      background: none;\n      box-shadow: inset 0 0 0 var(--lg-rim-width) var(--lg-border);\n    }\n\n    :root:not([data-lg-reduce-transparency='0'])\n      :is(\n        .lg-dialog-content,\n        .lg-popover-content,\n        .lg-toast-root,\n        .lg-tooltip-content,\n        .lg-sheet-content,\n        .lg-menu-content,\n        .lg-select-content,\n        .lg-dock-label\n      ) {\n      background: var(--lg-opaque-surface) !important;\n      -webkit-backdrop-filter: none !important;\n      backdrop-filter: none !important;\n    }\n\n    :root:not([data-lg-reduce-transparency='0'])\n      :is(\n        .lg-button__distortion,\n        .lg-input,\n        .lg-accordion-trigger,\n        .lg-dialog-overlay,\n        .lg-badge,\n        .lg-alert\n      ) {\n      -webkit-backdrop-filter: none !important;\n      backdrop-filter: none !important;\n    }\n\n    :root:not([data-lg-reduce-transparency='0'])\n      .lg-button--prominent\n      > .lg-button__layers\n      > .lg-button__distortion {\n      background: var(--lg-prominent-fill) !important;\n    }\n\n    :root:not([data-lg-reduce-transparency='0'])\n      .lg-button:not(.lg-button--ghost, .lg-button--prominent) {\n      --lg-button-fill: var(--lg-control-surface) !important;\n      --lg-button-fill-hover: var(--lg-control-surface-hover) !important;\n    }\n\n    :root:not([data-lg-reduce-transparency='0']) .lg-button__layers > .lg-button__light {\n      display: none !important;\n    }\n\n    :root:not([data-lg-reduce-transparency='0']) :is(.lg-switch-thumb, .lg-slider-thumb) {\n      background: var(--lg-knob) !important;\n    }\n\n    :root:not([data-lg-reduce-transparency='0']) :is(.lg-button__shine, .lg-button__tint) {\n      opacity: 0;\n    }\n\n    :root:not([data-lg-reduce-transparency='0']) :is(.lg-button__bloom, .lg-refraction-background) {\n      display: none;\n    }\n\n    :root:not([data-lg-reduce-transparency='0']) .lg-segmented > .lg-segmented-indicator,\n    :root:not([data-lg-reduce-transparency='0'])\n      :is(.lg-segmented, .lg-tabs-list)[data-lg-indicator='ready']\n      > :is(.lg-segmented-indicator, .lg-tabs-indicator) {\n      background: var(--lg-control-surface-hover);\n    }\n\n    :root:not([data-lg-reduce-transparency='0']) .lg-scene-drop {\n      background: var(--lg-opaque-surface);\n      -webkit-backdrop-filter: none;\n      backdrop-filter: none;\n    }\n  }\n}\n",
      "type": "registry:file",
      "target": "components/glassyui/styles/liquid.css"
    },
    {
      "path": "registry/glassyui/glass-surface.tsx",
      "content": "'use client';\n\nimport clsx from 'clsx';\nimport { Children, forwardRef, useMemo, useRef, useSyncExternalStore } from 'react';\nimport type { CSSProperties, HTMLAttributes, ReactNode } from 'react';\nimport { mergeRefs } from './lib/merge-refs';\nimport { useGlassScenePane } from './lib/scene-context';\nimport { useLensFilter, useRefractionFilter } from './lib/use-refraction-filter';\nimport { useOptionalPreferences } from './glass-provider';\n\nexport type SurfaceRefraction = 'none' | 'soft' | 'strong';\n\nexport type RefractionBackgroundSpace = 'local' | 'viewport';\n\nexport type SurfacePreset = 'subtle' | 'standard' | 'prominent' | 'control' | 'showcase';\n\nexport type GlassSurfaceProps = HTMLAttributes<HTMLDivElement> & {\n  /** Brightens the surface a touch on hover. */\n  interactive?: boolean;\n  /** Chromium edge lens over the frost. On by default for control and showcase presets. */\n  lens?: boolean;\n  preset?: SurfacePreset;\n  refraction?: SurfaceRefraction;\n  refractionBackground?: ReactNode;\n  refractionBackgroundSpace?: RefractionBackgroundSpace;\n  refractionDisplacement?: number;\n  /**\n   * How thick this glass is, as a multiple of regular. A thicker slab has a\n   * wider rim that bends the backdrop further and splits more colour. Defaults\n   * to the site's thickness preference. Works with a supplied backdrop in every\n   * browser, or with the Chromium lens over live content.\n   */\n  thickness?: number;\n};\n\n// Increased contrast dims the lens through its tokens, which the lens reads only when it measures.\nconst contrastQuery = '(prefers-contrast: more)';\n\nconst subscribeToContrast = (onChange: () => void) => {\n  const query = window.matchMedia(contrastQuery);\n  query.addEventListener('change', onChange);\n\n  return () => query.removeEventListener('change', onChange);\n};\n\nconst readContrast = () => window.matchMedia(contrastQuery).matches;\n\nconst readServerContrast = () => false;\n\nexport const GlassSurface = forwardRef<HTMLDivElement, GlassSurfaceProps>(\n  (\n    {\n      className,\n      children,\n      interactive = false,\n      preset = 'standard',\n      lens = preset === 'control' || preset === 'showcase',\n      refraction = preset === 'showcase' ? 'strong' : 'none',\n      refractionBackground,\n      refractionBackgroundSpace = 'local',\n      refractionDisplacement,\n      style,\n      thickness,\n      ...rest\n    },\n    forwardedRef,\n  ) => {\n    const { preferences } = useOptionalPreferences();\n    const reduceMotion = Boolean(preferences?.reduceMotion);\n    const reduceTransparency = Boolean(preferences?.reduceTransparency);\n    const surfaceRef = useRef<HTMLDivElement | null>(null);\n    const ref = useMemo(() => mergeRefs(surfaceRef, forwardedRef), [forwardedRef]);\n\n    const generatedRefractionEnabled =\n      refraction !== 'none' &&\n      Boolean(refractionBackground) &&\n      !reduceMotion &&\n      !reduceTransparency;\n\n    const { active, filterElement, filterStyle, sceneRef } = useRefractionFilter(surfaceRef, {\n      displacement: refractionDisplacement,\n      enabled: generatedRefractionEnabled,\n      reduceTransparency,\n      strength: refraction === 'none' ? 'soft' : refraction,\n      thickness: thickness ?? preferences?.thickness,\n      viewportAligned: refractionBackgroundSpace === 'viewport',\n    });\n\n    const moreContrast = useSyncExternalStore(\n      subscribeToContrast,\n      readContrast,\n      readServerContrast,\n    );\n\n    // One refraction technique at a time: a generated background scene covers the frost.\n    const lensFilter = useLensFilter(surfaceRef, {\n      enabled: lens && !generatedRefractionEnabled && !reduceTransparency,\n      signature: `${preferences?.theme}:${preferences?.mode}:${preferences?.quality}:${thickness ?? preferences?.thickness}:${moreContrast}`,\n    });\n\n    // Inside a GlassScene the canvas draws this glass; a generated refraction\n    // scene is its own backdrop and keeps its CSS material.\n    useGlassScenePane(surfaceRef, !generatedRefractionEnabled);\n\n    return (\n      <div\n        ref={ref}\n        data-lg-generated-refraction={active ? 'true' : 'false'}\n        data-lg-interactive={interactive ? 'true' : 'false'}\n        data-lg-lens={lensFilter.active ? 'active' : undefined}\n        data-lg-preset={preset}\n        data-lg-refraction={refraction}\n        data-lg-refraction-background-space={refractionBackgroundSpace}\n        className={clsx('lg-glass-surface', className)}\n        style={\n          // SAFETY: CSSProperties has no custom-property index; these add string-valued properties.\n          lensFilter.filterStyle || thickness !== undefined\n            ? ({\n                ...style,\n                ...(thickness === undefined ? null : { '--lg-glass-thickness': thickness }),\n                ...(lensFilter.filterStyle ? { '--lg-lens-filter': lensFilter.filterStyle } : null),\n              } as CSSProperties)\n            : style\n        }\n        {...rest}\n      >\n        {filterElement}\n        {lensFilter.filterElement}\n        {active ? (\n          <div\n            className=\"lg-refraction-background\"\n            aria-hidden=\"true\"\n            style={{ filter: filterStyle }}\n          >\n            <div ref={sceneRef} className=\"lg-refraction-scene\">\n              {refractionBackground}\n            </div>\n          </div>\n        ) : null}\n        <span className=\"lg-noise\" aria-hidden />\n        {Children.map(children, (child) =>\n          // Children.map yields null, elements, portals or text; wrap only the text.\n          child === null || child instanceof Object ? (\n            child\n          ) : (\n            <span className=\"lg-glass-text\">{child}</span>\n          ),\n        )}\n      </div>\n    );\n  },\n);\n\nGlassSurface.displayName = 'GlassSurface';\n",
      "type": "registry:ui",
      "target": "components/glassyui/glass-surface.tsx"
    },
    {
      "path": "registry/glassyui/lib/merge-refs.ts",
      "content": "import type { Ref } from 'react';\n\nexport function mergeRefs<T>(...refs: Array<Ref<T> | undefined>) {\n  return (node: T) => {\n    for (const ref of refs) {\n      if (!ref) continue;\n\n      if ('current' in ref) {\n        try {\n          ref.current = node;\n        } catch {\n          // Read-only refs cannot be assigned.\n        }\n      } else {\n        ref(node);\n      }\n    }\n  };\n}\n",
      "type": "registry:lib",
      "target": "components/glassyui/lib/merge-refs.ts"
    },
    {
      "path": "registry/glassyui/lib/refraction-map.ts",
      "content": "import { SLAB_AIR_GAP, SLAB_MAX_SLOPE, SLAB_MIN_RISE, SLAB_RISE_SPAN } from './slab-optics';\n\nexport type GeneratedRefractionStrength = 'soft' | 'strong';\n\ntype RefractionPreset = {\n  centerNeutralRatio: number;\n  defaultDisplacement: number;\n  edgeBandRatio: number;\n  edgeWidth: number;\n  /** Rim pull at the default displacement, as a share of the edge band. */\n  rimPull: number;\n};\n\nexport type RefractionMapOptions = {\n  devicePixelRatio?: number;\n  displacement?: number;\n  height: number;\n  radius: number;\n  strength: GeneratedRefractionStrength;\n  thickness?: number;\n  width: number;\n};\n\nexport type RefractionMapMetrics = {\n  cacheKey: string;\n  dispersion: number;\n  edgeBand: number;\n  /** Corner radius of the bend field, never tighter than the edge band. */\n  fieldRadius: number;\n  filterBlur: number;\n  filterPadding: number;\n  filterScale: number;\n  height: number;\n  mapHeight: number;\n  mapPixels: number;\n  mapWidth: number;\n  paddedHeight: number;\n  paddedWidth: number;\n  /** Inward offset at the rim, in CSS pixels. */\n  pull: number;\n  radius: number;\n  width: number;\n};\n\nexport type RefractionMapBuildResult = {\n  href: string;\n  metrics: RefractionMapMetrics;\n};\n\nexport const MAX_REFRACTION_MAP_PIXELS = 160000;\n\nconst REFRACTION_PRESETS: Record<GeneratedRefractionStrength, RefractionPreset> = {\n  soft: {\n    centerNeutralRatio: 0.68,\n    defaultDisplacement: 72,\n    edgeBandRatio: 0.18,\n    edgeWidth: 1.08,\n    rimPull: 0.22,\n  },\n  strong: {\n    centerNeutralRatio: 0.58,\n    defaultDisplacement: 112,\n    edgeBandRatio: 0.2,\n    edgeWidth: 1.22,\n    rimPull: 0.34,\n  },\n};\n\n/**\n * Scene blur under the rim, in CSS pixels. Chromium and Firefox sample the bend\n * nearest-neighbour, so the magnified rim would stair-step at 1x pixel density. The\n * map's blue channel keeps the blur off the flat centre.\n */\nconst RIM_BLUR = 0.8;\n\n/**\n * The bend falls off as (1 - t)^2 across the edge band, steepest at the rim. Any pull\n * under half the band keeps each sample further in than its outer neighbour, so the rim\n * compresses the view like thick glass and never mirrors it. The base pull is 0.34;\n * even the furthest colour stays below 0.4 to leave room for the map's 8-bit rounding.\n */\nconst MAX_RIM_PULL = 0.34;\n\nconst MAX_CHROMATIC_RIM_PULL = 0.4;\n\nconst refractionMapCache = new Map<string, string>();\n\nconst maxCachedRefractionMaps = 48;\n\nexport function clamp(value: number, min: number, max: number) {\n  return Math.min(max, Math.max(min, value));\n}\n\nfunction smoothstep(edge0: number, edge1: number, value: number) {\n  const t = clamp((value - edge0) / Math.max(edge1 - edge0, 0.0001), 0, 1);\n\n  return t * t * (3 - 2 * t);\n}\n\ntype Edge = { distance: number; normalX: number; normalY: number };\n\n// Distance to a rounded rectangle plus its outward unit normal.\nfunction roundedRectEdge(\n  x: number,\n  y: number,\n  width: number,\n  height: number,\n  radius: number,\n  edge: Edge,\n) {\n  const px = x - width / 2;\n  const py = y - height / 2;\n  const qx = Math.abs(px) - (width / 2 - radius);\n  const qy = Math.abs(py) - (height / 2 - radius);\n  const signX = px < 0 ? -1 : 1;\n  const signY = py < 0 ? -1 : 1;\n\n  if (qx > 0 && qy > 0) {\n    const length = Math.hypot(qx, qy);\n\n    edge.distance = length - radius;\n    edge.normalX = (signX * qx) / length;\n    edge.normalY = (signY * qy) / length;\n  } else if (qx > qy) {\n    edge.distance = qx - radius;\n    edge.normalX = signX;\n    edge.normalY = 0;\n  } else {\n    edge.distance = qy - radius;\n    edge.normalX = 0;\n    edge.normalY = signY;\n  }\n\n  return edge;\n}\n\nfunction fitMapSize(width: number, height: number, pixelRatio: number) {\n  let mapWidth = clamp(Math.round(width * pixelRatio), 32, 1800);\n  let mapHeight = clamp(Math.round(height * pixelRatio), 32, 1200);\n\n  const pixels = mapWidth * mapHeight;\n\n  if (pixels <= MAX_REFRACTION_MAP_PIXELS) {\n    return { mapWidth, mapHeight };\n  }\n\n  const ratio = Math.sqrt(MAX_REFRACTION_MAP_PIXELS / pixels);\n  mapWidth = Math.max(32, Math.floor(mapWidth * ratio));\n  mapHeight = Math.max(32, Math.floor(mapHeight * ratio));\n\n  while (mapWidth * mapHeight > MAX_REFRACTION_MAP_PIXELS) {\n    if (mapWidth >= mapHeight) {\n      mapWidth -= 1;\n    } else {\n      mapHeight -= 1;\n    }\n  }\n\n  return { mapWidth, mapHeight };\n}\n\nexport function computeRefractionMapMetrics(options: RefractionMapOptions): RefractionMapMetrics {\n  const preset = REFRACTION_PRESETS[options.strength];\n  const width = Math.max(0, options.width);\n  const height = Math.max(0, options.height);\n  const minDimension = Math.min(width, height);\n  const radius = clamp(options.radius, 0, minDimension / 2);\n  const displacement = clamp(options.displacement ?? preset.defaultDisplacement, 0, 196);\n  const thickness = clamp(options.thickness ?? 1, 0.1, 4);\n  const rimWidth = 0.6 + 0.4 * thickness;\n  const dispersion = clamp((thickness - 1) * 0.2, 0, 0.6);\n  const blueFactor = 1 + dispersion / 2;\n  const neutralInset = (minDimension * (1 - preset.centerNeutralRatio)) / 2;\n\n  const edgeBand = clamp(\n    Math.min(minDimension * preset.edgeBandRatio, neutralInset) * preset.edgeWidth * rimWidth,\n    6,\n    Math.min(72 * rimWidth, (radius || 56) * 1.15 * rimWidth, minDimension * 0.48),\n  );\n\n  // Inside a tighter corner the inset contours would turn sharp and pinch the bend.\n  const fieldRadius = clamp(Math.max(radius, edgeBand), 0, minDimension / 2);\n\n  const pull =\n    edgeBand *\n    Math.min(\n      MAX_RIM_PULL,\n      MAX_CHROMATIC_RIM_PULL / blueFactor,\n      (preset.rimPull * displacement) / preset.defaultDisplacement,\n    );\n\n  // WebKit shifts a clipped, filtered scene unless the filter region reaches past the\n  // box as far as the primitives read: the blue pull plus three blur deviations.\n  const filterPadding = Math.ceil(pull * blueFactor + RIM_BLUR * 3) + 2;\n  const paddedWidth = width + filterPadding * 2;\n  const paddedHeight = height + filterPadding * 2;\n  const targetRatio = clamp((options.devicePixelRatio ?? 1) * 1.12, 1.15, 2.1);\n  const targetPixels = paddedWidth * paddedHeight * targetRatio * targetRatio;\n\n  const pixelRatio =\n    targetPixels > MAX_REFRACTION_MAP_PIXELS\n      ? Math.max(1, targetRatio * Math.sqrt(MAX_REFRACTION_MAP_PIXELS / targetPixels))\n      : targetRatio;\n\n  const { mapWidth, mapHeight } = fitMapSize(paddedWidth, paddedHeight, pixelRatio);\n\n  const cacheKey = [\n    mapWidth,\n    mapHeight,\n    Math.round(width),\n    Math.round(height),\n    Math.round(fieldRadius * 10),\n    Math.round(edgeBand * 10),\n    filterPadding,\n  ].join(':');\n\n  return {\n    cacheKey,\n    dispersion,\n    edgeBand,\n    fieldRadius,\n    filterBlur: RIM_BLUR,\n    filterPadding,\n    // Map channels hold a unit offset; the scale turns it into CSS pixels.\n    filterScale: Math.round(pull * 2 * 100) / 100,\n    height,\n    mapHeight,\n    mapPixels: mapWidth * mapHeight,\n    mapWidth,\n    paddedHeight,\n    paddedWidth,\n    pull,\n    radius,\n    width,\n  };\n}\n\n/**\n * Encodes a unit rim field: R/G = 0.5 + 0.5 * inward offset. Past the field's edge the\n * rim offset carries on unchanged, so the map stays smooth across the clipped border.\n * B is the share of softened scene: full through the outer half of the band, which\n * holds every point the steep rim samples, and gone by the flat centre.\n */\nexport async function buildRefractionMapDataUrl(\n  options: RefractionMapOptions,\n): Promise<RefractionMapBuildResult> {\n  const metrics = computeRefractionMapMetrics(options);\n  const cached = refractionMapCache.get(metrics.cacheKey);\n\n  if (cached) return { href: cached, metrics };\n\n  if (typeof document === 'undefined') {\n    throw new Error('Refraction maps require a browser document');\n  }\n\n  const canvas = document.createElement('canvas');\n  canvas.width = metrics.mapWidth;\n  canvas.height = metrics.mapHeight;\n\n  const ctx = canvas.getContext('2d');\n\n  if (!ctx) {\n    throw new Error('Canvas 2D context unavailable');\n  }\n\n  const {\n    edgeBand,\n    fieldRadius,\n    filterPadding,\n    height,\n    mapHeight,\n    mapWidth,\n    paddedHeight,\n    paddedWidth,\n    width,\n  } = metrics;\n\n  const data = new Uint8ClampedArray(mapWidth * mapHeight * 4);\n  const edge: Edge = { distance: 0, normalX: 0, normalY: 0 };\n\n  for (let yIndex = 0; yIndex < mapHeight; yIndex += 1) {\n    const y = ((yIndex + 0.5) / mapHeight) * paddedHeight - filterPadding;\n\n    for (let xIndex = 0; xIndex < mapWidth; xIndex += 1) {\n      const x = ((xIndex + 0.5) / mapWidth) * paddedWidth - filterPadding;\n      const index = (yIndex * mapWidth + xIndex) * 4;\n      roundedRectEdge(x, y, width, height, fieldRadius, edge);\n      const depth = clamp(-edge.distance / edgeBand, 0, 1);\n      const falloff = (1 - depth) ** 2;\n      const offsetX = -edge.normalX * falloff;\n      const offsetY = -edge.normalY * falloff;\n\n      data[index] = Math.round((0.5 + offsetX / 2) * 255);\n      data[index + 1] = Math.round((0.5 + offsetY / 2) * 255);\n      data[index + 2] = Math.round((1 - smoothstep(0.5, 1, depth)) * 255);\n      data[index + 3] = 255;\n    }\n  }\n\n  ctx.putImageData(new ImageData(data, mapWidth, mapHeight), 0, 0);\n  const href = canvas.toDataURL('image/png');\n  refractionMapCache.set(metrics.cacheKey, href);\n\n  if (refractionMapCache.size > maxCachedRefractionMaps) {\n    const oldestKey = refractionMapCache.keys().next().value;\n\n    if (oldestKey) refractionMapCache.delete(oldestKey);\n  }\n\n  return { href, metrics };\n}\n\n/** Corner radii in CSS pixels, clockwise from the top left. */\nexport type LensRadii = readonly [number, number, number, number];\n\nexport type LensMapOptions = {\n  /** Width of the curved rim in CSS pixels. */\n  bevel: number;\n  /** Multiplies how far the rim bends the backdrop. 0 leaves it flat. */\n  depth: number;\n  devicePixelRatio?: number;\n  height: number;\n  /** Refractive index of the glass. */\n  ior: number;\n  radii: LensRadii;\n  /** Height of the slab in CSS pixels. Thicker glass bends further. */\n  thickness: number;\n  width: number;\n};\n\nexport type LensMapMetrics = {\n  bevel: number;\n  cacheKey: string;\n  height: number;\n  mapHeight: number;\n  mapWidth: number;\n  /** The furthest the rim reads the backdrop from, in CSS pixels. */\n  reach: number;\n  width: number;\n};\n\nexport type LensMapBuildResult = {\n  href: string;\n  metrics: LensMapMetrics;\n};\n\nconst MAX_LENS_MAP_PIXELS = 420000;\n\nexport const MAX_LENS_SURFACE_AREA = 720000;\n\n// The rim reads the backdrop from no further than this share of its width, and\n// the point it reads from advances by at least a quarter of every pixel across\n// the rim, so the view compresses toward the edge and never folds back on itself.\nconst LENS_REACH = 0.7;\n\nconst LENS_FOLD = 0.75;\n\nconst LENS_PROFILE_STEPS = 512;\n\n// The rim and the flat top are the same frosted glass, but smoked glass lets more\n// light through its rim. Blue holds the share of the rim's light: all of it near\n// the edge, none past four fifths of the rim or a sixth of the surface, whichever\n// comes first, so small pieces keep the top's shade in the middle.\nconst LENS_RIM_LIGHT = 0.8;\n\nconst LENS_RIM_LIGHT_SURFACE = 0.16;\n\nconst LENS_RIM_LIGHT_FALLOFF = 0.45;\n\nconst lensMapCache = new Map<string, LensMapBuildResult>();\n\nconst maxCachedLensMaps = 32;\n\n// Native byte order keeps the neutral RGBA pixel identical on every platform.\nconst FLAT_LENS_PIXEL = new Uint32Array(new Uint8Array([128, 128, 0, 255]).buffer)[0];\n\n/**\n * How far inward a view ray lands on the backdrop after it crosses a slab of glass\n * whose top curves down into a rim, s pixels in from the edge. The top follows\n * (1 - (1 - u)^4)^(1/4) across the rim, Snell's law bends the ray into the glass and\n * again out of its flat underside, and it crosses an air gap to the backdrop. This is\n * the WebGL scene's `through()`, for a ray straight down.\n */\nfunction slabOffset(s: number, bevel: number, thickness: number, ior: number) {\n  const u = s / bevel;\n  const v = 1 - Math.max(u, 0.002);\n  let rise = 1;\n  let steepness = 0;\n\n  if (u < 1) {\n    const v4 = v ** 4;\n\n    rise = (1 - v4) ** 0.25;\n    steepness = v ** 3 * Math.max(1 - v4, 1e-6) ** -0.75;\n  }\n\n  const slope = Math.min(((SLAB_RISE_SPAN * thickness) / bevel) * steepness, SLAB_MAX_SLOPE);\n  const height = thickness * (SLAB_MIN_RISE + SLAB_RISE_SPAN * rise);\n  const tilt = Math.hypot(slope, 1);\n  const sinTilt = slope / tilt;\n  const cosTilt = 1 / tilt;\n  const eta = 1 / ior;\n  const root = Math.sqrt(Math.max(1 - eta * eta * sinTilt * sinTilt, 0));\n  const bend = eta * cosTilt - root;\n  const along = bend * sinTilt;\n  const down = Math.max(eta - bend * cosTilt, 0.05);\n  const sinOut = ior * Math.abs(along);\n  const cosOut = Math.sqrt(Math.max(1 - sinOut * sinOut, 0));\n  const leaving = (ior * along) / Math.max(sinOut, 1);\n\n  return -(along * (height / down) + leaving * (SLAB_AIR_GAP / Math.max(cosOut, 0.1)));\n}\n\n/**\n * The inward offset across the rim, from the edge to its inner boundary. The physical\n * offset is softly capped, then limited so it never falls faster than the pixels it\n * crosses, which would fold the view back on itself.\n */\nfunction lensProfile(bevel: number, thickness: number, ior: number, depth: number) {\n  const cap = LENS_REACH * bevel;\n  const step = bevel / LENS_PROFILE_STEPS;\n  const offsets = new Float32Array(LENS_PROFILE_STEPS + 1);\n\n  for (let index = 0; index < LENS_PROFILE_STEPS; index += 1) {\n    offsets[index] =\n      cap * Math.tanh((depth * slabOffset(index * step, bevel, thickness, ior)) / cap);\n  }\n\n  for (let index = LENS_PROFILE_STEPS - 1; index >= 0; index -= 1) {\n    offsets[index] = Math.min(offsets[index], offsets[index + 1] + LENS_FOLD * step);\n  }\n\n  return { offsets, reach: Math.max(...offsets, 0.01) };\n}\n\n// Distance to a rounded rectangle with its own radius in every corner, plus its outward unit normal.\nfunction roundedBoxEdge(\n  x: number,\n  y: number,\n  width: number,\n  height: number,\n  radii: LensRadii,\n  edge: Edge,\n) {\n  const px = x - width / 2;\n  const py = y - height / 2;\n  const radius = px < 0 ? (py < 0 ? radii[0] : radii[3]) : py < 0 ? radii[1] : radii[2];\n  const qx = Math.abs(px) - (width / 2 - radius);\n  const qy = Math.abs(py) - (height / 2 - radius);\n  const signX = px < 0 ? -1 : 1;\n  const signY = py < 0 ? -1 : 1;\n\n  if (qx > 0 && qy > 0) {\n    const length = Math.hypot(qx, qy);\n\n    edge.distance = length - radius;\n    edge.normalX = (signX * qx) / length;\n    edge.normalY = (signY * qy) / length;\n  } else if (qx > qy) {\n    edge.distance = qx - radius;\n    edge.normalX = signX;\n    edge.normalY = 0;\n  } else {\n    edge.distance = qy - radius;\n    edge.normalX = 0;\n    edge.normalY = signY;\n  }\n\n  return edge;\n}\n\nfunction computeLensMapMetrics(options: LensMapOptions) {\n  const width = Math.max(1, options.width);\n  const height = Math.max(1, options.height);\n  const bevel = clamp(options.bevel, 1, Math.min(width, height) / 2);\n  const pixelRatio = clamp(options.devicePixelRatio ?? 1, 1, 2);\n  let mapWidth = clamp(Math.round(width * pixelRatio), 32, 1800);\n  let mapHeight = clamp(Math.round(height * pixelRatio), 32, 1200);\n\n  if (mapWidth * mapHeight > MAX_LENS_MAP_PIXELS) {\n    const ratio = Math.sqrt(MAX_LENS_MAP_PIXELS / (mapWidth * mapHeight));\n\n    mapWidth = Math.max(32, Math.floor(mapWidth * ratio));\n    mapHeight = Math.max(32, Math.floor(mapHeight * ratio));\n  }\n\n  const cacheKey = [\n    mapWidth,\n    mapHeight,\n    Math.round(width),\n    Math.round(height),\n    ...options.radii.map((radius) => Math.round(radius * 10)),\n    Math.round(bevel * 10),\n    Math.round(options.thickness * 10),\n    Math.round(options.ior * 100),\n    Math.round(options.depth * 100),\n  ].join(':');\n\n  return { bevel, cacheKey, height, mapHeight, mapWidth, width };\n}\n\n/**\n * Encodes the rim of a slab of glass as a displacement field: R/G = 0.5 + 0.5 * the\n * offset the backdrop is read from, as a share of `reach`. The SVG feDisplacementMap\n * scale of twice `reach` turns it back into CSS pixels. B is the share of the rim's\n * light, which smoked glass dims less than its top. The field is flat past the rim.\n */\nexport function buildLensMapDataUrl(options: LensMapOptions): LensMapBuildResult {\n  const base = computeLensMapMetrics(options);\n  const cached = lensMapCache.get(base.cacheKey);\n\n  if (cached) {\n    lensMapCache.delete(base.cacheKey);\n    lensMapCache.set(base.cacheKey, cached);\n\n    return cached;\n  }\n\n  if (typeof document === 'undefined') {\n    throw new Error('Lens maps require a browser document');\n  }\n\n  const canvas = document.createElement('canvas');\n  canvas.width = base.mapWidth;\n  canvas.height = base.mapHeight;\n\n  const ctx = canvas.getContext('2d');\n\n  if (!ctx) {\n    throw new Error('Canvas 2D context unavailable');\n  }\n\n  const { bevel, height, mapHeight, mapWidth, width } = base;\n  const { offsets, reach } = lensProfile(bevel, options.thickness, options.ior, options.depth);\n\n  const litTo = Math.min(\n    LENS_RIM_LIGHT,\n    (LENS_RIM_LIGHT_SURFACE * Math.min(width, height)) / bevel,\n  );\n\n  const litFrom = litTo * LENS_RIM_LIGHT_FALLOFF;\n  const data = new Uint8ClampedArray(mapWidth * mapHeight * 4);\n  const pixels = new Uint32Array(data.buffer);\n  const edge: Edge = { distance: 0, normalX: 0, normalY: 0 };\n  // Beyond every corner and the bevel, the map is exactly neutral. Keep a full\n  // texel inside that rectangle so fractional dimensions cannot round a rim in.\n  const flatInset = Math.max(bevel, ...options.radii);\n  const flatLeft = Math.min(mapWidth, Math.ceil((flatInset / width) * mapWidth + 0.5));\n  const flatRight = Math.max(flatLeft, Math.floor(((width - flatInset) / width) * mapWidth - 0.5));\n  const flatTop = Math.ceil((bevel / height) * mapHeight + 0.5);\n  const flatBottom = Math.floor(((height - bevel) / height) * mapHeight - 0.5);\n\n  for (let yIndex = 0; yIndex < mapHeight; yIndex += 1) {\n    const y = ((yIndex + 0.5) / mapHeight) * height;\n    const flatRow = yIndex >= flatTop && yIndex < flatBottom;\n\n    for (let xIndex = 0; xIndex < mapWidth; xIndex += 1) {\n      if (flatRow && xIndex === flatLeft && flatRight > flatLeft) {\n        pixels.fill(FLAT_LENS_PIXEL, yIndex * mapWidth + flatLeft, yIndex * mapWidth + flatRight);\n        xIndex = flatRight - 1;\n\n        continue;\n      }\n\n      const x = ((xIndex + 0.5) / mapWidth) * width;\n      const index = (yIndex * mapWidth + xIndex) * 4;\n      roundedBoxEdge(x, y, width, height, options.radii, edge);\n      const inset = Math.max(-edge.distance, 0);\n      let offset = 0;\n\n      if (inset < bevel) {\n        const position = (inset / bevel) * LENS_PROFILE_STEPS;\n        const lower = Math.floor(position);\n        const fraction = position - lower;\n\n        offset = offsets[lower] * (1 - fraction) + offsets[lower + 1] * fraction;\n      }\n\n      data[index] = Math.round(clamp(0.5 - (offset * edge.normalX) / (2 * reach), 0, 1) * 255);\n      data[index + 1] = Math.round(clamp(0.5 - (offset * edge.normalY) / (2 * reach), 0, 1) * 255);\n      data[index + 2] = Math.round((1 - smoothstep(litFrom, litTo, inset / bevel)) * 255);\n      data[index + 3] = 255;\n    }\n  }\n\n  ctx.putImageData(new ImageData(data, mapWidth, mapHeight), 0, 0);\n\n  const result = {\n    href: canvas.toDataURL('image/png'),\n    metrics: { ...base, reach },\n  };\n\n  lensMapCache.set(base.cacheKey, result);\n\n  if (lensMapCache.size > maxCachedLensMaps) {\n    const oldestKey = lensMapCache.keys().next().value;\n\n    if (oldestKey) lensMapCache.delete(oldestKey);\n  }\n\n  return result;\n}\n\nexport type MagnifierMapOptions = {\n  devicePixelRatio?: number;\n  size: number;\n};\n\nexport type MagnifierMapMetrics = {\n  /** Width of the ring that bends, in CSS pixels. */\n  band: number;\n  cacheKey: string;\n  /** Outward offset at the rim, in CSS pixels. */\n  depth: number;\n  mapSize: number;\n  size: number;\n};\n\nexport type MagnifierMapBuildResult = {\n  href: string;\n  metrics: MagnifierMapMetrics;\n};\n\nconst magnifierMapCache = new Map<string, string>();\n\nconst maxCachedMagnifierMaps = 8;\n\nexport function computeMagnifierMapMetrics(options: MagnifierMapOptions): MagnifierMapMetrics {\n  const size = Math.max(1, options.size);\n  const radius = size / 2;\n  const mapSize = clamp(Math.round(size * clamp(options.devicePixelRatio ?? 1, 1, 2)), 32, 400);\n\n  return {\n    band: radius * 0.46,\n    cacheKey: [mapSize, Math.round(size * 10)].join(':'),\n    depth: radius * 0.5,\n    mapSize,\n    size,\n  };\n}\n\n/**\n * Encodes an outward offset that grows toward the rim of a circle:\n * R/G = 0.5 + 0.5 * offset / depth. Each pixel samples a little further out than its\n * inner neighbour, so the view compresses into the rim like thick glass and never folds\n * back on itself, even over sharp text.\n */\nexport function buildMagnifierMapDataUrl(options: MagnifierMapOptions): MagnifierMapBuildResult {\n  const metrics = computeMagnifierMapMetrics(options);\n  const cached = magnifierMapCache.get(metrics.cacheKey);\n\n  if (cached) return { href: cached, metrics };\n\n  if (typeof document === 'undefined') {\n    throw new Error('Magnifier maps require a browser document');\n  }\n\n  const canvas = document.createElement('canvas');\n  canvas.width = metrics.mapSize;\n  canvas.height = metrics.mapSize;\n\n  const ctx = canvas.getContext('2d');\n\n  if (!ctx) {\n    throw new Error('Canvas 2D context unavailable');\n  }\n\n  const { band, mapSize, size } = metrics;\n  const radius = size / 2;\n  const data = new Uint8ClampedArray(mapSize * mapSize * 4);\n\n  for (let yIndex = 0; yIndex < mapSize; yIndex += 1) {\n    const dy = ((yIndex + 0.5) / mapSize) * size - radius;\n\n    for (let xIndex = 0; xIndex < mapSize; xIndex += 1) {\n      const dx = ((xIndex + 0.5) / mapSize) * size - radius;\n      const index = (yIndex * mapSize + xIndex) * 4;\n      const distance = Math.hypot(dx, dy) || 1;\n      // Flat in the centre, cubic through the ring so the bend starts without a crease.\n      const rim = clamp((distance - (radius - band)) / band, 0, 1) ** 3;\n\n      data[index] = Math.round((0.5 + (0.5 * rim * dx) / distance) * 255);\n      data[index + 1] = Math.round((0.5 + (0.5 * rim * dy) / distance) * 255);\n      data[index + 2] = 128;\n      data[index + 3] = 255;\n    }\n  }\n\n  ctx.putImageData(new ImageData(data, mapSize, mapSize), 0, 0);\n  const href = canvas.toDataURL('image/png');\n  magnifierMapCache.set(metrics.cacheKey, href);\n\n  if (magnifierMapCache.size > maxCachedMagnifierMaps) {\n    const oldestKey = magnifierMapCache.keys().next().value;\n\n    if (oldestKey) magnifierMapCache.delete(oldestKey);\n  }\n\n  return { href, metrics };\n}\n\nexport type CapsuleLensMapOptions = {\n  devicePixelRatio?: number;\n  height: number;\n  /** Multiple of regular glass: a thicker capsule bends further at its rim. */\n  thickness?: number;\n  width: number;\n};\n\ntype CapsuleLensMapMetrics = {\n  /** Width of the band inside the rim that bends, in CSS pixels. */\n  band: number;\n  cacheKey: string;\n  /** Outward offset at the rim, in CSS pixels. */\n  depth: number;\n  height: number;\n  mapHeight: number;\n  mapWidth: number;\n  width: number;\n};\n\nexport type CapsuleLensMapBuildResult = {\n  href: string;\n  metrics: CapsuleLensMapMetrics;\n};\n\n// The lens itself shows its scene evenly, a little smaller; only a thin band at the rim bends.\nconst CAPSULE_BAND = 0.3;\n\nconst CAPSULE_DEPTH = 0.25;\n\nconst capsuleLensMapCache = new Map<string, string>();\n\nconst maxCachedCapsuleLensMaps = 8;\n\nfunction computeCapsuleLensMapMetrics(options: CapsuleLensMapOptions): CapsuleLensMapMetrics {\n  const width = Math.max(1, options.width);\n  const height = Math.max(1, options.height);\n  const radius = Math.min(width, height) / 2;\n  const thickness = clamp(options.thickness ?? 1, 0.1, 4);\n  // The map is drawn at twice the device scale, so the bend stays smooth on a small knob.\n  const scale = clamp(options.devicePixelRatio ?? 1, 1, 2) * 2;\n  const mapWidth = clamp(Math.round(width * scale), 32, 400);\n  const mapHeight = clamp(Math.round(height * scale), 32, 400);\n  const band = radius * CAPSULE_BAND;\n  const depth = radius * CAPSULE_DEPTH * thickness;\n\n  return {\n    band,\n    cacheKey: [mapWidth, mapHeight, Math.round(width * 10), Math.round(height * 10)].join(':'),\n    depth,\n    height,\n    mapHeight,\n    mapWidth,\n    width,\n  };\n}\n\n/**\n * The rim's field for a capsule lens, such as a switch knob: R/G = 0.5 + 0.5 * the outward\n * offset as a share of `depth`, along the outward normal of the nearest rim. It is flat in\n * the middle and grows cubically through a thin band, so each pixel there samples a little\n * further out than its inner neighbour: the view compresses into the rim like thick glass\n * and never folds back on itself. The ends and the straight sides meet without a crease.\n * B rises through the band, so the filter softens only the scene the rim bends and the\n * middle stays sharp.\n */\nexport function buildCapsuleLensMapDataUrl(\n  options: CapsuleLensMapOptions,\n): CapsuleLensMapBuildResult {\n  const metrics = computeCapsuleLensMapMetrics(options);\n  const cached = capsuleLensMapCache.get(metrics.cacheKey);\n\n  if (cached) return { href: cached, metrics };\n\n  if (typeof document === 'undefined') {\n    throw new Error('Lens maps require a browser document');\n  }\n\n  const canvas = document.createElement('canvas');\n  canvas.width = metrics.mapWidth;\n  canvas.height = metrics.mapHeight;\n\n  const ctx = canvas.getContext('2d');\n\n  if (!ctx) {\n    throw new Error('Canvas 2D context unavailable');\n  }\n\n  const { band, height, mapHeight, mapWidth, width } = metrics;\n  const radius = Math.min(width, height) / 2;\n  const radii: LensRadii = [radius, radius, radius, radius];\n  const data = new Uint8ClampedArray(mapWidth * mapHeight * 4);\n  const edge: Edge = { distance: 0, normalX: 0, normalY: 0 };\n\n  for (let yIndex = 0; yIndex < mapHeight; yIndex += 1) {\n    const y = ((yIndex + 0.5) / mapHeight) * height;\n\n    for (let xIndex = 0; xIndex < mapWidth; xIndex += 1) {\n      const x = ((xIndex + 0.5) / mapWidth) * width;\n      const index = (yIndex * mapWidth + xIndex) * 4;\n      roundedBoxEdge(x, y, width, height, radii, edge);\n      const inBand = clamp((band + edge.distance) / band, 0, 1);\n      const rim = inBand ** 3;\n\n      data[index] = Math.round((0.5 + 0.5 * rim * edge.normalX) * 255);\n      data[index + 1] = Math.round((0.5 + 0.5 * rim * edge.normalY) * 255);\n      data[index + 2] = Math.round(inBand * 255);\n      data[index + 3] = 255;\n    }\n  }\n\n  ctx.putImageData(new ImageData(data, mapWidth, mapHeight), 0, 0);\n  const href = canvas.toDataURL('image/png');\n  capsuleLensMapCache.set(metrics.cacheKey, href);\n\n  if (capsuleLensMapCache.size > maxCachedCapsuleLensMaps) {\n    const oldestKey = capsuleLensMapCache.keys().next().value;\n\n    if (oldestKey) capsuleLensMapCache.delete(oldestKey);\n  }\n\n  return { href, metrics };\n}\n",
      "type": "registry:lib",
      "target": "components/glassyui/lib/refraction-map.ts"
    },
    {
      "path": "registry/glassyui/lib/slab-optics.ts",
      "content": "// The glass floats this far above its backdrop, in CSS pixels.\nexport const SLAB_AIR_GAP = 8;\n\n// Fractions of full slab thickness at the rim and added across its curved top.\nexport const SLAB_MIN_RISE = 0.3;\n\nexport const SLAB_RISE_SPAN = 0.7;\n\nexport const SLAB_MAX_SLOPE = 12;\n",
      "type": "registry:lib",
      "target": "components/glassyui/lib/slab-optics.ts"
    },
    {
      "path": "registry/glassyui/lib/use-refraction-filter.tsx",
      "content": "'use client';\n\nimport { useCallback, useEffect, useId, useMemo, useRef, useState, type RefObject } from 'react';\nimport {\n  buildCapsuleLensMapDataUrl,\n  buildLensMapDataUrl,\n  buildMagnifierMapDataUrl,\n  buildRefractionMapDataUrl,\n  clamp,\n  computeMagnifierMapMetrics,\n  MAX_LENS_SURFACE_AREA,\n  type CapsuleLensMapBuildResult,\n  type GeneratedRefractionStrength,\n  type LensMapMetrics,\n  type LensRadii,\n  type MagnifierMapBuildResult,\n  type RefractionMapMetrics,\n} from './refraction-map';\n\ntype RefractionFilterOptions = {\n  displacement?: number;\n  enabled: boolean;\n  reduceTransparency?: boolean;\n  strength: GeneratedRefractionStrength;\n  thickness?: number;\n  viewportAligned?: boolean;\n};\n\ntype RefractionFilterState = {\n  href: string | null;\n  metrics: RefractionMapMetrics | null;\n};\n\nfunction isProductionRuntime() {\n  // SAFETY: only Node and bundler shims define `process`, so every step of the probe stays optional.\n  const runtime = globalThis as typeof globalThis & {\n    process?: { env?: { NODE_ENV?: string } };\n  };\n\n  return runtime.process?.env?.NODE_ENV === 'production';\n}\n\nfunction parseRadiusValue(value: string, width: number, height: number) {\n  const [first] = value.trim().split(/\\s+/);\n  const maxRadius = Math.min(width, height) / 2;\n\n  const parsed = Number.parseFloat(first);\n\n  if (first.endsWith('%')) {\n    return clamp((parsed / 100) * Math.min(width, height), 0, maxRadius);\n  }\n\n  return clamp(Number.isFinite(parsed) ? parsed : maxRadius, 0, maxRadius);\n}\n\nfunction readUniformRadius(el: HTMLElement, width: number, height: number) {\n  const style = window.getComputedStyle(el);\n\n  const rawRadii = [\n    style.borderTopLeftRadius,\n    style.borderTopRightRadius,\n    style.borderBottomRightRadius,\n    style.borderBottomLeftRadius,\n  ];\n\n  const radii = rawRadii.map((value) => parseRadiusValue(value, width, height));\n  const first = radii[0];\n  const mixed = radii.some((radius) => Math.abs(radius - first) > 0.5);\n\n  return mixed ? null : first;\n}\n\nfunction readCornerRadii(style: CSSStyleDeclaration, width: number, height: number): LensRadii {\n  return [\n    parseRadiusValue(style.borderTopLeftRadius, width, height),\n    parseRadiusValue(style.borderTopRightRadius, width, height),\n    parseRadiusValue(style.borderBottomRightRadius, width, height),\n    parseRadiusValue(style.borderBottomLeftRadius, width, height),\n  ];\n}\n\n/**\n * A scroll event reaches script a frame after the compositor has scrolled, so a scene moved from\n * script trails the page. Chromium filters a composited layer on its compositor, which lets a\n * scroll-driven animation carry the scene in step with the scroll and still bend it. WebKit leaves\n * a scene on its own compositing layer out of the SVG filter and Gecko has no scroll timelines, so\n * both keep moving the scene from script. Only Chromium has userAgentData.\n */\nfunction supportsCompositedSceneScroll() {\n  return (\n    typeof ViewTimeline !== 'undefined' &&\n    typeof navigator !== 'undefined' &&\n    'userAgentData' in navigator\n  );\n}\n\n// Across the timeline the scene moves down exactly as far as the scroll carries the surface up.\nconst sceneScrollKeyframes = (span: number): Keyframe[] => [\n  { translate: '0px 0px' },\n  { translate: `0px ${span}px` },\n];\n\n/**\n * A view timeline places its subject where it would sit if nothing were fixed or stuck, so it runs\n * on while such a surface stands still. Those surfaces keep following the scroll from script.\n */\nfunction standsStillWhileScrolling(el: Element, source: Element) {\n  for (let node: Element | null = el; node && node !== source; node = node.parentElement) {\n    const { position } = window.getComputedStyle(node);\n\n    if (position === 'fixed' || position === 'sticky') {\n      return true;\n    }\n  }\n\n  return false;\n}\n\nexport function useRefractionFilter(\n  surfaceRef: RefObject<HTMLElement | null>,\n  {\n    displacement,\n    enabled,\n    reduceTransparency = false,\n    strength,\n    thickness,\n    viewportAligned = false,\n  }: RefractionFilterOptions,\n) {\n  const rawId = useId().replaceAll(':', '');\n  const filterId = `lg-refraction-${rawId}`;\n  const generationRef = useRef(0);\n  const warnedMixedRadiusRef = useRef(false);\n  const [state, setState] = useState<RefractionFilterState>({ href: null, metrics: null });\n  const sceneRef = useRef<HTMLDivElement | null>(null);\n  // Set while the scene is kept aligned, so a scene that mounts is aligned before it first paints.\n  const alignSceneNowRef = useRef<(() => void) | null>(null);\n\n  const setScene = useCallback((node: HTMLDivElement | null) => {\n    sceneRef.current = node;\n    alignSceneNowRef.current?.();\n  }, []);\n\n  useEffect(() => {\n    if (!enabled || reduceTransparency || !viewportAligned) {\n      return;\n    }\n\n    const el = surfaceRef.current;\n\n    if (!el) {\n      return;\n    }\n\n    let alignmentFrame = 0;\n    let disposed = false;\n    // Aligning a scene that no one can see only costs a layout, a style pass and a repaint on\n    // every scroll frame, so it waits until the surface is within a quarter screen of the viewport.\n    let nearViewport = true;\n\n    const timeline = supportsCompositedSceneScroll()\n      ? new ViewTimeline({ axis: 'block', subject: el })\n      : null;\n\n    let sceneScroll: Animation | null = null;\n    let sceneScrollSpan = Number.NaN;\n\n    // Keeps the scene's scroll-driven animation spanning the timeline and returns how far along\n    // the block axis it has carried the scene, which the offset below then leaves out. Past\n    // either end of the timeline the animation holds still, but the unclamped distance keeps the\n    // offset constant, so plain scrolling rewrites nothing and the scene never waits on script.\n    const followScroll = () => {\n      const scene = sceneRef.current;\n      const source = timeline?.source ?? null;\n\n      if (\n        !timeline ||\n        !scene ||\n        !source ||\n        timeline.currentTime === null ||\n        standsStillWhileScrolling(el, source)\n      ) {\n        sceneScroll?.cancel();\n        sceneScroll = null;\n\n        return 0;\n      }\n\n      const start = timeline.startOffset.to('px').value;\n      const span = timeline.endOffset.to('px').value - start;\n\n      if (sceneScroll?.effect instanceof KeyframeEffect && sceneScroll.effect.target === scene) {\n        if (span !== sceneScrollSpan) {\n          sceneScroll.effect.setKeyframes(sceneScrollKeyframes(span));\n        }\n      } else {\n        sceneScroll?.cancel();\n        sceneScroll = scene.animate(sceneScrollKeyframes(span), { fill: 'both', timeline });\n      }\n\n      sceneScrollSpan = span;\n\n      return source.scrollTop - start;\n    };\n\n    const writeProperty = (property: string, value: string) => {\n      if (el.style.getPropertyValue(property) !== value) {\n        el.style.setProperty(property, value);\n      }\n    };\n\n    const alignScene = () => {\n      alignmentFrame = 0;\n\n      if (disposed) {\n        return;\n      }\n\n      const followed = followScroll();\n      const rect = el.getBoundingClientRect();\n      writeProperty('--lg-refraction-scene-x', `${-(rect.left + el.clientLeft)}px`);\n      writeProperty('--lg-refraction-scene-y', `${-(rect.top + el.clientTop) - followed}px`);\n      writeProperty('--lg-refraction-scene-width', `${document.documentElement.clientWidth}px`);\n      writeProperty('--lg-refraction-scene-height', `${document.documentElement.clientHeight}px`);\n    };\n\n    const scheduleAlignment = () => {\n      if (nearViewport && !alignmentFrame) {\n        alignmentFrame = requestAnimationFrame(alignScene);\n      }\n    };\n\n    alignSceneNowRef.current = () => {\n      cancelAnimationFrame(alignmentFrame);\n      alignScene();\n    };\n\n    const visibilityObserver =\n      typeof IntersectionObserver === 'undefined'\n        ? null\n        : new IntersectionObserver(\n            (entries) => {\n              const wasNear = nearViewport;\n              nearViewport = entries[entries.length - 1]?.isIntersecting ?? true;\n\n              // Coming into range aligns at once, in this task. A frame asked for from here would run\n              // after whatever the page queued for the next frame, and that could read the scene\n              // where it still was.\n              if (nearViewport && !wasNear) {\n                cancelAnimationFrame(alignmentFrame);\n                alignScene();\n              }\n            },\n            { rootMargin: '25% 0px' },\n          );\n\n    visibilityObserver?.observe(el);\n\n    const resizeObserver =\n      typeof ResizeObserver === 'undefined' ? null : new ResizeObserver(scheduleAlignment);\n\n    for (let ancestor: HTMLElement | null = el; ancestor; ancestor = ancestor.parentElement) {\n      resizeObserver?.observe(ancestor);\n    }\n\n    const readExternalStyleSignature = () => {\n      const declarations: string[] = [];\n\n      for (let index = 0; index < el.style.length; index += 1) {\n        const property = el.style.item(index);\n\n        if (property.startsWith('--lg-refraction-scene-')) {\n          continue;\n        }\n\n        declarations.push(\n          `${property}:${el.style.getPropertyValue(property)}:${el.style.getPropertyPriority(property)}`,\n        );\n      }\n\n      return declarations.sort().join(';');\n    };\n\n    let externalStyleSignature = readExternalStyleSignature();\n\n    const mutationObserver =\n      typeof MutationObserver === 'undefined'\n        ? null\n        : new MutationObserver((records) => {\n            const hasExternalMutation = records.some((record) => {\n              if (\n                record.type === 'attributes' &&\n                record.target === el &&\n                record.attributeName === 'style'\n              ) {\n                const nextExternalStyleSignature = readExternalStyleSignature();\n\n                if (nextExternalStyleSignature === externalStyleSignature) {\n                  return false;\n                }\n\n                externalStyleSignature = nextExternalStyleSignature;\n              }\n\n              return true;\n            });\n\n            if (hasExternalMutation) {\n              scheduleAlignment();\n            }\n          });\n\n    mutationObserver?.observe(document.body, {\n      attributeFilter: ['class', 'hidden', 'open', 'style'],\n      attributes: true,\n      characterData: true,\n      childList: true,\n      subtree: true,\n    });\n    document.addEventListener('scroll', scheduleAlignment, {\n      capture: true,\n      passive: true,\n    });\n    document.addEventListener('load', scheduleAlignment, {\n      capture: true,\n      passive: true,\n    });\n    document.fonts?.addEventListener('loadingdone', scheduleAlignment);\n    window.addEventListener('resize', scheduleAlignment, { passive: true });\n    window.visualViewport?.addEventListener('resize', scheduleAlignment, { passive: true });\n    window.visualViewport?.addEventListener('scroll', scheduleAlignment, { passive: true });\n    scheduleAlignment();\n\n    return () => {\n      disposed = true;\n      alignSceneNowRef.current = null;\n      cancelAnimationFrame(alignmentFrame);\n      sceneScroll?.cancel();\n      resizeObserver?.disconnect();\n      mutationObserver?.disconnect();\n      visibilityObserver?.disconnect();\n      document.removeEventListener('scroll', scheduleAlignment, { capture: true });\n      document.removeEventListener('load', scheduleAlignment, { capture: true });\n      document.fonts?.removeEventListener('loadingdone', scheduleAlignment);\n      window.removeEventListener('resize', scheduleAlignment);\n      window.visualViewport?.removeEventListener('resize', scheduleAlignment);\n      window.visualViewport?.removeEventListener('scroll', scheduleAlignment);\n      el.style.removeProperty('--lg-refraction-scene-height');\n      el.style.removeProperty('--lg-refraction-scene-width');\n      el.style.removeProperty('--lg-refraction-scene-x');\n      el.style.removeProperty('--lg-refraction-scene-y');\n    };\n  }, [enabled, reduceTransparency, surfaceRef, viewportAligned]);\n\n  useEffect(() => {\n    generationRef.current += 1;\n    const generation = generationRef.current;\n\n    if (!enabled || reduceTransparency || typeof ResizeObserver === 'undefined') {\n      queueMicrotask(() => {\n        if (generationRef.current === generation) {\n          setState({ href: null, metrics: null });\n        }\n      });\n\n      return;\n    }\n\n    const el = surfaceRef.current;\n\n    if (!el) {\n      queueMicrotask(() => {\n        if (generationRef.current === generation) {\n          setState({ href: null, metrics: null });\n        }\n      });\n\n      return;\n    }\n\n    let raf = 0;\n    let disposed = false;\n\n    const clear = () => {\n      if (generationRef.current === generation) {\n        setState({ href: null, metrics: null });\n      }\n    };\n\n    const schedule = () => {\n      cancelAnimationFrame(raf);\n      raf = requestAnimationFrame(() => {\n        const rect = el.getBoundingClientRect();\n        const width = Math.max(0, rect.width);\n        const height = Math.max(0, rect.height);\n\n        if (!width || !height) {\n          clear();\n\n          return;\n        }\n\n        const radius = readUniformRadius(el, width, height);\n\n        if (radius === null) {\n          if (!isProductionRuntime() && !warnedMixedRadiusRef.current) {\n            console.warn(\n              'Glassy UI supplied-background refraction currently supports uniform rounded rectangles only.',\n            );\n            warnedMixedRadiusRef.current = true;\n          }\n\n          clear();\n\n          return;\n        }\n\n        void buildRefractionMapDataUrl({\n          devicePixelRatio: window.devicePixelRatio || 1,\n          displacement,\n          height,\n          radius,\n          strength,\n          thickness,\n          width,\n        })\n          .then((result) => {\n            if (!disposed && generationRef.current === generation) {\n              setState({ href: result.href, metrics: result.metrics });\n            }\n          })\n          .catch(() => {\n            if (!disposed) {\n              clear();\n            }\n          });\n      });\n    };\n\n    const observer = new ResizeObserver(schedule);\n    observer.observe(el);\n    schedule();\n\n    return () => {\n      disposed = true;\n      cancelAnimationFrame(raf);\n      observer.disconnect();\n    };\n  }, [displacement, enabled, reduceTransparency, strength, surfaceRef, thickness]);\n\n  const filterElement = useMemo(() => {\n    if (!state.href || !state.metrics) return null;\n\n    const {\n      dispersion,\n      filterBlur,\n      filterPadding,\n      filterScale,\n      height,\n      paddedHeight,\n      paddedWidth,\n      width,\n    } = state.metrics;\n\n    // Every colour follows the same two-axis rim normal, so the sides split as much as the ends.\n    const channel = (name: string, matrix: string, factor: number) => (\n      <>\n        <feDisplacementMap\n          in=\"scene\"\n          in2=\"map\"\n          scale={Math.round(filterScale * factor * 100) / 100}\n          xChannelSelector=\"R\"\n          yChannelSelector=\"G\"\n          result={`${name}-scene`}\n        />\n        <feColorMatrix in={`${name}-scene`} type=\"matrix\" values={matrix} result={`${name}-bent`} />\n      </>\n    );\n\n    return (\n      <svg aria-hidden=\"true\" className=\"lg-refraction-filter\" focusable=\"false\" viewBox=\"0 0 0 0\">\n        <defs>\n          <filter\n            id={filterId}\n            x={-filterPadding}\n            y={-filterPadding}\n            width={paddedWidth}\n            height={paddedHeight}\n            filterUnits=\"userSpaceOnUse\"\n            primitiveUnits=\"userSpaceOnUse\"\n            colorInterpolationFilters=\"sRGB\"\n          >\n            <feGaussianBlur in=\"SourceGraphic\" stdDeviation={filterBlur} result=\"blurred\" />\n            <feImage\n              href={state.href}\n              x={-filterPadding}\n              y={-filterPadding}\n              width={width + filterPadding * 2}\n              height={height + filterPadding * 2}\n              preserveAspectRatio=\"none\"\n              result=\"map\"\n            />\n            {/* The map's blue channel softens only the scene the rim magnifies. */}\n            <feColorMatrix\n              in=\"map\"\n              type=\"matrix\"\n              values=\"0 0 0 0 0  0 0 0 0 0  0 0 0 0 0  0 0 1 0 0\"\n              result=\"rim\"\n            />\n            <feComposite in=\"blurred\" in2=\"rim\" operator=\"in\" result=\"softRim\" />\n            <feComposite in=\"softRim\" in2=\"SourceGraphic\" operator=\"over\" result=\"scene\" />\n            {dispersion > 0 ? (\n              <>\n                {channel('red', '1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1', 1 - dispersion / 2)}\n                {channel('green', '0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1', 1)}\n                {channel('blue', '0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1', 1 + dispersion / 2)}\n                <feBlend in=\"red-bent\" in2=\"green-bent\" mode=\"screen\" result=\"red-green\" />\n                <feBlend in=\"red-green\" in2=\"blue-bent\" mode=\"screen\" result=\"rgb\" />\n                {/* Combine opaque colour, then restore coverage once so translucent scenes stay translucent. */}\n                <feComposite in=\"rgb\" in2=\"green-scene\" operator=\"in\" />\n              </>\n            ) : (\n              <feDisplacementMap\n                in=\"scene\"\n                in2=\"map\"\n                scale={filterScale}\n                xChannelSelector=\"R\"\n                yChannelSelector=\"G\"\n              />\n            )}\n          </filter>\n        </defs>\n      </svg>\n    );\n  }, [filterId, state.href, state.metrics]);\n\n  return {\n    active: Boolean(state.href && state.metrics),\n    filterElement,\n    filterStyle: state.href ? `url(#${filterId})` : undefined,\n    sceneRef: setScene,\n  };\n}\n\ntype LensFilterOptions = {\n  enabled: boolean;\n  /** Changes whenever theme, mode, quality or variant tokens may have changed. */\n  signature?: string;\n};\n\ntype LensFilterState = {\n  blur: number;\n  bodyBrightness: number;\n  dispersion: number;\n  href: string;\n  metrics: LensMapMetrics;\n  rimBrightness: number;\n  saturation: number;\n};\n\n/**\n * Only Chromium renders SVG references inside backdrop-filter. WebKit and\n * Gecko drop the whole declaration when url() is present, and CSS.supports()\n * reports true everywhere, so the engine is detected explicitly.\n */\nfunction supportsBackdropLens() {\n  return (\n    typeof navigator !== 'undefined' &&\n    'userAgentData' in navigator &&\n    typeof ResizeObserver !== 'undefined'\n  );\n}\n\nfunction readNumberToken(style: CSSStyleDeclaration, name: string) {\n  const value = Number.parseFloat(style.getPropertyValue(name));\n\n  return Number.isFinite(value) ? value : 0;\n}\n\nfunction readTokenOr(style: CSSStyleDeclaration, name: string, fallback: number) {\n  const value = Number.parseFloat(style.getPropertyValue(name));\n\n  return Number.isFinite(value) ? value : fallback;\n}\n\nfunction sameLens(previous: LensFilterState | null, next: LensFilterState) {\n  return (\n    previous !== null &&\n    previous.href === next.href &&\n    previous.blur === next.blur &&\n    previous.bodyBrightness === next.bodyBrightness &&\n    previous.dispersion === next.dispersion &&\n    previous.rimBrightness === next.rimBrightness &&\n    previous.saturation === next.saturation\n  );\n}\n\n// A rim as wide as the corners are round, up to a little wider than the WebGL scene's default.\nconst LENS_BEVEL = 36;\n\n// Slab height per pixel of rim, as in the scene (40 px of glass under a 28 px rim).\nconst LENS_THICKNESS_RATIO = 1.4;\n\n// The least frost the lens reads through, so bent edges never stair-step.\nconst MIN_FROST = 0.5;\n\n// Each colour follows the same rim normal: red bends least and blue most.\n// Both live-backdrop glass and the magnifier use this material pass.\nfunction refractColours(source: string, map: string, scale: number, dispersion: number) {\n  if (dispersion <= 0.005) {\n    return (\n      <feDisplacementMap\n        in={source}\n        in2={map}\n        scale={scale}\n        xChannelSelector=\"R\"\n        yChannelSelector=\"G\"\n        result=\"bent\"\n      />\n    );\n  }\n\n  const channel = (name: string, matrix: string, factor: number) => (\n    <>\n      <feDisplacementMap\n        in={source}\n        in2={map}\n        scale={Math.round(scale * factor * 100) / 100}\n        xChannelSelector=\"R\"\n        yChannelSelector=\"G\"\n        result={`${name}-scene`}\n      />\n      <feColorMatrix in={`${name}-scene`} type=\"matrix\" values={matrix} result={`${name}-bent`} />\n    </>\n  );\n\n  return (\n    <>\n      {channel('red', '1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1', 1 - dispersion / 2)}\n      {channel('green', '0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1', 1)}\n      {channel('blue', '0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1', 1 + dispersion / 2)}\n      <feBlend in=\"red-bent\" in2=\"green-bent\" mode=\"screen\" result=\"red-green\" />\n      <feBlend in=\"red-green\" in2=\"blue-bent\" mode=\"screen\" result=\"rgb\" />\n      {/* Combine opaque colour, then restore the reference channel's coverage once. */}\n      <feComposite in=\"rgb\" in2=\"green-scene\" operator=\"in\" result=\"bent\" />\n    </>\n  );\n}\n\n/**\n * Chromium-only lens for glass over live content. The backdrop is frosted, then read\n * through a slab of glass whose top curves down into a rounded rim, so content bends\n * and splits into colour along the edge and lies flat everywhere else. The\n * --lg-lens-* tokens shape it: depth, bevel, thickness, ior, dispersion, blur and\n * saturation, and --lg-glass-thickness scales the whole slab at once. Other engines,\n * zero depth and oversized surfaces keep the CSS glass.\n */\nexport function useLensFilter(\n  surfaceRef: RefObject<HTMLElement | null>,\n  { enabled, signature }: LensFilterOptions,\n) {\n  const rawId = useId().replaceAll(':', '');\n  const filterId = `lg-lens-${rawId}`;\n  const generationRef = useRef(0);\n  const [state, setState] = useState<LensFilterState | null>(null);\n\n  useEffect(() => {\n    generationRef.current += 1;\n    const generation = generationRef.current;\n    const el = surfaceRef.current;\n\n    if (!enabled || !el || !supportsBackdropLens()) {\n      queueMicrotask(() => {\n        if (generationRef.current === generation) {\n          setState(null);\n        }\n      });\n\n      return;\n    }\n\n    let frame = 0;\n    let disposed = false;\n\n    const measure = () => {\n      frame = 0;\n\n      if (disposed || generationRef.current !== generation) {\n        return;\n      }\n\n      // The lens layer fills the padding box, so borders and scrollbars stay out of the map.\n      const width = el.clientWidth;\n      const height = el.clientHeight;\n      const style = window.getComputedStyle(el);\n      const depth = readNumberToken(style, '--lg-lens-depth');\n\n      if (depth <= 0 || !width || !height || width * height > MAX_LENS_SURFACE_AREA) {\n        setState(null);\n\n        return;\n      }\n\n      const radii = readCornerRadii(style, width, height);\n      const roundest = Math.max(...radii);\n      const multiplier = clamp(readTokenOr(style, '--lg-glass-thickness', 1), 0.1, 4);\n      const bevelToken = readNumberToken(style, '--lg-lens-bevel');\n      const thicknessToken = readNumberToken(style, '--lg-lens-thickness');\n      const baseBevel = bevelToken > 0 ? bevelToken : clamp(roundest, 6, LENS_BEVEL);\n      // A thicker slab also has a wider rim, though not in proportion.\n      const bevel = clamp(baseBevel * (0.6 + 0.4 * multiplier), 4, Math.min(width, height) / 2);\n\n      const thickness =\n        (thicknessToken > 0 ? thicknessToken : baseBevel * LENS_THICKNESS_RATIO) * multiplier;\n\n      const { href, metrics } = buildLensMapDataUrl({\n        bevel,\n        depth,\n        devicePixelRatio: window.devicePixelRatio || 1,\n        height,\n        ior: Math.max(1, readTokenOr(style, '--lg-lens-ior', 1.5)),\n        radii,\n        thickness,\n        width,\n      });\n\n      const next = {\n        blur: Math.max(0, readNumberToken(style, '--lg-lens-blur')),\n        bodyBrightness: clamp(readTokenOr(style, '--lg-lens-body-brightness', 1), 0, 1),\n        dispersion: clamp(readNumberToken(style, '--lg-lens-dispersion') * multiplier, 0, 1),\n        href,\n        metrics,\n        rimBrightness: clamp(readTokenOr(style, '--lg-lens-rim-brightness', 1), 0, 1),\n        saturation: readNumberToken(style, '--lg-lens-saturation') || 1,\n      };\n\n      setState((previous) => (sameLens(previous, next) ? previous : next));\n    };\n\n    const schedule = () => {\n      if (!frame) {\n        frame = requestAnimationFrame(measure);\n      }\n    };\n\n    const observer = new ResizeObserver(schedule);\n    observer.observe(el);\n    schedule();\n\n    return () => {\n      disposed = true;\n      cancelAnimationFrame(frame);\n      observer.disconnect();\n    };\n  }, [enabled, signature, surfaceRef]);\n\n  const filterElement = useMemo(() => {\n    if (!state) return null;\n\n    const { blur, bodyBrightness, dispersion, href, metrics, rimBrightness, saturation } = state;\n    // The rim is the same frosted glass as the flat top: it bends and splits what the frost\n    // leaves and is never clearer, so content does not show through a sharp band at the edge.\n    const frost = Math.max(blur, MIN_FROST);\n    const padding = Math.ceil(frost * 3) + 2;\n    // Map channels hold a unit offset; the scale turns it into CSS pixels.\n    const scale = Math.round(2 * metrics.reach * 100) / 100;\n\n    // Smoked glass darkens the flat top more than its rim, which lets the light through. A\n    // primitive is added only where it changes something: each one is another pass on the GPU.\n    const dim = (input: string, brightness: number, result: string) =>\n      brightness < 1 ? (\n        <feComponentTransfer in={input} result={result}>\n          <feFuncR type=\"linear\" slope={brightness} />\n          <feFuncG type=\"linear\" slope={brightness} />\n          <feFuncB type=\"linear\" slope={brightness} />\n        </feComponentTransfer>\n      ) : null;\n\n    // The map's blue channel weights the rim's light over the top's. Where both let the same\n    // light through, the bent frost alone is the glass.\n    const shaded = rimBrightness !== bodyBrightness;\n    const rimSource = rimBrightness < 1 ? 'rim-lit' : 'bent';\n    const topSource = bodyBrightness < 1 ? 'top-lit' : 'bent';\n    const glass = shaded ? 'mixed' : topSource;\n\n    return (\n      <svg aria-hidden=\"true\" className=\"lg-refraction-filter\" focusable=\"false\" viewBox=\"0 0 0 0\">\n        <defs>\n          <filter\n            id={filterId}\n            x={-padding}\n            y={-padding}\n            width={metrics.width + padding * 2}\n            height={metrics.height + padding * 2}\n            filterUnits=\"userSpaceOnUse\"\n            primitiveUnits=\"userSpaceOnUse\"\n            colorInterpolationFilters=\"sRGB\"\n          >\n            <feGaussianBlur in=\"SourceGraphic\" stdDeviation={frost} result=\"frost\" />\n            <feImage\n              href={href}\n              x={0}\n              y={0}\n              width={metrics.width}\n              height={metrics.height}\n              preserveAspectRatio=\"none\"\n              result=\"lens\"\n            />\n            {refractColours('frost', 'lens', scale, dispersion)}\n            {shaded ? (\n              <>\n                <feColorMatrix\n                  in=\"lens\"\n                  type=\"matrix\"\n                  values=\"0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0\"\n                  result=\"rim\"\n                />\n                {dim('bent', rimBrightness, 'rim-lit')}\n                {dim('bent', bodyBrightness, 'top-lit')}\n                <feComposite in={rimSource} in2=\"rim\" operator=\"in\" result=\"rim-glass\" />\n                {/* The rim, weighted by its mask, over the top, which is opaque: the mask's\n                    complement is implied, so the top needs no mask of its own. */}\n                <feComposite in=\"rim-glass\" in2={topSource} operator=\"over\" result=\"mixed\" />\n              </>\n            ) : (\n              dim('bent', bodyBrightness, 'top-lit')\n            )}\n            {saturation === 1 ? null : (\n              <feColorMatrix in={glass} type=\"saturate\" values={String(saturation)} />\n            )}\n          </filter>\n        </defs>\n      </svg>\n    );\n  }, [filterId, state]);\n\n  return {\n    active: state !== null,\n    filterElement,\n    filterStyle: state ? `url(#${filterId})` : undefined,\n  };\n}\n\ntype MagnifierFilterOptions = LensFilterOptions & {\n  /** Diameter of the round lens in CSS pixels. */\n  size: number;\n};\n\n// Softens the compressed rim just enough to keep sharp edges from stair-stepping.\nconst MAGNIFIER_BLUR = 0.35;\n\n/**\n * Rim refraction for the round magnifier, applied with `filter` to its zoomed view, which\n * every engine with SVG filters on HTML supports. Near the rim each pixel samples content\n * from further out, so the view bends into the edge like a glass bead.\n *\n * The view extends `margin` past the lens on every side so the rim has content to sample.\n * WebKit only lines the filtered view up with the map when the view clips its own overflow\n * and the filter region reaches past it by as far as the primitives can read, so the\n * region is the view plus another margin and the map sits one margin in.\n */\nexport function useMagnifierFilter(\n  surfaceRef: RefObject<HTMLElement | null>,\n  { enabled, signature, size }: MagnifierFilterOptions,\n) {\n  const rawId = useId().replaceAll(':', '');\n  const filterId = `lg-magnifier-${rawId}`;\n  const [map, setMap] = useState<(MagnifierMapBuildResult & { dispersion: number }) | null>(null);\n\n  // Blue reaches furthest; leave enough scene beyond the rim for it and the blur.\n  const margin =\n    Math.ceil(\n      computeMagnifierMapMetrics({ size }).depth * (1 + (map?.dispersion ?? 0) / 2) +\n        MAGNIFIER_BLUR * 3,\n    ) + 2;\n\n  useEffect(() => {\n    let disposed = false;\n\n    // The map is drawn on a canvas, so it can only be built in the browser.\n    queueMicrotask(() => {\n      if (disposed) return;\n\n      const surface = surfaceRef.current;\n\n      if (!enabled || !surface) {\n        setMap(null);\n\n        return;\n      }\n\n      const style = window.getComputedStyle(surface);\n      const thickness = clamp(readTokenOr(style, '--lg-glass-thickness', 1), 0.1, 4);\n      setMap({\n        ...buildMagnifierMapDataUrl({ devicePixelRatio: window.devicePixelRatio || 1, size }),\n        dispersion: clamp(readNumberToken(style, '--lg-lens-dispersion') * thickness, 0, 1),\n      });\n    });\n\n    return () => {\n      disposed = true;\n    };\n  }, [enabled, signature, size, surfaceRef]);\n\n  const filterElement = useMemo(() => {\n    if (!map) return null;\n\n    const {\n      dispersion,\n      metrics: { depth, size: mapCssSize },\n    } = map;\n\n    return (\n      <svg aria-hidden=\"true\" className=\"lg-refraction-filter\" focusable=\"false\" viewBox=\"0 0 0 0\">\n        <defs>\n          <filter\n            id={filterId}\n            x={-margin}\n            y={-margin}\n            width={mapCssSize + margin * 4}\n            height={mapCssSize + margin * 4}\n            filterUnits=\"userSpaceOnUse\"\n            primitiveUnits=\"userSpaceOnUse\"\n            colorInterpolationFilters=\"sRGB\"\n          >\n            <feGaussianBlur in=\"SourceGraphic\" stdDeviation={MAGNIFIER_BLUR} result=\"soft\" />\n            <feImage\n              href={map.href}\n              x={margin}\n              y={margin}\n              width={mapCssSize}\n              height={mapCssSize}\n              preserveAspectRatio=\"none\"\n              result=\"bend\"\n            />\n            {refractColours('soft', 'bend', depth * 2, dispersion)}\n          </filter>\n        </defs>\n      </svg>\n    );\n  }, [filterId, map, margin]);\n\n  return {\n    active: map !== null,\n    filterElement,\n    filterStyle: map ? `url(#${filterId})` : undefined,\n    margin,\n  };\n}\n\ntype CapsuleLensFilterOptions = LensFilterOptions & {\n  /** Colour split at the rim for regular glass; --lg-glass-thickness scales it. */\n  dispersion: number;\n  /**\n   * How many times the capsule's size the filtered copy is laid out at before it is scaled\n   * back down. WebKit filters at layout resolution, so a small lens bends in steps without it.\n   */\n  supersample?: number;\n};\n\ntype CapsuleLensState = CapsuleLensMapBuildResult & { dispersion: number };\n\n/**\n * Rim refraction for a capsule lens, such as a switch knob, applied with `filter` to a copy\n * of what lies under it. Every engine with SVG filters on HTML runs it. Near the rim each\n * pixel samples the copy from further out, so it bends into the edge like a bead of glass\n * and splits into colour there; --lg-glass-thickness deepens both. The copy must reach\n * `margin` past the capsule on every side so the rim has content to sample, and the filter\n * region reaches one margin further, as the round magnifier's does.\n */\nexport function useCapsuleLensFilter(\n  surfaceRef: RefObject<HTMLElement | null>,\n  { dispersion, enabled, signature, supersample = 1 }: CapsuleLensFilterOptions,\n) {\n  const rawId = useId().replaceAll(':', '');\n  const filterId = `lg-capsule-${rawId}`;\n  const [map, setMap] = useState<CapsuleLensState | null>(null);\n\n  useEffect(() => {\n    const el = surfaceRef.current;\n\n    if (!enabled || !el) {\n      queueMicrotask(() => setMap(null));\n\n      return;\n    }\n\n    let frame = 0;\n    let disposed = false;\n\n    const measure = () => {\n      frame = 0;\n\n      if (disposed) return;\n\n      const width = el.clientWidth;\n      const height = el.clientHeight;\n\n      if (!width || !height) {\n        setMap(null);\n\n        return;\n      }\n\n      const thickness = clamp(\n        readTokenOr(window.getComputedStyle(el), '--lg-glass-thickness', 1),\n        0.1,\n        4,\n      );\n\n      const next = {\n        // A supersampled copy already has the resolution the map needs.\n        ...buildCapsuleLensMapDataUrl({\n          devicePixelRatio: supersample > 1 ? 1 : window.devicePixelRatio || 1,\n          height: height * supersample,\n          thickness,\n          width: width * supersample,\n        }),\n        dispersion: clamp(dispersion * thickness, 0, 1),\n      };\n\n      setMap((previous) =>\n        previous &&\n        previous.href === next.href &&\n        previous.metrics.depth === next.metrics.depth &&\n        previous.dispersion === next.dispersion\n          ? previous\n          : next,\n      );\n    };\n\n    const schedule = () => {\n      if (!frame) frame = requestAnimationFrame(measure);\n    };\n\n    const observer = new ResizeObserver(schedule);\n    observer.observe(el);\n    schedule();\n\n    return () => {\n      disposed = true;\n      cancelAnimationFrame(frame);\n      observer.disconnect();\n    };\n  }, [dispersion, enabled, signature, supersample, surfaceRef]);\n\n  // Blue reaches furthest; leave enough content beyond the rim for it and the blur. The\n  // filter works in the copy's supersampled pixels; the margin is returned in CSS pixels,\n  // rounded up to a whole one so the scaled copy lands on the knob without a sliver.\n  const blur = MAGNIFIER_BLUR * supersample;\n\n  const scaledMargin = map\n    ? Math.ceil(\n        (map.metrics.depth * (1 + map.dispersion / 2) + blur * 3 + 2 * supersample) / supersample,\n      ) * supersample\n    : 0;\n\n  const filterElement = useMemo(() => {\n    if (!map) return null;\n\n    const { depth, height, width } = map.metrics;\n    const margin = scaledMargin;\n\n    return (\n      <svg aria-hidden=\"true\" className=\"lg-refraction-filter\" focusable=\"false\" viewBox=\"0 0 0 0\">\n        <defs>\n          <filter\n            id={filterId}\n            x={-margin}\n            y={-margin}\n            width={width + margin * 4}\n            height={height + margin * 4}\n            filterUnits=\"userSpaceOnUse\"\n            primitiveUnits=\"userSpaceOnUse\"\n            colorInterpolationFilters=\"sRGB\"\n          >\n            <feGaussianBlur in=\"SourceGraphic\" stdDeviation={blur} result=\"blurred\" />\n            <feImage\n              href={map.href}\n              x={margin}\n              y={margin}\n              width={width}\n              height={height}\n              preserveAspectRatio=\"none\"\n              result=\"bend\"\n            />\n            {/* The map's blue channel softens only the scene the rim bends. */}\n            <feColorMatrix\n              in=\"bend\"\n              type=\"matrix\"\n              values=\"0 0 0 0 0  0 0 0 0 0  0 0 0 0 0  0 0 1 0 0\"\n              result=\"rim\"\n            />\n            <feComposite in=\"blurred\" in2=\"rim\" operator=\"in\" result=\"softRim\" />\n            <feComposite in=\"softRim\" in2=\"SourceGraphic\" operator=\"over\" result=\"soft\" />\n            {refractColours('soft', 'bend', depth * 2, map.dispersion)}\n          </filter>\n        </defs>\n      </svg>\n    );\n  }, [blur, filterId, map, scaledMargin]);\n\n  return {\n    active: map !== null,\n    filterElement,\n    filterStyle: map ? `url(#${filterId})` : undefined,\n    margin: scaledMargin / supersample,\n    supersample,\n  };\n}\n",
      "type": "registry:hook",
      "target": "components/glassyui/lib/use-refraction-filter.tsx"
    },
    {
      "path": "registry/glassyui/lib/scene-context.ts",
      "content": "'use client';\n\nimport { createContext, useContext, useLayoutEffect } from 'react';\nimport type { RefObject } from 'react';\n\nexport type GlassSceneRegistry = {\n  elements: ReadonlySet<HTMLElement>;\n  register: (element: HTMLElement) => () => void;\n  subscribe: (listener: () => void) => () => void;\n};\n\n// The registry exists before any effect runs, because children register in\n// their effects and those run before the scene's own effect.\nexport function createGlassSceneRegistry(): GlassSceneRegistry {\n  const elements = new Set<HTMLElement>();\n  const listeners = new Set<() => void>();\n  const notify = () => listeners.forEach((listener) => listener());\n\n  return {\n    elements,\n    register(element) {\n      elements.add(element);\n      notify();\n\n      return () => {\n        elements.delete(element);\n        notify();\n      };\n    },\n    subscribe(listener) {\n      listeners.add(listener);\n\n      return () => {\n        listeners.delete(listener);\n      };\n    },\n  };\n}\n\nexport const GlassSceneContext = createContext<GlassSceneRegistry | null>(null);\n\n/**\n * Lets a glass element hand its material to the nearest GlassScene. Outside a\n * scene it does nothing. It registers before paint, so glass that mounts into\n * a live scene never shows its CSS material first.\n */\nexport function useGlassScenePane(ref: RefObject<HTMLElement | null>, enabled = true) {\n  const registry = useContext(GlassSceneContext);\n\n  useLayoutEffect(() => {\n    const element = ref.current;\n\n    if (!registry || !enabled || !element) return;\n\n    return registry.register(element);\n  }, [enabled, ref, registry]);\n}\n",
      "type": "registry:lib",
      "target": "components/glassyui/lib/scene-context.ts"
    },
    {
      "path": "registry/glassyui/glass-panel.tsx",
      "content": "'use client';\n\nimport clsx from 'clsx';\nimport { forwardRef } from 'react';\nimport type { HTMLAttributes, ReactNode } from 'react';\nimport { GlassSurface } from './glass-surface';\nimport type { RefractionBackgroundSpace } from './glass-surface';\n\ntype PanelVariant = 'panel' | 'card' | 'pill';\n\ntype PanelElevation = 'base' | 'raised';\n\ntype PanelRefraction = 'none' | 'soft' | 'strong';\n\ntype PanelPreset = 'subtle' | 'standard' | 'prominent' | 'control' | 'showcase';\n\nexport type GlassPanelProps = HTMLAttributes<HTMLDivElement> & {\n  variant?: PanelVariant;\n  elevation?: PanelElevation;\n  /** Brightens the surface a touch on hover. */\n  interactive?: boolean;\n  /** Chromium edge lens over the frost. On by default for control and showcase presets. */\n  lens?: boolean;\n  preset?: PanelPreset;\n  refraction?: PanelRefraction;\n  refractionBackground?: ReactNode;\n  refractionBackgroundSpace?: RefractionBackgroundSpace;\n  refractionDisplacement?: number;\n  /** How thick the glass is, as a multiple of regular. See GlassSurface. */\n  thickness?: number;\n};\n\n// Shape, spacing and elevation live in liquid.css, below Tailwind utilities.\nconst VARIANT_CLASS: Record<PanelVariant, string> = {\n  panel: 'lg-panel--panel',\n  card: 'lg-panel--card',\n  pill: 'lg-panel--pill',\n};\n\nexport const GlassPanel = forwardRef<HTMLDivElement, GlassPanelProps>(\n  (\n    {\n      className,\n      variant = 'panel',\n      elevation = 'base',\n      interactive = false,\n      lens,\n      preset = variant === 'pill' ? 'control' : 'standard',\n      refraction = preset === 'showcase' ? 'strong' : 'none',\n      refractionBackground,\n      refractionBackgroundSpace,\n      refractionDisplacement,\n      ...rest\n    },\n    forwardedRef,\n  ) => {\n    return (\n      <GlassSurface\n        ref={forwardedRef}\n        interactive={interactive}\n        lens={lens}\n        preset={preset}\n        refraction={refraction}\n        refractionBackground={refractionBackground}\n        refractionBackgroundSpace={refractionBackgroundSpace}\n        refractionDisplacement={refractionDisplacement}\n        className={clsx(\n          VARIANT_CLASS[variant],\n          elevation === 'raised' && 'lg-panel--raised',\n          className,\n        )}\n        {...rest}\n      />\n    );\n  },\n);\n\nGlassPanel.displayName = 'GlassPanel';\n",
      "type": "registry:ui",
      "target": "components/glassyui/glass-panel.tsx"
    },
    {
      "path": "registry/glassyui/glass-accordion.tsx",
      "content": "'use client';\n\nimport * as AccordionPrimitive from '@radix-ui/react-accordion';\nimport clsx from 'clsx';\nimport { GlassPanel } from './glass-panel';\n\nconst radixSlotProps = { asChild: true };\n\nexport const GlassAccordion = AccordionPrimitive.Root;\n\nexport const GlassAccordionItem = AccordionPrimitive.Item;\n\nexport function GlassAccordionTrigger(\n  props: React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Trigger>,\n) {\n  const { className, children, ...rest } = props;\n\n  return (\n    <AccordionPrimitive.Header>\n      <AccordionPrimitive.Trigger\n        {...rest}\n        className={clsx('lg-button lg-accordion-trigger', className)}\n      >\n        <span>{children}</span>\n        <svg\n          viewBox=\"0 0 20 20\"\n          className=\"lg-accordion-chevron h-4 w-4 text-[var(--lg-muted-foreground)]\"\n          aria-hidden\n        >\n          <path\n            d=\"M5 7.5l5 5 5-5\"\n            fill=\"none\"\n            stroke=\"currentColor\"\n            strokeWidth=\"1.6\"\n            strokeLinecap=\"round\"\n            strokeLinejoin=\"round\"\n          />\n        </svg>\n      </AccordionPrimitive.Trigger>\n    </AccordionPrimitive.Header>\n  );\n}\n\nexport function GlassAccordionContent(\n  props: React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Content>,\n) {\n  const { className, children, ...rest } = props;\n\n  return (\n    <AccordionPrimitive.Content {...rest} {...radixSlotProps}>\n      <GlassPanel\n        variant=\"card\"\n        elevation=\"base\"\n        refraction=\"soft\"\n        className={clsx('lg-accordion-content', className)}\n      >\n        {children}\n      </GlassPanel>\n    </AccordionPrimitive.Content>\n  );\n}\n",
      "type": "registry:ui",
      "target": "components/glassyui/glass-accordion.tsx"
    },
    {
      "path": "registry/glassyui/glass-avatar.tsx",
      "content": "import * as AvatarPrimitive from '@radix-ui/react-avatar';\nimport clsx from 'clsx';\nimport { Children, forwardRef } from 'react';\nimport type { HTMLAttributes, ReactNode } from 'react';\n\nexport type GlassAvatarSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl';\n\nexport type GlassAvatarStatus = 'online' | 'away' | 'busy' | 'offline';\n\nexport type GlassAvatarProps = Omit<HTMLAttributes<HTMLSpanElement>, 'children'> & {\n  /** Describes the image. Defaults to `name`. */\n  alt?: string;\n  /** Shown when there is no image or it fails to load. Defaults to the initials of `name`. */\n  fallback?: ReactNode;\n  /** Names the person. Its initials fill in for a missing image and pick the colour. */\n  name?: string;\n  size?: GlassAvatarSize;\n  src?: string;\n  /** A presence dot on the corner. */\n  status?: GlassAvatarStatus;\n};\n\n// The number of colours the stylesheet defines for initials.\nconst TONES = 8;\n\nfunction initialsOf(name: string) {\n  const words = name.trim().split(/\\s+/).filter(Boolean);\n\n  if (words.length === 0) return '';\n\n  const first = Array.from(words[0])[0] ?? '';\n  const last = words.length > 1 ? (Array.from(words[words.length - 1])[0] ?? '') : '';\n\n  return `${first}${last}`.toUpperCase();\n}\n\n// The same name always gets the same colour.\nfunction toneOf(name: string) {\n  let hash = 0;\n\n  for (const character of name) hash = (hash * 31 + (character.codePointAt(0) ?? 0)) >>> 0;\n\n  return hash % TONES;\n}\n\n/** A round photo that falls back to coloured initials. */\nexport const GlassAvatar = forwardRef<HTMLSpanElement, GlassAvatarProps>(\n  ({ alt, className, fallback, name, size = 'md', src, status, ...props }, forwardedRef) => {\n    const described = [alt ?? name, status].filter(Boolean).join(', ');\n\n    return (\n      <span\n        aria-label={described || undefined}\n        role={described ? 'img' : undefined}\n        {...props}\n        ref={forwardedRef}\n        className={clsx('lg-avatar', className)}\n        data-size={size}\n        data-status={status}\n      >\n        <AvatarPrimitive.Root className=\"lg-avatar-face\">\n          {src ? <AvatarPrimitive.Image alt=\"\" className=\"lg-avatar-image\" src={src} /> : null}\n          <AvatarPrimitive.Fallback\n            aria-hidden\n            className=\"lg-avatar-fallback\"\n            data-tone={name ? toneOf(name) : undefined}\n          >\n            {fallback ?? (name ? initialsOf(name) : null)}\n          </AvatarPrimitive.Fallback>\n        </AvatarPrimitive.Root>\n        {status ? <span aria-hidden className=\"lg-avatar-status\" /> : null}\n      </span>\n    );\n  },\n);\n\nGlassAvatar.displayName = 'GlassAvatar';\n\nexport type GlassAvatarGroupProps = HTMLAttributes<HTMLDivElement> & {\n  /** Shows this many avatars, then a \"+N\" for the rest. */\n  max?: number;\n  /** Sizes every avatar in the group. */\n  size?: GlassAvatarSize;\n};\n\n/** Avatars stacked edge to edge, each cut away where the next one overlaps it. */\nexport const GlassAvatarGroup = forwardRef<HTMLDivElement, GlassAvatarGroupProps>(\n  ({ children, className, max, size = 'md', ...props }, forwardedRef) => {\n    const items = Children.toArray(children);\n    const shown = max === undefined ? items : items.slice(0, Math.max(0, max));\n    const hidden = items.length - shown.length;\n\n    return (\n      <div\n        role=\"group\"\n        {...props}\n        ref={forwardedRef}\n        className={clsx('lg-avatar-group', className)}\n        data-size={size}\n      >\n        {shown}\n        {hidden > 0 ? (\n          <span aria-label={`${hidden} more`} className=\"lg-avatar\" data-size={size} role=\"img\">\n            <span aria-hidden className=\"lg-avatar-face lg-avatar-more\">\n              +{hidden}\n            </span>\n          </span>\n        ) : null}\n      </div>\n    );\n  },\n);\n\nGlassAvatarGroup.displayName = 'GlassAvatarGroup';\n",
      "type": "registry:ui",
      "target": "components/glassyui/glass-avatar.tsx"
    },
    {
      "path": "registry/glassyui/glass-badge.tsx",
      "content": "import './styles/liquid.css';\n\nimport clsx from 'clsx';\nimport { forwardRef } from 'react';\nimport type { HTMLAttributes } from 'react';\n\nexport type GlassBadgeTone = 'neutral' | 'blue' | 'green' | 'orange' | 'red' | 'purple';\n\nexport type GlassBadgeProps = HTMLAttributes<HTMLSpanElement> & {\n  /** Leading status dot in the tone colour. */\n  dot?: boolean;\n  tone?: GlassBadgeTone;\n};\n\nexport const GlassBadge = forwardRef<HTMLSpanElement, GlassBadgeProps>(\n  ({ children, className, dot = false, tone = 'neutral', ...props }, forwardedRef) => (\n    <span ref={forwardedRef} data-tone={tone} className={clsx('lg-badge', className)} {...props}>\n      {dot ? <span aria-hidden className=\"lg-badge-dot\" /> : null}\n      {children}\n    </span>\n  ),\n);\n\nGlassBadge.displayName = 'GlassBadge';\n",
      "type": "registry:ui",
      "target": "components/glassyui/glass-badge.tsx"
    },
    {
      "path": "registry/glassyui/glass-button.tsx",
      "content": "'use client';\n\nimport { Slot, Slottable } from '@radix-ui/react-slot';\nimport clsx from 'clsx';\nimport {\n  cloneElement,\n  forwardRef,\n  isValidElement,\n  use,\n  useCallback,\n  useEffect,\n  useMemo,\n  useRef,\n} from 'react';\nimport type { CSSProperties, ReactNode } from 'react';\nimport { mergeRefs } from './lib/merge-refs';\nimport { useGlassScenePane } from './lib/scene-context';\nimport { useLensFilter } from './lib/use-refraction-filter';\nimport { useOptionalPreferences } from './glass-provider';\n\nexport type ButtonVariant = 'primary' | 'prominent' | 'ghost' | 'soft';\n\nexport type ButtonSize = 'sm' | 'md' | 'lg';\n\ntype ButtonPreset = 'control' | 'showcase';\n\nexport interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n  /** Renders the single child element, such as a link, with the button's material. Links cannot be disabled. */\n  asChild?: boolean;\n  /** Chromium edge lens over the frost. On by default for filled variants. */\n  lens?: boolean;\n  preset?: ButtonPreset;\n  variant?: ButtonVariant;\n  size?: ButtonSize;\n}\n\nconst VARIANT_CLASS: Record<ButtonVariant, string> = {\n  primary: 'lg-button--primary',\n  prominent: 'lg-button--prominent',\n  ghost: 'lg-button--ghost',\n  soft: 'lg-button--soft',\n};\n\nconst SIZE_CLASS: Record<ButtonSize, string> = {\n  sm: 'lg-button--sm',\n  md: 'lg-button--md',\n  lg: 'lg-button--lg',\n};\n\nconst REACT_LAZY = Symbol.for('react.lazy');\n\n// A server component's element can reach a client component as a lazy reference, which React 19\n// does in development; its payload is the chunk the element arrives in, a kind of Promise. Slot\n// unwraps one before slotting it, so the label has to as well.\nfunction isLazyNode(node: unknown): node is { _payload: Promise<ReactNode> } {\n  return (\n    node instanceof Object &&\n    '$$typeof' in node &&\n    node.$$typeof === REACT_LAZY &&\n    '_payload' in node &&\n    node._payload instanceof Promise\n  );\n}\n\n// The label sits above the material layers, so a slotted child's content moves into it.\nfunction withLabel(children: ReactNode) {\n  if (!isValidElement<{ children?: ReactNode }>(children)) return children;\n\n  return cloneElement(\n    children,\n    undefined,\n    <span className=\"lg-button__label\">{children.props.children}</span>,\n  );\n}\n\nexport const GlassButton = forwardRef<HTMLButtonElement, ButtonProps>(\n  (\n    {\n      asChild = false,\n      className,\n      preset = 'control',\n      variant = 'primary',\n      lens = variant !== 'ghost',\n      size = 'md',\n      type,\n      disabled = false,\n      onPointerLeave,\n      onPointerCancel,\n      onPointerDown,\n      onPointerUp,\n      onBlur,\n      onKeyDown,\n      onKeyUp,\n      style,\n      children,\n      ...rest\n    },\n    forwardedRef,\n  ) => {\n    const { preferences } = useOptionalPreferences();\n    const reduceMotion = Boolean(preferences?.reduceMotion);\n    const reduceTransparency = Boolean(preferences?.reduceTransparency);\n    const buttonRef = useRef<HTMLButtonElement | null>(null);\n    const bloomRef = useRef<HTMLSpanElement | null>(null);\n    const ref = useMemo(() => mergeRefs(forwardedRef, buttonRef), [forwardedRef]);\n\n    const releasePress = useCallback((target: HTMLButtonElement) => {\n      target.style.setProperty('--lg-press', '0');\n      target.dataset.pressed = 'false';\n    }, []);\n\n    // A press lights the glass from the point it lands and the light spreads\n    // outward, as it does through Apple's glass under a fingertip.\n    const bloom = useCallback(\n      (target: HTMLElement, x: number, y: number) => {\n        const element = bloomRef.current;\n\n        if (!element || reduceMotion) return;\n\n        element.style.setProperty('--lg-bloom-x', `${x}px`);\n        element.style.setProperty('--lg-bloom-y', `${y}px`);\n        element.style.setProperty(\n          '--lg-bloom-size',\n          `${Math.max(target.offsetWidth, target.offsetHeight) * 2.4}px`,\n        );\n        element.animate?.(\n          [\n            { opacity: 0, transform: 'scale(0.08)' },\n            { opacity: 1, transform: 'scale(0.42)', offset: 0.16 },\n            { opacity: 0, transform: 'scale(1)' },\n          ],\n          { duration: 720, easing: 'cubic-bezier(0.22, 0.8, 0.3, 1)' },\n        );\n      },\n      [reduceMotion],\n    );\n\n    const handlePointerLeave = useCallback(\n      (event: React.PointerEvent<HTMLButtonElement>) => {\n        onPointerLeave?.(event);\n        event.currentTarget.releasePointerCapture?.(event.pointerId);\n        releasePress(event.currentTarget);\n      },\n      [onPointerLeave, releasePress],\n    );\n\n    const handlePointerCancel = useCallback(\n      (event: React.PointerEvent<HTMLButtonElement>) => {\n        onPointerCancel?.(event);\n        event.currentTarget.releasePointerCapture?.(event.pointerId);\n        releasePress(event.currentTarget);\n      },\n      [onPointerCancel, releasePress],\n    );\n\n    const handlePointerDown = useCallback(\n      (event: React.PointerEvent<HTMLButtonElement>) => {\n        onPointerDown?.(event);\n\n        if (event.defaultPrevented || disabled) return;\n        const target = event.currentTarget;\n        const bounds = target.getBoundingClientRect();\n        // A scaled button maps client pixels back to its own, so the bloom starts under the finger.\n        const scale = bounds.width / Math.max(target.offsetWidth, 1) || 1;\n\n        target.setPointerCapture?.(event.pointerId);\n        target.style.setProperty('--lg-press', '1');\n        target.dataset.pressed = 'true';\n        bloom(target, (event.clientX - bounds.left) / scale, (event.clientY - bounds.top) / scale);\n      },\n      [bloom, disabled, onPointerDown],\n    );\n\n    const handlePointerUp = useCallback(\n      (event: React.PointerEvent<HTMLButtonElement>) => {\n        onPointerUp?.(event);\n        event.currentTarget.releasePointerCapture?.(event.pointerId);\n        event.currentTarget.style.setProperty('--lg-press', '0');\n        event.currentTarget.dataset.pressed = 'false';\n      },\n      [onPointerUp],\n    );\n\n    const handleBlur = useCallback(\n      (event: React.FocusEvent<HTMLButtonElement>) => {\n        onBlur?.(event);\n        releasePress(event.currentTarget);\n      },\n      [onBlur, releasePress],\n    );\n\n    const handleKeyDown = useCallback(\n      (event: React.KeyboardEvent<HTMLButtonElement>) => {\n        onKeyDown?.(event);\n\n        if (event.defaultPrevented || disabled) return;\n\n        if (event.key === ' ' || event.key === 'Enter') {\n          const target = event.currentTarget;\n\n          target.style.setProperty('--lg-press', '1');\n          target.dataset.pressed = 'true';\n\n          if (!event.repeat) bloom(target, target.offsetWidth / 2, target.offsetHeight / 2);\n        }\n      },\n      [bloom, disabled, onKeyDown],\n    );\n\n    const handleKeyUp = useCallback(\n      (event: React.KeyboardEvent<HTMLButtonElement>) => {\n        onKeyUp?.(event);\n\n        if (event.key === ' ' || event.key === 'Enter') {\n          event.currentTarget.style.setProperty('--lg-press', '0');\n          event.currentTarget.dataset.pressed = 'false';\n        }\n      },\n      [onKeyUp],\n    );\n\n    // A button disabled mid-press lets go of it.\n    useEffect(() => {\n      if (disabled && buttonRef.current) releasePress(buttonRef.current);\n    }, [disabled, releasePress]);\n\n    // Inside a GlassScene the canvas draws this glass. Ghost buttons have none.\n    useGlassScenePane(buttonRef, variant !== 'ghost');\n\n    const lensFilter = useLensFilter(buttonRef, {\n      enabled: lens && !disabled && !reduceTransparency,\n      signature: `${preferences?.theme}:${preferences?.mode}:${preferences?.quality}:${preferences?.thickness}`,\n    });\n\n    // Without this, the client renders a lazy child's content outside the label: it sinks under\n    // the material layers, and hydration fails.\n    const slotted = asChild && isLazyNode(children) ? use(children._payload) : children;\n\n    const Component = asChild ? Slot : 'button';\n\n    return (\n      <Component\n        {...rest}\n        ref={ref}\n        type={asChild ? type : (type ?? 'button')}\n        disabled={asChild ? undefined : disabled}\n        className={clsx('lg-button', VARIANT_CLASS[variant], SIZE_CLASS[size], className)}\n        data-lg-lens={lensFilter.active ? 'active' : undefined}\n        data-lg-preset={preset}\n        style={\n          // SAFETY: CSSProperties has no custom-property index; this adds one string-valued property.\n          lensFilter.filterStyle\n            ? ({ ...style, '--lg-lens-filter': lensFilter.filterStyle } as CSSProperties)\n            : style\n        }\n        onPointerLeave={handlePointerLeave}\n        onPointerCancel={handlePointerCancel}\n        onPointerDown={handlePointerDown}\n        onPointerUp={handlePointerUp}\n        onBlur={handleBlur}\n        onKeyDown={handleKeyDown}\n        onKeyUp={handleKeyUp}\n        data-pressed=\"false\"\n      >\n        <span className=\"lg-button__layers\" aria-hidden=\"true\">\n          {lensFilter.filterElement}\n          <span className=\"lg-button__light\" />\n          <span className=\"lg-button__distortion\" />\n          <span className=\"lg-button__tint\" />\n          <span className=\"lg-button__shine\" />\n          <span ref={bloomRef} className=\"lg-button__bloom\" />\n          <span className=\"lg-button__rim\" />\n        </span>\n        {asChild ? (\n          <Slottable>{withLabel(slotted)}</Slottable>\n        ) : (\n          <span className=\"lg-button__label\">{children}</span>\n        )}\n      </Component>\n    );\n  },\n);\n\nGlassButton.displayName = 'GlassButton';\n",
      "type": "registry:ui",
      "target": "components/glassyui/glass-button.tsx"
    },
    {
      "path": "registry/glassyui/glass-header.tsx",
      "content": "'use client';\n\nimport clsx from 'clsx';\nimport { forwardRef, useLayoutEffect, useMemo, useRef, useState } from 'react';\nimport type { HTMLAttributes, ReactNode, RefObject } from 'react';\nimport {\n  createFrameLoop,\n  createSpring,\n  motionReduced,\n  retuneSpring,\n  stepSpring,\n} from './lib/liquid-motion';\nimport { mergeRefs } from './lib/merge-refs';\nimport { GlassSurface } from './glass-surface';\nimport './styles/header.css';\n\nexport type GlassHeaderProps = HTMLAttributes<HTMLElement> & {\n  /** A wordmark or logo, usually linked to the home page. */\n  brand: ReactNode;\n  /** Buttons or links at the end of the capsule. */\n  actions?: ReactNode;\n  /**\n   * Opens out across the top of the page without glass, and condenses into the capsule once\n   * the page scrolls. Fixed headers only.\n   */\n  condenseOnScroll?: boolean;\n  /** Accessible name for the desktop and mobile navigation. */\n  navigationLabel?: string;\n  /** Fixed above the page by default; static keeps it in the surrounding layout. */\n  position?: 'fixed' | 'static';\n};\n\n// The header condenses once the page has scrolled past this many CSS pixels, and opens again\n// only when it is back at the top, so it never flickers on the threshold.\nconst CONDENSE_AFTER = 8;\n\nconst OPEN_WITHIN = 1;\n\ntype Feel = readonly [response: number, bounce: number];\n\n// Condensing, the glass forms at once, before a fast scroll can carry the page under bare\n// links, and the capsule gathers in behind it, settling with a slight squeeze. Opening, the bar\n// spreads out without overshoot while its glass thins a little more slowly, so the material is\n// seen to stretch before it goes.\nconst GATHER: Feel = [0.56, 0.22];\n\nconst FORM: Feel = [0.24, 0];\n\nconst SPREAD: Feel = [0.44, 0];\n\nconst THIN: Feel = [0.5, 0];\n\n/**\n * Springs the header between the open bar at the top of the page and the capsule. It writes\n * --lg-header-spread (1 open, 0 capsule) and --lg-header-material (0 no glass, 1 glass) while\n * it moves; at rest the data-condensed state sets both. Reduced motion jumps. Until this runs,\n * the state is unknown and CSS follows the scroll position on its own.\n */\nfunction useCondensing(headerRef: RefObject<HTMLElement | null>, enabled: boolean) {\n  const [condensed, setCondensed] = useState<boolean | null>(null);\n  const [moving, setMoving] = useState(false);\n\n  useLayoutEffect(() => {\n    const header = headerRef.current;\n\n    if (!enabled || !header) return;\n\n    const spread = createSpring(...SPREAD, 1);\n    const material = createSpring(...THIN, 0);\n    let target: boolean | null = null;\n\n    const paint = () => {\n      header.style.setProperty('--lg-header-spread', spread.value.toFixed(4));\n      header.style.setProperty(\n        '--lg-header-material',\n        Math.min(Math.max(material.value, 0), 1).toFixed(4),\n      );\n    };\n\n    const clear = () => {\n      header.style.removeProperty('--lg-header-spread');\n      header.style.removeProperty('--lg-header-material');\n    };\n\n    const loop = createFrameLoop((dt) => {\n      const reduced = motionReduced();\n      const spreading = stepSpring(spread, dt, reduced);\n      const forming = stepSpring(material, dt, reduced);\n\n      if (spreading || forming) {\n        paint();\n\n        return true;\n      }\n\n      clear();\n      setMoving(false);\n\n      return false;\n    });\n\n    const update = (animate: boolean) => {\n      const scrolled = window.scrollY;\n      const next = target ? scrolled > OPEN_WITHIN : scrolled > CONDENSE_AFTER;\n\n      if (next === target) return;\n\n      target = next;\n      spread.target = next ? 0 : 1;\n      material.target = next ? 1 : 0;\n      retuneSpring(spread, ...(next ? GATHER : SPREAD));\n      retuneSpring(material, ...(next ? FORM : THIN));\n      setCondensed(next);\n\n      if (animate && !motionReduced()) {\n        // A jump or a fling can carry the page further than the header reaches before it\n        // condenses. The glass is then there at once, so the links never sit bare on content;\n        // only the shape gathers in.\n        if (next && scrolled > header.getBoundingClientRect().bottom) {\n          material.value = 1;\n          material.velocity = 0;\n        }\n\n        // Pins the current shape inline before the new state's values apply.\n        paint();\n        setMoving(true);\n        loop.start();\n\n        return;\n      }\n\n      loop.stop();\n\n      for (const spring of [spread, material]) {\n        spring.value = spring.target;\n        spring.velocity = 0;\n      }\n\n      clear();\n      setMoving(false);\n    };\n\n    // A page that opens partway down, or returns there, starts condensed without moving.\n    update(false);\n\n    const onScroll = () => update(true);\n\n    window.addEventListener('scroll', onScroll, { passive: true });\n\n    return () => {\n      window.removeEventListener('scroll', onScroll);\n      loop.stop();\n      clear();\n      setMoving(false);\n    };\n  }, [enabled, headerRef]);\n\n  return { condensed, moving };\n}\n\nexport const GlassHeader = forwardRef<HTMLElement, GlassHeaderProps>(\n  (\n    {\n      brand,\n      actions,\n      children,\n      className,\n      condenseOnScroll = false,\n      navigationLabel = 'Primary',\n      position = 'fixed',\n      ...rest\n    },\n    forwardedRef,\n  ) => {\n    const headerRef = useRef<HTMLElement | null>(null);\n    const ref = useMemo(() => mergeRefs(headerRef, forwardedRef), [forwardedRef]);\n    const condensing = condenseOnScroll && position === 'fixed';\n    const { condensed, moving } = useCondensing(headerRef, condensing);\n\n    return (\n      <header\n        ref={ref}\n        className={clsx('lg-header', className)}\n        data-condense-on-scroll={condensing ? '' : undefined}\n        data-condensed={condensing && condensed !== null ? String(condensed) : undefined}\n        data-position={position}\n        {...rest}\n      >\n        {/* The lens map is drawn for one size, so a condensing header bends light only once its\n            capsule has settled; it frosts while the shape moves. */}\n        <GlassSurface\n          aria-hidden\n          className=\"lg-header-glass\"\n          lens={!condensing || (condensed === true && !moving)}\n          preset=\"standard\"\n        />\n        <div className=\"lg-header-bar\">\n          <div className=\"lg-header-brand\">{brand}</div>\n          {children ? (\n            <>\n              <nav aria-label={navigationLabel} className=\"lg-header-links lg-header-desktop\">\n                {children}\n              </nav>\n              <details\n                className=\"lg-header-menu\"\n                onKeyDown={(event) => {\n                  if (event.key === 'Escape' && event.currentTarget.open) {\n                    event.preventDefault();\n                    event.currentTarget.open = false;\n                    event.currentTarget.querySelector('summary')?.focus();\n                  }\n                }}\n              >\n                <summary>Menu</summary>\n                <nav\n                  aria-label={navigationLabel}\n                  className=\"lg-header-links lg-header-menu-links\"\n                  onClick={(event) => {\n                    if (event.target instanceof Element && event.target.closest('a[href]')) {\n                      const menu = event.currentTarget.closest('details');\n\n                      if (menu) {\n                        menu.open = false;\n                        menu.querySelector('summary')?.focus();\n                      }\n                    }\n                  }}\n                >\n                  {children}\n                </nav>\n              </details>\n            </>\n          ) : null}\n          {actions ? <div className=\"lg-header-actions\">{actions}</div> : null}\n        </div>\n      </header>\n    );\n  },\n);\n\nGlassHeader.displayName = 'GlassHeader';\n",
      "type": "registry:ui",
      "target": "components/glassyui/glass-header.tsx"
    },
    {
      "path": "registry/glassyui/lib/liquid-motion.ts",
      "content": "'use client';\n\nimport { useLayoutEffect } from 'react';\nimport type { RefObject } from 'react';\n\nexport type Spring = {\n  value: number;\n  velocity: number;\n  target: number;\n  stiffness: number;\n  damping: number;\n  precision: number;\n};\n\n/*\n * Springs take a response and a bounce: response is the period of the\n * undamped oscillation in seconds, and bounce 0 is critically damped. For\n * unit mass that is stiffness (2π / response)² and damping\n * 4π (1 - bounce) / response.\n */\nexport const createSpring = (\n  response: number,\n  bounce: number,\n  value: number,\n  precision = 0.001,\n): Spring => ({\n  value,\n  velocity: 0,\n  target: value,\n  stiffness: ((2 * Math.PI) / response) ** 2,\n  damping: (4 * Math.PI * (1 - bounce)) / response,\n  precision,\n});\n\n// Changes how a spring moves without stopping it, so it carries its velocity\n// into the new motion.\nexport const retuneSpring = (spring: Spring, response: number, bounce: number) => {\n  spring.stiffness = ((2 * Math.PI) / response) ** 2;\n  spring.damping = (4 * Math.PI * (1 - bounce)) / response;\n};\n\n// Semi-implicit Euler in steps of at most 1/120 s is stable for every spring\n// here. Returns whether the spring is still moving.\nexport const stepSpring = (spring: Spring, dt: number, snap: boolean) => {\n  if (snap || (spring.value === spring.target && spring.velocity === 0)) {\n    spring.value = spring.target;\n    spring.velocity = 0;\n\n    return false;\n  }\n\n  const steps = Math.max(1, Math.ceil(dt * 120));\n  const step = dt / steps;\n\n  for (let index = 0; index < steps; index += 1) {\n    spring.velocity +=\n      (-spring.stiffness * (spring.value - spring.target) - spring.damping * spring.velocity) *\n      step;\n    spring.value += spring.velocity * step;\n  }\n\n  if (\n    Math.abs(spring.value - spring.target) < spring.precision &&\n    Math.abs(spring.velocity) < spring.precision * 10\n  ) {\n    spring.value = spring.target;\n    spring.velocity = 0;\n\n    return false;\n  }\n\n  return true;\n};\n\nlet motionQuery: MediaQueryList | undefined;\n\n// The provider mirrors its preference onto <html>; the system setting always\n// counts, as it does in liquid.css.\nexport function motionReduced() {\n  motionQuery ??= window.matchMedia('(prefers-reduced-motion: reduce)');\n\n  return (\n    document.documentElement.getAttribute('data-lg-reduce-motion') === '1' || motionQuery.matches\n  );\n}\n\nexport type FrameLoop = {\n  start: () => void;\n  stop: () => void;\n};\n\n// Calls step once a frame with the seconds since the last one until it\n// returns false. A long pause counts as one short frame.\nexport function createFrameLoop(step: (dt: number) => boolean): FrameLoop {\n  let frame = 0;\n  let last = 0;\n\n  const tick = (now: number) => {\n    const dt = last ? Math.min((now - last) / 1000, 1 / 20) : 1 / 60;\n\n    last = now;\n    frame = 0;\n\n    if (step(dt)) {\n      frame = requestAnimationFrame(tick);\n\n      return;\n    }\n\n    last = 0;\n  };\n\n  return {\n    start() {\n      if (!frame) frame = requestAnimationFrame(tick);\n    },\n    stop() {\n      cancelAnimationFrame(frame);\n      frame = 0;\n      last = 0;\n    },\n  };\n}\n\ntype Edge = 'left' | 'top' | 'right' | 'bottom';\n\ntype Box = Record<Edge, number>;\n\ntype Feel = readonly [response: number, bounce: number];\n\nconst EDGES: readonly Edge[] = ['left', 'top', 'right', 'bottom'];\n\n// The edge heading for the new item leads and the far edge follows, so the\n// bubble stretches into a drop on the way and rounds off when it lands. The\n// leading edge overshoots a little and rings back, which is what makes the\n// landing feel like a drop settling rather than a slide stopping.\nconst LEAD: Feel = [0.2, 0.32];\n\nconst TRAIL: Feel = [0.3, 0.12];\n\nconst EVEN: Feel = [0.26, 0.22];\n\n// Under a finger the bubble keeps up closely but still leans into the drag.\nconst DRAG_LEAD: Feel = [0.1, 0.12];\n\nconst DRAG_TRAIL: Feel = [0.18, 0.04];\n\n// How far a lifted bubble grows past its item, in CSS pixels. It never grows\n// past the control's own edge. Kept to a hair: more reads as the bubble\n// zooming out of its track.\nconst SWELL = 1;\n\nconst DRAG_THRESHOLD = 4;\n\n// The bubble counts as travelling, and stays lifted, while an edge moves faster\n// than this in CSS pixels a second, so it settles the moment it slows down.\nconst TRAVEL_SPEED = 90;\n\n// How far a press on another item wakes the bubble before it moves.\nconst ANTICIPATION = 0.5;\n\n// Measure before the containing plane is projected. Client rectangles describe the projected\n// bounding box, which cannot be scaled back into a rectangle once an ancestor turns in 3D.\nexport function localRect(element: HTMLElement, root: HTMLElement) {\n  const size = (node: HTMLElement, style: CSSStyleDeclaration) => {\n    const borderBox = style.boxSizing === 'border-box';\n    const width = parseFloat(style.width);\n    const height = parseFloat(style.height);\n\n    return {\n      width: Number.isFinite(width)\n        ? width +\n          (borderBox\n            ? 0\n            : parseFloat(style.paddingLeft) +\n              parseFloat(style.paddingRight) +\n              parseFloat(style.borderLeftWidth) +\n              parseFloat(style.borderRightWidth))\n        : node.offsetWidth,\n      height: Number.isFinite(height)\n        ? height +\n          (borderBox\n            ? 0\n            : parseFloat(style.paddingTop) +\n              parseFloat(style.paddingBottom) +\n              parseFloat(style.borderTopWidth) +\n              parseFloat(style.borderBottomWidth))\n        : node.offsetHeight,\n    };\n  };\n\n  const elementStyle = getComputedStyle(element);\n  const dimensions = size(element, elementStyle);\n  let matrix = new DOMMatrix();\n\n  for (let node: HTMLElement | null = element; node && node !== root;) {\n    const style = node === element ? elementStyle : getComputedStyle(node);\n    const parent: Element | null = node.offsetParent;\n    const { width, height } = size(node, style);\n\n    const length = (value: string, extent: number) =>\n      value.endsWith('%') ? (parseFloat(value) * extent) / 100 : parseFloat(value) || 0;\n\n    const origin = style.transformOrigin.split(' ');\n    const translate = style.translate.split(' ');\n    const scale = style.scale === 'none' ? [1, 1] : style.scale.split(' ').map(Number);\n\n    const left =\n      style.position === 'absolute' && style.left !== 'auto'\n        ? parseFloat(style.left)\n        : node.offsetLeft;\n\n    const top =\n      style.position === 'absolute' && style.top !== 'auto'\n        ? parseFloat(style.top)\n        : node.offsetTop;\n\n    const borderX =\n      parent instanceof HTMLElement && parent !== root ? parent.clientLeft - parent.scrollLeft : 0;\n\n    const borderY =\n      parent instanceof HTMLElement && parent !== root ? parent.clientTop - parent.scrollTop : 0;\n\n    const x = length(origin[0], width);\n    const y = length(origin[1], height);\n\n    const transform = new DOMMatrix()\n      .translate(left + borderX, top + borderY)\n      .translate(x, y)\n      .translate(length(translate[0], width), length(translate[1] ?? '0', height))\n      .scale(scale[0], scale[1] ?? scale[0])\n      .multiply(new DOMMatrix(style.transform === 'none' ? undefined : style.transform))\n      .translate(-x, -y);\n\n    matrix = transform.multiply(matrix);\n    node = parent instanceof HTMLElement ? parent : null;\n  }\n\n  const points = [\n    [0, 0],\n    [dimensions.width, 0],\n    [dimensions.width, dimensions.height],\n    [0, dimensions.height],\n  ].map(([x, y]) => new DOMPoint(x, y).matrixTransform(matrix));\n\n  const left = Math.min(...points.map((point) => point.x));\n  const top = Math.min(...points.map((point) => point.y));\n\n  return {\n    left,\n    top,\n    width: Math.max(...points.map((point) => point.x)) - left,\n    height: Math.max(...points.map((point) => point.y)) - top,\n  };\n}\n\nfunction boxWithin(element: HTMLElement, frame: HTMLElement): Box {\n  const { left, top, width, height } = localRect(element, frame);\n\n  return { left, top, right: left + width, bottom: top + height };\n}\n\n// Four zero-size points give the browser's actual projection, including perspective. Only a\n// drag needs these; the static bubble and glass never need to read projected geometry.\nfunction pointerPlane(element: HTMLElement) {\n  const probes = [\n    [0, 0],\n    [100, 0],\n    [100, 100],\n    [0, 100],\n  ].map(([x, y]) => {\n    const probe = document.createElement('span');\n    probe.ariaHidden = 'true';\n    probe.style.cssText = `position:absolute;left:${x}%;top:${y}%;width:0;height:0;visibility:hidden;pointer-events:none;`;\n    element.append(probe);\n\n    return probe;\n  });\n\n  return {\n    x(clientX: number, clientY: number) {\n      const [p0, p1, p2, p3] = probes.map((probe) => probe.getBoundingClientRect());\n\n      const dx1 = p1.x - p2.x,\n        dx2 = p3.x - p2.x,\n        dx3 = p0.x - p1.x + p2.x - p3.x;\n\n      const dy1 = p1.y - p2.y,\n        dy2 = p3.y - p2.y,\n        dy3 = p0.y - p1.y + p2.y - p3.y;\n\n      const determinant = dx1 * dy2 - dx2 * dy1;\n      const g = (dx3 * dy2 - dx2 * dy3) / determinant;\n      const h = (dx1 * dy3 - dx3 * dy1) / determinant;\n      const a = p1.x - p0.x + g * p1.x - clientX * g;\n      const b = p3.x - p0.x + h * p3.x - clientX * h;\n      const d = p1.y - p0.y + g * p1.y - clientY * g;\n      const e = p3.y - p0.y + h * p3.y - clientY * h;\n      const x = ((clientX - p0.x) * e - b * (clientY - p0.y)) / (a * e - b * d);\n\n      return x * element.clientWidth + element.scrollLeft;\n    },\n    destroy: () => probes.forEach((probe) => probe.remove()),\n  };\n}\n\nconst clamp = (value: number, min: number, max: number) => Math.min(max, Math.max(min, value));\n\nexport type LiquidIndicatorOptions = {\n  /** Matches the item the bubble sits under. */\n  selected: string;\n  /** Matches every item the bubble can move to. */\n  item: string;\n  /** Lets a pointer pick the bubble up and drop it on another item. */\n  draggable?: boolean;\n  /** Strength of the bubble's stretch and lift. */\n  deformation?: number;\n};\n\n/**\n * Moves a selection bubble between items like a glass droplet: it\n * lifts, stretches toward the new item and lands with a little bounce.\n * Labels stay fixed while the bubble moves. CSS places the bubble until this\n * runs. Reduced motion jumps instead.\n */\nexport function useLiquidIndicator(\n  rootRef: RefObject<HTMLElement | null>,\n  indicatorRef: RefObject<HTMLElement | null>,\n  { selected, item, draggable = false, deformation = 1 }: LiquidIndicatorOptions,\n) {\n  useLayoutEffect(() => {\n    const root = rootRef.current;\n    const indicator = indicatorRef.current;\n\n    if (!root || !indicator) return;\n\n    const edges: Record<Edge, Spring> = {\n      left: createSpring(...EVEN, 0, 0.05),\n      top: createSpring(...EVEN, 0, 0.05),\n      right: createSpring(...EVEN, 0, 0.05),\n      bottom: createSpring(...EVEN, 0, 0.05),\n    };\n\n    const lift = createSpring(0.22, 0.2, 0);\n    let items: HTMLElement[] = [];\n    let centres: number[] = [];\n    let room = 0;\n    let placed = false;\n    let held: Element | null = null;\n    let drag: { pointer: number; startX: number; offset: number; active: boolean } | null = null;\n    let plane: ReturnType<typeof pointerPlane> | null = null;\n\n    const frameOf = () =>\n      indicator.offsetParent instanceof HTMLElement ? indicator.offsetParent : root;\n\n    const paint = () => {\n      const width = edges.right.value - edges.left.value;\n      const height = edges.bottom.value - edges.top.value;\n      const restWidth = Math.max(edges.right.target - edges.left.target, 1);\n      const restHeight = Math.max(edges.bottom.target - edges.top.target, 1);\n      // A stretched drop keeps its volume, so it thins across its travel.\n      const thinY = clamp(1 / Math.sqrt(Math.max(width / restWidth, 1)), 0.8, 1);\n      const thinX = clamp(1 / Math.sqrt(Math.max(height / restHeight, 1)), 0.8, 1);\n      // A spring that rings past rest must not lift the bubble below its resting size.\n      const raised = Math.max(lift.value, 0) * deformation;\n      const swell = raised * Math.min(room, SWELL);\n      const drawnWidth = restWidth + (width * thinX - restWidth) * deformation + swell * 2;\n      const drawnHeight = restHeight + (height * thinY - restHeight) * deformation + swell * 2;\n      const centreX = (edges.left.value + edges.right.value) / 2;\n      const centreY = (edges.top.value + edges.bottom.value) / 2;\n\n      indicator.style.translate = `${centreX - drawnWidth / 2}px ${centreY - drawnHeight / 2}px`;\n      indicator.style.width = `${drawnWidth}px`;\n      indicator.style.height = `${drawnHeight}px`;\n      indicator.style.setProperty('--lg-lift', raised.toFixed(3));\n    };\n\n    const step = (dt: number) => {\n      const reduced = motionReduced();\n      const travelling = EDGES.some((edge) => Math.abs(edges[edge].velocity) > TRAVEL_SPEED);\n      const pressed = held?.matches(selected) ?? false;\n      const woken = held !== null ? ANTICIPATION : 0;\n\n      lift.target = reduced ? 0 : pressed || drag?.active || travelling ? 1 : woken;\n      let moving = false;\n\n      for (const edge of EDGES) {\n        moving = stepSpring(edges[edge], dt, reduced) || moving;\n      }\n\n      moving = stepSpring(lift, dt, reduced) || moving;\n      paint();\n\n      return moving;\n    };\n\n    const loop = createFrameLoop(step);\n\n    const current = (): Box => ({\n      left: edges.left.value,\n      top: edges.top.value,\n      right: edges.right.value,\n      bottom: edges.bottom.value,\n    });\n\n    // Tunes each axis so the edge in front leads and the one behind trails.\n    const lean = (from: Box, to: Box, lead: Feel, trail: Feel) => {\n      const axes: [Edge, Edge, number][] = [\n        ['left', 'right', (to.left + to.right - from.left - from.right) / 2],\n        ['top', 'bottom', (to.top + to.bottom - from.top - from.bottom) / 2],\n      ];\n\n      for (const [start, end, distance] of axes) {\n        if (Math.abs(distance) < 1) {\n          retuneSpring(edges[start], ...EVEN);\n          retuneSpring(edges[end], ...EVEN);\n        } else {\n          retuneSpring(edges[distance > 0 ? end : start], ...lead);\n          retuneSpring(edges[distance > 0 ? start : end], ...trail);\n        }\n      }\n    };\n\n    const aim = (to: Box, jump: boolean) => {\n      for (const edge of EDGES) {\n        edges[edge].target = to[edge];\n\n        if (jump) {\n          edges[edge].value = to[edge];\n          edges[edge].velocity = 0;\n        }\n      }\n    };\n\n    const sync = (snap: boolean) => {\n      const frame = frameOf();\n      const target = root.querySelector<HTMLElement>(selected);\n\n      // Only a drag needs every item's centre; ordinary tabs measure their selected item.\n      items = draggable\n        ? Array.from(root.querySelectorAll<HTMLElement>(item))\n        : target\n          ? [target]\n          : [];\n\n      const boxes = items.map((element) => boxWithin(element, frame));\n\n      centres = boxes.map((box) => (box.left + box.right) / 2);\n\n      // A pointer owns the bubble until it lets go.\n      if (drag?.active) return;\n\n      if (!target) {\n        indicator.setAttribute('data-lg-empty', '');\n        placed = false;\n\n        return;\n      }\n\n      const targetIndex = items.indexOf(target);\n      const box = targetIndex < 0 ? boxWithin(target, frame) : boxes[targetIndex];\n      const jump = snap || !placed || motionReduced();\n\n      indicator.removeAttribute('data-lg-empty');\n      room = Math.max(0, Math.min(box.top, frame.clientHeight - box.bottom));\n\n      if (!jump) lean(current(), box, LEAD, TRAIL);\n\n      aim(box, jump);\n      placed = true;\n\n      if (jump) paint();\n\n      loop.start();\n    };\n\n    const follow = (event: PointerEvent) => {\n      if (!drag || !plane || centres.length === 0) return;\n\n      const width = edges.right.target - edges.left.target;\n\n      const centre = clamp(\n        plane.x(event.clientX, event.clientY) - drag.offset,\n        Math.min(...centres),\n        Math.max(...centres),\n      );\n\n      const from = current();\n      const to = { ...from, left: centre - width / 2, right: centre + width / 2 };\n\n      lean(from, to, DRAG_LEAD, DRAG_TRAIL);\n      aim({ ...to, top: edges.top.target, bottom: edges.bottom.target }, motionReduced());\n      loop.start();\n    };\n\n    // Drops a dragged bubble on the nearest enabled item, or puts it back.\n    const release = (commit: boolean) => {\n      if (!drag) return;\n\n      const { active, pointer } = drag;\n\n      drag = null;\n      plane?.destroy();\n      plane = null;\n      held = null;\n      root.removeAttribute('data-lg-dragging');\n\n      if (root.hasPointerCapture(pointer)) root.releasePointerCapture(pointer);\n\n      if (active && commit) {\n        const centre = (edges.left.target + edges.right.target) / 2;\n        let nearest = -1;\n\n        centres.forEach((value, index) => {\n          if (items[index].matches('[data-disabled]')) return;\n\n          if (nearest < 0 || Math.abs(value - centre) < Math.abs(centres[nearest] - centre))\n            nearest = index;\n        });\n\n        if (nearest >= 0) {\n          if (root.contains(document.activeElement)) items[nearest].focus({ preventScroll: true });\n\n          items[nearest].click();\n        }\n      }\n\n      sync(false);\n    };\n\n    const onPointerDown = (event: PointerEvent) => {\n      if (!event.isPrimary || event.button !== 0 || !(event.target instanceof Element)) return;\n\n      const pressed = event.target.closest(item);\n\n      if (\n        !(pressed instanceof HTMLElement) ||\n        !root.contains(pressed) ||\n        pressed.matches('[data-disabled]')\n      )\n        return;\n\n      held = pressed;\n      loop.start();\n\n      if (!draggable || !pressed.matches(selected)) return;\n\n      const centre = (edges.left.target + edges.right.target) / 2;\n      plane = pointerPlane(frameOf());\n\n      drag = {\n        pointer: event.pointerId,\n        startX: event.clientX,\n        offset: plane.x(event.clientX, event.clientY) - centre,\n        active: false,\n      };\n    };\n\n    const onPointerMove = (event: PointerEvent) => {\n      if (!drag || event.pointerId !== drag.pointer) return;\n\n      if (!drag.active) {\n        if (Math.abs(event.clientX - drag.startX) < DRAG_THRESHOLD) return;\n\n        drag.active = true;\n        root.setAttribute('data-lg-dragging', '');\n        root.setPointerCapture(event.pointerId);\n      }\n\n      follow(event);\n    };\n\n    // Listens on the window, so a press that ends outside the control still ends.\n    const onPointerUp = (event: PointerEvent) => {\n      if (drag && event.pointerId === drag.pointer) {\n        release(event.type === 'pointerup');\n\n        return;\n      }\n\n      if (!held) return;\n\n      held = null;\n      loop.start();\n    };\n\n    // Taking the pointer from a touched item fires this on the item; only the\n    // root losing it ends a drag.\n    const onLostCapture = (event: PointerEvent) => {\n      if (event.target === root && drag?.active && event.pointerId === drag.pointer) release(false);\n    };\n\n    const resizes = new ResizeObserver(() => sync(true));\n\n    const observeSizes = () => {\n      resizes.disconnect();\n      resizes.observe(root);\n      root.querySelectorAll<HTMLElement>(item).forEach((element) => resizes.observe(element));\n    };\n\n    const mutations = new MutationObserver((records) => {\n      if (records.some((record) => record.type === 'childList')) observeSizes();\n\n      sync(false);\n    });\n\n    root.setAttribute('data-lg-indicator', 'ready');\n    sync(true);\n    observeSizes();\n    mutations.observe(root, {\n      attributes: true,\n      attributeFilter: ['data-state', 'data-disabled'],\n      childList: true,\n      subtree: true,\n    });\n    root.addEventListener('pointerdown', onPointerDown);\n    root.addEventListener('pointermove', onPointerMove);\n    root.addEventListener('lostpointercapture', onLostCapture);\n    window.addEventListener('pointerup', onPointerUp);\n    window.addEventListener('pointercancel', onPointerUp);\n\n    return () => {\n      loop.stop();\n      plane?.destroy();\n      mutations.disconnect();\n      resizes.disconnect();\n      root.removeEventListener('pointerdown', onPointerDown);\n      root.removeEventListener('pointermove', onPointerMove);\n      root.removeEventListener('lostpointercapture', onLostCapture);\n      window.removeEventListener('pointerup', onPointerUp);\n      window.removeEventListener('pointercancel', onPointerUp);\n      root.removeAttribute('data-lg-indicator');\n      root.removeAttribute('data-lg-dragging');\n      indicator.removeAttribute('data-lg-empty');\n      ['translate', 'width', 'height', '--lg-lift'].forEach((property) =>\n        indicator.style.removeProperty(property),\n      );\n    };\n  }, [deformation, draggable, indicatorRef, item, rootRef, selected]);\n}\n",
      "type": "registry:lib",
      "target": "components/glassyui/lib/liquid-motion.ts"
    },
    {
      "path": "registry/glassyui/styles/header.css",
      "content": "@layer components {\n  /* A slab of glass floating clear of the page, with its menu outside the\n     material's paint clip. Container queries also fit embedded headers. */\n  .lg-header {\n    position: fixed;\n    inset: 14px 0 auto;\n    z-index: 40;\n    box-sizing: border-box;\n    width: min(920px, calc(100vw - 32px));\n    height: 56px;\n    margin-inline: auto;\n    border-radius: 999px;\n    color: var(--lg-foreground);\n    container-type: inline-size;\n  }\n\n  .lg-header[data-position='static'] {\n    position: relative;\n    inset: auto;\n    z-index: auto;\n    width: 100%;\n    max-width: 920px;\n  }\n\n  /* Frosted as lightly as the other slabs, so the page shows through and bends\n     at the rim. The --lg-header-* tint and dimming keep the links legible. */\n  .lg-header > .lg-header-glass {\n    --lg-panel-radius: 999px;\n    --lg-glass-blur: calc(var(--lg-slab-blur) * 1px);\n    --lg-lens-blur: var(--lg-slab-blur);\n    --lg-lens-body-brightness: var(--lg-header-brightness);\n    --lg-lens-rim-brightness: var(--lg-header-rim-brightness);\n    --lg-glass-contrast: 1;\n    --lg-glass-sat: 1.5;\n    --lg-glass-brightness: var(--lg-header-brightness);\n    --lg-panel-elevation-shadow:\n      0 2px 4px -2px rgb(52 62 84 / 0.18), 0 4px 14px -3px rgb(52 62 84 / 0.2);\n    position: absolute;\n    inset: 0;\n    height: 100%;\n    pointer-events: none;\n  }\n\n  .lg-header > .lg-header-glass::before {\n    background-color: var(--lg-header-tint);\n  }\n\n  /* A condensing header opens out across the top of the page with no glass and gathers into\n     the capsule once the page scrolls. GlassHeader springs --lg-header-spread (1 open, 0 the\n     capsule) and --lg-header-material (the glass, 0 to 1) while it moves; at rest its\n     data-condensed state sets them. The open bar is never narrower than the capsule, so the\n     links stay on one side of the menu breakpoint throughout. */\n  .lg-header[data-condense-on-scroll] {\n    --lg-header-spread: 1;\n    --lg-header-material: 0;\n    --lg-header-capsule-width: min(920px, calc(100vw - 32px));\n    --lg-header-bar-width: max(var(--lg-header-capsule-width), min(1200px, calc(100% - 48px)));\n  }\n\n  .lg-header[data-condensed='true'] {\n    --lg-header-spread: 0;\n    --lg-header-material: 1;\n  }\n\n  .lg-header[data-position='fixed'][data-condense-on-scroll] {\n    width: calc(\n      var(--lg-header-capsule-width) +\n        (var(--lg-header-bar-width) - var(--lg-header-capsule-width)) * var(--lg-header-spread)\n    );\n  }\n\n  /* Before the script runs, as on a page opened at an anchor, the scroll position alone picks\n     the shape: a custom property animates discretely, so it switches halfway, 8px down. */\n  @supports (animation-timeline: scroll()) {\n    .lg-header[data-condense-on-scroll]:not([data-condensed]) {\n      animation: lg-header-condensed linear both;\n      animation-timeline: scroll(root);\n      animation-range: 0px 16px;\n    }\n  }\n\n  @keyframes lg-header-condensed {\n    to {\n      --lg-header-spread: 0;\n      --lg-header-material: 1;\n    }\n  }\n\n  /* The glass fades on its own layers, never on an ancestor: an ancestor's opacity would cut\n     the frost off from the page it bends. The spring sets the shadow every frame, so the\n     surface's own shadow transition stays out of its way. */\n  .lg-header[data-condense-on-scroll] > .lg-header-glass {\n    --lg-panel-elevation-shadow:\n      0 2px 4px -2px rgb(52 62 84 / calc(0.18 * var(--lg-header-material))),\n      0 4px 14px -3px rgb(52 62 84 / calc(0.2 * var(--lg-header-material)));\n    transition: none;\n  }\n\n  .lg-header[data-condense-on-scroll] > .lg-header-glass::before,\n  .lg-header[data-condense-on-scroll] > .lg-header-glass::after {\n    opacity: var(--lg-header-material);\n  }\n\n  .lg-header[data-condense-on-scroll] > .lg-header-glass > .lg-noise {\n    opacity: calc(var(--lg-noise-alpha) * var(--lg-header-material));\n  }\n\n  /* The forced-colours outline edges the glass, so it goes with it: the open bar has none.\n     Increased contrast edges it with the ring above, which fades with the glass. */\n  @media (forced-colors: active) {\n    .lg-header[data-condense-on-scroll] > .lg-header-glass {\n      outline-width: calc(1px * var(--lg-header-material)) !important;\n    }\n  }\n\n  /* A small button at the end sits as far from the rim as from the top and bottom, so it nests\n     in the capsule's curve, and the brand starts as far in as that button's label. */\n  .lg-header-bar {\n    position: relative;\n    display: flex;\n    align-items: center;\n    gap: 16px;\n    height: 100%;\n    padding: 0 12px 0 24px;\n  }\n\n  .lg-header-brand {\n    flex: none;\n    min-width: 0;\n    margin-inline-end: auto;\n    font-size: 18px;\n    font-weight: 600;\n    line-height: 1;\n    letter-spacing: -0.03em;\n    white-space: nowrap;\n  }\n\n  .lg-header-brand a {\n    color: inherit;\n    text-decoration: none;\n  }\n\n  .lg-header-links {\n    display: flex;\n    align-items: center;\n    justify-content: center;\n    gap: 2px;\n  }\n\n  .lg-header-desktop {\n    margin-inline: auto;\n  }\n\n  .lg-header-links a {\n    display: inline-flex;\n    align-items: center;\n    justify-content: center;\n    height: 38px;\n    padding: 0 12px;\n    border-radius: 999px;\n    color: var(--lg-muted-foreground);\n    font-size: 15px;\n    font-weight: 500;\n    line-height: 1;\n    letter-spacing: -0.01em;\n    text-decoration: none;\n    white-space: nowrap;\n    transition:\n      color var(--lg-motion-duration) ease,\n      background-color var(--lg-motion-duration) ease;\n  }\n\n  /* Colour alone marks hover and the current page in the bar: a fill would lay a pale patch\n     over the glass and whatever the page shows through it. The opaque menu keeps its fill. */\n  .lg-header-links a:hover,\n  .lg-header-links a[aria-current='page'] {\n    color: var(--lg-foreground);\n  }\n\n  .lg-header :is(a, summary):focus-visible {\n    outline: 2px solid var(--lg-focus-ring);\n    outline-offset: 2px;\n  }\n\n  .lg-header-actions {\n    display: flex;\n    flex: none;\n    align-items: center;\n    gap: 4px;\n  }\n\n  .lg-header-menu {\n    display: none;\n  }\n\n  .lg-header-menu summary {\n    display: flex;\n    align-items: center;\n    justify-content: center;\n    height: 40px;\n    padding: 0 12px;\n    border-radius: 999px;\n    font-size: 14px;\n    font-weight: 500;\n    cursor: pointer;\n    list-style: none;\n    user-select: none;\n  }\n\n  .lg-header-menu summary::-webkit-details-marker {\n    display: none;\n  }\n\n  .lg-header-menu-links {\n    position: absolute;\n    top: calc(100% + 8px);\n    right: 10px;\n    z-index: 1;\n    flex-direction: column;\n    align-items: stretch;\n    box-sizing: border-box;\n    width: min(240px, calc(100cqw - 20px));\n    max-height: calc(100dvh - 96px);\n    overflow-y: auto;\n    padding: 8px;\n    border: 1px solid var(--lg-border);\n    border-radius: 20px;\n    background: var(--lg-opaque-surface);\n    box-shadow: var(--lg-shadow-raised);\n  }\n\n  .lg-header-menu-links a {\n    justify-content: flex-start;\n    height: 44px;\n    padding: 0 16px;\n    border-radius: 12px;\n  }\n\n  .lg-header-menu-links a:hover,\n  .lg-header-menu-links a[aria-current='page'] {\n    background: var(--lg-control-surface);\n  }\n\n  .lg-header-menu:not([open]) > nav {\n    display: none;\n  }\n\n  @container (max-width: 780px) {\n    .lg-header-bar {\n      gap: 8px;\n    }\n\n    .lg-header-desktop {\n      display: none;\n    }\n\n    .lg-header-menu {\n      display: block;\n    }\n  }\n\n  /* The narrowest phones close up the items and the margins, so the bar still fits and an icon\n     button at the end still nests in the curve. */\n  @container (max-width: 320px) {\n    .lg-header-bar {\n      gap: 4px;\n      padding: 0 10px 0 20px;\n    }\n  }\n\n  @media (max-width: 700px) {\n    .lg-header[data-position='fixed'] {\n      top: 8px;\n      width: calc(100vw - 20px);\n    }\n\n    /* On a phone the open bar reaches the screen's edges and the capsule draws in from them. */\n    .lg-header[data-condense-on-scroll] {\n      --lg-header-capsule-width: calc(100vw - 20px);\n      --lg-header-bar-width: 100%;\n    }\n  }\n}\n",
      "type": "registry:file",
      "target": "components/glassyui/styles/header.css"
    },
    {
      "path": "registry/glassyui/glass-kbd.tsx",
      "content": "import clsx from 'clsx';\nimport { forwardRef } from 'react';\nimport type { HTMLAttributes } from 'react';\n\n/** A keycap. Put one key, or a symbol such as ⌘, in each. */\nexport const GlassKbd = forwardRef<HTMLElement, HTMLAttributes<HTMLElement>>(\n  ({ className, ...props }, forwardedRef) => (\n    <kbd {...props} ref={forwardedRef} className={clsx('lg-kbd', className)} />\n  ),\n);\n\nGlassKbd.displayName = 'GlassKbd';\n\n/** Sets a shortcut's keys side by side. */\nexport const GlassKbdGroup = forwardRef<HTMLSpanElement, HTMLAttributes<HTMLSpanElement>>(\n  ({ className, ...props }, forwardedRef) => (\n    <span {...props} ref={forwardedRef} className={clsx('lg-kbd-group', className)} />\n  ),\n);\n\nGlassKbdGroup.displayName = 'GlassKbdGroup';\n",
      "type": "registry:ui",
      "target": "components/glassyui/glass-kbd.tsx"
    },
    {
      "path": "registry/glassyui/glass-menu.tsx",
      "content": "'use client';\n\nimport * as MenuPrimitive from '@radix-ui/react-dropdown-menu';\nimport clsx from 'clsx';\nimport { forwardRef, useMemo, useRef } from 'react';\nimport type { HTMLAttributes } from 'react';\nimport { mergeRefs } from './lib/merge-refs';\nimport { GlassPanel } from './glass-panel';\n\nconst radixSlotProps = { asChild: true };\n\n/**\n * Menus are non-modal by default, like the WAI-ARIA menu button: the page stays in the\n * accessibility tree and keeps its scroll, while Radix still blocks Tab inside the open\n * menu and closes it when focus leaves. Pass `modal` to lock the page instead.\n */\nexport function GlassMenu({\n  modal = false,\n  ...props\n}: React.ComponentProps<typeof MenuPrimitive.Root>) {\n  return <MenuPrimitive.Root modal={modal} {...props} />;\n}\n\nexport const GlassMenuTrigger = MenuPrimitive.Trigger;\n\nexport const GlassMenuGroup = MenuPrimitive.Group;\n\nexport const GlassMenuRadioGroup = MenuPrimitive.RadioGroup;\n\nexport const GlassMenuSub = MenuPrimitive.Sub;\n\nexport type GlassMenuContentProps = React.ComponentPropsWithoutRef<typeof MenuPrimitive.Content> & {\n  /** How thick the glass is, as a multiple of regular. See GlassSurface. */\n  thickness?: number;\n};\n\nexport const GlassMenuContent = forwardRef<HTMLDivElement, GlassMenuContentProps>(\n  ({ children, className, onInteractOutside, sideOffset = 8, ...props }, forwardedRef) => {\n    const contentRef = useRef<HTMLDivElement | null>(null);\n    const ref = useMemo(() => mergeRefs(contentRef, forwardedRef), [forwardedRef]);\n\n    return (\n      <MenuPrimitive.Portal>\n        <MenuPrimitive.Content\n          ref={ref}\n          sideOffset={sideOffset}\n          {...props}\n          onInteractOutside={(event) => {\n            onInteractOutside?.(event);\n\n            const content = contentRef.current;\n            const triggerId = content?.getAttribute('aria-labelledby');\n\n            if (!content || !triggerId) return;\n\n            const trigger = content.ownerDocument.getElementById(triggerId);\n\n            // The trigger already toggles the menu. Its closing layer stays mounted for the\n            // exit animation and must not dismiss the same pointer click that reopens it.\n            if (event.target instanceof Node && trigger?.contains(event.target)) {\n              event.preventDefault();\n            }\n          }}\n          {...radixSlotProps}\n        >\n          <GlassPanel\n            elevation=\"raised\"\n            lens\n            preset=\"prominent\"\n            refraction=\"none\"\n            variant=\"card\"\n            className={clsx('lg-menu-content', className)}\n          >\n            {children}\n          </GlassPanel>\n        </MenuPrimitive.Content>\n      </MenuPrimitive.Portal>\n    );\n  },\n);\n\nGlassMenuContent.displayName = 'GlassMenuContent';\n\nexport type GlassMenuItemProps = React.ComponentPropsWithoutRef<typeof MenuPrimitive.Item> & {\n  /** Leaves room for a check or radio indicator so labels line up. */\n  inset?: boolean;\n  tone?: 'default' | 'destructive';\n};\n\nexport const GlassMenuItem = forwardRef<HTMLDivElement, GlassMenuItemProps>(\n  ({ className, inset = false, tone = 'default', ...props }, forwardedRef) => (\n    <MenuPrimitive.Item\n      ref={forwardedRef}\n      data-tone={tone}\n      className={clsx('lg-menu-item', inset && 'lg-menu-item--inset', className)}\n      {...props}\n    />\n  ),\n);\n\nGlassMenuItem.displayName = 'GlassMenuItem';\n\nexport const GlassMenuCheckboxItem = forwardRef<\n  HTMLDivElement,\n  React.ComponentPropsWithoutRef<typeof MenuPrimitive.CheckboxItem>\n>(({ children, className, ...props }, forwardedRef) => (\n  <MenuPrimitive.CheckboxItem\n    ref={forwardedRef}\n    className={clsx('lg-menu-item lg-menu-item--inset', className)}\n    {...props}\n  >\n    <MenuPrimitive.ItemIndicator className=\"lg-menu-indicator\">\n      <svg viewBox=\"0 0 16 16\" aria-hidden>\n        <path\n          d=\"M3.5 8.5l3 3 6-7\"\n          fill=\"none\"\n          stroke=\"currentColor\"\n          strokeLinecap=\"round\"\n          strokeLinejoin=\"round\"\n          strokeWidth=\"1.8\"\n        />\n      </svg>\n    </MenuPrimitive.ItemIndicator>\n    {children}\n  </MenuPrimitive.CheckboxItem>\n));\n\nGlassMenuCheckboxItem.displayName = 'GlassMenuCheckboxItem';\n\nexport const GlassMenuRadioItem = forwardRef<\n  HTMLDivElement,\n  React.ComponentPropsWithoutRef<typeof MenuPrimitive.RadioItem>\n>(({ children, className, ...props }, forwardedRef) => (\n  <MenuPrimitive.RadioItem\n    ref={forwardedRef}\n    className={clsx('lg-menu-item lg-menu-item--inset', className)}\n    {...props}\n  >\n    <MenuPrimitive.ItemIndicator className=\"lg-menu-indicator\">\n      <svg viewBox=\"0 0 16 16\" aria-hidden>\n        <circle cx=\"8\" cy=\"8\" r=\"3.25\" fill=\"currentColor\" />\n      </svg>\n    </MenuPrimitive.ItemIndicator>\n    {children}\n  </MenuPrimitive.RadioItem>\n));\n\nGlassMenuRadioItem.displayName = 'GlassMenuRadioItem';\n\nexport const GlassMenuLabel = forwardRef<\n  HTMLDivElement,\n  React.ComponentPropsWithoutRef<typeof MenuPrimitive.Label>\n>(({ className, ...props }, forwardedRef) => (\n  <MenuPrimitive.Label ref={forwardedRef} className={clsx('lg-menu-label', className)} {...props} />\n));\n\nGlassMenuLabel.displayName = 'GlassMenuLabel';\n\nexport const GlassMenuSeparator = forwardRef<\n  HTMLDivElement,\n  React.ComponentPropsWithoutRef<typeof MenuPrimitive.Separator>\n>(({ className, ...props }, forwardedRef) => (\n  <MenuPrimitive.Separator\n    ref={forwardedRef}\n    className={clsx('lg-menu-separator', className)}\n    {...props}\n  />\n));\n\nGlassMenuSeparator.displayName = 'GlassMenuSeparator';\n\nexport function GlassMenuShortcut({ className, ...props }: HTMLAttributes<HTMLSpanElement>) {\n  return <span className={clsx('lg-menu-shortcut', className)} {...props} />;\n}\n\nexport const GlassMenuSubTrigger = forwardRef<\n  HTMLDivElement,\n  React.ComponentPropsWithoutRef<typeof MenuPrimitive.SubTrigger> & { inset?: boolean }\n>(({ children, className, inset = false, ...props }, forwardedRef) => (\n  <MenuPrimitive.SubTrigger\n    ref={forwardedRef}\n    className={clsx('lg-menu-item', inset && 'lg-menu-item--inset', className)}\n    {...props}\n  >\n    {children}\n    <svg viewBox=\"0 0 16 16\" aria-hidden className=\"lg-menu-chevron\">\n      <path\n        d=\"M6 3.5 10.5 8 6 12.5\"\n        fill=\"none\"\n        stroke=\"currentColor\"\n        strokeLinecap=\"round\"\n        strokeLinejoin=\"round\"\n        strokeWidth=\"1.6\"\n      />\n    </svg>\n  </MenuPrimitive.SubTrigger>\n));\n\nGlassMenuSubTrigger.displayName = 'GlassMenuSubTrigger';\n\nexport const GlassMenuSubContent = forwardRef<\n  HTMLDivElement,\n  React.ComponentPropsWithoutRef<typeof MenuPrimitive.SubContent>\n>(({ alignOffset = -6, children, className, sideOffset = 6, ...props }, forwardedRef) => (\n  <MenuPrimitive.Portal>\n    <MenuPrimitive.SubContent\n      ref={forwardedRef}\n      alignOffset={alignOffset}\n      sideOffset={sideOffset}\n      {...props}\n      {...radixSlotProps}\n    >\n      <GlassPanel\n        elevation=\"raised\"\n        preset=\"prominent\"\n        refraction=\"none\"\n        variant=\"card\"\n        className={clsx('lg-menu-content', className)}\n      >\n        {children}\n      </GlassPanel>\n    </MenuPrimitive.SubContent>\n  </MenuPrimitive.Portal>\n));\n\nGlassMenuSubContent.displayName = 'GlassMenuSubContent';\n",
      "type": "registry:ui",
      "target": "components/glassyui/glass-menu.tsx"
    },
    {
      "path": "registry/glassyui/glass-progress.tsx",
      "content": "'use client';\n\nimport clsx from 'clsx';\nimport { forwardRef, useId } from 'react';\nimport type { CSSProperties, HTMLAttributes, ReactNode } from 'react';\n\nexport type GlassProgressSize = 'sm' | 'md' | 'lg';\n\nexport type GlassProgressProps = Omit<HTMLAttributes<HTMLDivElement>, 'children'> & {\n  /** Text above the bar. It also names the bar for assistive technology. */\n  label?: ReactNode;\n  /** The value that means done. Defaults to 100. */\n  max?: number;\n  /** Shows the percentage beside the label. */\n  showValue?: boolean;\n  size?: GlassProgressSize;\n  /** How far along. Leave it out, or pass null, when the length is unknown. */\n  value?: number | null;\n};\n\n/**\n * A glass track with a fill that slides to its value. Without a value the fill sweeps\n * along, for work of unknown length.\n */\nexport const GlassProgress = forwardRef<HTMLDivElement, GlassProgressProps>(\n  (\n    {\n      'aria-label': ariaLabel,\n      'aria-labelledby': ariaLabelledBy,\n      className,\n      label,\n      max = 100,\n      showValue = false,\n      size = 'md',\n      value,\n      ...props\n    },\n    forwardedRef,\n  ) => {\n    const labelId = useId();\n    const known = value !== null && value !== undefined && Number.isFinite(value);\n    const clamped = known ? Math.min(Math.max(value, 0), max) : 0;\n    const percent = known && max > 0 ? (clamped / max) * 100 : 0;\n    const state = !known ? 'indeterminate' : percent >= 100 ? 'complete' : 'loading';\n\n    return (\n      <div\n        {...props}\n        ref={forwardedRef}\n        className={clsx('lg-progress', className)}\n        data-size={size}\n        data-state={state}\n      >\n        {label || (showValue && known) ? (\n          <div className=\"lg-progress-header\">\n            <span id={labelId}>{label}</span>\n            {showValue && known ? (\n              <span className=\"lg-progress-value\">{Math.round(percent)}%</span>\n            ) : null}\n          </div>\n        ) : null}\n        <div\n          aria-label={ariaLabel}\n          aria-labelledby={ariaLabelledBy ?? (label ? labelId : undefined)}\n          aria-valuemax={max}\n          aria-valuemin={0}\n          aria-valuenow={known ? clamped : undefined}\n          className=\"lg-progress-track\"\n          role=\"progressbar\"\n        >\n          <div\n            className=\"lg-progress-fill\"\n            // SAFETY: CSSProperties has no custom-property index; this adds one number-valued property.\n            style={{ '--lg-progress': percent } as CSSProperties}\n          />\n        </div>\n      </div>\n    );\n  },\n);\n\nGlassProgress.displayName = 'GlassProgress';\n",
      "type": "registry:ui",
      "target": "components/glassyui/glass-progress.tsx"
    },
    {
      "path": "registry/glassyui/glass-segmented-control.tsx",
      "content": "'use client';\n\nimport * as RadioGroupPrimitive from '@radix-ui/react-radio-group';\nimport clsx from 'clsx';\nimport { forwardRef, useMemo, useRef } from 'react';\nimport { useLiquidIndicator } from './lib/liquid-motion';\nimport { mergeRefs } from './lib/merge-refs';\nimport { GlassPanel } from './glass-panel';\n\nconst radixSlotProps = { asChild: true };\n\nexport type GlassSegmentedControlProps = React.ComponentPropsWithoutRef<\n  typeof RadioGroupPrimitive.Root\n>;\n\nconst INDICATOR = {\n  selected: '[role=\"radio\"][data-state=\"checked\"]',\n  item: '[role=\"radio\"]',\n  draggable: true,\n  deformation: 0.25,\n};\n\n/**\n * A single-choice control for two to six options. CSS places the indicator from the\n * checked item, so it is correct from the first server render; once scripts run it\n * moves like a drop of glass and can be dragged to another option.\n */\nexport const GlassSegmentedControl = forwardRef<HTMLDivElement, GlassSegmentedControlProps>(\n  ({ children, className, ...props }, forwardedRef) => {\n    const rootRef = useRef<HTMLDivElement | null>(null);\n    const indicatorRef = useRef<HTMLSpanElement | null>(null);\n    const ref = useMemo(() => mergeRefs(rootRef, forwardedRef), [forwardedRef]);\n\n    useLiquidIndicator(rootRef, indicatorRef, INDICATOR);\n\n    return (\n      <RadioGroupPrimitive.Root ref={ref} {...props} {...radixSlotProps}>\n        <GlassPanel\n          variant=\"pill\"\n          preset=\"control\"\n          refraction=\"none\"\n          className={clsx('lg-segmented', className)}\n        >\n          <span ref={indicatorRef} aria-hidden className=\"lg-segmented-indicator\" />\n          {children}\n        </GlassPanel>\n      </RadioGroupPrimitive.Root>\n    );\n  },\n);\n\nGlassSegmentedControl.displayName = 'GlassSegmentedControl';\n\nexport const GlassSegmentedControlItem = forwardRef<\n  HTMLButtonElement,\n  React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Item>\n>(({ className, ...props }, forwardedRef) => (\n  <RadioGroupPrimitive.Item\n    ref={forwardedRef}\n    className={clsx('lg-segmented-item', className)}\n    {...props}\n  />\n));\n\nGlassSegmentedControlItem.displayName = 'GlassSegmentedControlItem';\n",
      "type": "registry:ui",
      "target": "components/glassyui/glass-segmented-control.tsx"
    },
    {
      "path": "registry/glassyui/glass-switch.tsx",
      "content": "'use client';\n\nimport './styles/liquid.css';\n\nimport * as SwitchPrimitive from '@radix-ui/react-switch';\nimport clsx from 'clsx';\nimport { forwardRef, useEffect, useMemo, useRef } from 'react';\nimport type { CSSProperties } from 'react';\nimport { motionReduced } from './lib/liquid-motion';\nimport { mergeRefs } from './lib/merge-refs';\nimport { useCapsuleLensFilter } from './lib/use-refraction-filter';\nimport { useOptionalPreferences } from './glass-provider';\n\nexport type GlassSwitchProps = React.ComponentPropsWithoutRef<typeof SwitchPrimitive.Root> & {\n  size?: 'sm' | 'md';\n};\n\n// How long the knob stays glass after a flip, a little longer than its slide.\nconst TRAVEL_MS = 460;\n\n// The colour split at the knob's rim. A lens this small, drawn only while the knob is\n// touched or sliding, costs little, so it splits colour at every quality but low.\nconst KNOB_DISPERSION = 0.3;\n\n// The lens's copy is laid out at three times the knob's size and scaled back down, so\n// engines that filter at layout resolution still bend it smoothly.\nconst LENS_SUPERSAMPLE = 3;\n\nlet backdropCanvas: HTMLCanvasElement | null = null;\n\n// The colour behind an element: its ancestors' background colours laid over one another,\n// from the page down. Undefined when none of them is opaque.\nfunction backdropColour(element: HTMLElement) {\n  const colours: string[] = [];\n\n  for (let node = element.parentElement; node; node = node.parentElement) {\n    const colour = window.getComputedStyle(node).backgroundColor;\n\n    if (colour && colour !== 'transparent' && colour !== 'rgba(0, 0, 0, 0)') colours.push(colour);\n  }\n\n  backdropCanvas ??= document.createElement('canvas');\n  backdropCanvas.width = 1;\n  backdropCanvas.height = 1;\n\n  const context = backdropCanvas.getContext('2d', { willReadFrequently: true });\n\n  if (!context || colours.length === 0) return undefined;\n\n  for (const colour of colours.reverse()) {\n    context.fillStyle = colour;\n    context.fillRect(0, 0, 1, 1);\n  }\n\n  const [red, green, blue, alpha] = context.getImageData(0, 0, 1, 1).data;\n\n  return alpha === 255 ? `rgb(${red} ${green} ${blue})` : undefined;\n}\n\n// The knob swells into glass while pressed and stays that way while it slides to\n// its new side, then shrinks back; see .lg-switch in liquid.css. The glass\n// is a lens over a copy of the track and the colour behind the switch: it shows them a\n// little smaller, and they bend into the rim and split into colour there in every engine.\nexport const GlassSwitch = forwardRef<HTMLButtonElement, GlassSwitchProps>(\n  (\n    { className, disabled, size = 'md', onCheckedChange, onPointerDown, ...props },\n    forwardedRef,\n  ) => {\n    const { preferences } = useOptionalPreferences();\n    const rootRef = useRef<HTMLButtonElement | null>(null);\n    const thumbRef = useRef<HTMLSpanElement | null>(null);\n    const travel = useRef(0);\n    const ref = useMemo(() => mergeRefs(rootRef, forwardedRef), [forwardedRef]);\n\n    const lens = useCapsuleLensFilter(thumbRef, {\n      dispersion: KNOB_DISPERSION,\n      enabled: !disabled && !preferences.reduceTransparency && preferences.quality !== 'low',\n      signature: `${preferences.theme}:${preferences.quality}:${preferences.thickness}`,\n      supersample: LENS_SUPERSAMPLE,\n    });\n\n    useEffect(() => () => window.clearTimeout(travel.current), []);\n\n    // The lens hides the real track under the knob behind the colour around the switch,\n    // read as the knob turns to glass, since the page under it can change.\n    const readBackdrop = () => {\n      const root = rootRef.current;\n      const thumb = thumbRef.current;\n\n      if (!lens.active || !root || !thumb) return;\n\n      const colour = backdropColour(root);\n\n      if (colour) thumb.style.setProperty('--lg-switch-lens-backdrop', colour);\n      else thumb.style.removeProperty('--lg-switch-lens-backdrop');\n    };\n\n    const handlePointerDown = (event: React.PointerEvent<HTMLButtonElement>) => {\n      onPointerDown?.(event);\n      readBackdrop();\n    };\n\n    const handleCheckedChange = (checked: boolean) => {\n      onCheckedChange?.(checked);\n\n      const root = rootRef.current;\n\n      if (!root || motionReduced()) return;\n\n      readBackdrop();\n      window.clearTimeout(travel.current);\n      root.setAttribute('data-lg-moving', '');\n      travel.current = window.setTimeout(() => root.removeAttribute('data-lg-moving'), TRAVEL_MS);\n    };\n\n    return (\n      <SwitchPrimitive.Root\n        ref={ref}\n        data-size={size}\n        className={clsx('lg-switch', className)}\n        disabled={disabled}\n        onCheckedChange={handleCheckedChange}\n        onPointerDown={handlePointerDown}\n        {...props}\n      >\n        {lens.filterElement}\n        <SwitchPrimitive.Thumb\n          ref={thumbRef}\n          className=\"lg-switch-thumb\"\n          style={\n            // SAFETY: CSSProperties has no custom-property index; this adds two custom properties.\n            lens.active\n              ? ({\n                  '--lg-switch-lens-margin': `${lens.margin}px`,\n                  '--lg-switch-lens-scale': lens.supersample,\n                } as CSSProperties)\n              : undefined\n          }\n        >\n          {lens.active ? (\n            <span aria-hidden className=\"lg-switch-lens\">\n              <span className=\"lg-switch-lens-view\" style={{ filter: lens.filterStyle }}>\n                <span className=\"lg-switch-lens-scene\">\n                  <span className=\"lg-switch-lens-track\" />\n                </span>\n              </span>\n            </span>\n          ) : null}\n        </SwitchPrimitive.Thumb>\n      </SwitchPrimitive.Root>\n    );\n  },\n);\n\nGlassSwitch.displayName = 'GlassSwitch';\n",
      "type": "registry:ui",
      "target": "components/glassyui/glass-switch.tsx"
    },
    {
      "path": "registry/glassyui/glass-toast.tsx",
      "content": "'use client';\n\nimport * as ToastPrimitive from '@radix-ui/react-toast';\nimport clsx from 'clsx';\nimport { forwardRef, useSyncExternalStore } from 'react';\nimport { createPortal } from 'react-dom';\nimport { GlassPanel } from './glass-panel';\n\nconst subscribeToClient = () => () => {};\n\nconst getClientSnapshot = () => true;\n\nconst getServerSnapshot = () => false;\n\nexport const GlassToastProvider = ToastPrimitive.Provider;\n\nexport const GlassToastViewport = (\n  props: React.ComponentPropsWithoutRef<typeof ToastPrimitive.Viewport>,\n) => {\n  const canPortal = useSyncExternalStore(subscribeToClient, getClientSnapshot, getServerSnapshot);\n\n  if (!canPortal) return null;\n\n  return createPortal(\n    <ToastPrimitive.Viewport {...props} className={clsx('lg-toast-viewport', props.className)} />,\n    document.body,\n  );\n};\n\nexport function GlassToast(props: React.ComponentPropsWithoutRef<typeof ToastPrimitive.Root>) {\n  const { className, children, ...rest } = props;\n\n  return (\n    <ToastPrimitive.Root {...rest} className={clsx('lg-toast', className)}>\n      <GlassPanel refraction=\"soft\" variant=\"card\" elevation=\"raised\" className=\"lg-toast-root\">\n        {children}\n      </GlassPanel>\n    </ToastPrimitive.Root>\n  );\n}\n\nexport const GlassToastTitle = (\n  props: React.ComponentPropsWithoutRef<typeof ToastPrimitive.Title>,\n) => <ToastPrimitive.Title {...props} className={clsx('lg-toast-title', props.className)} />;\n\nexport const GlassToastDescription = (\n  props: React.ComponentPropsWithoutRef<typeof ToastPrimitive.Description>,\n) => (\n  <ToastPrimitive.Description\n    {...props}\n    className={clsx('lg-toast-description', props.className)}\n  />\n);\n\n/**\n * A round button that dismisses the toast. It draws its own × and is named \"Dismiss\"; give it\n * children and their text names it, or pass `aria-label`.\n */\nexport const GlassToastClose = forwardRef<\n  HTMLButtonElement,\n  React.ComponentPropsWithoutRef<typeof ToastPrimitive.Close>\n>(({ children, className, ...props }, forwardedRef) => (\n  <ToastPrimitive.Close\n    aria-label={children === undefined ? 'Dismiss' : undefined}\n    {...props}\n    ref={forwardedRef}\n    className={clsx('lg-toast-close', className)}\n  >\n    {children ?? (\n      <svg aria-hidden viewBox=\"0 0 20 20\">\n        <path\n          d=\"M5.5 5.5l9 9m0-9l-9 9\"\n          fill=\"none\"\n          stroke=\"currentColor\"\n          strokeLinecap=\"round\"\n          strokeWidth=\"1.6\"\n        />\n      </svg>\n    )}\n  </ToastPrimitive.Close>\n));\n\nGlassToastClose.displayName = 'GlassToastClose';\n\n/** A pill under the message, such as Undo. `altText` says how to do it without the button. */\nexport const GlassToastAction = forwardRef<\n  HTMLButtonElement,\n  React.ComponentPropsWithoutRef<typeof ToastPrimitive.Action>\n>(({ className, ...props }, forwardedRef) => (\n  <ToastPrimitive.Action\n    {...props}\n    ref={forwardedRef}\n    className={clsx('lg-toast-action', className)}\n  />\n));\n\nGlassToastAction.displayName = 'GlassToastAction';\n",
      "type": "registry:ui",
      "target": "components/glassyui/glass-toast.tsx"
    },
    {
      "path": "registry/glassyui/templates/still/still.tsx",
      "content": "'use client';\n\nimport './still.css';\n\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport {\n  GlassAccordion,\n  GlassAccordionContent,\n  GlassAccordionItem,\n  GlassAccordionTrigger,\n} from '../../glass-accordion';\nimport { GlassAvatar } from '../../glass-avatar';\nimport { GlassButton } from '../../glass-button';\nimport { GlassHeader } from '../../glass-header';\nimport {\n  GlassToast,\n  GlassToastDescription,\n  GlassToastProvider,\n  GlassToastViewport,\n} from '../../glass-toast';\nimport { BreathGuide } from './breath-guide';\nimport { EveningPhone } from './evening-phone';\nimport { BellIcon, FadeIcon, MarkIcon, PlusIcon, StarIcon, SunriseIcon } from './icons';\nimport { PricingPlan } from './pricing-plan';\nimport { HeroSky } from './sky';\nimport { SoundScenes } from './sound-scenes';\nimport { slotProps, StoreMenu, type StoreLinks } from './store-menu';\nimport { StoryCarousel } from './story-carousel';\n\nexport type { StoreLinks, StorePlatform } from './store-menu';\n\n/*\n  Still: a landing page for a meditation and sleep app for iPhone and Android.\n\n  It is a dark page: set data-lg-theme=\"dark\" on <html>. Set --still-accent (with\n  --still-accent-rotate, about the accent's hue minus 40deg, for the prominent buttons, and\n  --still-accent-ink for their label) and the --still-serif and --still-sans font stacks on any\n  ancestor to make it yours.\n*/\n\nconst NAV = [\n  { href: '#sounds', label: 'Sounds' },\n  { href: '#stories', label: 'Stories' },\n  { href: '#evenings', label: 'Evenings' },\n  { href: '#pricing', label: 'Pricing' },\n];\n\nconst FACTS = [\n  {\n    title: '3 min',\n    body: 'A full session. Long enough to settle, short enough to do every night.',\n  },\n  {\n    title: 'Offline',\n    body: 'Every scene and story downloads, so the phone can stay in flight mode.',\n  },\n  {\n    title: 'No streaks',\n    body: 'Miss a night and nothing happens. Still never counts, scores or nags.',\n  },\n];\n\nconst POINTS = [\n  {\n    Icon: BellIcon,\n    title: 'One gentle nudge',\n    body: 'A single reminder at the time you choose. Never a streak, never a second ping.',\n  },\n  {\n    Icon: FadeIcon,\n    title: 'Sounds that let go',\n    body: 'Scenes fade out over ten minutes once you’ve stopped touching the phone.',\n  },\n  {\n    Icon: SunriseIcon,\n    title: 'A wake window',\n    body: 'Instead of one alarm, birdsong rises slowly across a half hour you choose.',\n  },\n];\n\nconst VOICES = [\n  {\n    quote:\n      'I used to scroll until one in the morning. Now it’s three minutes of breathing, the night train, and I’m gone before the second stop.',\n    initials: 'PN',\n    name: 'Priya N.',\n    role: 'Nurse on night shifts',\n    tone: 'lilac',\n  },\n  {\n    quote:\n      'It’s the only app on my phone that has never asked me for anything. No streaks, no badges, no little red dots.',\n    initials: 'TW',\n    name: 'Tom W.',\n    role: 'Secondary school teacher',\n    tone: 'rose',\n  },\n  {\n    quote:\n      'The stories are so gently uneventful. I have never once heard the end of one, and I mean that as a compliment.',\n    initials: 'LM',\n    name: 'Lena M.',\n    role: 'New parent, light sleeper',\n    tone: 'blue',\n  },\n];\n\nconst FAQ = [\n  {\n    question: 'Is the free week really free?',\n    answer:\n      'Yes. Nothing is charged during the first seven nights, and Still reminds you two days before the week ends. Cancel from your phone’s subscription settings in a couple of taps.',\n  },\n  {\n    question: 'Do I need headphones?',\n    answer:\n      'No. Every scene is mixed to sound right from a phone on a bedside table, and from headphones if you prefer them.',\n  },\n  {\n    question: 'Does it work offline?',\n    answer:\n      'Download a scene or story once and it plays without a connection, including in flight mode. The breathing guide never needs one.',\n  },\n  {\n    question: 'Will it wake me in the night?',\n    answer:\n      'No. Sounds fade out on a timer you choose, and nothing plays again until your wake window, if you set one.',\n  },\n  {\n    question: 'What does Still know about me?',\n    answer:\n      'Very little. Your sessions stay on your phone. The free basics need no account, and there are no ads and nothing to sell.',\n  },\n  {\n    question: 'Is Still a medical app?',\n    answer:\n      'No. It helps you relax and fall asleep. If poor sleep goes on for weeks, a doctor is the right person to talk to.',\n  },\n];\n\nconst FOOTER = [\n  {\n    id: 'app',\n    title: 'The app',\n    links: [\n      { href: '#practice', label: 'Breathing' },\n      { href: '#sounds', label: 'Sound scenes' },\n      { href: '#stories', label: 'Sleep stories' },\n      { href: '#evenings', label: 'Evenings' },\n    ],\n  },\n  {\n    id: 'still',\n    title: 'Still',\n    links: [\n      { href: '#voices', label: 'Reviews' },\n      { href: '#pricing', label: 'Pricing' },\n      { href: '#download', label: 'Download' },\n    ],\n  },\n  {\n    id: 'help',\n    title: 'Help',\n    links: [\n      { href: '#faq', label: 'Questions' },\n      { href: 'mailto:hello@still.example', label: 'Write to us' },\n    ],\n  },\n];\n\nfunction useOnScreen(ref: React.RefObject<HTMLElement | null>) {\n  const [onScreen, setOnScreen] = useState(true);\n\n  useEffect(() => {\n    const element = ref.current;\n\n    if (!element) return;\n\n    const observer = new IntersectionObserver(([entry]) => setOnScreen(entry.isIntersecting));\n\n    observer.observe(element);\n\n    return () => observer.disconnect();\n  }, [ref]);\n\n  return onScreen;\n}\n\nfunction Brand() {\n  return (\n    <>\n      <MarkIcon className=\"still-brand-mark\" />\n      Still\n    </>\n  );\n}\n\n/**\n * The Still landing page. Pass `storeLinks` with your app's store pages; a store without a link\n * shows a demo note and opens nothing.\n */\nexport function Still({ storeLinks }: { storeLinks?: StoreLinks }) {\n  const heroRef = useRef<HTMLElement>(null);\n  const glowRef = useRef<HTMLDivElement>(null);\n  const heroOnScreen = useOnScreen(heroRef);\n  const [breathing, setBreathing] = useState(false);\n  const [notice, setNotice] = useState(0);\n\n  const showDemo = useCallback(() => setNotice((count) => count + 1), []);\n\n  return (\n    <GlassToastProvider duration={3800} label=\"Notification\">\n      <div\n        className=\"still still-page\"\n        data-breathing={breathing || undefined}\n        data-lg-theme=\"dark\"\n      >\n        <a className=\"still-skip\" href=\"#still-main\">\n          Skip to content\n        </a>\n\n        <GlassHeader\n          actions={\n            <GlassButton {...slotProps} className=\"still-header-cta still-button-sm\" size=\"sm\">\n              <a href=\"#download\">Get Still</a>\n            </GlassButton>\n          }\n          brand={\n            <a className=\"still-brand\" href=\"#top\">\n              <Brand />\n            </a>\n          }\n          className=\"still-header\"\n        >\n          {NAV.map((link) => (\n            <a key={link.href} href={link.href}>\n              {link.label}\n            </a>\n          ))}\n          <a className=\"still-menu-cta\" href=\"#download\">\n            Get Still\n          </a>\n        </GlassHeader>\n\n        <main id=\"still-main\" tabIndex={-1}>\n          <section\n            ref={heroRef}\n            aria-labelledby=\"still-hero-title\"\n            className=\"still-hero\"\n            data-away={heroOnScreen ? undefined : ''}\n            id=\"top\"\n          >\n            <HeroSky glowRef={glowRef} />\n            <BreathGuide glowRef={glowRef} onBreathingChange={setBreathing}>\n              <h1 className=\"still-hero-title\" id=\"still-hero-title\">\n                <span className=\"still-hero-line\">Breathe out.</span>\n                <span className=\"still-hero-line still-hero-line--soft\">The day can wait.</span>\n              </h1>\n              <p className=\"still-hero-lede\">\n                Guided breathing, sleep sounds and stories read slowly. For iPhone and Android.\n              </p>\n            </BreathGuide>\n          </section>\n\n          <section\n            aria-labelledby=\"still-practice-title\"\n            className=\"still-section still-practice\"\n            id=\"practice\"\n          >\n            <div className=\"still-wrap still-practice-grid\">\n              <header className=\"still-practice-head still-rise\">\n                <p className=\"still-eyebrow\">The practice</p>\n                <h2 className=\"still-h2\" id=\"still-practice-title\">\n                  Three minutes is enough.\n                </h2>\n              </header>\n              <p className=\"still-practice-body still-rise\">\n                No mountain, no hour on a cushion. Breathe in for four, hold for two, out for six.\n                Fifteen of those take three minutes, about as long as a cup of tea takes to steep.\n              </p>\n              <figure className=\"still-curve still-rise\">\n                <svg\n                  aria-hidden\n                  className=\"still-curve-art\"\n                  focusable=\"false\"\n                  viewBox=\"0 0 1200 280\"\n                >\n                  <defs>\n                    <linearGradient id=\"still-curve-fill\" x1=\"0\" x2=\"0\" y1=\"0\" y2=\"1\">\n                      <stop offset=\"0\" stopColor=\"#e6dcff\" stopOpacity=\"0.16\" />\n                      <stop offset=\"1\" stopColor=\"#e6dcff\" stopOpacity=\"0\" />\n                    </linearGradient>\n                  </defs>\n                  <path className=\"still-curve-base\" d=\"M0 250H1200\" />\n                  <path className=\"still-curve-guide\" d=\"M400 20V250M600 20V250\" />\n                  <path\n                    className=\"still-curve-area\"\n                    d=\"M0 250C200 250 200 40 400 40H600C900 40 900 250 1200 250Z\"\n                  />\n                  <path\n                    className=\"still-curve-line\"\n                    d=\"M0 250C200 250 200 40 400 40H600C900 40 900 250 1200 250\"\n                    pathLength={1}\n                  />\n                  <circle className=\"still-curve-dot\" cx=\"0\" cy=\"250\" r=\"7\" />\n                  <circle className=\"still-curve-dot\" cx=\"400\" cy=\"40\" r=\"7\" />\n                  <circle className=\"still-curve-dot\" cx=\"600\" cy=\"40\" r=\"7\" />\n                  <circle className=\"still-curve-dot\" cx=\"1200\" cy=\"250\" r=\"7\" />\n                </svg>\n                <div className=\"still-curve-labels\">\n                  <p>\n                    <b>In</b>\n                    <span>4 s</span>\n                  </p>\n                  <p>\n                    <b>Hold</b>\n                    <span>2 s</span>\n                  </p>\n                  <p>\n                    <b>Out</b>\n                    <span>6 s</span>\n                  </p>\n                </div>\n                <figcaption>\n                  One breath takes twelve seconds. A long, slow out-breath is the part that settles\n                  you.\n                </figcaption>\n              </figure>\n              <div className=\"still-facts\">\n                {FACTS.map((fact) => (\n                  <div key={fact.title} className=\"still-fact still-rise\">\n                    <h3>{fact.title}</h3>\n                    <p>{fact.body}</p>\n                  </div>\n                ))}\n              </div>\n            </div>\n          </section>\n\n          <SoundScenes />\n\n          <StoryCarousel />\n\n          <section\n            aria-labelledby=\"still-evenings-title\"\n            className=\"still-section still-evenings\"\n            id=\"evenings\"\n          >\n            <div className=\"still-wrap still-evenings-grid\">\n              <div className=\"still-evenings-copy still-rise\">\n                <p className=\"still-eyebrow\">Evenings</p>\n                <h2 className=\"still-h2\" id=\"still-evenings-title\">\n                  Your evening, set before you get there.\n                </h2>\n                <p className=\"still-lede\">\n                  Tell Still when you’d like to be asleep. An hour before, it nudges you once, warms\n                  the screen and lines up tonight’s breath, sound and story.\n                </p>\n                <ul className=\"still-points\">\n                  {POINTS.map(({ Icon, title, body }) => (\n                    <li key={title} className=\"still-point\">\n                      <span className=\"still-point-icon\">\n                        <Icon />\n                      </span>\n                      <div>\n                        <h3>{title}</h3>\n                        <p>{body}</p>\n                      </div>\n                    </li>\n                  ))}\n                </ul>\n              </div>\n              <div className=\"still-evenings-phone\">\n                <EveningPhone />\n              </div>\n            </div>\n          </section>\n\n          <section\n            aria-labelledby=\"still-voices-title\"\n            className=\"still-section still-voices\"\n            id=\"voices\"\n          >\n            <div className=\"still-wrap\">\n              <header className=\"still-rise\">\n                <p className=\"still-eyebrow\">From the people who use it</p>\n                <h2 className=\"still-h2\" id=\"still-voices-title\">\n                  Said quietly.\n                </h2>\n                <p className=\"still-rating\">\n                  <span aria-hidden className=\"still-rating-marks\">\n                    <StarIcon />\n                    <StarIcon />\n                    <StarIcon />\n                    <StarIcon />\n                    <StarIcon />\n                  </span>\n                  Rated 4.8 by 21,400 people on iPhone and Android\n                </p>\n              </header>\n              <div className=\"still-voices-grid\">\n                {VOICES.map((voice) => (\n                  <figure key={voice.name} className=\"still-voice still-rise\">\n                    <blockquote>“{voice.quote}”</blockquote>\n                    <figcaption>\n                      <GlassAvatar\n                        aria-hidden\n                        className={`still-avatar still-avatar--${voice.tone}`}\n                        fallback={voice.initials}\n                      />\n                      <span>\n                        <b>{voice.name}</b>\n                        {voice.role}\n                      </span>\n                    </figcaption>\n                  </figure>\n                ))}\n              </div>\n            </div>\n          </section>\n\n          <section\n            aria-labelledby=\"still-pricing-title\"\n            className=\"still-section still-pricing\"\n            id=\"pricing\"\n          >\n            <div className=\"still-wrap\">\n              <header className=\"still-rise\">\n                <p className=\"still-eyebrow\">Pricing</p>\n                <h2 className=\"still-h2\" id=\"still-pricing-title\">\n                  Seven nights on us.\n                </h2>\n                <p className=\"still-lede\">\n                  Try the whole library for a week. If Still isn’t helping, cancel before the eighth\n                  night and you pay nothing.\n                </p>\n              </header>\n              <div className=\"still-pricing-stage\">\n                <div aria-hidden className=\"still-pricing-art\">\n                  <div className=\"still-pricing-orbit\" />\n                  <div className=\"still-pricing-moon\" />\n                  <svg focusable=\"false\" height=\"100%\" width=\"100%\">\n                    <circle cx=\"12%\" cy=\"18%\" opacity=\".6\" r=\"1.1\" />\n                    <circle cx=\"24%\" cy=\"40%\" opacity=\".5\" r=\".8\" />\n                    <circle cx=\"8%\" cy=\"62%\" opacity=\".55\" r=\"1.2\" />\n                    <circle cx=\"30%\" cy=\"78%\" opacity=\".4\" r=\".8\" />\n                    <circle cx=\"76%\" cy=\"64%\" opacity=\".5\" r=\"1\" />\n                    <circle cx=\"90%\" cy=\"82%\" opacity=\".55\" r=\"1.2\" />\n                    <circle cx=\"84%\" cy=\"10%\" opacity=\".5\" r=\".8\" />\n                    <circle cx=\"40%\" cy=\"8%\" opacity=\".5\" r=\"1\" />\n                  </svg>\n                </div>\n                <PricingPlan storeLinks={storeLinks} onDemo={showDemo} />\n                <p className=\"still-pricing-free\">\n                  Prefer to keep it simple? The breathing guide and three sound scenes stay free,\n                  with no account.\n                </p>\n              </div>\n            </div>\n          </section>\n\n          <section aria-labelledby=\"still-faq-title\" className=\"still-section still-faq\" id=\"faq\">\n            <div className=\"still-wrap still-faq-grid\">\n              <header className=\"still-rise\">\n                <p className=\"still-eyebrow\">Questions</p>\n                <h2 className=\"still-h2\" id=\"still-faq-title\">\n                  Questions before bed.\n                </h2>\n                <p className=\"still-lede\">\n                  Anything else, write to us at{' '}\n                  <a href=\"mailto:hello@still.example\">hello@still.example</a> and a person will\n                  reply within a day.\n                </p>\n              </header>\n              <GlassAccordion\n                className=\"still-faq-list still-rise\"\n                defaultValue={[FAQ[0].question]}\n                type=\"multiple\"\n              >\n                {FAQ.map((item) => (\n                  <GlassAccordionItem\n                    key={item.question}\n                    className=\"still-faq-item\"\n                    value={item.question}\n                  >\n                    <GlassAccordionTrigger>\n                      <span className=\"still-faq-question\">{item.question}</span>\n                      <span aria-hidden className=\"still-faq-icon\">\n                        <PlusIcon />\n                      </span>\n                    </GlassAccordionTrigger>\n                    <GlassAccordionContent>\n                      <p>{item.answer}</p>\n                    </GlassAccordionContent>\n                  </GlassAccordionItem>\n                ))}\n              </GlassAccordion>\n            </div>\n          </section>\n\n          <section aria-labelledby=\"still-download-title\" className=\"still-download\" id=\"download\">\n            <div aria-hidden className=\"still-download-art\">\n              <svg className=\"still-download-stars\" focusable=\"false\" height=\"70%\" width=\"100%\">\n                <circle cx=\"8%\" cy=\"20%\" opacity=\".6\" r=\"1.1\" />\n                <circle cx=\"18%\" cy=\"46%\" opacity=\".5\" r=\".8\" />\n                <circle cx=\"28%\" cy=\"14%\" opacity=\".55\" r=\"1.2\" />\n                <circle cx=\"36%\" cy=\"62%\" opacity=\".4\" r=\".7\" />\n                <circle cx=\"64%\" cy=\"70%\" opacity=\".5\" r=\".9\" />\n                <circle cx=\"72%\" cy=\"40%\" opacity=\".6\" r=\"1.2\" />\n                <circle cx=\"86%\" cy=\"18%\" opacity=\".5\" r=\".8\" />\n                <circle cx=\"94%\" cy=\"54%\" opacity=\".5\" r=\"1\" />\n                <circle cx=\"48%\" cy=\"8%\" opacity=\".45\" r=\".8\" />\n              </svg>\n              <svg className=\"still-download-moon\" focusable=\"false\" viewBox=\"0 0 100 100\">\n                <defs>\n                  <mask id=\"still-crescent\">\n                    <rect fill=\"#fff\" height=\"100\" width=\"100\" />\n                    <circle cx=\"66\" cy=\"40\" fill=\"#000\" r=\"38\" />\n                  </mask>\n                  <radialGradient cx=\".3\" cy=\".35\" id=\"still-moon-fill\" r=\".8\">\n                    <stop offset=\"0\" stopColor=\"#fdfaff\" />\n                    <stop offset=\"1\" stopColor=\"#d8caf6\" />\n                  </radialGradient>\n                  {/* The glow is drawn inside the SVG: WebKit can paint a CSS filter on a masked\n                      SVG as a stray square at the top of the page. */}\n                  <filter height=\"400%\" id=\"still-moon-glow\" width=\"400%\" x=\"-150%\" y=\"-150%\">\n                    <feDropShadow\n                      dx=\"0\"\n                      dy=\"0\"\n                      floodColor=\"rgb(220 200 255)\"\n                      floodOpacity=\".45\"\n                      stdDeviation=\"28\"\n                    />\n                  </filter>\n                </defs>\n                <g filter=\"url(#still-moon-glow)\">\n                  <circle\n                    cx=\"50\"\n                    cy=\"50\"\n                    fill=\"url(#still-moon-fill)\"\n                    mask=\"url(#still-crescent)\"\n                    r=\"40\"\n                  />\n                </g>\n              </svg>\n            </div>\n            <div className=\"still-wrap\">\n              <h2 id=\"still-download-title\">\n                Tonight, <em>try one breath.</em>\n              </h2>\n              <p className=\"still-lede\">\n                Seven nights free, then $39.99 a year. For iPhone and Android.\n              </p>\n              <div className=\"still-download-actions\">\n                <StoreMenu links={storeLinks} onDemo={showDemo} />\n              </div>\n              <p className=\"still-download-note\">\n                The breathing guide stays free, with no account.\n              </p>\n            </div>\n          </section>\n        </main>\n\n        <footer className=\"still-footer\">\n          <div className=\"still-wrap\">\n            <div className=\"still-footer-grid\">\n              <div className=\"still-footer-brand\">\n                <a className=\"still-brand\" href=\"#top\">\n                  <Brand />\n                </a>\n                <p>A quiet place for the end of the day. For iPhone and Android.</p>\n              </div>\n              {FOOTER.map((column) => (\n                <nav key={column.title} aria-labelledby={`still-footer-${column.id}`}>\n                  <h2 id={`still-footer-${column.id}`}>{column.title}</h2>\n                  <ul>\n                    {column.links.map((link) => (\n                      <li key={link.href}>\n                        <a href={link.href}>{link.label}</a>\n                      </li>\n                    ))}\n                  </ul>\n                </nav>\n              ))}\n            </div>\n            <div className=\"still-footer-base\">\n              <span>© 2026 Still Labs</span>\n              <span>Made slowly, in a small studio by the sea</span>\n            </div>\n          </div>\n        </footer>\n\n        {notice > 0 ? (\n          <GlassToast key={notice} className=\"still still-toast\">\n            <span aria-hidden className=\"still-toast-icon\">\n              <MarkIcon />\n            </span>\n            <GlassToastDescription className=\"still-toast-text\">\n              Demo. No store was opened.\n            </GlassToastDescription>\n          </GlassToast>\n        ) : null}\n        <GlassToastViewport className=\"still still-toasts\" />\n      </div>\n    </GlassToastProvider>\n  );\n}\n",
      "type": "registry:block",
      "target": "components/glassyui/templates/still/still.tsx"
    },
    {
      "path": "registry/glassyui/templates/still/breath-guide.tsx",
      "content": "'use client';\n\nimport { useCallback, useEffect, useLayoutEffect, useRef, useState } from 'react';\nimport type { ReactNode, RefObject } from 'react';\nimport { motionReduced } from '../../lib/liquid-motion';\nimport { GlassButton } from '../../glass-button';\nimport { GlassKbd } from '../../glass-kbd';\nimport { GlassSurface } from '../../glass-surface';\nimport { BreathIcon, StopIcon } from './icons';\n\ntype GuideState = 'idle' | 'running' | 'done';\n\ntype BreathGuideProps = {\n  /** Seconds to breathe in, hold and breathe out. */\n  pattern?: readonly [number, number, number];\n  breaths?: number;\n  /** The hero's title and lede, set between the orb and its controls. */\n  children: ReactNode;\n  /** The sky's glow, which swells with the orb. */\n  glowRef?: RefObject<HTMLElement | null>;\n  onBreathingChange?: (breathing: boolean) => void;\n};\n\nconst PHASES = ['Breathe in', 'Hold', 'Breathe out'] as const;\n\nconst FOUR_TWO_SIX = [4, 2, 6] as const;\n\nconst SWELL = 0.12;\n\nconst NUMBERS = ['One', 'Two', 'Three', 'Four', 'Five', 'Six', 'Seven', 'Eight', 'Nine', 'Ten'];\n\nconst easeInOut = (x: number) => -(Math.cos(Math.PI * x) - 1) / 2;\n\nconst finishedStatus = 'In the app, sessions run up to twenty minutes.';\n\n/**\n * A guided breath: the orb swells as you breathe in, holds, and settles as you breathe out, while\n * the ring traces each breath. With motion reduced the orb stays still and the ring steps once a\n * second, so the count and the words carry the rhythm.\n */\nexport function BreathGuide({\n  pattern = FOUR_TWO_SIX,\n  breaths = 5,\n  children,\n  glowRef,\n  onBreathingChange,\n}: BreathGuideProps) {\n  const [state, setState] = useState<GuideState>('idle');\n  const [phase, setPhase] = useState<number | null>(null);\n  const [breath, setBreath] = useState(0);\n  const [words, setWords] = useState('');\n  const guideRef = useRef<HTMLDivElement>(null);\n  const orbRef = useRef<HTMLDivElement>(null);\n  const traceRef = useRef<SVGCircleElement>(null);\n  const beadRef = useRef<SVGCircleElement>(null);\n  const wordsRef = useRef<HTMLSpanElement>(null);\n  const countRef = useRef<HTMLSpanElement>(null);\n  const startRef = useRef<HTMLButtonElement>(null);\n  const stopRef = useRef<HTMLButtonElement>(null);\n  // Odd breaths draw the ring and even ones let it go, so the trace never snaps back; a session\n  // that starts with the ring full lets go first.\n  const parityRef = useRef(0);\n  const ringFullRef = useRef(false);\n  const focusRef = useRef<'start' | 'stop' | null>(null);\n  // Kept in a ref, so the session's clock never restarts when the owner re-renders.\n  const onBreathingChangeRef = useRef(onBreathingChange);\n  const cycle = pattern[0] + pattern[1] + pattern[2];\n  const count = NUMBERS[breaths - 1] ?? String(breaths);\n  const minutes = Math.round((cycle * breaths) / 60);\n\n  useLayoutEffect(() => {\n    onBreathingChangeRef.current = onBreathingChange;\n  });\n\n  const finish = useCallback(\n    (done: boolean) => {\n      const orb = orbRef.current;\n      const trace = traceRef.current;\n\n      if (orb) orb.style.transform = '';\n\n      if (glowRef?.current) glowRef.current.style.transform = '';\n      beadRef.current?.removeAttribute('transform');\n\n      if (countRef.current) countRef.current.textContent = '';\n\n      if (done && trace) {\n        ringFullRef.current = (breaths - 1 + parityRef.current) % 2 === 0;\n        trace.style.strokeDasharray = ringFullRef.current ? '1 1' : '0 1';\n        trace.style.strokeDashoffset = ringFullRef.current ? '0' : '-1';\n      }\n\n      focusRef.current = document.activeElement === stopRef.current ? 'start' : null;\n      setPhase(null);\n      setWords(done ? `That was ${minutes === 1 ? 'a minute' : `${minutes} minutes`}.` : '');\n      setState(done ? 'done' : 'idle');\n      onBreathingChangeRef.current?.(false);\n    },\n    [breaths, glowRef, minutes],\n  );\n\n  const begin = () => {\n    const trace = traceRef.current;\n\n    parityRef.current = state === 'done' && ringFullRef.current ? 1 : 0;\n\n    if (!parityRef.current && trace) {\n      trace.style.strokeDasharray = '0 1';\n      trace.style.strokeDashoffset = '0';\n    }\n\n    focusRef.current = 'stop';\n    setBreath(1);\n    setState('running');\n    onBreathingChangeRef.current?.(true);\n  };\n\n  // The session's clock: the orb, glow, ring and count follow every frame without re-rendering;\n  // the words and the breath number change a few times a breath.\n  useEffect(() => {\n    if (state !== 'running') return;\n\n    const start = performance.now();\n    let frame = requestAnimationFrame(tick);\n    let shownPhase = -1;\n    let shownBreath = -1;\n    let shownCount = -1;\n\n    function tick(now: number) {\n      const elapsed = Math.max(0, now - start) / 1000;\n\n      if (elapsed >= cycle * breaths) {\n        finish(true);\n\n        return;\n      }\n\n      const reduced = motionReduced();\n      const current = Math.floor(elapsed / cycle);\n      const within = elapsed - current * cycle;\n      const step = within < pattern[0] ? 0 : within < pattern[0] + pattern[1] ? 1 : 2;\n      const from = step === 0 ? 0 : step === 1 ? pattern[0] : pattern[0] + pattern[1];\n      const progress = (within - from) / pattern[step];\n\n      if (current !== shownBreath) {\n        shownBreath = current;\n        setBreath(current + 1);\n      }\n\n      if (step !== shownPhase) {\n        shownPhase = step;\n        setPhase(step);\n        setWords(PHASES[step]);\n      }\n\n      const seconds = Math.max(1, Math.ceil(pattern[step] * (1 - progress) - 0.0001));\n\n      if (seconds !== shownCount && countRef.current) {\n        shownCount = seconds;\n        countRef.current.textContent = String(seconds);\n      }\n\n      const lap = reduced ? Math.floor(within) / cycle : within / cycle;\n\n      if (!reduced) {\n        const scale =\n          step === 0\n            ? 1 + SWELL * easeInOut(progress)\n            : step === 1\n              ? 1 + SWELL\n              : 1 + SWELL * (1 - easeInOut(progress));\n\n        if (orbRef.current) orbRef.current.style.transform = `scale(${scale.toFixed(4)})`;\n\n        if (glowRef?.current) {\n          glowRef.current.style.transform = `scale(${(1 + (scale - 1) * 1.8).toFixed(4)})`;\n        }\n      }\n\n      const filling = (current + parityRef.current) % 2 === 0;\n      const trace = traceRef.current;\n\n      if (trace) {\n        trace.style.strokeDasharray = `${(filling ? lap : 1 - lap).toFixed(4)} 1`;\n        trace.style.strokeDashoffset = filling ? '0' : (-lap).toFixed(4);\n      }\n\n      beadRef.current?.setAttribute('transform', `rotate(${(lap * 360).toFixed(2)} 100 100)`);\n      frame = requestAnimationFrame(tick);\n    }\n\n    return () => cancelAnimationFrame(frame);\n  }, [breaths, cycle, finish, glowRef, pattern, state]);\n\n  // Escape, a hidden tab or the guide leaving the screen ends a session where it stands.\n  useEffect(() => {\n    const guide = guideRef.current;\n\n    if (state !== 'running' || !guide) return;\n\n    const onKey = (event: KeyboardEvent) => {\n      if (event.key === 'Escape') finish(false);\n    };\n\n    const onVisibility = () => {\n      if (document.hidden) finish(false);\n    };\n\n    const observer = new IntersectionObserver(([entry]) => {\n      if (!entry.isIntersecting) finish(false);\n    });\n\n    document.addEventListener('keydown', onKey);\n    document.addEventListener('visibilitychange', onVisibility);\n    observer.observe(guide);\n\n    return () => {\n      document.removeEventListener('keydown', onKey);\n      document.removeEventListener('visibilitychange', onVisibility);\n      observer.disconnect();\n    };\n  }, [finish, state]);\n\n  // The button that replaces the one in use takes its focus where it stands, so nothing scrolls.\n  useLayoutEffect(() => {\n    const target = focusRef.current;\n\n    focusRef.current = null;\n\n    if (target === 'stop') stopRef.current?.focus({ preventScroll: true });\n\n    if (target === 'start') startRef.current?.focus({ preventScroll: true });\n  }, [state]);\n\n  useEffect(() => {\n    const element = wordsRef.current;\n\n    if (!element || !words || motionReduced()) return;\n\n    element.animate(\n      [\n        { filter: 'blur(8px)', opacity: 0, transform: 'translateY(6px)' },\n        { filter: 'blur(0)', opacity: 1, transform: 'none' },\n      ],\n      { duration: 700, easing: 'cubic-bezier(0.32, 0.72, 0, 1)' },\n    );\n  }, [words]);\n\n  return (\n    <div ref={guideRef} className=\"still-breath\" data-phase={phase ?? undefined} data-state={state}>\n      <div className=\"still-breath-stage\">\n        <svg aria-hidden className=\"still-breath-ring\" focusable=\"false\" viewBox=\"0 0 200 200\">\n          <circle className=\"still-breath-track\" cx=\"100\" cy=\"100\" r=\"98.5\" />\n          <circle\n            ref={traceRef}\n            className=\"still-breath-trace\"\n            cx=\"100\"\n            cy=\"100\"\n            pathLength={1}\n            r=\"98.5\"\n            transform=\"rotate(-90 100 100)\"\n          />\n          <circle className=\"still-breath-tick still-breath-tick--in\" cx=\"100\" cy=\"1.5\" r=\"1.5\" />\n          <circle\n            className=\"still-breath-tick still-breath-tick--hold\"\n            cx=\"185.3\"\n            cy=\"149.25\"\n            r=\"1.5\"\n          />\n          <circle\n            className=\"still-breath-tick still-breath-tick--out\"\n            cx=\"100\"\n            cy=\"198.5\"\n            r=\"1.5\"\n          />\n          <circle ref={beadRef} className=\"still-breath-bead\" cx=\"100\" cy=\"1.5\" r=\"2.4\" />\n        </svg>\n        <div className=\"still-breath-rise\">\n          <GlassSurface ref={orbRef} className=\"still-breath-orb\" lens>\n            <span aria-hidden className=\"still-breath-shine\" />\n            <span ref={wordsRef} aria-live=\"polite\" className=\"still-breath-words\">\n              {words}\n            </span>\n            <span ref={countRef} aria-hidden className=\"still-breath-count\" />\n          </GlassSurface>\n        </div>\n      </div>\n      {children}\n      <div className=\"still-breath-controls\">\n        {state === 'running' ? (\n          <GlassButton ref={stopRef} className=\"still-button-xl\" onClick={() => finish(false)}>\n            <StopIcon />\n            Stop\n          </GlassButton>\n        ) : (\n          <GlassButton\n            ref={startRef}\n            className=\"still-button-xl\"\n            variant=\"prominent\"\n            onClick={begin}\n          >\n            <BreathIcon />\n            {state === 'done' ? 'Breathe again' : 'Breathe with me'}\n          </GlassButton>\n        )}\n      </div>\n      <p className=\"still-breath-status\">\n        {state === 'running' ? (\n          <>\n            Breath {breath} of {breaths}\n            <span className=\"still-breath-escape\">\n              <span aria-hidden>·</span>\n              <GlassKbd>Esc</GlassKbd>to stop\n            </span>\n          </>\n        ) : state === 'done' ? (\n          `${count} slow breaths. ${finishedStatus}`\n        ) : (\n          `${count} breaths, about ${minutes === 1 ? 'a minute' : `${minutes} minutes`}`\n        )}\n      </p>\n    </div>\n  );\n}\n",
      "type": "registry:component",
      "target": "components/glassyui/templates/still/breath-guide.tsx"
    },
    {
      "path": "registry/glassyui/templates/still/sky.tsx",
      "content": "import type { RefObject } from 'react';\n\n/*\n  The hero's dusk: a sky over still water, with a moon path and the horizon the breathing orb\n  rests on. Its stars and glints are fixed, so the server and the browser draw the same sky.\n*/\n\ntype Star = [\n  x: number,\n  y: number,\n  r: number,\n  opacity: number,\n  wideOnly: 0 | 1,\n  twinkle: number | null,\n];\n\ntype Glint = [\n  x: number,\n  y: number,\n  width: number,\n  height: number,\n  opacity: number,\n  twinkle: number | null,\n];\n\n// Positions in percent of the sky. Stars marked wideOnly leave phones' smaller sky uncluttered;\n// the ones with a twinkle delay shimmer, the page's one quiet loop.\nconst STARS: Star[] = [\n  [0, 81.3, 0.57, 0.47, 0, null],\n  [72.9, 35.8, 0.6, 0.76, 1, null],\n  [75.5, 36.8, 0.98, 0.7, 0, -13.1],\n  [24.2, 21.1, 1.01, 0.73, 1, null],\n  [5.4, 52, 0.71, 0.86, 0, null],\n  [80.7, 4, 0.75, 0.86, 1, null],\n  [68.9, 47.5, 0.83, 0.85, 0, -14.5],\n  [37.2, 17.9, 1.24, 0.53, 1, null],\n  [15.3, 14.9, 0.67, 0.51, 0, null],\n  [93.7, 38.3, 1.05, 0.83, 1, -0.9],\n  [27.3, 38.6, 0.75, 0.58, 0, null],\n  [19.3, 79.7, 0.5, 0.55, 1, null],\n  [34.4, 49.8, 1.43, 0.63, 0, -2.6],\n  [40.6, 13.9, 0.62, 0.58, 1, null],\n  [33.3, 35.7, 0.88, 0.48, 0, -14.5],\n  [45.8, 73.8, 0.91, 0.7, 1, null],\n  [51.6, 33, 0.98, 0.87, 0, null],\n  [39.7, 54.8, 0.55, 0.67, 1, null],\n  [35.1, 17.5, 0.64, 0.79, 0, null],\n  [87.8, 3.4, 1.21, 0.39, 1, -6.5],\n  [15.4, 2, 1.59, 0.47, 0, -10.1],\n  [14.4, 28.4, 0.85, 0.43, 1, -14.7],\n  [88.5, 77.3, 1.34, 0.85, 0, -12.2],\n  [27.5, 0.1, 0.55, 0.39, 1, null],\n  [0.2, 44.6, 0.54, 0.76, 0, null],\n  [48.9, 52.4, 0.55, 0.84, 1, null],\n  [23.5, 21, 1.36, 0.42, 0, null],\n  [48.9, 0, 1.4, 0.7, 1, null],\n  [92.2, 0.3, 1.37, 0.45, 0, -15.5],\n  [56.5, 51.5, 0.56, 0.47, 1, null],\n  [20.9, 39, 0.5, 0.77, 0, null],\n  [70.1, 55.5, 0.74, 0.37, 1, null],\n  [11, 81.1, 0.51, 0.73, 0, null],\n  [89.3, 0.7, 1.34, 0.82, 1, -15.9],\n  [95.4, 61.5, 0.66, 0.49, 0, null],\n  [72.8, 76.2, 0.65, 0.48, 1, null],\n  [40.5, 76.9, 0.81, 0.54, 0, null],\n  [62.2, 58, 0.6, 0.75, 1, null],\n  [42.3, 8.1, 0.58, 0.89, 0, null],\n  [99.4, 46.3, 1.31, 0.86, 1, null],\n  [20, 47.7, 0.51, 0.62, 0, null],\n  [55.7, 62.3, 1.47, 0.62, 1, null],\n  [18.7, 27.5, 0.52, 0.71, 0, null],\n  [52.2, 38.7, 0.75, 0.77, 1, null],\n  [36.2, 59.9, 0.5, 0.51, 0, null],\n  [54.2, 8.4, 1.04, 0.51, 1, null],\n  [23.6, 49.3, 0.67, 0.39, 0, null],\n  [77.3, 68.7, 1.41, 0.85, 1, null],\n  [68.1, 86.4, 0.5, 0.77, 0, null],\n  [60.1, 56.7, 1.37, 0.37, 1, null],\n  [13.6, 2.1, 0.51, 0.4, 0, null],\n  [0.9, 43.3, 1.47, 0.46, 1, null],\n  [13.4, 8.4, 0.96, 0.48, 0, null],\n  [45.6, 91.2, 0.67, 0.72, 1, null],\n  [77.4, 23, 0.66, 0.38, 0, null],\n  [23, 66.8, 1.54, 0.43, 1, null],\n  [92.6, 33.4, 0.51, 0.47, 0, null],\n  [60.3, 6.5, 0.5, 0.5, 1, null],\n  [64.7, 38.2, 0.72, 0.9, 0, null],\n  [7.5, 24.5, 0.59, 0.35, 1, null],\n  [0.6, 24.5, 0.51, 0.48, 0, null],\n  [92.4, 63.1, 1.11, 0.59, 1, null],\n  [85.5, 86.9, 1.18, 0.71, 0, null],\n  [57.2, 18.9, 0.65, 0.62, 1, null],\n  [49.5, 39.3, 1.04, 0.72, 0, null],\n  [63.3, 57.3, 1.34, 0.81, 1, null],\n  [98.8, 26.7, 0.73, 0.88, 0, null],\n  [97.5, 19.7, 0.5, 0.54, 1, null],\n  [88.3, 54.9, 1.06, 0.88, 0, null],\n  [78.7, 8.7, 0.55, 0.79, 1, null],\n  [10.4, 80.6, 1.17, 0.7, 0, null],\n  [71.1, 36.1, 0.68, 0.83, 1, null],\n  [56.3, 75.1, 0.56, 0.73, 0, null],\n  [43.4, 22.8, 0.53, 0.67, 1, null],\n];\n\n// The moon path's glints on the water, in perspective, on a 300 by 240 canvas.\nconst GLINTS: Glint[] = [\n  [148, 4.3, 1.9, 0.8, 0.49, -1.5],\n  [153.3, 4.3, 2.6, 0.8, 0.57, -3.6],\n  [150.4, 7.5, 3.2, 0.8, 0.48, null],\n  [140.8, 7.5, 2.1, 0.8, 0.57, -2.3],\n  [137.6, 12.2, 4.3, 0.8, 0.42, null],\n  [151.8, 12.2, 3.9, 0.8, 0.46, null],\n  [152.2, 18.2, 4, 0.8, 0.44, null],\n  [158.5, 18.2, 4, 0.8, 0.44, null],\n  [145.8, 25.4, 4.2, 0.8, 0.56, -6.7],\n  [137.4, 25.4, 5.8, 0.8, 0.4, null],\n  [158.5, 25.4, 3.3, 0.8, 0.5, null],\n  [133.9, 33.9, 7.6, 0.8, 0.45, null],\n  [163.3, 33.9, 4, 0.8, 0.49, null],\n  [151.7, 33.9, 7.8, 0.8, 0.51, -6.2],\n  [144.4, 43.4, 8.5, 1, 0.49, null],\n  [160, 43.4, 5.7, 1, 0.42, null],\n  [130.2, 43.4, 8.5, 1, 0.52, null],\n  [153.5, 54.1, 5.1, 1, 0.4, null],\n  [163.5, 54.1, 8.2, 1, 0.5, null],\n  [135.9, 54.1, 7.9, 1, 0.44, null],\n  [137.2, 65.7, 10.8, 1, 0.46, null],\n  [182.1, 65.7, 8.3, 1, 0.38, null],\n  [157.9, 65.7, 9.9, 1, 0.32, null],\n  [148.5, 78.5, 9.3, 1, 0.31, null],\n  [185.4, 78.5, 12.8, 1, 0.45, null],\n  [164.2, 78.5, 10, 1, 0.37, null],\n  [153.5, 92.1, 12, 1, 0.39, null],\n  [134.6, 92.1, 10.3, 1, 0.31, null],\n  [115, 92.1, 14.2, 1, 0.42, null],\n  [178.3, 92.1, 14.6, 1, 0.4, null],\n  [159.9, 106.8, 17.4, 1, 0.32, null],\n  [100.8, 106.8, 17.2, 1, 0.39, null],\n  [137.2, 106.8, 17.4, 1, 0.31, null],\n  [186.4, 106.8, 10.6, 1, 0.29, null],\n  [147, 122.4, 19.7, 1, 0.28, null],\n  [96.2, 122.4, 13.7, 1, 0.35, null],\n  [180.3, 122.4, 17.1, 1, 0.26, null],\n  [117.2, 122.4, 10.9, 1, 0.25, null],\n  [193.6, 139, 20.2, 1, 0.23, null],\n  [108.1, 139, 13.6, 1, 0.24, null],\n  [137.1, 139, 13.5, 1, 0.28, null],\n  [79.4, 139, 13.7, 1, 0.26, null],\n  [172.8, 156.4, 17.2, 1, 0.28, null],\n  [198.1, 156.4, 18.2, 1, 0.24, null],\n  [115, 156.4, 18.5, 1, 0.19, null],\n  [69.3, 156.4, 17.5, 1, 0.21, null],\n  [92.4, 174.7, 23.3, 1, 0.21, null],\n  [217.3, 174.7, 17.6, 1, 0.21, null],\n  [141.4, 174.7, 20.9, 1, 0.23, null],\n  [185.2, 174.7, 14.5, 1, 0.21, null],\n  [135.9, 194, 28.9, 1, 0.15, null],\n  [176.2, 194, 23, 1, 0.2, null],\n  [81.2, 194, 27.3, 1, 0.14, null],\n  [51, 194, 16.2, 1, 0.17, null],\n  [168.9, 214.1, 30.6, 1, 0.16, null],\n  [208.8, 214.1, 19.3, 1, 0.16, null],\n  [31.9, 214.1, 22.4, 1, 0.14, null],\n  [118.6, 214.1, 32.4, 1, 0.15, null],\n  [107.6, 235, 32.1, 1, 0.09, null],\n  [171.6, 235, 19.8, 1, 0.12, null],\n  [200.1, 235, 27.5, 1, 0.11, null],\n  [31.7, 235, 18.7, 1, 0.08, null],\n];\n\nfunction twinkle(delay: number | null) {\n  return delay === null ? undefined : { animationDelay: `${delay}s` };\n}\n\nexport function HeroSky({ glowRef }: { glowRef: RefObject<HTMLDivElement | null> }) {\n  return (\n    <div aria-hidden className=\"still-sky\">\n      <div className=\"still-sky-gradient\" />\n      <svg className=\"still-sky-stars\" focusable=\"false\" height=\"100%\" width=\"100%\">\n        {STARS.map(([x, y, r, opacity, wideOnly, delay]) => (\n          <circle\n            key={`${x}-${y}`}\n            className={\n              [wideOnly ? 'still-sky-wide' : '', delay === null ? '' : 'still-twinkle']\n                .filter(Boolean)\n                .join(' ') || undefined\n            }\n            cx={`${x}%`}\n            cy={`${y}%`}\n            opacity={opacity}\n            r={r}\n            style={twinkle(delay)}\n          />\n        ))}\n      </svg>\n      <div className=\"still-sky-water\" />\n      <div ref={glowRef} className=\"still-sky-glow\" />\n      <span className=\"still-sky-venus\" />\n      <div className=\"still-sky-path\" />\n      <svg\n        className=\"still-sky-glints\"\n        focusable=\"false\"\n        preserveAspectRatio=\"none\"\n        viewBox=\"0 0 300 240\"\n      >\n        {GLINTS.map(([x, y, width, height, opacity, delay]) => (\n          <rect\n            key={`${x}-${y}`}\n            className={delay === null ? undefined : 'still-twinkle'}\n            height={height}\n            opacity={opacity}\n            rx={height / 2}\n            style={twinkle(delay)}\n            width={width}\n            x={x}\n            y={y}\n          />\n        ))}\n      </svg>\n      <svg\n        className=\"still-sky-land still-sky-land--west\"\n        focusable=\"false\"\n        preserveAspectRatio=\"none\"\n        viewBox=\"0 0 600 14\"\n      >\n        <path d=\"M0 6.2C40 5 80 1.6 128 1.2S196 3.4 252 5.6S380 9.6 470 11.6S560 13.4 600 14H0Z\" />\n      </svg>\n      <svg\n        className=\"still-sky-land still-sky-land--east\"\n        focusable=\"false\"\n        preserveAspectRatio=\"none\"\n        viewBox=\"0 0 300 7\"\n      >\n        <path d=\"M0 7C22 5.4 40 3 74 2.4S132 2.8 168 4.2S250 6.2 300 7Z\" />\n      </svg>\n      <div className=\"still-sky-horizon\" />\n    </div>\n  );\n}\n",
      "type": "registry:component",
      "target": "components/glassyui/templates/still/sky.tsx"
    },
    {
      "path": "registry/glassyui/templates/still/sound-scenes.tsx",
      "content": "'use client';\n\nimport { useEffect, useRef, useState } from 'react';\nimport type { ReactNode } from 'react';\nimport { motionReduced } from '../../lib/liquid-motion';\nimport { GlassBadge } from '../../glass-badge';\nimport { GlassButton } from '../../glass-button';\nimport { GlassPanel } from '../../glass-panel';\nimport { PauseIcon, PlayIcon } from './icons';\nimport { RainArt, TrainArt, WindArt } from './scene-art';\n\ntype SceneKind = 'rain' | 'train' | 'wind';\n\ntype Scene = {\n  kind: SceneKind;\n  title: string;\n  description: string;\n  art: ReactNode;\n};\n\nconst SCENES: Scene[] = [\n  {\n    kind: 'rain',\n    title: 'Rain on tin',\n    description: 'A garden shed roof in steady rain. No thunder, no birds, nothing that changes.',\n    art: <RainArt />,\n  },\n  {\n    kind: 'train',\n    title: 'Night train',\n    description:\n      'A sleeper carriage after midnight: the rails, the low hum, a door far down the corridor.',\n    art: <TrainArt />,\n  },\n  {\n    kind: 'wind',\n    title: 'Coastal wind',\n    description:\n      'Dune grass and a distant sea on a cold, clear night, with the wind coming and going.',\n    art: <WindArt />,\n  },\n];\n\nconst LENGTH = 3600;\n\nconst BARS = 36;\n\n// Each scene's waveform at rest, a fingerprint of how it sounds.\nconst REST: Record<SceneKind, (bar: number) => number> = {\n  rain: (bar) => 0.22 + 0.2 * Math.abs(Math.sin(bar * 1.9) * Math.cos(bar * 0.7)),\n  train: (bar) => 0.14 + 0.36 * Math.abs(Math.sin(bar * 0.55)) ** 4,\n  wind: (bar) => 0.12 + 0.4 * Math.sin((bar / (BARS - 1)) * Math.PI) ** 2,\n};\n\ntype Live = { now: number[]; goal: number[]; at: number[] };\n\n// How each scene moves while it plays: rain patters at random, the train clacks over the rail\n// joints, and the wind rolls through in long gusts.\nconst LIVE: Record<SceneKind, (live: Live, time: number, bar: number) => number> = {\n  rain: (live, time, bar) => {\n    if (time - live.at[bar] > 60 + (bar % 5) * 14) {\n      live.goal[bar] = 0.22 + Math.random() * 0.62;\n      live.at[bar] = time;\n    }\n\n    live.now[bar] += (live.goal[bar] - live.now[bar]) * 0.32;\n\n    return live.now[bar];\n  },\n  train: (_live, time, bar) => {\n    const seconds = time / 1000;\n    const beat = seconds % 1.2;\n    const clack = Math.exp(-beat * 10) + (beat > 0.22 ? 0.85 * Math.exp(-(beat - 0.22) * 10) : 0);\n\n    return (\n      0.2 +\n      0.06 * Math.sin(seconds * 3.1 + bar * 0.45) +\n      0.62 * clack * (0.45 + 0.55 * Math.sin(bar * 0.8 + 1.2) ** 2)\n    );\n  },\n  wind: (_live, time, bar) => {\n    const seconds = time / 1000;\n\n    return (\n      0.12 +\n      0.8 *\n        (0.5 + 0.5 * Math.sin(seconds * 0.95 - bar * 0.21)) *\n        (0.5 + 0.5 * Math.sin(seconds * 0.33 + bar * 0.04))\n    );\n  },\n};\n\nconst restHeights = (kind: SceneKind) => Array.from({ length: BARS }, (_, bar) => REST[kind](bar));\n\nconst barScale = (value: number) => `scaleY(${Math.min(1, Math.max(0.05, value)).toFixed(3)})`;\n\nconst clock = (seconds: number) =>\n  `${Math.floor(seconds / 60)}:${String(seconds % 60).padStart(2, '0')}`;\n\nfunction paint(wave: HTMLElement | null, heights: number[]) {\n  wave?.querySelectorAll<HTMLElement>('.still-scene-bar').forEach((bar, index) => {\n    bar.style.transform = barScale(heights[index]);\n  });\n}\n\nfunction SceneCard({\n  scene,\n  elapsed,\n  playing,\n  onToggle,\n  waveRef,\n}: {\n  scene: Scene;\n  elapsed: number;\n  playing: boolean;\n  onToggle: () => void;\n  waveRef: (element: HTMLDivElement | null) => void;\n}) {\n  const titleId = `still-scene-${scene.kind}`;\n\n  return (\n    <article aria-labelledby={titleId} className=\"still-scene still-rise\" data-playing={playing}>\n      <div className=\"still-scene-art\">{scene.art}</div>\n      <GlassPanel className=\"still-scene-body still-pane\" lens variant=\"card\">\n        <div className=\"still-scene-head\">\n          <h3 className=\"still-scene-title\" id={titleId}>\n            {scene.title}\n          </h3>\n          <GlassBadge>60 min</GlassBadge>\n        </div>\n        <p className=\"still-scene-description\">{scene.description}</p>\n        <div ref={waveRef} aria-hidden className=\"still-scene-wave\">\n          {restHeights(scene.kind).map((height, bar) => (\n            <span key={bar} className=\"still-scene-bar\" style={{ transform: barScale(height) }} />\n          ))}\n        </div>\n        <div className=\"still-scene-foot\">\n          <GlassButton className=\"still-scene-toggle still-button\" lens={false} onClick={onToggle}>\n            {playing ? <PauseIcon /> : <PlayIcon />}\n            {playing ? 'Pause' : 'Play'}\n            <span className=\"still-sr-only\"> {scene.title}</span>\n          </GlassButton>\n          <span className=\"still-scene-time\">\n            <span className=\"still-sr-only\">Elapsed </span>\n            <time>{clock(elapsed)}</time> / {clock(LENGTH)}\n          </span>\n        </div>\n      </GlassPanel>\n    </article>\n  );\n}\n\n/**\n * Three sound scenes, one playing at a time. The previews are silent: a scene's artwork moves\n * and its waveform plays while its clock runs.\n */\nexport function SoundScenes() {\n  const sectionRef = useRef<HTMLElement>(null);\n  const wavesRef = useRef<(HTMLDivElement | null)[]>([]);\n  const [current, setCurrent] = useState<number | null>(null);\n  const [elapsed, setElapsed] = useState(() => SCENES.map(() => 0));\n  const [onScreen, setOnScreen] = useState(true);\n\n  useEffect(() => {\n    const section = sectionRef.current;\n\n    if (!section) return;\n\n    const observer = new IntersectionObserver(([entry]) => setOnScreen(entry.isIntersecting));\n\n    observer.observe(section);\n\n    return () => observer.disconnect();\n  }, []);\n\n  // Where the playing scene's clock started, so it knows when its hour is up.\n  const startedAtRef = useRef(0);\n\n  // The playing scene's clock, until the hour is up.\n  useEffect(() => {\n    if (current === null) return;\n\n    let seconds = startedAtRef.current;\n\n    const timer = window.setInterval(() => {\n      seconds = Math.min(LENGTH, seconds + 1);\n      setElapsed((times) => times.map((time, index) => (index === current ? seconds : time)));\n\n      if (seconds >= LENGTH) setCurrent(null);\n    }, 1000);\n\n    return () => window.clearInterval(timer);\n  }, [current]);\n\n  // The playing scene's waveform, while it is on screen. With motion reduced it holds one\n  // louder shape instead of moving.\n  useEffect(() => {\n    if (current === null) return;\n\n    const scene = SCENES[current];\n    const wave = wavesRef.current[current];\n    const rest = restHeights(scene.kind);\n\n    if (motionReduced()) {\n      paint(\n        wave,\n        rest.map((height, bar) => height * 2.3 + 0.14 * Math.abs(Math.sin(bar * 1.3))),\n      );\n\n      return () => paint(wave, rest);\n    }\n\n    if (!onScreen) return;\n\n    const live: Live = { now: rest.slice(), goal: rest.slice(), at: rest.map(() => 0) };\n    const started = performance.now();\n    const bars = wave ? [...wave.querySelectorAll<HTMLElement>('.still-scene-bar')] : [];\n    let frame = requestAnimationFrame(step);\n\n    function step(time: number) {\n      const ramp = 1 - (1 - Math.min(1, (time - started) / 700)) ** 3;\n\n      bars.forEach((bar, index) => {\n        const height = LIVE[scene.kind](live, time, index);\n\n        bar.style.transform = barScale(rest[index] + (height - rest[index]) * ramp);\n      });\n\n      frame = requestAnimationFrame(step);\n    }\n\n    return () => {\n      cancelAnimationFrame(frame);\n      paint(wave, rest);\n    };\n  }, [current, onScreen]);\n\n  return (\n    <section\n      ref={sectionRef}\n      aria-labelledby=\"still-sounds-title\"\n      className=\"still-section still-sounds\"\n      data-away={onScreen ? undefined : ''}\n      id=\"sounds\"\n    >\n      <div className=\"still-wrap\">\n        <header className=\"still-rise\">\n          <p className=\"still-eyebrow\">Sound scenes</p>\n          <h2 className=\"still-h2\" id=\"still-sounds-title\">\n            Rooms to fall asleep in.\n          </h2>\n          <p className=\"still-lede\">\n            Each scene is one unbroken hour, recorded where it happened and mixed to sit quietly\n            under a bedside phone. Previews here are silent; press play to watch one move.\n          </p>\n        </header>\n        <div className=\"still-scenes\">\n          {SCENES.map((scene, index) => (\n            <SceneCard\n              key={scene.kind}\n              elapsed={elapsed[index]}\n              playing={current === index}\n              scene={scene}\n              waveRef={(element) => {\n                wavesRef.current[index] = element;\n              }}\n              onToggle={() => {\n                startedAtRef.current = elapsed[index] >= LENGTH ? 0 : elapsed[index];\n                setCurrent(current === index ? null : index);\n              }}\n            />\n          ))}\n        </div>\n      </div>\n    </section>\n  );\n}\n",
      "type": "registry:component",
      "target": "components/glassyui/templates/still/sound-scenes.tsx"
    },
    {
      "path": "registry/glassyui/templates/still/scene-art.tsx",
      "content": "/*\n  The sound scenes' artwork. Each is drawn 1:1 in CSS pixels from the top, so its brightest line\n  crosses the pane's rim, where the lens bends it. The parts that move carry still-scene-move or\n  still-scene-grass and run only while their scene plays.\n*/\n\n// The corrugated tin roof: one ridge every 14 px across the scene.\nconst ROOF = `M0 152 ${'q7 -10 14 0 '.repeat(65)}`;\n\n/** A shed roof in steady rain, falling in two layers. */\nexport function RainArt() {\n  return (\n    <svg aria-hidden focusable=\"false\" viewBox=\"0 0 900 520\" preserveAspectRatio=\"xMidYMin slice\">\n      <defs>\n        <linearGradient id=\"still-rn-bg\" x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\">\n          <stop offset=\"0\" stopColor=\"#1c1838\" />\n          <stop offset=\".3\" stopColor=\"#3b3170\" />\n          <stop offset=\"1\" stopColor=\"#231c45\" />\n        </linearGradient>\n        <radialGradient id=\"still-rn-glow\" gradientUnits=\"userSpaceOnUse\" cx=\"560\" cy=\"24\" r=\"250\">\n          <stop offset=\"0\" stopColor=\"#c9b8ff\" stopOpacity=\".5\" />\n          <stop offset=\"1\" stopColor=\"#c9b8ff\" stopOpacity=\"0\" />\n        </radialGradient>\n        <pattern id=\"still-rn-far\" width=\"30\" height=\"165\" patternUnits=\"userSpaceOnUse\">\n          <path\n            d=\"M24 10l-4 22M9 70l-3 16.5M18 118l-4 22\"\n            stroke=\"#d6ccff\"\n            strokeOpacity=\".28\"\n            strokeWidth=\"1\"\n            strokeLinecap=\"round\"\n          />\n        </pattern>\n        <pattern id=\"still-rn-near\" width=\"40\" height=\"220\" patternUnits=\"userSpaceOnUse\">\n          <path\n            d=\"M30 20l-6 33M12 110l-5 27.5M36 160l-6 33\"\n            stroke=\"#efe9ff\"\n            strokeOpacity=\".5\"\n            strokeWidth=\"1.5\"\n            strokeLinecap=\"round\"\n          />\n        </pattern>\n        <linearGradient id=\"still-rn-tin\" x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\">\n          <stop offset=\"0\" stopColor=\"#8276bd\" />\n          <stop offset=\".07\" stopColor=\"#4c4184\" />\n          <stop offset=\".42\" stopColor=\"#2d2558\" />\n          <stop offset=\"1\" stopColor=\"#1b1633\" />\n        </linearGradient>\n        <pattern id=\"still-rn-ridge\" width=\"14\" height=\"12\" patternUnits=\"userSpaceOnUse\">\n          <rect x=\"1.5\" width=\"4.5\" height=\"12\" fill=\"#fff\" fillOpacity=\".16\" />\n          <rect x=\"8.5\" width=\"4\" height=\"12\" fill=\"#0b0720\" fillOpacity=\".3\" />\n        </pattern>\n        <linearGradient id=\"still-rn-fade\" x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\">\n          <stop offset=\"0\" stopColor=\"#fff\" />\n          <stop offset=\"1\" stopColor=\"#fff\" stopOpacity=\"0\" />\n        </linearGradient>\n        <mask id=\"still-rn-mask\">\n          <rect y=\"148\" width=\"900\" height=\"300\" fill=\"url(#still-rn-fade)\" />\n        </mask>\n      </defs>\n      <rect width=\"900\" height=\"520\" fill=\"url(#still-rn-bg)\" />\n      <rect width=\"900\" height=\"520\" fill=\"url(#still-rn-glow)\" />\n      <g className=\"still-scene-move still-scene-move--rain-far\">\n        <rect x=\"-60\" y=\"-165\" width=\"1020\" height=\"700\" fill=\"url(#still-rn-far)\" />\n      </g>\n      <path fill=\"url(#still-rn-tin)\" d={`${ROOF}V520 H0Z`} />\n      <rect\n        y=\"146\"\n        width=\"900\"\n        height=\"300\"\n        fill=\"url(#still-rn-ridge)\"\n        mask=\"url(#still-rn-mask)\"\n      />\n      <path fill=\"none\" stroke=\"#cfc4ff\" strokeOpacity=\".5\" strokeWidth=\"1.2\" d={ROOF} />\n      <g fill=\"#efe9ff\" fillOpacity=\".65\">\n        <ellipse cx=\"301\" cy=\"145.6\" rx=\"3.5\" ry=\"1\" />\n        <ellipse cx=\"371\" cy=\"145.6\" rx=\"2.5\" ry=\".8\" />\n        <ellipse cx=\"455\" cy=\"145.6\" rx=\"3\" ry=\"1\" />\n        <ellipse cx=\"525\" cy=\"145.6\" rx=\"2.5\" ry=\".8\" />\n        <ellipse cx=\"595\" cy=\"145.6\" rx=\"3.5\" ry=\"1\" />\n        <ellipse cx=\"231\" cy=\"145.6\" rx=\"3\" ry=\"1\" />\n        <ellipse cx=\"665\" cy=\"145.6\" rx=\"2.5\" ry=\".8\" />\n      </g>\n      <g className=\"still-scene-move still-scene-move--rain-near\">\n        <rect x=\"-80\" y=\"-220\" width=\"1060\" height=\"800\" fill=\"url(#still-rn-near)\" />\n      </g>\n    </svg>\n  );\n}\n\n/** A sleeper train passing under the moon, its windows lit. */\nexport function TrainArt() {\n  return (\n    <svg aria-hidden focusable=\"false\" viewBox=\"0 0 900 520\" preserveAspectRatio=\"xMidYMin slice\">\n      <defs>\n        <linearGradient\n          id=\"still-tr-bg\"\n          gradientUnits=\"userSpaceOnUse\"\n          x1=\"0\"\n          y1=\"0\"\n          x2=\"0\"\n          y2=\"520\"\n        >\n          <stop offset=\"0\" stopColor=\"#16132e\" />\n          <stop offset=\".2\" stopColor=\"#2f2350\" />\n          <stop offset=\".3\" stopColor=\"#4c2d5c\" />\n          <stop offset=\".5\" stopColor=\"#1e1634\" />\n        </linearGradient>\n        <radialGradient id=\"still-tr-moon\">\n          <stop offset=\"0\" stopColor=\"#f3e8ff\" stopOpacity=\".55\" />\n          <stop offset=\"1\" stopColor=\"#f3e8ff\" stopOpacity=\"0\" />\n        </radialGradient>\n        <pattern\n          id=\"still-tr-win\"\n          x=\"0\"\n          y=\"170\"\n          width=\"46\"\n          height=\"30\"\n          patternUnits=\"userSpaceOnUse\"\n        >\n          <rect x=\"9\" y=\"2\" width=\"26\" height=\"22\" rx=\"5\" fill=\"#ffd6a3\" />\n          <rect x=\"9\" y=\"2\" width=\"26\" height=\"7\" rx=\"3.5\" fill=\"#fff3df\" fillOpacity=\".6\" />\n        </pattern>\n        <pattern\n          id=\"still-tr-sleep\"\n          x=\"0\"\n          y=\"215\"\n          width=\"23\"\n          height=\"8\"\n          patternUnits=\"userSpaceOnUse\"\n        >\n          <rect width=\"11\" height=\"3\" rx=\"1\" fill=\"#3e2f5c\" />\n        </pattern>\n        <linearGradient id=\"still-tr-pool\" x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\">\n          <stop offset=\"0\" stopColor=\"#ffc98f\" stopOpacity=\".34\" />\n          <stop offset=\"1\" stopColor=\"#ffc98f\" stopOpacity=\"0\" />\n        </linearGradient>\n        <pattern\n          id=\"still-tr-refl\"\n          x=\"0\"\n          y=\"222\"\n          width=\"46\"\n          height=\"70\"\n          patternUnits=\"userSpaceOnUse\"\n        >\n          <rect x=\"11\" width=\"22\" height=\"58\" rx=\"8\" fill=\"url(#still-tr-pool)\" />\n        </pattern>\n        <linearGradient id=\"still-tr-spill\" x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\">\n          <stop offset=\"0\" stopColor=\"#ffc98f\" stopOpacity=\".2\" />\n          <stop offset=\"1\" stopColor=\"#ffc98f\" stopOpacity=\"0\" />\n        </linearGradient>\n      </defs>\n      <rect width=\"900\" height=\"520\" fill=\"url(#still-tr-bg)\" />\n      <circle cx=\"556\" cy=\"60\" r=\"58\" fill=\"url(#still-tr-moon)\" />\n      <circle cx=\"556\" cy=\"60\" r=\"15\" fill=\"#f7f0ff\" />\n      <g fill=\"#efe9ff\">\n        <circle cx=\"296\" cy=\"34\" r=\"1.1\" opacity=\".7\" />\n        <circle cx=\"352\" cy=\"74\" r=\".8\" opacity=\".6\" />\n        <circle cx=\"424\" cy=\"26\" r=\"1.2\" opacity=\".8\" />\n        <circle cx=\"482\" cy=\"98\" r=\".8\" opacity=\".5\" />\n        <circle cx=\"626\" cy=\"116\" r=\"1\" opacity=\".6\" />\n        <circle cx=\"386\" cy=\"108\" r=\".9\" opacity=\".5\" />\n        <circle cx=\"270\" cy=\"102\" r=\".8\" opacity=\".5\" />\n        <circle cx=\"666\" cy=\"40\" r=\".9\" opacity=\".6\" />\n        <circle cx=\"160\" cy=\"60\" r=\"1\" opacity=\".5\" />\n        <circle cx=\"760\" cy=\"84\" r=\"1\" opacity=\".5\" />\n      </g>\n      <path\n        d=\"M0 140C80 124 150 132 230 122S350 112 420 126S520 112 600 122S720 136 790 120S870 124 900 130V520H0Z\"\n        fill=\"#2a1c40\"\n      />\n      <rect x=\"-20\" y=\"162\" width=\"940\" height=\"48\" rx=\"12\" fill=\"#110d20\" />\n      <g className=\"still-scene-move still-scene-move--train\">\n        <rect x=\"-46\" y=\"170\" width=\"992\" height=\"30\" fill=\"url(#still-tr-win)\" />\n      </g>\n      <rect y=\"210\" width=\"900\" height=\"310\" fill=\"#19132b\" />\n      <rect y=\"210\" width=\"900\" height=\"90\" fill=\"url(#still-tr-spill)\" />\n      <path d=\"M0 213.5H900\" stroke=\"#5c4c7e\" strokeWidth=\"1.2\" />\n      <g className=\"still-scene-move still-scene-move--train\">\n        <rect x=\"-46\" y=\"215\" width=\"992\" height=\"4\" fill=\"url(#still-tr-sleep)\" />\n        <rect x=\"-46\" y=\"222\" width=\"992\" height=\"70\" fill=\"url(#still-tr-refl)\" />\n      </g>\n    </svg>\n  );\n}\n\n/** Dune grass above a far sea at dusk, with the wind going through it. */\nexport function WindArt() {\n  return (\n    <svg aria-hidden focusable=\"false\" viewBox=\"0 0 900 520\" preserveAspectRatio=\"xMidYMin slice\">\n      <defs>\n        <linearGradient\n          id=\"still-wd-bg\"\n          gradientUnits=\"userSpaceOnUse\"\n          x1=\"0\"\n          y1=\"0\"\n          x2=\"0\"\n          y2=\"520\"\n        >\n          <stop offset=\"0\" stopColor=\"#19163a\" />\n          <stop offset=\".17\" stopColor=\"#2d2452\" />\n          <stop offset=\".265\" stopColor=\"#7a4868\" />\n          <stop offset=\".298\" stopColor=\"#cd889c\" />\n          <stop offset=\".303\" stopColor=\"#43305e\" />\n          <stop offset=\".42\" stopColor=\"#271d42\" />\n          <stop offset=\"1\" stopColor=\"#1a1530\" />\n        </linearGradient>\n        <linearGradient id=\"still-wd-sea\" x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\">\n          <stop offset=\"0\" stopColor=\"#e79ab0\" stopOpacity=\".42\" />\n          <stop offset=\"1\" stopColor=\"#e79ab0\" stopOpacity=\"0\" />\n        </linearGradient>\n        <pattern id=\"still-wd-streak\" width=\"190\" height=\"150\" patternUnits=\"userSpaceOnUse\">\n          <path\n            d=\"M10 30q40-6 90 0M70 74q50-8 110-2M0 118q30-4 70 0\"\n            fill=\"none\"\n            stroke=\"#f4ecff\"\n            strokeOpacity=\".34\"\n            strokeWidth=\"1.2\"\n            strokeLinecap=\"round\"\n          />\n        </pattern>\n      </defs>\n      <rect width=\"900\" height=\"520\" fill=\"url(#still-wd-bg)\" />\n      <rect y=\"158\" width=\"900\" height=\"34\" fill=\"url(#still-wd-sea)\" />\n      <g fill=\"#efe9ff\">\n        <circle cx=\"314\" cy=\"30\" r=\"1\" opacity=\".6\" />\n        <circle cx=\"406\" cy=\"54\" r=\".8\" opacity=\".5\" />\n        <circle cx=\"502\" cy=\"22\" r=\"1.2\" opacity=\".7\" />\n        <circle cx=\"586\" cy=\"70\" r=\".9\" opacity=\".5\" />\n        <circle cx=\"210\" cy=\"64\" r=\"1\" opacity=\".5\" />\n        <circle cx=\"700\" cy=\"40\" r=\".9\" opacity=\".6\" />\n      </g>\n      <g className=\"still-scene-move still-scene-move--wind\">\n        <rect width=\"1090\" height=\"140\" fill=\"url(#still-wd-streak)\" />\n      </g>\n      <g\n        className=\"still-scene-grass\"\n        fill=\"none\"\n        stroke=\"#c3b2ec\"\n        strokeOpacity=\".62\"\n        strokeWidth=\"1.1\"\n        strokeLinecap=\"round\"\n      >\n        <path d=\"M205.8 192q-4.9 -8.0 -13.6 -14.6M206.6 192q-3.5 -12.7 -10.1 -23.1M207.3 192q-2.6 -11.3 -9.4 -20.6M208.0 192q-1.1 -18.1 -5.5 -32.9M208.7 192q0.4 -13.6 -1.6 -24.7M209.4 192q1.5 -8.4 0.1 -15.2M210.2 192q3.0 -10.5 4.1 -19.0\" />\n      </g>\n      <g\n        className=\"still-scene-grass\"\n        fill=\"none\"\n        stroke=\"#c3b2ec\"\n        strokeOpacity=\".62\"\n        strokeWidth=\"1.1\"\n        strokeLinecap=\"round\"\n      >\n        <path d=\"M297.5 187q-5.1 -13.6 -13.0 -24.8M298.2 187q-3.7 -11.3 -9.4 -20.6M298.9 187q-3.4 -19.6 -11.4 -35.7M299.6 187q-2.0 -20.7 -8.2 -37.7M300.4 187q-0.4 -12.4 -4.0 -22.6M301.1 187q1.0 -15.2 -0.3 -27.6M301.8 187q1.9 -17.0 0.5 -30.8M302.5 187q2.5 -9.3 0.1 -16.9\" />\n      </g>\n      <g\n        className=\"still-scene-grass\"\n        fill=\"none\"\n        stroke=\"#c3b2ec\"\n        strokeOpacity=\".62\"\n        strokeWidth=\"1.1\"\n        strokeLinecap=\"round\"\n      >\n        <path d=\"M395.7 184q-5.4 -8.2 -15.7 -15.0M396.5 184q-3.7 -12.1 -11.1 -22.0M397.2 184q-2.4 -13.0 -8.1 -23.6M398.0 184q-0.6 -13.3 -3.1 -24.1M398.8 184q0.4 -17.3 -1.7 -31.5M399.5 184q1.7 -14.4 1.0 -26.3M400.3 184q2.2 -13.4 -0.3 -24.4\" />\n      </g>\n      <g\n        className=\"still-scene-grass\"\n        fill=\"none\"\n        stroke=\"#c3b2ec\"\n        strokeOpacity=\".62\"\n        strokeWidth=\"1.1\"\n        strokeLinecap=\"round\"\n      >\n        <path d=\"M549.4 189q-6.1 -14.0 -17.1 -25.4M550.1 189q-4.8 -14.7 -14.4 -26.8M550.9 189q-3.2 -12.4 -10.2 -22.6M551.6 189q-1.6 -21.2 -5.9 -38.5M552.4 189q-1.2 -22.2 -7.9 -40.4M553.1 189q0.7 -15.1 -1.9 -27.5M553.9 189q2.0 -13.7 0.4 -24.9M554.6 189q3.2 -15.7 2.9 -28.5\" />\n      </g>\n      <g\n        className=\"still-scene-grass\"\n        fill=\"none\"\n        stroke=\"#c3b2ec\"\n        strokeOpacity=\".62\"\n        strokeWidth=\"1.1\"\n        strokeLinecap=\"round\"\n      >\n        <path d=\"M643.8 193q-4.2 -7.2 -10.4 -13.2M644.6 193q-4.0 -13.3 -12.9 -24.1M645.3 193q-2.3 -13.5 -7.8 -24.6M646.0 193q-1.3 -15.8 -6.7 -28.7M646.7 193q0.0 -11.4 -3.6 -20.7M647.4 193q1.2 -12.2 -1.3 -22.1M648.2 193q2.9 -8.1 3.6 -14.8\" />\n      </g>\n      <g\n        className=\"still-scene-grass\"\n        fill=\"none\"\n        stroke=\"#c3b2ec\"\n        strokeOpacity=\".62\"\n        strokeWidth=\"1.1\"\n        strokeLinecap=\"round\"\n      >\n        <path d=\"M739.6 189q-5.7 -10.1 -16.6 -18.4M740.4 189q-4.0 -11.9 -11.9 -21.6M741.2 189q-2.1 -13.4 -6.3 -24.3M742.0 189q-1.6 -12.7 -7.9 -23.2M742.8 189q0.3 -17.5 -2.6 -31.8M743.6 189q1.3 -14.5 -1.7 -26.3M744.4 189q2.3 -13.6 -0.7 -24.8\" />\n      </g>\n      <path\n        d=\"M0 196C90 178 170 176 260 190S380 178 470 186S600 200 690 192S820 178 900 186V520H0Z\"\n        fill=\"#24193d\"\n      />\n      <path\n        d=\"M0 196C90 178 170 176 260 190S380 178 470 186S600 200 690 192S820 178 900 186\"\n        fill=\"none\"\n        stroke=\"#8a72b8\"\n        strokeOpacity=\".55\"\n        strokeWidth=\"1.2\"\n      />\n      <g\n        className=\"still-scene-grass\"\n        fill=\"none\"\n        stroke=\"#a593d2\"\n        strokeOpacity=\".42\"\n        strokeWidth=\"1.3\"\n        strokeLinecap=\"round\"\n      >\n        <path d=\"M258.6 250q-8.1 -14.7 -23.7 -26.7M259.6 250q-5.8 -22.7 -17.2 -41.3M260.6 250q-4.1 -24.8 -13.1 -45.1M261.5 250q-2.1 -21.0 -7.9 -38.3M262.5 250q-0.3 -27.6 -4.0 -50.2M263.4 250q0.2 -15.2 -6.2 -27.7M264.4 250q2.3 -20.7 -0.3 -37.7M265.4 250q4.7 -18.6 6.6 -33.7\" />\n      </g>\n      <g\n        className=\"still-scene-grass\"\n        fill=\"none\"\n        stroke=\"#a593d2\"\n        strokeOpacity=\".42\"\n        strokeWidth=\"1.3\"\n        strokeLinecap=\"round\"\n      >\n        <path d=\"M471.0 254q-6.2 -11.9 -15.9 -21.6M471.9 254q-4.6 -15.2 -12.2 -27.7M472.7 254q-3.4 -13.6 -10.6 -24.7M473.6 254q-2.9 -24.9 -12.6 -45.3M474.4 254q-0.8 -23.1 -5.9 -42.1M475.3 254q-0.0 -15.5 -6.7 -28.2M476.1 254q1.7 -16.2 -2.1 -29.5M477.0 254q3.9 -10.1 4.7 -18.3\" />\n      </g>\n      <g\n        className=\"still-scene-grass\"\n        fill=\"none\"\n        stroke=\"#a593d2\"\n        strokeOpacity=\".42\"\n        strokeWidth=\"1.3\"\n        strokeLinecap=\"round\"\n      >\n        <path d=\"M614.5 246q-8.1 -19.2 -22.9 -35.0M615.4 246q-6.3 -22.3 -18.3 -40.5M616.3 246q-4.8 -19.5 -15.2 -35.5M617.1 246q-2.9 -27.1 -9.9 -49.3M618.0 246q-1.4 -25.2 -6.8 -45.8M618.9 246q0.6 -26.1 -1.5 -47.4M619.7 246q0.4 -22.6 -6.8 -41.1M620.6 246q2.4 -13.2 -0.8 -24.0M621.5 246q3.4 -17.4 -0.2 -31.7\" />\n      </g>\n      <path\n        d=\"M0 262C110 238 210 244 300 256S470 252 560 246S760 262 900 250V520H0Z\"\n        fill=\"#1d1532\"\n      />\n      <path\n        d=\"M0 262C110 238 210 244 300 256S470 252 560 246S760 262 900 250\"\n        fill=\"none\"\n        stroke=\"#6f5a9a\"\n        strokeOpacity=\".4\"\n        strokeWidth=\"1.2\"\n      />\n    </svg>\n  );\n}\n",
      "type": "registry:component",
      "target": "components/glassyui/templates/still/scene-art.tsx"
    },
    {
      "path": "registry/glassyui/templates/still/story-carousel.tsx",
      "content": "'use client';\n\nimport { useEffect, useRef, useState } from 'react';\nimport type { KeyboardEvent, ReactNode } from 'react';\nimport { motionReduced } from '../../lib/liquid-motion';\nimport { GlassBadge } from '../../glass-badge';\nimport { GlassButton } from '../../glass-button';\nimport { GlassSurface } from '../../glass-surface';\nimport { LeftIcon, RightIcon } from './icons';\nimport {\n  HutArt,\n  LibraryArt,\n  LighthouseArt,\n  MapArt,\n  MarketArt,\n  ObservatoryArt,\n  OrchardArt,\n  RiverArt,\n} from './story-art';\n\ntype Story = { title: string; minutes: number; shelf: string; reader: string; art: ReactNode };\n\nconst STORIES: Story[] = [\n  {\n    title: 'The lighthouse keeper’s last winter',\n    minutes: 34,\n    shelf: 'Coastal',\n    reader: 'Ines Varga',\n    art: <LighthouseArt />,\n  },\n  {\n    title: 'A slow boat up the river',\n    minutes: 29,\n    shelf: 'Travel',\n    reader: 'Tomas Hale',\n    art: <RiverArt />,\n  },\n  {\n    title: 'The library after closing',\n    minutes: 31,\n    shelf: 'Quiet places',\n    reader: 'Ruth Okafor',\n    art: <LibraryArt />,\n  },\n  {\n    title: 'Night market, after rain',\n    minutes: 26,\n    shelf: 'City',\n    reader: 'Kenji Arai',\n    art: <MarketArt />,\n  },\n  {\n    title: 'The orchard in October',\n    minutes: 38,\n    shelf: 'Seasons',\n    reader: 'Margit Sole',\n    art: <OrchardArt />,\n  },\n  {\n    title: 'Letters from a mountain hut',\n    minutes: 33,\n    shelf: 'Mountains',\n    reader: 'Ada Brennan',\n    art: <HutArt />,\n  },\n  {\n    title: 'The cartographer’s quiet year',\n    minutes: 41,\n    shelf: 'Fiction',\n    reader: 'Felix Mora',\n    art: <MapArt />,\n  },\n  {\n    title: 'Snow on the observatory',\n    minutes: 27,\n    shelf: 'Winter',\n    reader: 'Noor Haddad',\n    art: <ObservatoryArt />,\n  },\n];\n\ntype View = { first: number; last: number; atStart: boolean; atEnd: boolean };\n\n/**\n * The buttons and the arrow keys move one story; Home and End go to either end. The count says\n * which stories are in view.\n */\nexport function StoryCarousel() {\n  const trackRef = useRef<HTMLUListElement>(null);\n  const [view, setView] = useState<View>({ first: 1, last: 4, atStart: true, atEnd: false });\n\n  const stride = () => {\n    const [first, second] = trackRef.current?.querySelectorAll('li') ?? [];\n\n    if (!first || !second) return trackRef.current?.clientWidth ?? 0;\n\n    return second.offsetLeft - first.offsetLeft;\n  };\n\n  useEffect(() => {\n    const track = trackRef.current;\n\n    if (!track) return;\n\n    let frame = 0;\n\n    const update = () => {\n      frame = 0;\n\n      const step = stride();\n      const style = getComputedStyle(track);\n      const gap = Number.parseFloat(style.columnGap) || 0;\n      const inner = track.clientWidth - Number.parseFloat(style.paddingLeft);\n      const end = track.scrollWidth - track.clientWidth;\n      const x = track.scrollLeft;\n      const visible = Math.max(1, Math.floor((inner + gap) / step + 0.04));\n      let first = Math.min(STORIES.length, Math.round(x / step) + 1);\n\n      if (x >= end - 2) first = Math.max(1, STORIES.length - visible + 1);\n\n      const next = {\n        first,\n        last: Math.min(STORIES.length, first + visible - 1),\n        atStart: x <= 2,\n        atEnd: x >= end - 2,\n      };\n\n      setView((shown) =>\n        shown.first === next.first &&\n        shown.last === next.last &&\n        shown.atStart === next.atStart &&\n        shown.atEnd === next.atEnd\n          ? shown\n          : next,\n      );\n    };\n\n    const schedule = () => {\n      if (!frame) frame = requestAnimationFrame(update);\n    };\n\n    const observer = new ResizeObserver(schedule);\n\n    observer.observe(track);\n    track.addEventListener('scroll', schedule, { passive: true });\n\n    return () => {\n      cancelAnimationFrame(frame);\n      observer.disconnect();\n      track.removeEventListener('scroll', schedule);\n    };\n  }, []);\n\n  const behavior = (): ScrollBehavior => (motionReduced() ? 'auto' : 'smooth');\n\n  const go = (direction: 1 | -1) => {\n    trackRef.current?.scrollBy({ left: direction * stride(), behavior: behavior() });\n  };\n\n  const onKeyDown = (event: KeyboardEvent<HTMLElement>) => {\n    const track = trackRef.current;\n\n    if (!track) return;\n\n    if (event.key === 'ArrowRight' || event.key === 'ArrowLeft') {\n      event.preventDefault();\n      go(event.key === 'ArrowRight' ? 1 : -1);\n    } else if (event.target === track && (event.key === 'Home' || event.key === 'End')) {\n      event.preventDefault();\n      track.scrollTo({ left: event.key === 'Home' ? 0 : track.scrollWidth, behavior: behavior() });\n    }\n  };\n\n  const count =\n    view.first === view.last\n      ? `${view.first} of ${STORIES.length}`\n      : `${view.first}–${view.last} of ${STORIES.length}`;\n\n  return (\n    <section\n      aria-labelledby=\"still-stories-title\"\n      className=\"still-section still-stories\"\n      id=\"stories\"\n    >\n      <div\n        aria-labelledby=\"still-stories-title\"\n        aria-roledescription=\"carousel\"\n        className=\"still-carousel\"\n        role=\"region\"\n        onKeyDown={onKeyDown}\n      >\n        <div className=\"still-wrap still-carousel-bar\">\n          <header className=\"still-rise\">\n            <p className=\"still-eyebrow\">Sleep stories</p>\n            <h2 className=\"still-h2\" id=\"still-stories-title\">\n              Stories that don’t go anywhere.\n            </h2>\n            <p className=\"still-lede\">\n              Unhurried tales read by voices chosen for how little they rush. Most listeners drift\n              off before the middle. A new one arrives every Sunday.\n            </p>\n          </header>\n          <div className=\"still-carousel-controls\">\n            <GlassButton\n              aria-controls=\"still-story-track\"\n              aria-disabled={view.atStart}\n              aria-label=\"Previous story\"\n              className=\"still-carousel-button still-button\"\n              lens={false}\n              onClick={() => {\n                if (!view.atStart) go(-1);\n              }}\n            >\n              <LeftIcon />\n            </GlassButton>\n            <span aria-live=\"polite\" className=\"still-carousel-count\">\n              {count}\n            </span>\n            <GlassButton\n              aria-controls=\"still-story-track\"\n              aria-disabled={view.atEnd}\n              aria-label=\"Next story\"\n              className=\"still-carousel-button still-button\"\n              lens={false}\n              onClick={() => {\n                if (!view.atEnd) go(1);\n              }}\n            >\n              <RightIcon />\n            </GlassButton>\n          </div>\n        </div>\n        <ul\n          ref={trackRef}\n          aria-label=\"Sleep stories. Use the arrow keys to move through them.\"\n          className=\"still-carousel-track\"\n          id=\"still-story-track\"\n          tabIndex={0}\n        >\n          {STORIES.map((story, index) => (\n            <li key={story.title} className=\"still-carousel-item\">\n              <article aria-labelledby={`still-story-${index}`} className=\"still-story\">\n                {story.art}\n                <GlassSurface className=\"still-story-meta still-pane\" lens>\n                  <div className=\"still-story-chips\">\n                    <GlassBadge>{story.minutes} min</GlassBadge>\n                    {story.shelf}\n                  </div>\n                  <h3 id={`still-story-${index}`}>{story.title}</h3>\n                  <p>Read by {story.reader}</p>\n                </GlassSurface>\n              </article>\n            </li>\n          ))}\n        </ul>\n      </div>\n    </section>\n  );\n}\n",
      "type": "registry:component",
      "target": "components/glassyui/templates/still/story-carousel.tsx"
    },
    {
      "path": "registry/glassyui/templates/still/story-art.tsx",
      "content": "/* The sleep stories' covers, each drawn on a 300 by 400 canvas that fills its card. */\n\nexport function LighthouseArt() {\n  return (\n    <svg\n      focusable=\"false\"\n      className=\"still-story-art\"\n      viewBox=\"0 0 300 400\"\n      preserveAspectRatio=\"xMidYMid slice\"\n      aria-hidden\n    >\n      <defs>\n        <linearGradient id=\"still-s1a\" x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\">\n          <stop offset=\"0\" stopColor=\"#151f3e\" />\n          <stop offset=\".6\" stopColor=\"#3b3a74\" />\n          <stop offset=\".6\" stopColor=\"#1a2244\" />\n          <stop offset=\"1\" stopColor=\"#111932\" />\n        </linearGradient>\n        <linearGradient id=\"still-s1b\" x1=\"1\" y1=\"0\" x2=\"0\" y2=\"0\">\n          <stop offset=\"0\" stopColor=\"#fff1d6\" stopOpacity=\".75\" />\n          <stop offset=\"1\" stopColor=\"#fff1d6\" stopOpacity=\"0\" />\n        </linearGradient>\n      </defs>\n      <rect width=\"300\" height=\"400\" fill=\"url(#still-s1a)\" />\n      <g fill=\"#e6dcff\">\n        <circle cx=\"40\" cy=\"40\" r=\"1.2\" />\n        <circle cx=\"92\" cy=\"24\" r=\".9\" />\n        <circle cx=\"150\" cy=\"58\" r=\"1.1\" />\n        <circle cx=\"262\" cy=\"40\" r=\"1.3\" />\n        <circle cx=\"118\" cy=\"140\" r=\".8\" />\n        <circle cx=\"56\" cy=\"190\" r=\"1\" />\n      </g>\n      <path d=\"M212 116 0 64v108Z\" fill=\"url(#still-s1b)\" />\n      <path d=\"M200 240 207 122h14l7 118Z\" fill=\"#dcd4f0\" />\n      <path d=\"M206.2 150h15.6M204.6 180h18.8M203 210h22\" stroke=\"#3b3a74\" strokeWidth=\"8\" />\n      <rect x=\"205\" y=\"104\" width=\"18\" height=\"16\" rx=\"3\" fill=\"#fff1d6\" />\n      <path d=\"M200 106h28l-14-13Z\" fill=\"#dcd4f0\" />\n      <path d=\"M140 244q30-16 64-8t96-2v14H140Z\" fill=\"#121a36\" />\n      <g stroke=\"#e6dcff\" strokeOpacity=\".28\" strokeWidth=\"1.4\" strokeLinecap=\"round\">\n        <path d=\"M30 276h40M112 288h62M206 272h52M56 312h72M174 330h84M24 352h50\" />\n      </g>\n    </svg>\n  );\n}\n\nexport function RiverArt() {\n  return (\n    <svg\n      focusable=\"false\"\n      className=\"still-story-art\"\n      viewBox=\"0 0 300 400\"\n      preserveAspectRatio=\"xMidYMid slice\"\n      aria-hidden\n    >\n      <defs>\n        <linearGradient id=\"still-s2a\" x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\">\n          <stop offset=\"0\" stopColor=\"#0f2638\" />\n          <stop offset=\".55\" stopColor=\"#2b3a66\" />\n          <stop offset=\"1\" stopColor=\"#1a2a48\" />\n        </linearGradient>\n        <radialGradient id=\"still-s2b\">\n          <stop offset=\"0\" stopColor=\"#f4eefe\" stopOpacity=\".45\" />\n          <stop offset=\"1\" stopColor=\"#f4eefe\" stopOpacity=\"0\" />\n        </radialGradient>\n        <linearGradient id=\"still-s2c\" x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\">\n          <stop offset=\"0\" stopColor=\"#2a4c6e\" />\n          <stop offset=\"1\" stopColor=\"#0d1828\" />\n        </linearGradient>\n        <radialGradient id=\"still-s2d\" cx=\".5\" cy=\"0\" r=\".5\" fx=\".5\" fy=\"0\">\n          <stop offset=\"0\" stopColor=\"#f4eefe\" stopOpacity=\".24\" />\n          <stop offset=\".55\" stopColor=\"#f4eefe\" stopOpacity=\".07\" />\n          <stop offset=\"1\" stopColor=\"#f4eefe\" stopOpacity=\"0\" />\n        </radialGradient>\n      </defs>\n      <rect width=\"300\" height=\"400\" fill=\"url(#still-s2a)\" />\n      <circle cx=\"84\" cy=\"92\" r=\"64\" fill=\"url(#still-s2b)\" />\n      <circle cx=\"84\" cy=\"92\" r=\"20\" fill=\"#f4eefe\" />\n      <path d=\"M0 206C60 192 120 212 180 202S260 192 300 204V230H0Z\" fill=\"#0f1f30\" />\n      <rect y=\"228\" width=\"300\" height=\"172\" fill=\"url(#still-s2c)\" />\n      <rect x=\"34\" y=\"228\" width=\"100\" height=\"172\" fill=\"url(#still-s2d)\" />\n      <g stroke=\"#f4eefe\" strokeLinecap=\"round\" strokeWidth=\"1.3\">\n        <path d=\"M82.8 232.9h2.8M84.8 232.9h3.3\" opacity=\"0.49\" />\n        <path d=\"M82.2 236.4h2.2M81.2 236.4h4.3\" opacity=\"0.48\" />\n        <path d=\"M81.2 240.9h5.3M84.5 240.9h3.8\" opacity=\"0.46\" />\n        <path d=\"M84.0 246.3h4.9M78.3 246.3h3.3\" opacity=\"0.45\" />\n        <path d=\"M74.5 252.3h5.2M73.2 252.3h6.0M80.1 252.3h6.0\" opacity=\"0.42\" />\n        <path d=\"M78.9 259.1h6.2M79.8 259.1h7.3M82.7 259.1h5.7\" opacity=\"0.4\" />\n        <path d=\"M77.2 266.4h7.6M64.6 266.4h8.6M70.2 266.4h6.3\" opacity=\"0.37\" />\n        <path d=\"M88.8 274.2h9.7M84.2 274.2h5.4M78.3 274.2h5.8\" opacity=\"0.34\" />\n        <path d=\"M90.1 282.5h9.0M78.1 282.5h7.0M70.3 282.5h7.3\" opacity=\"0.31\" />\n        <path d=\"M78.6 291.4h9.7M57.1 291.4h10.4M65.3 291.4h12.1\" opacity=\"0.28\" />\n        <path d=\"M103.3 300.6h11.4M48.5 300.6h7.6M99.2 300.6h13.1\" opacity=\"0.25\" />\n        <path d=\"M48.9 310.4h11.7M74.8 310.4h13.9M68.2 310.4h11.7\" opacity=\"0.21\" />\n        <path d=\"M75.0 320.5h15.4M81.5 320.5h16.6M103.3 320.5h11.4\" opacity=\"0.18\" />\n        <path d=\"M96.3 331.0h9.9M67.1 331.0h17.0M109.5 331.0h8.8\" opacity=\"0.14\" />\n      </g>\n      <path d=\"M150 300h74l-12 13h-52Z\" fill=\"#081120\" />\n      <path d=\"M186 300v-30\" stroke=\"#081120\" strokeWidth=\"2\" />\n      <circle cx=\"206\" cy=\"292\" r=\"14\" fill=\"#ffd9a8\" opacity=\".2\" />\n      <circle cx=\"206\" cy=\"292\" r=\"3.4\" fill=\"#ffd9a8\" />\n      <path\n        d=\"M196 322h22M200 334h14\"\n        stroke=\"#ffd9a8\"\n        strokeWidth=\"2\"\n        strokeLinecap=\"round\"\n        opacity=\".35\"\n      />\n    </svg>\n  );\n}\n\nexport function LibraryArt() {\n  return (\n    <svg\n      focusable=\"false\"\n      className=\"still-story-art\"\n      viewBox=\"0 0 300 400\"\n      preserveAspectRatio=\"xMidYMid slice\"\n      aria-hidden\n    >\n      <defs>\n        <linearGradient id=\"still-s3a\" x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\">\n          <stop offset=\"0\" stopColor=\"#28132e\" />\n          <stop offset=\"1\" stopColor=\"#4a2341\" />\n        </linearGradient>\n        <linearGradient id=\"still-s3b\" x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\">\n          <stop offset=\"0\" stopColor=\"#ffd9a8\" />\n          <stop offset=\"1\" stopColor=\"#f29a7c\" stopOpacity=\".75\" />\n        </linearGradient>\n      </defs>\n      <rect width=\"300\" height=\"400\" fill=\"url(#still-s3a)\" />\n      <g fill=\"url(#still-s3b)\">\n        <path d=\"M36 240V132a28 28 0 0 1 56 0v108Z\" />\n        <path d=\"M122 240V116a28 28 0 0 1 56 0v124Z\" />\n        <path d=\"M208 240V132a28 28 0 0 1 56 0v108Z\" />\n      </g>\n      <g stroke=\"#4a2341\" strokeWidth=\"3\">\n        <path d=\"M64 104V240M36 176h56M150 88V240M122 168h56M236 104V240M208 176h56\" />\n      </g>\n      <rect y=\"240\" width=\"300\" height=\"160\" fill=\"#1f0f24\" />\n      <g fill=\"#ffd9a8\" opacity=\".12\">\n        <rect x=\"36\" y=\"244\" width=\"56\" height=\"70\" />\n        <rect x=\"122\" y=\"244\" width=\"56\" height=\"90\" />\n        <rect x=\"208\" y=\"244\" width=\"56\" height=\"70\" />\n      </g>\n      <g fill=\"#5e2f52\">\n        <rect x=\"20\" y=\"300\" width=\"8\" height=\"40\" rx=\"1\" />\n        <rect x=\"30\" y=\"306\" width=\"10\" height=\"34\" rx=\"1\" />\n        <rect x=\"42\" y=\"296\" width=\"7\" height=\"44\" rx=\"1\" />\n        <rect x=\"250\" y=\"304\" width=\"9\" height=\"36\" rx=\"1\" />\n        <rect x=\"261\" y=\"298\" width=\"7\" height=\"42\" rx=\"1\" />\n        <rect x=\"270\" y=\"308\" width=\"11\" height=\"32\" rx=\"1\" />\n      </g>\n    </svg>\n  );\n}\n\nexport function MarketArt() {\n  return (\n    <svg\n      focusable=\"false\"\n      className=\"still-story-art\"\n      viewBox=\"0 0 300 400\"\n      preserveAspectRatio=\"xMidYMid slice\"\n      aria-hidden\n    >\n      <defs>\n        <linearGradient id=\"still-s4a\" x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\">\n          <stop offset=\"0\" stopColor=\"#2b1233\" />\n          <stop offset=\".62\" stopColor=\"#5a2a4a\" />\n          <stop offset=\"1\" stopColor=\"#220f28\" />\n        </linearGradient>\n      </defs>\n      <rect width=\"300\" height=\"400\" fill=\"url(#still-s4a)\" />\n      <path\n        d=\"M-10 88Q150 160 310 88\"\n        fill=\"none\"\n        stroke=\"#f0d7e8\"\n        strokeOpacity=\".45\"\n        strokeWidth=\"1.2\"\n      />\n      <g opacity=\".2\">\n        <circle cx=\"30\" cy=\"102\" r=\"22\" fill=\"#ffb38a\" />\n        <circle cx=\"90\" cy=\"120\" r=\"22\" fill=\"#ffd9a8\" />\n        <circle cx=\"150\" cy=\"124\" r=\"22\" fill=\"#f7a6b8\" />\n        <circle cx=\"210\" cy=\"120\" r=\"22\" fill=\"#ffd9a8\" />\n        <circle cx=\"270\" cy=\"102\" r=\"22\" fill=\"#ffb38a\" />\n      </g>\n      <circle cx=\"30\" cy=\"102\" r=\"10\" fill=\"#ffb38a\" />\n      <circle cx=\"90\" cy=\"120\" r=\"10\" fill=\"#ffd9a8\" />\n      <circle cx=\"150\" cy=\"124\" r=\"10\" fill=\"#f7a6b8\" />\n      <circle cx=\"210\" cy=\"120\" r=\"10\" fill=\"#ffd9a8\" />\n      <circle cx=\"270\" cy=\"102\" r=\"10\" fill=\"#ffb38a\" />\n      <path d=\"M0 250h70l20-22h50l20 22h140v150H0Z\" fill=\"#1c0b22\" />\n      <path d=\"M20 250h44M168 250h112\" stroke=\"#ffd9a8\" strokeOpacity=\".35\" strokeWidth=\"2\" />\n      <g opacity=\".22\">\n        <rect x=\"27\" y=\"286\" width=\"6\" height=\"70\" rx=\"3\" fill=\"#ffb38a\" />\n        <rect x=\"87\" y=\"292\" width=\"6\" height=\"80\" rx=\"3\" fill=\"#ffd9a8\" />\n        <rect x=\"147\" y=\"290\" width=\"6\" height=\"90\" rx=\"3\" fill=\"#f7a6b8\" />\n        <rect x=\"207\" y=\"292\" width=\"6\" height=\"76\" rx=\"3\" fill=\"#ffd9a8\" />\n        <rect x=\"267\" y=\"286\" width=\"6\" height=\"66\" rx=\"3\" fill=\"#ffb38a\" />\n      </g>\n    </svg>\n  );\n}\n\nexport function OrchardArt() {\n  return (\n    <svg\n      focusable=\"false\"\n      className=\"still-story-art\"\n      viewBox=\"0 0 300 400\"\n      preserveAspectRatio=\"xMidYMid slice\"\n      aria-hidden\n    >\n      <defs>\n        <linearGradient id=\"still-s5a\" x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\">\n          <stop offset=\"0\" stopColor=\"#12233a\" />\n          <stop offset=\"1\" stopColor=\"#2c3a5c\" />\n        </linearGradient>\n      </defs>\n      <rect width=\"300\" height=\"400\" fill=\"url(#still-s5a)\" />\n      <circle cx=\"196\" cy=\"108\" r=\"74\" fill=\"#f6efe2\" opacity=\".08\" />\n      <circle cx=\"196\" cy=\"108\" r=\"44\" fill=\"#f6efe2\" opacity=\".92\" />\n      <path d=\"M0 210C70 180 150 196 300 176V400H0Z\" fill=\"#1c3046\" />\n      <path d=\"M0 250C90 226 190 240 300 222V400H0Z\" fill=\"#162739\" />\n      <g fill=\"#25444c\">\n        <circle cx=\"40\" cy=\"196\" r=\"16\" />\n        <circle cx=\"92\" cy=\"190\" r=\"17\" />\n        <circle cx=\"146\" cy=\"190\" r=\"16\" />\n        <circle cx=\"200\" cy=\"184\" r=\"17\" />\n        <circle cx=\"254\" cy=\"180\" r=\"16\" />\n      </g>\n      <g fill=\"#1d3640\">\n        <circle cx=\"20\" cy=\"242\" r=\"20\" />\n        <circle cx=\"82\" cy=\"236\" r=\"21\" />\n        <circle cx=\"146\" cy=\"232\" r=\"20\" />\n        <circle cx=\"210\" cy=\"228\" r=\"21\" />\n        <circle cx=\"274\" cy=\"224\" r=\"20\" />\n      </g>\n      <g fill=\"#f2b98a\">\n        <circle cx=\"86\" cy=\"230\" r=\"2.4\" />\n        <circle cx=\"214\" cy=\"222\" r=\"2.4\" />\n        <circle cx=\"150\" cy=\"186\" r=\"2\" />\n      </g>\n    </svg>\n  );\n}\n\nexport function HutArt() {\n  return (\n    <svg\n      focusable=\"false\"\n      className=\"still-story-art\"\n      viewBox=\"0 0 300 400\"\n      preserveAspectRatio=\"xMidYMid slice\"\n      aria-hidden\n    >\n      <defs>\n        <linearGradient id=\"still-s6a\" x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\">\n          <stop offset=\"0\" stopColor=\"#1a1c3e\" />\n          <stop offset=\"1\" stopColor=\"#3e3b6e\" />\n        </linearGradient>\n      </defs>\n      <rect width=\"300\" height=\"400\" fill=\"url(#still-s6a)\" />\n      <g fill=\"#e6dcff\">\n        <circle cx=\"38\" cy=\"44\" r=\"1.2\" />\n        <circle cx=\"120\" cy=\"30\" r=\"1\" />\n        <circle cx=\"240\" cy=\"54\" r=\"1.3\" />\n        <circle cx=\"276\" cy=\"20\" r=\".9\" />\n        <circle cx=\"178\" cy=\"76\" r=\".8\" />\n      </g>\n      <path d=\"M0 250 80 146l50 52 70-94 100 124V400H0Z\" fill=\"#2b2c58\" />\n      <path d=\"M200 104l-17 22 10-3 9 8 12-8Z\" fill=\"#ebe6f8\" opacity=\".85\" />\n      <path d=\"M80 146l-12 16 8-2 6 5 8-6Z\" fill=\"#ebe6f8\" opacity=\".7\" />\n      <path d=\"M0 300 64 236l56 54 72-74 108 88V400H0Z\" fill=\"#1f2048\" />\n      <path d=\"M136 300h34v24h-34Z\" fill=\"#110f27\" />\n      <path d=\"M132 302l21-16 21 16Z\" fill=\"#110f27\" />\n      <circle cx=\"153\" cy=\"312\" r=\"12\" fill=\"#ffd9a8\" opacity=\".18\" />\n      <rect x=\"149\" y=\"308\" width=\"8\" height=\"8\" rx=\"1.5\" fill=\"#ffd9a8\" />\n    </svg>\n  );\n}\n\nexport function MapArt() {\n  return (\n    <svg\n      focusable=\"false\"\n      className=\"still-story-art\"\n      viewBox=\"0 0 300 400\"\n      preserveAspectRatio=\"xMidYMid slice\"\n      aria-hidden\n    >\n      <defs>\n        <linearGradient id=\"still-s7a\" x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\">\n          <stop offset=\"0\" stopColor=\"#2a2140\" />\n          <stop offset=\"1\" stopColor=\"#40325a\" />\n        </linearGradient>\n      </defs>\n      <rect width=\"300\" height=\"400\" fill=\"url(#still-s7a)\" />\n      <g fill=\"none\" stroke=\"#e6dcff\" strokeLinecap=\"round\">\n        <path\n          d=\"M150 74c62-6 118 40 116 104s-54 116-122 112S30 238 34 172 88 80 150 74Z\"\n          strokeOpacity=\".16\"\n        />\n        <path\n          d=\"M152 100c46-4 88 30 86 78s-42 88-92 84-86-40-82-88 42-70 88-74Z\"\n          strokeOpacity=\".24\"\n        />\n        <path\n          d=\"M150 126c32-2 60 22 58 54s-30 58-64 56-56-28-54-60 28-48 60-50Z\"\n          strokeOpacity=\".34\"\n        />\n        <path\n          d=\"M152 150c18-2 34 12 32 30s-18 32-36 30-30-16-28-34 16-24 32-26Z\"\n          strokeOpacity=\".5\"\n        />\n      </g>\n      <path\n        d=\"M40 340C70 320 80 290 112 268s34-60 38-84\"\n        fill=\"none\"\n        stroke=\"#ffd9a8\"\n        strokeOpacity=\".7\"\n        strokeWidth=\"2\"\n        strokeDasharray=\"2 7\"\n        strokeLinecap=\"round\"\n      />\n      <circle cx=\"150\" cy=\"182\" r=\"5\" fill=\"#ffd9a8\" />\n      <path\n        d=\"M252 40l4 12 12 4-12 4-4 12-4-12-12-4 12-4Z\"\n        fill=\"none\"\n        stroke=\"#e6dcff\"\n        strokeOpacity=\".7\"\n        strokeWidth=\"1.4\"\n        strokeLinejoin=\"round\"\n      />\n    </svg>\n  );\n}\n\nexport function ObservatoryArt() {\n  return (\n    <svg\n      focusable=\"false\"\n      className=\"still-story-art\"\n      viewBox=\"0 0 300 400\"\n      preserveAspectRatio=\"xMidYMid slice\"\n      aria-hidden\n    >\n      <defs>\n        <linearGradient id=\"still-s8a\" x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\">\n          <stop offset=\"0\" stopColor=\"#0f1834\" />\n          <stop offset=\"1\" stopColor=\"#2c2b5e\" />\n        </linearGradient>\n      </defs>\n      <rect width=\"300\" height=\"400\" fill=\"url(#still-s8a)\" />\n      <g fill=\"none\" stroke=\"#e6dcff\" strokeLinecap=\"round\" strokeWidth=\"1.2\">\n        <circle cx=\"150\" cy=\"70\" r=\"40\" strokeOpacity=\".3\" strokeDasharray=\"26 18\" />\n        <circle cx=\"150\" cy=\"70\" r=\"70\" strokeOpacity=\".26\" strokeDasharray=\"40 26\" />\n        <circle cx=\"150\" cy=\"70\" r=\"100\" strokeOpacity=\".22\" strokeDasharray=\"58 30\" />\n        <circle cx=\"150\" cy=\"70\" r=\"132\" strokeOpacity=\".18\" strokeDasharray=\"70 40\" />\n        <circle cx=\"150\" cy=\"70\" r=\"166\" strokeOpacity=\".14\" strokeDasharray=\"90 44\" />\n        <circle cx=\"150\" cy=\"70\" r=\"202\" strokeOpacity=\".1\" strokeDasharray=\"110 50\" />\n      </g>\n      <circle cx=\"150\" cy=\"70\" r=\"2\" fill=\"#fff\" />\n      <path d=\"M0 300c60-10 110-6 150-12s100-8 150 0V400H0Z\" fill=\"#141c3c\" />\n      <path d=\"M96 300a54 54 0 0 1 108 0Z\" fill=\"#0b1128\" />\n      <path d=\"M144 248h12v52h-12Z\" fill=\"#1d2a54\" />\n      <path d=\"M80 300h140v100H80Z\" fill=\"#090e22\" />\n      <g fill=\"#e6dcff\" opacity=\".7\">\n        <circle cx=\"40\" cy=\"250\" r=\".9\" />\n        <circle cx=\"262\" cy=\"232\" r=\"1.1\" />\n        <circle cx=\"230\" cy=\"266\" r=\".8\" />\n      </g>\n    </svg>\n  );\n}\n",
      "type": "registry:component",
      "target": "components/glassyui/templates/still/story-art.tsx"
    },
    {
      "path": "registry/glassyui/templates/still/evening-phone.tsx",
      "content": "'use client';\n\nimport { useId, useState } from 'react';\nimport { GlassProgress } from '../../glass-progress';\nimport { GlassSurface } from '../../glass-surface';\nimport { GlassSwitch } from '../../glass-switch';\nimport {\n  BookIcon,\n  BreathIcon,\n  FadeIcon,\n  HomeIcon,\n  MarkIcon,\n  MoonIcon,\n  RainIcon,\n  RightIcon,\n  SunriseIcon,\n} from './icons';\n\ntype Star = [x: number, y: number, r: number, opacity: number];\n\ntype Glint = [x: number, y: number, width: number, height: number, opacity: number];\n\n// The screen's wallpaper: the hero's dusk in miniature, positions in percent.\nconst WALL_STARS: Star[] = [\n  [12, 22, 1, 0.7],\n  [30, 12, 0.8, 0.6],\n  [46, 30, 1.1, 0.8],\n  [62, 8, 0.8, 0.5],\n  [88, 42, 1, 0.6],\n  [20, 54, 0.7, 0.5],\n  [54, 62, 0.9, 0.6],\n  [80, 70, 0.7, 0.5],\n  [8, 80, 0.8, 0.5],\n];\n\nconst WALL_GLINTS: Glint[] = [\n  [72.1, 18.5, 1.8, 1, 0.2],\n  [74.2, 18.6, 1.6, 1, 0.24],\n  [72.1, 37.8, 3.1, 1, 0.23],\n  [73.1, 3.5, 0.6, 1, 0.26],\n  [74.4, 55.7, 3.7, 0.8, 0.14],\n  [72.5, 61.1, 2.7, 1, 0.08],\n  [74.5, 57.7, 3.1, 0.8, 0.1],\n  [71.1, 4.8, 1, 0.8, 0.38],\n  [74.6, 58.4, 2.7, 0.8, 0.12],\n  [69.5, 66.5, 2.4, 0.8, 0.09],\n  [73.1, 58.4, 2.3, 0.8, 0.11],\n  [73.5, 21.2, 1.7, 0.8, 0.26],\n  [71.1, 15.7, 0.9, 0.8, 0.29],\n  [77.8, 63.6, 4.2, 1, 0.07],\n  [71.9, 25.3, 1.5, 0.8, 0.3],\n  [73.3, 2.6, 0.8, 0.8, 0.4],\n  [72, 3.6, 0.9, 1, 0.33],\n  [72.8, 45.2, 1.9, 1, 0.15],\n  [73.5, 12.4, 1.5, 1, 0.32],\n  [76.2, 47.8, 2.5, 0.8, 0.15],\n  [73.4, 5.7, 0.7, 1, 0.28],\n  [82.6, 46.2, 1.8, 1, 0.18],\n  [72.6, 20.9, 1.8, 0.8, 0.25],\n  [73, 2, 0.8, 1, 0.33],\n  [72.7, 12.7, 1.5, 0.8, 0.25],\n  [68.1, 63.6, 4.4, 0.8, 0.08],\n];\n\nfunction StatusGlyphs() {\n  return (\n    <svg focusable=\"false\" viewBox=\"0 0 68 18\">\n      <rect height=\"6\" rx=\"1\" width=\"3.4\" x=\"0\" y=\"11\" />\n      <rect height=\"9\" rx=\"1\" width=\"3.4\" x=\"5\" y=\"8\" />\n      <rect height=\"12\" rx=\"1\" width=\"3.4\" x=\"10\" y=\"5\" />\n      <rect height=\"15\" opacity=\".4\" rx=\"1\" width=\"3.4\" x=\"15\" y=\"2\" />\n      <path d=\"M31 6.4a10 10 0 0 1 13 0l-1.6 1.7a7.6 7.6 0 0 0-9.8 0Zm3 3.3a5.4 5.4 0 0 1 7 0L37.5 13Z\" />\n      <rect\n        fill=\"none\"\n        height=\"11\"\n        opacity=\".55\"\n        rx=\"3\"\n        stroke=\"currentColor\"\n        strokeWidth=\"1.2\"\n        width=\"17\"\n        x=\"48.5\"\n        y=\"3.5\"\n      />\n      <rect height=\"7\" rx=\"1.5\" width=\"10\" x=\"50.5\" y=\"5.5\" />\n      <rect height=\"4\" opacity=\".55\" rx=\".8\" width=\"1.6\" x=\"66.4\" y=\"7\" />\n    </svg>\n  );\n}\n\n/**\n * Still's evening screen in an unbranded phone. Its two switches work: one warms and dims the\n * screen they sit on, the other turns the wake window off.\n */\nexport function EveningPhone() {\n  const id = useId();\n  const [warm, setWarm] = useState(true);\n  const [wake, setWake] = useState(true);\n\n  return (\n    <figure aria-labelledby={`${id}-caption`} className=\"still-phone still-rise\">\n      <figcaption className=\"still-sr-only\" id={`${id}-caption`}>\n        Still’s evening screen at 21:48, with tonight’s plan and two working switches.\n      </figcaption>\n      <div className=\"still-phone-body\">\n        <div className=\"still-phone-screen\" data-warm={warm || undefined}>\n          <div aria-hidden className=\"still-phone-wall\">\n            <svg focusable=\"false\" height=\"62%\" width=\"100%\">\n              {WALL_STARS.map(([x, y, r, opacity]) => (\n                <circle key={`${x}-${y}`} cx={`${x}%`} cy={`${y}%`} opacity={opacity} r={r} />\n              ))}\n            </svg>\n            <svg className=\"still-phone-glints\" focusable=\"false\" height=\"36%\" width=\"100%\">\n              {WALL_GLINTS.map(([x, y, width, height, opacity]) => (\n                <rect\n                  key={`${x}-${y}`}\n                  height={height}\n                  opacity={opacity}\n                  rx=\".5\"\n                  width={`${width}%`}\n                  x={`${x}%`}\n                  y={`${y}%`}\n                />\n              ))}\n            </svg>\n          </div>\n          <div aria-hidden className=\"still-phone-warm\" />\n          <div aria-hidden className=\"still-phone-island\" />\n          <div aria-hidden className=\"still-phone-status\">\n            <span>21:48</span>\n            <StatusGlyphs />\n          </div>\n          <div className=\"still-phone-content\">\n            <p className=\"still-ev-date\">Thursday 30 October</p>\n            <p className=\"still-ev-hello\">Good evening, Sam.</p>\n            <GlassSurface className=\"still-ev-card still-pane\" lens>\n              <div className=\"still-ev-row\">\n                <span className=\"still-ev-tile\">\n                  <MoonIcon />\n                </span>\n                <span>\n                  <span className=\"still-ev-title\">Wind down at 22:00</span>\n                  <span className=\"still-ev-meta\">In 12 minutes</span>\n                </span>\n              </div>\n              <GlassProgress\n                aria-label=\"Time until wind down\"\n                className=\"still-ev-progress\"\n                max={60}\n                size=\"sm\"\n                value={48}\n              />\n              <div className=\"still-ev-split\">\n                <span id={`${id}-warm`}>Warm and dim the screen</span>\n                <GlassSwitch\n                  aria-labelledby={`${id}-warm`}\n                  checked={warm}\n                  size=\"sm\"\n                  onCheckedChange={setWarm}\n                />\n              </div>\n            </GlassSurface>\n            <p className=\"still-ev-label\">Tonight</p>\n            <GlassSurface className=\"still-ev-list still-pane\" lens>\n              <ul>\n                <li>\n                  <span className=\"still-ev-tile\">\n                    <MarkIcon />\n                  </span>\n                  <span>\n                    <span className=\"still-ev-title\">Breathe</span>\n                    <span className=\"still-ev-meta\">3 min · in 4, hold 2, out 6</span>\n                  </span>\n                  <RightIcon className=\"still-ev-chevron\" />\n                </li>\n                <li>\n                  <span className=\"still-ev-tile still-ev-tile--dusk\">\n                    <RainIcon />\n                  </span>\n                  <span>\n                    <span className=\"still-ev-title\">Rain on tin</span>\n                    <span className=\"still-ev-meta\">Fades out after 45 min</span>\n                  </span>\n                  <RightIcon className=\"still-ev-chevron\" />\n                </li>\n                <li>\n                  <span className=\"still-ev-tile still-ev-tile--rose\">\n                    <BookIcon />\n                  </span>\n                  <span>\n                    <span className=\"still-ev-title\">The library after closing</span>\n                    <span className=\"still-ev-meta\">31 min · Ruth Okafor</span>\n                  </span>\n                  <RightIcon className=\"still-ev-chevron\" />\n                </li>\n              </ul>\n            </GlassSurface>\n            <GlassSurface className=\"still-ev-card still-pane\" lens>\n              <div className=\"still-ev-row\">\n                <span className=\"still-ev-tile still-ev-tile--sun\">\n                  <SunriseIcon />\n                </span>\n                <span>\n                  <span className=\"still-ev-title\" id={`${id}-wake`}>\n                    Wake 6:50 to 7:20\n                  </span>\n                  <span className=\"still-ev-meta\" id={`${id}-wake-meta`}>\n                    {wake ? 'Birdsong rises from 6:50' : 'No alarm, just the window'}\n                  </span>\n                </span>\n                <GlassSwitch\n                  aria-describedby={`${id}-wake-meta`}\n                  aria-labelledby={`${id}-wake`}\n                  checked={wake}\n                  size=\"sm\"\n                  onCheckedChange={setWake}\n                />\n              </div>\n            </GlassSurface>\n            <span aria-hidden className=\"still-ev-begin\">\n              <BreathIcon />\n              Begin wind down\n            </span>\n          </div>\n          <GlassSurface aria-hidden className=\"still-phone-tabs still-pane\" lens>\n            <span className=\"still-phone-tab\" data-active>\n              <HomeIcon />\n              Tonight\n            </span>\n            <span className=\"still-phone-tab\">\n              <MarkIcon />\n              Breathe\n            </span>\n            <span className=\"still-phone-tab\">\n              <FadeIcon />\n              Sounds\n            </span>\n            <span className=\"still-phone-tab\">\n              <BookIcon />\n              Stories\n            </span>\n          </GlassSurface>\n        </div>\n      </div>\n    </figure>\n  );\n}\n",
      "type": "registry:component",
      "target": "components/glassyui/templates/still/evening-phone.tsx"
    },
    {
      "path": "registry/glassyui/templates/still/pricing-plan.tsx",
      "content": "'use client';\n\nimport { useEffect, useRef, useState } from 'react';\nimport { motionReduced } from '../../lib/liquid-motion';\nimport { GlassPanel } from '../../glass-panel';\nimport { GlassSegmentedControl, GlassSegmentedControlItem } from '../../glass-segmented-control';\nimport { CheckIcon } from './icons';\nimport { StoreMenu, type StoreLinks, type StorePlatform } from './store-menu';\n\ntype Period = 'yearly' | 'monthly';\n\nconst PLANS: Record<Period, { price: number; per: string; note: string }> = {\n  yearly: {\n    price: 39.99,\n    per: 'a year, after your free week',\n    note: 'That’s $3.33 a month, billed once a year.',\n  },\n  monthly: {\n    price: 7.99,\n    per: 'a month, after your free week',\n    note: 'Billed monthly. Cancel whenever you like.',\n  },\n};\n\nconst INCLUDED = [\n  'Every sound scene and sleep story, with a new story each Sunday',\n  'Breathing sessions from one minute to twenty',\n  'Downloads for nights without signal',\n  'Up to five people in one household',\n];\n\n/** A price that counts to its new value when the billing period changes. */\nfunction useCountedPrice(target: number) {\n  const [shown, setShown] = useState(target);\n  const shownRef = useRef(target);\n\n  useEffect(() => {\n    const from = shownRef.current;\n\n    if (from === target) return;\n\n    const start = performance.now();\n    let frame = requestAnimationFrame(tick);\n\n    function tick(now: number) {\n      const progress = motionReduced() ? 1 : Math.min(1, (now - start) / 620);\n      const value = progress === 1 ? target : from + (target - from) * (1 - (1 - progress) ** 3);\n\n      shownRef.current = value;\n      setShown(value);\n\n      if (progress < 1) frame = requestAnimationFrame(tick);\n    }\n\n    return () => cancelAnimationFrame(frame);\n  }, [target]);\n\n  return shown;\n}\n\nexport function PricingPlan({\n  storeLinks,\n  onDemo,\n}: {\n  storeLinks?: StoreLinks;\n  onDemo: (platform: StorePlatform) => void;\n}) {\n  const [period, setPeriod] = useState<Period>('yearly');\n  const plan = PLANS[period];\n  const price = useCountedPrice(plan.price);\n\n  return (\n    <GlassPanel\n      aria-labelledby=\"still-plan-title\"\n      className=\"still-plan still-pane still-rise\"\n      lens\n      role=\"group\"\n      variant=\"card\"\n    >\n      <div className=\"still-plan-top\">\n        <h3 id=\"still-plan-title\">Everything in Still</h3>\n        <GlassSegmentedControl\n          aria-label=\"Billing period\"\n          className=\"still-period\"\n          value={period}\n          onValueChange={(value) => setPeriod(value === 'monthly' ? 'monthly' : 'yearly')}\n        >\n          <GlassSegmentedControlItem value=\"yearly\">Yearly</GlassSegmentedControlItem>\n          <GlassSegmentedControlItem value=\"monthly\">Monthly</GlassSegmentedControlItem>\n        </GlassSegmentedControl>\n      </div>\n      <div aria-live=\"polite\">\n        <p className=\"still-price\">\n          <span className=\"still-price-figure\">\n            <span aria-hidden>${price.toFixed(2)}</span>\n            <span className=\"still-sr-only\">${plan.price.toFixed(2)}</span>\n          </span>\n          <span className=\"still-price-per\">{plan.per}</span>\n        </p>\n        <p className=\"still-price-note\">{plan.note}</p>\n      </div>\n      <ul className=\"still-plan-list\">\n        {INCLUDED.map((item) => (\n          <li key={item}>\n            <CheckIcon />\n            {item}\n          </li>\n        ))}\n      </ul>\n      <div className=\"still-plan-action\">\n        <StoreMenu links={storeLinks} onDemo={onDemo} />\n      </div>\n      <p className=\"still-plan-fine\">We’ll remind you two days before the week ends.</p>\n    </GlassPanel>\n  );\n}\n",
      "type": "registry:component",
      "target": "components/glassyui/templates/still/pricing-plan.tsx"
    },
    {
      "path": "registry/glassyui/templates/still/store-menu.tsx",
      "content": "'use client';\n\nimport { GlassButton } from '../../glass-button';\nimport { GlassMenu, GlassMenuContent, GlassMenuItem, GlassMenuTrigger } from '../../glass-menu';\nimport { DownIcon, HandsetIcon, PhoneIcon } from './icons';\n\nexport type StorePlatform = 'iphone' | 'android';\n\n/** Your app's store pages. A platform without one shows a demo note instead of leaving the page. */\nexport type StoreLinks = Partial<Record<StorePlatform, string>>;\n\n// Spread rather than written as an attribute, as the library does: the shadcn CLI rewrites a\n// literal asChild into a render prop for some styles, which these Radix parts do not take.\nexport const slotProps = { asChild: true };\n\nconst STORES = [\n  { platform: 'iphone', name: 'For iPhone', detail: 'iOS 17 and later', Glyph: PhoneIcon },\n  { platform: 'android', name: 'For Android', detail: 'Android 10 and later', Glyph: HandsetIcon },\n] as const;\n\n/** Its menu draws the stores with Still's own glyphs rather than any store's badge. */\nexport function StoreMenu({\n  label = 'Start your free week',\n  links,\n  onDemo,\n}: {\n  label?: string;\n  links?: StoreLinks;\n  onDemo: (platform: StorePlatform) => void;\n}) {\n  return (\n    <GlassMenu>\n      <GlassMenuTrigger {...slotProps}>\n        <GlassButton className=\"still-button-xl still-store-trigger\" variant=\"prominent\">\n          {label}\n          <DownIcon />\n        </GlassButton>\n      </GlassMenuTrigger>\n      <GlassMenuContent\n        aria-label=\"Choose your phone\"\n        className=\"still still-store-menu\"\n        data-lg-theme=\"dark\"\n      >\n        {STORES.map(({ platform, name, detail, Glyph }) => {\n          const href = links?.[platform];\n\n          const body = (\n            <>\n              <Glyph />\n              <span>\n                <b>{name}</b>\n                <small>{detail}</small>\n              </span>\n            </>\n          );\n\n          return href ? (\n            <GlassMenuItem key={platform} {...slotProps} className=\"still-store-item\">\n              <a href={href}>{body}</a>\n            </GlassMenuItem>\n          ) : (\n            <GlassMenuItem\n              key={platform}\n              className=\"still-store-item\"\n              onSelect={() => onDemo(platform)}\n            >\n              {body}\n            </GlassMenuItem>\n          );\n        })}\n      </GlassMenuContent>\n    </GlassMenu>\n  );\n}\n",
      "type": "registry:component",
      "target": "components/glassyui/templates/still/store-menu.tsx"
    },
    {
      "path": "registry/glassyui/templates/still/icons.tsx",
      "content": "import type { SVGProps } from 'react';\n\ntype IconProps = SVGProps<SVGSVGElement>;\n\nfunction Icon({ children, className, ...props }: IconProps) {\n  return (\n    <svg\n      aria-hidden\n      className={className ? `still-icon ${className}` : 'still-icon'}\n      focusable=\"false\"\n      viewBox=\"0 0 24 24\"\n      {...props}\n    >\n      {children}\n    </svg>\n  );\n}\n\n/** Still's mark: the moon resting on the horizon. */\nexport function MarkIcon(props: IconProps) {\n  return (\n    <Icon {...props}>\n      <path d=\"M5.68 15.5a7 7 0 1 1 12.64 0M2.75 15.5h18.5M9.25 19h5.5\" />\n    </Icon>\n  );\n}\n\nexport function BreathIcon(props: IconProps) {\n  return (\n    <Icon {...props}>\n      <circle cx=\"12\" cy=\"12\" r=\"2.6\" />\n      <path d=\"M6.4 6.4a7.9 7.9 0 1 0 11.2 0\" />\n    </Icon>\n  );\n}\n\nexport function StopIcon(props: IconProps) {\n  return (\n    <Icon {...props}>\n      <rect height=\"10\" rx=\"2.6\" width=\"10\" x=\"7\" y=\"7\" />\n    </Icon>\n  );\n}\n\nexport function PlayIcon(props: IconProps) {\n  return (\n    <Icon {...props}>\n      <path d=\"M8.5 6.6v10.8a.9.9 0 0 0 1.37.77l8.6-5.4a.9.9 0 0 0 0-1.54l-8.6-5.4a.9.9 0 0 0-1.37.77Z\" />\n    </Icon>\n  );\n}\n\nexport function PauseIcon(props: IconProps) {\n  return (\n    <Icon {...props}>\n      <path d=\"M9 6.5v11M15 6.5v11\" />\n    </Icon>\n  );\n}\n\nexport function LeftIcon(props: IconProps) {\n  return (\n    <Icon {...props}>\n      <path d=\"M14.5 6.5 9 12l5.5 5.5\" />\n    </Icon>\n  );\n}\n\nexport function RightIcon(props: IconProps) {\n  return (\n    <Icon {...props}>\n      <path d=\"M9.5 6.5 15 12l-5.5 5.5\" />\n    </Icon>\n  );\n}\n\nexport function DownIcon(props: IconProps) {\n  return (\n    <Icon {...props}>\n      <path d=\"m6.5 9.5 5.5 5.5 5.5-5.5\" />\n    </Icon>\n  );\n}\n\nexport function PlusIcon(props: IconProps) {\n  return (\n    <Icon {...props}>\n      <path d=\"M12 6v12M6 12h12\" />\n    </Icon>\n  );\n}\n\nexport function CheckIcon(props: IconProps) {\n  return (\n    <Icon {...props}>\n      <path d=\"m5.5 12.5 4 4 9-9\" />\n    </Icon>\n  );\n}\n\nexport function MoonIcon(props: IconProps) {\n  return (\n    <Icon {...props}>\n      <path d=\"M18.8 14.6A7.4 7.4 0 0 1 9.4 5.2a7.4 7.4 0 1 0 9.4 9.4Z\" />\n    </Icon>\n  );\n}\n\n/** A plain handset, for the iPhone store: no platform's own mark. */\nexport function PhoneIcon(props: IconProps) {\n  return (\n    <Icon {...props}>\n      <rect height=\"18\" rx=\"2.8\" width=\"10\" x=\"7\" y=\"3\" />\n      <path d=\"M10.5 18h3\" />\n    </Icon>\n  );\n}\n\n/** A second handset with a top speaker, for the Android store. */\nexport function HandsetIcon(props: IconProps) {\n  return (\n    <Icon {...props}>\n      <rect height=\"18\" rx=\"2.2\" width=\"11\" x=\"6.5\" y=\"3\" />\n      <path d=\"M10 5.6h4\" />\n    </Icon>\n  );\n}\n\nexport function BellIcon(props: IconProps) {\n  return (\n    <Icon {...props}>\n      <path d=\"M7 16V11a5 5 0 0 1 10 0v5l1.5 1.5h-13Z\" />\n      <path d=\"M10.5 20.2h3\" />\n    </Icon>\n  );\n}\n\nexport function FadeIcon(props: IconProps) {\n  return (\n    <Icon {...props}>\n      <path d=\"M4 12h1M7.5 8.5v7M11 6.5v11M14.5 9v6M18 11v2\" />\n    </Icon>\n  );\n}\n\nexport function SunriseIcon(props: IconProps) {\n  return (\n    <Icon {...props}>\n      <path d=\"M4 17.5h16M7.5 17.5a4.5 4.5 0 0 1 9 0M12 6v3M6.4 9.4 7.8 10.8M17.6 9.4l-1.4 1.4\" />\n    </Icon>\n  );\n}\n\nexport function BookIcon(props: IconProps) {\n  return (\n    <Icon {...props}>\n      <path d=\"M4.5 5.5H9a3 3 0 0 1 3 3V19a2 2 0 0 0-2-2H4.5Z\" />\n      <path d=\"M19.5 5.5H15a3 3 0 0 0-3 3V19a2 2 0 0 1 2-2h5.5Z\" />\n    </Icon>\n  );\n}\n\nexport function RainIcon(props: IconProps) {\n  return (\n    <Icon {...props}>\n      <path d=\"M7.5 13.5a4 4 0 0 1-.3-8 5 5 0 0 1 9.4 1.3 3.4 3.4 0 0 1 .3 6.7Z\" />\n      <path d=\"m8 16.5-1 2.5M12 16.5l-1 2.5M16 16.5l-1 2.5\" />\n    </Icon>\n  );\n}\n\nexport function HomeIcon(props: IconProps) {\n  return (\n    <Icon {...props}>\n      <path d=\"M5 10.8 12 5l7 5.8V18a1.5 1.5 0 0 1-1.5 1.5h-11A1.5 1.5 0 0 1 5 18Z\" />\n    </Icon>\n  );\n}\n\n/** A filled star for the rating, the one icon without a stroke. */\nexport function StarIcon() {\n  return (\n    <svg aria-hidden focusable=\"false\" viewBox=\"0 0 24 24\">\n      <path d=\"M12 3.5l2.3 5.6 6 .5-4.6 3.9 1.4 5.9L12 16.3l-5.1 3.1 1.4-5.9-4.6-3.9 6-.5Z\" />\n    </svg>\n  );\n}\n",
      "type": "registry:component",
      "target": "components/glassyui/templates/still/icons.tsx"
    },
    {
      "path": "registry/glassyui/templates/still/still.css",
      "content": "/*\n  Still, a Glassy UI template. Every rule is scoped to .still. Set --still-accent,\n  --still-accent-rotate, --still-accent-ink, --still-serif and --still-sans on any ancestor to\n  change the accent and the fonts.\n*/\n\n.still {\n  --st-accent: var(--still-accent, #e6dcff);\n  --st-accent-ink: var(--still-accent-ink, #1d1638);\n  --st-serif: var(--still-serif, 'Iowan Old Style', Georgia, 'Times New Roman', serif);\n  --st-sans: var(\n    --still-sans,\n    -apple-system,\n    BlinkMacSystemFont,\n    'Segoe UI',\n    system-ui,\n    sans-serif\n  );\n  --st-night: #17142a;\n  --st-ink: #f3eefb;\n  --st-ink-2: #c3b9d6;\n  --st-ink-3: #a99fc0;\n  --st-line: rgb(230 220 255 / 0.14);\n  --st-wrap: 1200px;\n  --st-pad: clamp(20px, 4vw, 40px);\n  --st-section: clamp(80px, 7.5vw, 120px);\n  --st-ease-in: cubic-bezier(0.5, 0, 0.75, 0);\n\n  /* The library's tokens, in Still's night and lavender. */\n  --lg-foreground: var(--st-ink);\n  --lg-muted-foreground: var(--st-ink-2);\n  --lg-accent: var(--st-accent);\n  --lg-accent-foreground: var(--st-accent-ink);\n  --lg-prominent-fill: var(--st-accent);\n  /* Recolours whatever sits behind a prominent button into a pale lavender, so its dark label\n     keeps 11:1 over the dusk. */\n  --lg-prominent-tint: grayscale(1) contrast(0.15) brightness(1.35) sepia(1)\n    hue-rotate(var(--still-accent-rotate, 210deg)) saturate(0.9) brightness(1.2);\n  --lg-prominent-glow: 248 244 255;\n  --lg-prominent-shade: 29 22 56;\n  --lg-switch-on: #8b78c9;\n  --lg-focus-ring: var(--st-accent);\n  --lg-control-surface: rgb(16 12 34 / 0.5);\n  --lg-control-surface-hover: rgb(16 12 34 / 0.66);\n  --lg-border: rgb(230 220 255 / 0.14);\n  --lg-overlay-surface: rgb(33 27 58 / 0.86);\n  --lg-opaque-surface: #231d3c;\n  --lg-header-tint: rgb(49 39 100 / 0.5);\n  --lg-track: rgb(255 255 255 / 0.12);\n\n  color: var(--st-ink);\n  font-family: var(--st-sans);\n  letter-spacing: normal;\n}\n\n@layer base {\n  .still :where(h1, h2, h3, p, ul, blockquote, figure) {\n    margin: 0;\n    padding: 0;\n  }\n\n  .still :where(ul) {\n    list-style: none;\n  }\n\n  .still :where(a) {\n    color: inherit;\n  }\n\n  .still :where(h1, h2, h3) {\n    font-family: var(--st-serif);\n    font-weight: 500;\n    letter-spacing: -0.01em;\n    text-wrap: balance;\n  }\n\n  .still :where(p) {\n    text-wrap: pretty;\n  }\n}\n\nhtml:has(.still-page) {\n  background: #17142a;\n  scroll-padding-top: 92px;\n}\n\n@media (prefers-reduced-motion: no-preference) {\n  html:has(.still-page) {\n    scroll-behavior: smooth;\n  }\n}\n\n/* One evening down the page: dusk plum deepens to night. */\n.still-page {\n  position: relative;\n  min-height: 100vh;\n  min-width: 320px;\n  overflow-x: clip;\n  background: linear-gradient(\n    180deg,\n    #17142a 0%,\n    #1a1631 16%,\n    #1f1737 32%,\n    #231939 46%,\n    #1e1636 60%,\n    #18142f 76%,\n    #17142a 100%\n  );\n  font-size: 17px;\n  line-height: 1.6;\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n}\n\n.still-icon {\n  display: block;\n  width: 20px;\n  height: 20px;\n  flex: none;\n  fill: none;\n  stroke: currentColor;\n  stroke-width: 1.7;\n  stroke-linecap: round;\n  stroke-linejoin: round;\n}\n\n.still-sr-only {\n  position: absolute;\n  width: 1px;\n  height: 1px;\n  margin: -1px;\n  padding: 0;\n  overflow: hidden;\n  clip-path: inset(50%);\n  white-space: nowrap;\n  border: 0;\n}\n\n.still :where(a, [tabindex]:not([tabindex='-1'])):focus-visible {\n  outline: 2px solid var(--st-accent);\n  outline-offset: 3px;\n  border-radius: 6px;\n}\n\n.still [tabindex='-1']:focus {\n  outline: none;\n}\n\n.still-skip {\n  position: fixed;\n  z-index: 100;\n  top: 16px;\n  left: 16px;\n  padding: 10px 16px;\n  border-radius: 999px;\n  background: var(--st-accent);\n  color: var(--st-accent-ink);\n  font-weight: 600;\n  text-decoration: none;\n  transform: translateY(-160%);\n  transition: transform 200ms var(--lg-ease-out);\n}\n\n.still-skip:focus {\n  transform: none;\n}\n\n.still-wrap {\n  width: min(100% - 2 * var(--st-pad), var(--st-wrap));\n  margin-inline: auto;\n}\n\n.still-section {\n  position: relative;\n  padding-block: var(--st-section);\n}\n\n.still-eyebrow {\n  display: inline-flex;\n  align-items: center;\n  gap: 10px;\n  margin-bottom: 20px;\n  color: var(--st-accent);\n  font: 600 13px/1.2 var(--st-sans);\n  letter-spacing: 0.06em;\n}\n\n.still-eyebrow::before {\n  content: '';\n  width: 20px;\n  height: 1px;\n  background: currentColor;\n  opacity: 0.6;\n}\n\n.still-h2 {\n  font-size: clamp(38px, 3vw + 14px, 60px);\n  line-height: 1.03;\n  letter-spacing: -0.015em;\n}\n\n.still-lede {\n  max-width: 52ch;\n  margin-top: 20px;\n  color: var(--st-ink-2);\n  font-size: clamp(17px, 0.25vw + 15.5px, 19px);\n}\n\n.still-lede a {\n  text-decoration: underline;\n  text-decoration-color: color-mix(in srgb, var(--st-accent) 45%, transparent);\n  text-underline-offset: 3px;\n}\n\n/* Panes take the night's plum into their frost, as the page's own glass. */\n.still-pane::before {\n  background-color: rgb(42 34 72 / 0.3);\n}\n\n/* Buttons: the library's slabs at Still's sizes. */\n.still-button-sm {\n  min-height: 32px;\n  padding: 0 15px;\n  font-size: 14px;\n  font-weight: 600;\n}\n\n.still-button {\n  min-height: 44px;\n  padding: 0 20px;\n  font-size: 15px;\n  font-weight: 600;\n}\n\n.still-button-xl {\n  min-height: 56px;\n  padding: 0 26px;\n  font-size: 17px;\n  font-weight: 600;\n}\n\n/* The secondary slabs take a little of the lavender into their glass. */\n.still .lg-button:not(.lg-button--prominent, .lg-accordion-trigger) {\n  --lg-button-fill: rgb(230 220 255 / 0.05);\n  --lg-button-fill-hover: rgb(230 220 255 / 0.1);\n}\n\n.still .lg-button .lg-button__label {\n  display: inline-flex;\n  align-items: center;\n  gap: 8px;\n}\n\n/* A prominent button's glass recolours the page behind it. In Safari and Firefox the glass may\n   see little or none of the page, so its face would show only the dark light under it, behind a\n   dark label. There it takes the solid fill instead, as the library does where glass cannot be\n   drawn. */\n@supports not (-webkit-app-region: drag) {\n  .still .lg-button--prominent > .lg-button__layers > .lg-button__distortion {\n    background-color: var(--lg-prominent-fill);\n    -webkit-backdrop-filter: none;\n    backdrop-filter: none;\n  }\n}\n\n/* Header */\n.still-header.lg-header {\n  top: 16px;\n  width: min(880px, calc(100vw - 32px));\n  height: 60px;\n  font-family: var(--st-sans);\n  transition: transform 640ms var(--lg-ease-out);\n}\n\n.still[data-breathing] .still-header.lg-header {\n  transform: translateY(calc(-100% - 28px));\n  transition: transform 420ms var(--st-ease-in);\n}\n\n.still-header .lg-header-bar {\n  gap: 8px;\n  padding: 0 8px 0 18px;\n}\n\n.still-brand {\n  display: inline-flex;\n  align-items: center;\n  gap: 9px;\n  padding: 6px 4px;\n  font: 600 26px/1 var(--st-serif);\n  letter-spacing: 0.01em;\n  text-decoration: none;\n}\n\n.still-brand-mark.still-icon {\n  width: 24px;\n  height: 24px;\n  color: var(--st-accent);\n  stroke-width: 1.8;\n}\n\n.still-header .lg-header-desktop {\n  margin-inline: auto 0;\n}\n\n.still-header .lg-header-desktop a {\n  height: auto;\n  padding: 9px 14px;\n  color: var(--st-ink-2);\n  font-size: 15px;\n  letter-spacing: 0;\n}\n\n.still-header .lg-header-desktop a:hover {\n  background: rgb(255 255 255 / 0.06);\n  color: var(--st-ink);\n}\n\n.still-header .lg-header-desktop .still-menu-cta {\n  display: none;\n}\n\n.still-header-cta {\n  margin-left: 6px;\n}\n\n/* The menu on phones */\n.still-header .lg-header-menu summary {\n  gap: 8px;\n  height: 40px;\n  padding: 0 18px 0 14px;\n  border-radius: 999px;\n  background: rgb(230 220 255 / 0.1);\n  box-shadow:\n    inset 0 0 0 1px rgb(230 220 255 / 0.16),\n    0 6px 16px -10px rgb(6 2 18 / 0.8);\n  font-size: 15px;\n  font-weight: 600;\n}\n\n.still-header .lg-header-menu summary::before {\n  content: '';\n  width: 18px;\n  height: 18px;\n  background: currentColor;\n  -webkit-mask: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.7' stroke-linecap='round'%3E%3Cpath d='M5 9h14M5 15h14'/%3E%3C/svg%3E\")\n    center / contain no-repeat;\n  mask: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.7' stroke-linecap='round'%3E%3Cpath d='M5 9h14M5 15h14'/%3E%3C/svg%3E\")\n    center / contain no-repeat;\n}\n\n.still-header .lg-header-menu[open] summary::before {\n  -webkit-mask-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.7' stroke-linecap='round'%3E%3Cpath d='m7 7 10 10M17 7 7 17'/%3E%3C/svg%3E\");\n  mask-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.7' stroke-linecap='round'%3E%3Cpath d='m7 7 10 10M17 7 7 17'/%3E%3C/svg%3E\");\n}\n\n.still-header .lg-header-menu-links {\n  top: calc(100% + 8px);\n  right: 0;\n  width: 100cqw;\n  padding: 10px;\n  border-radius: 26px;\n  background: var(--lg-overlay-surface);\n  box-shadow:\n    inset 0 0 0 1px rgb(230 220 255 / 0.12),\n    0 30px 60px -24px rgb(6 2 18 / 0.9);\n  -webkit-backdrop-filter: blur(24px) saturate(1.3);\n  backdrop-filter: blur(24px) saturate(1.3);\n}\n\n.still-header .lg-header-menu-links a {\n  justify-content: space-between;\n  height: 56px;\n  padding: 0 16px;\n  border-radius: 18px;\n  color: var(--st-ink);\n  font: 500 27px/1 var(--st-serif);\n  letter-spacing: 0;\n}\n\n.still-header .lg-header-menu-links a:not(.still-menu-cta)::after {\n  content: '';\n  width: 20px;\n  height: 20px;\n  background: var(--st-ink-2);\n  -webkit-mask: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M9.5 6.5 15 12l-5.5 5.5'/%3E%3C/svg%3E\")\n    center / contain no-repeat;\n  mask: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M9.5 6.5 15 12l-5.5 5.5'/%3E%3C/svg%3E\")\n    center / contain no-repeat;\n}\n\n.still-header .lg-header-menu-links a:hover {\n  background: rgb(255 255 255 / 0.06);\n}\n\n.still-header .lg-header-menu-links .still-menu-cta {\n  justify-content: center;\n  height: 48px;\n  margin-top: 8px;\n  border-radius: 999px;\n  background: rgb(230 220 255 / 0.1);\n  box-shadow: inset 0 0 0 1px rgb(230 220 255 / 0.16);\n  font: 600 16px/1 var(--st-sans);\n}\n\n@container (max-width: 780px) {\n  .still-header-cta {\n    display: none;\n  }\n}\n\n@media (max-width: 859px) {\n  .still-header.lg-header {\n    top: 12px;\n    width: calc(100vw - 24px);\n    height: 56px;\n  }\n\n  .still-header .lg-header-bar {\n    padding-left: 14px;\n  }\n}\n\n/* Hero */\n.still-hero {\n  --nav-h: 92px;\n  --orb: min(72vw, 34svh, 360px);\n  --gap: calc(var(--orb) * 0.09);\n  --hero-top: calc(var(--nav-h) + clamp(0px, (100svh - 860px) * 0.35, 120px));\n  --horizon: calc(var(--hero-top) + var(--gap) + var(--orb) * 0.72);\n  position: relative;\n  min-height: 100svh;\n  padding-bottom: 48px;\n  overflow: clip;\n}\n\n.still-sky {\n  position: absolute;\n  inset: 0;\n  z-index: 0;\n  pointer-events: none;\n}\n\n.still-sky > * {\n  position: absolute;\n  left: 0;\n  right: 0;\n}\n\n.still-sky-gradient {\n  top: 0;\n  height: var(--horizon);\n  background: linear-gradient(\n    180deg,\n    #17142a 0%,\n    #1b1734 26%,\n    #281e44 50%,\n    #43295a 70%,\n    #6e3d62 86%,\n    #a3627c 97%,\n    #c0798e 100%\n  );\n}\n\n.still-sky-stars {\n  top: 0;\n  width: 100%;\n  height: calc(var(--horizon) - 30px);\n  fill: #f6f1ff;\n}\n\n.still-sky-water {\n  top: var(--horizon);\n  bottom: 0;\n  background: linear-gradient(\n    180deg,\n    #47294f 0%,\n    #2c1d40 9%,\n    #211936 30%,\n    #1a1631 60%,\n    #17142a 100%\n  );\n}\n\n/* The moon path: a soft column with fine glints in perspective, for the orb to bend. */\n.still-sky-path {\n  top: var(--horizon);\n  width: calc(var(--orb) * 0.9);\n  height: 300px;\n  margin-inline: auto;\n  background: radial-gradient(\n    30% 100% at 50% 0%,\n    rgb(255 206 222 / 0.3),\n    rgb(255 186 210 / 0.1) 42%,\n    transparent 78%\n  );\n}\n\n.still-sky-glints {\n  top: calc(var(--horizon) + 1px);\n  width: calc(var(--orb) * 0.7);\n  height: 240px;\n  margin-inline: auto;\n  fill: #ffe2ec;\n  -webkit-mask-image: linear-gradient(\n    180deg,\n    #000 calc(var(--orb) * 0.2),\n    transparent calc(var(--orb) * 0.27)\n  );\n  mask-image: linear-gradient(\n    180deg,\n    #000 calc(var(--orb) * 0.2),\n    transparent calc(var(--orb) * 0.27)\n  );\n}\n\n.still-sky-land {\n  fill: #57304f;\n}\n\n.still-sky-land--west {\n  top: calc(var(--horizon) - 13px);\n  right: auto;\n  width: max(0px, 50% - var(--orb) * 0.6);\n  height: 14px;\n}\n\n.still-sky-land--east {\n  top: calc(var(--horizon) - 6px);\n  left: calc(50% + var(--orb) * 0.58);\n  right: auto;\n  width: calc(var(--orb) * 0.8);\n  height: 7px;\n}\n\n.still-sky-venus {\n  top: calc(var(--horizon) - var(--orb) * 0.46);\n  left: calc(50% - var(--orb) * 1.16);\n  right: auto;\n  width: 3px;\n  height: 3px;\n  border-radius: 50%;\n  background: #fff6fa;\n  box-shadow:\n    0 0 6px 1px rgb(255 226 238 / 0.7),\n    0 0 18px 4px rgb(255 190 214 / 0.18);\n}\n\n.still-sky-glow {\n  top: calc(var(--horizon) - 230px);\n  width: min(1240px, 100%);\n  height: 460px;\n  margin-inline: auto;\n  background: radial-gradient(\n    50% 50% at 50% 50%,\n    rgb(255 176 196 / 0.42),\n    rgb(200 118 160 / 0.16) 46%,\n    transparent 72%\n  );\n  transform-origin: 50% 50%;\n}\n\n.still-sky-horizon {\n  top: calc(var(--horizon) - 4px);\n  height: 9px;\n  background:\n    linear-gradient(\n        90deg,\n        transparent,\n        rgb(255 214 228 / 0.3) 18%,\n        rgb(255 230 238 / 0.85) 50%,\n        rgb(255 214 228 / 0.3) 82%,\n        transparent\n      )\n      50% 50% / 100% 1px no-repeat,\n    radial-gradient(50% 50% at 50% 50%, rgb(255 200 220 / 0.28), transparent);\n}\n\n/* BreathGuide */\n.still-breath {\n  position: relative;\n  z-index: 1;\n  display: flex;\n  flex-direction: column;\n  align-items: center;\n  width: min(100% - 2 * var(--st-pad), 980px);\n  margin-inline: auto;\n  padding-top: var(--hero-top);\n  text-align: center;\n}\n\n.still-breath-stage {\n  position: relative;\n  display: grid;\n  place-items: center;\n  width: calc(var(--orb) + 2 * var(--gap));\n  aspect-ratio: 1;\n}\n\n.still-breath-ring {\n  position: absolute;\n  inset: 0;\n  width: 100%;\n  height: 100%;\n  overflow: visible;\n  fill: none;\n}\n\n.still-breath-track {\n  stroke: rgb(230 220 255 / 0.18);\n  stroke-width: 0.6;\n}\n\n.still-breath-trace {\n  opacity: 0;\n  stroke: var(--st-accent);\n  stroke-width: 1;\n  stroke-linecap: round;\n  stroke-dasharray: 0 1;\n  transition: opacity 700ms var(--st-ease-in);\n}\n\n.still-breath:is([data-state='running'], [data-state='done']) .still-breath-trace {\n  opacity: 1;\n  transition: none;\n}\n\n.still-breath[data-state='done'] .still-breath-trace {\n  stroke-width: 1.4;\n  transition: stroke-width 900ms var(--lg-ease-out);\n}\n\n.still-breath-tick {\n  r: 1.5px;\n  fill: rgb(230 220 255 / 0.55);\n  transition:\n    r 500ms var(--lg-spring),\n    fill 400ms var(--lg-ease-out);\n}\n\n.still-breath[data-phase='0'] .still-breath-tick--in,\n.still-breath[data-phase='1'] .still-breath-tick--hold,\n.still-breath[data-phase='2'] .still-breath-tick--out {\n  r: 2.6px;\n  fill: #fff;\n}\n\n.still-breath-bead {\n  opacity: 0;\n  fill: #fff;\n  filter: drop-shadow(0 0 3px rgb(230 220 255 / 0.95));\n  transition: opacity 400ms var(--lg-ease-out);\n}\n\n.still-breath[data-state='running'] .still-breath-bead {\n  opacity: 1;\n}\n\n.still-breath-rise {\n  position: relative;\n  width: var(--orb);\n  aspect-ratio: 1;\n}\n\n/* The orb is a dome of glass: a lens as deep as it is round, which lifts the horizon behind it\n   into an arc and splits it at the rim. */\n.still-breath-orb.lg-glass-surface {\n  --lg-panel-radius: 50%;\n  --lg-glass-blur: 3px;\n  --lg-glass-sat: 1.4;\n  --lg-lens-bevel: 9999;\n  --lg-lens-thickness: 150;\n  --lg-lens-blur: 0.5;\n  --lg-lens-saturation: 1.4;\n  --lg-lens-dispersion: 0.06;\n  display: grid;\n  align-content: center;\n  justify-items: center;\n  gap: 10px;\n  width: 100%;\n  height: 100%;\n  border-radius: 50%;\n  transform-origin: 50% 50%;\n  will-change: transform;\n}\n\n.still-breath-orb::before {\n  background-color: rgb(72 54 116 / 0.08);\n}\n\n.still-breath:not([data-state='running']) .still-breath-orb {\n  transition: transform 1400ms var(--lg-ease-out);\n}\n\n.still-breath-shine {\n  position: absolute;\n  inset: 0;\n  z-index: 2;\n  border-radius: 50%;\n  pointer-events: none;\n  background:\n    radial-gradient(9% 4.5% at 33% 15%, rgb(255 255 255 / 0.5), transparent 76%),\n    radial-gradient(38% 22% at 36% 19%, rgb(255 255 255 / 0.07), transparent 72%),\n    radial-gradient(72% 36% at 50% 100%, rgb(255 196 214 / 0.22), transparent 72%),\n    radial-gradient(\n      closest-side,\n      transparent 78%,\n      rgb(28 16 50 / 0.26) 97%,\n      rgb(28 16 50 / 0.08) 100%\n    );\n}\n\n.still-breath-words {\n  position: relative;\n  z-index: 3;\n  min-height: 1em;\n  padding: 0 12%;\n  color: #fdfbff;\n  font: italic 500 clamp(27px, 1.6vw + 14px, 38px) / 1.05 var(--st-serif);\n  text-shadow: 0 1px 14px rgb(23 20 42 / 0.55);\n}\n\n.still-breath[data-state='done'] .still-breath-words {\n  font-size: clamp(22px, 1vw + 14px, 30px);\n  text-wrap: balance;\n}\n\n.still-breath-count {\n  position: relative;\n  z-index: 3;\n  min-height: 1em;\n  color: var(--st-ink-2);\n  font: 600 13px/1 var(--st-sans);\n  font-variant-numeric: tabular-nums;\n  letter-spacing: 0.08em;\n}\n\n.still-hero-title {\n  margin-top: clamp(18px, 2.6vh, 30px);\n  font-size: clamp(46px, 4.6vw + 14px, 80px);\n  line-height: 1.02;\n  letter-spacing: -0.015em;\n  transition:\n    opacity 900ms var(--lg-ease-out),\n    filter 900ms var(--lg-ease-out);\n}\n\n.still-hero-line {\n  display: block;\n}\n\n.still-hero-line--soft {\n  color: var(--st-ink-3);\n  font-style: italic;\n}\n\n.still-hero-lede {\n  max-width: 42ch;\n  margin-top: 14px;\n  color: var(--st-ink-2);\n  font-size: clamp(16px, 0.3vw + 15px, 18px);\n  transition:\n    opacity 900ms var(--lg-ease-out),\n    filter 900ms var(--lg-ease-out);\n}\n\n/* While you breathe, the words around the orb step back; they hold no glass. */\n.still[data-breathing] :is(.still-hero-title, .still-hero-lede) {\n  opacity: 0.18;\n  filter: blur(3px);\n  transition-duration: 1600ms;\n}\n\n.still-breath-controls {\n  display: flex;\n  justify-content: center;\n  gap: 12px;\n  min-height: 56px;\n  margin-top: 26px;\n}\n\n.still-breath-status {\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  gap: 8px;\n  min-height: 24px;\n  margin-top: 14px;\n  color: var(--st-ink-2);\n  font-size: 14px;\n}\n\n.still-breath-escape {\n  display: inline-flex;\n  align-items: center;\n  gap: 8px;\n}\n\n.still-breath-escape .lg-kbd {\n  color: var(--st-ink);\n}\n\n@media (hover: none) and (pointer: coarse) {\n  .still-breath-escape {\n    display: none;\n  }\n}\n\n/* The practice */\n.still-practice {\n  padding-top: clamp(48px, 5vw, 80px);\n}\n\n.still-practice-grid {\n  display: grid;\n  grid-template-columns: repeat(12, minmax(0, 1fr));\n  align-items: end;\n  column-gap: 24px;\n  row-gap: 32px;\n}\n\n.still-practice-head {\n  grid-column: 1 / span 6;\n}\n\n.still-practice-body {\n  grid-column: 8 / span 5;\n  color: var(--st-ink-2);\n  font-size: 18px;\n}\n\n.still-curve {\n  grid-column: 1 / -1;\n  margin-top: 72px;\n  view-timeline-name: --still-curve;\n}\n\n.still-curve-art {\n  display: block;\n  width: 100%;\n  height: auto;\n  overflow: visible;\n}\n\n.still-curve-area {\n  fill: url(#still-curve-fill);\n}\n\n.still-curve-line {\n  fill: none;\n  stroke: var(--st-accent);\n  stroke-width: 3;\n  stroke-linecap: round;\n  stroke-dasharray: 1 1;\n  stroke-dashoffset: 0;\n}\n\n.still-curve-guide {\n  stroke: rgb(230 220 255 / 0.22);\n  stroke-width: 1.5;\n  stroke-dasharray: 4 8;\n}\n\n.still-curve-base {\n  stroke: rgb(230 220 255 / 0.16);\n  stroke-width: 1.5;\n}\n\n.still-curve-dot {\n  fill: #17142a;\n  stroke: var(--st-accent);\n  stroke-width: 3;\n}\n\n.still-curve-labels {\n  display: grid;\n  grid-template-columns: 4fr 2fr 6fr;\n  margin-top: 18px;\n}\n\n.still-curve-labels p {\n  display: grid;\n  gap: 2px;\n  padding-left: 14px;\n  border-left: 1px solid var(--st-line);\n}\n\n.still-curve-labels b {\n  font: italic 500 24px/1.1 var(--st-serif);\n}\n\n.still-curve-labels span {\n  color: var(--st-ink-2);\n  font-size: 14px;\n}\n\n.still-curve figcaption {\n  margin-top: 28px;\n  color: var(--st-ink-2);\n  font-size: 15px;\n}\n\n.still-facts {\n  display: grid;\n  grid-column: 1 / -1;\n  grid-template-columns: repeat(3, minmax(0, 1fr));\n  gap: 24px;\n  margin-top: 88px;\n}\n\n.still-fact {\n  padding-top: 24px;\n  border-top: 1px solid var(--st-line);\n}\n\n.still-fact h3 {\n  font-size: 44px;\n  line-height: 1;\n}\n\n.still-fact p {\n  max-width: 32ch;\n  margin-top: 12px;\n  color: var(--st-ink-2);\n}\n\n/* Sound scenes */\n.still-sounds::before {\n  content: '';\n  position: absolute;\n  inset: 0;\n  pointer-events: none;\n  background:\n    radial-gradient(60% 36% at 12% 30%, rgb(196 120 160 / 0.1), transparent 70%),\n    radial-gradient(50% 34% at 88% 62%, rgb(140 120 230 / 0.08), transparent 70%);\n}\n\n.still-scenes {\n  position: relative;\n  display: grid;\n  grid-template-columns: repeat(3, minmax(0, 1fr));\n  gap: 24px;\n  margin-top: 64px;\n}\n\n/* The art is drawn 1:1 in px, so each scene's brightest line crosses the pane's top rim. */\n.still-scene {\n  --scene-art: 184px;\n  position: relative;\n  isolation: isolate;\n  display: grid;\n  align-content: end;\n  padding: var(--scene-art) 12px 12px;\n  overflow: hidden;\n  border-radius: 32px;\n  background: #221b3e;\n  box-shadow:\n    0 30px 60px -36px rgb(6 2 18 / 0.9),\n    inset 0 0 0 1px rgb(255 255 255 / 0.06);\n}\n\n.still-scene-art {\n  position: absolute;\n  inset: 0;\n}\n\n.still-scene-art svg {\n  display: block;\n  width: 100%;\n  height: max(520px, 100%);\n}\n\n.still-scene-body.lg-glass-surface {\n  --lg-panel-radius: 24px;\n  display: grid;\n  gap: 14px;\n  padding: 22px 22px 18px;\n}\n\n.still-scene-head {\n  display: flex;\n  align-items: center;\n  justify-content: space-between;\n  gap: 12px;\n}\n\n.still-scene-title {\n  font-size: 31px;\n  line-height: 1.05;\n}\n\n.still-scene-description {\n  color: var(--st-ink-2);\n  font-size: 15px;\n  line-height: 1.55;\n}\n\n.still-scene-wave {\n  display: flex;\n  align-items: center;\n  gap: 3px;\n  height: 52px;\n  margin-block: 2px;\n}\n\n.still-scene-bar {\n  flex: 1;\n  height: 100%;\n  border-radius: 3px;\n  background: linear-gradient(180deg, rgb(236 228 255 / 0.95), rgb(206 190 255 / 0.55));\n  opacity: 0.62;\n  transform-origin: 50% 50%;\n  transition:\n    transform 700ms var(--lg-ease-out),\n    opacity 500ms var(--lg-ease-out);\n}\n\n.still-scene[data-playing='true'] .still-scene-bar {\n  opacity: 1;\n  transition: opacity 400ms var(--lg-ease-out);\n}\n\n.still-scene-foot {\n  display: flex;\n  align-items: center;\n  justify-content: space-between;\n  gap: 12px;\n}\n\n.still-scene-toggle {\n  min-width: 112px;\n}\n\n/* The scene and story buttons draw no lens, to keep each viewport's lenses in budget. Their frost\n   stays neutral instead of saturating the violet behind them. */\n.still .lg-button:is(.still-scene-toggle, .still-carousel-button) {\n  --lg-button-fill: rgb(255 255 255 / 0.08);\n  --lg-button-fill-hover: rgb(255 255 255 / 0.12);\n  --lg-glass-sat: 1.3;\n}\n\n.still-scene-toggle .still-icon {\n  width: 18px;\n  height: 18px;\n}\n\n.still-scene-time {\n  color: var(--st-ink-2);\n  font-size: 14px;\n  font-variant-numeric: tabular-nums;\n  font-weight: 500;\n}\n\n.still-scene-time time {\n  color: var(--st-ink);\n}\n\n.still-scene-move,\n.still-scene-grass {\n  animation-play-state: paused;\n}\n\n.still-scene-grass {\n  transform-box: fill-box;\n  transform-origin: 50% 100%;\n}\n\n@keyframes still-rain-near {\n  to {\n    transform: translate(-40px, 220px);\n  }\n}\n\n@keyframes still-rain-far {\n  to {\n    transform: translate(-30px, 165px);\n  }\n}\n\n@keyframes still-train-pass {\n  to {\n    transform: translateX(-46px);\n  }\n}\n\n@keyframes still-wind-drift {\n  to {\n    transform: translateX(-190px);\n  }\n}\n\n@keyframes still-wind-sway {\n  from {\n    transform: skewX(-5deg);\n  }\n\n  to {\n    transform: skewX(4deg);\n  }\n}\n\n@media (prefers-reduced-motion: no-preference) {\n  :root:not([data-lg-reduce-motion='1']) .still-scene-move--rain-near {\n    animation: still-rain-near 0.75s linear infinite paused;\n  }\n\n  :root:not([data-lg-reduce-motion='1']) .still-scene-move--rain-far {\n    animation: still-rain-far 1.5s linear infinite paused;\n  }\n\n  :root:not([data-lg-reduce-motion='1']) .still-scene-move--train {\n    animation: still-train-pass 0.9s linear infinite paused;\n  }\n\n  :root:not([data-lg-reduce-motion='1']) .still-scene-move--wind {\n    animation: still-wind-drift 7s linear infinite paused;\n  }\n\n  :root:not([data-lg-reduce-motion='1']) .still-scene-grass {\n    animation: still-wind-sway 2.6s ease-in-out infinite alternate paused;\n  }\n\n  .still-scene[data-playing='true'] :is(.still-scene-move, .still-scene-grass) {\n    animation-play-state: running;\n  }\n\n  .still-sounds[data-away]\n    .still-scene[data-playing='true']\n    :is(.still-scene-move, .still-scene-grass) {\n    animation-play-state: paused;\n  }\n}\n\n/* Sleep stories */\n.still-carousel-bar {\n  display: flex;\n  align-items: flex-end;\n  justify-content: space-between;\n  gap: 32px;\n}\n\n.still-carousel-controls {\n  display: flex;\n  flex: none;\n  align-items: center;\n  gap: 10px;\n}\n\n.still-carousel-button.still-button {\n  width: 44px;\n  padding: 0;\n}\n\n.still-carousel-button[aria-disabled='true'] {\n  color: rgb(243 238 251 / 0.34);\n  cursor: default;\n}\n\n.still-carousel-count {\n  min-width: 10ch;\n  color: var(--st-ink-2);\n  font-size: 14px;\n  font-variant-numeric: tabular-nums;\n  font-weight: 500;\n  text-align: center;\n}\n\n.still-carousel-track {\n  --edge: max(var(--st-pad), calc((100% - var(--st-wrap)) / 2));\n  display: grid;\n  grid-auto-columns: clamp(244px, 20vw + 12px, 300px);\n  grid-auto-flow: column;\n  gap: 20px;\n  margin: 48px 0 0;\n  padding: 8px var(--edge) 28px;\n  overflow-x: auto;\n  overscroll-behavior-x: contain;\n  scroll-padding-inline: var(--edge);\n  scroll-snap-type: x mandatory;\n  scrollbar-width: none;\n}\n\n.still-carousel-track::-webkit-scrollbar {\n  display: none;\n}\n\n.still .still-carousel-track:focus-visible {\n  border-radius: 36px;\n  outline-offset: -4px;\n}\n\n.still-carousel-item {\n  scroll-snap-align: start;\n}\n\n.still-story {\n  position: relative;\n  isolation: isolate;\n  aspect-ratio: 3 / 4;\n  overflow: hidden;\n  border-radius: 28px;\n  background: #241c40;\n  box-shadow:\n    0 26px 50px -30px rgb(6 2 18 / 0.9),\n    inset 0 0 0 1px rgb(255 255 255 / 0.06);\n  transition: transform 500ms var(--lg-ease-out);\n}\n\n.still-story:hover {\n  transform: translateY(-4px);\n}\n\n.still-story-art {\n  position: absolute;\n  inset: 0;\n  display: block;\n  width: 100%;\n  height: 100%;\n}\n\n.still-story-meta.lg-glass-surface {\n  --lg-panel-radius: 20px;\n  position: absolute;\n  left: 10px;\n  right: 10px;\n  bottom: 10px;\n  display: grid;\n  gap: 6px;\n  padding: 14px 16px 15px;\n}\n\n.still-story-chips {\n  display: flex;\n  align-items: center;\n  gap: 10px;\n  margin-bottom: 2px;\n  color: var(--st-ink-2);\n  font-size: 13px;\n}\n\n.still-story h3 {\n  font-size: 23px;\n  line-height: 1.1;\n}\n\n.still-story p {\n  color: var(--st-ink-2);\n  font-size: 14px;\n}\n\n/* Badges: a pale chip of frost that lifts the lavender of the glass under it. */\n.still .lg-badge,\n.still-toast .lg-badge {\n  --lg-badge-ink: var(--st-ink);\n  --lg-glass-sat: 1.6;\n  --lg-glass-contrast: 1;\n  height: 28px;\n  padding: 0 12px;\n  background: rgb(255 255 255 / 0.08);\n  box-shadow:\n    inset 0 0 0 1px rgb(255 255 255 / 0.12),\n    inset 0 1px 0 rgb(255 255 255 / 0.16);\n  font-family: var(--st-sans);\n  font-size: 13px;\n}\n\n/* Evenings */\n.still-evenings-grid {\n  display: grid;\n  grid-template-columns: repeat(12, minmax(0, 1fr));\n  align-items: center;\n  column-gap: 24px;\n  row-gap: 64px;\n}\n\n.still-evenings-copy {\n  grid-column: 1 / span 5;\n}\n\n.still-evenings-phone {\n  position: relative;\n  display: grid;\n  grid-column: 7 / span 6;\n  place-items: center;\n}\n\n.still-evenings-phone::before {\n  content: '';\n  position: absolute;\n  width: min(620px, 100%);\n  aspect-ratio: 1;\n  border-radius: 50%;\n  background: radial-gradient(\n    closest-side,\n    rgb(214 128 160 / 0.26),\n    rgb(140 110 220 / 0.1) 55%,\n    transparent\n  );\n  pointer-events: none;\n}\n\n.still-points {\n  display: grid;\n  gap: 28px;\n  margin-top: 44px;\n}\n\n.still-point {\n  display: grid;\n  grid-template-columns: 44px 1fr;\n  gap: 18px;\n}\n\n.still-point-icon {\n  display: grid;\n  place-items: center;\n  width: 44px;\n  height: 44px;\n  border-radius: 14px;\n  background: rgb(230 220 255 / 0.07);\n  box-shadow: inset 0 0 0 1px rgb(230 220 255 / 0.12);\n  color: var(--st-accent);\n}\n\n.still-point h3 {\n  font: 600 17px/1.35 var(--st-sans);\n  letter-spacing: 0;\n}\n\n.still-point p {\n  margin-top: 4px;\n  color: var(--st-ink-2);\n  font-size: 16px;\n}\n\n/* The phone: an unbranded frame around a live screen laid out in container units. */\n.still-phone {\n  --w: clamp(270px, 22vw + 20px, 330px);\n  position: relative;\n  width: var(--w);\n  margin: 0;\n}\n\n.still-phone-body {\n  position: relative;\n  aspect-ratio: 402 / 874;\n  padding: calc(var(--w) * 0.034);\n  border-radius: calc(var(--w) * 0.16);\n  background: linear-gradient(150deg, #4a4262, #1a1624 34%, #231d33 66%, #514868);\n  box-shadow:\n    inset 0 0 0 1px rgb(255 255 255 / 0.14),\n    inset 0 0 0 3px #0d0a15,\n    0 50px 90px -40px rgb(6 2 18 / 0.95),\n    0 0 0 1px rgb(0 0 0 / 0.35);\n}\n\n.still-phone-body::before,\n.still-phone-body::after {\n  content: '';\n  position: absolute;\n  width: 3px;\n  border-radius: 3px;\n  background: #3a3350;\n}\n\n.still-phone-body::before {\n  top: 22%;\n  left: -2px;\n  height: 9%;\n  box-shadow: 0 calc(var(--w) * 0.24) 0 #3a3350;\n}\n\n.still-phone-body::after {\n  top: 28%;\n  right: -2px;\n  height: 14%;\n}\n\n.still-phone-screen {\n  position: relative;\n  height: 100%;\n  overflow: hidden;\n  border-radius: calc(var(--w) * 0.128);\n  background: #1a1530;\n  color: var(--st-ink);\n  container-type: inline-size;\n}\n\n.still-phone-wall {\n  position: absolute;\n  inset: 0;\n  background:\n    radial-gradient(56cqw 40cqw at 76% 17%, rgb(236 222 255 / 0.32), transparent 70%),\n    radial-gradient(12cqw 64cqw at 74% 61.5%, rgb(255 206 222 / 0.3), transparent 72%),\n    radial-gradient(100cqw 34cqw at 50% 61%, rgb(255 160 186 / 0.4), transparent 70%),\n    linear-gradient(\n      180deg,\n      #19152f 0%,\n      #2a2048 30%,\n      #563262 52%,\n      #a0607a 61%,\n      #3d2549 61.4%,\n      #261b3c 74%,\n      #18142c 100%\n    );\n}\n\n.still-phone-wall svg {\n  position: absolute;\n  inset: 0;\n  width: 100%;\n  height: 62%;\n  fill: #f6f1ff;\n}\n\n.still-phone-wall .still-phone-glints {\n  top: 61.8%;\n  height: 36%;\n  fill: #ffe2ec;\n}\n\n.still-phone-wall::after {\n  content: '';\n  position: absolute;\n  left: 0;\n  right: 0;\n  top: 61.2%;\n  height: 1px;\n  background: linear-gradient(90deg, transparent, rgb(255 226 236 / 0.8), transparent);\n}\n\n.still-phone-warm {\n  position: absolute;\n  inset: 0;\n  background: linear-gradient(180deg, rgb(255 150 70 / 0.06), rgb(150 60 20 / 0.24));\n  opacity: 0;\n  pointer-events: none;\n  transition: opacity 900ms var(--lg-ease-out);\n}\n\n.still-phone-screen[data-warm] .still-phone-warm {\n  opacity: 1;\n}\n\n.still-phone-island {\n  position: absolute;\n  z-index: 3;\n  top: 3.2cqw;\n  left: 35cqw;\n  width: 30cqw;\n  height: 8.8cqw;\n  border-radius: 99px;\n  background: #06040b;\n}\n\n.still-phone-status {\n  position: absolute;\n  z-index: 2;\n  top: 0;\n  left: 0;\n  right: 0;\n  display: flex;\n  align-items: center;\n  justify-content: space-between;\n  height: 15cqw;\n  padding: 0 8cqw 0 9cqw;\n  font: 600 4.3cqw/1 var(--st-sans);\n}\n\n.still-phone-status svg {\n  width: 17cqw;\n  height: 4.4cqw;\n  fill: currentColor;\n}\n\n.still-phone-content {\n  position: absolute;\n  inset: 16cqw 4.5cqw 23cqw;\n  display: flex;\n  flex-direction: column;\n  gap: 3cqw;\n}\n\n.still-ev-date {\n  margin-top: 2cqw;\n  padding-left: 1.5cqw;\n  color: var(--st-ink-2);\n  font: 600 3.5cqw/1.2 var(--st-sans);\n}\n\n.still-ev-hello {\n  margin-bottom: 1.5cqw;\n  padding-left: 1.5cqw;\n  font: 500 9.6cqw/1 var(--st-serif);\n  letter-spacing: -0.01em;\n}\n\n.still-ev-card.lg-glass-surface {\n  --lg-panel-radius: 5.6cqw;\n  display: grid;\n  gap: 3cqw;\n  padding: 4cqw;\n  border-radius: 5.6cqw;\n}\n\n.still-ev-row {\n  display: flex;\n  align-items: center;\n  gap: 3cqw;\n}\n\n.still-ev-row > span:not(.still-ev-tile),\n.still-ev-list li > span:not(.still-ev-tile) {\n  display: grid;\n  flex: 1;\n  min-width: 0;\n}\n\n.still-ev-tile {\n  display: grid;\n  flex: none;\n  place-items: center;\n  width: 10cqw;\n  height: 10cqw;\n  border-radius: 3cqw;\n  background: linear-gradient(150deg, #9483dc, #4e3c8c);\n  box-shadow: inset 0 1px 0 rgb(255 255 255 / 0.3);\n  color: #fff;\n}\n\n.still-ev-tile .still-icon {\n  width: 5.6cqw;\n  height: 5.6cqw;\n}\n\n.still-ev-tile--rose {\n  background: linear-gradient(150deg, #e09ab0, #8a4a6e);\n}\n\n.still-ev-tile--dusk {\n  background: linear-gradient(150deg, #7f9be0, #3e4a8c);\n}\n\n.still-ev-tile--sun {\n  background: linear-gradient(150deg, #f2c08e, #b4607a);\n}\n\n.still-ev-title {\n  overflow: hidden;\n  font: 600 4.2cqw/1.25 var(--st-sans);\n  text-overflow: ellipsis;\n  white-space: nowrap;\n}\n\n.still-ev-meta {\n  overflow: hidden;\n  color: var(--st-ink-2);\n  font: 400 3.4cqw/1.35 var(--st-sans);\n  text-overflow: ellipsis;\n  white-space: nowrap;\n}\n\n.still-ev-progress.lg-progress {\n  --lg-progress-height: 1.3cqw;\n}\n\n.still-ev-progress .lg-progress-track {\n  box-shadow: none;\n}\n\n.still-ev-progress .lg-progress-fill {\n  background: linear-gradient(90deg, #b9a8f0, var(--st-accent));\n  box-shadow: none;\n}\n\n.still-ev-split {\n  display: flex;\n  align-items: center;\n  justify-content: space-between;\n  gap: 3cqw;\n  padding-top: 3cqw;\n  border-top: 1px solid rgb(255 255 255 / 0.08);\n  font: 500 3.8cqw/1.2 var(--st-sans);\n}\n\n.still-ev-begin {\n  display: inline-flex;\n  align-items: center;\n  align-self: center;\n  gap: 2cqw;\n  height: 11.5cqw;\n  margin-top: auto;\n  padding: 0 6cqw;\n  border-radius: 99px;\n  background: linear-gradient(180deg, #f1ebff, #d9ccfb);\n  box-shadow:\n    inset 0 1px 0 rgb(255 255 255 / 0.7),\n    0 6px 16px -6px rgb(10 4 30 / 0.6);\n  color: var(--st-accent-ink);\n  font: 600 3.9cqw/1 var(--st-sans);\n}\n\n.still-ev-begin .still-icon {\n  width: 5cqw;\n  height: 5cqw;\n}\n\n.still-ev-label {\n  margin-top: 1cqw;\n  padding-left: 1.5cqw;\n  color: var(--st-ink-2);\n  font: 600 3.5cqw/1 var(--st-sans);\n}\n\n.still-ev-list.lg-glass-surface {\n  --lg-panel-radius: 5.6cqw;\n  padding: 1cqw 4cqw;\n  border-radius: 5.6cqw;\n}\n\n.still-ev-list li {\n  display: flex;\n  align-items: center;\n  gap: 3cqw;\n  padding: 2.7cqw 0;\n}\n\n.still-ev-list li + li {\n  border-top: 1px solid rgb(255 255 255 / 0.08);\n}\n\n.still-ev-chevron.still-icon {\n  width: 4.4cqw;\n  height: 4.4cqw;\n  color: var(--st-ink-2);\n}\n\n.still-phone .lg-switch {\n  flex: none;\n}\n\n.still-phone-tabs.lg-glass-surface {\n  --lg-panel-radius: 99px;\n  position: absolute;\n  left: 5cqw;\n  right: 5cqw;\n  bottom: 5cqw;\n  display: flex;\n  align-items: center;\n  justify-content: space-around;\n  height: 15.5cqw;\n  border-radius: 99px;\n}\n\n.still-phone-tab {\n  display: grid;\n  justify-items: center;\n  gap: 1cqw;\n  color: var(--st-ink-2);\n  font: 600 2.7cqw/1 var(--st-sans);\n}\n\n.still-phone-tab .still-icon {\n  width: 6cqw;\n  height: 6cqw;\n}\n\n.still-phone-tab[data-active] {\n  color: var(--st-accent);\n}\n\n/* Voices */\n.still-voices {\n  text-align: center;\n}\n\n.still-voices-grid {\n  display: grid;\n  grid-template-columns: repeat(3, minmax(0, 1fr));\n  gap: clamp(32px, 4vw, 64px);\n  margin-top: 72px;\n  text-align: left;\n}\n\n.still-voice {\n  display: flex;\n  flex-direction: column;\n  justify-content: space-between;\n  gap: 28px;\n  padding-top: 28px;\n  border-top: 1px solid var(--st-line);\n}\n\n.still-voice blockquote {\n  margin: 0;\n  color: var(--st-ink);\n  font: italic 400 clamp(23px, 0.7vw + 16px, 27px) / 1.36 var(--st-serif);\n}\n\n.still-voice figcaption {\n  display: flex;\n  align-items: center;\n  gap: 12px;\n  color: var(--st-ink-2);\n  font-size: 14px;\n  line-height: 1.4;\n}\n\n.still-voice figcaption b {\n  display: block;\n  color: var(--st-ink);\n  font-weight: 600;\n}\n\n.still-avatar.lg-avatar {\n  width: 40px;\n  height: 40px;\n  flex: none;\n}\n\n.still-avatar .lg-avatar-fallback {\n  background: linear-gradient(140deg, var(--a), var(--b));\n  color: var(--st-accent-ink);\n  font: 700 13px/1 var(--st-sans);\n  letter-spacing: 0.02em;\n}\n\n.still-avatar--lilac {\n  --a: #efe7ff;\n  --b: #c4a6e6;\n}\n\n.still-avatar--rose {\n  --a: #ffe1ea;\n  --b: #dc93ac;\n}\n\n.still-avatar--blue {\n  --a: #dfe8ff;\n  --b: #a4b3ee;\n}\n\n.still-rating {\n  display: inline-flex;\n  align-items: center;\n  gap: 12px;\n  margin-top: 18px;\n  color: var(--st-ink-2);\n  font-size: 15px;\n}\n\n.still-rating-marks {\n  display: inline-flex;\n  gap: 3px;\n  color: var(--st-accent);\n}\n\n.still-rating-marks svg {\n  display: block;\n  width: 14px;\n  height: 14px;\n  fill: currentColor;\n}\n\n/* Pricing */\n.still-pricing {\n  text-align: center;\n}\n\n.still-pricing header {\n  position: relative;\n  z-index: 1;\n}\n\n.still-pricing .still-lede {\n  margin-inline: auto;\n}\n\n.still-pricing-stage {\n  position: relative;\n  display: grid;\n  justify-items: center;\n  margin-top: 64px;\n}\n\n.still-pricing-art {\n  position: absolute;\n  inset: -48px calc(-1 * var(--st-pad)) -40px;\n  overflow-x: clip;\n  overflow-y: visible;\n  pointer-events: none;\n}\n\n.still-pricing-moon {\n  position: absolute;\n  top: 20px;\n  left: calc(50% + 160px);\n  width: 250px;\n  height: 250px;\n  border-radius: 50%;\n  background: radial-gradient(\n    circle at 34% 32%,\n    #f2ecff 0%,\n    #d3c4f6 30%,\n    #9c86dc 62%,\n    #4f3d90 92%,\n    #3d2f78 100%\n  );\n  box-shadow:\n    inset -18px -22px 40px -10px rgb(30 20 70 / 0.45),\n    0 0 80px 8px rgb(200 180 255 / 0.12);\n}\n\n.still-pricing-moon::after {\n  content: '';\n  position: absolute;\n  inset: 0;\n  border-radius: inherit;\n  background:\n    radial-gradient(14% 14% at 30% 58%, rgb(124 99 196 / 0.28), transparent 70%),\n    radial-gradient(10% 10% at 62% 30%, rgb(124 99 196 / 0.22), transparent 70%),\n    radial-gradient(18% 18% at 66% 70%, rgb(124 99 196 / 0.18), transparent 70%);\n}\n\n.still-pricing-orbit {\n  position: absolute;\n  top: 52%;\n  left: 50%;\n  width: 1100px;\n  height: 260px;\n  margin-left: -550px;\n  border: 1px solid rgb(230 220 255 / 0.18);\n  border-radius: 50%;\n  transform: rotate(-8deg);\n}\n\n.still-pricing-art svg {\n  position: absolute;\n  inset: 0;\n  width: 100%;\n  height: 100%;\n  fill: #f6f1ff;\n}\n\n.still-plan.lg-glass-surface {\n  --lg-panel-radius: 36px;\n  position: relative;\n  z-index: 2;\n  width: min(100%, 560px);\n  padding: 40px clamp(22px, 4vw, 48px) 32px;\n  text-align: left;\n}\n\n.still-plan-top {\n  display: flex;\n  flex-wrap: wrap;\n  align-items: center;\n  justify-content: space-between;\n  gap: 16px;\n}\n\n.still-plan-top h3 {\n  font-size: 30px;\n  line-height: 1.1;\n}\n\n.still-period.lg-segmented {\n  width: auto;\n  font-family: var(--st-sans);\n  font-size: 13px;\n}\n\n/* A darker track, so both labels stay legible where the moon lights the glass. */\n.still-period.lg-segmented::before {\n  background-color: rgb(20 15 42 / 0.55);\n}\n\n.still-period .lg-segmented-item {\n  padding: 6px 13px;\n  font-weight: 600;\n}\n\n.still-price {\n  display: flex;\n  flex-wrap: wrap;\n  align-items: baseline;\n  gap: 4px 14px;\n  margin-top: 28px;\n}\n\n.still-price-figure {\n  font: 500 clamp(60px, 4vw + 30px, 78px) / 1 var(--st-serif);\n  font-variant-numeric: lining-nums tabular-nums;\n  letter-spacing: -0.02em;\n}\n\n.still-price-per {\n  color: var(--st-ink-2);\n  font-size: 17px;\n}\n\n.still-price-note {\n  margin-top: 8px;\n  color: var(--st-ink-2);\n  font-size: 15px;\n}\n\n.still-plan-list {\n  display: grid;\n  gap: 12px;\n  margin: 28px 0 32px;\n  padding: 28px 0 0;\n  border-top: 1px solid var(--st-line);\n}\n\n.still-plan-list li {\n  display: grid;\n  grid-template-columns: 22px 1fr;\n  gap: 12px;\n}\n\n.still-plan-list .still-icon {\n  margin-top: 3px;\n  color: var(--st-accent);\n}\n\n.still-plan-action,\n.still-plan-action .still-store-trigger {\n  width: 100%;\n}\n\n.still-plan-fine {\n  margin-top: 16px;\n  color: var(--st-ink-2);\n  font-size: 14px;\n  text-align: center;\n}\n\n.still-pricing-free {\n  position: relative;\n  margin-top: 48px;\n  color: var(--st-ink-2);\n}\n\n/* StoreMenu */\n.still-store-trigger .still-icon {\n  width: 18px;\n  height: 18px;\n  transition: transform 320ms var(--lg-spring);\n}\n\n.still-store-trigger[data-state='open'] .still-icon {\n  transform: rotate(180deg);\n}\n\n.still-store-menu.lg-menu-content {\n  display: grid;\n  gap: 2px;\n  width: 272px;\n  padding: 8px;\n  border-radius: 22px;\n  color: var(--st-ink);\n  font-family: var(--st-sans);\n  text-align: left;\n}\n\n.still-store-item.lg-menu-item {\n  display: flex;\n  align-items: center;\n  gap: 14px;\n  height: auto;\n  padding: 12px;\n  border-radius: 15px;\n  color: var(--st-ink);\n  text-decoration: none;\n}\n\n.still-store-item b {\n  display: block;\n  font-size: 15px;\n  font-weight: 600;\n  line-height: 1.3;\n}\n\n.still-store-item small {\n  display: block;\n  color: var(--st-ink-2);\n  font-size: 13px;\n  line-height: 1.4;\n}\n\n.still-store-item .still-icon {\n  width: 22px;\n  height: 22px;\n  color: var(--st-accent);\n}\n\n/* Questions */\n.still-faq-grid {\n  display: grid;\n  grid-template-columns: repeat(12, minmax(0, 1fr));\n  column-gap: 24px;\n  row-gap: 48px;\n}\n\n.still-faq-grid > header {\n  position: sticky;\n  top: 120px;\n  grid-column: 1 / span 4;\n  align-self: start;\n}\n\n.still-faq-list {\n  grid-column: 6 / span 7;\n  border-top: 1px solid var(--st-line);\n}\n\n.still-faq-item {\n  border-bottom: 1px solid var(--st-line);\n}\n\n/* The answers are rows on the page, not glass of their own. */\n.still-faq-list .lg-accordion-trigger {\n  width: 100%;\n  min-height: 0;\n  padding: 24px 4px;\n  border: 0;\n  border-radius: 6px;\n  background: none;\n  box-shadow: none;\n  color: var(--st-ink);\n  font: 500 clamp(22px, 0.6vw + 16px, 26px) / 1.25 var(--st-serif);\n  letter-spacing: 0;\n  text-align: left;\n  -webkit-backdrop-filter: none;\n  backdrop-filter: none;\n}\n\n.still-faq-list .lg-accordion-trigger:hover {\n  background: none;\n}\n\n.still-faq-list .lg-accordion-trigger:focus-visible {\n  outline: 2px solid var(--st-accent);\n  outline-offset: 3px;\n}\n\n.still-faq-list .lg-accordion-trigger > span:first-child {\n  display: flex;\n  flex: 1;\n  align-items: center;\n  justify-content: space-between;\n  gap: 24px;\n}\n\n.still-faq-list .lg-accordion-chevron {\n  display: none;\n}\n\n.still-faq-icon {\n  display: grid;\n  flex: none;\n  place-items: center;\n  width: 32px;\n  height: 32px;\n  border-radius: 50%;\n  box-shadow: inset 0 0 0 1px var(--st-line);\n  color: var(--st-accent);\n  transition:\n    transform 460ms var(--lg-spring),\n    background-color 200ms;\n}\n\n.still-faq-icon .still-icon {\n  width: 16px;\n  height: 16px;\n}\n\n.still-faq-list .lg-accordion-trigger:hover .still-faq-icon {\n  background: rgb(255 255 255 / 0.06);\n}\n\n.still-faq-list .lg-accordion-trigger[data-state='open'] .still-faq-icon {\n  transform: rotate(45deg);\n}\n\n.still-faq-list .lg-accordion-content {\n  --lg-panel-elevation-shadow: none;\n  margin: 0;\n  padding: 0;\n  border-radius: 0;\n  background: none;\n  box-shadow: none;\n  -webkit-backdrop-filter: none;\n  backdrop-filter: none;\n}\n\n.still-faq-list .lg-accordion-content::before,\n.still-faq-list .lg-accordion-content::after,\n.still-faq-list .lg-accordion-content > .lg-noise {\n  display: none;\n}\n\n.still-faq-list .lg-accordion-content p {\n  max-width: 60ch;\n  padding: 0 4px 26px;\n  color: var(--st-ink-2);\n  font-size: 17px;\n  line-height: 1.6;\n}\n\n/* Download */\n.still-download {\n  position: relative;\n  isolation: isolate;\n  padding-block: clamp(128px, 13vw, 196px) clamp(88px, 8vw, 128px);\n  overflow-x: clip;\n  text-align: center;\n}\n\n.still-download-art {\n  position: absolute;\n  inset: 0;\n  overflow: hidden;\n  pointer-events: none;\n}\n\n.still-download-stars {\n  position: absolute;\n  inset: 0;\n  width: 100%;\n  height: 70%;\n  fill: #f6f1ff;\n}\n\n.still-download-moon {\n  position: absolute;\n  top: clamp(40px, 6vw, 80px);\n  left: calc(50% + clamp(90px, 16vw, 250px));\n  width: clamp(64px, 6vw, 92px);\n  height: auto;\n  overflow: visible;\n}\n\n.still-download h2 {\n  position: relative;\n  font-size: clamp(46px, 4.4vw + 12px, 84px);\n  line-height: 1.02;\n  letter-spacing: -0.015em;\n}\n\n.still-download h2 em {\n  color: var(--st-ink-3);\n}\n\n.still-download .still-lede {\n  position: relative;\n  margin-inline: auto;\n}\n\n.still-download-actions {\n  position: relative;\n  display: flex;\n  justify-content: center;\n  margin-top: 44px;\n}\n\n.still-download-actions::before,\n.still-download-actions::after {\n  content: '';\n  position: absolute;\n  left: 50%;\n  width: 100vw;\n  margin-left: -50vw;\n  pointer-events: none;\n}\n\n.still-download-actions::before {\n  top: 50%;\n  height: 1px;\n  background: linear-gradient(\n    90deg,\n    transparent,\n    rgb(255 214 228 / 0.24) 18%,\n    rgb(255 228 236 / 0.75) 50%,\n    rgb(255 214 228 / 0.24) 82%,\n    transparent\n  );\n}\n\n.still-download-actions::after {\n  z-index: -1;\n  top: 50%;\n  height: 420px;\n  margin-top: -260px;\n  -webkit-mask-image: linear-gradient(90deg, transparent, #000 24%, #000 76%, transparent);\n  mask-image: linear-gradient(90deg, transparent, #000 24%, #000 76%, transparent);\n  background:\n    radial-gradient(\n      36% 34% at 50% 62%,\n      rgb(255 170 192 / 0.3),\n      rgb(190 120 170 / 0.1) 50%,\n      transparent 78%\n    ),\n    linear-gradient(\n      180deg,\n      transparent,\n      rgb(110 61 98 / 0.16) 48%,\n      rgb(163 98 124 / 0.22) 61.9%,\n      rgb(40 26 58 / 0.3) 62%,\n      transparent 92%\n    );\n}\n\n.still-download-actions > * {\n  position: relative;\n  z-index: 1;\n}\n\n.still-download-note {\n  position: relative;\n  margin-top: 28px;\n  color: var(--st-ink-2);\n  font-size: 14px;\n}\n\n/* Footer */\n.still-footer {\n  padding: 72px 0 40px;\n  border-top: 1px solid var(--st-line);\n  color: var(--st-ink-2);\n  font-size: 15px;\n}\n\n.still-footer-grid {\n  display: grid;\n  grid-template-columns: 2fr repeat(3, 1fr);\n  gap: 32px;\n}\n\n.still-footer-brand p {\n  max-width: 30ch;\n  margin-top: 14px;\n}\n\n.still-footer-brand .still-brand {\n  color: var(--st-ink);\n}\n\n.still-footer h2 {\n  margin-bottom: 16px;\n  color: var(--st-ink);\n  font: 600 13px/1.2 var(--st-sans);\n  letter-spacing: 0.06em;\n}\n\n.still-footer ul {\n  display: grid;\n  gap: 10px;\n}\n\n.still-footer a {\n  text-decoration: none;\n  transition: color 200ms;\n}\n\n.still-footer a:hover {\n  color: var(--st-ink);\n}\n\n.still-footer-base {\n  display: flex;\n  flex-wrap: wrap;\n  justify-content: space-between;\n  gap: 12px 24px;\n  margin-top: 64px;\n  padding-top: 24px;\n  border-top: 1px solid var(--st-line);\n  font-size: 14px;\n}\n\n/* The demo note when a store has no link yet. */\n.still-toast .lg-toast-root {\n  display: flex;\n  align-items: center;\n  gap: 12px;\n  padding: 10px 20px 10px 10px;\n}\n\n.still-toast-icon {\n  display: grid;\n  place-items: center;\n  width: 30px;\n  height: 30px;\n  flex: none;\n  border-radius: 50%;\n  background: var(--st-accent);\n  color: var(--st-accent-ink);\n}\n\n.still-toast-icon .still-icon {\n  width: 17px;\n  height: 17px;\n}\n\n.still-toast-text {\n  color: var(--st-ink);\n  font-size: 15px;\n  line-height: 1.38;\n}\n\n/* Motion */\n@keyframes still-rise {\n  from {\n    transform: translateY(var(--from, 24px));\n  }\n}\n\n@keyframes still-reveal {\n  from {\n    transform: translateY(32px);\n  }\n}\n\n@keyframes still-focus-in {\n  from {\n    filter: blur(10px);\n    transform: translateY(8px);\n  }\n}\n\n@keyframes still-fade {\n  from {\n    opacity: 0;\n  }\n}\n\n@keyframes still-open {\n  from {\n    opacity: 0;\n    transform: scaleX(0.2);\n  }\n}\n\n@keyframes still-twinkle {\n  50% {\n    opacity: 0.22;\n  }\n}\n\n@keyframes still-curve-draw {\n  0%,\n  24% {\n    stroke-dashoffset: 1;\n  }\n\n  100% {\n    stroke-dashoffset: 0;\n  }\n}\n\n@keyframes still-curve-in {\n  0%,\n  70% {\n    opacity: 0;\n  }\n}\n\n@media (prefers-reduced-motion: no-preference) {\n  :root:not([data-lg-reduce-motion='1']) .still-breath-rise {\n    --from: 40px;\n    animation: still-rise 1.8s var(--lg-ease-out) both;\n  }\n\n  :root:not([data-lg-reduce-motion='1']) .still-breath-ring {\n    animation: still-fade 1.4s 0.3s var(--lg-ease-out) backwards;\n  }\n\n  :root:not([data-lg-reduce-motion='1']) :is(.still-sky-glow, .still-sky-path, .still-sky-glints) {\n    animation: still-fade 2s var(--lg-ease-out) backwards;\n  }\n\n  :root:not([data-lg-reduce-motion='1']) .still-sky-horizon {\n    animation: still-open 1.6s 0.1s var(--lg-ease-out) backwards;\n  }\n\n  :root:not([data-lg-reduce-motion='1']) .still-hero-line {\n    animation: still-focus-in 1.1s 0.15s var(--lg-ease-out) both;\n  }\n\n  :root:not([data-lg-reduce-motion='1']) .still-hero-line--soft {\n    animation-delay: 0.45s;\n  }\n\n  :root:not([data-lg-reduce-motion='1']) :is(.still-hero-lede, .still-breath-status) {\n    animation: still-focus-in 0.9s 0.8s var(--lg-ease-out) both;\n  }\n\n  :root:not([data-lg-reduce-motion='1']) .still-breath-controls {\n    --from: 14px;\n    animation: still-rise 0.9s 1s var(--lg-ease-out) both;\n  }\n\n  /* The page's one quiet loop: a few stars and glints shimmer while the hero is on screen. */\n  :root:not([data-lg-reduce-motion='1']) .still-sky .still-twinkle {\n    animation: still-twinkle 16s ease-in-out infinite;\n  }\n\n  .still-hero[data-away] .still-sky .still-twinkle {\n    animation-play-state: paused;\n  }\n\n  @supports (animation-timeline: view()) {\n    /* Sections rise into place as they scroll in; they move only, so their glass keeps its\n       backdrop. */\n    :root:not([data-lg-reduce-motion='1']) .still-rise {\n      animation: still-reveal linear both;\n      animation-timeline: view();\n      animation-range: entry 0% entry 80%;\n    }\n\n    /* The breath draws itself as it scrolls in. Off screen, and without scroll timelines, it\n       stays drawn. */\n    :root:not([data-lg-reduce-motion='1'])\n      :is(.still-curve-line, .still-curve-area, .still-curve-dot) {\n      animation: still-curve-draw linear forwards;\n      animation-timeline: --still-curve;\n      animation-range: entry 0% cover 54%;\n    }\n\n    :root:not([data-lg-reduce-motion='1']) :is(.still-curve-area, .still-curve-dot) {\n      animation-name: still-curve-in;\n    }\n  }\n}\n\n@media (prefers-reduced-motion: reduce) {\n  .still-header.lg-header,\n  .still-story,\n  .still-faq-icon,\n  .still-store-trigger .still-icon,\n  .still-breath-orb,\n  .still-breath-trace,\n  .still-breath-tick,\n  .still-hero-title,\n  .still-hero-lede,\n  .still-phone-warm,\n  .still-skip {\n    transition: none !important;\n  }\n}\n\n:root[data-lg-reduce-motion='1']\n  :is(\n    .still-header.lg-header,\n    .still-story,\n    .still-faq-icon,\n    .still-breath-orb,\n    .still-breath-trace,\n    .still-breath-tick,\n    .still-hero-title,\n    .still-hero-lede,\n    .still-phone-warm\n  ) {\n  transition: none !important;\n}\n\n/* Layout */\n@media (max-width: 899px) {\n  .still-practice-head,\n  .still-practice-body,\n  .still-evenings-copy,\n  .still-evenings-phone,\n  .still-faq-grid > header,\n  .still-faq-list {\n    grid-column: 1 / -1;\n  }\n\n  .still-practice-body {\n    font-size: 17px;\n  }\n\n  .still-curve {\n    margin-top: 40px;\n  }\n\n  .still-curve-line,\n  .still-curve-dot {\n    stroke-width: 6;\n  }\n\n  .still-curve-labels b {\n    font-size: 20px;\n  }\n\n  .still-curve-labels span {\n    font-size: 13px;\n  }\n\n  .still-facts {\n    grid-template-columns: 1fr;\n    gap: 32px;\n    margin-top: 64px;\n  }\n\n  .still-scenes {\n    grid-template-columns: 1fr;\n    gap: 20px;\n    margin-top: 48px;\n  }\n\n  .still-carousel-bar {\n    flex-direction: column;\n    align-items: flex-start;\n    gap: 24px;\n  }\n\n  .still-voices-grid {\n    grid-template-columns: 1fr;\n    gap: 40px;\n    margin-top: 56px;\n  }\n\n  .still-faq-grid > header {\n    position: static;\n  }\n\n  .still-footer-grid {\n    grid-template-columns: repeat(3, 1fr);\n  }\n\n  .still-footer-brand {\n    grid-column: 1 / -1;\n  }\n\n  .still-pricing-moon {\n    left: auto;\n    right: -70px;\n    width: 240px;\n    height: 240px;\n  }\n}\n\n@media (max-width: 859px) {\n  .still-hero {\n    --nav-h: 82px;\n  }\n}\n\n@media (max-width: 600px) {\n  .still-sky-stars .still-sky-wide,\n  .still-sky-venus,\n  .still-sky-land {\n    display: none;\n  }\n\n  .still-rating {\n    flex-direction: column;\n    gap: 8px;\n  }\n\n  .still-curve-labels p {\n    padding-left: 8px;\n  }\n\n  .still-curve-labels b {\n    font-size: 18px;\n  }\n\n  .still-scene-body.lg-glass-surface {\n    padding: 20px 18px 16px;\n  }\n\n  .still-scene-title {\n    font-size: 28px;\n  }\n\n  .still-download h2 em {\n    display: block;\n  }\n\n  .still-footer-grid {\n    grid-template-columns: repeat(2, 1fr);\n  }\n\n  .still-footer-base {\n    flex-direction: column;\n  }\n}\n",
      "type": "registry:file",
      "target": "components/glassyui/templates/still/still.css"
    }
  ],
  "type": "registry:ui",
  "dependencies": [
    "clsx",
    "@radix-ui/react-accordion",
    "@radix-ui/react-avatar",
    "@radix-ui/react-slot",
    "@radix-ui/react-dropdown-menu",
    "@radix-ui/react-radio-group",
    "@radix-ui/react-switch",
    "@radix-ui/react-toast"
  ]
}