/* =====================================================================
   HOUSE MOTION KIT — house-motion.css
   Willow Rain Company LLC · the shared motion language for every house
   surface. One import:
       <link rel="stylesheet" href="/assets/house-motion.css">
       <script src="/assets/house-motion.js" defer></script>
   Standard: ~/workspace/launch-ops/motion-system/MOTION-STANDARD.md

   Rules baked in:
   - Motion TELLS the work-state. A character's animation is a status
     readout, never decoration for its own sake.
   - Transform + opacity only on animated elements (no layout thrash).
   - Nothing here may delay a task, a form, or a payment.
   - prefers-reduced-motion stills EVERYTHING below.
   ===================================================================== */

:root{
  /* Timing tokens — AA's living-head language (index.css, Oct 2026)
     promoted to the house standard. */
  --hm-glance: 7.5s;    /* idle eye/head glance cycle            */
  --hm-blink: 5.8s;     /* blink cycle                           */
  --hm-bob: 6.5s;       /* idle body bob                         */
  --hm-think: 2.8s;     /* thinking cycle                        */
  --hm-work: 1.7s;      /* working cycle                         */
  --hm-press: 160ms;    /* button press                            */
  --hm-pop: 420ms;      /* success pop                             */
  --hm-reveal: 520ms;   /* entrance reveal                       */
  --hm-ease: cubic-bezier(.22,.9,.28,1);        /* house ease-out   */
  --hm-spring: cubic-bezier(.34,1.56,.64,1);    /* house spring     */
  /* Character colors — palette law: obsidian black + ultra white,
     ONE vivid accent per surface. */
  --hm-ant: #101016;
  --hm-ant-accent: #7c3aed;
}

/* ---------------- The character rig (Chief Ant, SVG) ----------------
   Markup (house-motion.js builds it, or copy the SVG by hand):
     <span class="hm-ant" data-state="idle"></span>
   States: idle · thinking · working · attention · done ·
           celebrating · sleeping
--------------------------------------------------------------------- */
.hm-ant{ display:inline-flex; line-height:0; }
.hm-ant svg{ display:block; overflow:visible; }
.hm-ant .hm-ant-body{ transform-box:fill-box; transform-origin:50% 80%; }
.hm-ant .hm-pupils{ transform-box:fill-box; transform-origin:center; }
.hm-ant .hm-eyes{ transform-box:fill-box; transform-origin:center; }
.hm-ant .hm-ant-a,
.hm-ant .hm-ant-b{ transform-box:fill-box; }
.hm-ant .hm-ant-a{ transform-origin:90% 95%; }
.hm-ant .hm-ant-b{ transform-origin:10% 95%; }
.hm-ant .hm-zzz{ opacity:0; font:700 13px/1 system-ui,sans-serif; fill:var(--hm-ant-accent); }

/* idle — breathe + bob; eyes glance and blink */
.hm-ant[data-state="idle"] .hm-ant-body{ animation:hm-breathe var(--hm-bob) ease-in-out infinite; }
.hm-ant[data-state="idle"] .hm-pupils{ animation:hm-glance var(--hm-glance) ease-in-out infinite; }
.hm-ant[data-state="idle"] .hm-eyes{ animation:hm-blink var(--hm-blink) ease-in-out infinite; }

/* thinking — head tilts up, eyes search, antennae slow-wave */
.hm-ant[data-state="thinking"] .hm-ant-body{ animation:hm-think var(--hm-think) ease-in-out infinite; }
.hm-ant[data-state="thinking"] .hm-pupils{ animation:hm-look-up var(--hm-think) ease-in-out infinite; }
.hm-ant[data-state="thinking"] .hm-ant-a{ animation:hm-antenna-slow var(--hm-think) ease-in-out infinite; }

/* working — brisk side-to-side, antennae busy */
.hm-ant[data-state="working"] .hm-ant-body{ animation:hm-work var(--hm-work) ease-in-out infinite; }
.hm-ant[data-state="working"] .hm-ant-a{ animation:hm-antenna-busy var(--hm-work) ease-in-out infinite; }
.hm-ant[data-state="working"] .hm-ant-b{ animation:hm-antenna-busy var(--hm-work) ease-in-out infinite reverse; }
.hm-ant[data-state="working"] .hm-pupils{ animation:hm-glance-work var(--hm-work) ease-in-out infinite; }

/* attention — pulse (something needs the human) */
.hm-ant[data-state="attention"] .hm-ant-body{ animation:hm-attn 2.4s ease-in-out infinite; }
.hm-ant[data-state="attention"] .hm-pupils{ transform:scale(1.12); }

/* done — one soft contented blink-and-settle, then calm */
.hm-ant[data-state="done"] .hm-ant-body{ animation:hm-settle 4.5s ease-in-out infinite; }
.hm-ant[data-state="done"] .hm-eyes{ animation:hm-blink var(--hm-blink) ease-in-out infinite; }

/* celebrating — the win beat: two jumps + antennae wave (JS removes
   the state after ~1.6s and lands on done) */
.hm-ant[data-state="celebrating"] .hm-ant-body{ animation:hm-celebrate 800ms var(--hm-spring) 2; }
.hm-ant[data-state="celebrating"] .hm-ant-a{ animation:hm-antenna-wave 400ms ease-in-out 4; }
.hm-ant[data-state="celebrating"] .hm-ant-b{ animation:hm-antenna-wave 400ms ease-in-out 4 reverse; }

/* sleeping — slow deep breathe, eyes shut, a drifting z */
.hm-ant[data-state="sleeping"] .hm-ant-body{ animation:hm-breathe 9s ease-in-out infinite; }
.hm-ant[data-state="sleeping"] .hm-eyes{ transform:scaleY(.08); }
.hm-ant[data-state="sleeping"] .hm-zzz{ animation:hm-zzz 3.6s ease-in infinite; }

@keyframes hm-breathe{ 0%,100%{ transform:translateY(0) scale(1,1);} 50%{ transform:translateY(-2px) scale(1.015,.985);} }
@keyframes hm-glance{
  0%,16%{ transform:translateX(0);} 23%,38%{ transform:translateX(-2.6px);}
  45%,61%{ transform:translateX(0);} 68%,83%{ transform:translateX(2.6px);} 90%,100%{ transform:translateX(0);} }
@keyframes hm-blink{ 0%,91%,98%,100%{ transform:scaleY(1);} 94%{ transform:scaleY(.08);} }
@keyframes hm-think{ 0%,20%{ transform:rotate(0deg);} 35%,55%{ transform:rotate(-4deg) translateY(-1px);} 70%,88%{ transform:rotate(3deg) translateY(-1px);} 100%{ transform:rotate(0deg);} }
@keyframes hm-look-up{ 0%,20%{ transform:translate(0,0);} 35%,55%{ transform:translate(-2px,-2px);} 70%,88%{ transform:translate(2px,-2px);} 100%{ transform:translate(0,0);} }
@keyframes hm-work{ 0%,100%{ transform:rotate(-3deg) translateX(-1.4px);} 50%{ transform:rotate(3deg) translateX(1.4px);} }
@keyframes hm-glance-work{ 0%,100%{ transform:translateX(-2.6px);} 50%{ transform:translateX(2.6px);} }
@keyframes hm-antenna-busy{ 0%,100%{ transform:rotate(-7deg);} 50%{ transform:rotate(8deg);} }
@keyframes hm-antenna-slow{ 0%,100%{ transform:rotate(-3deg);} 50%{ transform:rotate(4deg);} }
@keyframes hm-antenna-wave{ 0%,100%{ transform:rotate(-14deg);} 50%{ transform:rotate(16deg);} }
@keyframes hm-attn{ 0%,100%{ transform:scale(1);} 50%{ transform:scale(1.05);} }
@keyframes hm-settle{ 0%,72%,100%{ transform:translateY(0) scale(1,1);} 80%{ transform:translateY(-1.6px) scale(1.02,.94);} 88%{ transform:translateY(-.8px) scale(1.01,.98);} }
@keyframes hm-celebrate{ 0%,100%{ transform:translateY(0) scale(1,1);} 30%{ transform:translateY(1px) scale(1.06,.9);} 55%{ transform:translateY(-9px) scale(.97,1.05);} 75%{ transform:translateY(0) scale(1.03,.96);} }
@keyframes hm-zzz{ 0%{ opacity:0; transform:translate(0,0);} 25%{ opacity:.9;} 100%{ opacity:0; transform:translate(7px,-13px);} }

/* Light-body variant for dark surfaces (e.g. the Obsidian Pay sheet):
   the ant goes ultra-white so its eyes invert and stay readable. */
.hm-ant--light{ --hm-ant:#e9ebf7; }
.hm-ant--light .hm-eyes > circle{ fill:#101016; }
.hm-ant--light .hm-pupils circle{ fill:#fff; }
.hm-ant--light path[stroke="#fff"]{ stroke:#101016; }

/* Raster variant — for surfaces whose character is a rendered head
   image (Anthony Asi's head set): same timings, micro head-turns.
   <img class="hm-head" data-state="idle"> */
.hm-head{ transform-origin:50% 62%; }
.hm-head[data-state="idle"]{ animation:hm-head-idle var(--hm-glance) ease-in-out infinite; }
.hm-head[data-state="thinking"]{ animation:hm-head-think var(--hm-think) ease-in-out infinite; }
.hm-head[data-state="working"]{ animation:hm-head-work var(--hm-work) ease-in-out infinite; }
.hm-head[data-state="attention"]{ animation:hm-attn 2.4s ease-in-out infinite; }
.hm-head[data-state="done"]{ animation:hm-settle 4.5s ease-in-out infinite; }
.hm-head[data-state="celebrating"]{ animation:hm-celebrate 800ms var(--hm-spring) 2; }
.hm-head[data-state="sleeping"]{ animation:hm-breathe 9s ease-in-out infinite; }
@keyframes hm-head-idle{
  0%,16%{ transform:rotate(0deg) translateX(0);} 23%,38%{ transform:rotate(-2.6deg) translateX(-1.5px);}
  45%,61%{ transform:rotate(0deg) translateX(0);} 68%,83%{ transform:rotate(2.6deg) translateX(1.5px);}
  90%,100%{ transform:rotate(0deg) translateX(0);} }
@keyframes hm-head-think{
  0%,20%{ transform:rotate(0deg) translate(0,0);} 35%,55%{ transform:rotate(-3.4deg) translate(-1.6px,-1.6px);}
  70%,88%{ transform:rotate(2.8deg) translate(1.6px,-1.6px);} 100%{ transform:rotate(0deg) translate(0,0);} }
@keyframes hm-head-work{ 0%,100%{ transform:rotate(-3.2deg) translateX(-1.8px);} 50%{ transform:rotate(3.2deg) translateX(1.8px);} }

/* ---------------- Buttons & micro-interactions ------------------- */
.hm-btn{
  transition:transform var(--hm-press) var(--hm-ease), box-shadow var(--hm-press) var(--hm-ease),
             background-color 200ms ease, opacity 200ms ease;
  -webkit-tap-highlight-color:transparent;
}
.hm-btn:active,.hm-btn.hm-pressing{ transform:scale(.965); }
.hm-btn:disabled{ cursor:wait; }
/* Loading: label dims, spinner rides the button — the button never
   changes size (no layout shift at a payment moment). */
.hm-btn[data-loading="true"]{ pointer-events:none; }
.hm-btn[data-loading="true"] .hm-btn-label{ opacity:.55; }
.hm-btn .hm-spinner{
  display:none; width:1em; height:1em; margin-right:.5em; vertical-align:-.12em;
  border-radius:50%; border:2px solid currentColor; border-top-color:transparent;
}
.hm-btn[data-loading="true"] .hm-spinner{ display:inline-block; animation:hm-spin .7s linear infinite; }
@keyframes hm-spin{ to{ transform:rotate(360deg);} }
/* Success pop — one spring beat when an action lands. */
.hm-pop{ animation:hm-pop var(--hm-pop) var(--hm-spring); }
@keyframes hm-pop{ 0%{ transform:scale(1);} 35%{ transform:scale(1.06);} 100%{ transform:scale(1);} }
/* Attention ring for the one CTA that matters on a screen (hub
   buttons, primary offers) — a soft breathing halo, never strobing. */
.hm-halo{ position:relative; }
.hm-halo::after{
  content:""; position:absolute; inset:-3px; border-radius:inherit; pointer-events:none;
  border:2px solid var(--hm-ant-accent); opacity:0; animation:hm-halo 3.2s ease-in-out infinite;
}
@keyframes hm-halo{ 0%,100%{ opacity:0; transform:scale(1);} 50%{ opacity:.45; transform:scale(1.03);} }

/* ---------------- Living icons ----------------------------------- */
.hm-icon{ display:inline-flex; transform-origin:center; }
.hm-icon[data-live="working"]{ animation:hm-icon-work 1.4s ease-in-out infinite; }
.hm-icon[data-live="spin"]{ animation:hm-spin 1.1s linear infinite; }
.hm-icon[data-live="pulse"]{ animation:hm-attn 2.4s ease-in-out infinite; }
@keyframes hm-icon-work{ 0%,100%{ transform:rotate(-6deg);} 50%{ transform:rotate(6deg);} }

/* ---------------- Entrances -------------------------------------- */
/* Stagger with style="--hm-i:2" (0-based). Entrance only — elements
   are fully visible if CSS fails to load late. */
.hm-reveal{ animation:hm-reveal var(--hm-reveal) var(--hm-ease) both; animation-delay:calc(var(--hm-i,0)*70ms); }
@keyframes hm-reveal{ from{ opacity:0; transform:translateY(10px);} to{ opacity:1; transform:translateY(0);} }
.hm-sheet-in{ animation:hm-sheet-in 460ms var(--hm-spring) both; }
@keyframes hm-sheet-in{ from{ opacity:0; transform:translateY(14px) scale(.985);} to{ opacity:1; transform:translateY(0) scale(1);} }

/* ---------------- Living background ------------------------------
   Optional slow drift for hero fields on the hyper-vivid palette.
   Paint-only and SLOW by law; never behind forms or amounts. */
.hm-bg-drift{
  background-size:180% 180%;
  animation:hm-drift 26s ease-in-out infinite alternate;
}
@keyframes hm-drift{ from{ background-position:0% 40%;} to{ background-position:100% 60%;} }

/* ---------------- Reduced motion: the law ------------------------ */
@media (prefers-reduced-motion: reduce){
  .hm-ant *, .hm-head, .hm-btn, .hm-icon, .hm-halo::after,
  .hm-reveal, .hm-sheet-in, .hm-bg-drift, .hm-pop{
    animation:none !important; transition:none !important;
  }
}
