/* exomaly.com: the brand's home page. Its own look, not the Download page's purple: the whole interface wears one
   neon palette, "Neon sâu" (lime, mint, cyan, blue, violet, ultraviolet: --rgb-stops; the owner combined options 1, 30 and 33 of tools/palette-preview.html because
   a full six-colour rainbow reads as the pride flag). Frames get a conic gradient border that turns round them (border-image + the registered
   property --a); text, tick marks and the cursor get the same spectrum flowing sideways (rgbflow). The three planets
   keep their own colours (violet = download, red = upload, blue = upscale). All motion is CSS (+ home.js toggling
   .glitching now and then) and switches off for prefers-reduced-motion (the colours stay, standing still). */
@property --a { syntax: '<angle>'; inherits: false; initial-value: 0deg; }
:root {
  --bg: #05040A;
  --ink: #ECEAF7;
  --dim: #9892B4;
  --a: 0deg;  /* where the border light is; animated by rgbspin (the @property above makes it animatable) */
  --rgb-stops: #c6ff00, #05ffa1, #19e6ff, #3b82ff, #8b5cf6, #b44dff, #8b5cf6, #3b82ff, #19e6ff, #05ffa1, #c6ff00;  /* "Neon sâu": all cool hues, no pink, no red/orange/yellow (owner, 2026-10-07); last = first: it loops */
  --rgb: linear-gradient(90deg, var(--rgb-stops));
  --ok: #3FD99A;
  /* the sky (atmos.js sets html[data-time] and html[data-weather]; the defaults below are a clear night): */
  --stars-t: 1; --bright-t: 1; --sun-t: 0; --sun-x: 70%; --sun-y: 8%; --sun-color: 255, 244, 206; --sky: 0, 0, 0; --sky-a: 0; --cloud-rgb: 130, 150, 200; --fog-rgb: 110, 125, 165;
  --stars-w: 1; --bright-w: 1; --sun-w: 1; --cloud: 0; --fog: 0;
  --line: rgba(255, 255, 255, .1);
  --f-title: 'Unbounded', 'Chakra Petch', system-ui, sans-serif;
  --f-head: 'Chakra Petch', system-ui, sans-serif;
  --f-body: 'IBM Plex Sans', system-ui, sans-serif;
  --f-mono: 'JetBrains Mono', ui-monospace, Consolas, monospace;
}
*, *::before, *::after { box-sizing: border-box; }
html { background: var(--bg); scroll-behavior: smooth; transition: background-color 1.2s; }
html.sky-init, html.sky-init *, html.sky-init *::before, html.sky-init *::after { transition: none !important; }   /* first moment: no fade between sky states */
body { margin: 0; min-height: 100vh; background: var(--bg); color: var(--ink); font: 400 16px/1.6 var(--f-body); -webkit-font-smoothing: antialiased; }
a { color: inherit; }
img { display: block; max-width: 100%; }
h1, h2, h3, p, ul, ol, dl, dd { margin: 0; padding: 0; }
:focus-visible { outline: 2px solid #fff; outline-offset: 3px; }

/* ---------- the RGB light: flowing text, turning frame borders ---------- */
/* background-size is 200%, so a background-position of 200% is exactly one tile: seamless. (With size 100% a percent
   position moves nothing at all: that was a bug until 2026-10-07, the text colours never flowed.) */
@keyframes rgbflow { to { background-position: 200% 0; } }
@keyframes rgbspin { to { --a: 360deg; } }
/* text: the spectrum flows through the letters (one gradient the width of the element, shifted by exactly its width) */
.title .gl-base, .label, .local, .word, .sec, .tagline .gt, .card h3, .down span, .dev-card a, .foot .c {
  background: var(--rgb); background-size: 200% 100%; background-repeat: repeat;
  -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent; color: transparent;
  animation: rgbflow 5s linear infinite;
}
/* the gradient only paints inside the element's box, and a line-height of 1 clips Vietnamese accents (the "Ò" of
   "DÒ TÍN HIỆU" lost its mark): grow the painted area up and down without moving anything */
.down span { padding: .5em 0; }
.sec, .label { padding-block: .6em; margin-block: -.6em; }
.local { padding-block: .6em; margin-block: calc(10px - .6em) -.6em; }
/* frames: a conic gradient border (square corners only: border-image ignores border-radius) */
.card, .dev-card, .down, .lang {
  border: 1px solid transparent; border-image: conic-gradient(from var(--a), var(--rgb-stops)) 1;
  animation: rgbspin 6s linear infinite;
}

/* ---------- stars: two fixed layers of dots that breathe at different speeds ---------- */
.stars { position: fixed; inset: 0; z-index: 0; pointer-events: none; opacity: calc(var(--stars-t) * var(--stars-w)); transition: opacity 1.2s; }
.stars i { position: absolute; inset: 0; background-repeat: repeat; }
.stars .s1 {
  background-size: 520px 520px; opacity: .55; animation: twinkle 6s ease-in-out infinite alternate;
  background-image:
    radial-gradient(1px 1px at 12% 18%, #fff, transparent 60%), radial-gradient(1px 1px at 33% 72%, #cfc4ff, transparent 60%),
    radial-gradient(1.4px 1.4px at 58% 31%, #fff, transparent 60%), radial-gradient(1px 1px at 81% 64%, #fff, transparent 60%),
    radial-gradient(1px 1px at 90% 12%, #b9a4ff, transparent 60%), radial-gradient(1.2px 1.2px at 47% 92%, #fff, transparent 60%),
    radial-gradient(1px 1px at 69% 49%, #fff, transparent 60%), radial-gradient(1px 1px at 5% 86%, #cfc4ff, transparent 60%);
}
.stars .s2 {
  background-size: 780px 780px; opacity: .4; animation: twinkle 9s -3s ease-in-out infinite alternate;
  background-image:
    radial-gradient(1px 1px at 21% 41%, #fff, transparent 60%), radial-gradient(1.5px 1.5px at 74% 22%, #fff, transparent 60%),
    radial-gradient(1px 1px at 52% 66%, #b9a4ff, transparent 60%), radial-gradient(1px 1px at 9% 7%, #fff, transparent 60%),
    radial-gradient(1.2px 1.2px at 88% 88%, #fff, transparent 60%), radial-gradient(1px 1px at 38% 95%, #cfc4ff, transparent 60%);
}
@keyframes twinkle { from { opacity: .25; } to { opacity: .8; } }

/* ---------- top bar ---------- */
.sysbar {
  position: absolute; top: 0; left: 0; right: 0; z-index: 5; display: flex; align-items: center; gap: 14px;
  padding: 16px clamp(16px, 4vw, 48px); font: 500 12px/1 var(--f-mono); letter-spacing: .16em; text-transform: uppercase; color: var(--dim);
}
/* the logo: the cracked planet in a round frame with the turning RGB light (a gradient ring: border-image cannot follow a circle) */
.sys { display: inline-flex; align-items: center; gap: 10px; }
.logo-ring { flex: none; display: inline-grid; padding: 2px; border-radius: 50%; background: conic-gradient(from var(--a), var(--rgb-stops)); animation: rgbspin 6s linear infinite; }
.logo { display: block; width: 30px; height: 30px; border-radius: 50%; background: var(--bg); }
.sysbar .ticks { flex: 1; height: 8px; opacity: .8; background: var(--rgb); background-size: 200% 100%; animation: rgbflow 7s linear infinite;
  -webkit-mask-image: repeating-linear-gradient(90deg, #000 0 1px, transparent 1px 8px); mask-image: repeating-linear-gradient(90deg, #000 0 1px, transparent 1px 8px); }
.online { display: inline-flex; align-items: center; gap: 8px; color: var(--ok); white-space: nowrap; }
.online i { width: 7px; height: 7px; border-radius: 50%; background: var(--ok); box-shadow: 0 0 10px var(--ok); animation: pulse 2.2s ease-in-out infinite; }
@keyframes pulse { 50% { opacity: .35; } }
.lang { display: inline-flex; }
.lang button { padding: 6px 10px; border: 0; background: transparent; color: var(--dim); font: inherit; letter-spacing: .14em; cursor: pointer; }
.lang button[aria-pressed="true"] { background: var(--rgb); background-size: 200% 100%; animation: rgbflow 4s linear infinite; color: #07050B; font-weight: 700; }
.lang button:hover:not([aria-pressed="true"]) { color: #fff; }

/* ---------- hero ---------- */
.hero { position: relative; z-index: 1; min-height: 100vh; min-height: 100svh; display: flex; align-items: center; overflow: hidden;
  padding: 88px clamp(24px, 6vw, 96px) 72px; }
.sky { position: absolute; inset: 0; }
.par { position: absolute; inset: 0; transform: translate3d(var(--px, 0px), var(--py, 0px), 0); transition: transform .35s ease-out; will-change: transform; }
.scene {
  position: absolute; top: 0; right: -22vw; height: 100%; aspect-ratio: 1456 / 816; transform-origin: 62% 50%;
  animation: drift 28s ease-in-out infinite alternate;
  -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 18%); mask-image: linear-gradient(90deg, transparent 0, #000 18%);
}
.scene img { position: absolute; inset: 0; width: 100%; height: 100%; max-width: none; }
/* the second copy keeps only the brightest parts (the rift, the rim) and breathes on top of the first */
.scene-rift { filter: contrast(2.6) brightness(.8) saturate(1.8); mix-blend-mode: screen; opacity: .15; animation: rift 5.2s ease-in-out infinite alternate; }
@keyframes drift { from { transform: scale(1) translate3d(0, 0, 0); } to { transform: scale(1.045) translate3d(-.8%, .6%, 0); } }
@keyframes rift { from { opacity: .1; } to { opacity: .8; } }
.shade { position: absolute; inset: 0; pointer-events: none;
  background:
    linear-gradient(180deg, color-mix(in srgb, var(--bg) 55%, transparent) 0, transparent 20%, transparent 68%, var(--bg) 100%),
    linear-gradient(90deg, color-mix(in srgb, var(--bg) 80%, transparent) 0, color-mix(in srgb, var(--bg) 40%, transparent) 36%, transparent 62%); }

.copy { position: relative; z-index: 2; max-width: 680px; }
.label { display: flex; gap: 10px; width: fit-content; font: 700 12px/1 var(--f-mono); letter-spacing: .26em; }
.title { position: relative; display: inline-block; margin: 14px 0 18px; font: 800 clamp(40px, 7.4vw, 108px)/.98 var(--f-title); letter-spacing: .02em;
  color: #fff; filter: drop-shadow(0 0 22px rgba(255, 255, 255, .2)); white-space: nowrap; }
.gl { position: absolute; inset: 0; opacity: 0; pointer-events: none; mix-blend-mode: screen; text-shadow: none; }
.gl-r { color: #ff2a55; }
.gl-c { color: #19e6ff; }
.glitching .gl-r { animation: glr .5s steps(1, end) both; }
.glitching .gl-c { animation: glc .5s steps(1, end) both; }
.glitching .gl-base { display: inline-block; animation: rgbflow 5s linear infinite, jit .5s steps(1, end) both; }
@keyframes glr {
  0% { opacity: .9; transform: translate(-5px, 1px); clip-path: inset(8% 0 62% 0); }
  18% { transform: translate(4px, -1px); clip-path: inset(52% 0 18% 0); }
  36% { transform: translate(-8px, 0); clip-path: inset(26% 0 44% 0); }
  54% { transform: translate(6px, 2px); clip-path: inset(70% 0 4% 0); }
  72% { transform: translate(-3px, 0); clip-path: inset(0 0 80% 0); }
  100% { opacity: 0; transform: none; clip-path: inset(0); }
}
@keyframes glc {
  0% { opacity: .9; transform: translate(5px, -1px); clip-path: inset(60% 0 12% 0); }
  18% { transform: translate(-4px, 1px); clip-path: inset(14% 0 58% 0); }
  36% { transform: translate(8px, 0); clip-path: inset(46% 0 30% 0); }
  54% { transform: translate(-6px, -2px); clip-path: inset(4% 0 74% 0); }
  72% { transform: translate(3px, 0); clip-path: inset(82% 0 0 0); }
  100% { opacity: 0; transform: none; clip-path: inset(0); }
}
@keyframes jit { 0% { transform: translateX(2px) skewX(-3deg); } 30% { transform: translateX(-3px); } 60% { transform: translateX(2px) skewX(2deg); } 100% { transform: none; } }
.hero.glitching .par { animation: shake .5s steps(1, end); }
.hero.glitching .scene-rift { opacity: 1; animation: none; }
.hero.glitching .scene-img { filter: hue-rotate(14deg) saturate(1.5); }
/* the glitch is for the whole page (owner, 2026-10-07): while body.glitching every piece of text gets a red / cyan split
   (text-shadow is inherited, so one rule reaches the cards, the contact names, everything) and the plain text blocks
   jump sideways for a moment. Not on elements that already run an animation (gradient text, frames): a second
   `animation` would replace theirs. The title keeps its own layers (.gl). */
body.glitching { text-shadow: -2px 0 rgba(255, 42, 85, .9), 2px 0 rgba(25, 230, 255, .9); }
body.glitching .gl { text-shadow: none; }
/* .foot is left out on purpose: it is as wide as the page, so jumping sideways made a horizontal scrollbar flash (seen 2026-10-07) */
body.glitching :is(.sub, .tagline, .card p, .card .meta, .card .go, .dev-card dl, .who) { animation: jit .5s steps(1, end) both; }
@keyframes shake { 0% { transform: translate3d(6px, 0, 0); } 25% { transform: translate3d(-5px, 2px, 0); } 50% { transform: translate3d(3px, -1px, 0); } 75% { transform: translate3d(-2px, 0, 0); } }

.tagline { font: 600 clamp(18px, 2.2vw, 28px)/1.3 var(--f-head); letter-spacing: .02em; }
.cursor { display: inline-block; width: .5em; height: 1em; margin-left: 6px; vertical-align: -.12em; background: var(--rgb); background-size: 200% 100%; animation: rgbflow 3s linear infinite, blink 1.1s steps(1) infinite; }
@keyframes blink { 50% { opacity: 0; } }
.sub { margin-top: 14px; max-width: 46ch; color: var(--dim); font-size: 17px; }
.downs { display: flex; flex-wrap: wrap; gap: 14px; margin-top: 30px; }
.downs .down { margin-top: 0; }
.down { display: inline-flex; align-items: center; gap: 12px; margin-top: 30px; padding: 11px 16px;
  font: 700 12px/1 var(--f-mono); letter-spacing: .2em; text-transform: uppercase; text-decoration: none; transition: background .2s, color .2s; }
.down:hover { background: rgba(255, 255, 255, .08); }
.down i { width: 1px; height: 14px; background: var(--rgb); background-size: 200% 100%; animation: fall 1.8s ease-in-out infinite, rgbflow 3s linear infinite; }
@keyframes fall { 0%, 100% { transform: translateY(-3px); opacity: .4; } 50% { transform: translateY(3px); opacity: 1; } }

/* ---------- signals: one planet card per tool ---------- */
.signals, .dev { position: relative; z-index: 2; width: min(1280px, 100%); margin: 0 auto; padding: 56px clamp(20px, 6vw, 96px) 0; }
.sec { display: flex; align-items: center; gap: 10px; width: fit-content; font: 700 12px/1 var(--f-mono); letter-spacing: .24em; text-transform: uppercase; }
.sec h2 { font: inherit; letter-spacing: inherit; text-transform: inherit; }
.grid { list-style: none; display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; margin-top: 22px; }
.card { position: relative; display: flex; flex-direction: column; height: 100%; padding: 16px 18px 22px;
  background: linear-gradient(180deg, rgba(255, 255, 255, .04), rgba(255, 255, 255, .012)); color: inherit; text-decoration: none; overflow: hidden;
  transition: border-color .25s, box-shadow .25s, transform .25s; }
.card::before, .card::after { content: ''; position: absolute; width: 14px; height: 14px; border: 0 solid var(--c); opacity: .85; pointer-events: none; }
.card::before { top: 6px; left: 6px; border-top-width: 1px; border-left-width: 1px; }
.card::after { right: 6px; bottom: 6px; border-right-width: 1px; border-bottom-width: 1px; }
/* the planet's glow is a round gradient behind it, not a drop-shadow: the picture's black is opaque, so a drop-shadow
   would outline its rectangle. mix-blend-mode: screen makes the black vanish into the card. */
.orb { position: relative; display: block; aspect-ratio: 5 / 4; margin: -6px -8px 4px; }
.orb::before { content: ''; position: absolute; inset: 14% 20%; border-radius: 50%; filter: blur(22px); opacity: .55; transition: opacity .4s;
  background: radial-gradient(closest-side, color-mix(in srgb, var(--c) 55%, transparent), transparent); }
.orb img { position: relative; width: 100%; height: 100%; object-fit: cover; mix-blend-mode: screen; transition: transform .6s cubic-bezier(.2, .7, .2, 1), filter .4s;
  /* the edges fade out, so not even the picture's near-black rectangle can show against the card */
  -webkit-mask-image: radial-gradient(ellipse closest-side, #000 86%, transparent 100%); mask-image: radial-gradient(ellipse closest-side, #000 86%, transparent 100%); }
.meta { display: flex; justify-content: space-between; align-items: center; font: 500 11px/1 var(--f-mono); letter-spacing: .16em; text-transform: uppercase; color: var(--dim); }
.status { display: inline-flex; align-items: center; gap: 8px; }
.status i { width: 7px; height: 7px; border-radius: 50%; background: var(--ok); box-shadow: 0 0 8px var(--ok); animation: pulse 2.2s ease-in-out infinite; }
.card h3 { align-self: flex-start; margin: 14px 0 8px; font: 700 22px/1.2 var(--f-head); letter-spacing: .02em; }
.card p { flex: 1; color: var(--dim); font-size: 15px; }
.go { display: inline-flex; gap: 8px; margin-top: 18px; font: 700 13px/1 var(--f-mono); letter-spacing: .12em; text-transform: uppercase; color: var(--c2); }
.go b { font-weight: 700; transition: transform .25s; }
.card.live:hover, .card.live:focus-visible { box-shadow: 0 0 0 1px color-mix(in srgb, var(--c) 45%, transparent), 0 0 44px -12px var(--c); transform: translateY(-3px); }
.card.live:hover .orb img, .card.live:focus-visible .orb img { transform: scale(1.07) rotate(1.5deg); }
.card.live:hover .orb::before, .card.live:focus-visible .orb::before { opacity: 1; }
.card.live:hover .go b { transform: translateX(5px); }
.card.live:focus-visible { outline: 2px solid var(--c2); outline-offset: 3px; }
.card.soon { cursor: default; }
.card.soon .orb img { filter: saturate(.7) brightness(.8); }
.card.soon .orb::before { opacity: .25; }
.card.soon h3, .card.soon p { opacity: .85; }
.card.soon .status i { background: transparent; border: 1px dashed var(--c); box-shadow: none; animation: none; }
.go.muted { color: var(--dim); }

/* leaving for a tool: the sky zooms in and the page fades (home.js adds .warp, then follows the link) */
.warp .par { transform: scale(1.45) !important; opacity: 0; transition: transform .45s ease-in, opacity .45s ease-in; }
.warp .copy, .warp .signals, .warp .dev, .warp .foot, .warp .sysbar { opacity: 0; transition: opacity .38s ease-in; }
.warp .card.live .orb img { transform: scale(1.5); transition: transform .45s ease-in; }

/* ---------- origin: the brand story (draft wording: the owner will refine it) ---------- */
.origin { position: relative; z-index: 2; width: min(1280px, 100%); margin: 0 auto; padding: 56px clamp(20px, 6vw, 96px) 0; }
.origin-wrap { position: relative; padding: 8px 0 12px; }
.origin-bg { position: absolute; top: 0; right: -4%; z-index: -1; width: min(70%, 780px); height: 100%; max-width: none; object-fit: cover; opacity: .34; pointer-events: none;
  /* a radial fade on every side, so the picture never shows a rectangle's edge */
  -webkit-mask-image: radial-gradient(ellipse 62% 70% at 62% 50%, #000 25%, transparent 78%); mask-image: radial-gradient(ellipse 62% 70% at 62% 50%, #000 25%, transparent 78%); }
/* EXO + ANOMALY: "+" and "ANO" shrink to nothing (max-width), so EXO and MALY end up side by side. No opacity on the spans: it would
   take them out of the parent's gradient text. */
.word { margin: 26px 0 14px; width: fit-content; max-width: 100%; font: 800 clamp(24px, 7vw, 84px)/1 var(--f-title); letter-spacing: .02em; white-space: nowrap; }
.word { cursor: pointer; -webkit-tap-highlight-color: transparent; }
.word:focus-visible { outline: 2px solid var(--ink); outline-offset: 8px; }
.word-hint { margin: 0 0 14px; font: 500 12px/1 var(--f-mono); letter-spacing: .18em; text-transform: uppercase; color: var(--dim); }
.word span { display: inline-block; overflow: hidden; vertical-align: bottom; white-space: nowrap; }
.w-plus { max-width: 1.4em; padding: 0 .3em; transition: max-width .9s .55s ease, padding .9s .55s ease; }
.w-ano { max-width: 3.4em; transition: max-width .9s .55s ease; }
.word.in .w-plus, .word.in .w-ano { max-width: 0; padding: 0; }
.origin .lead { max-width: 56ch; margin-bottom: 8px; color: var(--dim); font-size: 17px; }
.beats { list-style: none; display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; margin-top: 26px; }
.beats li { padding-top: 14px; border-top: 1px solid var(--line); }
.beats .n { font: 700 12px/1 var(--f-mono); letter-spacing: .2em; color: var(--dim); }
.beats h3 { margin: 10px 0 6px; font: 700 20px/1.25 var(--f-head); letter-spacing: .02em; }
.beats p { color: var(--dim); font-size: 15px; }
.beats b { color: var(--ink); font-weight: 600; letter-spacing: .06em; text-transform: uppercase; }
.beats b::after { content: ":"; }

/* ---------- developer card + footer ---------- */
.dev { padding-top: 48px; }
.dev-card { margin-top: 18px; padding: 18px 20px; background: rgba(255, 255, 255, .025); }
.who { font: 600 18px/1.3 var(--f-head); }
.who .brandname { color: var(--dim); font-weight: 500; }
.dev-card dl { display: grid; grid-template-columns: auto 1fr; gap: 8px 22px; margin-top: 14px; }
.dev-card dt { font: 500 12px/1.6 var(--f-mono); letter-spacing: .16em; text-transform: uppercase; color: var(--dim); }
.dev-card a { text-decoration: none; }
.dev-card a:hover { text-decoration: underline; text-decoration-color: #fff; }
.foot { position: relative; z-index: 2; padding: 34px 20px 52px; text-align: center; font: 500 12px/1.6 var(--f-mono); letter-spacing: .08em; color: var(--dim); }
.foot strong { color: var(--ink); font-weight: 600; }

/* ---------- the sky: time of day x weather (atmos.js). Always a dark page: the day is a purple-toned dark page, not a white one.
   The milky veils (the cloud layers --cloud, the fog layer --fog) belong to OVERCAST and FOG only (owner, 2026-10-07: a hazy
   day was "ám trắng"): clear, cloudy, rain and snow stay see-through. ---------- */
html[data-time="day"] { --fog-rgb: 175, 190, 212; }
html[data-time="day"]   { --bg: #1a1248; --stars-t: .08; --bright-t: 1.08; --sun-t: 0;   --sun-rx: 30%; --sun-ry: 24%; --sun-x: 66%; --sun-y: -2%; --sun-color: 190, 225, 255; --sky: 150, 100, 240; --sky-a: .24; --cloud-rgb: 215, 230, 250; }
html[data-weather="clouds"]   { --stars-w: .7;  --bright-w: .98; --sun-w: .8; }
html[data-weather="overcast"] { --stars-w: .35; --bright-w: .93; --sun-w: .45; --cloud: .28; }
html[data-weather="fog"]      { --stars-w: .2;  --bright-w: .8;  --sun-w: .35; --fog: .85; }
html[data-weather="drizzle"]  { --stars-w: .35; --bright-w: .9;  --sun-w: .35; }
html[data-weather="rain"]     { --stars-w: .2;  --bright-w: .84; --sun-w: .25; }
html[data-weather="downpour"] { --stars-w: .1;  --bright-w: .74; --sun-w: .15; }
html[data-weather="thunder"]  { --stars-w: .1;  --bright-w: .72; --sun-w: .15; }
html[data-weather="snow"]     { --stars-w: .35; --bright-w: .95; --sun-w: .4; }

.tint { position: fixed; inset: 0; z-index: 0; pointer-events: none; transition: opacity 1.2s;
  background: linear-gradient(180deg, rgba(var(--sky), calc(var(--sky-a) * var(--sun-w))) 0, transparent 62%); }
.scene-img { filter: brightness(calc(var(--bright-t) * var(--bright-w))); transition: filter 1.2s; }
.sunglow { position: absolute; inset: 0; pointer-events: none; mix-blend-mode: screen;
  background: radial-gradient(ellipse var(--sun-rx, 55%) var(--sun-ry, 50%) at var(--sun-x) var(--sun-y), rgba(var(--sun-color), calc(var(--sun-t) * var(--sun-w))) 0, transparent 70%); }

/* weather overlay: over everything, light enough to read through, never catches the pointer */
.atmos { position: fixed; inset: 0; z-index: 3; pointer-events: none; overflow: hidden; }
.cloud { position: absolute; left: -30vw; width: 160vw; height: 46vh; opacity: calc(var(--cloud) * .9); transition: opacity 1.2s;
  background:
    radial-gradient(ellipse 26% 50% at 18% 50%, rgba(var(--cloud-rgb), .5), transparent),
    radial-gradient(ellipse 30% 55% at 52% 40%, rgba(var(--cloud-rgb), .45), transparent),
    radial-gradient(ellipse 24% 48% at 84% 55%, rgba(var(--cloud-rgb), .5), transparent); }
.cloud-a { top: -8vh; animation: cloudA 70s ease-in-out infinite alternate; }
.cloud-b { top: 14vh; opacity: calc(var(--cloud) * .6); animation: cloudB 95s ease-in-out infinite alternate; }
@keyframes cloudA { from { transform: translateX(0); } to { transform: translateX(26vw); } }
@keyframes cloudB { from { transform: translateX(22vw); } to { transform: translateX(-4vw); } }
.fog { position: absolute; left: 0; right: 0; bottom: 0; height: 75vh; opacity: var(--fog); transition: opacity 1.2s;
  background:
    radial-gradient(ellipse 60% 40% at 30% 70%, rgba(var(--fog-rgb), .34), transparent),
    radial-gradient(ellipse 50% 35% at 75% 60%, rgba(var(--fog-rgb), .3), transparent),
    linear-gradient(0deg, rgba(var(--fog-rgb), .3), transparent 75%);
  background-size: 170% 100%, 170% 100%, 100% 100%; animation: fogMove 42s ease-in-out infinite alternate; }
@keyframes fogMove { from { background-position: 0 0, 100% 0, 0 0; } to { background-position: 100% 0, 0 0, 0 0; } }
#wx { position: absolute; inset: 0; width: 100%; height: 100%; }
/* lightning: one soft double flash (never more than 2 in a second, never bright) */
.flash { position: absolute; inset: 0; background: #bed2ff; opacity: 0; }
.flash.bolt { animation: bolt .9s linear; }
@keyframes bolt { 0% { opacity: 0; } 6% { opacity: .22; } 14% { opacity: .04; } 22% { opacity: .16; } 100% { opacity: 0; } }

/* the line under SIGNAL DETECTED: where the sky comes from (city, temperature, weather, part of the day) */
.local { display: flex; flex-wrap: wrap; gap: 4px 10px; width: fit-content; max-width: 100%; font: 700 12px/1.3 var(--f-mono); letter-spacing: .2em; text-transform: uppercase; }
.credit { margin-top: 6px; font: 500 11px/1.5 var(--f-mono); letter-spacing: .04em; }
.credit a { color: inherit; }

/* ---------- narrower than a laptop: the planet moves above the text ---------- */
@media (max-width: 1099px) {
  .hero { display: block; min-height: 0; padding: 70px 22px 24px; }
  .sky { inset: 0 0 auto 0; height: calc(min(150vw, 900px) * .5625 + 40px); }
  .scene { top: 40px; right: auto; left: 50%; width: min(150vw, 900px); height: auto; margin-left: calc(min(150vw, 900px) / -2);
    -webkit-mask-image: none; mask-image: none; }
  .shade { background: linear-gradient(180deg, color-mix(in srgb, var(--bg) 40%, transparent) 0, transparent 20%, transparent 62%, var(--bg) 100%); }
  .copy { margin-top: calc(min(150vw, 900px) * .5625 - 36px); }
  .title { font-size: clamp(40px, 12.4vw, 96px); }
  .sub { font-size: 16px; }
}
@media (max-width: 899px) {
  .grid, .beats { grid-template-columns: 1fr; }
  .origin-bg { right: 0; width: 100%; opacity: .24; -webkit-mask-image: radial-gradient(ellipse 80% 62% at 50% 28%, #000 25%, transparent 78%); mask-image: radial-gradient(ellipse 80% 62% at 50% 28%, #000 25%, transparent 78%); }
  .signals { padding-top: 40px; }
}
@media (max-width: 480px) {
  .sysbar { gap: 10px; padding-top: 14px; font-size: 11px; }
  .sysbar .sys { letter-spacing: .1em; gap: 8px; }
  .logo { width: 26px; height: 26px; }
  .online span { display: none; }   /* phone: the green dot alone (the words wrapped onto two lines next to the logo) */
  .dev-card dl { grid-template-columns: 1fr; gap: 2px; }
  .dev-card dd { margin-bottom: 8px; }
}
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation: none !important; transition: none !important; scroll-behavior: auto !important; }
  .scene-rift { opacity: .35; }
  .stars i { opacity: .5; }
}
