/* oh-race-yo.com. Structure copied from pollen.naola.net's style.css, re-themed
   as a simple 80s arcade cabinet: a dark ink marquee (the hero, dark in both
   themes) with the candy-pink title, an arcade-red and pink racing stripe
   under it, and numbered "01 02 03" cards. No image and no web font: the
   brand is text, and the font stack is the system's, so nothing is fetched
   from anywhere. test/contrast.test.mjs checks every text/background pair
   declared here, in both themes, so keep pairs in these tokens. Every icon is
   an inline SVG (src/icons.mjs) drawn in currentColor, so it takes its colour
   from a token too. Logical properties only (inline/block, start/end): the
   pages must mirror in ar, he, fa, ur once those locales are built. */
:root {
  /* The marquee (hero), the same in both themes. --field-top is also the
     theme-color meta of every page (test/contrast.test.mjs checks). */
  --field-top: #1b1230;
  --field-bottom: #2a1747;
  --title: #ff6fb0;
  --tint: #f6e7ff;
  /* Arcade red: the racing stripe and the "coming soon" badge's edge. */
  --stripe: #d62839;
  --bg: #fff8ef;
  --surface: #fbeee6;
  --text: #1b1230;
  --muted: #5c5070;
  --link: #b3172b;
  --border: #ecdcd3;
  /* The cards' number badges: deep pink on pale pink. */
  --accent: #a3134f;
  --accent-soft: #ffe0ee;
  --font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  --font-mono: ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace;
}

/* Dark, twice. The theme control (Light / Dark / Device, /js/theme.js) sets
   data-theme on <html> only for a chosen Light or Dark:
   - Device, and every visitor without JavaScript, follow the system through
     the media query; a chosen Light opts out of it with :not([data-theme]).
   - A chosen Dark applies the same tokens whatever the system says.
   test/contrast.test.mjs fails if the two dark blocks differ. */
:root {
  color-scheme: light dark;
}

:root[data-theme="light"] {
  color-scheme: light;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg: #120c1f;
    --surface: #1d1530;
    --text: #f4eefc;
    --muted: #b8accd;
    --link: #ff6fb0;
    --border: #2f2445;
    --accent: #ff8fc2;
    --accent-soft: #3a1830;
  }
}

:root[data-theme="dark"] {
  --bg: #120c1f;
  --surface: #1d1530;
  --text: #f4eefc;
  --muted: #b8accd;
  --link: #ff6fb0;
  --border: #2f2445;
  --accent: #ff8fc2;
  --accent-soft: #3a1830;
  color-scheme: dark;
}

* { box-sizing: border-box; }

/* `hidden` must win over any display set below (.theme-switch is flex): the
   theme control and the language search stay hidden until their scripts
   reveal them, and the search hides list items with it. */
[hidden] { display: none !important; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-sans);
  font-size: 1.0625rem;
  line-height: 1.55;
}

a { color: var(--link); }

/* Hidden from sight, kept for screen readers: the theme legend, the
   features heading, the "Language:" before the current language, the
   search's live region. Never display:none, which hides it from both. */
.visually-hidden {
  position: absolute !important;
  inline-size: 1px;
  block-size: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* Icons (src/icons.mjs): Lucide's stroke settings, which it ships as
   attributes on the <svg>, live here; the size is a class, never a style
   attribute (CSP style-src 'self'). */
.svg-icon {
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
  flex: none;
}

.svg-icon-16 { inline-size: 16px; block-size: 16px; }
.svg-icon-20 { inline-size: 20px; block-size: 20px; }

/* Focus rings are drawn here, never left to the browser: the default blue
   is near-invisible on the dark marquee (WCAG 2.4.7, 1.4.11). --text on the
   page and on surfaces; white on the marquee and the skip link.
   test/contrast.test.mjs checks each at 3:1, and forced-colors mode replaces
   outline colours itself. */
:focus-visible {
  outline: 2px solid var(--text);
  outline-offset: 2px;
}

.hero :focus-visible {
  outline-color: #ffffff;
}

/* Skip link (WCAG 2.4.1): first focusable element on every page, off-screen
   until focused. Kept in the layout (not display:none) so it stays in the
   accessibility tree. Logical sides so it sits top-right in RTL. */
.skip-link {
  position: absolute;
  inset-block-start: 0;
  inset-inline-start: 0;
  z-index: 30;
  background: var(--field-bottom);
  color: #ffffff;
  font-weight: 600;
  padding: 10px 16px;
  text-decoration: none;
  border-end-end-radius: 8px;
  transform: translateY(-110%);
}

.skip-link:focus {
  transform: none;
}

.skip-link:focus-visible {
  outline: 2px solid #ffffff;
  outline-offset: -5px;
}

/* ---------- Site header (src/templates/_header.html) ----------
   On the page background with a hairline under it (the line is decoration:
   the header's controls carry their own 3:1 edges). One row on a wide
   screen: brand at the start, theme control and language menu at the end.
   Not sticky. */
.site-header {
  background: var(--bg);
  border-block-end: 1px solid var(--border);
}

.site-nav {
  max-inline-size: 960px;
  margin-inline: auto;
  min-block-size: 64px;
  padding-block: 10px;
  padding-inline: 16px;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px;
}

/* The brand is text (no logo yet): heavy italic, like a cabinet's marquee. */
.brand {
  display: inline-flex;
  align-items: center;
  min-block-size: 44px;
  color: var(--text);
  font-weight: 900;
  font-style: italic;
  font-size: 1.15rem;
  text-decoration: none;
}

/* The language menu pushes itself and the theme control to the end. The DOM
   order is brand, language, theme, and so is the visual order at every width:
   on narrow screens (320 px included) row 1 is the brand and the language
   button, row 2 the theme control at full width, so Tab follows what the eye
   sees (2.4.3). The language menu takes the rest of row 1 (flex-basis 0, so
   it never wraps) and shortens the language name with an ellipsis instead of
   pushing the page sideways (1.4.10). */
.lang-menu { margin-inline-start: auto; }

@media (max-width: 48em) {
  .theme-switch {
    flex: 1 1 100%;
  }

  .lang-menu {
    flex: 1 1 0;
    min-inline-size: 0;
    display: flex;
    justify-content: flex-end;
  }
}

/* ---------- Theme control ----------
   Light / Dark / Device: a fieldset of native radios drawn as one joined
   segmented control. The radio itself is invisible but stays in the page, so
   keyboard (Tab, then arrows) and screen readers use the real input; its
   label is the visible target, an icon and a word. Pairs in
   test/contrast.test.mjs: segment edges --muted on --bg (3:1), selected fill
   --link on --bg (3:1), selected text --bg on --link (4.5:1). The selected
   segment also turns bold, so it is told apart by more than colour (1.4.1). */
.theme-switch {
  border: 0;
  padding: 0;
  margin-block: 0;
  min-inline-size: 0;
  display: flex;
}

/* Wide screens: each option is as wide as its label, on one line, so the
   control is exactly as tall as the language button (44 px). Narrow screens
   (the media block below) give each option an equal share of the full-width
   row and let a long label wrap there instead. */
.theme-option {
  position: relative;
  display: flex;
  flex: 0 0 auto;
}

.theme-option input {
  position: absolute;
  inset: 0;
  opacity: 0;
  margin: 0;
  cursor: pointer;
}

.theme-option span {
  display: flex;
  flex: 1 1 auto;
  align-items: center;
  justify-content: center;
  gap: 6px;
  min-block-size: 44px; /* WCAG 2.5.8 asks 24; 44 matches the apps. Never a fixed height: labels may wrap. */
  padding-block: 6px;
  padding-inline: 12px;
  border: 1px solid var(--muted);
  color: var(--text);
  text-align: center;
  white-space: nowrap;
}

/* Joined: neighbours share one edge, and only the outer corners round. */
.theme-option + .theme-option span { margin-inline-start: -1px; }
.theme-option:first-of-type span { border-start-start-radius: 999px; border-end-start-radius: 999px; }
.theme-option:last-of-type span { border-start-end-radius: 999px; border-end-end-radius: 999px; }

.theme-option input:checked + span {
  background: var(--link);
  border-color: var(--link);
  color: var(--bg);
  font-weight: 700;
  position: relative;
  z-index: 1;
}

.theme-option input:focus-visible + span {
  outline: 2px solid var(--text);
  outline-offset: 2px;
  position: relative;
  z-index: 2;
}

/* Narrow screens: the theme control has its own full-width row (above), so
   the options share it by label length and a long label wraps rather than
   pushing the page sideways (1.4.10). After the rules above, so it wins. */
@media (max-width: 48em) {
  .theme-option { flex: 1 1 auto; }

  .theme-option span {
    gap: 4px;
    padding-inline: 8px;
    white-space: normal;
    overflow-wrap: anywhere;
  }
}

/* ---------- Language menu ----------
   A <details> of links (build.mjs). The button shows a globe, the current
   language (cut with an ellipsis, never wrapped) and a chevron; the panel
   opens under it, at the inline end. Pairs in test/contrast.test.mjs:
   button edge --muted on --bg, panel text and links on --surface, search
   field edge --muted on --surface. */
.lang-menu { position: relative; }

.lang-menu-button {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  max-inline-size: min(11rem, 100%);
  min-block-size: 44px;
  padding-inline: 12px;
  border: 1px solid var(--muted);
  border-radius: 999px;
  color: var(--text);
  cursor: pointer;
  list-style: none;
}

.lang-menu-button::-webkit-details-marker { display: none; }

.lang-menu-current {
  min-inline-size: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.lang-menu[open] .lang-menu-button .svg-icon-16 { transform: rotate(180deg); }

.lang-menu-panel {
  position: absolute;
  inset-block-start: calc(100% + 8px);
  inset-inline-end: 0;
  z-index: 20;
  inline-size: min(20rem, calc(100vw - 32px));
  max-block-size: 70vh;
  overflow: auto;
  padding: 12px;
  background: var(--surface);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 12px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.18);
}

.lang-search { margin-block-end: 8px; }

.lang-search-label {
  display: block;
  font-weight: 600;
  margin-block-end: 4px;
}

.lang-search-field {
  position: relative;
  display: flex;
  align-items: center;
}

.lang-search-field .svg-icon {
  position: absolute;
  inset-inline-start: 12px;
  color: var(--muted);
  pointer-events: none;
}

.lang-search-input {
  inline-size: 100%;
  min-block-size: 44px;
  padding-block: 6px;
  padding-inline: 36px 12px;
  border: 1px solid var(--muted);
  border-radius: 8px;
  background: var(--bg);
  color: var(--text);
  font: inherit;
}

.lang-search-empty {
  margin-block: 8px 0;
  color: var(--muted);
}

.lang-menu-list {
  list-style: none;
  margin: 0;
  padding: 0;
}

.lang-menu-list a {
  display: flex;
  align-items: center;
  min-block-size: 44px;
  padding-inline: 12px;
  border-radius: 8px;
  color: var(--text);
  text-decoration: none;
  text-align: start;
}

.lang-menu-list a:hover { text-decoration: underline; }

.lang-menu-list a[aria-current="page"] { font-weight: 700; }

/* ---------- Home (src/templates/index.html) ---------- */
main {
  max-inline-size: 960px;
  margin-inline: auto;
  padding-block: 48px;
  padding-inline: 16px;
}

main.home {
  max-inline-size: none;
  padding: 0;
}

/* The marquee: ink, dark in both themes, with the racing stripe drawn under
   it (decoration only, so it carries no meaning and needs no text pair). */
.hero {
  position: relative;
  background: linear-gradient(160deg, var(--field-top), var(--field-bottom));
  color: #ffffff;
  text-align: center;
  padding-block: 64px 72px;
  padding-inline: 16px;
}

.hero::after {
  content: "";
  position: absolute;
  inset-inline: 0;
  inset-block-end: 0;
  block-size: 10px;
  background: repeating-linear-gradient(90deg, var(--stripe) 0 32px, var(--title) 32px 64px);
}

/* The title: candy pink, heavy italic, with an arcade-red drop shadow. The
   shadow is decoration; the contrast row measures the pink on the ink. The
   brand is never uppercased by CSS: it is spelled "Oh-Race-Yo!" everywhere. */
.hero h1 {
  color: var(--title);
  font-size: clamp(2.5rem, 11vw, 4.5rem);
  font-weight: 900;
  font-style: italic;
  line-height: 1.05;
  letter-spacing: 0.01em;
  text-shadow: 0.06em 0.06em 0 var(--stripe);
  margin-block: 0 16px;
  overflow-wrap: anywhere;
}

.tagline {
  color: var(--tint);
  font-size: 1.2rem;
  max-inline-size: 34rem;
  margin: 0 auto;
}

.soon {
  display: inline-block;
  margin-block: 28px 0;
  padding-block: 8px;
  padding-inline: 16px;
  border: 2px solid var(--stripe);
  border-radius: 6px;
  font-family: var(--font-mono);
  font-weight: 700;
  font-size: 0.95rem;
  letter-spacing: 0.04em;
}

.features {
  max-inline-size: 960px;
  margin-inline: auto;
  padding-block: 48px;
  padding-inline: 16px;
}

.feature-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 240px), 1fr));
  gap: 16px;
  counter-reset: feature;
}

.feature {
  background: var(--surface);
  border: 1px solid var(--border);
  border-block-start: 4px solid var(--stripe);
  border-radius: 12px;
  padding: 24px;
  counter-increment: feature;
}

/* "01", "02", "03": drawn, with empty alternative text, so a screen reader
   hears the list's own position instead of a number read twice. */
.feature::before {
  content: counter(feature, decimal-leading-zero);
  content: counter(feature, decimal-leading-zero) / "";
  display: inline-block;
  min-inline-size: 44px;
  padding-block: 4px;
  padding-inline: 8px;
  border-radius: 6px;
  background: var(--accent-soft);
  color: var(--accent);
  font-family: var(--font-mono);
  font-weight: 700;
  text-align: center;
}

.feature h3 {
  font-size: 1.1rem;
  margin-block: 16px 6px;
}

.feature p { margin: 0; color: var(--muted); }

/* ---------- 404 (src/templates/404.html) ---------- */
main.not-found {
  max-inline-size: 40rem;
  text-align: center;
}

.not-found h1 {
  font-size: clamp(1.9rem, 5vw, 2.5rem);
  font-style: italic;
  margin-block: 20px 8px;
}

.not-found-actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  gap: 12px 24px;
  margin-block-start: 24px;
}

/* The page's main link, drawn as a button: --bg on --link (contrast row
   "primary link label"), 48 tall, never a fixed height. */
.button-primary {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-block-size: 48px;
  padding-block: 10px;
  padding-inline: 20px;
  border-radius: 999px;
  background: var(--link);
  color: var(--bg);
  font-weight: 700;
  text-decoration: none;
}

/* ---------- Footer (src/templates/_footer.html) ---------- */
.site-footer {
  border-block-start: 1px solid var(--border);
  color: var(--muted);
  font-size: 0.95rem;
  text-align: center;
  padding-block: 24px 40px;
  padding-inline: 16px;
}

.site-footer p { margin-block: 4px; overflow-wrap: anywhere; }

/* The dot between the support address and each legal link: drawn, with
   empty alternative text so screen readers skip it. */
.footer-sep::before {
  content: "·";
  content: "·" / "";
  margin-inline: 0.5em;
}

/* ---------- Legal pages (src/templates/privacy.html, terms.html) ----------
   Body text is --text on --bg, the date and the translation notice --muted
   on --bg, links --link on --bg: pairs already in test/contrast.test.mjs. */
main.legal { max-inline-size: 46rem; }

.legal h1 {
  font-size: clamp(1.9rem, 5vw, 2.5rem);
  margin-block: 0 8px;
}

.legal h2 { font-size: 1.35rem; margin-block: 40px 8px; }

.legal .updated,
.legal .disclaimer { color: var(--muted); margin-block: 0 16px; }

.legal li { margin-block: 4px; }

/* Long words and email addresses must not push the page sideways at 320 px. */
.legal p,
.legal li { overflow-wrap: anywhere; }

/* ---------- Reduced motion ----------
   Nothing on the site animates today (the chevron turns at once). This
   keeps it so if a transition is ever added: under Reduce Motion it is off.
   test/a11y.test.mjs fails if this block goes. */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation: none !important;
    transition: none !important;
    scroll-behavior: auto !important;
  }
}

/* ---------- Windows High Contrast / forced colours ----------
   Fills become system colours, so each theme segment keeps a visible edge
   and the selected one takes the system's own selection pair; the icons
   follow (currentColor). The racing stripe is decoration and may vanish. */
@media (forced-colors: active) {
  .theme-option span {
    border-color: ButtonText;
  }

  .theme-option input:checked + span {
    background: Highlight;
    border-color: Highlight;
    color: HighlightText;
    forced-color-adjust: none;
  }

  .feature::before { border: 1px solid CanvasText; }
}
