/* ==========================================================================
   Echo — base layer
   echo.thebraincompany.co · shared by every page on this subdomain

   Requires tokens.css, loaded first:
     <link rel="stylesheet" href="/styles/tokens.css">
     <link rel="stylesheet" href="/styles/base.css">

   What is in here: the self-hosted face, a small reset, the app's type
   styles, the atmosphere glow, and the handful of chrome primitives the app
   shares (the green capsule, the surface card, form fields, focus rings).
   Nothing page-specific.
   ========================================================================== */

/* --------------------------------------------------------------------------
   The face
   --------------------------------------------------------------------------
   Echo's typeface is Söhne (Klim), Buch 400 and Halbfett 600.

   It is NOT shipped here, and must not be. Every Söhne file on the build
   machine — Echo/Fonts/*.otf in the app repo and ~/Library/Fonts — is a Klim
   *test font*: name ID 14 points at klim.co.nz/licences/test-fonts, whose
   terms are "You must not use the Test Fonts for any commercial purposes.
   This includes, but is not limited to, any consumer or customer facing
   applications." A public marketing site is exactly that. They are also
   68-glyph subsets with no apostrophe, colon, slash or at-sign, so they
   physically cannot set this site's copy.

   Shipped instead: Inter (SIL Open Font License 1.1 — see
   fonts/Inter-LICENSE.txt), subset to Latin, at the same two weights. It is
   the closest freely licensable neo-grotesque to Söhne.

   TO SWAP IN THE REAL FACE once a Klim webfont licence is in hand: drop
   sohne-buch.woff2 and sohne-halbfett.woff2 into /fonts/ and move each
   Söhne url() to the front of its `src` list below. Nothing else on this
   site — no page, no rule, no token — refers to a font by name; everything
   goes through --font-sans, so both weights change here and only here.
   -------------------------------------------------------------------------- */

@font-face {
  font-family: "Echo Sans";
  /* src: url("/fonts/sohne-buch.woff2") format("woff2"), */
  src: url("/fonts/inter-regular.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Echo Sans";
  /* src: url("/fonts/sohne-halbfett.woff2") format("woff2"), */
  src: url("/fonts/inter-semibold.woff2") format("woff2");
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}

/* --------------------------------------------------------------------------
   Reset
   -------------------------------------------------------------------------- */

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

html {
  -webkit-text-size-adjust: 100%;
}

body,
h1,
h2,
h3,
p,
figure,
blockquote,
ul,
ol {
  margin: 0;
  padding: 0;
}

ul,
ol {
  list-style: none;
}

img,
svg,
picture {
  display: block;
  max-width: 100%;
}

button,
input,
textarea,
select {
  font: inherit;
  color: inherit;
}

/* --------------------------------------------------------------------------
   Page
   -------------------------------------------------------------------------- */

html {
  /* The paper is painted on the root as well as the body, so the colour
     survives overscroll on iOS rather than showing the browser's own white. */
  background: var(--paper);
}

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-sans);
  font-size: var(--text-body);
  font-weight: var(--weight-body);
  line-height: var(--leading-body);
  font-feature-settings: "kern" 1, "liga" 1, "calt" 1;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  /* Never scroll sideways. Wide children (tables, code) opt out locally. */
  overflow-x: hidden;
}

/* --------------------------------------------------------------------------
   The atmosphere
   --------------------------------------------------------------------------
   Echo's one ambient use of the green: a slow pool of Signal Green light
   breathing up from the bottom boundary of the canvas, fully spent by
   mid-screen. Three pools of the one brand green — a wide low wash, a
   brighter heart riding off-centre, and a faint shoulder to one side — each
   an ellipse whose centre sits *below* the viewport (y 105–113%), so the
   light arrives at the bottom edge already soft. Ported from
   Echo/EchoAtmosphere.swift, geometry and opacities intact.

   Usage — one element, anywhere on the page, as the first child of <body>:
     <div class="atmosphere" aria-hidden="true"></div>
   It is fixed to the viewport, so the light always rises from the bottom
   edge of whatever the visitor is looking at, exactly as it does in the app.
   Put page content in a positioned wrapper above it (see .page).

   The mask is the hard guarantee: whatever the pools do as they swell, the
   light is gone by the halfway line. Tune the inks via the --glow-* tokens;
   do not derive further washes or tints from this. It is a signature, not a
   licence.
   -------------------------------------------------------------------------- */

.atmosphere {
  position: fixed;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  pointer-events: none;
  /* Dark mode only: the paper itself deepens toward the bottom edge, a still
     well for the light to sit in. --glow-well is 0 in light mode. */
  background: linear-gradient(
    to bottom,
    transparent 50%,
    rgba(0, 0, 0, var(--glow-well)) 100%
  );
  -webkit-mask-image: linear-gradient(to top, #fff 0, #fff 20%, transparent 50%);
  mask-image: linear-gradient(to top, #fff 0, #fff 20%, transparent 50%);
}

.atmosphere::before {
  content: "";
  position: absolute;
  inset: 0;
  background:
    /* the faint shoulder, there only to break the other two's symmetry */
    radial-gradient(
      37.95vh 28.05vh at 80% 108%,
      rgba(75, 177, 38, var(--glow-shoulder)) 0%,
      rgba(75, 177, 38, calc(var(--glow-shoulder) * 0.38)) 45%,
      rgba(75, 177, 38, 0) 100%
    ),
    /* the brighter heart, off-centre and taller than it is wide */
      radial-gradient(
        34.96vh 41.8vh at 46% 105%,
        rgba(75, 177, 38, var(--glow-heart)) 0%,
        rgba(75, 177, 38, calc(var(--glow-heart) * 0.38)) 45%,
        rgba(75, 177, 38, 0) 100%
      ),
    /* the wide ambient wash, squashed low and wide along the boundary */
      radial-gradient(
        83.2vh 51.2vh at 50% 113%,
        rgba(75, 177, 38, var(--glow-wash)) 0%,
        rgba(75, 177, 38, calc(var(--glow-wash) * 0.38)) 45%,
        rgba(75, 177, 38, 0) 100%
      );
  transform-origin: 50% 100%;
  /* Two incommensurate periods, as in the app, so the light never visibly
     repeats: a 12s swell and a 19s lateral sway. They animate separate
     properties (scale, translate) so neither overwrites the other. */
  animation: echo-breath 12s ease-in-out infinite alternate,
    echo-drift 19s ease-in-out infinite alternate;
  will-change: scale, translate, opacity;
}

@keyframes echo-breath {
  from {
    scale: 1 1;
    opacity: 0.86;
  }
  to {
    scale: 1.035 1.05;
    opacity: 1;
  }
}

@keyframes echo-drift {
  from {
    translate: -1.4% 0;
  }
  to {
    translate: 1.4% 0;
  }
}

/* Content sits above the light. */
.page {
  position: relative;
  z-index: 1;
}

/* --------------------------------------------------------------------------
   Type styles
   -------------------------------------------------------------------------- */

.display,
.headline {
  font-weight: var(--weight-strong);
  letter-spacing: var(--tracking-tight);
  line-height: var(--leading-tight);
  color: var(--ink);
}

.display {
  font-size: var(--text-display);
}

.headline {
  font-size: var(--text-headline);
}

.subhead {
  font-size: var(--text-subhead);
  font-weight: var(--weight-strong);
  line-height: 1.35;
  color: var(--ink);
}

/* Reading text. Body copy is --ink, never green; emphasis is weight. */
.prose {
  max-width: var(--measure);
}

.prose > * + * {
  margin-top: var(--sp-5);
}

.prose strong,
.prose b {
  font-weight: var(--weight-strong);
}

.caption {
  font-size: var(--text-caption);
  color: var(--ink-secondary);
  line-height: 1.5;
}

.secondary {
  color: var(--ink-secondary);
}

/* --------------------------------------------------------------------------
   Chrome primitives — the app's shared language, ported
   -------------------------------------------------------------------------- */

/* Links: ink, never green. The underline is offset far enough to clear the
   descenders, the way the app keeps its labels uncrowded. */
a {
  color: var(--ink);
  text-decoration-line: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.22em;
  text-decoration-color: color-mix(in srgb, var(--ink) 32%, transparent);
  transition: text-decoration-color 120ms ease-out;
}

a:hover {
  text-decoration-color: var(--ink);
}

/* The app's one CTA language: a filled Signal Green capsule with a near-black
   Halbfett label. Never a white label — it fails contrast on this green
   (2.76:1); the near-black reads 6.46:1. The 44px floor is the touch target,
   not the capsule. */
.cta {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  padding: var(--sp-3) var(--sp-6);
  border: 0;
  border-radius: var(--radius-pill);
  background: var(--green);
  color: var(--ink-on-green);
  font-size: 1.0625rem;
  font-weight: var(--weight-strong);
  line-height: 1;
  text-decoration: none;
  box-shadow: var(--shadow-cta);
  cursor: pointer;
  transition: background-color 120ms ease-out, scale 120ms ease-out;
}

.cta:hover {
  text-decoration: none;
}

.cta:active {
  background: var(--green-pressed);
  scale: 0.98;
}

.cta--compact {
  min-height: 44px;
  padding: var(--sp-2) var(--sp-4);
  font-size: 0.9375rem;
}

/* A sheet of the brand's surface colour under a hairline. In dark mode the
   shadow token resolves to `none` and elevation reads from the surface being
   lighter than the paper, plus the hairline. */
.card {
  border: 1px solid var(--hairline);
  border-radius: var(--radius-lg);
  background: var(--surface);
  box-shadow: var(--shadow-card);
}

.card--row {
  border-radius: var(--radius);
}

/* Form fields, tokenised so no page has to invent a palette for them. */
.field {
  display: block;
}

.field > .label {
  display: block;
  margin-bottom: var(--sp-2);
  font-size: 0.9375rem;
  font-weight: var(--weight-strong);
}

.input,
.textarea,
.select {
  width: 100%;
  min-height: 44px;
  padding: var(--sp-3) var(--sp-4);
  border: 1px solid var(--hairline);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--ink);
  font-size: var(--text-body);
  line-height: 1.4;
  transition: border-color 120ms ease-out;
}

.textarea {
  min-height: 8rem;
  resize: vertical;
}

.input::placeholder,
.textarea::placeholder {
  color: var(--ink-secondary);
}

.input:hover,
.textarea:hover {
  border-color: color-mix(in srgb, var(--ink) 26%, var(--hairline));
}

/* Focus: Signal Green is legible as a *ring* in both modes even where it
   fails as text, and a focus ring is the definition of a moment that
   matters. The paper-coloured inner ring keeps it visible on any surface. */
:focus-visible {
  outline: 2px solid var(--green);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}

.input:focus-visible,
.textarea:focus-visible,
.select:focus-visible {
  outline-offset: 1px;
  border-color: var(--green);
}

/* Visible only to screen readers. */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* --------------------------------------------------------------------------
   Layout helpers
   -------------------------------------------------------------------------- */

.shell {
  width: 100%;
  max-width: var(--page-max);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

/* The brand mark. Sized by height; the artwork's own 122:150 ratio holds. */
.mark {
  display: block;
  width: auto;
  height: 1.75rem;
  aspect-ratio: 122 / 150;
}

/* --------------------------------------------------------------------------
   Motion
   --------------------------------------------------------------------------
   Under reduce motion the light holds still, mid-swell — the same thing the
   app does (EtherealGlow reads accessibilityReduceMotion and freezes the
   breath at 0.5). Everything else drops its transition too.
   -------------------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  .atmosphere::before {
    animation: none;
    scale: 1.018 1.025; /* mid-swell */
    opacity: 0.93;
    will-change: auto;
  }

  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* --------------------------------------------------------------------------
   Breakpoints — the type scale grows up; it was designed down at 400px.
   -------------------------------------------------------------------------- */

@media (min-width: 40rem) {
  :root {
    --text-display: 2.5rem; /* 40 */
    --text-headline: 1.75rem; /* 28 */
    --gutter: var(--sp-7);
  }
}

@media (min-width: 60rem) {
  :root {
    --text-headline: 1.875rem; /* 30 */
    --gutter: var(--sp-8);
  }
}
