/*
 * base.css: shared by every page of dr-dev.ch.
 *
 * Holds the fonts, the design tokens and the parts every page uses (page
 * shell, header, footer, links, skip link). Page files (home.css,
 * privacy.css, error.css, ...) style only what is theirs and use these
 * tokens for every colour, size and space.
 *
 * Rules (enforced by tests/css.test.mjs):
 *   - Colour literals appear only in custom-property declarations, which
 *     means the token blocks below.
 *   - Pixel values appear only in custom-property declarations and @media
 *     conditions. A deliberate exception carries a trailing
 *     `/* literal: <reason> *\/` comment on the same line.
 *   - Custom properties cannot be used inside @media conditions, so the
 *     breakpoints (900px tablet, 600px phone) are written out wherever they
 *     appear.
 */

/* ── Fonts (self-hosted; no third-party requests, see privacy.html) ── */
@font-face {
  font-family: 'JetBrains Mono';
  font-style: normal;
  font-weight: 400 800;
  font-display: swap;
  src: url('../../fonts/jetbrains-mono-latin.woff2') format('woff2');
  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: 'JetBrains Mono';
  font-style: normal;
  font-weight: 400 800;
  font-display: swap;
  src: url('../../fonts/jetbrains-mono-latin-ext.woff2') format('woff2');
  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: 'Space Grotesk';
  font-style: normal;
  font-weight: 300 700;
  font-display: swap;
  src: url('../../fonts/space-grotesk-latin.woff2') format('woff2');
  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: 'Space Grotesk';
  font-style: normal;
  font-weight: 300 700;
  font-display: swap;
  src: url('../../fonts/space-grotesk-latin-ext.woff2') format('woff2');
  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;
}

/* ── Tokens: colour, dark theme (the default) ───────────────────── */
:root {
  --bg:    #0b0e12;
  --card:  #11151b;
  --fg:    #e6edf3;
  --mut:   #8b98a5;
  --line:  #1e242c;
  --acc:   #a3e635;
  --accfg: #0b0e12;
  /* Form fields. Their boundary is at least 3:1 against both the page and
     the field (WCAG 1.4.11); placeholder text at least 4.5:1 (1.4.3).
     tests/a11y.test.mjs measures both. */
  --field-border: #5b656f;
  --placeholder:  #75818d;
  /* Ambient decor: deliberately stronger than --line so the grid and
     watermark actually read against the background */
  --grid:  rgba(139, 152, 165, 0.28);
  --wm:    rgba(230, 237, 243, 0.04);
  --wm-trace: rgba(163, 230, 53, 0.25); /* subtle accent line traced along the watermark */
  /* card lift on hover/focus: faint lime halo + depth for the dark theme */
  --glow:  0 0 28px rgba(163, 230, 53, 0.10), 0 16px 44px rgba(0, 0, 0, 0.45);
  color-scheme: dark;
}

/* ── Tokens: colour, light theme ────────────────────────────────── */
:root[data-theme="light"] {
  --bg:    #f5f7f4;
  --card:  #ffffff;
  --fg:    #141a14;
  --mut:   #5b6b5e;
  --line:  #d8ded4;
  --acc:   #3f6212;
  --accfg: #ffffff;
  --field-border: #859185;
  --placeholder:  #6a796c;
  --grid:  rgba(60, 80, 64, 0.30);
  --wm:    rgba(20, 26, 20, 0.04);
  --wm-trace: rgba(63, 98, 18, 0.25);
  /* softer, green-tinted depth for the light theme; no halo (muddy on white) */
  --glow:  0 10px 30px rgba(31, 45, 26, 0.12);
  color-scheme: light;
}

/* ── Tokens: type, space, shape, layout ─────────────────────────── */
:root {
  --font-sans: 'Space Grotesk', sans-serif;
  --font-mono: 'JetBrains Mono', monospace;

  /* Type scale. UI sizes are fixed; display sizes scale with the viewport. */
  --fs-micro:   11px;
  --fs-caption: 12px;
  --fs-label:   13px;
  --fs-ui:      14px;
  --fs-input:   15px;
  --fs-body:    16px;
  --fs-logo:    18px;
  --fs-lead:    22px;
  --fs-card-title: 30px;
  --fs-section-title: 44px;
  --fs-error-code: 72px;
  --fs-page-title: clamp(34px, 6vw, 52px);
  --fs-hero:       clamp(52px, 8vw, 96px);
  --fs-watermark:  clamp(120px, 24vw, 230px);

  --lh-display: 1.02;
  --lh-heading: 1.1;
  --lh-snug:    1.3;
  --lh-body:    1.6;
  --lh-relaxed: 1.7;
  --lh-loose:   1.8;

  /* Spacing scale: --space-N is N × 4px (Tailwind's naming). */
  --space-1:   4px;
  --space-1_5: 6px;
  --space-2:   8px;
  --space-2_5: 10px;
  --space-3:   12px;
  --space-3_5: 14px;
  --space-4:   16px;
  --space-5:   20px;
  --space-5_5: 22px;
  --space-6:   24px;
  --space-7:   28px;
  --space-8:   32px;
  --space-9:   36px;
  --space-10:  40px;
  --space-11:  44px;
  --space-12:  48px;
  --space-14:  56px;
  --space-16:  64px;

  --hairline:  1px;
  --underline-weight:   2px;
  --underline-overhang: var(--space-6); /* how far the section underline runs past its label */
  --focus-width:  2px;
  --focus-offset: 2px;

  --control-size: 40px;  /* square icon buttons */
  --icon-size:    20px;

  --radius-sm:   6px;
  --radius-md:   8px;
  --radius-lg:   12px;
  --radius-pill: 99px;

  --container:        1200px;
  --container-narrow: 760px;
  --measure:          560px;   /* project card text */
  --measure-wide:     640px;   /* about text */
  --about-label-col:  220px;

  /* Theme toggle motion: icon swing with a slight overshoot, rays that
     shoot out one after another, and the circular theme reveal. */
  --ease-spring:   cubic-bezier(0.34, 1.56, 0.64, 1);
  --dur-icon:      500ms;
  --dur-icon-fade: 250ms;
  --dur-ray:       350ms;
  --dur-ray-wait:  180ms;   /* rays start once the sun's core is in */
  --ray-stagger:   35ms;
  --dur-reveal:    650ms;
  --ease-reveal:   cubic-bezier(0.65, 0, 0.35, 1);

  --hover-dim: 0.8;          /* links */
  --hover-dim-filled: 0.85;  /* buttons with an accent fill */
  --transition-hover: 0.25s ease;

  /* Responsive layout tokens, redefined at the breakpoints below so each
     page reads one value instead of overriding it per breakpoint. */
  --gutter:            40px;
  --section-pad:       90px;
  --hero-pad-top:      140px;
  --hero-pad-bottom:   110px;
  --contact-pad-bottom: 110px;
}

@media (max-width: 900px) {
  :root {
    --gutter:            24px;
    --section-pad:       72px;
    --hero-pad-top:      100px;
    --hero-pad-bottom:   80px;
    --contact-pad-bottom: 80px;
  }
}

@media (max-width: 600px) {
  :root {
    --gutter:            20px;
    --section-pad:       56px;
    --hero-pad-top:      36px;
    --hero-pad-bottom:   64px;
    --contact-pad-bottom: 56px;
    --fs-section-title:  36px;
  }
}

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

/* No grey/blue box over links and buttons on tap (Android, iOS). Feedback
   comes from the site's own hover, focus and toggle states instead.
   Inherited, so setting it once on the root covers every element. */
html { -webkit-tap-highlight-color: transparent; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--fg);
  font: 400 var(--fs-body)/var(--lh-body) var(--font-sans);
  -webkit-font-smoothing: antialiased;
}

a { color: inherit; text-decoration: none; }
a:hover { opacity: var(--hover-dim); }

:focus-visible { outline: var(--focus-width) solid var(--acc); outline-offset: var(--focus-offset); }

/* ── Page shell ─────────────────────────────────────────────────── */
/* The hero grid bleeds into .wrap's side padding on purpose. On a phone the
   gutter is narrower than the bleed, so clip at .wrap's edge, which is the
   screen edge there; on desktop the gutter fits the bleed and nothing is cut.
   Set here, not on body: body's overflow is handed to the viewport, where
   mobile browsers still let the page pan sideways. `clip`, unlike `hidden`,
   does not create a scroll container. */
.wrap {
  max-width: var(--container);
  margin: 0 auto;
  padding: 0 var(--gutter);
  overflow-x: clip;
}
.wrap--narrow { max-width: var(--container-narrow); }

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

.skip-link {
  position: absolute;
  top: -100%; left: var(--space-4);
  z-index: 10;
  font: 500 var(--fs-label) var(--font-mono);
  background: var(--acc);
  color: var(--accfg);
  padding: var(--space-2_5) var(--space-4);
  border-radius: 0 0 var(--radius-md) var(--radius-md);
}
.skip-link:focus { top: 0; }

/* Links inside running text: underlined, because colour alone does not set
   them apart from the surrounding text (WCAG 1.4.1). */
.text-link {
  color: var(--acc);
  text-decoration: underline;
  text-decoration-thickness: var(--hairline);
  text-underline-offset: 0.2em;
}

/* ── Header ─────────────────────────────────────────────────────── */
.site-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  flex-wrap: wrap;
  padding: var(--space-6) 0;
  border-bottom: var(--hairline) solid var(--line);
}

.logo { font: 700 var(--fs-logo) var(--font-mono); color: var(--acc); }

/* ── Footer ─────────────────────────────────────────────────────── */
.site-footer { border-top: var(--hairline) solid var(--line); }
.site-footer .wrap {
  display: flex;
  justify-content: space-between;
  gap: var(--space-2) var(--space-6);
  flex-wrap: wrap;
  padding-top: var(--space-6);
  padding-bottom: var(--space-6);
  font: 400 var(--fs-caption) var(--font-mono);
  color: var(--mut);
}
