/* Zenawi Development: the Eclipse system. Shared by the home page and the 404.
   Fonts are self-hosted from /fonts/, so no font provider sees a visit.

   Performance rule for this file: anything that moves forever animates only
   transform or opacity, one animation per property per element, and nothing
   that moves forever carries a filter. That keeps every loop on the GPU, so an
   idle page does no main-thread work (measured 2026-10-25: 313 ms -> 5 ms per 5 s).
   Fonts are subsets: Bricolage to ASCII plus typographic punctuation (it only sets
   the wordmark and headlines), Geist to its Latin range at weights 400-600. */

@font-face{font-family:"Bricolage Grotesque";font-style:normal;font-weight:200 800;font-stretch:75% 100%;font-display:swap;
  src:url(/fonts/Bricolage-d96-ascii.woff2) format("woff2");
  unicode-range:U+0020-007E,U+2013-2014,U+2018-2019,U+201C-201D,U+2026,U+2192}
@font-face{font-family:Geist;font-style:normal;font-weight:400 600;font-display:swap;
  src:url(/fonts/Geist-400-600.woff2) format("woff2");
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}

:root{
  --ink:#07070B; --tx:#EDEDF0; --tx2:#B4B4BE; --tx3:#8E8E9A; --line:rgba(237,237,240,.2);
  --accent:#FFB547; --on-accent:#15110A; --error:#FF9A8A;
  --display:"Bricolage Grotesque","Helvetica Neue",Arial,sans-serif;
  --sans:Geist,"Helvetica Neue",Arial,sans-serif;
  --out:cubic-bezier(.16,1,.3,1);
  --pad:clamp(24px,6.6vw,96px);
  color-scheme:dark;
}
*{box-sizing:border-box}
html,body{margin:0;background:var(--ink)}
body{color:var(--tx);font-family:var(--sans);-webkit-font-smoothing:antialiased;overflow-x:hidden}
a{color:var(--tx)}
:focus-visible{outline:2px solid var(--accent);outline-offset:3px;border-radius:6px}
[hidden]{display:none!important}
.sr{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}

/* ---------- the sky: nebula, three drifting star tiles, a meteor ---------- */
.sky{position:fixed;inset:0;z-index:-1;overflow:hidden;pointer-events:none}
.px{position:absolute;inset:-40px;transition:transform 1.4s var(--out);
  transform:translate3d(calc(var(--mx,0) * var(--d,0px) * -1),calc(var(--my,0) * var(--d,0px) * -.7),0)}
.neb{position:absolute;border-radius:50%;will-change:transform}
.neb.a{left:36%;top:-18%;width:64vw;height:56vw;background:radial-gradient(closest-side,rgba(58,70,96,.42),transparent);
  animation:nebA 46s ease-in-out infinite alternate}
.neb.b{left:-14%;top:48%;width:58vw;height:46vw;background:radial-gradient(closest-side,rgba(40,48,70,.36),transparent);
  animation:nebB 61s ease-in-out infinite alternate}
@keyframes nebA{to{transform:translate(-4vw,3vw) scale(1.12)}}
@keyframes nebB{to{transform:translate(5vw,-2vw) scale(.92)}}
/* each layer is one tile wider than the sky and slides left by exactly one tile, so the loop is seamless */
.stars{position:absolute;top:0;bottom:0;left:0;width:calc(100% + var(--tile));background-size:var(--tile) var(--tile);
  will-change:transform;animation:drift var(--dur) linear infinite}
@keyframes drift{to{transform:translate3d(calc(var(--tile) * -1),0,0)}}
.stars.far{--tile:720px;--dur:220s;background-image:
 radial-gradient(1px 1px at 4% 9%,#fff,transparent),radial-gradient(1px 1px at 13% 34%,#c9ccd6,transparent),
 radial-gradient(1px 1px at 21% 12%,#fff,transparent),radial-gradient(1px 1px at 28% 55%,#c9ccd6,transparent),
 radial-gradient(1px 1px at 36% 23%,#fff,transparent),radial-gradient(1px 1px at 43% 71%,#fff,transparent),
 radial-gradient(1px 1px at 51% 41%,#c9ccd6,transparent),radial-gradient(1px 1px at 58% 8%,#fff,transparent),
 radial-gradient(1px 1px at 64% 88%,#c9ccd6,transparent),radial-gradient(1px 1px at 71% 29%,#fff,transparent),
 radial-gradient(1px 1px at 79% 63%,#fff,transparent),radial-gradient(1px 1px at 86% 16%,#c9ccd6,transparent),
 radial-gradient(1px 1px at 93% 47%,#fff,transparent),radial-gradient(1px 1px at 9% 79%,#fff,transparent),
 radial-gradient(1px 1px at 33% 93%,#c9ccd6,transparent),radial-gradient(1px 1px at 97% 84%,#fff,transparent)}
.stars.mid{--tile:540px;--dur:130s;background-image:
 radial-gradient(1.4px 1.4px at 7% 21%,#fff,transparent),radial-gradient(1.4px 1.4px at 26% 67%,#e3e5ec,transparent),
 radial-gradient(1.4px 1.4px at 44% 13%,#fff,transparent),radial-gradient(1.4px 1.4px at 61% 52%,#fff,transparent),
 radial-gradient(1.4px 1.4px at 82% 31%,#e3e5ec,transparent),radial-gradient(1.4px 1.4px at 91% 78%,#fff,transparent)}
.stars.near{--tile:880px;--dur:70s;animation:drift var(--dur) linear infinite,twinkle 4.5s ease-in-out infinite alternate;background-image:
 radial-gradient(2px 2px at 12% 18%,#fff,transparent),radial-gradient(2.2px 2.2px at 47% 72%,#fff,transparent),
 radial-gradient(2px 2px at 78% 38%,#fff,transparent)}
@keyframes twinkle{from{opacity:.5}to{opacity:1}}
.meteor{position:absolute;left:42%;top:10%;width:180px;height:1.5px;border-radius:2px;
  background:linear-gradient(90deg,rgba(237,237,240,.9),rgba(237,237,240,0));animation:meteor 13s linear 4s infinite;opacity:0}
@keyframes meteor{0%,88%{opacity:0;transform:translate(0,0) rotate(-28deg)}90%{opacity:1}
  97%{opacity:0;transform:translate(-460px,245px) rotate(-28deg)}100%{opacity:0}}

/* ---------- the eclipse: every part sized in % of the planet (--p) ---------- */
.eclipse{position:absolute;width:var(--p);aspect-ratio:1;pointer-events:none}
.eclipse>*,.e-in,.e-in>*{position:absolute}
.e-in{inset:0;animation:emerge 2s var(--out) .15s both}
@keyframes emerge{from{opacity:0;transform:scale(.93)}to{opacity:1;transform:none}}
.glow{left:-26.1%;top:-26.1%;width:143.8%;height:143.8%;border-radius:50%;
  background:radial-gradient(closest-side,color-mix(in srgb,var(--accent) 15%,transparent),transparent)}
/* soft-edged stops instead of filter:blur, which re-blurred this rotating layer every frame */
.rays{left:-38.2%;top:-38.2%;width:171.9%;height:171.9%;border-radius:50%;will-change:transform;
  background:repeating-conic-gradient(from 0deg,transparent 0deg,color-mix(in srgb,var(--accent) 6%,transparent) 1.1deg,transparent 2.6deg 13deg);
  -webkit-mask-image:radial-gradient(circle closest-side,transparent 58%,#000 63%,transparent 88%);
  mask-image:radial-gradient(circle closest-side,transparent 58%,#000 63%,transparent 88%);
  animation:spin 160s linear infinite,ignite 3s ease-out 1.2s both}
.corona{left:-8.4%;top:-8.4%;width:112.5%;height:112.5%;border-radius:50%;filter:blur(2px);
  background:radial-gradient(circle closest-side,transparent 86%,var(--accent) 89%,color-mix(in srgb,var(--accent) 36%,transparent) 91.5%,transparent 97%)}
.planet{inset:0;border-radius:50%;overflow:hidden;background:radial-gradient(circle at 70% 78%,#17171F 0%,#0C0C12 55%,#09090D 100%)}
/* the surface bands slide down by one tile; transform only */
.bands{position:absolute;left:0;top:-100%;width:100%;height:200%;will-change:transform;animation:bands 90s linear infinite;
  background-image:repeating-linear-gradient(180deg,rgba(237,237,240,.016) 0 2.8%,transparent 2.8% 7.2%);background-size:100% 50%}
@keyframes bands{to{transform:translate3d(0,50%,0)}}
.lit{position:absolute;inset:0;background:radial-gradient(circle at 12% 10%,color-mix(in srgb,var(--accent) 24%,transparent) 0%,transparent 40%)}
.bead{left:11.3%;top:11.3%;width:2.2%;min-width:9px;aspect-ratio:1;border-radius:50%;background:#FFF6E6;
  box-shadow:0 0 18px 6px color-mix(in srgb,var(--accent) 70%,transparent),0 0 60px 20px color-mix(in srgb,var(--accent) 25%,transparent);
  animation:bead 3s var(--out) .9s both}
@keyframes bead{0%{opacity:0;transform:scale(0)}35%{opacity:1;transform:scale(1.6)}100%{opacity:.55;transform:scale(.7)}}
.orbit{left:-23.4%;top:31.25%;width:146.9%;height:37.5%;border-radius:50%;border:1px solid rgba(237,237,240,.13);transform:rotate(-16deg)}
/* the moon rides the ellipse on two eased translations a quarter-period apart
   (offset-path cannot be composited, so it cost a style recalc every frame) */
.mx,.my{position:absolute;inset:0}
.mx{animation:mx 14s ease-in-out infinite alternate}
.my{animation:my 14s ease-in-out -7s infinite alternate}
@keyframes mx{to{transform:translateX(100%)}}
@keyframes my{to{transform:translateY(100%)}}
.moon{position:absolute;left:-5.5px;top:-5.5px;width:11px;height:11px;border-radius:50%;background:#EDEDF0;
  box-shadow:inset -3px -2px 0 rgba(7,7,11,.55)}
/* fade-in and breathing live on different elements: two opacity animations on
   one element stop either from being composited */
.ig{inset:0}
.ig>*{position:absolute}
.ignite{animation:ignite 2.4s ease-out .9s both}
.breathe{animation:breathe 7s ease-in-out 3.3s infinite alternate}
@keyframes ignite{from{opacity:0}to{opacity:1}}
@keyframes breathe{to{opacity:.7}}
@keyframes spin{to{transform:rotate(360deg)}}

/* ---------- entrance motion: short, so the headline is readable fast ---------- */
.mask{display:inline-block;overflow:hidden;padding-bottom:.06em;vertical-align:top}
.ch{display:inline-block;animation:up .9s var(--out) both}
@keyframes up{from{transform:translateY(108%)}to{transform:none}}
.rise{animation:rise .9s var(--out) both}
@keyframes rise{from{opacity:0;transform:translateY(16px)}to{opacity:1;transform:none}}

/* ---------- the mark ---------- */
.brand{display:inline-flex;align-items:center;gap:12px;text-decoration:none;
  font:700 19px/1 var(--display);letter-spacing:-.02em;color:var(--tx)}
.brand svg{width:34px;height:34px;flex:none}

/* small screens carry two star layers, not three, and no meteor */
@media (max-width:600px){.stars.mid,.meteor{display:none}}

/* the pause button in the footer (WCAG 2.2.2) freezes every loop where it stands */
.still :is(.neb,.stars,.meteor,.rays,.bands,.mx,.my,.breathe,.rot-in){animation-play-state:paused!important}

@media (prefers-reduced-motion:reduce){
  .neb,.stars,.meteor,.e-in,.rays,.bead,.bands,.mx,.my,.ignite,.breathe,.ch,.rise,.rot-in{animation:none!important}
  .meteor{display:none}
  .px{transition:none}
}
