/* ==========================================================================
   AttiCali effects layer (2026-10-18, approved by Isaac)
   Rebuilt from scratch, no library. Loaded after style.css on the homepage.

   Rules this file follows:
   - Only transform / opacity animate (compositor work, no repaint, no blur
     filters), so nothing flickers over the WebGL light layers.
   - Every looping effect is PAUSED by default. js/effects-pause.js adds
     .fx-run only while the element is on screen, max 3 at once.
   - prefers-reduced-motion: everything is static (bottom of file).

   Hooks (class names used in index.html):
     .fx-beam-host  + <span class="fx-beam">   glowing streak around a box (1)
     .fx-ring                                  spinning gradient border (2)
     .fx-float      + <span class="fx-sheen">  float + light sweep (5)
     .fx-live                                  pulsing sky dot (10)
     .btn-book                                 soft orange glow (static)
   ========================================================================== */

:root{
  --fx-green:#1E7A46;
  --fx-sky:#3BA9DA;
  --fx-mint:#EAF4EC;
  --fx-orange:240,138,43;   /* rgb triplet of #F08A2B */
}

/* Default: every looping animation waits for .fx-run */
.fx-beam::before,
.fx-ring::before,
.fx-float,
.fx-sheen::before,
.fx-live::after{animation-play-state:paused}
.fx-run.fx-beam-host .fx-beam::before,
.fx-run.fx-ring::before,
.fx-run.fx-float,
.fx-run.fx-float .fx-sheen::before,
.fx-run.fx-live::after{animation-play-state:running}

/* --------------------------------------------------------------------------
   (1) Border streak. The span sits 4px outside the box and BEHIND it
   (z-index:-1, host is not a stacking context), so the box's own background
   hides the middle and only a thin edge shows. Inside, an oversized square
   with a conic gradient rotates (transform only); the rounded overflow clip
   turns it into a streak running along the edge.
   -------------------------------------------------------------------------- */
.fx-beam-host{position:relative}
.fx-beam{
  position:absolute;inset:-4px;z-index:-1;pointer-events:none;
  border-radius:calc(var(--fx-r,26px) + 4px);
  overflow:hidden;
  background:rgba(234,244,236,.18);          /* faint static rim */
}
.fx-beam::before{
  content:"";position:absolute;left:50%;top:50%;
  width:max(160%,700px);aspect-ratio:1;
  translate:-50% -50%;
  background:conic-gradient(from 0deg, /* taste-skill-ignore: the approved border-streak effect IS a gradient (Isaac 2026-10-18) */
    transparent 0 68%,
    rgba(30,122,70,0) 68%,
    var(--fx-green) 80%,
    var(--fx-sky) 92%,
    var(--fx-mint) 96%,
    transparent 97% 100%);
  animation:fx-spin 6s linear infinite paused;
  will-change:transform;
}
/* Booking form: big radius */
.form.fx-beam-host{--fx-r:34px}

/* Offers box: becomes a soft panel so the streak has an edge to run on */
.bk-offers.fx-beam-host{
  --fx-r:26px;
  background:#155E35;                        /* = --green-deep, same as the steps box */
  border-radius:var(--fx-r);
  padding:clamp(14px,1.6vw,20px);
}
.bk-offers.fx-beam-host .tickets{margin:0 0 10px}

/* --------------------------------------------------------------------------
   (2) Spinning gradient border on the hero "$300 off" chip.
   Chip turns into an isolated stack: rotating conic (bottom), paper fill
   2px smaller (middle), text (top). Transform-only rotation.
   -------------------------------------------------------------------------- */
.hero-facts li.fx-ring{
  position:relative;isolation:isolate;overflow:hidden;
  background:transparent;
}
.fx-ring::before{
  content:"";position:absolute;left:50%;top:50%;z-index:-2;
  width:max(140%,280px);aspect-ratio:1;
  translate:-50% -50%;
  /* brighter, faster spark (Isaac 2026-10-18): a bright sky-to-white streak racing around a green border */
  background:conic-gradient(from 0deg, /* taste-skill-ignore: approved spinning-border effect */
    var(--fx-green) 0 52%, var(--fx-sky) 66%, #ffffff 76%, var(--fx-sky) 84%, var(--fx-green) 96%);
  animation:fx-spin 3.2s linear infinite paused;
  will-change:transform;
}
.fx-ring::after{
  content:"";position:absolute;inset:3px;z-index:-1;
  border-radius:inherit;background:var(--paper,#FAFAF7);
}

/* --------------------------------------------------------------------------
   (5) Gentle float on the coupons + a light sweep across the $300 coupon.
   The sweep lives inside the coupon's main area (overflow clipped there),
   never over a photo.
   -------------------------------------------------------------------------- */
.fx-float{animation:fx-float 6s ease-in-out infinite paused;will-change:transform}
.fx-sheen{position:absolute;inset:0;overflow:hidden;border-radius:inherit;pointer-events:none;z-index:0}
.fx-sheen::before{
  content:"";position:absolute;top:0;bottom:0;left:0;width:60%;
  background:linear-gradient(105deg,transparent 20%,rgba(255,255,255,.75) 50%,transparent 80%); /* taste-skill-ignore: approved light-sweep effect */
  transform:translateX(-120%);
  animation:fx-sweep 7s ease-in-out 1.2s infinite paused;
}
.bk-offers .t-main{position:relative}
.bk-offers .t-main > p{position:relative;z-index:1}

/* --------------------------------------------------------------------------
   (10) Small sky dot next to the office hours. It pulses only while the
   office is open (js/business-hours.js adds .is-open); otherwise a calm
   static dot, so we never suggest "open now" at night.
   -------------------------------------------------------------------------- */
.fx-hours{white-space:nowrap}
.fx-live{
  position:relative;display:inline-block;flex:none;
  width:10px;height:10px;margin-right:8px;vertical-align:.08em;
  border-radius:50%;background:var(--fx-sky);
  outline:2px solid rgba(255,255,255,.85);
}
.fx-live::after{
  content:"";position:absolute;inset:0;border-radius:50%;
  background:var(--fx-sky);opacity:0;
}
.fx-live.is-open::after{animation:fx-ping 1.9s ease-out infinite paused}
.fx-run.fx-live.is-open::after{animation-play-state:running}
.fx-live:not(.is-open){background:var(--fx-mint)}

/* --------------------------------------------------------------------------
   Soft orange glow under Book buttons. Static radial gradient painted once
   (no box-shadow recalculation, no filter); brightens on hover via opacity.
   It sits below the label (z-index:-1 in the button's own stack); over the
   orange fill it is invisible, beyond the edge it reads as a warm halo.
   -------------------------------------------------------------------------- */
.btn-book{position:relative;isolation:isolate}
.btn-book::before{
  content:"";position:absolute;z-index:-1;pointer-events:none;
  left:2%;right:2%;top:30%;bottom:-30px;
  border-radius:50%;
  background:radial-gradient(50% 50% at 50% 55%,rgba(var(--fx-orange),.8) 0%,rgba(var(--fx-orange),.4) 45%,rgba(var(--fx-orange),0) 85%); /* taste-skill-ignore: approved soft glow under Book buttons */
  opacity:.85;transition:opacity .3s ease;
}
.btn-book:hover::before,.btn-book:focus-visible::before{opacity:1}

/* Keyframes (transform / opacity only) */
@keyframes fx-spin{to{transform:rotate(1turn)}}
@keyframes fx-float{0%,100%{transform:translateY(0)}50%{transform:translateY(-5px)}}
@keyframes fx-sweep{0%,55%{transform:translateX(-120%)}100%{transform:translateX(260%)}}
@keyframes fx-ping{0%{transform:scale(1);opacity:.85}100%{transform:scale(2.8);opacity:0}}

/* Reduced motion: keep the look, drop the movement */
@media (prefers-reduced-motion:reduce){
  .fx-beam::before,.fx-ring::before,.fx-float,.fx-sheen::before,.fx-live::after{animation:none !important}
  .fx-sheen{display:none}
  /* streak frozen at a nice spot on the top-right edge */
  .fx-beam::before{transform:rotate(.12turn)}
}

/* Header bar button: no halo (it would hang below the bar onto the page) */
.bar-book::before{display:none}

/* Phones: slimmer offers panel so the coupons keep their width */
@media (max-width:900px){
  .bk-offers.fx-beam-host{padding:10px}
}

/* --------------------------------------------------------------------------
   (6) One-time light sweep on the other hero boxes and buttons (Isaac 2026-10-18).
   Each crosses once, in sequence, right after the page loads, then stays calm.
   Uses a background-image layer, so the Book button's glow (::before) is untouched.
   -------------------------------------------------------------------------- */
.fx-once{
  background-image:linear-gradient(105deg,transparent 38%,rgba(255,255,255,.6) 50%,transparent 62%); /* taste-skill-ignore: one-time light sweep */
  background-repeat:no-repeat;background-size:260% 100%;background-position:130% 0;
  animation:fx-once-sweep 1.1s cubic-bezier(.23,1,.32,1) var(--fx-d,.6s) 1 both;
}
@keyframes fx-once-sweep{from{background-position:130% 0}to{background-position:-30% 0}}
@media (prefers-reduced-motion:reduce){.fx-once{animation:none;background-image:none}}
/* (6b) make sure the one-time sweep wins over the chips' own background shorthand, and use a
   sky-blue light on the white Call button (a white light is invisible on white). */
.hero-facts li.fx-once,.hero-ctas .btn.fx-once{
  background-image:linear-gradient(105deg,transparent 36%,rgba(255,255,255,.75) 50%,transparent 64%) !important; /* taste-skill-ignore: one-time light sweep */
  background-repeat:no-repeat !important;background-size:260% 100% !important;
}
.hero-ctas .btn-ghost.fx-once{
  background-image:linear-gradient(105deg,transparent 36%,rgba(59,169,218,.55) 50%,transparent 64%) !important; /* taste-skill-ignore: one-time light sweep */
}
@media (prefers-reduced-motion:reduce){.hero-facts li.fx-once,.hero-ctas .btn.fx-once{background-image:none !important}}
