/* Energy Variance — landing and sign-in.
   One black view. FROM on the left, TO on the right, and the fleet
   assembling into a sphere in the gap between them. */

:root {
  --black: #000000;
  --white: #FFFFFF;
  --dim:   #7C8288;
  --dimmer:#4A4F54;          /* rules and underlines only: 2.5:1 on black */
  --quiet: #757B80;          /* text that recedes: 4.9:1 on black, WCAG AA */
  --mint:  #84E8C8;          /* the output veins on the how-it-works page */
  --line:  #26292D;

  --display: "Archivo", "Helvetica Neue", Arial, sans-serif;

  color-scheme: dark;
}

* { box-sizing: border-box; }

/* The page is one view at any ordinary size, and is allowed to scroll when
   it is not one: at 200% zoom, or on a phone with the keyboard up over the
   sign-in form. It used to be `overflow: hidden` on html and body, which
   left whatever fell below the fold unreachable. The sphere is fixed to the
   viewport, so it stays full-bleed behind whatever scrolls. */

body {
  margin: 0;
  background: var(--black);
  color: var(--white);
  font-family: var(--display);
  font-variation-settings: "wdth" 100, "wght" 400;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

::selection { background: var(--white); color: var(--black); }

:focus-visible { outline: 1px solid var(--white); outline-offset: 4px; }

/* ---------- the fleet ---------- */

#sphere {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  z-index: 0;
}

/* ---------- stage ---------- */

/* At least one view tall, and taller only when what it holds needs it: the
   middle row is `1fr` (never smaller than its content), so a sign-in panel
   that does not fit pushes the footer down and the page scrolls, rather
   than the two overlapping. */
.stage {
  position: relative;
  z-index: 1;
  min-height: 100vh;
  min-height: 100svh;
  display: grid;
  grid-template-rows: auto 1fr auto;
  padding: clamp(16px, 3vh, 34px) clamp(20px, 4vw, 56px);
  pointer-events: none;      /* let the pointer reach the canvas for parallax */
}

.stage a,
.stage button,
.stage input,
.stage form { pointer-events: auto; }

.mono {
  font-family: var(--display);
  font-variation-settings: "wdth" 100, "wght" 500;
  font-size: 10.5px;
  letter-spacing: 0.17em;
  text-transform: uppercase;
  font-weight: 400;
}

.top {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 16px;
  color: var(--quiet);
}

.wordmark {
  font-family: var(--display);
  font-variation-settings: "wdth" 116, "wght" 600;
  font-size: 15px;
  letter-spacing: 0.005em;
  text-transform: none;
  color: var(--white);
  text-decoration: none;
}

/* The landing header only (login.html shares .top and is left as it was): the
   name with the logo after it, and the two other pages on the right. */
.top-nav {
  flex-wrap: wrap;
  align-items: center;
  gap: 10px 16px;
}

.top-nav .wordmark {
  display: inline-flex;
  align-items: center;
  gap: 0.45em;
}

.wm-logo {
  display: block;
  height: 1.92em;
  width: auto;
}

.nav {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  justify-content: flex-end;
  margin-left: auto;
  gap: 10px clamp(16px, 2.6vw, 32px);
}

.nav > a {
  font-family: var(--display);
  font-variation-settings: "wdth" 100, "wght" 500;
  font-size: 10.5px;
  letter-spacing: 0.17em;
  text-transform: uppercase;
  color: var(--dim);
  text-decoration: none;
  white-space: nowrap;
  padding-bottom: 3px;
  border-bottom: 1px solid transparent;
  transition: color 160ms ease, border-color 160ms ease;
}

.nav > a:hover,
.nav > a:focus-visible { color: var(--white); }

.nav > a[aria-current="page"] {
  color: var(--white);
  border-bottom-color: var(--dimmer);
}

/* ---------- from | sphere | to ---------- */

/* The middle column is exactly the sphere: RADIUS_FRAC in sphere.js is 0.29
   of the short edge, so the diameter is 58vmin. Keep the two in step — that
   is what makes the side columns land precisely in the gap between the
   sphere's edge and the screen's, with the text centred in each. */
.axis {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 58vmin minmax(0, 1fr);
  align-items: center;
  gap: clamp(10px, 1.4vw, 26px);
}

.side {
  max-width: min(100%, 15ch);
  justify-self: center;
  text-align: center;
}

.tag {
  display: block;
  font-family: var(--display);
  font-variation-settings: "wdth" 100, "wght" 500;
  font-size: 10.5px;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--quiet);
  margin-bottom: clamp(10px, 1.6vh, 18px);
}

.side .tag { color: var(--white); }

.line {
  margin: 0;
  font-variation-settings: "wdth" 106, "wght" 500;
  font-size: clamp(24px, 3.1vw, 46px);
  line-height: 1.08;
  letter-spacing: -0.03em;
  text-wrap: balance;
}

/* "To" is where the flexibility ends up, so it takes the green of the output
   veins on the how-it-works page. */
.side.to .line { color: var(--mint); }

/* Both sides read the same weight and colour — the words carry the contrast,
   not the styling. */

/* The strapline sits dead centre, inside the sphere, so the flock reads as
   the ground the sentence stands on. Anchored to the viewport centre — the
   same origin the canvas uses — rather than to the grid row, which is offset
   by the header and footer.

   Held narrower than the sphere's 58vmin diameter so it wraps within the
   formation rather than running out across the FROM and TO columns. */
.strap {
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  z-index: 2;
  margin: 0;
  width: max-content;
  max-width: min(78vw, 52vmin, 520px);
  text-align: center;
  font-size: clamp(13px, 1vw, 15.5px);
  line-height: 1.65;
  color: var(--white);
}

/* White text over white dots needs a floor to sit on. A soft radial scrim is
   enough — the dots stay visible through it, so the sphere is not punched out
   with a rectangle. */
.strap::before {
  content: "";
  position: absolute;
  inset: -1.6em -2.6em;
  z-index: -1;
  pointer-events: none;
  background: radial-gradient(
    ellipse at center,
    rgba(0, 0, 0, 0.82) 0%,
    rgba(0, 0, 0, 0.62) 42%,
    rgba(0, 0, 0, 0.28) 68%,
    transparent 85%
  );
}

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

.foot {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
  align-items: end;
  gap: 16px;
  color: var(--quiet);
}

/* Right-aligns a label in the third column. The footer is deliberately left
   a three-column grid with only two children, so the sign-in button stays in
   the middle column and dead centre of the page; scoped to .mono so it cannot
   land on that button. */
.foot > .mono:last-child { text-align: right; }

/* Landing only: the footer holds just the sign-in button, centred. */
.foot-solo {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: clamp(14px, 2.4vh, 22px);
}

/* The address, as on the other pages (assets/contact.js): set in full, a click
   copies it, and "Copied" takes its place for a moment — the two share one grid
   cell so nothing shifts. */
.contact {
  display: inline-grid;
  padding: 0 0 3px;
  border: 0;
  border-bottom: 1px solid transparent;
  background: none;
  cursor: pointer;
  font-family: var(--display);
  font-variation-settings: "wdth" 100, "wght" 500;
  font-size: 11px;
  letter-spacing: 0.06em;
  color: var(--white);
  transition: border-color 160ms ease;
}

.contact > span {
  grid-area: 1 / 1;
  white-space: nowrap;
  text-align: center;
}

.contact:hover,
.contact:focus-visible { border-bottom-color: var(--dimmer); }

.contact-done {
  visibility: hidden;
  font-size: 10.5px;
  letter-spacing: 0.17em;
  text-transform: uppercase;
  color: var(--mint);
}

.contact.copied .contact-address { visibility: hidden; }
.contact.copied .contact-done { visibility: visible; }

.enter {
  justify-self: center;
  display: inline-flex;
  align-items: center;
  gap: 14px;
  padding: 13px 26px;
  border: 1px solid var(--line);
  background: rgba(0, 0, 0, 0.4);
  color: var(--white);
  font-family: var(--display);
  font-variation-settings: "wdth" 104, "wght" 500;
  font-size: 15px;
  text-decoration: none;
  cursor: pointer;
  border-radius: 0;
  transition: background 160ms ease, color 160ms ease, border-color 160ms ease;
}

.enter .tick {
  font-family: var(--display);
  font-variation-settings: "wdth" 100, "wght" 500;
  font-size: 11px;
  letter-spacing: 0.16em;
  color: var(--quiet);
  transition: color 160ms ease;
}

.enter:hover,
.enter:focus-visible {
  background: var(--white);
  color: var(--black);
  border-color: var(--white);
}

.enter:hover .tick,
.enter:focus-visible .tick { color: var(--black); }

/* ---------- sign-in ---------- */

.axis.single {
  grid-template-columns: 1fr;
  justify-items: center;
}

/* Frosted rather than clear: darker, and the sphere behind it blurred to a
   haze, so it is still there but no longer reads as dots behind the labels
   and inputs. At 0.55 with no blur the dots came straight through, worst on
   a phone on its side, where the panel covers the whole sphere. */
.panel {
  width: min(100%, 360px);
  margin-block: 12px;
  background: rgba(0, 0, 0, 0.7);
  -webkit-backdrop-filter: blur(2.5px);
  backdrop-filter: blur(2.5px);
  padding: clamp(20px, 3vh, 30px);
  border: 1px solid var(--line);
  pointer-events: auto;
}

.panel h1 {
  margin: 0 0 24px;
  font-variation-settings: "wdth" 108, "wght" 500;
  font-size: 26px;
  line-height: 1.1;
  letter-spacing: -0.028em;
}

.field { margin-bottom: 18px; }

.field label {
  display: block;
  font-family: var(--display);
  font-variation-settings: "wdth" 100, "wght" 500;
  font-size: 10px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--quiet);
  margin-bottom: 7px;
}

.field input {
  width: 100%;
  font-family: var(--display);
  font-variation-settings: "wdth" 100, "wght" 500;
  font-size: 15px;
  padding: 10px 0;
  background: transparent;
  border: 0;
  border-bottom: 1px solid var(--line);
  color: var(--white);
  border-radius: 0;
  transition: border-color 160ms ease;
}

.field input:focus { outline: none; border-bottom-color: var(--white); }

button.enter { width: 100%; justify-content: center; margin-top: 22px; }
button.enter:disabled { opacity: 0.5; cursor: progress; }

.alert {
  margin: 0 0 20px;
  padding: 9px 0 9px 13px;
  border-left: 1px solid #E8704F;
  color: #E8704F;
  font-size: 13px;
  line-height: 1.45;
}

.alert[hidden] { display: none; }

.note {
  margin: 18px 0 0;
  color: var(--quiet);
  font-size: 12px;
  line-height: 1.5;
}

.back { color: var(--quiet); text-decoration: none; }
.back:hover { color: var(--white); }

/* ---------- narrow ---------- */

/* Portrait and squarish screens only. A phone on its side (844 x 390) is
   narrower than 900px too, and stacking FROM and TO above and below a sphere
   on a 390px-high screen put FROM under the nav and TO over the footer; it
   has the width for the three columns, so it keeps them, as a laptop does. */
@media (max-width: 900px) and (max-aspect-ratio: 4/3) {
  /* From, the sentence and To are one statement about the sphere, so all
     three are measured from the same line: the middle of the viewport, which
     is where the sphere and the strapline already are.

     In flow they were centred on the stage's middle grid row instead, and that
     row sits between a header and a footer of different heights — 33 against
     44 on a phone, 17 against 44 on a tablet, because the masthead's label
     wraps at one width and not the other. The strapline never moved, being
     fixed at 50% already, so the difference surfaced as a gap above the
     sentence that did not match the gap below it: 11px out on a phone and
     27px on a tablet. Anchoring both sides to 50% makes the two gaps equal by
     construction, at any header or footer height. */
  .axis { grid-template-columns: 1fr; }

  .side {
    position: fixed;
    left: 50%;
    transform: translateX(-50%);
    max-width: 14ch;
    z-index: 2;
  }

  /* Half the band the strapline needs, either side of centre, plus 15px of air
     the operator asked for in two passes once the two sides were symmetrical. */
  .side.from { bottom: calc(50% + clamp(94px, calc(13vh + 15px), 123px)); }
  .side.to { top: calc(50% + clamp(94px, calc(13vh + 15px), 123px)); }
  .line { font-size: clamp(22px, 6.4vw, 34px); }
  .strap { font-size: 13px; }
}

/* Phones: the links sit on the left, under the name. */
@media (max-width: 560px) {
  .nav { flex-basis: 100%; margin-left: 0; justify-content: flex-start; }
}

/* The smallest phones: tighten the three tabs so they stay on one line. */
@media (max-width: 360px) {
  .nav { column-gap: 12px; }
  .nav > a { letter-spacing: 0.1em; }
}

@media (max-width: 640px) {
  .foot { grid-template-columns: 1fr; justify-items: center; }
  .foot .mono { display: none; }
}

@media (max-height: 560px) {
  .line { font-size: clamp(19px, 3vw, 28px); }

  /* The sign-in panel, tightened to fit a phone on its side. */
  .panel h1 { margin-bottom: 14px; }
  .field { margin-bottom: 12px; }
  button.enter { margin-top: 14px; }
}

/* A stacked screen too short for the two sides to stand clear of the
   header and footer around a fixed centre: a portrait phone at 200% zoom,
   say. The three lines go back into the page's flow, FROM, the sentence,
   then TO, and the page scrolls if they still do not fit. */
@media (max-width: 900px) and (max-aspect-ratio: 4/3) and (max-height: 500px) {
  .axis {
    grid-template-columns: minmax(0, 1fr);
    align-content: center;
    justify-items: center;
    row-gap: 22px;
    padding-block: 18px;
  }
  .axis > div[aria-hidden] { display: none; }
  .side { position: static; transform: none; }
  .strap {
    order: 1;
    position: relative;     /* still the box its scrim is drawn inside */
    top: auto;
    left: auto;
    transform: none;
    width: auto;            /* max-content would size the column to the whole sentence */
    max-width: 34ch;
  }
  /* In the flow the scrim must stay inside the stage's side padding, or it
     widens the page by its own overhang. */
  .strap::before { inset: -1.2em -1em; }
  .side.to { order: 2; }
}

@media (prefers-reduced-motion: reduce) {
  * { transition-duration: 0.01ms !important; }
}
