UNPKG

@ryanhelsing/ry-ui

Version:

Framework-agnostic, Light DOM web components. CSS is the source of truth.

1,838 lines (1,547 loc) 198 kB
/** * ry-ui Design Tokens * * CORE KNOBS → DERIVED TOKENS → COMPONENTS * * Themes only need to set the ~18 core knobs at the top. * Everything else derives automatically via color-mix() and calc(). * Override any derived token for fine-tuning. */ /* ═══════════════════════════════════════════════════════════════ @property — typed custom properties for animation & type safety Note: color tokens are NOT registered here because @property prevents light-dark() from re-resolving on dynamic color-scheme changes in Firefox. Colors use unregistered custom properties. ═══════════════════════════════════════════════════════════════ */ @property --ry-duration-fast { syntax: "<time>"; inherits: true; initial-value: 100ms; } @property --ry-duration-normal { syntax: "<time>"; inherits: true; initial-value: 200ms; } @property --ry-duration-slow { syntax: "<time>"; inherits: true; initial-value: 300ms; } @property --ry-space-1 { syntax: "<length>"; inherits: true; initial-value: 0.25rem; } @property --ry-space-2 { syntax: "<length>"; inherits: true; initial-value: 0.5rem; } @property --ry-space-3 { syntax: "<length>"; inherits: true; initial-value: 0.75rem; } @property --ry-space-4 { syntax: "<length>"; inherits: true; initial-value: 1rem; } @property --ry-space-6 { syntax: "<length>"; inherits: true; initial-value: 1.5rem; } @property --ry-space-8 { syntax: "<length>"; inherits: true; initial-value: 2rem; } @layer ry-tokens, ry-structure, ry-theme; @layer ry-tokens { :root { color-scheme: light dark; /* ═══════════════════════════════════════════════════════════════ CORE KNOBS — set these to define a theme ═══════════════════════════════════════════════════════════════ */ /* Palette: 3 roles */ --ry-color-primary: light-dark(oklch(0.623 0.188 259.8), oklch(0.714 0.143 254.6)); --ry-color-secondary: light-dark(oklch(0.554 0.041 257.4), oklch(0.711 0.035 256.8)); --ry-color-accent: light-dark(oklch(0.627 0.213 303.9), oklch(0.714 0.183 303.9)); /* Surface */ --ry-color-bg: light-dark(oklch(1 0 0), oklch(0.208 0.04 265.8)); --ry-color-text: light-dark(oklch(0.279 0.037 260), oklch(0.968 0.007 248.1)); /* Semantic (overrideable, but defaults are universal) */ --ry-color-success: oklch(0.723 0.192 149.6); --ry-color-warning: oklch(0.769 0.165 70.1); --ry-color-danger: oklch(0.637 0.208 25.3); --ry-color-info: oklch(0.715 0.126 215.2); /* Type: 2 fonts */ --ry-font-primary: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; --ry-font-secondary: ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, monospace; /* Shape */ --ry-radius-base: 0.375rem; --ry-border-width: 1px; --ry-outline-width: 0px; /* Depth */ --ry-shadow-color: light-dark(oklch(0 0 0 / 0.1), oklch(0 0 0 / 0.4)); --ry-shadow-strength: 1; --ry-shadow-spread: 1; /* Surface treatment */ --ry-panel-opacity: 1; --ry-panel-blur: 0px; /* Motion */ --ry-animation-style: smooth; /* none | smooth | bouncy */ --ry-duration-scale: 1; /* Density */ --ry-space-scale: 1; /* ═══════════════════════════════════════════════════════════════ DERIVED: COLORS — auto-generated from core palette ═══════════════════════════════════════════════════════════════ */ /* Hover/active states via color-mix */ --ry-color-primary-hover: color-mix(in oklch, var(--ry-color-primary) 80%, var(--ry-color-text)); --ry-color-primary-active: color-mix(in oklch, var(--ry-color-primary) 65%, var(--ry-color-text)); --ry-color-secondary-hover: color-mix(in oklch, var(--ry-color-secondary) 80%, var(--ry-color-text)); --ry-color-secondary-active: color-mix(in oklch, var(--ry-color-secondary) 65%, var(--ry-color-text)); --ry-color-accent-hover: color-mix(in oklch, var(--ry-color-accent) 80%, var(--ry-color-text)); --ry-color-accent-active: color-mix(in oklch, var(--ry-color-accent) 65%, var(--ry-color-text)); --ry-color-danger-hover: color-mix(in oklch, var(--ry-color-danger) 80%, var(--ry-color-text)); /* Text variants */ --ry-color-text-muted: color-mix(in oklch, var(--ry-color-text) 55%, var(--ry-color-bg)); --ry-color-text-inverse: var(--ry-color-bg); /* Background variants */ --ry-color-bg-subtle: color-mix(in oklch, var(--ry-color-bg) 96%, var(--ry-color-text)); --ry-color-bg-muted: color-mix(in oklch, var(--ry-color-bg) 92%, var(--ry-color-text)); /* Border variants */ --ry-color-border: color-mix(in oklch, var(--ry-color-bg) 82%, var(--ry-color-text)); --ry-color-border-strong: color-mix(in oklch, var(--ry-color-bg) 70%, var(--ry-color-text)); /* Overlay */ --ry-color-overlay: color-mix(in oklch, var(--ry-color-text) 50%, transparent); --ry-color-hover-overlay: color-mix(in oklch, var(--ry-color-text) 4%, transparent); /* Semantic backgrounds & text — derived from base semantic colors */ --ry-color-info-bg: color-mix(in srgb, var(--ry-color-info) 12%, var(--ry-color-bg)); --ry-color-info-text: color-mix(in oklch, var(--ry-color-info) 70%, var(--ry-color-text)); --ry-color-success-bg: color-mix(in srgb, var(--ry-color-success) 12%, var(--ry-color-bg)); --ry-color-success-text: color-mix(in oklch, var(--ry-color-success) 70%, var(--ry-color-text)); --ry-color-warning-bg: color-mix(in srgb, var(--ry-color-warning) 12%, var(--ry-color-bg)); --ry-color-warning-text: color-mix(in oklch, var(--ry-color-warning) 70%, var(--ry-color-text)); --ry-color-danger-bg: color-mix(in srgb, var(--ry-color-danger) 12%, var(--ry-color-bg)); --ry-color-danger-text: color-mix(in oklch, var(--ry-color-danger) 70%, var(--ry-color-text)); /* ═══════════════════════════════════════════════════════════════ DERIVED: CODE SYNTAX — from palette, auto-adapts to any theme ═══════════════════════════════════════════════════════════════ */ --ry-code-bg: var(--ry-color-bg-subtle); --ry-code-header-bg: var(--ry-color-bg-muted); --ry-code-text-color: var(--ry-color-text); --ry-code-title-color: var(--ry-color-text-muted); --ry-code-icon-color: var(--ry-color-text-muted); --ry-code-icon-hover-bg: var(--ry-color-bg-muted); --ry-code-icon-hover-color: var(--ry-color-text); --ry-code-line-number-color: var(--ry-color-secondary); --ry-code-line-border-color: var(--ry-color-border); --ry-code-color-preview-border: var(--ry-color-border); --ry-code-keyword: var(--ry-color-danger); --ry-code-property: var(--ry-color-primary); --ry-code-value: var(--ry-color-accent); --ry-code-string: var(--ry-color-success); --ry-code-number: var(--ry-color-warning); --ry-code-comment: var(--ry-color-text-muted); --ry-code-selector: var(--ry-color-info); --ry-code-punctuation: var(--ry-color-text-muted); --ry-code-tag: var(--ry-color-info); --ry-code-attribute: var(--ry-color-primary); /* ═══════════════════════════════════════════════════════════════ DERIVED: TYPOGRAPHY — from core font knobs ═══════════════════════════════════════════════════════════════ */ --ry-font-sans: var(--ry-font-primary); --ry-font-mono: var(--ry-font-secondary); /* Font sizes */ --ry-text-xs: 0.75rem; --ry-text-sm: 0.875rem; --ry-text-base: 1rem; --ry-text-lg: 1.125rem; --ry-text-xl: 1.25rem; --ry-text-2xl: 1.5rem; --ry-text-3xl: 1.875rem; --ry-text-4xl: 2.25rem; /* Font weights */ --ry-font-normal: 400; --ry-font-medium: 500; --ry-font-semibold: 600; --ry-font-bold: 700; /* Line heights */ --ry-leading-tight: 1.25; --ry-leading-normal: 1.5; --ry-leading-relaxed: 1.75; /* ═══════════════════════════════════════════════════════════════ DERIVED: SPACING — scaled from base ═══════════════════════════════════════════════════════════════ */ --ry-space-0: 0; --ry-space-1: calc(0.25rem * var(--ry-space-scale)); --ry-space-2: calc(0.5rem * var(--ry-space-scale)); --ry-space-3: calc(0.75rem * var(--ry-space-scale)); --ry-space-4: calc(1rem * var(--ry-space-scale)); --ry-space-5: calc(1.25rem * var(--ry-space-scale)); --ry-space-6: calc(1.5rem * var(--ry-space-scale)); --ry-space-8: calc(2rem * var(--ry-space-scale)); --ry-space-10: calc(2.5rem * var(--ry-space-scale)); --ry-space-12: calc(3rem * var(--ry-space-scale)); --ry-space-16: calc(4rem * var(--ry-space-scale)); --ry-space-20: calc(5rem * var(--ry-space-scale)); /* ═══════════════════════════════════════════════════════════════ DERIVED: BORDERS & RADIUS — scaled from base ═══════════════════════════════════════════════════════════════ */ --ry-radius-none: 0; --ry-radius-sm: calc(var(--ry-radius-base) * 0.66); --ry-radius-md: var(--ry-radius-base); --ry-radius-lg: calc(var(--ry-radius-base) * 1.33); --ry-radius-xl: calc(var(--ry-radius-base) * 2); --ry-radius-2xl: calc(var(--ry-radius-base) * 2.66); --ry-radius-full: 9999px; /* ═══════════════════════════════════════════════════════════════ DERIVED: SHADOWS — scaled from strength + spread knobs ═══════════════════════════════════════════════════════════════ */ --ry-shadow-color-sm: color-mix(in oklch, var(--ry-shadow-color) calc(50% * var(--ry-shadow-strength)), transparent); --ry-shadow-sm: 0 calc(1px * var(--ry-shadow-spread)) calc(2px * var(--ry-shadow-spread)) 0 var(--ry-shadow-color-sm); --ry-shadow-md: 0 calc(4px * var(--ry-shadow-spread)) calc(6px * var(--ry-shadow-spread)) calc(-1px * var(--ry-shadow-spread)) var(--ry-shadow-color), 0 calc(2px * var(--ry-shadow-spread)) calc(4px * var(--ry-shadow-spread)) calc(-2px * var(--ry-shadow-spread)) var(--ry-shadow-color); --ry-shadow-lg: 0 calc(10px * var(--ry-shadow-spread)) calc(15px * var(--ry-shadow-spread)) calc(-3px * var(--ry-shadow-spread)) var(--ry-shadow-color), 0 calc(4px * var(--ry-shadow-spread)) calc(6px * var(--ry-shadow-spread)) calc(-4px * var(--ry-shadow-spread)) var(--ry-shadow-color); --ry-shadow-xl: 0 calc(20px * var(--ry-shadow-spread)) calc(25px * var(--ry-shadow-spread)) calc(-5px * var(--ry-shadow-spread)) var(--ry-shadow-color), 0 calc(8px * var(--ry-shadow-spread)) calc(10px * var(--ry-shadow-spread)) calc(-6px * var(--ry-shadow-spread)) var(--ry-shadow-color); /* ═══════════════════════════════════════════════════════════════ DERIVED: TRANSITIONS — scaled from duration-scale + animation style ═══════════════════════════════════════════════════════════════ */ --ry-duration-fast: calc(100ms * var(--ry-duration-scale)); --ry-duration-normal: calc(200ms * var(--ry-duration-scale)); --ry-duration-slow: calc(300ms * var(--ry-duration-scale)); --ry-ease: cubic-bezier(0.4, 0, 0.2, 1); --ry-ease-in: cubic-bezier(0.4, 0, 1, 1); --ry-ease-out: cubic-bezier(0, 0, 0.2, 1); --ry-ease-out-back: cubic-bezier(0.34, 1.85, 0.64, 1); --ry-ease-out-quint: cubic-bezier(0.23, 1, 0.32, 1); --ry-ease-in-out-expo: cubic-bezier(1, 0, 0, 1); /* ═══════════════════════════════════════════════════════════════ Z-INDEX (not themeable — structural) ═══════════════════════════════════════════════════════════════ */ --ry-z-dropdown: 1000; --ry-z-sticky: 1020; --ry-z-fixed: 1030; --ry-z-modal-backdrop: 1040; --ry-z-modal: 1050; --ry-z-popover: 1060; --ry-z-tooltip: 1070; --ry-z-toast: 1080; /* ═══════════════════════════════════════════════════════════════ DERIVED: FOCUS — from primary ═══════════════════════════════════════════════════════════════ */ --ry-focus-ring: 0 0 0 3px color-mix(in oklch, var(--ry-color-primary) 50%, transparent); } /* Force light or dark mode */ [data-ry-theme="light"] { color-scheme: light; } [data-ry-theme="dark"] { color-scheme: dark; } } /* @layer ry-tokens */ /** * ry-ui Structure CSS * * Pure layout and behavioral styles using data-ry-target selectors. * No colors, shadows, or decorative properties. * Works with any theme or no theme at all. * * Users can bring their own styling (e.g., Tailwind) - classes are optional. * JS queries use [data-ry-target], structure CSS uses [data-ry-target], * only theme CSS requires .ry-* classes. */ @layer ry-structure { /* Enable native height: auto animation for all components */ :root { interpolate-size: allow-keywords; } /* ═══════════════════════════════════════════════════════════════ SCROLL LOCK (for modals, drawers) ═══════════════════════════════════════════════════════════════ */ body { margin: 0; min-height: 100dvh; line-height: 1.5; -webkit-font-smoothing: antialiased; text-rendering: optimizeLegibility; } body[data-ry-scroll-lock] { overflow: hidden; padding-right: var(--ry-scrollbar-width, 0); } /* ═══════════════════════════════════════════════════════════════ PREFLIGHT RESET (opt-in via data-ry-reset on body/html) Faithful equivalent of Tailwind Preflight. ═══════════════════════════════════════════════════════════════ */ /* Universal — :where() gives zero specificity so component styles always win */ :where([data-ry-reset]) *, :where([data-ry-reset]) *::before, :where([data-ry-reset]) *::after, :where([data-ry-reset]) *::backdrop { box-sizing: border-box; margin: 0; padding: 0; border: 0 solid; } /* Root */ :where([data-ry-reset]) { line-height: 1.5; -webkit-text-size-adjust: 100%; tab-size: 4; -webkit-tap-highlight-color: transparent; } /* Typography */ :where([data-ry-reset]) :where(h1, h2, h3, h4, h5, h6) { font-size: inherit; font-weight: inherit; } :where([data-ry-reset]) :where(a) { color: inherit; text-decoration: inherit; } :where([data-ry-reset]) :where(b, strong) { font-weight: bolder; } :where([data-ry-reset]) :where(code, kbd, samp, pre) { font-size: 1em; } :where([data-ry-reset]) :where(small) { font-size: 80%; } :where([data-ry-reset]) :where(sub, sup) { font-size: 75%; line-height: 0; position: relative; vertical-align: baseline; } :where([data-ry-reset]) :where(sub) { bottom: -0.25em; } :where([data-ry-reset]) :where(sup) { top: -0.5em; } /* Lists */ :where([data-ry-reset]) :where(ol, ul, menu) { list-style: none; } /* Table */ :where([data-ry-reset]) :where(table) { text-indent: 0; border-color: inherit; border-collapse: collapse; } /* HR */ :where([data-ry-reset]) :where(hr) { height: 0; color: inherit; border-top-width: 1px; } /* Media */ :where([data-ry-reset]) :where(img, svg, video, canvas, audio, iframe, embed, object) { display: block; vertical-align: middle; } :where([data-ry-reset]) :where(img, video) { max-width: 100%; height: auto; } /* Form controls */ :where([data-ry-reset]) :where(button, input, select, optgroup, textarea) { font: inherit; font-feature-settings: inherit; font-variation-settings: inherit; letter-spacing: inherit; color: inherit; border-radius: 0; background-color: transparent; } :where([data-ry-reset]) ::placeholder { opacity: 1; } @supports (color: color-mix(in oklab, currentcolor 50%, transparent)) { :where([data-ry-reset]) ::placeholder { color: color-mix(in oklab, currentcolor 50%, transparent); } } :where([data-ry-reset]) :where(textarea) { resize: vertical; } :where([data-ry-reset]) :where(button, input:where([type='button'], [type='reset'], [type='submit'])) { appearance: button; } :where([data-ry-reset]) ::-webkit-search-decoration { -webkit-appearance: none; } :where([data-ry-reset]) ::-webkit-inner-spin-button, :where([data-ry-reset]) ::-webkit-outer-spin-button { height: auto; } /* Misc */ :where([data-ry-reset]) :where(summary) { display: list-item; } :where([data-ry-reset]) :where([hidden]:not([hidden='until-found'])) { display: none !important; } /* ═══════════════════════════════════════════════════════════════ TRANSFORM WRAPPER (FOUC prevention) ═══════════════════════════════════════════════════════════════ */ ry, ry-search-item, ry-search-group { display: none; } /* ═══════════════════════════════════════════════════════════════ BOX SIZING RESET ═══════════════════════════════════════════════════════════════ */ :where([data-ry-target], ry-page, ry-header, ry-main, ry-footer, ry-section, ry-aside, ry-grid, ry-stack, ry-cluster, ry-split, ry-center, ry-card, ry-accordion, ry-modal, ry-tabs, ry-dropdown, ry-button, ry-badge, ry-alert, ry-field, ry-nav, ry-logo, ry-actions, ry-accordion-item, ry-tab, ry-menu, ry-menu-item, ry-divider, ry-theme-toggle, ry-select, ry-switch, ry-tooltip, ry-drawer, ry-toast, ry-toggle-button, ry-knob, ry-slider, ry-number-select, ry-color-picker, ry-color-input, ry-gradient-picker, ry-tree, ry-tree-item, ry-tag, ry-tag-input, ry-hero, ry-stat, ry-feature, ry-feature-grid, ry-pricing, ry-pricing-card, ry-carousel, ry-combobox, ry-heading, ry-logo-bar) { box-sizing: border-box; } :where([data-ry-target], ry-page, ry-header, ry-main, ry-footer, ry-section, ry-card, ry-accordion, ry-modal, ry-tabs, ry-dropdown) * { box-sizing: inherit; } /* ═══════════════════════════════════════════════════════════════ CUSTOM ELEMENT DISPLAY DEFAULTS ═══════════════════════════════════════════════════════════════ */ /* Block elements */ :is(ry-page, ry-header, ry-main, ry-footer, ry-section, ry-aside, ry-card, ry-accordion, ry-accordion-item, ry-tabs, ry-tab, ry-alert, ry-field, ry-tag-input, ry-carousel) { display: block; } /* Flex containers */ :is(ry-grid, ry-stack, ry-cluster, ry-split, ry-center, ry-nav, ry-actions) { display: flex; } /* Inline elements */ :is(ry-badge, ry-logo, ry-tag) { display: inline-flex; } /* Contents (wrapper doesn't affect layout) */ :is(ry-modal, ry-drawer) { display: contents; } /* Button-like elements */ :is(ry-button, ry-menu-item) { display: inline-flex; } /* Balanced text wrapping for headings in overlay/display components */ :is(ry-modal [data-ry-target="header"] h3, ry-card h3, ry-hero h1, ry-pricing-card h3, ry-heading [data-ry-target="title"]) { text-wrap: balance; } /* ═══════════════════════════════════════════════════════════════ PAGE LAYOUT ═══════════════════════════════════════════════════════════════ */ ry-page { display: flex; flex-direction: column; min-height: 100vh; min-height: 100dvh; container-type: inline-size; scrollbar-gutter: stable; overflow-x: clip; } /* ═══════════════════════════════════════════════════════════════ HEADER ═══════════════════════════════════════════════════════════════ */ ry-header { display: flex; align-items: center; justify-content: space-between; gap: var(--ry-space-4, 1rem); padding: var(--ry-space-4, 1rem) var(--ry-space-6, 1.5rem); } ry-header[sticky] { position: sticky; top: 0; z-index: var(--ry-z-sticky, 1020); } /* ═══════════════════════════════════════════════════════════════ MAIN ═══════════════════════════════════════════════════════════════ */ ry-main { flex: 1; width: 100%; max-width: 1200px; margin: 0 auto; padding: var(--ry-space-8, 2rem) var(--ry-space-6, 1.5rem); container-type: inline-size; scrollbar-gutter: stable; } /* ═══════════════════════════════════════════════════════════════ FOOTER ═══════════════════════════════════════════════════════════════ */ ry-footer { padding: var(--ry-space-6, 1.5rem); text-align: center; } /* Full footer with columns */ ry-footer[layout="columns"] { text-align: start; padding: var(--ry-space-12, 3rem) var(--ry-space-6, 1.5rem); } ry-footer[layout="columns"] > [data-ry-target="columns"], ry-footer[layout="columns"] > .ry-footer__columns { display: grid; grid-template-columns: 1.5fr repeat(auto-fit, minmax(8rem, 1fr)); gap: var(--ry-space-8, 2rem); padding-block-end: var(--ry-space-8, 2rem); } ry-footer[layout="columns"] > [data-ry-target="columns"] nav, ry-footer[layout="columns"] > .ry-footer__columns nav { display: flex; flex-direction: column; gap: var(--ry-space-2, 0.5rem); } ry-footer[layout="columns"] > [data-ry-target="columns"] nav strong, ry-footer[layout="columns"] > .ry-footer__columns nav strong { margin-block-end: var(--ry-space-2, 0.5rem); } ry-footer[layout="columns"] > [data-ry-target="bottom"], ry-footer[layout="columns"] > .ry-footer__bottom { display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: var(--ry-space-4, 1rem); padding-block-start: var(--ry-space-6, 1.5rem); border-top: 1px solid currentColor; opacity: 0.5; } @media (max-width: 768px) { ry-footer[layout="columns"] > [data-ry-target="columns"], ry-footer[layout="columns"] > .ry-footer__columns { grid-template-columns: 1fr 1fr; } } /* ═══════════════════════════════════════════════════════════════ SECTION ═══════════════════════════════════════════════════════════════ */ ry-section { margin-block-end: var(--ry-space-12, 3rem); container-type: inline-size; } ry-section:last-child { margin-block-end: 0; } ry-section[narrow] { max-inline-size: 48rem; margin-inline: auto; } /* Full-width breakout — bg goes edge-to-edge, content stays centered */ ry-section[full], ry-section[inverted], ry-footer, ry-logo-bar { width: 100vw; margin-inline-start: calc(50% - 50vw); padding-inline: max(var(--ry-space-6, 1.5rem), calc(50vw - 50%)); } ry-section[inverted] { padding-block: var(--ry-space-12, 3rem); } ry-section[pad-bottom="lg"] { padding-bottom: var(--ry-space-20, 5rem); } /* ═══════════════════════════════════════════════════════════════ LOGO BAR ═══════════════════════════════════════════════════════════════ */ ry-logo-bar { display: flex; flex-wrap: wrap; justify-content: center; align-items: center; gap: var(--ry-space-8, 2rem); padding-block: var(--ry-space-8, 2rem); text-align: center; } ry-logo-bar > p { width: 100%; margin: 0; } ry-logo-bar > :not(p) { display: inline-flex; align-items: center; } /* Scroll layout — horizontal scroll, no wrap */ ry-logo-bar[layout="scroll"] { flex-wrap: nowrap; overflow-x: auto; overflow-y: hidden; scrollbar-width: none; -webkit-overflow-scrolling: touch; } ry-logo-bar[layout="scroll"]::-webkit-scrollbar { display: none; } ry-logo-bar[layout="scroll"] > :not(p) { flex-shrink: 0; } /* Marquee layout — infinite auto-scroll */ ry-logo-bar[layout="marquee"] { flex-wrap: nowrap; overflow: hidden; } ry-logo-bar[layout="marquee"] [data-ry-target="track"] { display: flex; align-items: center; gap: var(--ry-space-8, 2rem); width: max-content; animation: ry-marquee var(--ry-logo-bar-speed, 30s) linear infinite; } ry-logo-bar[layout="marquee"] [data-ry-target="track"] > * { display: inline-flex; align-items: center; flex-shrink: 0; } ry-logo-bar[layout="marquee"]:hover [data-ry-target="track"] { animation-play-state: paused; } @keyframes ry-marquee { from { transform: translateX(0); } to { transform: translateX(-25%); } } /* Size variants */ ry-logo-bar[size="sm"] { padding: var(--ry-space-4, 1rem) var(--ry-space-4, 1rem); gap: var(--ry-space-4, 1rem); } ry-logo-bar[size="lg"] { padding: var(--ry-space-12, 3rem) var(--ry-space-6, 1.5rem); gap: var(--ry-space-6, 1.5rem); } /* Logo items */ ry-logo-bar img { height: var(--ry-logo-bar-height, 2rem); width: auto; object-fit: contain; } ry-logo-bar span { white-space: nowrap; } /* ═══════════════════════════════════════════════════════════════ GRID ═══════════════════════════════════════════════════════════════ */ ry-grid { display: grid; gap: var(--ry-space-4, 1rem); } ry-grid[cols="1"] { grid-template-columns: 1fr; } ry-grid[cols="2"] { grid-template-columns: repeat(2, 1fr); } ry-grid[cols="3"] { grid-template-columns: repeat(3, 1fr); } ry-grid[cols="4"] { grid-template-columns: repeat(4, 1fr); } ry-grid[cols="5"] { grid-template-columns: repeat(5, 1fr); } ry-grid[cols="6"] { grid-template-columns: repeat(6, 1fr); } /* Auto-fit mode: fluid columns based on min-width */ ry-grid[cols="auto-fit"] { grid-template-columns: repeat(auto-fit, minmax(var(--ry-grid-min, 280px), 1fr)); } ry-grid[cols="auto-fill"] { grid-template-columns: repeat(auto-fill, minmax(var(--ry-grid-min, 280px), 1fr)); } ry-grid[overlap] { position: relative; z-index: 1; margin-top: calc(-1 * var(--ry-space-12, 3rem)); padding-inline: var(--ry-space-6, 1.5rem); } /* Default responsive behavior */ @container (max-width: 640px) { :is(ry-grid[cols="2"], ry-grid[cols="3"], ry-grid[cols="4"], ry-grid[cols="5"], ry-grid[cols="6"]) { grid-template-columns: 1fr; } } @container (min-width: 641px) and (max-width: 1024px) { :is(ry-grid[cols="3"], ry-grid[cols="4"], ry-grid[cols="5"], ry-grid[cols="6"]) { grid-template-columns: repeat(2, 1fr); } } /* Per-breakpoint column overrides: cols-sm, cols-md, cols-lg */ @container (max-width: 640px) { ry-grid[cols-sm="1"] { grid-template-columns: 1fr; } ry-grid[cols-sm="2"] { grid-template-columns: repeat(2, 1fr); } ry-grid[cols-sm="3"] { grid-template-columns: repeat(3, 1fr); } } @container (min-width: 641px) and (max-width: 1024px) { ry-grid[cols-md="1"] { grid-template-columns: 1fr; } ry-grid[cols-md="2"] { grid-template-columns: repeat(2, 1fr); } ry-grid[cols-md="3"] { grid-template-columns: repeat(3, 1fr); } ry-grid[cols-md="4"] { grid-template-columns: repeat(4, 1fr); } } @container (min-width: 1025px) { ry-grid[cols-lg="2"] { grid-template-columns: repeat(2, 1fr); } ry-grid[cols-lg="3"] { grid-template-columns: repeat(3, 1fr); } ry-grid[cols-lg="4"] { grid-template-columns: repeat(4, 1fr); } ry-grid[cols-lg="5"] { grid-template-columns: repeat(5, 1fr); } ry-grid[cols-lg="6"] { grid-template-columns: repeat(6, 1fr); } } /* ═══════════════════════════════════════════════════════════════ STACK (vertical) ═══════════════════════════════════════════════════════════════ */ ry-stack { display: flex; flex-direction: column; gap: var(--ry-space-4, 1rem); } ry-stack[gap="sm"] { gap: var(--ry-space-2, 0.5rem); } ry-stack[gap="md"] { gap: var(--ry-space-4, 1rem); } ry-stack[gap="lg"] { gap: var(--ry-space-6, 1.5rem); } ry-stack[gap="xl"] { gap: var(--ry-space-8, 2rem); } /* ═══════════════════════════════════════════════════════════════ CLUSTER (horizontal, wraps) ═══════════════════════════════════════════════════════════════ */ ry-cluster { display: flex; flex-wrap: wrap; align-items: center; gap: var(--ry-space-3, 0.75rem); } ry-cluster[gap="sm"] { gap: var(--ry-space-2, 0.5rem); } ry-cluster[gap="md"] { gap: var(--ry-space-3, 0.75rem); } ry-cluster[gap="lg"] { gap: var(--ry-space-4, 1rem); } /* ═══════════════════════════════════════════════════════════════ SPLIT (two columns) ═══════════════════════════════════════════════════════════════ */ ry-split { display: flex; gap: var(--ry-space-6, 1.5rem); } ry-split > :first-child { flex: 1; } ry-split > :last-child { flex-shrink: 0; width: var(--ry-split-width, 300px); min-width: var(--ry-split-min-width, 0); } /* Resize handle */ ry-split [data-ry-target="handle"] { flex-shrink: 0; width: 8px; margin-inline: -4px; cursor: col-resize; position: relative; z-index: 1; touch-action: none; } /* Larger hit area via pseudo-element */ ry-split [data-ry-target="handle"]::before { content: ''; position: absolute; inset-block: 0; inset-inline: -4px; } /* Visible drag indicator */ ry-split [data-ry-target="handle"]::after { content: ''; position: absolute; inset-block-start: 50%; inset-inline-start: 50%; width: 4px; height: 32px; transform: translate(-50%, -50%); border-radius: 2px; opacity: 0; transition: opacity var(--ry-duration-fast, 100ms); } ry-split [data-ry-target="handle"]:hover::after, ry-split[data-ry-resizing] [data-ry-target="handle"]::after { opacity: 1; } @container (max-width: 768px) { ry-split { flex-direction: column; } ry-split > :last-child { width: 100%; } ry-split [data-ry-target="handle"] { display: none; } } /* ═══════════════════════════════════════════════════════════════ CENTER ═══════════════════════════════════════════════════════════════ */ ry-center { display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center; } /* ═══════════════════════════════════════════════════════════════ NAV ═══════════════════════════════════════════════════════════════ */ ry-nav { display: flex; align-items: center; gap: var(--ry-space-1, 0.25rem); } ry-nav a { text-decoration: none; padding: var(--ry-space-2, 0.5rem) var(--ry-space-3, 0.75rem); white-space: nowrap; } /* ═══════════════════════════════════════════════════════════════ LOGO ═══════════════════════════════════════════════════════════════ */ ry-logo { display: inline-flex; align-items: center; } /* ═══════════════════════════════════════════════════════════════ ACTIONS ═══════════════════════════════════════════════════════════════ */ ry-actions { display: flex; align-items: center; gap: var(--ry-space-2, 0.5rem); margin-inline-start: auto; } /* ═══════════════════════════════════════════════════════════════ DIVIDER ═══════════════════════════════════════════════════════════════ */ ry-divider { display: block; height: 1px; margin-block: var(--ry-space-4, 1rem); margin-inline: 0; } ry-divider[vertical] { width: 1px; height: auto; align-self: stretch; margin-block: 0; margin-inline: var(--ry-space-4, 1rem); } /* ═══════════════════════════════════════════════════════════════ BUTTONS ═══════════════════════════════════════════════════════════════ */ ry-button { display: inline-flex; align-items: center; justify-content: center; gap: var(--ry-space-2, 0.5rem); padding: var(--ry-space-2, 0.5rem) var(--ry-space-4, 1rem); white-space: nowrap; cursor: pointer; user-select: none; } ry-button[disabled] { cursor: not-allowed; pointer-events: none; } /* Button sizes */ ry-button[size="sm"] { padding: var(--ry-space-1, 0.25rem) var(--ry-space-3, 0.75rem); } ry-button[size="lg"] { padding: var(--ry-space-3, 0.75rem) var(--ry-space-6, 1.5rem); } /* Icon-only button */ ry-button[icon]:empty { padding: var(--ry-space-2, 0.5rem); } ry-button[icon][size="sm"]:empty { padding: var(--ry-space-1, 0.25rem); } /* Link variant — inline text link style */ ry-button[variant="link"] { background: none; border: none; padding: 0; display: inline; cursor: pointer; } /* ═══════════════════════════════════════════════════════════════ TOGGLE BUTTON ═══════════════════════════════════════════════════════════════ */ ry-toggle-button { display: inline-flex; align-items: center; justify-content: center; gap: var(--ry-space-2, 0.5rem); padding: var(--ry-space-2, 0.5rem) var(--ry-space-4, 1rem); white-space: nowrap; cursor: pointer; user-select: none; } ry-toggle-button[disabled] { cursor: not-allowed; pointer-events: none; } /* Toggle button sizes */ ry-toggle-button[size="sm"] { padding: var(--ry-space-1, 0.25rem) var(--ry-space-3, 0.75rem); } ry-toggle-button[size="lg"] { padding: var(--ry-space-3, 0.75rem) var(--ry-space-6, 1.5rem); } /* Icon-only toggle button */ ry-toggle-button[icon]:empty { padding: var(--ry-space-2, 0.5rem); } ry-toggle-button[icon][size="sm"]:empty { padding: var(--ry-space-1, 0.25rem); } ry-toggle-button[icon][size="lg"]:empty { padding: var(--ry-space-3, 0.75rem); } /* Block toggle button (card-style, full width) */ ry-toggle-button[block] { display: block; width: 100%; text-align: start; padding: var(--ry-space-4, 1rem); } /* ═══════════════════════════════════════════════════════════════ KNOB ═══════════════════════════════════════════════════════════════ */ ry-knob { display: inline-flex; flex-direction: column; align-items: center; gap: var(--ry-space-1, 0.25rem); user-select: none; outline: none; } ry-knob[disabled] { pointer-events: none; } ry-knob [data-ry-target="ring"] { --knob-size: 64px; --knob-rotation: -135deg; --knob-percent: 0; position: relative; width: var(--knob-size); height: var(--knob-size); cursor: grab; } ry-knob [data-ry-target="ring"].ry-knob__ring--dragging { cursor: grabbing; } ry-knob [data-ry-target="cap"] { position: absolute; inset: 0; transform: rotate(var(--knob-rotation)); } ry-knob [data-ry-target="indicator"] { position: absolute; width: 3px; height: 10px; top: 6px; left: 50%; margin-left: -1.5px; } ry-knob [data-ry-target="display"] { display: block; min-width: 3em; text-align: center; } ry-knob [data-ry-target="label"] { display: block; text-align: center; } /* Sizes */ ry-knob[size="sm"] [data-ry-target="ring"] { --knob-size: 48px; } ry-knob[size="lg"] [data-ry-target="ring"] { --knob-size: 80px; } /* ═══════════════════════════════════════════════════════════════ NUMBER SELECT ═══════════════════════════════════════════════════════════════ */ ry-number-select { display: inline-flex; align-items: center; gap: 0; user-select: none; touch-action: none; } ry-number-select[disabled] { pointer-events: none; } ry-number-select :is([data-ry-target="decrement"], [data-ry-target="increment"]) { display: inline-flex; align-items: center; justify-content: center; width: 32px; height: 36px; padding: 0; flex-shrink: 0; cursor: pointer; } ry-number-select :is([data-ry-target="decrement"], [data-ry-target="increment"]) svg { width: 16px; height: 16px; } ry-number-select [data-ry-target="display"] { display: inline-flex; align-items: center; justify-content: center; min-width: 48px; height: 36px; padding: 0 var(--ry-space-2, 0.5rem); position: relative; cursor: ew-resize; outline: none; } :is(ry-number-select[drag="y"], ry-number-select[arrows="stacked"]:not([drag]), ry-number-select[arrows="stacked-end"]:not([drag]), ry-number-select[arrows="stacked-start"]:not([drag])) [data-ry-target="display"] { cursor: ns-resize; } ry-number-select[drag="none"] [data-ry-target="display"] { cursor: default; } ry-number-select[data-dragging] { cursor: ew-resize; } :is(ry-number-select[drag="y"], ry-number-select[arrows="stacked"]:not([drag]), ry-number-select[arrows="stacked-end"]:not([drag]), ry-number-select[arrows="stacked-start"]:not([drag]))[data-dragging] { cursor: ns-resize; } ry-number-select [data-ry-target="value"] { display: inline-block; min-width: 2em; text-align: center; transition: transform 60ms ease-out; } ry-number-select :is([data-ry-target="prefix"], [data-ry-target="suffix"]) { flex-shrink: 0; pointer-events: none; } ry-number-select [data-ry-target="input"] { display: none; position: absolute; inset: 0; width: 100%; height: 100%; text-align: center; padding: 0 var(--ry-space-1, 0.25rem); outline: none; } ry-number-select [data-ry-target="label"] { display: block; text-align: center; margin-inline-end: var(--ry-space-2, 0.5rem); order: -1; } /* Stacked layout (buttons above/below) */ ry-number-select[arrows="stacked"] { flex-direction: column; align-items: stretch; } ry-number-select[arrows="stacked"] :is([data-ry-target="decrement"], [data-ry-target="increment"]) { width: auto; height: 24px; } ry-number-select[arrows="stacked"] :is([data-ry-target="decrement"], [data-ry-target="increment"]) svg { width: 14px; height: 14px; } /* Stacked-end / stacked-start (buttons grouped beside display) */ ry-number-select [data-ry-target="btn-group"] { display: flex; flex-direction: column; flex-shrink: 0; } :is(ry-number-select[arrows="stacked-end"], ry-number-select[arrows="stacked-start"]) :is([data-ry-target="decrement"], [data-ry-target="increment"]) { width: 28px; height: 18px; } :is(ry-number-select[arrows="stacked-end"], ry-number-select[arrows="stacked-start"]) :is([data-ry-target="decrement"], [data-ry-target="increment"]) svg { width: 12px; height: 12px; } /* Sizes */ ry-number-select[size="xs"] :is([data-ry-target="decrement"], [data-ry-target="increment"]) { width: 20px; height: 22px; } ry-number-select[size="xs"] [data-ry-target="display"] { min-width: 28px; height: 22px; padding: 0 var(--ry-space-1, 0.25rem); } ry-number-select[size="xs"] :is([data-ry-target="decrement"], [data-ry-target="increment"]) svg { width: 12px; height: 12px; } ry-number-select[size="sm"] :is([data-ry-target="decrement"], [data-ry-target="increment"]) { width: 24px; height: 28px; } ry-number-select[size="sm"] [data-ry-target="display"] { min-width: 36px; height: 28px; } ry-number-select[size="lg"] :is([data-ry-target="decrement"], [data-ry-target="increment"]) { width: 40px; height: 44px; } ry-number-select[size="lg"] [data-ry-target="display"] { min-width: 60px; height: 44px; } /* ═══════════════════════════════════════════════════════════════ SLIDER ═══════════════════════════════════════════════════════════════ */ ry-slider { display: block; position: relative; padding: var(--ry-space-4, 1rem) 0; touch-action: none; user-select: none; } ry-slider[disabled] { pointer-events: none; } ry-slider [data-ry-target="track"] { position: relative; height: var(--ry-slider-track, 14px); cursor: pointer; } ry-slider [data-ry-target="fill"] { position: absolute; height: 100%; } ry-slider [data-ry-target^="thumb"] { position: absolute; width: var(--ry-slider-thumb, 32px); height: var(--ry-slider-thumb, 32px); top: 50%; transform: translate(-50%, -50%); cursor: grab; } ry-slider [data-ry-target^="thumb"]:active { cursor: grabbing; } ry-slider [data-ry-target="labels"] { display: flex; justify-content: space-between; margin-block-start: var(--ry-space-2, 0.5rem); pointer-events: none; } ry-slider [data-ry-target^="tooltip"] { position: absolute; bottom: calc(100% + 8px); left: 50%; transform: translateX(-50%); white-space: nowrap; opacity: 0; visibility: hidden; transition: opacity var(--ry-duration-fast, 100ms) var(--ry-ease, ease), visibility var(--ry-duration-fast, 100ms) var(--ry-ease, ease); transition-behavior: allow-discrete; pointer-events: none; } :is(ry-slider [data-ry-target^="thumb"]:hover, ry-slider [data-ry-target^="thumb"]:focus, ry-slider[data-dragging]) [data-ry-target^="tooltip"] { opacity: 1; visibility: visible; } @starting-style { :is(ry-slider [data-ry-target^="thumb"]:hover, ry-slider [data-ry-target^="thumb"]:focus, ry-slider[data-dragging]) [data-ry-target^="tooltip"] { opacity: 0; } } /* Vertical */ ry-slider[vertical] { display: inline-flex; width: auto; height: 200px; padding: 0 var(--ry-space-4, 1rem); } ry-slider[vertical] [data-ry-target="track"] { width: var(--ry-slider-track, 14px); height: 100%; } ry-slider[vertical] [data-ry-target="fill"] { width: 100%; height: auto; bottom: 0; left: 0; } ry-slider[vertical] [data-ry-target^="thumb"] { left: 50%; top: auto; transform: translate(-50%, 50%); } ry-slider[vertical] [data-ry-target="labels"] { flex-direction: column-reverse; justify-content: space-between; height: 100%; margin-block-start: 0; margin-inline-start: var(--ry-space-2, 0.5rem); } /* Sizes */ ry-slider[size="sm"] { --ry-slider-track: 10px; --ry-slider-thumb: 24px; } ry-slider[size="lg"] { --ry-slider-track: 18px; --ry-slider-thumb: 40px; } /* ═══════════════════════════════════════════════════════════════ CARDS ═══════════════════════════════════════════════════════════════ */ ry-card { display: block; padding: var(--ry-space-6, 1.5rem); container-type: inline-size; } :is(a, [interactive]):is(ry-card) { cursor: pointer; transition: transform var(--ry-duration-normal, 200ms) var(--ry-ease, ease); } :is(a, [interactive]):is(ry-card):hover { transform: translateY(-1px); } :is(a, [interactive]):is(ry-card):active { transform: translateY(0); } ry-card h3 { margin: 0 0 var(--ry-space-2, 0.5rem) 0; } ry-card p { margin: 0 0 var(--ry-space-4, 1rem) 0; } ry-card p:last-child { margin-bottom: 0; } ry-card > img:first-child { display: block; width: 100%; margin-bottom: var(--ry-space-4, 1rem); } /* ═══════════════════════════════════════════════════════════════ BADGES ═══════════════════════════════════════════════════════════════ */ ry-badge { display: inline-flex; align-items: center; padding: var(--ry-space-1, 0.25rem) var(--ry-space-2, 0.5rem); line-height: 1; } /* ═══════════════════════════════════════════════════════════════ ALERTS ═══════════════════════════════════════════════════════════════ */ ry-alert { display: flex; gap: var(--ry-space-3, 0.75rem); padding: var(--ry-space-4, 1rem); } .ry-alert__title { margin: 0 0 var(--ry-space-1, 0.25rem) 0; } ry-alert p, ry-alert [data-ry-target="content"] { margin: 0; } /* ═══════════════════════════════════════════════════════════════ FORM ELEMENTS ═══════════════════════════════════════════════════════════════ */ ry-field :is(input, textarea, select) { display: block; width: 100%; padding: var(--ry-space-2, 0.5rem) var(--ry-space-3, 0.75rem); } ry-field :is(input, textarea):disabled { cursor: not-allowed; } ry-field :is(label, [data-ry-target="label"]) { display: block; margin-block-end: var(--ry-space-2, 0.5rem); } ry-field { display: block; margin-block-end: var(--ry-space-4, 1rem); } ry-field [data-ry-target="error"]:empty, ry-field [data-ry-target="hint"]:empty { display: none; } ry-field [data-ry-target="error"]:not(:empty) ~ [data-ry-target="hint"] { display: none; } ry-field :is([data-ry-target="error"], [data-ry-target="hint"]) { margin-block-start: var(--ry-space-1, 0.25rem); } /* ═══════════════════════════════════════════════════════════════ ACCORDION ═══════════════════════════════════════════════════════════════ */ ry-accordion { overflow: hidden; } ry-accordion [data-ry-target="trigger"] { display: flex; align-items: center; justify-content: space-between; width: 100%; padding: var(--ry-space-4, 1rem) var(--ry-space-6, 1.5rem); text-align: start; border: none; cursor: pointer; } ry-accordion [data-ry-target="icon"] { flex-shrink: 0; transition: transform var(--ry-duration-normal, 200ms) var(--ry-ease, ease); } ry-accordion [data-ry-target="item"][data-ry-state="open"] [data-ry-target="icon"] { transform: rotate(180deg); } ry-accordion [data-ry-target="panel"] { overflow: hidden; } ry-accordion [data-ry-target="item"][data-ry-state="closed"] [data-ry-target="panel"] { display: none; } ry-accordion [data-ry-target="panel"] > * { padding: var(--ry-space-4, 1rem) var(--ry-space-6, 1.5rem); } /* ═══════════════════════════════════════════════════════════════ TABS ═══════════════════════════════════════════════════════════════ */ ry-tabs { display: block; } ry-tabs [data-ry-target="list"] { display: flex; gap: var(--ry-space-1, 0.25rem); margin-block-end: var(--ry-space-4, 1rem); } ry-tabs [data-ry-target="trigger"] { padding: var(--ry-space-2, 0.5rem) var(--ry-space-4, 1rem); border: none; border-block-end: 2px solid transparent; margin-block-end: -1px; cursor: pointer; } ry-tabs [data-ry-target="panel"], ry-tab { display: none; } :is(ry-tabs [data-ry-target="panel"][data-ry-state="active"], ry-tab[active], ry-tab[data-ry-state="active"]) { display: block; } ry-tabs:not(:defined) ry-tab:first-of-type { display: block; } /* ═══════════════════════════════════════════════════════════════ MODAL ═══════════════════════════════════════════════════════════════ */ ry-modal { display: contents; } ry-modal [data-ry-target="backdrop"] { position: fixed; inset: 0; z-index: var(--ry-z-modal-backdrop, 1040); opacity: 0; visibility: hidden; transition: opacity var(--ry-duration-normal, 200ms) var(--ry-ease, ease), visibility var(--ry-duration-normal, 200ms) var(--ry-ease, ease); transition-behavior: allow-discrete; } ry-modal[data-ry-state="open"] [data-ry-target="backdrop"] { opacity: 1; visibility: visible; } @starting-style { ry-modal[data-ry-state="open"] [data-ry-target="backdrop"] { opacity: 0; } } ry-modal [data-ry-target="dialog"] { position: fixed; top: 50%; left: 50%; z-index: var(--ry-z-modal, 1050); width: 100%; max-width: 32rem; max-height: calc(100vh - var(--ry-space-8, 2rem)); overflow: auto; overscroll-behavior: contain; opacity: 0; visibility: hidden; transform: translate(-50%, -50%) scale(0.95); transition: opacity var(--ry-duration-normal, 200ms) var(--ry-ease, ease), visibility var(--ry-duration-normal, 200ms) var(--ry-ease, ease), transform var(--ry-duration-normal, 200ms) var(--ry-ease, ease); transition-behavior: allow-discrete; } ry-modal[data-ry-state="open"] [data-ry-target="dialog"] { opacity: 1; visibility: visible; transform: translate(-50%, -50%) scale(1); } @starting-style { ry-modal[data-ry-state="open"] [data-ry-target="dialog"] { opacity: 0; transform: translate(-50%, -50%) scale(0.95); } } ry-modal [data-ry-target="header"] { display: flex; align-items: center; justify-content: space-between; padding: var(--ry-space-4, 1rem) var(--ry-space-6, 1.5rem); } ry-modal [data-ry-target="header"] h3 { margin: 0; } ry-modal [data-ry-target="close"] { display: flex; align-items: center; justify-content: center; width: 2rem; height: 2rem; padding: 0; border: none; cursor: pointer; } ry-modal [data-ry-target="body"] { padding: var(--ry-space-6, 1.5rem); } ry-modal [data-ry-target="footer"] { display: flex; justify-content: flex-end; gap: var(--ry-space-3, 0.75rem); padding: var(--ry-space-4, 1rem) var(--ry-space-6, 1.5rem); } /* ═══════════════════════════════════════════════════════════════ DROPDOWN ═══════════════════════════════════════════════════════════════ */ ry-dropdown { position: relative; display: inline-block; } ry-dropdown :is([data-ry-target="menu"], ry-menu) { position: absolute; top: 100%; left: 0; z-index: var(--ry-z-dropdown, 1000); min-width: 12rem; margin-block-start: var(--ry-space-1, 0.25rem); padding: var(--ry-space-1, 0.25rem); opacity: 0; visibility: hidden; transform: translateY(-0.5rem); transition: opacity var(--ry-duration-fast, 100ms) var(--ry-ease, ease), visibility var(--ry-duration-fast, 100ms) var(--ry-ease, ease), transform var(--ry-duration-fast, 100ms) var(--ry-ease, ease); transition-behavior: allow-discrete; } ry-dropdown[data-ry-state="open"] :is([data-ry-target="menu"], ry-menu) { opacity: 1; visibility: visible; transform: translateY(0); } @starting-style { ry-dropdown[data-ry-state="open"] :is([data-ry-target="menu"], ry-menu) { opacity: 0; transform: translateY(-0.5rem); } } ry-dropdown[data-ry-position="top"] :is([data-ry-target="menu"], ry-menu) { top: auto; bottom: 100%; margin-block-start: 0; margin-block-end: var(--ry-space-1, 0.25rem); transform: translateY(0.5rem); } ry-dropdown[data-ry-position="top"][data-ry-state="open"] :is([data-ry-target="menu"], ry-menu) { transform: translateY(0); } ry-menu-item { display: block; width: 100%; padding: var(--ry-space-2, 0.5rem) var(--ry-space-3, 0.75rem); text-align: start; text-decoration: none; border: none; cursor: pointer; } /* ═══════════════════════════════════════════════════════════════ SWITCH ═══════════════════════════════════════════════════════════════ */ ry-switch { display: inline-flex; align-items: center; gap: var(--ry-space-3, 0.75rem); cursor: pointer; user-select: none; } ry-switch[disabled] { cursor: not-allowed; } ry-switch [data-ry-target="track"] { position: relative; display: inline-flex; width: 2.75rem; height: 1.5rem; flex-shrink: 0; } ry-switch [data-ry-target="thumb"] { position: absolute; top: 2px; left: 2px; width: 1.125rem; height: 1.125rem; transition: transform var(--ry-duration-fast, 100ms) var(--ry-ease, ease); } ry-switch[checked] [data-ry-target="thumb"] { transform: translateX(1.25rem); } ry-switch [data-ry-target="input"] { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0, 0, 0, 0); border: 0; } ry-switch:focus-visible { outline: none; } /* ═══════════════════════════════════════════════════════════════ TOOLTIP ═══════════════════════════════════════════════════════════════ */ ry-tooltip { position: relative; display: inline-block; } ry-tooltip [data-ry-target="content"] { position: absolute; z-index: var(--ry-z-tooltip, 1070); padding: var(--ry-space-2, 0.5rem) var(--ry-space-3, 0.75rem); white-space: nowrap; opacity: 0; visibility: hidden; pointer-events: none; transition: opacity var(--ry-duration-fast, 100ms) var(--ry-ease, ease), visibility var(--ry-duration-fast, 100ms) var(--ry-ease, ease); transition-behavior: allow-discrete; } ry-tooltip[data-ry-state="open"] [data-ry-target="content"] { opacity: 1; visibility: visible; } @starting-style { ry-tooltip[data-ry-state="open"] [data-ry-target="content"] { opacity: 0; } } /* Tooltip positioning - CSS handles all layout, no JS needed */ ry-tooltip[data-ry-position="top"] [data-ry-target="content"] { bottom: 100%; left: 50%; transform: translateX(-50%); margin-bottom: var(--ry-space-2, 0.5rem); } ry-tooltip[data-ry-position="bottom"] [data-ry-target="content"] { top: 100%; left: 50%; transform: translateX(-50%); margin-top: var(--ry-space-2, 0.5rem); } ry-tooltip[data-ry-position="left"] [data-ry-target="content"] { right: 100%; top: 50%; transform: translateY(-50%); margin-r