@import 'tailwind/_base.css'; @import 'tailwind/_components.css'; @import 'tailwind/_utilities.css'; @import 'intro.js/introjs.css'; @import '_checkbox-radio-switch.css'; @import '_progress.css'; @import '_scrollbars.css'; @import '_table.css'; @import '_helper.css'; @import '_calendar.css'; @import '_select-dropdown.css'; @import '_theme.css'; @import '_rich-text.css'; /* ═══════════════════════════════════════════════════════════════════ Custom Font Declarations ═══════════════════════════════════════════════════════════════════ */ @font-face { font-family: 'Maple'; src: url('/fonts/MapleMedium.otf') format('opentype'); } /* Page transition timing - single source of truth */ :root { --crossfade-duration: 700ms; /* Smooth easing: slow start, gentle acceleration, soft landing */ /* Chrome/Firefox: Material Design standard easing */ --crossfade-easing: cubic-bezier(0.4, 0, 0.2, 1); } /* Safari-specific easing - Safari's bezier curve rendering is different, use a simpler curve that Safari handles more smoothly */ @supports (-webkit-touch-callout: none) { :root { /* Safari: use ease-in-out which Safari renders more consistently */ --crossfade-easing: cubic-bezier(0.42, 0, 0.58, 1); } } /* Firefox-specific optimizations */ @-moz-document url-prefix() { :root { /* Firefox handles the standard easing well, but we can optimize */ --crossfade-easing: cubic-bezier(0.4, 0, 0.2, 1); } } .introjs-tooltip { @apply min-w-[400px] max-w-[480px] p-2 !important; } .good-img { @apply -mt-96 !important; } .end-img { @apply -mt-72 !important; } .introjs-button { @apply bg-blue-600 text-white !important; text-shadow: none !important; } .introjs-bullets ul li a.active { @apply bg-blue-600 !important; } .introjs-prevbutton { @apply bg-transparent border border-blue-600 text-blue-600 !important; } /* Page crossfade animation keyframes - Safari optimized */ @-webkit-keyframes page-crossfade-in { from { opacity: 0; -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0); } to { opacity: 1; -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0); } } @keyframes page-crossfade-in { from { opacity: 0; transform: translate3d(0, 0, 0); } to { opacity: 1; transform: translate3d(0, 0, 0); } } @-webkit-keyframes page-crossfade-out { from { opacity: 1; -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0); } to { opacity: 0; -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0); } } @keyframes page-crossfade-out { from { opacity: 1; transform: translate3d(0, 0, 0); } to { opacity: 0; transform: translate3d(0, 0, 0); } } /* Fade from black animation - black overlay fades out 1 → 0 */ /* Page has already switched, black covers it then reveals new content */ @keyframes fade-from-black { 0% { opacity: 1; } 100% { opacity: 0; } } /* Crossfade animation classes - GPU accelerated for all browsers */ /* Duration controlled by --transition-duration (from JS) or --crossfade-duration (CSS variable) */ /* This allows the hierarchical transition settings to override the default CSS duration */ .animate-crossfade-in { /* Explicit initial state prevents flash during animation setup */ opacity: 0; -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0); /* Full animation property for maximum browser compatibility */ -webkit-animation-name: page-crossfade-in; animation-name: page-crossfade-in; -webkit-animation-duration: var(--transition-duration, var(--crossfade-duration, 700ms)); animation-duration: var(--transition-duration, var(--crossfade-duration, 700ms)); -webkit-animation-timing-function: var( --transition-easing, var(--crossfade-easing, cubic-bezier(0.4, 0, 0.2, 1)) ); animation-timing-function: var( --transition-easing, var(--crossfade-easing, cubic-bezier(0.4, 0, 0.2, 1)) ); -webkit-animation-fill-mode: forwards; animation-fill-mode: forwards; -webkit-animation-play-state: running; animation-play-state: running; -webkit-backface-visibility: hidden; backface-visibility: hidden; /* Optimize compositing */ will-change: opacity; contain: layout style paint; } .animate-crossfade-out { /* Explicit initial state prevents flash during animation setup */ opacity: 1; -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0); /* Full animation property for maximum browser compatibility */ -webkit-animation-name: page-crossfade-out; animation-name: page-crossfade-out; -webkit-animation-duration: var(--transition-duration, var(--crossfade-duration, 700ms)); animation-duration: var(--transition-duration, var(--crossfade-duration, 700ms)); -webkit-animation-timing-function: var( --transition-easing, var(--crossfade-easing, cubic-bezier(0.4, 0, 0.2, 1)) ); animation-timing-function: var( --transition-easing, var(--crossfade-easing, cubic-bezier(0.4, 0, 0.2, 1)) ); -webkit-animation-fill-mode: forwards; animation-fill-mode: forwards; -webkit-animation-play-state: running; animation-play-state: running; -webkit-backface-visibility: hidden; backface-visibility: hidden; /* Optimize compositing */ will-change: opacity; contain: layout style paint; } /* Safari-specific GPU compositing optimization */ @supports (-webkit-touch-callout: none) { .animate-crossfade-in, .animate-crossfade-out { /* Force GPU layer creation in Safari */ -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0); /* Isolate the layer for better compositing */ isolation: isolate; /* Use will-change instead of perspective for GPU acceleration */ will-change: opacity, transform; } } /* Firefox-specific optimizations */ @-moz-document url-prefix() { .animate-crossfade-in, .animate-crossfade-out { /* Firefox handles animations well but benefits from layer isolation */ will-change: opacity, transform; } } /* Fade from black animation class - for smooth page transitions via black overlay */ /* Black starts opaque (hiding page switch), then fades out to reveal new page */ .animate-fade-from-black { opacity: 1; -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0); -webkit-animation-name: fade-from-black; animation-name: fade-from-black; -webkit-animation-duration: var(--transition-duration, var(--crossfade-duration, 700ms)); animation-duration: var(--transition-duration, var(--crossfade-duration, 700ms)); -webkit-animation-timing-function: var( --transition-easing, var(--crossfade-easing, cubic-bezier(0.4, 0, 0.2, 1)) ); animation-timing-function: var( --transition-easing, var(--crossfade-easing, cubic-bezier(0.4, 0, 0.2, 1)) ); -webkit-animation-fill-mode: forwards; animation-fill-mode: forwards; -webkit-backface-visibility: hidden; backface-visibility: hidden; will-change: opacity; contain: layout style paint; } /* Transition-based crossfade (Safari-optimized alternative to animations) */ /* Use this for better Safari stability - transitions don't have the "snap" issue when state changes because they interpolate between current and target values */ .crossfade-transition { transition: opacity var(--crossfade-duration, 700ms) var(--crossfade-easing, cubic-bezier(0.4, 0, 0.2, 1)); -webkit-transition: opacity var(--crossfade-duration, 700ms) var(--crossfade-easing, cubic-bezier(0.4, 0, 0.2, 1)); -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0); -webkit-backface-visibility: hidden; backface-visibility: hidden; will-change: opacity; } /* Safari-specific optimization for transitions */ @supports (-webkit-touch-callout: none) { .crossfade-transition { isolation: isolate; will-change: opacity, transform; } } /* ============================================================= Page Transition Animations (Slide, Zoom) These animations support the hierarchical transition settings: Global → Project → Element cascade with configurable: - Duration: --transition-duration CSS variable - Easing: --transition-easing CSS variable - Overlay Color: --overlay-color CSS variable (used by TransitionBlackOverlay) Animation classes use these variables when present, falling back to --crossfade-duration/--crossfade-easing for compatibility. ============================================================= */ /* Element appear animation keyframes - Safari optimized */ @-webkit-keyframes element-fade-in { from { opacity: 0; -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0); } to { opacity: 1; -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0); } } @keyframes element-fade-in { from { opacity: 0; transform: translate3d(0, 0, 0); } to { opacity: 1; transform: translate3d(0, 0, 0); } } @-webkit-keyframes element-slide-up { from { opacity: 0; -webkit-transform: translate3d(0, 20px, 0); transform: translate3d(0, 20px, 0); } to { opacity: 1; -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0); } } @keyframes element-slide-up { from { opacity: 0; transform: translate3d(0, 20px, 0); } to { opacity: 1; transform: translate3d(0, 0, 0); } } @-webkit-keyframes element-slide-down { from { opacity: 0; -webkit-transform: translate3d(0, -20px, 0); transform: translate3d(0, -20px, 0); } to { opacity: 1; -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0); } } @keyframes element-slide-down { from { opacity: 0; transform: translate3d(0, -20px, 0); } to { opacity: 1; transform: translate3d(0, 0, 0); } } @-webkit-keyframes element-slide-left { from { opacity: 0; -webkit-transform: translate3d(20px, 0, 0); transform: translate3d(20px, 0, 0); } to { opacity: 1; -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0); } } @keyframes element-slide-left { from { opacity: 0; transform: translate3d(20px, 0, 0); } to { opacity: 1; transform: translate3d(0, 0, 0); } } @-webkit-keyframes element-slide-right { from { opacity: 0; -webkit-transform: translate3d(-20px, 0, 0); transform: translate3d(-20px, 0, 0); } to { opacity: 1; -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0); } } @keyframes element-slide-right { from { opacity: 0; transform: translate3d(-20px, 0, 0); } to { opacity: 1; transform: translate3d(0, 0, 0); } } @-webkit-keyframes element-scale-in { from { opacity: 0; -webkit-transform: scale3d(0.8, 0.8, 1); transform: scale3d(0.8, 0.8, 1); } to { opacity: 1; -webkit-transform: scale3d(1, 1, 1); transform: scale3d(1, 1, 1); } } @keyframes element-scale-in { from { opacity: 0; transform: scale3d(0.8, 0.8, 1); } to { opacity: 1; transform: scale3d(1, 1, 1); } } /* Instrument Sans font utilities */ .font-instrument-condensed { font-family: 'Instrument Sans Variable', sans-serif; font-stretch: 75%; } .font-instrument { font-family: 'Instrument Sans Variable', sans-serif; font-stretch: 100%; } /* iOS Safari: Hide native video play button overlay These selectors target WebKit-specific pseudo-elements that appear when autoplay is blocked or when iOS detects an unmuted video */ video::-webkit-media-controls-start-playback-button { display: none !important; -webkit-appearance: none; } video::-webkit-media-controls-overlay-play-button { display: none !important; -webkit-appearance: none; } /* Prevent controls from appearing on autoplay fail */ video::-webkit-media-controls-panel { display: none !important; -webkit-appearance: none; } video::-webkit-media-controls { display: none !important; }