Spaces:
Running
Running
Fix mobile UI overlap, increase 3D avatar size, and re-enable touch rotation on mobile
7bc4b9d verified Download style.css from venmugilrajan/SignLens: direct link, hf CLI and curl.
- Browser
- Download file 77.9 kB
-
https://huggingface.co/spaces/venmugilrajan/SignLens/resolve/main/style.css
- Command line
-
hf download hf://spaces/venmugilrajan/SignLens/style.css
-
curl -L -o style.css https://huggingface.co/spaces/venmugilrajan/SignLens/resolve/main/style.css
77.9 kB
| /* ============================================================ | |
| SignLens | |
| Real-time sign language readout. | |
| Design read: instrument UI, not a marketing page. The camera | |
| feed and the skeleton overlay are the moving content, so the | |
| chrome around them stays still and quiet on purpose. | |
| Locks (one each, applied everywhere): | |
| Theme dark only. A bright page reflects off the signer and | |
| washes out the very hand the model has to read. | |
| Accent amber. Semantic red for failure. Nothing else. | |
| Radius panels 18px / controls 10px / pills full. | |
| Numbers always Geist Mono. Text always Geist. | |
| ============================================================ */ | |
| :root { | |
| /* Ground. Near-black, very slightly warm, never #000. */ | |
| --bg: #0a0a0b; | |
| --surface: #121213; | |
| --surface-2: #17171a; | |
| --surface-3: #1e1e22; | |
| --line: #26262b; | |
| --line-bright: #37373e; | |
| --text: #f2f1ee; | |
| --text-dim: #9c9a95; | |
| --text-mute: #6b6963; | |
| /* Single accent. Live state, focus, fill, active control. */ | |
| --accent: #f0a53f; | |
| --accent-soft: color-mix(in oklab, var(--accent) 16%, transparent); | |
| --accent-line: color-mix(in oklab, var(--accent) 38%, transparent); | |
| --accent-text: #ffcb84; | |
| /* Semantic failure only. Never decorative. */ | |
| --danger: #e2574a; | |
| --danger-soft: color-mix(in oklab, var(--danger) 14%, transparent); | |
| --danger-line: color-mix(in oklab, var(--danger) 36%, transparent); | |
| /* One radius system. */ | |
| --r-panel: 18px; | |
| --r-ctrl: 10px; | |
| --r-pill: 999px; | |
| /* Motion. Feedback only, so short and flat. */ | |
| --dur: 180ms; | |
| --dur-slow: 420ms; | |
| --ease: cubic-bezier(0.2, 0, 1, 1); | |
| --focus: 0 0 0 2px var(--bg), 0 0 0 4px var(--accent); | |
| --font: "Geist", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif; | |
| --mono: "Geist Mono", ui-monospace, "SF Mono", "JetBrains Mono", monospace; | |
| } | |
| /* ── Light Mode Palette ──────────────────────────────────────────────── */ | |
| :root[data-theme="light"], | |
| [data-theme="light"] { | |
| --bg: #f4f5f8; | |
| --surface: #ffffff; | |
| --surface-2: #eceef3; | |
| --surface-3: #e1e4ec; | |
| --line: #d5d8e2; | |
| --line-bright: #b8bdcb; | |
| --text: #141518; | |
| --text-dim: #4e525d; | |
| --text-mute: #7d8291; | |
| --accent: #d97706; | |
| --accent-soft: color-mix(in oklab, var(--accent) 14%, transparent); | |
| --accent-line: color-mix(in oklab, var(--accent) 40%, transparent); | |
| --accent-text: #92400e; | |
| --danger: #dc2626; | |
| --danger-soft: color-mix(in oklab, var(--danger) 14%, transparent); | |
| --danger-line: color-mix(in oklab, var(--danger) 38%, transparent); | |
| } | |
| /* Streak fill, registered so the dial can interpolate instead of jumping. */ | |
| @property --streak { | |
| syntax: "<number>"; | |
| inherits: true; | |
| initial-value: 0; | |
| } | |
| *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; } | |
| html { | |
| color-scheme: dark; | |
| } | |
| html[data-theme="light"] { | |
| color-scheme: light; | |
| } | |
| body { | |
| height: 100dvh; | |
| overflow: hidden; | |
| display: flex; | |
| flex-direction: column; | |
| background: var(--bg); | |
| color: var(--text); | |
| font-family: var(--font); | |
| font-size: 14px; | |
| line-height: 1.5; | |
| -webkit-font-smoothing: antialiased; | |
| text-rendering: optimizeLegibility; | |
| } | |
| /* Every numeral in the UI is tabular mono, so live values do not | |
| reflow their neighbours as they tick. */ | |
| .detected-letter, .streak-label, .field-value, .step-n, | |
| kbd, .word-chip, .cam-error-code { | |
| font-family: var(--mono); | |
| font-variant-numeric: tabular-nums; | |
| } | |
| ::selection { background: var(--accent-soft); color: var(--text); } | |
| :where(button, input, [popovertarget]):focus-visible { | |
| outline: none; | |
| box-shadow: var(--focus); | |
| } | |
| /* ── Top bar ─────────────────────────────────────────────────────────── | |
| Fixed 64px. Three zones, single line, never wraps. */ | |
| .topbar { | |
| flex: none; | |
| height: 64px; | |
| display: grid; | |
| grid-template-columns: 1fr auto 1fr; | |
| align-items: center; | |
| gap: 16px; | |
| padding-inline: 20px; | |
| border-bottom: 1px solid var(--line); | |
| background: var(--surface); | |
| } | |
| .brand { display: flex; align-items: center; gap: 10px; min-width: 0; } | |
| .brand-mark { width: 18px; height: 18px; fill: var(--accent); flex: none; } | |
| .brand-name { | |
| font-size: 0.95rem; font-weight: 600; letter-spacing: -0.01em; | |
| white-space: nowrap; | |
| } | |
| .topbar-right { | |
| display: flex; align-items: center; justify-content: flex-end; | |
| gap: 8px; min-width: 0; | |
| } | |
| /* ── Mode toggle ───────────────────────────────────────────────────── */ | |
| .mode-toggle { | |
| position: relative; | |
| display: flex; | |
| padding: 3px; | |
| gap: 2px; | |
| background: var(--surface-2); | |
| border: 1px solid var(--line); | |
| border-radius: var(--r-pill); | |
| } | |
| .mode-btn { | |
| position: relative; z-index: 2; | |
| flex: 1 1 0; | |
| min-width: 72px; | |
| padding: 6px 14px; | |
| text-align: center; | |
| border: none; background: none; | |
| border-radius: var(--r-pill); | |
| font-family: var(--font); | |
| font-size: 0.78rem; font-weight: 600; letter-spacing: 0.04em; | |
| color: var(--text-mute); | |
| cursor: pointer; | |
| transition: color var(--dur) var(--ease); | |
| } | |
| .mode-btn:hover { color: var(--text-dim); } | |
| .mode-btn.active { color: #23180a; } | |
| .mode-slider { | |
| position: absolute; z-index: 1; | |
| top: 3px; left: 3px; | |
| width: calc((100% - 12px) / 4); height: calc(100% - 6px); | |
| background: var(--accent); | |
| border-radius: var(--r-pill); | |
| transition: transform var(--dur-slow) var(--ease); | |
| } | |
| .mode-toggle.isl-mode .mode-slider { transform: translateX(calc(100% + 2px)); } | |
| .mode-toggle.visually-mode .mode-slider { transform: translateX(calc(200% + 4px)); } | |
| .mode-toggle.upload-mode .mode-slider { transform: translateX(calc(300% + 6px)); } | |
| .hidden, | |
| .hidden * { | |
| display: none ; | |
| visibility: hidden ; | |
| pointer-events: none ; | |
| } | |
| /* ── Status pill ───────────────────────────────────────────────────── */ | |
| .status-pill { | |
| display: flex; align-items: center; gap: 7px; | |
| padding: 5px 12px 5px 10px; | |
| border: 1px solid var(--line); | |
| border-radius: var(--r-pill); | |
| background: var(--surface-2); | |
| font-size: 0.75rem; font-weight: 500; | |
| color: var(--text-dim); | |
| white-space: nowrap; | |
| } | |
| .status-dot { | |
| width: 6px; height: 6px; border-radius: 50%; | |
| background: var(--text-mute); | |
| flex: none; | |
| } | |
| .status-pill.loading .status-dot { background: var(--accent); } | |
| .status-pill.ready, | |
| .status-pill.ok { | |
| color: var(--accent-text); | |
| border-color: var(--accent-line); | |
| background: var(--accent-soft); | |
| } | |
| .status-pill.ready .status-dot, | |
| .status-pill.ok .status-dot { background: var(--accent); } | |
| .status-pill.err { | |
| color: var(--danger); | |
| border-color: var(--danger-line); | |
| background: var(--danger-soft); | |
| } | |
| .status-pill.err .status-dot { background: var(--danger); } | |
| /* ── Workspace ───────────────────────────────────────────────────────── | |
| Stage carries the weight, rail is a fixed-ish column beside it. */ | |
| .workspace { | |
| flex: 1; | |
| display: grid; | |
| grid-template-columns: minmax(0, 1.55fr) minmax(330px, 0.85fr); | |
| gap: 18px; | |
| padding: 18px 20px; | |
| align-items: stretch; | |
| min-height: 0; | |
| overflow: hidden; | |
| } | |
| /* ── Stage ─────────────────────────────────────────────────────────── */ | |
| .stage { | |
| display: flex; | |
| flex-direction: column; | |
| gap: 14px; | |
| min-width: 0; | |
| min-height: 0; | |
| } | |
| .viewport { | |
| position: relative; | |
| flex: 1; | |
| min-height: 0; | |
| aspect-ratio: 4 / 3; | |
| width: auto; | |
| max-width: 100%; | |
| margin-inline: auto; | |
| overflow: hidden; | |
| background: #000; | |
| border: 1px solid var(--line); | |
| border-radius: var(--r-panel); | |
| } | |
| @supports (corner-shape: squircle) { | |
| .viewport, .panel, .sheet { corner-shape: squircle; } | |
| } | |
| #webcam-video { | |
| position: absolute; | |
| top: 0; | |
| left: 0; | |
| width: 1px; | |
| height: 1px; | |
| opacity: 0; | |
| pointer-events: none; | |
| z-index: -1; | |
| } | |
| #display-canvas { | |
| display: block; | |
| width: 100%; height: 100%; | |
| object-fit: contain; | |
| transition: transform var(--dur) var(--ease); | |
| } | |
| #display-canvas.mirrored { | |
| transform: scaleX(-1); | |
| } | |
| /* ── Idle / error overlay ────────────────────────────────────────────── | |
| app.js toggles `.visible` for idle and `.error` for camera failure. */ | |
| .no-hand-overlay { | |
| position: absolute; inset: 0; | |
| display: flex; flex-direction: column; | |
| align-items: center; justify-content: center; | |
| gap: 6px; | |
| padding: 0 32px; | |
| text-align: center; | |
| background: color-mix(in oklab, var(--bg) 72%, transparent); | |
| opacity: 0; | |
| pointer-events: none; | |
| transition: opacity var(--dur-slow) var(--ease); | |
| } | |
| .no-hand-overlay.visible { opacity: 1; } | |
| .no-hand-overlay.hidden { opacity: 0; } | |
| .idle-title { font-size: 0.95rem; font-weight: 500; color: var(--text); } | |
| .idle-sub { font-size: 0.8rem; color: var(--text-mute); text-wrap: pretty; } | |
| /* Camera failure. Replaces the native alert() camera_utils would raise. */ | |
| .no-hand-overlay.error { | |
| opacity: 1; | |
| gap: 10px; | |
| background: color-mix(in oklab, var(--bg) 94%, transparent); | |
| backdrop-filter: blur(6px); | |
| pointer-events: auto; | |
| } | |
| .cam-error-icon { | |
| width: 34px; height: 34px; | |
| display: grid; place-items: center; | |
| border-radius: var(--r-pill); | |
| background: var(--danger-soft); | |
| border: 1px solid var(--danger-line); | |
| color: var(--danger); | |
| font-size: 1rem; | |
| } | |
| .cam-error-title { font-size: 1rem; font-weight: 600; } | |
| .cam-error-msg { | |
| font-size: 0.83rem; line-height: 1.55; | |
| color: var(--text-dim); | |
| max-width: 46ch; | |
| text-wrap: pretty; | |
| } | |
| .cam-error-code { | |
| margin-top: 2px; | |
| padding: 3px 9px; | |
| font-size: 0.68rem; letter-spacing: 0.06em; | |
| color: var(--danger); | |
| background: var(--danger-soft); | |
| border: 1px solid var(--danger-line); | |
| border-radius: var(--r-pill); | |
| } | |
| /* ── Readout ─────────────────────────────────────────────────────────── | |
| The dial is the primary affordance: current letter in the middle, | |
| capture progress as the ring around it. */ | |
| .readout { | |
| display: grid; | |
| grid-template-columns: auto minmax(0, 1fr) auto; | |
| align-items: center; | |
| gap: 22px; | |
| flex: none; | |
| padding: 14px 16px; | |
| background: var(--surface); | |
| border: 1px solid var(--line); | |
| border-radius: var(--r-panel); | |
| transition: border-color var(--dur) var(--ease); | |
| } | |
| /* Only light the panel when tracking is actually live. */ | |
| .readout:has(.hand-badge.live) { border-color: var(--accent-line); } | |
| .readout-dial { | |
| position: relative; | |
| display: grid; place-items: center; | |
| width: 74px; height: 74px; | |
| flex: none; | |
| } | |
| .dial-ring { | |
| position: absolute; inset: 0; | |
| border-radius: 50%; | |
| /* --streak is written by app.js alongside the bar width. */ | |
| background: conic-gradient( | |
| var(--accent) calc(var(--streak, 0) * 1%), | |
| var(--surface-3) 0 | |
| ); | |
| mask: radial-gradient(closest-side, transparent calc(100% - 4px), #000 calc(100% - 3px)); | |
| transition: --streak var(--dur) linear; | |
| } | |
| .detected-letter { | |
| font-size: 2.1rem; font-weight: 600; line-height: 1; | |
| letter-spacing: -0.02em; | |
| color: var(--text); | |
| } | |
| /* Null state: a dimmed placeholder, so the dial never collapses. */ | |
| .detected-letter:empty::after { | |
| content: "·"; | |
| color: var(--text-mute); | |
| } | |
| .detected-letter.flash { animation: capture 420ms var(--ease); } | |
| @keyframes capture { | |
| 0% { transform: scale(1); color: var(--text); } | |
| 30% { transform: scale(1.16); color: var(--accent); } | |
| 100% { transform: scale(1); color: var(--text); } | |
| } | |
| .readout-body { | |
| display: flex; flex-direction: column; gap: 9px; | |
| min-width: 0; max-width: 340px; | |
| } | |
| .readout-line { display: flex; align-items: center; gap: 10px; } | |
| .detected-sub { | |
| font-size: 0.82rem; color: var(--text-dim); | |
| white-space: nowrap; overflow: hidden; text-overflow: ellipsis; | |
| } | |
| .hand-badge { | |
| flex: none; | |
| padding: 3px 9px; | |
| border-radius: var(--r-pill); | |
| border: 1px solid var(--line-bright); | |
| background: var(--surface-2); | |
| font-size: 0.63rem; font-weight: 600; letter-spacing: 0.09em; | |
| color: var(--text-mute); | |
| transition: color var(--dur) var(--ease), | |
| background-color var(--dur) var(--ease), | |
| border-color var(--dur) var(--ease); | |
| } | |
| .hand-badge.live, | |
| .hand-badge.detected { | |
| color: var(--accent-text); | |
| background: var(--accent-soft); | |
| border-color: var(--accent-line); | |
| } | |
| .streak-row { display: flex; align-items: center; gap: 10px; } | |
| .streak-track { | |
| flex: 1; | |
| height: 3px; | |
| background: var(--surface-3); | |
| border-radius: var(--r-pill); | |
| overflow: hidden; | |
| } | |
| .streak-fill { | |
| height: 100%; width: 0; | |
| background: var(--accent); | |
| border-radius: inherit; | |
| transition: width var(--dur) linear; | |
| } | |
| .streak-label { font-size: 0.7rem; color: var(--text-mute); flex: none; } | |
| .stage-actions { display: flex; gap: 8px; flex: none; } | |
| /* ── Controls ──────────────────────────────────────────────────────── */ | |
| .ctrl-btn, .btn, .ghost-btn { | |
| font-family: var(--font); | |
| font-size: 0.8rem; font-weight: 500; | |
| color: var(--text-dim); | |
| background: var(--surface-2); | |
| border: 1px solid var(--line); | |
| border-radius: var(--r-ctrl); | |
| padding: 8px 14px; | |
| cursor: pointer; | |
| white-space: nowrap; | |
| transition: color var(--dur) var(--ease), | |
| background-color var(--dur) var(--ease), | |
| border-color var(--dur) var(--ease), | |
| transform var(--dur) var(--ease); | |
| } | |
| .ctrl-btn:hover, .btn:hover, .ghost-btn:hover { | |
| color: var(--text); | |
| background: var(--surface-3); | |
| border-color: var(--line-bright); | |
| } | |
| .ctrl-btn:active, .btn:active, .ghost-btn:active { transform: scale(0.98); } | |
| .ghost-btn { background: none; border-color: transparent; padding: 7px 11px; } | |
| /* Pause / Stop Camera when engaged. Amber = a live control is on. */ | |
| .ctrl-btn.active-btn { | |
| color: var(--accent-text); | |
| background: var(--accent-soft); | |
| border-color: var(--accent-line); | |
| } | |
| .btn-sm { padding: 5px 11px; font-size: 0.74rem; } | |
| .btn-quiet { color: var(--text-mute); } | |
| .btn-danger { | |
| width: 100%; | |
| margin-top: 2px; | |
| color: var(--danger); | |
| background: var(--danger-soft); | |
| border-color: var(--danger-line); | |
| } | |
| .btn-danger:hover { | |
| color: #fff; | |
| background: var(--danger); | |
| border-color: var(--danger); | |
| } | |
| /* ── Rail ────────────────────────────────────────────────────────────── | |
| Panels size against the rail's own width, not the viewport, so the | |
| layout holds wherever the rail ends up. */ | |
| .rail { | |
| container-type: inline-size; | |
| container-name: rail; | |
| display: flex; | |
| flex-direction: column; | |
| gap: 14px; | |
| min-width: 0; | |
| min-height: 0; | |
| overflow-y: auto; | |
| } | |
| .panel-grow { flex: 1; min-height: 0; } | |
| .panel-grow .sentence-display { flex: 1; overflow-y: auto; } | |
| .panel { | |
| display: flex; | |
| flex-direction: column; | |
| gap: 12px; | |
| padding: 16px; | |
| background: var(--surface); | |
| border: 1px solid var(--line); | |
| border-radius: var(--r-panel); | |
| } | |
| .panel-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; } | |
| .panel-title { | |
| font-size: 0.68rem; font-weight: 600; | |
| letter-spacing: 0.11em; text-transform: uppercase; | |
| color: var(--text-mute); | |
| } | |
| .panel-head-actions { display: flex; gap: 6px; } | |
| .word-display { | |
| min-height: 62px; | |
| display: flex; align-items: center; | |
| padding: 10px 14px; | |
| background: var(--bg); | |
| border: 1px solid var(--line); | |
| border-radius: var(--r-ctrl); | |
| font-family: var(--mono); | |
| font-size: 1.6rem; font-weight: 500; | |
| letter-spacing: 0.1em; | |
| word-break: break-all; | |
| } | |
| .sentence-display { | |
| min-height: 74px; | |
| padding: 12px 14px; | |
| background: var(--bg); | |
| border: 1px solid var(--line); | |
| border-radius: var(--r-ctrl); | |
| font-size: 1rem; line-height: 1.55; | |
| text-wrap: pretty; | |
| } | |
| .ph { color: var(--text-mute); font-style: normal; letter-spacing: 0; font-size: 0.85rem; } | |
| .panel-actions { display: flex; gap: 7px; } | |
| .panel-actions .btn { flex: 1; padding-inline: 8px; } | |
| /* Chip row only earns its margin once there are chips in it. */ | |
| .word-chips { display: none; flex-wrap: wrap; gap: 6px; } | |
| #sentence-panel:has(.word-chip) .word-chips { display: flex; } | |
| .word-chip { | |
| padding: 3px 9px; | |
| background: var(--surface-3); | |
| border: 1px solid var(--line-bright); | |
| border-radius: var(--r-pill); | |
| font-size: 0.72rem; | |
| color: var(--text-dim); | |
| animation: chip-in 220ms var(--ease); | |
| } | |
| @keyframes chip-in { | |
| from { opacity: 0; transform: translateY(3px); } | |
| to { opacity: 1; transform: none; } | |
| } | |
| /* Narrow rail: actions stack rather than crushing their labels. */ | |
| @container rail (max-width: 300px) { | |
| .panel-actions { flex-wrap: wrap; } | |
| .panel-actions .btn { flex: 1 1 100%; } | |
| .word-display { font-size: 1.3rem; } | |
| } | |
| /* ── Sheets (Popover API, top layer) ────────────────────────────────── | |
| Popover keeps these out of the z-index stack entirely, and gives | |
| light-dismiss plus Esc for free. */ | |
| /* Native popovers: strictly hide them when not open so they never occupy space or bleed into live view */ | |
| .sheet:not(:popover-open), | |
| [popover]:not(:popover-open) { | |
| display: none ; | |
| visibility: hidden ; | |
| pointer-events: none ; | |
| opacity: 0 ; | |
| } | |
| .sheet { | |
| width: min(420px, calc(100vw - 32px)); | |
| padding: 18px; | |
| border: 1px solid var(--line-bright); | |
| border-radius: var(--r-panel); | |
| background: var(--surface); | |
| color: var(--text); | |
| inset: auto; | |
| position: fixed; | |
| top: 70px; right: 20px; | |
| margin: 0; | |
| display: none; | |
| opacity: 0; | |
| transform: translateY(-6px) scale(0.98); | |
| transition-property: opacity, transform, display, overlay; | |
| transition-duration: var(--dur); | |
| transition-timing-function: var(--ease); | |
| transition-behavior: allow-discrete; | |
| } | |
| .sheet:popover-open, | |
| .sheet.open { | |
| display: flex ; | |
| flex-direction: column; | |
| visibility: visible ; | |
| pointer-events: auto ; | |
| opacity: 1 ; | |
| transform: none ; | |
| @starting-style { | |
| opacity: 0 ; | |
| transform: translateY(-6px) scale(0.98) ; | |
| } | |
| } | |
| .sheet::backdrop { | |
| background: color-mix(in oklab, var(--bg) 55%, transparent); | |
| opacity: 0; | |
| transition-property: opacity, display, overlay; | |
| transition-duration: var(--dur); | |
| transition-behavior: allow-discrete; | |
| } | |
| .sheet:popover-open::backdrop { | |
| opacity: 1; | |
| @starting-style { opacity: 0; } | |
| } | |
| .sheet-head { | |
| display: flex; align-items: center; justify-content: space-between; | |
| margin-bottom: 16px; | |
| } | |
| .sheet-title { font-size: 0.95rem; font-weight: 600; } | |
| /* ── Fields ────────────────────────────────────────────────────────── */ | |
| .field { display: flex; flex-direction: column; gap: 7px; } | |
| .field + .field { margin-top: 18px; } | |
| .field label { font-size: 0.82rem; font-weight: 500; color: var(--text); } | |
| .field-row { display: flex; align-items: center; gap: 12px; } | |
| .field-value { | |
| min-width: 44px; text-align: right; | |
| font-size: 0.82rem; color: var(--accent-text); | |
| } | |
| .field-help { font-size: 0.76rem; color: var(--text-mute); text-wrap: pretty; } | |
| input[type="range"] { | |
| flex: 1; | |
| accent-color: var(--accent); | |
| height: 18px; | |
| cursor: pointer; | |
| } | |
| /* ── Steps and keys ────────────────────────────────────────────────── */ | |
| .steps { list-style: none; display: flex; flex-direction: column; gap: 10px; } | |
| .steps li { | |
| display: flex; align-items: baseline; gap: 10px; | |
| font-size: 0.85rem; color: var(--text-dim); | |
| text-wrap: pretty; | |
| } | |
| .step-n { | |
| flex: none; | |
| width: 20px; height: 20px; | |
| display: grid; place-items: center; | |
| border-radius: var(--r-pill); | |
| background: var(--accent-soft); | |
| border: 1px solid var(--accent-line); | |
| color: var(--accent-text); | |
| font-size: 0.68rem; | |
| } | |
| .keys { | |
| margin-top: 18px; padding-top: 16px; | |
| border-top: 1px solid var(--line); | |
| display: flex; flex-direction: column; gap: 8px; | |
| } | |
| .key-row { display: flex; align-items: center; gap: 10px; font-size: 0.8rem; color: var(--text-dim); } | |
| kbd { | |
| min-width: 26px; | |
| padding: 2px 7px; | |
| background: var(--surface-3); | |
| border: 1px solid var(--line-bright); | |
| border-bottom-width: 2px; | |
| border-radius: 6px; | |
| font-size: 0.7rem; | |
| color: var(--text); | |
| text-align: center; | |
| } | |
| /* ── Toast ─────────────────────────────────────────────────────────── */ | |
| .toast { | |
| position: fixed; | |
| bottom: 22px; left: 50%; | |
| padding: 9px 18px; | |
| background: var(--surface-3); | |
| border: 1px solid var(--line-bright); | |
| border-radius: var(--r-pill); | |
| font-size: 0.82rem; | |
| color: var(--text); | |
| box-shadow: 0 8px 28px rgb(0 0 0 / 0.45); | |
| opacity: 0; | |
| transform: translateX(-50%) translateY(10px); | |
| pointer-events: none; | |
| transition: opacity var(--dur) var(--ease), transform var(--dur) var(--ease); | |
| } | |
| .toast.show { opacity: 1; transform: translateX(-50%) translateY(0); } | |
| /* ── Responsive ────────────────────────────────────────────────────── */ | |
| @media (max-width: 1000px) { | |
| body { height: auto; min-height: 100dvh; overflow-y: auto; overflow-x: hidden; } | |
| .workspace { grid-template-columns: minmax(0, 1fr); overflow: visible; } | |
| .rail { overflow: visible; } | |
| .viewport { flex: none; width: 100%; } | |
| /* Practice Studio (VISUALLY) on tablet/mobile: 3D Avatar at TOP, controls BELOW */ | |
| .visually-workspace { | |
| display: flex ; | |
| flex-direction: column ; | |
| grid-template-columns: minmax(0, 1fr) ; | |
| overflow: visible ; | |
| gap: 14px; | |
| } | |
| .visually-workspace .practice-stage { | |
| order: -1 ; /* Move 3D Avatar to the top */ | |
| width: 100%; | |
| flex: none; | |
| } | |
| .visually-workspace .practice-input-rail { | |
| order: 1 ; /* Move controls & timeline below */ | |
| width: 100%; | |
| overflow: visible; | |
| } | |
| .avatar-viewport { | |
| min-height: 340px; | |
| height: 48vh; | |
| max-height: 460px; | |
| } | |
| } | |
| @media (max-width: 768px) { | |
| /* Prevent horizontal blowout & enable smooth native vertical touch scrolling */ | |
| html, body { | |
| height: auto ; | |
| min-height: 100% ; | |
| overflow-y: auto ; | |
| overflow-x: hidden ; | |
| max-width: 100vw; | |
| -webkit-overflow-scrolling: touch ; | |
| } | |
| /* ── Top Bar on Mobile ─────────────────────────────────────────── */ | |
| .topbar { | |
| height: auto; | |
| display: flex; | |
| flex-wrap: wrap; | |
| align-items: center; | |
| justify-content: space-between; | |
| gap: 8px; | |
| padding: 8px 10px; | |
| position: relative; | |
| z-index: 50; | |
| } | |
| .brand { | |
| gap: 6px; | |
| flex: 0 0 auto; | |
| } | |
| .brand-name { | |
| display: inline; | |
| font-size: 0.88rem; | |
| font-weight: 700; | |
| } | |
| .brand-mark { | |
| width: 16px; | |
| height: 16px; | |
| } | |
| /* Right-side quick controls */ | |
| .topbar-right { | |
| display: flex; | |
| align-items: center; | |
| gap: 4px; | |
| flex: 1 1 auto; | |
| justify-content: flex-end; | |
| min-width: 0; | |
| } | |
| .ghost-btn { | |
| padding: 5px 8px; | |
| font-size: 0.74rem; | |
| white-space: nowrap; | |
| flex-shrink: 0; | |
| } | |
| .guide-btn svg { | |
| margin-right: 2px; | |
| } | |
| /* Hide verbose guide text on mobile topbar to avoid crowding the row */ | |
| .topbar-right .guide-btn span { | |
| display: inline; | |
| } | |
| .status-pill { | |
| font-size: 0.68rem; | |
| padding: 4px 7px; | |
| gap: 4px; | |
| flex-shrink: 0; | |
| } | |
| /* Mode Toggle spans full width on row 2 */ | |
| .topbar .mode-toggle { | |
| order: 3; | |
| width: 100%; | |
| margin-top: 2px; | |
| display: flex; | |
| } | |
| .mode-btn { | |
| flex: 1; | |
| min-width: 0; | |
| padding: 7px 10px; | |
| font-size: 0.75rem; | |
| text-align: center; | |
| } | |
| /* ── Workspace General ─────────────────────────────────────────── */ | |
| .workspace { | |
| padding: 10px 12px 20px; | |
| gap: 12px; | |
| grid-template-columns: minmax(0, 1fr) ; | |
| overflow: visible; | |
| } | |
| /* ── Live Camera Stage ─────────────────────────────────────────── */ | |
| .stage { | |
| gap: 10px; | |
| } | |
| .viewport { | |
| aspect-ratio: 4 / 3; | |
| max-height: 52vh; | |
| border-radius: 14px; | |
| } | |
| /* Readout panel */ | |
| .readout { | |
| display: grid; | |
| grid-template-columns: auto minmax(0, 1fr); | |
| gap: 12px; | |
| padding: 12px; | |
| border-radius: 14px; | |
| } | |
| .readout-dial { | |
| width: 58px; | |
| height: 58px; | |
| } | |
| .detected-letter { | |
| font-size: 1.65rem; | |
| } | |
| .readout-body { | |
| max-width: 100%; | |
| gap: 6px; | |
| } | |
| .readout-line { | |
| gap: 8px; | |
| flex-wrap: wrap; | |
| } | |
| .detected-sub { | |
| font-size: 0.76rem; | |
| } | |
| .hand-badge { | |
| padding: 2px 7px; | |
| font-size: 0.6rem; | |
| } | |
| /* Stage action buttons (Guide / Pause / Stop Camera) full width row */ | |
| .stage-actions { | |
| grid-column: 1 / -1; | |
| display: flex; | |
| width: 100%; | |
| gap: 6px; | |
| } | |
| .stage-actions .ctrl-btn { | |
| flex: 1; | |
| min-width: 0; | |
| padding: 8px 6px; | |
| font-size: 0.76rem; | |
| text-align: center; | |
| } | |
| /* ── Output Rail (Word & Sentence Panels) ───────────────────────── */ | |
| .rail { | |
| gap: 10px; | |
| overflow: visible; | |
| } | |
| .panel { | |
| padding: 12px; | |
| gap: 10px; | |
| border-radius: 14px; | |
| } | |
| .word-display { | |
| min-height: 52px; | |
| font-size: 1.3rem; | |
| padding: 8px 12px; | |
| } | |
| .panel-actions { | |
| gap: 6px; | |
| } | |
| .panel-actions .btn { | |
| padding: 8px 6px; | |
| font-size: 0.75rem; | |
| } | |
| .sentence-display { | |
| min-height: 64px; | |
| font-size: 0.92rem; | |
| padding: 10px 12px; | |
| } | |
| /* ── VISUALLY (Practice Studio) on Mobile ───────────────────────── */ | |
| .visually-workspace { | |
| grid-template-columns: minmax(0, 1fr) ; | |
| padding: 10px 12px 24px; | |
| gap: 14px; | |
| } | |
| .practice-input-rail { | |
| width: 100%; | |
| overflow: visible; | |
| } | |
| .practice-panel { | |
| gap: 12px; | |
| padding: 12px; | |
| border-radius: 14px; | |
| } | |
| .practice-panel .panel-head { | |
| flex-wrap: wrap; | |
| gap: 8px; | |
| } | |
| .practice-head-title { | |
| flex: 1; | |
| min-width: 120px; | |
| } | |
| .practice-dialect-toggle { | |
| flex: none; | |
| } | |
| .dialect-pill { | |
| padding: 4px 12px; | |
| font-size: 0.75rem; | |
| } | |
| .practice-textarea-box { | |
| padding: 10px; | |
| gap: 8px; | |
| } | |
| .practice-textarea-box textarea { | |
| font-size: 0.88rem; | |
| rows: 3; | |
| } | |
| .practice-input-tools { | |
| flex-wrap: wrap; | |
| gap: 6px; | |
| } | |
| .tool-btn { | |
| padding: 5px 8px; | |
| font-size: 0.72rem; | |
| } | |
| /* Quick samples horizontal scroll */ | |
| .quick-samples { | |
| gap: 5px; | |
| overflow-x: auto; | |
| flex-wrap: nowrap; | |
| padding-bottom: 4px; | |
| scrollbar-width: none; | |
| -webkit-overflow-scrolling: touch; | |
| } | |
| .quick-samples::-webkit-scrollbar { | |
| display: none; | |
| } | |
| .sample-chip { | |
| flex: none; | |
| padding: 4px 9px; | |
| font-size: 0.7rem; | |
| } | |
| /* Practice Action Row (Demonstrate Sign + Speed) */ | |
| .practice-action-row { | |
| flex-direction: column; | |
| align-items: stretch; | |
| gap: 8px; | |
| } | |
| .btn-demo { | |
| width: 100%; | |
| justify-content: center; | |
| padding: 10px 14px; | |
| font-size: 0.85rem; | |
| } | |
| .speed-control { | |
| justify-content: center; | |
| width: 100%; | |
| padding: 4px; | |
| } | |
| .speed-btn { | |
| flex: 1; | |
| padding: 5px 8px; | |
| text-align: center; | |
| } | |
| /* Sequence Timeline */ | |
| .sequence-chips { | |
| min-height: 72px; | |
| max-height: 120px; | |
| padding: 8px; | |
| gap: 4px; | |
| } | |
| .sequence-chip { | |
| min-width: 28px; | |
| height: 28px; | |
| font-size: 0.78rem; | |
| padding: 0 6px; | |
| } | |
| /* Practice 3D Avatar Stage on Mobile: Avatar at TOP, Controls BELOW */ | |
| .visually-workspace { | |
| display: flex ; | |
| flex-direction: column ; | |
| padding: 10px 12px 24px ; | |
| gap: 12px ; | |
| overflow: visible ; | |
| height: auto ; | |
| min-height: auto ; | |
| } | |
| .visually-workspace .practice-stage { | |
| order: -1 ; /* Move 3D Avatar to the very top */ | |
| width: 100% ; | |
| height: auto ; | |
| margin-bottom: 4px ; | |
| } | |
| .visually-workspace .practice-input-rail { | |
| order: 1 ; /* Controls, text input, timeline placed below */ | |
| width: 100% ; | |
| overflow: visible ; | |
| } | |
| .avatar-viewport { | |
| min-height: 290px ; | |
| height: 42vh ; | |
| max-height: 380px ; | |
| border-radius: 14px; | |
| position: relative; | |
| overflow: hidden; | |
| touch-action: pan-y ; | |
| } | |
| #avatar-canvas-3d, | |
| #avatar-canvas { | |
| touch-action: pan-y ; | |
| } | |
| .hud-letter-char { | |
| font-size: 1.65rem ; | |
| } | |
| .hud-letter-sub { | |
| font-size: 0.66rem ; | |
| } | |
| .hud-letter-cue { | |
| display: none ; | |
| } | |
| .avatar-hud-letter { | |
| top: 10px; | |
| left: 12px; | |
| z-index: 5; | |
| max-width: 55%; | |
| pointer-events: none; | |
| } | |
| .avatar-hud-status { | |
| top: 10px ; | |
| right: 10px ; | |
| padding: 3px 8px ; | |
| font-size: 0.65rem ; | |
| z-index: 10 ; | |
| } | |
| /* Sign Reference Card placed cleanly in top-right of Avatar on Mobile (sitting below status badge, NO overlap!) */ | |
| .avatar-sign-preview { | |
| top: 42px ; | |
| bottom: auto ; | |
| right: 10px ; | |
| left: auto ; | |
| width: 82px ; | |
| max-height: 115px ; | |
| height: auto ; | |
| box-shadow: 0 6px 18px rgba(0, 0, 0, 0.45) ; | |
| z-index: 8 ; | |
| border-radius: 10px ; | |
| overflow: hidden ; | |
| } | |
| .avatar-sign-img-wrap { | |
| width: 100% ; | |
| height: 60px ; | |
| aspect-ratio: auto ; | |
| background: #000; | |
| } | |
| .avatar-sign-info { | |
| padding: 2px 5px 3px ; | |
| } | |
| .avatar-sign-char { | |
| font-size: 0.74rem ; | |
| } | |
| .avatar-sign-hands { | |
| font-size: 0.55rem ; | |
| padding: 1px 3px ; | |
| } | |
| .avatar-sign-desc { | |
| display: none ; | |
| } | |
| /* Floating controls bar in avatar viewport on mobile */ | |
| .avatar-controls-bar { | |
| min-width: 0 ; | |
| width: calc(100% - 16px) ; | |
| max-width: calc(100% - 16px) ; | |
| bottom: 8px ; | |
| padding: 4px 8px ; | |
| gap: 6px ; | |
| z-index: 10 ; | |
| } | |
| .avatar-ctrl-btn { | |
| width: 28px ; | |
| height: 28px ; | |
| font-size: 0.72rem ; | |
| } | |
| .avatar-scrubber { | |
| height: 4px ; | |
| } | |
| /* ── Sheets & Modals on Mobile ─────────────────────────────────── */ | |
| .sheet { | |
| top: auto ; | |
| bottom: 10px ; | |
| right: 10px ; | |
| left: 10px ; | |
| width: calc(100vw - 20px) ; | |
| max-height: 85vh; | |
| border-radius: 16px; | |
| padding: 14px; | |
| transform: none ; | |
| } | |
| /* Crucial: Sign Guide wide modal centered & full size on mobile */ | |
| .sheet.sheet-wide, | |
| #panel-guide.sheet.sheet-wide { | |
| position: fixed ; | |
| inset: 12px ; | |
| top: 12px ; | |
| left: 12px ; | |
| right: 12px ; | |
| bottom: 12px ; | |
| width: auto ; | |
| max-width: none ; | |
| height: auto ; | |
| max-height: none ; | |
| transform: none ; | |
| border-radius: 18px ; | |
| box-shadow: 0 16px 60px rgba(0, 0, 0, 0.6) ; | |
| z-index: 9999 ; | |
| } | |
| .sheet.sheet-wide:popover-open, | |
| .sheet.sheet-wide.open, | |
| #panel-guide.sheet.sheet-wide:popover-open, | |
| #panel-guide.sheet.sheet-wide.open { | |
| display: flex ; | |
| flex-direction: column ; | |
| transform: none ; | |
| } | |
| .sheet-wide .sheet-head { | |
| padding: 14px 16px; | |
| flex-wrap: wrap; | |
| gap: 8px; | |
| border-bottom: 1px solid var(--line); | |
| } | |
| .sheet-title-group { | |
| flex: 1; | |
| min-width: 140px; | |
| } | |
| .sheet-title-group .sheet-title { | |
| font-size: 1.05rem; | |
| } | |
| .sheet-sub { | |
| font-size: 0.72rem; | |
| } | |
| .guide-tabs { | |
| width: 100%; | |
| order: 3; | |
| display: flex; | |
| } | |
| .guide-tab-btn { | |
| flex: 1; | |
| justify-content: center; | |
| padding: 7px 10px; | |
| font-size: 0.74rem; | |
| } | |
| .guide-tab-content { | |
| padding: 12px 14px 20px; | |
| flex: 1; | |
| overflow-y: auto; | |
| -webkit-overflow-scrolling: touch; | |
| } | |
| .guide-cards-grid { | |
| grid-template-columns: repeat(auto-fill, minmax(95px, 1fr)); | |
| gap: 8px; | |
| } | |
| .guide-card-char { | |
| font-size: 0.95rem; | |
| } | |
| .guide-card-desc { | |
| font-size: 0.68rem; | |
| padding: 4px 6px 6px; | |
| } | |
| /* Sign Reference Lightbox Dialog on Mobile */ | |
| .sign-lightbox { | |
| padding: 20px 16px 16px; | |
| width: calc(100vw - 24px); | |
| max-width: calc(100vw - 24px); | |
| } | |
| } | |
| @media (max-width: 400px) { | |
| /* Extra-compact phones (iPhone SE, narrow Android) */ | |
| .topbar { | |
| padding: 6px 8px; | |
| gap: 6px; | |
| } | |
| .brand-name { | |
| font-size: 0.82rem; | |
| } | |
| .ghost-btn { | |
| padding: 4px 6px; | |
| font-size: 0.68rem; | |
| } | |
| .status-pill { | |
| padding: 3px 6px; | |
| font-size: 0.64rem; | |
| } | |
| .mode-btn { | |
| font-size: 0.7rem; | |
| padding: 6px 4px; | |
| } | |
| .readout-dial { | |
| width: 50px; | |
| height: 50px; | |
| } | |
| .detected-letter { | |
| font-size: 1.45rem; | |
| } | |
| .guide-cards-grid { | |
| grid-template-columns: repeat(2, 1fr); | |
| } | |
| .avatar-sign-preview { | |
| width: 76px ; | |
| top: 40px ; | |
| bottom: auto ; | |
| } | |
| } | |
| /* ── Reduced motion ────────────────────────────────────────────────── */ | |
| @media (prefers-reduced-motion: reduce) { | |
| *, *::before, *::after { | |
| animation-duration: 0.001ms ; | |
| animation-iteration-count: 1 ; | |
| transition-duration: 0.001ms ; | |
| } | |
| } | |
| /* ── Reduced transparency ──────────────────────────────────────────── */ | |
| @media (prefers-reduced-transparency: reduce) { | |
| .no-hand-overlay, .no-hand-overlay.error { backdrop-filter: none; background: var(--bg); } | |
| } | |
| ::-webkit-scrollbar { width: 6px; height: 6px; } | |
| ::-webkit-scrollbar-thumb { background: var(--line-bright); border-radius: var(--r-pill); } | |
| /* ══════════════════════════════════════════════════════════════════════ | |
| VISUALLY — Practice Studio | |
| Interactive 3D avatar & gesture synthesizer matching RyloTranslate. | |
| ══════════════════════════════════════════════════════════════════════ */ | |
| .visually-workspace { | |
| grid-template-columns: minmax(380px, 0.95fr) minmax(0, 1.45fr); | |
| } | |
| .practice-input-rail { | |
| display: flex; | |
| flex-direction: column; | |
| gap: 14px; | |
| min-width: 0; | |
| min-height: 0; | |
| overflow: visible; | |
| } | |
| .practice-panel { | |
| display: flex; | |
| flex-direction: column; | |
| gap: 16px; | |
| overflow: visible; | |
| } | |
| .practice-head-title { | |
| display: flex; | |
| flex-direction: column; | |
| gap: 4px; | |
| } | |
| .practice-badge { | |
| display: inline-block; | |
| align-self: flex-start; | |
| padding: 2px 8px; | |
| font-family: var(--mono); | |
| font-size: 0.68rem; | |
| font-weight: 600; | |
| letter-spacing: 0.08em; | |
| color: var(--accent-text); | |
| background: var(--accent-soft); | |
| border: 1px solid var(--accent-line); | |
| border-radius: var(--r-pill); | |
| } | |
| .practice-dialect-toggle { | |
| display: flex; | |
| gap: 4px; | |
| background: var(--surface-3); | |
| padding: 3px; | |
| border-radius: var(--r-pill); | |
| border: 1px solid var(--line); | |
| position: relative; | |
| z-index: 20; | |
| } | |
| .dialect-pill { | |
| position: relative; | |
| z-index: 21; | |
| padding: 5px 16px; | |
| min-height: 28px; | |
| border-radius: var(--r-pill); | |
| border: none; | |
| background: transparent; | |
| font-family: var(--mono); | |
| font-size: 0.8rem; | |
| font-weight: 600; | |
| color: var(--text-dim); | |
| cursor: pointer; | |
| user-select: none; | |
| touch-action: manipulation; | |
| transition: all var(--dur) var(--ease); | |
| } | |
| .dialect-pill:hover { | |
| color: var(--text); | |
| } | |
| .dialect-pill.active { | |
| background: var(--accent); | |
| color: #23180a; | |
| } | |
| /* Textarea & Tools */ | |
| .practice-textarea-box { | |
| display: flex; | |
| flex-direction: column; | |
| background: var(--surface-2); | |
| border: 1px solid var(--line); | |
| border-radius: var(--r-ctrl); | |
| padding: 12px; | |
| gap: 10px; | |
| transition: border-color var(--dur) var(--ease); | |
| } | |
| .practice-textarea-box:focus-within { | |
| border-color: var(--accent-line); | |
| box-shadow: 0 0 0 1px var(--accent-line); | |
| } | |
| .practice-textarea-box textarea { | |
| width: 100%; | |
| background: transparent; | |
| border: none; | |
| color: var(--text); | |
| font-family: var(--font); | |
| font-size: 0.95rem; | |
| line-height: 1.5; | |
| resize: none; | |
| outline: none; | |
| } | |
| .practice-textarea-box textarea::placeholder { | |
| color: var(--text-mute); | |
| } | |
| .practice-input-tools { | |
| display: flex; | |
| align-items: center; | |
| gap: 8px; | |
| padding-top: 8px; | |
| border-top: 1px solid var(--line); | |
| } | |
| .tool-btn { | |
| display: inline-flex; | |
| align-items: center; | |
| gap: 6px; | |
| padding: 5px 10px; | |
| background: var(--surface-3); | |
| border: 1px solid var(--line); | |
| border-radius: var(--r-ctrl); | |
| font-family: var(--font); | |
| font-size: 0.78rem; | |
| font-weight: 500; | |
| color: var(--text-dim); | |
| cursor: pointer; | |
| transition: all var(--dur) var(--ease); | |
| } | |
| .tool-btn:hover { | |
| color: var(--text); | |
| border-color: var(--line-bright); | |
| } | |
| .tool-btn .icon { | |
| width: 15px; | |
| height: 15px; | |
| flex: none; | |
| } | |
| .mic-btn.listening { | |
| background: var(--danger-soft); | |
| color: var(--danger); | |
| border-color: var(--danger-line); | |
| animation: pulse-mic 1.2s infinite ease-in-out; | |
| } | |
| @keyframes pulse-mic { | |
| 0%, 100% { box-shadow: 0 0 0 0 color-mix(in oklab, var(--danger) 40%, transparent); } | |
| 50% { box-shadow: 0 0 0 6px transparent; } | |
| } | |
| .char-count { | |
| margin-left: auto; | |
| font-family: var(--mono); | |
| font-size: 0.72rem; | |
| color: var(--text-mute); | |
| } | |
| /* Quick Samples */ | |
| .quick-samples { | |
| display: flex; | |
| align-items: center; | |
| flex-wrap: wrap; | |
| gap: 6px; | |
| } | |
| .quick-label { | |
| font-size: 0.75rem; | |
| color: var(--text-mute); | |
| margin-right: 2px; | |
| } | |
| .sample-chip { | |
| padding: 3px 9px; | |
| background: var(--surface-2); | |
| border: 1px solid var(--line); | |
| border-radius: var(--r-pill); | |
| font-family: var(--mono); | |
| font-size: 0.72rem; | |
| color: var(--text-dim); | |
| cursor: pointer; | |
| transition: all var(--dur) var(--ease); | |
| } | |
| .sample-chip:hover { | |
| color: var(--accent-text); | |
| border-color: var(--accent-line); | |
| background: var(--accent-soft); | |
| } | |
| /* Main Action Row */ | |
| .practice-action-row { | |
| display: flex; | |
| align-items: center; | |
| gap: 12px; | |
| } | |
| .btn-demo { | |
| flex: 1; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| gap: 8px; | |
| padding: 10px 18px; | |
| font-weight: 600; | |
| } | |
| .icon-play { | |
| width: 16px; | |
| height: 16px; | |
| } | |
| .speed-control { | |
| display: flex; | |
| align-items: center; | |
| gap: 4px; | |
| background: var(--surface-2); | |
| border: 1px solid var(--line); | |
| border-radius: var(--r-ctrl); | |
| padding: 3px; | |
| } | |
| .speed-label { | |
| font-size: 0.72rem; | |
| color: var(--text-mute); | |
| padding-inline: 6px 2px; | |
| } | |
| .speed-btn { | |
| padding: 3px 8px; | |
| background: transparent; | |
| border: none; | |
| border-radius: 6px; | |
| font-family: var(--mono); | |
| font-size: 0.72rem; | |
| color: var(--text-dim); | |
| cursor: pointer; | |
| transition: all var(--dur) var(--ease); | |
| } | |
| .speed-btn:hover { | |
| color: var(--text); | |
| } | |
| .speed-btn.active { | |
| background: var(--surface-3); | |
| color: var(--accent); | |
| font-weight: 600; | |
| } | |
| /* Sequence Timeline */ | |
| .sequence-section { | |
| display: flex; | |
| flex-direction: column; | |
| gap: 8px; | |
| flex: 1; | |
| min-height: 0; | |
| overflow: hidden; | |
| } | |
| .sequence-head { | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| } | |
| .seq-title { | |
| font-size: 0.78rem; | |
| font-weight: 600; | |
| color: var(--text-dim); | |
| letter-spacing: 0.02em; | |
| } | |
| .seq-counter { | |
| font-family: var(--mono); | |
| font-size: 0.72rem; | |
| color: var(--text-mute); | |
| } | |
| .sequence-chips { | |
| display: flex; | |
| flex-wrap: wrap; | |
| align-content: flex-start; | |
| gap: 6px; | |
| padding: 10px; | |
| background: var(--surface-2); | |
| border: 1px solid var(--line); | |
| border-radius: var(--r-ctrl); | |
| min-height: 100px; | |
| max-height: 180px; | |
| overflow-y: auto; | |
| } | |
| .sequence-chips .ph { | |
| color: var(--text-mute); | |
| font-size: 0.8rem; | |
| align-self: center; | |
| margin: auto; | |
| } | |
| .sequence-chip { | |
| display: inline-flex; | |
| align-items: center; | |
| justify-content: center; | |
| min-width: 32px; | |
| height: 32px; | |
| padding: 0 8px; | |
| background: var(--surface-3); | |
| border: 1px solid var(--line-bright); | |
| border-radius: 8px; | |
| font-family: var(--mono); | |
| font-size: 0.88rem; | |
| font-weight: 600; | |
| color: var(--text); | |
| cursor: pointer; | |
| transition: all var(--dur) var(--ease); | |
| } | |
| .sequence-chip:hover { | |
| border-color: var(--accent-line); | |
| color: var(--accent-text); | |
| } | |
| .sequence-chip.is-space { | |
| min-width: 22px; | |
| background: transparent; | |
| border-style: dashed; | |
| color: var(--text-mute); | |
| font-size: 0.65rem; | |
| } | |
| .sequence-chip.active { | |
| background: var(--accent-soft); | |
| border-color: var(--accent); | |
| color: var(--accent-text); | |
| box-shadow: 0 0 12px color-mix(in oklab, var(--accent) 35%, transparent); | |
| transform: scale(1.08); | |
| } | |
| /* ── Practice Avatar Stage ─────────────────────────────────────────────── */ | |
| .practice-stage { | |
| display: flex; | |
| flex-direction: column; | |
| min-width: 0; | |
| min-height: 0; | |
| height: 100%; | |
| } | |
| .avatar-viewport { | |
| position: relative; | |
| flex: 1; | |
| width: 100%; | |
| height: 100%; | |
| min-height: 480px; | |
| background: #161619; | |
| border: 1px solid var(--line); | |
| border-radius: var(--r-panel); | |
| overflow: hidden; | |
| } | |
| #avatar-canvas-3d, | |
| #avatar-canvas { | |
| position: absolute; | |
| inset: 0; | |
| display: block; | |
| width: 100%; | |
| height: 100%; | |
| } | |
| #avatar-canvas-3d { | |
| z-index: 1; | |
| } | |
| #avatar-canvas { | |
| z-index: 2; | |
| pointer-events: none; | |
| } | |
| /* 3D Avatar Loading Indicator Overlay */ | |
| .avatar-3d-loading-overlay { | |
| position: absolute; | |
| inset: 0; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| padding: 24px; | |
| background: color-mix(in oklab, var(--bg-card, #161619) 92%, transparent); | |
| backdrop-filter: blur(12px); | |
| -webkit-backdrop-filter: blur(12px); | |
| z-index: 6; | |
| opacity: 1; | |
| visibility: visible; | |
| transition: opacity 0.4s ease, visibility 0.4s ease; | |
| pointer-events: auto; | |
| } | |
| .avatar-3d-loading-overlay.loaded { | |
| opacity: 0; | |
| visibility: hidden; | |
| pointer-events: none; | |
| } | |
| .avatar-loading-box { | |
| display: flex; | |
| flex-direction: column; | |
| align-items: center; | |
| text-align: center; | |
| max-width: 380px; | |
| width: 100%; | |
| padding: 28px 24px; | |
| border-radius: var(--r-panel, 14px); | |
| background: var(--bg-card, #1a1a1f); | |
| border: 1px solid var(--line, rgba(255, 255, 255, 0.1)); | |
| box-shadow: 0 18px 40px rgba(0, 0, 0, 0.45); | |
| } | |
| .avatar-loading-spinner-ring { | |
| position: relative; | |
| width: 48px; | |
| height: 48px; | |
| margin-bottom: 18px; | |
| border-radius: 50%; | |
| border: 3px solid color-mix(in oklab, var(--accent, #6366f1) 20%, transparent); | |
| border-top-color: var(--accent, #6366f1); | |
| border-right-color: color-mix(in oklab, var(--accent, #6366f1) 60%, transparent); | |
| animation: avatarSpin 1.1s cubic-bezier(0.55, 0.15, 0.45, 0.85) infinite; | |
| } | |
| .avatar-loading-core-dot { | |
| position: absolute; | |
| top: 50%; | |
| left: 50%; | |
| width: 8px; | |
| height: 8px; | |
| margin-top: -4px; | |
| margin-left: -4px; | |
| border-radius: 50%; | |
| background: var(--accent, #6366f1); | |
| box-shadow: 0 0 12px var(--accent, #6366f1); | |
| animation: avatarPulse 1.8s ease-in-out infinite; | |
| } | |
| @keyframes avatarSpin { | |
| to { transform: rotate(360deg); } | |
| } | |
| @keyframes avatarPulse { | |
| 0%, 100% { transform: scale(0.85); opacity: 0.6; } | |
| 50% { transform: scale(1.35); opacity: 1; } | |
| } | |
| .avatar-loading-title { | |
| font-family: var(--sans, 'Geist', sans-serif); | |
| font-size: 1.05rem; | |
| font-weight: 600; | |
| color: var(--text, #f1f5f9); | |
| letter-spacing: -0.01em; | |
| margin-bottom: 6px; | |
| } | |
| .avatar-loading-subtitle { | |
| font-size: 0.8rem; | |
| color: var(--text-dim, #94a3b8); | |
| margin-bottom: 16px; | |
| line-height: 1.4; | |
| min-height: 1.2rem; | |
| } | |
| .avatar-loading-progress-track { | |
| width: 100%; | |
| height: 5px; | |
| background: color-mix(in oklab, var(--line, rgba(255, 255, 255, 0.1)) 80%, transparent); | |
| border-radius: 999px; | |
| overflow: hidden; | |
| } | |
| .avatar-loading-progress-bar { | |
| width: 25%; | |
| height: 100%; | |
| border-radius: 999px; | |
| background: linear-gradient(90deg, var(--accent, #6366f1), #a855f7); | |
| transition: width 0.25s ease-out; | |
| box-shadow: 0 0 8px color-mix(in oklab, var(--accent, #6366f1) 50%, transparent); | |
| } | |
| /* 3D Avatar Model Missing Placeholder Overlay */ | |
| .avatar-3d-placeholder { | |
| position: absolute; | |
| inset: 0; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| padding: 24px; | |
| background: color-mix(in oklab, var(--bg-card, #161619) 88%, transparent); | |
| backdrop-filter: blur(8px); | |
| -webkit-backdrop-filter: blur(8px); | |
| z-index: 10; | |
| } | |
| .avatar-3d-placeholder .ph-card { | |
| max-width: 440px; | |
| width: 100%; | |
| padding: 24px 28px; | |
| border-radius: var(--r-panel, 14px); | |
| background: var(--bg-card, #1a1a1f); | |
| border: 1px solid var(--line, rgba(255, 255, 255, 0.1)); | |
| box-shadow: 0 16px 36px rgba(0, 0, 0, 0.35); | |
| text-align: center; | |
| } | |
| .avatar-3d-placeholder .ph-icon { | |
| font-size: 2.5rem; | |
| margin-bottom: 10px; | |
| } | |
| .avatar-3d-placeholder .ph-title { | |
| font-size: 1.15rem; | |
| font-weight: 600; | |
| color: var(--text, #f1f5f9); | |
| margin-bottom: 8px; | |
| } | |
| .avatar-3d-placeholder .ph-desc { | |
| font-size: 0.85rem; | |
| color: var(--text-dim, #94a3b8); | |
| margin-bottom: 10px; | |
| line-height: 1.45; | |
| } | |
| .avatar-3d-placeholder .ph-path { | |
| display: inline-block; | |
| padding: 6px 12px; | |
| margin-bottom: 12px; | |
| border-radius: 6px; | |
| background: color-mix(in oklab, var(--accent, #6366f1) 15%, transparent); | |
| border: 1px solid color-mix(in oklab, var(--accent, #6366f1) 35%, transparent); | |
| color: var(--accent, #818cf8); | |
| font-family: var(--mono, monospace); | |
| font-size: 0.82rem; | |
| user-select: all; | |
| } | |
| .avatar-3d-placeholder .ph-hint { | |
| font-size: 0.76rem; | |
| color: var(--text-dim, #64748b); | |
| line-height: 1.4; | |
| margin-bottom: 16px; | |
| } | |
| .avatar-3d-placeholder .ph-btn { | |
| padding: 8px 18px; | |
| border-radius: var(--r-ctrl, 8px); | |
| background: color-mix(in oklab, var(--text, #fff) 10%, transparent); | |
| border: 1px solid var(--line, rgba(255, 255, 255, 0.15)); | |
| color: var(--text, #f1f5f9); | |
| font-size: 0.82rem; | |
| font-weight: 500; | |
| cursor: pointer; | |
| transition: all 0.2s ease; | |
| } | |
| .avatar-3d-placeholder .ph-btn:hover { | |
| background: var(--accent, #6366f1); | |
| color: #fff; | |
| border-color: transparent; | |
| } | |
| /* Avatar HUD Badges */ | |
| .avatar-hud-letter { | |
| position: absolute; | |
| top: 18px; | |
| left: 20px; | |
| display: flex; | |
| flex-direction: column; | |
| pointer-events: none; | |
| } | |
| .hud-letter-char { | |
| font-family: var(--mono); | |
| font-size: 3.2rem; | |
| font-weight: 700; | |
| line-height: 1; | |
| color: var(--text); | |
| text-shadow: 0 0 20px color-mix(in oklab, var(--accent) 40%, transparent); | |
| } | |
| .hud-letter-sub { | |
| font-size: 0.78rem; | |
| color: var(--text-dim); | |
| margin-top: 4px; | |
| } | |
| .hud-letter-cue { | |
| display: inline-flex; | |
| align-items: center; | |
| gap: 6px; | |
| margin-top: 6px; | |
| padding: 4px 10px; | |
| border-radius: var(--r-ctrl); | |
| background: color-mix(in oklab, var(--accent) 14%, transparent); | |
| border: 1px solid color-mix(in oklab, var(--accent) 30%, transparent); | |
| font-size: 0.76rem; | |
| font-weight: 500; | |
| color: var(--accent); | |
| max-width: 340px; | |
| line-height: 1.35; | |
| backdrop-filter: blur(8px); | |
| } | |
| .avatar-hud-status { | |
| position: absolute; | |
| top: 18px; | |
| right: 20px; | |
| display: flex; | |
| align-items: center; | |
| gap: 7px; | |
| padding: 5px 12px; | |
| border-radius: var(--r-pill); | |
| background: rgb(18 18 19 / 0.85); | |
| backdrop-filter: blur(8px); | |
| border: 1px solid var(--line); | |
| font-family: var(--mono); | |
| font-size: 0.75rem; | |
| color: var(--text-dim); | |
| } | |
| .status-badge-dot { | |
| width: 7px; | |
| height: 7px; | |
| border-radius: 50%; | |
| background: var(--text-mute); | |
| } | |
| .avatar-hud-status.playing .status-badge-dot { | |
| background: var(--accent); | |
| box-shadow: 0 0 8px var(--accent); | |
| } | |
| /* ── Top-Right Real Human Sign Preview Reference Card ─────────────────── */ | |
| .avatar-sign-preview { | |
| position: absolute; | |
| top: 54px; | |
| right: 20px; | |
| width: 140px; | |
| background: var(--surface); | |
| border: 1px solid var(--line-bright); | |
| border-radius: var(--r-ctrl); | |
| overflow: hidden; | |
| box-shadow: 0 12px 32px rgba(0, 0, 0, 0.45); | |
| display: flex; | |
| flex-direction: column; | |
| z-index: 10; | |
| cursor: pointer; | |
| transition: transform var(--dur) var(--ease), border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease); | |
| } | |
| .avatar-sign-preview:hover { | |
| transform: translateY(-2px); | |
| border-color: var(--accent); | |
| box-shadow: 0 16px 40px rgba(0, 0, 0, 0.55); | |
| } | |
| .avatar-sign-img-wrap { | |
| width: 100%; | |
| aspect-ratio: 1; | |
| background: #000; | |
| position: relative; | |
| overflow: hidden; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| } | |
| .avatar-sign-img-wrap img { | |
| width: 100%; | |
| height: 100%; | |
| object-fit: cover; | |
| display: block; | |
| } | |
| .avatar-sign-badge { | |
| position: absolute; | |
| bottom: 6px; | |
| right: 6px; | |
| padding: 2px 6px; | |
| font-size: 0.65rem; | |
| font-weight: 700; | |
| font-family: var(--mono); | |
| background: rgba(0, 0, 0, 0.75); | |
| backdrop-filter: blur(4px); | |
| color: var(--accent); | |
| border-radius: 4px; | |
| border: 1px solid var(--line-bright); | |
| } | |
| .avatar-sign-info { | |
| padding: 6px 8px 8px; | |
| background: var(--surface-2); | |
| border-top: 1px solid var(--line); | |
| display: flex; | |
| flex-direction: column; | |
| gap: 3px; | |
| } | |
| .avatar-sign-char-row { | |
| display: flex; | |
| align-items: center; | |
| justify-content: space-between; | |
| } | |
| .avatar-sign-char { | |
| font-family: var(--mono); | |
| font-size: 0.95rem; | |
| font-weight: 700; | |
| color: var(--text); | |
| } | |
| .avatar-sign-hands { | |
| font-size: 0.62rem; | |
| font-weight: 600; | |
| padding: 1px 5px; | |
| border-radius: 4px; | |
| background: var(--surface-3); | |
| color: var(--text-dim); | |
| } | |
| .avatar-sign-desc { | |
| font-size: 0.65rem; | |
| color: var(--text-dim); | |
| line-height: 1.25; | |
| white-space: nowrap; | |
| overflow: hidden; | |
| text-overflow: ellipsis; | |
| } | |
| [data-theme="light"] .avatar-sign-preview { | |
| background: #ffffff; | |
| border-color: #cbd5e1; | |
| box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12); | |
| } | |
| [data-theme="light"] .avatar-sign-info { | |
| background: #f8fafc; | |
| border-top-color: #e2e8f0; | |
| } | |
| [data-theme="light"] .avatar-sign-desc { | |
| color: #64748b; | |
| } | |
| /* Floating Avatar Controls Bar */ | |
| .avatar-controls-bar { | |
| position: absolute; | |
| bottom: 18px; | |
| left: 50%; | |
| transform: translateX(-50%); | |
| display: flex; | |
| align-items: center; | |
| gap: 10px; | |
| padding: 8px 16px; | |
| background: rgb(18 18 20 / 0.88); | |
| backdrop-filter: blur(12px); | |
| border: 1px solid var(--line-bright); | |
| border-radius: var(--r-pill); | |
| box-shadow: 0 8px 32px rgb(0 0 0 / 0.6); | |
| z-index: 10; | |
| min-width: 380px; | |
| max-width: 90%; | |
| } | |
| .avatar-ctrl-btn { | |
| width: 34px; | |
| height: 34px; | |
| display: grid; | |
| place-items: center; | |
| background: var(--surface-3); | |
| border: 1px solid var(--line); | |
| border-radius: 50%; | |
| color: var(--text); | |
| font-size: 0.88rem; | |
| cursor: pointer; | |
| transition: all var(--dur) var(--ease); | |
| flex: none; | |
| } | |
| .avatar-ctrl-btn:hover { | |
| background: var(--accent-soft); | |
| color: var(--accent-text); | |
| border-color: var(--accent-line); | |
| } | |
| .play-pause-btn { | |
| background: var(--accent); | |
| color: #23180a; | |
| border: none; | |
| } | |
| .play-pause-btn:hover { | |
| background: #ffb854; | |
| color: #1a1005; | |
| } | |
| .avatar-progress-wrap { | |
| flex: 1; | |
| display: flex; | |
| align-items: center; | |
| padding-inline: 6px; | |
| } | |
| .avatar-scrubber { | |
| width: 100%; | |
| accent-color: var(--accent); | |
| cursor: pointer; | |
| height: 4px; | |
| } | |
| /* ════ SIGN REFERENCE GUIDE MODAL & PHOTO PREVIEW ═══════════════════════ */ | |
| .guide-btn { | |
| background: var(--surface-2); | |
| border: 1px solid var(--accent-line); | |
| color: var(--accent-text); | |
| font-weight: 500; | |
| } | |
| .guide-btn:hover { | |
| background: var(--accent-soft); | |
| color: #fff; | |
| border-color: var(--accent); | |
| } | |
| .sheet.sheet-wide { | |
| width: min(1040px, calc(100vw - 48px)); | |
| max-height: min(88vh, 880px); | |
| top: 50%; | |
| left: 50%; | |
| right: auto; | |
| bottom: auto; | |
| transform: translate(-50%, -50%) scale(0.96); | |
| padding: 0; | |
| overflow: hidden; | |
| box-shadow: 0 28px 80px rgba(0, 0, 0, 0.55), 0 0 0 1px var(--line-bright); | |
| } | |
| .sheet.sheet-wide:not(:popover-open):not(.open) { | |
| display: none ; | |
| visibility: hidden ; | |
| pointer-events: none ; | |
| opacity: 0 ; | |
| } | |
| .sheet.sheet-wide:popover-open, | |
| .sheet.sheet-wide.open { | |
| display: flex ; | |
| flex-direction: column ; | |
| visibility: visible ; | |
| pointer-events: auto ; | |
| opacity: 1 ; | |
| transform: translate(-50%, -50%) scale(1) ; | |
| } | |
| .sheet-wide .sheet-head { | |
| padding: 20px 28px; | |
| border-bottom: 1px solid var(--line); | |
| display: flex; | |
| align-items: center; | |
| justify-content: space-between; | |
| gap: 16px; | |
| background: var(--surface); | |
| position: sticky; | |
| top: 0; | |
| z-index: 10; | |
| } | |
| .sheet-title-group { | |
| display: flex; | |
| flex-direction: column; | |
| gap: 3px; | |
| } | |
| .sheet-title-group .sheet-title { | |
| font-size: 1.15rem; | |
| font-weight: 700; | |
| color: var(--text); | |
| margin: 0; | |
| } | |
| .sheet-sub { | |
| font-size: 0.8rem; | |
| color: var(--text-dim); | |
| } | |
| .guide-tabs { | |
| display: inline-flex; | |
| gap: 4px; | |
| background: var(--surface-3); | |
| padding: 4px; | |
| border-radius: var(--r-pill); | |
| border: 1px solid var(--line); | |
| } | |
| .guide-tab-btn { | |
| padding: 6px 16px; | |
| border: none; | |
| background: transparent; | |
| color: var(--text-dim); | |
| font-family: var(--font); | |
| font-size: 0.82rem; | |
| font-weight: 600; | |
| border-radius: var(--r-pill); | |
| cursor: pointer; | |
| transition: all var(--dur) var(--ease); | |
| display: inline-flex; | |
| align-items: center; | |
| gap: 6px; | |
| } | |
| .guide-tab-btn:hover { | |
| color: var(--text); | |
| } | |
| .guide-tab-btn.active { | |
| background: var(--accent); | |
| color: #ffffff; | |
| box-shadow: 0 2px 8px color-mix(in oklab, var(--accent) 30%, transparent); | |
| } | |
| .guide-tab-content { | |
| flex: 1; | |
| overflow-y: auto; | |
| padding: 20px 24px 28px; | |
| } | |
| .guide-alert-banner { | |
| display: flex; | |
| align-items: flex-start; | |
| gap: 10px; | |
| padding: 12px 16px; | |
| background: color-mix(in oklab, var(--accent) 10%, var(--surface-2)); | |
| border: 1px solid var(--accent-line); | |
| border-radius: var(--r-ctrl); | |
| color: var(--text); | |
| font-size: 0.82rem; | |
| line-height: 1.45; | |
| margin-bottom: 20px; | |
| } | |
| .guide-alert-banner kbd { | |
| background: var(--surface-3); | |
| padding: 1px 5px; | |
| border-radius: 4px; | |
| border: 1px solid var(--line-bright); | |
| font-family: var(--mono); | |
| font-size: 0.75rem; | |
| } | |
| .banner-icon { | |
| font-size: 1.1rem; | |
| line-height: 1; | |
| } | |
| .guide-section-head { | |
| display: flex; | |
| align-items: center; | |
| justify-content: space-between; | |
| margin-bottom: 12px; | |
| } | |
| .guide-section-title { | |
| font-size: 0.88rem; | |
| font-weight: 600; | |
| color: var(--text); | |
| } | |
| .pill-badge { | |
| font-size: 0.72rem; | |
| font-weight: 600; | |
| padding: 3px 9px; | |
| border-radius: var(--r-pill); | |
| text-transform: uppercase; | |
| letter-spacing: 0.04em; | |
| } | |
| .pill-amber { | |
| background: var(--accent-soft); | |
| color: var(--accent-text); | |
| border: 1px solid var(--accent-line); | |
| } | |
| .pill-blue { | |
| background: color-mix(in oklab, #3b82f6 18%, transparent); | |
| color: #93c5fd; | |
| border: 1px solid color-mix(in oklab, #3b82f6 36%, transparent); | |
| } | |
| .guide-cards-grid { | |
| display: grid; | |
| grid-template-columns: repeat(auto-fill, minmax(130px, 1fr)); | |
| gap: 12px; | |
| } | |
| .guide-card { | |
| background: var(--surface-2); | |
| border: 1px solid var(--line); | |
| border-radius: var(--r-ctrl); | |
| padding: 0; | |
| display: flex; | |
| flex-direction: column; | |
| overflow: hidden; | |
| cursor: pointer; | |
| user-select: none; | |
| transition: transform var(--dur) var(--ease), border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease); | |
| } | |
| .guide-card:hover { | |
| transform: translateY(-2px); | |
| border-color: var(--accent-line); | |
| box-shadow: 0 6px 18px rgba(0, 0, 0, 0.25); | |
| } | |
| .guide-card:active { | |
| transform: scale(0.98); | |
| } | |
| .guide-card-img-wrap { | |
| width: 100%; | |
| aspect-ratio: 1; | |
| background: #000; | |
| position: relative; | |
| overflow: hidden; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| } | |
| .guide-card-img-wrap img { | |
| width: 100%; | |
| height: 100%; | |
| object-fit: cover; | |
| display: block; | |
| } | |
| .guide-card-body { | |
| padding: 8px 10px; | |
| display: flex; | |
| align-items: center; | |
| justify-content: space-between; | |
| background: var(--surface-3); | |
| border-top: 1px solid var(--line); | |
| } | |
| .guide-card-char { | |
| font-family: var(--mono); | |
| font-size: 1.05rem; | |
| font-weight: 700; | |
| color: var(--text); | |
| } | |
| .guide-card-hands { | |
| font-size: 0.65rem; | |
| font-weight: 600; | |
| } | |
| .guide-card-desc { | |
| padding: 6px 10px 10px; | |
| font-size: 0.72rem; | |
| color: var(--text-dim); | |
| line-height: 1.35; | |
| margin: 0; | |
| display: -webkit-box; | |
| -webkit-line-clamp: 2; | |
| -webkit-box-orient: vertical; | |
| overflow: hidden; | |
| } | |
| /* ASL Full Chart view */ | |
| .asl-chart-wrap { | |
| width: 100%; | |
| border-radius: var(--r-ctrl); | |
| overflow: hidden; | |
| border: 1px solid var(--line); | |
| background: #000; | |
| } | |
| .asl-full-chart { | |
| width: 100%; | |
| height: auto; | |
| display: block; | |
| } | |
| /* Practice Studio Real Human Photo Preview Card - permanently disabled on live screen */ | |
| .avatar-photo-ref, | |
| #avatar-photo-ref, | |
| .visually-workspace .avatar-photo-ref, | |
| #live-workspace .avatar-photo-ref, | |
| .hidden .avatar-photo-ref { | |
| display: none ; | |
| visibility: hidden ; | |
| pointer-events: none ; | |
| opacity: 0 ; | |
| width: 0 ; | |
| height: 0 ; | |
| overflow: hidden ; | |
| } | |
| /* ══════════════════════════════════════════════════════════════════════ | |
| SIGN REFERENCE GUIDE MODAL | |
| ══════════════════════════════════════════════════════════════════════ */ | |
| #panel-guide:not(:popover-open):not(.open) { | |
| display: none ; | |
| visibility: hidden ; | |
| pointer-events: none ; | |
| opacity: 0 ; | |
| } | |
| #panel-guide:popover-open, | |
| #panel-guide.open { | |
| display: flex ; | |
| flex-direction: column ; | |
| visibility: visible ; | |
| pointer-events: auto ; | |
| opacity: 1 ; | |
| transform: translate(-50%, -50%) scale(1) ; | |
| } | |
| .asl-chart-wrap { | |
| width: 100%; | |
| border-radius: 10px; | |
| overflow: hidden; | |
| border: 1px solid var(--line); | |
| background: #000; | |
| } | |
| .asl-full-chart { | |
| width: 100%; | |
| display: block; | |
| object-fit: contain; | |
| } | |
| /* ── Light Mode Specific Polish & Theme Toggle ───────────────────────── */ | |
| .theme-toggle-btn { | |
| display: inline-flex; | |
| align-items: center; | |
| justify-content: center; | |
| padding: 6px 10px; | |
| min-width: 36px; | |
| height: 32px; | |
| cursor: pointer; | |
| border-radius: var(--r-ctrl); | |
| border: 1px solid var(--line); | |
| background: var(--surface-2); | |
| color: var(--text); | |
| font-size: 0.95rem; | |
| line-height: 1; | |
| transition: all var(--dur) var(--ease); | |
| } | |
| .theme-toggle-btn:hover { | |
| background: var(--surface-3); | |
| border-color: var(--line-bright); | |
| transform: translateY(-1px); | |
| } | |
| .theme-toggle-btn:active { | |
| transform: scale(0.95); | |
| } | |
| [data-theme="light"] .mode-btn.active { | |
| color: #ffffff; | |
| } | |
| [data-theme="light"] .avatar-viewport { | |
| background: #eaedf4; | |
| } | |
| [data-theme="light"] .guide-card-img-wrap, | |
| [data-theme="light"] .asl-chart-wrap { | |
| background: #f1f3f8; | |
| } | |
| [data-theme="light"] .topbar { | |
| background: #ffffff; | |
| box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05); | |
| } | |
| [data-theme="light"] .sheet { | |
| box-shadow: 0 12px 36px rgba(0, 0, 0, 0.12), 0 2px 8px rgba(0, 0, 0, 0.06); | |
| } | |
| [data-theme="light"] .sheet.sheet-wide { | |
| background: #ffffff; | |
| border-color: #e2e8f0; | |
| box-shadow: 0 24px 60px rgba(0, 0, 0, 0.15), 0 4px 16px rgba(0, 0, 0, 0.08); | |
| } | |
| [data-theme="light"] .sheet-wide .sheet-head { | |
| background: #ffffff; | |
| border-bottom-color: #e2e8f0; | |
| } | |
| [data-theme="light"] .guide-card { | |
| background: #ffffff; | |
| border-color: #e2e8f0; | |
| box-shadow: 0 2px 6px rgba(0, 0, 0, 0.04); | |
| } | |
| [data-theme="light"] .guide-card:hover { | |
| border-color: var(--accent); | |
| box-shadow: 0 6px 18px rgba(0, 0, 0, 0.08); | |
| } | |
| [data-theme="light"] .guide-card-body { | |
| background: #f8fafc; | |
| border-top-color: #e2e8f0; | |
| } | |
| [data-theme="light"] .guide-card-desc { | |
| color: #64748b; | |
| } | |
| [data-theme="light"] .guide-tabs { | |
| background: #f1f5f9; | |
| border-color: #e2e8f0; | |
| } | |
| [data-theme="light"] .guide-tab-btn { | |
| color: #475569; | |
| } | |
| [data-theme="light"] .guide-tab-btn:hover { | |
| color: #0f172a; | |
| } | |
| [data-theme="light"] .guide-tab-btn.active { | |
| background: var(--accent); | |
| color: #ffffff; | |
| } | |
| /* ═══════════════════════════════════════════════════════════════════════════ | |
| SIGN GUIDE LIGHTBOX — fullscreen popup for viewing sign images in detail | |
| Uses native <dialog> to render above popovers in the Top Layer! | |
| ═══════════════════════════════════════════════════════════════════════════ */ | |
| dialog.sign-lightbox-dialog { | |
| border: none; | |
| background: transparent; | |
| padding: 0; | |
| margin: 0; | |
| max-width: 100vw; | |
| max-height: 100vh; | |
| width: 100vw; | |
| height: 100vh; | |
| position: fixed; | |
| inset: 0; | |
| display: none; | |
| align-items: center; | |
| justify-content: center; | |
| z-index: 2147483647; | |
| opacity: 0; | |
| pointer-events: none; | |
| transition: opacity 0.25s ease, transform 0.25s ease; | |
| } | |
| dialog.sign-lightbox-dialog:not([open]) { | |
| display: none ; | |
| pointer-events: none ; | |
| visibility: hidden ; | |
| } | |
| dialog.sign-lightbox-dialog[open] { | |
| display: flex ; | |
| opacity: 1; | |
| pointer-events: auto; | |
| visibility: visible ; | |
| } | |
| dialog.sign-lightbox-dialog::backdrop { | |
| background: rgba(0, 0, 0, 0.78); | |
| backdrop-filter: blur(10px); | |
| -webkit-backdrop-filter: blur(10px); | |
| opacity: 0; | |
| transition: opacity 0.25s ease; | |
| } | |
| dialog.sign-lightbox-dialog[open]::backdrop { | |
| opacity: 1; | |
| } | |
| .sign-lightbox { | |
| position: relative; | |
| display: flex; | |
| flex-direction: column; | |
| align-items: center; | |
| background: var(--surface-1, #1a1a1e); | |
| border: 1px solid var(--line, #2a2a2e); | |
| border-radius: 18px; | |
| padding: 28px 32px 24px; | |
| max-width: 420px; | |
| width: 90vw; | |
| max-height: 90vh; | |
| overflow-y: auto; | |
| box-shadow: 0 30px 80px rgba(0, 0, 0, 0.5), 0 8px 24px rgba(0, 0, 0, 0.3); | |
| transform: scale(0.9) translateY(20px); | |
| transition: transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1); | |
| } | |
| dialog.sign-lightbox-dialog[open] .sign-lightbox { | |
| transform: scale(1) translateY(0); | |
| } | |
| .sign-lightbox-close { | |
| position: absolute; | |
| top: 12px; | |
| right: 14px; | |
| width: 32px; | |
| height: 32px; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| border: 1px solid var(--line, #2a2a2e); | |
| border-radius: 8px; | |
| background: var(--surface-2, #222226); | |
| color: var(--text-dim, #888); | |
| font-size: 1.1rem; | |
| cursor: pointer; | |
| transition: all 0.15s ease; | |
| z-index: 2; | |
| } | |
| .sign-lightbox-close:hover { | |
| background: var(--surface-3, #333); | |
| color: var(--text, #fff); | |
| border-color: var(--accent-line, #e67e22); | |
| } | |
| .sign-lightbox-img-wrap { | |
| width: 100%; | |
| max-width: 340px; | |
| aspect-ratio: 1; | |
| border-radius: 14px; | |
| overflow: hidden; | |
| background: #000; | |
| border: 1px solid var(--line, #2a2a2e); | |
| margin-bottom: 18px; | |
| } | |
| .sign-lightbox-img-wrap img { | |
| width: 100%; | |
| height: 100%; | |
| object-fit: contain; | |
| display: block; | |
| } | |
| .sign-lightbox-letter { | |
| font-family: var(--mono, 'Geist Mono', monospace); | |
| font-size: 2.2rem; | |
| font-weight: 800; | |
| color: var(--text, #fff); | |
| margin-bottom: 4px; | |
| } | |
| .sign-lightbox-type { | |
| display: inline-flex; | |
| align-items: center; | |
| gap: 6px; | |
| padding: 4px 14px; | |
| border-radius: 20px; | |
| font-size: 0.78rem; | |
| font-weight: 600; | |
| margin-bottom: 14px; | |
| } | |
| .sign-lightbox-type.one-hand { | |
| background: rgba(245, 158, 11, 0.15); | |
| color: #f59e0b; | |
| border: 1px solid rgba(245, 158, 11, 0.25); | |
| } | |
| .sign-lightbox-type.two-hand { | |
| background: rgba(59, 130, 246, 0.15); | |
| color: #60a5fa; | |
| border: 1px solid rgba(59, 130, 246, 0.25); | |
| } | |
| .sign-lightbox-desc { | |
| font-size: 0.88rem; | |
| color: var(--text-dim, #999); | |
| line-height: 1.5; | |
| text-align: center; | |
| margin: 0; | |
| padding: 0 8px; | |
| } | |
| .sign-lightbox-lang { | |
| font-size: 0.72rem; | |
| color: var(--text-dim, #666); | |
| margin-top: 14px; | |
| padding-top: 12px; | |
| border-top: 1px solid var(--line, #2a2a2e); | |
| width: 100%; | |
| text-align: center; | |
| text-transform: uppercase; | |
| letter-spacing: 0.08em; | |
| font-weight: 600; | |
| } | |
| /* Light mode adjustments */ | |
| [data-theme="light"] dialog.sign-lightbox-dialog::backdrop { | |
| background: rgba(255, 255, 255, 0.75); | |
| } | |
| [data-theme="light"] .sign-lightbox { | |
| background: #fff; | |
| border-color: #e5e5e5; | |
| box-shadow: 0 30px 80px rgba(0, 0, 0, 0.15), 0 8px 24px rgba(0, 0, 0, 0.08); | |
| } | |
| [data-theme="light"] .sign-lightbox-img-wrap { | |
| background: #f5f5f5; | |
| border-color: #e5e5e5; | |
| } | |
| [data-theme="light"] .sign-lightbox-close { | |
| background: #f0f0f0; | |
| border-color: #ddd; | |
| color: #666; | |
| } | |
| [data-theme="light"] .sign-lightbox-close:hover { | |
| background: #e5e5e5; | |
| color: #333; | |
| } | |
| /* ══════════════════════════════════════════════════════════════════════ | |
| UPLOAD SIGN RECOGNITION STUDIO STYLES | |
| ══════════════════════════════════════════════════════════════════════ */ | |
| .upload-workspace { | |
| grid-template-columns: minmax(320px, 380px) 1fr; | |
| align-items: stretch; | |
| } | |
| .upload-sidebar { | |
| display: flex; | |
| flex-direction: column; | |
| height: 100%; | |
| min-height: 0; | |
| } | |
| .upload-panel { | |
| display: flex; | |
| flex-direction: column; | |
| gap: 16px; | |
| height: 100%; | |
| } | |
| .upload-badge { | |
| font-family: var(--mono); | |
| font-size: 0.62rem; | |
| font-weight: 700; | |
| letter-spacing: 0.1em; | |
| padding: 3px 7px; | |
| border-radius: var(--r-pill); | |
| background: var(--accent-soft); | |
| color: var(--accent-text); | |
| border: 1px solid var(--accent-line); | |
| display: inline-block; | |
| margin-bottom: 4px; | |
| } | |
| .upload-dialect-toggle { | |
| display: flex; | |
| background: var(--surface-3); | |
| padding: 2px; | |
| border-radius: var(--r-pill); | |
| border: 1px solid var(--line); | |
| gap: 2px; | |
| } | |
| .upload-dialect-btn { | |
| padding: 4px 12px; | |
| font-family: var(--font); | |
| font-size: 0.74rem; | |
| font-weight: 600; | |
| border: none; | |
| background: transparent; | |
| color: var(--text-mute); | |
| border-radius: var(--r-pill); | |
| cursor: pointer; | |
| transition: all var(--dur) var(--ease); | |
| } | |
| .upload-dialect-btn:hover { | |
| color: var(--text); | |
| } | |
| .upload-dialect-btn.active { | |
| background: var(--accent); | |
| color: #23180a; | |
| } | |
| [data-theme="light"] .upload-dialect-btn.active { | |
| color: #fff; | |
| } | |
| /* Drag & Drop Area */ | |
| .upload-dropzone { | |
| position: relative; | |
| display: flex; | |
| flex-direction: column; | |
| align-items: center; | |
| justify-content: center; | |
| padding: 28px 18px; | |
| border: 2px dashed var(--line-bright); | |
| border-radius: var(--r-panel); | |
| background: var(--surface-2); | |
| text-align: center; | |
| cursor: pointer; | |
| transition: all var(--dur) var(--ease); | |
| } | |
| .upload-dropzone:hover, | |
| .upload-dropzone.dragover { | |
| border-color: var(--accent); | |
| background: var(--accent-soft); | |
| transform: scale(1.01); | |
| } | |
| .upload-file-hidden { | |
| position: absolute; | |
| inset: 0; | |
| opacity: 0; | |
| cursor: pointer; | |
| width: 100%; | |
| height: 100%; | |
| } | |
| .dropzone-icon { | |
| color: var(--accent); | |
| margin-bottom: 12px; | |
| transition: transform var(--dur) var(--ease); | |
| } | |
| .upload-dropzone:hover .dropzone-icon { | |
| transform: translateY(-3px); | |
| } | |
| .dropzone-title { | |
| font-size: 0.92rem; | |
| font-weight: 600; | |
| color: var(--text); | |
| margin-bottom: 4px; | |
| } | |
| .dropzone-sub { | |
| font-size: 0.8rem; | |
| color: var(--text-dim); | |
| margin-bottom: 8px; | |
| } | |
| .dropzone-browse { | |
| color: var(--accent-text); | |
| text-decoration: underline; | |
| text-underline-offset: 3px; | |
| font-weight: 600; | |
| } | |
| .dropzone-formats { | |
| font-size: 0.68rem; | |
| font-family: var(--mono); | |
| color: var(--text-mute); | |
| } | |
| /* Samples Section */ | |
| .upload-samples-wrap { | |
| display: flex; | |
| flex-direction: column; | |
| gap: 8px; | |
| margin-top: 4px; | |
| } | |
| .upload-samples-label { | |
| font-size: 0.72rem; | |
| font-weight: 600; | |
| text-transform: uppercase; | |
| letter-spacing: 0.06em; | |
| color: var(--text-mute); | |
| } | |
| .upload-samples-chips { | |
| display: flex; | |
| flex-wrap: wrap; | |
| gap: 6px; | |
| } | |
| .sample-img-chip { | |
| padding: 5px 11px; | |
| font-family: var(--mono); | |
| font-size: 0.74rem; | |
| font-weight: 600; | |
| border-radius: var(--r-pill); | |
| border: 1px solid var(--line); | |
| background: var(--surface-3); | |
| color: var(--text-dim); | |
| cursor: pointer; | |
| transition: all var(--dur) var(--ease); | |
| } | |
| .sample-img-chip:hover { | |
| background: var(--accent-soft); | |
| border-color: var(--accent-line); | |
| color: var(--accent-text); | |
| transform: translateY(-1px); | |
| } | |
| /* Upload Stage & Visual Viewport */ | |
| .upload-stage { | |
| display: flex; | |
| flex-direction: column; | |
| height: 100%; | |
| min-height: 0; | |
| } | |
| .upload-viewport { | |
| position: relative; | |
| flex: 1; | |
| width: 100%; | |
| height: 100%; | |
| background: #0e0e11; | |
| border: 1px solid var(--line); | |
| border-radius: var(--r-panel); | |
| overflow: hidden; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| } | |
| [data-theme="light"] .upload-viewport { | |
| background: #f0f2f7; | |
| } | |
| .upload-empty-state { | |
| max-width: 420px; | |
| padding: 32px; | |
| text-align: center; | |
| display: flex; | |
| flex-direction: column; | |
| align-items: center; | |
| gap: 12px; | |
| } | |
| .upload-empty-icon { | |
| font-size: 3.5rem; | |
| margin-bottom: 4px; | |
| animation: floatHand 3s ease-in-out infinite; | |
| } | |
| @keyframes floatHand { | |
| 0%, 100% { transform: translateY(0); } | |
| 50% { transform: translateY(-8px); } | |
| } | |
| .upload-empty-state h3 { | |
| font-size: 1.25rem; | |
| font-weight: 600; | |
| color: var(--text); | |
| } | |
| .upload-empty-state p { | |
| font-size: 0.84rem; | |
| color: var(--text-dim); | |
| line-height: 1.55; | |
| margin-bottom: 6px; | |
| } | |
| .upload-canvas-wrap { | |
| width: 100%; | |
| height: 100%; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| overflow: hidden; | |
| padding: 16px; | |
| box-sizing: border-box; | |
| } | |
| #upload-canvas { | |
| width: auto; | |
| height: auto; | |
| min-width: min(340px, 85%); | |
| min-height: min(340px, 75%); | |
| max-width: 92%; | |
| max-height: 88%; | |
| object-fit: contain; | |
| display: block; | |
| border-radius: 12px; | |
| box-shadow: 0 14px 40px rgba(0, 0, 0, 0.5); | |
| background: #141418; | |
| } | |
| /* Floating Results Card inside Viewport */ | |
| .upload-result-hud { | |
| position: absolute; | |
| top: 18px; | |
| left: 18px; | |
| width: 310px; | |
| max-width: calc(100% - 36px); | |
| background: rgb(18 18 20 / 0.88); | |
| backdrop-filter: blur(14px); | |
| border: 1px solid var(--line-bright); | |
| border-radius: var(--r-panel); | |
| padding: 16px; | |
| box-shadow: 0 16px 36px rgba(0, 0, 0, 0.45); | |
| display: flex; | |
| flex-direction: column; | |
| gap: 14px; | |
| z-index: 10; | |
| animation: hudSlideIn 0.28s cubic-bezier(0.2, 0, 0.2, 1); | |
| } | |
| [data-theme="light"] .upload-result-hud { | |
| background: rgb(255 255 255 / 0.92); | |
| box-shadow: 0 16px 36px rgba(0, 0, 0, 0.12); | |
| } | |
| @keyframes hudSlideIn { | |
| from { opacity: 0; transform: translateY(-8px) scale(0.96); } | |
| to { opacity: 1; transform: translateY(0) scale(1); } | |
| } | |
| .result-hud-header { | |
| display: flex; | |
| align-items: center; | |
| justify-content: space-between; | |
| } | |
| .result-badge-dialect { | |
| font-family: var(--mono); | |
| font-size: 0.72rem; | |
| font-weight: 700; | |
| padding: 2px 8px; | |
| border-radius: var(--r-pill); | |
| background: var(--accent); | |
| color: #23180a; | |
| } | |
| [data-theme="light"] .result-badge-dialect { | |
| color: #fff; | |
| } | |
| .result-badge-hands { | |
| font-size: 0.72rem; | |
| font-weight: 500; | |
| color: var(--text-dim); | |
| } | |
| .result-main-row { | |
| display: flex; | |
| align-items: center; | |
| gap: 16px; | |
| } | |
| .result-letter-huge { | |
| font-family: var(--mono); | |
| font-size: 3.4rem; | |
| font-weight: 700; | |
| line-height: 1; | |
| color: var(--text); | |
| min-width: 64px; | |
| text-align: center; | |
| text-shadow: 0 0 24px color-mix(in oklab, var(--accent) 45%, transparent); | |
| } | |
| .result-details { | |
| display: flex; | |
| flex-direction: column; | |
| gap: 4px; | |
| flex: 1; | |
| } | |
| .result-conf-row { | |
| display: flex; | |
| align-items: baseline; | |
| justify-content: space-between; | |
| } | |
| .result-conf-label { | |
| font-size: 0.72rem; | |
| color: var(--text-mute); | |
| text-transform: uppercase; | |
| letter-spacing: 0.05em; | |
| } | |
| .result-conf-val { | |
| font-family: var(--mono); | |
| font-size: 1rem; | |
| font-weight: 700; | |
| color: var(--accent-text); | |
| } | |
| .result-desc { | |
| font-size: 0.76rem; | |
| color: var(--text-dim); | |
| line-height: 1.35; | |
| } | |
| /* Top 3 Breakdown */ | |
| .result-top3-section { | |
| display: flex; | |
| flex-direction: column; | |
| gap: 8px; | |
| border-top: 1px solid var(--line); | |
| padding-top: 10px; | |
| } | |
| .result-top3-title { | |
| font-size: 0.68rem; | |
| font-weight: 600; | |
| text-transform: uppercase; | |
| letter-spacing: 0.06em; | |
| color: var(--text-mute); | |
| } | |
| .result-top3-bars { | |
| display: flex; | |
| flex-direction: column; | |
| gap: 6px; | |
| } | |
| .top3-row { | |
| display: flex; | |
| align-items: center; | |
| gap: 8px; | |
| font-size: 0.75rem; | |
| } | |
| .top3-label { | |
| font-family: var(--mono); | |
| font-weight: 700; | |
| min-width: 22px; | |
| color: var(--text); | |
| } | |
| .top3-bar-track { | |
| flex: 1; | |
| height: 6px; | |
| background: var(--surface-3); | |
| border-radius: var(--r-pill); | |
| overflow: hidden; | |
| } | |
| .top3-bar-fill { | |
| height: 100%; | |
| border-radius: inherit; | |
| background: var(--accent); | |
| transition: width 0.35s ease; | |
| } | |
| .top3-val { | |
| font-family: var(--mono); | |
| font-size: 0.7rem; | |
| color: var(--text-dim); | |
| min-width: 38px; | |
| text-align: right; | |
| } | |