/* wavedash.eu: the same look as the sign-in pages (id.wavedash.eu), as plain HTML and CSS. */

@font-face {
  font-family: 'Figtree Variable';
  font-style: normal;
  font-display: swap;
  font-weight: 300 900;
  src: url('/assets/fonts/figtree-latin-wght-normal.woff2') format('woff2-variations');
  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;
}
@font-face {
  font-family: 'Figtree Variable';
  font-style: normal;
  font-display: swap;
  font-weight: 300 900;
  src: url('/assets/fonts/figtree-latin-ext-wght-normal.woff2') format('woff2-variations');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Source Code Pro Variable';
  font-style: normal;
  font-display: swap;
  font-weight: 200 900;
  src: url('/assets/fonts/source-code-pro-latin-wght-normal.woff2') format('woff2-variations');
}

:root {
  --bd-dark-1: #2a0d3f;
  --bd-dark-2: #3d1556;
  --bd-blob-1: #8a45b8;
  --bd-blob-2: #5b2a9a;
  --bd-blob-3: #b0529e;
  --bd-blob-4: #4a2a8c;
  --bd-blob-opacity: 0.55;
  --bd-grain-opacity: 0.08;
  --bd-speed: 38s;

  --color-bg: #2f0f45;
  --color-panel: rgb(26 9 40 / 0.55);
  --color-field: rgb(255 255 255 / 0.06);
  --color-text: #f7f1fb;
  --color-text-muted: #c8b5d6;
  --color-border: rgb(255 255 255 / 0.14);
  --color-accent: #d3a1f7;
  --color-button: #8a4bb8;
  --color-button-hover: #9a5bc8;

  --color-up: #c58bf7;
  --color-degraded: #f2c46d;
  --color-down: #ff6b81;

  --font-body: 'Figtree Variable', system-ui, sans-serif;
  --font-mono: 'Source Code Pro Variable', ui-monospace, monospace;

  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: 1rem;
  --space-4: 1.5rem;
  --space-5: 3rem;
  --space-6: 5rem;
  --radius: 0.75rem;
  --measure: 40rem;
}

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

html {
  font-size: clamp(16px, 0.25vw + 12px, 19px);
  scroll-behavior: smooth;
}
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
}

body {
  margin: 0;
  min-height: 100vh;
  background: var(--color-bg);
  color: var(--color-text);
  font-family: var(--font-body);
  line-height: 1.55;
}

/* The backdrop: soft blobs drifting slowly, and a fine film grain over them. */
.backdrop {
  position: fixed;
  inset: 0;
  z-index: -1;
  overflow: hidden;
  background: linear-gradient(135deg, var(--bd-dark-1), var(--bd-dark-2));
}
.blob {
  position: absolute;
  border-radius: 50%;
  opacity: var(--bd-blob-opacity);
  will-change: transform;
  animation: drift calc(var(--bd-speed) * var(--loop, 1)) ease-in-out infinite alternate;
  /* assets/scene.js sets --phase (ms since the first page of this visit), so a new page carries on
     from where the last one was instead of starting the drift again. */
  animation-delay: calc(var(--phase, 0) * -1ms);
}
.blob-1 { --c: var(--bd-blob-1); --loop: 1;   width: 80vmax; height: 80vmax; left: -15vmax;  top: -25vmax;    background: radial-gradient(closest-side, var(--c), transparent); }
.blob-2 { --c: var(--bd-blob-2); --loop: 1.3; width: 70vmax; height: 70vmax; right: -20vmax; top: 5vmax;      background: radial-gradient(closest-side, var(--c), transparent); }
.blob-3 { --c: var(--bd-blob-3); --loop: 0.8; width: 50vmax; height: 50vmax; left: 10vmax;   bottom: -25vmax; background: radial-gradient(closest-side, var(--c), transparent); }
.blob-4 { --c: var(--bd-blob-4); --loop: 1.6; width: 60vmax; height: 60vmax; right: 5vmax;   bottom: -30vmax; background: radial-gradient(closest-side, var(--c), transparent); }
@keyframes drift {
  from { transform: translate(0, 0) scale(1); }
  to   { transform: translate(12vmax, 8vmax) scale(1.18); }
}
.grain {
  position: absolute;
  inset: 0;
  opacity: var(--bd-grain-opacity);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}
@media (prefers-reduced-motion: reduce) {
  .blob { animation: none; }
}

/*
 * Time of day (assets/scene.js sets data-tod on <html> from the visitor's clock). Every part stays
 * dark, because the text is light: day is a bluer, lighter purple, never pale. The blobs and the
 * sky are written as oklch(lightness chroma hue), so a time of day only moves --tod-h (hue) and
 * --tod-l / --tod-d (lightness), and a service only sets --svc-h (hue) and --svc-mt (the same shift
 * for the mountain picture, in degrees). Browsers without oklch keep the purple hex values above.
 */
:root {
  --tod-h: 312; --tod-l: 0; --tod-d: 0;
  --tod-mt: 0; --tod-mt-b: 1;
  --svc-h: 0; --svc-mt: 0;
  --stars: 0.9;
  --orb-x: 18%; --orb-y: 15%;
  --orb-core: #f1e6fb; --orb-glow: rgb(205 180 230 / 0.32);
}
html[data-tod="dawn"] { --tod-h: 345; --tod-l: 0.03; --tod-d: 0.02; --tod-mt: 30; --tod-mt-b: 1.1; --stars: 0.25; --orb-x: 12%; --orb-y: 23%; --orb-core: #ffd9c2; --orb-glow: rgb(255 150 120 / 0.34); }
html[data-tod="day"]  { --tod-h: 282; --tod-l: 0.05; --tod-d: 0.05; --tod-mt: -28; --tod-mt-b: 1.12; --stars: 0; --orb-x: 36%; --orb-y: 11%; --orb-core: #fff3d6; --orb-glow: rgb(255 235 190 / 0.26); }
html[data-tod="dusk"] { --tod-h: 335; --tod-l: 0.03; --tod-d: 0.03; --tod-mt: 50; --tod-mt-b: 1.05; --stars: 0.35; --orb-x: 7%; --orb-y: 24%; --orb-core: #ffc58a; --orb-glow: rgb(255 130 90 / 0.38); }
@supports (color: oklch(0.5 0.1 100)) {
  :root {
    --bd-dark-1: oklch(calc(0.20 + var(--tod-d)) 0.09 calc(var(--tod-h) + var(--svc-h)));
    --bd-dark-2: oklch(calc(0.27 + var(--tod-d)) 0.11 calc(var(--tod-h) + var(--svc-h)));
    --bd-blob-1: oklch(calc(0.54 + var(--tod-l)) 0.17 calc(var(--tod-h) + var(--svc-h)));
    --bd-blob-2: oklch(calc(0.40 + var(--tod-l)) 0.17 calc(var(--tod-h) + var(--svc-h) - 20));
    --bd-blob-3: oklch(calc(0.57 + var(--tod-l)) 0.16 calc(var(--tod-h) + var(--svc-h) + 25));
    --bd-blob-4: oklch(calc(0.37 + var(--tod-l)) 0.15 calc(var(--tod-h) + var(--svc-h) - 30));

    /* The interface follows the same hue, so buttons and links are never purple on a blue sky. */
    --color-bg: var(--bd-dark-1);
    --color-panel: oklch(0.17 0.06 calc(var(--tod-h) + var(--svc-h)) / 0.55);
    --color-text: oklch(0.96 0.01 calc(var(--tod-h) + var(--svc-h)));
    --color-text-muted: oklch(0.8 0.04 calc(var(--tod-h) + var(--svc-h)));
    --color-accent: oklch(0.77 0.12 calc(var(--tod-h) + var(--svc-h)));
    --color-button: oklch(0.52 0.16 calc(var(--tod-h) + var(--svc-h)));
    --color-button-hover: oklch(0.58 0.16 calc(var(--tod-h) + var(--svc-h)));
  }
}

/* The sky: stars (night, a few at dawn and dusk) and the moon or sun, behind the blobs. */
.backdrop::before {
  content: '';
  position: absolute;
  inset: 0;
  background:
    radial-gradient(circle at var(--orb-x) var(--orb-y), var(--orb-core) 0 1rem, var(--orb-glow) 1.2rem, transparent 9rem),
    radial-gradient(1.5px 1.5px at 8% 12%, rgb(255 255 255 / var(--stars)) 50%, transparent 52%),
    radial-gradient(1px 1px at 14% 31%, rgb(255 255 255 / var(--stars)) 50%, transparent 52%),
    radial-gradient(1.5px 1.5px at 27% 8%, rgb(255 255 255 / var(--stars)) 50%, transparent 52%),
    radial-gradient(1px 1px at 33% 24%, rgb(255 255 255 / var(--stars)) 50%, transparent 52%),
    radial-gradient(1px 1px at 41% 40%, rgb(255 255 255 / var(--stars)) 50%, transparent 52%),
    radial-gradient(1.5px 1.5px at 46% 14%, rgb(255 255 255 / var(--stars)) 50%, transparent 52%),
    radial-gradient(1px 1px at 55% 33%, rgb(255 255 255 / var(--stars)) 50%, transparent 52%),
    radial-gradient(1px 1px at 61% 6%, rgb(255 255 255 / var(--stars)) 50%, transparent 52%),
    radial-gradient(1.5px 1.5px at 68% 21%, rgb(255 255 255 / var(--stars)) 50%, transparent 52%),
    radial-gradient(1px 1px at 5% 52%, rgb(255 255 255 / var(--stars)) 50%, transparent 52%),
    radial-gradient(1px 1px at 22% 47%, rgb(255 255 255 / var(--stars)) 50%, transparent 52%),
    radial-gradient(1.5px 1.5px at 38% 58%, rgb(255 255 255 / var(--stars)) 50%, transparent 52%),
    radial-gradient(1px 1px at 52% 50%, rgb(255 255 255 / var(--stars)) 50%, transparent 52%),
    radial-gradient(1px 1px at 74% 38%, rgb(255 255 255 / var(--stars)) 50%, transparent 52%);
}

/*
 * The mountain: it stands on the right and is taller than the window. It drifts up a little more
 * slowly than the page scrolls (assets/scene.js sets --scroll), so going down the page shows
 * more of it. Without the script it simply stays where it is.
 */
.mountain {
  position: absolute;
  /* The picture is 1000 by 1700, so it is 1.7 times as tall as it is wide. The layer has exactly that
     shape (no taller: a bigger layer only costs memory, and the colour filter below runs on all of it),
     and it is at least wide enough to be as tall as the screen, so its bottom edge is never in view. */
  --mt-top: 6rem; /* the summit stays clear of the header */
  --mt-w: max(min(78vw, 70rem), calc((100vh - var(--mt-top)) / 1.7));
  top: var(--mt-top);
  right: 0;
  width: var(--mt-w);
  aspect-ratio: 1000 / 1700;
  background: url('/assets/mountain.svg') no-repeat center / 100% 100%;
  /* The far ranges fade out on the left instead of ending at the edge of the picture. */
  -webkit-mask-image: linear-gradient(to right, transparent 0, #000 35%);
  mask-image: linear-gradient(to right, transparent 0, #000 35%);
  /* It drifts up slower than the page, but never so far that its bottom edge rises into the screen
     (on a phone the page is long and the picture is not much taller than the screen). 100vh is the
     tallest the screen gets on a phone, when the browser's bars are hidden. */
  transform: translate3d(0, min(0px, max(calc(var(--scroll, 0) * -0.45px), calc(100vh - var(--mt-top) - var(--mt-w) * 1.7))), 0);
  will-change: transform;
  /* The picture's colours are fixed, so the time of day and the service shift them as a whole. */
  filter: hue-rotate(calc((var(--tod-mt) + var(--svc-mt)) * 1deg)) brightness(var(--tod-mt-b));
}
@media (prefers-reduced-motion: reduce) {
  .mountain { transform: none; }
}
/* On a phone the summit has to stay on the screen: it sits 70% of the way across the picture, so the
   picture is a little wider than the screen and shifted only slightly, and it starts below the nav. */
@media (max-width: 48rem) {
  .mountain { --mt-top: 5rem; --mt-w: max(118vw, calc((100vh - 5rem) / 1.7)); right: -14vw; opacity: 0.85; }
}

/* ---- structure: a header, the content in a centred column, a footer ---- */

/* The same header on every page: just the links, on the right. */
.top {
  display: flex;
  justify-content: flex-end;
  width: min(100% - 2 * var(--space-4), 64rem);
  margin-inline: auto;
  padding-block: var(--space-4);
}
.nav {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: var(--space-1) var(--space-4);
}
.nav a {
  color: var(--color-text-muted);
  font-weight: 600;
  text-decoration: none;
}
.nav a:hover,
.nav a[aria-current='page'] {
  color: var(--color-text);
}

.column {
  width: min(100% - 2 * var(--space-4), var(--measure));
  margin-inline: auto;
}

/* ---- the home page ---- */

/* The first screen: someone saying hello, on the left, with the mountain on the right. */
.hero {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: center;
  width: min(100% - 2 * var(--space-4), 64rem);
  min-height: calc(100dvh - 7rem);
  margin-inline: auto;
  padding: var(--space-4) 0 var(--space-6);
}
.hero h1 {
  margin: 0 0 var(--space-3);
  font-size: clamp(3rem, 8vw, 5.6rem);
  font-weight: 700;
  line-height: 1;
  letter-spacing: -0.04em;
}
.lead {
  text-wrap: balance; /* no single word left alone on the last line */
  max-width: 26rem;
  margin: 0;
  color: var(--color-text-muted);
  font-size: 1.2rem;
}
.actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3) var(--space-4);
  margin-top: var(--space-5);
}

/* The quiet line under the buttons: how new people get in. */
.hero .note {
  max-width: 26rem;
  margin: var(--space-3) 0 0;
  color: var(--color-text-muted);
  font-size: 0.8rem;
}

.button {
  display: inline-block;
  padding: 0.85rem 1.6rem;
  background: var(--color-button);
  color: #fff;
  border-radius: var(--radius);
  font-weight: 600;
  text-decoration: none;
}
.button:hover { background: var(--color-button-hover); }
.link {
  color: var(--color-text-muted);
  font-weight: 600;
  text-decoration: none;
}
.link:hover { color: var(--color-text); }

/* The status board, below the first screen. */
.board {
  padding: var(--space-5) 0 var(--space-6);
}
.board h2 {
  margin: 0 0 var(--space-1);
  font-size: 1.75rem;
  line-height: 1.2;
}
.checked {
  margin: 0 0 var(--space-4);
  color: var(--color-text-muted);
  font-size: 0.9rem;
}
/* A second, smaller list under the status rows, for things that are not checked. */
.board-sub {
  margin: var(--space-5) 0 var(--space-1);
  font-size: 1.25rem;
  line-height: 1.2;
}
.rows {
  margin: 0;
  padding: 0;
  list-style: none;
  background: var(--color-panel);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  backdrop-filter: blur(24px);
}
.row {
  scroll-margin-top: var(--space-4);
}
/* Only the outer corners of the list are round, so a highlighted row in the middle stays square. */
.row:first-child { border-radius: var(--radius) var(--radius) 0 0; }
.row:last-child { border-radius: 0 0 var(--radius) var(--radius); }
.row:only-child { border-radius: var(--radius); }
.row + .row { border-top: 1px solid var(--color-border); }
.row-body {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  border-radius: inherit;
  color: inherit;
  text-decoration: none;
}
/* A row that leads somewhere says so when you point at it. */
a.row-body:hover { background: rgb(255 255 255 / 0.06); }
/* Arriving at the page by /#mail (or any of the others) lights that row up. */
.row:target { background: rgb(197 139 247 / 0.16); }
.row h3 {
  margin: 0;
  font-size: 1.05rem;
  font-weight: 600;
}
.row p {
  margin: 0;
  color: var(--color-text-muted);
  font-size: 0.95rem;
}
.state {
  display: inline-flex;
  flex: none;
  align-items: center;
  gap: 0.55rem;
  color: var(--color-text-muted);
  font-size: 0.95rem;
  white-space: nowrap;
}
.state::before {
  content: '';
  width: 0.7rem;
  height: 0.7rem;
  border-radius: 50%;
  background: var(--color-text-muted);
  opacity: 0.6;
}
.state[data-state='up'] { color: var(--color-text); }
.state[data-state='up']::before { background: var(--color-up); opacity: 1; }
.state[data-state='degraded']::before { background: var(--color-degraded); opacity: 1; }
.state[data-state='down']::before { background: var(--color-down); opacity: 1; }

/* ---- terms, privacy, contact ---- */

/* The text sits on a panel like the status board's, so it reads well with the mountain behind it. */
.doc {
  margin-block: var(--space-4) var(--space-6);
  padding: var(--space-5) var(--space-4);
  background: var(--color-panel);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  backdrop-filter: blur(24px);
}
.doc > * + * { margin-top: var(--space-4); }
.doc h2 {
  margin: 0;
  font-size: clamp(2rem, 5vw, 2.8rem);
  line-height: 1.1;
  letter-spacing: -0.02em;
}
.doc h3 {
  margin: 0 0 var(--space-1);
  font-size: 1.05rem;
  font-weight: 600;
}
/* Spacing between the blocks comes from `.doc > * + *` above; a paragraph adds none of its own. */
.doc p { margin-bottom: 0; }
.doc section > p { margin-top: 0; }
.doc a { color: var(--color-accent); }

/* ---- footer ---- */

.foot {
  width: min(100% - 2 * var(--space-4), 64rem);
  margin: 0 auto;
  padding: var(--space-4) 0 var(--space-5);
  border-top: 1px solid var(--color-border);
  color: var(--color-text-muted);
  font-size: 0.9rem;
  text-align: center;
}
.foot a { color: var(--color-text-muted); }
.foot a:hover { color: var(--color-text); }
.foot-links {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--space-1) var(--space-4);
  margin-bottom: var(--space-2);
}
.foot p { margin: 0; }
/* The background picker, the last item of the footer links: the choice is a cookie shared by every
   *.wavedash.eu site (assets/scene.js). */
.scene-select {
  padding: 0.1rem 0.3rem;
  border: 1px solid var(--color-border);
  border-radius: 0.4rem;
  background: var(--color-field);
  color: var(--color-text-muted);
  font: inherit;
  cursor: pointer;
}
.scene-select:hover { color: var(--color-text); }
.scene-select option { background: #1f0a30; color: #f7f1fb; }
.scene-select:focus-visible {
  outline: 2px solid var(--color-accent);
  outline-offset: 2px;
}

a:focus-visible,
.button:focus-visible {
  outline: 2px solid var(--color-accent);
  outline-offset: 3px;
}

@media (max-width: 40rem) {
  .top { padding-block: var(--space-3); }
  .doc { padding: var(--space-4) var(--space-3); }
  .hero { min-height: calc(100dvh - 9rem); padding-bottom: var(--space-5); }
  .row-body { flex-direction: column; align-items: flex-start; gap: var(--space-2); }
}
