diff --git a/theme/assets/css/main.css b/theme/assets/css/main.css index d1275f4..6ccbe1d 100644 --- a/theme/assets/css/main.css +++ b/theme/assets/css/main.css @@ -125,7 +125,8 @@ a:hover { color: var(--color-primary); } 60% { transform: scale(1.2); opacity: 1; } 100% { transform: scale(1); } } -.feature-icon.icon-pop { +.feature-icon.icon-pop, +.value-icon.icon-pop { animation: icon-pop 0.4s ease-out backwards; } @@ -146,15 +147,17 @@ a:hover { color: var(--color-primary); } from { transform: rotate(0deg); } to { transform: rotate(360deg); } } -/* Float + ring on all feature icons (but only once the card has +/* Float + ring on all feature/value icons (but only once the card has scroll-revealed — the .is-animated class is set by demo-animator.js). */ -.oribi-card.is-animated .feature-icon { +.oribi-card.is-animated .feature-icon, +.oribi-card.is-animated .value-icon { animation: icon-float 3.6s ease-in-out infinite, icon-ring 3.6s ease-out infinite; } /* Pause ambient animation during hover so the scale transform - from .oribi-card:hover .feature-icon takes over cleanly. */ -.oribi-card:hover .feature-icon { + from .oribi-card:hover .feature-icon / .value-icon takes over cleanly. */ +.oribi-card:hover .feature-icon, +.oribi-card:hover .value-icon { animation: none; } /* Cog icons spin slowly — contextually appropriate regardless of card. */ @@ -164,7 +167,8 @@ a:hover { color: var(--color-primary); } } /* Respect reduced-motion preference. */ @media (prefers-reduced-motion: reduce) { - .oribi-card.is-animated .feature-icon { animation: none; } + .oribi-card.is-animated .feature-icon, + .oribi-card.is-animated .value-icon { animation: none; } .feature-icon .fa-cog, .feature-icon .fa-users-cog { animation: none; } } @@ -3888,13 +3892,12 @@ p:last-child { margin-bottom: 0; } .pkg-stage { display: flex; align-items: center; - justify-content: space-between; + justify-content: center; + gap: 2rem; width: 100%; max-width: 400px; margin: 0 auto; padding: 2rem 0; - position: relative; - color: var(--color-primary); } .pkg-node { @@ -3903,7 +3906,6 @@ p:last-child { margin-bottom: 0; } align-items: center; gap: 0.45rem; flex-shrink: 0; - z-index: 2; } .pkg-node__label { @@ -3914,6 +3916,15 @@ p:last-child { margin-bottom: 0; } text-transform: uppercase; } +.pkg-plus { + font-size: 2rem; + font-weight: 300; + color: var(--color-primary); + line-height: 1; + flex-shrink: 0; + margin-bottom: 1.1rem; /* align with device bodies above label */ +} + /* ── Player device ────────────────────────────────────────── */ .pkg-player { display: flex; @@ -3987,85 +3998,6 @@ p:last-child { margin-bottom: 0; } 40%, 60% { opacity: 0.25; box-shadow: none; } } -/* ── Bundle box ───────────────────────────────────────────── */ -.pkg-box { - display: flex; - flex-direction: column; - align-items: center; -} - -.pkg-box__lids { - display: flex; - width: 76px; - gap: 3px; - perspective: 80px; -} - -.pkg-box__flap { - flex: 1; - height: 14px; - background: var(--color-primary-dk, #A22702); - border-radius: 3px 3px 0 0; -} - -.pkg-box__flap--l { - transform-origin: bottom center; - animation: pkg-flap-l 6s ease-in-out infinite; -} - -.pkg-box__flap--r { - transform-origin: bottom center; - animation: pkg-flap-r 6s ease-in-out infinite; -} - -@keyframes pkg-flap-l { - 0%, 10% { transform: rotateX(0deg); } - 28%, 72% { transform: rotateX(-110deg); } - 90%, 100% { transform: rotateX(0deg); } -} - -@keyframes pkg-flap-r { - 0%, 12% { transform: rotateX(0deg); } - 30%, 74% { transform: rotateX(-110deg); } - 92%, 100% { transform: rotateX(0deg); } -} - -.pkg-box__body { - width: 76px; - height: 68px; - background: var(--color-primary); - border-radius: 0 0 6px 6px; - position: relative; - overflow: hidden; - animation: pkg-box-glow 6s ease-in-out infinite; -} - -/* Tape stripe */ -.pkg-box__body::before { - content: ''; - position: absolute; - top: 0; bottom: 0; - left: 50%; - transform: translateX(-50%); - width: 13px; - background: rgba(255,255,255,.18); -} - -/* Horizontal fold line */ -.pkg-box__body::after { - content: ''; - position: absolute; - top: 32px; left: 8px; right: 8px; - height: 1px; - background: rgba(0,0,0,.15); -} - -@keyframes pkg-box-glow { - 0%, 25% { box-shadow: 0 6px 18px rgba(var(--color-primary-rgb), .25); } - 45%, 65% { box-shadow: 0 6px 34px rgba(var(--color-primary-rgb), .55); } - 85%, 100% { box-shadow: 0 6px 18px rgba(var(--color-primary-rgb), .25); } -} - /* ── TV / Display ─────────────────────────────────────────── */ .pkg-tv { display: flex; @@ -4114,81 +4046,13 @@ p:last-child { margin-bottom: 0; } border-radius: 0 0 3px 3px; } -/* ── Connecting lines ─────────────────────────────────────── */ -.pkg-line { - flex-grow: 1; - height: 2px; - background: rgba(var(--color-primary-rgb), .18); - margin: 0 1rem; - position: relative; - display: flex; - align-items: center; - overflow: hidden; - border-radius: 2px; -} - -[data-theme="dark"] .pkg-line { - background: rgba(255,255,255,.1); -} - -.pkg-pkt { - width: 10px; - height: 4px; - background: var(--color-primary); - border-radius: 4px; - position: absolute; - left: -12px; - box-shadow: 0 0 6px var(--color-primary); -} - -[data-theme="dark"] .pkg-pkt { - background: #fff; - box-shadow: 0 0 6px rgba(255,255,255,.7); -} - -/* LTR packets (player → box) */ -.pkg-pkt--ltr-1 { animation: pkg-travel-ltr 2s linear infinite; } -.pkg-pkt--ltr-2 { animation: pkg-travel-ltr 2s linear infinite 0.65s; } -.pkg-pkt--ltr-3 { animation: pkg-travel-ltr 2s linear infinite 1.3s; } - -@keyframes pkg-travel-ltr { - 0% { left: -12px; opacity: 0; } - 8% { opacity: 1; } - 92% { opacity: 1; } - 100% { left: 100%; opacity: 0; } -} - -/* RTL packets (display → box) */ -.pkg-pkt--rtl-1 { animation: pkg-travel-rtl 2s linear infinite; } -.pkg-pkt--rtl-2 { animation: pkg-travel-rtl 2s linear infinite 0.65s; } -.pkg-pkt--rtl-3 { animation: pkg-travel-rtl 2s linear infinite 1.3s; } - -@keyframes pkg-travel-rtl { - 0% { left: calc(100% + 12px); opacity: 0; } - 8% { opacity: 1; } - 92% { opacity: 1; } - 100% { left: -12px; opacity: 0; } -} - @media (prefers-reduced-motion: reduce) { .pkg-player__led, - .pkg-box__flap--l, - .pkg-box__flap--r, - .pkg-box__body, - .pkg-pkt, .pkg-tv__screen::after { animation: none; } - .pkg-box__flap--l, - .pkg-box__flap--r { transform: rotateX(-90deg); } - .pkg-pkt--ltr-1 { left: 15%; opacity: 1; } - .pkg-pkt--ltr-2 { left: 50%; opacity: 1; } - .pkg-pkt--ltr-3 { left: 75%; opacity: 1; } - .pkg-pkt--rtl-1 { left: 75%; opacity: 1; } - .pkg-pkt--rtl-2 { left: 50%; opacity: 1; } - .pkg-pkt--rtl-3 { left: 15%; opacity: 1; } } @media (max-width: 640px) { - .pkg-stage { max-width: 300px; } + .pkg-stage { max-width: 300px; gap: 1.5rem; } } diff --git a/theme/assets/js/demo-animator.js b/theme/assets/js/demo-animator.js index 23b52fa..a883663 100644 --- a/theme/assets/js/demo-animator.js +++ b/theme/assets/js/demo-animator.js @@ -1,22 +1,24 @@ /** * Feature Section Card Animator - * Staggered scroll-reveal entrance + icon pop-in for .feature-section cards. + * Staggered scroll-reveal entrance + icon pop-in for .feature-section and + * .value-section cards, plus stagger for .platform-row elements. * Coordinates with the main.js scroll-hidden/visible system: - * 1. Sets --scroll-delay CSS custom property on each card so main.js's + * 1. Sets --scroll-delay CSS custom property on each card/row so main.js's * scroll-visible transition fires at staggered intervals. * 2. Uses MutationObserver to detect when scroll-visible is applied, then - * triggers the icon-pop animation on the card's .feature-icon. + * triggers the icon-pop animation on the card's .feature-icon or .value-icon. * 3. Resets the delay to 0s after the entrance so hover interactions stay snappy. */ (function () { 'use strict'; var STAGGER = 0.08; // seconds between each card's entrance + var ROW_STAGGER = 0.12; // slightly longer stagger for platform-row blocks document.addEventListener('DOMContentLoaded', function () { if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) return; - // 1. Assign incrementing --scroll-delay to every card within a feature-section. + // 1. Assign incrementing --scroll-delay to every card within a feature/value-section. // The block renders .grid-2/.grid-3/.grid-4 wrappers (no .feature-section class). // main.js's .scroll-visible rule reads this via var(--scroll-delay, 0s). document.querySelectorAll('.grid-2, .grid-3, .grid-4').forEach(function (grid) { @@ -25,6 +27,21 @@ }); }); + // 1b. Assign incrementing --scroll-delay to .platform-row elements grouped + // by their parent container, so rows in the same section stagger in sequence. + var rowGroups = new Map(); + document.querySelectorAll('.platform-row').forEach(function (row) { + var parent = row.parentElement; + if (!parent) return; + if (!rowGroups.has(parent)) rowGroups.set(parent, []); + rowGroups.get(parent).push(row); + }); + rowGroups.forEach(function (rows) { + rows.forEach(function (row, i) { + row.style.setProperty('--scroll-delay', (i * ROW_STAGGER).toFixed(2) + 's'); + }); + }); + // 2. Watch for scroll-visible being added to each card. var cards = document.querySelectorAll('.grid-2 .oribi-card, .grid-3 .oribi-card, .grid-4 .oribi-card'); if (!cards.length) return; @@ -37,7 +54,8 @@ mo.unobserve(card); // Trigger icon pop ~150ms after the card itself starts fading in. - var icon = card.querySelector('.feature-icon'); + // Supports both .feature-icon (feature-cards) and .value-icon (value-cards). + var icon = card.querySelector('.feature-icon') || card.querySelector('.value-icon'); if (icon) { var cardDelay = parseFloat(card.style.getPropertyValue('--scroll-delay')) || 0; icon.style.animationDelay = (cardDelay + 0.15).toFixed(2) + 's'; diff --git a/theme/blocks/index.php b/theme/blocks/index.php index 141f88b..05330b5 100644 --- a/theme/blocks/index.php +++ b/theme/blocks/index.php @@ -1023,15 +1023,8 @@ function oribi_render_intro_section($a) $pkg .= '