/* ============================================================
   TaskLogix360 — Depth & motion layer (added 2026-07-28)

   WHY THIS FILE EXISTS
   The home page read as "washed out": five consecutive near-white
   sections opened the page, the largest luminance delta between
   neighbours was ~4%, and .problem (#fff) vs .fork (#F9FAFB) differed
   by 1.5% — a functionally invisible boundary. Meanwhile product.html
   felt rich. Decoding it showed the richness is a SYSTEM, not a style:
     1. never a flat white ground — always a ramp with radial tints
     2. green is emitted light (small saturated points), never paint
     3. every card carries a second, green-tinted shadow
     4. value inverts every ~1500-2000px (a rhythm, not a ratio)
     5. every section has one always-on ambient motion
   Those five recipes were pasted inline in product.html. Here they are
   named once so any section can opt in, instead of being re-pasted and
   drifting.

   SIBLING, NOT CLONE (Sam's constraint: "dark, but not the same as
   Enterprise"). The dark ground below uses the same two-radial + ramp
   formula as product.html:87-93, but MIRRORED — blue bloom top-LEFT
   instead of top-right, green bloom bottom-RIGHT instead of
   bottom-left — on a different ramp angle (192deg vs 168deg) and
   different stops. Same grammar, different sentence.

   CONVENTION (base.css/product.html house rule, non-negotiable):
   default state = FINAL state. JS adds .tlx-armed to opt an element
   into its "from" state, then .tlx-go to play it. No-JS and
   reduced-motion users get the finished artwork, never a blank box.
   Only opacity / transform / stroke-dashoffset / box-shadow animate.
   ============================================================ */

/* ------------------------------------------------------------
   1. GROUNDS — no flat fills anywhere
   ------------------------------------------------------------ */

/* Deep navy ground. Mirror-image sibling of .vha-hero (product.html:87-93).
   Re-grounded 2026-08-07 onto the shared --gd-* ramp so it stops being its own
   navy. The mirrored bloom placement (blue top-LEFT, green bottom-RIGHT) is
   kept — that is the "sibling not clone" constraint — but the blue is pulled
   from .50 to the shared strength, which is what made the fork read blotchy
   against the flatter hero above it. */
.ground-dark{
  position:relative;overflow:hidden;color:#fff;
  background:
    radial-gradient(115% 85% at 14% -12%, rgba(35,120,196,var(--gd-glow-blue)) 0%, rgba(35,120,196,0) 58%),
    radial-gradient(120% 80% at 50% 116%, rgba(30,154,68,var(--gd-glow-green)) 0%, rgba(30,154,68,0) 60%),
    linear-gradient(var(--gd-angle), var(--gd-1) 0%, var(--gd-2) 46%, var(--gd-3) 100%);
}

/* Light ground. Replaces every flat #fff / #F9FAFB on the page: a blue-
   tinted ramp, two blurred glows, and a dot grid that is MASKED so it
   fades out rather than tiling edge to edge (base.css:261-262 rule). */
.ground-lit{
  position:relative;overflow:hidden;
  background:
    radial-gradient(80% 60% at 88% 8%, rgba(35,120,196,.09) 0%, rgba(35,120,196,0) 62%),
    radial-gradient(70% 55% at 6% 96%, rgba(30,154,68,.08) 0%, rgba(30,154,68,0) 60%),
    linear-gradient(174deg, #FFFFFF 0%, #F4F9FD 54%, #EAF3FA 100%);
}
.ground-lit::before{
  content:"";position:absolute;inset:0;pointer-events:none;z-index:0;opacity:.55;
  background-image:radial-gradient(rgba(11,70,120,.16) 1px, transparent 1px);
  background-size:28px 28px;
  -webkit-mask-image:radial-gradient(88% 84% at 50% 42%, #000 18%, transparent 100%);
  mask-image:radial-gradient(88% 84% at 50% 42%, #000 18%, transparent 100%);
}
/* Content must clear the decorative layers on both grounds. */
.ground-lit>*,.ground-dark>*{position:relative;z-index:1}

/* ------------------------------------------------------------
   2. LIFT — the 4-layer shadow, incl. the green spill
   The single highest-value device on product.html (L189-206) and the
   one thing that appears NOWHERE on the home page. Invisible on any
   single card; transformative in aggregate.
   ------------------------------------------------------------ */

.lift{
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.14),      /* top edge highlight */
    inset 0 0 0 1px rgba(151,196,236,.16),    /* hairline ring      */
    0 40px 90px -30px rgba(0,10,22,.85),      /* deep lift          */
    0 24px 60px -28px rgba(30,154,68,.35);    /* GREEN SPILL        */
}
/* Light-ground inversion — same 4 layers, re-weighted for a pale card. */
.lift-lit{
  box-shadow:
    inset 0 1px 0 #fff,
    inset 0 0 0 1px rgba(11,70,120,.12),
    0 30px 70px -34px rgba(8,54,93,.34),
    0 22px 54px -32px rgba(30,154,68,.24);
}
@media (hover:hover){
  .lift-hover{transition:transform .3s var(--ease),box-shadow .3s var(--ease)}
  .lift-hover:hover{transform:translateY(-4px)}
}

/* ------------------------------------------------------------
   3. EDGES — hairline + horizon hand-off
   ------------------------------------------------------------ */

/* Gradient top-edge light line. Put on a card/band that needs an edge. */
.hairline{position:relative}
.hairline::before{
  content:"";position:absolute;top:0;left:0;right:0;height:1px;pointer-events:none;z-index:2;
  background:linear-gradient(90deg,transparent,rgba(30,154,68,.7),rgba(11,70,120,.4),transparent);
}

/* Glowing green hand-off for exiting a dark band into a light one with
   no seam. Port of .vha-horizon (product.html:133-141). */
.horizon{
  position:absolute;left:0;right:0;bottom:0;height:160px;pointer-events:none;z-index:2;
  background:radial-gradient(62% 140% at 50% 102%, rgba(30,154,68,.32) 0%, rgba(30,154,68,0) 70%);
}
.horizon::after{
  content:"";position:absolute;left:0;right:0;bottom:0;height:2px;
  background:linear-gradient(90deg, rgba(30,154,68,0) 4%, rgba(74,222,128,.95) 50%, rgba(30,154,68,0) 96%);
  box-shadow:0 0 14px 1px rgba(62,201,110,.45);
}
/* Inverted: entering a dark band from a light one above it. */
.horizon-top{top:0;bottom:auto;transform:scaleY(-1)}

/* ------------------------------------------------------------
   4. AMBIENT — always-on motion, one per section
   "Nothing is ever static." Entrance-only reveals are precisely what
   "washed out" feels like.
   ------------------------------------------------------------ */

/* Drifting light beams (product.html:120-130). Place 2-3 inside a
   .ground-dark. MOBILE: display:none, never just paused — a static
   filter:blur() still composites every frame (product.html:312-313). */
.beam{
  position:absolute;top:-32%;height:170%;width:clamp(160px,22vw,340px);
  pointer-events:none;z-index:0;filter:blur(34px);
  background:linear-gradient(180deg, rgba(255,255,255,.14) 0%, rgba(157,209,255,.07) 45%, rgba(255,255,255,0) 78%);
  transform:rotate(-24deg);   /* mirrored vs product.html's +24deg */
  animation:tlxBeamDrift 14s ease-in-out infinite alternate;
}
.beam.b1{left:4%}
.beam.b2{left:41%;opacity:.6;animation-delay:-7s;animation-duration:18s}
.beam.b3{right:-6%;opacity:.5;animation-delay:-3s;animation-duration:16s}
@keyframes tlxBeamDrift{
  from{transform:rotate(-24deg) translateX(-28px)}
  to{transform:rotate(-24deg) translateX(28px)}
}

/* Sheen glint across glass. Note the 32% keyframe: the sweep occupies
   the first third of the cycle then idles, so it reads as a glint and
   not a strobe (product.html:208-218). */
.sheen{position:relative;overflow:hidden}
.sheen::after{
  content:"";position:absolute;top:-30%;bottom:-30%;left:-24%;width:34%;pointer-events:none;z-index:5;
  background:linear-gradient(100deg, rgba(255,255,255,0) 0%, rgba(255,255,255,.055) 50%, rgba(255,255,255,0) 100%);
  transform:translateX(-140%) rotate(8deg);
  animation:tlxSheen 7.5s var(--ease) 2.2s infinite;
}
@keyframes tlxSheen{
  0%{transform:translateX(-140%) rotate(8deg)}
  32%{transform:translateX(560%) rotate(8deg)}
  100%{transform:translateX(560%) rotate(8deg)}
}

/* Emitted-light dot — green as a saturated POINT, never a fill. */
.emit{width:8px;height:8px;border-radius:50%;background:#3ECB6E;
  box-shadow:0 0 0 0 rgba(62,203,110,.55);animation:tlxEmit 1.9s var(--ease) infinite}
@keyframes tlxEmit{
  0%{box-shadow:0 0 0 0 rgba(62,203,110,.5)}
  70%{box-shadow:0 0 0 9px rgba(62,203,110,0)}
  100%{box-shadow:0 0 0 0 rgba(62,203,110,0)}
}

/* Highlighted headline word. SOLID green, not gradient-clipped text (Sam,
   2026-07-28: "on titles use the green text to highlight instead of
   gradients"). Gradient text also degrades badly - it needs three prefixed
   properties, breaks selection highlighting, and renders as invisible
   transparent text anywhere background-clip:text is unsupported.
   Split by ground so both sides stay AA: --green-bright on dark,
   --green-aa on light. */
.glow-word{color:var(--green-bright)}
.glow-word-lit{color:var(--green-aa)}

/* ------------------------------------------------------------
   5. MOTION GRAMMAR — verb x slot
   Generalises product.html's per-section choreography (L426-439) into
   two orthogonal axes so a new section is choreographed declaratively:
       verb:  .tlx-in-{rise|draw|pop|wipe|blur}
       slot:  .tlx-t1 ... .tlx-t9   (80ms cadence)
   ARMING: the "from" state applies ONLY under html.tlx-js, which a tiny
   inline <head> snippet sets BEFORE first paint (same trick as
   product.html's .vha-js). Deferring this to depth.js would paint the
   finished state first and then snap back to the "from" state — a
   visible flash. Without JS, html.tlx-js never appears and the finished
   artwork ships as-is.
   ------------------------------------------------------------ */

.tlx-anim [class*="tlx-in-"]{
  transition:
    opacity .78s var(--rv-ease),
    transform .78s var(--rv-ease),
    clip-path .78s var(--rv-ease),
    filter .78s var(--rv-ease),
    stroke-dashoffset 1.15s var(--rv-ease);
  transition-delay:var(--tlx-delay,0ms);
}

/* --- from states (armed only) --- */
.tlx-js .tlx-anim .tlx-in-rise{opacity:0;transform:translateY(38px)}
.tlx-js .tlx-anim .tlx-in-pop {opacity:0;transform:translateY(24px) scale(.92);transition-timing-function:var(--rv-ease-pop)}
.tlx-js .tlx-anim .tlx-in-wipe{opacity:1;transform:scale(1.05);clip-path:inset(0 100% 0 0)}
.tlx-js .tlx-anim .tlx-in-blur{opacity:0;transform:translateY(22px);filter:blur(8px)}
/* draw: pair with pathLength="1" so one keyframe drives any path length
   (product.html:248-253). Author sets stroke-dasharray:1 1 on the path. */
.tlx-js .tlx-anim .tlx-in-draw{stroke-dashoffset:1}

/* --- to states --- */
.tlx-js .tlx-anim.tlx-go .tlx-in-rise,
.tlx-js .tlx-anim.tlx-go .tlx-in-pop,
.tlx-js .tlx-anim.tlx-go .tlx-in-blur{opacity:1;transform:none;filter:none}
.tlx-js .tlx-anim.tlx-go .tlx-in-wipe{transform:none;clip-path:inset(0 0 0 0)}
.tlx-js .tlx-anim.tlx-go .tlx-in-draw{stroke-dashoffset:0}

/* --- timing slots --- */
.tlx-t1{--tlx-delay:0ms}   .tlx-t2{--tlx-delay:80ms}  .tlx-t3{--tlx-delay:160ms}
.tlx-t4{--tlx-delay:240ms} .tlx-t5{--tlx-delay:320ms} .tlx-t6{--tlx-delay:400ms}
.tlx-t7{--tlx-delay:480ms} .tlx-t8{--tlx-delay:560ms} .tlx-t9{--tlx-delay:640ms}

/* ------------------------------------------------------------
   6. SCROLL-DRIVEN ENHANCEMENT
   IntersectionObserver (site.js:100-137) is the BASELINE and always
   runs. Native scroll-driven animation is layered on top only where
   supported (~84% global: Chrome/Edge 115+, Safari 18+; Firefox is
   behind a flag and simply keeps the IO path).
   Used for continuous parallax/scrub effects that IO cannot express —
   NOT for entrances, which stay on the observer so behaviour is
   identical everywhere.
   ------------------------------------------------------------ */
@supports (animation-timeline: view()){
  @media (prefers-reduced-motion:no-preference){
    .tlx-scrub{
      animation:tlxScrub linear both;
      animation-timeline:view();
      animation-range:entry 12% cover 62%;
    }
    @keyframes tlxScrub{from{transform:translateY(var(--scrub-from,28px))}to{transform:translateY(var(--scrub-to,-28px))}}

    .tlx-scrub-fade{
      animation:tlxScrubFade linear both;
      animation-timeline:view();
      animation-range:entry 0% entry 70%;
    }
    @keyframes tlxScrubFade{from{opacity:.35}to{opacity:1}}
  }
}

/* ------------------------------------------------------------
   7. GUARDS — reduced motion, mobile, print
   ------------------------------------------------------------ */
@media (prefers-reduced-motion:reduce){
  /* Final state, no motion — matches base.css:229-233. */
  .tlx-anim [class*="tlx-in-"]{
    opacity:1 !important;transform:none !important;filter:none !important;
    clip-path:none !important;stroke-dashoffset:0 !important;transition:none !important;
  }
  .beam,.sheen::after,.emit,.ground-dark [class*="tlxAmbient"]{animation:none !important}
  .tlx-scrub,.tlx-scrub-fade{animation:none !important}
  /* SMIL ignores media queries entirely — it must be display:none'd. */
  .ground-dark animateMotion,.ground-dark animate{display:none}
}

@media (max-width:860px){
  /* Kill blurred layers outright on small screens. A paused blur still
     composites every frame; only display:none actually stops the cost. */
  .beam{display:none}
  .sheen::after{display:none}
  .ground-lit::before{opacity:.4}
}

@media print{
  .beam,.sheen::after,.horizon{display:none}
  .ground-dark{background:#08365D !important;-webkit-print-color-adjust:exact;print-color-adjust:exact}
}
