/* ═══════════════════════════════════════════════════════════════════════════
   SOLUTRA MOTION SYSTEM
   Tokens + de fjorton primitiverna. Ingen sektionsspecifik kod hör hemma här.

   FÄRGER — LÅST PALETT. Tillåtna färger i allt rörligt:
     var(--g1..--g4)          blåskalan (accenter, pulser, gradienter)
     var(--line), var(--line2) hårfina linjer
     var(--card), var(--panel) ytor
     var(--text), var(--muted), var(--faint) text
     var(--motion-gron)       ENDAST bockar/bekräftelser (morgonmötespanelen)
     var(--motion-amber)      ENDAST "detta kräver en människa"
   Ingenting annat. Felsök ALDRIG med stroke:red eller liknande — mitt i en
   marinblå palett läser rött som ett felmeddelande, och glömda debugfärger
   har redan läckt till inspelningar en gång. Använd ?debug=motion, som ritar
   sina egna outlines i palettens färger och städas bort utan parametern.

   Tre regler som gäller allt nedan:
     1. Varje tid och kurva kommer från en token. Ingen hårdkodad 0.37s.
     2. Rörelse är transform och opacity. Enda undantaget är layout-morphen
        i signaturmomentets beat 5, som är isolerad och sker en gång.
     3. Allt är scopat under .js-enabled. Utan JS finns ingen opacity:0 —
        sajten är då statisk men fullständig.
   ═══════════════════════════════════════════════════════════════════════════ */

:root{
  /* Easing — signaturen. Snabb ut, lång mjuk landning. Detta är karaktären. */
  --ease-solutra: cubic-bezier(.16, 1, .3, 1);
  --ease-out-soft: cubic-bezier(.22, .61, .36, 1);
  --ease-in-out:   cubic-bezier(.65, 0, .35, 1);
  --ease-spring:   cubic-bezier(.34, 1.56, .64, 1); /* SPARSAMT — max 2 ställen */

  /* Durationsskala. Allt ligger på skalan. */
  --d-instant: 120ms;   /* hover, fokus, tryck */
  --d-quick:   280ms;   /* små tillståndsbyten, sidbyten */
  --d-base:    450ms;   /* standardreveal */
  --d-slow:    700ms;   /* kort som blommar, linjer som ritas */
  --d-story:  1100ms;   /* narrativa steg i signaturmomentet */

  /* Stagger — rytmen mellan syskon. */
  --stag-tight: 60ms;
  --stag-base:  90ms;
  --stag-loose: 140ms;

  /* Distanser — subtilt, aldrig hoppigt. */
  --lift-sm: 8px;
  --lift-md: 14px;
  --lift-lg: 24px;

  /* Loopar och ambienta förlopp. Egen skala, eftersom de inte är reveals och
     inte hör hemma på durationsskalan ovan — men de ska ändå aldrig stå
     hårdkodade ute i reglerna. */
  --loop-caret:  1060ms;  /* caretens blink */
  --loop-puls:   1150ms;  /* puls längs en eke */
  --loop-amber:  1900ms;  /* "detta kräver en människa" */
  --loop-sweep:  2200ms;  /* ljusstrimman över ett område */
  --loop-drift:    26s;   /* bakgrundens atmosfär */
}

/* ── 1 · REVEAL ─────────────────────────────────────────────────────────────
   Basen. Allt annat är undantag från den här. Delas ut av IntersectionObserver
   som kopplar loss sig efter första träffen. --d bär stagger-fördröjningen. */
.js-enabled [data-reveal]{
  opacity:0;
  transform:translate3d(0, var(--lift-md), 0);
  transition:opacity var(--d-base) var(--ease-solutra) var(--d, 0ms),
             transform var(--d-base) var(--ease-solutra) var(--d, 0ms);
}
.js-enabled [data-reveal].in{opacity:1;transform:none}
.js-enabled [data-reveal="sm"]{transform:translate3d(0, var(--lift-sm), 0)}
.js-enabled [data-reveal="lg"]{transform:translate3d(0, var(--lift-lg), 0)}

/* Staggrade ord i en rubrik. Ordet är inslaget i .ord av orkestratorn, som
   sätter --d per ord. Masken gör att ordet stiger upp bakom en kant i stället
   för att tona in i tomma luften — det läser som tryckt, inte som fade. */
.js-enabled .ordmask{display:inline-block;overflow:hidden;vertical-align:top;padding-bottom:.08em}
.js-enabled .ordmask .ord{
  display:inline-block;
  transform:translate3d(0, 108%, 0);
  transition:transform var(--d-slow) var(--ease-solutra) var(--d, 0ms);
}
.js-enabled .ordmask.in .ord{transform:none}

/* ── 2 · TYPEWRITER ────────────────────────────────────────────────────────
   Texten skrivs av rAF-loopen i motion.js. CSS äger bara careten.
   Caretens blink är steps(1) — en mjuk fade läser som ett fel. */
.caret{display:inline-block;width:.08em;height:1em;background:currentColor;
  vertical-align:-.12em;margin-left:.12em;opacity:0}
.caret.blinkar{animation:caretBlink var(--loop-caret) steps(1) infinite}
@keyframes caretBlink{0%,49%{opacity:1}50%,100%{opacity:0}}

/* ── 3 · COUNTUP ───────────────────────────────────────────────────────────
   Tabulära siffror så bredden inte hoppar medan talet räknas upp. */
.tal{font-variant-numeric:tabular-nums;font-feature-settings:"tnum" 1}

/* ── 4 · PATHDRAW ──────────────────────────────────────────────────────────
   Linjen ritas via stroke-dashoffset. --len sätts av orkestratorn från
   elementets faktiska längd, så samma klass fungerar för alla linjelängder. */
.js-enabled .rita{
  stroke-dasharray:var(--len, 1000);
  stroke-dashoffset:var(--len, 1000);
  transition:stroke-dashoffset var(--d-slow) var(--ease-out-soft) var(--d, 0ms);
}
.js-enabled .rita.in{stroke-dashoffset:0}

/* ── 5 · TOKEN JOURNEY ─────────────────────────────────────────────────────
   Kortet som färdas mellan noder. Positionen sätts som transform av JS.
   Övergången är --d-story så det känns som ett paket som lämnas över,
   inte som en prick som studsar. */
.token{
  position:absolute;left:0;top:0;z-index:18;white-space:nowrap;
  padding:.5rem .8rem;border-radius:10px;
  background:var(--g2, #5c8dff);color:#fff;
  box-shadow:0 10px 30px rgba(6,12,52,.6);
  opacity:0;pointer-events:none;
  transition:transform var(--d-story) var(--ease-solutra),
             opacity var(--d-quick) var(--ease-solutra),
             background-color var(--d-base) var(--ease-solutra);
}
.token.syns{opacity:1}
.token.klar{background:var(--motion-gron, #62d39a);color:#07210f}
.token .tk-rad1{display:block;font-size:.72rem;font-weight:700;font-family:'JetBrains Mono',monospace}
.token .tk-rad2{display:block;font-size:.66rem;margin-top:.15rem;opacity:.9}

/* ── 6 · NODEGLINT ─────────────────────────────────────────────────────────
   Bekräftelsen när token landar. Ramen skalar 0.96 → 1.06 och tonar bort. */
.glint{position:absolute;left:0;top:0;border-radius:16px;pointer-events:none;
  border:2px solid var(--g2, #5c8dff);opacity:0;z-index:15}
.glint.blixt{animation:glintGo var(--d-slow) var(--ease-solutra) 1}
@keyframes glintGo{
  0%  {opacity:0;transform:scale(.96)}
  35% {opacity:.95}
  100%{opacity:0;transform:scale(1.06)}
}

/* ── 7 · CARDBLOOM ─────────────────────────────────────────────────────────
   Kortet stiger, landar, en ring blixtrar en gång, border svalnar tillbaka.
   Ringen är box-shadow (ingen layout) och skalan är transform. */
.js-enabled .bloom{opacity:0}
.js-enabled .bloom.in{animation:cardBloom var(--d-story) var(--ease-solutra) both var(--d, 0ms)}
@keyframes cardBloom{
  0%  {opacity:0;transform:translate3d(0,var(--lift-md),0) scale(.94);
       box-shadow:0 0 0 0 rgba(92,141,255,.45)}
  45% {opacity:1;transform:none;
       box-shadow:0 0 0 14px rgba(92,141,255,.16)}
  70% {box-shadow:0 0 0 22px rgba(92,141,255,0)}
  100%{opacity:1;transform:none;
       box-shadow:0 0 0 22px rgba(92,141,255,0)}
}

/* ── 8 · SWEEP ─────────────────────────────────────────────────────────────
   Diagonal ljusstrimma. Signalerar "systemet arbetar". Går en gång. */
.sweep{position:absolute;top:0;left:0;height:100%;width:170px;
  pointer-events:none;opacity:0;z-index:6;
  transform:translate3d(-220px,0,0) skewX(-14deg);
  background:linear-gradient(90deg,
    rgba(108,151,255,0) 0%, rgba(108,151,255,.16) 45%,
    rgba(140,190,255,.34) 50%, rgba(108,151,255,.16) 55%,
    rgba(108,151,255,0) 100%);
}
.sweep.gar{animation:sweepGo var(--loop-sweep) var(--ease-out-soft) forwards}
@keyframes sweepGo{
  0%  {opacity:0;transform:translate3d(-220px,0,0) skewX(-14deg)}
  12% {opacity:1}
  88% {opacity:1}
  100%{opacity:0;transform:translate3d(var(--sweep-slut,1100px),0,0) skewX(-14deg)}
}

/* ── 9 · HUBPULSE ──────────────────────────────────────────────────────────
   Pulser vandrar längs ekrarna in mot navet. --dx/--dy är resan, satt av JS.
   Fördröjningarna är avsiktligt ojämna så det aldrig blir en marsch i takt. */
.puls{opacity:0}
.puls.gar{animation:pulsRun var(--loop-puls) var(--ease-in-out) var(--d,0ms) infinite}
@keyframes pulsRun{
  0%  {opacity:0;transform:translate3d(0,0,0)}
  14% {opacity:1}
  86% {opacity:1}
  100%{opacity:0;transform:translate3d(var(--dx,0),var(--dy,0),0)}
}
/* Ringen som kvitterar att navet tagit emot. */
.navring{position:absolute;border-radius:22px;pointer-events:none;
  border:1px solid rgba(92,141,255,.45);opacity:0}
.navring.gar{animation:navRing var(--d-story) var(--ease-solutra) forwards}
@keyframes navRing{
  0%  {opacity:0;transform:scale(.94)}
  40% {opacity:1}
  100%{opacity:0;transform:scale(1.1)}
}

/* ── 10 · AMBERPULSE ───────────────────────────────────────────────────────
   Betyder alltid: detta kräver en människa. Aldrig dekorativ, aldrig fler än
   ett element åt gången. Långsam nog att aldrig läsas som ett larm. */
.amber{animation:amberPuls var(--loop-amber) var(--ease-in-out) infinite}
@keyframes amberPuls{0%,100%{opacity:1}50%{opacity:.62}}

/* ── 11 · DRIFT ────────────────────────────────────────────────────────────
   Atmosfär. ~16px över 26s. Ska knappt gå att upptäcka medvetet.
   Pausas av orkestratorn när elementet lämnar viewporten. */
.drift{animation:driftGo var(--loop-drift) var(--ease-in-out) infinite alternate}
@keyframes driftGo{
  from{transform:translate3d(0,0,0)}
  to  {transform:translate3d(-16px,14px,0)}
}
.motion-pausad{animation-play-state:paused !important}

/* ── 12 · FORMAUTOFILL ─────────────────────────────────────────────────────
   Fält som fyller sig själva, ett i taget, med stämpel bredvid. */
.js-enabled .autofalt{border-color:var(--line, rgba(130,160,255,.16));
  transition:border-color var(--d-base) var(--ease-solutra)}
.js-enabled .autofalt.fylld{border-color:rgba(92,141,255,.55)}
.js-enabled .autofalt .autovarde{opacity:0;transition:opacity var(--d-quick) var(--ease-solutra)}
.js-enabled .autofalt.fylld .autovarde{opacity:1}
.js-enabled .autostampel{opacity:0;transition:opacity var(--d-quick) var(--ease-solutra) var(--d-instant)}
.js-enabled .autofalt.fylld .autostampel{opacity:1}

/* ── 13 · SCROLLSCRUB ──────────────────────────────────────────────────────
   Besökaren driver berättelsen med sitt eget scrollhjul. Ett moment på hela
   sajten. Scenen är sticky; höjden på .scrub-spar bestämmer scrollsträckan. */
.scrub-spar{position:relative}
.scrub-scen{position:sticky;top:0;height:100svh;overflow:hidden}
/* Beats tonar in och ut på scrollprogress. --p sätts av rAF-loopen. */
.beat{position:absolute;inset:0;opacity:0;pointer-events:none;
  transition:opacity var(--d-quick) var(--ease-solutra)}
.beat.aktiv{opacity:1}

/* ── 14 · MAGNETICCTA ──────────────────────────────────────────────────────
   Max 6px förskjutning mot pekaren, plus en ljusstrimma var 6:e sekund.
   Endast desktop med precis pekare — aldrig på touch, där den bara stör. */
.magnet{transition:transform var(--d-quick) var(--ease-out-soft)}
@media (hover:hover) and (pointer:fine){
  .magnet.dras{transition:transform var(--d-instant) var(--ease-out-soft)}
  .magnet{position:relative;overflow:hidden}
  .magnet .strimma{position:absolute;top:0;left:0;height:100%;width:42%;
    pointer-events:none;opacity:0;
    background:linear-gradient(90deg,transparent,rgba(255,255,255,.42),transparent);
    transform:translate3d(-140%,0,0) skewX(-18deg)}
  .magnet.glimtar .strimma{animation:strimmaGo 900ms var(--ease-out-soft) 1}
}
@keyframes strimmaGo{
  0%  {opacity:0;transform:translate3d(-140%,0,0) skewX(-18deg)}
  18% {opacity:1}
  82% {opacity:1}
  100%{opacity:0;transform:translate3d(240%,0,0) skewX(-18deg)}
}

/* ── Hjälpare ──────────────────────────────────────────────────────────────
   will-change sätts av orkestratorn precis före en animation och tas bort
   direkt efter. Aldrig permanent — ett permanent lager kostar minne på
   varje ruta även när inget rör sig. */
.motion-lager{will-change:transform, opacity}

/* ── prefers-reduced-motion ────────────────────────────────────────────────
   Allt innehåll i slutläge, ingen rörelse. Sajten ska fortfarande vara vacker,
   aldrig en tom ruta. */
@media (prefers-reduced-motion: reduce){
  .js-enabled [data-reveal],
  .js-enabled [data-reveal].in{opacity:1;transform:none;transition:none}
  .js-enabled .ordmask .ord{transform:none;transition:none}
  .js-enabled .rita,
  .js-enabled .rita.in{stroke-dashoffset:0;transition:none}
  .js-enabled .bloom,
  .js-enabled .bloom.in{opacity:1;animation:none}
  .js-enabled .autofalt .autovarde,
  .js-enabled .autostampel{opacity:1;transition:none}
  .token{transition:none}
  .caret,.sweep,.puls,.navring,.glint{display:none !important}
  .drift,.amber{animation:none !important}
  .magnet{transform:none !important}
  .beat{transition:none}
}
