/* Motion for the site: the app's stylesheet (app/idra-system.css) and the living mark's moves (app/idra-character.jsx), copied so the site needs neither the app nor React. Re-copy both when they change. */
  /* The swell lifts T.shadow.md (rest) to T.shadow.lg (peak); these two values mirror those tokens. */
  @keyframes idraBreathe { 0%,100% { transform: scale(1); box-shadow: 0 10px 22px -8px rgba(15,14,10,.5); } 50% { transform: scale(1.04); box-shadow: 0 18px 40px -12px rgba(15,14,10,.45); } }
  .idra-breathe { animation: idraBreathe 2.8s ease-in-out infinite; }
  @keyframes idraBreatheDot { 0%,100% { transform: scale(1); } 50% { transform: scale(1.1); } }
  .idra-breathe-dot { animation: idraBreatheDot 2.8s ease-in-out infinite; }
  @keyframes idraRingPulse { 0% { transform: scale(.66); opacity: .85; } 70% { transform: scale(1.7); opacity: 0; } 100% { opacity: 0; } }
  .idra-ring-pulse { animation: idraRingPulse 2.8s ease-out infinite; transform-box: fill-box; transform-origin: center; }
  @keyframes spin { to { transform: rotate(360deg); } }
  .idra-spin { animation: spin 1.4s linear infinite; }
  @keyframes idraPop { 0% { transform: scale(0); } 45% { transform: scale(1.35); } 70% { transform: scale(.9); } 86% { transform: scale(1.05); } 100% { transform: scale(1); } }
  .idra-pop { animation: idraPop .5s cubic-bezier(.3,.7,.4,1) both; }
  @keyframes idraConfirm { 0% { transform: scale(.88); } 45% { transform: scale(1.08); } 72% { transform: scale(.97); } 100% { transform: scale(1); } }
  .idra-confirm { animation: idraConfirm .4s cubic-bezier(.3,.7,.4,1) both; }
  @keyframes idraCheckDraw { from { stroke-dashoffset: 32; } to { stroke-dashoffset: 0; } }
  .idra-check-draw { stroke-dasharray: 32; stroke-dashoffset: 32; animation: idraCheckDraw .4s ease-out .28s forwards; }
  @keyframes idraNodeCheck { from { stroke-dashoffset: 23; } to { stroke-dashoffset: 0; } }
  .idra-node-check { stroke-dasharray: 23; stroke-dashoffset: 23; animation: idraNodeCheck .4s ease-out .2s forwards; }
  @keyframes idraFadeIn { from { opacity: 0; } to { opacity: 1; } }
  .idra-fade-in { animation: idraFadeIn .4s ease both; }
  @keyframes idraRise { 0% { opacity: 0; transform: translateY(12px); } 60% { opacity: 1; transform: translateY(-2px); } 100% { opacity: 1; transform: none; } }
  .idra-rise { animation: idraRise .4s cubic-bezier(.3,.7,.4,1) both; }
  @keyframes idraMarkPulse { 0% { transform: scale(1); } 38% { transform: scale(1.16); } 100% { transform: scale(1); } }
  .idra-mark-pulse { display: flex; flex: 0 0 auto; animation: idraMarkPulse .5s cubic-bezier(.34,1.4,.64,1) both; }
  @keyframes idraWordIn { from { opacity: 0; transform: translateY(5px); } to { opacity: 1; transform: translateY(0); } }
  .idra-word-in { display: inline-block; max-width: 100%; white-space: pre-wrap; animation: idraWordIn .3s ease-out both; }
  @keyframes idraCrisisRise { from { opacity: 0; transform: translateY(48px) scale(.975); } to { opacity: 1; transform: translateY(0) scale(1); } }
  .crisis-rise { animation: idraCrisisRise .8s cubic-bezier(.22,.61,.36,1) both; }
  @keyframes idraRoutineLand { 0% { opacity: 0; transform: scale(.85) translateY(10px); } 45% { opacity: 1; transform: scale(1.06) translateY(-4px); } 70% { transform: scale(.98); } 100% { transform: none; } }
  .idra-routine-land { animation: idraRoutineLand .6s cubic-bezier(.3,.7,.4,1) both; }
  /* The check-in card landing out of the point — the check-in's own level 1 close. Same overshoot
     family as the routine card's landing, and deliberately not the same class: that one is a
     graduation, whose gold light is its own layer, and a daily moment cannot borrow level 3's light.
     The card animates GEOMETRY ONLY. Celebration light never touches a card's own box-shadow:
     box-shadow is a single property, so a keyframe that sets it replaces the whole declaration
     and — under fill-mode both — holds that replacement forever, taking the card's elevation and
     its gold hairline with it. The light is a sibling layer behind the card instead, the way
     idra-commit-bloom already does it, which is also what "a light rises around the card" means. */
  @keyframes idraCheckinLand { 0% { opacity: 0; transform: translateY(-40px) rotate(-5deg) scale(.9); } 50% { opacity: 1; transform: translateY(6px) rotate(1.5deg) scale(1.03); } 72% { transform: translateY(-3px) rotate(-.6deg); } 100% { transform: none; } }
  .idra-checkin-land { animation: idraCheckinLand .6s cubic-bezier(.25,.8,.35,1) both; }
  /* The check-in card's level 1 light: a pale sky halo rising around the day's card as it lands
     over its dimmed home screen.
     Sky, not gold — a daily level 1 cannot spend level 3's colour. */
  @keyframes idraCardLight {
    0% { opacity: 0; transform: scale(.82); }
    50% { opacity: 1; transform: scale(1.06); }
    100% { opacity: 0; transform: scale(1.12); }
  }
  .idra-card-light { animation: idraCardLight .9s cubic-bezier(.2,.65,.3,1) both; }
  @keyframes idraSparkle {
    0% { opacity: 0; transform: translate(0,0) scale(.3) rotate(0deg); }
    35% { opacity: 1; }
    100% { opacity: 0; transform: translate(calc(var(--sx,0px) * 2), calc(var(--sy,0px) * 2)) scale(1.1) rotate(60deg); }
  }
  .idra-sparkle { animation: idraSparkle .8s ease-out both; }
  /* The graduation field's sparks — same drift, slower and wider, so a screen-scale burst
     reads as one long rising shimmer rather than a fast pop around a card. */
  .idra-sparkle-slow { animation: idraSparkle 2.1s ease-out both; }
  /* Commit bloom — the moment an insight is saved, a behavior starts, or a breather begins:
     a soft sky light rises from under the card while the card itself lifts and settles. The tier
     between a plain state change and graduation's gold bloom, and it stays sky — amber light is
     graduation's alone, so the two moments never read as the same size. One-shot, on the commit. */
  @keyframes idraCommitBloom { 0% { opacity: 0; transform: translate(-50%,14%) scale(.6); } 28% { opacity: 1; } 100% { opacity: 0; transform: translate(-50%,-24%) scale(1.5); } }
  .idra-commit-bloom { animation: idraCommitBloom 1.3s cubic-bezier(.2,.65,.3,1) both; }
  @keyframes idraCommitLift { 0% { transform: none; } 30% { transform: translateY(-9px) scale(1.045); } 60% { transform: translateY(2px) scale(.99); } 100% { transform: none; } }
  .idra-commit-lift { animation: idraCommitLift .55s cubic-bezier(.3,.7,.4,1) both; }
  /* Graduation bloom — the earned, warm (not confetti) celebration: a soft gold light
     blooms out behind the card and two halo rings expand and fade. Daytime-energetic,
     still calm. Plays once with the sparkle burst. */
  @keyframes idraGoldBloom { 0% { opacity: 0; transform: translate(-50%,-50%) scale(.55); } 26% { opacity: .9; } 100% { opacity: 0; transform: translate(-50%,-50%) scale(1.7); } }
  .idra-gold-bloom { animation: idraGoldBloom 1.1s cubic-bezier(.2,.65,.3,1) both; }
  @keyframes idraHaloRing { 0% { opacity: .55; transform: translate(-50%,-50%) scale(.5); } 100% { opacity: 0; transform: translate(-50%,-50%) scale(2); } }
  .idra-halo-ring { animation: idraHaloRing 1s cubic-bezier(.2,.7,.3,1) both; }
  /* Graduation screen wash — the whole conversation briefly warms with a gold glow
     rising from where the card lands, so the screen itself marks the moment. One-shot. */
  @keyframes idraGoldWash { 0% { opacity: 0; } 24% { opacity: 1; } 58% { opacity: .8; } 100% { opacity: 0; } }
  .idra-gold-wash { animation: idraGoldWash 1.3s ease-in-out both; }
  /* Perfect-run wave — a gold halo blooms around each ring dot in sequence, once, when a
     run finishes with every day filled (no missed dot left). Plays on open, no loop.
     Shared by the live ring (wrap) and the frozen record ring. */
  @keyframes idraDotHalo { 0% { opacity: 0; transform: scale(.55); } 22% { opacity: .9; } 100% { opacity: 0; transform: scale(2); } }
  .idra-dot-halo { animation: idraDotHalo 1s ease-out both; transform-box: fill-box; transform-origin: center; }
  /* the traveling light itself — a glowing gold arc segment sweeps once around the
     ring track, passing (and lighting) each dot in turn. */
  @keyframes idraRingWave { 0% { opacity: 0; transform: rotate(-90deg); } 3% { opacity: 1; } 92% { opacity: 1; } 100% { opacity: 0; transform: rotate(270deg); } }
  .idra-ring-wave { animation: idraRingWave 2s linear both; transform-box: fill-box; transform-origin: center; }
  /* Card mint — a card made from other cards unwinds out of the point they went into, one and a
     half turns, and seats. The check-in's three answer cards turn 540° into their point and the
     day's card comes back out of it on this curve and duration; the round's close and the run's
     seal are made the same way. The turn says a card was minted here — it is not a celebration
     tier, so a plain record takes it as readily as an award, and it is always the whole card that
     turns, never a mark inside one. */
  @keyframes idraCardMint { from { opacity: 0; transform: rotate(-540deg) scale(.07); } to { opacity: 1; transform: rotate(0deg) scale(1); } }
  .idra-card-mint { animation: idraCardMint .5s cubic-bezier(.2,1.5,.4,1) .28s both; }
  /* Persistent routine shimmer — a slow gold sheen blooms out of the medallion the object is
     marked with, then rests. Ambient identity glow, not an alert. */
  @keyframes idraShimmer { 0%, 100% { opacity: 0; transform: translate(-50%,-50%) scale(.25); } 14% { opacity: .8; } 24% { opacity: .66; } 48% { opacity: 0; transform: translate(-50%,-50%) scale(1.75); } }
  .idra-shimmer { animation: idraShimmer 7s ease-in-out infinite; }
  /* Sheet entry — the panel travels up from the bottom edge while its scrim fades in with it,
     so the wash and the panel arrive as one movement. Decelerating, brisk: a sheet is a
     question, and the answer shouldn't be kept waiting. */
  @keyframes idraSheetRise { from { transform: translateY(100%); } to { transform: translateY(0); } }
  .idra-sheet-rise { animation: idraSheetRise .4s cubic-bezier(0,0,.2,1) both; }
  @keyframes idraScrimIn { from { opacity: 0; } to { opacity: 1; } }
  .idra-scrim-in { animation: idraScrimIn .4s cubic-bezier(0,0,.2,1) both; }
  /* The room's wall, lit — one short segment gliding around a closed edge, for the enclosure that
     holds Idra and the person on the confidentiality page. 12s, the ambient presence tempo, so it
     says the room is live without asking to be tapped. The dash geometry is the path's own, set
     where it is drawn. */
  @keyframes idraRoomLight { to { stroke-dashoffset: -579; } }
  .idra-room-light { animation: idraRoomLight 12s linear infinite; }
  /* Bell ring — the notifications bell swings from its crown, ±14° settling to rest over the first
     .9s of Idra's 2.8s clock, then holds still until the next cycle. */
  @keyframes idraBellRing { 0% { transform: rotate(0); } 5% { transform: rotate(14deg); } 10% { transform: rotate(-12deg); } 15% { transform: rotate(9deg); } 20% { transform: rotate(-6deg); } 25% { transform: rotate(3deg); } 32%, 100% { transform: rotate(0); } }
  .idra-bell-ring { display: flex; transform-origin: 50% 12%; animation: idraBellRing 2.8s ease-in-out infinite; }
  @media (prefers-reduced-motion: reduce) {
    .idra-breathe, .idra-breathe-dot, .idra-ring-pulse, .idra-spin, .idra-pop, .idra-confirm, .idra-rise, .idra-mark-pulse, .idra-word-in, .idra-routine-land, .idra-checkin-land, .idra-card-light, .idra-sparkle, .idra-sparkle-slow, .idra-commit-bloom, .idra-commit-lift, .idra-gold-bloom, .idra-halo-ring, .idra-gold-wash, .idra-dot-halo, .idra-ring-wave, .idra-card-mint, .idra-shimmer, .idra-room-light, .idra-bell-ring { animation: none; }
    /* Every transition cross-fades: the root fade stays, and a sheet, its scrim and the crisis
       surface fade in place over the same .4s instead of travelling. */
    .idra-sheet-rise, .idra-scrim-in, .crisis-rise { animation: idraFadeIn .4s ease both; }
    .idra-check-draw, .idra-node-check { animation: none; stroke-dashoffset: 0; }
  }

/* Tap feedback for whole-row targets (masthead identity row). Opacity only — no new color. */
.idra-tap{cursor:pointer}
.idra-tap:active{opacity:.62}

/* The living mark */

.lm g{transform-box:view-box}
.lm-fig,.lm-body{transform-origin:512px 840px}
.lm-arm{transform-origin:512px 540px;transition:transform .4s cubic-bezier(.32,.72,0,1)}
@keyframes lmBob{0%,100%{transform:none}50%{transform:translateY(-16px)}}
@keyframes lmTilt{0%,100%{transform:rotate(-4deg)}50%{transform:rotate(4deg)}}
.st-think .lm-body{animation:lmTilt 2.8s ease-in-out infinite}
.st-think .lm-armL{transform:rotate(-12deg)}.st-think .lm-armR{transform:rotate(12deg)}
@keyframes lmNod{0%,100%{transform:none}50%{transform:translateY(14px)}}
@keyframes lmParty{0%{transform:none}10%{transform:scale(1.12,.84)}28%{transform:translateY(-130px) scale(.94,1.08)}44%{transform:scale(1.1,.88)}56%{transform:translateY(-90px) rotate(-6deg)}70%{transform:scale(1.08,.9)}84%{transform:scale(.98,1.02)}100%{transform:none}}
@keyframes lmPartyL{0%,100%{transform:none}15%,85%{transform:rotate(82deg)}}@keyframes lmPartyR{0%,100%{transform:none}15%,85%{transform:rotate(-82deg)}}
.st-run .lm-fig{animation:lmParty 1.4s cubic-bezier(.3,.7,.4,1) both}.st-run .lm-armL{animation:lmPartyL 1.4s ease-in-out both}.st-run .lm-armR{animation:lmPartyR 1.4s ease-in-out both}
/* Wave — the arrival. She has been sitting while you were away: the figure starts low and squashed,
   springs up, then the right arm waves twice and the head bobs. Quick, since it plays on every arrival. */
@keyframes lmStandUp{0%{transform:translateY(120px) scale(1.08,.8)}22%{transform:translateY(-40px) scale(.95,1.06)}34%{transform:scale(1.05,.95)}42%,100%{transform:none}}
@keyframes lmWave{0%,30%,100%{transform:none}44%,72%{transform:rotate(-58deg)}58%,86%{transform:rotate(-38deg)}}
@keyframes lmWaveBob{0%,30%,100%{transform:none}65%{transform:translateY(-16px)}}
.st-hello .lm-fig{animation:lmStandUp 1.3s cubic-bezier(.3,.7,.4,1) both}.st-hello .lm-armR{animation:lmWave 1.3s ease-in-out both}.st-hello .lm-bob{animation:lmWaveBob 1.3s ease-in-out both}
/* Bouncy — Calm with more spring: higher bounces, a deeper squash, arms swinging up as she leaves
   the ground. The first of a level 2's two moves, played twice through. */
@keyframes lmBouncy{0%,100%{transform:none}30%{transform:translateY(-70px) scale(.95,1.06)}55%{transform:translateY(0) scale(1.1,.88)}70%{transform:translateY(-14px)}85%{transform:none}}
@keyframes lmBouncyL{0%,55%,100%{transform:rotate(6deg)}30%{transform:rotate(50deg)}}@keyframes lmBouncyR{0%,55%,100%{transform:rotate(-6deg)}30%{transform:rotate(-50deg)}}
.st-bouncy .lm-fig{animation:lmBouncy 1.2s cubic-bezier(.3,.7,.4,1) infinite}.st-bouncy .lm-armL{animation:lmBouncyL 1.2s ease-in-out infinite}.st-bouncy .lm-armR{animation:lmBouncyR 1.2s ease-in-out infinite}
@keyframes lmHop{0%,100%{transform:none}20%{transform:scale(1.08,.9)}45%{transform:translateY(-70px) scale(.96,1.05)}70%{transform:scale(1.05,.95)}}
.st-hop .lm-fig{animation:lmHop .7s cubic-bezier(.3,.7,.4,1) both}
@keyframes lmSpark{0%{opacity:0;transform:translate(0,0) scale(.3) rotate(0)}22%{opacity:1}100%{opacity:0;transform:translate(var(--sx),var(--sy)) scale(1) rotate(150deg)}}
.lm-spark{animation:lmSpark 1.1s cubic-bezier(.15,.7,.3,1) both}
@keyframes lmGlow{0%{opacity:0;transform:translate(-50%,-50%) scale(.5)}30%{opacity:1}100%{opacity:0;transform:translate(-50%,-50%) scale(2.2)}}
.lm-glow{animation:lmGlow 1.3s cubic-bezier(.2,.65,.3,1) both}
/* Energetic one-shots — the app's own classes, quicker and with more bounce where things land. */
@keyframes idraPop{0%{transform:scale(0)}45%{transform:scale(1.35)}70%{transform:scale(.9)}86%{transform:scale(1.05)}100%{transform:scale(1)}}
.idra-pop{animation:idraPop .5s cubic-bezier(.3,.7,.4,1) both}
@keyframes idraConfirm{0%{transform:scale(.88)}45%{transform:scale(1.08)}72%{transform:scale(.97)}100%{transform:scale(1)}}
.idra-confirm{animation:idraConfirm .4s cubic-bezier(.3,.7,.4,1) both}
@keyframes idraRise{0%{opacity:0;transform:translateY(12px)}60%{opacity:1;transform:translateY(-2px)}100%{opacity:1;transform:none}}
.idra-rise{animation:idraRise .4s cubic-bezier(.3,.7,.4,1) both}
@keyframes idraDashSeat{0%{transform:rotate(-90deg)}100%{transform:none}}
.idra-dash-seat{transform-box:fill-box;transform-origin:center;animation:idraDashSeat .5s cubic-bezier(.3,1.25,.5,1) both}
@keyframes idraCheckinLand{0%{opacity:0;transform:translateY(-40px) rotate(-5deg) scale(.9)}50%{opacity:1;transform:translateY(6px) rotate(1.5deg) scale(1.03)}72%{transform:translateY(-3px) rotate(-.6deg)}100%{transform:none}}
.idra-checkin-land{animation:idraCheckinLand .6s cubic-bezier(.25,.8,.35,1) both}
@keyframes idraRoutineLand{0%{opacity:0;transform:scale(.85) translateY(10px)}45%{opacity:1;transform:scale(1.06) translateY(-4px)}70%{transform:scale(.98)}100%{transform:none}}
.idra-routine-land{animation:idraRoutineLand .6s cubic-bezier(.3,.7,.4,1) both}
.idra-card-mint{animation-duration:.5s;animation-timing-function:cubic-bezier(.2,1.5,.4,1)}
@keyframes idraCommitLift{0%{transform:none}30%{transform:translateY(-9px) scale(1.045)}60%{transform:translateY(2px) scale(.99)}100%{transform:none}}
.idra-commit-lift{animation:idraCommitLift .55s cubic-bezier(.3,.7,.4,1) both}
@keyframes idraSparkle{0%{opacity:0;transform:translate(0,0) scale(.3) rotate(0deg)}35%{opacity:1}100%{opacity:0;transform:translate(calc(var(--sx,0px) * 2),calc(var(--sy,0px) * 2)) scale(1.1) rotate(60deg)}}
/* The ring jumps as its days turn to stars: up 12 with a 1.04 swell, a squash on the way down, settle. */
@keyframes idraRingLand{0%,100%{transform:none}30%{transform:translateY(-12px) scale(1.04)}55%{transform:translateY(3px) scale(.97,1.03)}75%{transform:translateY(-2px)}}@keyframes idraRingLand2{0%,100%{transform:none}30%{transform:translateY(-12px) scale(1.04)}55%{transform:translateY(3px) scale(.97,1.03)}75%{transform:translateY(-2px)}}
@keyframes idraDotBurst{0%{opacity:1;transform:scale(1)}100%{opacity:0;transform:scale(2.4)}}
.idra-dot-burst{transform-box:fill-box;transform-origin:center;animation:idraDotBurst .6s cubic-bezier(.2,.65,.3,1) .15s both}
.idra-ring-land{animation:idraRingLand .6s cubic-bezier(.3,.7,.4,1) .1s both}.idra-ring-land2{animation:idraRingLand2 .6s cubic-bezier(.3,.7,.4,1) .1s both}
.idra-sparkle{animation-duration:.8s}.idra-gold-bloom{animation-duration:1.1s}.idra-halo-ring{animation-duration:1s}.idra-gold-wash{animation-duration:1.3s}
/* Playful idle — a bouncier bob with squash at the bottom, the head lagging the body a beat,
   and the arms swinging out of step, like a small dance on the spot. */
.lm-bob{transform-origin:512px 383px}
@keyframes lmBobFun{0%,100%{transform:none}35%{transform:translateY(-26px) scale(.97,1.04)}62%{transform:translateY(0) scale(1.06,.94)}78%{transform:translateY(-6px)}}
@keyframes lmBodyFun{0%,100%{transform:none}55%{transform:scale(1.04,.95)}75%{transform:scale(.98,1.02)}}
@keyframes lmSwayFunL{0%,100%{transform:rotate(-4deg)}50%{transform:rotate(9deg)}}
@keyframes lmSwayFunR{0%,100%{transform:rotate(-9deg)}50%{transform:rotate(4deg)}}
.st-idle .lm-bob{animation:lmBobFun 2.4s ease-in-out infinite;animation-delay:-.25s}.st-idle .lm-body{animation:lmBodyFun 2.4s ease-in-out infinite}
.st-idle .lm-armL{animation:lmSwayFunL 2.4s ease-in-out infinite}.st-idle .lm-armR{animation:lmSwayFunR 2.4s ease-in-out infinite;animation-delay:-.4s}
/* Idle moves and the poke */
@keyframes lmWiggle{0%,100%{transform:none}15%{transform:rotate(-10deg)}35%{transform:rotate(9deg)}55%{transform:rotate(-6deg)}75%{transform:rotate(3deg)}}
.st-wiggle .lm-body{animation:lmWiggle .75s ease-in-out both}.st-wiggle .lm-bob{animation:lmNod .25s ease-in-out 3}
@keyframes lmHeadPop{0%,100%{transform:none}20%{transform:translateY(14px) scale(1.1,.88)}50%{transform:translateY(-150px) scale(.94,1.06)}78%{transform:translateY(6px) scale(1.08,.92)}}
.st-headpop .lm-bob{animation:lmHeadPop .85s cubic-bezier(.3,.7,.4,1) both}
@keyframes lmPeek{0%,100%{transform:none}30%,55%{transform:translateY(130px) scale(1.1,.55)}75%{transform:translateY(-40px) scale(.95,1.08)}}
.st-peek .lm-fig{animation:lmPeek 1.1s cubic-bezier(.3,.7,.4,1) both}
@keyframes lmDanceL{0%,50%,100%{transform:none}25%{transform:rotate(60deg)}75%{transform:rotate(-14deg)}}
@keyframes lmDanceR{0%,50%,100%{transform:none}25%{transform:rotate(14deg)}75%{transform:rotate(-60deg)}}
@keyframes lmDanceBody{0%,50%,100%{transform:none}25%{transform:rotate(-6deg) translateY(-14px)}75%{transform:rotate(6deg) translateY(-14px)}}
.st-dance .lm-armL{animation:lmDanceL .7s ease-in-out 2 both}.st-dance .lm-armR{animation:lmDanceR .7s ease-in-out 2 both}.st-dance .lm-body{animation:lmDanceBody .7s ease-in-out 2 both}
/* Stumble — she wobbles left, then right, then tips over to the right and lands on her side with
   her head just out past the disc's right edge, where she stays while the failure is on screen.
   The lying pose is the class's own resting transform, so Reduce Motion shows her already down.
   Get up rights her when it clears. */
@keyframes lmStumble{0%{transform:none}16%{transform:rotate(-14deg)}34%{transform:rotate(12deg)}46%{transform:rotate(4deg) scale(1.04,.96)}74%{transform:translate(-30px,-200px) rotate(98deg)}86%{transform:translate(-30px,-200px) rotate(86deg) scale(1.04,.96)}100%{transform:translate(-30px,-200px) rotate(90deg)}}
.st-stumble .lm-fig{transform:translate(-30px,-200px) rotate(90deg);animation:lmStumble 1.1s cubic-bezier(.4,0,.3,1) both}
@keyframes lmGetUp{0%{transform:translate(-30px,-200px) rotate(90deg)}50%{transform:translateY(-60px) rotate(-8deg) scale(.96,1.04)}78%{transform:scale(1.06,.94)}100%{transform:none}}
.st-getup .lm-fig{animation:lmGetUp .6s cubic-bezier(.3,.7,.4,1) both}
/* Voice lights start at the phone's top and bottom edges: each grows past the stage by the
   header's or the composer's height (the stage is no longer clipped), and paints behind both. */
[data-voice-stage]>[data-voice-light="top"]{top:-150px!important;height:calc(75% + 150px)!important}
[data-voice-stage]>[data-voice-light="bottom"]{bottom:-116px!important;height:calc(75% + 116px)!important}
/* The lights sit beneath everything on the screen: the screen holding the stage is its own
   stacking context and the lights take its lowest level, so they pass behind the header's mark and
   close and the user's mic, while a sheet or scrim opened over the screen still covers them all. */
:has(> [data-voice-stage]){isolation:isolate}
[data-voice-stage]>[data-voice-light]{z-index:-1}
/* On a voice screen the header's cream fade would wash over her light, so it stands down there. */
:has(> [data-voice-stage])>[data-idra-mast] .idra-topfade{display:none}
/* The glass fallback's finish — T.glass's rim and T.shadow.sm. */
.idra-glass-lit{box-shadow:0 0 0 1px rgba(15,14,10,.06),0 1px 2px rgba(15,14,10,.05), 0 14px 30px -16px rgba(15,14,10,.3)!important}
.idra-topfade{position:absolute;left:0;right:0;top:0;height:170px;pointer-events:none;background:linear-gradient(rgba(254,253,249,.9) 40%,rgba(254,253,249,0))}
/* Composer at rest and the round buttons beside it: the same light glass. Typing keeps its 2px ink edge. */
.idra-composer:not(.idra-composer-typing)>:first-child,.idra-composer .idra-glass,.idra-glass-lit,.idra-glass.idra-glass-lit{box-shadow:0 0 0 1px rgba(15,14,10,.06),0 1px 2px rgba(15,14,10,.05), 0 14px 30px -16px rgba(15,14,10,.3)!important}
/* A secondary button keeps its 1px inkMuted edge over the glass finish. */
.idra-glass.idra-glass-lit.idra-outline{box-shadow:inset 0 0 0 1px #4F4E4A,0 0 0 1px rgba(15,14,10,.06),0 1px 2px rgba(15,14,10,.05), 0 14px 30px -16px rgba(15,14,10,.3)!important}
/* Exaggerated head travel for the conversation states — the head is the part that talks. */
@keyframes lmOrbitBig{0%{transform:translate(0,-34px)}25%{transform:translate(40px,0)}50%{transform:translate(0,30px)}75%{transform:translate(-40px,0)}100%{transform:translate(0,-34px)}}
.st-think .lm-bob{animation:lmOrbitBig 1.4s linear infinite}
@keyframes lmNodBig{0%,100%{transform:none}45%{transform:translateY(38px) scale(1.06,.92)}70%{transform:translateY(-8px)}}
.st-speak .lm-bob{animation:lmNodBig .6s ease-in-out infinite}
@keyframes lmListenBig{0%,100%{transform:translate(44px,6px)}50%{transform:translate(44px,40px) scale(1.04,.94)}}
.st-listen .lm-bob{animation:lmListenBig 1.1s ease-in-out infinite}.st-listen .lm-body{transform:rotate(9deg)}
/* Twirl — the whole mark turns a full circle about its vertical axis, like a person turning on
   the spot, with a small hop. 3D on the svg element itself, in the disc's perspective. */
.lm{perspective:420px}
@keyframes lmTwirl{0%{transform:none}18%{transform:translateY(3%) scale(1.06,.92)}50%{transform:translateY(-16%) rotateY(180deg)}82%{transform:translateY(0) rotateY(360deg) scale(1.05,.95)}100%{transform:rotateY(360deg)}}
svg.st-twirl{animation:lmTwirl 1s cubic-bezier(.3,.7,.4,1) both;transform-origin:50% 50%}
/* Yawn — slow, no overshoot: a long breath in as she stretches tall and leans back, head tipping
   up, arms lifting a little out to the sides; then a long breath out as she sags below rest, head
   and arms drooping, and settles. The figure never leaves the ground. */
@keyframes lmYawnL{0%,100%{transform:none}40%{transform:rotate(30deg)}55%{transform:rotate(34deg)}75%{transform:rotate(-4deg)}}@keyframes lmYawnR{0%,100%{transform:none}40%{transform:rotate(-30deg)}55%{transform:rotate(-34deg)}75%{transform:rotate(4deg)}}
@keyframes lmYawnHead{0%,100%{transform:none}40%,55%{transform:translate(-14px,-30px)}75%{transform:translateY(16px)}}
@keyframes lmYawnBody{0%,100%{transform:none}40%{transform:rotate(-4deg) scale(.98,1.05)}55%{transform:rotate(-5deg) scale(.98,1.05)}75%{transform:scale(1.03,.96)}}
.st-yawn .lm-armL{animation:lmYawnL 3s ease-in-out both}.st-yawn .lm-armR{animation:lmYawnR 3s ease-in-out both}.st-yawn .lm-bob{animation:lmYawnHead 3s ease-in-out both}.st-yawn .lm-body{animation:lmYawnBody 3s ease-in-out both}
/* Boards don't scroll, so glass is tint and rim only: no backdrop blur anywhere on the canvas. */
.idra-glass,.idra-composer>:first-child{-webkit-backdrop-filter:none!important;backdrop-filter:none!important}
@media (prefers-reduced-motion:reduce){.lm *{animation:none!important;transition:none!important}.lm-spark,.lm-glow,.idra-dot-burst{display:none}}
