/* ============================================================
   Tiny Thoughts — Motion Layer
   ------------------------------------------------------------
   Rules this file follows:
   1. Motion must guide attention, communicate state, or
      preserve spatial continuity. Decoration is kept minimal
      and is always the first thing disabled.
   2. Animate transform + opacity only. Never width/height/top/left.
   3. Reduced motion and low-end devices are first-class paths,
      not afterthoughts.
   4. Content is NEVER hidden by a rule that depends on JS
      succeeding. See the [data-reveal] section.
   ============================================================ */


/* ── 1. Motion tokens ────────────────────────────────────── */

:root{
  --dur-fast:180ms;
  --dur-normal:350ms;
  --dur-slow:600ms;

  --ease-smooth:cubic-bezier(.22, 1, .36, 1);
  --ease-sharp:cubic-bezier(.4, 0, .2, 1);

  --dist-sm:8px;
  --dist-md:16px;
  --dist-lg:24px;

  /* Kept at/below 100ms — longer staggers read as sluggish. */
  --stagger:60ms;
}

/* Set by motion.js when the device reports low memory / few cores.
   Same choreography, less time on screen. */
html.low-power{
  --dur-fast:110ms;
  --dur-normal:190ms;
  --dur-slow:260ms;
  --stagger:30ms;
}


/* ── 2. Global affordances ───────────────────────────────── */

/* style.css sets scroll-behavior:smooth unconditionally, which is a
   vestibular trigger. Re-declared here so the reduced-motion block
   at the bottom of this file can take it back. */
html{
  scroll-behavior:smooth;
  /* Keeps anchored sections clear of the 84px sticky navbar. */
  scroll-padding-top:100px;
}

/* Keyboard users get the same clarity mouse users get on hover. */
a:focus-visible,
button:focus-visible{
  outline:3px solid var(--ink);
  outline-offset:3px;
  border-radius:6px;
}

footer a:focus-visible,
footer button:focus-visible,
.join a:focus-visible,
.team a:focus-visible{
  outline-color:#fff;
}


/* ── 3. Scroll progress ──────────────────────────────────── */
/* Communicates "how much is left" — most valuable on the report. */

.scroll-progress{
  position:fixed;
  top:0;
  left:0;
  width:100%;
  height:5px;
  z-index:1000;
  pointer-events:none;
  background:transparent;
}

.scroll-progress-bar{
  display:block;
  width:100%;
  height:100%;
  background:linear-gradient(90deg, var(--pink), var(--purple));
  transform:scaleX(var(--progress, 0));
  transform-origin:0 50%;
  /* No transition: this is scroll-linked, it must track the finger. */
}


/* ── 4. Navbar: scrolled state + scrollspy ───────────────── */

.navbar{
  transition:box-shadow var(--dur-normal) var(--ease-sharp),
             background-color var(--dur-normal) var(--ease-sharp);
}

.navbar.is-scrolled{
  background:rgba(255,255,255,.94);
  box-shadow:0 8px 24px rgba(43,43,69,.10);
}

.nav-links a:not(.btn){
  position:relative;
  transition:color var(--dur-fast) var(--ease-sharp);
}

.nav-links a:not(.btn)::after{
  content:"";
  position:absolute;
  left:0;
  right:0;
  bottom:-7px;
  height:3px;
  border-radius:999px;
  background:var(--pink);
  transform:scaleX(0);
  transform-origin:0 50%;
  transition:transform var(--dur-fast) var(--ease-smooth);
}

.nav-links a:not(.btn):hover::after,
.nav-links a:not(.btn):focus-visible::after,
.nav-links a:not(.btn).is-current::after{
  transform:scaleX(1);
}

.nav-links a:not(.btn).is-current{
  color:var(--pink);
}


/* ── 5. Mobile nav ───────────────────────────────────────── */
/* style.css animated `left` (a layout property, forces reflow every
   frame) and left the off-screen links focusable. Both fixed here. */

@media(max-width:720px){

  .nav-links{
    left:0;
    transform:translate3d(-100%, 0, 0);
    opacity:0;
    visibility:hidden;
    transition:transform var(--dur-normal) var(--ease-smooth),
               opacity var(--dur-fast) linear,
               visibility 0s linear var(--dur-normal);
  }

  .nav-links.active{
    transform:translate3d(0, 0, 0);
    opacity:1;
    visibility:visible;
    transition:transform var(--dur-normal) var(--ease-smooth),
               opacity var(--dur-fast) linear,
               visibility 0s linear 0s;
  }

  /* Links arrive in sequence so the eye follows the panel open. */
  .nav-links > *{
    opacity:0;
    transform:translate3d(0, calc(var(--dist-sm) * -1), 0);
    transition:opacity var(--dur-fast) var(--ease-smooth),
               transform var(--dur-fast) var(--ease-smooth);
  }

  .nav-links.active > *{
    opacity:1;
    transform:none;
    transition-delay:calc(var(--i, 0) * var(--stagger));
  }

  .mobile-toggle{
    transition:transform var(--dur-fast) var(--ease-sharp);
  }

  .mobile-toggle:active{
    transform:scale(.88);
  }
}


/* ── 6. Hero ─────────────────────────────────────────────── */
/* Pure CSS, no JS dependency: the entrance always completes, so
   hero copy can never be left invisible by a script failure. */

@keyframes rise-in{
  from{ opacity:0; transform:translate3d(0, var(--dist-lg), 0); }
  to  { opacity:1; transform:none; }
}

@keyframes pop-in-tilt{
  from{ opacity:0; transform:rotate(6deg) scale(.86); }
  to  { opacity:1; transform:rotate(-2deg) scale(1); }
}

@keyframes fade-in{
  from{ opacity:0; }
  to  { opacity:1; }
}

/* One decorative element, deliberately: the brand mark breathes. */
@keyframes float-soft{
  0%, 100%{ transform:translate3d(0, 0, 0); }
  50%     { transform:translate3d(0, -14px, 0); }
}

@keyframes drift{
  0%, 100%{ transform:translate3d(0, 0, 0) scale(1); }
  50%     { transform:translate3d(3%, -5%, 0) scale(1.08); }
}

.hero-tag,
.hero h1,
.hero p,
.hero-buttons,
.hero-art{
  animation:rise-in var(--dur-slow) var(--ease-smooth) backwards;
}

.hero-tag      { animation-delay:60ms;  }
.hero h1       { animation-delay:120ms; }
.hero p        { animation-delay:200ms; }
.hero-buttons  { animation-delay:280ms; }
.hero-art      { animation-delay:180ms; }

/* The sticker keeps its -2deg resting tilt from style.css. */
.hero h1 span{
  animation:pop-in-tilt var(--dur-slow) var(--ease-smooth) 340ms backwards;
  transition:transform var(--dur-fast) var(--ease-smooth);
}

.hero h1 span:hover{
  transform:rotate(2deg) scale(1.04);
}

/* Each layer owns exactly one transform so nothing fights:
   .hero-art = entrance, .hero-art-inner = scroll parallax,
   .feature-logo = float. */
.hero-art-inner{
  display:flex;
  justify-content:center;
  align-items:center;
  will-change:transform;
}

.hero-art .feature-logo{
  animation:float-soft 7s ease-in-out infinite;
}

/* Soft depth behind the hero. Pointer-inert, first thing removed
   under reduced motion. */
.hero::before,
.hero::after{
  content:"";
  position:absolute;
  border-radius:50%;
  pointer-events:none;
  z-index:0;
  filter:blur(50px);
  opacity:.55;
}

.hero::before{
  width:420px;
  height:420px;
  top:-120px;
  left:-100px;
  background:var(--butter);
  animation:drift 18s ease-in-out infinite;
}

.hero::after{
  width:360px;
  height:360px;
  bottom:-140px;
  right:-80px;
  background:var(--pink-soft);
  animation:drift 22s ease-in-out infinite reverse;
}

.hero-grid{
  position:relative;
  z-index:1;
}


/* ── 7. Reveal on scroll ─────────────────────────────────── */
/* Default state is VISIBLE. The hidden state is scoped to
   html.js-motion, which motion.js sets as its first statement —
   so if JS is blocked or fails, every section still renders. */

[data-reveal]{
  opacity:1;
}

/* Deliberately no transition on the hidden state. If this class lands
   after first paint on a slow load, content snaps out of view rather
   than visibly blinking from shown -> hidden -> shown. The transition
   lives on .is-visible, which is the direction that should animate. */
html.js-motion [data-reveal]{
  opacity:0;
  transform:translate3d(0, var(--dist-lg), 0);
  will-change:opacity, transform;
}

html.js-motion [data-reveal="left"] { transform:translate3d(calc(var(--dist-lg) * -1.5), 0, 0); }
html.js-motion [data-reveal="right"]{ transform:translate3d(calc(var(--dist-lg) *  1.5), 0, 0); }
html.js-motion [data-reveal="scale"]{ transform:scale(.94); }
html.js-motion [data-reveal="fade"] { transform:none; }

html.js-motion [data-reveal].is-visible{
  opacity:1;
  transform:none;
  transition:opacity var(--dur-normal) var(--ease-smooth) var(--reveal-delay, 0ms),
             transform var(--dur-normal) var(--ease-smooth) var(--reveal-delay, 0ms);
  /* Released once settled — a permanent will-change wastes a layer. */
  will-change:auto;
}


/* ── 8. Micro-interactions ───────────────────────────────── */

.btn{
  transition:transform var(--dur-fast) var(--ease-sharp),
             box-shadow var(--dur-fast) var(--ease-sharp),
             filter var(--dur-fast) var(--ease-sharp);
  box-shadow:0 0 0 var(--ink);
}

.btn:hover{
  transform:translateY(-4px);
  box-shadow:0 6px 0 var(--ink);
}

/* Press feedback — the tactile half most sites forget. */
.btn:active{
  transform:translateY(0) scale(.97);
  box-shadow:0 0 0 var(--ink);
  transition-duration:90ms;
}

.what-card,
.team-card,
.card,
.resource-card{
  transition:transform var(--dur-normal) var(--ease-smooth),
             box-shadow var(--dur-normal) var(--ease-smooth);
}

.what-card:hover,
.team-card:hover{
  transform:translateY(-8px);
  box-shadow:8px 8px 0 var(--ink);
}

.card:hover,
.resource-card:hover{
  transform:translateY(-4px);
  box-shadow:14px 14px 0 var(--ink);
}

.what-card li{
  transition:transform var(--dur-fast) var(--ease-smooth);
}

.what-card:hover li{
  transform:translateX(6px);
}

.what-card li:nth-child(2){ transition-delay:40ms; }
.what-card li:nth-child(3){ transition-delay:80ms; }

/* Scaling the wrapper, not the <img> — two avatars carry their own
   crop transform that must not be clobbered. */
.avatar{
  transition:transform var(--dur-normal) var(--ease-smooth),
             background-color var(--dur-normal) var(--ease-smooth);
}

.team-card:hover .avatar{
  transform:scale(1.08) rotate(-4deg);
  background:var(--pink-soft);
}

.team-card h4,
.team-card .role{
  transition:color var(--dur-fast) var(--ease-sharp);
}

.logo-mark{
  transition:transform var(--dur-normal) var(--ease-smooth);
}

.logo:hover .logo-mark{
  transform:rotate(-10deg) scale(1.08);
}

.about .feature-logo{
  transition:transform var(--dur-slow) var(--ease-smooth);
}

.about .feature-logo:hover{
  transform:rotate(4deg) scale(1.05);
}

.footer-links a,
.footer-copy{
  transition:opacity var(--dur-fast) var(--ease-sharp),
             transform var(--dur-fast) var(--ease-smooth);
}

.footer-links a:hover,
.footer-copy:hover,
.footer-copy:focus-visible{
  transform:translateX(4px);
}


/* ── 9. Back to top ──────────────────────────────────────── */

.to-top{
  position:fixed;
  right:24px;
  bottom:24px;
  z-index:30;
  width:54px;
  height:54px;
  display:grid;
  place-items:center;
  border:3px solid var(--ink);
  border-radius:50%;
  background:#fff;
  color:var(--ink);
  font-family:'Baloo 2', sans-serif;
  font-size:1.4rem;
  font-weight:800;
  line-height:1;
  cursor:pointer;
  box-shadow:4px 4px 0 var(--ink);
  opacity:0;
  transform:translate3d(0, var(--dist-md), 0) scale(.9);
  pointer-events:none;
  transition:opacity var(--dur-normal) var(--ease-smooth),
             transform var(--dur-normal) var(--ease-smooth),
             box-shadow var(--dur-fast) var(--ease-sharp);
}

.to-top.is-visible{
  opacity:1;
  transform:none;
  pointer-events:auto;
}

.to-top.is-visible:hover{
  transform:translateY(-4px);
  box-shadow:6px 7px 0 var(--ink);
}

.to-top.is-visible:active{
  transform:translateY(0) scale(.92);
  box-shadow:2px 2px 0 var(--ink);
  transition-duration:90ms;
}


/* ── 10. Copy toast + button state ───────────────────────── */

.copy-toast{
  transform:translate(-50%, var(--dist-md)) scale(.96);
  transition:opacity var(--dur-fast) var(--ease-smooth),
             transform var(--dur-normal) var(--ease-smooth);
}

.copy-toast.show{
  transform:translate(-50%, 0) scale(1);
}

@keyframes tick-pop{
  0%  { transform:scale(1); }
  45% { transform:scale(1.14); }
  100%{ transform:scale(1); }
}

.footer-copy.is-copied{
  opacity:1;
  color:var(--green-soft);
  animation:tick-pop var(--dur-normal) var(--ease-smooth);
}

/* Keeps the toast clear of the back-to-top button on narrow screens. */
@media(max-width:520px){
  .copy-toast{ bottom:96px; }
}


/* ── 11. Report page ─────────────────────────────────────── */

.callout{
  transition:transform var(--dur-normal) var(--ease-smooth),
             box-shadow var(--dur-normal) var(--ease-smooth);
}

.callout:hover{
  transform:translateY(-4px);
  box-shadow:6px 6px 0 rgba(43,43,69,.16);
}

.callout::before{
  transform:scaleY(var(--rule-scale, 1));
  transform-origin:0 0;
  transition:transform var(--dur-slow) var(--ease-smooth);
}

html.js-motion [data-reveal] .callout::before,
html.js-motion .callout[data-reveal]::before{
  --rule-scale:0;
}

html.js-motion [data-reveal].is-visible .callout::before,
html.js-motion .callout[data-reveal].is-visible::before{
  --rule-scale:1;
}

.report-gallery figure{
  transition:transform var(--dur-normal) var(--ease-smooth),
             box-shadow var(--dur-normal) var(--ease-smooth);
}

.report-gallery figure:hover{
  transform:translateY(-6px);
  box-shadow:8px 10px 0 rgba(43,43,69,.14);
}

.report-gallery figure img{
  transition:transform var(--dur-slow) var(--ease-smooth);
}

.report-gallery figure:hover img{
  transform:scale(1.06);
}

.term{
  transition:transform var(--dur-fast) var(--ease-smooth),
             background-color var(--dur-fast) var(--ease-sharp);
}

.term:hover{
  transform:translateY(-2px) rotate(-1.5deg);
  background:#ffef8f;
}

.back-link{
  transition:opacity var(--dur-fast) var(--ease-sharp),
             transform var(--dur-fast) var(--ease-smooth);
}

.back-link:hover{
  transform:translateX(-5px);
}

.report-cta::before{
  animation:drift 26s ease-in-out infinite;
}

/* Section rail - quiet marginalia in the left gutter, not a floating
   menu. A track you read your position from at a glance, and it is
   only present while the article body is actually on screen. */

.report-toc{
  --rail-x:7px;          /* centre of the track, from the rail's left edge */
  --dot:9px;

  position:fixed;
  left:clamp(14px, 1.8vw, 34px);
  top:50%;
  z-index:40;
  display:none;
  flex-direction:column;
  gap:0;
  width:172px;

  opacity:0;
  /* translateY(-50%) is layout, not motion - it survives everywhere. */
  transform:translateY(-50%) translateX(-10px);
  pointer-events:none;
  transition:opacity var(--dur-normal) var(--ease-smooth),
             transform var(--dur-normal) var(--ease-smooth);
}

.report-toc.is-active{
  opacity:1;
  transform:translateY(-50%) translateX(0);
  pointer-events:auto;
}

/* The track the markers sit on. */
.report-toc::before{
  content:"";
  position:absolute;
  left:calc(var(--rail-x) - 1px);
  top:12px;
  bottom:12px;
  width:2px;
  border-radius:2px;
  background:rgba(43,43,69,.13);
}

.report-toc button{
  position:relative;
  display:block;
  width:100%;
  padding:7px 0 7px 24px;
  border:0;
  background:transparent;
  color:rgba(43,43,69,.40);
  font-family:'Quicksand', sans-serif;
  font-size:.75rem;
  font-weight:700;
  line-height:1.35;
  text-align:left;
  cursor:pointer;
  transition:color var(--dur-fast) var(--ease-sharp),
             transform var(--dur-fast) var(--ease-smooth);
}

/* Marker, centred on the track. Filled, not a hollow ring - an
   outlined circle reads as an empty radio button. */
.report-toc button::before{
  content:"";
  position:absolute;
  left:calc(var(--rail-x) - var(--dot) / 2);
  top:50%;
  width:var(--dot);
  height:var(--dot);
  margin-top:calc(var(--dot) / -2);
  border-radius:50%;
  background:rgba(43,43,69,.20);
  transition:transform var(--dur-normal) var(--ease-smooth),
             background-color var(--dur-normal) var(--ease-sharp),
             box-shadow var(--dur-normal) var(--ease-sharp);
}

/* Sections already read stay filled - the rail doubles as progress. */
.report-toc button.is-passed{
  color:rgba(43,43,69,.55);
}

.report-toc button.is-passed::before{
  background:rgba(43,43,69,.34);
}

.report-toc button:hover{
  color:var(--ink);
  transform:translateX(2px);
}

.report-toc button:hover::before{
  background:var(--ink);
}

.report-toc button.is-current{
  color:var(--ink);
  font-weight:800;
}

.report-toc button.is-current::before{
  background:var(--pink);
  transform:scale(1.4);
  box-shadow:0 0 0 4px rgba(240,23,140,.14);
}

.report-toc button:focus-visible{
  outline:2px solid var(--ink);
  outline-offset:2px;
  border-radius:6px;
  color:var(--ink);
}

/* Only where the gutter is genuinely wide enough to hold it without
   crowding the article card (860px, centred). Below this the rail
   would sit on top of the text. */
@media(min-width:1300px){
  .report-toc{ display:flex; }
}


/* ── 12. Reduced motion ──────────────────────────────────── */
/* Surgical, not a blanket kill: transforms and looping decoration
   go away, short opacity fades stay so state changes remain legible. */

@media (prefers-reduced-motion: reduce){

  html{
    scroll-behavior:auto;
    scroll-padding-top:100px;
  }

  /* Decoration is the first thing to go. */
  .hero::before,
  .hero::after,
  .hero-art .feature-logo,
  .report-cta::before{
    animation:none;
  }

  .hero-tag,
  .hero h1,
  .hero p,
  .hero-buttons,
  .hero-art{
    animation:fade-in var(--dur-fast) linear backwards;
  }

  /* Keeps the sticker's static -2deg tilt from style.css. */
  .hero h1 span{
    animation:none;
  }

  html.js-motion [data-reveal],
  html.js-motion [data-reveal="left"],
  html.js-motion [data-reveal="right"],
  html.js-motion [data-reveal="scale"]{
    transform:none;
  }

  html.js-motion [data-reveal].is-visible{
    transform:none;
    transition:opacity var(--dur-fast) linear var(--reveal-delay, 0ms);
  }

  .callout::before{
    transform:none;
    transition:none;
  }

  /* State still reads, it just no longer moves. */
  .btn:hover,
  .btn:active,
  .card:hover,
  .resource-card:hover,
  .what-card:hover,
  .what-card:hover li,
  .team-card:hover,
  .team-card:hover .avatar,
  .callout:hover,
  .report-gallery figure:hover,
  .report-gallery figure:hover img,
  .term:hover,
  .back-link:hover,
  .logo:hover .logo-mark,
  .about .feature-logo:hover,
  .footer-links a:hover,
  .footer-copy:hover,
  .hero h1 span:hover,
  .to-top.is-visible:hover,
  .to-top.is-visible:active,
  .report-toc button:hover,
  .mobile-toggle:active{
    transform:none;
  }

  .to-top{
    transform:none;
    transition:opacity var(--dur-fast) linear;
  }

  /* translateY(-50%) is positioning; only the slide-in is motion. */
  .report-toc,
  .report-toc.is-active{
    transform:translateY(-50%);
    transition:opacity var(--dur-fast) linear;
  }

  .report-toc button::before{
    transition:background-color var(--dur-fast) linear;
  }

  .footer-copy.is-copied{
    animation:none;
  }

  .copy-toast{
    transform:translate(-50%, 0) scale(1);
    transition:opacity var(--dur-fast) linear;
  }

  @media(max-width:720px){
    .nav-links,
    .nav-links.active,
    .nav-links > *,
    .nav-links.active > *{
      transform:none;
    }
  }
}
