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>
294 lines
6.3 KiB
CSS
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;
|
|
}
|
|
}
|
|
|