/* Tracklister — heading face. woff2 first, woff as the fallback. */
@font-face {
  font-family: "Tracklister";
  src: url("../assets/fonts/Tracklister-Regular.woff2") format("woff2"),
       url("../assets/fonts/Tracklister-Regular.woff") format("woff");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Tracklister";
  src: url("../assets/fonts/Tracklister-Medium.woff2") format("woff2"),
       url("../assets/fonts/Tracklister-Medium.woff") format("woff");
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Tracklister";
  src: url("../assets/fonts/Tracklister-Bold.woff2") format("woff2"),
       url("../assets/fonts/Tracklister-Bold.woff") format("woff");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

/* Hawkbit Interactive
   ------------------------------------------------------------------
   Three colours: off-white, dark grey, green.
   ------------------------------------------------------------------ */

:root {
  --off-white: #fffff4;
  --dark-grey: #323232;
  --green:     #729e68;

  --transition-fast: 0.2s ease;
  --transition-med:  0.3s ease;
  --transition-slow: 0.4s ease;

  --font-heading: "Tracklister", "Helvetica Neue", Helvetica, Arial, sans-serif;

  --label-col: clamp(3rem, 5vw, 4.5rem);

  --maxw: 720px;

  /* Top bar, and the hamburger's resting inset and height. The bar is
     shallower than the hamburger's own inset allows, so while it is up the
     hamburger is nudged to the bar's centre line — see body.bar-visible. */
  --bar-h: 4rem;
  --ham-top: 2rem;
  --ham-h: 24px;
}

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

html { overflow-x: hidden; }

body {
  /* the hero flower bleeds past the right edge on purpose; the hero does not
     clip it, so keep that bleed from scrolling the page sideways */
  overflow-x: hidden;
  overflow-x: clip;
  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
  font-size: 1.0625rem;
  line-height: 1.7;
  color: var(--dark-grey);
  background: var(--off-white);
  -webkit-font-smoothing: antialiased;
}

body.menu-open { overflow: hidden; }

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

/* --- Top bar -------------------------------------------------------
   No plate across the page any more: the bar is just a transparent rail
   holding the parked wordmark's line. What comes up instead is a soft
   veil in the top-left corner, sized to sit behind the mark and the line
   only, blurring whatever scrolls under it and fading out to nothing on
   its right and bottom edges so it has no seam. The swap happens while
   the mark is off-stage, so the veil is never seen arriving on top of it.
   Sits under the menu (900) and under the wordmark itself (850). */

.topbar {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  height: var(--bar-h);
  z-index: 840;
  pointer-events: none;
}

/* The veil: a soft patch of blurred page colour that reaches only as far as
   the mark and the line it sits behind. Its box is those two plus a margin
   on the right and below, and the mask runs the alpha all the way to zero
   inside that margin, so the veil ends in air rather than on an edge. It
   keeps its full strength up to the top and left edges of the screen — there
   is nothing out there to dissolve into. --mark-w and --tag-w are the parked
   mark's and the line's measured widths, both published by js/logo-travel.js.
   Opacity lives here rather than on .topbar: an ancestor mid-fade would cut
   the blur off from the page behind it and leave it with nothing to sample.
   The static bar's veil is the same patch, only measured off the row it sits
   behind rather than off those two variables — see .topbar-inner::before. */
.topbar::before,
.topbar-inner::before {
  /* how far past the pair the fade keeps running */
  --veil-x: 5rem;
  --veil-y: 2.5rem;
  /* left inset + mark + the gap the line sits off + the line */
  --veil-w: calc(var(--ham-top) + var(--mark-w, 101px) + 0.85rem + var(--tag-w, 11rem));

  content: "";
  position: absolute;
  top: 0;
  left: 0;
  width: calc(var(--veil-w) + var(--veil-x));
  height: calc(var(--bar-h) + var(--veil-y));
  background: rgba(255, 255, 244, 0.55);
  /* Also what puts the veil on its own compositing layer, so it does not
     lag a frame behind the content scrolling under it. Nothing above it may
     carry a transform or an opacity of its own — either would cut the blur
     off from the page and leave it sampling an empty backdrop. */
  -webkit-backdrop-filter: blur(14px);
  backdrop-filter: blur(14px);
  /* Two ramps, one per axis, multiplied together: the corner where they meet
     thins out on both counts, which rounds it off. The stops approximate an
     ease-out so neither ramp shows a seam where it starts. */
  -webkit-mask-image:
    linear-gradient(to right,
      #000 calc(100% - var(--veil-x)),
      rgba(0, 0, 0, 0.62) calc(100% - var(--veil-x) * 0.62),
      rgba(0, 0, 0, 0.2)  calc(100% - var(--veil-x) * 0.3),
      transparent 100%),
    linear-gradient(to bottom,
      #000 calc(100% - var(--veil-y)),
      rgba(0, 0, 0, 0.62) calc(100% - var(--veil-y) * 0.62),
      rgba(0, 0, 0, 0.2)  calc(100% - var(--veil-y) * 0.3),
      transparent 100%);
  mask-image:
    linear-gradient(to right,
      #000 calc(100% - var(--veil-x)),
      rgba(0, 0, 0, 0.62) calc(100% - var(--veil-x) * 0.62),
      rgba(0, 0, 0, 0.2)  calc(100% - var(--veil-x) * 0.3),
      transparent 100%),
    linear-gradient(to bottom,
      #000 calc(100% - var(--veil-y)),
      rgba(0, 0, 0, 0.62) calc(100% - var(--veil-y) * 0.62),
      rgba(0, 0, 0, 0.2)  calc(100% - var(--veil-y) * 0.3),
      transparent 100%);
  -webkit-mask-composite: source-in;
  mask-composite: intersect;
  opacity: 0;
  transition: opacity var(--transition-med);
}

/* Without a backdrop filter there is nothing to blur, so the veil has to
   carry the corner on tint alone. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .topbar::before,
  .topbar-inner::before { background: rgba(255, 255, 244, 0.92); }
}

body.bar-visible .topbar::before { opacity: 1; }

/* The hero line, repeated small beside the parked wordmark. It waits for the
   mark to land — body.mark-home — so veil, mark and line arrive in that order
   rather than the text sitting beside an empty gap. --mark-w is the parked
   mark's width, published by js/logo-travel.js; --ham-top is the same inset
   the mark parks at. */
.topbar-tagline {
  position: absolute;
  top: 50%;
  left: calc(var(--ham-top) + var(--mark-w, 101px) + 0.85rem);
  transform: translateY(-50%);
  margin: 0;
  font-family: var(--font-heading);
  font-size: clamp(0.85rem, 1.1vw, 1rem);
  line-height: 1;
  white-space: nowrap;
  color: var(--dark-grey);
  opacity: 0;
  /* a shade slower than the veil, so the line reads as arriving rather than
     switching on */
  transition: opacity var(--transition-slow);
}

body.mark-home .topbar-tagline { opacity: 1; }

body.menu-open .topbar::before,
body.menu-open .topbar-tagline { opacity: 0; }

/* --- Static top bar (every page but the home page) -----------------
   The home page assembles this bar out of the scroll: the wordmark flies
   out of the hero and parks in the corner, the veil comes up under it and
   the line fades in beside it. Off the home page there is no hero to fly
   out of, so the same three pieces are simply laid out and left standing.
   The row is a real flex line rather than the home page's absolutely placed
   pair, which is also what lets the veil size itself: it is measured off
   the row's own width instead of off the two widths logo-travel.js has to
   publish. */

.topbar-inner {
  position: absolute;
  top: 0;
  left: var(--ham-top);
  height: var(--bar-h);
  display: flex;
  align-items: center;
  gap: 0.85rem;
}

/* Same patch as the home page's, but its box is the row plus the inset it
   is held off the left edge by — so it reaches the screen edge there, as
   the home page's does — and it is up from the start rather than on scroll. */
.topbar-inner::before {
  --veil-w: calc(100% + var(--ham-top));
  left: calc(-1 * var(--ham-top));
  opacity: 1;
}

/* The veil is an absolutely positioned pseudo-element carrying a backdrop
   filter, so it is a stacking context of its own sitting at level 0 and it
   covers the whole row. The pair has to be lifted over it explicitly —
   left in flow they would be painted underneath and come out blurred. */
.topbar-brand,
.topbar-inner .topbar-tagline {
  position: relative;
  z-index: 1;
}

/* The bar itself stays click-through so the page scrolls under it; the
   wordmark is a link home and takes its clicks back. */
.topbar-brand {
  display: block;
  pointer-events: auto;
  transition: opacity var(--transition-med);
}

/* The width the home page's mark ends up at: the hero's size, taken down by
   the same PARK_SCALE js/logo-travel.js shrinks it by on the way in. */
.topbar-brand img { width: calc(clamp(90px, 9vw, 130px) * 0.78); }

/* In the row the line is laid out beside the mark rather than placed off its
   measured width, and it has nothing to wait for. */
.topbar-inner .topbar-tagline {
  top: auto;
  left: auto;
  transform: none;
  opacity: 1;
}

/* Out of the way while the menu is coming over it. The line needs the row in
   its selector to outweigh the rule above that holds it open. */
body.menu-open .topbar-inner::before,
body.menu-open .topbar-inner .topbar-brand,
body.menu-open .topbar-inner .topbar-tagline { opacity: 0; }

body.menu-open .topbar-brand { pointer-events: none; }

/* Clear of the fixed bar. */
.topbar--static ~ .wrap { padding-top: calc(var(--bar-h) + 2rem); }

/* The letters in flight. js/slogan-letters.js copies the hero's slogan into
   this layer one span per letter and flies each of them, on its own stretch of
   the scroll, from where it sits in the hero to where it belongs in the bar,
   shrinking on the way. While it is running, the two real lines stay where
   they are but are not drawn: the hero's letters hold the block's width open,
   and the bar's line is what the copies are aimed at. The layer sits above the
   veil (840) and below the wordmark (850), so the mark passes over the letters
   rather than under them. */
.slogan-flight {
  position: fixed;
  inset: 0;
  z-index: 845;
  pointer-events: none;
  /* only ever drawn while the script is driving it, so a reader who has asked
     for no motion is left with the two real lines and nothing on top */
  visibility: hidden;
}

body.slogan-split .slogan-flight { visibility: visible; }

.slogan-flight span {
  position: absolute;
  top: 0;
  left: 0;
  font-family: var(--font-heading);
  font-weight: 400;
  line-height: 1;
  letter-spacing: -0.01em;
  color: var(--dark-grey);
  /* the script places every letter by its own top-left corner, so the shrink
     has to be anchored there too */
  transform-origin: 0 0;
  will-change: transform;
}

/* Taken out of the paint, not out of the page: the slogan is still the
   heading a reader or a crawler is given, and the hero's letters still hold
   the block open at its full width. Colour rather than visibility, because
   visibility would take the heading out of the accessibility tree with it. */
body.slogan-split .hero-bottom h1 > span,
body.slogan-split .topbar-tagline { color: transparent; }

/* An absolutely positioned copy is a block, and a block's box is its line box
   — taller than the inline box a letter sits in, with the glyph offset inside
   it. Both real lines are switched to inline-block so all three boxes are
   built the same way: one line-height tall, glyph at the same offset within.
   Lining the boxes up then lines the glyphs up, at either end of the trip. */
body.slogan-split .hero-bottom h1 > span,
body.slogan-split .topbar-tagline > span { display: inline-block; }

body.menu-open .slogan-flight { opacity: 0; transition: opacity var(--transition-med); }

/* --- Layout ------------------------------------------------------- */

.wrap {
  max-width: var(--maxw);
  margin-inline: auto;
  padding: 2rem 1.5rem 4rem;
}

/* --- Type --------------------------------------------------------- */

h1, h2, h3 { font-family: var(--font-heading); font-weight: 400; }
h1 { font-size: 2rem; line-height: 1.2; }
h2 { font-size: 1.125rem; letter-spacing: 0.1em; text-transform: uppercase; }
h3 { font-size: 1.0625rem; }

a { color: var(--dark-grey); text-underline-offset: 3px; text-decoration-color: var(--green); text-decoration-thickness: 2px; }
a:hover { color: var(--green); }

:focus-visible { outline: 2px solid var(--green); outline-offset: 3px; }

/* --- Hamburger ---------------------------------------------------- */

.hamburger {
  position: fixed;
  top: var(--ham-top);
  right: 2rem;
  z-index: 1000;
  width: 36px;
  height: var(--ham-h);
  padding: 0;
  background: none;
  border: none;
  cursor: pointer;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  transition: transform var(--transition-med);
}

/* The bars are 36 by 24; the thumb gets a 44-by-44 target around them
   without the drawing growing. Out of flow, so the bars' spacing is left
   alone. */
.hamburger::before {
  content: "";
  position: absolute;
  inset: -10px -4px;
}

/* Centred on the bar while it is up, at its own inset otherwise. */
body.bar-visible .hamburger {
  transform: translateY(calc((var(--bar-h) - var(--ham-h)) / 2 - var(--ham-top)));
}

.hamburger span {
  display: block;
  width: 100%;
  height: 3px;
  border-radius: 2px;
  transform-origin: center center;
  transition: transform var(--transition-med), opacity var(--transition-med), background-color var(--transition-med);

  /* Difference blending keeps the bars legible wherever they land: they read as
     dark grey on the off-white page and light grey over the oversized hero logo. */
  background: #cdcdcd;
  mix-blend-mode: difference;
}

/* Over the green overlay the bars are drawn plainly, not blended. */
.hamburger.open span { mix-blend-mode: normal; }

.hamburger.open span { background: var(--off-white); }
.hamburger.open span:nth-child(1) { transform: translateY(10.5px) rotate(45deg); }
.hamburger.open span:nth-child(2) { opacity: 0; }
.hamburger.open span:nth-child(3) { transform: translateY(-10.5px) rotate(-45deg); }

/* --- Full-screen menu --------------------------------------------- */

.menu-overlay {
  position: fixed;
  inset: 0;
  z-index: 900;
  background: var(--green);
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--transition-slow);
}

.menu-overlay.open { opacity: 1; pointer-events: auto; }

.menu-inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 3rem;
}

/* The logo is pinned to the top of the overlay so it stays put no matter how
   many links the menu holds; the links keep the centre of the screen. */
.menu-logo {
  position: absolute;
  top: 2rem;
  left: 50%;
  transform: translateX(-50%);
  height: 3.5rem;
  width: auto;
}

.menu-overlay ul {
  list-style: none;
  padding: 0;
  text-align: center;
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
}

/* The page links are set in the heading face so the menu reads as part of the
   site rather than a generic overlay. Each item rises into place as the
   overlay fades in, one after the other. */
.menu-overlay li {
  opacity: 0;
  transform: translateY(0.75rem);
  transition: opacity var(--transition-med), transform var(--transition-med);
}

.menu-overlay.open li {
  opacity: 1;
  transform: none;
}

.menu-overlay.open li:nth-child(2) { transition-delay: 0.06s; }
.menu-overlay.open li:nth-child(3) { transition-delay: 0.12s; }

.menu-overlay a {
  color: var(--off-white);
  text-decoration: none;
  font-family: var(--font-heading);
  font-size: 3.25rem;
  font-weight: 400;
  line-height: 1.1;
  letter-spacing: 0.02em;
  transition: opacity var(--transition-fast);
}

.menu-overlay a:hover { opacity: 0.7; color: var(--off-white); }
.menu-overlay a[aria-current="page"] { opacity: 0.55; }

/* The legal pages sit in one quiet row at the foot of the overlay, the way the
   wordmark is pinned to the top, so the page links keep the centre. Set small
   and tracked like the section labels, so they belong without competing. */
.menu-details {
  position: absolute;
  bottom: 2rem;
  left: 50%;
  transform: translateX(-50%);
  width: max-content;
  max-width: calc(100% - 3rem);
}

.menu-overlay .menu-details ul {
  flex-direction: row;
  justify-content: center;
  flex-wrap: wrap;
  gap: 0.75rem 2rem;
  margin: 0;
}

.menu-overlay .menu-details li {
  opacity: 0;
  transform: none;
  transition: opacity var(--transition-slow);
}

.menu-overlay.open .menu-details li { opacity: 1; transition-delay: 0.2s; }

.menu-overlay .menu-details a {
  font-family: inherit;
  font-size: 0.75rem;
  font-weight: 400;
  line-height: 1;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  opacity: 0.6;
}

.menu-overlay .menu-details a:hover { opacity: 1; }
.menu-overlay .menu-details a[aria-current="page"] { opacity: 0.4; }

/* --- Landing hero -------------------------------------------------- */

.hero {
  position: relative;
  min-height: 100vh;
  min-height: 100svh;
  display: flex;
  align-items: flex-end;
  padding: 2rem 2.5rem 3rem;
}

/* The hawkbit growing out of the bottom-right corner.
   Anchored from the top so the bloom stays in frame and the stem runs off the
   bottom edge. --flower-h drives both its size and the room the text block
   leaves for it (the ink of the artwork is about 0.52 of its height wide, plus
   transparent margins — the 0.677 below is the text block's clearance). */
.hero {
  --flower-h: clamp(680px, 156vh, 1520px);
}

.hero-flower {
  position: absolute;
  right: -150px;
  top: 2vh;
  height: var(--flower-h);
  width: auto;
  pointer-events: none;
  user-select: none;
}

/* Wordmark tucked into the bottom-right corner. It is pinned to the viewport
   rather than the hero because js/logo-travel.js flies it out past the right
   edge on scroll and brings it back in from the left to park in the top-left
   corner. right/bottom set where that run starts; the script only ever writes
   a transform, and transform-origin keeps the shrink anchored to the top-left
   so the parked mark lines up with the hamburger. Sits above the bar (840)
   and under the menu overlay (900). */
.hero-logo {
  position: fixed;
  right: 2.5rem;
  bottom: 3rem;
  z-index: 850;
  width: clamp(90px, 9vw, 130px);
  transform-origin: 0 0;
  will-change: transform;
  pointer-events: none;
  user-select: none;
}

.hero-bottom {
  position: relative;
  z-index: 1;
  width: 100%;
  padding-right: min(calc(var(--flower-h) * 0.677 + 2rem), 46vw);
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 2rem;
}

/* Slogan block. The wrapper is only as wide as the slogan line itself
   (fit-content on a nowrap line), so the line under it has the slogan's exact
   measure to sit in. Both lines are driven by --slogan-size: the second one is
   a fixed fraction of it (--subline-ratio, the slogan's advance width divided
   by the sub-line's at the same size), so the two lines start and end on the
   same edges at every viewport width. */
.hero-slogan {
  --slogan-size: clamp(2rem, 6vw, 5rem);
  --subline-ratio: 0.34763;
  width: fit-content;
  max-width: 100%;
}

.hero-bottom h1 {
  font-size: var(--slogan-size);
  line-height: 1;
  letter-spacing: -0.01em;
  white-space: nowrap;
  margin: 0;
}

.hero-bottom .hero-subline {
  max-width: none;
  margin: 0;
  font-family: var(--font-heading);
  font-size: calc(var(--slogan-size) * var(--subline-ratio));
  line-height: 1.1;
  letter-spacing: -0.01em;
  white-space: nowrap;
}

.hero-bottom p {
  max-width: 32ch;
  font-size: 0.9375rem;
  line-height: 1.5;
  margin: 0 0 0.75rem;
}

/* Phones and portrait tablets. The flower no longer has a column of its own
   beside the text: it grows in from the right edge of the screen. It is sized
   off the screen's height, hung from the top and tilted a little anticlockwise
   about the bloom, so the stem runs out past the right edge and its lower
   quarter is off the screen — the hero clips it there. The slogan is anchored
   in the bottom-left corner with the same inset all round, and the wordmark
   sits on the line above it, on the same left edge. The two lines give up
   their shared measure — a sub-line set at a third of a 40px slogan is not
   readable — and the sub-line wraps at a size of its own, inside the slogan's
   width, so the left edge still lines up.

   The mark stays pinned to the viewport for js/logo-travel.js, so it cannot
   simply be laid out above the slogan: its foot is worked out instead from
   the hero's own inset and the text block's two line boxes (the slogan's at
   line-height 1, the sub-line's at 1.3, and the gap between them), which is
   why those sizes are held in variables here. Both are set in vw, so the
   sub-line stays on one line at every phone width, and the sum holds.

   The artwork's geometry, as fractions of its own box (1119 × 1520): the bloom
   is centred at about (0.375, 0.217), the stem's foot sits at (0.688, 0.88),
   and the box is 0.736 times as wide as it is tall. */
@media (max-width: 900px) {
  .hero {
    --flower-h: clamp(520px, 80vh, 900px);
    --flower-h: clamp(520px, 80svh, 900px);
    --flower-w: calc(var(--flower-h) * 0.736);
    /* where the bloom's centre sits on the screen */
    --bloom-x: 50vw;
    --bloom-y: 24vh;
    --bloom-y: 24svh;
    --hero-inset: 1.5rem;
    --hero-foot: 2rem;
    /* the text block, line by line — see .hero-logo below */
    --slogan-size-phone: clamp(2.25rem, 11vw, 4rem);
    --subline-size: clamp(1rem, 4.2vw, 1.25rem);
    --subline-gap: 0.5rem;
    /* the wordmark, and its clearance above the slogan */
    --mark-hero-w: 104px;
    --mark-gap: 1.25rem;
    padding: var(--hero-inset) var(--hero-inset) var(--hero-foot);
    /* the stem runs off the right edge and past the foot of the hero */
    overflow: hidden;
  }

  .hero-flower {
    right: auto;
    left: calc(var(--bloom-x) - var(--flower-w) * 0.375);
    top: calc(var(--bloom-y) - var(--flower-h) * 0.217);
    /* sized by height, and wider than the screen: the base max-width would
       squash it to fit */
    max-width: none;
    transform: rotate(-16deg);
    transform-origin: 37.5% 21.7%;
  }

  .hero-logo {
    /* the mark's own height, at the artwork's 446:145 */
    --mark-hero-h: calc(var(--mark-hero-w) * 145 / 446);
    /* the text block, the gaps, and the mark itself, up from the foot */
    --mark-hero-rise: calc(
      var(--hero-foot)
      + var(--slogan-size-phone)
      + var(--subline-gap)
      + var(--subline-size) * 1.3
      + var(--mark-gap)
      + var(--mark-hero-h)
    );
    right: auto;
    left: var(--hero-inset);
    /* Hung from the top rather than the bottom: a phone's address bar
       collapses on the first scroll, the viewport grows, and a mark pinned
       to its foot would ride down with it before the flight has begun. The
       small viewport height is the one the bar leaves, and it does not
       move — it is also what the hero's own height is set from, so the
       mark and the slogan under it stay put together. */
    bottom: auto;
    top: calc(100vh - var(--mark-hero-rise));
    top: calc(100svh - var(--mark-hero-rise));
    width: var(--mark-hero-w);
  }

  .hero-bottom {
    padding-right: 0;
    padding-bottom: 0;
    flex-direction: column;
    align-items: flex-start;
    gap: 1rem;
  }

  .hero-slogan { --slogan-size: var(--slogan-size-phone); }

  .hero-bottom .hero-subline {
    margin-top: var(--subline-gap);
    font-size: var(--subline-size);
    line-height: 1.3;
    white-space: normal;
  }
}

/* Landscape phones: the screen is too short for the flower to sit inside
   it, so the bloom is kept small and the text with it. */
@media (max-width: 900px) and (max-height: 520px) {
  .hero {
    --flower-h: 130vh;
    --bloom-x: 70vw;
    --bloom-y: 40vh;
    --slogan-size-phone: clamp(2rem, 6vw, 3rem);
  }
}

/* --- Statement band under the hero --------------------------------- */

.intro {
  position: relative;
  z-index: 1;
  color: var(--dark-grey);
  background: rgba(114, 158, 104, 0.07);
  padding: clamp(5rem, 14vh, 9rem) clamp(1rem, 2vw, 1.75rem);
  text-align: left;
}

/* No label in this band, but the copy still sits in the content column so it
   lines up with the first games card. */
.intro p,
.intro-heading { grid-column: 2; }

.intro-heading {
  font-size: clamp(1.5rem, 2.5vw, 2rem);
  letter-spacing: 0;
  text-transform: none;
  margin-bottom: 0;
}

/* sits directly on the copy, overriding the base h2 + * spacing */
.intro-heading + p { margin-top: 0; }

.intro-more {
  margin-top: 1rem;
  font-size: 1.0625rem;
}

/* Shared band layout: rotated label column + content, so the labels in the
   grey band and the games section sit on the same left edge at every width. */
.band-inner {
  max-width: 1400px;
  margin-inline: auto;
  display: grid;
  grid-template-columns: var(--label-col) 1fr;
  column-gap: clamp(1.5rem, 5vw, 4rem);
  row-gap: 0;
  align-items: stretch;
}

.intro p {
  align-self: start;
  max-width: 42rem;
  margin-inline: 0;
  font-size: clamp(1.0625rem, 1.5vw, 1.375rem);
  line-height: 1.6;
}

/* --- Games ---------------------------------------------------------- */

.games {
  padding: clamp(3.5rem, 9vh, 6rem) clamp(1rem, 2vw, 1.75rem);
}

/* Vertical section label, reading bottom to top */
.games-title {
  margin: 0;
  display: grid;
  place-items: center;
  writing-mode: vertical-rl;
  transform: rotate(180deg);
  font-size: clamp(2.25rem, 5vw, 4rem);
  line-height: 0.9;
  letter-spacing: 0.02em;
  text-transform: uppercase;
}

.games-row + .games-row { margin-top: clamp(2.5rem, 6vh, 4rem); }

.games-row-title {
  font-size: 1rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  margin-bottom: 1rem;
  opacity: 0.65;
}

.game-grid {
  list-style: none;
  padding: 0;
  margin: 0;
  display: grid;
  gap: clamp(0.75rem, 2vw, 1.5rem);
}

.game-grid--2 { grid-template-columns: repeat(2, 1fr); }
.game-grid--4 { grid-template-columns: repeat(4, 1fr); }
.game-grid li { margin: 0; }

/* --- Game card ------------------------------------------------------ */

.game-card {
  position: relative;
  display: block;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  text-decoration: none;
  background: var(--dark-grey);
}

.game-card-media,
.game-card img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  transition: filter var(--transition-med), transform var(--transition-med);
}

/* A 16:9 card lands on a fractional pixel height at most window widths, which
   leaves the card's dark background showing as a hairline under the keyart —
   visible whenever the art is light at that edge (Ikami). Overhanging the image
   by a pixel, clipped by the card's overflow, keeps the edge covered. */
.game-card img { height: calc(100% + 1px); }

/* Placeholder styling — inert once a real <img> replaces the div */
.game-card-media[data-placeholder] {
  display: grid;
  place-items: center;
  background: var(--dark-grey);
  color: var(--off-white);
  font-size: 0.8125rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  opacity: 0.55;
}
.game-card-media[data-placeholder]::after { content: attr(data-placeholder); }

/* Banner sweeps the full width of the card, centred */
.game-card-banner {
  position: absolute;
  left: 0;
  right: 0;
  top: 50%;
  transform: translateY(-50%);
  padding: 0.85rem 1rem;
  background: var(--green);
  color: var(--off-white);
  font-family: var(--font-heading);
  font-size: clamp(0.9375rem, 1.4vw, 1.25rem);
  text-align: center;
  opacity: 0;
  transition: opacity var(--transition-med);
}

/* Every card that is a link leaves the site, and says so. */
.game-card[target="_blank"] .game-card-banner::after {
  content: "\2197";
  margin-left: 0.35em;
  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
  font-size: 0.8em;
}

.game-card:hover .game-card-media,
.game-card:focus-visible .game-card-media,
.game-card:hover img,
.game-card:focus-visible img { filter: blur(6px); }

.game-card:hover .game-card-banner,
.game-card:focus-visible .game-card-banner { opacity: 1; }

/* The reserved slot is not a link and stays static. It is drawn as an
   outline rather than a filled tile, so the released game beside it is the
   one thing in the row with any weight. */
.game-card--tba {
  cursor: default;
  background: none;
  border: 1px dashed rgba(114, 158, 104, 0.6);
}

.game-card--tba .game-card-media[data-placeholder] {
  background: none;
  color: var(--green);
  opacity: 1;
}

/* No pointer to hover with: the banner would never be seen, so the title
   is set under the art as a caption instead. The card gives up its fixed
   ratio to make room and the media takes it over, so the grid rows still
   line up; the reserved slot has no caption and keeps the ratio itself. */
@media (hover: none) and (pointer: coarse) {
  .game-card {
    aspect-ratio: auto;
    overflow: visible;
    background: none;
    display: flex;
    flex-direction: column;
  }

  .game-card--tba { aspect-ratio: 16 / 9; }

  .game-card-media,
  .game-card img {
    aspect-ratio: 16 / 9;
    height: auto;
  }

  .game-card img { background: var(--dark-grey); }

  .game-card-banner {
    position: static;
    transform: none;
    opacity: 1;
    padding: 0.6rem 0 0;
    background: none;
    color: var(--dark-grey);
    font-size: 0.9375rem;
    text-align: left;
  }

  /* the tap itself is the interaction; nothing to blur over */
  .game-card:hover .game-card-media,
  .game-card:hover img { filter: none; }
}

@media (max-width: 900px) {
  .game-grid--4 { grid-template-columns: repeat(2, 1fr); }
}

/* On a phone the originals stack — Ikami is the one card that wants the
   full width — while the collaborations stay two across, so the row is two
   short rows rather than four screens of scrolling. */
@media (max-width: 560px) {
  .game-grid--2 { grid-template-columns: 1fr; }
  .game-grid--4 { gap: 0.75rem 0.875rem; }
}

/* One column: the rotated label beside the cards costs a quarter of a
   phone's width, so it is stood upright and set over the cards instead,
   and the intro copy takes the same full measure. */
@media (max-width: 600px) {
  .band-inner { grid-template-columns: 1fr; }

  .intro p,
  .intro-heading { grid-column: 1; }

  .games-title {
    display: block;
    writing-mode: horizontal-tb;
    transform: none;
    margin-bottom: 1.5rem;
    font-size: 2.5rem;
    line-height: 1;
  }
}

/* --- Sections ----------------------------------------------------- */

.wrap section + section { margin-top: 3.5rem; }
h2 + * { margin-top: 1.5rem; }
p + p, p + ul, ul + p, h3 + p, dl + h2 { margin-top: 1rem; }
p + h3 { margin-top: 2rem; }
h1 + p { margin-top: 1rem; }

/* --- About page ----------------------------------------------------
   Opens on the slogan set large, then three sections in one order: what
   we are after, how we go about it, what we hold to on the way. Each
   section is a two-column row — its name on the left, held in place while
   the body scrolls past, the point of the section in heading type and the
   body on the right. The values are laid out as a set of cards rather than
   a run of paragraphs. Everything here is scoped to the page: the legal
   pages run plain sections and keep the base rhythm. */

.wrap--about {
  --maxw: 1080px;
  padding-inline: clamp(1.5rem, 4vw, 2.5rem);
}

/* --- Opener ---
   Eyebrow, slogan, sub-line. The slogan is the page's heading and takes the
   size the hero gives it on the home page; the sub-line is the same one
   that sits under it there. A hairline closes the block off from the
   sections under it. */
.about-head {
  padding: clamp(1.5rem, 5vw, 3.5rem) 0 clamp(2.75rem, 7vw, 4.5rem);
  border-bottom: 1px solid rgba(114, 158, 104, 0.35);
}

.about-eyebrow,
.eyebrow {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  font-family: var(--font-heading);
  font-size: 0.8125rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--green);
}

/* a short rule leading into the label */
.about-eyebrow::before,
.eyebrow::before {
  content: "";
  width: 2rem;
  height: 2px;
  border-radius: 1px;
  background: var(--green);
}

.about-slogan {
  margin-top: 1.25rem;
  font-size: clamp(2.75rem, 8vw, 5.5rem);
  line-height: 0.95;
  letter-spacing: -0.02em;
}

.about-subline {
  margin-top: 1.25rem;
  max-width: 28ch;
  font-family: var(--font-heading);
  font-size: clamp(1.125rem, 2.2vw, 1.5rem);
  line-height: 1.3;
  letter-spacing: -0.01em;
  opacity: 0.7;
}

/* --- Sections --- */
.about-block {
  display: grid;
  grid-template-columns: minmax(7rem, 13rem) 1fr;
  column-gap: clamp(2rem, 6vw, 5rem);
  padding-block: clamp(3rem, 7vw, 5rem);
}

.about-block + .about-block {
  border-top: 1px solid rgba(114, 158, 104, 0.35);
}

/* The label rides along while its section scrolls, parked just under the
   top bar. A short green rule sits above it — the same mark the eyebrow
   carries, so the page's labels all open the same way. */
.about-label h2 {
  position: sticky;
  top: calc(var(--bar-h) + 1.5rem);
  font-size: 0.9375rem;
  letter-spacing: 0.14em;
}

.about-label h2::before {
  content: "";
  display: block;
  width: 2rem;
  height: 2px;
  margin-bottom: 1rem;
  border-radius: 1px;
  background: var(--green);
}

.about-body { max-width: 62ch; }

/* The point of the section, in heading type: long enough to say something
   on its own, short enough to be read before the body under it. */
.statement {
  font-family: var(--font-heading);
  font-size: clamp(1.5rem, 3.2vw, 2.25rem);
  line-height: 1.2;
  letter-spacing: -0.015em;
  text-wrap: balance;
}

.statement + p { margin-top: 1.5rem; }

.about-body > p:not(.statement) {
  font-size: 1.0625rem;
  line-height: 1.75;
  color: rgba(50, 50, 50, 0.85);
}

/* The values section has a wider body: the cards want the room. */
.about-block--values .about-body { max-width: none; }

/* --- Values, as cards ---
   Two across, each carrying its number as a small marker drawn from the
   counter rather than written into the text. */
.value-list {
  list-style: none;
  padding: 0;
  counter-reset: value;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(1rem, 2vw, 1.5rem);
}

/* the grid gap is what spaces these; the base list rule would add to it */
.value-list > li + li { margin-top: 0; }

.value-list > li {
  counter-increment: value;
  display: flex;
  flex-direction: column;
  padding: clamp(1.5rem, 3vw, 2.25rem);
  border-radius: 6px;
  background: rgba(114, 158, 104, 0.07);
  border: 1px solid rgba(114, 158, 104, 0.22);
  transition: border-color var(--transition-med);
}

/* not a link, so nothing moves: the edge just firms up under the pointer */
.value-list > li:hover { border-color: rgba(114, 158, 104, 0.6); }

.value-list > li::before {
  content: counter(value, decimal-leading-zero);
  margin-bottom: 1.25rem;
  font-family: var(--font-heading);
  font-size: 0.875rem;
  letter-spacing: 0.14em;
  line-height: 1;
  color: var(--green);
}

.value-list h3 {
  font-size: clamp(1.125rem, 1.6vw, 1.3125rem);
  line-height: 1.3;
  letter-spacing: -0.01em;
  text-wrap: balance;
}

.value-list p {
  margin-top: 0.75rem;
  font-size: 1rem;
  line-height: 1.65;
  color: rgba(50, 50, 50, 0.85);
}

/* --- Reveal ---
   js/reveal.js hides these only once it knows it can show them again, so a
   page without the script, or one read with reduced motion on, is drawn in
   place. The entrance is an animation rather than a transition so it can
   run on a delay — the cards come in one after another, on --i set in the
   markup — without that delay hanging on the cards' hover transition later.
   The fill runs backwards only: it holds the hidden frame through the delay
   and then lets go, so once a card is in, hover has its transform back. */
body.js-reveal [data-reveal] { opacity: 0; }

body.js-reveal [data-reveal].is-in {
  opacity: 1;
  animation: about-reveal 0.8s cubic-bezier(0.22, 1, 0.36, 1) backwards;
  animation-delay: calc(var(--i, 0) * 90ms);
}

@keyframes about-reveal {
  from { opacity: 0; transform: translateY(1.25rem); }
  to   { opacity: 1; transform: none; }
}

/* One column: the label goes above the body it belongs to and no longer
   needs to ride along. */
@media (max-width: 760px) {
  .about-block {
    grid-template-columns: 1fr;
    row-gap: 1.5rem;
  }
  .about-label h2 { position: static; }
}

@media (max-width: 600px) {
  .value-list { grid-template-columns: 1fr; }
}

/* --- Legal pages (imprint, privacy) ---------------------------------
   The same opener as the about page, a size down, then a single column
   of sections parted by hairlines: reading matter, so the measure stays
   narrow. Labels open the way the about page's do. Detail lists are set
   as tables — a rule per row, the key in small caps. */

.wrap--legal { --maxw: 760px; }

.legal-head {
  padding: clamp(1.5rem, 5vw, 3rem) 0 clamp(2rem, 5vw, 3rem);
  border-bottom: 1px solid rgba(114, 158, 104, 0.35);
}

.legal-head h1 {
  margin-top: 1rem;
  font-size: clamp(2.25rem, 6vw, 3.75rem);
  line-height: 1;
  letter-spacing: -0.02em;
}

.legal-meta {
  margin-top: 1rem;
  font-family: var(--font-heading);
  font-size: 0.9375rem;
  letter-spacing: 0.04em;
  opacity: 0.65;
}

.legal section { padding-block: clamp(2rem, 5vw, 3rem); }

.legal section + section {
  margin-top: 0;
  border-top: 1px solid rgba(114, 158, 104, 0.35);
}

.legal h2 {
  font-size: 0.9375rem;
  letter-spacing: 0.14em;
}

.legal h2::before {
  content: "";
  display: block;
  width: 2rem;
  height: 2px;
  margin-bottom: 1rem;
  border-radius: 1px;
  background: var(--green);
}

.legal h2 + * { margin-top: 1.25rem; }
.legal dl + h2 { margin-top: 2.75rem; }

.legal p,
.legal li {
  color: rgba(50, 50, 50, 0.85);
  line-height: 1.75;
}

/* the one line worth pulling out */
.legal .statement {
  font-size: clamp(1.375rem, 2.6vw, 1.75rem);
  color: var(--dark-grey);
}

.legal ul {
  list-style: none;
  padding: 0;
}

.legal li { padding-left: 1.5rem; position: relative; }
.legal li + li { margin-top: 0.5rem; }

.legal li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.85em;
  width: 0.625rem;
  height: 2px;
  border-radius: 1px;
  background: var(--green);
}

.legal dl {
  grid-template-columns: 11rem 1fr;
  gap: 0;
  border-bottom: 1px solid rgba(114, 158, 104, 0.18);
}

.legal dt,
.legal dd {
  padding: 0.65rem 0;
  border-top: 1px solid rgba(114, 158, 104, 0.18);
}

.legal dt {
  padding-top: 0.85rem;
  font-family: var(--font-heading);
  font-size: 0.8125rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  opacity: 0.6;
}

.legal dd { padding-right: 0; }

/* One column: the key sits over its value, and the pair shares one rule. */
@media (max-width: 560px) {
  .legal dl { grid-template-columns: 1fr; }
  .legal dt { padding-bottom: 0.1rem; }
  .legal dd { padding-top: 0; border-top: 0; margin-bottom: 0; }
}

/* --- Lists -------------------------------------------------------- */

ul { padding-left: 1.1rem; }
main li + li { margin-top: 0.35rem; }

.game-list { list-style: none; padding: 0; }
.game-list li { padding-top: 1rem; border-top: 1px solid var(--green); }
.game-list li + li { margin-top: 1rem; }
.game-list p { opacity: 0.75; font-size: 0.9375rem; }

/* --- Detail lists (imprint, contact) ------------------------------ */

dl { display: grid; grid-template-columns: 12rem 1fr; gap: 0.35rem 1.5rem; }
dt { opacity: 0.6; }
dd { margin: 0; }

/* --- Footer ------------------------------------------------------- */

/* Full-bleed band: the rule runs edge to edge, the row inside it keeps the
   same 1400px measure as the intro and games bands. Three cells — copyright,
   contact, legal — with the outer two sharing the leftover width equally so
   the contact block sits on the page's centre line, not the centre of what
   is left after the longer of the two ends. */
.site-footer {
  padding: 1.75rem clamp(1rem, 2vw, 1.75rem) 2rem;
  border-top: 1px solid var(--green);
  font-size: 0.9375rem;
}

.footer-inner {
  max-width: 1400px;
  margin-inline: auto;
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  column-gap: clamp(1.5rem, 4vw, 3rem);
  row-gap: 1.75rem;
}

.footer-copy { margin: 0; opacity: 0.8; }

.footer-contact {
  display: flex;
  align-items: center;
  gap: 1rem;
}

/* The icon is its own mailto link, so the anchor takes over the flex item's
   duties and the svg just fills it. */
.footer-icon-link {
  display: flex;
  flex: none;
  /* the opened flap stands above the icon's own box */
  overflow: visible;
}

/* Sized to the two stacked lines it sits beside, both set solid at 1.4. */
.footer-icon {
  --footer-contact-height: calc((0.875rem + 0.9375rem) * 1.4);
  flex: none;
  height: var(--footer-contact-height);
  width: calc(var(--footer-contact-height) * 48 / 34);
  fill: none;
  stroke: var(--green);
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
  /* the opened flap stands above the 48x34 box */
  overflow: visible;
}

/* Hover opens the envelope: the flap hinges on the line between the two top
   corners and folds all the way back, overshooting a little on the way out so
   it lands rather than stops, and the sheet rises out behind it. Halfway
   through the fold the flap is edge-on and has no height of its own —
   non-scaling-stroke is what keeps the line at full weight there instead of
   thinning away to nothing. Closing is the plain curve, no bounce.
   Focus is in as well, so the keyboard reaches the same state as the mouse
   when the address beside the icon takes focus.

   The two run in order, and the order flips: on the way out the flap goes
   first and the sheet follows it, on the way back the sheet drops in before
   the flap comes down on top of it. */
.footer-icon-flap {
  transform-box: view-box;
  transform-origin: 24px 3.5px;
  transition: transform var(--transition-slow) 0.12s;
}

.footer-icon-sheet {
  transition: transform var(--transition-med);
}

.footer-icon-sheet rect { fill: var(--off-white); }
.footer-icon-sheet path { stroke-width: 1.6; }

.footer-contact:hover .footer-icon-flap,
.footer-contact:focus-within .footer-icon-flap {
  transform: scaleY(-1);
  transition-timing-function: cubic-bezier(0.34, 1.4, 0.64, 1);
  transition-delay: 0s;
}

.footer-contact:hover .footer-icon-sheet,
.footer-contact:focus-within .footer-icon-sheet {
  transform: translateY(-29px);
  transition-delay: 0.12s;
}

.footer-contact-body p { margin: 0; line-height: 1.4; }

.footer-contact-label {
  font-family: var(--font-heading);
  font-size: 0.875rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.footer-legal { justify-self: end; }

.footer-legal ul {
  display: flex;
  flex-wrap: wrap;
  gap: 1.25rem;
  list-style: none;
  padding: 0;
  margin: 0;
}

.footer-legal a { opacity: 0.8; }
.site-footer a { text-decoration: none; }

/* Stacked and left-aligned once the three cells stop fitting on one line. */
@media (max-width: 860px) {
  .footer-inner {
    grid-template-columns: 1fr;
    justify-items: start;
    row-gap: 1.5rem;
  }
  .footer-contact { order: -1; }
  .footer-legal { justify-self: start; }
}

/* --- Small screens ------------------------------------------------ */

/* The small tracked links — the legal row in the menu and in the footer —
   are set at 12px and would be a thin strip to hit. Under a thumb they get
   a band of padding above and below, which is invisible and leaves the
   row's rhythm as it was. */
@media (hover: none) and (pointer: coarse) {
  .menu-details a,
  .footer-legal a,
  .footer-contact-body a {
    display: inline-block;
    padding-block: 0.5rem;
    margin-block: -0.5rem;
  }
}

@media (max-width: 560px) {
  :root { --bar-h: 3.25rem; --ham-top: 1.2rem; }
  .hamburger { right: 1.2rem; }
  /* the bands share the hero's inset once there is no label column */
  .intro,
  .games,
  .site-footer { padding-inline: 1.5rem; }
  .menu-overlay a { font-size: 2.5rem; }
  .menu-logo { top: 1.2rem; height: 2.5rem; }
  .menu-details { bottom: 1.5rem; }
  .menu-overlay .menu-details ul { gap: 0.75rem 1.5rem; }
  .menu-inner { gap: 2rem; }
  dl { grid-template-columns: 1fr; gap: 0; }
  dd { margin-bottom: 0.75rem; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { transition-duration: 0.01ms !important; }

  /* No flight: the wordmark stays in the hero and scrolls away with it.
     logo-travel.js leaves the transform alone in this mode. */
  .hero-logo { position: absolute; z-index: 2; }
}
