/* global.css — the one design system every klarhimmel.com page follows.
   Load it first; the page-family sheets (signals.css for the numbered
   list, style.css for prose pages, events.css for /events/) consume the
   tokens defined here and add nothing of their own to the vocabulary.

   The system in one paragraph: a flat sky colour and an ink that reads on
   it, chosen once per session (the inline script in <head> sets
   html[data-sky]; night follows the OS dark preference). Inter for
   everything, on 37signals.com's fluid scale (2026-09-25, Felix): a
   vw-fluid base with no cap, steps as percentages of it, a wider spread
   on large hover-capable screens. Bold at the base size is the only
   heading weight; hierarchy comes from position and a little size, not
   from big display type. Links are ink, underlined. No borders, no cards,
   no shadows: the sky is the surface, the ink is the only material.

   Layout spacing uses em (relative to the fluid base) so rhythm scales
   with the type, as on 37signals.com. */

@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url('/assets/fonts/Inter-Variable.woff2') format('woff2');
}

@font-face {
  font-family: 'Inter';
  font-style: italic;
  font-weight: 100 900;
  font-display: swap;
  src: url('/assets/fonts/Inter-Italic-Variable.woff2') format('woff2');
}

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

:root {
  --font-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Helvetica Neue', sans-serif;

  /* Fluid type scale (37signals.com, verbatim): the base grows with the
     viewport; each step is a percentage of whatever font-size it sits in,
     so apply --font-size once on body and the steps inside it. */
  --font-size: calc(1em + 1vw);
  --font-size-x-small: 60%;
  --font-size-small: 80%;
  --font-size-large: 105%;
  --font-size-x-large: 110%;
  --font-size-xx-large: 115%;
  --font-size-xxx-large: 125%;
  --font-size-xxxx-large: 140%;
  --line: 1.35;

  /* Layout. --edge is the page margin; --measure the one reading width;
     --num-w the number column the homepage list hangs from (prose pages
     share it so a body of text sits at the same x as a signal's). */
  --edge: 1.25rem;
  --measure: 46ch;
  --gap: 0.85em;
  --num-w: 2.9ch;
  --t: 0.2s ease;

  /* Colour: one sky, one ink. Everything else is the ink at an opacity. */
  --sky: #dbe9f7;
  --rgb-ink: 11, 37, 69;
  --ink: rgb(var(--rgb-ink));
  --ink-soft: rgba(var(--rgb-ink), 0.86);  /* running text */
  --ink-mute: rgba(var(--rgb-ink), 0.78);  /* meta, notes: 4.5:1+ on every sky */
  --dim: 0.62;                             /* dimmed bold lines: 3:1+ on every sky */
  --rule: rgba(var(--rgb-ink), 0.18);      /* hairlines */
  --tint: rgba(var(--rgb-ink), 0.07);      /* a panel on the sky */
  --field: #fff;                           /* form fields */
}

/* Skies. Each is a flat colour plus an ink that reads on it. The inline
   <head> script picks one light sky per session and "night" when the OS
   prefers dark; the media query below is the no-JS fallback for night. */
@media (prefers-color-scheme: dark) {
  :root { --sky: #0c1a2c; --rgb-ink: 233, 240, 248; }
}
html[data-sky="morning"] { --sky: #dbe9f7; --rgb-ink: 11, 37, 69; }
html[data-sky="noon"]    { --sky: #bcd8f4; --rgb-ink: 9, 30, 58; }
html[data-sky="haze"]    { --sky: #e8ecf0; --rgb-ink: 26, 33, 46; }
html[data-sky="dusk"]    { --sky: #f2dccb; --rgb-ink: 60, 31, 20; }
html[data-sky="evening"] { --sky: #c6cde6; --rgb-ink: 25, 26, 62; }
html[data-sky="night"]   { --sky: #0c1a2c; --rgb-ink: 233, 240, 248; }

/* Large screens with a mouse: bigger base, wider spread (small steps
   smaller, large steps larger). Gated on pointer, not just width, so a
   landscape tablet keeps the touch scale — same gate as 37signals.com. */
@media (min-width: 64em) and (hover: hover) and (pointer: fine) {
  :root {
    --font-size: calc(1.25em + 1vw);
    --font-size-x-small: 50%;
    --font-size-small: 65%;
    --font-size-large: 110%;
    --font-size-x-large: 120%;
    --font-size-xx-large: 130%;
    --font-size-xxx-large: 150%;
    --font-size-xxxx-large: 180%;
    --line: 1.3;
  }
}

@media (min-width: 64em) {
  :root { --edge: 1.6rem; }
}

/* Base */
html {
  font-size: 16px;
  scroll-padding-top: 7em;
}

@media (min-width: 64em) {
  html { scroll-padding-top: max(24vh, 6em); }
}

body {
  min-height: 100vh;
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
  background: var(--sky);
  color: var(--ink-soft);
  font-family: var(--font-sans);
  font-size: var(--font-size);
  line-height: var(--line);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}

::selection { background: rgba(var(--rgb-ink), 0.14); }

a {
  color: var(--ink);
  text-decoration: underline;
  text-decoration-thickness: 0.06em;
  text-underline-offset: 0.12em;
  transition: color var(--t), opacity var(--t);
}

strong { color: var(--ink); }

/* Main: pushed down so content starts well below the fold's top edge,
   under the fixed header. */
main {
  flex: 1;
  padding: 7em var(--edge) 5em;
}

@media (min-width: 64em) {
  main { padding-top: max(24vh, 6em); }
}

/* Visually hidden but read by assistive tech. */
.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* Skip link: off-screen until focused. */
.skip-link {
  position: fixed;
  top: var(--edge); left: var(--edge);
  z-index: 20;
  padding: 0.3em 0.6em;
  background: var(--ink);
  color: var(--sky);
  font-size: var(--font-size-small);
  font-weight: 700;
  text-decoration: none;
  transform: translateY(-200%);
}
.skip-link:focus { transform: none; }

/* One focus ring, in ink, so it reads on every sky. */
:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 0.15em;
}

/* Header: wordmark right, links left, fixed, fading into the sky. The
   same three-word header on every page; no hamburger, it never needs one. */
.header {
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: 10;
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--gap);
  padding: var(--edge);
  pointer-events: none;
  background: linear-gradient(180deg, var(--sky) 0%, var(--sky) 45%, transparent 100%);
}

.header__mark {
  order: 2;
  pointer-events: auto;
  font-weight: 700;
  font-size: max(var(--font-size-small), 0.8rem);
  letter-spacing: 0.01em;
  text-decoration: none;
}

.header__links {
  order: 1;
  display: flex;
  flex-wrap: wrap;
  gap: 0 1.1em;
  list-style: none;
  pointer-events: auto;
  font-size: max(var(--font-size-small), 0.8rem);
  font-weight: 700;
}

.header__links a,
.header__links button {
  background: none;
  border: 0;
  padding: 0;
  font: inherit;
  color: var(--ink);
  cursor: pointer;
  text-decoration: none;
}
.header__links a:hover,
.header__links a:focus-visible,
.header__links button:hover,
.header__links button:focus-visible { text-decoration: underline; }
/* The section you are in, marked aria-current="page" in the markup.
   Dimmed, not to 50%: at 0.5 the ink reads 2.9:1 on dusk and evening,
   under WCAG's 3:1 floor even for large bold text. 0.62 clears 3:1 on
   every sky for the desktop size (bold, 22px+); phones set the links at
   12px, where 4.5:1 is required, so they dim only to 0.7 (4.9:1+). */
.header__links a[aria-current="page"] { opacity: var(--dim); }
@media (max-width: 30em) {
  .header__links a[aria-current="page"] { opacity: 0.7; }
}

/* Phones: four links and the wordmark on one line, a touch smaller. */
@media (max-width: 30em) {
  .header { gap: 0.6em; }
  .header__links { gap: 0 0.7em; }
  .header__links,
  .header__mark { font-size: 0.75rem; }
}

/* Footer: a link row and the legal line. */
.footer {
  position: relative;
  z-index: 2;
  padding: 0 var(--edge) var(--edge);
  font-size: max(var(--font-size-small), 0.8rem); /* never below ~13px */
}

.footer__links {
  display: flex;
  flex-wrap: wrap;
  gap: 0.2em 1.1em;
  list-style: none;
  font-weight: 700;
}

.footer__links a { text-decoration: none; }
.footer__links a:hover { text-decoration: underline; }

.footer__note {
  margin-top: 0.8em;
  color: var(--ink-mute);
  font-size: max(0.85em, 0.75rem);
}

/* Buttons and pills: ink on sky, or a hairline. The request form's
   submit, the events filter, and the register link all share these. */
.btn {
  display: inline-block;
  padding: 0.45em 1.1em;
  border: 0;
  border-radius: 2em;
  background: var(--ink);
  color: var(--sky);
  font: inherit;
  font-size: max(var(--font-size-small), 0.8rem);
  font-weight: 700;
  line-height: 1.3;
  text-decoration: none;
  cursor: pointer;
}
.btn:hover { color: var(--sky); opacity: 0.88; }
.btn:disabled { opacity: 0.5; cursor: progress; }

.pill {
  display: inline-block;
  padding: 0.3em 0.8em;
  border: 1px solid var(--rule);
  border-radius: 2em;
  background: none;
  color: var(--ink-mute);
  font: inherit;
  font-size: max(var(--font-size-small), 0.75rem);
  font-weight: 700;
  line-height: 1.3;
  text-decoration: none;
  cursor: pointer;
  transition: color var(--t), border-color var(--t), background-color var(--t);
}
.pill:hover,
.pill:focus-visible { color: var(--ink); border-color: var(--ink); }
/* Pressed: ink on sky. Stated after :hover and with higher specificity so
   hovering a pressed pill never paints ink text on an ink background. */
.pill[aria-pressed="true"],
.pill.is-on,
.pill[aria-pressed="true"]:hover,
.pill.is-on:hover,
.pill[aria-pressed="true"]:focus-visible,
.pill.is-on:focus-visible { background: var(--ink); border-color: var(--ink); color: var(--sky); }

/* The project-request form (homepage signal 12, /contact/, /lab/), after
   37signals.com's signup: a
   tinted panel, a textarea, and a white pill holding the email field and
   the button. Errors have no text; the bad field turns red (js/request.js). */
.request {
  margin-top: 0.9em;
  padding: 1em 1.2em 1.1em;
  border-radius: 0.3em;
  background: var(--tint);
  font-size: var(--font-size-small);
}

.request__label {
  display: block;
  margin-bottom: 0.5em;
  font-weight: 700;
  color: var(--ink);
}

.request textarea,
.request input[type="email"] {
  appearance: none;
  border: 0;
  font: inherit;
  color: rgb(11, 27, 51);
  background: var(--field);
}

.request textarea {
  display: block;
  width: 100%;
  min-height: 5.5em;
  padding: 0.7em 0.9em;
  border-radius: 0.6em;
  resize: vertical;
  line-height: 1.4;
}

.request__pill {
  display: flex;
  margin-top: 0.6em;
  padding: 0.25em;
  border-radius: 2em;
  background: var(--field);
}

.request input[type="email"] {
  flex: 1;
  min-width: 0;
  padding: 0.3em 0 0.3em 0.9em;
  background: none;
}

.request textarea::placeholder,
.request input[type="email"]::placeholder { color: rgba(11, 27, 51, 0.42); }

.request textarea:focus,
.request input[type="email"]:focus { outline: none; }
.request textarea:focus-visible,
.request__pill:focus-within { box-shadow: 0 0 0 2px var(--ink); }

.request textarea.is-error,
.request input.is-error {
  color: #c0271c;
  text-decoration: underline;
  text-decoration-thickness: from-font;
}
.request textarea.is-error { box-shadow: 0 0 0 2px #c0271c; }

.request button {
  flex: none;
  padding: 0.45em 1.1em;
  border: 0;
  border-radius: 2em;
  background: var(--ink);
  color: var(--sky);
  font: inherit;
  font-weight: 700;
  cursor: pointer;
}
.request button:disabled { opacity: 0.5; cursor: progress; }

.request__trap { position: absolute; left: -5000px; }

.request__note {
  margin-top: 0.6em;
  color: var(--ink-mute);
}

.request__failed { display: none; margin-top: 0.4em; color: var(--ink); }
.request.is-failed .request__failed { display: block; }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { transition: none !important; }
}
