/* ══════════════════════════════════════════════════════════════════════════════════════════════
   glance-motion.css — the interaction layer for glance.report
   ══════════════════════════════════════════════════════════════════════════════════════════════

   WHY THIS IS ONE FILE AND NOT 28 EDITS

   Every page on this site carries its own inline <style> block, so `.card` is declared 28 times
   with 28 chances to drift. Adding hover states inline would have meant 28 copies of the same
   rule and 28 places for the next person to miss one. This is linked LAST in each <head>, after
   the inline block, so it wins on source order at equal specificity without needing !important.

   WHAT IT DOES NOT TOUCH

   `.rd-card`, `.rd-boardcard` and everything else under `.rd-*` are the scroll-replayed demo
   blocks driven by glance-demos.js — an IntersectionObserver toggles `.in` and the animation is
   parked until then. `scripts/check-anim.mjs` fails the deploy if those stop moving. Adding a
   transition to them would fight the keyframes that are the whole point of them. They are out
   of scope here, on purpose.

   THE RULE THAT DECIDES WHAT GETS WHAT

   A resting shadow is DEPTH — it says "this is a surface". A hover lift is a PROMISE — it says
   "this responds to you". Static content cards get the first and not the second. Only cards that
   are actually anchors get the lift, because motion that implies a click where there is none is
   the thing a careful visitor notices and quietly distrusts.
   ══════════════════════════════════════════════════════════════════════════════════════════════ */

:root{
  /* Same two speeds and three curves as the app's design system, so the site and the product
     move at the same rate. See docs/glance/DESIGN_SYSTEM.md § Spacing and motion tokens. */
  --dur-fast:120ms; --dur-base:150ms; --dur-slow:400ms;
  --ease-standard:ease; --ease-out:ease-out; --ease-glide:cubic-bezier(.22,1,.36,1);

  /* Elevation. `--shadow` already exists per page and is the RAISED weight (0 16px 42px) — it is
     used on buttons and the header. These two add the step below it and the step above, keyed to
     the warm paper palette rather than neutral grey, or the shadow reads blue against #f5f2ea. */
  --shadow-resting:0 1px 2px rgba(60,45,20,.05), 0 6px 18px rgba(60,45,20,.06);
  --shadow-raised:0 2px 4px rgba(60,45,20,.07), 0 18px 44px rgba(60,45,20,.16);
  --lift:-3px;
}

:root[data-theme="dark"]{
  --shadow-resting:0 1px 2px rgba(0,0,0,.30), 0 6px 18px rgba(0,0,0,.28);
  --shadow-raised:0 2px 4px rgba(0,0,0,.38), 0 18px 44px rgba(0,0,0,.52);
}

/* ── 1. Depth on every card surface ───────────────────────────────────────────────────────────
   These cards were border-only. On a warm paper background a 1px line is the entire separation
   between a card and the page, which is why a grid of them reads flat.

   The list is not guesswork — it is every class in the site's inline styles matching the card
   pattern (`background:var(--panel)` + `border:1px solid var(--line)` + `border-radius`).
   `.card` alone would have missed six of the twenty-eight pages: pricing.html has no `.card` at
   all, it has `.tier`; compare.html has `.cmp-card`; solutions.html has `.scard`.

   DELIBERATELY EXCLUDED, all of which match the pattern but are not top-level surfaces:
     .sup, .kpi     sit on --panel2 INSIDE another card. A shadow on a nested panel reads as a
                    card floating inside a card.
     .sw, .tablewrap  scroll/overflow wrappers with no background of their own.
     .mock          the device frame around a product screenshot — it is a picture, not a card.
     .rv-form       a form container; elevation would compete with the inputs inside it. */
.card,.scard,.cmp-card,.aicard,.rv-card,.tier,.pl,.way,.perk,.addon,
.fstep,.job,.stat,.op,.bwrap,.pollbox{
  box-shadow:var(--shadow-resting);
  transition:border-color var(--dur-base) var(--ease-standard),
             box-shadow var(--dur-base) var(--ease-standard),
             transform var(--dur-fast) var(--ease-standard);
}

/* ── 2. Lift only what clicks ─────────────────────────────────────────────────────────────────
   Gated on a real pointer: on a phone `:hover` latches after the tap and the card stays raised
   until you touch elsewhere. `.cards.audience .card` already lifted before this file existed —
   it is restated here at matching specificity so it takes the shared value instead of its own.

   Written as `a.<class>` throughout: today only three cards on the site are anchors (all on
   index.html), but writing it against the element rather than a hand-listed subset means a card
   that BECOMES a link later gets the affordance without anyone remembering to come back here. */
@media (hover:hover) and (pointer:fine){
  a.card:hover,a.scard:hover,a.cmp-card:hover,a.tier:hover,a.pl:hover,a.way:hover,
  a.perk:hover,a.addon:hover,a.fstep:hover,a.job:hover,a.stat:hover,a.op:hover,
  .cards.audience .card:hover{
    transform:translateY(var(--lift));
    box-shadow:var(--shadow-raised);
  }
}

/* Keyboard parity. Tabbing through a row of cards should read the same as running a mouse over
   it — outline rather than a border swap, so focus never changes the box and shifts the layout. */
a.card:focus-visible,a.scard:focus-visible,a.cmp-card:focus-visible,a.tier:focus-visible,
a.pl:focus-visible,a.way:focus-visible,a.perk:focus-visible,a.addon:focus-visible,
a.fstep:focus-visible,a.job:focus-visible,a.stat:focus-visible,a.op:focus-visible,
.cards.audience .card:focus-visible{
  outline:2px solid var(--accent);
  outline-offset:3px;
  transform:translateY(var(--lift));
  box-shadow:var(--shadow-raised);
}

a.card:active,a.scard:active,a.cmp-card:active,a.tier:active,a.pl:active,a.way:active,
a.perk:active,a.addon:active,a.fstep:active,a.job:active,a.stat:active,a.op:active,
.cards.audience .card:active{
  transform:translateY(0);
  box-shadow:var(--shadow-resting);
  transition-duration:var(--dur-fast);
}

/* ── 3. Buttons ───────────────────────────────────────────────────────────────────────────────
   `.btn` already lifted 2px on hover but its shadow stayed put, so it slid rather than rose.
   The shadow now travels with it, and the press returns it to the resting weight. */
.btn{
  transition:transform var(--dur-fast) var(--ease-standard),
             box-shadow var(--dur-base) var(--ease-standard),
             border-color var(--dur-base) var(--ease-standard);
}
@media (hover:hover) and (pointer:fine){
  .btn:hover{box-shadow:var(--shadow-raised)}
  .btn.ghost:hover{box-shadow:var(--shadow-resting);border-color:var(--accent)}
}
.btn:active{transform:translateY(0);box-shadow:var(--shadow-resting)}
.btn:focus-visible{outline:2px solid var(--accent);outline-offset:3px}

/* ── 4. Reduced motion drops the MOVEMENT, not the feedback ───────────────────────────────────
   Someone who asked for less animation still needs to know what is under the cursor, so the
   shadow and border still respond — only the translate is removed. */
@media (prefers-reduced-motion:reduce){
  .card,.scard,.cmp-card,.aicard,.rv-card,.tier,.pl,.way,.perk,.addon,
  .fstep,.job,.stat,.op,.bwrap,.pollbox,.btn{
    transition:border-color var(--dur-base) var(--ease-standard),
               box-shadow var(--dur-base) var(--ease-standard);
  }
  a.card:hover,a.scard:hover,a.cmp-card:hover,a.tier:hover,a.pl:hover,a.way:hover,
  a.perk:hover,a.addon:hover,a.fstep:hover,a.job:hover,a.stat:hover,a.op:hover,
  .cards.audience .card:hover,
  a.card:focus-visible,a.scard:focus-visible,a.cmp-card:focus-visible,a.tier:focus-visible,
  a.pl:focus-visible,a.way:focus-visible,a.perk:focus-visible,a.addon:focus-visible,
  a.fstep:focus-visible,a.job:focus-visible,a.stat:focus-visible,a.op:focus-visible,
  .cards.audience .card:focus-visible,
  .btn:hover,.btn:active{
    transform:none;
  }
}

/* ── 5. Paper ─────────────────────────────────────────────────────────────────────────────────
   A 44px shadow prints as a band of grey. */
@media print{
  .card,.scard,.cmp-card,.aicard,.rv-card,.tier,.pl,.way,.perk,.addon,
  .fstep,.job,.stat,.op,.bwrap,.pollbox,.btn{box-shadow:none;transform:none}
}
