/* ============================================================ ModernSK — Components layer (ported to Radix Primitives) Visual recipes kept 1:1 from the Claude Design bundle; state hooks rewired from .is-* classes to Radix data-attributes ([data-state], [data-highlighted], [data-disabled]). ============================================================ */ @keyframes modern-sk-pop { from { opacity: 0; transform: scale(0.6); } to { opacity: 1; transform: scale(1); } } @keyframes modern-sk-scale-in { from { opacity: 0; transform: scale(0.96); } to { opacity: 1; transform: scale(1); } } @keyframes modern-sk-scale-out { from { opacity: 1; transform: scale(1); } to { opacity: 0; transform: scale(0.96); } } @keyframes modern-sk-fade-in { from { opacity: 0; } to { opacity: 1; } } @keyframes modern-sk-fade-out { from { opacity: 1; } to { opacity: 0; } } /* ---------- BUTTONS ---------- */ .modern-sk-btn { font-family: var(--font-sans); font-size: var(--ctl-font); font-weight: 600; line-height: 1.1; padding: var(--ctl-pad-y) var(--ctl-pad-x); border-radius: var(--r-md); cursor: pointer; user-select: none; display: inline-flex; align-items: center; justify-content: center; gap: 7px; border: 1px solid var(--hair-strong); color: var(--fg-1); background: var(--grad-key); box-shadow: var(--shadow-raised); transition: filter var(--dur-quick) var(--ease-out), box-shadow var(--dur-quick) var(--ease-out), transform var(--dur-press) var(--ease-out), background var(--dur-quick) var(--ease-out); } .modern-sk-btn:hover { background: var(--grad-key-hover); } .modern-sk-btn:active { background: var(--grad-key-down); box-shadow: var(--shadow-pressed); transform: translateY(1px); } .modern-sk-btn:focus-visible { outline: none; box-shadow: var(--focus-ring), var(--shadow-raised); } .modern-sk-btn[disabled], .modern-sk-btn.is-disabled { opacity: 0.4; filter: saturate(0.6); pointer-events: none; } .modern-sk-btn .ph { font-size: 1.05em; display: inline-flex; } .modern-sk-btn--primary { color: var(--lime-ink); background: var(--grad-primary); border-color: var(--lime-deep); text-shadow: 0 1px 0 rgba(255, 255, 255, 0.25); box-shadow: 0 1px 0 rgba(255, 255, 255, 0.3) inset, var(--glow-lime), 0 2px 4px rgba(0, 0, 0, 0.35); } .modern-sk-btn--primary:hover { filter: brightness(1.04); background: var(--grad-primary); } .modern-sk-btn--primary:active { background: var(--grad-primary-down); box-shadow: 0 3px 6px rgba(60, 90, 10, 0.5) inset; transform: translateY(1px); } .modern-sk-btn--primary:focus-visible { box-shadow: var(--focus-ring), 0 1px 0 rgba(255, 255, 255, 0.3) inset, 0 2px 4px rgba(0, 0, 0, 0.35); } .modern-sk-btn--ember { color: #fff; background: var(--grad-ember); border-color: var(--ember-deep); text-shadow: 0 1px 1px rgba(0, 0, 0, 0.25); box-shadow: 0 1px 0 rgba(255, 255, 255, 0.08) inset, 0 2px 4px rgba(0, 0, 0, 0.35), 0 6px 14px rgba(233, 87, 43, 0.18); } .modern-sk-btn--ember:hover { background: var(--grad-ember); filter: brightness(1.06); } .modern-sk-btn--ember:active { background: var(--grad-ember-down); box-shadow: 0 3px 6px rgba(90, 30, 10, 0.55) inset; transform: translateY(1px); } .modern-sk-btn--ember:focus-visible { box-shadow: var(--focus-ring-ember), 0 2px 4px rgba(0, 0, 0, 0.35); } .modern-sk-btn--ghost { color: var(--fg-2); background: transparent; border-color: var(--hair-strong); box-shadow: none; text-shadow: none; } .modern-sk-btn--ghost:hover { background: rgba(255, 255, 255, 0.04); color: var(--fg-1); } .modern-sk-btn--ghost:active { background: rgba(0, 0, 0, 0.2); box-shadow: var(--shadow-pressed); transform: translateY(1px); } .modern-sk-btn--sm { font-size: 12px; padding: 4px 11px; gap: 5px; } .modern-sk-btn--icon { padding: var(--ctl-pad-y); width: calc(var(--ctl-font) + 2 * var(--ctl-pad-y)); aspect-ratio: 1; } /* ---------- TEXT FIELDS ---------- */ .modern-sk-field { width: 100%; font-family: var(--font-sans); font-size: 14px; color: var(--fg-1); padding: var(--field-pad-y) var(--field-pad-x); border-radius: var(--r-md); background: var(--steel-900); border: 1px solid var(--edge-inset); box-shadow: var(--shadow-inset-well); outline: none; transition: box-shadow var(--dur-quick) var(--ease-out), border-color var(--dur-quick) var(--ease-out); } .modern-sk-field::placeholder { color: var(--fg-3); } .modern-sk-field:focus { border-color: var(--lime-deep); box-shadow: var(--shadow-inset-well), var(--focus-ring); } textarea.modern-sk-field { resize: vertical; min-height: 64px; line-height: 1.5; } .modern-sk-search { position: relative; display: flex; align-items: center; } .modern-sk-search .ph { position: absolute; left: 11px; color: var(--fg-3); font-size: 16px; pointer-events: none; display: inline-flex; } .modern-sk-search .modern-sk-field { padding-left: 34px; } /* ---------- TYPING ANIMATION (osu!-lazer style char in/out) ---------- */ /* The real field renders transparent over a mirrored per-letter overlay. */ .modern-sk-field-wrap { position: relative; width: 100%; } .modern-sk-search .modern-sk-field-wrap { width: 100%; } .modern-sk-field--animated { color: transparent; caret-color: var(--fg-1); } .modern-sk-field--animated::placeholder { color: var(--fg-3); } .modern-sk-field-overlay { position: absolute; inset: 0; overflow: hidden; pointer-events: none; /* transparent border mirrors the field's 1px border so content aligns */ border: 1px solid transparent; padding: var(--field-pad-y) var(--field-pad-x); font-family: var(--font-sans); font-size: 14px; line-height: normal; color: var(--fg-1); white-space: pre; text-align: left; will-change: transform; } .modern-sk-field-overlay--multiline { white-space: pre-wrap; overflow-wrap: break-word; line-height: 1.5; } .modern-sk-search .modern-sk-field-overlay { padding-left: 34px; } .modern-sk-field-char { /* inline (not inline-block) so the overlay wraps exactly like the field; inherit white-space so multiline (pre-wrap) wraps while input (pre) won't. 'pre' on the span itself would suppress wrapping at its boundaries. Multiline keeps this inline path: inline boxes ignore transform, so the rise eases `top` (a layout property — acceptable here, textarea wraps instead of scrolling so there's no per-keystroke scroll-sync thrash). */ position: relative; white-space: inherit; animation: modern-sk-char-in var(--dur-base) var(--ease-snap) both; } /* Single-line never wraps, so chars can be inline-block and animate `transform` (compositor-only) instead of `top` (relayout every frame). The single-line field scrolls horizontally and syncs the overlay each keystroke, so the layout-triggering `top` path janked there — this doesn't. */ .modern-sk-field-char--composited { display: inline-block; will-change: transform, opacity; animation-name: modern-sk-char-in-rise; } .modern-sk-field-char--leaving { display: inline-block; position: absolute; white-space: pre; animation: modern-sk-char-out var(--dur-base) var(--ease-out) forwards; } /* inline elements ignore transform, so the rise uses top instead */ @keyframes modern-sk-char-in { from { opacity: 0; top: -0.32em; } to { opacity: 1; top: 0; } } /* inline-block (single-line) variant — composited transform, no relayout */ @keyframes modern-sk-char-in-rise { from { opacity: 0; transform: translateY(-0.32em); } to { opacity: 1; transform: none; } } @keyframes modern-sk-char-out { from { opacity: 1; transform: translateY(0); } to { opacity: 0; transform: translateY(0.7em) scale(0.9); } } @media (prefers-reduced-motion: reduce) { .modern-sk-field-char { animation: none; } .modern-sk-field-char--leaving { animation: modern-sk-char-out 1ms linear forwards; } } /* ---------- SELECT (Radix Select, styled as the glossy key) ---------- */ .modern-sk-select { font-family: var(--font-sans); font-size: 14px; color: var(--fg-1); cursor: pointer; display: inline-flex; align-items: center; gap: 10px; padding: var(--field-pad-y) 12px var(--field-pad-y) var(--field-pad-x); border-radius: var(--r-md); border: 1px solid var(--hair-strong); background: var(--grad-key); box-shadow: var(--shadow-raised); outline: none; } .modern-sk-select:hover { background: var(--grad-key-hover); } .modern-sk-select:focus-visible { box-shadow: var(--focus-ring), var(--shadow-raised); } .modern-sk-select__icon { color: var(--fg-2); display: inline-flex; margin-left: auto; } .modern-sk-select__content { min-width: var(--radix-select-trigger-width); padding: 6px; border-radius: var(--r-lg); border: 1px solid var(--hair-strong); background: rgba(34, 36, 27, 0.86); backdrop-filter: blur(24px) saturate(1.3); -webkit-backdrop-filter: blur(24px) saturate(1.3); box-shadow: var(--shadow-window); z-index: 50; transform-origin: var(--radix-select-content-transform-origin); } /* slide out of the trigger: grows from the radix transform-origin while sliding in from the open side. Symmetric, token-driven exit. */ .modern-sk-select__content[data-side='bottom'] { --sel-from-y: -6px; } .modern-sk-select__content[data-side='top'] { --sel-from-y: 6px; } .modern-sk-select__content[data-side='left'], .modern-sk-select__content[data-side='right'] { --sel-from-y: 0px; } .modern-sk-select__content[data-state='open'] { animation: modern-sk-select-in var(--dur-base) var(--ease-snap); } .modern-sk-select__content[data-state='closed'] { animation: modern-sk-select-out var(--dur-quick) var(--ease-out); } @keyframes modern-sk-select-in { from { opacity: 0; transform: translateY(var(--sel-from-y, -6px)) scale(0.94); } to { opacity: 1; transform: translateY(0) scale(1); } } @keyframes modern-sk-select-out { from { opacity: 1; transform: translateY(0) scale(1); } to { opacity: 0; transform: translateY(var(--sel-from-y, -6px)) scale(0.96); } } @media (prefers-reduced-motion: reduce) { .modern-sk-select__content[data-state='open'], .modern-sk-select__content[data-state='closed'] { animation: modern-sk-fade-in var(--dur-quick) var(--ease-out); } } .modern-sk-select__item { display: flex; align-items: center; gap: 10px; padding: 7px 10px; border-radius: var(--r-sm); font-size: 13px; color: var(--fg-1); cursor: pointer; outline: none; user-select: none; } .modern-sk-select__item[data-highlighted] { background: linear-gradient(180deg, var(--lime), var(--lime-deep)); color: var(--lime-ink); } .modern-sk-select__item-indicator { margin-left: auto; display: inline-flex; } /* ---------- SWITCH ---------- */ .modern-sk-switch { position: relative; width: var(--switch-w); height: var(--switch-h); flex-shrink: 0; border-radius: 8px; padding: 0; border: 1px solid var(--edge-inset); background: var(--steel-700); box-shadow: var(--shadow-inset-well); cursor: pointer; transition: background var(--dur-base) var(--ease-out), border-color var(--dur-base) var(--ease-out); } .modern-sk-switch__thumb { display: block; position: absolute; top: 50%; left: var(--switch-gap); transform: translateY(-50%); width: var(--switch-knob); height: var(--switch-knob); border-radius: 5px; background: linear-gradient(180deg, #cfd1c4, #a7a99c); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.4), 0 1px 0 rgba(255, 255, 255, 0.7) inset; transition: left var(--dur-base) var(--ease-snap), background var(--dur-base) var(--ease-out); } .modern-sk-switch[data-state='checked'] { background: linear-gradient(180deg, var(--lime), var(--lime-deep)); border-color: var(--lime-deep); } .modern-sk-switch[data-state='checked'] .modern-sk-switch__thumb { left: calc(100% - var(--switch-knob) - var(--switch-gap)); background: linear-gradient(180deg, #fff, #e6e8dd); } .modern-sk-switch:focus-visible { outline: none; box-shadow: var(--shadow-inset-well), var(--focus-ring); } /* ---------- CHECKBOX ---------- */ .modern-sk-check { width: 22px; height: 22px; flex-shrink: 0; border-radius: 4px; padding: 0; background: var(--steel-900); border: 1px solid var(--edge-inset); box-shadow: var(--shadow-inset-well); cursor: pointer; display: flex; align-items: center; justify-content: center; transition: background var(--dur-quick) var(--ease-out), border-color var(--dur-quick) var(--ease-out); } .modern-sk-check[data-state='checked'] { background: linear-gradient(180deg, var(--lime-bright), var(--lime-deep)); border-color: var(--lime-deep); box-shadow: 0 1px 0 rgba(255, 255, 255, 0.4) inset; } .modern-sk-check__indicator { display: flex; align-items: center; justify-content: center; animation: modern-sk-pop var(--dur-quick) var(--ease-snap); } .modern-sk-check__indicator svg { width: 13px; height: 13px; display: block; } .modern-sk-check:focus-visible { outline: none; box-shadow: var(--shadow-inset-well), var(--focus-ring); } /* ---------- RADIO ---------- */ .modern-sk-radio { width: 22px; height: 22px; flex-shrink: 0; border-radius: 50%; padding: 0; background: var(--steel-900); border: 1px solid var(--edge-inset); box-shadow: var(--shadow-inset-well); cursor: pointer; display: flex; align-items: center; justify-content: center; transition: border-color var(--dur-quick) var(--ease-out); } .modern-sk-radio__indicator { display: flex; align-items: center; justify-content: center; width: 100%; height: 100%; } .modern-sk-radio__indicator::after { content: ''; width: 11px; height: 11px; border-radius: 50%; background: radial-gradient( circle at 50% 38%, var(--lime-bright), var(--lime-deep) ); box-shadow: 0 0 8px rgba(190, 242, 100, 0.45), 0 1px 0 rgba(255, 255, 255, 0.45) inset; animation: modern-sk-pop var(--dur-quick) var(--ease-snap); } .modern-sk-radio:focus-visible { outline: none; box-shadow: var(--shadow-inset-well), var(--focus-ring); } /* control + label row helper */ .modern-sk-control { display: inline-flex; align-items: center; gap: 10px; font-size: 14px; color: var(--fg-2); cursor: pointer; } /* ---------- SEGMENTED CONTROL (Radix ToggleGroup) ---------- */ .modern-sk-seg { position: relative; display: inline-flex; background: var(--steel-900); border: 1px solid var(--edge-inset); border-radius: var(--r-md); padding: 3px; box-shadow: var(--shadow-inset-well); gap: 2px; } .modern-sk-seg__thumb { position: absolute; top: 3px; left: 0; height: calc(100% - 6px); background: var(--grad-key); border-radius: var(--r-sm); box-shadow: var(--shadow-raised); pointer-events: none; transition: transform 180ms var(--ease-snap), width 180ms var(--ease-snap); will-change: transform, width; } .modern-sk-seg__item { position: relative; z-index: 1; font-family: var(--font-sans); font-size: 13px; font-weight: 600; color: var(--fg-2); background: transparent; border: none; padding: var(--seg-pad-y) 14px; border-radius: var(--r-sm); cursor: pointer; transition: color var(--dur-quick); } .modern-sk-seg__item:hover { color: var(--fg-1); } .modern-sk-seg__item[data-state='on'] { color: var(--fg-1); } /* ---------- SLIDER ---------- */ .modern-sk-slider { --ms-thumb: 20px; --ms-thumb-w: var(--ms-thumb); position: relative; display: flex; align-items: center; width: 100%; height: var(--ms-thumb); user-select: none; touch-action: none; } .modern-sk-slider__track { position: relative; flex-grow: 1; height: 6px; border-radius: 3px; background: var(--steel-800); box-shadow: var(--shadow-inset-well); } .modern-sk-slider__range { position: absolute; height: 100%; border-radius: 3px; background: linear-gradient(90deg, var(--lime-deep), var(--lime)); box-shadow: 0 0 10px rgba(190, 242, 100, 0.4); } /* Radix positions the range via left/right offsets (not width); ease those so the fill glides between discrete steps while dragging. */ .modern-sk-slider--animated .modern-sk-slider__range { transition: left 0.12s ease-out, right 0.12s ease-out; } .modern-sk-slider__thumb { display: block; width: var(--ms-thumb-w); height: var(--ms-thumb); border-radius: 4px; background: linear-gradient(180deg, #fff, #e6e8dd); box-shadow: 0 2px 5px rgba(0, 0, 0, 0.5), 0 1px 0 rgba(255, 255, 255, 0.9) inset; cursor: pointer; outline: none; } /* Radix sets the step position (left) on a WRAPPER span around the thumb, not on the thumb element itself — so the transition must live on that wrapper. The wrapper is the slider's direct child span that isn't the track. */ .modern-sk-slider--animated > span:not(.modern-sk-slider__track) { transition: left 0.12s ease-out; } @media (prefers-reduced-motion: reduce) { .modern-sk-slider--animated > span:not(.modern-sk-slider__track), .modern-sk-slider--animated .modern-sk-slider__range { transition: none; } } .modern-sk-slider--knob-square .modern-sk-slider__thumb { --ms-thumb-w: 14px; } .modern-sk-slider--knob-round .modern-sk-slider__thumb { --ms-thumb-w: var(--ms-thumb); border-radius: 50%; } .modern-sk-slider__thumb:focus-visible { box-shadow: 0 2px 5px rgba(0, 0, 0, 0.5), 0 1px 0 rgba(255, 255, 255, 0.9) inset, var(--focus-ring); } /* Notches sit OUTSIDE the bar, anchored to the track edges. Horizontal position tracks the thumb centre: it travels from thumb-radius to (width - radius). Reserve layout room with padding so ticks/labels never collide with neighbours. */ .modern-sk-slider--notch-top { padding-top: 14px; } .modern-sk-slider--notch-bottom { padding-bottom: 14px; } .modern-sk-slider--has-labels { padding-bottom: 18px; } .modern-sk-slider--notch-bottom.modern-sk-slider--has-labels { padding-bottom: 30px; } .modern-sk-slider__notches { position: absolute; left: 0; right: 0; height: 0; pointer-events: none; } .modern-sk-slider__notches--top { bottom: calc(100% + 7px); } .modern-sk-slider__notches--bottom { top: calc(100% + 7px); } .modern-sk-slider__notch { position: absolute; left: calc(var(--ms-thumb) / 2 + (100% - var(--ms-thumb)) * var(--p)); width: 3px; height: 3px; border-radius: 99px; background: var(--steel-500); transform: translateX(-50%); } .modern-sk-slider__notches--top .modern-sk-slider__notch { bottom: 0; } .modern-sk-slider__notches--bottom .modern-sk-slider__notch { top: 0; } .modern-sk-slider__labels { position: absolute; left: 0; right: 0; top: calc(100% + 8px); pointer-events: none; } .modern-sk-slider--notch-bottom .modern-sk-slider__labels { top: calc(100% + 18px); } .modern-sk-slider__label { position: absolute; left: calc(var(--ms-thumb) / 2 + (100% - var(--ms-thumb)) * var(--p)); transform: translateX(-50%); font-family: var(--font-mono); font-size: 10px; line-height: 1; color: var(--fg-3); white-space: nowrap; } /* ---------- KNOB (circular slider) ---------- Skeuomorphic rotary control. The dial follows the pointer 1:1 while dragging (bound to the mouse); the gauge fill + value snap to detents and *glide* between them (like the stepped Slider) when `--animated`. Anatomy: recessed SVG gauge ring → glossy cap → knurled dial (rotates, carries the accent pointer) → turned-metal hub. Sizing flows from --knob-size. */ .modern-sk-knob { --knob-size: 108px; --knob-accent: var(--lime); --knob-accent-deep: var(--lime-deep); --knob-glow: rgba(190, 242, 100, 0.5); position: relative; flex-shrink: 0; width: var(--knob-size); height: var(--knob-size); cursor: grab; outline: none; touch-action: none; -webkit-tap-highlight-color: transparent; } .modern-sk-knob.is-dragging { cursor: grabbing; } .modern-sk-knob--disabled { cursor: default; opacity: 0.55; } /* recessed gauge ring */ .modern-sk-knob__gauge { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; pointer-events: none; } .modern-sk-knob__track { fill: none; stroke: var(--steel-800); stroke-width: 5; stroke-linecap: round; } /* The fill is the full arc, revealed up to the value via stroke-dashoffset (set inline as a plain number). When `--animated`, transition the offset so the accent eases along the circle between detents. */ .modern-sk-knob__fill { fill: none; stroke: var(--knob-accent); stroke-width: 5; stroke-linecap: round; filter: drop-shadow(0 0 5px var(--knob-glow)); transition: stroke var(--dur-quick) var(--ease-out); } .modern-sk-knob--animated .modern-sk-knob__fill { transition: stroke-dashoffset 0.12s ease-out, stroke var(--dur-quick) var(--ease-out); } .modern-sk-knob__tick { stroke: var(--fg-3); stroke-width: 1.6; stroke-linecap: round; opacity: 0.45; transition: stroke var(--dur-quick), opacity var(--dur-quick); } .modern-sk-knob__tick.is-on { stroke: var(--knob-accent); opacity: 0.95; } /* glossy cap — static top-down gloss (light source stays put) */ .modern-sk-knob__cap { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: calc(var(--knob-size) - 34px); height: calc(var(--knob-size) - 34px); border-radius: 50%; border: 1px solid var(--hair-strong); background: radial-gradient(circle at 50% 30%, rgba(255, 255, 255, 0.16), transparent 58%), var(--grad-key); box-shadow: 0 1px 0 rgba(255, 255, 255, 0.08) inset, 0 4px 9px rgba(0, 0, 0, 0.5), 0 11px 22px rgba(0, 0, 0, 0.42); overflow: hidden; transition: box-shadow var(--dur-quick) var(--ease-out); } /* knurled dial — rotates with the pointer, carries the glowing pointer dot. The ribbed grip lives on ::before (masked to a ring) so the pointer dot can sit unmasked on top and keep its full halo. While dragging it tracks the mouse with no transition; otherwise it glides to the settled value. */ .modern-sk-knob__dial { position: absolute; inset: 0; border-radius: 50%; will-change: transform; } .modern-sk-knob--animated .modern-sk-knob__dial { transition: transform 0.12s ease-out; } .modern-sk-knob.is-dragging .modern-sk-knob__dial { transition: none; } .modern-sk-knob__dial::before { content: ''; position: absolute; inset: 0; border-radius: 50%; background: repeating-conic-gradient( from 0deg, rgba(255, 255, 255, 0.09) 0deg 3deg, rgba(0, 0, 0, 0.28) 3deg 6deg ); -webkit-mask: radial-gradient(circle, transparent 0 58%, #000 61% 100%); mask: radial-gradient(circle, transparent 0 58%, #000 61% 100%); } .modern-sk-knob__pointer { position: absolute; top: 5%; left: 50%; transform: translateX(-50%); width: 6px; height: 6px; border-radius: 50%; background: var(--knob-accent); box-shadow: 0 0 6px var(--knob-glow); } /* turned-metal hub covers the inner ends; pointer reads as an outer notch */ .modern-sk-knob__hub { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 48%; height: 48%; border-radius: 50%; background: radial-gradient(circle at 50% 34%, #36372c, #1d1e17); box-shadow: 0 1px 0 rgba(255, 255, 255, 0.07) inset, 0 1px 3px rgba(0, 0, 0, 0.55); } .modern-sk-knob:focus-visible .modern-sk-knob__cap { box-shadow: var(--focus-ring), 0 1px 0 rgba(255, 255, 255, 0.08) inset, 0 4px 9px rgba(0, 0, 0, 0.5), 0 11px 22px rgba(0, 0, 0, 0.42); } /* ember accent variant */ .modern-sk-knob--ember { --knob-accent: var(--ember); --knob-accent-deep: var(--ember-deep); --knob-glow: rgba(233, 87, 43, 0.5); } @media (prefers-reduced-motion: reduce) { .modern-sk-knob--animated .modern-sk-knob__fill, .modern-sk-knob--animated .modern-sk-knob__dial { transition: none; } } /* light theme: brighter cap gloss, darker knurl ridges so the grip reads, a pale turned hub, and a lighter recessed gauge channel. */ [data-theme='light'] .modern-sk-knob__cap { box-shadow: 0 1px 0 rgba(255, 255, 255, 0.9) inset, 0 2px 5px rgba(0, 0, 0, 0.16), 0 7px 16px rgba(0, 0, 0, 0.12); } [data-theme='light'] .modern-sk-knob__dial::before { background: repeating-conic-gradient( from 0deg, rgba(0, 0, 0, 0.09) 0deg 3deg, rgba(255, 255, 255, 0.6) 3deg 6deg ); } [data-theme='light'] .modern-sk-knob__hub { background: radial-gradient(circle at 50% 34%, #ffffff, #e2e2d6); box-shadow: 0 1px 0 rgba(255, 255, 255, 0.9) inset, 0 1px 3px rgba(0, 0, 0, 0.16); } [data-theme='light'] .modern-sk-knob__track { stroke: var(--steel-500); } [data-theme='light'] .modern-sk-knob__tick { stroke: var(--steel-400); } /* ---------- STEPPER ---------- */ .modern-sk-stepper { display: inline-flex; border-radius: var(--r-md); overflow: hidden; box-shadow: var(--shadow-raised); border: 1px solid var(--hair-strong); } .modern-sk-stepper button { font-family: var(--font-mono); font-size: 16px; font-weight: 600; color: var(--fg-1); background: var(--grad-key); border: none; width: 34px; height: var(--stepper-h); cursor: pointer; transition: background var(--dur-quick); } .modern-sk-stepper button:hover { background: var(--grad-key-hover); } .modern-sk-stepper button:active { background: var(--grad-key-down); } .modern-sk-stepper button:first-child { border-right: 1px solid var(--edge-inset); } /* ---------- BADGES / CHIPS / TAGS ---------- */ .modern-sk-badge { display: inline-flex; align-items: center; gap: 5px; font-size: 11px; font-weight: 700; line-height: 1; padding: 4px 9px; border-radius: var(--r-pill); letter-spacing: 0.02em; border: 1px solid transparent; } .modern-sk-badge--lime { color: var(--lime-ink); background: linear-gradient(180deg, var(--lime-bright), var(--lime-deep)); border-color: var(--lime-deep); } .modern-sk-badge--ember { color: #fff; background: var(--grad-ember); border-color: var(--ember-deep); } .modern-sk-badge--neutral { color: var(--fg-2); background: var(--steel-700); border-color: var(--hair-strong); } .modern-sk-badge--outline { color: var(--fg-2); background: transparent; border-color: var(--hair-strong); } .modern-sk-badge--dot::before { content: ''; width: 6px; height: 6px; border-radius: 50%; background: currentColor; } .modern-sk-chip { display: inline-flex; align-items: center; gap: 6px; font-size: 13px; font-weight: 500; color: var(--fg-1); padding: 5px 11px; border-radius: var(--r-pill); background: var(--steel-700); border: 1px solid var(--hair-strong); } .modern-sk-chip .x { color: var(--fg-3); cursor: pointer; font-size: 14px; line-height: 1; background: none; border: none; padding: 0; display: inline-flex; } .modern-sk-chip .x:hover { color: var(--fg-1); } /* ---------- CARD ---------- */ .modern-sk-card { background: var(--steel-900); border: 1px solid var(--hair); border-radius: var(--r-lg); box-shadow: var(--shadow-card); padding: 18px; } /* ---------- LIST ROWS ---------- */ .modern-sk-list { background: var(--steel-900); border: 1px solid var(--hair); border-radius: var(--r-lg); box-shadow: var(--shadow-card); overflow: hidden; } .modern-sk-row { display: flex; align-items: center; gap: 12px; padding: 10px 14px; border-bottom: 1px solid var(--hair); cursor: default; font-size: 14px; color: var(--fg-1); } .modern-sk-row:last-child { border-bottom: none; } .modern-sk-row:hover { background: var(--steel-800); } .modern-sk-row.is-selected { background: linear-gradient( 180deg, rgba(190, 242, 100, 0.16), rgba(190, 242, 100, 0.08) ); } .modern-sk-row .nm { font-size: 14px; font-weight: 500; color: var(--fg-1); white-space: nowrap; } .modern-sk-row .meta { margin-left: auto; font-family: var(--font-mono); font-size: 11px; color: var(--fg-3); } /* ---------- MENU / POPOVER (Radix DropdownMenu) ---------- */ .modern-sk-menu { min-width: 208px; padding: 6px; border-radius: var(--r-lg); border: 1px solid var(--hair-strong); background: rgba(34, 36, 27, 0.86); backdrop-filter: blur(24px) saturate(1.3); -webkit-backdrop-filter: blur(24px) saturate(1.3); box-shadow: var(--shadow-window); z-index: 50; transform-origin: var(--radix-dropdown-menu-content-transform-origin); } .modern-sk-menu[data-state='open'] { animation: modern-sk-scale-in var(--dur-base) var(--ease-out); } .modern-sk-menu[data-state='closed'] { animation: modern-sk-scale-out var(--dur-quick) var(--ease-out); } .modern-sk-menu-item { display: flex; align-items: center; gap: 10px; padding: 7px 10px; border-radius: var(--r-sm); font-size: 13px; color: var(--fg-1); cursor: pointer; outline: none; user-select: none; } .modern-sk-menu-item .ph { font-size: 16px; color: var(--fg-2); display: inline-flex; } .modern-sk-menu-item .sc { margin-left: auto; font-family: var(--font-mono); font-size: 11px; color: var(--fg-3); } .modern-sk-menu-item[data-highlighted] { background: linear-gradient(180deg, var(--lime), var(--lime-deep)); color: var(--lime-ink); } .modern-sk-menu-item[data-highlighted] .ph, .modern-sk-menu-item[data-highlighted] .sc { color: var(--lime-ink); } .modern-sk-menu-sep { height: 1px; background: var(--hair); margin: 5px 4px; } /* ---------- TABS (Radix Tabs) ---------- */ .modern-sk-tabs { display: flex; gap: 2px; border-bottom: 1px solid var(--hair); } .modern-sk-tabs__trigger { font-family: var(--font-sans); font-size: 13px; font-weight: 600; color: var(--fg-3); background: transparent; border: none; padding: 9px 14px; cursor: pointer; position: relative; transition: color var(--dur-quick); } .modern-sk-tabs__trigger:hover { color: var(--fg-2); } .modern-sk-tabs__trigger[data-state='active'] { color: var(--fg-1); } .modern-sk-tabs__trigger[data-state='active']::after { content: ''; position: absolute; left: 8px; right: 8px; bottom: -1px; height: 2px; border-radius: 2px; background: var(--lime); box-shadow: 0 0 8px rgba(190, 242, 100, 0.5); } /* ---------- PROGRESS (Radix Progress) ---------- */ .modern-sk-progress { width: 100%; height: 8px; border-radius: var(--r-pill); background: var(--steel-800); box-shadow: var(--shadow-inset-well); overflow: hidden; } .modern-sk-progress__indicator { display: block; height: 100%; border-radius: var(--r-pill); background: linear-gradient(90deg, var(--lime-deep), var(--lime)); box-shadow: 0 0 10px rgba(190, 242, 100, 0.4); transition: width var(--dur-base) var(--ease-out); } /* ---------- WINDOW CHROME ---------- */ .modern-sk-window { border-radius: var(--r-xl); overflow: hidden; border: 1px solid var(--hair-strong); background: var(--steel-800); box-shadow: var(--shadow-window); } .modern-sk-titlebar { height: 42px; display: flex; align-items: center; gap: 9px; padding: 0 14px; background: var(--grad-titlebar); border-bottom: 1px solid rgba(0, 0, 0, 0.4); box-shadow: 0 1px 0 rgba(255, 255, 255, 0.05) inset; } .modern-sk-titlebar .ttl { margin-left: 6px; font-size: 13px; font-weight: 600; color: var(--fg-2); } .modern-sk-traffic { width: 12px; height: 12px; border-radius: 50%; box-shadow: 0 1px 1px rgba(0, 0, 0, 0.4) inset, 0 0 0 0.5px rgba(0, 0, 0, 0.3); } .modern-sk-traffic.r { background: radial-gradient(circle at 35% 30%, #ff8a7a, #ec5f55); } .modern-sk-traffic.y { background: radial-gradient(circle at 35% 30%, #ffd97a, #e6a93c); } .modern-sk-traffic.g { background: radial-gradient(circle at 35% 30%, #bff07a, #9bce4c); } /* ---------- TOOLTIP (Radix Tooltip) ---------- */ .modern-sk-tooltip { display: inline-flex; align-items: center; font-size: 12px; font-weight: 500; color: var(--fg-1); padding: 5px 9px; border-radius: var(--r-sm); background: rgba(20, 21, 15, 0.92); border: 1px solid var(--hair-strong); box-shadow: var(--shadow-card); z-index: 60; transform-origin: var(--radix-tooltip-content-transform-origin); } .modern-sk-tooltip[data-state='delayed-open'], .modern-sk-tooltip[data-state='instant-open'] { animation: modern-sk-scale-in var(--dur-base) var(--ease-out); } .modern-sk-tooltip[data-state='closed'] { animation: modern-sk-fade-out var(--dur-quick) var(--ease-out); } /* ---------- ICON BUTTON ---------- Square tactile key. Reuses the .modern-sk-btn engine; variants below just recolor. Pair with .modern-sk-btn / .modern-sk-btn--primary etc. */ .modern-sk-iconbtn { padding: 0; width: 32px; height: 32px; aspect-ratio: 1; display: inline-flex; align-items: center; justify-content: center; } .modern-sk-iconbtn--sm { width: 26px; height: 26px; } .modern-sk-iconbtn--lg { width: 38px; height: 38px; } /* ---------- SPINNER ---------- A carved donut groove (flat felt sunk by an SVG inner shadow, like the switch well) with a glowing lime arc spinning in the channel. Groove recess + arc glow are SVG filters; CSS only sizes the box and drives the rotation. Honors reduced motion. */ .modern-sk-spinner { display: inline-block; width: 24px; height: 24px; line-height: 0; } .modern-sk-spinner--sm { width: 16px; height: 16px; } .modern-sk-spinner--lg { width: 34px; height: 34px; } .modern-sk-spinner svg { width: 100%; height: 100%; display: block; overflow: visible; /* let the arc glow spill past the box, not clip square */ } .modern-sk-spinner__arc { transform-origin: center; animation: modern-sk-spin 0.7s linear infinite; } @keyframes modern-sk-spin { to { transform: rotate(360deg); } } @media (prefers-reduced-motion: reduce) { .modern-sk-spinner__arc { animation-duration: 1.8s; } } /* ---------- CALLOUT ---------- Soft semantic surface (12–14% tint on the felt) with a glossy icon chip. Variants reuse the semantic --*-bg tokens. */ .modern-sk-callout { display: flex; gap: 12px; align-items: flex-start; padding: 13px 15px; border-radius: var(--r-lg); border: 1px solid var(--hair); background: var(--info-bg); color: var(--fg-1); box-shadow: var(--shadow-inset-well); } .modern-sk-callout__icon { flex-shrink: 0; display: inline-flex; align-items: center; justify-content: center; width: 26px; height: 26px; border-radius: var(--r-sm); color: var(--info); } .modern-sk-callout__body { font-size: 13px; line-height: 1.5; color: var(--fg-2); padding-top: 3px; } .modern-sk-callout__body strong { color: var(--fg-1); font-weight: 600; } .modern-sk-callout--success { background: var(--success-bg); border-color: rgba(190, 242, 100, 0.22); } .modern-sk-callout--success .modern-sk-callout__icon { color: var(--success); } .modern-sk-callout--warning { background: var(--warning-bg); border-color: rgba(230, 169, 60, 0.22); } .modern-sk-callout--warning .modern-sk-callout__icon { color: var(--warning); } .modern-sk-callout--danger { background: var(--danger-bg); border-color: rgba(233, 87, 43, 0.25); } .modern-sk-callout--danger .modern-sk-callout__icon { color: var(--danger); } /* ---------- TABLE ---------- The list-row aesthetic stretched to columns: hairline grid, sunk header strip, mono numerals, lime row selection. */ .modern-sk-table-wrap { background: var(--steel-900); border: 1px solid var(--hair); border-radius: var(--r-lg); box-shadow: var(--shadow-card); overflow: hidden; } .modern-sk-table { width: 100%; border-collapse: collapse; font-size: 14px; } .modern-sk-table thead th { text-align: left; font-family: var(--font-sans); font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.14em; color: var(--fg-3); padding: 9px 14px; background: var(--grad-titlebar); border-bottom: 1px solid var(--hair-strong); box-shadow: 0 1px 0 rgba(255, 255, 255, 0.04) inset; white-space: nowrap; } .modern-sk-table tbody td { padding: 10px 14px; border-bottom: 1px solid var(--hair); color: var(--fg-1); vertical-align: middle; } .modern-sk-table tbody tr:last-child td { border-bottom: none; } .modern-sk-table tbody tr:hover td { background: rgba(255, 255, 255, 0.03); } .modern-sk-table tbody tr.is-selected td { background: linear-gradient( 180deg, rgba(190, 242, 100, 0.16), rgba(190, 242, 100, 0.08) ); } .modern-sk-table .num { font-family: var(--font-mono); font-size: 12px; color: var(--fg-2); text-align: right; } .modern-sk-table .muted { color: var(--fg-3); } [data-theme='light'] .modern-sk-table tbody tr:hover td { background: rgba(0, 0, 0, 0.035); } /* ---------- SCROLL AREA (Radix) ---------- */ .modern-sk-scroll { overflow: hidden; } .modern-sk-scroll__viewport { width: 100%; height: 100%; border-radius: inherit; } .modern-sk-scroll__bar { display: flex; user-select: none; touch-action: none; padding: 2px; background: transparent; transition: background var(--dur-base) var(--ease-out); } .modern-sk-scroll__bar[data-orientation='vertical'] { width: 10px; } .modern-sk-scroll__bar[data-orientation='horizontal'] { flex-direction: column; height: 10px; } .modern-sk-scroll:hover .modern-sk-scroll__bar { background: rgba(0, 0, 0, 0.18); } .modern-sk-scroll__thumb { flex: 1; background: var(--steel-500); border-radius: var(--r-pill); position: relative; box-shadow: 0 1px 0 rgba(255, 255, 255, 0.08) inset; } .modern-sk-scroll__thumb:hover { background: var(--steel-400); } .modern-sk-scroll__thumb::before { content: ''; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 100%; height: 100%; min-width: 44px; min-height: 44px; } /* ---------- DIALOG / MODAL (Radix Dialog + AlertDialog) ---------- The floating sheet: window chrome aesthetic, scrim with blur. */ .modern-sk-overlay { position: fixed; inset: 0; z-index: 80; background: rgba(8, 9, 6, 0.55); backdrop-filter: blur(3px); -webkit-backdrop-filter: blur(3px); } .modern-sk-overlay[data-state='open'] { animation: modern-sk-fade-in var(--dur-base) var(--ease-out); } .modern-sk-overlay[data-state='closed'] { animation: modern-sk-fade-out var(--dur-quick) var(--ease-out); } .modern-sk-dialog { position: fixed; z-index: 81; top: 50%; left: 50%; translate: -50% -50%; width: min(92vw, 460px); max-height: 85vh; overflow: auto; border-radius: var(--r-xl); border: 1px solid var(--hair-strong); background: var(--steel-800); box-shadow: var(--shadow-window); padding: 22px 22px 20px; transform-origin: center; font-family: var(--font-sans); } .modern-sk-dialog[data-state='open'] { animation: modern-sk-scale-in var(--dur-base) var(--ease-out); } .modern-sk-dialog[data-state='closed'] { animation: modern-sk-scale-out var(--dur-quick) var(--ease-out); } .modern-sk-dialog__title { font-family: var(--font-sans); font-size: var(--text-lg); font-weight: 600; color: var(--fg-1); letter-spacing: var(--track-snug); } .modern-sk-dialog__desc { margin-top: 8px; font-size: 14px; line-height: 1.55; color: var(--fg-2); } .modern-sk-dialog__body { margin-top: 16px; } .modern-sk-dialog__footer { display: flex; justify-content: flex-end; gap: 12px; margin-top: 22px; } .modern-sk-dialog__close { position: absolute; top: 14px; right: 14px; } /* ============================================================ LIGHT THEME — component overrides (ported 1:1) ============================================================ */ [data-theme='light'] .modern-sk-btn--ghost:hover { background: rgba(0, 0, 0, 0.05); color: var(--fg-1); } [data-theme='light'] .modern-sk-btn--ghost:active { background: rgba(0, 0, 0, 0.08); } [data-theme='light'] .modern-sk-row:hover { background: rgba(0, 0, 0, 0.035); } [data-theme='light'] .modern-sk-btn--ember { box-shadow: 0 1px 0 rgba(255, 255, 255, 0.25) inset, 0 1px 2px rgba(0, 0, 0, 0.18), 0 6px 14px rgba(233, 87, 43, 0.22); } [data-theme='light'] .modern-sk-switch__thumb { background: linear-gradient(180deg, #ffffff, #e7e7dd); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.22), 0 1px 0 rgba(255, 255, 255, 0.9) inset; } [data-theme='light'] .modern-sk-switch { background: var(--steel-600); } [data-theme='light'] .modern-sk-switch[data-state='checked'] { background: linear-gradient(180deg, var(--lime), var(--lime-deep)); } [data-theme='light'] .modern-sk-slider__thumb { box-shadow: 0 1px 3px rgba(0, 0, 0, 0.28), 0 1px 0 rgba(255, 255, 255, 0.95) inset, 0 0 0 0.5px rgba(0, 0, 0, 0.06); } [data-theme='light'] .modern-sk-menu { background: rgba(246, 246, 239, 0.82); border-color: var(--hair-strong); } [data-theme='light'] .modern-sk-select__content { background: rgba(246, 246, 239, 0.82); } [data-theme='light'] .modern-sk-tooltip { background: rgba(246, 246, 239, 0.94); color: var(--fg-1); } [data-theme='light'] .modern-sk-titlebar { border-bottom-color: rgba(0, 0, 0, 0.12); } [data-theme='light'] .modern-sk-traffic { box-shadow: 0 1px 1px rgba(0, 0, 0, 0.18) inset, 0 0 0 0.5px rgba(0, 0, 0, 0.14); } [data-theme='light'] .modern-sk-overlay { background: rgba(60, 62, 52, 0.32); } [data-theme='light'] .modern-sk-scroll:hover .modern-sk-scroll__bar { background: rgba(0, 0, 0, 0.06); } [data-theme='light'] .modern-sk-table thead th { box-shadow: 0 1px 0 rgba(255, 255, 255, 0.6) inset; }