/* ==========================================================================
   Faro Schäfer — homepage
   Restrained black-and-white design with a yellow (dark) / blue (light) accent, dark by default with a light variant.
   ========================================================================== */

/* Dark is the default and the no-JS fallback. The inline script in base.html
   sets `data-theme` on <html> before first paint (saved choice, else the OS
   preference); the header toggle flips it. Every colour on the site goes
   through these tokens, so a new component only needs to use them to work in
   both themes. */
:root {
  /* Manrope for text, Space Grotesk for headings and display text.
     The token keeps its name --font-serif although the face is a grotesque. */
  --font-sans: "Manrope", system-ui, -apple-system, Segoe UI, Roboto, sans-serif;
  --font-serif: "Space Grotesk", system-ui, -apple-system, Segoe UI, sans-serif;

  --bg: #000000;
  --bg-alt: #0e0e0e;
  --surface: #111111;
  --text: #f2f2f2;
  --muted: #9e9e9e;
  --border: #232323;
  --accent: #f7e500;   /* yellow (owner's pick, 2026-11-15) */
  --accent-contrast: #000000;
  --shadow: 0 1px 2px rgba(0, 0, 0, .25), 0 8px 24px rgba(0, 0, 0, .25);
  --shadow-hover: 0 2px 6px rgba(0, 0, 0, .35), 0 16px 40px rgba(0, 0, 0, .4);

  /* Overlays on photos and media (Home preview and phone cards, game
     messages) stay light on a dark shade in both themes, so
     these are not redefined for light mode. */
  --media-shade: #111315;
  --media-text: #f1efea;
  --media-accent: #f7e500;

  --maxw: 1200px;   /* Home, CV, Research, Consulting share it; running text keeps its own measure */
  --radius: 4px;

  /* Tour map (tours.js reads --cat-* and --map-*, so the theme switch
     restyles the map too). */
  --faint: #6e6e6e;
  --glass: rgba(0, 0, 0, .88);
  --cat-alpine-mountaineering: #b493ff;
  --cat-mountaineering: #5fcf8c;
  --cat-long-distance-hike: #ff7a66;
  --cat-ski-tour: #64aefc;
  --cat-trail-run: #3fd3c6;
  --cat-cycling: #f5b23d;
  --map-land: #1a1c1f;
  --map-water: #101316;
  --map-ice: #23272b;
  --map-shadow: #000000;
  --map-highlight: #4a4e54;
  --map-contour: rgba(255, 255, 255, .07);
  --map-contour-major: rgba(255, 255, 255, .13);
  --map-road: #2e3236;
  --map-path: #3a3e43;
  --map-boundary: #4d5157;
  --map-label: #8f8d88;
  --map-label-strong: #b7b4ae;
  --map-halo: #1a1c1f;
  --map-sky: #23272b;

  color-scheme: dark;
}
:root[data-theme="light"] {
  --bg: #ffffff;
  --bg-alt: #f4f4f4;
  --surface: #ffffff;
  --text: #111111;
  --muted: #5a5a5a;
  --border: #e5e5e5;
  --accent: #6a9bf3;   /* light blue (owner's pick, 2026-11-15) */
  --accent-contrast: #000000;
  --shadow: 0 1px 2px rgba(0, 0, 0, .06), 0 6px 18px rgba(0, 0, 0, .06);
  --shadow-hover: 0 2px 6px rgba(0, 0, 0, .1), 0 14px 34px rgba(0, 0, 0, .12);

  --faint: #8a8a8a;
  --glass: rgba(255, 255, 255, .92);
  --cat-alpine-mountaineering: #6b3fc4;
  --cat-mountaineering: #198049;
  --cat-long-distance-hike: #d23a26;
  --cat-ski-tour: #1d6dd0;
  --cat-trail-run: #008f88;
  --cat-cycling: #d27400;
  --map-land: #ecebe8;
  --map-water: #d3d7da;
  --map-ice: #f7f7f6;
  --map-shadow: #5c5c5c;
  --map-highlight: #ffffff;
  --map-contour: rgba(0, 0, 0, .07);
  --map-contour-major: rgba(0, 0, 0, .14);
  --map-road: #ffffff;
  --map-path: #c9c6c0;
  --map-boundary: #a9a59e;
  --map-label: #75716a;
  --map-label-strong: #45423d;
  --map-halo: #ecebe8;
  --map-sky: #dfe3e6;

  color-scheme: light;
}

* { box-sizing: border-box; }

/* Anchor jumps and keyboard focus stop below the sticky header. */
html { scroll-behavior: smooth; scroll-padding-top: 84px; }

body {
  margin: 0;
  font-family: var(--font-sans);
  background: var(--bg);
  color: var(--text);
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

.container {
  width: 100%;
  max-width: var(--maxw);
  margin-inline: auto;
  padding-inline: 32px;
}

a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; text-underline-offset: 3px; }

h1, h2, h3 { font-family: var(--font-serif); font-weight: 500; line-height: 1.2; letter-spacing: -0.005em; }
h3 { letter-spacing: 0; }   /* small display sizes crowd with any negative tracking */

img { max-width: 100%; height: auto; display: block; }

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  background: var(--accent);
  color: var(--accent-contrast);
  padding: 8px 14px;
  z-index: 100;
}
.skip-link:focus { left: 0; }

/* ---------- header / nav ---------- */
.site-header {
  position: sticky;
  top: 0;
  z-index: 50;
  background: color-mix(in srgb, var(--bg) 90%, transparent);
  backdrop-filter: saturate(160%) blur(10px);
  border-bottom: 1px solid var(--border);
}
/* Everything in the bar shares one text baseline (the small uppercase language
   switch would sit high if centred as a box); the icon button is centred. */
.nav {
  display: flex;
  align-items: baseline;
  gap: 28px;
  height: 68px;
  padding-top: 19px;
}
.brand {
  font-family: var(--font-serif);
  font-size: 1.2rem;
  color: var(--text);
}
.brand:hover { text-decoration: none; color: var(--accent); }
.nav-links { display: flex; align-items: baseline; gap: 28px; margin-left: auto; }
.nav-links > a {
  color: var(--muted);
  font-size: .88rem;
  letter-spacing: .01em;
}
.nav-links > a:hover { color: var(--text); text-decoration: none; }
.nav-links > a.active { color: var(--text); }
/* Inline links, so the block pseudo-element sits below the label. */
.nav-links > a.active::after {
  content: "";
  display: block;
  height: 1px;
  background: var(--accent);
  margin-top: 2px;
}
.lang-switch {
  color: var(--muted);
  font-size: .75rem;
  letter-spacing: .1em;
}
.lang-switch:hover { color: var(--text); text-decoration: none; }
.theme-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  margin-left: -7px;   /* cancels the 7px around the 16px icon, so the gap to the icon matches the nav gap */
  align-self: flex-start;  /* from the bar's padding edge; the 3px puts the icon on the text's middle (tuned for Manrope) */
  margin-top: 3px;
  padding: 0;
  border: 1px solid transparent;
  border-radius: var(--radius);
  background: none;
  color: var(--muted);
  cursor: pointer;
}
.theme-toggle[hidden] { display: none; }
.theme-toggle:hover { color: var(--text); border-color: var(--border); }
.theme-toggle:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.theme-toggle svg { width: 16px; height: 16px; }
/* Show what a click switches *to*. */
.theme-toggle .icon-moon { display: none; }
:root[data-theme="light"] .theme-toggle .icon-sun { display: none; }
:root[data-theme="light"] .theme-toggle .icon-moon { display: block; }

/* ---------- contact call to action (Consulting) ---------- */
.contact-cta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 20px 32px;
  margin-top: 32px;
  padding: 22px 26px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
}
.contact-cta-text { flex: 1 1 320px; }
.contact-cta-prompt { margin: 0 0 4px; font-family: var(--font-serif); font-size: 1.3rem; color: var(--text); }
.contact-cta-note { margin: 0; color: var(--muted); font-size: .95rem; max-width: 52ch; }
.btn {
  display: inline-flex;
  align-items: center;
  padding: 10px 22px;
  border-radius: var(--radius);
  background: var(--accent);
  color: var(--accent-contrast);
  font-weight: 500;
  font-size: .95rem;
  border: 0;
  font-family: inherit;
  cursor: pointer;
}
.btn:hover { filter: brightness(1.08); }

/* ---------- toast (copied email address) ---------- */
.toast {
  position: fixed;
  left: 24px;
  bottom: 24px;
  z-index: 60;
  display: flex;
  align-items: center;
  gap: 10px;
  max-width: calc(100vw - 48px);
  padding: 14px 20px 14px 16px;
  border-radius: var(--radius);
  background: var(--accent);
  color: var(--accent-contrast);
  font-size: 1rem;
  font-weight: 500;
  box-shadow: var(--shadow-hover);
  opacity: 0;
  transform: translateY(12px) scale(.98);
  transition: opacity .25s ease, transform .25s ease;
}
/* A check mark in a ring (an exclamation mark when copying failed), drawn in
   CSS so the text stays the only content. */
.toast::before {
  content: "\2713";
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  border: 1.5px solid currentColor;
  border-radius: 50%;
  font-size: .8rem;
}
.toast.is-failed::before { content: "!"; font-weight: 600; }
.toast.is-visible { opacity: 1; transform: none; }
.toast[hidden] { display: none; }

/* ---------- layout rhythm ---------- */
main.container { padding-top: 64px; padding-bottom: 96px; }
.page-head { margin-bottom: 48px; }
.page-title { font-size: clamp(2.2rem, 4.5vw, 3rem); font-weight: 400; margin: 0 0 .3em; }
.lead { color: var(--text); font-size: 1.1rem; max-width: 62ch; margin: 0; }
/* Page intros are justified like the Home bio (left-aligned on phones). */
.page-head .lead { text-align: justify; hyphens: auto; }

/* ---------- hero (home) ---------- */
/* Eyebrow, name and a three-paragraph bio; the portrait floats right inside
   the bio, so the text runs beside it and then underneath. The list of pages
   follows below a rule. */
main.container:has(> .hero) { padding-top: 0; }
.hero {
  padding: 88px 0 64px;
  border-bottom: 1px solid var(--border);
}
/* Wider screens: the bio in a readable column on the left, the portrait flush
   with the right edge of the page (in line with the page list below). Phones
   keep the float, so the text wraps beside and under the portrait. */
@media (min-width: 761px) {
  .hero-text { display: grid; grid-template-columns: minmax(0, 680px) auto; justify-content: space-between; column-gap: 56px; }
  .hero-text > h1, .hero-subtitle { grid-column: 1 / -1; }
  .hero-text .hero-photo { grid-column: 2; grid-row: 3 / span 3; float: none; margin: 6px 0 0; align-self: start; }
  .hero-lede { grid-column: 1; }
}
.hero-text::after { content: ""; display: block; clear: both; }
.hero-text h1 {
  font-weight: 400;
  font-size: clamp(2.8rem, 6vw, 4.2rem);
  line-height: 1.04;
  letter-spacing: -.015em;
  margin: 0 0 14px;
}
/* The title, as a subtitle under the name (owner's choice, 2026-11-15). */
.hero-subtitle {
  font-family: var(--font-serif);
  font-size: clamp(1.15rem, 2.2vw, 1.4rem);
  line-height: 1.35;
  color: var(--text);
  margin: 0 0 32px;
}
.hero-lede {
  font-size: 1.1rem;
  line-height: 1.65;
  color: var(--text);
  margin: 0;
  text-align: justify;
  hyphens: auto;
}
.hero-lede + .hero-lede { margin-top: .75em; }
.hero-photo {
  float: right;
  width: 260px;
  height: auto;
  aspect-ratio: 4 / 5;
  margin: 6px 0 24px 56px;
  object-fit: cover;
  filter: grayscale(.25) contrast(1.05);
}

/* The page list on the right, the active page's preview on the left. */
.home-index {
  display: grid;
  grid-template-columns: 1fr 360px;
  gap: 64px;
  padding-top: 48px;
}
.home-list { order: 2; }
/* Names line up on the right edge, away from the preview. */
.home-item {
  display: flex;
  justify-content: flex-end;
  padding: 18px 0;
  border-bottom: 1px solid var(--border);
  color: var(--muted);
  transition: color .2s ease, padding-right .25s ease;
}
.home-item:first-child { border-top: 1px solid var(--border); }
.home-item:hover { text-decoration: none; }
.home-item.is-active { color: var(--accent); padding-right: 10px; }   /* the shown page's name in the accent */
.home-item-name {
  font-family: var(--font-serif);
  font-size: 1.6rem;
  /* An accent underline grows in under the hovered or focused name, so the
     list reads as links without arrows. */
  padding-bottom: 2px;
  background: linear-gradient(var(--accent), var(--accent)) right bottom / 0 1px no-repeat;
  transition: background-size .25s ease;
}
.home-item:hover .home-item-name,
.home-item:focus-visible .home-item-name { background-size: 100% 1px; }
/* The phone cards' image and keywords (see the 760px block). */
.home-item-img, .home-item-keys { display: none; }

.home-preview {
  display: grid;
  min-height: 340px;
}
/* Hidden previews are `visibility: hidden` too, so screen readers skip their keywords.
   Each preview lies on its page's image under a dark shade towards the bottom
   left, where the keywords sit (light on dark in both themes, see --media-*). */
.home-pv {
  grid-area: 1 / 1;
  position: relative;
  display: flex;
  align-items: flex-end;
  padding: 28px 32px;
  overflow: hidden;
  border-radius: var(--radius);
  opacity: 0;
  visibility: hidden;
  transition: opacity .3s ease, visibility 0s linear .3s;
}
.home-pv::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(20deg,
    color-mix(in srgb, var(--media-shade) 80%, transparent) 0%,
    color-mix(in srgb, var(--media-shade) 35%, transparent) 45%,
    color-mix(in srgb, var(--media-shade) 0%, transparent) 75%);
}
.home-pv-img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.home-pv.is-active { opacity: 1; visibility: visible; transition: opacity .3s ease; }
.home-pv-keywords {
  position: relative;
  z-index: 1;
  margin: 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-wrap: wrap;  /* one line at full width; wraps only on narrower screens */
  white-space: nowrap;
  font-family: var(--font-serif);
  font-size: 1.08rem;
  line-height: 1.5;
  color: var(--media-text);
}
/* One line, dot-separated; the dot trails its keyword so a wrap never starts with one. */
.home-pv-keywords li:not(:last-child)::after { content: "\00b7"; margin: 0 .5em; color: var(--media-text); }

/* ---------- CV ---------- */
.cv-section { margin-bottom: 52px; }
/* Two columns: the timelines on the left, the rest on the right (cv.html). */
/* --cv-side was measured so both columns end at about the same height with
   every entry closed, in both languages; re-measure after larger CV changes. */
.cv-columns { --cv-side: 370px; display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, var(--cv-side)); gap: 64px; align-items: start; }
.cv-side .entry { grid-template-columns: minmax(0, 1fr); gap: 2px; }
.cv-side .entry-period { padding-top: 0; }
.cv-side .entry-duration { display: inline; margin-left: .5em; }
.cv-side .timeline { gap: 22px; }
.cv-side .skill-row { grid-template-columns: minmax(0, 1fr); gap: 2px; }
.cv-side .lang-list { flex-direction: column; gap: 8px; }
.section-title {
  font-size: 1.5rem;
  font-weight: 400;
  margin: 0 0 24px;
  padding-bottom: 10px;
  border-bottom: 1px solid var(--border);
}
.timeline { display: flex; flex-direction: column; gap: 30px; }
.entry { display: grid; grid-template-columns: 172px minmax(0, 1fr); gap: 24px; }
/* Long German compounds break instead of widening the page on phones. */
.entry-body { overflow-wrap: break-word; hyphens: auto; }
.entry-period { color: var(--muted); font-size: .92rem; font-weight: 500; padding-top: 3px; white-space: nowrap; }
.entry-title { font-size: 1.18rem; margin: 0 0 .2em; }
.entry-role { margin: 0 0 .5em; color: var(--text); font-weight: 500; }  /* the accent is for links only */
.entry-place { color: var(--muted); }
.entry-place::before { content: "· "; }
.entry-duration { display: block; margin-top: 2px; font-size: .82rem; font-weight: 400; opacity: .8; }
.entry-detail { margin: 0 0 .4em; }
.entry-bullets { margin: 0 0 .4em; padding-left: 1.1em; }
.entry-bullets li { margin-bottom: .25em; padding-left: .2em; }
.entry-bullets li::marker { color: var(--faint); }
.entry-extra { margin: 0 0 .4em; color: var(--text); font-style: italic; }
.entry-links { margin: .6em 0 0; display: flex; gap: 18px; flex-wrap: wrap; font-size: .92rem; font-weight: 500; }

/* Entries in a collapsible section are <details>: the heading row (org, role)
   is the summary and opens or closes the rest on click or tap — never on
   hover. */
.entry-summary {
  display: block;
  list-style: none;
  cursor: pointer;
  margin: -8px -12px;
  padding: 8px 12px;
  border-radius: var(--radius);
  transition: background-color .25s ease;
}
.entry-summary::-webkit-details-marker { display: none; }
.entry-summary:hover { background: var(--bg-alt); }
.entry-summary:focus-visible { outline: none; box-shadow: 0 0 0 2px var(--accent); }
.entry-summary .entry-role { margin-bottom: 0; }
.entry-expand-hint {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  margin-left: 6px;
  color: var(--accent);
  vertical-align: middle;
  transition: transform .2s ease;
}
.entry-summary:hover .entry-expand-hint { transform: translateY(2px); }   /* points the way the entry opens */
.entry-body[open] .entry-expand-hint { transform: rotate(180deg); }
.entry-body[open] .entry-summary:hover .entry-expand-hint { transform: rotate(180deg) translateY(2px); }
.entry-more { padding-top: 14px; }
@supports (interpolate-size: allow-keywords) {
  .entry-body { interpolate-size: allow-keywords; }
  .entry-body::details-content {
    height: 0;
    opacity: 0;
    overflow: clip;
    transition: height .4s cubic-bezier(.22, 1, .36, 1), opacity .3s ease, content-visibility .4s allow-discrete;
  }
  .entry-body[open]::details-content { height: auto; opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
  .entry-body::details-content { transition: none; }
}
.entry-media { margin: 14px 0 0; }
.entry-media img,
.entry-media video { border-radius: var(--radius); border: 1px solid var(--border); max-width: 100%; width: 100%; display: block; }


.skills { margin: 0; display: flex; flex-direction: column; gap: 14px; }
.skill-row { display: grid; grid-template-columns: 180px 1fr; gap: 18px; }
.skill-row dt { font-weight: 600; color: var(--text); }
.skill-row dd { margin: 0; }

.lang-list { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: 12px 40px; }
.lang-list li { display: flex; gap: 10px; align-items: baseline; }
.lang-name { font-weight: 600; }
.lang-level { color: var(--muted); }

/* ---------- consulting project tiles ---------- */
/* Three per row (two on tablets, one on phones): the image at its cut 340:300
   aspect, client under the title, title and the result; the story
   (situation, task, action) opens in place under "Read more". */
.project-tiles {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 48px 28px;
  align-items: start;   /* equal heights come from tiles.js, so an open story grows only its own tile */
}
.tile { min-width: 0; overflow-wrap: break-word; hyphens: auto; display: flex; flex-direction: column; }
/* "Read more" sits at the bottom of every tile, level across the row. */
.tile .project-result { margin-bottom: 4px; }
.tile-story { margin-top: auto; }
/* Framed (owner's pick, 2026-11-15): a hairline card, the image edge to edge
   on top, the text inset; a faint shadow in light mode. */
.project-tiles { gap: 28px; }
.tile {
  border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--surface); overflow: hidden;
}
:where(html[data-theme="light"]) .tile { box-shadow: var(--shadow); }
.tile { padding: 0 20px 10px; }
.tile .project-media { border-radius: 0; border-bottom: 1px solid var(--border); margin: 0 -20px 18px; }
.project-media { background: var(--bg-alt); display: flex; align-items: center; justify-content: center; overflow: hidden; aspect-ratio: 340 / 300; border-radius: var(--radius); }
.tile .project-media { margin-bottom: 18px; }
.project-media img,
.project-media video { width: 100%; height: 100%; object-fit: cover; display: block; }
/* Scaled down, browsers can leave a 1px dark seam at a video's edge; the slight
   zoom pushes it outside the box (the clips have a white margin, nothing is lost). */
.project-media video { transform: scale(1.02); }
/* The client under the title, like the title under the name on Home: the
   heading font, plain text colour, no accent (2026-11-15). */
.project-client { margin: -.3em 0 1em; font-family: var(--font-serif); font-size: 1rem; line-height: 1.35; color: var(--text); }
.tile .project-title { font-size: 1.22rem; line-height: 1.3; letter-spacing: -.005em; margin: 0 0 .7em; hyphens: manual; }
.project-result { margin: 0; color: var(--text); }
/* "Result" / "Aim": plain text colour, underlined, on its own line. */
.project-result strong {
  display: block; margin-bottom: .25em; color: var(--text); font-weight: 600;
  text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 3px;
}
.tile-story > summary {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 6px 0; list-style: none; cursor: pointer;
  color: var(--accent); font-weight: 500; font-size: .92rem;
}
.tile-story > summary::-webkit-details-marker { display: none; }
.tile-story > summary:hover { text-decoration: underline; text-underline-offset: 3px; }
.tile-story > summary svg { transition: transform .2s ease; }
.tile-story > summary:hover svg { transform: translateY(2px); }
.tile-story[open] > summary svg { transform: rotate(180deg); }
.tile-story p { margin: 8px 0 0; padding-top: 12px; border-top: 1px solid var(--border); color: var(--text); }

/* ---------- publication tiles (research) ---------- */
.pub-tiles {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 16px;
}
.pub-tile {
  position: relative;
  display: flex;
  flex-direction: column;
  padding: 20px 22px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  transition: border-color .2s ease, transform .2s ease, box-shadow .2s ease;
}
.pub-tile:has(.pub-main):hover {
  border-color: color-mix(in srgb, var(--accent) 55%, var(--border));
  box-shadow: var(--shadow);
  transform: translateY(-2px);
}
.pub-year { color: var(--text); font-size: .78rem; letter-spacing: .12em; margin-bottom: 8px; }
.pub-title { font-size: 1.12rem; line-height: 1.35; margin: 0 0 10px; }
.pub-main { color: inherit; }
.pub-main:hover { text-decoration: none; }
/* Stretched link: the whole tile is the main link's hit area. */
.pub-main::after { content: ""; position: absolute; inset: 0; border-radius: inherit; }
.pub-main:focus-visible { outline: none; }
.pub-main:focus-visible::after { outline: 2px solid var(--accent); outline-offset: 2px; }
.pub-authors { margin: 0 0 4px; font-size: .9rem; color: var(--muted); }
.pub-authors strong { color: var(--text); font-weight: 500; }
.pub-venue { margin: 0; font-size: .88rem; color: var(--muted); font-style: italic; }
/* Pinned to the bottom so the icons line up across a row of tiles. */
.pub-links {
  margin-top: auto;
  padding-top: 16px;
  display: flex;
  align-items: center;
  gap: 10px;
  line-height: 1;
  color: var(--accent);
}
/* Above the stretched main link, so each icon takes its own hover and click. */
.pub-links a { position: relative; z-index: 1; color: inherit; }
.pub-links a:hover { text-decoration: none; }
.pub-pdf { display: inline-flex; transition: transform .2s ease; }
.pub-pdf svg { width: 16px; height: 16px; }
.pub-pdf:hover, .pub-pdf:focus-visible { transform: translateY(-2px); }

/* The ↗ that marks an outbound link, site-wide. It nudges up and to the right
   only while the pointer is on the arrow itself — the same small move everywhere. */
.link-arrow { display: inline-block; font-size: 1rem; transition: transform .2s ease; }
.link-arrow:hover { transform: translate(2px, -2px); }

/* ---------- footer ---------- */
.site-footer {
  border-top: 1px solid var(--border);
  padding: 28px 0;
  color: var(--muted);
  font-size: .9rem;
}
/* Three columns: ©, "Unlock more" centred, the links. */
.footer-inner { display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; gap: 12px 24px; }
.footer-links { display: flex; align-items: center; justify-content: flex-end; gap: 20px; flex-wrap: wrap; }
.footer-center { display: inline-flex; align-items: center; gap: 18px; }
.footer-unlock { display: inline-flex; align-items: center; gap: 6px; color: var(--accent); }
.footer-replay { color: var(--muted); }
.footer-replay:hover { color: var(--accent); text-decoration: underline; text-underline-offset: 3px; }
.footer-replay[hidden] { display: none; }
.footer-unlock:hover { text-decoration: underline; text-underline-offset: 3px; }
.footer-unlock.active { text-decoration: underline; text-underline-offset: 3px; }
.footer-lock { width: 15px; height: 15px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; }
.footer-unlock.is-unlocked .footer-lock { display: none; }
.footer-links > a { color: var(--muted); }
.footer-links > a:hover { color: var(--accent); }

/* Footer "Email" dropdown — a <details>, so it works without JS. */
.mail-menu { position: relative; }
.mail-menu > summary {
  cursor: pointer;
  color: var(--muted);
  list-style: none;          /* Firefox */
}
.mail-menu > summary::-webkit-details-marker { display: none; }
.mail-menu > summary::after { content: "\25BE"; margin-left: .35em; font-size: .85em; }
.mail-menu > summary:hover { color: var(--accent); }
.mail-menu[open] > summary { color: var(--text); }
/* Opens upward: the footer is the last thing on the page. */
.mail-menu-panel {
  position: absolute;
  bottom: calc(100% + 10px);
  left: 0;
  z-index: 20;
  min-width: 232px;
  padding: 6px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
}
.mail-option { display: block; width: 100%; padding: 8px 10px; border: 0; border-radius: var(--radius); background: none; font: inherit; text-align: left; color: var(--muted); cursor: pointer; }
.mail-option:hover { background: var(--bg-alt); }
.mail-option-label { display: block; color: var(--text); font-weight: 500; }
.mail-option-addr { display: block; font-size: .88rem; }
/* Momentary confirmation after the address is copied to the clipboard. */
.mail-option.is-copied { background: var(--bg-alt); }
.mail-option.is-copied .mail-option-addr { color: var(--accent); font-weight: 500; }

/* ---------- consulting ---------- */
/* Clear space between the intro's contact box and the projects. */
.projects-title { margin-top: 64px; }

/* ---------- responsive ---------- */
@media (max-width: 1100px) {
  .cv-columns { --cv-side: 300px; }
}
@media (max-width: 900px) {
  .cv-columns { grid-template-columns: minmax(0, 1fr); gap: 0; }
}
@media (max-width: 760px) {
  .container { padding-inline: 16px; }
  .hero { padding: 48px 0 40px; }
  .hero-photo { width: 140px; margin-left: 20px; }
  /* Justified text beside the floated photo leaves wide gaps on a phone. */
  .hero-lede, .page-head .lead { text-align: left; }
  .home-index { grid-template-columns: 1fr; gap: 0; padding-top: 0; }
  /* No preview pane on a phone: each page is a card instead, its image under
     the same dark shade as the pane, name and keywords bottom left. */
  .home-preview { display: none; }
  .home-list { order: 0; display: grid; gap: 14px; }
  .home-item, .home-item.is-active {
    position: relative;
    flex-direction: column;
    justify-content: flex-end;
    align-items: flex-start;
    gap: 4px;
    aspect-ratio: 16 / 10;
    padding: 18px 20px;
    border: 0;
    border-radius: var(--radius);
    overflow: hidden;
    color: var(--media-text);
  }
  .home-item:first-child { border-top: 0; }
  .home-item::after {
    content: "";
    position: absolute;
    inset: 0;
    background: linear-gradient(20deg,
      color-mix(in srgb, var(--media-shade) 85%, transparent) 0%,
      color-mix(in srgb, var(--media-shade) 40%, transparent) 50%,
      color-mix(in srgb, var(--media-shade) 0%, transparent) 80%);
  }
  .home-item-img { display: block; position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
  .home-item-name, .home-item-keys { position: relative; z-index: 1; }
  /* No hover on a phone: the underline is always there. */
  .home-item-name {
    font-size: 1.45rem;
    background-image: linear-gradient(var(--media-accent), var(--media-accent));
    background-size: 100% 1px;
    background-position: left bottom;
  }
  .home-item-keys { display: flex; flex-wrap: wrap; font-family: var(--font-serif); font-size: .95rem; line-height: 1.4; }
  .home-item-keys span:not(:last-child)::after { content: "\00b7"; margin: 0 .45em; color: var(--media-text); }
  .entry { grid-template-columns: minmax(0, 1fr); gap: 6px; }
  .entry-period { padding-top: 0; }
  .entry-duration { display: inline; margin-left: .5em; }
  .entry-duration::before { content: "· "; }
  /* Own line on phones, so a long role never strands half a place name. */
  .entry-place { display: block; font-size: .92rem; }
  .entry-place::before { content: none; }
  .skill-row { grid-template-columns: 1fr; gap: 2px; }
  .pub-tiles { grid-template-columns: 1fr; }
  /* Five links + the language switch don't fit on one phone-width row.
     Brand, language switch and theme button keep row one; the links go on
     row two, so the switch never ends up stranded on a row of its own. */
  .nav { flex-wrap: wrap; height: auto; padding-block: 12px; gap: 10px 12px; }
  .brand { order: 0; margin-right: auto; }
  .lang-switch { order: 1; }
  .theme-toggle { order: 1; margin-left: -4px; }
  /* One row, never wrapping: spread over the width, and nav-fit.js shrinks
     --nav-size if the links would still not fit (any phone, any language). */
  .nav-links { order: 2; flex: 1 1 100%; min-width: 0; flex-wrap: nowrap; justify-content: space-between; gap: 10px; margin-left: 0; }
  .nav-links > a { font-size: var(--nav-size, .85rem); white-space: nowrap; }
  /* Footer stacked and centred: "Unlock more", the links, then ©. */
  .footer-inner { grid-template-columns: 1fr; justify-items: center; gap: 16px; }
  .footer-center { order: -1; }
  .footer-links { justify-content: center; }
  .footer-copy { order: 1; }
  /* Finger-sized tap areas (about 44px high) from an invisible ::before, so
     nothing moves. Horizontal overhang stays under half the gap between links. */
  .nav-links > a, .lang-switch, .theme-toggle, .footer-links > a, .footer-unlock, .mail-menu > summary { position: relative; }
  .nav-links > a::before, .lang-switch::before, .footer-links > a::before, .footer-unlock::before, .mail-menu > summary::before {
    content: "";
    position: absolute;
    inset: -10px -7px;
  }
  .nav-links > a::before { inset: -10px -5px; }   /* under half the 10px gap */
  /* Row-one targets stop above the row gap, so they never take taps meant for
     the links below. */
  .lang-switch::before { inset: -12px -12px -5px; }
  .theme-toggle::before { content: ""; position: absolute; inset: -7px -7px 0; }
  html { scroll-padding-top: 110px; }   /* the two-row phone header is ~95px */
}
/* Tablets: a narrower image column and a card as tall as its text, before the
   text column gets too narrow for the fixed card height. Phones: stacked. */
@media (max-width: 1024px) {
  .project-tiles { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 760px) {
  .project-tiles { grid-template-columns: minmax(0, 1fr); gap: 40px; }
}
/* Narrow phones: smaller still, so the German links stay on one line. */
@media (max-width: 359px) {
  .nav-links { gap: 5px; }
  .nav-links > a { font-size: var(--nav-size, .8rem); }
  .nav-links > a::before { inset: -10px -2px; }
}

@media (prefers-reduced-motion: reduce) {
  * { scroll-behavior: auto !important; transition: none !important; }
}

/* ---------- "Unlock more": the game, then the tour map (tours.html) ---------- */
/* The note and the games, laid out like the other pages. */
.unlock-game { padding-block: 40px 56px; }
.unlock-game[hidden] { display: none; }
.unlock-head .lead + .lead { margin-top: .8em; }
/* The prompt above the games, as a section heading with its rule. */
.unlock-lead { margin-top: 56px; }
.unlock-games { width: 100%; }
/* All six games in a grid, each under its sport's name. */
.unlock-games--all {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(340px, 100%), 1fr));
  gap: 32px 24px;
}
.game-title {
  margin: 0 0 10px;
  font-family: var(--font-serif);
  font-weight: 500;
  font-size: 1.15rem;
  letter-spacing: -.005em;
  color: var(--text);   /* the accent is for things you can click */
}

/* Screen-reader copy of the message over the canvas. */
.game-live { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
.game-stage { position: relative; }
.game-canvas {
  display: block;
  width: 100%;
  aspect-ratio: 16 / 7;      /* jump games; steer games below */
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: var(--shadow);
  touch-action: none;       /* dragging steers instead of scrolling */
  cursor: pointer;
}
.game-canvas:focus { outline: none; }
.game-canvas:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.game-panel--steer .game-canvas { aspect-ratio: 16 / 10; }
.unlock-games--all .game-canvas { aspect-ratio: 4 / 3; }
/* Messages (goal, fail, win) in a box over the faded canvas; long text
   scrolls inside the box rather than running past the canvas. */
.game-msg {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 12px;
  border-radius: var(--radius);
  background: color-mix(in srgb, var(--surface) 55%, transparent);
  cursor: pointer;
}
.game-msg[hidden] { display: none; }
.game-msg-box {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  max-width: 36ch;
  max-height: 100%;
  overflow-y: auto;
  padding: 14px 18px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: var(--shadow);
  text-align: center;
}
/* The play button on the start and retry messages (the whole message is the
   click target; this only shows it). */
.game-play {
  width: 44px; height: 44px; margin-bottom: 4px;
  border-radius: 50%;
  background: var(--accent);
  box-shadow: var(--shadow);
  transition: transform .2s;
}
.game-play::before {
  content: ""; display: block; width: 100%; height: 100%;
  background: var(--accent-contrast);
  clip-path: polygon(40% 30%, 40% 70%, 72% 50%);
}
.game-play[hidden] { display: none; }
.game-msg:hover .game-play { transform: scale(1.06); }
.game-msg strong { font-family: var(--font-serif); font-weight: 500; font-size: 1.1rem; line-height: 1.3; color: var(--text); }
.game-msg span { font-size: .85rem; line-height: 1.45; color: var(--muted); }
/* The win's button to the map: the site's accent button. */
.game-link { margin-top: 10px; box-shadow: var(--shadow); }
.game-link[hidden] { display: none; }
.game-link:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
/* The controls, for screen readers only (the canvas's description); seeing
   the game is explanation enough. */
.game-hint { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; margin: 0; }

/* The map fills the page between header and footer. */
body.is-map { height: 100dvh; display: flex; flex-direction: column; }
body.is-map .unlock { flex: 1; min-height: 0; display: flex; }
.tm {
  position: relative;
  flex: 1;
  min-height: 0;
  overflow: clip;           /* not even scripts may scroll it (no hidden scrolling) */
  background: var(--map-land);
  border-block: 1px solid var(--border);
  font-size: 14px;
  line-height: 1.45;
  animation: tm-in .6s ease both;
}
@keyframes tm-in { from { opacity: 0; } }
.tm[hidden] { display: none; }
.tm button { font: inherit; color: inherit; }
.tm svg {
  width: 16px; height: 16px; flex: none;
  fill: none; stroke: currentColor; stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round;
}
/* .tm prefix: maplibre-gl.css, loaded later, sets .maplibregl-map relative. */
.tm .tm-map { position: absolute; inset: 0; }

/* Side panel (wide screens) / bottom sheet (phones). */
.tm-panel {
  position: absolute;
  z-index: 10;
  top: 12px; left: 12px; bottom: 12px;
  width: 384px;
  display: flex; flex-direction: column;
  background: var(--surface);   /* solid, so the sticky type headings hide the rows under them */
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  overflow: hidden;
}
.tm-grip { display: none; }
/* Opaque and above the list, so no scrolled row ever shows in the head. */
.tm-head { position: relative; z-index: 2; display: flex; align-items: center; justify-content: space-between; padding: 16px 12px 12px 18px; background: var(--surface); }
.tm-title {
  margin: 0;
  font-family: var(--font-serif);
  font-weight: 500; font-size: 1.35rem; letter-spacing: -.01em;
}
.tm-count { margin-left: 4px; font: 500 .9rem var(--font-sans); color: var(--faint); font-variant-numeric: tabular-nums; }
/* Phone-only parts of the sheet (see the phone block below). */
.tm-head-btn, .tm-head-back, .tm-filters-label, .tm-regions-sheet { display: none; }
.tm-view { display: flex; flex-direction: column; min-height: 0; flex: 1; }
.tm-view[hidden] { display: none; }

.tm .chips {
  display: flex; flex-wrap: wrap; gap: 6px;
  margin: 0 14px; padding: 0 0 12px; border-bottom: 1px solid var(--border);
}
.tm .chip {
  display: inline-flex; align-items: center; gap: 6px;
  height: 28px; padding: 0 10px 0 8px;
  border-radius: var(--radius); border: 1px solid var(--border);
  background: none; cursor: pointer;
  font-size: .78rem; font-weight: 500;
  transition: border-color .15s, opacity .15s;
}
.tm .chip:hover { border-color: var(--c); }
.tm .chip .dot { width: 8px; height: 8px; border-radius: 50%; background: var(--c); }
.tm .chip .n { color: var(--faint); font-variant-numeric: tabular-nums; }
.tm .chip[aria-pressed="false"] { opacity: .5; }
.tm .chip[aria-pressed="false"] .dot { background: none; box-shadow: inset 0 0 0 1.5px var(--c); }

/* No top padding: a sticky heading stops that far below the top, and rows
   would show above it. */
.tm .list { flex: 1; overflow-y: auto; padding: 0 6px 16px; outline: none; scrollbar-width: thin; }
/* "Play again", pinned under the list. */
.tm-replay { display: none; margin: 0; padding: 8px 16px 12px; border-top: 1px solid var(--border); }   /* phones only, see below; elsewhere it is in the footer */
.tm-replay:has(> [hidden]) { display: none; }
.tm .tm-replay-btn {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 4px 0; border: 0; background: none; cursor: pointer;
  font: 500 .9rem var(--font-sans); color: var(--accent);
}
.tm .tm-replay-btn:hover { text-decoration: underline; text-underline-offset: 3px; }
.tm-replay-btn svg { width: 12px; height: 12px; fill: currentColor; }
.tm .group-head {
  position: sticky; top: -1px; z-index: 1;   /* -1px: no sliver of a row above it at fractional offsets */
  display: flex; align-items: baseline; gap: 8px;
  padding: 13px 10px 6px;
  margin-bottom: 4px;
  background: var(--surface);
  box-shadow: 0 1px 0 var(--border);   /* a clean edge where rows pass under it */
  font-size: .7rem; font-weight: 600; letter-spacing: .07em; text-transform: uppercase;
  color: var(--muted);
}
.tm .group-head .bar-c { width: 14px; height: 3px; border-radius: 2px; background: var(--c); align-self: center; }
.tm .group-head .by { margin-left: auto; font-weight: 500; letter-spacing: .02em; text-transform: none; color: var(--faint); }
.tm .row {
  position: relative;
  display: block; width: 100%; text-align: left;
  padding: 9px 10px 9px 22px; margin: 1px 0;
  border: 0; border-radius: var(--radius); background: none; cursor: pointer;
  transition: background .12s;
}
.tm .row::before {
  content: ""; position: absolute; left: 9px; top: 15px;
  width: 7px; height: 7px; border-radius: 50%; background: var(--c);
  transition: transform .15s;
}
.tm .row:hover, .tm .row.is-hover, .tm .row.is-cursor { background: var(--bg-alt); }
.tm .row.is-hover::before, .tm .row.is-cursor::before { transform: scale(1.5); }
.tm .row.mixed::before { background: linear-gradient(90deg, var(--c) 50%, var(--c2) 50%); }
.tm .row-title { font-weight: 600; font-size: .9rem; line-height: 1.3; }
.tm .meta {
  display: flex; flex-wrap: wrap; gap: 2px 11px; margin-top: 3px;
  font-size: .76rem; color: var(--muted); font-variant-numeric: tabular-nums;
}
.tm .meta span { display: inline-flex; align-items: center; gap: 3px; white-space: nowrap; }
.tm .meta svg { width: 12px; height: 12px; color: var(--faint); }
.tm .empty { padding: 32px 18px; color: var(--muted); text-align: center; }

/* Detail of the selected tour. */
.tm .detail { overflow-y: auto; padding: 0 18px 22px; scrollbar-width: thin; }
.tm .back {
  align-self: flex-start; display: inline-flex; align-items: center; gap: 6px;
  margin: 0 0 12px -6px; padding: 6px 8px; border: 0; border-radius: var(--radius);
  background: none; color: var(--muted); cursor: pointer; font-size: .82rem;
}
.tm .back:hover { color: var(--accent); background: var(--bg-alt); }
.tm .tags { display: flex; flex-wrap: wrap; gap: 4px 14px; }
.tm .tag {
  display: inline-flex; align-items: center; gap: 7px;
  font-size: .7rem; font-weight: 600; letter-spacing: .07em; text-transform: uppercase; color: var(--c);
}
.tm .tag::before { content: ""; width: 8px; height: 8px; border-radius: 50%; background: var(--c); }
.tm .detail h2 { margin: 6px 0 4px; font: 500 1.55rem/1.15 var(--font-serif); letter-spacing: -.015em; text-wrap: balance; }
.tm .sub { color: var(--muted); font-size: .82rem; }
.tm .kpis { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; margin: 18px 0 6px; }
.tm .kpi { padding: 10px 10px 9px; border-radius: var(--radius); background: var(--bg-alt); min-width: 0; }
.tm .kpi .v { font: 500 1.08rem var(--font-serif); font-variant-numeric: tabular-nums; white-space: nowrap; }
.tm .kpi .l { display: flex; align-items: center; gap: 4px; font-size: .68rem; color: var(--muted); }
.tm .kpi .l svg { width: 11px; height: 11px; }
.tm .peak { font-size: .76rem; color: var(--muted); margin: 2px 0 0; }
.tm .peak b { color: var(--text); font-weight: 600; }

.tm .profile { position: relative; margin: 16px -4px 4px; height: 140px; touch-action: pan-y; }
.tm .profile svg { width: 100%; height: 100%; stroke-width: 1; overflow: visible; }
.tm .profile .area { fill: url(#tm-pgrad); stroke: none; }
.tm .profile .line { stroke: var(--c); stroke-width: 1.6; fill: none; }
.tm .profile .sep { stroke: var(--border); stroke-dasharray: 2 3; }
.tm .profile .axis { fill: var(--faint); stroke: none; font: 500 10px var(--font-sans); }
.tm .profile .dayband { fill: var(--c); opacity: .12; stroke: none; }
.tm .profile .cur { stroke: var(--text); stroke-width: 1; opacity: .6; }
.tm .profile .curdot { fill: var(--c); stroke: var(--surface); stroke-width: 2; }
.tm .readout {
  position: absolute; top: -6px; transform: translateX(-50%);
  padding: 2px 7px; border-radius: var(--radius); pointer-events: none; white-space: nowrap;
  background: var(--text); color: var(--bg); font-size: .7rem; font-weight: 600;
  font-variant-numeric: tabular-nums;
}

.tm .actions { display: flex; gap: 8px; margin: 14px 0 6px; }
.tm-btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  flex: 1; height: 36px; border-radius: var(--radius); cursor: pointer;
  border: 1px solid var(--border); background: none; font-size: .82rem; font-weight: 600;
  transition: background .15s, border-color .15s, color .15s;
}
.tm-btn:hover { border-color: var(--accent); color: var(--accent); }
.tm-btn.on { background: var(--accent); border-color: var(--accent); color: var(--accent-contrast); }
.tm .empty .tm-btn { flex: none; padding: 0 16px; }

.tm .days { list-style: none; margin: 14px 0 0; padding: 0; border-top: 1px solid var(--border); }
.tm .day {
  display: grid; grid-template-columns: 30px 1fr; gap: 0 8px;
  padding: 10px 6px; margin: 0 -6px; border-radius: var(--radius); cursor: pointer;
}
.tm .day:hover, .tm .day.on { background: var(--bg-alt); }
.tm .day .no { font: 500 .95rem var(--font-serif); color: var(--faint); padding-top: 1px; }
.tm .day.on .no { color: var(--c); }
.tm .day .t { font-weight: 600; font-size: .85rem; line-height: 1.3; }

/* Over the map: region shortcuts along the top, controls on the right. */
.tm-regions {
  position: absolute; z-index: 5; top: 14px;
  left: 410px; right: 70px;
  display: flex; gap: 6px; overflow-x: auto; scrollbar-width: none;
  pointer-events: none;
}
.tm-regions button {
  pointer-events: auto; flex: none;
  height: 30px; padding: 0 12px; border-radius: var(--radius);
  border: 1px solid var(--border); background: var(--glass);
  backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);
  font-size: .78rem; font-weight: 500; cursor: pointer; box-shadow: var(--shadow);
  transition: color .15s, border-color .15s;
}
.tm-regions button:hover { color: var(--accent); border-color: var(--accent); }
.tm-regions .n { color: var(--faint); margin-left: 4px; font-variant-numeric: tabular-nums; }
.tm-ctrls {
  position: absolute; z-index: 5; right: 14px; top: 14px;
  display: flex; flex-direction: column; gap: 1px;
  border-radius: var(--radius); overflow: hidden; box-shadow: var(--shadow);
  border: 1px solid var(--border); background: var(--border);
}
.tm-ctrl {
  display: grid; place-items: center; width: 38px; height: 38px;
  border: 0; background: var(--glass); cursor: pointer;
  backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);
}
.tm-ctrl:hover { color: var(--accent); }
.tm-ctrl .tm-fill { fill: currentColor; }
.tm-ctrl-text { font: 600 .75rem var(--font-serif); letter-spacing: .02em; }
.tm-ctrl[aria-pressed="true"] { background: var(--accent); color: var(--accent-contrast); }
#tm-compass svg { transition: transform .2s; }

.tm-toast {
  position: absolute; z-index: 20; left: calc(50% + 198px); bottom: 28px; transform: translateX(-50%);
  max-width: min(440px, calc(100% - 32px)); padding: 9px 14px; border-radius: var(--radius);
  background: var(--text); color: var(--bg); font-size: .8rem; box-shadow: var(--shadow);
  pointer-events: none; transition: opacity .3s;
}
.tm-toast.fade { opacity: 0; }
.tm-tip {
  position: fixed; z-index: 20; pointer-events: none;
  max-width: 280px; padding: 7px 10px 8px; border-radius: var(--radius);
  background: var(--glass); border: 1px solid var(--border); box-shadow: var(--shadow);
  backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);
}
.tm-tip .row-title { font-size: .84rem; }
.tm-tip .meta { margin-top: 2px; }

.tm .maplibregl-ctrl-attrib {
  background: var(--glass) !important; color: var(--faint); font-size: 10px;
  border-radius: var(--radius) 0 0 0;
}
.tm .maplibregl-ctrl-attrib a { color: var(--muted) !important; }
:root[data-theme="dark"] .tm .maplibregl-ctrl-attrib-button { filter: invert(.8); }
.tm .maplibregl-canvas:focus-visible { outline: none; }
.tm :focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

@media (max-width: 760px) {
  .unlock-game { padding-block: 28px 40px; }
  .unlock-lead { margin-top: 40px; }
  .game-canvas { aspect-ratio: 1 / 1; }
  .game-panel--steer .game-canvas { aspect-ratio: 3 / 4; }
  /* Six in a column: a little shorter, so a phone screen shows one whole game. */
  .unlock-games--all .game-canvas { aspect-ratio: 4 / 3; }
  .unlock-games--all .game-panel--steer .game-canvas { aspect-ratio: 1 / 1; }
  .game-msg { padding: 8px; }
  .game-msg-box { padding: 10px 12px; gap: 4px; }
  .game-msg strong { font-size: 1rem; }
  .game-msg span { font-size: .8rem; }
}
/* Phones, upright or turned sideways (tours.js uses the same query): the map
   takes everything below the header, with simpler controls. Upright phones
   then get the bottom sheet, sideways ones a left/right split (both below). */
@media (max-width: 760px), (max-height: 500px) {
  body.is-map .site-footer { display: none; }
  .tm-replay { display: block; }   /* the footer, with its "Play again", is hidden */
  .tm-sheet-btn { display: none !important; }   /* the sheet's own, below */
  .tm { border-bottom: 0; }
  .tm-head { gap: 8px; padding: 2px 8px 6px 16px; }
  .tm-title { margin-right: auto; font-size: 1.15rem; }
  .tm-head-btn {
    position: relative;
    display: grid; place-items: center; width: 40px; height: 36px;
    border: 1px solid var(--border); border-radius: var(--radius); background: none; cursor: pointer;
  }
  .tm-head-btn[hidden] { display: none; }
  .tm-filter-btn[aria-expanded="true"] { border-color: var(--accent); color: var(--accent); }
  /* Some tour types switched off: an accent dot on the button. */
  .tm-filter-btn.is-filtered::after {
    content: ""; position: absolute; top: 5px; right: 5px;
    width: 7px; height: 7px; border-radius: 50%; background: var(--accent);
  }
  /* Tour types and regions only when asked for (the filter button), so the
     list keeps the room and the map stays clear. */
  .tm-regions { display: none; }
  .tm-filters { display: none; margin: 0 16px; padding-bottom: 12px; border-bottom: 1px solid var(--border); }
  .tm-panel.show-types .tm-filters { display: block; }
  .tm .tm-filters .chips { margin: 0; padding: 0; border: 0; }
  .tm-filters-label {
    display: block; margin: 8px 0 6px;
    font-size: .68rem; font-weight: 600; letter-spacing: .07em; text-transform: uppercase; color: var(--muted);
  }
  .tm-regions-sheet { display: flex; flex-wrap: wrap; gap: 6px; }
  .tm-regions-sheet button {
    height: 28px; padding: 0 10px; border: 1px solid var(--border); border-radius: var(--radius);
    background: none; cursor: pointer; font-size: .78rem; font-weight: 500;
  }
  .tm-regions-sheet .n { margin-left: 4px; color: var(--faint); font-variant-numeric: tabular-nums; }
  /* A tour open: back in the head bar instead of the title, the tour's card
     right under it (what the closed sheet shows), the details below. */
  .tm-panel.is-tour .tm-title, .tm-panel.is-tour .tm-filter-btn, .tm-panel.is-tour .tm-filters { display: none; }
  .tm-panel.is-tour .tm-head-back {
    display: inline-flex; align-items: center; gap: 4px; margin-right: auto;
    height: 36px; padding: 0 8px 0 2px; border: 0; background: none; cursor: pointer;
    font-size: .88rem; color: var(--muted);
  }
  .tm .detail .back { display: none; }
  /* A calm tour view: the type is a coloured dot before the title (the
     summits are on the map), one line of dates, one line of figures with
     icons instead of boxes (labels kept for screen readers), the profile,
     and only "Fly along" (the map has 3D, and opens on the whole tour). */
  .tm .detail { padding: 0 16px 16px; }
  .tm .tags, .tm .peak, #tm-act-fit, #tm-act-3d { display: none; }
  .tm .detail h2 { margin: 2px 0 2px; font-size: 1.2rem; }
  .tm .tm-card h2::before {
    content: ""; display: inline-block; width: 9px; height: 9px; margin: 0 9px 0 1px;
    border-radius: 50%; background: var(--c); vertical-align: .12em;
  }
  .tm .sub { font-size: .8rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  /* Always one line: spread across the panel, the size shrinking with the
     panel's width (cqw), not the screen's. */
  .tm-panel { container-type: inline-size; }
  .tm .kpis { display: flex; flex-wrap: nowrap; justify-content: space-between; gap: 8px; margin: 10px 0 2px; }
  .tm .kpi { display: flex; flex-direction: row-reverse; align-items: center; gap: 4px; padding: 0; background: none; }
  .tm .kpi .v { font-size: clamp(.74rem, 3.8cqw, .95rem); }
  .tm .kpi .l { font-size: 0; color: var(--faint); }
  .tm .kpi .l svg { width: 13px; height: 13px; }
  .tm .profile { height: 96px; margin-top: 14px; }
  .tm .actions { justify-content: flex-end; margin: 4px 0 2px; }
  .tm .actions .tm-btn { flex: none; height: 30px; padding: 0 4px; border: 0; color: var(--muted); font-size: .78rem; gap: 5px; }
  .tm .actions .tm-btn.on { background: none; color: var(--accent); }
  .tm .days { margin-top: 10px; }
  .tm .day { padding: 7px 6px; }
  /* Zoom and rotate by gestures; compass and 3D stay. */
  #tm-zoom-in, #tm-zoom-out, #tm-rot-left, #tm-rot-right { display: none; }
  .tm-regions { left: 12px; right: 64px; top: 12px; }
  .tm-ctrls { right: 10px; top: 12px; }
  .tm-tip { display: none; }
}
/* Upright phones (tours.js uses the same query): the panel is a bottom sheet,
   closed, half or fully open, dragged or opened by its arrow button. */
@media (max-width: 760px) and (orientation: portrait) {
  .tm-panel {
    top: auto; left: 0; right: 0; bottom: 0;
    width: auto; height: 92%;
    border-radius: var(--radius) var(--radius) 0 0; border-bottom: 0;
    transform: translateY(calc(100% - var(--sheet-h, 172px)));
    transition: transform .28s cubic-bezier(.2, .8, .2, 1);
    touch-action: none;
  }
  .tm-panel.dragging { transition: none; }
  .tm .list, .tm .detail { touch-action: pan-y; }
  .tm-grip { display: block; padding: 8px 0 0; cursor: grab; }
  .tm-grip span { display: block; width: 38px; height: 4px; margin: 0 auto; border-radius: 2px; background: var(--border); }
  .tm-sheet-btn { display: grid !important; }
  .tm-sheet-btn svg { transition: transform .2s; }
  .tm-sheet-btn[aria-expanded="true"] svg { transform: rotate(180deg); }
  /* The sheet's hidden part (below the screen when it is half open) is
     added under the list and the tour, so both scroll to their very end. */
  .tm .detail { padding-bottom: calc(var(--sheet-hidden, 0px) + 16px); }
  .tm-replay { padding-bottom: calc(var(--sheet-hidden, 0px) + 12px); }
  .tm .maplibregl-ctrl-bottom-right { bottom: var(--sheet-h, 172px); }
}
/* Phones turned sideways: list and tour on the left, the map on the right. */
@media (max-width: 760px) and (orientation: landscape), (max-height: 500px) and (orientation: landscape) {
  .tm-panel { top: 8px; left: 8px; bottom: 8px; width: min(340px, 46%); }
  .tm-head { padding-top: 10px; }
}
/* Landscape phones: too short for square or portrait canvases. */
@media (max-height: 500px) {
  .game-canvas, .game-panel--steer .game-canvas, .unlock-games--all .game-canvas { aspect-ratio: 16 / 7; }
}
