/* ==========================================================================
   Coding School — motion layer
   Robots · coding tiles · science experiments
   Everything here is decorative. All of it stops under prefers-reduced-motion,
   and animations only run while their block is on screen (.is-live).
   ========================================================================== */

/* ---------- shared ---------- */
.fx{position:absolute;inset:0;pointer-events:none;overflow:hidden;z-index:0}
.fx *{pointer-events:none}

/* animations idle until the block scrolls into view */
.anim{animation-play-state:paused}
.is-live .anim{animation-play-state:running}

@media (prefers-reduced-motion:reduce){
  .anim,.is-live .anim{animation:none!important}
  .fx{display:none!important}
}

/* ==========================================================================
   1. Science — rising bubbles
   ========================================================================== */
@keyframes bubble-rise{
  0%   {transform:translate3d(0,110%,0) scale(.55);opacity:0}
  12%  {opacity:.85}
  70%  {opacity:.55}
  100% {transform:translate3d(var(--drift,14px),-130%,0) scale(1.12);opacity:0}
}
.bubble{
  position:absolute;bottom:-10%;
  width:var(--s,16px);height:var(--s,16px);border-radius:50%;
  background:radial-gradient(circle at 32% 28%,rgba(255,255,255,.95),rgba(255,255,255,.22) 42%,rgba(255,255,255,.06) 70%);
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.35);
  animation:bubble-rise var(--d,11s) linear infinite;
  animation-delay:var(--t,0s);
}
.bubble.is-yellow{background:radial-gradient(circle at 32% 28%,rgba(255,203,4,.95),rgba(255,203,4,.25) 45%,transparent 72%)}
.bubble.is-pink{background:radial-gradient(circle at 32% 28%,rgba(236,0,140,.9),rgba(236,0,140,.22) 45%,transparent 72%)}

/* ==========================================================================
   2. Coding — floating command tiles (the Kubo puzzle tiles)
   ========================================================================== */
@keyframes tile-float{
  0%,100%{transform:translate3d(0,0,0) rotate(var(--r,0deg))}
  50%    {transform:translate3d(0,-16px,0) rotate(calc(var(--r,0deg) + 5deg))}
}
.code-tile{
  position:absolute;width:var(--s,42px);height:var(--s,42px);
  border-radius:11px;display:grid;place-items:center;
  background:rgba(255,255,255,.07);border:1.5px solid rgba(255,203,4,.4);
  animation:tile-float var(--d,7s) ease-in-out infinite;
  animation-delay:var(--t,0s);
}
.code-tile svg{width:52%;height:52%;stroke:var(--yellow);fill:none;stroke-width:2.6;
  stroke-linecap:round;stroke-linejoin:round}
.code-tile.is-pink{border-color:rgba(236,0,140,.5)}
.code-tile.is-pink svg{stroke:var(--magenta)}

/* ==========================================================================
   3. Molecules — slow orbiting atoms
   ========================================================================== */
@keyframes orbit{to{transform:rotate(360deg)}}
@keyframes counter-orbit{to{transform:rotate(-360deg)}}
.molecule{position:absolute;width:var(--s,90px);height:var(--s,90px);opacity:.5}
.molecule .ring{
  position:absolute;inset:0;border-radius:50%;
  border:1.5px dashed rgba(255,255,255,.28);
  animation:orbit var(--d,26s) linear infinite;
}
.molecule .ring:nth-child(2){transform:rotate(60deg);animation-duration:calc(var(--d,26s) * 1.45)}
.molecule .ring:nth-child(3){transform:rotate(120deg);animation-duration:calc(var(--d,26s) * .8);
  animation-direction:reverse}
.molecule .ring::after{
  content:"";position:absolute;top:-4px;left:50%;margin-left:-4px;
  width:8px;height:8px;border-radius:50%;background:var(--yellow);
  box-shadow:0 0 10px rgba(255,203,4,.8);
}
.molecule .ring:nth-child(2)::after{background:var(--magenta);box-shadow:0 0 10px rgba(236,0,140,.8)}
.molecule .nucleus{
  position:absolute;top:50%;left:50%;width:12px;height:12px;margin:-6px 0 0 -6px;
  border-radius:50%;background:#fff;opacity:.85;
}

/* ==========================================================================
   4. The robot (mascot styling matches the logo mark)
   ========================================================================== */
@keyframes robot-bob{0%,100%{transform:translateY(0)}50%{transform:translateY(-5px)}}
@keyframes eye-blink{0%,92%,100%{transform:scaleY(1)}96%{transform:scaleY(.08)}}
@keyframes wheel-spin{to{transform:rotate(360deg)}}
@keyframes antenna-ping{
  0%,100%{transform:scale(1);opacity:1}
  50%    {transform:scale(1.5);opacity:.55}
}
.robot .body{animation:robot-bob 2.4s ease-in-out infinite}
.robot .eye{transform-origin:center;animation:eye-blink 4.2s ease-in-out infinite}
.robot .eye.is-right{animation-delay:.06s}
.robot .antenna-dot{transform-origin:center;animation:antenna-ping 1.8s ease-in-out infinite}
.robot .wheel-spoke{transform-origin:center;animation:wheel-spin 1.4s linear infinite}

/* ==========================================================================
   5. Mission mat — robot drives a route while command tiles fire in sequence
   ========================================================================== */
.mission{
  /* the framed photo above throws an 11x13px magenta offset outside its own
     layout box, so this block needs real clearance, not a hairline gap */
  margin-top:clamp(2.6rem,5vw,4.4rem);
  position:relative;border-radius:var(--radius-lg);overflow:hidden;
  background:linear-gradient(160deg,#2C1B52,#231544);
  border:1px solid rgba(255,255,255,.12);
  padding:clamp(1.4rem,3vw,2.2rem);
  display:grid;gap:clamp(1.2rem,3vw,2rem);
  grid-template-columns:minmax(0,1.15fr) minmax(0,.85fr);align-items:center;
}
@media (max-width:820px){.mission{grid-template-columns:1fr}}
.on-light .mission,.on-paper .mission{
  background:linear-gradient(160deg,#FFFDF6,#FFF4D9);border-color:#F0E2B8}

.mission-stage{position:relative;width:100%}
.mission-stage svg{width:100%;height:auto;display:block;overflow:visible}

/* grid + route */
.mat-cell{fill:rgba(255,255,255,.045);stroke:rgba(255,255,255,.1);stroke-width:1}
.on-light .mat-cell,.on-paper .mat-cell{fill:rgba(55,36,97,.04);stroke:rgba(55,36,97,.12)}
.mat-route{
  fill:none;stroke:var(--yellow);stroke-width:3;stroke-linecap:round;stroke-linejoin:round;
  stroke-dasharray:8 10;opacity:.55;
  animation:route-crawl 1.6s linear infinite;
}
@keyframes route-crawl{to{stroke-dashoffset:-18}}
.mat-goal{fill:var(--magenta)}
.mat-goal-ring{fill:none;stroke:var(--magenta);stroke-width:2.5;transform-origin:center;
  animation:goal-pulse 2s ease-out infinite}
@keyframes goal-pulse{
  0%  {transform:scale(.7);opacity:.9}
  100%{transform:scale(1.9);opacity:0}
}

/* the robot walking the route: 4 moves, 8s loop */
@keyframes robot-route{
  0%,4%    {transform:translate(0px,0px)}
  14%,22%  {transform:translate(64px,0px)}
  32%,40%  {transform:translate(64px,-58px)}
  50%,58%  {transform:translate(128px,-58px)}
  68%,88%  {transform:translate(192px,-58px)}
  96%,100% {transform:translate(0px,0px)}
}
.mat-robot{animation:robot-route 8s cubic-bezier(.55,.06,.3,1) infinite}

/* command tiles firing in time with the route */
.mission-tiles{display:grid;grid-template-columns:repeat(4,1fr);gap:.6rem}
.mission-tiles li{
  aspect-ratio:1;border-radius:14px;display:grid;place-items:center;
  background:rgba(255,255,255,.06);border:2px solid rgba(255,255,255,.14);
  animation:tile-fire 8s linear infinite;
}
.on-light .mission-tiles li,.on-paper .mission-tiles li{
  background:#fff;border-color:#EFE2C4}
.mission-tiles li:nth-child(1){animation-delay:0s}
.mission-tiles li:nth-child(2){animation-delay:1.44s}
.mission-tiles li:nth-child(3){animation-delay:2.88s}
.mission-tiles li:nth-child(4){animation-delay:4.32s}
.mission-tiles svg{width:46%;height:46%;stroke:var(--yellow);fill:none;stroke-width:2.8;
  stroke-linecap:round;stroke-linejoin:round}
.on-light .mission-tiles svg,.on-paper .mission-tiles svg{stroke:var(--purple)}
@keyframes tile-fire{
  0%     {transform:scale(1);border-color:rgba(255,255,255,.14);
          box-shadow:0 0 0 0 rgba(255,203,4,0)}
  4%     {transform:scale(1.12);border-color:var(--yellow);
          box-shadow:0 0 0 6px rgba(255,203,4,.16)}
  16%    {transform:scale(1);border-color:rgba(255,255,255,.14);
          box-shadow:0 0 0 0 rgba(255,203,4,0)}
  100%   {transform:scale(1)}
}
.mission-caption{font-size:.82rem;letter-spacing:.13em;text-transform:uppercase;
  font-weight:800;color:var(--yellow);margin-bottom:.9rem}
.on-light .mission-caption,.on-paper .mission-caption{color:#A8720B}

/* ==========================================================================
   6. Experiment station icons (the four Tinker Fair booths)
   ========================================================================== */
.exp-ico{
  flex:0 0 auto;width:46px;height:46px;border-radius:13px;
  display:grid;place-items:center;overflow:hidden;position:relative;
  background:rgba(236,0,140,.08);border:1px solid rgba(236,0,140,.22);
}
.on-purple .exp-ico,.on-deep .exp-ico{
  background:rgba(255,203,4,.12);border-color:rgba(255,203,4,.3)}
.exp-ico svg{width:100%;height:100%;overflow:visible}

/* lava lamp — blobs rising and sinking */
@keyframes lava-a{0%,100%{transform:translateY(4px) scale(1)}50%{transform:translateY(-7px) scale(1.18)}}
@keyframes lava-b{0%,100%{transform:translateY(-6px) scale(1.1)}50%{transform:translateY(5px) scale(.88)}}
.lava-a{animation:lava-a 3.4s ease-in-out infinite}
.lava-b{animation:lava-b 4.1s ease-in-out infinite}

/* elephant toothpaste — foam erupting */
@keyframes foam-up{
  0%  {transform:translateY(8px) scale(.35);opacity:0}
  25% {opacity:1}
  100%{transform:translateY(-13px) scale(1.25);opacity:0}
}
.foam{animation:foam-up 2.1s ease-out infinite}
.foam:nth-of-type(2){animation-delay:.42s}
.foam:nth-of-type(3){animation-delay:.84s}
.foam:nth-of-type(4){animation-delay:1.26s}

/* walking water — colour travelling across the paper bridge */
@keyframes water-walk{
  0%  {stroke-dashoffset:44;opacity:.25}
  45% {opacity:1}
  100%{stroke-dashoffset:0;opacity:.25}
}
.water-path{stroke-dasharray:44;animation:water-walk 3s ease-in-out infinite}

/* balloon inflator — balloon swelling */
@keyframes balloon-inflate{
  0%,100%{transform:scale(.62)}
  55%    {transform:scale(1)}
}
.balloon{transform-origin:50% 100%;animation:balloon-inflate 3.2s ease-in-out infinite}
@keyframes fizz{0%,100%{opacity:.2;transform:translateY(0)}50%{opacity:1;transform:translateY(-3px)}}
.fizz{animation:fizz 1.1s ease-in-out infinite}
.fizz:nth-of-type(2){animation-delay:.3s}
.fizz:nth-of-type(3){animation-delay:.6s}

/* ==========================================================================
   7. Dry ice — drifting fog
   ========================================================================== */
@keyframes fog-drift{
  0%  {transform:translate3d(-8%,12px,0) scale(.85);opacity:0}
  25% {opacity:.5}
  100%{transform:translate3d(14%,-26px,0) scale(1.5);opacity:0}
}
.fog{
  position:absolute;border-radius:50%;filter:blur(11px);
  background:rgba(255,255,255,.55);
  animation:fog-drift var(--d,7s) ease-out infinite;animation-delay:var(--t,0s);
}

/* ==========================================================================
   8. Programme card icons
   ========================================================================== */
.prog-ico{
  width:56px;height:56px;border-radius:16px;display:grid;place-items:center;
  background:rgba(255,203,4,.14);border:1px solid rgba(255,203,4,.32);
  margin-bottom:1rem;overflow:hidden;
}
.on-light .prog-ico,.on-paper .prog-ico{background:rgba(255,203,4,.22);border-color:rgba(255,203,4,.55)}
.prog-ico svg{width:64%;height:64%;overflow:visible}

/* flask bubbling */
@keyframes flask-bubble{
  0%  {transform:translateY(3px) scale(.5);opacity:0}
  30% {opacity:1}
  100%{transform:translateY(-11px) scale(1);opacity:0}
}
.flask-b{animation:flask-bubble 1.9s ease-out infinite}
.flask-b:nth-of-type(2){animation-delay:.55s}
.flask-b:nth-of-type(3){animation-delay:1.1s}

/* paint stroke drawing itself */
@keyframes stroke-draw{
  0%  {stroke-dashoffset:120}
  55% {stroke-dashoffset:0}
  100%{stroke-dashoffset:0;opacity:0}
}
.paint-stroke{stroke-dasharray:120;animation:stroke-draw 3.4s ease-in-out infinite}

/* code brackets + typing caret */
@keyframes caret-blink{0%,49%{opacity:1}50%,100%{opacity:0}}
.caret{animation:caret-blink 1s steps(1) infinite}
@keyframes bracket-nudge{0%,100%{transform:translateX(0)}50%{transform:translateX(-2px)}}
.bracket-l{animation:bracket-nudge 2.4s ease-in-out infinite}
.bracket-r{animation:bracket-nudge 2.4s ease-in-out infinite reverse}

/* ==========================================================================
   9. Specialty icons — gentle idle motion
   ========================================================================== */
@keyframes ico-pop{0%,100%{transform:scale(1) rotate(0)}50%{transform:scale(1.09) rotate(-4deg)}}
.spec:hover .spec-mark{animation:ico-pop .7s ease-in-out}

/* ==========================================================================
   10. Stat counters
   ========================================================================== */
.hero-facts b{font-variant-numeric:tabular-nums}

/* ==========================================================================
   11. Hero decoration placement
   ========================================================================== */
.fx-hero .bubble{z-index:0}
.fx-hero .code-tile{z-index:0}
.fx-hero .molecule{z-index:0}
@media (max-width:820px){
  .fx-hero .code-tile,.fx-hero .molecule{display:none}
}

/* section ambience */
.fx-ambient .molecule{opacity:.32}
.fx-ambient .bubble{opacity:.5}

/* ---------- bullets that carry an animated icon ---------- */
.ticks.with-ico li{display:flex;gap:.95rem;align-items:center;padding-left:0;margin-bottom:.9rem}
.ticks.with-ico li::before{display:none}
.ticks.with-ico .exp-ico{color:var(--magenta)}
.on-purple .ticks.with-ico .exp-ico,.on-deep .ticks.with-ico .exp-ico{color:var(--yellow)}

/* ---------- fog sits inside the framed photo ---------- */
.framed.has-fog{overflow:hidden}
.framed.has-fog .fog-layer{border-radius:inherit;z-index:2}

/* ==========================================================================
   12. Idle-until-visible (must stay LAST)
   Individual rules above use the `animation` shorthand, which resets
   animation-play-state to running. Scoping the pause to the section and
   placing it last means every decorative loop really is idle off-screen.
   ========================================================================== */
.hero:not(.is-live) *,
.section:not(.is-live) *{animation-play-state:paused}
