/* Space Grotesk and Inter, served from this origin. Calling
   fonts.googleapis.com sends the visitor's IP address to Google on every
   page view (LG Muenchen I, 20.01.2022, 3 O 17493/20) and would
   contradict what the privacy policy states. One variable file per
   subset covers every weight the design uses. Filenames carry a content
   hash, because nginx serves them immutable for 30 days.
   SIL Open Font License 1.1, see /fonts/OFL.txt. */
@font-face{font-family:'Space Grotesk';font-style:normal;font-weight:400 700;font-display:swap;src:url('/fonts/space-grotesk-var-latin.06408904.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:400 700;font-display:swap;src:url('/fonts/space-grotesk-var-latin-ext.952dddb4.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:'Inter';font-style:normal;font-weight:400 700;font-display:swap;src:url('/fonts/inter-var-latin.3100e775.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:'Inter';font-style:normal;font-weight:400 700;font-display:swap;src:url('/fonts/inter-var-latin-ext.34b9c504.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}

/* Dark app palette from docs/design-concept.md. The website is always dark. */
:root {
  color-scheme: dark;
  --bg: #07111F;
  --surface: #1A2D44;
  --surface-low: #1D3149;
  --text: #EFF6F1;
  --text-muted: #B8C8C2;
  --primary: #8EB8FF;
  --accent: #FF9A86;
  --secondary: #7AD9A2;
  --line: #8A9A94;
  --hairline: #748A81;
  --band-strong: #8EB8FF;
  --band-mid: #5E9B7A;
  --band-soft: #354C43;
  --shadow: 0 12px 32px rgba(0, 0, 0, .18);
  --pad: 20px;
}

@media (min-width: 760px) {
  :root { --pad: 32px; }
}

* { box-sizing: border-box }
/* .notice and .picker carry a display value, which would otherwise beat the
   browser default for [hidden] and leave an empty bar on the page. */
[hidden] { display: none !important }

body {
  margin: 0;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  background-color: var(--bg);
  background-image: linear-gradient(135deg, rgba(142, 184, 255, .055), transparent 48%, rgba(122, 217, 162, .035)),
    linear-gradient(rgba(142, 184, 255, .032) 1px, transparent 1px),
    linear-gradient(90deg, rgba(142, 184, 255, .032) 1px, transparent 1px);
  background-size: 100% 100%, 48px 48px, 48px 48px;
  color: var(--text);
  font: 400 16px/1.65 Inter, system-ui, sans-serif;
  -webkit-font-smoothing: antialiased;
}
main { flex: 1 }

h1, h2, h3, .brand, .score, .seg-value {
  font-family: 'Space Grotesk', system-ui, sans-serif;
  font-weight: 600;
  letter-spacing: -.02em;
}

h1 { font-size: clamp(38px,5vw,60px); line-height: 1.05; margin: 16px 0 24px }
h2 { font-size: clamp(24px, 3vw, 32px); line-height: 1.2; margin: 0 0 8px }
h3 { font-size: 18px; margin: 0 0 8px }
p { margin: 0 0 16px }

a { color: var(--primary) }
main a { text-underline-offset: 3px }

:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 3px;
  border-radius: 4px;
}

/* Page shell. The canon caps content at 680 px; that is a reading measure, so
   every text block below stays inside it while the shell itself may hold two
   columns side by side. */
.nav, .hero, .grid, .matchday, .record, .protocol, footer, .legal {
  width: min(1080px, calc(100% - 2 * var(--pad)));
  margin-inline: auto;
}

.nav {
  min-height: 80px;
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px 24px;
  padding: 16px 0;
}
/* On a phone the in-page anchor is redundant — the section it points at is the
   next thing on screen — and keeping it forces the nav into three lines. */
@media (max-width: 560px) { .nav a[href^="#"] { display: none } }
/* Legal pages hold a narrow reading column; the nav follows it so the brand
   sits above the heading instead of floating out to the left. */
body:has(main.legal) .nav { width: min(680px, calc(100% - 2 * var(--pad))) }
.nav .brand { margin-right: auto }
.nav a { text-decoration: none; color: var(--text-muted); font-weight: 500 }
.nav a:hover { color: var(--text) }
/* The language switch is a destination, not a section of this page: the border
   keeps it from reading as one more nav item. It survives the phone rule above
   because the reader who needs it most is the one on the wrong language. */
.nav a.lang {
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 4px 12px;
}

.brand { display: inline-flex; align-items: center; font-size: 22px; letter-spacing: -.04em; text-decoration: none; color: var(--text); white-space: nowrap }
.brand img { flex: none; display: block }
.brand i { color: var(--primary); font-style: normal }

.eyebrow {
  color: var(--primary);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .12em;
  font-size: 12px;
}

.lead { font-size: 20px; line-height: 1.55; color: var(--text-muted); max-width: 40ch }
.card p, .legal p, .legal li { max-width: 68ch }

.hero {
  display: grid;
  grid-template-columns: 1fr;
  gap: 28px;
  padding: 16px 0 40px;
  align-items: start;
}
/* Only the start page puts a second column beside the text; /ledger/ and the
   legal pages use the same hero with one column. */
@media (min-width: 900px) {
  .hero { padding: 32px 0 48px }
  .hero.split { grid-template-columns: 1fr minmax(360px, 460px); gap: 40px }
}

.card, .matchcard {
  background: linear-gradient(135deg, rgba(23, 59, 98, .42), var(--surface-low));
  border: 1px solid rgba(142, 184, 255, .22);
  border-radius: 18px;
  padding: 20px;
}
.matchcard { box-shadow: var(--shadow) }

.grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 24px;
  padding: 24px 0 56px;
}
@media (min-width: 760px) { .grid { grid-template-columns: 1fr 1fr } }
.card p:last-child { margin-bottom: 0 }

/* Match card — the geometry of the central prediction surface from the canon:
   heading line, both team names of equal rank, the distribution band, the
   confidence sentence, the reasoning. AP 2.3 fills the same DOM from the API. */
.matchcard .meta {
  color: var(--text-muted);
  font-size: 14px;
  display: flex;
  justify-content: space-between;
  gap: 8px;
}
.matchcard .teams {
  display: flex;
  justify-content: space-between;
  gap: 16px;
  margin: 8px 0 24px;
  font-size: 19px;
  font-weight: 600;
}
.matchcard .teams span { max-width: 48%; overflow-wrap: anywhere }
.matchcard .teams span + span { text-align: right }

.band { display: flex; gap: 4px; margin: 8px 0 4px }
.band i {
  display: block;
  height: 10px;
  border-radius: 5px;
  background: var(--band-soft);
  animation: grow 450ms ease-out both;
}
.band .strong { background: var(--band-strong) }
.band .mid { background: var(--band-mid) }
.band .soft { background: var(--band-soft) }
.band i:nth-child(2) { animation-delay: 60ms }
.band i:nth-child(3) { animation-delay: 120ms }
@keyframes grow { from { transform: scaleX(0); transform-origin: left } }
@media (prefers-reduced-motion: reduce) { .band i { animation: none } }

.legend {
  display: flex;
  justify-content: space-between;
  gap: 8px;
  font-size: 13px;
  color: var(--text-muted);
  margin-bottom: 24px;
}
.legend b { display: block; font-weight: 500 }
.seg-value { font-variant-numeric: tabular-nums; font-size: 17px; color: var(--text) }
.legend span:nth-child(2) { text-align: center }
.legend span:nth-child(3) { text-align: right }

.score {
  font-size: clamp(44px, 8vw, 60px);
  line-height: 1;
  font-variant-numeric: tabular-nums;
  color: var(--text);
}
.verdict { font-size: 17px; line-height: 1.5; margin: 8px 0 24px }
.reasoning { font-size: 17px; line-height: 1.5; color: var(--text) }
.provisional-note {
  margin: -8px 0 20px;
  padding: 12px 14px;
  border-radius: 12px;
  background: var(--background);
  color: var(--text-muted);
  line-height: 1.45;
}
.provisional-note strong { color: var(--text) }

/* Matchday section -- the same card, once as a spotlight beside the headline
   and once per match of the current matchday. */
.matchday { padding: 8px 0 32px }
.matchday-head {
  display: flex;
  flex-wrap: wrap;
  align-items: end;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 24px;
}
.matchday-head h2 { margin: 0 }

.picker { display: flex; flex-wrap: wrap; max-width: 100%; align-items: center; gap: 8px; font-size: 14px; color: var(--text-muted) }
.picker select {
  max-width: 100%;
  font: inherit;
  color: var(--text);
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-radius: 10px;
  padding: 8px 12px;
}

/* Columns rather than a grid: the cards differ in height -- a match still
   waiting for its prediction is a third as tall as one carrying a reasoning --
   and a grid row would either stretch the short one or leave the gap below it
   open. Columns pack them, and the DOM order stays chronological. */
.cards { columns: 1; column-gap: 24px }
@media (min-width: 760px) { .cards { columns: 2 } }
.cards .matchcard { break-inside: avoid; margin-bottom: 24px }

/* A state change is an 180 ms cross-fade, cards 60 ms apart and capped at
   240 ms in total -- the movement budget from docs/design-concept.md. */
.cards .matchcard {
  animation: appear 180ms ease-out both;
  animation-delay: min(calc(var(--card-index, 0) * 60ms), 240ms);
}
@keyframes appear { from { opacity: 0; transform: translateY(6px) } }
@media (prefers-reduced-motion: reduce) { .cards .matchcard { animation: none } }

/* Waiting for the service: the final geometry in grey, so nothing jumps when
   the figures arrive. The placeholder words never become readable. */
.skeleton [data-field], .skeleton h3 {
  color: transparent;
  background: var(--hairline);
  border-radius: 4px;
}
.skeleton .band i { background: var(--hairline); animation: none }
.skeleton .verdict strong { background: var(--hairline) }

/* Old figures are still figures, but they must not look current. The same
   accent the notice carries, so the mark and its explanation belong together. */
.stale .matchcard { border-color: var(--accent) }

/* Nothing to show, or nothing reachable -- never an empty surface. */
.matchcard.message { display: flex; align-items: center; min-height: 180px }
.matchcard.message p { margin: 0; color: var(--text-muted); font-size: 17px }
.verdict.pending { color: var(--text-muted); margin-bottom: 0 }

.notice {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 12px 24px;
  margin: 0 0 24px;
  padding: 12px 16px;
  border: 1px solid var(--hairline);
  border-left: 3px solid var(--accent);
  border-radius: 12px;
  background: var(--surface);
  color: var(--text-muted);
  font-size: 15px;
}
.notice button,
.consent-button {
  font: inherit;
  font-weight: 600;
  color: var(--primary);
  background: none;
  border: 1px solid var(--primary);
  border-radius: 10px;
  padding: 6px 14px;
  cursor: pointer;
}
.notice button:hover,
.consent-button:hover { background: var(--surface) }

.links { display: flex; flex-wrap: wrap; gap: 24px }

.legal { max-width: min(680px, calc(100% - 2 * var(--pad))); padding: 40px 0 64px }
.legal h1 { font-size: clamp(32px, 5vw, 44px) }
.legal h2 { margin-top: 40px; font-size: 22px }
.legal ul { padding-left: 20px }
.legal li { margin-bottom: 8px }
code {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: .9em;
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-radius: 4px;
  padding: 1px 5px;
}

code { overflow-wrap: anywhere }

/* Consent banner. Both buttons carry the same weight and neither is
   preselected: a refusal has to be as easy to reach as a consent
   (Art. 7 Abs. 3 DSGVO, § 25 Abs. 1 TDDDG). The rules live here rather than
   in a style attribute so the page can carry a Content-Security-Policy
   without an inline exception. */
.consent-banner {
  position: fixed;
  inset: auto 0 0 0;
  z-index: 20;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 12px 20px;
  padding: 16px var(--pad);
  border-top: 1px solid var(--hairline);
  background: var(--surface);
  color: var(--text);
  box-shadow: var(--shadow);
  font-size: 15px;
  line-height: 1.5;
}
.consent-banner p { flex: 1 1 320px; max-width: 620px; margin: 0 }
.consent-banner a { color: var(--primary) }
[data-consent-control] { margin-top: 12px }
[data-consent-control] p { margin: 0 0 10px }

/* Result and original prediction use the same weight for hits and misses. */
.result-summary { margin: 16px 0; color: var(--text) }
.result-summary p { margin: 4px 0; overflow-wrap: anywhere }
.final-score { font-family: 'Space Grotesk', system-ui, sans-serif; font-size: 2rem; font-weight: 600 }
.recorded-stamp { color: var(--text-muted); font-size: .875rem; overflow-wrap: anywhere }
.matchcard summary { cursor: pointer; min-height: 44px; display: list-item; align-content: center }
.matchcard summary:focus-visible { outline: 2px solid var(--text); outline-offset: 4px }

/* Verdict text and icons share the existing accessible brand/surface pairs. */
.result-correct { color: var(--secondary) }
.result-incorrect { color: var(--accent) }

.match-context { margin-top: 24px; overflow-wrap: anywhere; }
.match-context summary { cursor: pointer; min-height: 48px; padding-block: 12px; }
.match-context button { min-height: 48px; padding: 8px 16px; font: inherit; }
.match-context p { margin-block: 12px; }

.match-context button { color: var(--primary); background: var(--surface); border: 1px solid currentColor; border-radius: 8px; cursor: pointer; }
.match-context :focus-visible { outline: 2px solid var(--primary); outline-offset: 4px; }

.match-context select { font: inherit; min-height: 48px; max-width: 100%; color: var(--text); background: var(--surface); }

.venue-context { margin-block: 16px; overflow-wrap: anywhere; }
.venue-context h4 { font: inherit; font-weight: 600; margin-block: 8px; }
.venue-context .venue-distance { font-family: "Space Grotesk", sans-serif; font-size: 1.2em; font-weight: 600; }
.venue-context a { display: inline-flex; align-items: center; min-height: 48px; }

.weather-context { margin-block: 1.5rem; overflow-wrap: anywhere; }
.weather-point { margin-block: 1rem; }
.weather-point h5 { font-size: 1rem; margin-bottom: .5rem; }

.weather-context a { display: inline-flex; align-items: center; min-height: 48px; }

.venue-map { margin-block: 1rem; }
.venue-map svg { display: block; width: 100%; max-height: 140px; }

.weather-overview { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 1rem; margin-block: 1rem; }
.weather-overview strong { font-size: 1.3rem; }
.weather-overview h5, .weather-overview p { margin-block: .3rem; }

.matchcard button.teams { width: 100%; padding: 0; border: 0; border-radius: 0; background: transparent; color: inherit; font-family: inherit; line-height: inherit; cursor: pointer; text-align: left; min-height: 48px; }
.matchcard button.teams:hover { color: var(--primary); }
.matchcard button.teams:focus-visible { outline: 2px solid var(--primary); outline-offset: 4px; }
.match-context.from-team-trigger:not([open]) { margin: 0; padding: 0; }
.matchcard .context-summary { margin-block: 0 16px; font-size: .9rem; }
.match-context a { display: inline-block; min-height: 48px; padding-block: 12px; }
.weather-context { container-type: inline-size; }
@container (max-width: 15rem) { .weather-overview { grid-template-columns: 1fr; } }
.weather-overview small { display: block; }
/* Let enlarged text shrink grid tracks and wrap instead of widening the page. */
.hero > *, .grid > * { min-width: 0; }
.hero, .grid, .cards { overflow-wrap: anywhere; }
.matchcard .meta { flex-wrap: wrap; }
.hero.split:has(.match-context[open]) { align-items: start; }

.prediction-evidence > h4 { margin-block: 20px 8px; }
.prediction-factor { margin-block: 20px; }
.prediction-factor h5 { margin-block: 0 4px; font: inherit; font-weight: 700; }
.prediction-factor p { margin-block: 4px; }

.match-form > h5 { margin-block: 24px 8px; font: inherit; font-weight: 700; }
.form-match { margin-block: 20px; }
.form-match p { margin-block: 4px; }

.match-calendar h5 { font-size: 1rem; margin: 1.25rem 0 .5rem; }
.calendar-match { margin: 1rem 0; }
.calendar-match p { margin: .25rem 0; }

.calendar-timeline-stop { border-left: 1px solid var(--line); padding-left: 1rem; margin-top: 1.25rem; }
.calendar-timeline-entry { margin: .75rem 0 1.25rem; }
.calendar-timeline-entry h6 { font: inherit; font-weight: 600; margin: 0 0 .25rem; }
.calendar-timeline-entry p, .calendar-timeline-stop > p { margin: .25rem 0; }

.match-share { margin-top: 1.5rem; }
.match-share-image { display: block; width: min(100%, 360px); height: auto; margin: 1rem 0; }
.match-share button { margin-top: .75rem; }
