spaxel/dashboard/css/quick-actions.css
jedarden 07abc03ef4 style(dashboard): complete design token migration and live view cleanup
Replace remaining hard-coded colors across all CSS files with design
tokens from tokens.css. Remove duplicate inline positioning from
live.html panels (now in layout.css). Add replay session blob fetch
for immediate 3D scene state on seek.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-24 16:39:53 -04:00

294 lines
6.3 KiB
CSS

/**
* Spaxel Dashboard - Spatial Quick Actions Styles
*
* Right-click (desktop) or long-press (mobile) context menus
* on 3D elements for context-sensitive actions.
*/
/* ===== Context Menu Container ===== */
.context-menu {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 1000;
display: none;
}
.context-menu.visible {
display: block;
}
.context-backdrop {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: var(--shadow-lg);
backdrop-filter: blur(2px);
-webkit-backdrop-filter: blur(2px);
animation: fadeIn 0.15s ease-out;
}
/* ===== Safe Area Insets for iOS ===== */
@supports (padding: max(0px)) {
.context-menu {
/* Respect safe area insets for notched devices */
padding-top: env(safe-area-inset-top);
padding-bottom: env(safe-area-inset-bottom);
padding-left: env(safe-area-inset-left);
padding-right: env(safe-area-inset-right);
}
.follow-mode-indicator {
/* Adjust bottom position to account for safe area */
bottom: calc(80px + env(safe-area-inset-bottom));
}
@media (max-width: 600px) {
.follow-mode-indicator {
bottom: calc(100px + env(safe-area-inset-bottom));
}
}
}
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
/* ===== Context Container ===== */
.context-container {
position: absolute;
min-width: 280px;
max-width: 340px;
background: var(--context-bg, var(--bg-card));
border-radius: var(--radius-card);
box-shadow: 0 8px 32px var(--shadow-xl);
border: 1px solid var(--context-border, var(--bg-hover));
display: flex;
flex-direction: column;
overflow: hidden;
animation: scaleIn 0.15s ease-out;
}
@keyframes scaleIn {
from {
opacity: 0;
transform: scale(0.95);
}
to {
opacity: 1;
transform: scale(1);
}
}
/* ===== Context Header ===== */
.context-header {
display: flex;
align-items: center;
gap: var(--space-3);
padding: 14px var(--space-4);
border-bottom: 1px solid var(--context-border, var(--bg-hover));
background: var(--context-header-bg, var(--border-subtle));
}
.context-icon {
font-size: 22px;
flex-shrink: 0;
width: 32px;
height: 32px;
display: flex;
align-items: center;
justify-content: center;
background: var(--context-icon-bg, var(--blue-muted));
border-radius: var(--radius-card);
}
.context-title {
flex: 1;
font-size: var(--text-md);
font-weight: 600;
color: var(--context-text, var(--slate-12));
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
/* ===== Context Body ===== */
.context-body {
max-height: 400px;
overflow-y: auto;
overflow-x: hidden;
}
.context-body::-webkit-scrollbar {
width: 6px;
}
.context-body::-webkit-scrollbar-track {
background: transparent;
}
.context-body::-webkit-scrollbar-thumb {
background: var(--border-strong);
border-radius: var(--radius-control);
}
.context-body::-webkit-scrollbar-thumb:hover {
background: var(--slate-7);
}
/* ===== Context Items ===== */
.context-item {
display: flex;
align-items: flex-start;
gap: var(--space-3);
padding: var(--space-3) var(--space-4);
cursor: pointer;
transition: background 0.15s ease;
border-left: 3px solid transparent;
}
.context-item:hover {
background: var(--context-hover, var(--border-subtle));
}
.context-item:active {
background: var(--context-active, var(--border-default));
}
.item-icon {
font-size: var(--text-xl);
flex-shrink: 0;
width: 24px;
text-align: center;
padding-top: 2px;
}
.item-content {
flex: 1;
min-width: 0;
}
.item-label {
font-size: var(--text-sm);
font-weight: 500;
color: var(--context-text, var(--slate-12));
margin-bottom: 2px;
}
.item-description {
font-size: var(--text-xs);
color: var(--context-description, var(--text-muted));
line-height: 1.3;
}
/* ===== Target-Specific Styling ===== */
/* Blob/Person context */
.context-menu[data-target="blob"] .context-icon {
background: var(--blue-muted);
color: var(--blue-10);
}
/* Node context */
.context-menu[data-target="node"] .context-icon {
background: var(--ok-bg);
color: var(--ok);
}
/* Zone context */
.context-menu[data-target="zone"] .context-icon {
background: var(--warn-bg);
color: var(--warn);
}
/* Empty space context */
.context-menu[data-target="empty"] .context-icon {
background: var(--bg-active);
color: var(--slate-10);
}
/* Portal context */
.context-menu[data-target="portal"] .context-icon {
background: var(--blue-muted);
color: var(--blue-8);
}
/* Trigger context */
.context-menu[data-target="trigger"] .context-icon {
background: var(--alert-bg);
color: var(--alert);
}
/* ===== Follow Mode Indicator ===== */
.follow-mode-indicator {
position: fixed;
bottom: 80px;
left: 50%;
transform: translateX(-50%);
background: var(--blue-10);
color: var(--text-on-accent);
padding: 10px var(--space-5);
border-radius: var(--radius-modal);
font-size: var(--text-sm);
font-weight: 500;
display: flex;
align-items: center;
gap: var(--space-2);
z-index: 999;
animation: slideUp 0.2s ease-out;
pointer-events: none;
}
.follow-mode-indicator::before {
content: '🎯';
}
@keyframes slideUp {
from {
opacity: 0;
transform: translate(-50%, 20px);
}
to {
opacity: 1;
transform: translate(-50%, 0);
}
}
/* ===== Responsive Design ===== */
@media (max-width: 600px) {
.context-container {
min-width: 260px;
max-width: 90vw;
}
.context-item {
padding: 14px var(--space-4);
}
.follow-mode-indicator {
bottom: 100px;
padding: var(--space-3) var(--space-6);
font-size: var(--text-md);
}
}
/* ===== Accessibility ===== */
.context-item:focus-visible {
outline: 2px solid var(--context-accent, var(--blue-10));
outline-offset: -2px;
}
/* ===== Reduced Motion ===== */
@media (prefers-reduced-motion: reduce) {
.context-menu * {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}