/* ----- resets ----- */

.skip-links,
header.mainHeader,
footer.mainFooter {
  display: none;
}

body {
  padding: 0;
}

* {
  font-family: unset;
}

a {
  color: inherit;
}

ol {
  margin-left: 30px;
}

strong {
  font-family: inherit;
}

/* ----- fonts ----- */

/* Only absolute weights are valid @font-face descriptors - `bolder` is silently treated as
   400, which is why the Black face was overriding Regular and everything looked heavy. */

@font-face {
  font-family: "Eurostile Extended";
  src: url("fonts/Eurostile-Extended/EurostileExt-Reg.otf") format("opentype");
  font-weight: 400;
}

@font-face {
  font-family: "Eurostile Extended";
  src: url("fonts/Eurostile-Extended/EurostileExt-Med.otf") format("opentype");
  font-weight: 500;
}

@font-face {
  font-family: "Eurostile Extended";
  src: url("fonts/Eurostile-Extended/EurostileExt-Bla.otf") format("opentype");
  font-weight: 900;
}

@font-face {
  font-family: "IBM Plex Mono";
  src: url("fonts/IBM-Plex-Mono/IBMPlexMono-Medium.ttf") format("truetype");
  font-weight: 500;
}

/* ----- vars ----- */

@property --wc-text-fade {
  syntax: "<length-percentage>";
  inherits: true;
  initial-value: 40%;
}

:root {
  --color-dark: #000;
  --color-mid: #5c5952;
  --color-light: #e6dfce;

  --font-s: 12px;
  --font-m: 15px;
  --font-l: 32px;

  --font-mono: "IBM Plex Mono", monospace;
  --font-sans: "Eurostile Extended", sans-serif;

  --spacing-s: 10px;
  --spacing-m: 20px;
  --spacing-xl: 300px;

  --wc-doc-action-size: 28px;

  /* how far the bottom links stop short of the right edge, clearing the logo row */
  --wc-nav-2-inset: clamp(0px, calc((100vw - 1100px) * 0.5), 9%);

  /* the shadow that drifts along the horizon */
  --wc-sweep-duration: 16s;
  --wc-sweep-width: 55vw;
  --wc-sweep-strength: 0.92;

  /* media panel: diagonal step between tiles, and the delay between their reveals */
  --wc-tile-width: 62%; /* tiles after the first; the first fills the panel */
  --wc-tile-step: 16%;
  --wc-tile-fade: 260ms;
  --wc-tile-drift: 16px;
  --wc-tile-jitter: 0.6;
  --wc-tile-size-jitter: 0.35;

  /* Vertical framing of bg.png. Lower values push the image down the screen; at 100%
     (bottom) the arc crosses the title, 76% drops its crest just under the lettering. */
  --wc-bg-y: 76%;
  /* where the horizon starts before it settles - see the landing intro at the end */
  --wc-bg-y-from: 30%;
  --wc-title-from: translateY(70px);

  --wc-stack-height: 26vh;

  /* Stack-in: how far a front-most collage layer starts below its design position before
     the copy is scrolled. Depth is per layer (--d, written by the renderer), so the plates
     behind are in place from the start and the pieces stack onto them as you read. */
  --wc-stack-in: 56px;
  /* each plane waits --wc-stack-lag * its depth before setting off, then takes
     --wc-stack-window of the scroll to land - so the planes arrive in turn */
  --wc-stack-lag: 0.35;
  --wc-stack-window: 0.55;
  /* How abruptly a layer becomes visible, as a multiple of its own arrival window: 6 means
     it is fully there after a sixth of its travel, so it reads as landing rather than
     fading up. Lower it towards 1 for a softer entrance. */
  --wc-stack-snap: 6;

  --wc-nav-1-height: calc(var(--font-s) + var(--spacing-s));
  --wc-nav-2-height: calc(var(--font-l) + var(--spacing-s));
  --wc-nav-2-banner-height: calc(100vw / 27 * 2);
  --content-height: calc(
    100vh - var(--wc-nav-1-height) - var(--wc-nav-2-height) -
      var(--wc-nav-2-banner-height) - 2 * var(--spacing-s)
  );

  --wc-transition: 600ms cubic-bezier(0.16, 1, 0.3, 1);

  /* height of the scroll fade at the bottom edge of .wc-text */
  /* As a share of the text block's height, so the fade keeps meeting the horizon as the
     viewport changes. The title is centred in the viewport and the horizon sits just
     under it, which puts it near the block's midpoint. */
  --wc-text-fade: 73%;

  /* The text column stops near the horizon rather than running to the bottom of the
     content area, so the copy has dissolved by the time it reaches the light band. */
  --wc-text-height: 58%;
}

@supports (height: 100dvh) {
  :root {
    --content-height: calc(
      100dvh - var(--wc-nav-1-height) - var(--wc-nav-2-height) -
        var(--wc-nav-2-banner-height) - 2 * var(--spacing-s)
    );
  }
}

/* ----- general ----- */

body {
  background-color: var(--color-dark);
  color: var(--color-light);
  font-size: var(--font-m);
  font-family: var(--font-mono);
  background-image: url("../img/uni-wc/bg.png");
  background-size: cover;
  background-repeat: no-repeat;
  /* framing of the horizon against the title - see --wc-bg-y */
  background-position: 50% var(--wc-bg-y);
  padding: var(--spacing-s);
}

/* ----- nav ----- */

/* nav-1 is transformed, and a transform does not free the element's flow slot.
   Taking it out of flow lets .wc-viewport own that height instead, so no gap is
   left behind when the nav slides down. */
main {
  position: relative;
}

.wc-nav-1 {
  position: relative;
  z-index: 5;
}


.wc-nav-1 ul {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  text-transform: uppercase;
  font-family: var(--font-sans);
  font-weight: 500;
  letter-spacing: 0;
  height: var(--wc-nav-1-height);
  list-style: none;
  font-size: var(--font-s);
  color: var(--color-mid);
}

.wc-nav-1 ul li a {
  text-decoration: none;
  transition: color 200ms ease;
}

.wc-nav-1 ul li a:hover,
.wc-nav-1 ul li a.active {
  color: var(--color-light);
}

.wc-lang {
  display: flex;
  align-items: center;
  gap: calc(var(--spacing-s) / 2);
  flex: 0 0 auto;
  height: var(--wc-nav-1-height);
  color: var(--color-mid);
}

/* `* { font-family: unset }` above strips the UA button font, so restate it here. */
.wc-lang button {
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  font-family: var(--font-sans);
  font-size: 10px;
  font-weight: 500;
  text-transform: uppercase;
  cursor: pointer;
  transition: color 200ms ease;
}

.wc-lang button:hover,
.wc-lang button.active {
  color: var(--color-light);
}

.wc-nav-2 {
  width: 100%;
  display: flex;
  letter-spacing: -0.02em;
  gap: var(--spacing-xl);
  align-items: center;
  justify-content: space-between;
  text-transform: uppercase;
  font-family: var(--font-sans);
  font-weight: 500;
  height: var(--wc-nav-2-height);
  font-size: var(--font-l);
  color: var(--color-mid);
}

/* The links stop short of the right edge: at full width APPLY ran into the FAST logo in
   the logo row beside it. */
.wc-nav-2 .nav-items {
  display: flex;
  align-items: center;
  justify-content: space-between;
  list-style: none;
  /* takes whatever the logo row leaves rather than claiming 100% and being shrunk into
     wrapping - the labels spread into the space on their right instead */
  flex: 1 1 auto;
  min-width: 0;
  padding-right: var(--wc-nav-2-inset);
  box-sizing: border-box;
  gap: var(--spacing-m);
}

/* a label never breaks across two lines */
.wc-nav-2 .nav-items li {
  white-space: nowrap;
}

/* Apply is the call to action, so it sits at the lighter colour while the two documents
   stay at --color-mid. */
.wc-nav-2 .nav-items li.wc-nav-2-apply {
  color: var(--color-light);
}

.wc-nav-2 .nav-logos {
  display: flex;
  align-items: center;
  justify-content: space-between;
  list-style: none;
  flex: 0 0 auto;
}

.wc-nav-2 .nav-logos img {
  max-height: 35px;
  display: block;
  margin-bottom: 13px;
}

.wc-nav-2-banner {
  width: 100%;
  height: var(--wc-nav-2-banner-height);
}

/* The bottom bar has to paint above the collage. Two reasons, one rule: the logo images are
   35px tall with a 13px bottom margin inside a --wc-nav-2-height row, so each one overhangs
   ~3px into .wc-viewport's box - and every collage layer is absolutely positioned, so
   without a z-index of its own the static bar loses that overlap to whichever layer happens
   to sit in the corner. On mobile it also has to stay legible above the menu overlay (20).
   Below the document popup (40), above nav-1 (5). */
.wc-nav-2,
.wc-nav-2-banner {
  position: relative;
  z-index: 25;
}

.wc-nav-2-banner img {
  width: 100%;
  height: 100%;
  object-fit: contain;
}

/* ----- content ----- */

.wc-viewport {
  width: 100%;
  height: var(--content-height);
  position: relative;
  overflow: hidden;
}

.wc-title {
  position: absolute;
  top: 50%;
  left: 0;
  width: 100%;
  transform: translateY(-50%);
  transition: opacity var(--wc-transition);
  pointer-events: none;
}

.wc-title img {
  display: block;
  width: 100%;
  height: auto;
}

main.content-open .wc-title {
  opacity: 0;
}

.wc-content {
  position: absolute;
  inset: 0;
  transform: translateY(-100%);
  transition: transform var(--wc-transition);
}

.wc-content.active {
  transform: translateY(0);
}

/* Swapping sections while the panel is already down must not re-animate. */
.wc-viewport.wc-no-transition .wc-content {
  transition: none;
}

/* The section name, lifted out of .wc-text so mobile can place it under the copy. */
.wc-lead {
  display: none; /* mobile only - desktop keeps the lead image inside the stack */
}

/* the section name sits between the copy and the collage on mobile only; on desktop the
   highlighted nav item already says which section you are in */
.wc-heading {
  display: none;
}

/* the designer's mobile frames; the desktop collage covers this ground above 1000px.
   Hidden rather than absent, so none of it - the GIFs included - is fetched on desktop. */
.wc-lead,
.wc-collage-mobile {
  display: none;
}

.wc-mobile-bar {
  display: none;
}

.wc-text {
  position: absolute;
  top: 0;
  left: 0;
  width: 50%;
  height: var(--wc-text-height);
  overflow-y: scroll;
  padding-right: var(--spacing-s);
  box-sizing: border-box;

  /* hidden, but still scrollable */
  scrollbar-width: none;
  -ms-overflow-style: none;

  /* Soft fade at the bottom edge instead of a hard clip. The mask is painted on the
     element's own box, not the scrolled content, so the fade stays pinned to the edge
     as the text scrolls underneath it. */
  -webkit-mask-image: linear-gradient(
    to bottom,
    rgba(0, 0, 0, 1) calc(100% - var(--wc-text-fade)),
    rgba(0, 0, 0, 0.75) calc(100% - var(--wc-text-fade) * 0.62),
    rgba(0, 0, 0, 0.35) calc(100% - var(--wc-text-fade) * 0.3),
    rgba(0, 0, 0, 0) 100%
  );
  mask-image: linear-gradient(
    to bottom,
    rgba(0, 0, 0, 1) calc(100% - var(--wc-text-fade)),
    rgba(0, 0, 0, 0.75) calc(100% - var(--wc-text-fade) * 0.62),
    rgba(0, 0, 0, 0.35) calc(100% - var(--wc-text-fade) * 0.3),
    rgba(0, 0, 0, 0) 100%
  );
  transition: --wc-text-fade 250ms ease;
}

.wc-text::-webkit-scrollbar {
  display: none;
}

/* scrolled to the bottom: nothing left below, so drop the fade */
/* At the end of the scroll there is nothing left to rise out of the horizon, and the last
   lines need to be readable - so the gradient clears. 0% rather than 0px keeps both ends of
   the transition in the same unit. */
.wc-text.at-end {
  --wc-text-fade: 0%;
}

.wc-text h2,
.wc-text h3,
.wc-text h4,
.wc-text .text-huge,
.wc-text .text-big {
  font-size: var(--font-s);
  font-weight: 500;
  font-family: var(--font-sans);
  text-transform: uppercase;
}

.wc-text .text-huge,
.wc-text h3 {
  margin-top: var(--spacing-m);
}

.wc-text .text-big,
.wc-text h4 {
  margin-top: var(--spacing-m);
}

.wc-text p {
  margin-bottom: var(--spacing-m);
}

.wc-text a {
  text-decoration: underline;
  text-underline-offset: 3px;
}

/* Spans the whole content area - placeBands() confines each band to the space .wc-text
   does not occupy, so tiles never land behind the copy. */
.wc-media {
  position: absolute;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
}

/* Only the band matching the text column's scroll position is painted. */
/* Inset by the drift distance so a tile at either end of its travel still sits inside the
   panel instead of being clipped by the overflow. */
.wc-media-band {
  position: absolute;
  left: var(--band-l, 0px);
  top: var(--band-t, var(--wc-tile-drift));
  width: var(--band-w, 100%);
  height: var(--band-h, calc(100% - 2 * var(--wc-tile-drift)));
  opacity: 0;
  visibility: hidden;

  /* random origin for the stack, set by JS once the tiles have measurable size */
  --band-x: 0px;
  --band-y: 0px;
}

.wc-media-band.active {
  opacity: 1;
  visibility: visible;
}

/* The stack runs top-right to bottom-left: tile 0 sits at the origin, each later tile is
   one step down and one step further left. */
.wc-media-tile {
  position: absolute;

  /* Steps along the diagonal, in multiples of --wc-tile-step. JS jitters these per tile;
     the --i fallback keeps the stack evenly spaced until it does. */
  --kx: var(--i);
  --ky: var(--i);

  /* width multiplier, also jittered by JS */
  --kw: 1;

  top: calc(var(--band-y) + var(--ky) * var(--wc-tile-step));
  right: calc(var(--band-x) + var(--kx) * var(--wc-tile-step));
  width: calc(var(--kw) * var(--wc-tile-width));
  height: auto;
  z-index: var(--i);
  will-change: transform;
}

/* The band opens on an image sized to fit the whole panel; the rest stack over it, smaller
   and offset. `contain` keeps its aspect ratio, so tall images are letterboxed rather than
   stretched or clipped by the panel's overflow. */
.wc-media-band .wc-media-tile:first-child {
  width: 100%;
  height: 100%;
  object-fit: contain;
  object-position: top right;
}

/* Tiles are revealed one at a time as the reader scrolls through the band - JS adds
   .revealed at each tile's share of the band's progress - rather than on a timer. */
.wc-media-band .wc-media-tile {
  opacity: 0;
  transition: opacity var(--wc-tile-fade) ease;
}

.wc-media-band.active .wc-media-tile.revealed {
  opacity: 1;
}


.wc-contrast-toggle {
  display: flex;
  align-items: center;
  /* buttons do not inherit font-size from the UA stylesheet, so restate it - then the icon
     can be sized in em and track the nav text at either breakpoint */
  font-size: inherit;
  width: 1.6em;
  height: 1.6em;
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  cursor: pointer;
}

.wc-contrast-toggle svg {
  display: block;
  width: 100%;
  height: 100%;
  margin-bottom: 8px;
}

.wc-contrast-toggle:hover,
.wc-contrast-toggle[aria-pressed="true"] {
  color: var(--color-light);
}

/* ----- collage -----
   Static composition transcribed from Figma. Layer boxes are positioned in percentages of
   .wc-content by the view; the inner <img> carries the design's crop, so an image can be
   larger than its box and offset within it. */

.wc-collage {
  position: absolute;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
}

/* The design frame's content area, at its own pixel size. uni-wc.js scales it uniformly to
   cover .wc-collage, so nothing is ever stretched on one axis. */
.wc-collage-canvas {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 1440px;
  height: 737px;
  transform: translate(-50%, -50%) scale(var(--wc-collage-scale, 1));
  transform-origin: center;
}

/* isolate makes the children composite among themselves first, so the group's own blend
   mode applies to the combined result - matching how Figma blends a group */
.wc-collage-group {
  position: absolute;
  inset: 0;
  isolation: isolate;
}

.wc-collage-layer {
  position: absolute;
  overflow: hidden;
}

/* Content-reactive imagery, driven by --wc-scroll (0..1, written onto the active
   .wc-content by uni-wc.js): the foreground planes start below their design position and
   stack into it as you read, the deeper plane leading the nearer one. --d 0 is the
   backdrop, in place from the start, and at full scroll every layer sits exactly where
   Figma puts it. The fallback is 1, not 0, so without JS the collage is simply complete. */
.wc-collage-layer {
  --wc-stack-p: clamp(
    0,
    (var(--wc-scroll, 1) - var(--d, 0) * var(--wc-stack-lag)) /
      var(--wc-stack-window),
    1
  );
  /* Not there at all until its turn comes, then in over the first sliver of its own window
     while it is still travelling - so it lands in rather than fades up. --o is the layer's
     own opacity from Figma, which multiplies with the reveal instead of being replaced by
     it; --r 0 (the backdrop, and the default) opts out and stays visible throughout. */
  opacity: calc(
    var(--o, 1) *
      clamp(0, 1 - var(--r, 0) + var(--wc-stack-p) * var(--wc-stack-snap), 1)
  );
  transform: translate3d(
    0,
    calc((1 - var(--wc-stack-p)) * var(--d, 0) * var(--wc-stack-in)),
    0
  );
}

.wc-collage-layer img {
  position: absolute;
  display: block;
  max-width: none;
}

/* the collage is rendered after .wc-text in the markup, so the copy needs lifting above it */
.wc-text {
  z-index: 1;
}

/* ----- document popup ----- */

/* Above everything else on the page: nav-1 (5), the mobile menu overlay (20), nav-2 and
   the banner (25) and the mobile bar (30). */
.wc-doc-overlay {
  position: fixed;
  inset: 0;
  z-index: 40;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--spacing-m);
  background-color: rgb(0 0 0 / 0.85);
}

.wc-doc-overlay[hidden] {
  display: none;
}

.wc-doc {
  position: relative;
  max-width: 100%;
  max-height: 100%;
}

.wc-doc img {
  display: block;
  max-width: 100%;
  max-height: calc(100vh - 2 * var(--spacing-m));
  max-height: calc(100dvh - 2 * var(--spacing-m));
  width: auto;
  height: auto;
}

.wc-doc-actions {
  position: absolute;
  top: var(--spacing-s);
  right: var(--spacing-s);
  display: flex;
  gap: calc(var(--spacing-s) / 2);
}

/* `* { font-family: unset }` and the UA button styles both need overriding here. */
.wc-doc-download,
.wc-doc-close {
  width: var(--wc-doc-action-size);
  height: var(--wc-doc-action-size);
  box-sizing: border-box;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 5px;
  border: 0;
  background-color: var(--color-dark);
  color: var(--color-light);
  cursor: pointer;
}

.wc-doc-download {
  padding: 3px;
}

.wc-doc-download svg,
.wc-doc-close svg {
  display: block;
  width: 100%;
  height: 100%;
}

.wc-doc-download svg {
  border-bottom: 2px solid currentColor;
}

/* ----- mobile ----- */

@media (max-width: 1000px) {
  /* The desktop layout stacks to exactly 100vh through a chain of calc()s. Mobile has an
     extra bar and a two-row nav-2, so let flex distribute the height instead. */
  :root {
    /* a touch lower than the desktop framing so the horizon sits under the copy rather
       than level with it */
    --wc-bg-y: 25%;
    --wc-bg-y-from: 0%;
    /* h1 is rotated 90deg here, so local -X is screen "up" */
    --wc-title-from: translateX(-70px);
    /* On a tall viewport `cover` scales bg.png by height, so there is no vertical overflow
       for --wc-bg-y to shift. Oversizing it creates that headroom; the max() keeps the
       image wide enough to still cover a landscape phone. */
    --wc-bg-size: auto max(130%, 62.5vw);
    /* deeper than desktop: the copy should have dissolved by the time it reaches the
       horizon, so it reads as falling away behind it */
    --wc-text-fade: 70%;
    /* the mobile frames give the lower collage 21-34% of the screen; this is the ceiling */
    --wc-stack-height: 34vh;
    /* the clamp keeps OPEN CALL / WHITE PAPER off a second line on narrow phones */
    --wc-nav-font: clamp(11px, 3.6vw, var(--font-m));
    /* shared by the top bar and the menu list so the two always match */
    --wc-bar-font: clamp(9px, 2.6vw, var(--font-s));
    /* the desktop grey is close to unreadable on a phone; lift it without going to full
       --color-light, which is reserved for the active item */
    --color-mid: #8f8b81;
  }

  body {
    background-size: var(--wc-bg-size);
  }

  main {
    display: flex;
    flex-direction: column;
    height: calc(100vh - 2 * var(--spacing-s));
    height: calc(100dvh - 2 * var(--spacing-s));
  }

  .wc-mobile-bar {
    display: flex;
    flex: 0 0 auto;
    align-items: center;
    justify-content: space-between;
    gap: var(--spacing-s);
    height: var(--wc-nav-1-height);
    position: relative;
    z-index: 30;
    font-family: var(--font-sans);
    /* Eurostile Extended is wide; scale the bar down on narrow phones so MENU, the wordmark
       and EN/ES stay on one line. */
    font-size: var(--wc-bar-font);
    font-weight: 500;
    letter-spacing: 0;
    text-transform: uppercase;
    white-space: nowrap;
    background-color: var(--color-dark);
    color: var(--color-mid);
  }

  /* The bar is --wc-nav-1-height tall, so these buttons are barely 12px of text. The
     pseudo-element extends the touch area to ~44px without changing the layout - downward
     only, since above the bar is the browser's own top chrome, which eats the tap. */
  .wc-menu-toggle::after,
  .wc-contrast-toggle::after {
    content: "";
    position: absolute;
    inset: -6px -14px -22px;
  }

  .wc-menu-toggle,
  .wc-contrast-toggle {
    position: relative;
    /* over the sibling's expanded hit area, whichever paints later */
    z-index: 1;
    /* opts out of double-tap-to-zoom, so the tap fires immediately instead of being held
       back 300ms and then dropped when the section swap re-renders underneath it */
    touch-action: manipulation;
    -webkit-tap-highlight-color: rgb(255 255 255 / 0.2);
  }

  .wc-menu-toggle {
    padding: 0;
    border: 0;
    background: none;
    color: inherit;
    font: inherit;
    text-transform: uppercase;
    cursor: pointer;
  }

  /* nav-1 becomes a full-screen overlay under the bar: it blurs whatever is behind it and
     carries the gradient panel on its list. */
  .wc-nav-1 {
    position: fixed;
    inset: 0;
    z-index: 20;
    display: none;
    padding: calc(var(--wc-nav-1-height) + var(--spacing-s)) 0 0;
    background: none;
    /* blurs everything behind the overlay - page background included - rather than only
       the content panel, so the whole view softens as in the reference */
    backdrop-filter: blur(18px);
    -webkit-backdrop-filter: blur(18px);
    transform: none;
    transition: none;
  }

  main.menu-open .wc-nav-1 {
    display: block;
  }

  /* .wc-text is the page's only scroll container, so locking it (and the body, for mobile
     browsers that let the viewport rubber-band) freezes the view behind the menu */
  body.wc-menu-open,
  main.menu-open .wc-text {
    overflow: hidden;
  }

  /* The panel behind the items fades out below the last one instead of ending on a hard
     edge. It sits on the list, so it is only as wide as the longest label. */
  .wc-nav-1 ul {
    flex-direction: column;
    align-items: flex-start;
    justify-content: flex-start;
    gap: var(--spacing-m);
    width: max-content;
    max-width: 90%;
    height: auto;
    padding: var(--spacing-m) var(--spacing-m) calc(3 * var(--spacing-m))
      var(--spacing-s);
    font-size: var(--wc-bar-font);
    letter-spacing: 0;
    background-image: linear-gradient(
      to bottom,
      var(--color-dark) 0%,
      var(--color-dark) 52%,
      rgba(0, 0, 0, 0.6) 76%,
      rgba(0, 0, 0, 0) 100%
    );
  }

  /* the language pair lives in the bar on mobile */
  .wc-nav-1 .wc-lang {
    display: none;
  }

  .wc-viewport {
    flex: 1 1 auto;
    min-height: 0;
    height: auto;
  }

  /* copy (with the lead image scrolling inside it) / section name / collage */
  .wc-content {
    display: grid;
    grid-template-rows: minmax(0, 1fr) auto auto;
  }

  .wc-heading {
    display: block;
    grid-row: 2;
    margin: 0;
    padding: var(--spacing-s) 0;
    font-family: var(--font-sans);
    font-size: var(--wc-bar-font);
    font-weight: 500;
    letter-spacing: 0;
    text-transform: uppercase;
    color: var(--color-light);
  }

  /* The desktop collage is a 1440x737 composition - cropping it to a phone loses the
     composition entirely, and the designer drew separate mobile frames anyway. */
  .wc-collage {
    display: none;
  }

  /* The lower collage, at the design's own proportions. The box carries the frame's own
     aspect ratio (--wc-stack-ar, from the file itself) and takes its width from it, so
     --wc-stack-height can cap it on a short viewport without ever letterboxing the image -
     and so the GIF overlays, which are positioned in percentages of the frame, land on the
     pictures they were measured against at every width. */
  .wc-collage-mobile {
    position: relative;
    display: block;
    grid-row: 3;
    align-self: end;
    width: min(100%, calc(var(--wc-stack-height) * var(--wc-stack-ar)));
    aspect-ratio: var(--wc-stack-ar);
  }

  .wc-collage-mobile > img {
    display: block;
    width: 100%;
    height: 100%;
  }

  /* One baked-in picture's worth of the frame, with the live GIF inside it. The window
     clips the GIF to the region the design gives it; the GIF is opaque, so it covers the
     still frame underneath rather than blending with it and doubling the rain. */
  .wc-mobile-gif {
    position: absolute;
    overflow: hidden;
  }

  .wc-mobile-gif img {
    position: absolute;
    display: block;
    /* the design crops the GIF, so it is placed larger than its window - the site's global
       img { max-width: 100%; max-height: 100% } would otherwise shrink it back and put the
       rain out of register with the still frame it is covering */
    max-width: none;
    max-height: none;
  }

  /* the band above the copy, which scrolls away with it - as the /Scroll frames show */
  .wc-lead {
    display: block;
    margin-bottom: var(--spacing-m);
  }

  .wc-lead img {
    display: block;
    width: 100%;
    height: auto;
  }



  .wc-text {
    position: static;
    grid-row: 1;
    width: 100%;
    height: auto;
    min-height: 0;
    /* the copy inherits --font-m (15px) from body; that is heavy in a phone-width column */
    font-size: clamp(11px, 3.4vw, 13px);
  }

  /* relative, not static: the bands inside are absolutely positioned and would otherwise
     resolve against .wc-content and spill across the whole section */
  .wc-media {
    position: relative;
    grid-row: 2;
    width: 100%;
    height: var(--wc-stack-height);
  }

  /* Keep every stacked tile inside the box below the text: the max constraints clamp the
     element, object-fit keeps the image undistorted within it, and placeBands measures the
     clamped size so its fit pass stays correct. */
  .wc-media .wc-media-tile {
    max-width: 100%;
    max-height: 100%;
    object-fit: contain;
    object-position: top right;
  }




  .wc-title {
    top: 50%;
    left: 50%;
    width: auto;
    transform: translate(-50%, -50%);
  }

  .wc-title h1 {
    margin: 0;
    transform: rotate(-90deg);
  }

  /* Rotated, so the image's layout width becomes its visual height. vh measures the large
     viewport on iOS (URL bar hidden), which overshot the space .wc-viewport actually gets
     once the bar, nav-2, logos and banner are subtracted - hence the crop. */
  .wc-title img {
    width: 74vh;
    width: 66dvh;
    max-width: none;
  }

  .wc-nav-2 {
    flex-wrap: wrap;
    gap: var(--spacing-s);
    height: auto;
    font-size: var(--wc-nav-font);
  }

  .wc-nav-2 .nav-items,
  .wc-nav-2 .nav-logos {
    width: 100%;
  }

  /* the logo row is below the links here, so they can use the full width */
  .wc-nav-2 .nav-items {
    padding-right: 0;
  }

  /* The row is full width here, and space-between leaves a lone item at the start - which
     is what it now is, with only the academy logo left showing. */
  .wc-nav-2 .nav-logos {
    justify-content: flex-end;
  }
}

/* ----- reduced motion ----- */

@media (prefers-reduced-motion: reduce) {
  .wc-nav-1,
  .wc-content,
  .wc-title,
  .wc-text,
  .wc-media-tile {
    transition: none;
  }
}

/* ----- scrollbar ----- */

::-webkit-scrollbar {
  width: 10px;
}

::-webkit-scrollbar-track {
  background: transparent;
}

::-webkit-scrollbar-thumb {
  background: var(--color-mid);
}

::-webkit-scrollbar-thumb:hover {
  background: var(--color-light);
}

/* ----- contrast mode ----- */

/* Plain black ground, no gradients, every text at the design's off-white. Lifting
   --color-mid to match --color-light carries it into the nav, copy and buttons without
   restating each rule; --color-light itself is left alone. */
body.wc-contrast {
  --color-mid: var(--color-light);
  --wc-text-fade: 0%;

  background-image: none;
  background-color: #000;
}

/* Without the fade, stopping the column short of the content area leaves a hard cut where
   the gradient used to disguise the edge - so it runs the full height instead. */
body.wc-contrast .wc-text {
  /* the collage still renders behind the copy, so it needs a solid ground to sit on */
  background-color: var(--color-dark);
  height: 100%;
  -webkit-mask-image: none;
  mask-image: none;
}

body.wc-contrast .wc-nav-1 ul {
  background-image: none;
  background-color: #000;
}

/* --color-mid and --color-light are the same here, so the active page needs another cue */
body.wc-contrast .wc-nav-1 ul li a.active {
  text-decoration: underline;
}

/* ----- horizon sweep -----
   A soft dark band drifting left to right across the page. Over black it is invisible, so
   it only reads where bg.png is bright - along the horizon - without needing a mask. It
   sits at z-index -1: above the body's background image, behind everything on the page. */

@keyframes wc-horizon-sweep {
  from {
    transform: translateX(0);
  }
  to {
    transform: translateX(calc(100vw + var(--wc-sweep-width)));
  }
}

body::after {
  content: "";
  position: fixed;
  top: 0;
  bottom: 0;
  left: calc(-1 * var(--wc-sweep-width));
  width: var(--wc-sweep-width);
  z-index: -1;
  pointer-events: none;
  background-image: linear-gradient(
    90deg,
    rgba(0, 0, 0, 0) 0%,
    rgba(0, 0, 0, var(--wc-sweep-strength)) 50%,
    rgba(0, 0, 0, 0) 100%
  );
  animation: wc-horizon-sweep var(--wc-sweep-duration) linear infinite;
  will-change: transform;
}

/* nothing to sweep across once the ground is flat black */
body.wc-contrast::after {
  display: none;
}

@media (prefers-reduced-motion: reduce) {
  body::after {
    animation: none;
    display: none;
  }
}

/* uni-wc.js pins --wc-scroll to 1 here too; this also covers the page without JS */
@media (prefers-reduced-motion: reduce) {
  .wc-collage-layer {
    opacity: var(--o, 1);
    transform: none;
  }
}

/* ----- landing intro ----- */

/* Plays once per session, set up by the inline script in uni-wc-home.php so the opening
   state is in place before first paint. Each keyframe declares only `from` - the implicit
   `to` is the element's own resting value, so the animations respect whatever the
   breakpoint (or contrast mode) has already decided. */

@keyframes wc-horizon-settle {
  from {
    background-position: 50% var(--wc-bg-y-from);
  }
}

@keyframes wc-bg-reveal {
  from {
    opacity: 1;
  }
}

@keyframes wc-title-emerge {
  from {
    opacity: 0;
    filter: blur(14px);
    transform: var(--wc-title-from);
  }
}

@keyframes wc-chrome-in {
  from {
    opacity: 0;
  }
}

html.wc-intro body {
  animation: wc-horizon-settle 2200ms cubic-bezier(0.22, 0.61, 0.36, 1) backwards;
}

/* background-image cannot be faded directly, so a flat veil over it clears instead.
   z-index -1 keeps it behind the page's content but above the body's own background, so
   only the image crossfades - the title and nav are untouched. */
html.wc-intro body::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  background-color: var(--color-dark);
  opacity: 0;
  animation: wc-bg-reveal 1500ms ease backwards;
}

/* on the img, not .wc-title - the wrapper's transform does the centring and differs
   between breakpoints, so animating it there would need two sets of keyframes */
html.wc-intro .wc-title img {
  animation: wc-title-emerge 1500ms cubic-bezier(0.22, 0.61, 0.36, 1) 400ms backwards;
}

html.wc-intro .wc-nav-1 {
  animation: wc-chrome-in 700ms ease 1300ms backwards;
}

html.wc-intro .wc-mobile-bar {
  animation: wc-chrome-in 700ms ease 1300ms backwards;
}

html.wc-intro .wc-nav-2 {
  animation: wc-chrome-in 700ms ease 1450ms backwards;
}

html.wc-intro .wc-nav-2-banner {
  animation: wc-chrome-in 700ms ease 1600ms backwards;
}

@media (prefers-reduced-motion: reduce) {
  html.wc-intro body,
  html.wc-intro body::before,
  html.wc-intro .wc-title img,
  html.wc-intro .wc-nav-1,
  html.wc-intro .wc-mobile-bar,
  html.wc-intro .wc-nav-2,
  html.wc-intro .wc-nav-2-banner {
    animation: none;
  }
}
