/* mws-site-kit v0.1.0 | patterns.css
   ==========================================================================
   The reusable structural and motion patterns.
   Depends on tokens.css + base.css. Pairs with patterns.js.

   Four things live here:
     1. Torn edge   - the structural signature
     2. Reveal      - fade/rise on scroll
     3. Card entrance - the gravity "slam"
     4. Mode hooks  - featured item, weather canvas
   ========================================================================== */


/* ==========================================================================
   1. TORN EDGE

   A band with a ragged bottom edge. The mechanism is generic; the SVG path
   is generated per site by tear.js (see js/tear.js), so every client gets a
   different edge from the same six lines of CSS.

   Usage:
     <section class="band band--tear">
       ...content...
       <div class="tear" data-tear="torn" style="--tear-fill:var(--paper)"></div>
     </section>

   --tear-fill must be the colour of the section BELOW, because the shape is
   cut out of the next section and laid over this one. Getting this backwards
   is the single most common mistake with this pattern.
   ========================================================================== */
.band{position:relative}

/* Reserve room so the edge never eats the band's own content. */
.band--tear{padding-bottom:calc(var(--sp-6) + var(--tear-h))}

.tear{
  position:absolute;left:0;right:0;bottom:-1px;   /* -1px kills the hairline
                                                     seam that subpixel
                                                     rounding leaves at some
                                                     zoom levels */
  height:var(--tear-h);
  line-height:0;
  pointer-events:none;
}
.tear svg{width:100%;height:100%;display:block}
.tear path{fill:var(--tear-fill,var(--paper))}

/* Mirror the same generated edge for visual variety without a second path. */
.tear--flip svg{transform:scaleX(-1)}


/* ==========================================================================
   2. REVEAL ON SCROLL

   Add data-rv to anything that should fade and rise into view.
   Add data-rv-d="1".."6" to stagger siblings.

     <p class="eyebrow" data-rv>Troy, Ohio</p>
     <h1 data-rv data-rv-d="1">If it's in the way, it's gone.</h1>

   patterns.js adds .in when the element intersects. If JS fails or
   IntersectionObserver is missing, patterns.js adds .in to everything
   immediately - content must never be invisible because a script broke.
   ========================================================================== */
[data-rv]{
  opacity:0;
  transform:translate3d(0,26px,0);
  transition:opacity .55s var(--ease-out),
             transform .55s var(--ease-out);
}
[data-rv].in{opacity:1;transform:none}

[data-rv-d="1"]{transition-delay:70ms}
[data-rv-d="2"]{transition-delay:140ms}
[data-rv-d="3"]{transition-delay:210ms}
[data-rv-d="4"]{transition-delay:280ms}
[data-rv-d="5"]{transition-delay:350ms}
[data-rv-d="6"]{transition-delay:420ms}

@media(prefers-reduced-motion:reduce){
  [data-rv]{opacity:1;transform:none}
}


/* ==========================================================================
   3. CARD ENTRANCE - "the slam"

   Cards fall under gravity, squash on impact, rebound, and settle. The
   per-keyframe easing is what makes it read as WEIGHT rather than as a
   fade with extra steps - accelerate in, decelerate out of the bounce.

   Tunable per site, on the grid or on an individual card:
     --slam-drop      how far above its resting place the card starts
     --slam-dur       total duration
     --tilt           per-card rotation while falling (set inline, varied)
     --d              start delay (patterns.js sets this per column)
   ========================================================================== */
.card{
  --slam-drop:-230px;
  --slam-dur:.95s;

  position:relative;
  background:var(--white);
  border:1px solid var(--ink-100);
  display:flex;flex-direction:column;
  transition:border-color .22s,box-shadow .26s var(--ease-out);

  /* Resting state before the animation runs. */
  opacity:0;
  transform:translate3d(0,var(--slam-drop),0) rotate(var(--tilt,0deg)) scale(1.06);
}
.card:hover{
  border-color:var(--brand-400);
  box-shadow:0 14px 34px rgba(20,23,11,.10);
}

.card.slam{
  animation:slam var(--slam-dur) var(--d,0ms) forwards;
  will-change:transform,opacity;
}

/* THE CLEANUP, AND IT IS LOAD-BEARING. Once a card has landed, drop the
   animation, the will-change hint and the blurred dust child.

   This is not tidiness. Leaving several animated composited layers alive
   causes stale paint tiles in Chromium - cards render half-drawn until
   something forces a repaint. Found once on the Limitless build; kept here
   so it is never rediscovered per site. patterns.js adds .landed on
   animationend. Do not remove either half. */
.card.landed{
  animation:none;
  will-change:auto;
  opacity:1;
  transform:none;
}
.card.landed .card__dust{display:none}

@keyframes slam{
  0%{
    opacity:0;
    transform:translate3d(0,var(--slam-drop),0) rotate(var(--tilt,0deg)) scale(1.06);
    animation-timing-function:cubic-bezier(.5,0,.75,.2);   /* accelerate: gravity */
  }
  14%{
    opacity:1;
    transform:translate3d(0,calc(var(--slam-drop) * .83),0) rotate(calc(var(--tilt,0deg) * .85)) scale(1.05);
    animation-timing-function:cubic-bezier(.5,0,.75,.2);
  }
  56%{                                                      /* touchdown */
    opacity:1;
    transform:translate3d(0,0,0) rotate(calc(var(--tilt,0deg) * .12)) scale(1);
    animation-timing-function:cubic-bezier(.2,.8,.3,1);
  }
  64%{                                                      /* squash */
    transform:translate3d(0,9px,0) rotate(0deg) scale(1.025,.955);
    animation-timing-function:cubic-bezier(.3,.7,.4,1);
  }
  76%{                                                      /* rebound + stretch */
    transform:translate3d(0,-8px,0) scale(.99,1.018);
  }
  87%{transform:translate3d(0,2.5px,0) scale(1.004,.995)}
  94%{transform:translate3d(0,-1px,0) scale(1)}
  100%{opacity:1;transform:none}
}

/* Dust kicks out at the moment of touchdown. Optional child:
     <span class="card__dust" aria-hidden="true"></span> */
.card__dust{
  position:absolute;left:4%;right:4%;bottom:-11px;height:22px;
  border-radius:50%;
  background:rgba(20,23,11,.30);
  filter:blur(9px);
  opacity:0;transform:scaleX(.35);
  pointer-events:none;
}
.card.slam .card__dust{animation:thud var(--slam-dur) var(--d,0ms) forwards}

@keyframes thud{
  0%,50%{opacity:0;transform:scaleX(.3) scaleY(.6)}
  58%   {opacity:.85;transform:scaleX(1.14) scaleY(1.1)}
  72%   {opacity:.45;transform:scaleX(1.02) scaleY(.9)}
  100%  {opacity:0;transform:scaleX(.92) scaleY(.8)}
}

/* If motion is reduced, cards are simply present. No fall, no dust. */
@media(prefers-reduced-motion:reduce){
  .card{opacity:1;transform:none}
  .card__dust{display:none}
}

/* ---------- minimal card shell ----------
   Enough structure for the entrance to have something to animate. Style
   the interior per site; these are sane defaults, not a design system. */
.card__media{
  position:relative;aspect-ratio:4/3;overflow:hidden;
  background:var(--brand-050);
  border-bottom:1px solid var(--ink-100);
}
.card__media img{
  width:100%;height:100%;object-fit:cover;
  transition:transform .6s var(--ease-out);
}
.card:hover .card__media img{transform:scale(1.045)}

.card__body{padding:clamp(1.1rem,2.2vw,1.5rem);flex:1}
.card h3{margin-bottom:.45rem}
.card p{font-size:var(--step--1);color:var(--ink-500);margin:0}

/* Accent rule that wipes across on hover. */
.card__rule{height:3px;background:var(--accent);width:0;transition:width .34s var(--ease-out)}
.card:hover .card__rule{width:100%}


/* ==========================================================================
   4. MODE HOOKS

   A "featured" item, promoted by the current mode. Pure CSS ordering, so
   promoting a card is one class and needs no DOM reshuffling.
   ========================================================================== */
.card{order:0}
.card.is-feat{
  order:-1;
  border-color:var(--accent);
  box-shadow:0 10px 30px rgba(20,23,11,.10);
}
.card.is-feat .card__rule{width:100%}

.card__flag{
  position:absolute;top:10px;right:10px;z-index:3;
  background:var(--accent);color:var(--ink-950);
  font:700 .68rem/1 var(--font-util);
  letter-spacing:.14em;text-transform:uppercase;
  padding:.4rem .6rem;border-radius:2px;
  opacity:0;transform:translateY(-6px);
  transition:opacity .35s var(--ease-out),transform .35s var(--ease-out);
}
.card.is-feat .card__flag{opacity:1;transform:none}

/* ---------- weather canvas ----------
   Positioning only. The particle system is js/weather.js and is OFF unless
   a site explicitly initialises it. z-index sits above content but below
   the header, and it never takes pointer events. */
.wx-canvas{
  position:fixed;inset:0;
  width:100%;height:100%;
  z-index:40;
  pointer-events:none;
  opacity:0;
  transition:opacity .8s ease;
}
.wx-canvas.on{opacity:1}
