/** * Spaxel Dashboard - 3D Scene Styles * * 3D scene layout with responsive canvas sizing. * Handles iOS Safari visual viewport quirks and bottom navigation spacing. * * WCAG 2.1 Touch Target Compliance: * - All interactive elements meet minimum 44x44px touch target size * - Touch targets are expanded using padding or pseudo-elements where needed */ /* ===== WCAG 2.1 Touch Target Compliance Utilities ===== */ /* Touch target expansion for small checkboxes */ .panel-form-checkbox input[type="checkbox"], .pattern-checkbox input[type="checkbox"], .timeline-category-checkbox input[type="checkbox"], .sim-gdop-controls input[type="checkbox"] { /* Ensure checkbox touch area is 44x44px minimum */ width: 18px; height: 18px; min-width: 18px; min-height: 18px; position: relative; } /* Expand checkbox hit area with pseudo-element */ .panel-form-checkbox input[type="checkbox"]::before, .pattern-checkbox input[type="checkbox"]::before, .timeline-category-checkbox input[type="checkbox"]::before, .sim-gdop-controls input[type="checkbox"]::before { content: ''; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 44px; height: 44px; border-radius: 50%; } /* Expand small toggle switches to 44px height */ .toggle-switch { min-height: 44px; } .toggle-switch .slider { min-height: 44px; height: 44px; } .toggle-switch .slider:before { width: 36px; height: 36px; top: var(--space-1); left: var(--space-1); } .toggle-switch input:checked + .slider:before { transform: translateX(22px); } /* Expand slider thumb touch area */ .panel-form-group input[type="range"] { height: 44px; /* Full touch target height */ background: transparent; cursor: pointer; } .panel-form-group input[type="range"]::-webkit-slider-runnable-track { height: 6px; background: var(--bg-hover); border-radius: var(--radius-control); margin: 19px; /* Center track within 44px height */ } .panel-form-group input[type="range"]::-webkit-slider-thumb { -webkit-appearance: none; appearance: none; width: 32px; height: 32px; background: var(--blue-10); border-radius: 50%; cursor: pointer; margin-top: -13px; /* Center thumb on track */ transition: transform 0.1s; } .panel-form-group input[type="range"]::-webkit-slider-thumb:hover { transform: scale(1.15); } .panel-form-group input[type="range"]::-moz-range-track { height: 6px; background: var(--bg-hover); border-radius: var(--radius-control); } .panel-form-group input[type="range"]::-moz-range-thumb { width: 32px; height: 32px; background: var(--blue-10); border-radius: 50%; cursor: pointer; border: none; } /* Expand close button touch targets to 44x44px */ .panel-close, .modal-close, .panel-modal-close, .sim-close-btn { min-width: 44px; min-height: 44px; width: 44px; height: 44px; font-size: var(--text-3xl); line-height: 44px; padding: 0; } /* Expand context menu items to 44px minimum height */ .context-item, .blob-context-menu-item { min-height: 44px; padding: var(--space-3) var(--space-4); } /* Expand link list items to 44px minimum */ .link-item { min-height: 44px; padding: var(--space-3) var(--space-4); font-size: var(--text-sm); } /* Ensure all buttons meet 44x44px minimum */ .panel-btn, .modal-btn, .btn, .sim-btn, .alert-banner-btn, .timeline-filter-toggle, .timeline-load-more-btn, .view-btn, #floorplan-btn, .node-identify-btn { min-height: 44px; min-width: 44px; padding: var(--space-3) var(--space-5); font-size: var(--text-sm); } /* Small buttons: expand with padding while keeping appearance compact */ .btn-sm, .timeline-feedback-btn, .timeline-seek-btn { min-height: 44px; min-width: 44px; padding: 14px var(--space-3); /* Extra vertical padding to reach 44px */ } /* Volume tools buttons */ .volume-tools button { min-height: 44px; min-width: 44px; padding: var(--space-3) var(--space-4); } /* Hamburger tabs - ensure 44px minimum */ .hamburger-tab { min-height: 44px; min-width: 44px; } /* Hamburger items - already 44px, ensure explicit */ .hamburger-item { min-height: 44px; padding: var(--space-3) var(--space-4); } /* Toast dismiss button */ .toast-dismiss { min-width: 44px; min-height: 44px; width: 44px; height: 44px; font-size: var(--text-xl); } /* Action items */ .action-item .action-remove { min-width: 44px; min-height: 44px; padding: var(--space-3) var(--space-2); font-size: var(--text-sm); } /* Sim item delete button */ .sim-item-delete { min-height: 44px; min-width: 44px; padding: var(--space-3) var(--space-4); } /* Form controls */ .panel-form-group input[type="text"], .panel-form-group input[type="number"], .panel-form-group input[type="password"], .panel-form-group input[type="email"], .panel-form-group input[type="url"], .panel-form-group select, .panel-form-group textarea, .panel-input, .form-control, .timeline-filter-select, .timeline-search, .timeline-date-input { min-height: 44px; padding: var(--space-3) var(--space-4); } /* ===== Scene Container (3D Canvas) — grid child ===== #scene-container lives inside .app-main (the grid main area). It fills its parent via width/height: 100% instead of position:fixed. */ #scene-container { width: 100%; height: 100%; touch-action: none; z-index: 1; /* Mobile-specific touch handling improvements */ -webkit-touch-callout: none; -webkit-user-select: none; user-select: none; /* Prevent iOS Safari from delaying single taps */ -webkit-tap-highlight-color: transparent; } /* iOS Safari-specific handling for visual viewport */ @supports (-webkit-touch-callout: none) { /* iOS Safari with visual viewport API */ #scene-container { /* Use dynamic viewport height on iOS (handles address bar) */ height: 100dvh; } } /* iOS Safari orientation change handling */ @supports (-webkit-touch-callout: none) { body { -webkit-text-size-adjust: 100%; } } /* Ensure canvas doesn't overflow during transitions */ #scene-container canvas { display: block; max-width: 100%; max-height: 100%; touch-action: none; /* Mobile-specific touch handling improvements */ -webkit-touch-callout: none; -webkit-user-select: none; user-select: none; -webkit-tap-highlight-color: transparent; } /* Handle visual viewport resize events (iOS Safari keyboard, address bar) */ .visual-viewport-resizing #scene-container { pointer-events: none; } /* ===== Status Bar — grid header via layout.css ===== When #status-bar is a direct child of .app-shell--live, it is the grid header. Uses position:sticky to stay visible during scroll. */ #status-bar { position: sticky; top: 0; z-index: 100; } /* ===== Alert Banner — full-width overlay ===== */ #alert-banner { position: fixed; top: 0; left: 0; right: 0; z-index: 5000; } /* ===== Orientation-specific adjustments ===== */ /* Landscape orientation */ @media screen and (orientation: landscape) { #scene-container { height: 100%; height: 100dvh; } } /* Portrait orientation */ @media screen and (orientation: portrait) { #scene-container { height: 100%; height: 100dvh; } } /* ===== Responsive breakpoints ===== */ /* Small mobile devices */ @media screen and (max-width: 600px) { #scene-container { height: 100%; height: 100dvh; } } /* Tablets and larger */ @media screen and (min-width: 601px) { #scene-container { height: 100%; height: 100dvh; } } /* ===== Safe area insets for notched devices ===== */ @supports (padding: max(0px)) { body { padding-top: env(safe-area-inset-top); padding-bottom: env(safe-area-inset-bottom); } #scene-container { padding-left: env(safe-area-inset-left); padding-right: env(safe-area-inset-right); } #scene-container { height: calc(100% - env(safe-area-inset-top) - env(safe-area-inset-bottom)); height: calc(100dvh - env(safe-area-inset-top) - env(safe-area-inset-bottom)); } } /* ===== Prevent overscroll/bounce on iOS ===== */ @supports (-webkit-touch-callout: none) { #scene-container { -webkit-overflow-scrolling: touch; overscroll-behavior: none; } } /* ===== Loading state ===== */ #scene-container.loading { opacity: 0.5; pointer-events: none; transition: opacity 0.3s ease; }