/* =============================================================================
   FF BRAUNAU — DESIGN TOKENS
   =============================================================================

   This is the ONLY file in the project allowed to contain literal design
   values. Every component references var(--token). Enforced by:

       npm run check:tokens

   Three layers, in order. Do not cross the boundaries:

     1. PRIMITIVES   raw scale values, named for what they ARE (--red-600).
                     Components must NEVER use these directly.
     2. SEMANTIC     named for their ROLE (--color-surface). Mapped from
                     primitives. This is the ONLY layer components touch.
     3. THEMES       :root (light editorial) and [data-theme='dark']
                     (dark cinematic) remap layer 2.

   To restyle the entire site, edit layer 2/3. Nothing else should need to move.
   ============================================================================= */

/* =============================================================================
   LAYER 1 — PRIMITIVES
   Raw values. Never referenced outside this file's own semantic layer.
   ============================================================================= */

:root {
  /* --- Brand red -----------------------------------------------------------
     Sampled from the Feuerwehr Braunau crest. Austrian fire service red.
     Replace this ramp to rebrand; nothing downstream needs to change.        */
  --red-50: #fff1f1;
  --red-100: #ffdfdf;
  --red-200: #ffc5c5;
  --red-300: #ff9d9d;
  --red-400: #ff6464;
  --red-500: #f83333;
  --red-600: #e11414;
  --red-700: #bd0f0f;
  --red-800: #9c1212;
  --red-900: #811616;
  --red-950: #460505;

  /* --- Neutrals -------------------------------------------------------------
     Very slightly warm so large dark surfaces don't read as cold blue-grey.  */
  --neutral-0: #ffffff;
  --neutral-50: #faf9f8;
  --neutral-100: #f4f2f1;
  --neutral-200: #e7e4e2;
  --neutral-300: #d3cecb;
  --neutral-400: #a8a29e;
  --neutral-500: #79736f;
  --neutral-600: #57514e;
  --neutral-700: #423d3a;
  --neutral-800: #292524;
  --neutral-900: #1a1817;
  --neutral-950: #0e0d0c;
  --neutral-1000: #000000;

  /* --- Einsatz category hues -----------------------------------------------
     Distinct enough to tell apart at a glance in the archive, and chosen to
     stay distinguishable for the most common forms of color blindness.
     Never the only signal — always paired with a text label.                 */
  --hue-fire: #e14a14;      /* Brand              */
  --hue-technical: #2563c9; /* Technische Hilfe   */
  --hue-rescue: #12876a;    /* Personen/Tier      */
  --hue-water: #0d7fa8;     /* Wasserdienst       */
  --hue-hazmat: #b45309;    /* Schadstoff         */
  --hue-height: #7c3aed;    /* Höhenrettung       */
  --hue-traffic: #c2410c;   /* Verkehrsunfall     */
  --hue-other: #57514e;     /* Sonstiges          */

  /* --- Alarm levels (Alarmstufe 1-4) --------------------------------------- */
  --level-1: #4b9b3f;
  --level-2: #d19a00;
  --level-3: #e2670a;
  --level-4: #d01515;

  /* --- Spacing scale --------------------------------------------------------
     1 unit = 0.25rem = 4px.                                                  */
  --space-0: 0;
  --space-px: 1px;
  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: 0.75rem;
  --space-4: 1rem;
  --space-5: 1.25rem;
  --space-6: 1.5rem;
  --space-8: 2rem;
  --space-10: 2.5rem;
  --space-12: 3rem;
  --space-16: 4rem;
  --space-20: 5rem;
  --space-24: 6rem;
  --space-32: 8rem;
  --space-40: 10rem;

  /* --- Fluid type scale -----------------------------------------------------
     clamp(min, preferred, max). Scales between a 360px and a 1440px viewport
     without breakpoints.                                                     */
  --text-xs: clamp(0.75rem, 0.73rem + 0.09vw, 0.8125rem);
  --text-sm: clamp(0.875rem, 0.85rem + 0.11vw, 0.9375rem);
  --text-base: clamp(1rem, 0.97rem + 0.14vw, 1.0625rem);
  --text-lg: clamp(1.125rem, 1.08rem + 0.23vw, 1.25rem);
  --text-xl: clamp(1.25rem, 1.17rem + 0.37vw, 1.5rem);
  --text-2xl: clamp(1.5rem, 1.35rem + 0.65vw, 1.875rem);
  --text-3xl: clamp(1.875rem, 1.62rem + 1.1vw, 2.5rem);
  --text-4xl: clamp(2.25rem, 1.8rem + 2vw, 3.5rem);
  --text-5xl: clamp(2.75rem, 1.9rem + 3.7vw, 5rem);
  --text-hero: clamp(3rem, 1.6rem + 6vw, 7.5rem);

  --leading-tight: 1.05;
  --leading-snug: 1.25;
  --leading-normal: 1.55;
  --leading-relaxed: 1.7;

  --tracking-tighter: -0.03em;
  --tracking-tight: -0.015em;
  --tracking-normal: 0;
  --tracking-wide: 0.02em;
  --tracking-widest: 0.14em;

  --weight-normal: 400;
  --weight-medium: 500;
  --weight-semibold: 600;
  --weight-bold: 700;

  /* --- Radii --------------------------------------------------------------- */
  --radius-none: 0;
  --radius-sm: 0.25rem;
  --radius-md: 0.5rem;
  --radius-lg: 0.875rem;
  --radius-xl: 1.25rem;
  --radius-full: 9999px;

  /* --- Motion ---------------------------------------------------------------
     Components reference these so a global motion change is one edit.        */
  --duration-instant: 80ms;
  --duration-fast: 160ms;
  --duration-normal: 260ms;
  --duration-slow: 480ms;
  --duration-slower: 900ms;
  --ease-out: cubic-bezier(0.22, 1, 0.36, 1);
  --ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);
  --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);

  /* Scroll-reveal: distance an element travels as it fades in, and the delay
     step between siblings that enter together (see the REVEAL block below). */
  --reveal-shift: 1.25rem;
  --reveal-stagger: 65ms;

  /* --- Layout --------------------------------------------------------------- */
  --container-sm: 40rem;
  --container-md: 52rem;
  --container-lg: 68rem;
  --container-xl: 80rem;
  --container-full: 96rem;
  --gutter: clamp(var(--space-4), 4vw, var(--space-12));
  --header-height: 4.5rem;

  --z-base: 0;
  --z-raised: 10;
  --z-sticky: 100;
  --z-header: 200;
  --z-overlay: 300;
  --z-modal: 400;

  /* --- Typography families --------------------------------------------------
     --font-sans / --font-display are emitted by Astro's font pipeline
     (see astro.config.mjs) and self-hosted at build time.                    */
  --font-body: var(--font-sans), system-ui, sans-serif;
  --font-heading: var(--font-display), var(--font-sans), system-ui, sans-serif;
  --font-mono: ui-monospace, "SF Mono", "Cascadia Mono", Menlo, monospace;
}

/* =============================================================================
   LAYER 2 + 3 — SEMANTIC TOKENS, LIGHT THEME ("editorial")
   Default. Used for content pages: archive, reports, info pages.
   ============================================================================= */

:root,
[data-theme='light'] {
  color-scheme: light;

  /* Surfaces */
  --color-surface: var(--neutral-0);
  --color-surface-sunken: var(--neutral-100);
  --color-surface-raised: var(--neutral-0);
  --color-surface-overlay: var(--neutral-0);
  --color-surface-inverse: var(--neutral-950);

  /* Text */
  --color-text: var(--neutral-900);
  --color-text-muted: var(--neutral-600);
  --color-text-subtle: var(--neutral-500);
  --color-text-inverse: var(--neutral-0);
  --color-text-on-brand: var(--neutral-0);

  /* Brand */
  --color-brand: var(--red-700);
  --color-brand-hover: var(--red-800);
  --color-brand-subtle: var(--red-50);
  --color-brand-border: var(--red-200);

  /* Borders and separators */
  --color-border: var(--neutral-200);
  --color-border-strong: var(--neutral-300);
  --color-divider: var(--neutral-200);

  /* Interaction */
  --color-focus: var(--red-600);
  --color-selection-bg: var(--red-100);
  --color-selection-text: var(--neutral-950);

  /* Feedback — error/danger text (form validation, failed submits) */
  --color-danger: var(--red-700);

  /* Elevation — shadows are theme-specific, hence defined here not in layer 1 */
  --shadow-sm: 0 1px 2px rgb(0 0 0 / 0.05);
  --shadow-md: 0 2px 4px rgb(0 0 0 / 0.05), 0 4px 12px rgb(0 0 0 / 0.06);
  --shadow-lg: 0 4px 8px rgb(0 0 0 / 0.05), 0 12px 32px rgb(0 0 0 / 0.1);
  --shadow-xl: 0 8px 16px rgb(0 0 0 / 0.06), 0 24px 56px rgb(0 0 0 / 0.14);

  /* Header — translucent over content, solid enough to stay readable */
  --color-header-bg: rgb(255 255 255 / 0.82);
  --color-header-border: var(--neutral-200);

  /* Transparent (over-hero) header — a frosted glass panel: dark enough to lift
     the light logo/nav off the footage, translucent + blurred so the video
     still reads through it. Deliberately dark in BOTH themes, like the hero
     scrim, because the header text over it is always --color-hero-text. */
  --color-hero-header-bg: rgb(0 0 0 / 0.25);
  --color-hero-header-border: rgb(255 255 255 / 0.16);

  /* Hero scrim — the gradient that keeps hero copy legible over the video.

     The stops are placed against where the text actually sits, not by eye. The
     hero content block begins around 40% depth (the eyebrow) and runs to the
     buttons near the bottom, so the ramp to a heavy alpha happens at 40% and
     the video is left brightest above that, where nothing overlaps it.

     Measured by compositing the live gradient over the brightest pixel in each
     text row: an earlier 0.28@30% / 0.62@62% ramp left the eyebrow at 2.95:1,
     failing AA. Re-measure if the footage is replaced with brighter material —
     values are frame-dependent.                                              */
  --hero-scrim: linear-gradient(
    to bottom,
    rgb(0 0 0 / 0.5) 0%,
    rgb(0 0 0 / 0.3) 22%,
    rgb(0 0 0 / 0.66) 40%,
    rgb(0 0 0 / 0.9) 100%
  );
  --color-hero-text: var(--neutral-0);
  --color-hero-text-muted: var(--neutral-200);

  /* Chart track — the unfilled portion of a bar. Must read clearly as "empty"
     in both themes and never compete with the fill for attention. */
  --color-chart-track: var(--neutral-200);
  --color-chart-baseline: var(--neutral-300);

  /* Lightbox / media viewer.
     Deliberately dark in BOTH themes — a full-bleed white overlay behind a
     photo is painful, and photos read better against dark. These do not flip
     with the theme, which is why they are their own tokens rather than reusing
     --color-surface-inverse. */
  --color-backdrop: rgb(0 0 0 / 0.9);
  --color-lightbox-bg: var(--neutral-1000);
  --color-lightbox-text: var(--neutral-100);

  /* Einsatz categories */
  --color-art-brand: var(--hue-fire);
  --color-art-technisch: var(--hue-technical);
  --color-art-rettung: var(--hue-rescue);
  --color-art-wasser: var(--hue-water);
  --color-art-schadstoff: var(--hue-hazmat);
  --color-art-hoehe: var(--hue-height);
  --color-art-verkehr: var(--hue-traffic);
  --color-art-sonstiges: var(--hue-other);

  /* Alarm levels */
  --color-alarm-1: var(--level-1);
  --color-alarm-2: var(--level-2);
  --color-alarm-3: var(--level-3);
  --color-alarm-4: var(--level-4);
}

/* =============================================================================
   THEME — DARK ("cinematic")
   Landing-page mode. Near-black, signal red, video-forward.
   ============================================================================= */

[data-theme='dark'] {
  color-scheme: dark;

  --color-surface: var(--neutral-950);
  --color-surface-sunken: var(--neutral-1000);
  --color-surface-raised: var(--neutral-900);
  --color-surface-overlay: var(--neutral-800);
  --color-surface-inverse: var(--neutral-0);

  --color-text: var(--neutral-50);
  --color-text-muted: var(--neutral-400);
  --color-text-subtle: var(--neutral-500);
  --color-text-inverse: var(--neutral-950);
  --color-text-on-brand: var(--neutral-0);

  /* Lighter red on dark: --red-700 fails contrast against near-black. */
  --color-brand: var(--red-500);
  --color-brand-hover: var(--red-400);
  --color-brand-subtle: var(--red-950);
  --color-brand-border: var(--red-900);

  --color-border: var(--neutral-800);
  --color-border-strong: var(--neutral-700);
  --color-divider: var(--neutral-800);

  --color-focus: var(--red-400);
  --color-selection-bg: var(--red-800);
  --color-selection-text: var(--neutral-0);

  /* Lighter red for danger too: --red-700 fails contrast on near-black. */
  --color-danger: var(--red-400);

  /* Shadows barely read on dark surfaces — lean on borders instead, and keep
     shadows only for genuine depth cues. */
  --shadow-sm: 0 1px 2px rgb(0 0 0 / 0.4);
  --shadow-md: 0 2px 4px rgb(0 0 0 / 0.4), 0 4px 12px rgb(0 0 0 / 0.5);
  --shadow-lg: 0 4px 8px rgb(0 0 0 / 0.45), 0 12px 32px rgb(0 0 0 / 0.6);
  --shadow-xl: 0 8px 16px rgb(0 0 0 / 0.5), 0 24px 56px rgb(0 0 0 / 0.7);

  --color-header-bg: rgb(14 13 12 / 0.72);
  --color-header-border: var(--neutral-800);

  /* On dark, --neutral-1000 (pure black) sits *below* the page surface and a
     full-height track reads as a filled bar. Use a low-contrast grey instead. */
  --color-chart-track: var(--neutral-800);
  --color-chart-baseline: var(--neutral-700);

  --hero-scrim: linear-gradient(
    to bottom,
    rgb(0 0 0 / 0.55) 0%,
    rgb(0 0 0 / 0.34) 22%,
    rgb(0 0 0 / 0.7) 40%,
    rgb(14 13 12 / 0.98) 100%
  );
  --color-hero-text: var(--neutral-0);
  --color-hero-text-muted: var(--neutral-300);

  /* Category hues need lifting on dark to keep contrast. */
  --color-art-brand: #ff7847;
  --color-art-technisch: #6ba3ff;
  --color-art-rettung: #35c79e;
  --color-art-wasser: #3cb9e0;
  --color-art-schadstoff: #f0a13c;
  --color-art-hoehe: #b18aff;
  --color-art-verkehr: #ff8a5c;
  --color-art-sonstiges: #a8a29e;

  --color-alarm-1: #6cc95e;
  --color-alarm-2: #f0c02e;
  --color-alarm-3: #ff8f3c;
  --color-alarm-4: #ff5252;
}

/* Follow the OS when the user has not chosen explicitly.
   BaseLayout stamps data-theme pre-paint, so this is the no-JS fallback. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme='light']) {
    color-scheme: dark;

    --color-surface: var(--neutral-950);
    --color-surface-sunken: var(--neutral-1000);
    --color-surface-raised: var(--neutral-900);
    --color-surface-overlay: var(--neutral-800);
    --color-surface-inverse: var(--neutral-0);

    --color-text: var(--neutral-50);
    --color-text-muted: var(--neutral-400);
    --color-text-subtle: var(--neutral-500);
    --color-text-inverse: var(--neutral-950);

    --color-brand: var(--red-500);
    --color-brand-hover: var(--red-400);
    --color-brand-subtle: var(--red-950);
    --color-brand-border: var(--red-900);

    --color-border: var(--neutral-800);
    --color-border-strong: var(--neutral-700);
    --color-divider: var(--neutral-800);

    --color-focus: var(--red-400);
    --color-selection-bg: var(--red-800);
    --color-selection-text: var(--neutral-0);

    --color-danger: var(--red-400);

    --shadow-sm: 0 1px 2px rgb(0 0 0 / 0.4);
    --shadow-md: 0 2px 4px rgb(0 0 0 / 0.4), 0 4px 12px rgb(0 0 0 / 0.5);
    --shadow-lg: 0 4px 8px rgb(0 0 0 / 0.45), 0 12px 32px rgb(0 0 0 / 0.6);
    --shadow-xl: 0 8px 16px rgb(0 0 0 / 0.5), 0 24px 56px rgb(0 0 0 / 0.7);

    --color-header-bg: rgb(14 13 12 / 0.72);
    --color-header-border: var(--neutral-800);

    --color-chart-track: var(--neutral-800);
    --color-chart-baseline: var(--neutral-700);

    --hero-scrim: linear-gradient(
      to bottom,
      rgb(0 0 0 / 0.6) 0%,
      rgb(0 0 0 / 0.35) 35%,
      rgb(0 0 0 / 0.55) 70%,
      rgb(14 13 12 / 0.98) 100%
    );
    --color-hero-text-muted: var(--neutral-300);

    --color-art-brand: #ff7847;
    --color-art-technisch: #6ba3ff;
    --color-art-rettung: #35c79e;
    --color-art-wasser: #3cb9e0;
    --color-art-schadstoff: #f0a13c;
    --color-art-hoehe: #b18aff;
    --color-art-verkehr: #ff8a5c;
    --color-art-sonstiges: #a8a29e;

    --color-alarm-1: #6cc95e;
    --color-alarm-2: #f0c02e;
    --color-alarm-3: #ff8f3c;
    --color-alarm-4: #ff5252;
  }
}

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

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

* {
  margin: 0;
}

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--header-height) + var(--space-4));
}

body {
  min-height: 100svh;
  font-family: var(--font-body);
  font-size: var(--text-base);
  line-height: var(--leading-normal);
  color: var(--color-text);
  background-color: var(--color-surface);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  transition:
    background-color var(--duration-normal) var(--ease-out),
    color var(--duration-normal) var(--ease-out);
}

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

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

p,
h1,
h2,
h3,
h4,
h5,
h6 {
  overflow-wrap: break-word;
}

h1,
h2,
h3,
h4 {
  font-family: var(--font-heading);
  font-weight: var(--weight-bold);
  line-height: var(--leading-tight);
  letter-spacing: var(--tracking-tight);
  text-wrap: balance;
}

p {
  text-wrap: pretty;
}

a {
  color: inherit;
  text-decoration-color: var(--color-brand);
  text-underline-offset: 0.2em;
}

ul[role='list'],
ol[role='list'] {
  list-style: none;
  padding: 0;
}

::selection {
  background-color: var(--color-selection-bg);
  color: var(--color-selection-text);
}

/* =============================================================================
   FOCUS
   One consistent, always-visible focus ring. Never remove it.
   ============================================================================= */

:focus-visible {
  outline: 2px solid var(--color-focus);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}

:focus:not(:focus-visible) {
  outline: none;
}

/* =============================================================================
   UTILITIES
   Small and deliberate — this is not a utility framework.
   ============================================================================= */

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

.container--narrow {
  max-width: var(--container-md);
}

.container--wide {
  max-width: var(--container-full);
}

.section {
  padding-block: clamp(var(--space-12), 8vw, var(--space-24));
}

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

.skip-link {
  position: absolute;
  top: var(--space-2);
  left: var(--space-2);
  z-index: var(--z-modal);
  padding: var(--space-3) var(--space-5);
  background-color: var(--color-brand);
  color: var(--color-text-on-brand);
  font-weight: var(--weight-semibold);
  border-radius: var(--radius-md);
  transform: translateY(-200%);
  transition: transform var(--duration-fast) var(--ease-out);
}

.skip-link:focus-visible {
  transform: translateY(0);
}

/* Eyebrow label above section headings */
.eyebrow {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
  letter-spacing: var(--tracking-widest);
  text-transform: uppercase;
  color: var(--color-brand);
}

.eyebrow::before {
  content: '';
  inline-size: var(--space-8);
  block-size: 2px;
  background-color: var(--color-brand);
}

/* =============================================================================
   REVEAL ON SCROLL
   -----------------------------------------------------------------------------
   Elements marked `data-reveal` start shifted and transparent, then settle into
   place when they scroll into view. The hidden state only applies once the
   reveal script has added `.reveal-ready` to <html>, so with JS disabled — or
   under reduced motion, where the script bails before adding the class — the
   content is simply visible from the start. The script sets `--reveal-i` (a
   unitless index) on each element that enters together, producing a staggered,
   top-to-bottom cascade.
   ============================================================================= */

@media (prefers-reduced-motion: no-preference) {
  :root.reveal-ready [data-reveal] {
    opacity: 0;
    transform: translateY(var(--reveal-shift));
    transition:
      opacity var(--duration-slow) var(--ease-out),
      transform var(--duration-slow) var(--ease-out);
    transition-delay: calc(var(--reveal-i, 0) * var(--reveal-stagger));
    will-change: opacity, transform;
  }

  /* Horizontal variant — the element slides in from the leading edge. */
  :root.reveal-ready [data-reveal='inline'] {
    transform: translateX(calc(-1 * var(--reveal-shift)));
  }

  :root.reveal-ready [data-reveal].is-revealed {
    opacity: 1;
    transform: none;
    will-change: auto;
  }
}

/* =============================================================================
   MOTION PREFERENCES
   ============================================================================= */

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }

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