/* ------------------------------------------------------------------------
   base.css — the design system as CSS. Shared by every page, the atlas
   included, and loaded straight after tokens.css.

   This is the layer that makes the site and the application one product:
   the reset, the four type voices, the glass ladder, the button pair, the
   weather switch, the logomark's dots, and the focus ring. Anything used on
   both sides of the codebase belongs here; anything used on one belongs in
   site.css or atlas.css.

   Carries no colour of its own — every value is a var() into tokens.css.
   ---------------------------------------------------------------------- */


/* ================================================================== RESET */

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

/* several hidden elements are flex/grid containers, which would otherwise win
   over the user-agent [hidden] rule */
[hidden] { display: none !important; }

h1, h2, h3, h4, p, ul, ol, figure, dl, dd, blockquote { margin: 0; }

body {
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--text-body);
  line-height: var(--leading-body);
  font-weight: var(--weight-body);
  color: var(--ink);
  background: var(--sky-far);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  /* The sky cross-fades over 1.6s; ink follows at a third of it. */
  transition: background var(--t-weather), color var(--t-theme);
}

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

/* One ring, one value, both weathers. A focus ring is a state, not
   decoration, which is the one job besides a primary action that the accent
   is allowed to do. */
:focus-visible {
  outline: 2px solid var(--ring);
  outline-offset: 3px;
  border-radius: var(--radius-default);
}


/* ============================================================ TYPE VOICES */
/* One family, four voices. What separates a heading from a label from a
   datum is tracking and figure style, never a second typeface. */

.eyebrow {
  font-size: var(--text-eyebrow);
  line-height: var(--leading-eyebrow);
  letter-spacing: var(--tracking-eyebrow);
  font-weight: var(--weight-strong);
  text-transform: uppercase;
  color: var(--ink-faint);
  transition: color var(--t-theme);
}

.h1 {
  font-size: var(--text-h1);
  line-height: var(--leading-h1);
  letter-spacing: var(--tracking-h1);
  font-weight: var(--weight-display);
  text-wrap: balance;
}
.h2 {
  font-size: var(--text-h2);
  line-height: var(--leading-h2);
  letter-spacing: var(--tracking-h2);
  font-weight: var(--weight-display);
  text-wrap: balance;
}
.h3 {
  font-size: var(--text-h3);
  line-height: var(--leading-h3);
  letter-spacing: var(--tracking-h3);
  font-weight: var(--weight-display);
}

.lead {
  font-size: var(--text-lead);
  line-height: var(--leading-lead);
  color: var(--ink-soft);
  max-width: var(--measure);
  transition: color var(--t-theme);
}
.body { color: var(--ink-soft); max-width: var(--measure); transition: color var(--t-theme); }
.fine {
  font-size: var(--text-fine);
  line-height: var(--leading-fine);
  color: var(--ink-faint);
  transition: color var(--t-theme);
}

/* The measured voice. Figtree carries tabular figures on its variable axis,
   so a column of atlas values lines up without a second face — which is the
   entire reason the system needs only one. Every number wears this, and
   every number wears a unit. */
.num {
  font-family: var(--font-data);
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
  letter-spacing: var(--tracking-data);
}

/* Emphasis inside body copy. Nothing is bolder than 500 except the
   wordmark, so `b` and `strong` step up in colour, not in weight. */
b, strong { font-weight: var(--weight-strong); color: var(--ink); }

/* A link inside running text. The palette has one chromatic value and it is
   spent on the primary action, so a link is ink with a hairline underline
   and only takes the accent on hover — where it is a response to being
   touched rather than a second colour standing on the page. Left to itself
   the browser paints #0000EE, which is the only colour on the site that is
   in no palette at all. */
.lead a, .body a, .fine a, .faq__a a {
  color: var(--ink);
  text-decoration-color: var(--ink-hairline-strong);
  text-underline-offset: 3px;
  transition: color var(--t-ui), text-decoration-color var(--t-ui);
}
.lead a:hover, .body a:hover, .fine a:hover, .faq__a a:hover {
  color: var(--accent);
  text-decoration-color: var(--accent);
}


/* ====================================================== LAYOUT PRIMITIVES */

.wrap {
  width: 100%;
  max-width: var(--page-max-width);
  margin-inline: auto;
  padding-inline: var(--space-24);
}
.section { padding-block: var(--section-rhythm); }

.stack { display: flex; flex-direction: column; }
.stack-8  { gap: var(--space-8); }
.stack-12 { gap: var(--space-12); }
.stack-16 { gap: var(--space-16); }
.stack-20 { gap: var(--space-20); }
.stack-28 { gap: var(--space-28); }
.stack-40 { gap: var(--space-40); }


/* ================================================================== GLASS */
/* Three levels. A fourth is a layout problem wearing a blur.

   Surfaces sit on a moving photograph, so unlike a flat canvas each level
   gets exactly one soft shadow and one inner highlight — that is the entire
   elevation vocabulary. Cards never take a hairline: if a surface needs an
   edge to be legible, its value step is wrong. */

.glass {
  background: linear-gradient(145deg, var(--glass-a), var(--glass-b));
  border: 1px solid var(--glass-line);
  box-shadow: var(--glass-shadow), var(--glass-inner);
  -webkit-backdrop-filter: saturate(185%) blur(20px);
  backdrop-filter: saturate(185%) blur(20px);
  transition: background var(--t-theme), border-color var(--t-theme),
              box-shadow var(--t-theme);
}

/* content — cards, the Atlas window */
.glass--panel {
  -webkit-backdrop-filter: saturate(160%) blur(14px);
  backdrop-filter: saturate(160%) blur(14px);
}

/* lead — one per screen, maximum */
.glass--lifted {
  border-color: var(--glass-line-lit);
  box-shadow: var(--glass-shadow-lg), var(--glass-inner);
  -webkit-backdrop-filter: saturate(190%) blur(26px);
  backdrop-filter: saturate(190%) blur(26px);
}

/* The opaque variant, for surfaces on solid ground where a backdrop filter
   has nothing to filter: the same gradient and highlight over a raised base,
   and no hairline — a border would draw the eye to the container instead of
   to what is inside it. */
.glass--solid {
  background: linear-gradient(160deg, var(--glass-a), var(--glass-b)), var(--ground-raised);
  border: 0;
  box-shadow: var(--glass-inner), var(--glass-shadow);
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
  transition: background var(--t-theme), box-shadow var(--t-theme);
}


/* ================================================================ BUTTONS */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 9px;
  padding: 12px 22px;
  border-radius: var(--radius-pill);
  border: 1px solid transparent;
  font-size: 15px;
  font-weight: var(--weight-strong);
  letter-spacing: -.005em;
  line-height: 1.2;
  text-decoration: none;
  cursor: pointer;
  color: var(--ink);
  transition: transform var(--t-ui), background-color var(--t-ui),
              box-shadow var(--t-ui), border-color var(--t-ui), color var(--t-ui);
}
.btn:active { transform: translateY(0); }
.btn--sm { padding: 8px 16px; font-size: var(--text-fine); }

/* The one chromatic action. ONE PER SCREEN — the accent is never a rail, a
   bullet, an icon fill or a hover tint, because a decorative accent is no
   longer an action. */
.btn--primary {
  background: var(--accent);
  color: var(--accent-ink);
  box-shadow: 0 6px 18px var(--accent-glow), inset 0 1px 0 #ffffff30;
}
.btn--primary:hover {
  background: var(--accent-hover);
  box-shadow: 0 10px 28px var(--accent-glow), inset 0 1px 0 #ffffff38;
  transform: translateY(-1px);
}

/* The secondary. Same geometry as the primary, so the two sit side by side
   without either dominating. */
.btn--glass {
  background: linear-gradient(145deg, var(--glass-a), var(--glass-b));
  border-color: var(--glass-line-lit);
  box-shadow: var(--glass-inner), 0 6px 16px #0f172a1a;
  -webkit-backdrop-filter: saturate(175%) blur(16px);
  backdrop-filter: saturate(175%) blur(16px);
}
.btn--glass:hover {
  transform: translateY(-1px);
  box-shadow: var(--glass-inner), 0 12px 24px #0f172a26;
}


/* ========================================================= WEATHER SWITCH */
/* Two states and ONE button, showing the weather in force rather than a row
   of options — it is a switch, and a switch is one control. The same one
   appears in the site nav and in the atlas top bar, on one key, so the two
   halves of the product never disagree about the weather. */

.weather {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  padding: 0;
  border-radius: var(--radius-pill);
  background: var(--wash);
  border: 1px solid var(--ink-hairline);
  color: var(--ink-soft);
  cursor: pointer;
  transition: background var(--t-theme), border-color var(--t-theme),
              color var(--t-ui), box-shadow var(--t-ui);
}
.weather:hover {
  color: var(--ink);
  background: linear-gradient(145deg, var(--glass-a), var(--glass-b));
  box-shadow: var(--glass-inner), 0 2px 8px #0f172a1f;
}
/* The icon names the weather the reader is IN, which is what a switch reports.
   Both ship in the markup so the swap is a CSS state change, not a repaint the
   script has to remember to do.

   Every selector here carries the same `.weather svg` weight on purpose: a bare
   `.weather__rain { display: none }` is (0,1,0) and loses to the `.weather svg`
   default at (0,1,1), which draws BOTH icons side by side. */
.weather svg { flex: 0 0 auto; }
.weather svg.weather__clear { display: block; }
.weather svg.weather__rain { display: none; }
.weather[aria-checked="true"] svg.weather__clear { display: none; }
.weather[aria-checked="true"] svg.weather__rain { display: block; }


/* ================================================================== BRAND */
/* Four dots on one axis, radii 1 : 1.4 : 2 : 2.7, blur proportional to
   radius. The mark is a SEQUENCE, so it is reused wherever content is
   genuinely sequential and nowhere else.

   This file carries no `.mark` / `.wordmark` pair: the nav and the footer
   both render the lockup ARTWORK through `Logo.astro`, which is the drawing
   itself rather than a CSS reconstruction of it. */

/* the mark, decomposed */
.seq-dot {
  border-radius: var(--radius-pill);
  background: var(--ink);
  transition: background var(--t-theme);
}
.seq-dot--1 { width: 5px;  height: 5px;  }
.seq-dot--2 { width: 7px;  height: 7px;  filter: blur(.28px); }
.seq-dot--3 { width: 10px; height: 10px; filter: blur(.6px); }
.seq-dot--4 { width: 14px; height: 14px; filter: blur(1.25px); }

/* Two logo files, one shown (see src/components/Logo.astro). Keyed on
   `data-theme` rather than `prefers-color-scheme`, because the reader can
   override the OS from the weather switch and the logo has to follow the
   reader. */
.logo { display: inline-flex; align-items: center; line-height: 0; }
/* The `width`/`height` attributes carry the intended size (Logo.astro
   computes the pair from the file's own viewBox), so CSS must not override
   them — a `height: inherit` here renders the lockup at its intrinsic
   1029x320. */
.logo img { display: block; max-width: 100%; height: auto; }
.logo .logo-paper { display: none; }

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .logo .logo-ink { display: none; }
  :root:not([data-theme="light"]) .logo .logo-paper { display: block; }
}
:root[data-theme="dark"] .logo .logo-ink { display: none; }
:root[data-theme="dark"] .logo .logo-paper { display: block; }
:root[data-theme="light"] .logo .logo-ink { display: block; }
:root[data-theme="light"] .logo .logo-paper { display: none; }


/* ================================================================= MOTION */
/* The sky is the only thing that moves on its own. Everything else moves
   because it was touched. */

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
  }
}
