/* ==========================================================================
   OnWard Media — homepage motion system  (v2: real amplitude)
   Palette only: brand green #1f6f3c / #2dba63, gold #c9a24a, teal #2dd0c0,
   red #ef4b42, navy #0a1f3c. No new brand colors.

   Driven by CSS custom properties written once per frame by
   assets/js/onward-motion.js: --om-scroll --om-progress --om-px --om-py.

   HARD RULES baked into this file:
   1. Decorative layers are ALWAYS behind content (z-index 0/1, content 2+)
      and never reduce the opacity of real text.
   2. Nothing decorative adds layout height. Overlays are absolute.
   3. Float animations only run AFTER .rv-in so they can't fight the
      entrance transform.
   ========================================================================== */

:root { --om-scroll: 0; --om-progress: 0; --om-px: 0; --om-py: 0; }

.om-tab-hidden [class*="om-f"],
.om-tab-hidden .om-parallax-layer,
.om-tab-hidden .om-particle,
.om-tab-hidden .om-hero-sweep,
.om-tab-hidden .om-stadium-sweep,
.om-tab-hidden .om-trace-layer__pulse,
.om-tab-hidden .om-trace-layer__node,
.om-tab-hidden .om-bg-blob,
.om-tab-hidden .om-bg-rings,
.om-tab-hidden .om-sched-rail__pulse,
.om-tab-hidden .om-fcard__dot { animation-play-state: paused !important; }

/* Far-offscreen sections stop animating (JS adds .om-off) */
.om-off [class*="om-f"],
.om-off .om-particle,
.om-off .om-trace-layer__pulse,
.om-off .om-bg-blob,
.om-off .om-stadium-sweep { animation-play-state: paused !important; }

/* ==========================================================================
   SAFETY: content must never be left invisible by a missed observer
   ========================================================================== */
/* NOTE: `transform` here must NOT be !important. Per the CSS cascade an
   !important declaration outranks a running animation, so `transform: none
   !important` silently cancels every float/parallax animation on the element.
   The selector is already specific enough to beat the base [data-reveal]
   offset without it. Only `opacity` needs the force. */
html.omnia-anim [data-reveal].om-force-in { opacity: 1 !important; transform: none; }
html.omnia-anim [data-reveal="down"] { transform: translateY(-28px); }

/* ==========================================================================
   SCROLL PROGRESS TRACER
   ========================================================================== */
.om-progress {
    position: fixed; top: 0; left: 0; right: 0; height: 2px;
    z-index: 9000; background: rgba(255,255,255,.07); pointer-events: none;
}
.om-progress__bar {
    height: 100%; width: calc(var(--om-progress) * 100%);
    background: linear-gradient(90deg, #1f6f3c, #2dba63 45%, #c9a24a);
    box-shadow: 0 0 10px rgba(45,186,99,.75);
}
.om-progress__bar::after {
    content: ''; position: absolute; top: -3px; right: -4px;
    width: 8px; height: 8px; border-radius: 50%;
    background: #c9a24a; box-shadow: 0 0 10px 2px rgba(201,162,74,.9);
}
.om-progress__bar { position: relative; }

/* ==========================================================================
   DECORATION CONTAINMENT
   All decorative overlays live INSIDE .container, never as a direct child of
   <section>. Reason: the Visual Editor's "glass" effect emits
   `<section-vpath> > * { position: relative !important }`, which would force
   an absolutely-positioned decorative layer back into the layout — a 620px
   blob or a 340px SVG then becomes real height and blows a hole in the page.
   Being a descendant (not a direct child) keeps that rule from applying.
   `.om-bleed` restores full-viewport width from inside the padded container.
   ========================================================================== */
.om-bleed {
    left: 50% !important;
    right: auto !important;
    width: 100vw !important;
    max-width: 100vw !important;
    margin-left: -50vw !important;
}

/* ---------------------------------------------------------------------------
   DECORATION LAYOUT GUARD  (do not simplify these repeated class names)

   The Visual Editor's "frosted glass" effect emits, for whichever element the
   owner applied it to:

       <vpath> > * { position: relative !important; z-index: 1 !important }

   On this homepage that vpath is the SERVICES CONTAINER
   (`section:nth-of-type(3)>div:nth-of-type(1)`), so every child of the
   container — including decorative overlays — gets forced back into normal
   flow. A 589px background blob then becomes 589px of real dead space
   (that is exactly what produced the giant gap above "Our Services").

   That rule is !important with specificity (0,3,4), so a plain
   `position: absolute` — or even `!important` at lower specificity — loses.
   Repeating the marker class raises the class column to (0,6,0), which beats
   it deterministically no matter which element the owner glasses, and no
   matter how deeply nested it is.

   Every decorative element therefore carries `om-fx` (background layer) or
   `om-fx-fg` (foreground layer). Content never carries either.
   --------------------------------------------------------------------------- */
.om-fx.om-fx.om-fx.om-fx.om-fx.om-fx,
.om-fx-fg.om-fx-fg.om-fx-fg.om-fx-fg.om-fx-fg.om-fx-fg {
    position: absolute !important;
    pointer-events: none !important;
}
.om-fx.om-fx.om-fx.om-fx.om-fx.om-fx       { z-index: -1 !important; }
.om-fx-fg.om-fx-fg.om-fx-fg.om-fx-fg.om-fx-fg.om-fx-fg { z-index: 3 !important; }

.om-progress { position: fixed; }

/* CRITICAL painting-order rule.
   Within a stacking context the paint order is: block backgrounds, then
   floats, then normal-flow INLINE/TEXT content, and only THEN positioned
   elements with z-index auto/0. So an absolutely-positioned decorative layer
   at `z-index: 0` paints ON TOP of headings and paragraphs, washing them out
   (and obscuring them completely once the Visual Editor's glass overlay is
   applied). Negative z-index moves these below all content while still
   keeping them above the section's own background. */
.om-trace-layer, .om-bg-grid, .om-bg-blob, .om-bg-rings, .om-bg-wave,
.om-yardlines, .om-stadium-sweep, .om-route, .om-sched-rail {
    z-index: -1 !important;
}

/* Visual Editor: hide purely decorative motion layers while editing so they
   can never obscure or be mistaken for selectable content. The editor runs
   with html.ve-on (set by assets/js/ve-bridge.js). */
html.ve-on .om-trace-layer,
html.ve-on .om-bg-grid,
html.ve-on .om-bg-blob,
html.ve-on .om-bg-rings,
html.ve-on .om-bg-wave,
html.ve-on .om-yardlines,
html.ve-on .om-stadium-sweep,
html.ve-on .om-route,
html.ve-on .om-hero-layers,
html.ve-on .om-fcards,
html.ve-on .om-sec-badge,
html.ve-on .om-sched-rail,
html.ve-on .om-progress {
    display: none !important;
}

/* Visual Editor: content must ALWAYS be visible and static while editing.
   [data-reveal] elements start at opacity:0 and rely on an IntersectionObserver
   to reveal them, which does not fire dependably inside the editor's iframe —
   that left cards and headings invisible the moment the owner clicked around.
   Editing is not a place for entrance animation, idle float, or parallax, so
   everything is pinned to its final resting state here. */
html.ve-on [data-reveal] {
    opacity: 1 !important;
    transform: none !important;
    transition: none !important;
}
html.ve-on [class*="om-f"],
html.ve-on .om-depth-1,
html.ve-on .om-depth-2,
html.ve-on .om-depth-3 {
    animation: none !important;
    transform: none !important;
    translate: none !important;
}
html.ve-on .om-hero-content-shift { transform: none !important; }

/* ==========================================================================
   TRACE OVERLAYS — zero layout height, absolutely positioned, BEHIND content.
   Deliberately oversized (top/bottom -18%) so a single trace visually spans
   across the section boundary into its neighbours.
   ========================================================================== */
.om-trace-layer {
    position: absolute;
    left: 0; right: 0; top: -18%; bottom: -18%;
    width: 100%; height: 136%;
    z-index: 0;
    pointer-events: none;
    overflow: visible;
}
.om-trace-layer__path {
    fill: none;
    stroke-width: 2.4;
    stroke-linecap: round;
    stroke-linejoin: round;
    opacity: .9;
}
.om-trace-layer__path--brand { stroke: #2dba63; filter: drop-shadow(0 0 4px rgba(45,186,99,.55)); }
.om-trace-layer__path--gold  { stroke: #c9a24a; filter: drop-shadow(0 0 4px rgba(201,162,74,.55)); }
.om-trace-layer__path--teal  { stroke: #2dd0c0; filter: drop-shadow(0 0 4px rgba(45,208,192,.5)); }
.om-trace-layer__path--faint { stroke: rgba(201,162,74,.34); stroke-width: 1.5; stroke-dasharray: 3 8; }

/* Nodes light up on a loop, like a signal passing through a patch bay */
.om-trace-layer__node {
    fill: #0b1410; stroke-width: 2.2;
    animation: omNodeLight 4.6s ease-in-out infinite;
}
.om-trace-layer__node--brand { stroke: #2dba63; }
.om-trace-layer__node--gold  { stroke: #c9a24a; }
.om-trace-layer__node--teal  { stroke: #2dd0c0; }
@keyframes omNodeLight {
    0%, 100% { fill: #0b1410; r: 5; }
    45%      { fill: #c9a24a; r: 7.5; }
}

/* Illuminated pulse travels the drawn path */
.om-trace-layer__pulse {
    r: 5;
    fill: #c9a24a;
    filter: drop-shadow(0 0 7px rgba(201,162,74,1));
    offset-rotate: 0deg;
    opacity: 0;
    animation: omPulseTravel 7s cubic-bezier(.45,0,.55,1) infinite;
}
.om-trace-layer__pulse--b {
    r: 3.8; fill: #2dba63;
    filter: drop-shadow(0 0 6px rgba(45,186,99,1));
    animation-duration: 9.5s; animation-delay: 3.2s;
}
@keyframes omPulseTravel {
    0%   { offset-distance: 0%;   opacity: 0; }
    8%   { opacity: 1; }
    90%  { opacity: 1; }
    100% { offset-distance: 100%; opacity: 0; }
}

/* Draw-in on scroll (JS adds .om-drawn) */
.om-trace-layer__path { stroke-dasharray: var(--om-len, 2000); stroke-dashoffset: var(--om-len, 2000); }
.om-trace-layer.om-drawn .om-trace-layer__path {
    stroke-dashoffset: 0;
    transition: stroke-dashoffset 2s cubic-bezier(.2,.7,.2,1);
}
.om-trace-layer.om-drawn .om-trace-layer__path--faint { transition-delay: .5s; }

/* ==========================================================================
   FLOAT PATTERNS — 6 distinct idle motions, 20-25px travel, 5-10s,
   ease-in-out alternate so it reads as floating, never bouncing.
   Applied only once .rv-in has landed (or on non-reveal decorative elements).
   ========================================================================== */
.rv-in.om-f1, .om-force-in.om-f1, .om-fcard.om-f1, .om-sec-badge.om-f1 { animation: omF1 7s ease-in-out var(--om-fdelay, 0s) infinite alternate; }
.rv-in.om-f2, .om-force-in.om-f2, .om-fcard.om-f2, .om-sec-badge.om-f2 { animation: omF2 8.5s ease-in-out var(--om-fdelay, 0s) infinite alternate; }
.rv-in.om-f3, .om-force-in.om-f3, .om-fcard.om-f3, .om-sec-badge.om-f3 { animation: omF3 6.5s ease-in-out var(--om-fdelay, 0s) infinite alternate; }
.rv-in.om-f4, .om-force-in.om-f4, .om-fcard.om-f4, .om-sec-badge.om-f4 { animation: omF4 9.5s ease-in-out var(--om-fdelay, 0s) infinite alternate; }
.rv-in.om-f5, .om-force-in.om-f5, .om-fcard.om-f5, .om-sec-badge.om-f5 { animation: omF5 7.8s ease-in-out var(--om-fdelay, 0s) infinite alternate; }
.rv-in.om-f6, .om-force-in.om-f6, .om-fcard.om-f6, .om-sec-badge.om-f6 { animation: omF6 10s ease-in-out var(--om-fdelay, 0s) infinite alternate; }

/* vertical drift, 24px */
@keyframes omF1 { from { transform: translate3d(0,-12px,0); } to { transform: translate3d(0,12px,0); } }
/* horizontal + rotation */
@keyframes omF2 { from { transform: translate3d(-11px,0,0) rotate(-0.7deg); } to { transform: translate3d(11px,4px,0) rotate(0.7deg); } }
/* diagonal, ~22px of travel */
@keyframes omF3 { from { transform: translate3d(-8px,-9px,0); } to { transform: translate3d(8px,9px,0); } }
/* vertical, longer + slight scale so it reads as depth change */
@keyframes omF4 { from { transform: translate3d(0,13px,0) scale(.994); } to { transform: translate3d(0,-11px,0) scale(1.006); } }
/* rotation-led drift */
@keyframes omF5 { from { transform: translate3d(6px,-10px,0) rotate(0.9deg); } to { transform: translate3d(-6px,10px,0) rotate(-0.9deg); } }
/* wide horizontal */
@keyframes omF6 { from { transform: translate3d(-12px,5px,0); } to { transform: translate3d(12px,-5px,0); } }

/* ==========================================================================
   POINTER DEPTH — foreground 22px / middle 13px / background 6px
   ========================================================================== */
.om-depth-1 { --om-dx: calc(var(--om-px) * 22px); --om-dy: calc(var(--om-py) * 22px); }
.om-depth-2 { --om-dx: calc(var(--om-px) * 13px); --om-dy: calc(var(--om-py) * 13px); }
.om-depth-3 { --om-dx: calc(var(--om-px) * 6px);  --om-dy: calc(var(--om-py) * 6px);  }
/* Depth is applied on a wrapper-free element via translate (float animation
   owns `transform`), so pointer depth rides on `translate` — a separate
   property that composites independently and won't be clobbered. */
.om-depth-1, .om-depth-2, .om-depth-3 {
    translate: var(--om-dx, 0) var(--om-dy, 0);
    transition: translate .5s cubic-bezier(.2,.7,.2,1);
    will-change: translate;
}
@media (max-width: 980px), (pointer: coarse) {
    .om-depth-1, .om-depth-2, .om-depth-3 { translate: none !important; }
}

/* ==========================================================================
   HERO LAYERS
   ========================================================================== */
.om-hero-layers { position: absolute; inset: 0; display: block; overflow: hidden; pointer-events: none; }
.om-parallax-layer { position: absolute; inset: -12% -12%; display: block; will-change: transform; }

.om-hero-grid {
    background-image:
        linear-gradient(rgba(45,186,99,.13) 1px, transparent 1px),
        linear-gradient(90deg, rgba(201,162,74,.10) 1px, transparent 1px);
    background-size: 48px 48px;
    transform: translate3d(0, calc(var(--om-scroll) * -0.05px), 0);
    animation: omGridDrift 22s linear infinite;
    opacity: .6;
}
@keyframes omGridDrift {
    from { background-position: 0 0, 0 0; }
    to   { background-position: 48px 96px, -48px 48px; }
}
.om-hero-diagonals {
    background-image: repeating-linear-gradient(128deg, rgba(255,255,255,.05) 0 1px, transparent 1px 32px);
    transform: translate3d(0, calc(var(--om-scroll) * -0.11px), 0);
    opacity: .55;
    animation: omDiagDrift 30s linear infinite;
}
@keyframes omDiagDrift { from { background-position: 0 0; } to { background-position: 320px 0; } }

.om-hero-sweep {
    position: absolute; top: -20%; left: -35%; display: block;
    width: 50%; height: 140%;
    background: linear-gradient(100deg, transparent 38%, rgba(201,162,74,.13) 50%, transparent 62%);
    animation: omSweep 8s ease-in-out infinite;
}
@keyframes omSweep { 0%,100% { left: -40%; } 50% { left: 108%; } }

.om-particle {
    position: absolute; display: block;
    width: 5px; height: 5px; border-radius: 50%;
    background: #2dba63; box-shadow: 0 0 8px rgba(45,186,99,.9);
    bottom: 0; opacity: 0;
    animation-name: omParticleRise; animation-timing-function: linear; animation-iteration-count: infinite;
}
.om-particle--gold { background: #c9a24a; box-shadow: 0 0 8px rgba(201,162,74,.9); }
.om-particle--teal { background: #2dd0c0; box-shadow: 0 0 8px rgba(45,208,192,.85); }
@keyframes omParticleRise {
    0%   { transform: translate3d(0,0,0) scale(.5); opacity: 0; }
    10%  { opacity: .9; }
    80%  { opacity: .55; }
    100% { transform: translate3d(22px,-280px,0) scale(1.1); opacity: 0; }
}

/* width:100% is doing the real work here - left:0/right:0 cannot stretch this.
   An <svg> is a REPLACED element, and this one carries an intrinsic aspect ratio
   from its viewBox (1200x60 = 20:1). With width:auto the browser sizes it from
   the height instead and drops the `right` constraint: 70px x 20 = a hard 1400px.
   On a 1544px hero the waves stopped 144px short of the right edge; on anything
   narrower than 1400px they ran off the side and were silently cropped by
   .om-hero-layers' overflow:hidden.
   preserveAspectRatio="none" on the element is what lets the paths stretch to
   whatever width they are given rather than re-introducing the ratio. */
.om-hero-wave { position: absolute; left: 0; right: 0; bottom: 0; width: 100%; height: 70px; opacity: .4; }
.om-hero-wave path { fill: none; stroke: #2dba63; stroke-width: 1.5; }
.om-hero-wave .om-wave-2 { stroke: #c9a24a; opacity: .65; }
.om-hero-wave path { animation: omWaveShift 9s ease-in-out infinite alternate; }
.om-hero-wave .om-wave-2 { animation-duration: 12s; }
@keyframes omWaveShift { from { transform: translateY(0) scaleY(1); } to { transform: translateY(-7px) scaleY(1.5); } }

.om-hero-content-shift { transform: translate3d(0, calc(var(--om-scroll) * -0.08px), 0); }

/* ==========================================================================
   FLOATING BROADCAST CARDS
   ========================================================================== */
.om-fcards { position: absolute; inset: 0; display: block; z-index: 5; pointer-events: none; }
.om-fcard {
    position: absolute;
    display: inline-flex; align-items: center; gap: .5rem;
    padding: .5rem .85rem;
    border-radius: 12px;
    background: rgba(8,12,10,.74);
    border: 1px solid rgba(201,162,74,.3);
    box-shadow: 0 12px 30px rgba(0,0,0,.5), inset 0 1px 0 rgba(255,255,255,.07);
    backdrop-filter: blur(7px); -webkit-backdrop-filter: blur(7px);
    font-size: .76rem; color: #eef2ef; white-space: nowrap;
}
.om-fcard--sm { font-size: .7rem; padding: .38rem .7rem; opacity: .9; }
.om-fcard__tag {
    font-weight: 900; font-size: .64rem; letter-spacing: .1em;
    padding: .18em .5em; border-radius: 5px; color: #08110a;
}
.om-fcard__tag--live { background: #ef4b42; color: #fff; }
.om-fcard__tag--air  { background: #2dba63; color: #06170d; }
.om-fcard__tag--gold { background: #c9a24a; }
.om-fcard__label { color: rgba(238,242,239,.9); font-weight: 600; }
.om-fcard__dot {
    width: 7px; height: 7px; border-radius: 50%; flex-shrink: 0;
    background: #ef4b42; box-shadow: 0 0 7px rgba(239,75,66,1);
    animation: omBlink 1.5s ease-in-out infinite;
}
@keyframes omBlink { 0%,100%{opacity:1;transform:scale(1);} 50%{opacity:.3;transform:scale(.82);} }

/* Section-edge badges — deliberately overlap the section boundary */
.om-sec-badge {
    position: absolute; z-index: 3;
    display: inline-flex; align-items: center; gap: .5rem;
    padding: .5rem .85rem; border-radius: 12px;
    background: rgba(8,12,10,.8);
    border: 1px solid rgba(201,162,74,.32);
    box-shadow: 0 14px 34px rgba(0,0,0,.5);
    font-size: .74rem; color: #eef2ef; white-space: nowrap;
    pointer-events: none;
}
.om-sec-badge--svc  { top: -18px; right: 6%; }
.om-sec-badge--rdsn { bottom: -16px; left: 5%; }
@media (max-width: 1180px) { .om-sec-badge { display: none; } }
@media (max-width: 1100px) { .om-fcards { display: none; } }

/* ==========================================================================
   SECTION BACKGROUND DEPTH (middle ground)
   ========================================================================== */
.om-sec { position: relative; }
.om-bg-grid, .om-bg-blob, .om-bg-rings, .om-bg-wave, .om-yardlines {
    position: absolute; display: block; pointer-events: none; z-index: 0;
}
.om-bg-grid {
    inset: 0;
    background-image:
        linear-gradient(rgba(31,111,60,.07) 1px, transparent 1px),
        linear-gradient(90deg, rgba(31,111,60,.07) 1px, transparent 1px);
    background-size: 60px 60px;
    transform: translate3d(0, calc(var(--om-scroll) * 0.018px), 0);
}
.om-bg-blob {
    width: 46vw; height: 46vw; max-width: 620px; max-height: 620px;
    border-radius: 50%;
    filter: blur(60px);
    opacity: .5;
}
.om-bg-blob--a {
    top: -14%; left: -10%;
    background: radial-gradient(circle, rgba(45,186,99,.22), transparent 70%);
    animation: omBlobA 20s ease-in-out infinite alternate;
}
.om-bg-blob--b {
    bottom: -18%; right: -8%;
    background: radial-gradient(circle, rgba(201,162,74,.2), transparent 70%);
    animation: omBlobB 26s ease-in-out infinite alternate;
}
@keyframes omBlobA { from { transform: translate3d(0,0,0) scale(1); } to { transform: translate3d(70px,50px,0) scale(1.18); } }
@keyframes omBlobB { from { transform: translate3d(0,0,0) scale(1.1); } to { transform: translate3d(-60px,-45px,0) scale(1); } }

.om-bg-rings {
    inset: -20% auto auto -10%;
    width: 70vw; height: 70vw; max-width: 900px; max-height: 900px;
    border-radius: 50%;
    border: 1px solid rgba(201,162,74,.12);
    box-shadow: 0 0 0 60px rgba(201,162,74,.05), 0 0 0 140px rgba(45,186,99,.04);
    animation: omRings 24s ease-in-out infinite alternate;
    opacity: .8;
}
@keyframes omRings { from { transform: scale(.92) translate3d(0,0,0); } to { transform: scale(1.06) translate3d(40px,30px,0); } }

.om-bg-wave {
    inset: auto 0 0 0; height: 180px;
    background-image:
        repeating-linear-gradient(90deg, rgba(45,208,192,.10) 0 2px, transparent 2px 9px);
    -webkit-mask: linear-gradient(180deg, transparent, #000);
            mask: linear-gradient(180deg, transparent, #000);
    animation: omWaveBg 14s linear infinite;
    opacity: .7;
}
@keyframes omWaveBg { from { background-position: 0 0; } to { background-position: 220px 0; } }

/* Football yard lines for the RDSN band */
.om-yardlines {
    inset: 0;
    background-image: repeating-linear-gradient(90deg,
        rgba(255,255,255,.055) 0 2px, transparent 2px 84px);
    transform: translate3d(0, calc(var(--om-scroll) * 0.02px), 0);
    opacity: .85;
}

/* ==========================================================================
   SERVICES — offset composition instead of a flat grid
   ========================================================================== */
.om-svc-card {
    position: relative;
    z-index: 2;
    transition: box-shadow .35s ease, border-color .35s ease;
}
/* Stagger every other card vertically so the row isn't a straight line.
   Uses margin (not transform) so it can't fight the float animation. */
@media (min-width: 900px) {
    .om-svc-grid > a:nth-child(even) { margin-top: 34px; }
    .om-svc-grid > a:nth-child(3n)   { margin-top: 16px; }
}
.om-svc-card::after {
    content: ''; position: absolute; inset: 0; border-radius: inherit;
    background: linear-gradient(120deg, transparent 32%, rgba(201,162,74,.2) 50%, transparent 68%);
    opacity: 0; transition: opacity .4s ease; pointer-events: none;
}
.om-svc-card:hover::after { opacity: 1; }
.om-svc-card:hover {
    box-shadow: 0 24px 50px rgba(0,0,0,.4), 0 0 0 1px rgba(45,186,99,.45);
}
/* Animated top accent that fills on hover */
.om-svc-card::before {
    content: ''; position: absolute; top: 0; left: 0; height: 4px; width: 0;
    background: linear-gradient(90deg, #2dba63, #c9a24a);
    transition: width .5s cubic-bezier(.2,.7,.2,1); z-index: 3;
}
.om-svc-card:hover::before { width: 100%; }

@media (hover: hover) and (pointer: fine) {
    .om-tilt:hover { rotate: none; }
}

/* ==========================================================================
   RDSN
   ========================================================================== */
.om-stadium-sweep {
    position: absolute; inset: 0; display: block; overflow: hidden; z-index: 0; pointer-events: none;
}
.om-stadium-sweep::before {
    content: '';
    position: absolute; top: -45%; left: -25%; width: 42%; height: 190%;
    background: linear-gradient(100deg, transparent, rgba(201,162,74,.1), transparent);
    animation: omSweep 12s ease-in-out infinite;
}
.om-route { position: absolute; inset: 0; z-index: 0; pointer-events: none; opacity: .6; }
.om-route__p {
    fill: none; stroke: rgba(201,162,74,.4); stroke-width: 1.8;
    stroke-dasharray: 6 9;
    animation: omRouteDash 3.4s linear infinite;
}
.om-route__p--b { stroke: rgba(45,186,99,.34); animation-duration: 4.6s; animation-direction: reverse; }
@keyframes omRouteDash { to { stroke-dashoffset: -60; } }

.om-feat-card { z-index: 2; }
.arc-card { position: relative; z-index: 2; }

.om-badge-pulse { position: relative; }
.om-badge-pulse::before {
    content: ''; position: absolute; inset: -3px; border-radius: inherit;
    border: 1.5px solid rgba(201,162,74,.6);
    animation: omBadgeRing 2.2s ease-out infinite;
}
@keyframes omBadgeRing {
    0%   { transform: scale(1); opacity: .9; }
    100% { transform: scale(1.45); opacity: 0; }
}

/* ==========================================================================
   SCHEDULE — broadcast rail with a travelling signal
   ========================================================================== */
.om-sched-grid { position: relative; }
.om-sched-rail {
    position: absolute; display: block;
    left: 0; right: 0; top: 46px; height: 2px;
    background: linear-gradient(90deg, transparent, rgba(201,162,74,.4) 6%, rgba(201,162,74,.4) 94%, transparent);
    z-index: 0; pointer-events: none;
}
.om-sched-rail__fill {
    position: absolute; inset: 0 auto 0 0; display: block;
    width: calc(var(--om-progress) * 190%);
    max-width: 100%;
    background: linear-gradient(90deg, #2dba63, #c9a24a);
    box-shadow: 0 0 10px rgba(45,186,99,.7);
}
.om-sched-rail__pulse {
    position: absolute; top: -4px; left: 0; display: block;
    width: 10px; height: 10px; border-radius: 50%;
    background: #c9a24a; box-shadow: 0 0 12px 3px rgba(201,162,74,.9);
    animation: omRailPulse 6s cubic-bezier(.45,0,.55,1) infinite;
}
@keyframes omRailPulse {
    0%   { left: 0%;   opacity: 0; }
    10%  { opacity: 1; }
    90%  { opacity: 1; }
    100% { left: 100%; opacity: 0; }
}
.om-sched-card { position: relative; z-index: 2; }
.om-sched-node {
    position: absolute; display: block;
    top: -6px; left: 50%; margin-left: -6px;
    width: 12px; height: 12px; border-radius: 50%;
    background: #0d1512; border: 2px solid rgba(201,162,74,.55);
    z-index: 3; pointer-events: none;
    transition: background .5s ease, border-color .5s ease, box-shadow .5s ease;
}
.om-sched-card.rv-in .om-sched-node,
.om-sched-card.om-force-in .om-sched-node {
    background: #c9a24a; border-color: #c9a24a;
    box-shadow: 0 0 12px 2px rgba(201,162,74,.75);
}
@media (max-width: 900px) { .om-sched-rail { display: none; } .om-sched-node { display: none; } }

/* ==========================================================================
   CONTRAST GUARDRAILS
   These sections carry dark background images set in the Visual Editor, so
   text must be explicitly light. Decorative layers above are all z-index 0
   and never touch content opacity.
   ========================================================================== */
.om-sec--rdsn .section-head h2,
.om-sec--rdsn .om-feat-card h3 { color: #f2f5f2 !important; }
.om-sec--rdsn .section-head p { color: rgba(242,245,242,.82) !important; }
.om-sec--rdsn .btn-ghost { border-color: rgba(255,255,255,.55) !important; color: #fff !important; }
.om-sec--rdsn .btn-ghost:hover { border-color: #c9a24a !important; color: #c9a24a !important; }

.om-sec--sched .btn-ghost { border-color: rgba(255,255,255,.5) !important; color: #fff !important; }
.om-sec--sched .btn-ghost:hover { border-color: #c9a24a !important; color: #c9a24a !important; }

/* Any card sitting on a decorated section keeps its own solid surface so
   body copy never fights a background image. */
.om-sec .tk-card, .om-sec .arc-card, .om-sec .sch-home-card { position: relative; z-index: 2; }

/* ==========================================================================
   IMAGE PARALLAX FRAME
   ========================================================================== */
.om-img-frame { overflow: hidden; position: relative; }
.om-img-frame img {
    display: block; width: 100%; height: 100%; object-fit: cover;
    transform: translateY(var(--om-frame-shift, 0px)) scale(1.1);
}

/* ==========================================================================
   MOBILE — keep motion, reduce amplitude/count
   ========================================================================== */
@media (max-width: 900px) {
    .om-trace-layer { top: -8%; bottom: -8%; height: 116%; }
    .om-trace-layer__path { stroke-width: 2; }
    .om-bg-blob { filter: blur(44px); opacity: .4; }
}
@media (max-width: 700px) {
    /* Halve float travel on phones */
    @keyframes omF1 { from { transform: translate3d(0,-6px,0); } to { transform: translate3d(0,6px,0); } }
    @keyframes omF2 { from { transform: translate3d(-5px,0,0) rotate(-.4deg); } to { transform: translate3d(5px,2px,0) rotate(.4deg); } }
    @keyframes omF3 { from { transform: translate3d(-4px,-4px,0); } to { transform: translate3d(4px,4px,0); } }
    @keyframes omF4 { from { transform: translate3d(0,6px,0); } to { transform: translate3d(0,-5px,0); } }
    @keyframes omF5 { from { transform: translate3d(3px,-5px,0) rotate(.5deg); } to { transform: translate3d(-3px,5px,0) rotate(-.5deg); } }
    @keyframes omF6 { from { transform: translate3d(-6px,2px,0); } to { transform: translate3d(6px,-2px,0); } }
    .om-particle:nth-of-type(n+4) { display: none; }
    .om-svc-grid > a:nth-child(even), .om-svc-grid > a:nth-child(3n) { margin-top: 0; }
    .om-hero-sweep, .om-stadium-sweep::before { animation-duration: 16s; }
}

/* ==========================================================================
   HOMEPAGE GALLERY (admin-managed) — part of the same motion system:
   staggered directional reveals, om-f* idle float, trace overlay behind it.
   Tiles vary in height so it reads as a composition rather than a plain grid.
   ========================================================================== */
.om-gal-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
    gap: 1.2rem;
    align-items: start;
}
.om-gal-card { margin: 0; position: relative; z-index: 2; }
@media (min-width: 900px) {
    /* Gentle vertical offsets = layered composition, using margin so it can
       never fight the float animation's transform. */
    .om-gal-grid > .om-gal-card:nth-child(even) { margin-top: 28px; }
    .om-gal-grid > .om-gal-card:nth-child(3n)   { margin-top: 14px; }
}
.om-gal-open {
    display: block; width: 100%; padding: 0; cursor: zoom-in;
    background: var(--c-panel); color: inherit; text-align: left;
    border: 1px solid var(--c-line); border-radius: 16px; overflow: hidden;
    transition: transform .35s cubic-bezier(.2,.7,.2,1), box-shadow .35s ease, border-color .35s ease;
}
.om-gal-open:hover, .om-gal-open:focus-visible {
    border-color: rgba(45,208,192,.5);
    box-shadow: 0 22px 46px rgba(0,0,0,.38), 0 0 0 1px rgba(45,208,192,.35);
}
@media (hover: hover) and (pointer: fine) {
    .om-gal-open:hover { transform: translateY(-4px) scale(1.012); }
}
.om-gal-frame {
    position: relative; display: block; overflow: hidden;
    aspect-ratio: 4 / 3; background: #0b1210;
}
.om-gal-card--tall .om-gal-frame { aspect-ratio: 3 / 4; }
.om-gal-img {
    position: absolute; inset: 0;
    width: 100%; height: 100%; object-fit: cover; display: block;
    transition: transform .7s cubic-bezier(.2,.7,.2,1), opacity .55s ease;
}
@media (hover: hover) and (pointer: fine) {
    .om-gal-open:hover .om-gal-img { transform: scale(1.06); }
}
/* Before/After pair: the second frame crossfades in on hover/focus */
.om-gal-img--alt { opacity: 0; }
.om-gal-open:hover .om-gal-img--alt,
.om-gal-open:focus-visible .om-gal-img--alt { opacity: 1; }
.om-gal-badge {
    position: absolute; top: .6rem; left: .6rem; z-index: 2;
    font-size: .6rem; font-weight: 900; letter-spacing: .12em; text-transform: uppercase;
    background: rgba(8,12,10,.8); color: #2dd0c0;
    border: 1px solid rgba(45,208,192,.45); border-radius: 5px; padding: .22em .55em;
}
/* Broadcast scan sweep across each tile */
.om-gal-scan {
    position: absolute; top: 0; bottom: 0; left: -40%; width: 35%; z-index: 1;
    background: linear-gradient(100deg, transparent, rgba(201,162,74,.16), transparent);
    animation: omSweep 9s ease-in-out infinite;
    pointer-events: none;
}
.om-gal-cap { padding: .9rem 1rem 1rem; display: block; }
.om-gal-cap__t { display: block; font-weight: 700; color: var(--c-text); font-size: 1rem; line-height: 1.3; }
.om-gal-cap__c { display: block; color: var(--c-muted); font-size: .89rem; margin-top: .2rem; line-height: 1.5; }

/* Reduce motion/mobile: keep reveal + hover, drop the constant sweep */
@media (max-width: 700px) {
    .om-gal-scan { animation-duration: 15s; }
    .om-gal-grid > .om-gal-card:nth-child(even),
    .om-gal-grid > .om-gal-card:nth-child(3n) { margin-top: 0; }
    .om-gal-card--tall .om-gal-frame { aspect-ratio: 4 / 3; }
}
.om-tab-hidden .om-gal-scan { animation-play-state: paused !important; }
.om-off .om-gal-scan { animation-play-state: paused !important; }
html.ve-on .om-gal-scan { display: none !important; }

/* ---------------- Lightbox ---------------- */
.om-lb {
    position: fixed; inset: 0; z-index: 10000;
    display: none; align-items: center; justify-content: center;
    background: rgba(4,8,6,.92);
    backdrop-filter: blur(4px); -webkit-backdrop-filter: blur(4px);
    padding: 4vh 4vw;
}
.om-lb.is-open { display: flex; }
.om-lb__figure { margin: 0; max-width: 100%; max-height: 100%; text-align: center; }
.om-lb__img {
    max-width: 100%; max-height: 82vh; width: auto; height: auto;
    border-radius: 12px; border: 1px solid rgba(201,162,74,.35);
    box-shadow: 0 30px 70px rgba(0,0,0,.6);
    animation: omLbIn .35s cubic-bezier(.2,.7,.2,1) both;
}
@keyframes omLbIn { from { opacity: 0; transform: scale(.94); } to { opacity: 1; transform: none; } }
.om-lb__cap { color: #e8ece9; margin-top: .9rem; font-size: .95rem; line-height: 1.5; }
.om-lb__cap strong { display: block; font-size: 1.05rem; margin-bottom: .15rem; }
.om-lb__close {
    position: absolute; top: 1.1rem; right: 1.3rem;
    width: 44px; height: 44px; border-radius: 50%;
    background: rgba(255,255,255,.1); border: 1px solid rgba(255,255,255,.3);
    color: #fff; font-size: 1.6rem; line-height: 1; cursor: pointer;
}
.om-lb__close:hover { background: rgba(255,255,255,.2); }
