/* Moonshine Nexus — moonshine-nexus.com
   Every colour below is sampled from the brand mark in site/brand/logo-master.jpg:
   the void it was drawn on, the moon's rim light, and the sage green of NEXUS. */

/* ---------- fonts (self-hosted, latin subset, SIL OFL 1.1) ---------- */

@font-face {
  font-family: Cinzel;
  src: url(/assets/fonts/cinzel-latin-var.woff2) format('woff2');
  font-weight: 400 900;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'IBM Plex Mono';
  src: url(/assets/fonts/plex-mono-400-latin.woff2) format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'IBM Plex Mono';
  src: url(/assets/fonts/plex-mono-500-latin.woff2) format('woff2');
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}

/* ---------- tokens ---------- */

:root {
  --void: #020307;      /* the mark's own black — the image sits on this seamlessly */
  --ink: #070a11;       /* plate fill, one step off the void */
  --hair: #1b2430;      /* hairline borders */
  --moon: #b3cde1;      /* moon rim light — primary text */
  --moon-dim: #6b91b3;  /* moonlight mid — links */
  --sage: #a8c79c;      /* the green of NEXUS — labels, nodes */
  --dust: #7a8695;      /* muted */

  /* The halo is the page's unit of measure; the mark and the bloom are derived
     from it. Bounded by width AND height so the email never falls below the
     fold: everything under the mark costs roughly `0.26 x viewport + 176px`,
     which is what the height term subtracts. The svh line is dropped by
     browsers that don't know the unit. */
  --halo-min: 220px;
  --stack: 176px;   /* the fixed part of everything below the mark */
  --halo: clamp(var(--halo-min), min(106vw, calc(74vh - var(--stack))), 640px);
  --halo: clamp(var(--halo-min), min(106vw, calc(74svh - var(--stack))), 640px);
  --mark: calc(var(--halo) * 0.50);

  /* The mark is an OPAQUE rectangle (700x775, drawn on --void), 0.50 x --halo
     wide, so its CORNERS reach 0.373 x --halo from centre. Anything the
     rectangle must not carve into has to start beyond that radius — the bloom
     does, and the ring (r = 0.44 x --halo) clears it too. */
  --mark-corner: calc(var(--halo) * .39);
}

/* ---------- base ---------- */

*, *::before, *::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  overflow-x: hidden;
  overflow-x: clip;
}

body {
  margin: 0;
  background: var(--void);
  color: var(--moon);
  font-family: 'IBM Plex Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 15px;
  line-height: 1.6;
  overflow-x: hidden;
  overflow-x: clip; /* the halo may bleed off narrow screens; never scroll sideways */
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

img { display: block; max-width: 100%; height: auto; }

::selection { background: rgba(168, 199, 156, .24); color: #fff; }

:focus-visible { outline: 2px solid rgba(168, 199, 156, .75); outline-offset: 2px; }

.page {
  min-height: 100vh;
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 40px 20px 28px;
  text-align: center;
}

/* ---------- the mark, and its halo ---------- */

.mark {
  position: relative;
  width: var(--halo);
  aspect-ratio: 1;
  margin: 0;
  display: grid;
  place-items: center;
}

/* Moonlight continuing past the edge of the artwork: begins outside
   --mark-corner, so the opaque image can never carve its own rectangle out of
   the glow, and peaks on the ring.

   The stops are explicit LENGTHS, not percentages: a radial-gradient's
   percentages resolve against the farthest corner of its box, which put the
   first stop well inside the image and left a visible 13/255 step along the
   image's edge. The layer is also inset past the mark on every side so the
   outer stop reaches zero before its own box clips it — same artefact, one
   level out. */
.mark::before {
  content: "";
  position: absolute;
  inset: -14%;
  border-radius: 50%;
  pointer-events: none;
  background: radial-gradient(circle closest-side at 50% 50%,
    rgba(107, 145, 179, 0)   var(--mark-corner),
    rgba(107, 145, 179, .16) calc(var(--halo) * .46),
    rgba(107, 145, 179, .06) calc(var(--halo) * .53),
    rgba(107, 145, 179, 0)   calc(var(--halo) * .61));
}

.mark__img { width: var(--mark); }

.halo {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
  pointer-events: none;
}

.halo__arc {
  stroke: rgba(179, 205, 225, .26);
  stroke-width: 1;
  stroke-linecap: round;
}

.halo__node {
  fill: rgba(168, 199, 156, .55);
  filter: drop-shadow(0 0 3px rgba(168, 199, 156, .35));
  transform-box: fill-box;
  transform-origin: center;
}

/* ---------- statement ---------- */

.statement {
  margin: clamp(16px, 3vh, 32px) 0 0;
  font-family: Cinzel, 'Trajan Pro', Georgia, serif;
  font-weight: 400;
  font-size: clamp(.95rem, 2.4vw, 1.35rem);
  line-height: 1.35;
  letter-spacing: .3em;
  text-indent: .3em; /* balance the trailing letter-space */
  text-transform: uppercase;
  color: var(--moon);
}

/* Engraved-metal type, as on the wordmark. Falls back to flat --moon. */
@supports ((-webkit-background-clip: text) or (background-clip: text)) {
  .statement {
    background-image: linear-gradient(180deg, #d9e7f3 0%, var(--moon) 44%, #7fa3c2 100%);
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
  }
}

.rule {
  width: 64px;
  height: 1px;
  border: 0;
  margin: clamp(20px, 3.4vh, 34px) auto 0;
  background: linear-gradient(90deg, transparent, rgba(168, 199, 156, .45), transparent);
}

/* ---------- contact ---------- */

.contact {
  width: 100%;
  max-width: 420px;
  margin: clamp(20px, 3.4vh, 34px) 0 0;
}

.eyebrow {
  margin: 0 0 12px;
  font-size: 10.5px;
  font-weight: 400;
  line-height: 1.5;
  letter-spacing: .2em;
  text-indent: .2em;
  text-transform: uppercase;
  color: var(--sage);
}

.plate {
  display: flex;
  align-items: stretch;
  border: 1px solid var(--hair);
  border-radius: 3px;
  background: var(--ink);
  overflow: hidden;
}

.plate__email {
  flex: 1 1 auto;
  min-width: 0;
  padding: 13px 14px;
  font-weight: 500;
  font-size: clamp(.75rem, 3.3vw, .9375rem);
  color: var(--moon-dim);
  text-decoration: none;
  /* The address is the page's whole payload — never truncate it. If it can't
     fit on one line it wraps; an ellipsis would hide the thing people came for. */
  overflow-wrap: anywhere;
  transition: color 160ms ease, background-color 160ms ease;
}

.plate__copy {
  flex: 0 0 auto;
  padding: 0 14px;
  border: 0;
  border-left: 1px solid var(--hair);
  border-radius: 0;
  background: transparent;
  color: var(--dust);
  font-family: inherit;
  font-size: 11px;
  letter-spacing: .14em;
  text-transform: uppercase;
  cursor: pointer;
  transition: color 160ms ease, background-color 160ms ease;
}

.plate__email:hover,
.plate__email:focus-visible { color: var(--moon); background: rgba(179, 205, 225, .05); }

.plate__copy:hover,
.plate__copy:focus-visible { color: var(--sage); background: rgba(168, 199, 156, .07); }

.plate__email:focus-visible,
.plate__copy:focus-visible { outline-offset: -3px; }

/* Below this the address and the button stop fitting side by side, and the
   address is the part that must stay readable. Stacking costs a row, so the
   mark gives that height back. */
@media (max-width: 359px) {
  :root { --halo-min: 190px; --stack: 224px; }
  .plate { flex-direction: column; }
  .plate__copy {
    padding: 10px 14px;
    border-left: 0;
    border-top: 1px solid var(--hair);
  }
}

.status {
  margin: 10px 0 0;
  min-height: 1.5em; /* reserve the line so nothing shifts */
  font-size: 11px;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--sage);
  opacity: 0;
  transition: opacity 180ms ease;
}

.status.is-shown { opacity: 1; }

/* ---------- foot ---------- */

.foot { margin: clamp(36px, 6.5vh, 68px) 0 0; }

.foot p {
  margin: 0;
  font-size: 11px;
  letter-spacing: .12em;
  color: var(--dust);
}

/* ---------- load sequence ----------
   One orchestrated moment: the mark surfaces, the words arrive, then the ring
   closes around them. Content lands before the ambience finishes. */

@keyframes rise   { from { opacity: 0; transform: translateY(8px) scale(.985); } to { opacity: 1; transform: none; } }
@keyframes lift   { from { opacity: 0; transform: translateY(10px); }            to { opacity: 1; transform: none; } }
@keyframes fade   { from { opacity: 0; }                                        to { opacity: 1; } }
@keyframes widen  { from { transform: scaleX(0); }                              to { transform: scaleX(1); } }
@keyframes draw   { from { stroke-dashoffset: 2460; }                           to { stroke-dashoffset: 0; } }
@keyframes node   { from { opacity: 0; transform: scale(.4); }                   to { opacity: 1; transform: none; } }

@media (prefers-reduced-motion: no-preference) {
  .mark::before { animation: fade 900ms 60ms both ease-out; }
  .mark__img    { animation: rise 800ms 120ms both cubic-bezier(.2, .7, .2, 1); }
  .statement    { animation: lift 650ms 520ms both ease-out; }
  .rule         { animation: widen 560ms 640ms both cubic-bezier(.2, .7, .2, 1); }
  .contact      { animation: lift 650ms 720ms both ease-out; }
  .foot         { animation: fade 600ms 900ms both ease-out; }

  .halo__arc  { stroke-dasharray: 2460; animation: draw 1100ms 420ms both cubic-bezier(.35, 0, .15, 1); }
  .halo__node { animation: node 460ms both ease-out; }

  /* each node lights as the arc reaches it */
  .halo__node:nth-of-type(1) { animation-delay: 480ms; }
  .halo__node:nth-of-type(2) { animation-delay: 663ms; }
  .halo__node:nth-of-type(3) { animation-delay: 847ms; }
  .halo__node:nth-of-type(4) { animation-delay: 1030ms; }
  .halo__node:nth-of-type(5) { animation-delay: 1213ms; }
  .halo__node:nth-of-type(6) { animation-delay: 1397ms; }
  .halo__node:nth-of-type(7) { animation-delay: 1580ms; }
}
